/* ============================================================================
   Remote job board — design system
   Dark-first, compact, zero framework. ~9 KB.
   ========================================================================== */

:root {
  --bg: #0b0d12;
  --surface: #12151c;
  --surface-2: #171b24;
  --surface-hover: #1b2029;
  --border: rgba(255, 255, 255, 0.07);
  --border-strong: rgba(255, 255, 255, 0.13);
  --text: #e8eaed;
  --text-muted: #8b92a4;
  --text-dim: #656c7d;
  --accent: #c8f751;
  --accent-ink: #0b0d12;
  --accent-glow: rgba(200, 247, 81, 0.16);
  --warn: #ffb86b;
  --radius: 8px;
  --radius-lg: 12px;
  --max: 1140px;
  --row-h: 68px;
  --font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Inter, Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
}

/* ---------- Theme resolution ---------------------------------------------
   Three states, resolved with the cascade rather than JavaScript:

     auto (default)  no data-theme attribute -> follows prefers-color-scheme
     light           data-theme="light"      -> always light
     dark            data-theme="dark"       -> always dark

   Doing "auto" in CSS instead of JS means the correct theme paints on the very
   first frame with no flash, and it keeps working with JavaScript disabled.
   The tiny inline script in <head> only runs when the visitor has made an
   EXPLICIT choice, which is the only case CSS cannot express.
   ------------------------------------------------------------------------ */

/* auto -> light, when the visitor's OS asks for light and they have not chosen */
@media (prefers-color-scheme: light) {
  :root:not([data-theme]) {
    --bg: #fbfbfd;
    --surface: #ffffff;
    --surface-2: #f4f5f8;
    --surface-hover: #f0f2f6;
    --border: rgba(10, 12, 20, 0.09);
    --border-strong: rgba(10, 12, 20, 0.16);
    --text: #14171f;
    --text-muted: #5b6373;
    --text-dim: #7b8494;
    --accent: #2f6f2f;
    --accent-ink: #ffffff;
    --accent-glow: rgba(47, 111, 47, 0.1);
  }
}

/* explicit light, chosen via the toggle */
[data-theme='light'] {
  --bg: #fbfbfd;
  --surface: #ffffff;
  --surface-2: #f4f5f8;
  --surface-hover: #f0f2f6;
  --border: rgba(10, 12, 20, 0.09);
  --border-strong: rgba(10, 12, 20, 0.16);
  --text: #14171f;
  --text-muted: #5b6373;
  --text-dim: #7b8494;
  --accent: #2f6f2f;
  --accent-ink: #ffffff;
  --accent-glow: rgba(47, 111, 47, 0.1);
}

/* explicit dark wins over a light system preference */
[data-theme='dark'] {
  --bg: #0b0d12;
  --surface: #12151c;
  --surface-2: #171b24;
  --surface-hover: #1b2029;
  --border: rgba(255, 255, 255, 0.07);
  --border-strong: rgba(255, 255, 255, 0.13);
  --text: #e8eaed;
  --text-muted: #8b92a4;
  --text-dim: #656c7d;
  --accent: #c8f751;
  --accent-ink: #0b0d12;
  --accent-glow: rgba(200, 247, 81, 0.16);
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  font-feature-settings: 'tnum' 0;
}

/* An author `display` rule beats the user agent's `[hidden] { display: none }`,
   because the UA sheet is the weakest origin in the cascade. Any element that
   sets its own display AND gets hidden from script therefore stays on screen.
   That was not a hypothetical: `.job-row` is `display: grid`, so every filter on
   the browse page — search, category, region, type, salary — computed the right
   answer, updated the count to "4 of 18", and then hid nothing at all. */
[hidden] { display: none !important; }

a { color: inherit; text-decoration: none; }
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

.wrap { max-width: var(--max); margin: 0 auto; padding: 0 20px; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: 100;
  background: var(--accent); color: var(--accent-ink);
  padding: 10px 16px; border-radius: var(--radius); font-weight: 600;
  transition: top .16s ease;
}
.skip-link:focus { top: 12px; }

/* ---------- Header ------------------------------------------------------- */

.site-header {
  position: sticky; top: 0; z-index: 50;
  height: 56px; display: flex; align-items: center;
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  border-bottom: 1px solid transparent;
  transition: border-color .2s ease, background .2s ease;
}
.site-header.is-stuck {
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  border-bottom-color: var(--border);
}
.site-header .wrap { display: flex; align-items: center; gap: 16px; width: 100%; }

.brand { display: flex; align-items: center; gap: 9px; font-weight: 700; font-size: 15.5px; letter-spacing: -0.02em; flex-shrink: 0; }
.brand-mark {
  width: 26px; height: 26px; border-radius: 7px; flex-shrink: 0;
  background: linear-gradient(135deg, var(--accent), color-mix(in srgb, var(--accent) 55%, #6ee7ff));
  display: grid; place-items: center; color: var(--accent-ink); font-size: 13px; font-weight: 800;
}
.header-nav { display: flex; align-items: center; gap: 4px; margin-left: auto; }
.header-nav a.nav-link {
  padding: 7px 11px; border-radius: var(--radius); color: var(--text-muted);
  font-size: 13.5px; font-weight: 500; transition: color .15s ease, background .15s ease;
}
.header-nav a.nav-link:hover { color: var(--text); background: var(--surface-2); }

/* The header is one row and cannot wrap — it is sticky and a fixed height — so
   an overflowing header widens the whole document and every page below it
   scrolls sideways, which is what makes a site feel broken on a phone.

   Until 1.4 the answer was to drop links: secondary ones below 700px, all of
   them below 460px. That kept the bar intact and made the menu disappear. The
   links now move into a panel instead — see "Mobile navigation" further down. */
@media (max-width: 460px) {
  .header-nav { gap: 6px; }
  .brand { font-size: 15px; }
  .header-nav .btn-primary { padding: 8px 12px; }
}
@media (max-width: 340px) {
  /* Wordmark goes, logo stays, so the CTA is never squeezed off the screen. */
  .brand > span:not(.brand-mark) { display: none; }
}

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 8px 15px; border-radius: var(--radius); border: 1px solid var(--border-strong);
  background: var(--surface-2); color: var(--text);
  font-size: 13.5px; font-weight: 600; font-family: inherit; cursor: pointer;
  transition: transform .12s ease, background .15s ease, border-color .15s ease;
}
.btn:hover { background: var(--surface-hover); border-color: var(--border-strong); }
.btn:active { transform: translateY(1px); }
.btn-primary { background: var(--accent); color: var(--accent-ink); border-color: transparent; font-weight: 700; }
.btn-primary:hover { background: color-mix(in srgb, var(--accent) 88%, white); }
.btn-lg { padding: 12px 22px; font-size: 15px; }
.btn-block { width: 100%; }
.btn-icon { padding: 8px; width: 34px; height: 34px; }

/* ---------- Hero --------------------------------------------------------- */

.hero { position: relative; overflow: hidden; border-bottom: 1px solid var(--border); }
/* padding-block, not the shorthand: `.hero-inner` sits on the same element as
   `.wrap`, and a `padding` shorthand there wipes out the 20px inline padding
   every other section on the page uses — which is why the headline sat 20px
   left of the job list below it. */
/* No max-height. `.hero` is overflow: hidden (it clips the aurora), so a height
   cap on the inner column does not shrink the content — it cuts the bottom off
   it. On a 700px-tall window, 38vh hid the tag chips and the stats line
   entirely, and the shorter the window the more of the hero disappeared. */
.hero-inner { position: relative; z-index: 2; padding-block: 36px 24px; }
@media (max-width: 760px) { .hero-inner { padding-block: 30px 22px; } }

/* Aurora background. transform/opacity only, so it stays off the main thread.
   Never the LCP element — the headline paints first and does not wait on this. */
.aurora { position: absolute; inset: -40% -10% auto -10%; height: 320px; z-index: 1; filter: blur(72px); opacity: .5; pointer-events: none; }
.aurora span { position: absolute; display: block; border-radius: 50%; will-change: transform; }
.aurora span:nth-child(1) { width: 460px; height: 300px; left: 4%;  background: radial-gradient(circle, var(--accent) 0%, transparent 68%); animation: drift1 calc(19s * var(--fx-speed, 1)) ease-in-out infinite; }
.aurora span:nth-child(2) { width: 380px; height: 280px; left: 38%; background: radial-gradient(circle, #6ee7ff 0%, transparent 68%); animation: drift2 calc(23s * var(--fx-speed, 1)) ease-in-out infinite; }
.aurora span:nth-child(3) { width: 420px; height: 260px; right: 6%; background: radial-gradient(circle, #b98cff 0%, transparent 68%); animation: drift3 calc(27s * var(--fx-speed, 1)) ease-in-out infinite; }
@keyframes drift1 { 0%,100% { transform: translate3d(0,0,0) scale(1); } 50% { transform: translate3d(60px,26px,0) scale(1.13); } }
@keyframes drift2 { 0%,100% { transform: translate3d(0,0,0) scale(1.05); } 50% { transform: translate3d(-50px,34px,0) scale(.92); } }
@keyframes drift3 { 0%,100% { transform: translate3d(0,0,0) scale(.95); } 50% { transform: translate3d(-38px,-22px,0) scale(1.1); } }
@media (prefers-color-scheme: light) { :root:not([data-theme]) .aurora { opacity: .3; } }
[data-theme='light'] .aurora { opacity: .3; }

h1.hero-title {
  margin: 0 0 9px; font-size: clamp(27px, 4vw, 38px); line-height: 1.1;
  letter-spacing: -0.035em; font-weight: 800; max-width: 15ch;
}
.hero-title .accent { color: var(--accent); }
.hero-sub { margin: 0 0 16px; color: var(--text-muted); font-size: 16px; max-width: 56ch; }

.hero-search { display: flex; gap: 8px; max-width: 540px; margin-bottom: 12px; }
.hero-search input {
  flex: 1; padding: 11px 14px; border-radius: var(--radius);
  border: 1px solid var(--border-strong); background: var(--surface);
  color: var(--text); font-size: 15px; font-family: inherit;
}
.hero-search input::placeholder { color: var(--text-dim); }

.chip-row { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 5px 11px; border-radius: 999px; border: 1px solid var(--border);
  background: var(--surface); color: var(--text-muted);
  font-size: 12.5px; font-weight: 500; cursor: pointer; font-family: inherit;
  transition: transform .13s cubic-bezier(.34,1.56,.64,1), background .15s ease, color .15s ease, border-color .15s ease;
}
.chip:hover { color: var(--text); border-color: var(--border-strong); background: var(--surface-2); }
.chip[aria-pressed='true'], .chip.is-active {
  background: var(--accent); color: var(--accent-ink); border-color: transparent; font-weight: 650;
  transform: scale(1.04);
}
.hero-stats { color: var(--text-dim); font-size: 13px; }
.hero-stats strong { color: var(--text); font-weight: 650; font-variant-numeric: tabular-nums; }

/* ---------- Filter bar --------------------------------------------------- */

.filter-bar {
  position: sticky; top: 56px; z-index: 40;
  background: color-mix(in srgb, var(--bg) 90%, transparent);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border); padding: 10px 0;
}
.filter-bar .wrap { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.select {
  appearance: none; padding: 7px 30px 7px 11px; border-radius: var(--radius);
  border: 1px solid var(--border); background: var(--surface); color: var(--text-muted);
  font-size: 13px; font-family: inherit; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%238b92a4' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 10px center;
}
.select:hover { border-color: var(--border-strong); color: var(--text); }
.result-count { margin-left: auto; color: var(--text-dim); font-size: 12.5px; font-variant-numeric: tabular-nums; }

/* ---------- Job rows ----------------------------------------------------- */

.job-list { margin: 0; padding: 0; list-style: none; }

/* Seven children: logo, main, tags, salary, region, age, apply.
   The column count must match exactly or items wrap onto a second implicit row. */
.job-row {
  position: relative; display: grid; align-items: center; gap: 14px;
  grid-template-columns: 40px minmax(0, 1fr) auto auto auto 38px 78px;
  min-height: var(--row-h); padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  transition: background .14s ease, transform .14s ease;
}
/* The apply cell keeps its width whether or not the button is visible, so rows
   do not reflow on hover. */
.job-row > .job-apply { justify-self: end; }
.job-row:hover, .job-row:focus-within { background: var(--surface); transform: translateY(-1px); }
.job-row.is-featured { background: var(--feat, var(--surface-2)); border-left: 2px solid var(--feat-border, var(--accent)); padding-left: 12px; }
.job-row.is-expired { opacity: .55; }

.job-logo {
  width: 40px; height: 40px; border-radius: var(--radius); flex-shrink: 0;
  display: grid; place-items: center; font-weight: 700; font-size: 14px;
  background: var(--logo-bg, var(--surface-2)); color: #fff; letter-spacing: -0.02em;
}
.job-main { min-width: 0; }
.job-title {
  display: block; font-size: 15px; font-weight: 620; letter-spacing: -0.012em;
  color: var(--text); margin-bottom: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.job-row:hover .job-title { color: var(--accent); }
.job-meta { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--text-muted); min-width: 0; }
.job-company { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.job-company:hover { color: var(--text); text-decoration: underline; }

.tag-list { display: flex; gap: 5px; flex-wrap: nowrap; }
.tag {
  padding: 3px 8px; border-radius: 5px; background: var(--surface-2);
  border: 1px solid var(--border); color: var(--text-muted);
  font-size: 11.5px; font-weight: 500; white-space: nowrap;
}
.tag:hover { color: var(--text); border-color: var(--border-strong); }

.job-salary { font-size: 13px; font-weight: 600; color: var(--text); white-space: nowrap; font-variant-numeric: tabular-nums; }
.job-salary.is-undisclosed { color: var(--text-dim); font-weight: 500; }
.job-region { font-size: 12.5px; color: var(--text-muted); white-space: nowrap; }
.job-age { font-size: 12px; color: var(--text-dim); white-space: nowrap; font-variant-numeric: tabular-nums; min-width: 34px; text-align: right; }

/* Apply reveals on hover AND focus-within. Hover does not exist on touch and is
   invisible to keyboard users, so the whole row is always a link underneath. */
.job-apply {
  opacity: 0; transform: translateX(6px);
  transition: opacity .16s ease, transform .16s ease;
  padding: 6px 13px; font-size: 12.5px; white-space: nowrap;
}
.job-row:hover .job-apply, .job-row:focus-within .job-apply { opacity: 1; transform: translateX(0); }
@media (hover: none) { .job-apply { display: none; } }

.badge {
  display: inline-block; padding: 2px 7px; border-radius: 4px;
  font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em;
}
.badge-new { background: var(--accent-glow); color: var(--accent); }
.badge-featured { background: var(--accent); color: var(--accent-ink); }
.badge-expired { background: rgba(255, 184, 107, .14); color: var(--warn); }

/* Narrow screens get an explicit two-row layout rather than a narrower version
   of the same seven-column grid.
 *
 * This has to be spelled out. Hiding .tag-list and .job-region removes them
 * from the grid entirely, so the remaining children reflow into whatever
 * columns are left and land in the wrong places — the classic symptom being an
 * age stamp that drops onto its own line under the logo. Every remaining child
 * is therefore placed by hand.
 */
@media (max-width: 860px) {
  .job-row {
    grid-template-columns: 36px minmax(0, 1fr) auto;
    grid-template-rows: auto auto;
    align-items: start;
    column-gap: 11px; row-gap: 3px;
    padding: 11px 12px;
  }
  .tag-list, .job-region, .job-apply { display: none; }

  .job-row > .job-logo   { grid-column: 1; grid-row: 1 / span 2; align-self: start; }
  .job-row > .job-main   { grid-column: 2; grid-row: 1; }
  .job-row > .job-salary { grid-column: 2; grid-row: 2; font-size: 12.5px; }
  .job-row > .job-age    { grid-column: 3; grid-row: 1; }

  .job-logo { width: 36px; height: 36px; font-size: 13px; }
  .job-title { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
  .job-meta { flex-wrap: wrap; row-gap: 2px; }
}

/* ---------- Sections ----------------------------------------------------- */

.section { padding: 34px 0; }
.section-head { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; margin-bottom: 14px; }
h2.section-title { margin: 0; font-size: 19px; font-weight: 700; letter-spacing: -0.02em; }
.section-link { color: var(--text-muted); font-size: 13px; font-weight: 500; }
.section-link:hover { color: var(--accent); }

.empty-state { padding: 48px 20px; text-align: center; color: var(--text-muted); }
.empty-state p { margin: 0 0 14px; }

.link-cloud { display: flex; flex-wrap: wrap; gap: 7px; }
.link-cloud a {
  padding: 6px 12px; border-radius: var(--radius); border: 1px solid var(--border);
  background: var(--surface); color: var(--text-muted); font-size: 13px;
}
.link-cloud a:hover { color: var(--text); border-color: var(--border-strong); background: var(--surface-2); }

/* ---------- Job detail --------------------------------------------------- */

.breadcrumb { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; font-size: 12.5px; color: var(--text-dim); padding: 18px 0 0; }
.breadcrumb a:hover { color: var(--text); }
.breadcrumb .sep { opacity: .5; }

.job-header { padding: 18px 0 24px; border-bottom: 1px solid var(--border); }
.job-header-top { display: flex; gap: 16px; align-items: flex-start; }
.job-header .job-logo { width: 60px; height: 60px; font-size: 20px; border-radius: var(--radius-lg); }
h1.job-h1 { margin: 0 0 5px; font-size: clamp(23px, 3.4vw, 31px); line-height: 1.16; letter-spacing: -0.03em; font-weight: 750; }
.job-header-company { color: var(--text-muted); font-size: 14.5px; }
.job-header-company a { color: var(--text); font-weight: 600; }
.job-header-company a:hover { color: var(--accent); }

.meta-chips { display: flex; flex-wrap: wrap; gap: 7px; margin: 16px 0 18px; }
.meta-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px; border-radius: var(--radius); border: 1px solid var(--border);
  background: var(--surface); font-size: 13px; color: var(--text-muted);
}
.meta-chip strong { color: var(--text); font-weight: 600; }

.notice {
  padding: 14px 16px; border-radius: var(--radius-lg); margin: 18px 0;
  border: 1px solid; font-size: 14px; line-height: 1.5;
}
.notice-warn { background: rgba(255, 184, 107, .08); border-color: rgba(255, 184, 107, .28); color: var(--warn); }
.notice-warn strong { color: var(--text); }

/* Validation summary at the top of a returned form. Sits above the fields it
   describes and takes focus, so a screen reader announces the problem rather
   than dropping the user back at the top of a form that looks unchanged. */
.form-errors {
  padding: 14px 16px; border-radius: var(--radius-lg); margin: 0 0 22px;
  background: rgba(255, 107, 107, .09); border: 1px solid rgba(255, 107, 107, .32);
  color: var(--text); font-size: 14px; line-height: 1.5;
}
.form-errors:focus { outline: 2px solid var(--accent); outline-offset: 3px; }
.form-errors ul { margin: 8px 0 0; padding-left: 20px; color: var(--text-muted); }
.form-errors li { margin-bottom: 3px; }

.job-layout { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 40px; padding: 28px 0 48px; align-items: start; }
@media (max-width: 900px) { .job-layout { grid-template-columns: 1fr; gap: 28px; } }

.prose { font-size: 15.5px; line-height: 1.68; color: #cfd4de; max-width: 68ch; }
@media (prefers-color-scheme: light) { :root:not([data-theme]) .prose { color: #303747; } }
[data-theme='light'] .prose { color: #303747; }
.prose h2 { margin: 30px 0 10px; font-size: 18px; font-weight: 700; color: var(--text); letter-spacing: -0.015em; }
.prose h3 { margin: 22px 0 8px; font-size: 15.5px; font-weight: 650; color: var(--text); }
.prose h2:first-child, .prose h3:first-child { margin-top: 0; }
.prose p { margin: 0 0 14px; }
.prose ul, .prose ol { margin: 0 0 16px; padding-left: 20px; }
.prose li { margin-bottom: 6px; }
.prose li::marker { color: var(--text-dim); }
.prose strong { color: var(--text); font-weight: 640; }
.prose a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.prose code { font-family: var(--mono); font-size: .89em; background: var(--surface-2); padding: 2px 5px; border-radius: 4px; }
.prose blockquote { margin: 0 0 16px; padding-left: 14px; border-left: 2px solid var(--border-strong); color: var(--text-muted); }
.prose hr { border: 0; border-top: 1px solid var(--border); margin: 24px 0; }

.benefit-grid { display: flex; flex-wrap: wrap; gap: 7px; margin: 8px 0 0; }
.benefit { display: inline-flex; align-items: center; gap: 6px; padding: 6px 11px; border-radius: var(--radius); background: var(--surface-2); border: 1px solid var(--border); font-size: 12.5px; color: var(--text-muted); }

.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 18px; margin-bottom: 16px; }
.card h3 { margin: 0 0 10px; font-size: 14px; font-weight: 650; letter-spacing: -0.01em; }
.card p { margin: 0 0 12px; font-size: 13.5px; color: var(--text-muted); line-height: 1.55; }
.sidebar { position: sticky; top: 78px; }
@media (max-width: 900px) { .sidebar { position: static; } }

.apply-card { border-color: var(--border-strong); }
.apply-note { font-size: 12px; color: var(--text-dim); margin: 10px 0 0; text-align: center; }

.share-row { display: flex; gap: 7px; flex-wrap: wrap; }

/* Sticky mobile apply bar */
.sticky-apply {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  padding: 10px 16px calc(10px + env(safe-area-inset-bottom));
  background: color-mix(in srgb, var(--bg) 94%, transparent);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border-top: 1px solid var(--border);
  display: none; gap: 12px; align-items: center;
  transform: translateY(100%); transition: transform .22s ease;
}
.sticky-apply.is-visible { transform: translateY(0); }
.sticky-apply .sa-title { flex: 1; min-width: 0; font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 900px) { .sticky-apply { display: flex; } body.has-sticky-apply { padding-bottom: 66px; } }

/* ---------- Company page ------------------------------------------------- */

.company-header { display: flex; gap: 18px; align-items: center; padding: 28px 0; border-bottom: 1px solid var(--border); }
.company-header .job-logo { width: 64px; height: 64px; font-size: 22px; border-radius: var(--radius-lg); }
h1.company-h1 { margin: 0 0 4px; font-size: 27px; letter-spacing: -0.03em; font-weight: 750; }

.company-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 12px; }
.company-card { display: block; padding: 16px; border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--surface); transition: transform .14s ease, border-color .15s ease; }
.company-card:hover { transform: translateY(-2px); border-color: var(--border-strong); }
.company-card .cc-head { display: flex; align-items: center; gap: 11px; margin-bottom: 9px; }
.company-card .job-logo { width: 34px; height: 34px; font-size: 12px; }
.company-card h3 { margin: 0; font-size: 14.5px; font-weight: 650; }
.company-card p { margin: 0; font-size: 12.5px; color: var(--text-muted); line-height: 1.5; }
.company-card .cc-count { margin-top: 9px; font-size: 12px; color: var(--accent); font-weight: 600; }

/* ---------- Pagination --------------------------------------------------- */

.pagination { display: flex; align-items: center; justify-content: center; gap: 6px; padding: 28px 0; flex-wrap: wrap; }
.pagination a, .pagination span {
  min-width: 34px; height: 34px; padding: 0 10px; border-radius: var(--radius);
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border); background: var(--surface);
  font-size: 13px; color: var(--text-muted); font-variant-numeric: tabular-nums;
}
.pagination a:hover { color: var(--text); border-color: var(--border-strong); }
.pagination .is-current { background: var(--accent); color: var(--accent-ink); border-color: transparent; font-weight: 700; }
.pagination .is-gap { border: 0; background: none; }

/* ---------- Alerts / forms ----------------------------------------------- */

.alert-box { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 26px; text-align: center; }
.alert-box h2 { margin: 0 0 7px; font-size: 19px; letter-spacing: -0.02em; }
.alert-box p { margin: 0 0 16px; color: var(--text-muted); font-size: 14px; }
.alert-form { display: flex; gap: 8px; max-width: 420px; margin: 0 auto; }
.alert-form input {
  flex: 1; padding: 10px 13px; border-radius: var(--radius);
  border: 1px solid var(--border-strong); background: var(--bg);
  color: var(--text); font-size: 14.5px; font-family: inherit;
}
@media (max-width: 520px) { .alert-form { flex-direction: column; } }

.field { margin-bottom: 16px; }
.field label { display: block; font-size: 13.5px; font-weight: 600; margin-bottom: 5px; }
.field .hint { display: block; font-size: 12.5px; color: var(--text-dim); margin-bottom: 7px; font-weight: 400; }
.field input, .field textarea, .field select {
  width: 100%; padding: 10px 13px; border-radius: var(--radius);
  border: 1px solid var(--border-strong); background: var(--surface);
  color: var(--text); font-size: 14.5px; font-family: inherit;
}
.field textarea { min-height: 150px; resize: vertical; line-height: 1.55; }

/* ---------- FAQ ---------------------------------------------------------- */

.faq details { border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); margin-bottom: 8px; }
.faq summary { padding: 13px 16px; cursor: pointer; font-weight: 600; font-size: 14px; list-style: none; display: flex; justify-content: space-between; gap: 12px; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: '+'; color: var(--text-dim); font-size: 17px; line-height: 1; }
.faq details[open] summary::after { content: '−'; }
.faq .faq-body { padding: 0 16px 14px; color: var(--text-muted); font-size: 13.5px; line-height: 1.6; }
.faq .faq-body p { margin: 0 0 10px; }
.faq .faq-body p:last-child { margin: 0; }

/* ---------- Footer ------------------------------------------------------- */

.site-footer { border-top: 1px solid var(--border); padding: 34px 0 44px; margin-top: 20px; color: var(--text-muted); font-size: 13px; }
.footer-cols { display: grid; grid-template-columns: 1.6fr repeat(3, 1fr); gap: 28px; margin-bottom: 26px; }
@media (max-width: 760px) { .footer-cols { grid-template-columns: 1fr 1fr; gap: 22px; } }
.footer-cols h4 { margin: 0 0 9px; font-size: 12px; text-transform: uppercase; letter-spacing: .07em; color: var(--text-dim); font-weight: 650; }
.footer-cols ul { margin: 0; padding: 0; list-style: none; }
.footer-cols li { margin-bottom: 6px; }
.footer-cols a:hover { color: var(--text); }
.footer-bottom { display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; padding-top: 18px; border-top: 1px solid var(--border); font-size: 12.5px; color: var(--text-dim); }

/* ---------- Motion preferences ------------------------------------------- */
/* Mandatory: this is an accessibility requirement, not a nicety. */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  .aurora span { animation: none !important; }
  .job-apply { opacity: 1; transform: none; }
}


/* ---------- Theme toggle (single button) --------------------------------- */

.theme-toggle {
  display: inline-grid; place-items: center;
  width: 34px; height: 34px; padding: 0;
  color: var(--text-muted);
}
.theme-toggle:hover { color: var(--text); }
.theme-toggle svg {
  width: 15px; height: 15px; fill: none; stroke: currentColor;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
#theme-auto { margin-right: 10px; }
#theme-auto:hover { color: var(--text); }
/* The toggle stays visible at every width. Phones are where a light/dark switch
   matters most, so hiding it on small screens would remove the feature exactly
   where it is used. */

/* ============================================================================
   Utility classes.

   These exist so no template ever needs an inline style="" attribute. A strict
   `style-src 'self'` blocks inline style attributes, not just <style> elements,
   so an inline style anywhere would force either 'unsafe-inline' (which guts
   the policy) or per-page hashes (impossible to cache). Named classes are the
   clean way out.

   The only dynamic per-element value is a company's brand colour, handled by
   Templates::brandStyleSheet() which emits one <style> block whose SHA-256 hash
   is added to the CSP at request time.
   ========================================================================== */

.u-flush        { margin: 0; }
.u-mt-sm        { margin-top: 10px; }
.u-mt           { margin-top: 20px; }
.u-mt-lg        { margin-top: 30px; }
.u-mt-xl        { margin-top: 34px; }
.u-mb-sm        { margin-bottom: 8px; }
.u-mb           { margin-bottom: 16px; }
.u-mb-lg        { margin-bottom: 22px; }
.u-pt-0         { padding-top: 0; }
.u-pt-sm        { padding-top: 16px; }
.u-pt           { padding-top: 24px; }
.u-pad-page     { padding: 26px 0 12px; }
.u-pad-page-lg  { padding: 40px 0; }
.u-pad-hero     { padding: 34px 0 8px; }
.u-pad-empty    { padding: 90px 20px; }

.u-narrow       { max-width: 620px; }
.u-readable     { max-width: 680px; }
.u-wide         { max-width: 720px; }
.u-measure      { max-width: 62ch; }
.u-measure-sm   { max-width: 34ch; }
.u-min0         { min-width: 0; }
.u-grow         { flex: 1; }
.u-w-sm         { width: 100px; }

.u-muted        { color: var(--text-muted); }
.u-dim          { color: var(--text-dim); }
.u-body         { font-size: 15px; }
.u-body-lg      { font-size: 16px; }
.u-small        { font-size: 13px; }
.u-tiny         { font-size: 12px; }
.u-center       { text-align: center; }
.u-row          { display: flex; gap: 8px; }
.u-stack-sm > * { margin-bottom: 6px; }
.u-offscreen    { position: absolute; left: -9999px; }
.u-tall         { min-height: 110px; }
.u-inline-mr    { margin-right: 5px; }

.page-title     { margin: 0 0 8px; font-size: clamp(24px, 3.6vw, 32px); letter-spacing: -.03em; font-weight: 750; }
.page-title-lg  { margin: 0 0 10px; font-size: clamp(25px, 3.8vw, 34px); letter-spacing: -.03em; font-weight: 780; }
.page-title-xl  { margin: 12px 0 10px; font-size: clamp(26px, 4vw, 38px); letter-spacing: -.03em; font-weight: 800; }
.page-lede      { margin: 0; color: var(--text-muted); max-width: 62ch; font-size: 15px; }
.sub-heading    { font-size: 18px; margin: 0 0 10px; letter-spacing: -.015em; }
.form-heading   { font-size: 18px; margin: 28px 0 14px; letter-spacing: -.015em; }
.country-pill   { padding: 6px 12px; border-radius: 8px; border: 1px solid var(--border); background: var(--surface); color: var(--text-muted); font-size: 13px; }
.big-404        { font-size: 56px; margin: 0 0 6px; letter-spacing: -.04em; font-weight: 800; }

/* ---------- Uploaded brand image ----------------------------------------- */
/* A logo is an <img> only when one has been uploaded; otherwise the monogram
   markup above is used. Height is capped so an oversized upload cannot push
   the 56px header out of shape. */
/* Sized from the logo's own proportions.
   --logo-h is computed on upload from the image's aspect ratio (see
   Settings::logoHeight): a long wordmark gets less height, a square badge more,
   because one fixed height cannot flatter both and the person uploading should
   not have to work that out. --logo-w is the manual override, for when they
   want to. */
.brand-img {
  display: block;
  height: var(--logo-h, 34px);
  width: auto;
  max-width: min(280px, 42vw);
  object-fit: contain;
}
.brand-img-sized { width: var(--logo-w, auto); height: auto; max-height: calc(var(--logo-h, 34px) + 6px); }
.site-footer .brand-img { height: calc(var(--logo-h, 34px) * .78); }

/* The header is 62px and 58px; a logo scales with it rather than staying put
   and crowding the bar on a phone. */
@media (max-width: 700px) {
  .brand-img { height: calc(var(--logo-h, 34px) * .84); max-width: 44vw; }
}
@media (max-width: 420px) {
  .brand-img { height: calc(var(--logo-h, 34px) * .76); max-width: 40vw; }
}

/* ---------- Employer account area ---------------------------------------- */
/* The only tabular data on the public site. Deliberately quiet — this is a
   utility screen, not part of the board's front door. */

.page-head-row {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 20px; flex-wrap: wrap; margin-bottom: 8px;
}

.data-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.data-table th, .data-table td {
  padding: 12px 14px; text-align: left; border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.data-table thead th {
  font-size: 11px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--text-dim); font-weight: 700;
}
.data-table tbody tr:last-child td { border-bottom: 0; }
.data-table tbody tr:hover { background: var(--surface); }
.data-table a { font-weight: 600; }
.data-table a:hover { color: var(--accent); }
.data-table .right { text-align: right; white-space: nowrap; }
.data-table .right .btn { margin-left: 6px; }

.u-inline { display: inline-block; }

/* Below this width the four columns stop being readable, so each row becomes
   a stacked card with its column name as a label. */
@media (max-width: 620px) {
  .data-table thead { display: none; }
  .data-table tbody tr {
    display: block; padding: 12px 0; border-bottom: 1px solid var(--border);
  }
  .data-table td { display: flex; justify-content: space-between; gap: 14px; padding: 4px 0; border: 0; }
  .data-table td::before {
    content: attr(data-label); color: var(--text-dim); font-size: 12.5px; flex-shrink: 0;
  }
  .data-table .right { text-align: left; }
  .data-table .right .btn { margin: 6px 6px 0 0; }
}

/* ============================================================================
   Post-a-job page — v1.0
   Two columns on a desktop: the form, and a live preview that follows you down
   the page. On a phone the preview moves above the form and collapses, because
   a sticky panel on a 700px-tall screen would eat the form it is describing.
   ========================================================================== */

.hire-hero {
  border-bottom: 1px solid var(--border);
  background:
    radial-gradient(900px 300px at 15% -20%, var(--accent-glow), transparent 60%),
    var(--surface);
}
.hire-hero-inner { padding-block: 40px 32px; }
.hire-trust {
  display: flex; flex-wrap: wrap; gap: 8px 22px;
  margin: 18px 0 0; padding: 0; list-style: none;
  font-size: 13.5px; color: var(--text-muted);
}
.hire-trust li { display: flex; align-items: center; gap: 7px; }
.hire-trust li::before {
  content: '✓'; color: var(--accent); font-weight: 800; font-size: 12px;
}

.hire-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) 380px;
  gap: 36px; align-items: start; padding: 32px 0 64px;
}
.hire-side { position: sticky; top: 72px; display: grid; gap: 16px; }

.hire-step {
  padding: 24px; margin-bottom: 18px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
.step-h {
  display: flex; align-items: center; gap: 11px;
  margin: 0 0 18px; font-size: 17px; letter-spacing: -.02em;
}
.step-n {
  display: grid; place-items: center; flex-shrink: 0;
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--accent); color: var(--accent-ink);
  font-size: 13px; font-weight: 800;
}
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }

.salary-row { display: grid; grid-template-columns: 1fr auto 1fr 110px; gap: 8px; align-items: center; }
.salary-dash { color: var(--text-dim); }

.counter { font-variant-numeric: tabular-nums; font-weight: 600; }
.counter.short { color: var(--warn); }
.counter.ok { color: var(--accent); }

/* ---------- Package cards ------------------------------------------------ */

.pkg-grid { display: grid; gap: 12px; }
.pkg { display: block; cursor: pointer; position: relative; }
.pkg input {
  position: absolute; opacity: 0; width: 1px; height: 1px;
}
.pkg-body {
  display: block; padding: 16px 18px;
  border: 1.5px solid var(--border-strong); border-radius: var(--radius-lg);
  background: var(--bg); transition: border-color .15s ease, background .15s ease;
}
.pkg:hover .pkg-body { border-color: var(--text-dim); }
.pkg input:checked + .pkg-body {
  border-color: var(--accent);
  background: var(--accent-glow);
}
/* Focus has to be visible on the label, since the real radio is off-screen. */
.pkg input:focus-visible + .pkg-body { outline: 2px solid var(--accent); outline-offset: 2px; }
.pkg-flag {
  position: absolute; top: -9px; right: 14px; z-index: 1;
  padding: 2px 9px; border-radius: 999px;
  background: var(--accent); color: var(--accent-ink);
  font-size: 10.5px; font-weight: 800; text-transform: uppercase; letter-spacing: .05em;
}
.pkg-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.pkg-name { font-weight: 700; font-size: 15.5px; }
.pkg-price { font-weight: 800; font-size: 19px; letter-spacing: -.02em; }
.pkg-blurb { display: block; margin-top: 4px; font-size: 13px; color: var(--text-muted); }
.pkg-perks {
  margin: 12px 0 0; padding: 0; list-style: none;
  display: grid; gap: 5px; font-size: 12.5px; color: var(--text-muted);
}
.pkg-perks li { display: flex; align-items: flex-start; gap: 7px; }
.pkg-perks li::before { content: '✓'; color: var(--accent); font-weight: 800; flex-shrink: 0; }

/* ---------- Preview ------------------------------------------------------ */

.preview-card, .order-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: 16px;
}
.preview-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 10px; font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .08em; color: var(--text-dim);
}
.preview-toggle {
  background: none; border: 0; padding: 2px 6px; cursor: pointer;
  color: var(--text-muted); font: inherit; text-transform: none; letter-spacing: 0;
  border-radius: 5px;
}
.preview-toggle:hover { color: var(--text); background: var(--surface-2); }
.preview-note { margin: 0 0 10px; font-size: 12.5px; color: var(--text-dim); }

/* The preview reuses the real .job-row rules, so what an employer sees is the
   component the board actually renders — not a drawing of it. */
.preview-list { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.preview-list .job-row { grid-template-columns: 34px minmax(0, 1fr) auto; gap: 10px; padding: 10px 11px; }
.preview-list .job-row:hover { transform: none; background: none; }
.preview-list .job-logo { width: 34px; height: 34px; font-size: 12px; }
.preview-list .tag-list, .preview-list .job-region, .preview-list .job-apply { display: none; }
.preview-list .job-salary { grid-column: 2; font-size: 12px; }
.preview-list .job-age { grid-column: 3; grid-row: 1; }
.preview-list .job-title { font-size: 14px; }

.preview-page {
  margin-top: 14px; padding: 14px;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg);
}
.preview-page-head { display: flex; align-items: center; gap: 11px; margin-bottom: 10px; }
.job-logo.lg { width: 40px; height: 40px; font-size: 14px; }
.preview-page-head strong { display: block; font-size: 14.5px; letter-spacing: -.015em; }
.preview-chips { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 10px; }
.preview-chips .meta-chip { font-size: 11.5px; padding: 3px 8px; }
.preview-body-text {
  font-size: 12.5px; color: var(--text-muted); line-height: 1.6;
  max-height: 190px; overflow: hidden; position: relative;
}
.preview-body-text.is-placeholder { color: var(--text-dim); font-style: italic; }
.preview-body-text p { margin: 0 0 7px; }
.preview-body-text strong { display: block; color: var(--text); margin: 10px 0 4px; }
/* Fades the cut-off rather than ending mid-word. */
.preview-body-text::after {
  content: ''; position: absolute; inset: auto 0 0 0; height: 40px;
  background: linear-gradient(transparent, var(--bg));
}

.order-card h3 { margin: 0 0 12px; font-size: 14px; letter-spacing: -.01em; }
.order-line {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding-bottom: 10px; border-bottom: 1px solid var(--border);
}
.order-line strong { font-size: 19px; letter-spacing: -.02em; }
.order-note { margin: 10px 0 0; font-size: 12.5px; color: var(--text-muted); }
.order-pay { margin: 8px 0 0; font-size: 12px; color: var(--text-dim); }

/* ---------- Small screens ------------------------------------------------
   The preview goes first — an employer should see what they are buying before
   they start typing — but collapsed, so it costs one line rather than a
   screenful. Sticky is dropped entirely; on a short viewport a pinned panel
   just squeezes the form. */
@media (max-width: 940px) {
  .hire-grid { grid-template-columns: 1fr; gap: 20px; }
  /* display: contents dissolves the sidebar so its cards become grid items in
     their own right and can be ordered individually. Without it the preview is
     stuck to whatever the sidebar does, and the sidebar has to come first —
     which is how the preview ended up ABOVE the form on a phone, asking someone
     to look at an empty preview before they had typed anything. */
  .hire-side { display: contents; }
  .order-card { order: -1; }        /* the price stays visible from the start */
  .hire-main { order: 0; }
  .preview-card { order: 1; }       /* after the form, where it is worth looking */
  .hire-testimonials { order: 2; }
  .hire-preview-bottom { order: 1; }
}
@media (max-width: 620px) {
  .hire-hero-inner { padding-block: 28px 24px; }
  .hire-step { padding: 18px 16px; }
  .field-row { grid-template-columns: 1fr; gap: 0; }
  .salary-row { grid-template-columns: 1fr 1fr; gap: 8px; }
  .salary-dash { display: none; }
  .salary-row select { grid-column: 1 / -1; }
  .pkg-body { padding: 14px 15px; }
  .pkg-price { font-size: 17px; }
  .hire-trust { gap: 6px 16px; font-size: 12.5px; }
  /* A full-width action at the bottom of the viewport is the one control that
     should never require scrolling to find on a phone. */
  .page-hire #hire-submit {
    position: sticky; bottom: 12px; z-index: 20;
    box-shadow: 0 8px 28px rgba(0, 0, 0, .45);
  }
}

/* The preview column is 380px wide, so the row inside it needs tighter rules
   than the real board — the company name and employment type must not fight
   each other for a line. */
.preview-list .job-meta { font-size: 11.5px; gap: 5px; flex-wrap: nowrap; overflow: hidden; }
.preview-list .job-company { max-width: 42%; }
.preview-list .badge { font-size: 9px; padding: 1px 5px; flex-shrink: 0; }
.preview-list .job-age { font-size: 11px; }

/* A note under a URL field when the scheme was filled in for the visitor.
   Announced, never silent — quietly rewriting what someone typed is how a form
   loses trust, and this one is asking for money. */
.scheme-note {
  display: block; margin-top: 6px; font-size: 12.5px;
  color: var(--accent); font-weight: 600;
}

/* ============================================================================
   v1.3 — header width, background effects, password meter, share, print
   ========================================================================== */

/* ---------- Header: full width -------------------------------------------
   The header used to sit inside the same 1140px column as the content, which
   on a wide monitor left the logo floating a long way in from the left edge
   with nothing around it. A site header is a bar; it should span the window
   and let its contents sit near the edges. The reading column stays narrow,
   because line length is a readability constraint and header width is not. */

/* The bar spans the window; its CONTENTS line up with the page content.
   1.3 had the whole header inside the 1140px reading column, which on a wide
   monitor left the logo stranded far from the edge. 1.4 overcorrected and
   pushed it hard against the window edge, where it no longer lined up with
   anything below it — the logo sat at 56px while the first job row started at
   260px. Aligning to the same container fixes both: the bar still reads as
   full width because its background and border are, and the logo now sits
   directly above the content it belongs to. */
.site-header .wrap { max-width: var(--max); }
.site-header { height: 62px; }

/* The reading column widens on a large monitor, but only so far. 1140px was
   set for prose; a job row is a table — logo, title, tags, salary, region, age —
   and at 1140 those columns are cramped while a third of a 1920px screen sits
   empty. Text that should stay narrow says so itself (.u-narrow, .u-measure),
   so widening the container does not widen paragraphs. */
@media (min-width: 1280px) {
  :root { --max: 1320px; }
}
@media (min-width: 1600px) {
  :root { --max: 1440px; }
}
.brand { font-size: 16.5px; gap: 10px; }
.brand-mark { width: 30px; height: 30px; border-radius: 8px; font-size: 14px; }
.header-nav { gap: 6px; }
.header-nav a.nav-link { font-size: 14px; padding: 8px 13px; }
.filter-bar { top: 62px; }

@media (max-width: 700px) {
  .site-header { height: 58px; }
  .site-header .wrap { padding-inline: 16px; }
  .filter-bar { top: 58px; }
}

/* ---------- Optional background effects ----------------------------------
   Chosen in the admin theme editor and applied as a body class, so the CSS is
   static and cacheable and only the class name is dynamic. All are pure CSS —
   no canvas, no JavaScript, nothing that costs a frame budget on a phone.
   Every one is switched off entirely under prefers-reduced-motion. */

/* z-index: -1 rather than raising everything else above a z-index: 0 layer.
   `html` sets no background, so body's colour propagates to the canvas and a
   negative-z-index child of body paints above that canvas and below every
   in-flow element — no other rule has to change. Raising `body > *` instead
   would give <main> a stacking context, which would trap the fixed apply bar
   (z-index 60) underneath the sticky header (z-index 50). */
.bg-fx {
  position: fixed; inset: 0; z-index: -1; pointer-events: none;
  contain: layout paint;
}

/* Mesh: slow-moving colour fields. The default choice — visible enough to feel
   alive, dim enough to read over. */
.fx-mesh .bg-fx {
  background:
    radial-gradient(45vw 45vw at 12% 8%, var(--accent-glow), transparent 70%),
    radial-gradient(40vw 40vw at 88% 22%, rgba(110, 231, 255, .10), transparent 70%),
    radial-gradient(50vw 50vw at 55% 92%, rgba(185, 140, 255, .09), transparent 70%);
  animation: meshDrift calc(34s * var(--fx-speed, 1)) ease-in-out infinite alternate;
}
@keyframes meshDrift {
  0%   { transform: translate3d(0, 0, 0) scale(1); }
  100% { transform: translate3d(-2%, 2%, 0) scale(1.08); }
}

/* Grid: an engineering-drawing feel, drifting slowly upward. */
.fx-grid .bg-fx {
  background-image:
    linear-gradient(var(--border) 1px, transparent 1px),
    linear-gradient(90deg, var(--border) 1px, transparent 1px);
  background-size: 56px 56px;
  mask-image: radial-gradient(120vw 80vh at 50% 0%, #000 20%, transparent 78%);
  -webkit-mask-image: radial-gradient(120vw 80vh at 50% 0%, #000 20%, transparent 78%);
  animation: gridDrift calc(26s * var(--fx-speed, 1)) linear infinite;
}
@keyframes gridDrift { to { background-position: 0 -56px, -56px 0; } }

/* Dots: quieter than the grid, same idea. */
.fx-dots .bg-fx {
  background-image: radial-gradient(var(--border-strong) 1px, transparent 1px);
  background-size: 26px 26px;
  mask-image: radial-gradient(120vw 70vh at 50% 0%, #000 10%, transparent 72%);
  -webkit-mask-image: radial-gradient(120vw 70vh at 50% 0%, #000 10%, transparent 72%);
  animation: gridDrift calc(40s * var(--fx-speed, 1)) linear infinite;
}

/* Beams: diagonal light sweeps crossing the page. */
.fx-beams .bg-fx {
  background:
    linear-gradient(115deg, transparent 38%, var(--accent-glow) 47%, transparent 56%),
    linear-gradient(115deg, transparent 62%, rgba(110, 231, 255, .08) 70%, transparent 78%);
  background-size: 260% 260%;
  animation: beamSweep calc(22s * var(--fx-speed, 1)) ease-in-out infinite alternate;
}
@keyframes beamSweep {
  0%   { background-position: 0% 0%, 100% 100%; }
  100% { background-position: 100% 100%, 0% 0%; }
}

/* Hero effects sit inside .hero, above the page effect. */
.hero-fx { position: absolute; inset: 0; z-index: 1; pointer-events: none; overflow: hidden; }
.hero-beams .hero-fx {
  background: linear-gradient(105deg, transparent 40%, var(--accent-glow) 50%, transparent 60%);
  background-size: 300% 100%;
  animation: beamSweep calc(16s * var(--fx-speed, 1)) ease-in-out infinite alternate;
}
.hero-mesh .hero-fx {
  background:
    radial-gradient(60% 90% at 18% 0%, var(--accent-glow), transparent 72%),
    radial-gradient(50% 80% at 82% 30%, rgba(110, 231, 255, .12), transparent 72%);
  animation: meshDrift calc(28s * var(--fx-speed, 1)) ease-in-out infinite alternate;
}

@media (prefers-reduced-motion: reduce) {
  .bg-fx, .hero-fx { animation: none !important; }
}

/* ---------- Password meter ---------------------------------------------- */

.pw-meter { margin-top: 8px; }
.pw-bar { display: grid; grid-template-columns: repeat(4, 1fr); gap: 4px; }
.pw-bar i {
  height: 4px; border-radius: 2px; background: var(--border-strong);
  transition: background .18s ease;
}
.pw-meter.score-1 .pw-bar i.on { background: #ff6b6b; }
.pw-meter.score-2 .pw-bar i.on { background: #ffb86b; }
.pw-meter.score-3 .pw-bar i.on { background: #7fd8a0; }
.pw-meter.score-4 .pw-bar i.on { background: var(--accent); }
.pw-label { margin: 6px 0 0; font-size: 12.5px; font-weight: 700; color: var(--text-muted); }
.pw-meter.score-1 .pw-label { color: #ff6b6b; }
.pw-meter.score-2 .pw-label { color: #ffb86b; }
.pw-meter.score-3 .pw-label,
.pw-meter.score-4 .pw-label { color: var(--accent); }
.pw-problems { margin: 5px 0 0; padding-left: 16px; font-size: 12px; color: var(--text-dim); }
.pw-problems li { margin-bottom: 2px; }
.pw-meter:not(.is-active) { display: none; }
input.is-mismatch, input.is-weak { border-color: #ff6b6b; }
input.is-mismatch:focus, input.is-weak:focus { border-color: #ff6b6b; box-shadow: 0 0 0 3px rgba(255, 107, 107, .18); }

/* ---------- Share, print, testimonials ----------------------------------- */

.share-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 7px; }
.share-btn {
  display: flex; align-items: center; gap: 8px; justify-content: flex-start;
  padding: 9px 12px; border-radius: var(--radius);
  border: 1px solid var(--border-strong); background: var(--surface);
  color: var(--text-muted); font-size: 13px; font-weight: 600;
  font-family: inherit; cursor: pointer; text-align: left; width: 100%;
  transition: color .14s ease, border-color .14s ease, background .14s ease;
}
.share-btn:hover { color: var(--text); border-color: var(--text-dim); background: var(--surface-2); }
.share-btn .icon { flex-shrink: 0; opacity: .8; }
.share-btn.is-done { color: var(--accent); border-color: var(--accent); }
/* Hiding is handled by the global [hidden] rule near the top of this file. */
#share-native { grid-column: 1 / -1; justify-content: center; }

/* A checkbox chip that is ticked. The class is set server-side for the state
   the page arrives in; :has() keeps it right as the visitor clicks. */
.chip:has(input:checked) {
  background: var(--accent); color: var(--accent-ink); border-color: transparent; font-weight: 650;
}

.job-subscribe { margin-top: 14px; }
.job-subscribe form { display: flex; gap: 7px; margin-top: 9px; }
.job-subscribe input { flex: 1; min-width: 0; }
@media (max-width: 380px) { .job-subscribe form { flex-direction: column; } }

.testimonial {
  padding: 15px 16px; border-radius: var(--radius-lg);
  background: var(--surface); border: 1px solid var(--border);
  margin-bottom: 10px;
}
.testimonial blockquote { margin: 0 0 10px; font-size: 13.5px; line-height: 1.6; color: var(--text); }
.testimonial figcaption { display: flex; align-items: center; gap: 9px; font-size: 12.5px; color: var(--text-dim); }
.testimonial .t-mark {
  width: 28px; height: 28px; border-radius: 50%; flex-shrink: 0;
  display: grid; place-items: center; font-size: 11px; font-weight: 800;
  background: var(--surface-2); color: var(--text-muted);
}
.testimonial cite { font-style: normal; font-weight: 650; color: var(--text-muted); }
.hire-testimonials { margin-top: 14px; }
.side-h {
  margin: 0 0 10px; font-size: 12px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .08em; color: var(--text-dim);
}

/* ---------- Print --------------------------------------------------------
   A candidate printing a listing wants the role, the pay and how to apply.
   Everything else is furniture. */

@media print {
  .site-header, .site-footer, .filter-bar, .sidebar, .sticky-apply,
  .share-grid, .job-subscribe, .skip-link, .bg-fx, .hero-fx, .aurora,
  .related-jobs, .job-apply { display: none !important; }
  body { background: #fff; color: #000; font-size: 11pt; }
  .wrap { max-width: 100%; padding: 0; }
  .job-layout { display: block; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; color: #444; }
  .prose { color: #000; }
  .meta-chip { border: 1px solid #999; color: #000; }
  h1, h2, h3 { color: #000; page-break-after: avoid; }
  p, li { page-break-inside: avoid; }
}

/* ============================================================================
   v1.4 — mobile navigation, animated New badge
   ========================================================================== */

/* ---------- Mobile navigation ---------------------------------------------
   Above 780px the panel is not a panel: it is the row of links it always was,
   laid out inline, and the menu button is not rendered at all. Below 780px the
   links move behind the button.

   `html.js` gates the collapsing behaviour. The class is set by the inline
   script in <head>, before the first paint, so there is no jump. With scripting
   off the panel simply sits on a second row — every link reachable, the header
   a little taller. A button that does nothing is the one outcome worth ruling
   out. */

.nav-panel { display: flex; align-items: center; gap: 4px; }
.nav-burger { display: none; }

@media (max-width: 780px) {
  .nav-burger {
    display: grid; place-items: center;
    width: 36px; height: 36px; flex-shrink: 0;
    padding: 0; border-radius: var(--radius);
    border: 1px solid var(--border-strong); background: var(--surface-2);
    color: var(--text); cursor: pointer; font-family: inherit;
    transition: background .15s ease, border-color .15s ease;
  }
  .nav-burger:hover { background: var(--surface-hover); }

  .nb-lines { display: grid; gap: 4px; width: 16px; }
  .nb-lines i {
    display: block; height: 2px; border-radius: 2px; background: currentColor;
    transition: transform .22s ease, opacity .16s ease;
  }
  /* Three lines fold into a cross. The middle one fades; the outer two rotate
     about their own centres after being translated onto it. */
  [aria-expanded='true'] .nb-lines i:nth-child(1) { transform: translateY(6px) rotate(45deg); }
  [aria-expanded='true'] .nb-lines i:nth-child(2) { opacity: 0; }
  [aria-expanded='true'] .nb-lines i:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

  /* Anchored to the header, not to the nav, so the sheet spans the window.
     .site-header is position: sticky, which is a positioned value, so it is
     already the containing block for this. */
  .js .nav-panel {
    position: absolute; top: 100%; left: 0; right: 0;
    display: none; flex-direction: column; align-items: stretch; gap: 2px;
    padding: 10px 16px 16px;
    background: var(--bg);
    border-bottom: 1px solid var(--border);
    box-shadow: 0 20px 44px rgba(0, 0, 0, .34);
  }
  .js .site-header.nav-open .nav-panel { display: flex; }
  .js .site-header.nav-open { border-bottom-color: var(--border); }

  .nav-panel a.nav-link {
    padding: 12px 12px; border-radius: var(--radius);
    font-size: 15px; font-weight: 550; color: var(--text);
  }
  .nav-panel a.nav-link:hover { background: var(--surface-2); }

  /* Scripting off: the links get their own row rather than disappearing. The
     header stops being a fixed-height bar, which is fine — it is only sticky,
     not measured by anything else. */
  /* Three rows is a lot to pin to the top of a phone screen, so this one does
     not stick. The filter bar then has nothing above it to clear. */
  html:not(.js) .site-header { position: static; height: auto; min-height: 58px; padding: 8px 0 10px; }
  html:not(.js) .filter-bar { top: 0; }
  html:not(.js) .site-header .wrap { flex-wrap: wrap; row-gap: 8px; }
  html:not(.js) .header-nav { flex-wrap: wrap; row-gap: 8px; justify-content: flex-end; }
  html:not(.js) .nav-panel {
    order: 3; flex: 1 0 100%;
    flex-wrap: wrap; justify-content: flex-start; gap: 4px;
    padding-top: 8px; border-top: 1px solid var(--border);
  }
  html:not(.js) .nav-burger { display: none; }
}

/* The menu editor's second flag used to mean "hide this below 700px". With the
   panel there is nothing left to hide from — every link fits on a phone now —
   so it means what the class always said instead: secondary. Drawn a shade
   quieter in the inline row, full strength in the panel where a row of dimmed
   links would just look disabled. */
.header-nav .nav-panel > .nav-secondary { color: var(--text-dim); }
.header-nav .nav-panel > .nav-secondary:hover { color: var(--text); }
@media (max-width: 780px) {
  .header-nav .nav-panel > .nav-secondary { color: var(--text); }
}

@media (max-width: 360px) {
  .header-nav { gap: 5px; }
  .header-nav .btn-primary { padding: 8px 11px; font-size: 13px; }
}

/* ---------- Animated "New" badge -------------------------------------------
   The window is set in the admin panel; this is only the motion. Each variant
   animates something other than the badge's own box wherever it can, because a
   transform on the badge nudges the job title sitting next to it.

   All three stop under prefers-reduced-motion, and none of them is the only
   signal that a listing is new — the word "New" is there either way. */

.badge-new { position: relative; }
/* Clipping belongs to the shine alone — the glow draws a ring OUTSIDE the
   badge's box, and hiding overflow on every variant would cut it off. */
.nb-shine { overflow: hidden; }

/* Shine: a narrow highlight crosses the badge every few seconds, clipped to its
   rounded box. The closest thing to the animated tag the big boards use, drawn
   rather than shipped as a GIF — no extra request, no fixed colour, and it
   follows the accent. */
.nb-shine > i {
  position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(105deg,
    transparent 38%,
    color-mix(in srgb, var(--accent) 55%, transparent) 48%,
    transparent 58%);
  background-size: 260% 100%;
  /* Without this the gradient tiles, so the badge sits permanently half-lit
     between sweeps instead of resting flat. */
  background-repeat: no-repeat;
  animation: badgeShine calc(3.4s * var(--badge-speed, 1)) ease-in-out infinite;
}
@keyframes badgeShine {
  0%, 62% { background-position: 130% 0; }
  100%    { background-position: -30% 0; }
}

/* Glow: the badge breathes. Box-shadow and background only — nothing that
   changes the badge's size, so the line it sits on never reflows. */
.nb-glow {
  animation: badgeGlow calc(2.6s * var(--badge-speed, 1)) ease-in-out infinite;
}
@keyframes badgeGlow {
  0%, 100% { box-shadow: 0 0 0 0 transparent; background: var(--accent-glow); }
  50%      { box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
             background: color-mix(in srgb, var(--accent) 26%, transparent); }
}

/* Pop: a brief nudge, with a long pause. inline-block plus a transform-origin
   on the left keeps the growth away from the title beside it. */
.nb-pop {
  transform-origin: left center;
  animation: badgePop calc(4s * var(--badge-speed, 1)) ease-in-out infinite;
}
@keyframes badgePop {
  0%, 88%, 100% { transform: scale(1); }
  92%           { transform: scale(1.13); }
  96%           { transform: scale(.99); }
}

@media (prefers-reduced-motion: reduce) {
  .nb-shine > i, .nb-glow, .nb-pop, .nb-blink, .nb-slide > i, .nb-ring::after, .nb-rainbow { animation: none; }
  .nb-shine > i { display: none; }
}

/* ---------- Single listing: no dead column ---------------------------------
   `.prose` is capped at 68ch for readability, which is right. The bug was the
   column it sat in: the job layout gave the article every spare pixel, so on a
   1600px screen a 586px paragraph sat in a 1060px column and left roughly 475px
   of nothing between the text and the sidebar. Widening the container in 1.4
   made an existing 200px gap into a chasm.

   Two changes, together: the page gets its own narrower measure, and inside the
   article column the prose fills what it is given. 68ch stops being a cap and
   starts being what the column is sized to. */

body.page-job { --max: 1120px; }
.page-job .job-layout { grid-template-columns: minmax(0, 1fr) 320px; gap: 44px; }
.page-job .job-layout .prose { max-width: none; }
@media (max-width: 900px) {
  .page-job .job-layout { grid-template-columns: 1fr; }
  /* Stacked, there is no sidebar to sit beside, so the reading measure comes
     back — a full-width paragraph on a wide phone-in-landscape is unreadable. */
  .page-job .job-layout .prose { max-width: 68ch; }
}

/* ============================================================================
   v1.5 — more effects, speed control, featured tint, place suggestions
   ========================================================================== */

/* ---------- More background effects ---------------------------------------
   Same rules as the originals: pure CSS, keyed off a body class, every duration
   routed through --fx-speed so one control in the panel retunes all of them,
   and all of it switched off under prefers-reduced-motion. */

/* Waves: wide bands rolling upward. Reads as depth rather than as a pattern. */
.fx-waves .bg-fx {
  background:
    repeating-linear-gradient(0deg,
      transparent 0 60px,
      color-mix(in srgb, var(--accent) 6%, transparent) 60px 62px,
      transparent 62px 130px);
  mask-image: radial-gradient(130vw 90vh at 50% 30%, #000 10%, transparent 80%);
  -webkit-mask-image: radial-gradient(130vw 90vh at 50% 30%, #000 10%, transparent 80%);
  animation: waveRoll calc(30s * var(--fx-speed, 1)) linear infinite;
}
@keyframes waveRoll { to { background-position: 0 -130px; } }

/* Spotlight: one pool of light wandering the page. */
.fx-spotlight .bg-fx {
  background: radial-gradient(38vw 38vw at 50% 50%, var(--accent-glow), transparent 70%);
  animation: spotWander calc(38s * var(--fx-speed, 1)) ease-in-out infinite alternate;
}
@keyframes spotWander {
  0%   { background-position: -22% -18%; }
  50%  { background-position: 62% 30%; }
  100% { background-position: 18% 74%; }
}

/* Grain: a still texture, no animation at all. The SVG is a data URL rather
   than a file so it costs no request; feTurbulence is a filter primitive, not
   script, and needs no CSP allowance. */
.fx-grain .bg-fx {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.42'/%3E%3C/svg%3E");
  opacity: .05;
}
[data-theme='light'] .fx-grain .bg-fx { opacity: .035; }

/* Orbits: two large soft rings turning behind everything. */
.fx-orbit .bg-fx {
  background:
    radial-gradient(closest-side circle at 22% 26%,
      transparent 58%, var(--accent-glow) 60%, transparent 63%),
    radial-gradient(closest-side circle at 78% 68%,
      transparent 62%, rgba(110, 231, 255, .10) 64%, transparent 67%);
  background-size: 62vw 62vw, 54vw 54vw;
  background-repeat: no-repeat;
  animation: orbitTurn calc(64s * var(--fx-speed, 1)) linear infinite;
}
@keyframes orbitTurn {
  to { transform: rotate(360deg) scale(1.06); }
}

/* Fanned rays across the hero. */
.hero-rays .hero-fx {
  background: repeating-conic-gradient(from 0deg at 12% -10%,
    var(--accent-glow) 0deg 3deg, transparent 3deg 14deg);
  opacity: .5;
  animation: rayTurn calc(52s * var(--fx-speed, 1)) linear infinite;
}
@keyframes rayTurn { to { transform: rotate(18deg); } }

.hero-pulse .hero-fx {
  background: radial-gradient(60% 100% at 30% 20%, var(--accent-glow), transparent 72%);
  animation: heroPulse calc(7s * var(--fx-speed, 1)) ease-in-out infinite;
}
@keyframes heroPulse {
  0%, 100% { opacity: .45; transform: scale(1); }
  50%      { opacity: 1;   transform: scale(1.08); }
}

.hero-scan .hero-fx {
  background: linear-gradient(180deg,
    transparent 0%,
    color-mix(in srgb, var(--accent) 40%, transparent) 50%,
    transparent 100%);
  background-size: 100% 90px;
  background-repeat: no-repeat;
  animation: heroScan calc(9s * var(--fx-speed, 1)) linear infinite;
}
@keyframes heroScan {
  0%   { background-position: 0 -120px; }
  100% { background-position: 0 130%; }
}

/* ---------- More badge movement ------------------------------------------- */

.nb-blink { animation: badgeBlink calc(2.2s * var(--badge-speed, 1)) ease-in-out infinite; }
@keyframes badgeBlink {
  /* Never to zero. A badge that disappears entirely reads as a rendering
     fault, and the word has to stay legible at every frame. */
  0%, 100% { opacity: 1; }
  50%      { opacity: .45; }
}

.nb-slide { overflow: hidden; }
.nb-slide > i {
  position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(90deg, var(--accent-glow), transparent 60%);
  animation: badgeSlide calc(2.8s * var(--badge-speed, 1)) ease-out infinite;
}
@keyframes badgeSlide {
  0%       { transform: translateX(-100%); }
  55%, 100% { transform: translateX(100%); }
}

/* The ring is drawn on a pseudo-element outside the badge box, so nothing on
   the line reflows while it expands. */
.nb-ring::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit;
  border: 1px solid var(--accent); pointer-events: none;
  animation: badgeRing calc(2.8s * var(--badge-speed, 1)) ease-out infinite;
}
@keyframes badgeRing {
  0%       { transform: scale(1); opacity: .7; }
  70%, 100% { transform: scale(1.5); opacity: 0; }
}

.nb-rainbow { animation: badgeHue calc(6s * var(--badge-speed, 1)) linear infinite; }
@keyframes badgeHue {
  /* Rotating the filter, not the colour value, so it works whatever accent is
     configured and needs nothing generated server-side. */
  to { filter: hue-rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
  .fx-waves .bg-fx, .fx-spotlight .bg-fx, .fx-orbit .bg-fx,
  .hero-rays .hero-fx, .hero-pulse .hero-fx, .hero-scan .hero-fx { animation: none; }
  .hero-scan .hero-fx, .nb-slide > i { display: none; }
}

/* ---------- Featured rows -------------------------------------------------
   "No tint" still keeps the coloured left edge and the badge, because a
   featured listing that looks identical to a free one is not worth paying for. */

.job-row.is-featured.feat-flat { background: transparent; }
.job-row.is-featured.feat-flat:hover { background: var(--surface); }

/* ---------- Place suggestions ---------------------------------------------
   Our own list, not Google's widget — see app/Places.php for why. That means
   it inherits the site's colours, radius and font for free, and needs no CSP
   allowance for a third party's inline styles. */

.places-wrap { position: relative; display: block; }
.filter-bar .places-wrap { display: inline-block; }
.places-list {
  position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 60;
  margin: 0; padding: 5px; list-style: none;
  max-height: 300px; overflow-y: auto;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  box-shadow: 0 18px 44px rgba(0, 0, 0, .3);
}
.places-list li {
  padding: 8px 10px; border-radius: var(--radius); cursor: pointer;
  display: flex; flex-direction: column; gap: 1px; line-height: 1.35;
}
.places-list li strong { font-size: 13.5px; font-weight: 600; color: var(--text); }
.places-list li span { font-size: 12px; color: var(--text-dim); }
.places-list li:hover, .places-list li.is-active { background: var(--surface-2); }
.select-place { min-width: 170px; }
@media (max-width: 700px) { .places-list { right: auto; min-width: 260px; } }

/* A quiet "Optional" beside a label, so the label itself stays scannable. */
.hint-inline {
  font-size: 11.5px; font-weight: 500; color: var(--text-dim);
  text-transform: uppercase; letter-spacing: .06em; margin-left: 6px;
}
.check-line { display: flex; align-items: flex-start; gap: 9px; cursor: pointer; }
.check-line input { margin-top: 3px; flex-shrink: 0; }
.check-line span { font-size: 13.5px; line-height: 1.5; color: var(--text-muted); }
.check-line strong { color: var(--text); }

.contact-card h3 { display: flex; align-items: center; gap: 8px; }
.contact-card h3 .icon { color: var(--text-dim); flex-shrink: 0; }
.phone-reveal { font-variant-numeric: tabular-nums; letter-spacing: .02em; }

/* ============================================================================
   v1.6 — hero layouts, geo dropdowns
   ========================================================================== */

/* ---------- Hero layouts ---------------------------------------------------
   Three, chosen in the theme panel. The copy column is capped so the headline
   keeps a sane measure whichever layout is running — a 1440px-wide h1 is not a
   headline, it is a banner. */

.hero-inner { display: grid; gap: 40px; align-items: center; }
.hero-copy { min-width: 0; max-width: 620px; }
.hero-aside { min-width: 0; }

/* Live panel and image both make it two columns. The aside is given a fixed
   share rather than 1fr so the headline never gets squeezed by a tall panel. */
.hero-stats .hero-inner,
.hero-image .hero-inner { grid-template-columns: minmax(0, 1fr) minmax(0, 400px); }

/* Centred: one column, everything on the middle line. */
.hero-centred .hero-inner { grid-template-columns: 1fr; justify-items: center; text-align: center; }
.hero-centred .hero-copy { max-width: 720px; }
.hero-centred .hero-search { margin-inline: auto; }
.hero-centred .chip-row { justify-content: center; }
.hero-centred .hero-sub { margin-inline: auto; }

/* The hero had a max-height that assumed a single short column. A panel beside
   it is taller than that, and clipping it is worse than a taller hero. */
.hero-stats .hero-inner,
.hero-image .hero-inner { padding-block: 34px 30px; }

.hero-aside-image img {
  display: block; width: 100%; height: auto;
  border-radius: var(--radius-lg);
  /* A photo of unknown proportions should not decide the height of the hero. */
  max-height: 340px; object-fit: cover;
}

.hp-card {
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 16px;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.hp-stats {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;
  padding-bottom: 14px; margin-bottom: 12px; border-bottom: 1px solid var(--border);
}
.hp-stats span { display: flex; flex-direction: column; font-size: 11.5px; color: var(--text-dim); }
.hp-stats strong {
  font-size: 20px; font-weight: 700; color: var(--text);
  letter-spacing: -.02em; font-variant-numeric: tabular-nums;
}
.hp-head {
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .08em; color: var(--text-dim); margin-bottom: 8px;
}
.hp-list { display: grid; gap: 2px; }
.hp-job {
  display: grid; grid-template-columns: 30px minmax(0, 1fr) auto;
  gap: 10px; align-items: center;
  padding: 8px; border-radius: var(--radius);
  transition: background .14s ease;
}
.hp-job:hover { background: var(--surface-2); }
.hp-job-main { min-width: 0; display: flex; flex-direction: column; }
.hp-job-title {
  font-size: 13.5px; font-weight: 600; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hp-job-meta {
  font-size: 11.5px; color: var(--text-dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hp-job-age { font-size: 11px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.job-logo.sm { width: 30px; height: 30px; font-size: 11px; border-radius: 7px; }
.hp-more {
  display: block; margin-top: 10px; padding-top: 10px;
  border-top: 1px solid var(--border);
  font-size: 12.5px; font-weight: 600; color: var(--accent);
}

/* One column on anything narrow. The panel goes BELOW the search box, never
   above it — the search is why the page exists. */
@media (max-width: 940px) {
  .hero-stats .hero-inner,
  .hero-image .hero-inner { grid-template-columns: 1fr; gap: 24px; }
  .hero-copy { max-width: none; }
  .hero-aside-image { display: none; }   /* decorative, and a phone has no room */
}
@media (max-width: 560px) {
  .hp-stats strong { font-size: 17px; }
}

/* ---------- Location dropdowns --------------------------------------------
   Country, region and city. The country list is server-rendered so it works
   with scripting off; the other two are filled from /api/geo on demand. */

.geo-group { display: contents; }
.geo-select:disabled { opacity: .5; cursor: not-allowed; }
.filter-bar .geo-select { min-width: 130px; max-width: 190px; }

.geo-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.geo-row .geo-select {
  width: 100%; padding: 10px 12px; border-radius: var(--radius);
  border: 1px solid var(--border-strong); background: var(--surface);
  color: var(--text); font-size: 14px; font-family: inherit;
}
@media (max-width: 620px) { .geo-row { grid-template-columns: 1fr; } }

/* The one-line explanation under the filter bar. Not a footnote nobody reads:
   without it, picking "Berlin" and seeing every Germany-wide role looks broken
   rather than correct. */
.filter-note {
  flex-basis: 100%; font-size: 12px; color: var(--text-dim);
  margin-top: 2px; line-height: 1.5;
}

/* ---------- Markdown editor ------------------------------------------------
   A toolbar and a preview tab around an ordinary textarea. Not a WYSIWYG: the
   stored format stays Markdown, so the allowlist renderer stays the security
   boundary. See assets/editor.js. */

.md-editor {
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--surface);
  overflow: hidden;
}
.md-editor:focus-within { border-color: var(--text-dim); }

.md-bar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 7px 8px; border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.md-tools { display: flex; gap: 2px; flex-wrap: wrap; }
.md-btn {
  min-width: 30px; height: 28px; padding: 0 8px;
  border: 1px solid transparent; border-radius: 6px;
  background: transparent; color: var(--text-muted);
  font-size: 12.5px; font-family: inherit; cursor: pointer; line-height: 1;
  transition: background .12s ease, color .12s ease;
}
.md-btn:hover { background: var(--surface); color: var(--text); border-color: var(--border); }
.md-btn.is-bold { font-weight: 800; }
.md-btn.is-italic { font-style: italic; font-family: Georgia, serif; }

.md-tabs { display: flex; gap: 2px; margin-left: auto; }
.md-tab {
  padding: 5px 12px; border: 1px solid transparent; border-radius: 6px;
  background: transparent; color: var(--text-dim);
  font-size: 12.5px; font-weight: 600; font-family: inherit; cursor: pointer;
}
.md-tab:hover { color: var(--text); }
.md-tab.is-on { background: var(--surface); color: var(--text); border-color: var(--border); }

/* The textarea loses its own frame — the shell provides it now. */
.md-editor textarea {
  display: block; width: 100%; border: 0; border-radius: 0;
  background: transparent; resize: vertical; min-height: 220px;
}
.md-editor textarea:focus { outline: none; }

.md-preview {
  padding: 16px 18px; min-height: 220px;
  max-height: 60vh; overflow-y: auto;
}
.md-preview .preview-empty { color: var(--text-dim); font-style: italic; }
.md-preview > :first-child { margin-top: 0; }

/* ---------- Posting page: the preview below the form -----------------------
   The other placement for the live preview. Full width, so the listing-page
   half of the preview is drawn at close to its real proportions rather than
   squeezed into a 320px column. */

.hire-preview-bottom {
  grid-column: 1 / -1;
  margin-top: 28px;
  padding-top: 24px;
  border-top: 1px solid var(--border);
}
.hire-preview-bottom .step-h { margin-bottom: 14px; }
.hire-preview-bottom .preview-card { position: static; }
@media (min-width: 901px) {
  /* Inside the form but outside the grid, so it spans the whole column. */
  .hire-preview-bottom .preview-page { max-width: 820px; }
}

/* Destructive action. Quiet until hovered — a red button that shouts from a
   resting state gets clicked by accident more often, not less. */
.btn-danger { color: #d94a4a; border-color: color-mix(in srgb, #d94a4a 35%, transparent); }
.btn-danger:hover { background: color-mix(in srgb, #d94a4a 12%, transparent); border-color: #d94a4a; }
.hire-account.is-signed-in {
  padding: 10px 14px; border-radius: var(--radius);
  background: var(--accent-glow); border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
  color: var(--text);
}
