/* ============================================================================
   Trabaho.AE — canonical shared stylesheet
   Served at /static/app.css (static/ is //go:embed'd; CSP style-src 'self').

   SINGLE SOURCE OF TRUTH for the design system. Every surface (the seeker
   SPA in templates/index.html, the employer dashboard in dashboard.go, the
   policy pages in policy_pages.go, the payment/consent/auth pages in
   handlers.go + *_pages.go) links this file and DELETES its local :root
   token block + theme overrides. See docs/DESIGN-SYSTEM.md for the adoption
   contract and the full token table.

   Identity: restrained dark canvas + warm gold accent + Jost typography.
   Premium hierarchy-first layout; Arabic falls back to IBM Plex Sans Arabic.

   Token values below are the reconciled UNION of all four surfaces' blocks.
   Where surfaces drifted, the canonical value is chosen and noted inline.
   ========================================================================== */

/* ============================================================================
   1. TOKENS — :root
   ========================================================================== */
:root {
  /* --- Brand primitives (theme-independent) --- */
  --primary:           #e4c35a;
  --primary-active:    #d4af37;
  --primary-disabled:  #3a3520;
  --primary-ink:       #12141a;          /* black on yellow — never invert */
  --primary-soft:      rgba(228,195,90,0.14);
  --on-primary:        #181a20;          /* alias of --primary-ink */

  /* --- Trading / status semantics (theme-independent) --- */
  --trading-up:   #0ecb81;
  --trading-down: #f6465d;

  /* --- Info / focus --- */
  --info: #3b82f6;

  /* --- Light palette primitives --- */
  --canvas-light:           #ffffff;
  --surface-soft-light:     #fafafa;
  --surface-strong-light:   #f5f5f5;
  --hairline-on-light:      #eaecef;
  --border-strong:          #cdd1d6;
  --ink:                    #181a20;

  /* --- Dark palette primitives --- */
  --canvas-dark:            #090b0f;
  --surface-card-dark:      #12161d;
  --surface-elevated-dark:  #1a2029;
  --hairline-on-dark:       #232a35;
  --on-dark:                #ffffff;
  --body-on-dark:           #eaecef;

  /* --- Neutrals (warm-tinted H~40 to harmonize with the yellow primary
     instead of fighting it with a cool undertone). These dark-canvas values
     fail AA on white, so both LIGHT branches override them with darker
     equivalents — see the theme blocks below. --- */
  --muted:        #7a808a;
  --muted-strong: #a3a9b4;

  /* ==== Adaptive tokens — DARK is the default brand chrome. Light is the
     opt-in override (system-preference branch + [data-theme="light"]). ==== */
  --canvas:           var(--canvas-dark);
  --surface-card:     var(--surface-card-dark);
  --surface-elevated: var(--surface-elevated-dark);
  --hairline:         var(--hairline-on-dark);
  --text:             var(--body-on-dark);
  --text-strong:      var(--on-dark);
  /* Accent text: brand yellow reads at AA on dark surfaces; falls back to
     ink on the light override (see below). */
  --accent-text:      var(--primary);
  --accent-soft:      var(--primary-soft);
  /* --accent: the brand-accent FILL (solid yellow), distinct from
     --accent-text (the on-surface accent text colour which flips to ink
     on light). Was previously DANGLING — .account-avatar referenced it
     with no definition, so the avatar fell back to transparent. Aliases
     --primary so the avatar (and any future accent-filled chip) is the
     Binance yellow in both themes; --on-accent is the ink that sits on it. */
  --accent:           var(--primary);
  --on-accent:        var(--primary-ink);
  --hero-glow:        rgba(228,195,90,0.07);
  --row-featured:     rgba(228,195,90,0.04);
  /* Partner-strip rest filter: plain grayscale reads ~2.1:1 on the dark
     canvas (below the 3:1 non-text floor), so dark adds a brightness lift;
     light needs none. */
  --partner-logo-filter: grayscale(1) brightness(1.5);
  --tag-new-bg:       rgba(14,203,129,0.12);
  --tag-new-fg:       var(--trading-up);
  --tag-urgent-bg:    rgba(246,70,93,0.12);
  --tag-urgent-fg:    var(--trading-down);

  /* --- Status tokens. Short names (--ok/--warn/--err) are the canonical
     fills for badges/pills/toasts; the *-bg / *-fg family is retained for
     the dashboard's banner+pill rules. Both swap with the theme. --- */
  --ok:      var(--trading-up);
  --warn:    var(--primary);
  --err:     var(--trading-down);
  --ok-bg:   rgba(56,217,135,0.14);
  --ok-fg:   #3dd58a;
  --warn-bg: rgba(252,213,53,0.14);
  --warn-fg: #f3c75b;
  --err-bg:  rgba(248,113,113,0.14);
  --err-fg:  #ff7a73;

  /* --- Signed-in realm tokens (.role-badge / .topnav--{role}). One hue
     per session realm so a glance answers "whose surface is this?":
     seeker = teal (free side), employer = brand gold (the paying
     tenant), operator = violet (staff). Deliberately distinct from the
     ok/warn/err status hues — a realm is an identity, not a status. */
  --role-seeker-bg:   rgba(56,189,217,0.14);
  --role-seeker-fg:   #53cbe0;
  --role-employer-bg: rgba(252,213,53,0.14);
  --role-employer-fg: #e4c35a;
  --role-operator-bg: rgba(167,139,250,0.16);
  --role-operator-fg: #b3a0f5;

  /* --- Spacing (4px scale; 8pt grid is the default — see DESIGN-SYSTEM §2). --- */
  --xxs: 4px;  --xs: 8px;  --sm: 12px;  --md: 16px;
  --lg: 24px;  --xl: 32px; --xxl: 48px; --section: 80px;

  /* --- Radii --- */
  --r-sm: 4px; --r-md: 6px; --r-lg: 8px; --r-xl: 12px; --r-pill: 9999px;

  /* --- Layout --- */
  --page-max: 800px;
  --site-max: 1280px;

  /* --- Type sizes (named tiers; sizes already in use across the codebase). --- */
  --fs-display: clamp(2.25rem, 4.8vw + 0.5rem, 3.75rem);
  --fs-h2:      clamp(1.375rem, 1.5vw + 0.75rem, 1.75rem);
  --fs-h3:      1rem;
  --fs-body:    0.875rem;
  --fs-body-lg: 1rem;
  --fs-meta:    0.8125rem;
  --fs-micro:   0.75rem;
  --fs-fine:    0.6875rem;

  /* --- Type families --- */
  --font-sans:   'Jost', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-arabic: 'IBM Plex Sans Arabic', 'Jost', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-mono:   ui-monospace, 'SF Mono', SFMono-Regular, Menlo, monospace;

  /* --- Motion durations (60ms grid). Every use MUST sit behind the
     prefers-reduced-motion guard below. See DESIGN-SYSTEM §4. --- */
  --dur-1: 120ms;   /* state flips: hover, active, focus-visible */
  --dur-2: 180ms;   /* element entry/exit: chips, pills, tags */
  --dur-3: 240ms;   /* overlay fades: modals, drawers, banners */
  --dur-4: 320ms;   /* layout transitions: drawer slide, FLIP */
  /* Aliases used by the dashboard / policy / payment surfaces. */
  --dur-micro: 120ms;   /* == --dur-1 */
  --dur-enter: 360ms;   /* reveal/settle on paint */
  --dur-count: 900ms;   /* tabular count-up */

  /* --- Easing — a small, named curve set. --- */
  --ease-out:    cubic-bezier(0.2, 0.9, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --ease-spring: cubic-bezier(0.3, 1.4, 0.5, 1);
  /* Aliases used by the dashboard / policy / payment surfaces. */
  --ease-enter:  cubic-bezier(0.16, 1, 0.3, 1);
  --ease-state:  cubic-bezier(0.4, 0, 0.2, 1);

  /* --- Stagger (sequenced reveals, e.g. job feed). --- */
  --stagger-step: 40ms;
  --stagger-cap:  240ms;

  /* --- A11y — focus outlines. Yellow-on-yellow rings are invisible, so
     use ink on yellow controls and the info blue elsewhere. --- */
  --focus-on-yellow: var(--ink);
  --focus-elsewhere: var(--info);
}

/* ----------------------------------------------------------------------------
   Theme: LIGHT via system preference (only when no explicit cookie/attr).
   Canonical drift resolutions:
     --surface-card  -> --surface-soft-light  (#fafafa; SPA/policy canon,
                        not the dashboard's #fff)
     --text          -> var(--ink) (#181a20; SPA/policy/payment canon,
                        not the dashboard's #404a5f)
   -------------------------------------------------------------------------- */
@media (prefers-color-scheme: light) {
  :root:not([data-theme]) {
    --canvas:           var(--canvas-light);
    --surface-card:     var(--surface-soft-light);
    --surface-elevated: var(--surface-strong-light);
    --hairline:         var(--hairline-on-light);
    --text:             var(--ink);
    --text-strong:      var(--ink);
    --accent-text:      var(--ink);
    /* Neutrals darkened for AA on white (#7a808a is 3.98:1; #a3a9b4 2.36:1). */
    --muted:            #5b616c;
    --muted-strong:     #6b7280;
    --hero-glow:        rgba(252,213,53,0.05);
    --row-featured:     rgba(252,213,53,0.08);
    --partner-logo-filter: grayscale(1);
    --tag-new-fg:       #097c4f;
    --tag-urgent-fg:    #b81f37;
    --ok-bg:   #e8f7ee;  --ok-fg:   #0a6b3f;
    --warn-bg: #fff4dc;  --warn-fg: #8a5400;
    --err-bg:  #fdf0ef;  --err-fg:  #a02520;
    /* Realm hues darkened for AA on white. */
    --role-seeker-bg:   #e2f5f9;  --role-seeker-fg:   #0c6478;
    --role-employer-bg: #fdf3d4;  --role-employer-fg: #7a5800;
    --role-operator-bg: #efeafc;  --role-operator-fg: #5b3fb5;
  }
}

/* Manual override: force DARK (wins even when the system prefers light). */
:root[data-theme="dark"] {
  --canvas:           var(--canvas-dark);
  --surface-card:     var(--surface-card-dark);
  --surface-elevated: var(--surface-elevated-dark);
  --hairline:         var(--hairline-on-dark);
  --text:             var(--body-on-dark);
  --text-strong:      var(--on-dark);
  --accent-text:      var(--primary);
  --hero-glow:        rgba(252,213,53,0.08);
  --row-featured:     rgba(252,213,53,0.04);
  --partner-logo-filter: grayscale(1) brightness(1.5);
  --tag-new-fg:       var(--trading-up);
  --tag-urgent-fg:    var(--trading-down);
  --ok-bg:   rgba(56,217,135,0.14);  --ok-fg:   #3dd58a;
  --warn-bg: rgba(252,213,53,0.14);  --warn-fg: #f3c75b;
  --err-bg:  rgba(248,113,113,0.14); --err-fg:  #ff7a73;
  --role-seeker-bg:   rgba(56,189,217,0.14);  --role-seeker-fg:   #53cbe0;
  --role-employer-bg: rgba(252,213,53,0.14);  --role-employer-fg: #e4c35a;
  --role-operator-bg: rgba(167,139,250,0.16); --role-operator-fg: #b3a0f5;
}

/* Manual override: force LIGHT (explicit so it wins even under prefers dark). */
:root[data-theme="light"] {
  --canvas:           var(--canvas-light);
  --surface-card:     var(--surface-soft-light);
  --surface-elevated: var(--surface-strong-light);
  --hairline:         var(--hairline-on-light);
  --text:             var(--ink);
  --text-strong:      var(--ink);
  --accent-text:      var(--ink);
  /* Neutrals darkened for AA on white (#7a808a is 3.98:1; #a3a9b4 2.36:1). */
  --muted:            #5b616c;
  --muted-strong:     #6b7280;
  --hero-glow:        rgba(252,213,53,0.05);
  --row-featured:     rgba(252,213,53,0.08);
  --partner-logo-filter: grayscale(1);
  --tag-new-fg:       #097c4f;
  --tag-urgent-fg:    #b81f37;
  --ok-bg:   #e8f7ee;  --ok-fg:   #0a6b3f;
  --warn-bg: #fff4dc;  --warn-fg: #8a5400;
  --err-bg:  #fdf0ef;  --err-fg:  #a02520;
  /* Realm hues darkened for AA on white. */
  --role-seeker-bg:   #e2f5f9;  --role-seeker-fg:   #0c6478;
  --role-employer-bg: #fdf3d4;  --role-employer-fg: #7a5800;
  --role-operator-bg: #efeafc;  --role-operator-fg: #5b3fb5;
}

/* ============================================================================
   2. BASE — reset + typography defaults + a11y
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; }

body {
  font-family: var(--font-sans);
  background: var(--canvas);
  color: var(--text);
  font-size: var(--fs-body-lg);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Arabic copy opts into the Arabic family via [lang="ar"] / dir="rtl". */
[lang="ar"], :root[dir="rtl"] { font-family: var(--font-arabic); }

h1, h2, h3, h4 { color: var(--text-strong); line-height: 1.2; }
a { color: var(--accent-text); }

code, kbd, samp, pre { font-family: var(--font-mono); }

img, svg, video { max-width: 100%; }

/* Focus-visible: ink ring on yellow controls, blue elsewhere. Keyboard
   users always see a clear, AA-contrast ring; mouse users do not. */
:focus-visible {
  outline: 3px solid var(--focus-elsewhere);
  outline-offset: 2px;
  border-radius: var(--r-md);
}
.btn-primary:focus-visible,
.btn.btn-primary:focus-visible,
button.primary:focus-visible,
[type="submit"]:focus-visible {
  outline-color: var(--focus-on-yellow);
}

/* Reduced motion: collapse animation/transition; pin reveal targets to
   their final state so an interrupted enter never strands content hidden. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0ms !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ============================================================================
   3. SHARED COMPONENTS
   Logical properties (margin-inline / padding-inline / inset-inline / *-start
   / *-end) throughout so the RTL mirror is automatic. Status uses --ok / --warn
   / --err so a single token drives color across surfaces.
   ========================================================================== */

/* --- Icon sizing. Icons inherit the cap height of their text (1em) and
   take the current text color via currentColor in the sprite. --- */
.icon {
  width: 1em;
  height: 1em;
  display: inline-block;
  vertical-align: -0.125em;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  flex: none;
}
.icon-sm { width: 0.875em; height: 0.875em; }
.icon-lg { width: 1.5em;   height: 1.5em; }
.icon-xl { width: 2em;     height: 2em; }
/* Multicolor / brand marks (e.g. the SSO logos, flag-uae) opt out of the
   stroke styling so their internal fills render. */
.icon-fill { fill: currentColor; stroke: none; }

/* --- Buttons --- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--xs);
  font-family: inherit;
  font-size: var(--fs-body-lg);
  font-weight: 600;
  line-height: 1;
  min-height: 44px;
  padding-block: 12px;
  padding-inline: 18px;
  border: 1px solid transparent;
  border-radius: var(--r-lg);
  cursor: pointer;
  text-decoration: none;
  transition: background var(--dur-1) var(--ease-out),
              border-color var(--dur-1) var(--ease-out),
              transform var(--dur-1) var(--ease-out),
              box-shadow var(--dur-1) var(--ease-out);
}
.btn:active { transform: translateY(1px); }
.btn:disabled,
.btn[aria-disabled="true"] { opacity: 0.55; cursor: not-allowed; transform: none; }

.btn-primary {
  background: var(--primary);
  color: var(--primary-ink);
  border-color: var(--primary);
}
.btn-primary:hover { background: var(--primary-active); border-color: var(--primary-active); }
.btn-primary:disabled { background: var(--surface-elevated); color: var(--muted); border-color: var(--hairline); }

.btn-secondary {
  background: var(--surface-card);
  color: var(--text-strong);
  border-color: var(--hairline);
}
.btn-secondary:hover { background: var(--surface-elevated); border-color: var(--text-strong); }

.btn-ghost {
  background: transparent;
  color: var(--text);
  border-color: transparent;
}
.btn-ghost:hover { background: var(--surface-elevated); color: var(--text-strong); }

/* Busy state for SSO / submit buttons. */
.btn[aria-busy="true"] { background: var(--surface-elevated); color: var(--muted); cursor: progress; }

/* --- Card --- */
.card {
  background: var(--surface-card);
  border: 1px solid var(--hairline);
  border-radius: var(--r-xl);
  padding: var(--lg);
}

/* --- Input / field --- */
.field {
  display: block;
  width: 100%;
  padding-block: 10px;
  padding-inline: 12px;
  font-family: inherit;
  font-size: var(--fs-body-lg);
  color: var(--text-strong);
  background: var(--canvas);
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
  transition: border-color var(--dur-1) var(--ease-state);
}
.field::placeholder { color: var(--muted); }
.field:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 1px;
  border-color: var(--primary);
}
.field-label {
  display: block;
  font-size: var(--fs-meta);
  font-weight: 500;
  color: var(--text);
  margin-block-end: var(--xs);
}

/* --- Badge / pill. Status variants carry a leading dot so meaning is
   never color-only (a11y: color-not-only). --- */
.badge,
.pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: var(--fs-fine);
  font-weight: 500;
  padding-block: 2px;
  padding-inline: 8px;
  border-radius: var(--r-pill);
  line-height: 1.4;
}
.pill::before {
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: var(--r-pill);
  background: currentColor;
}
.pill.ok,   .badge.ok   { background: var(--ok-bg);   color: var(--ok-fg); }
.pill.warn, .badge.warn { background: var(--warn-bg); color: var(--warn-fg); }
.pill.err,  .badge.err  { background: var(--err-bg);  color: var(--err-fg); }
.pill.neutral, .badge.neutral { background: var(--surface-elevated); color: var(--text); }
/* Brand-accent badge (e.g. "N new") — a nudge, not a status claim. */
.pill.accent, .badge.accent { background: var(--accent-soft); color: var(--accent-text); font-weight: 600; }
.pill.accent::before { background: var(--accent-text); }

/* --- MFA enrolment panel (mfa_panel.go, employer /settings + seeker
   /me/profile). The QR SVG ships its own white quiet zone + black
   modules (qr.go) so scanner contrast never follows the page theme;
   CSS only sizes and frames it. --- */
.mfa-qr {
  display: inline-block;
  margin: 6px 0 2px;
  border: 1px solid var(--hairline);
  border-radius: 8px;
  overflow: hidden;
  line-height: 0; /* kill inline-svg baseline gap */
}
.mfa-qr svg { display: block; width: 200px; height: 200px; }
.mfa-manual { margin-top: 10px; }
.mfa-manual summary { cursor: pointer; font-size: var(--fs-meta); color: var(--muted-strong); }
.mfa-manual code { word-break: break-all; }
.mfa-uri {
  white-space: pre-wrap;
  word-break: break-all;
  background: var(--surface-elevated);
  border: 1px solid var(--hairline);
  border-radius: 6px;
  padding: 8px;
  font-size: 12px;
}

/* --- Chip (filter) --- */
.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--xs);
  font-family: inherit;
  font-size: var(--fs-meta);
  font-weight: 500;
  line-height: 1;
  padding-block: 8px;
  padding-inline: 14px;
  color: var(--text);
  background: var(--surface-card);
  border: 1px solid var(--hairline);
  border-radius: var(--r-pill);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--dur-1) var(--ease-out),
              border-color var(--dur-1) var(--ease-out),
              color var(--dur-1) var(--ease-out);
}
.chip:hover { border-color: var(--text-strong); color: var(--text-strong); }
.chip.active,
.chip[aria-pressed="true"] {
  background: var(--primary);
  color: var(--primary-ink);
  border-color: var(--primary);
}

/* --- Toast (host + toast + status variants). Surfaces add ONE toast host
   near </body> and inject .toast nodes into it. RTL-safe via logical inset.

   Two host class names are accepted, both styled identically:
     .toast-host       — canonical name used by the shared toastJS (chrome.go)
                         and the Slice-4 surfaces.
     .toast-container  — back-compat alias with ZERO in-tree consumers (every
                         host uses .toast-host); kept only as a guard for
                         hypothetical out-of-tree embedders. Do not remove.

   Status variants: .ok (success) / .err (error) / .info / .warn. Each sets
   a status-coloured start border + tints its leading .icon. Meaning is never
   colour-only: the host model pairs every toast with a leading status icon.

   Motion: enter = tb-toast-in (slide+fade up). Exit = add .toast--leaving to
   play tb-toast-out before removal. Both collapse under prefers-reduced-motion
   via the global guard (§2), so a toast never strands half-animated. --- */
.toast-host,
.toast-container {
  position: fixed;
  inset-block-end: var(--lg);
  inset-inline-end: var(--lg);
  z-index: 1000;
  display: flex;
  flex-direction: column;
  gap: var(--xs);
  max-width: min(360px, calc(100vw - 2 * var(--lg)));
  pointer-events: none;
}
.toast {
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: var(--xs);
  padding-block: var(--sm);
  padding-inline: var(--md);
  font-size: var(--fs-body);
  line-height: 1.4;
  color: var(--text-strong);
  background: var(--surface-card);
  border: 1px solid var(--hairline);
  border-inline-start: 3px solid var(--muted);
  border-radius: var(--r-lg);
  box-shadow: 0 8px 24px rgba(0,0,0,0.24);
  animation: tb-toast-in var(--dur-2) var(--ease-out) both;
}
.toast .icon { margin-block-start: 0.1em; color: var(--muted-strong); }
.toast.ok   { border-inline-start-color: var(--ok-fg); }
.toast.ok   .icon { color: var(--ok-fg); }
.toast.err  { border-inline-start-color: var(--err-fg); }
.toast.err  .icon { color: var(--err-fg); }
.toast.warn { border-inline-start-color: var(--warn-fg); }
.toast.warn .icon { color: var(--warn-fg); }
.toast.info { border-inline-start-color: var(--info); }
.toast.info .icon { color: var(--info); }
/* Exit: caller adds .toast--leaving, waits --dur-2, then removes the node. */
.toast--leaving { animation: tb-toast-out var(--dur-2) var(--ease-in-out) both; }
@keyframes tb-toast-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
@keyframes tb-toast-out {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(8px); }
}

/* --- Shared reveal keyframe used by cards/banners on paint. --- */
@keyframes tb-reveal {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}

/* --- Scroll-reveal opt-in. Elements the shared reveal initJS (chrome.go's
   revealInitJS) manages get .reveal added just before observe; the JS pins
   opacity:0 inline and plays tb-reveal via WAAPI as they enter, then clears
   it. The CSS fallback below covers the no-JS / no-IntersectionObserver path:
   .reveal with no inline opacity stays fully visible (content is never gated
   behind a reveal). Reduced motion: the global guard (§2) zeroes the anim. --- */
.reveal { will-change: opacity, transform; }

/* --- Dev / pre-launch banner. Tokenised so it themes correctly (the old
   inline-styled banner was hard-coded light cream and broke dark mode).
   Uses the warn family with graceful fallbacks so it still renders if a
   surface somehow loads before the tokens resolve. Carries a leading icon
   (set by the markup) so the warning reads without colour. Gated server-side
   behind a config flag (see handlers.go devBannerHTML spec). --- */
.dev-banner {
  background: var(--warn-bg, #fff8e1);
  color: var(--warn-fg, #5b3a00);
  border-block-end: 1px solid var(--hairline, #f4c430);
  padding-block: var(--xs);
  padding-inline: var(--md);
  font-size: var(--fs-meta);
  line-height: 1.4;
  text-align: center;
  font-family: var(--font-sans);
}
.dev-banner .icon { vertical-align: -0.15em; margin-inline-end: 4px; }
.dev-banner strong { color: var(--text-strong); }
.dev-banner .dev-banner-sub { opacity: 0.85; }

/* ============================================================================
   3a. CANONICAL TOP NAV — the shared site header.
   Three surfaces (seeker SPA .topnav .container, dashboard .topnav-inner,
   policy .topnav-inner) drifted with copy-pasted header CSS. These rules are
   the single canonical version. They are ADDITIVE: each surface still ships
   its own inline header CSS today (which wins the cascade, being loaded after
   this file), so nothing changes until a surface deletes its local block and
   adopts renderTopnav (chrome.go). Both inner-container conventions are
   supported: .topnav-inner (server pages) and .topnav > .container (SPA).
   Logical properties throughout for the RTL mirror.
   ========================================================================== */
.topnav {
  position: sticky;
  inset-block-start: 0;
  z-index: 50;
  background: var(--canvas);
  border-block-end: 1px solid var(--hairline);
}
.topnav-inner,
.topnav > .container {
  max-width: var(--site-max);
  margin-inline: auto;
  min-height: 64px;
  padding-block: var(--xs);
  padding-inline: var(--lg);
  display: flex;
  align-items: center;
  gap: var(--md);
  flex-wrap: nowrap;
}
.topnav .brand {
  display: inline-flex;
  align-items: center;
  gap: var(--sm);
  text-decoration: none;
  flex-shrink: 0;
  min-width: 0;
  color: var(--text-strong);
}
/* --- Signed-in realm distinction (chrome.go roleBadgeHTML +
   topnavOptions.RoleClass). The badge is the explicit text label
   ("Job seeker" / "Employer" / "Operator") pinned beside the brand —
   OUTSIDE .topnav-nav, so it survives the ≤768px collapse; the
   .topnav--{role} inset underline is ambient reinforcement only
   (meaning is never colour-alone). --- */
.role-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex: none;
  font-size: var(--fs-fine);
  font-weight: 600;
  letter-spacing: .4px;
  text-transform: uppercase;
  padding-block: 2px;
  padding-inline: 8px;
  border-radius: var(--r-pill);
  white-space: nowrap;
}
.role-badge::before {
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: var(--r-pill);
  background: currentColor;
}
/* display:inline-flex above beats the UA [hidden] rule — the SPA's
   #account-role-badge ships hidden until renderAccountMenu fills it,
   so restate the hidden contract (today it's masked by the parent
   menu's display:none, but that's an accident waiting to regress). */
.role-badge[hidden] { display: none; }
.role-badge--seeker   { background: var(--role-seeker-bg);   color: var(--role-seeker-fg); }
.role-badge--employer { background: var(--role-employer-bg); color: var(--role-employer-fg); }
.role-badge--operator { background: var(--role-operator-bg); color: var(--role-operator-fg); }
/* Inset shadow, not a border, so the accent never shifts layout. */
.topnav--seeker   { box-shadow: inset 0 -2px 0 var(--role-seeker-fg); }
.topnav--employer { box-shadow: inset 0 -2px 0 var(--role-employer-fg); }
.topnav--operator { box-shadow: inset 0 -2px 0 var(--role-operator-fg); }
@media (max-width: 380px) {
  .role-badge { padding-inline: 6px; letter-spacing: .2px; }
}
/* Company mark — hard hat + handshake (/static/logo.png). */
.brand-logo-img {
  display: block;
  height: 40px;
  width: auto;
  max-width: 46px;
  object-fit: contain;
  object-position: center bottom;
  flex: none;
  background: transparent;
}
.topnav .brand-logo,
.brand .brand-logo,
.footer-brand .brand-logo {
  display: block;
  width: auto;
  height: 40px;
  flex: none;
  color: inherit;
}
/* Mobile nav toggle — hidden on desktop; animated bars in app.css. */
.topnav-menu-btn {
  display: none;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  background: var(--surface-card);
  color: var(--text-strong);
  cursor: pointer;
  margin-inline-start: auto;
  transition: background var(--dur-1) var(--ease-out),
              border-color var(--dur-1) var(--ease-out),
              color var(--dur-1) var(--ease-out);
}
.topnav-menu-btn:hover {
  background: var(--surface-elevated);
  border-color: var(--border-strong);
  color: var(--accent-text);
}
.topnav-menu-btn:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}
.topnav-menu-icon {
  position: relative;
  display: block;
  width: 18px;
  height: 12px;
}
.topnav-menu-bar {
  position: absolute;
  inset-inline: 0;
  height: 2px;
  border-radius: 1px;
  background: currentColor;
  transition: transform var(--dur-2) var(--ease-out),
              opacity var(--dur-1) var(--ease-out),
              top var(--dur-2) var(--ease-out);
}
.topnav-menu-bar:nth-child(1) { top: 0; }
.topnav-menu-bar:nth-child(2) { top: 5px; }
.topnav-menu-bar:nth-child(3) { top: 10px; }
.topnav-menu-btn.is-open .topnav-menu-bar:nth-child(1) {
  top: 5px;
  transform: rotate(45deg);
}
.topnav-menu-btn.is-open .topnav-menu-bar:nth-child(2) {
  opacity: 0;
}
.topnav-menu-btn.is-open .topnav-menu-bar:nth-child(3) {
  top: 5px;
  transform: rotate(-45deg);
}
.topnav--menu-open {
  border-block-end-color: transparent;
  box-shadow: 0 1px 0 var(--hairline);
}
.topnav-mobile-panel {
  display: none;
  border-block-end: 1px solid var(--hairline);
  background: var(--surface-card);
  padding-block: var(--sm) var(--md);
  box-shadow: 0 16px 32px rgba(0, 0, 0, 0.12);
}
.topnav-mobile-panel.is-open {
  display: block;
  animation: topnav-panel-in var(--dur-2) var(--ease-out) both;
}
@keyframes topnav-panel-in {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}
.topnav-mobile-panel .container,
.topnav-mobile-panel .topnav-inner {
  max-width: var(--site-max);
  margin-inline: auto;
  padding-inline: var(--lg);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.topnav-mobile-panel a {
  display: block;
  padding: 11px var(--md);
  border-radius: var(--r-sm);
  font-size: var(--fs-body);
  font-weight: 500;
  color: var(--text);
  text-decoration: none;
  border: 1px solid transparent;
  transition: background var(--dur-1) var(--ease-out),
              color var(--dur-1) var(--ease-out),
              border-color var(--dur-1) var(--ease-out);
}
.topnav-mobile-panel a:hover {
  background: var(--surface-elevated);
  color: var(--text-strong);
}
.topnav-mobile-panel a.active,
.topnav-mobile-panel a[aria-current="page"] {
  background: var(--primary-soft);
  border-color: rgba(228, 195, 90, 0.28);
  color: var(--text-strong);
  /* Weight stays 500: the pill background carries the state, and a
     constant weight keeps panel rows the same width open-to-open. */
}
/* The authed mobile panel carries the Sign out .nav-link-btn — give it
   the same row anatomy as the panel links so the list reads as one menu. */
.topnav-mobile-panel .nav-link-btn {
  display: block;
  width: 100%;
  text-align: start;
  padding: 12px 14px;
  border-radius: var(--r-sm);
  font-size: var(--fs-body);
  font-weight: 500;
  color: var(--text);
  background: none;
  border: 1px solid transparent;
}
.topnav-mobile-panel .nav-link-btn:hover {
  background: var(--surface-elevated);
  color: var(--text-strong);
}
.topnav .brand-mark {
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -0.3px;
  color: var(--text-strong);
  line-height: 1;
  font-family: var(--font-sans);
}
.topnav .brand-mark .tld { font-weight: 600; color: var(--accent-text); }
/* Nav cluster pushes to the inline-end edge. .topnav-nav is the server-page
   convention; .topnav-links is the SPA's. */
.topnav-nav,
.topnav-links {
  margin-inline-start: auto;
  display: flex;
  align-items: center;
  gap: var(--lg);
  flex-wrap: wrap;
}
.topnav-nav a,
.topnav-links a,
.nav-link-btn {
  position: relative; /* anchors the .active underline */
  font-size: var(--fs-body);
  font-weight: 500;
  color: var(--text);
  text-decoration: none;
  line-height: 1;
  transition: color var(--dur-1) var(--ease-out);
}
.topnav-nav a:hover,
.topnav-links a:hover,
.nav-link-btn:hover { color: var(--accent-text); }
/* Active page: stronger ink + an accent underline. The underline is
   position:absolute so it occupies NO layout space, and the font weight
   NEVER changes between states — link widths are byte-identical on every
   page, so the bar cannot shift or re-wrap as you navigate (the "jitter"
   fix). aria-current="page" is emitted alongside .active by every nav
   builder; styling both keeps the visual and assistive signals fused. */
.topnav-nav a.active,
.topnav-links a.active,
.topnav-nav a[aria-current="page"],
.topnav-links a[aria-current="page"] { color: var(--text-strong); }
.topnav-nav a.active::after,
.topnav-links a.active::after,
.topnav-nav a[aria-current="page"]::after,
.topnav-links a[aria-current="page"]::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  bottom: -8px;
  height: 2px;
  border-radius: 1px;
  background: var(--accent-text);
  pointer-events: none;
}
.nav-link-btn {
  background: none;
  border: 0;
  font-family: inherit;
  cursor: pointer;
  padding: 0;
}
/* Trailing action cluster (theme toggle + sign-in / account control). */
.topnav-actions {
  display: flex;
  align-items: center;
  gap: var(--xs);
  flex-shrink: 0;
  margin-inline-start: auto;
  min-width: 0;
}
/* When the header has no <nav> to consume the auto margin, the action
   cluster pushes itself to the inline-end edge. */
.topnav-actions--end { margin-inline-start: auto; }
/* Icon-only control (theme toggle). Square 36px hit target; SVG inherits
   currentColor via .icon (or a raw inline svg). */
.btn-icon {
  width: 36px;
  height: 36px;
  padding: 0;
  border-radius: var(--r-md);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text);
  background: transparent;
  border: 0;
  cursor: pointer;
  flex-shrink: 0;
  transition: background var(--dur-1) var(--ease-out),
              color var(--dur-1) var(--ease-out);
}
.btn-icon:hover { background: var(--surface-elevated); color: var(--text-strong); }
.btn-icon .icon,
.btn-icon svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
@media (max-width: 768px) {
  .topnav-inner,
  .topnav > .container {
    padding-inline: var(--md);
    gap: var(--sm);
  }
  .topnav .brand-mark { font-size: 16px; }
  .topnav-menu-btn { display: inline-flex; }
  .topnav-nav,
  .topnav-links { display: none !important; }
  /* Hide the theme toggle on mobile across every renderTopnav surface
     (matches the SPA): it is non-essential chrome and, on the public
     auth nav, it competed with the trailing CTA + hamburger and forced
     horizontal overflow. prefers-color-scheme still applies; the toggle
     returns on desktop. */
  .topnav #theme-toggle { display: none; }
  /* Compact the trailing public-nav action (Sign in / Sign up) on mobile
     so brand + CTA + hamburger never overflow a narrow viewport. */
  .topnav-actions .btn { padding: 8px 12px; font-size: 13px; }
  .brand-logo-img { height: 34px; max-width: 38px; }
}
@media (max-width: 640px) {
  .topnav-nav, .topnav-links { gap: var(--md); }
}
/* Tablet band: cover BOTH nav conventions identically (.topnav-nav =
   server pages, .topnav-links = SPA) — when only .topnav-nav shrank, the
   SPA bar wrapped to two lines at 769-830px ("Pricing" under "Jobs")
   while /pricing rendered one clean line at the same width, the exact
   cross-surface jitter the canonical nav exists to prevent. nowrap makes
   a two-line bar impossible above the 768px hamburger cutoff. */
@media (min-width: 769px) and (max-width: 1180px) {
  .topnav-nav,
  .topnav-links { gap: var(--sm); flex-wrap: nowrap; }
  .topnav-nav a,
  .topnav-links a { font-size: var(--fs-meta); }
}
@media (max-width: 380px) {
  .topnav .brand-mark { font-size: 14px; }
  .brand-logo-img { height: 30px; max-width: 34px; }
}

/* --- Footer brand row (logo + wordmark). --- */
.footer-brand {
  display: flex;
  align-items: center;
  gap: var(--sm);
  margin-block-end: var(--xs);
}
.footer-brand .brand-logo {
  width: 36px;
  height: 36px;
}
.footer-brand .brand-logo-img {
  height: 44px;
  max-width: 50px;
}
.footer-brand-mark {
  font-weight: 700;
  font-size: 18px;
  color: var(--text-strong);
  letter-spacing: -0.3px;
  line-height: 1;
}
.footer-brand-mark .tld { font-weight: 600; color: var(--accent-text); }

/* --- Visually-hidden utility (a11y labels for icon-only controls). --- */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ============================================================================
   4. MARKETING SECTIONS — homepage + policy surfaces
   ========================================================================== */
.section-eyebrow {
  font-family: var(--font-sans);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted-strong);
  margin: 0 0 var(--sm);
}
.section-title {
  font-size: var(--fs-h2);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--text-strong);
  margin: 0 0 var(--sm);
  max-width: 28ch;
  line-height: 1.15;
}
.section-lede {
  font-size: var(--fs-body-lg);
  color: var(--muted-strong);
  margin: 0 0 var(--xl);
  max-width: 62ch;
  line-height: 1.6;
}
.boundary-strip {
  border-block: 1px solid var(--hairline);
  background: var(--surface-card);
  padding: var(--sm) 0;
}
.boundary-strip p {
  margin: 0;
  font-size: var(--fs-meta);
  color: var(--muted-strong);
  text-align: center;
  letter-spacing: 0.01em;
}
.trust-section,
.process-section,
.partners-section,
.offer-section,
.faq-section {
  padding: var(--section) 0;
  border-bottom: 1px solid var(--hairline);
}
.partners-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--xl) var(--xxl);
  margin: 0;
  padding: 0;
  list-style: none;
}
.partner-logo a {
  display: block;
  border-radius: var(--r-sm, 4px);
}
.partner-logo a:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 4px;
}
.partner-logo img {
  display: block;
  height: 64px;
  width: auto;
  /* Desaturated at rest so the strip reads as one quiet band regardless of
     each logo's own palette; full colour returns on hover/focus. Rest state
     stays >= 3:1 (the non-text contrast floor) on both canvases: 0.8 opacity
     plus a dark-theme brightness lift via --partner-logo-filter (§1) —
     touch users never see the hover restore, so rest must stand alone. */
  filter: var(--partner-logo-filter, grayscale(1));
  opacity: 0.8;
  transition: filter var(--dur-1) var(--ease-out),
              opacity var(--dur-1) var(--ease-out);
}
.partner-logo:hover img,
.partner-logo:focus-within img {
  filter: none;
  opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  .partner-logo img { transition: none; }
}
.trust-grid,
.offer-grid {
  display: grid;
  gap: var(--lg);
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}
.trust-card,
.offer-card {
  background: var(--surface-card);
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
  padding: var(--lg);
  transition: border-color var(--dur-1) var(--ease-out),
              transform var(--dur-1) var(--ease-out);
}
.trust-card:hover,
.offer-card:hover {
  border-color: color-mix(in srgb, var(--primary) 35%, var(--hairline));
}
.trust-card h3,
.offer-card h3 {
  font-size: var(--fs-h3);
  font-weight: 600;
  margin: 0 0 var(--xs);
  color: var(--text-strong);
}
.trust-card p,
.offer-card p {
  margin: 0;
  font-size: var(--fs-body-lg);
  color: var(--text);
  line-height: 1.55;
}
.process-steps {
  display: grid;
  gap: var(--md);
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  counter-reset: step;
  margin: 0;
  padding: 0;
  list-style: none;
}
.process-step {
  position: relative;
  padding: var(--lg);
  background: var(--surface-card);
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
}
.process-step::before {
  counter-increment: step;
  content: counter(step, decimal-leading-zero);
  display: block;
  font-family: var(--font-sans);
  font-size: var(--fs-micro);
  font-weight: 600;
  color: var(--accent-text);
  margin-bottom: var(--sm);
}
.process-step h3 {
  font-size: var(--fs-h3);
  font-weight: 600;
  margin: 0 0 var(--xs);
}
.process-step p {
  margin: 0;
  font-size: var(--fs-body-lg);
  color: var(--muted-strong);
  line-height: 1.55;
}
.feed-intro {
  padding: var(--lg) 0 var(--sm);
}
.feed-intro p {
  margin: 0;
  font-size: var(--fs-body-lg);
  color: var(--muted-strong);
}
.faq-list {
  display: grid;
  gap: var(--md);
  max-width: 720px;
}
.faq-item {
  padding: var(--md) 0;
  border-bottom: 1px solid var(--hairline);
}
.faq-item:last-child { border-bottom: 0; }
.faq-item h3 {
  font-size: var(--fs-body-lg);
  font-weight: 600;
  margin: 0 0 var(--xs);
  color: var(--text-strong);
}
.faq-item p {
  margin: 0;
  font-size: var(--fs-body-lg);
  color: var(--text);
  line-height: 1.55;
}
@media (max-width: 768px) {
  .trust-section,
  .process-section,
  .partners-section,
  .offer-section,
  .faq-section {
    padding: var(--xxl) 0;
  }
  .partner-logo img { height: 48px; }
}
