/* Design tokens — the single source of truth for colour, type, space and motion.
 *
 * Every surface reads from this file: the recruiter shell, the candidate flow, and the
 * standalone review page. The review page must stay a self-contained artifact (it is
 * archived and read years later), so it inlines this file rather than linking it — but
 * it inlines *this* file, not a second copy of these values. Two ramps that drift apart
 * is how a product starts looking like two products.
 *
 * ── The one idea ────────────────────────────────────────────────────────────────
 * A score in this product is only as good as the words underneath it. So the visual
 * signature is a highlighter: `--marker`, a warm amber wash, means "this is the
 * evidence". It is used for exactly that and nothing else — never for a warning, never
 * for a button, never as decoration. When a recruiter sees amber, there are words
 * behind it. Everything else is structural.
 */

:root {
  color-scheme: light;

  /* ── Neutrals ──────────────────────────────────────────────────────────────
   * Slightly green-tinted so white surfaces sit warm against the canvas rather
   * than fluorescing.
   */
  --n-0:   #ffffff;
  --n-25:  #fbfcfc;
  --n-50:  #f4f7f6;
  --n-100: #e9efed;
  --n-150: #dfe7e5;
  --n-200: #d0dbd8;
  --n-300: #a7b9b5;
  --n-400: #778b86;
  --n-500: #586b66;
  --n-600: #54655f;
  --n-700: #3e4d48;
  --n-800: #2a3733;
  --n-900: #182320;
  --n-950: #0d1614;

  /* ── Accent: the interactive colour. Deep, calm, never neon. ─────────────── */
  --a-50:  #e4f6f2;
  --a-100: #c2ebe2;
  --a-200: #8ed8c8;
  --a-300: #55bfab;
  --a-400: #27a18e;
  --a-500: #0e7a6d;
  --a-600: #0a6156;
  --a-700: #0a544c;
  --a-800: #09443e;
  --a-900: #073733;

  /* ── Marker: evidence, and only evidence. ────────────────────────────────── */
  --m-100: #fdf1d0;
  --m-200: #fbe3a4;
  --m-300: #f6cd63;
  --m-400: #e9ae23;
  --m-500: #b8850f;

  /* ── Semantic status. Deliberately far apart in hue from each other. ─────── */
  --ok-fg:    #146c46;
  --ok-bg:    #e2f4ea;
  --ok-line:  #a9dcc2;
  --warn-fg:  #91541a;
  --warn-bg:  #fbeedd;
  --warn-line:#edcfa5;
  --bad-fg:   #a92b1f;
  --bad-bg:   #fdeae7;
  --bad-line: #f3bfb7;
  --info-fg:  #1d4ed8;
  --info-bg:  #e8efff;
  --info-line:#bdd0fb;

  /* ── Score tiers: the judgement colours. ──────────────────────────────────
   * Green ≥ 4.0, amber 3.0–3.9, red < 3.0 — the same thresholds as the
   * evidence bands, so the colour and the band can never disagree. The `-fill`
   * is a bar or chart mark; the `-ink` is text on a light surface. Distinct
   * from `--marker`: an amber wash still means "evidence", these mean "how
   * good".
   */
  --score-high-fill: #279264;
  --score-high-ink:  var(--ok-fg);
  --score-mid-fill:  #dfa32b;
  --score-mid-ink:   #96700d;
  --score-low-fill:  #cc4a3c;
  --score-low-ink:   var(--bad-fg);

  /* ── Semantic aliases: what components actually reference. ───────────────── */
  --canvas:        var(--n-50);
  --canvas-deep:   var(--n-100);
  --surface:       var(--n-0);
  --surface-sunk:  var(--n-50);
  --surface-raised:var(--n-0);
  --ink:           var(--n-900);
  --ink-soft:      var(--n-700);
  --ink-muted:     var(--n-500);
  --ink-faint:     var(--n-400);
  --line:          var(--n-150);
  --line-strong:   var(--n-200);
  --accent:        var(--a-500);
  --accent-hover:  var(--a-600);
  --accent-ink:    var(--a-700);
  --accent-wash:   var(--a-50);
  --accent-line:   var(--a-200);
  --on-accent:     #ffffff;
  --marker:        var(--m-200);
  --marker-strong: var(--m-300);
  --marker-ink:    var(--m-500);
  --focus:         var(--a-400);

  /* ── Elevation. Tinted with the neutral hue, layered so it reads as light
   * rather than as a grey blur. `-lift` is the hover state; the y-offset grows
   * more than the blur so things feel like they rise, not smear.
   */
  --shadow-xs:   0 1px 2px rgba(13, 22, 20, .05);
  --shadow-sm:   0 1px 2px rgba(13, 22, 20, .04), 0 2px 6px rgba(13, 22, 20, .04);
  --shadow-md:   0 2px 4px rgba(13, 22, 20, .04), 0 8px 20px rgba(13, 22, 20, .06);
  --shadow-lg:   0 4px 8px rgba(13, 22, 20, .05), 0 18px 44px rgba(13, 22, 20, .09);
  --shadow-lift: 0 6px 12px rgba(13, 22, 20, .06), 0 24px 56px rgba(13, 22, 20, .11);
  --shadow-accent: 0 4px 12px rgba(15, 131, 117, .22);
  --ring: 0 0 0 1px rgba(13, 22, 20, .04);

  /* ── Type ──────────────────────────────────────────────────────────────────
   * No webfont: the product must render identically offline and behind a strict
   * CSP, and a 300ms flash of fallback text on a candidate's interview page is a
   * worse trade than a familiar typeface. Personality comes from the treatment —
   * optical tracking, tabular figures, and a real weight range — not the file.
   */
  --font: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI Variable Text",
          "Segoe UI", Inter, Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-display: ui-sans-serif, -apple-system, "SF Pro Display", BlinkMacSystemFont,
          "Segoe UI Variable Display", "Segoe UI", Inter, Roboto, sans-serif;
  --font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, "Cascadia Mono",
          "Roboto Mono", monospace;

  --text-2xs: .6875rem;  /* 11 — pill / eyebrow            */
  --text-xs:  .75rem;    /* 12 — hint, meta                */
  --text-sm:  .8125rem;  /* 13 — dense UI                  */
  --text-md:  .875rem;   /* 14 — table, secondary body     */
  --text-base:.9375rem;  /* 15 — body                      */
  --text-lg:  1.0625rem; /* 17 — lede                      */
  --text-xl:  1.25rem;   /* 20 — section head              */
  --text-2xl: 1.5rem;    /* 24 — page head (dense screens) */
  --text-3xl: clamp(1.75rem, 1.4rem + 1.4vw, 2.25rem);
  --text-4xl: clamp(2.1rem, 1.5rem + 2.6vw, 3.1rem);

  --tracking-tight: -.022em;
  --tracking-snug:  -.012em;
  --tracking-wide:  .06em;
  --tracking-caps:  .085em;

  /* ── Space: a 4px base, named by use rather than by number. ──────────────── */
  --sp-1: 4px;   --sp-2: 8px;   --sp-3: 12px;  --sp-4: 16px;
  --sp-5: 20px;  --sp-6: 24px;  --sp-8: 32px;  --sp-10: 40px;
  --sp-12: 48px; --sp-16: 64px; --sp-20: 80px;

  --r-xs: 6px;  --r-sm: 9px;  --r-md: 13px;
  --r-lg: 18px; --r-xl: 26px; --r-full: 999px;

  /* ── Motion ────────────────────────────────────────────────────────────────
   * `--ease-out` is the workhorse: it moves almost all of its distance in the
   * first third, which is what makes an interface feel responsive rather than
   * animated. `--ease-spring` overshoots slightly and is reserved for things
   * that appear (a toast, a selected card) — never for things that move under
   * the pointer.
   */
  --ease-out:    cubic-bezier(.16, 1, .3, 1);
  --ease-in-out: cubic-bezier(.65, 0, .35, 1);
  --ease-spring: cubic-bezier(.34, 1.56, .64, 1);
  --t-fast:   120ms;
  --t-base:   200ms;
  --t-slow:   340ms;
  --t-slower: 560ms;

  --z-base: 1; --z-sticky: 40; --z-overlay: 60; --z-toast: 80; --z-skip: 100;

  --header-h: 60px;
}

/* ── Dark ────────────────────────────────────────────────────────────────────
 * Not an inversion. The canvas is a deep desaturated green-black, surfaces are
 * lifted with lightness rather than with borders, and the accent moves up the
 * ramp because a 500-weight teal on near-black fails contrast at small sizes.
 */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { color-scheme: dark; }
}
:root[data-theme="dark"] { color-scheme: dark; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --canvas:         #0a1211;
    --canvas-deep:    #060d0c;
    --surface:        #121d1b;
    --surface-sunk:   #0e1817;
    --surface-raised: #182523;
    --ink:            #e8f2ef;
    --ink-soft:       #bfd2cd;
    --ink-muted:      #8ba39d;
    --ink-faint:      #7c948e;
    --line:           #22322f;
    --line-strong:    #33473f;
    --accent:         #43c4ae;
    --accent-hover:   #66d6c2;
    --accent-ink:     #a5e8db;
    --accent-wash:    #10322d;
    --accent-line:    #1d554c;
    --on-accent:      #04211d;
    --marker:         #5f4a12;
    --marker-strong:  #86671a;
    --marker-ink:     #f6cd63;
    --focus:          #43c4ae;

    --ok-fg: #5fcf94;   --ok-bg: #0f3324;   --ok-line: #1e5a3f;
    --warn-fg: #edb35f; --warn-bg: #382709; --warn-line: #5e4415;
    --bad-fg: #ff9086;  --bad-bg: #3d1a17;  --bad-line: #632b25;
    --info-fg: #8fb5ff; --info-bg: #16264a; --info-line: #2a4179;

    --score-high-fill: #2fa476;
    --score-high-ink:  #5fcf94;
    --score-mid-fill:  #d9a338;
    --score-mid-ink:   #edb35f;
    --score-low-fill:  #d4574a;
    --score-low-ink:   #ff9086;

    --shadow-xs:   0 1px 2px rgba(0, 0, 0, .3);
    --shadow-sm:   0 1px 2px rgba(0, 0, 0, .3), 0 2px 6px rgba(0, 0, 0, .22);
    --shadow-md:   0 2px 4px rgba(0, 0, 0, .3), 0 8px 20px rgba(0, 0, 0, .3);
    --shadow-lg:   0 4px 8px rgba(0, 0, 0, .32), 0 18px 44px rgba(0, 0, 0, .42);
    --shadow-lift: 0 6px 12px rgba(0, 0, 0, .34), 0 24px 56px rgba(0, 0, 0, .48);
    --shadow-accent: 0 4px 14px rgba(67, 196, 174, .18);
    --ring: 0 0 0 1px rgba(255, 255, 255, .05);
  }
}

:root[data-theme="dark"] {
  --canvas:         #0a1211;
  --canvas-deep:    #060d0c;
  --surface:        #121d1b;
  --surface-sunk:   #0e1817;
  --surface-raised: #182523;
  --ink:            #e8f2ef;
  --ink-soft:       #bfd2cd;
  --ink-muted:      #8ba39d;
  --ink-faint:      #7c948e;
  --line:           #22322f;
  --line-strong:    #33473f;
  --accent:         #43c4ae;
  --accent-hover:   #66d6c2;
  --accent-ink:     #a5e8db;
  --accent-wash:    #10322d;
  --accent-line:    #1d554c;
  --on-accent:      #04211d;
  --marker:         #5f4a12;
  --marker-strong:  #86671a;
  --marker-ink:     #f6cd63;
  --focus:          #43c4ae;

  --ok-fg: #5fcf94;   --ok-bg: #0f3324;   --ok-line: #1e5a3f;
  --warn-fg: #edb35f; --warn-bg: #382709; --warn-line: #5e4415;
  --bad-fg: #ff9086;  --bad-bg: #3d1a17;  --bad-line: #632b25;
  --info-fg: #8fb5ff; --info-bg: #16264a; --info-line: #2a4179;

  --score-high-fill: #2fa476;
  --score-high-ink:  #5fcf94;
  --score-mid-fill:  #d9a338;
  --score-mid-ink:   #edb35f;
  --score-low-fill:  #d4574a;
  --score-low-ink:   #ff9086;

  --shadow-xs:   0 1px 2px rgba(0, 0, 0, .3);
  --shadow-sm:   0 1px 2px rgba(0, 0, 0, .3), 0 2px 6px rgba(0, 0, 0, .22);
  --shadow-md:   0 2px 4px rgba(0, 0, 0, .3), 0 8px 20px rgba(0, 0, 0, .3);
  --shadow-lg:   0 4px 8px rgba(0, 0, 0, .32), 0 18px 44px rgba(0, 0, 0, .42);
  --shadow-lift: 0 6px 12px rgba(0, 0, 0, .34), 0 24px 56px rgba(0, 0, 0, .48);
  --shadow-accent: 0 4px 14px rgba(67, 196, 174, .18);
  --ring: 0 0 0 1px rgba(255, 255, 255, .05);
}

/* Reset, typography, focus, and the motion primitives.
 *
 * Everything here is shared by the recruiter shell, the candidate flow, and the
 * standalone review page, so it must not assume any particular layout exists.
 */

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

html {
  overflow-x: clip;
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-width: 320px;
  background: var(--canvas);
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--text-base);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-synthesis-weight: none;
  text-rendering: optimizeLegibility;
}

/* Numbers in tables, metrics and timestamps must not shimmy as they update. */
table, .tabular, time, .metric-value, .num { font-variant-numeric: tabular-nums; }

h1, h2, h3, h4 {
  margin: 0;
  font-family: var(--font-display);
  color: var(--ink);
  font-weight: 640;
  letter-spacing: var(--tracking-tight);
  line-height: 1.15;
  text-wrap: balance;
}
h1 { font-size: var(--text-3xl); }
h2 { font-size: var(--text-xl); letter-spacing: var(--tracking-snug); line-height: 1.25; }
h3 { font-size: var(--text-md); letter-spacing: var(--tracking-snug); line-height: 1.35; font-weight: 660; }

p { margin: 0 0 var(--sp-4); text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--accent-hover); }

ul, ol { margin: 0; padding-left: 1.15em; }

button, input, textarea, select { font: inherit; color: inherit; }
button, a, input, textarea, select, summary, label { -webkit-tap-highlight-color: transparent; }

img, svg, video { max-width: 100%; height: auto; display: block; }

/* Components set an explicit `display`, which beats the user-agent rule for
 * `[hidden]`. Without this, `element.hidden = true` silently does nothing —
 * which is how a candidate ends up looking at an "I'm finished" button before
 * the interview has started. */
[hidden] { display: none !important; }

hr { height: 1px; margin: var(--sp-6) 0; border: 0; background: var(--line); }

code, kbd, samp { font-family: var(--font-mono); font-size: .92em; }

::selection { background: var(--accent-wash); color: var(--ink); }

/* One focus ring everywhere. Two-layer so it stays visible on both a white card
 * and a saturated button without needing a per-component override. */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}
:focus:not(:focus-visible) { outline: none; }

/* ── Utility ─────────────────────────────────────────────────────────────── */

.sr-only {
  position: absolute !important; width: 1px !important; height: 1px !important;
  padding: 0 !important; margin: -1px !important; overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important; white-space: nowrap !important; border: 0 !important;
}

.skip-link {
  position: fixed; top: var(--sp-2); left: var(--sp-4); z-index: var(--z-skip);
  padding: var(--sp-2) var(--sp-4); border-radius: var(--r-sm);
  background: var(--ink); color: var(--canvas); font-weight: 620; text-decoration: none;
  transform: translateY(calc(-100% - var(--sp-4)));
  transition: transform var(--t-base) var(--ease-out);
}
.skip-link:focus { transform: translateY(0); color: var(--canvas); }

.muted   { color: var(--ink-muted); }
.soft    { color: var(--ink-soft); }
.small   { font-size: var(--text-xs); }
.mono    { font-family: var(--font-mono); }
.stack   { display: grid; gap: var(--sp-4); }
.row     { display: flex; gap: var(--sp-3); align-items: center; flex-wrap: wrap; }
.spacer  { flex: 1 1 auto; }
.nowrap  { white-space: nowrap; }

.hint {
  margin-top: var(--sp-2);
  color: var(--ink-muted);
  font-size: var(--text-xs);
  line-height: 1.5;
}

/* An uppercase micro-label. Used sparingly — it is a signpost, not a decoration. */
.eyebrow {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  color: var(--ink-muted);
  font-size: var(--text-2xs); font-weight: 700;
  letter-spacing: var(--tracking-caps); text-transform: uppercase;
}

/* ── The marker ───────────────────────────────────────────────────────────────
 * The product's one signature. An amber wash that means "these are the actual
 * words". Drawn as a background gradient sized to the bottom 60% of the line so
 * it reads as a pen stroke rather than a filled box, and so descenders still
 * show through.
 */
.marker, mark {
  background:
    linear-gradient(to top, var(--marker) 0%, var(--marker) 58%, transparent 58%);
  color: inherit;
  border-radius: 2px;
  padding: 0 .12em;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}
mark.is-active {
  background: linear-gradient(to top, var(--marker-strong) 0%, var(--marker-strong) 100%);
  box-shadow: 0 0 0 2px var(--marker-strong);
}

/* The same stroke, animated on first paint — used for the one phrase per page
 * that carries the idea. */
.marker-draw {
  background: linear-gradient(to top, var(--marker) 0%, var(--marker) 58%, transparent 58%);
  background-size: 0% 100%;
  background-repeat: no-repeat;
  border-radius: 2px;
  padding: 0 .12em;
  animation: marker-sweep var(--t-slower) var(--ease-out) 220ms forwards;
}
@keyframes marker-sweep { to { background-size: 100% 100%; } }

/* ── Enter motion ─────────────────────────────────────────────────────────────
 * `.reveal` fades and lifts an element on first paint. `--i` staggers a list:
 * set it per item and each waits 45ms longer than the last. Capped so a long
 * table does not take three seconds to arrive.
 */
.reveal { animation: reveal var(--t-slow) var(--ease-out) both; }
@keyframes reveal {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

/* A staggered list. The delay lives in `nth-child` rather than an inline
 * `--i` custom property so that views never need a `style=` attribute — which
 * is what lets the CSP ship as `style-src 'self'` with no `unsafe-inline`.
 * Ten steps, then everything else arrives together: a long list should not take
 * two seconds to finish appearing. */
.stagger > * { animation: reveal var(--t-slow) var(--ease-out) both; }
.stagger > *:nth-child(1)  { animation-delay:   0ms; }
.stagger > *:nth-child(2)  { animation-delay:  40ms; }
.stagger > *:nth-child(3)  { animation-delay:  80ms; }
.stagger > *:nth-child(4)  { animation-delay: 120ms; }
.stagger > *:nth-child(5)  { animation-delay: 160ms; }
.stagger > *:nth-child(6)  { animation-delay: 200ms; }
.stagger > *:nth-child(7)  { animation-delay: 240ms; }
.stagger > *:nth-child(8)  { animation-delay: 280ms; }
.stagger > *:nth-child(9)  { animation-delay: 320ms; }
.stagger > *:nth-child(n+10) { animation-delay: 360ms; }

/* Reveal on scroll with no JavaScript at all, where the browser supports it. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .reveal-on-scroll {
      animation: reveal-scroll linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 18%;
    }
    @keyframes reveal-scroll {
      from { opacity: 0; transform: translateY(14px); }
      to   { opacity: 1; transform: none; }
    }
  }
}

/* ── Cross-document view transitions ──────────────────────────────────────────
 * This app is server rendered and navigates with real page loads. One rule makes
 * those loads cross-fade instead of blinking white, which is most of what makes
 * a multi-page app feel like a single one. Elements carrying a
 * `view-transition-name` (the header, the page title) are morphed between pages
 * rather than faded.
 */
@view-transition { navigation: auto; }

::view-transition-old(root) { animation: vt-out 90ms var(--ease-in-out) both; }
::view-transition-new(root) { animation: vt-in var(--t-base) var(--ease-out) both; }
@keyframes vt-out { to { opacity: 0; } }
@keyframes vt-in { from { opacity: 0; transform: translateY(6px); } }

/* ── Reduced motion ──────────────────────────────────────────────────────────
 * Honoured completely: transitions collapse, entrances resolve to their final
 * state instead of being skipped mid-way, and view transitions are turned off.
 */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    /* Negative, so the animation is already past its end when it starts. Without this
     * the block did not do what the paragraph above claims: `.stagger` entrances keep
     * their delay, and `animation-fill-mode: both` holds an element at its *initial*
     * state for the whole of it — so a reader who asked for no motion got content
     * held invisible for up to a fifth of a second instead of resolved.
     *
     * Found by an accessibility gate, which sampled a staggered row at opacity 0.64
     * and reported a contrast failure against a token that passes at 5.27:1. */
    animation-delay: -1ms !important;
    transition-duration: .01ms !important;
    transition-delay: 0s !important;
    scroll-behavior: auto !important;
  }
  @view-transition { navigation: none; }
  .marker-draw { background-size: 100% 100%; }
}

/* The icon sprite. Hidden by class rather than by a `style` attribute so the
 * Content-Security-Policy can forbid inline styles outright. */
.sprite { display: none; }

/* Components shared by every surface: the recruiter workspace, the candidate
 * flow, and the standalone review page.
 *
 * The split from `app.css` is not cosmetic. The review page is an archived
 * artifact that has to open years later with no server, so it inlines its CSS
 * rather than linking it — and before this file existed it inlined a *second*,
 * hand-maintained copy of the same buttons, pills and cards under different
 * class names (`--accent` here, `--brand` there). Two ramps that drift is how a
 * product starts looking like two products. Everything a review page and a
 * workspace can agree on lives here; `app.css` holds only what is genuinely
 * specific to the workspace.
 */
/* ══ Buttons ════════════════════════════════════════════════════════════════ */

.btn {
  --btn-bg: var(--surface);
  --btn-fg: var(--ink);
  --btn-line: var(--line-strong);
  position: relative;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  min-height: 38px; padding: 0 var(--sp-4);
  border: 1px solid var(--btn-line); border-radius: var(--r-sm);
  background: var(--btn-bg); color: var(--btn-fg);
  font-size: var(--text-md); font-weight: 640; line-height: 1;
  text-decoration: none; white-space: nowrap; cursor: pointer;
  box-shadow: var(--shadow-xs);
  transition:
    background var(--t-fast) var(--ease-out),
    border-color var(--t-fast) var(--ease-out),
    color var(--t-fast) var(--ease-out),
    box-shadow var(--t-base) var(--ease-out),
    transform var(--t-fast) var(--ease-out);
}
/* Hover states set the *tokens*, never `background` or `border-color` directly.
 *
 * This rule used to say `background: var(--surface-sunk)`. Because `.btn` reads
 * `background: var(--btn-bg)` and this selector is more specific, that literal
 * beat every variant's hover — `.btn.primary:hover` sets `--btn-bg` but never
 * re-declares `background`, so nothing read it. A primary button therefore went
 * near-white on hover while `--btn-fg` stayed white: an invisible label on the
 * most important control on the page.
 *
 * Keep the invariant: one `background` declaration in this file, on `.btn`, and
 * every state changes the token feeding it. `color` is re-asserted here only to
 * beat `a:hover` from base.css on anchors styled as buttons. */
.btn:hover {
  --btn-bg: var(--surface-sunk);
  --btn-line: var(--accent-line);
  color: var(--btn-fg);
  box-shadow: var(--shadow-sm);
}
.btn:active { transform: translateY(1px); box-shadow: none; }

.btn.primary {
  --btn-bg: var(--accent); --btn-fg: var(--on-accent); --btn-line: var(--accent);
  box-shadow: var(--shadow-accent);
}
.btn.primary:hover { --btn-bg: var(--accent-hover); --btn-line: var(--accent-hover); box-shadow: var(--shadow-accent), var(--shadow-md); }
.btn.quiet { --btn-bg: transparent; --btn-line: transparent; --btn-fg: var(--ink-soft); box-shadow: none; }
.btn.quiet:hover { --btn-bg: var(--surface-sunk); --btn-line: var(--line); }
.btn.danger { --btn-fg: var(--bad-fg); --btn-bg: var(--bad-bg); --btn-line: var(--bad-line); box-shadow: none; }
/* Without this, danger inherited the generic hover and lost its red tint — the
 * one button whose colour is the warning. */
.btn.danger:hover {
  --btn-bg: color-mix(in srgb, var(--bad-fg) 14%, var(--bad-bg));
  --btn-line: var(--bad-fg);
}
.btn.lg { min-height: 46px; padding: 0 var(--sp-6); font-size: var(--text-base); border-radius: var(--r-md); }
.btn.sm { min-height: 30px; padding: 0 var(--sp-3); font-size: var(--text-sm); }
.btn.block { width: 100%; }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; transform: none; box-shadow: none; }
.btn .i { flex: none; }

/* The arrow leans forward on hover — a small, cheap signal of direction. */
.btn .i-arrow { transition: transform var(--t-base) var(--ease-out); }
.btn:hover .i-arrow { transform: translateX(3px); }

/* ══ Surfaces ═══════════════════════════════════════════════════════════════ */

.card {
  padding: var(--sp-5);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
}
.card.sunk { background: var(--surface-sunk); box-shadow: none; }
.card.flush { padding: 0; overflow: hidden; }
.card + .card { margin-top: var(--sp-3); }

.panel {
  border: 1px solid var(--line); border-radius: var(--r-lg);
  background: var(--surface); box-shadow: var(--shadow-sm);
  overflow: hidden;
}

/* ══ Pills ══════════════════════════════════════════════════════════════════ */

.pill {
  display: inline-flex; align-items: center; gap: 5px;
  width: fit-content; min-height: 22px; padding: 1px var(--sp-2) 1px 7px;
  border: 1px solid var(--line-strong); border-radius: var(--r-full);
  background: var(--surface-sunk); color: var(--ink-soft);
  font-size: var(--text-2xs); font-weight: 650; line-height: 1.5;
  white-space: nowrap;
}
.pill::before {
  content: ""; width: 5px; height: 5px; flex: none;
  border-radius: var(--r-full); background: currentColor; opacity: .8;
}
.pill.no-dot::before { display: none; }
.pill.ok, .pill.published, .pill.ready, .pill.completed, .pill.jd {
  border-color: var(--ok-line); background: var(--ok-bg); color: var(--ok-fg);
}
.pill.warn, .pill.draft, .pill.in-progress, .pill.sug, .pill.queued,
.pill.transcribing, .pill.scoring {
  border-color: var(--warn-line); background: var(--warn-bg); color: var(--warn-fg);
}
.pill.bad, .pill.failed { border-color: var(--bad-line); background: var(--bad-bg); color: var(--bad-fg); }
.pill.accent, .pill.scored {
  border-color: var(--accent-line); background: var(--accent-wash); color: var(--accent-ink);
}
.pill.mute, .pill.lib, .pill.revoked, .pill.expired, .pill.skipped, .pill.used {
  color: var(--ink-muted); background: var(--surface-sunk);
}
.pill.marker {
  border-color: var(--marker-strong);
  background: linear-gradient(to top, var(--marker) 0%, var(--marker) 100%);
  color: var(--marker-ink); padding: 1px var(--sp-2);
}
.pill.marker::before { display: none; }

/* A pill that is still working. The dot breathes so a stuck job is visible. */
.pill.queued::before, .pill.transcribing::before, .pill.scoring::before,
.pill.in-progress::before {
  animation: pulse 1.6s var(--ease-in-out) infinite;
}
@keyframes pulse { 50% { opacity: .25; transform: scale(.7); } }

/* ══ Alerts ═════════════════════════════════════════════════════════════════ */

.alert {
  display: flex; gap: var(--sp-3); align-items: flex-start;
  padding: var(--sp-4);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface);
  margin-bottom: var(--sp-4);
}
.alert-icon {
  flex: none; width: 26px; height: 26px;
  display: grid; place-items: center;
  border-radius: var(--r-xs);
  background: color-mix(in srgb, currentColor 12%, transparent);
}
.alert-body { min-width: 0; flex: 1; }
.alert-title { display: block; margin-bottom: 2px; font-weight: 660; }
.alert p { margin-bottom: 0; font-size: var(--text-md); }
.alert.warn { border-color: var(--warn-line); background: var(--warn-bg); color: var(--warn-fg); }
.alert.bad  { border-color: var(--bad-line);  background: var(--bad-bg);  color: var(--bad-fg); }
.alert.ok   { border-color: var(--ok-line);   background: var(--ok-bg);   color: var(--ok-fg); }
.alert.warn .alert-body, .alert.bad .alert-body, .alert.ok .alert-body { color: var(--ink); }
.alert.warn .alert-title { color: var(--warn-fg); }
.alert.bad .alert-title  { color: var(--bad-fg); }
.alert.ok .alert-title   { color: var(--ok-fg); }

/* ══ Empty states ═══════════════════════════════════════════════════════════ */

.empty {
  display: grid; justify-items: center;
  padding: var(--sp-16) var(--sp-6);
  border: 1px dashed var(--line-strong); border-radius: var(--r-lg);
  background:
    radial-gradient(ellipse at 50% 0%, var(--accent-wash), transparent 70%),
    var(--surface-sunk);
  text-align: center;
}
.empty-mark {
  width: 52px; height: 52px; margin-bottom: var(--sp-4);
  display: grid; place-items: center;
  border-radius: 16px 16px 16px 5px;
  background: var(--surface); color: var(--accent);
  box-shadow: var(--shadow-md), var(--ring);
}
.empty b { font-family: var(--font-display); font-size: var(--text-lg); font-weight: 660; }
.empty p { max-width: 46ch; margin: var(--sp-2) 0 var(--sp-5); color: var(--ink-muted); }

/* ══ Forms ══════════════════════════════════════════════════════════════════ */

.form-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) 296px;
  gap: var(--sp-5); align-items: start;
}
.form-panel {
  padding: clamp(var(--sp-5), 3vw, var(--sp-8));
  border: 1px solid var(--line); border-radius: var(--r-lg);
  background: var(--surface); box-shadow: var(--shadow-sm);
}
.form-panel + .form-panel { margin-top: var(--sp-4); }
.form-panel-head { margin-bottom: var(--sp-5); }
.form-panel-head p { margin: var(--sp-1) 0 0; color: var(--ink-muted); font-size: var(--text-sm); }

.field { display: block; margin-bottom: var(--sp-5); }
.field:last-child { margin-bottom: 0; }
.field-label {
  display: flex; justify-content: space-between; align-items: baseline; gap: var(--sp-3);
  margin-bottom: 6px;
  font-size: var(--text-sm); font-weight: 650;
}
.field-optional { color: var(--ink-muted); font-size: var(--text-xs); font-weight: 550; }

input, textarea, select {
  width: 100%; min-height: 42px;
  padding: 9px var(--sp-3);
  border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink);
  box-shadow: inset 0 1px 1px rgba(13, 22, 20, .03);
  transition: border-color var(--t-fast) var(--ease-out), box-shadow var(--t-fast) var(--ease-out);
}
input::placeholder, textarea::placeholder { color: var(--ink-faint); }
input:hover, textarea:hover, select:hover { border-color: var(--line-strong); }
input:focus, textarea:focus, select:focus {
  outline: 0;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 16%, transparent);
}
textarea { min-height: 220px; line-height: 1.6; resize: vertical; }
textarea.compact { min-height: 104px; }
select { appearance: none; padding-right: var(--sp-8); cursor: pointer;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 18px) 50%, calc(100% - 13px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
input[type="file"] { padding: 6px; cursor: pointer; }
input[type="file"]::file-selector-button {
  margin-right: var(--sp-3); padding: 7px var(--sp-3);
  border: 0; border-radius: var(--r-xs);
  background: var(--surface-sunk); color: var(--ink);
  font-weight: 640; cursor: pointer;
}
input[type="checkbox"] { width: auto; min-height: 0; accent-color: var(--accent); box-shadow: none; }

.form-actions {
  display: flex; justify-content: space-between; align-items: center;
  gap: var(--sp-3); flex-wrap: wrap; margin-top: var(--sp-6);
}

.aside {
  position: sticky; top: calc(var(--header-h) + var(--sp-5));
  padding: var(--sp-5);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface-sunk);
}
.aside h3 { margin-bottom: var(--sp-3); }
.aside-list { display: grid; gap: var(--sp-3); margin: 0; padding: 0; list-style: none; }
.aside-list li {
  display: grid; grid-template-columns: 20px 1fr; gap: var(--sp-3);
  color: var(--ink-soft); font-size: var(--text-sm);
}
.aside-list .n {
  width: 20px; height: 20px; display: grid; place-items: center;
  border-radius: var(--r-xs); background: var(--surface); color: var(--accent);
  font-size: 10px; font-weight: 750;
}

.note {
  display: flex; gap: var(--sp-3); align-items: flex-start;
  padding: var(--sp-4);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface-sunk);
  color: var(--ink-soft); font-size: var(--text-sm);
}
.note-mark {
  flex: none; width: 26px; height: 26px;
  display: grid; place-items: center; border-radius: var(--r-xs);
  background: var(--accent-wash); color: var(--accent-ink);
}

details.disclose {
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface-sunk);
  overflow: hidden;
}
details.disclose > summary {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  color: var(--ink-soft); font-size: var(--text-md); font-weight: 640;
  cursor: pointer; list-style: none;
}
details.disclose > summary::-webkit-details-marker { display: none; }
details.disclose > summary:hover { color: var(--ink); }
details.disclose > summary .i-chevron { transition: transform var(--t-base) var(--ease-out); }
details.disclose[open] > summary .i-chevron { transform: rotate(90deg); }
.disclose-body { padding: 0 var(--sp-4) var(--sp-4); }
/* The summary is a flex row, so the name and its pill need a box of their own or the
   pill becomes a sibling of the chevron and the gap between the two words changes with
   it. */
.disclose-title { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.disclose-title b { color: var(--ink); }
/* Several of them in a column. Gap rather than a margin on the card, so a lone
   disclosure carries no trailing space it did not ask for. */
.disclose-stack { display: grid; gap: var(--sp-2); }

/* ══ Tables ═════════════════════════════════════════════════════════════════ */

.table-wrap {
  width: 100%; overflow-x: auto;
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface); box-shadow: var(--shadow-sm);
}
table { width: 100%; border-collapse: collapse; }
th, td { padding: var(--sp-3) var(--sp-4); text-align: left; vertical-align: middle; }
th {
  border-bottom: 1px solid var(--line);
  color: var(--ink-muted); font-size: 10px; font-weight: 750;
  letter-spacing: var(--tracking-caps); text-transform: uppercase;
  white-space: nowrap;
}
td { border-bottom: 1px solid var(--line); font-size: var(--text-md); }
tr:last-child td { border-bottom: 0; }
tbody tr { transition: background var(--t-fast) var(--ease-out); }
tbody tr:hover { background: var(--surface-sunk); }
.cell-title { color: var(--ink); font-weight: 640; text-decoration: none; }
.cell-title:hover { color: var(--accent); }

/* The line under a candidate's name: role, how the interview ended, when it started.
 * It carries what used to be three columns, so it has to read as subordinate to the
 * name — and the three facts have to stay separable at a glance. One colour and one
 * size for all three made a string nobody could parse without reading every word, so
 * each kind gets its own weight: plain text, a bordered chip, faint numerals.
 *
 * Gap rather than "·" separators, so a narrow column breaks *between* facts. Left to
 * itself the browser breaks inside them, and "2026-08-" / "27" reads as a bug. */
.cell-meta {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--sp-1) var(--sp-2);
  margin-top: 3px;
}
.cell-meta > * { white-space: nowrap; }
.meta-role { color: var(--ink-muted); font-size: var(--text-xs); font-weight: 500; }
/* How the interview ended, and only when that was not the ordinary "completed". A chip
 * because it is the exception you scan for — but a *neutral* chip: green/amber/red is
 * the score's language here and means "how did they do", and spending it on "how did
 * the interview end" would put two unrelated scales on one palette. */
.meta-flag {
  padding: 0 6px;
  border: 1px solid var(--line-strong); border-radius: var(--r-xs);
  background: var(--surface-sunk); color: var(--ink-soft);
  font-size: var(--text-2xs); font-weight: 650; line-height: 1.7;
}
.meta-date {
  color: var(--ink-faint); font-size: var(--text-2xs);
  font-variant-numeric: tabular-nums;
}

/* Below a list with more than one page: "Newest" on the left, "Older" on the right.
 * Quiet buttons, because paging is navigation, not an action on the data. */
.pager { display: flex; align-items: center; margin-top: var(--sp-3); }

/* A facet pill that is also the link to its own filter. The pill carries the look;
 * the anchor only removes the default underline and adds a hover affordance, so the
 * number and the rows behind it stay one gesture apart. */
.pill-link { text-decoration: none; }
.pill-link:hover .pill { border-color: var(--accent-line); color: var(--accent-ink); }

/* The list filters: a GET form of compact selects and a Filter button. Compact is the
 * point of these overrides — the shared control rule above says width:100% and 42px,
 * which is right for a form page and turns a toolbar into a wall. */
.filterbar {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--sp-2);
  margin: 0 0 var(--sp-4);
}
.filterbar select,
.filterbar input[type="search"] {
  width: auto; max-width: 240px; min-height: 30px;
  padding-top: 4px; padding-bottom: 4px;
  font-size: var(--text-sm);
}
.filterbar input[type="search"] { width: 230px; }
@media (max-width: 640px) {
  /* width alone is not enough: the desktop max-width survives the query and clamps
   * every control to a 240px stump instead of the full-width stack this intends. */
  .filterbar select, .filterbar input[type="search"] { width: 100%; max-width: none; }
}

/* The composite in a list row, wearing its judgement colour (green ≥ 4, amber ≥ 3,
 * red below — the evidence-band thresholds). N/A is a scored interview whose record
 * holds no composite; it must not read like a low score. */
.score-num {
  font-family: var(--font-mono);
  font-size: var(--text-md);
  font-variant-numeric: tabular-nums;
  font-weight: 650;
  white-space: nowrap;
}
.score-num small { color: var(--ink-faint); font-size: var(--text-2xs); font-weight: 500; }
.score-high { color: var(--score-high-ink); }
.score-mid { color: var(--score-mid-ink); }
.score-low { color: var(--score-low-ink); }
.score-na { color: var(--ink-faint); font-weight: 500; }

/* ══ Toast ══════════════════════════════════════════════════════════════════ */

.toaster {
  position: fixed; left: 50%; bottom: var(--sp-6); z-index: var(--z-toast);
  display: grid; gap: var(--sp-2); justify-items: center;
  transform: translateX(-50%);
  pointer-events: none;
}
.toast {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-5);
  border-radius: var(--r-full);
  background: var(--n-900); color: var(--n-25);
  font-size: var(--text-md); font-weight: 620;
  box-shadow: var(--shadow-lg);
  animation: toast-in var(--t-slow) var(--ease-spring) both;
}
:root[data-theme="dark"] .toast { background: var(--n-100); color: var(--n-900); }
.toast.is-leaving { animation: toast-out var(--t-base) var(--ease-out) both; }
@keyframes toast-in  { from { opacity: 0; transform: translateY(14px) scale(.94); } }
@keyframes toast-out { to   { opacity: 0; transform: translateY(8px) scale(.97); } }

/* ══ Transcript ═════════════════════════════════════════════════════════════ */

.transcript { display: grid; gap: var(--sp-4); }
.turn {
  max-width: 76%;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--line); border-radius: var(--r-md) var(--r-md) var(--r-md) var(--r-xs);
  background: var(--surface); box-shadow: var(--shadow-xs);
  scroll-margin-top: calc(var(--header-h) + var(--sp-5));
}
.turn.candidate {
  margin-left: auto;
  border-radius: var(--r-md) var(--r-md) var(--r-xs) var(--r-md);
  background: var(--accent-wash); border-color: var(--accent-line);
}
.turn .who {
  margin-bottom: 3px;
  color: var(--ink-muted); font-size: 10px; font-weight: 750;
  letter-spacing: var(--tracking-caps); text-transform: uppercase;
}
.turn .body { white-space: pre-wrap; }
.turn.interviewer .body { color: var(--ink-soft); }

/* ══ Utilities ════════════════════════════════════════════════════════════════
 * A deliberately tiny set. They exist so that views never need a `style="…"`
 * attribute, which is what lets the Content-Security-Policy ship as
 * `style-src 'self'` with no `unsafe-inline`. If this list starts growing, the
 * answer is a component, not another utility.
 */
.mt-1 { margin-top: var(--sp-1); }
.mt-2 { margin-top: var(--sp-2); }
.mt-3 { margin-top: var(--sp-3); }
.mt-4 { margin-top: var(--sp-4); }
.mt-5 { margin-top: var(--sp-5); }
.mt-6 { margin-top: var(--sp-6); }
.mb-3 { margin-bottom: var(--sp-3); }
.mb-4 { margin-bottom: var(--sp-4); }
.grow { flex: 1 1 auto; min-width: 0; }
.between { justify-content: space-between; }
.center { justify-content: center; }
.center-text { text-align: center; }
.full { width: 100%; }
.split { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-4); }
.inline-form { display: inline; }
@media (max-width: 820px) { .split { grid-template-columns: 1fr; } }

/* A form with nothing beside it.
 *
 * `.form-grid` reserves a 296px second column for an aside. When the create form
 * lost its aside the grid kept the column, leaving the panel two-thirds width with
 * a gap where nothing was. */
.form-single {
  display: grid;
  gap: var(--sp-5);
  align-items: start;
  max-width: 900px;
}

/* The application surface: shell, components, and the two rooms.
 *
 * Two audiences, one system. The recruiter side is an instrument — dense, quiet,
 * fast, the same screen forty times a week. The candidate side is a room — wide,
 * calm, one thing at a time, seen once in a person's life on the worst-nerves day
 * of their month. They share tokens and components; they do not share density.
 */

/* ══ Shell ══════════════════════════════════════════════════════════════════ */

.topbar {
  position: sticky; top: 0; z-index: var(--z-sticky);
  background: color-mix(in srgb, var(--surface) 82%, transparent);
  -webkit-backdrop-filter: blur(20px) saturate(1.6);
  backdrop-filter: blur(20px) saturate(1.6);
  border-bottom: 1px solid var(--line);
  view-transition-name: topbar;
}
.topbar-inner {
  max-width: 1320px; margin: 0 auto;
  min-height: var(--header-h);
  padding: 0 var(--sp-6);
  display: flex; align-items: center; gap: var(--sp-5);
}
.topbar-inner.centered { max-width: 1168px; justify-content: space-between; }

.brand {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  color: var(--ink); text-decoration: none; white-space: nowrap;
  border-radius: var(--r-sm);
}
.brand:hover { color: var(--ink); }
.brand-mark {
  position: relative;
  width: 30px; height: 30px; flex: 0 0 30px;
  display: grid; place-items: center;
  border-radius: 9px 9px 9px 3px;
  background: linear-gradient(150deg, var(--a-500), var(--a-700));
  color: #fff;
  font-family: var(--font-display);
  font-size: 15px; font-weight: 760; letter-spacing: -.04em;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.28), var(--shadow-accent);
}
/* The marker stroke, folded into the logotype. */
.brand-mark::after {
  content: ""; position: absolute; left: 5px; right: 5px; bottom: 6px; height: 3px;
  border-radius: 2px; background: var(--m-300); opacity: .95;
}
.brand-copy { display: grid; line-height: 1.05; }
.brand-name {
  font-family: var(--font-display);
  font-size: var(--text-md); font-weight: 700; letter-spacing: var(--tracking-tight);
}
.brand-tagline {
  margin-top: 3px; color: var(--ink-muted);
  font-size: 9.5px; font-weight: 640;
  letter-spacing: var(--tracking-caps); text-transform: uppercase;
}

.nav { display: flex; align-items: center; gap: 2px; }
.nav a {
  position: relative;
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: 34px; padding: 0 var(--sp-3);
  border-radius: var(--r-sm);
  color: var(--ink-muted); font-size: var(--text-md); font-weight: 620;
  text-decoration: none;
  transition: color var(--t-fast) var(--ease-out), background var(--t-fast) var(--ease-out);
}
.nav a:hover { color: var(--ink); background: var(--surface-sunk); }
.nav a[aria-current="page"] { color: var(--ink); }
/* The active marker: the same amber stroke as an evidence highlight. */
.nav a[aria-current="page"]::after {
  content: ""; position: absolute; left: var(--sp-3); right: var(--sp-3); bottom: -1px;
  height: 2px; border-radius: 2px; background: var(--marker-strong);
  view-transition-name: nav-indicator;
}

.chip {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: 30px; padding: 0 var(--sp-3);
  border: 1px solid var(--line); border-radius: var(--r-full);
  background: var(--surface);
  color: var(--ink-soft); font-size: var(--text-xs); font-weight: 640;
}
.dot {
  width: 6px; height: 6px; flex: none; border-radius: var(--r-full);
  background: var(--ok-fg); box-shadow: 0 0 0 3px var(--ok-bg);
}

.icon-btn {
  display: inline-grid; place-items: center;
  width: 34px; height: 34px; padding: 0;
  border: 1px solid transparent; border-radius: var(--r-sm);
  background: transparent; color: var(--ink-muted); cursor: pointer;
  transition: color var(--t-fast) var(--ease-out), background var(--t-fast) var(--ease-out);
}
.icon-btn:hover { color: var(--ink); background: var(--surface-sunk); }

/* The theme toggle swaps which glyph is shown purely in CSS, so it never flashes
 * the wrong icon while JavaScript boots. */
.theme-toggle .i-moon { display: none; }
:root[data-theme="dark"] .theme-toggle .i-sun { display: none; }
:root[data-theme="dark"] .theme-toggle .i-moon { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .i-sun { display: none; }
  :root:not([data-theme="light"]) .theme-toggle .i-moon { display: block; }
}

.shell {
  width: min(1320px, 100% - var(--sp-10));
  margin: 0 auto;
  padding: var(--sp-8) 0 var(--sp-20);
}
.shell.narrow { width: min(760px, 100% - var(--sp-10)); }
.shell.mid    { width: min(1000px, 100% - var(--sp-10)); }
.shell.stage  { width: min(880px, 100% - var(--sp-8)); padding-top: var(--sp-10); }
.shell.candidate-shell {
  width: min(1120px, 100% - var(--sp-8));
  padding-top: var(--sp-8);
}

.page-foot {
  width: min(880px, 100% - var(--sp-8)); margin: 0 auto;
  padding: 0 0 var(--sp-10);
  color: var(--ink-muted); font-size: var(--text-xs); text-align: center;
}

/* ══ Appearance settings ═══════════════════════════════════════════════════ */

.theme-choices {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-3);
}
.theme-choice {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: var(--sp-3);
  align-items: center;
  min-width: 0;
  padding: var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-sunk);
  cursor: pointer;
  transition:
    border-color var(--t-fast) var(--ease-out),
    background var(--t-fast) var(--ease-out),
    box-shadow var(--t-fast) var(--ease-out),
    transform var(--t-fast) var(--ease-out);
}
.theme-choice:hover {
  border-color: var(--accent-line);
  background: var(--surface-raised);
  transform: translateY(-1px);
}
.theme-choice:has(input:checked) {
  border-color: var(--accent);
  background: var(--accent-wash);
  box-shadow: 0 0 0 1px var(--accent);
}
.theme-choice:has(input:focus-visible) {
  outline: 3px solid color-mix(in srgb, var(--focus) 28%, transparent);
  outline-offset: 2px;
}
.theme-choice-glyph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
  width: 38px;
  height: 38px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--accent);
  box-shadow: var(--shadow-xs);
}
.theme-choice-copy { min-width: 0; }
.theme-choice-copy b,
.theme-choice-copy span { display: block; }
.theme-choice-copy b { font-size: var(--text-sm); }
.theme-choice-copy span {
  margin-top: 2px;
  color: var(--ink-muted);
  font-size: var(--text-xs);
  line-height: 1.35;
}
.theme-choice input {
  width: 18px;
  height: 18px;
  min-height: 18px;
  margin: 0;
  padding: 0;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-full);
  box-shadow: none;
  accent-color: var(--accent);
}
.theme-choice input:focus { box-shadow: none; }
.theme-settings-hint { margin: var(--sp-3) 0 0; }

@media (max-width: 660px) {
  .theme-choices { grid-template-columns: 1fr; }
}

/* ══ Page heading ═══════════════════════════════════════════════════════════ */

.page-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--sp-6); margin-bottom: var(--sp-6);
}
.page-head-copy { flex: 1 1 auto; min-width: 0; max-width: 66ch; }
.page-head h1 { view-transition-name: page-title; }
.page-head .lede {
  margin: var(--sp-3) 0 0;
  color: var(--ink-soft); font-size: var(--text-lg); line-height: 1.55;
}
.page-head-actions { display: flex; gap: var(--sp-2); flex-wrap: wrap; justify-content: flex-end; }
.crumb {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  margin-bottom: var(--sp-3);
  color: var(--ink-muted); font-size: var(--text-sm); font-weight: 600; text-decoration: none;
}
.crumb:hover { color: var(--ink); }

.section { margin-top: var(--sp-10); }
.section-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--sp-5); margin-bottom: var(--sp-4);
}
.section-head h2 { font-size: var(--text-lg); }
.section-head p { margin: 3px 0 0; color: var(--ink-muted); font-size: var(--text-sm); }

/* ══ Metrics ══════════════════════════════════════════════════════════════════
 * A quiet strip, not three billboards. A number nobody acts on does not deserve
 * 30px of type; these are calibration, read in half a second and moved past.
 */
.metrics {
  display: flex; flex-wrap: wrap;
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface); box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.metric {
  flex: 1 1 150px; min-width: 0;
  padding: var(--sp-4) var(--sp-5);
  border-left: 1px solid var(--line);
  text-decoration: none; color: inherit;
  transition: background var(--t-fast) var(--ease-out);
}
.metric:first-child { border-left: 0; }
a.metric:hover { background: var(--surface-sunk); color: inherit; }
.metric-value {
  display: block;
  font-family: var(--font-display);
  font-size: var(--text-2xl); font-weight: 660; letter-spacing: var(--tracking-tight);
  line-height: 1.1;
}
.metric-label { display: block; margin-top: 3px; color: var(--ink-muted); font-size: var(--text-sm); }
.metric.is-actionable .metric-value { color: var(--accent); }

/* ══ Stream: the roles / candidates list ══════════════════════════════════════
 * A table is the wrong shape for six rows that each carry a funnel, a status and
 * a date. These rows are cards you click anywhere on; the visible link stays a
 * real anchor so keyboard and middle-click still behave.
 */
.stream { display: grid; gap: var(--sp-2); }
.stream-item {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center; gap: var(--sp-5);
  padding: var(--sp-4) var(--sp-5);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface); box-shadow: var(--shadow-xs);
  transition:
    border-color var(--t-base) var(--ease-out),
    box-shadow var(--t-base) var(--ease-out),
    transform var(--t-base) var(--ease-out);
}
.stream-item:hover {
  border-color: var(--accent-line);
  box-shadow: var(--shadow-lift);
  transform: translateY(-1px);
}
.stream-item:has(a:focus-visible) { border-color: var(--accent); }
.stream-title {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  color: var(--ink); font-size: var(--text-base); font-weight: 660;
  letter-spacing: var(--tracking-snug); text-decoration: none;
}
/* The whole row is the target; the anchor still owns the semantics. */
.stream-title::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.stream-title:hover { color: var(--accent); }
.stream-meta { margin-top: 2px; color: var(--ink-muted); font-size: var(--text-xs); }
.stream-go { color: var(--ink-faint); transition: transform var(--t-base) var(--ease-out), color var(--t-base) var(--ease-out); }
.stream-item:hover .stream-go { color: var(--accent); transform: translateX(3px); }
.stream-end { gap: var(--sp-3); flex-wrap: nowrap; }

/* A five-segment funnel: invited → started → completed. Tiny, but it answers
 * "where is this role actually stuck" without opening it. */
.funnel { display: flex; align-items: center; gap: var(--sp-4); }
.funnel-step { text-align: right; }
.funnel-step b {
  display: block; font-size: var(--text-md); font-weight: 660; line-height: 1.2;
  font-variant-numeric: tabular-nums;
}
.funnel-step span {
  display: block; color: var(--ink-muted);
  font-size: 10px; font-weight: 650;
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
}
.funnel-step.is-zero b { color: var(--ink-muted); font-weight: 500; }

/* ══ Attention band ═══════════════════════════════════════════════════════════
 * The one thing the home page exists for: what is waiting on a human. It only
 * renders when there is something in it.
 */
.attention {
  border: 1px solid var(--accent-line); border-radius: var(--r-lg);
  background:
    linear-gradient(180deg, var(--accent-wash), color-mix(in srgb, var(--accent-wash) 30%, var(--surface)));
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.attention-head {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid color-mix(in srgb, var(--accent-line) 60%, transparent);
}
.attention-head h2 { font-size: var(--text-md); font-weight: 680; }
.attention-list { display: grid; }
.attention-row {
  display: flex; align-items: center; gap: var(--sp-4);
  padding: var(--sp-3) var(--sp-5);
  border-top: 1px solid color-mix(in srgb, var(--accent-line) 40%, transparent);
  background: color-mix(in srgb, var(--surface) 70%, transparent);
  transition: background var(--t-fast) var(--ease-out);
}
.attention-row:first-child { border-top: 0; }
.attention-row:hover { background: var(--surface); }
.attention-row .who { font-weight: 640; }

/* ══ Steps ══════════════════════════════════════════════════════════════════ */

.steps {
  display: flex; align-items: center;
  margin: 0 0 var(--sp-8); padding: 0; list-style: none;
}
.steps li {
  position: relative;
  display: flex; align-items: center; gap: var(--sp-2);
  color: var(--ink-muted); font-size: var(--text-sm); font-weight: 620; white-space: nowrap;
}
.steps li:not(:last-child) { flex: 1; }
.steps li:not(:last-child)::after {
  content: ""; flex: 1; min-width: var(--sp-4); height: 2px;
  margin: 0 var(--sp-3); border-radius: 2px; background: var(--line);
}
.step-n {
  width: 24px; height: 24px; flex: 0 0 24px;
  display: grid; place-items: center;
  border: 1.5px solid var(--line-strong); border-radius: var(--r-full);
  background: var(--surface);
  font-size: var(--text-xs); font-weight: 700;
}
.steps li.done { color: var(--ink-soft); }
.steps li.done .step-n { border-color: var(--accent); background: var(--accent-wash); color: var(--accent-ink); }
.steps li.done:not(:last-child)::after { background: var(--accent-line); }
.steps li.now { color: var(--ink); }
.steps li.now .step-n {
  border-color: var(--accent); background: var(--accent); color: var(--on-accent);
  box-shadow: 0 0 0 4px var(--accent-wash);
}

/* ══ Tabs ═══════════════════════════════════════════════════════════════════
 * Sibling pages of one object. The rail says which product you are in; these say
 * which part of one role you are looking at.
 *
 * They replaced `.steps` on the role page. A published role with forty candidates
 * was still rendering a three-step setup wizard with "Invite candidates" lit,
 * which is the product insisting you are still building something you finished
 * months ago.
 */

.tabs {
  /* Pinned under the appbar. A tab body can run long — the Q&A tab is six
   * textareas — and a tab bar that scrolls away is a page you can only leave by
   * scrolling back to the top of it. `top` is the appbar's own height. */
  position: sticky;
  top: 52px;
  z-index: 20;
  display: flex;
  gap: var(--sp-1);
  margin: 0 0 var(--sp-8);
  padding-top: var(--sp-1);
  background: var(--canvas);
  border-bottom: 1px solid var(--line);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }

.tab {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-3) calc(var(--sp-3) - 1px);
  margin-bottom: -1px;
  border-bottom: 2px solid transparent;
  color: var(--ink-muted);
  font-size: var(--text-md); font-weight: 570;
  text-decoration: none; white-space: nowrap;
  transition: color var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out);
}
.tab:hover { color: var(--ink); }
.tab[aria-current="page"] { color: var(--accent-ink); border-bottom-color: var(--accent); }

.tab-count {
  padding: 1px var(--sp-2);
  border-radius: var(--r-full);
  background: var(--canvas-deep);
  color: var(--ink-muted);
  font-size: var(--text-2xs); font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.tab[aria-current="page"] .tab-count { background: var(--accent-wash); color: var(--accent-ink); }

/* The one-line state summary above a tab's table. Facts, not calls to action —
 * the actionable one is a button in the row it belongs to. */
.tab-summary {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
  margin: 0 0 var(--sp-4);
}

/* ── The role's Q&A ─────────────────────────────────────────────────────────
 * Two borrowed defaults that are wrong here and right elsewhere. `.panel` is a
 * border, a radius and nothing else — every other user of it brings its own
 * padding, and this form was not bringing any. And `components.css` puts a 220px
 * floor under every textarea, which is correct for pasting a job description and
 * absurd for one line about a notice period: six of them made a page you had to
 * scroll past the tab bar to get out of.
 */
.faq-form { padding: var(--sp-5) var(--sp-5) var(--sp-4); }
.faq-form textarea {
  min-height: 4.6em;
  line-height: 1.5;
  resize: vertical;
}

/* ══ Rubric composer ════════════════════════════════════════════════════════
 * The bar and its segments moved to `frontend/src/composer/Composer.module.css`,
 * where the class names are local and cannot collide with anything here.
 *
 * The row styles below stay. They are not leftovers: the server renders the same
 * checkboxes and sliders inside the React root as a fallback, so a browser that
 * never runs the bundle still selects competencies and still publishes — and that
 * fallback has to look like the product. `.comp` is also still used on its own by
 * the competency detail page.
 */

.comp-list { display: grid; gap: var(--sp-2); }
.comp {
  display: grid; grid-template-columns: 22px minmax(0, 1fr) 172px;
  gap: var(--sp-4); align-items: start;
  padding: var(--sp-4) var(--sp-5);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface);
  transition:
    border-color var(--t-base) var(--ease-out),
    background var(--t-base) var(--ease-out),
    box-shadow var(--t-base) var(--ease-out),
    opacity var(--t-base) var(--ease-out);
}
.comp:hover { border-color: var(--line-strong); }
.comp:has(input[type="checkbox"]:checked) {
  border-color: var(--accent-line);
  background: color-mix(in srgb, var(--accent-wash) 45%, var(--surface));
  box-shadow: var(--shadow-sm);
}
.comp:not(:has(input[type="checkbox"]:checked)) { opacity: .62; }
.comp:not(:has(input[type="checkbox"]:checked)) .weight-field { opacity: .4; pointer-events: none; }
.comp:has(input[type="checkbox"]:focus-visible) { border-color: var(--accent); }
.comp input[type="checkbox"] { width: 20px; height: 20px; margin: 1px 0 0; cursor: pointer; }
.comp-main { min-width: 0; }
.comp-head { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.comp-head label { cursor: pointer; font-weight: 660; }

.quote {
  display: block; margin-top: var(--sp-3);
  padding-left: var(--sp-3);
  border-left: 2px solid var(--marker-strong);
  color: var(--ink-soft); font-size: var(--text-sm); font-style: italic;
}

/* ── Question editor ────────────────────────────────────────────────────────
 * Spans the whole competency row rather than sitting in a column: a question is
 * a paragraph of prose, and 172px of it is not editable in any useful sense.
 * Collapsed by default so the rubric stays scannable — a recruiter choosing what
 * to assess is not yet reading questions, and six open blocks bury the weights.
 */
.q-block { grid-column: 1 / -1; margin-top: var(--sp-3); }
.q-block > summary {
  display: flex; align-items: baseline; gap: var(--sp-2);
  padding: var(--sp-2) 0; cursor: pointer;
  font-size: var(--text-sm); font-weight: 660; color: var(--ink-soft);
}
.q-block > summary::marker { color: var(--ink-muted); }
.q-block[open] > summary { margin-bottom: var(--sp-2); }
.comp:not(:has(input[type="checkbox"]:checked)) .q-block { opacity: .5; }

/* ── Bookends: the words at either end of the conversation ─────────────────
 * Not collapsed, unlike the rubric and question blocks. There are exactly two of
 * them, they are short, and they are the cheapest thing on this page to review —
 * hiding them behind a disclosure triangle would mean most recruiters publish an
 * opening they never read.
 */
.bookend {
  width: 100%; font: inherit; line-height: 1.6; resize: vertical;
  min-height: 6em;
}

/* ── Rubric editor ──────────────────────────────────────────────────────────
 * Shown only for a generated competency, and collapsed for the same reason the
 * question block is: a recruiter deciding *what* to assess is not yet reading a
 * rating scale, and five open anchor grids bury the weights they came for.
 *
 * It borrows `.q-block`'s summary styling rather than restating it — the two are
 * the same affordance on the same row, and they should not drift apart.
 */
.rubric-block { grid-column: 1 / -1; margin-top: var(--sp-3); }
.rubric-block > summary {
  display: flex; align-items: baseline; gap: var(--sp-2);
  padding: var(--sp-2) 0; cursor: pointer;
  font-size: var(--text-sm); font-weight: 660; color: var(--ink-soft);
}
.rubric-block > summary::marker { color: var(--ink-muted); }
.rubric-block[open] > summary { margin-bottom: var(--sp-2); }
.comp:not(:has(input[type="checkbox"]:checked)) .rubric-block { opacity: .5; }
.rubric-block textarea { width: 100%; font: inherit; line-height: 1.5; resize: vertical; }
/* Same override as `.q-text`: the 220px floor in `components.css` is for pasting a
 * posting, and it turns a two-line definition into a page of empty box. */
.rubric-block textarea { min-height: 4.6em; }

.indicator-pair { display: grid; gap: var(--sp-3); grid-template-columns: repeat(2, minmax(0, 1fr)); }

.anchor-head {
  display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap;
  margin: var(--sp-4) 0 var(--sp-2);
  font-size: var(--text-sm);
}
.anchor-list { display: grid; gap: var(--sp-2); }
.anchor-row {
  display: grid; grid-template-columns: 8.5em minmax(0, 1fr); gap: var(--sp-3);
  padding: var(--sp-3); border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface-sunk);
}
/* The number is the thing being scanned down the column when someone checks that
 * level 4 really does describe more than level 3, so it leads and it is large. */
.anchor-level { display: flex; align-items: baseline; gap: var(--sp-2); }
.anchor-num {
  font-size: var(--text-lg); font-weight: 700; font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.anchor-name { color: var(--ink-muted); font-size: var(--text-sm); }
.anchor-fields { display: grid; gap: var(--sp-2); min-width: 0; }
.anchor-desc, .anchor-ex { min-height: 4.6em; }
/* Scoped past `.rubric-block textarea` on purpose. That rule sets `font: inherit`, and
 * the shorthand resets `font-style` — so the plain `.anchor-ex` selector lost the italic
 * to a rule that never mentions it. The examples are quotes in the candidate's voice and
 * have to read differently from the descriptor above them, which is the recruiter's. */
.rubric-block .anchor-ex { color: var(--ink-soft); font-style: italic; }

@media (max-width: 640px) {
  .indicator-pair { grid-template-columns: minmax(0, 1fr); }
  .anchor-row { grid-template-columns: minmax(0, 1fr); gap: var(--sp-2); }
}

.q-list, .fu-list, .el-list { display: grid; gap: var(--sp-3); }
.q-row {
  padding: var(--sp-3); border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface-sunk);
}
.q-row-head, .q-row-foot {
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
}
.q-row-head { justify-content: space-between; margin-bottom: var(--sp-2); }
.q-row-foot { margin-top: var(--sp-2); }
.q-row-foot .quote { flex-basis: 100%; margin-top: var(--sp-2); }
/* `components.css` gives every textarea a 220px floor, which is right for pasting a job
 * description and absurd for a one-sentence question — ten questions on screen became a
 * page of empty boxes. Sized to the two rows the markup asks for, still draggable. */
.q-text {
  width: 100%; font: inherit; line-height: 1.5; resize: vertical;
  min-height: 4.6em;
}
.q-flag {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  color: var(--ink-muted); font-size: var(--text-sm); white-space: nowrap;
}
.q-flag input[type="number"] { width: 5.5em; }
.q-flag input[type="checkbox"] { width: 16px; height: 16px; margin: 0; }

.fu-head {
  display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap;
  margin: var(--sp-4) 0 var(--sp-2);
  font-size: var(--text-sm);
}
.fu-row { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.fu-text { flex: 1 1 22em; min-width: 0; }
.fu-kind { flex: 0 0 16em; }

.el-row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--sp-2);
  padding: var(--sp-3); border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface-sunk);
}
.el-knock { grid-column: 1 / -1; display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.el-exp { flex: 0 1 16em; }
/* The justification only matters once the question is disqualifying, and an
 * always-visible field for a rarely-used flag is a field people fill in wrongly. */
.el-why { grid-column: 1 / -1; display: none; }
.el-row:has(.el-knock-box:checked) .el-why { display: block; }
.el-row.needs-why { border-color: var(--warn-line); }

@media (max-width: 640px) {
  .fu-text, .fu-kind { flex-basis: 100%; }
  .el-row { grid-template-columns: minmax(0, 1fr); }
}

.weight-field { transition: opacity var(--t-base) var(--ease-out); }
.weight-head {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-bottom: var(--sp-1);
}
.weight-head label {
  color: var(--ink-muted); font-size: 10px; font-weight: 700;
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
}
.weight-out {
  font-size: var(--text-md); font-weight: 680; font-variant-numeric: tabular-nums;
  color: var(--accent-ink);
}

input[type="range"] {
  -webkit-appearance: none; appearance: none;
  width: 100%; min-height: 0; height: 20px;
  padding: 0; border: 0; background: transparent; box-shadow: none;
  cursor: grab;
}
input[type="range"]:active { cursor: grabbing; }
input[type="range"]::-webkit-slider-runnable-track {
  height: 5px; border-radius: var(--r-full); background: var(--line-strong);
}
input[type="range"]::-moz-range-track {
  height: 5px; border-radius: var(--r-full); background: var(--line-strong);
}
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 16px; height: 16px; margin-top: -5.5px;
  border: 2px solid var(--surface); border-radius: var(--r-full);
  background: var(--accent);
  box-shadow: var(--shadow-sm);
  transition: transform var(--t-fast) var(--ease-out);
}
input[type="range"]::-moz-range-thumb {
  width: 16px; height: 16px;
  border: 2px solid var(--surface); border-radius: var(--r-full);
  background: var(--accent); box-shadow: var(--shadow-sm);
}
input[type="range"]:hover::-webkit-slider-thumb { transform: scale(1.15); }
input[type="range"]:focus-visible::-webkit-slider-thumb { transform: scale(1.15); }

/* ══ Invite links ═══════════════════════════════════════════════════════════ */

.linkbox {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-3);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface-sunk);
}
.linkbox code {
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--ink-soft); font-size: var(--text-xs);
}
.invite-form {
  display: grid; grid-template-columns: minmax(200px, 1fr) auto;
  gap: var(--sp-3); align-items: end;
  padding: var(--sp-4) var(--sp-5);
  background: var(--surface-sunk); border-bottom: 1px solid var(--line);
}
.invite-form .field { margin: 0; }

/* ══ Candidate: the landing ═══════════════════════════════════════════════════
 * Wide, quiet, and deliberately unlike the workspace. Someone arrives here
 * nervous and alone; the page should feel like a well-lit room, not a form.
 */
.candidate-body {
  background:
    radial-gradient(1100px 600px at 50% -240px, var(--accent-wash), transparent 68%),
    radial-gradient(700px 400px at 88% 8%, color-mix(in srgb, var(--marker) 26%, transparent), transparent 62%),
    var(--canvas);
  background-attachment: fixed;
}
.candidate-hero { text-align: center; margin-bottom: var(--sp-8); }
.candidate-hero h1 {
  max-width: 20ch; margin: 0 auto;
  font-size: var(--text-4xl); font-weight: 660; line-height: 1.08;
}
.candidate-hero .lede {
  max-width: 54ch; margin: var(--sp-4) auto 0;
  color: var(--ink-soft); font-size: var(--text-lg); line-height: 1.6;
}
.candidate-tag {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  margin-bottom: var(--sp-5); padding: 5px var(--sp-3);
  border: 1px solid var(--accent-line); border-radius: var(--r-full);
  background: color-mix(in srgb, var(--surface) 70%, transparent);
  color: var(--accent-ink); font-size: var(--text-xs); font-weight: 660;
}

/* The invitation has the visual grammar of a meeting link: role and private-room
 * preview on the left, identity and consent on the right. The preview is deliberately
 * inert — the real device controls belong to the lobby on the next screen. */
.candidate-entry {
  display: grid;
  grid-template-columns: minmax(0, 1.12fr) minmax(380px, .88fr);
  gap: clamp(var(--sp-8), 4vw, var(--sp-12));
  align-items: start;
  min-height: calc(100dvh - var(--header-h) - 132px);
  padding: var(--sp-5) 0 var(--sp-10);
}
.candidate-entry-copy { min-width: 0; }
.candidate-entry-copy h1 {
  max-width: 16ch;
  margin: 0;
  font-size: var(--text-4xl);
  font-weight: 680;
  line-height: 1.06;
  letter-spacing: var(--tracking-tight);
}
.candidate-role-meta {
  max-width: 38ch;
  margin: var(--sp-3) 0 var(--sp-5);
  color: var(--ink-soft);
  font-size: var(--text-lg);
  line-height: 1.5;
}
.candidate-meeting-meta {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
}
.candidate-meeting-meta > span {
  display: inline-flex;
  min-height: 32px;
  align-items: center;
  gap: 7px;
  padding: 0 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-full);
  background: color-mix(in srgb, var(--surface) 70%, transparent);
  color: var(--ink-soft);
  font-size: var(--text-xs);
  font-weight: 630;
  white-space: nowrap;
}
.candidate-meeting-meta .i { color: var(--accent); }

.candidate-call-preview {
  position: relative;
  aspect-ratio: 16 / 9;
  min-height: 280px;
  margin-top: var(--sp-6);
  overflow: hidden;
  pointer-events: none;
  border: 1px solid color-mix(in srgb, var(--a-300) 30%, var(--n-800));
  border-radius: var(--r-xl);
  background:
    radial-gradient(circle at 50% 44%, rgba(39, 161, 142, .2), transparent 34%),
    radial-gradient(circle at 7% 96%, rgba(85, 191, 171, .12), transparent 32%),
    linear-gradient(145deg, #12231f, #0b1513 72%);
  color: #f5fbf9;
  box-shadow: 0 24px 54px rgba(13, 22, 20, .18);
  isolation: isolate;
}
.candidate-call-preview::before {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(255,255,255,.025) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.025) 1px, transparent 1px);
  background-size: 36px 36px;
  content: "";
  -webkit-mask-image: linear-gradient(to bottom, rgba(0,0,0,.7), transparent 72%);
  mask-image: linear-gradient(to bottom, rgba(0,0,0,.7), transparent 72%);
}
.candidate-call-top {
  position: absolute;
  top: var(--sp-4);
  right: var(--sp-4);
  left: var(--sp-4);
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  color: #a9c0ba;
  font-size: var(--text-2xs);
  font-weight: 650;
  letter-spacing: .02em;
}
.candidate-call-top > span {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.candidate-call-top > span:first-child { color: #d9eee9; }
.candidate-call-stage {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: grid;
  place-content: center;
  justify-items: center;
  text-align: center;
}
.candidate-call-orb {
  position: relative;
  display: grid;
  width: 88px;
  height: 88px;
  place-items: center;
  margin-bottom: var(--sp-4);
  border: 1px solid rgba(255,255,255,.22);
  border-radius: var(--r-full);
  background:
    radial-gradient(circle at 34% 28%, rgba(255,255,255,.38), transparent 46%),
    linear-gradient(155deg, var(--a-300), var(--a-600));
  color: #fff;
  box-shadow:
    0 0 0 12px rgba(39,161,142,.08),
    0 18px 46px rgba(14,122,109,.3);
  animation: breathe 4.2s var(--ease-in-out) infinite;
}
.candidate-call-orb::before,
.candidate-call-orb::after {
  position: absolute;
  border: 1px solid rgba(142,216,200,.18);
  border-radius: var(--r-full);
  content: "";
}
.candidate-call-orb::before { inset: -20px; }
.candidate-call-orb::after { inset: -36px; opacity: .55; }
.candidate-call-stage b { font-size: var(--text-base); }
.candidate-call-stage small {
  margin-top: 3px;
  color: #9fb6b0;
  font-size: var(--text-2xs);
}
.candidate-self-preview {
  position: absolute;
  right: var(--sp-4);
  bottom: var(--sp-4);
  z-index: 2;
  display: grid;
  width: 112px;
  height: 72px;
  place-content: center;
  justify-items: center;
  gap: 5px;
  border: 1px solid rgba(255,255,255,.12);
  border-radius: var(--r-md);
  background: rgba(255,255,255,.07);
  box-shadow: 0 12px 26px rgba(0,0,0,.18);
  color: #d8e7e3;
}
.candidate-self-preview > span {
  display: grid;
  width: 32px;
  height: 32px;
  place-items: center;
  border-radius: var(--r-full);
  background: rgba(255,255,255,.1);
}
.candidate-self-preview small { color: #a9bbb6; font-size: 10px; }

.candidate-join-card {
  position: relative;
  min-width: 0;
  overflow: hidden;
  padding: clamp(var(--sp-6), 3vw, var(--sp-8));
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  background: var(--surface-raised);
  box-shadow: var(--shadow-lg);
}
.candidate-join-card::before {
  position: absolute;
  top: 0;
  right: var(--sp-8);
  left: var(--sp-8);
  height: 3px;
  border-radius: 0 0 var(--r-full) var(--r-full);
  background: linear-gradient(90deg, var(--a-600), var(--a-300));
  content: "";
}
.candidate-join-head { margin-bottom: var(--sp-5); }
.candidate-join-head h2 {
  margin: 0;
  font-size: var(--text-2xl);
  letter-spacing: var(--tracking-tight);
}
.candidate-join-head p {
  margin: var(--sp-1) 0 0;
  color: var(--ink-muted);
  font-size: var(--text-sm);
}
.candidate-fields {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-4);
}
.candidate-fields .field { margin: 0; }
.candidate-field-wide { grid-column: 1 / -1; }
.candidate-consent-launch {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: var(--sp-3);
  align-items: center;
  margin-top: var(--sp-4);
  padding: var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface-sunk);
}
.candidate-consent-icon {
  display: grid;
  width: 34px;
  height: 34px;
  place-items: center;
  border-radius: var(--r-sm);
  background: var(--accent-wash);
  color: var(--accent-ink);
}
.candidate-consent-label { display: grid; gap: 1px; min-width: 0; }
.candidate-consent-label b { font-size: var(--text-sm); line-height: 1.35; }
.candidate-consent-label small {
  color: var(--ink-muted);
  font-size: var(--text-2xs);
  line-height: 1.35;
}
.candidate-consent-launch[data-consent-complete="true"] {
  border-color: var(--ok-line);
  background: var(--ok-bg);
}
.candidate-consent-launch[data-consent-complete="true"] .candidate-consent-icon {
  background: color-mix(in srgb, var(--ok-fg) 14%, transparent);
  color: var(--ok-fg);
}
.candidate-consent-launch[data-consent-complete="true"] .candidate-consent-label small {
  color: var(--ok-fg);
}
.candidate-consent-dialog {
  position: fixed;
  inset: 50% auto auto 50%;
  width: min(640px, calc(100% - var(--sp-8)));
  max-width: none;
  max-height: calc(100dvh - var(--sp-8));
  margin: 0;
  padding: 0;
  overflow: hidden;
  transform: translate(-50%, -50%);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-lg);
  background: var(--surface-raised);
  color: var(--ink);
  box-shadow: var(--shadow-lift);
}
.candidate-consent-dialog[open] {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
}
.candidate-consent-dialog::backdrop {
  background: rgba(4, 18, 16, .58);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}
.candidate-consent-modal-head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: var(--sp-3);
  align-items: center;
  padding: var(--sp-5) var(--sp-6);
  border-bottom: 1px solid var(--line);
}
.candidate-consent-modal-head > span { color: var(--accent); }
.candidate-consent-modal-head p {
  margin: 0 0 2px;
  color: var(--ink-muted);
  font-size: var(--text-2xs);
  font-weight: 680;
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
}
.candidate-consent-modal-head h2 {
  margin: 0;
  font-size: var(--text-xl);
  letter-spacing: var(--tracking-tight);
}
.candidate-consent-modal-copy {
  min-height: 0;
  overflow: auto;
  padding: var(--sp-6);
  color: var(--ink-soft);
  font-size: var(--text-sm);
  line-height: 1.7;
}
.candidate-consent-modal-copy p { margin: 0; }
.candidate-consent-modal-copy p + p { margin-top: var(--sp-4); }
.candidate-consent-modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-6);
  border-top: 1px solid var(--line);
  background: var(--surface-sunk);
}
.candidate-join-action { margin-top: var(--sp-4); }

.expectations {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-3); margin-bottom: var(--sp-6);
}
.expectation {
  padding: var(--sp-4);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: color-mix(in srgb, var(--surface) 76%, transparent);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
.expectation-mark {
  width: 28px; height: 28px; margin-bottom: var(--sp-3);
  display: grid; place-items: center; border-radius: var(--r-xs);
  background: var(--accent-wash); color: var(--accent-ink);
}
.expectation b { display: block; font-size: var(--text-md); font-weight: 660; }
.expectation span { color: var(--ink-muted); font-size: var(--text-xs); line-height: 1.5; }

.candidate-card {
  padding: clamp(var(--sp-5), 4vw, var(--sp-10));
  border: 1px solid var(--line); border-radius: var(--r-xl);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
}

/* ── Consent, on the page rather than in the recording ──────────────────────
 * The disclosure used to be spoken forty seconds into a live room, into the
 * recording it was disclosing. Here it is read, before anything is captured, and
 * it can be re-read — which a spoken one never can.
 *
 * Styled quieter than the card below it on purpose. Nothing here is trying to be
 * persuasive; it is the page being straight with someone, and a legal notice
 * dressed up as a call to action reads as a trick.
 */
.consent-card {
  padding: clamp(var(--sp-5), 4vw, var(--sp-8));
  margin-bottom: var(--sp-5);
  border: 1px solid var(--line); border-radius: var(--r-xl);
  background: var(--surface-sunk);
}
.consent-card h2 { font-size: var(--text-lg); margin-bottom: var(--sp-4); }
.disclosure {
  padding: var(--sp-4);
  margin-bottom: var(--sp-4);
  border-left: 2px solid var(--marker-strong);
  background: var(--surface);
  color: var(--ink-soft);
  font-size: var(--text-sm); line-height: 1.7;
}

.adjust-set { border: 0; padding: 0; margin: var(--sp-5) 0 0; }
.adjust-set legend { font-weight: 660; padding: 0; }
.adjust-list {
  display: grid; gap: var(--sp-2); margin-top: var(--sp-3);
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}
.adjust {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  padding: var(--sp-3);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface);
  cursor: pointer;
  transition: border-color var(--t-base) var(--ease-out);
}
.adjust:hover { border-color: var(--line-strong); }
.adjust:has(input:checked) { border-color: var(--accent-line); background: var(--accent-wash); }
.adjust input { width: 18px; height: 18px; margin: 2px 0 0; flex: none; }
.adjust b { display: block; font-size: var(--text-sm); font-weight: 660; }
.adjust small { color: var(--ink-muted); font-size: var(--text-xs); line-height: 1.5; }

/* The one control on this page that must not be missable, and must not be
 * pre-ticked. Given its own weight for that reason and no other. */
.consent-check {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  margin-top: var(--sp-5); padding: var(--sp-4);
  border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  background: var(--surface);
  cursor: pointer; font-weight: 600;
}
.consent-check input { width: 20px; height: 20px; margin: 1px 0 0; flex: none; }
.consent-card:has(#consent:checked) .consent-check { border-color: var(--accent); }

/* Hidden until the interview ends, and then the only thing worth reading. */
.afterword {
  max-width: 34rem; margin: var(--sp-5) auto 0;
  padding: var(--sp-4);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface-sunk);
  color: var(--ink-soft); font-size: var(--text-sm); line-height: 1.7;
  text-align: left;
}
.afterword p + p { margin-top: var(--sp-2); }

/* ══ Candidate: the room ═════════════════════════════════════════════════════
 * The orb is the whole interface. It is not decoration: a candidate's first and
 * loudest question in a voice interview is "can it hear me?", and an orb that
 * moves with their own voice answers it continuously without a word of copy.
 */
/* Playback on the session page. Watched by people; never read by a model. */
.playback {
  display: block;
  width: 100%;
  max-height: 55vh;
  border-radius: var(--r-md);
  background: var(--n-950, #0d1614);
}

/* ══ Candidate: the stage ════════════════════════════════════════════════════
 * Two participants, a timer, one button. Everything that was explanation now
 * lives on the page before this one — once someone is talking to a machine about
 * their career, text on screen is competition, not help.
 *
 * The dimming is the whole mechanism: at a glance, from across a room, it is
 * obvious whose turn it is. `interview.js` sets data-speaking from the audio.
 */
.stage {
  min-height: 100dvh;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: var(--sp-10);
  padding: var(--sp-8) var(--sp-5);
}

.stage-parties {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(var(--sp-4), 4vw, var(--sp-8));
  align-items: start;
  /* `align-self: stretch` is load-bearing: the parent centres its children, which
   * shrink-wraps them, and the tiles came out at 154px instead of filling the row. */
  align-self: stretch;
  width: 100%; max-width: 820px;
  margin-inline: auto;
}

/* The tile is a fixed frame that never moves, resizes, or fades.
 *
 * The first version dimmed the inactive party and lifted the active one. Both were
 * wrong: dimming made the candidate's own face look switched off whenever they paused,
 * and the lift meant the layout twitched with every sound in the room. What is left is
 * a border that lights — the block stays exactly where it is, the same size, at full
 * brightness, and only its edge says whose turn it is.
 */
.party {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-3);
}
.party-frame {
  width: 100%;
  aspect-ratio: 4 / 3;
  display: grid; place-items: center;
  border-radius: var(--r-lg);
  border: 2px solid var(--line);
  background: var(--surface-sunk);
  overflow: hidden;
  min-height: 200px;
  transition: border-color var(--dur-3, .25s) var(--ease-out, ease),
              box-shadow var(--dur-3, .25s) var(--ease-out, ease);
}
.party[data-speaking="true"] .party-frame {
  border-color: var(--a-400);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--a-400) 18%, transparent);
}

.party-name {
  font-weight: 600; letter-spacing: var(--tracking-snug);
  font-size: var(--text-base);
}
.party-state {
  font-size: var(--text-2xs); font-weight: 640;
  letter-spacing: var(--tracking-caps); text-transform: uppercase;
  color: var(--ink-muted);
}
.party[data-speaking="true"] .party-state { color: var(--a-500); }

.party-initial {
  font-family: var(--font-display);
  font-size: 3rem; font-weight: 600; color: var(--ink-muted);
}

/* Inside the frame both parties fill it identically, so the two blocks are the same
 * shape whether one of them is a video and the other an orb. */
.party-frame .selfview,
.party-frame video {
  width: 100%; height: 100%;
  margin: 0; border-radius: 0; box-shadow: none;
  object-fit: cover;
}
.party-frame .orb { margin: 0; width: 62%; height: 62%; max-width: 190px; max-height: 190px; }

/* The initial stands in until the camera is live, so the candidate's tile is never
 * an empty box — before start, and for anyone who declines the camera. */
.party-frame .selfview[hidden] + .party-initial,
.party-frame .party-initial { display: block; }
.party-frame:has(.selfview:not([hidden])) .party-initial { display: none; }

.stage-controls {
  display: flex; align-items: center; justify-content: center;
  gap: var(--sp-3); flex-wrap: wrap;
}

.stage-status {
  font-size: var(--text-md); color: var(--ink-muted);
  text-align: center; max-width: 46ch; min-height: 1.4em;
}

@media (max-width: 560px) {
  .stage-parties { gap: var(--sp-4); }
  .party-initial { font-size: 2.2rem; }
  .party-frame .orb { width: 104px; height: 104px; }
}

@media (prefers-reduced-motion: reduce) {
  .party-frame { transition: none; }
}

.room { text-align: center; }

/* The self-view sits under the orb rather than replacing it. The orb answers "can
 * it hear me?" and the video answers "can it see me?" — two different anxieties,
 * and the audio one is the one that decides whether the interview works. Mirrored,
 * because an un-mirrored self-view reads as someone else's face. */
.selfview {
  display: block;
  width: min(280px, 60%);
  aspect-ratio: 4 / 3;
  margin: 0 auto var(--sp-6);
  border-radius: var(--r-lg);
  background: var(--n-900);
  object-fit: cover;
  transform: scaleX(-1);
  box-shadow: var(--shadow-md);
}
.selfview[hidden] { display: none; }

#camera-toggle[data-on] { border-color: var(--line-strong); }

.orb {
  --level: 0;              /* 0…1, written from the mic analyser  */
  --agent: 0;              /* 0…1, written from the agent's audio */
  position: relative;
  width: 200px; height: 200px;
  margin: var(--sp-6) auto var(--sp-8);
  display: grid; place-items: center;
  isolation: isolate;
}
.orb-aura {
  position: absolute; inset: -14%;
  border-radius: 50%;
  background: conic-gradient(from 0deg,
    var(--a-300), var(--m-300), var(--a-400), var(--a-200), var(--a-300));
  filter: blur(26px);
  opacity: calc(.20 + var(--level) * .5);
  transform: scale(calc(.86 + var(--level) * .2));
  animation: orb-spin 14s linear infinite;
  transition: opacity 90ms linear, transform 90ms linear;
}
@keyframes orb-spin { to { transform: rotate(360deg); } }

.orb-core {
  position: relative; z-index: 2;
  width: 118px; height: 118px;
  display: grid; place-items: center;
  border-radius: 50%;
  background:
    radial-gradient(circle at 34% 28%, color-mix(in srgb, var(--surface) 92%, transparent), transparent 58%),
    linear-gradient(155deg, var(--a-400), var(--a-600));
  color: #fff;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.32),
    0 10px 30px rgba(15, 131, 117, .28);
  transform: scale(calc(1 + var(--level) * .085));
  transition: transform 80ms var(--ease-out), background var(--t-slow) var(--ease-out);
}
/* Idle breathing, so a silent room is never a dead room. */
.orb[data-state="idle"] .orb-core,
.orb[data-state="ready"] .orb-core { animation: breathe 4.2s var(--ease-in-out) infinite; }
@keyframes breathe { 50% { transform: scale(1.035); } }

.orb-ring {
  position: absolute; inset: 0; z-index: 1;
  border: 1.5px solid var(--accent-line);
  border-radius: 50%;
  opacity: 0;
}
/* When the interviewer is talking, rings travel outward — the visual equivalent
 * of a voice filling a room. Nothing pulses while the candidate is speaking, so
 * the two directions never look the same. */
.orb[data-state="speaking"] .orb-ring { animation: ripple 2.6s var(--ease-out) infinite; }
.orb[data-state="speaking"] .orb-ring:nth-child(3) { animation-delay: .85s; }
.orb[data-state="speaking"] .orb-ring:nth-child(4) { animation-delay: 1.7s; }
@keyframes ripple {
  0%   { opacity: .55; transform: scale(.62); }
  100% { opacity: 0;   transform: scale(1.12); }
}

.orb[data-state="connecting"] .orb-core { animation: breathe 1.3s var(--ease-in-out) infinite; }
.orb[data-state="connecting"] .orb-aura { animation-duration: 4s; opacity: .5; }
.orb[data-state="listening"] .orb-core {
  background:
    radial-gradient(circle at 34% 28%, color-mix(in srgb, var(--surface) 92%, transparent), transparent 58%),
    linear-gradient(155deg, var(--m-300), var(--m-400));
  box-shadow: inset 0 1px 0 rgba(255,255,255,.34), 0 10px 30px rgba(233, 174, 35, .3);
}
.orb[data-state="ended"] .orb-core,
.orb[data-state="error"] .orb-core { animation: none; }
.orb[data-state="error"] .orb-core {
  background: linear-gradient(155deg, var(--bad-line), var(--bad-fg));
  box-shadow: none;
}
.orb[data-state="error"] .orb-aura { opacity: .12; animation: none; }
.orb[data-state="ended"] .orb-aura { opacity: .14; }

/* A ring of bars around the orb, each driven by one FFT band. This is the part
 * that reads as "alive" rather than "animated", because it cannot be faked by a
 * loop — it is the candidate's own voice. */
.orb-bars { position: absolute; inset: 0; z-index: 1; }
.orb-bars i {
  position: absolute; left: 50%; top: 50%;
  width: 3px; height: calc(7px + var(--b, 0) * 21px);
  margin-left: -1.5px;
  border-radius: 2px;
  background: var(--accent);
  opacity: calc(.16 + var(--b, 0) * .74);
  transform: rotate(var(--rot)) translateY(-79px);
  transform-origin: 50% 0;
  transition: height 70ms var(--ease-out), opacity 70ms linear;
}
.orb[data-state="listening"] .orb-bars i { background: var(--m-400); }

.room-status {
  min-height: 24px; margin-top: var(--sp-2);
  color: var(--ink-soft); font-size: var(--text-md); font-weight: 620;
}
.room-actions { justify-content: center; margin-top: var(--sp-6); }

.timer {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  color: var(--ink-muted); font-size: var(--text-xs); font-weight: 640;
  font-variant-numeric: tabular-nums;
}

.captions {
  margin-top: var(--sp-6); padding: var(--sp-4) var(--sp-5);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface-sunk);
  text-align: left; min-height: 76px;
}
.captions-label {
  display: block; margin-bottom: var(--sp-2);
  color: var(--ink-muted); font-size: 10px; font-weight: 750;
  letter-spacing: var(--tracking-caps); text-transform: uppercase;
}
#caption-text { font-size: var(--text-lg); line-height: 1.5; }

/* ══ Candidate: meeting lobby and live room ═════════════════════════════════
 * The interaction still uses the same LiveKit lifecycle. These classes only make its
 * real states legible as a familiar call: lobby, connecting, live, and complete.
 */
.interview-room {
  min-height: calc(100dvh - var(--header-h) - 150px);
  padding: var(--sp-3) 0 var(--sp-8);
}
.meeting-lobby-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  margin-bottom: var(--sp-4);
}
.meeting-lobby-head p,
.meeting-side-kicker {
  margin: 0 0 3px;
  color: var(--ink-muted);
  font-size: var(--text-2xs);
  font-weight: 700;
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
}
.meeting-lobby-head h2 {
  margin: 0;
  font-size: var(--text-xl);
  letter-spacing: var(--tracking-tight);
}
.meeting-lobby-head > span {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  color: var(--ink-muted);
  font-size: var(--text-sm);
}
.meeting-lobby-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(270px, .65fr);
  gap: var(--sp-5);
}
.meeting-preview,
.meeting-call {
  min-width: 0;
  overflow: hidden;
  border-radius: var(--r-lg);
  background: var(--n-950);
  color: #f5fbf9;
  box-shadow: var(--shadow-md);
}
.meeting-preview { padding: var(--sp-4); }
.meeting-preview-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(190px, .6fr);
  gap: var(--sp-3);
  min-height: 430px;
}
.meeting-preview-self,
.meeting-preview-agent {
  position: relative;
  display: grid;
  place-items: center;
  min-width: 0;
  overflow: hidden;
  border: 1px solid rgba(255,255,255,.08);
  border-radius: var(--r-md);
  background:
    radial-gradient(circle at 50% 18%, rgba(39,161,142,.18), transparent 38%),
    #15231f;
}
.meeting-preview-self .party-initial {
  display: grid;
  width: 94px;
  height: 94px;
  place-items: center;
  border-radius: var(--r-full);
  background: var(--a-50);
  color: var(--a-700);
  font-size: 2rem;
}
.meeting-tile-label,
.meeting-self-label {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  border-radius: var(--r-sm);
  background: rgba(4,10,9,.72);
  color: #f5fbf9;
  font-size: var(--text-xs);
}
.meeting-tile-label {
  position: absolute;
  bottom: var(--sp-3);
  left: var(--sp-3);
  padding: 7px 9px;
}
.meeting-preview-agent {
  align-content: center;
  gap: var(--sp-4);
  padding: var(--sp-5);
  text-align: center;
}
.meeting-preview-agent .orb {
  width: 116px;
  height: 116px;
  margin: 0 auto;
}
.meeting-preview-agent .orb-core { width: 72px; height: 72px; }
.meeting-preview-agent .orb-bars i { transform: rotate(var(--rot)) translateY(-46px); }
.meeting-preview-agent b,
.meeting-preview-agent small { display: block; }
.meeting-preview-agent small {
  margin-top: var(--sp-1);
  color: #9fb3ad;
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
}
.meeting-preflight {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
  padding-top: var(--sp-3);
}
.meeting-preflight > span,
.meeting-preflight > button {
  display: inline-flex;
  min-height: 38px;
  align-items: center;
  gap: var(--sp-2);
  padding: 0 var(--sp-3);
  border: 1px solid rgba(255,255,255,.08);
  border-radius: var(--r-sm);
  background: rgba(255,255,255,.07);
  color: #e9f3f0;
  font: inherit;
  font-size: var(--text-xs);
}
.meeting-preflight > button { cursor: pointer; }
.meeting-preflight > button[aria-pressed="true"] {
  border-color: var(--a-300);
  background: rgba(39,161,142,.2);
}

/* ── The device check ─────────────────────────────────────────────────────────
 *
 * On the dark preview surface, because it is about the preview: the meter is
 * over the candidate's own tile and the camera it turns on is the picture beside
 * it. Nothing here is a gate — a machine that cannot enumerate a single device
 * still reaches the start button.
 */
.meeting-check {
  display: grid;
  gap: var(--sp-3);
  padding-top: var(--sp-3);
}
.meeting-check-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3);
  flex-wrap: wrap;
}
.meeting-check-head p {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  color: #e9f3f0;
  font-size: var(--text-2xs);
  font-weight: 700;
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
}
.meeting-check-verdict {
  min-width: 0;
  flex: 1 1 240px;
  color: #9fb3ad;
  font-size: var(--text-xs);
  line-height: 1.45;
  text-align: right;
}
.meeting-check-verdict[data-tone="good"] { color: var(--a-300); }
.meeting-check-verdict[data-tone="warn"] { color: #f6c98a; }
.meeting-check-rows {
  display: grid;
  gap: var(--sp-2);
  padding: var(--sp-3);
  border: 1px solid rgba(255,255,255,.08);
  border-radius: var(--r-md);
  background: rgba(255,255,255,.04);
}
.meeting-check-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  min-height: 36px;
}
.meeting-check-row > span:first-child {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  color: #e9f3f0;
  font-size: var(--text-xs);
}
.meeting-check-sound {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
}
.meeting-check select {
  max-width: 210px;
  min-height: 34px;
  padding: 0 var(--sp-6) 0 var(--sp-2);
  border-color: rgba(255,255,255,.14);
  background-color: rgba(255,255,255,.06);
  color: #f5fbf9;
  font-size: var(--text-xs);
  text-overflow: ellipsis;
}
.meeting-check select option { color: #10201c; }
.meeting-check select:disabled { opacity: .6; }
/* Tokens, not paint: `.btn` reads `--btn-bg` and a literal here would outrank every
 * variant's hover. Only the base rule in components.css declares the properties. */
.meeting-check .btn.secondary {
  --btn-bg: rgba(255,255,255,.08);
  --btn-fg: #f5fbf9;
  --btn-line: rgba(255,255,255,.16);
}
.meeting-check .btn.secondary:hover:not(:disabled) { --btn-bg: rgba(255,255,255,.14); }
.meeting-check .btn.secondary[aria-pressed="true"] {
  --btn-bg: rgba(39,161,142,.24);
  --btn-line: var(--a-300);
}
.meeting-check-note {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
  margin: 0;
  padding-top: var(--sp-1);
  font-size: var(--text-xs);
  line-height: 1.45;
}
.meeting-check-note[data-tone="good"] { color: var(--a-300); }
.meeting-check-note[data-tone="warn"] { color: #f6c98a; }
.meeting-check-note[data-tone="ask"] { color: #e9f3f0; }
.meeting-check-start {
  border-color: var(--a-300) !important;
  background: rgba(39,161,142,.22) !important;
  cursor: pointer;
  font-weight: 600;
}

/* The camera preview fills the tile it is previewing, rather than floating in it. */
.meeting-preview-self .selfview {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  border-radius: 0;
  object-fit: cover;
  box-shadow: none;
}

/* The level meter, over the candidate's own tile.
 *
 * `--meter` is written by the paint loop sixty times a second; the segments read it
 * rather than being written to one by one, so the whole animation is one property. */
.meeting-meter {
  --meter: 0;
  position: absolute;
  right: var(--sp-3);
  /* Clear of the name pill, which shares this corner and would otherwise sit on top
   * of the one thing the candidate is being asked to watch. */
  bottom: calc(var(--sp-3) + 38px);
  left: var(--sp-3);
  display: flex;
  gap: 3px;
  height: 6px;
  opacity: 0;
  transition: opacity .2s ease;
}
.meeting-meter[data-live="true"] { opacity: 1; }
.meeting-meter i {
  flex: 1 1 0;
  border-radius: 2px;
  background: var(--a-300);
  /* Lit when the level has reached this segment's share of the ladder. */
  opacity: clamp(.14, calc((var(--meter) * 14) - var(--i)) * 4, 1);
}
@media (prefers-reduced-motion: reduce) {
  .meeting-meter { transition: none; }
}

/* Where `track.attach()` puts the interviewer's voice. Present, not painted. */
.interview-audio {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}
.meeting-ready {
  align-self: start;
  padding: var(--sp-6);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: var(--shadow-md);
}
.meeting-ready h2,
.interview-complete h2 {
  margin: 0;
  font-size: var(--text-2xl);
  letter-spacing: var(--tracking-tight);
}
.meeting-ready > div:first-child > p:last-child {
  margin: var(--sp-2) 0 0;
  color: var(--ink-muted);
  font-size: var(--text-sm);
  line-height: 1.5;
}
.meeting-ready-list {
  display: grid;
  margin: var(--sp-5) 0;
}
.meeting-ready-list > div {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--line);
  font-size: var(--text-sm);
}
.meeting-ready-list span {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  color: var(--ink-soft);
}
.meeting-ready-list b {
  color: var(--accent-ink);
  font-size: var(--text-xs);
}
.meeting-ready-status {
  display: block;
  min-height: 1.4em;
  margin: 0 0 var(--sp-4);
  color: var(--ink-muted);
  font-size: var(--text-sm);
  line-height: 1.5;
}
.meeting-error {
  margin-bottom: var(--sp-4);
  padding: var(--sp-3);
  border: 1px solid var(--warn-line);
  border-radius: var(--r-sm);
  background: var(--warn-bg);
  color: var(--warn-fg);
  font-size: var(--text-sm);
  line-height: 1.5;
}
.meeting-ready-note {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: var(--sp-2);
  margin: var(--sp-4) 0 0;
  color: var(--ink-muted);
  font-size: var(--text-xs);
  line-height: 1.45;
  text-align: center;
}

body:has(.meeting-live-layout) {
  overflow: hidden;
  background: var(--n-950);
}
body:has(.meeting-live-layout) .topbar,
body:has(.meeting-live-layout) .page-foot { display: none; }
.shell.candidate-shell:has(.meeting-live-layout) {
  width: 100%;
  max-width: none;
  padding: 0;
}
.interview-room:has(.meeting-live-layout) {
  min-height: 100dvh;
  padding: 0;
}
.meeting-live-layout {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  width: 100vw;
  height: 100dvh;
  overflow: hidden;
  background: var(--n-950);
}
.meeting-live-layout .meeting-call {
  position: relative;
  width: 100%;
  height: 100%;
  min-height: 0;
  border-radius: 0;
  background:
    radial-gradient(circle at 50% 38%, rgba(39,161,142,.13), transparent 40%),
    #07110f;
  box-shadow: none;
}
.meeting-call-top {
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  background: linear-gradient(to bottom, rgba(7,16,14,.94), transparent);
}
.meeting-call-top > strong { font-size: var(--text-sm); }
.meeting-call-title {
  min-width: 0;
}
.meeting-call-title > strong { font-size: var(--text-sm); }
.meeting-live-status {
  display: block;
  max-width: 58ch;
  margin-top: 2px;
  overflow: hidden;
  color: #a9bbb5;
  font-size: var(--text-2xs);
  line-height: 1.35;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.meeting-recording {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  color: #a9bbb5;
  font-size: var(--text-xs);
}
.meeting-recording > span {
  width: 7px;
  height: 7px;
  border-radius: var(--r-full);
  background: #e8685f;
}
.meeting-recording time { display: inline-flex; gap: var(--sp-2); }
.meeting-participants {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(8px, 1vw, 14px);
  min-width: 0;
  min-height: 0;
  padding:
    calc(68px + env(safe-area-inset-top))
    clamp(8px, 1vw, 14px)
    calc(92px + env(safe-area-inset-bottom));
}
.meeting-participant {
  position: relative;
  display: grid;
  min-width: 0;
  min-height: 0;
  place-items: center;
  overflow: hidden;
  border: 2px solid rgba(255,255,255,.09);
  border-radius: var(--r-lg);
  background:
    radial-gradient(circle at 50% 42%, rgba(39,161,142,.15), transparent 42%),
    #12201d;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.03);
  transition:
    border-color var(--t-base) var(--ease-out),
    box-shadow var(--t-base) var(--ease-out),
    background var(--t-slow) var(--ease-out);
  isolation: isolate;
}
.meeting-participant::after {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: rgba(2, 8, 7, .24);
  content: "";
  opacity: 1;
  transition: opacity var(--t-base) var(--ease-out);
}
.meeting-participants[data-active-speaker="idle"] .meeting-participant::after,
.meeting-participant[data-speaking="true"]::after { opacity: 0; }
.meeting-participant[data-speaking="true"] {
  border-color: var(--a-300);
  background:
    radial-gradient(circle at 50% 42%, rgba(62,188,165,.26), transparent 46%),
    #12231f;
  box-shadow:
    inset 0 0 0 1px rgba(142,216,200,.2),
    0 0 34px rgba(39,161,142,.16);
}
.meeting-participant-visual {
  position: relative;
  z-index: 0;
  display: grid;
  place-items: center;
  transition: transform var(--t-base) var(--ease-out);
}
.meeting-participant[data-speaking="true"] .meeting-participant-visual {
  transform: scale(1.045);
}
.meeting-participant-agent .orb {
  width: clamp(118px, 22vmin, 200px);
  height: clamp(118px, 22vmin, 200px);
  margin: 0;
}
.meeting-participant-agent .orb-core {
  width: 59%;
  height: 59%;
}
.meeting-participant-self .selfview {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  border-radius: 0;
  object-fit: cover;
  box-shadow: none;
}
.meeting-participant-self .party-initial {
  position: relative;
  z-index: 0;
  display: grid;
  width: clamp(90px, 17vmin, 138px);
  height: clamp(90px, 17vmin, 138px);
  place-items: center;
  border: 1px solid rgba(255,255,255,.14);
  border-radius: var(--r-full);
  background: linear-gradient(145deg, var(--a-50), var(--a-100));
  color: var(--a-700);
  font-size: clamp(2rem, 6vmin, 3.4rem);
  box-shadow: 0 18px 38px rgba(0,0,0,.2);
  transition: transform var(--t-base) var(--ease-out);
}
.meeting-participant-self[data-speaking="true"] .party-initial { transform: scale(1.045); }
.meeting-participant-self:has(.selfview:not([hidden])) .party-initial { display: none; }
.meeting-participant-label {
  position: absolute;
  bottom: var(--sp-4);
  left: var(--sp-4);
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 138px;
  padding: 8px 11px;
  border: 1px solid rgba(255,255,255,.1);
  border-radius: var(--r-sm);
  background: rgba(3,10,8,.74);
  color: #eef7f4;
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
}
.meeting-participant-label > span:last-child { display: grid; gap: 1px; }
.meeting-participant-label strong { font-size: var(--text-xs); line-height: 1.25; }
.meeting-participant-label small {
  color: #9fb3ad;
  font-size: 10px;
  font-weight: 680;
  letter-spacing: .07em;
  line-height: 1.25;
  text-transform: uppercase;
}
.meeting-speaker-dot {
  width: 8px;
  height: 8px;
  flex: none;
  border-radius: var(--r-full);
  background: #6f817c;
  box-shadow: 0 0 0 4px rgba(255,255,255,.04);
}
.meeting-participant[data-speaking="true"] .meeting-speaker-dot {
  background: var(--a-300);
  box-shadow: 0 0 0 4px rgba(85,191,171,.14);
}
.meeting-participant[data-speaking="true"] .meeting-participant-label small {
  color: var(--a-200);
}
.meeting-caption {
  position: absolute;
  right: 12%;
  bottom: calc(98px + env(safe-area-inset-bottom));
  left: 12%;
  z-index: 3;
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-sm);
  background: rgba(4,10,9,.82);
  color: #f5fbf9;
  font-size: var(--text-sm);
  line-height: 1.5;
  text-align: center;
}
.meeting-dock {
  position: absolute;
  right: auto;
  bottom: calc(14px + env(safe-area-inset-bottom));
  left: 50%;
  z-index: 4;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-3);
  padding: 7px;
  transform: translateX(-50%);
  border: 1px solid rgba(255,255,255,.1);
  border-radius: var(--r-lg);
  background: rgba(5,13,11,.82);
  box-shadow: 0 14px 36px rgba(0,0,0,.28);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
}
.meeting-control {
  display: inline-flex;
  min-width: 72px;
  min-height: 52px;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 7px var(--sp-3);
  border: 1px solid rgba(255,255,255,.08);
  border-radius: var(--r-sm);
  background: rgba(255,255,255,.09);
  color: #f5fbf9;
  font: inherit;
  font-size: var(--text-2xs);
  cursor: pointer;
}
.meeting-control:hover { background: rgba(255,255,255,.14); }
.meeting-control[aria-pressed="false"] { background: rgba(178,59,52,.44); }
.meeting-control.danger { background: rgba(178,59,52,.78); }
.meeting-control:disabled { opacity: .55; cursor: not-allowed; }
.meeting-finish-dialog {
  width: min(430px, calc(100% - var(--sp-8)));
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-lg);
}
.meeting-finish-dialog::backdrop { background: rgba(4,10,9,.58); }
.meeting-finish-dialog > div { padding: var(--sp-6); }
.meeting-finish-dialog h2 { margin: 0; font-size: var(--text-xl); }
.meeting-finish-dialog p {
  margin: var(--sp-2) 0 var(--sp-6);
  color: var(--ink-soft);
  line-height: 1.55;
}
.meeting-dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-2);
}
.interview-complete {
  display: grid;
  min-height: calc(100dvh - var(--header-h) - 190px);
  place-content: center;
  max-width: 620px;
  margin: 0 auto;
  text-align: center;
}
.interview-complete-mark {
  display: grid;
  width: 70px;
  height: 70px;
  place-items: center;
  margin: 0 auto var(--sp-5);
  border-radius: var(--r-full);
  background: var(--accent-wash);
  color: var(--accent-ink);
}
.interview-complete > p {
  margin: var(--sp-2) 0 0;
  color: var(--ink-soft);
}

/* ══ Status page (invalid / expired links, errors) ══════════════════════════ */

.status-page { max-width: 54ch; margin: 12vh auto 0; text-align: center; }
.status-mark {
  width: 64px; height: 64px; margin: 0 auto var(--sp-5);
  display: grid; place-items: center;
  border-radius: 20px 20px 20px 6px;
  background: var(--surface); color: var(--ink-muted);
  box-shadow: var(--shadow-md), var(--ring);
}
.status-page h1 { font-size: var(--text-3xl); }
.status-page p { margin-top: var(--sp-4); color: var(--ink-soft); font-size: var(--text-lg); }
.status-actions { justify-content: center; margin-top: var(--sp-6); }

/* ══ Create interview: posting sources and generation state ════════════════ */

.source-selector { margin-bottom: var(--sp-4); }
.source-selector > legend {
  margin-bottom: var(--sp-2);
  font-size: var(--text-sm); font-weight: 650;
}
.source-tabs {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-2);
}
.source-tab {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  align-items: center; gap: var(--sp-3);
  min-width: 0; min-height: 62px; padding: var(--sp-3);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface-sunk); color: var(--ink-soft);
  text-align: left; cursor: pointer;
  transition:
    border-color var(--t-fast) var(--ease-out),
    background var(--t-fast) var(--ease-out),
    box-shadow var(--t-fast) var(--ease-out),
    transform var(--t-fast) var(--ease-out);
}
.source-tab:hover {
  border-color: var(--accent-line); background: var(--surface-raised);
  transform: translateY(-1px);
}
.source-tab[aria-selected="true"] {
  border-color: var(--accent); background: var(--accent-wash); color: var(--ink);
  box-shadow: 0 0 0 1px var(--accent);
}
.source-tab:focus-visible {
  outline: 3px solid color-mix(in srgb, var(--focus) 28%, transparent);
  outline-offset: 2px;
}
.source-tab:disabled { opacity: .58; cursor: wait; transform: none; }
.source-tab-icon {
  width: 34px; height: 34px; display: grid; place-items: center;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); color: var(--accent);
}
.source-tab b, .source-tab small { display: block; }
.source-tab b { font-size: var(--text-sm); line-height: 1.3; }
.source-tab small {
  margin-top: 2px; color: var(--ink-muted);
  font-size: var(--text-2xs); line-height: 1.3;
}

.source-panels { min-height: 150px; }
.source-panel {
  padding: var(--sp-4);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface-sunk);
}
.source-panel .field { margin-bottom: var(--sp-3); }
.source-panel input, .source-panel textarea { background: var(--surface); }
.source-operation {
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
}
.source-message { flex: 1 1 230px; margin: 0; }
.source-guidance {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center; gap: var(--sp-3);
}
.source-guidance-icon {
  width: 36px; height: 36px; display: grid; place-items: center;
  border-radius: var(--r-sm); background: var(--surface); color: var(--accent);
  box-shadow: var(--shadow-xs);
}
.source-guidance b { font-size: var(--text-sm); }
.source-guidance p {
  margin: 2px 0 0; color: var(--ink-muted); font-size: var(--text-xs); line-height: 1.5;
}

.posting-review {
  margin-top: var(--sp-5); padding-top: var(--sp-5);
  border-top: 1px solid var(--line);
}
.posting-review.is-standalone { margin-top: 0; padding-top: 0; border-top: 0; }
.posting-review .field { margin-bottom: 0; }
.posting-review #jd-count { display: block; text-align: right; }

.task-progress {
  height: 4px; margin-top: var(--sp-3);
  border-radius: var(--r-full); background: var(--line); overflow: hidden;
}
.task-progress > span {
  display: block; width: 42%; height: 100%; border-radius: inherit;
  background: var(--accent);
  animation: task-progress 1.4s var(--ease-in-out) infinite;
}
@keyframes task-progress {
  from { transform: translateX(-120%); }
  to { transform: translateX(240%); }
}
.create-job-form .btn[data-loading]::before {
  content: ""; width: 14px; height: 14px; flex: none;
  border: 2px solid currentColor; border-right-color: transparent;
  border-radius: 50%; animation: activity-spin .75s linear infinite;
}
.create-job-form .btn[data-loading] { cursor: progress; opacity: .72; }
.create-job-form .btn[data-loading] > .i { display: none; }
@keyframes activity-spin { to { transform: rotate(360deg); } }

.source-feedback { display: grid; gap: var(--sp-2); margin-top: var(--sp-3); }
.source-feedback:empty { display: none; }
.source-result {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3); padding: var(--sp-3);
  border: 1px solid var(--ok-line); border-radius: var(--r-sm);
  background: var(--ok-bg); color: var(--ink);
}
.source-result strong, .source-result small { display: block; }
.source-result strong { color: var(--ok-fg); font-size: var(--text-sm); }
.source-result small { margin-top: 2px; color: var(--ink-muted); }
.source-result a { flex: none; font-size: var(--text-xs); font-weight: 650; }
/* Standalone now, sitting between the posting and the button that commits to it —
 * so it carries its own separation. It used to be the last thing in a source panel,
 * where the panel's own spacing did that job. */
.source-warning {
  display: block;  /* an <output>, which is inline by default */
  margin-bottom: var(--sp-5);
  padding: var(--sp-3);
  border: 1px solid var(--warn-line); border-radius: var(--r-sm);
  background: var(--warn-bg); color: var(--ink); font-size: var(--text-sm);
}
.source-warning strong { color: var(--warn-fg); }
.source-warning-top {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
}
.source-warning ul { margin: var(--sp-2) 0 0; padding-left: var(--sp-5); }
.source-warning li + li { margin-top: var(--sp-1); }

/* The plan build, in the page rather than over it. This replaced a full-screen
 * `<dialog>` on the create form: the build now runs server-side after an instant
 * redirect, and the editor's own URL wears this card until the draft lands. */
.build-panel {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr); gap: var(--sp-4);
  max-width: 560px; margin-top: var(--sp-4);
  padding: clamp(var(--sp-5), 4vw, var(--sp-8));
  border: 1px solid var(--accent-line); border-radius: var(--r-lg);
  background: var(--surface); box-shadow: var(--shadow-sm);
}
.build-panel.failed { border-color: var(--warn-line); }
.build-panel.failed > svg { color: var(--warn-fg); margin-top: 2px; }
.build-panel h2 {
  margin: 0; font-family: var(--font-display);
  font-size: var(--text-xl); letter-spacing: var(--tracking-tight);
}
.build-panel-copy p {
  margin: var(--sp-2) 0 0; color: var(--ink-soft); line-height: 1.55;
}
.build-panel-copy small { display: block; margin-top: var(--sp-3); color: var(--ink-muted); }
.build-stage { font-variant-numeric: tabular-nums; }
.build-retry { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-5); }
.activity-spinner {
  width: 30px; height: 30px;
  border: 3px solid var(--accent-wash); border-right-color: var(--accent);
  border-radius: 50%; animation: activity-spin .8s linear infinite;
}

/* The editor's table of contents before there is one: grey bars where the rail's
 * links are about to be. Purely decorative — the markup says `aria-hidden` — and
 * the widths live here rather than in `style=` attributes the CSP would block. */
.studio-rail.skeleton { gap: var(--sp-4); padding-top: var(--sp-3); }
.skl-bar {
  display: block; height: 11px; border-radius: var(--r-full);
  background: color-mix(in srgb, var(--ink-faint) 22%, transparent);
  animation: skl-pulse 1.8s var(--ease-in-out) infinite;
}
.skl-bar.cap { height: 8px; margin-bottom: var(--sp-2); opacity: .6; inline-size: 46%; }
.skl-bar:nth-of-type(2) { inline-size: 52%; }
.skl-bar:nth-of-type(3) { inline-size: 78%; }
.skl-bar:nth-of-type(4) { inline-size: 64%; }
.skl-bar:nth-of-type(5) { inline-size: 70%; }
.skl-bar:nth-of-type(6) { inline-size: 58%; }
.skl-bar:nth-of-type(7) { inline-size: 44%; }
.skl-bar:nth-of-type(8) { inline-size: 66%; }
@keyframes skl-pulse { 50% { opacity: .45; } }

fieldset { min-width: 0; margin: 0; padding: 0; border: 0; }
legend { width: 100%; padding: 0; }

/* ══ Responsive ═════════════════════════════════════════════════════════════ */

@media (max-width: 940px) {
  .form-grid { grid-template-columns: 1fr; }
  .aside { position: static; }
  .stream-item { grid-template-columns: minmax(0, 1fr) auto; }
  .funnel { grid-column: 1 / -1; justify-content: flex-start; gap: var(--sp-6); }
  .funnel-step { text-align: left; }
  .expectations { grid-template-columns: 1fr; }
  .comp { grid-template-columns: 22px minmax(0, 1fr); }
  .weight-field { grid-column: 2; max-width: 260px; }
}

@media (max-width: 620px) {
  .topbar-inner { padding: 0 var(--sp-4); gap: var(--sp-3); }
  .brand-tagline, .chip.hide-sm { display: none; }
  .nav { margin-left: auto; }
  .shell, .shell.narrow, .shell.mid, .shell.stage {
    width: calc(100% - var(--sp-8));
    padding: var(--sp-6) 0 var(--sp-16);
  }
  .page-head { flex-direction: column; align-items: stretch; }
  .page-head-actions { justify-content: flex-start; }
  /* The row is name-then-action, which needs more width than a phone has: the
   * button will not shrink, so the name was wrapping to one word per line.
   * Stack it and let the action sit under the name at full width. */
  .attention-row { flex-direction: column; align-items: stretch; gap: var(--sp-3); }
  .attention-row .btn { justify-content: center; }
  .attention-head { flex-wrap: wrap; }
  .attention-head h2 { flex: 1 1 100%; order: -1; }
  .metric { flex-basis: 50%; border-left: 0; border-top: 1px solid var(--line); }
  .metric:first-child, .metric:nth-child(2) { border-top: 0; }
  .metric + .metric:not(:nth-child(3)) { border-left: 1px solid var(--line); }
  .steps li:not(:last-child)::after { margin: 0 var(--sp-2); min-width: var(--sp-2); }
  .step-label { display: none; }
  .steps li.now .step-label { display: inline; }
  .invite-form { grid-template-columns: 1fr; }
  .turn { max-width: 92%; }
  .orb { width: 168px; height: 168px; }
  .orb-core { width: 100px; height: 100px; }
  .orb-bars i { transform: rotate(var(--rot)) translateY(-66px); }
  .form-panel { border-radius: var(--r-md); }
  .source-tabs { grid-template-columns: 1fr; }
  .source-tab { min-height: 56px; }
  .source-guidance { grid-template-columns: auto minmax(0, 1fr); }
  .source-guidance .btn { grid-column: 1 / -1; width: 100%; }
  .source-operation .btn { flex: 1 1 auto; }
  .source-message { flex-basis: 100%; }
  .source-result { align-items: flex-start; flex-direction: column; }
  .build-panel { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  .task-progress > span { width: 100%; animation: none; opacity: .65; }
  .activity-spinner, .create-job-form .btn[data-loading]::before { animation: none; }
  .skl-bar { animation: none; opacity: .6; }
}


/* ══ Candidate page ══════════════════════════════════════════════════════════
 * One candidate, one interview, everything known about it.
 *
 * Every rule here is scoped to `.candidate`. The first version of this file was
 * not, and it collided with four classes this stylesheet already owned —
 * `.panel` wrapped every tab body in a bordered card, `.quote` fought the
 * résumé-quote rule, `.tab` was written for the link-based console tabs and so
 * never matched these button-based ones, and `.playback` already carried a
 * 55vh cap that made the recording the largest thing on the page. Two of those
 * classes are renamed (`.tabpane`, `.cite`); the rest are scoped.
 */

.candidate { display: block; }

/* ── Identity ──────────────────────────────────────────────────────────────*/

.candidate .candhead {
  position: relative;
  display: flex; align-items: center; gap: var(--sp-4); margin-bottom: var(--sp-5);
}
.candidate .cand-avatar {
  flex: none; width: 44px; height: 44px;
  display: grid; place-items: center;
  border-radius: var(--r-md); border: 1px solid var(--accent-line);
  background: var(--accent-wash); color: var(--accent-ink);
  font-size: var(--text-md); font-weight: 760; letter-spacing: var(--tracking-snug);
}
.candidate .candhead-copy { flex: 1; min-width: 0; }
.candidate .candhead-copy h1 {
  margin: 0; font-size: var(--text-2xl); line-height: 1.15;
  letter-spacing: var(--tracking-tight);
}
.candidate .candhead-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
  margin-top: 5px; color: var(--ink-muted); font-size: var(--text-sm);
}
.candidate .candhead-meta .sep { color: var(--ink-faint); }
.candidate .candhead-acts {
  display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--sp-2);
  margin-left: auto;
}
.candidate .candmenu { position: relative; }
.candidate .candmenu > summary { min-width: 34px; padding-inline: var(--sp-2); list-style: none; }
.candidate .candmenu > summary::-webkit-details-marker { display: none; }
.candidate .candmenu[open] > summary {
  border-color: var(--accent-line); background: var(--surface-sunk);
}
.candidate .candmenu-pop {
  position: absolute; top: calc(100% + var(--sp-2)); right: 0; z-index: 30;
  width: min(360px, calc(100vw - 48px));
  padding: var(--sp-4); border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface); box-shadow: var(--shadow-lg);
}
.candidate .candmenu-note p,
.candidate .candmenu-danger p {
  margin: var(--sp-1) 0 0; color: var(--ink-muted); font-size: var(--text-sm);
}
.candidate .candmenu-danger {
  margin-top: var(--sp-4); padding-top: var(--sp-4); border-top: 1px solid var(--line);
}
.candidate .candmenu-danger form { margin-top: var(--sp-3); }
.candidate .candmenu-danger .field { margin-bottom: var(--sp-3); }
.candidate .candmenu-danger select { min-height: 36px; }

/* The score never travels without its coverage. A 4.0 drawn from two-thirds of
 * a rubric is a different claim from a 4.0 drawn from all of it. */
.candidate .cscore {
  flex: none; display: grid; gap: 2px; justify-items: end;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--accent-line); border-radius: var(--r-md);
  background: var(--accent-wash);
}
.candidate .cscore-n {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--text-2xl); font-weight: 640; line-height: 1;
  letter-spacing: var(--tracking-tight); color: var(--accent-ink);
}
.candidate .cscore-n small { font-size: var(--text-md); font-weight: 500; color: var(--ink-muted); }
.candidate .cscore-band {
  font-size: var(--text-2xs); font-weight: 700; color: var(--accent-ink);
  letter-spacing: var(--tracking-caps); text-transform: uppercase;
}
.candidate .cscore-cov {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--text-2xs); color: var(--ink-muted);
}

.candidate .needs {
  display: flex; gap: var(--sp-3); align-items: flex-start;
  margin-bottom: var(--sp-5); padding: var(--sp-4) var(--sp-5);
  border: 1px solid var(--warn-line); border-left: 3px solid var(--warn-fg);
  border-radius: var(--r-md); background: var(--warn-bg);
}
.candidate .needs-mark { flex: none; color: var(--warn-fg); font-size: var(--text-md); line-height: 1.5; }
.candidate .needs > div > b { display: block; color: var(--warn-fg); font-size: var(--text-md); }
.candidate .needs-list { margin: var(--sp-2) 0 0; padding: 0; list-style: none; display: grid; gap: 3px; }
.candidate .needs-list li { color: var(--ink-soft); font-size: var(--text-md); }

/* ── Playback ──────────────────────────────────────────────────────────────
 * The recording is context for the evidence, not the feature. It had 55vh from
 * the shared `.playback` rule, which on a laptop made a mostly-black rectangle
 * the largest object on a page whose subject is what somebody said. */

.candidate .player {
  display: grid; gap: var(--sp-4);
  padding: var(--sp-4); margin-bottom: var(--sp-5);
  border: 1px solid var(--line); border-radius: var(--r-lg);
  background: var(--surface); box-shadow: var(--shadow-xs);
}
.candidate .player:has(.track) { grid-template-columns: minmax(0, 300px) minmax(0, 1fr); align-items: center; }
.candidate .player .playback {
  width: 100%; max-height: 200px; border-radius: var(--r-md);
  background: var(--n-950, #0d1614);
}
.candidate .track { min-width: 0; }
.candidate .track-label {
  display: block; margin-bottom: var(--sp-2);
  color: var(--ink-faint); font-size: var(--text-2xs); font-weight: 700;
  letter-spacing: var(--tracking-caps); text-transform: uppercase;
}
.candidate .turns { display: flex; gap: 2px; height: 24px; border-radius: var(--r-xs); overflow: hidden; }
.candidate .turns i { display: block; border-radius: 2px; min-width: 1px; }
.candidate .turns i[data-who="int"] { background: var(--line-strong); }
.candidate .turns i[data-who="cand"] { background: var(--accent-line); }
/* Amber keeps the meaning it has everywhere else here: there are words behind
 * this. These are the moments a score actually rests on. */
.candidate .turns i[data-cite] { background: var(--marker-strong); }
.candidate .ticks {
  display: flex; justify-content: space-between; margin-top: 5px;
  color: var(--ink-faint); font-size: var(--text-2xs);
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
}
.candidate .track-key {
  display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-3);
  color: var(--ink-muted); font-size: var(--text-2xs);
}
.candidate .track-key span { display: inline-flex; align-items: center; gap: 5px; }
.candidate .track-key i { width: 10px; height: 10px; border-radius: 3px; display: block; }

/* ── Tabs ──────────────────────────────────────────────────────────────────
 * The console's `.tab` is an anchor keyed on `aria-current`; these are buttons
 * keyed on `aria-selected`, so they need their own selected state or every tab
 * renders identically and none looks chosen. */

.candidate .tabs {
  position: sticky; top: 52px; z-index: 20;
  display: flex; gap: var(--sp-1); margin: 0 0 var(--sp-2);
  padding-top: var(--sp-1);
  background: var(--canvas); border-bottom: 1px solid var(--line);
  overflow-x: auto; scrollbar-width: none;
}
.candidate .tabs::-webkit-scrollbar { display: none; }
.candidate .tab {
  position: relative; display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4); border: 0; border-radius: 0;
  background: none; color: var(--ink-muted);
  font: inherit; font-size: var(--text-md); font-weight: 600;
  cursor: pointer; white-space: nowrap;
  transition: color var(--t-fast) var(--ease-out);
}
.candidate .tab:hover { color: var(--ink); }
.candidate .tab[aria-selected="true"] { color: var(--ink); }
.candidate .tab[aria-selected="true"]::after {
  content: ""; position: absolute; left: var(--sp-3); right: var(--sp-3); bottom: -1px;
  height: 2px; border-radius: 2px; background: var(--marker-strong);
}
/* Renamed from `.panel`: that class is a bordered card in components.css, and
 * inheriting it wrapped every tab body in a box it was never meant to have. */
.candidate .tabpane { padding: var(--sp-6) 0 var(--sp-4); }
.candidate .tabpane[hidden] { display: none; }

/* ── Criterion cards ───────────────────────────────────────────────────────*/

.candidate .crit {
  border: 1px solid var(--line); border-left: 3px solid var(--line-strong);
  border-radius: var(--r-md); background: var(--surface);
  box-shadow: var(--shadow-xs); margin-bottom: var(--sp-4);
}
.candidate .crit[data-state="settled"]    { border-left-color: var(--ok-fg); }
.candidate .crit[data-state="split"]      { border-left-color: var(--warn-fg); }
.candidate .crit[data-state="noevidence"] { border-left-color: var(--ink-faint); }

.candidate .crit-head {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--sp-3) var(--sp-5); align-items: start;
  padding: var(--sp-5) var(--sp-5) var(--sp-4);
}
.candidate .crit-head h3 {
  margin: 0; font-size: var(--text-lg); letter-spacing: var(--tracking-snug);
}
.candidate .crit-w {
  margin-top: 3px; color: var(--ink-muted); font-size: var(--text-xs);
  font-family: var(--font-mono);
}
.candidate .crit-score { text-align: right; }
.candidate .crit-score .v {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--text-xl); font-weight: 640; letter-spacing: var(--tracking-tight);
}
.candidate .crit-score .v small { font-size: var(--text-sm); font-weight: 500; color: var(--ink-muted); }
.candidate .crit-score .none { font-size: var(--text-md); font-weight: 620; color: var(--ink-muted); }

.candidate .crit-meter {
  grid-column: 1 / -1; height: 6px; border-radius: var(--r-full);
  background: var(--surface-sunk); overflow: hidden;
}
.candidate .crit-meter i { display: block; height: 100%; border-radius: var(--r-full); background: var(--accent); }
/* Hatched, not a bar at some low value: "we could not assess this" must not
 * read as "they did badly at this".
 *
 * `unscored` rather than `empty`, and `disagreed` rather than `split`, because both
 * of those are existing components in this stylesheet — `.empty` is a padded
 * empty-state block and `.split` is a two-column grid. A modifier only ever used
 * compounded still picks up a bare rule of the same name. */
.candidate .crit-meter.unscored {
  background: repeating-linear-gradient(100deg,
    var(--surface-sunk) 0 5px, var(--canvas) 5px 10px);
}

.candidate .crit-body { padding: 0 var(--sp-5) var(--sp-5); display: grid; gap: var(--sp-4); }
.candidate .reason { margin: 0; color: var(--ink-soft); font-size: var(--text-md); max-width: 74ch; }
.candidate .reason.muted { color: var(--ink-muted); }

.candidate .runs {
  display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-3); align-items: center;
  padding: var(--sp-3) var(--sp-4); border-radius: var(--r-sm);
  background: var(--surface-sunk); border: 1px solid var(--line);
  font-size: var(--text-sm); color: var(--ink-soft);
}
.candidate .runs.disagreed { background: var(--warn-bg); border-color: var(--warn-line); }
.candidate .runs .model {
  font-family: var(--font-mono); font-size: var(--text-xs);
  color: var(--ink-muted); font-variant-numeric: tabular-nums;
}
.candidate .runs.disagreed .model { color: var(--warn-fg); }
.candidate .runs-note { flex-basis: 100%; font-size: var(--text-sm); color: var(--warn-fg); }

/* Renamed from `.quote`, which this stylesheet already uses for the italic
 * résumé line. A cited transcript line is a different object with a different
 * job: amber down the left, and a control that plays it. */
.candidate .cites { display: grid; gap: var(--sp-2); }
.candidate .cite {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: var(--sp-3);
  align-items: start; padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--line); border-left: 3px solid var(--marker-strong);
  border-radius: var(--r-sm); background: var(--surface-sunk);
}
.candidate .cite.against { border-left-color: var(--ink-faint); }
/* A citation pointing at a turn this transcript does not contain is shown as
 * broken, never dropped — a score resting on unverifiable evidence must not
 * look like a score resting on evidence. */
.candidate .cite.orphan { border-left-color: var(--bad-fg); background: var(--bad-bg); }
/* What a candidate answered a fact question with. Never scored, so it is set apart from
 * the rubric's evidence rather than styled like a citation. */
.candidate .fact-answer { display: flex; gap: var(--sp-2); align-items: baseline; margin-top: var(--sp-2); }
.candidate .fact-answer q { color: var(--ink); }
.candidate .fact-flag {
  flex: none; width: 18px; height: 18px; border-radius: 50%;
  display: grid; place-items: center; font-weight: 700;
  background: var(--warn-bg); color: var(--warn-fg);
}
.candidate .cite-body { display: grid; gap: var(--sp-1); min-width: 0; }
/* What the quote below it shows, so a list of citations can be scanned rather than
 * read. Set above the quote and in the criterion's own weight, not louder than it. */
.candidate .cite-headline { font-weight: 600; color: var(--ink); line-height: 1.35; }
.candidate .cite q { font-size: var(--text-md); color: var(--ink); line-height: 1.5; }
.candidate .cite q::before, .candidate .cite q::after { color: var(--ink-faint); }
.candidate .vmark {
  flex: none; margin-top: 2px; width: 18px; height: 18px;
  display: grid; place-items: center; border-radius: var(--r-full);
  background: var(--ok-bg); color: var(--ok-fg); font-size: 10px; font-weight: 800;
}
.candidate .vmark.no { background: var(--surface); color: var(--ink-faint); }
.candidate .cite.orphan .vmark.no { background: var(--surface); color: var(--bad-fg); }
.candidate .jump, .candidate .jump-dead {
  flex: none; padding: 3px var(--sp-2); border-radius: var(--r-sm);
  border: 1px solid var(--line); background: var(--surface);
  color: var(--ink-soft); font-family: var(--font-mono);
  font-size: var(--text-xs); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.candidate .jump { cursor: pointer; transition: border-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out); }
.candidate .jump:hover { border-color: var(--accent-line); color: var(--accent-ink); }
.candidate .jump-dead { color: var(--bad-fg); border-color: var(--bad-line); }

.candidate .probe {
  display: flex; gap: var(--sp-3); align-items: flex-start;
  padding: var(--sp-3) var(--sp-4); border-radius: var(--r-sm);
  background: var(--accent-wash); border: 1px solid var(--accent-line);
  color: var(--accent-ink); font-size: var(--text-md);
}

.candidate .findings { margin: 0; padding: 0; list-style: none; }
.candidate .findings li {
  display: flex; gap: var(--sp-3); align-items: flex-start;
  padding: var(--sp-3) 0; border-bottom: 1px solid var(--line);
  font-size: var(--text-md); color: var(--ink-soft);
}
.candidate .findings li:last-child { border-bottom: 0; padding-bottom: 0; }
.candidate .glyph {
  flex: none; width: 20px; height: 20px; margin-top: 1px;
  display: grid; place-items: center; border-radius: var(--r-full);
  font-size: 11px; font-weight: 800;
}
.candidate .glyph.up { background: var(--ok-bg); color: var(--ok-fg); }
.candidate .glyph.down { background: var(--warn-bg); color: var(--warn-fg); }
.candidate .glyph.next { background: var(--accent-wash); color: var(--accent-ink); }

.candidate .row-head { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.candidate .row-head h3 { margin: 0; font-size: var(--text-lg); }
.candidate .sig { padding-top: var(--sp-3); }
.candidate .quote-line {
  display: block; margin-top: var(--sp-2); color: var(--ink-muted);
  font-size: var(--text-sm); font-style: italic;
}
.candidate .cols { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-4); }
.candidate .lede { max-width: 74ch; }

@media (max-width: 860px) {
  .candidate .candhead { align-items: flex-start; flex-wrap: wrap; }
  .candidate .candhead-acts { flex-basis: 100%; margin-left: 60px; justify-content: flex-start; }
  .candidate .cscore { order: -1; margin-left: auto; }
  .candidate .player:has(.track) { grid-template-columns: 1fr; }
  .candidate .cols { grid-template-columns: 1fr; }
  .candidate .crit-head { grid-template-columns: 1fr; }
  .candidate .crit-score { text-align: left; }
}

@media (max-width: 560px) {
  .candidate .cand-avatar { width: 40px; height: 40px; }
  .candidate .candhead-acts { margin-left: 0; }
  .candidate .candhead-acts .btn:not(.primary),
  .candidate .candhead-acts .candmenu { flex: 1 1 auto; }
  .candidate .candhead-acts .candmenu > summary { width: 100%; }
  .candidate .candhead-acts .btn.primary { flex: 1 0 100%; }
}

/* Legend swatches, and the readout that replaced a bar.
 *
 * Coloured by class rather than by an inline style. `style-src` carries no
 * `unsafe-inline`, so a `style="background:…"` attribute is dropped by the
 * browser and every swatch renders colourless — which is a legend that
 * explains nothing. Verified against the served header, not assumed.
 */
.candidate .swatch-accent-line { background: var(--accent-line); }
.candidate .swatch-line-strong { background: var(--line-strong); }
.candidate .swatch-marker-strong { background: var(--marker-strong); }

/* The no-JavaScript fallback for a criterion's score. A proportional bar needs a
 * width, a width needs an inline style, and there is no script here to apply one. */
.candidate .crit-readout {
  grid-column: 1 / -1;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-sm);
  color: var(--ink-muted);
}

/* Autoplay refused: the interview is running and the candidate cannot hear it. Sits
 * above the controls because it is the next thing to do, and it is the only thing on
 * this page that competes with the finish button for attention. */
.stage-audio-blocked {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: var(--sp-3);
  max-width: 640px; margin: 0 auto var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--warn-line); border-radius: var(--r-md);
  background: var(--warn-bg); color: var(--ink);
  text-align: center;
}
.stage-audio-blocked p { margin: 0; font-size: var(--text-sm); }
.meeting-call > .stage-audio-blocked {
  position: absolute;
  top: 76px;
  left: 50%;
  z-index: 6;
  width: min(620px, calc(100% - 40px));
  margin: 0;
  transform: translateX(-50%);
  background: #fff4de;
  color: #4e3513;
  box-shadow: var(--shadow-md);
}

@media (max-width: 860px) {
  .candidate-entry {
    grid-template-columns: 1fr;
    gap: var(--sp-6);
    max-width: 700px;
    margin: 0 auto;
    min-height: auto;
  }
  .candidate-entry-copy h1 { max-width: none; }
  .candidate-call-preview {
    aspect-ratio: auto;
    min-height: 220px;
  }
  .meeting-lobby-layout { grid-template-columns: 1fr; }
}

@media (max-width: 700px) and (orientation: portrait) {
  .meeting-participants {
    grid-template-columns: 1fr;
    grid-template-rows: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  .shell.candidate-shell {
    width: calc(100% - var(--sp-6));
    padding: var(--sp-4) 0 var(--sp-10);
  }
  .candidate-entry { gap: var(--sp-4); padding-top: 0; }
  .candidate-tag { margin-bottom: var(--sp-3); }
  .candidate-entry-copy h1 { font-size: var(--text-3xl); }
  .candidate-role-meta { margin: var(--sp-2) 0 var(--sp-4); font-size: var(--text-base); }
  .candidate-meeting-meta { gap: var(--sp-1); }
  .candidate-meeting-meta > span {
    min-height: 28px;
    gap: 5px;
    padding: 0 var(--sp-2);
    font-size: var(--text-2xs);
  }
  .candidate-call-preview {
    min-height: 168px;
    margin-top: var(--sp-4);
    border-radius: var(--r-lg);
  }
  .candidate-call-top {
    top: var(--sp-3);
    right: var(--sp-3);
    left: var(--sp-3);
    font-size: 10px;
  }
  .candidate-call-top > span:last-child { display: none; }
  .candidate-call-orb {
    width: 58px;
    height: 58px;
    margin-bottom: var(--sp-2);
  }
  .candidate-call-orb::before { inset: -12px; }
  .candidate-call-orb::after { inset: -22px; }
  .candidate-call-stage b { font-size: var(--text-sm); }
  .candidate-self-preview {
    right: var(--sp-3);
    bottom: var(--sp-3);
    width: 72px;
    height: 50px;
    gap: 2px;
  }
  .candidate-self-preview > span { width: 24px; height: 24px; }
  .candidate-self-preview > span .i { width: 14px; height: 14px; }
  .candidate-join-card { padding: var(--sp-4); border-radius: var(--r-lg); }
  .candidate-join-card::before { right: var(--sp-4); left: var(--sp-4); }
  .candidate-join-head { margin-bottom: var(--sp-4); }
  .candidate-fields { grid-template-columns: 1fr; gap: var(--sp-3); }
  .candidate-field-wide { grid-column: 1; }
  .candidate-consent-launch { grid-template-columns: auto minmax(0, 1fr); }
  .candidate-consent-launch > .btn {
    grid-column: 1 / -1;
    width: 100%;
  }
  .candidate-consent-dialog {
    width: calc(100% - var(--sp-6));
    max-height: calc(100dvh - var(--sp-6));
  }
  .candidate-consent-modal-head,
  .candidate-consent-modal-copy { padding: var(--sp-4); }
  .candidate-consent-modal-actions {
    flex-direction: column;
    padding: var(--sp-4);
  }
  .candidate-consent-modal-actions .btn { width: 100%; }
  .meeting-lobby-head {
    align-items: flex-start;
    flex-direction: column;
    margin-bottom: var(--sp-3);
  }
  .meeting-lobby-layout { gap: var(--sp-3); }
  .meeting-preview { order: 0; padding: var(--sp-2); }
  .meeting-preview-grid { grid-template-columns: 1fr; min-height: auto; gap: var(--sp-2); }
  .meeting-preview-self { min-height: 220px; }
  .meeting-preview-agent {
    min-height: 74px;
    align-content: center;
    grid-template-columns: auto minmax(0, 1fr);
    gap: var(--sp-3);
    padding: var(--sp-2) var(--sp-3);
    text-align: left;
  }
  .meeting-preview-agent .orb { width: 50px; height: 50px; margin: 0; }
  .meeting-preview-agent .orb-core { width: 32px; height: 32px; }
  .meeting-preview-agent .orb-core .i { width: 14px; height: 14px; }
  .meeting-preview-agent .orb-bars { display: none; }
  .meeting-preview-agent > span { min-width: 0; }
  .meeting-preflight { flex-wrap: wrap; gap: var(--sp-1); padding-top: var(--sp-2); }
  .meeting-check-verdict { flex-basis: 100%; text-align: left; }
  .meeting-check-row { flex-wrap: wrap; }
  .meeting-check select { max-width: 100%; flex: 1 1 140px; }
  .meeting-preflight > span,
  .meeting-preflight > button {
    min-width: 0;
    flex: 1 1 0;
    justify-content: center;
    gap: 5px;
    padding: 0 6px;
    font-size: 10px;
    text-align: center;
  }
  .meeting-ready { padding: var(--sp-4); }
  .meeting-ready > .meeting-ready-list { margin: var(--sp-3) 0; }
  .meeting-ready-list > div { padding: var(--sp-2) 0; }

  .interview-room { min-height: auto; padding-top: 0; }
  .meeting-call { min-height: 560px; }
  .meeting-call-top {
    align-items: center;
    flex-direction: row;
    padding: 10px var(--sp-3);
  }
  .meeting-call-title {
    max-width: 58%;
    overflow: hidden;
  }
  .meeting-call-title > strong {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .meeting-live-status { display: none; }
  .meeting-recording { gap: 6px; font-size: 10px; }
  .meeting-participants {
    gap: 6px;
    padding:
      calc(52px + env(safe-area-inset-top))
      6px
      calc(72px + env(safe-area-inset-bottom));
  }
  .meeting-participant { border-radius: var(--r-md); }
  .meeting-participant-agent .orb {
    width: clamp(94px, 18vmin, 126px);
    height: clamp(94px, 18vmin, 126px);
  }
  .meeting-participant-label {
    bottom: 8px;
    left: 8px;
    min-width: 0;
    padding: 6px 8px;
  }
  .meeting-participant-label strong { font-size: var(--text-2xs); }
  .meeting-call > .stage-audio-blocked {
    top: 58px;
    width: calc(100% - var(--sp-6));
  }
  .meeting-caption {
    right: var(--sp-3);
    bottom: calc(76px + env(safe-area-inset-bottom));
    left: var(--sp-3);
  }
  .meeting-dock {
    bottom: calc(6px + env(safe-area-inset-bottom));
    gap: 4px;
    max-width: calc(100% - 12px);
    padding: 5px;
  }
  .meeting-control { min-width: 56px; min-height: 48px; padding-inline: 7px; }
  .meeting-dialog-actions { flex-direction: column-reverse; }
  .meeting-dialog-actions .btn { width: 100%; }
  .interview-complete { min-height: calc(100dvh - var(--header-h) - 140px); }
}

@media (max-width: 360px) {
  .meeting-dock { gap: 3px; padding-inline: 4px; }
  .meeting-control {
    min-width: 0;
    flex: 1 1 0;
    padding-inline: 3px;
    font-size: 10px;
  }
}

/* The workspace shell: sidebar, app bar, menus, command palette.
 *
 * The product moved from a centred marketing-style header to a persistent left
 * rail because those two layouts say different things. A centred header says
 * "you are reading a page". A rail says "you are inside a tool, and everything
 * it does is listed right here". The second is true, and the first was costing
 * a click and a page load every time someone wanted to be somewhere else.
 *
 * Three rules hold the layout together:
 *
 * 1. The rail never scrolls with the content. It is `position: sticky` at full
 *    viewport height with its own overflow, so the nav is reachable from the
 *    bottom of a long transcript without scrolling back up.
 * 2. Collapsing is a width change on one custom property. Everything else —
 *    labels, the search button, the account card — reacts to `--rail`, so there
 *    is no second set of rules describing a collapsed sidebar that can drift
 *    out of sync with the expanded one.
 * 3. Below 900px the rail is not a rail. It becomes an overlay drawer, because
 *    a 240px fixed column on a 390px phone leaves 150px for the product.
 */

.app-body-root { background: var(--canvas-deep); }

.app-frame {
  --rail: 248px;
  display: grid;
  grid-template-columns: var(--rail) minmax(0, 1fr);
  min-height: 100vh;
  min-height: 100dvh;
  transition: grid-template-columns var(--t-base) var(--ease-out);
}
.sidebar-collapsed .app-frame { --rail: 68px; }

/* ─────────────────────────────────────────────────────────────── rail ── */

.sidebar {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  height: 100vh;
  height: 100dvh;
  padding: var(--sp-3);
  overflow: hidden auto;
  overscroll-behavior: contain;
  background: var(--canvas-deep);
  scrollbar-width: thin;
}

.sidebar-top {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 40px;
  padding: 0 var(--sp-1);
}
.sidebar-top .brand { flex: 1; min-width: 0; }
.sidebar-collapse { flex: none; opacity: 0; transition: opacity var(--t-fast) var(--ease-out); }
.sidebar:hover .sidebar-collapse,
.sidebar-collapse:focus-visible { opacity: 1; }
.sidebar-collapsed .sidebar-collapse svg { transform: rotate(180deg); }

/* Everything that hides on collapse hides the same way: it is still in the
 * layout for screen readers, but it has no width and no opacity. */
.sidebar-collapsed .brand-copy,
.sidebar-collapsed .wswitch-copy,
.sidebar-collapsed .wswitch-go,
.sidebar-collapsed .navitem-label,
.sidebar-collapsed .searchbtn span,
.sidebar-collapsed .searchbtn .kbd,
.sidebar-collapsed .accountbtn-copy {
  width: 0;
  opacity: 0;
  overflow: hidden;
  white-space: nowrap;
  pointer-events: none;
}
.sidebar-collapsed .sidebar { padding-inline: 10px; }
.sidebar-collapsed .wswitch,
.sidebar-collapsed .searchbtn,
.sidebar-collapsed .accountbtn,
.sidebar-collapsed .navitem { justify-content: center; padding-inline: 0; }

/* ── workspace switcher ── */

.wswitch,
.accountbtn {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  width: 100%;
  min-height: 46px;
  padding: var(--sp-2);
  border: 1px solid transparent;
  border-radius: var(--r-md);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  text-align: left;
  transition: background var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out);
}
.wswitch:hover,
.accountbtn:hover { background: var(--surface); border-color: var(--line); }
.wswitch[aria-expanded="true"],
.accountbtn[aria-expanded="true"] { background: var(--surface); border-color: var(--line); }

.wswitch-mark {
  flex: none;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: var(--r-sm);
  background: linear-gradient(150deg, var(--a-400), var(--a-600));
  color: #fff;
  font-size: var(--text-sm);
  font-weight: 700;
  letter-spacing: 0;
  box-shadow: var(--shadow-xs);
}
.wswitch-mark.sm { width: 22px; height: 22px; font-size: var(--text-2xs); border-radius: 6px; }

.wswitch-copy,
.accountbtn-copy {
  display: grid;
  flex: 1;
  min-width: 0;
  line-height: 1.25;
  transition: opacity var(--t-fast) var(--ease-out);
}
.wswitch-copy b,
.accountbtn-copy b {
  overflow: hidden;
  font-size: var(--text-sm);
  font-weight: 620;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.wswitch-copy span,
.accountbtn-copy span {
  overflow: hidden;
  color: var(--ink-muted);
  font-size: var(--text-xs);
  text-overflow: ellipsis;
  white-space: nowrap;
}
.wswitch-go { flex: none; color: var(--ink-faint); }

.avatar {
  flex: none;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: var(--r-full);
  background: var(--surface-raised);
  border: 1px solid var(--line-strong);
  color: var(--ink-soft);
  font-size: var(--text-2xs);
  font-weight: 700;
}

/* ── search trigger ── */

.searchbtn {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  width: 100%;
  min-height: 38px;
  margin-top: var(--sp-1);
  padding: 0 var(--sp-2);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--ink-muted);
  cursor: pointer;
  font-size: var(--text-sm);
  transition: border-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out);
}
.searchbtn:hover { border-color: var(--line-strong); color: var(--ink-soft); }
.searchbtn span { flex: 1; text-align: left; }
.kbd {
  display: inline-flex;
  align-items: center;
  gap: 1px;
  padding: 2px 5px;
  border: 1px solid var(--line);
  border-radius: 5px;
  background: var(--surface-sunk);
  color: var(--ink-faint);
  font-family: var(--font);
  font-size: var(--text-2xs);
  font-weight: 600;
}
.kbd-mod { font-size: 12px; }

/* ── nav ── */

.sidenav {
  display: grid;
  gap: 1px;
  margin-top: var(--sp-3);
}
.navitem {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: 38px;
  padding: 0 var(--sp-2);
  border-radius: var(--r-sm);
  color: var(--ink-soft);
  font-size: var(--text-md);
  font-weight: 550;
  text-decoration: none;
  transition: background var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out);
}
.navitem-icon { display: grid; flex: none; place-items: center; color: var(--ink-faint); transition: color var(--t-fast) var(--ease-out); }
.navitem-label { transition: opacity var(--t-fast) var(--ease-out); }
.navitem:hover { background: var(--surface); color: var(--ink); }
.navitem:hover .navitem-icon { color: var(--ink-soft); }
.navitem[aria-current="page"] {
  background: var(--surface);
  color: var(--ink);
  font-weight: 620;
  box-shadow: var(--shadow-xs), var(--ring);
}
.navitem[aria-current="page"] .navitem-icon { color: var(--accent); }
/* The current-page marker is a bar on the rail edge, not a background colour:
 * it survives the collapse to an icon rail, where a tinted pill and a hover
 * state look identical. */
.navitem[aria-current="page"]::before {
  content: "";
  position: absolute;
  left: calc(var(--sp-2) * -1 - 1px);
  top: 50%;
  width: 3px;
  height: 18px;
  border-radius: 0 3px 3px 0;
  background: var(--accent);
  transform: translateY(-50%);
}
.sidebar-collapsed .navitem[aria-current="page"]::before { left: -10px; }

.sidebar-foot { margin-top: auto; padding-top: var(--sp-2); }

/* ─────────────────────────────────────────────────────────── menus ── */

.menu-wrap { position: relative; }
.menu {
  position: absolute;
  left: 0;
  right: 0;
  z-index: var(--z-overlay);
  min-width: 210px;
  margin-top: var(--sp-1);
  padding: var(--sp-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-raised);
  box-shadow: var(--shadow-lg);
  animation: menu-in var(--t-fast) var(--ease-out) both;
}
.menu.up { top: auto; bottom: 100%; margin: 0 0 var(--sp-1); }
.menu[hidden] { display: none; }
@keyframes menu-in { from { opacity: 0; transform: translateY(-4px) scale(.98); } }
.menu.up { transform-origin: bottom center; }

.menu-label {
  padding: var(--sp-2) var(--sp-2) var(--sp-1);
  overflow: hidden;
  color: var(--ink-faint);
  font-size: var(--text-2xs);
  font-weight: 700;
  letter-spacing: var(--tracking-caps);
  text-overflow: ellipsis;
  text-transform: uppercase;
  white-space: nowrap;
}
.menu-item {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  width: 100%;
  min-height: 34px;
  padding: 0 var(--sp-2);
  border: 0;
  border-radius: var(--r-xs);
  background: transparent;
  color: var(--ink-soft);
  cursor: pointer;
  font-size: var(--text-md);
  text-align: left;
  text-decoration: none;
}
.menu-item svg { color: var(--ink-faint); flex: none; }
.menu-item:hover { background: var(--surface-sunk); color: var(--ink); }
.menu-item.is-on { color: var(--ink); font-weight: 600; }
.menu-item.is-on svg:last-child { margin-left: auto; color: var(--accent); }
.menu-sep { height: 1px; margin: var(--sp-1) 0; background: var(--line); }

/* ──────────────────────────────────────────────────────── app body ── */

.app-body {
  display: flex;
  min-width: 0;
  flex-direction: column;
  border-left: 1px solid var(--line);
  background: var(--canvas);
}
/* The content column is the raised surface and the rail is the recess. One
 * radius on the inner corner is what makes it read as a panel rather than as
 * two halves of a page. */
@media (min-width: 901px) {
  .app-body {
    margin: var(--sp-2) var(--sp-2) var(--sp-2) 0;
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-sm);
    overflow: clip;
  }
  .app-frame { min-height: 100vh; min-height: 100dvh; }
}

.appbar {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 52px;
  padding: 0 var(--sp-4);
  border-bottom: 1px solid var(--line);
  background: color-mix(in srgb, var(--surface) 82%, transparent);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  backdrop-filter: saturate(180%) blur(14px);
}
.appbar-menu { display: none; }
.appbar-search { display: none; }
.appbar-actions { display: flex; gap: var(--sp-2); align-items: center; }

.crumbs {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
  font-size: var(--text-md);
}
.crumbs a, .crumbs span {
  overflow: hidden;
  color: var(--ink-muted);
  text-decoration: none;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.crumbs a:hover { color: var(--ink); }
.crumbs > :last-child { color: var(--ink); font-weight: 600; }
.crumbs > * + *::before {
  content: "/";
  margin-right: var(--sp-2);
  color: var(--ink-faint);
  font-weight: 400;
}

.app-body .shell { padding: var(--sp-8) var(--sp-6) var(--sp-16); }
.app-body .shell.narrow { max-width: 720px; }
.app-body .shell.mid { max-width: 960px; }

/* ────────────────────────────────────────────── drawer + scrim (sm) ── */

.scrim {
  position: fixed;
  inset: 0;
  z-index: 45;
  background: rgba(6, 13, 12, .5);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  animation: fade-in var(--t-base) var(--ease-out) both;
}
.scrim[hidden] { display: none; }
@keyframes fade-in { from { opacity: 0; } }

@media (max-width: 900px) {
  .app-frame { grid-template-columns: minmax(0, 1fr); }
  .sidebar {
    position: fixed;
    left: 0;
    top: 0;
    z-index: 50;
    width: 268px;
    border-right: 1px solid var(--line);
    background: var(--canvas-deep);
    box-shadow: var(--shadow-lg);
    transform: translateX(-100%);
    transition: transform var(--t-base) var(--ease-out);
  }
  .drawer-open .sidebar { transform: none; }
  .sidebar-collapse { display: none; }
  .appbar-menu { display: inline-grid; }
  .appbar-search { display: inline-grid; }
  .searchbtn { display: none; }
  .app-body { border-left: 0; }
  .app-body .shell { padding: var(--sp-6) var(--sp-4) var(--sp-12); }
  /* The bar has room for the menu, the breadcrumb and one action. Status pills and
   * the draft-rev counter yield first — the breadcrumb is how you know where you
   * are, and it was being squeezed to a row of slashes. */
  .appbar-actions .pill,
  .appbar-actions .studio-saved { display: none; }
}

/* ─────────────────────────────────────────────── command palette ── */

/* A native `<dialog>`, so its visibility is `[open]` — not `[hidden]`, which is what
 * this said while it was a `<div>`. A closed dialog is `display: none` by default and
 * this rule was overriding that, so the palette rendered as a dark panel on every
 * workspace page, over the content, on every load. */
.cmdk-root { display: none; }
.cmdk-root[open] {
  position: fixed;
  inset: 0;
  z-index: var(--z-toast);
  display: grid;
  align-items: start;
  justify-items: center;
  padding: clamp(48px, 12vh, 140px) var(--sp-4) var(--sp-4);
  background: rgba(6, 13, 12, .45);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  animation: fade-in var(--t-fast) var(--ease-out) both;
}

.cmdk {
  width: min(560px, 100%);
  overflow: hidden;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-lg);
  background: var(--surface-raised);
  box-shadow: var(--shadow-lift);
  animation: cmdk-in var(--t-base) var(--ease-out) both;
}
@keyframes cmdk-in { from { opacity: 0; transform: translateY(-10px) scale(.985); } }

.cmdk-search {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 0 var(--sp-4);
  border-bottom: 1px solid var(--line);
}
.cmdk-search svg { flex: none; color: var(--ink-faint); }
.cmdk-search input {
  width: 100%;
  min-height: 52px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--ink);
  font-size: var(--text-lg);
  box-shadow: none;
}
.cmdk-search input:focus { border: 0; box-shadow: none; outline: 0; }
.cmdk-search input::placeholder { color: var(--ink-faint); }

.cmdk-list { max-height: min(56vh, 420px); overflow: auto; padding: var(--sp-2); overscroll-behavior: contain; }
/* `--ink-muted`, not `--ink-faint`: this is 11px, and WCAG wants 4.5:1 for anything
 * under 18.66px bold. Faint measured 3.15:1 here. Text this small cannot be that
 * light, whatever the hierarchy would prefer. */
.cmdk-group { padding: var(--sp-2) var(--sp-2) var(--sp-1); color: var(--ink-muted); font-size: var(--text-2xs); font-weight: 700; letter-spacing: var(--tracking-caps); text-transform: uppercase; }
.cmdk-item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  min-height: 42px;
  padding: 0 var(--sp-3);
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--ink-soft);
  cursor: pointer;
  font-size: var(--text-md);
  text-align: left;
  text-decoration: none;
}
.cmdk-item svg { flex: none; color: var(--ink-faint); }
.cmdk-item b { font-weight: 580; color: var(--ink); }
.cmdk-item .cmdk-meta { margin-left: auto; color: var(--ink-faint); font-size: var(--text-xs); }
.cmdk-item[data-active] { background: var(--accent-wash); color: var(--ink); }
.cmdk-item[data-active] svg { color: var(--accent); }
.cmdk-empty { padding: var(--sp-8) var(--sp-4); color: var(--ink-muted); font-size: var(--text-md); text-align: center; }
.cmdk-foot {
  display: flex;
  gap: var(--sp-4);
  padding: var(--sp-2) var(--sp-4);
  border-top: 1px solid var(--line);
  background: var(--surface-sunk);
  /* Same reason as the group label above: 12px is small text, and faint measured
   * 2.92:1 on this background. */
  color: var(--ink-muted);
  font-size: var(--text-xs);
}
.cmdk-foot span { display: inline-flex; align-items: center; gap: 5px; }

@media (prefers-reduced-motion: reduce) {
  .app-frame, .sidebar, .menu, .cmdk, .cmdk-root, .scrim { transition: none; animation: none; }
}

/* ══ Studio ══════════════════════════════════════════════════════════════════
 * Authoring a plan, inside the workspace's own chrome. The editor used to be a
 * separate surface with its own top bar; from the create flow that read as being
 * handed to a different product. Now the sidebar, app bar and breadcrumb stay
 * put, and the plan's table of contents is a second rail inside the page.
 *
 * It replaced a single form measured at 138 named fields for a six-competency
 * role, and around 230 once rubrics are generated. Nothing here holds more than
 * one section of that at a time.
 */

.studio-saved {
  font-size: var(--text-xs);
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

.studio-body {
  display: grid;
  grid-template-columns: 236px minmax(0, 1fr);
  gap: 0 clamp(var(--sp-5), 3vw, var(--sp-10));
  align-items: start;
}

/* ── the plan's table of contents ── */

/* Sticky under the app bar (52px min-height), not under a bar of its own. */
.studio-rail {
  position: sticky;
  top: calc(52px + var(--sp-5));
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 0 var(--sp-3) var(--sp-6) 0;
  border-right: 1px solid var(--line);
  max-height: calc(100dvh - 52px - var(--sp-10));
  overflow: hidden auto;
}
.rail-group {
  padding: var(--sp-5) var(--sp-2) var(--sp-2);
  font-size: var(--text-2xs);
  font-weight: 700;
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--ink-faint);
}
.rail-group:first-child { padding-top: 0; }

.railitem {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 34px;
  padding: var(--sp-1) var(--sp-2);
  border-radius: var(--r-sm);
  color: var(--ink-soft);
  font-size: var(--text-md);
  font-weight: 550;
  text-decoration: none;
  transition: background var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out);
}
.railitem:hover { background: var(--surface); color: var(--ink); }
.railitem.sub {
  padding-left: var(--sp-6);
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--ink-muted);
}
.railitem[aria-current="page"] {
  background: var(--accent-wash);
  color: var(--accent-ink);
  font-weight: 640;
}
.railitem-label { flex: 1; min-width: 0; }
.rail-count {
  color: var(--ink-faint);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

/* A tick means one thing: this section has been saved. The wizard it replaced
 * asserted an order and a completeness it had no way to know. */
.railmark {
  flex: none;
  width: 16px;
  height: 16px;
  display: grid;
  place-items: center;
  border-radius: var(--r-full);
  font-size: var(--text-2xs);
  font-weight: 700;
}
.railmark.done { background: var(--ok-bg); color: var(--ok-fg); }
.railmark.warn { background: var(--warn-bg); color: var(--warn-fg); }

/* ── the section on screen ── */

.studio-pane {
  padding: var(--sp-8) clamp(var(--sp-4), 3vw, var(--sp-10)) var(--sp-20);
  max-width: 940px;
}
.studio-form { display: block; }
.studio-actions {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin-top: var(--sp-8);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--line);
}

/* One competency on its own page has no siblings to line up with, so it drops
 * the grid the list version needs. */
.comp.solo {
  display: block;
  padding: 0;
  border: 0;
  background: none;
}

.comp-go { margin-top: var(--sp-2); }
.warn-ink { color: var(--warn-fg); }

table.plain { width: 100%; border-collapse: collapse; }
table.plain th, table.plain td {
  padding: var(--sp-2) var(--sp-3);
  text-align: left;
  border-bottom: 1px solid var(--line);
}
table.plain th {
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--ink-faint);
}
table.plain .num { text-align: right; font-variant-numeric: tabular-nums; }
table.plain tr:last-child td { border-bottom: 0; }

@media (max-width: 900px) {
  .studio-body { grid-template-columns: 1fr; }
  .studio-rail {
    position: static;
    max-height: none;
    border-right: 0;
    border-bottom: 1px solid var(--line);
    padding: var(--sp-4) var(--sp-4) var(--sp-5);
  }
  .studio-pane { padding: var(--sp-6) var(--sp-4) var(--sp-16); }
}
