/* 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.interview-type {
  padding: 2px 9px; font-size: var(--text-xs); font-weight: 600;
  white-space: normal; vertical-align: middle;
}
.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; }
/* The required mark sits at the label's far end — the field's top corner — so a
   candidate scanning the form sees which boxes cannot be left empty before typing.
   The legend above the fields says what it means, once. */
.field-required { color: var(--bad-fg); font-weight: 700; margin-left: auto; }
.field-legend { margin: 0 0 var(--sp-3); color: var(--ink-muted); font-size: var(--text-xs); }
.field-legend .field-required { margin: 0 3px 0 0; }
/* A refused field: the reason in red under the control, and the control outlined in the
   same colour. `.invalid` is what the server sets on a re-rendered form and what the
   page's script sets on submit; `:user-invalid` covers a browser doing it alone. */
.field-error {
  display: block; margin-top: 6px;
  color: var(--bad-fg); font-size: var(--text-xs); font-weight: 600;
}
.field.invalid input, .field.invalid textarea, .field.invalid select,
input:user-invalid, textarea:user-invalid, select:user-invalid {
  border-color: var(--bad-fg);
  box-shadow: 0 0 0 3px var(--bad-bg);
}

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: its role, and how the interview ended. It carries
 * what used to be columns, so it has to read as subordinate to the name — and the facts
 * have to stay separable at a glance. One colour and one size for all of them made a
 * string nobody could parse without reading every word, so each kind gets its own
 * weight: plain text, and a bordered chip. The interview date is a column of its own,
 * because the lists sort by it.
 *
 * Gap rather than "·" separators, so a narrow column breaks *between* facts. Left to
 * itself the browser breaks inside them, and "transport" / "failed" 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;
}

/* Below a list with more than one page: "First page" on the left, "Next page" on the
 * right. Those labels, not "Newest" and "Older", because the list also sorts by name
 * and by score, where neither word is true. */
.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. */

/* Candidate search: a GET form whose controls and links work before the enhancement
 * loads, and without it.
 *
 * Two rows. The search box and its Search button, then the Filters panel across the
 * whole width, with its toggle and, when open, the fields below the toggle. The panel
 * is laid out as the ordinary block a <details> is. An earlier layout put the toggle in
 * the first row by giving <details> and its `::details-content` slot `display:
 * contents`; that pseudo-element is newer than the browser floor, and where it is
 * missing the fields fell out of the grid into the search column. Nothing here styles
 * the element's internal boxes, so every browser on the floor lays it out alike.
 *
 * The markup follows the rows: search box, Search button, then the panel. With the
 * button last, Tab went from the box down to Filters and the fields, then back up to
 * Search, an order a sighted keyboard user cannot follow on screen. */
.filterbar {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--sp-3); align-items: end;
  margin: 0 0 var(--sp-3); padding: var(--sp-4);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface);
}
.filter-search { grid-column: 1; grid-row: 1; min-width: 0; }
.filter-submit { grid-column: 2; grid-row: 1; min-height: 42px; }
.filter-panel { grid-column: 1 / -1; grid-row: 2; min-width: 0; }
/* No search box: the panel is the first row, and Apply follows the fields it applies. */
.filterbar.no-search .filter-panel { grid-row: 1; }
.filter-fields .filter-submit { grid-column: auto; grid-row: auto; align-self: end; justify-self: start; }
.filterbar label { display: block; margin-bottom: 6px; color: var(--ink-soft); font-size: var(--text-sm); font-weight: 640; }
.filterbar select,
.filterbar input[type="search"] {
  width: 100%; min-height: 42px; font-size: var(--text-md);
}
.filter-toggle {
  width: fit-content; min-height: 42px;
  --btn-bg: var(--accent); --btn-fg: var(--on-accent); --btn-line: var(--accent);
  list-style: none;
}
.filter-toggle::-webkit-details-marker { display: none; }
.filter-toggle:hover { --btn-bg: var(--accent-hover); --btn-line: var(--accent-hover); }
.filter-toggle:focus-visible, .filter-chip:focus-visible, .list-table th a:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 3px;
}
.filter-count {
  display: inline-grid; place-items: center; min-width: 22px; height: 22px;
  border-radius: 999px; padding: 0 5px;
  background: var(--on-accent); color: var(--accent); font-size: var(--text-sm);
}
.filter-fields {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: var(--sp-3); margin-top: var(--sp-3);
  padding-top: var(--sp-3); border-top: 1px solid var(--line);
}
.filter-field { min-width: 0; }
.applied-filters { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-4); }
.filter-chip {
  display: inline-flex; align-items: center; gap: var(--sp-2); max-width: 100%; min-height: 32px;
  padding: 4px 10px; border: 1px solid var(--accent-line); border-radius: var(--r-sm);
  background: var(--accent-wash); color: var(--ink); text-decoration: none; font-size: var(--text-sm);
}
.filter-chip span { overflow-wrap: anywhere; }
.filter-chip svg { flex: none; }
.filter-chip:hover { border-color: var(--accent); color: var(--ink); }
.filter-clear { font-size: var(--text-sm); font-weight: 640; padding: 6px; }
.list-summary { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--sp-2); margin: var(--sp-3) 0; font-size: var(--text-sm); }
/* After a pager, facet or empty-state link the script focuses the summary and scrolls
 * it to the top of the viewport. The top of the viewport is under the sticky app bar
 * (52px), and on a role under its sticky tabs as well, which hid the new count and the
 * focus ring behind them. `--list-pinned` is how tall the bars over the list are: the
 * app bar alone here, and the tabs added where the list sits under them (app.css).
 * A removed chip or Clear all hands focus to a chip or the Filters toggle, which the
 * script scrolls into view the same way when it is out of sight, and it reads this
 * margin to tell whether the bars cover it. */
[data-list-summary],
.candidate-list .filter-toggle,
.candidate-list .filter-chip {
  scroll-margin-top: calc(var(--list-pinned, 52px) + var(--sp-3));
}
/* The live region. It carries `sr-only` from the server and keeps it while a request is
 * in flight: shown, it pushed the search box down under the caret on every update. The
 * script unhides it only to report a failure with its Retry link. It is never
 * `display: none`, which would take the region out of the accessibility tree between
 * announcements. The busy state shows through the dimmed table below instead. */
.list-status { color: var(--ink-soft); }
.candidate-list [aria-busy="true"] .list-table { opacity: .6; }
.list-table table { min-width: 850px; }
/* The sticky header draws its divider as a shadow. With collapsed borders the rule
 * under a `<th>` belongs to the table grid and scrolls away with it, which left rows
 * sliding under the labels with no line between them. */
.list-table th {
  position: sticky; top: 0; z-index: 1;
  border-bottom: 0; box-shadow: inset 0 -1px 0 var(--line);
  background: var(--surface);
}
/* Forced colours drop every box shadow, and with it the only divider under the header.
 * A border on a box inside the sticky cell survives them and moves with the cell. */
@media (forced-colors: active) {
  .list-table th::after {
    content: ""; position: absolute; inset: auto 0 0;
    border-bottom: 1px solid CanvasText;
  }
}
.list-table th a { display: inline-flex; align-items: center; gap: var(--sp-2); color: var(--ink-soft); text-decoration: none; padding: 6px 0; }
.list-table th[aria-sort] a { color: var(--accent); }
.list-table td:nth-child(2) { font-variant-numeric: tabular-nums; white-space: nowrap; }
.list-table td:first-child { min-width: 200px; }
/* Counts read down a column when their digits line up at the right. */
.list-table .col-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.list-table .score-num small { color: var(--ink-muted); }
/* The scoring summary download: the row's action, in a column as narrow as its content
 * and set to the table's right edge, heading and all. `width: 1%` with `nowrap` is the
 * auto-layout idiom for "only as wide as the content". Every pixel this column takes
 * comes out of the ones a reader is scanning, which is why the control is the icon
 * alone. The heading sets the floor: "PDF" held it to 54px, and "Summary" — the name
 * the founder asked for on 2026-09-20, the thing rather than its file format — holds
 * it to 85. Measured at a 1280px window after the rename: the table still fits without
 * sideways scroll and the owner cell sits at 106px, where 87 is what broke "Rae Cruz"
 * across two lines when the first cut made this column 93px wide. */
.list-table .col-action {
  width: 1%; padding-left: var(--sp-2);
  text-align: right; white-space: nowrap;
  /* The containing block for an unscored row's `sr-only` sentence. Without it that
   * absolutely positioned span answers to an ancestor outside the table's scroll box,
   * is not clipped by it, and — sitting at the far end of an 850px table — gave a
   * 375px phone 492px of sideways page scroll. */
  position: relative;
}
.btn.sm.cell-pdf { width: 30px; padding: 0; color: var(--ink-soft); }
.btn.sm.cell-pdf:hover { color: var(--accent-ink); }
/* Under a finger it is the one control in the row that is not the row's own link, and
 * 30px is a mouse's target. The filter chips make the same allowance on a phone. */
@media (pointer: coarse) {
  .btn.sm.cell-pdf { width: 40px; min-height: 40px; }
}
/* An owner's name stays on one line under its chip. It always had room to, until the
 * column above arrived; measured at a 1280px window, the owner cell fell from 95px to
 * 87 and "Rae Cruz" became two lines on every row. A name long enough to need more
 * takes it from the candidate and assessment cells, which wrap by design. */
.list-table .cell-owner { white-space: nowrap; }
/* "Scroll across" is a fact about the table's box, not about the viewport: with the
 * sidebar open the table overflows windows far wider than a phone. So the hint answers
 * the list region's width, and appears where the table's 850px minimum and the
 * wrapper's two 1px borders stop fitting. */
.candidate-list { container-type: inline-size; }
.table-scroll-hint { display: none; margin: 0 0 var(--sp-2); color: var(--ink-muted); font-size: var(--text-sm); }
@container (width < 852px) {
  .table-scroll-hint { display: block; }
}
/* The page scrolls; the table does not. The rows used to scroll inside a box capped at
 * 65% of the viewport, which on a tall window left the lower third of the page empty
 * under a list that was still scrolling inside itself — the founder read it as a
 * broken layout. A page is as tall as its rows, and the pager decides how many there
 * are. The table keeps only its sideways overflow. */
@media (min-width: 641px) and (min-height: 700px) {
}
@media (max-width: 640px) {
  .filterbar { padding: var(--sp-3); }
  .filter-fields { grid-template-columns: 1fr; }
  .filter-chip { min-height: 40px; }
}
/* On the narrowest phones the Search button beside the box left it a 110px slot that
 * cut off its own placeholder. There the button takes the row under the box, which is
 * where it comes in the markup, so the order you see is still the order you tab. The
 * width is the list region's: under 300px the box beside the button would be narrower
 * than about 150px (a 360px phone), where a typed email scrolls out of sight at once. */
@container (width < 300px) {
  .filter-search, .filter-submit { grid-column: 1 / -1; }
  .filter-submit { grid-row: 2; justify-self: start; }
  .filter-panel { grid-row: 3; }
}
/* On paper there is nothing to scroll sideways: the box cut the columns past its right
 * edge. The header's divider goes back to a border, which prints whether or not the
 * reader prints backgrounds. */
@media print {
  .list-table { overflow: visible; }
  .list-table th { position: static; border-bottom: 1px solid var(--line); box-shadow: none; }
  .table-scroll-hint { display: 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); }
/* A row of controls that submits as one form — a field or two and a button — sitting
 * in a table cell or under a heading. The base rule above gives every input and select
 * the block width, which is right for a form and wrong for a row: here they take their
 * content's width, and the one control that is typed into, the address, keeps room to
 * read what was typed. Wraps rather than overflows on a narrow screen. */
.inline-form { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); max-width: 100%; }
.inline-form input:not([type="hidden"]), .inline-form select { width: auto; }
.inline-form select { flex: 0 0 auto; min-width: 9.5em; }
.inline-form input[type="email"] { flex: 1 1 240px; min-width: 0; }
/* A label, an owner chip and the control that changes it, on one line. */
.owner-line { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.owner-line .cell-owner { display: inline-flex; align-items: center; gap: var(--sp-2); }
@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 role's open link ═══════════════════════════════════════════════════════
 * One link anyone may register through, above the private links. Green while it is
 * taking registrations, amber when its places are used up, grey once it has stopped.
 */
.pill.open { border-color: var(--ok-line); background: var(--ok-bg); color: var(--ok-fg); }
.pill.full { border-color: var(--warn-line); background: var(--warn-bg); color: var(--warn-fg); }
.pill.closed { color: var(--ink-muted); background: var(--surface-sunk); }
.open-link { display: grid; gap: var(--sp-3); padding: var(--sp-4) var(--sp-5); }
.open-link .invite-form { padding: 0; background: none; border-bottom: 0; }
.open-link-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-3);
}
.invites-heading { font-size: var(--text-md); line-height: 1.35; }
.open-link-head .invites-heading { margin: 0; }
.open-link-head .hint { margin-top: var(--sp-1); }
.open-link-meta {
  margin: 0; color: var(--ink-muted); font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
}
.open-link-warn {
  margin: 0; padding: var(--sp-2) var(--sp-3); border-radius: var(--r-sm);
  background: var(--warn-bg); color: var(--warn-fg); font-size: var(--text-sm);
}
.open-link-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); }
.open-link-actions input[type="number"] { width: 6.5em; }

/* ══ Invitations ═══════════════════════════════════════════════════════════
 * A list of people pasted or uploaded on the Invites tab, and the address each private
 * link was made out to under its name (POR-247).
 */
.invite-list { display: grid; gap: var(--sp-3); padding: var(--sp-4) var(--sp-5); }
.invite-list .field { margin: 0; }
.invite-list > .btn { justify-self: start; }
.invite-list-row {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 12em);
  gap: var(--sp-3); align-items: start;
}
.invite-address { color: var(--ink-muted); font-size: var(--text-xs); overflow-wrap: anywhere; }
.invite-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.invite-send { display: grid; gap: var(--sp-1); margin-bottom: var(--sp-4); }
.invite-send label { display: inline-flex; align-items: center; gap: var(--sp-2); font-weight: 600; }
/* Where a link made out to someone has got to. Dio's email, then the candidate. */
.pill.sending { border-color: var(--warn-line); background: var(--warn-bg); color: var(--warn-fg); }
.pill.sending::before { animation: pulse 1.6s var(--ease-in-out) infinite; }
.pill.sent, .pill.reminded, .pill.registered, .pill.started {
  border-color: var(--accent-line); background: var(--accent-wash); color: var(--accent-ink);
}
.pill.send-failed { border-color: var(--bad-line); background: var(--bad-bg); color: var(--bad-fg); }
.pill.not-sent { color: var(--ink-muted); background: var(--surface-sunk); }
@media (max-width: 640px) {
  .invite-list-row { grid-template-columns: 1fr; }
}

/* ══ Confirmation ═════════════════════════════════════════════════════════ */
/* The product's own "are you sure", replacing the browser's. Same frame as the export
   dialog, narrower: a question, a sentence, two buttons. */

.confirm-dialog {
  position: fixed; inset: 50% auto auto 50%;
  width: min(440px, calc(100% - var(--sp-8))); max-width: none;
  margin: 0; padding: 0;
  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);
  animation: cmdk-in var(--t-base) var(--ease-out) both;
}
.confirm-dialog::backdrop { background: rgba(4, 18, 16, .58); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); }
.confirm-body { padding: var(--sp-5); }
.confirm-body h2 { margin: 0; font-size: var(--text-lg); line-height: 1.3; }
.confirm-body p { margin: var(--sp-3) 0 0; color: var(--ink-soft); font-size: var(--text-md); line-height: 1.55; }
.confirm-actions { display: flex; justify-content: flex-end; gap: var(--sp-2); flex-wrap: wrap; margin-top: var(--sp-5); }
@media (max-width: 640px) {
  .confirm-actions { flex-direction: column-reverse; }
  .confirm-actions .btn { width: 100%; }
}

/* ══ Exports ══════════════════════════════════════════════════════════════ */
/* The Export control above a candidate list, and the dialog it opens. The dialog
   is the same form the no-script page shows; only its frame is styled here. */

.list-tools { display: flex; justify-content: flex-end; align-items: center; gap: var(--sp-2); margin: 0 0 var(--sp-3); }
.export-dialog {
  position: fixed; inset: 50% auto auto 50%;
  width: min(560px, calc(100% - var(--sp-8))); max-width: none;
  max-height: calc(100dvh - var(--sp-8)); margin: 0; padding: 0; overflow: auto;
  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);
}
.export-dialog::backdrop { background: rgba(4, 18, 16, .58); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); }
.export-dialog-head {
  display: flex; justify-content: space-between; align-items: center; gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5); border-bottom: 1px solid var(--line);
}
.export-dialog-head h2 { margin: 0; font-size: var(--text-lg); }
.export-dialog .export-form { padding: var(--sp-5); }
.export-form { display: grid; gap: var(--sp-4); }
.export-choice { margin: 0; padding: 0; border: 0; min-width: 0; }
.export-choice legend { margin-bottom: var(--sp-2); color: var(--ink-soft); font-size: var(--text-sm); font-weight: 640; }
.export-choice .choice + .choice { margin-top: var(--sp-2); }
.choice {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--sp-3); align-items: start;
  padding: var(--sp-3) 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);
}
.choice:hover { border-color: var(--accent-line); background: var(--surface-raised); }
.choice:has(input:checked) { border-color: var(--accent); background: var(--accent-wash); box-shadow: 0 0 0 1px var(--accent); }
.choice:has(input:focus-visible) { outline: 3px solid color-mix(in srgb, var(--focus) 28%, transparent); outline-offset: 2px; }
.choice input { margin: 3px 0 0; }
.choice-copy { display: grid; gap: 2px; min-width: 0; }
.choice-copy > span { color: var(--ink-muted); font-size: var(--text-sm); line-height: 1.45; }
.export-scope { margin: 0; font-size: var(--text-md); }
.export-actions { display: flex; justify-content: flex-end; gap: var(--sp-2); flex-wrap: wrap; }
.export-status { margin: 0; font-size: var(--text-sm); color: var(--ink-soft); }
.export-status.is-failed { color: var(--bad-fg); }
@media (max-width: 640px) {
  .export-actions { flex-direction: column-reverse; }
  .export-actions .btn { width: 100%; }
}

/* 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; }
/* Who a candidate is interviewing with, beside Dio's name, where the workspace set one. */
.topbar-company {
  min-width: 0; margin-right: auto; padding-left: var(--sp-5);
  border-left: 1px solid var(--line);
  color: var(--ink-soft); font-size: var(--text-sm); font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.topbar-company + .chip { flex: none; white-space: nowrap; }

.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); }
/* The DIO icon, from the logo package. Shown as drawn: no tile behind it, no shadow,
 * no recolouring — the package's one rule. The box is the icon's clear space. */
.brand-mark {
  width: 30px; height: 30px; flex: 0 0 30px;
  display: grid; place-items: center;
}
.brand-mark img { display: block; width: 100%; height: 100%; }
.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; overflow-wrap: anywhere; }
.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-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; }

/* ══ 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); }

/* A candidate list under the tabs scrolls its summary to just below them, not just below
 * the app bar (see `[data-list-summary]` in components.css). The tabs pin 52px down,
 * under the bar, and are one `.tab` tall: the bar's 4px top padding, the tab's 12px
 * paddings less a pixel at the bottom, its 2px underline overlapping the bar's 1px rule
 * by a pixel, and one line of `--text-md` text at the body's line height of 1.6. */
.tabs ~ .candidate-list {
  --list-pinned: calc(52px + var(--sp-1) + 2 * var(--sp-3) + 1px + 1.6 * var(--text-md));
}

/* ── 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,
#qa textarea {
  min-height: 4.6em;
  line-height: 1.5;
  resize: vertical;
}
.qa-own { display: grid; gap: var(--sp-2); margin-top: var(--sp-3); }

/* What Dio can tell candidates, on Review & publish: each answer under the question it
 * answers, because the last look before candidates ask has to show the words. */
.qa-summary { display: grid; gap: var(--sp-3); margin: 0; }
.qa-summary dt { font-weight: 650; font-size: var(--text-sm); }
.qa-summary dd { margin: 2px 0 0; color: var(--ink-soft); }

/* ══ 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; }

/* ── A .comp that is not a row in the chooser ───────────────────────────────
 * One block on its own: a competency's rubric page, and the arc's question groups
 * before they got a card of their own. It has no checkbox and no weight field, so
 * the three-column grid has nothing to put in two of its columns — and, worse, the
 * dimming rule above reads "contains no checked checkbox" as "switched off" and
 * rendered the whole block at 62% opacity. That is what made the rubric editor and
 * every question on the arc page look greyed out and unclickable.
 */
.comp.solo { display: block; padding: var(--sp-5); }
.comp.solo:not(:has(input[type="checkbox"]:checked)) { opacity: 1; }
.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); }
}

/* ── The arc's questions ────────────────────────────────────────────────────
 * The page is a list of eight sentences somebody is checking the wording of, and
 * it read as eight identical grey boxes under two grey headings, all of it at 62%
 * opacity. Three things fix that and they are all here: a card per category so the
 * groups are objects rather than gaps, a number down the left so a question can be
 * referred to, and a field that looks like the sentence it holds instead of like an
 * empty form.
 */
.qgroup {
  padding: var(--sp-5);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface);
}
.qgroup + .qgroup { margin-top: var(--sp-4); }
.qgroup-head { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.qgroup-head h3 { margin: 0; font-size: var(--text-lg); }
.qgroup-count {
  margin-left: auto; color: var(--ink-faint);
  font-size: var(--text-xs); font-variant-numeric: tabular-nums;
}
.qgroup-hint {
  max-width: 78ch; margin: var(--sp-2) 0 0;
  color: var(--ink-soft); font-size: var(--text-sm); line-height: 1.55;
}
.qgroup-list { display: grid; gap: var(--sp-2); margin-top: var(--sp-4); }

/* The number is the row's anchor, not a bullet: it keeps its column when the question
 * wraps to three lines, which a list marker would not. */
.qgroup-list .q-row {
  display: grid; grid-template-columns: 1.65rem minmax(0, 1fr); gap: var(--sp-3);
  align-items: start; padding: 0; border: 0; background: none;
}
.q-num {
  padding-top: calc(var(--sp-2) + 1px);
  color: var(--ink-faint);
  font-size: var(--text-sm); font-weight: 700; font-variant-numeric: tabular-nums;
  text-align: right;
}
/* Field-shaped only once you are in it. At rest it is the sentence, on a quiet rule,
 * so the eye reads eight questions rather than eight inputs. */
.qgroup-list .q-text {
  min-height: 0; padding: var(--sp-2) var(--sp-3);
  border: 1px solid transparent; border-radius: var(--r-sm);
  background: var(--surface-sunk);
  font-size: var(--text-md); line-height: 1.55;
  transition:
    border-color var(--t-base) var(--ease-out),
    background var(--t-base) var(--ease-out);
}
.qgroup-list .q-text:hover { border-color: var(--line); }
.qgroup-list .q-text:focus {
  border-color: var(--accent); background: var(--surface);
}
/* `rows="2"` is the floor for a browser without `field-sizing`, and it leaves a blank
 * line under every one-line question — eight of them is a column of holes. Where the
 * property is supported the box is exactly as tall as the sentence in it, and grows as
 * you type, so the resize grabber has nothing left to do. */
@supports (field-sizing: content) {
  .qgroup-list .q-text { field-sizing: content; resize: none; }
}

/* ── Scoring: what each category is worth ───────────────────────────────────
 * A card per category, with the normalised share beside the slider — the number
 * a recruiter sets is relative and the number that ships is not, and showing only
 * the first is how somebody approves a split they never saw.
 */
.scorerows { display: grid; gap: var(--sp-4); }
.scorerow {
  padding: var(--sp-5);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface);
}
.scorerow-head { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.scorerow-head h3 { margin: 0; font-size: var(--text-lg); }
.scorerow-share {
  margin-left: auto;
  color: var(--ink); font-size: var(--text-xl); font-weight: 760;
  font-variant-numeric: tabular-nums;
}
.scorerow-hint {
  max-width: 78ch; margin: var(--sp-2) 0 var(--sp-4);
  color: var(--ink-soft); font-size: var(--text-sm); line-height: 1.55;
}
.scorerow input[type="range"] { width: 100%; }

/* ── Build notes ────────────────────────────────────────────────────────────
 * Diagnostics, under the content and shut. See `views._notes`.
 */
.notes {
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface-sunk);
}
.notes > summary {
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  cursor: pointer; font-size: var(--text-sm);
}
.notes > summary::-webkit-details-marker { display: none; }
.notes-mark { display: inline-flex; color: var(--ink-faint); }
.notes-hint { color: var(--ink-faint); font-size: var(--text-xs); }
.notes ul {
  margin: var(--sp-3) 0 0; padding-left: calc(var(--sp-5) + var(--sp-2));
  color: var(--ink-soft); font-size: var(--text-sm); line-height: 1.6;
}
.notes li + li { margin-top: var(--sp-1); }

/* ── Published weights ──────────────────────────────────────────────────────
 * A share reads as a length. See `views._weight_bars`.
 */
.weights {
  display: grid; gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface);
}
.weight-row {
  display: grid; grid-template-columns: minmax(8rem, 15rem) minmax(0, 1fr) 3.25rem;
  gap: var(--sp-4); align-items: center;
}
.weight-name { font-weight: 640; }
/* A `<progress>`, not a div with an inline width: `style-src` has no `unsafe-inline`,
 * so the attribute is dropped and the bar renders empty in a browser while looking
 * right everywhere a CSP does not apply. The pseudo-elements are the only way to paint
 * one, and all three are needed — WebKit splits bar and value, Firefox has neither. */
.weight-track {
  appearance: none; -webkit-appearance: none;
  width: 100%; height: 8px;
  border: 0; border-radius: 999px;
  background: var(--canvas-deep);
  overflow: hidden;
}
.weight-track::-webkit-progress-bar { background: var(--canvas-deep); border-radius: 999px; }
.weight-track::-webkit-progress-value { background: var(--accent); border-radius: 999px; }
.weight-track::-moz-progress-bar { background: var(--accent); border-radius: 999px; }
.weight-pct {
  color: var(--ink); font-weight: 700; font-variant-numeric: tabular-nums;
  text-align: right;
}
@media (max-width: 640px) {
  .weight-row { grid-template-columns: minmax(0, 1fr) 3.25rem; gap: var(--sp-2); }
  .weight-track { grid-column: 1 / -1; }
}

/* ── What will be asked ─────────────────────────────────────────────────────
 * The same eight sentences as the editor, numbered the same way, on the page that
 * freezes them. It was a bare <ol> and read as a paragraph with numbers in it.
 */
.asked {
  display: grid; gap: var(--sp-1);
  margin: 0; padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface);
  list-style: none;
}
.asked li {
  display: grid; grid-template-columns: 1.65rem minmax(0, 1fr); gap: var(--sp-3);
  align-items: baseline;
  padding: var(--sp-2) 0;
}
.asked li + li { border-top: 1px solid var(--line); }
.asked-n {
  color: var(--ink-faint);
  font-size: var(--text-sm); font-weight: 700; font-variant-numeric: tabular-nums;
  text-align: right;
}
.asked-text { line-height: 1.55; }
.asked-tag {
  margin-left: var(--sp-2); padding: 1px 7px;
  border-radius: var(--r-xs); background: var(--canvas-deep);
  color: var(--ink-faint); font-size: var(--text-2xs); white-space: nowrap;
}

.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 ═══════════════════════════════════════════════════════════ */

/* The open link's copy icon, beside the role's name in the header and on a list row.
 * An icon and nothing else: the name says which link, the toast says it was copied. */
.link-copy {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; margin-left: var(--sp-2); padding: 0;
  border: 0; border-radius: var(--r-sm); background: transparent;
  color: var(--ink-faint); cursor: pointer; vertical-align: middle;
  transition: color var(--t-fast) var(--ease-out), background var(--t-fast) var(--ease-out);
}
.link-copy:hover { background: var(--accent-wash); color: var(--accent); }
.link-copy:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.page-head h1 .link-copy { width: 34px; height: 34px; }

.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; }
/* The address a link was made out to: shown, not for changing. */
.candidate-fields input[readonly] { background: var(--surface-sunk); color: var(--ink-soft); cursor: default; }
.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);
}
/* The way back into an interview still running (#154). */
.interview-rejoin { justify-self: center; margin-top: var(--sp-5); }
/* "How was this interview?" — below the afterword, optional, one tap. */
.interview-rating,
.interview-rating-thanks {
  margin: var(--sp-5) auto 0;
  color: var(--ink-soft);
}
.interview-rating { padding: 0; border: 0; min-width: 0; }
.interview-rating > legend { margin: 0 auto var(--sp-2); padding: 0; }
.interview-rating > p[role="alert"] { margin: var(--sp-2) 0 0; }
.interview-rating-scale {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  align-items: center;
  justify-content: center;
  font-size: var(--text-sm);
}
.interview-rating-scale .btn[aria-pressed="true"] {
  --btn-line: var(--accent-line);
  --btn-bg: var(--accent-wash);
  --btn-fg: var(--accent-ink);
}

/* ══ 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 ═══════════════════════════════════════════════════════
 * One card. Three tabs for where the job description comes from, the box that takes
 * it, and — only once there is one — the details, already filled in from it. The tabs
 * are the role page's underline tabs, not bordered tiles: the choice is the least
 * important thing on the page, and the tiles made it look like the main decision.
 */

.create-job-form { max-width: 720px; }
.create-card { padding: 0; overflow: hidden; }

.src-tabs {
  display: flex; gap: var(--sp-4);
  padding: 0 var(--sp-6);
  border-bottom: 1px solid var(--line);
  overflow-x: auto; scrollbar-width: none;
}
.src-tab {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-4) 2px calc(var(--sp-4) - 2px);
  margin-bottom: -1px;
  border: 0; border-bottom: 2px solid transparent;
  background: none; color: var(--ink-muted);
  font-size: var(--text-md); font-weight: 600; white-space: nowrap;
  cursor: pointer;
  transition: color var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out);
}
.src-tab:hover { color: var(--ink); }
.src-tab[aria-selected="true"] { color: var(--accent-ink); border-bottom-color: var(--accent); }
.src-tab:focus-visible {
  outline: 3px solid color-mix(in srgb, var(--focus) 28%, transparent);
  outline-offset: -3px; border-radius: var(--r-xs);
}
.src-tab:disabled { opacity: .58; cursor: wait; }
.src-tab-short { display: none; }

.src-body { padding: var(--sp-6); }
.src-row { display: flex; gap: var(--sp-2); }
.src-row input { flex: 1; min-width: 0; }
.src-status {
  display: flex; align-items: center; gap: var(--sp-2);
  margin-top: var(--sp-2);
  color: var(--ink-soft); font-size: var(--text-sm);
}
.src-status:empty { display: none; }
.src-error {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3);
  margin: var(--sp-2) 0 0;
  color: var(--bad-fg); font-size: var(--text-sm); font-weight: 600;
}
.mini-spin {
  flex: none; width: 14px; height: 14px;
  border: 2px solid var(--accent-wash); border-right-color: var(--accent);
  border-radius: 50%; animation: activity-spin .75s linear infinite;
}
/* An action that sits in a line of text: a button, styled as the link it reads as. */
.linkbtn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 0; border: 0; background: none;
  color: var(--accent-ink); font-size: var(--text-xs); font-weight: 640;
  cursor: pointer;
}
.linkbtn:hover { text-decoration: underline; }
.src-error .linkbtn { font-size: var(--text-sm); }

/* An imported or drafted posting is a preview until somebody asks to edit it. The fade
 * says there is more; "Edit text" is how to read it. */
.src-input + .jd-view { margin-top: var(--sp-4); }
.jd-preview {
  position: relative;
  max-height: 11.4em; overflow: hidden;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface-sunk); color: var(--ink-soft);
  font-size: var(--text-md); line-height: 1.6;
  white-space: pre-line; overflow-wrap: anywhere;
}
.jd-preview::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2.6em;
  background: linear-gradient(transparent, var(--surface-sunk));
  pointer-events: none;
}
.jd-meta {
  display: flex; justify-content: space-between; align-items: center;
  flex-wrap: wrap; gap: var(--sp-2) var(--sp-4);
  margin-top: var(--sp-2);
  color: var(--ink-muted); font-size: var(--text-xs);
}
.jd-actions { display: inline-flex; gap: var(--sp-4); }
.create-card .source-warning { margin: var(--sp-4) 0 0; }

.details { padding: var(--sp-6); border-top: 1px solid var(--line); }
.field-pair {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-4); margin-bottom: var(--sp-5);
}
.field-pair .field { margin-bottom: 0; }
/* Where a filled-in title came from, beside it, so it is checked rather than trusted. */
.from-posting {
  display: inline-flex; align-items: center; gap: 4px;
  color: var(--accent-ink); font-size: var(--text-xs); font-weight: 600;
}
.from-posting.is-reading { color: var(--ink-muted); font-weight: 550; }

/* Two interview types, both visible: a dropdown hid the second one. */
.round-choice { min-width: 0; margin: 0 0 var(--sp-5); padding: 0; border: 0; }
.round-choice > legend { padding: 0; }
.round-choice .hint { display: block; margin-top: var(--sp-2); }
.seg {
  display: inline-flex; gap: 2px; padding: 3px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface-sunk);
}
.seg-opt {
  position: relative;
  display: inline-flex; align-items: center;
  min-height: 34px; padding: 0 var(--sp-4);
  border-radius: 7px;
  color: var(--ink-muted); font-size: var(--text-md); font-weight: 600; white-space: nowrap;
  cursor: pointer;
}
.seg-opt input {
  position: absolute; inset: 0;
  width: 100%; min-height: 0; margin: 0; padding: 0;
  opacity: 0; cursor: pointer;
}
.seg-opt:has(input:checked) {
  background: var(--surface); color: var(--accent-ink);
  box-shadow: 0 0 0 1px var(--accent), var(--shadow-xs);
}
.seg-opt:has(input:focus-visible) {
  outline: 3px solid color-mix(in srgb, var(--focus) 28%, transparent);
  outline-offset: 2px;
}
.form-actions.end { justify-content: flex-end; }

/* Without JavaScript nothing can read the posting, so the details are simply there. */
.create-fallback { padding: var(--sp-6); }
.create-fallback > .hint { display: block; margin: 0 0 var(--sp-4); }

.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); } }

/* 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; }
  .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); }
  .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); }
  .build-panel { grid-template-columns: 1fr; }
  .src-tabs { gap: var(--sp-3); padding: 0 var(--sp-4); }
  /* A tab with a short label shows it; its full one stays its name, read not seen. */
  .src-tab:has(.src-tab-short) .src-tab-label {
    position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap;
  }
  .src-tab-short { display: inline; }
  .src-body, .details, .create-fallback { padding: var(--sp-4); }
  .field-pair { grid-template-columns: 1fr; gap: var(--sp-5); }
  .seg { display: flex; }
  .seg-opt { flex: 1 1 auto; justify-content: center; padding: 0 var(--sp-3); }
  .form-actions.end .btn { flex: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .task-progress > span { width: 100%; animation: none; opacity: .65; }
  .activity-spinner, .mini-spin, .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 ──────────────────────────────────────────────────────────────
 * Three lines beside the avatar, one kind of fact on each: the name and where the
 * review stands; the role and the interview type; the date, the length and the
 * email. The avatar sits level with the name. Centred on the block, it drifted
 * below the name whenever the lines under it wrapped. */

.candidate .candhead {
  position: relative;
  display: flex; align-items: flex-start; gap: var(--sp-4); margin-bottom: var(--sp-5);
}
.candidate .cand-avatar {
  flex: none; width: 48px; height: 48px;
  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-base); font-weight: 760; letter-spacing: var(--tracking-snug);
}
.candidate .candhead-copy {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column; gap: 6px;
}
.candidate .candhead-copy h1 {
  margin: 0; font-size: var(--text-2xl); line-height: 1.2;
  letter-spacing: var(--tracking-tight);
}
.candidate .candhead-title,
.candidate .candhead-role,
.candidate .candhead-facts { display: flex; flex-wrap: wrap; align-items: center; }
.candidate .candhead-title { gap: 6px var(--sp-3); }
.candidate .candhead-role { gap: 6px 10px; }
.candidate .candhead-job { color: var(--ink-soft); font-size: var(--text-base); font-weight: 600; }
/* Separated by flex gap, never "·": a narrow page breaks the line between facts, and a
 * separator has nowhere to hang. */
.candidate .candhead-facts {
  gap: var(--sp-1) 18px; margin-top: 2px;
  color: var(--ink-muted); font-size: var(--text-sm);
}
.candidate .candhead-fact { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
/* A long address wraps on a phone; its icon and copy button stay on its first line. */
.candidate .candhead-email { min-width: 0; white-space: normal; align-items: flex-start; }
.candidate .candhead-email > .i { margin-top: 2px; }
.candidate .candhead-email .candhead-clip { margin-top: -4px; }
.candidate .candhead-email a { color: inherit; text-decoration: none; overflow-wrap: anywhere; }
.candidate .candhead-email a:hover { color: var(--ink); text-decoration: underline; }
.candidate .candhead-clip {
  flex: none; display: inline-grid; place-items: center;
  width: 26px; height: 26px; margin-left: -2px; padding: 0;
  border: 0; border-radius: var(--r-xs); background: transparent;
  color: var(--ink-muted); cursor: pointer;
}
.candidate .candhead-clip:hover { background: var(--surface-sunk); color: var(--ink); }
/* A mouse's target, and too small for a finger. */
@media (pointer: coarse) {
  .candidate .candhead-clip { width: 40px; height: 40px; }
}
.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 .candhead-files > summary { padding-inline: var(--sp-3) 10px; }
.candidate .candmenu-caret { transform: rotate(90deg); transition: transform var(--t-fast) var(--ease-out); }
.candidate .candmenu[open] .candmenu-caret { transform: rotate(-90deg); }
.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);
}
/* The Download menu: the interview's files as a short list rather than the panel the
 * "More" menu opens. After `.candmenu-pop`, which it narrows. */
.candidate .candmenu-list {
  display: grid; gap: 2px;
  width: 248px; padding: 6px;
}
.candidate .candmenu-item {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  padding: 9px 10px; border-radius: var(--r-xs);
  color: var(--ink); font-size: var(--text-sm); font-weight: 600; text-decoration: none;
}
.candidate .candmenu-item:hover { background: var(--surface-sunk); color: var(--ink); }
.candidate .candmenu-kind {
  color: var(--ink-muted); font-size: var(--text-2xs); font-weight: 700;
  letter-spacing: var(--tracking-wide);
}
.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);
}
/* "Review & decide" for a browser without JavaScript, under the score it acts on. */
.candidate .cand-decide { margin: var(--sp-3) 0 var(--sp-5); }

.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: calc(48px + var(--sp-4)); 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;
  }
}

/* ══ Settings area ═══════════════════════════════════════════════════════════
 * A sticky side navigation beside the sections. On the settings page the links are
 * in-page anchors and the script moves the current mark as the reader scrolls; on
 * the Team and Exports pages they lead back. Under 900px the column becomes a
 * scrollable row pinned under the app bar, the way the role tabs are.
 */

.settings-layout {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr);
  gap: var(--sp-8);
  align-items: start;
  margin-top: var(--sp-6);
}
.settings-nav {
  position: sticky;
  top: calc(var(--header-h) + var(--sp-5));
}
.settings-nav ul { display: grid; gap: 2px; margin: 0; padding: 0; list-style: none; }
.settings-nav a {
  display: block;
  padding: var(--sp-2) var(--sp-3);
  border-left: 2px solid transparent;
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  color: var(--ink-muted);
  font-size: var(--text-md); font-weight: 570;
  text-decoration: none;
  transition: color var(--t-fast) var(--ease-out), background var(--t-fast) var(--ease-out);
}
.settings-nav a:hover { color: var(--ink); background: var(--surface-sunk); }
.settings-nav a[aria-current] { color: var(--accent-ink); border-left-color: var(--accent); background: var(--accent-wash); }
.settings-nav a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.settings-body { min-width: 0; }
.settings-body > .section:first-child { margin-top: 0; }
.settings-body .section { scroll-margin-top: calc(var(--header-h) + var(--sp-5)); }

@media (max-width: 900px) {
  .settings-layout { grid-template-columns: minmax(0, 1fr); gap: var(--sp-5); }
  .settings-nav {
    top: var(--header-h);
    z-index: 20;
    margin: 0 calc(-1 * var(--sp-2));
    padding: var(--sp-2);
    background: var(--canvas);
    border-bottom: 1px solid var(--line);
  }
  .settings-nav ul {
    display: flex; gap: var(--sp-1);
    overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none;
  }
  .settings-nav ul::-webkit-scrollbar { display: none; }
  .settings-nav a { white-space: nowrap; border-left: 0; border-radius: var(--r-sm); }
  .settings-nav a[aria-current] { border-left: 0; }
}

/* The settings area uses the whole panel and never scrolls the window. The title, any
 * notices, and the column stay where they are; the sections scroll in a pane of their
 * own, so picking a section moves the content and nothing else. Only above the phone
 * breakpoint — on a narrow screen the page flows as any other and the column pins. */
@media (min-width: 901px) {
  /* The panel takes the viewport (less its own margins) and the page takes whatever the
   * app bar leaves, so there is nothing for the window to scroll — measured by the
   * browser rather than added up here, where a border would be one pixel off and the
   * window would still move by that pixel. */
  .app-body:has(> main.shell.settings) { height: calc(100dvh - 2 * var(--sp-2)); }
  .shell.settings {
    width: calc(100% - var(--sp-10));
    flex: 1 1 auto; min-height: 0;
    padding-bottom: var(--sp-6);
    display: flex; flex-direction: column;
    overflow: hidden;
  }
  .shell.settings > * { flex: none; }
  .shell.settings .settings-layout { flex: 1 1 auto; min-height: 0; margin-top: var(--sp-5); }
  .shell.settings .settings-nav { position: static; }
  .shell.settings .settings-body {
    /* The containing block for anything absolutely positioned inside — the visually
     * hidden label of an empty table heading, say. Without it such an element is placed
     * against the page instead, below the fold of this pane, and stretches the whole
     * document into a scroll of empty space under a pane that scrolls on its own. */
    position: relative;
    height: 100%; min-height: 0;
    overflow-y: auto; overscroll-behavior: contain;
    padding: 0 var(--sp-3) var(--sp-10) 0;
    scroll-behavior: smooth;
  }
  .shell.settings .settings-body .section { scroll-margin-top: var(--sp-2); }
}


/* ══ Integrations ═══════════════════════════════════════════════════════════ */

/* The one card a secret is ever rendered in: the accent wash so it reads as the thing
 * to act on, and the value selectable whole, because a key half-selected is a key half
 * pasted. Inline `style=` is not an option under the CSP; this is where the rule lives.
 * Not `.reveal`, which base.css already uses for the entrance animation. */
.secret-card {
  border-color: var(--accent-line);
  background: var(--accent-wash);
  margin-bottom: var(--sp-4);
}
.secret-title { display: block; margin-bottom: var(--sp-2); font-weight: 660; color: var(--accent-ink); }
.secret-card p { margin: 0 0 var(--sp-2); font-size: var(--text-sm); color: var(--ink-soft); }
.secret-value { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin-top: var(--sp-3); }
.secret-code {
  flex: 1 1 auto;
  min-width: 0;
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--accent-line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--text-sm);
  overflow-wrap: anywhere;
  user-select: all;
  -webkit-user-select: all;
}

/* The key form's three short fields side by side; the Add form's one checkbox per
 * event, each with its meaning, so the list reads as a list. */
.integ-fields {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: var(--sp-4);
  margin-bottom: var(--sp-5);
}
.integ-fields .field { margin-bottom: 0; }
.event-choices { margin: 0 0 var(--sp-5); padding: 0; border: 0; min-width: 0; }
.event-choices legend { padding: 0; }
.event-choice {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  margin: var(--sp-2) 0;
  font-size: var(--text-md);
  color: var(--ink-soft);
}
.event-choice input { margin-top: 4px; }
.event-choice code { color: var(--ink); }
.integ-subhead { margin: var(--sp-6) 0 0; font-size: var(--text-md); font-weight: 650; }
.integ-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.integ-actions form { margin: 0; }

/* The delivery and event logs' filters: a row of labelled selects and Apply, a GET
 * form like every list page's, with nothing to swap live. */
.integ-filters { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--sp-3); }
.integ-filter { display: grid; gap: 4px; }
.integ-filter select { width: auto; min-width: 160px; }

/* ══ Notifications ══════════════════════════════════════════════════════════ */

/* One list shape for the page and the bell's panel: each entry a form whose button is
 * the whole row, because opening one marks it read — a POST, never a link. */
.notice-list { margin: 0; padding: 0; list-style: none; }
.notice + .notice { border-top: 1px solid var(--line); }
.notice form { margin: 0; }
.notice-open {
  display: grid;
  grid-template-columns: 10px minmax(0, 1fr) auto;
  gap: var(--sp-2) var(--sp-3);
  align-items: start;
  width: 100%;
  padding: var(--sp-3);
  border: 0;
  background: transparent;
  color: var(--ink-soft);
  cursor: pointer;
  font: inherit;
  text-align: left;
}
.notice-open:hover { background: var(--surface-sunk); }
.notice-open:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.notice-dot { width: 8px; height: 8px; margin-top: 6px; border-radius: 50%; }
.notice.is-unread .notice-dot { background: var(--accent); }
.notice.is-unread .notice-copy b { color: var(--ink); }
.notice-copy { display: grid; gap: 2px; min-width: 0; }
.notice-copy b { color: var(--ink-soft); font-weight: 600; }
.notice-line, .notice-time { color: var(--ink-muted); font-size: var(--text-sm); }
.notice-time { white-space: nowrap; }
/* On a phone the time goes under the title rather than beside it: a column of dates
 * squeezed the titles to two words a line. */
@media (max-width: 600px) {
  .notice-open { grid-template-columns: 10px minmax(0, 1fr); }
  .notice-time { grid-column: 2; }
}
.shell .notice-list {
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  overflow: hidden;
}

/* The settings pages. A preference row's controls keep their width: a select squeezed
 * to its first letter reads as a bug, and the label column is the one that can wrap. */
.pref-table select { min-width: 9.5rem; }
.pref-table td:not(:first-child), .pref-table th:not(:first-child) { white-space: nowrap; }
.kind-label { display: grid; gap: 2px; }
.kind-label .pill { justify-self: start; }
.group-row th {
  padding-top: var(--sp-4);
  color: var(--ink-faint);
  font-size: var(--text-2xs);
  font-weight: 700;
  letter-spacing: var(--tracking-caps);
  text-align: left;
  text-transform: uppercase;
}
.schedule-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--sp-4);
}
.schedule-grid .span-all { grid-column: 1 / -1; }
.choice-inline {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  margin: var(--sp-1) var(--sp-4) var(--sp-1) 0;
  color: var(--ink-soft);
  font-size: var(--text-md);
}
.rules-readonly { margin: 0; padding: 0; border: 0; min-width: 0; }
/* The candidate receipt, shown word for word before anyone switches it on. */
.receipt-preview {
  padding: var(--sp-3) var(--sp-4);
  border-left: 3px solid var(--line-strong);
  border-radius: var(--r-xs);
  background: var(--surface-sunk);
  color: var(--ink-soft);
  font-size: var(--text-sm);
}
.receipt-preview p { margin: var(--sp-2) 0 0; }
.follow-control { display: inline-flex; gap: var(--sp-1); }

/* ═══════════════════════════════════════════════════════════ the audit log ══
   `audit_views.py`. A list table (components.css) whose cells stack a name over the
   line that tells two of them apart — an email, a role, a browser — and whose "What
   happened" cell ends in a disclosure holding the entry's codes. Top-aligned, so a row
   with its details open keeps its first line level with its neighbours'. */
.audit-table td { vertical-align: top; }
.audit-when { white-space: nowrap; font-variant-numeric: tabular-nums; }
.audit-who, .audit-on, .audit-from {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.audit-what { display: block; }
.audit-details { margin-top: var(--sp-1); }
.audit-details > summary {
  width: fit-content;
  cursor: pointer;
  color: var(--ink-muted);
  font-size: var(--text-xs);
}
.audit-detail-list { margin: var(--sp-2) 0 0; font-size: var(--text-xs); }
.audit-detail-list > div {
  display: grid;
  grid-template-columns: 6.5rem minmax(0, 1fr);
  gap: var(--sp-3);
  padding: 2px 0;
}
.audit-detail-list dt { color: var(--ink-muted); }
.audit-detail-list dd {
  margin: 0;
  font-family: var(--font-mono);
  overflow-wrap: anywhere;
}

/* Home: the dashboard each person arranges for themselves.
 *
 * One twelve-column grid of cards, each at the width its reader chose (`.w-quarter` …
 * `.w-full`), folding to two columns and then one as the window narrows. Colour follows
 * `tokens.css` and nothing else: teal for what acts and for the one series a chart is
 * about, the score tiers only for scores, neutral ink for every change up or down.
 *
 * The chart colours are the only ones defined here. The hiring flow's five steps are an
 * ordinal ramp of the accent — one hue, darker as a step goes further — checked for
 * monotone lightness and for its lightest step clearing the surface, in light and in
 * dark, where the ramp flips so the later steps are the brighter ones. The quiet N/A
 * segment is the neutral ramp's own grey, lightened in dark mode so it stays apart from
 * the red beside it for a reader who cannot tell red from grey by hue.
 */

:root {
  --flow-1: #55bfab;
  --flow-2: #27a18e;
  --flow-3: #0e7a6d;
  --flow-4: #0a6156;
  --flow-5: #09443e;
  --tier-na: #a7b9b5;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --flow-1: #1d554c;
    --flow-2: #2a8a7a;
    --flow-3: #43c4ae;
    --flow-4: #66d6c2;
    --flow-5: #a5e8db;
    --tier-na: #8ba39d;
  }
}
:root[data-theme="dark"] {
  --flow-1: #1d554c;
  --flow-2: #2a8a7a;
  --flow-3: #43c4ae;
  --flow-4: #66d6c2;
  --flow-5: #a5e8db;
  --tier-na: #8ba39d;
}

/* ══ The head ════════════════════════════════════════════════════════════════ */

.dash-head {
  display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between;
  gap: var(--sp-4) var(--sp-6); margin-bottom: var(--sp-5);
}
.dash-hello { flex: 1 1 420px; min-width: 0; max-width: 720px; }
.dash-date { margin: 0 0 var(--sp-1); color: var(--ink-muted); font-size: var(--text-sm); font-weight: 600; }
.dash-hello h1 { font-size: var(--text-2xl); letter-spacing: var(--tracking-tight); }
.dash-brief {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  margin: var(--sp-3) 0 0; color: var(--ink-soft); font-size: var(--text-base); line-height: 1.55;
}
.dash-brief b { color: var(--ink); font-weight: 650; }
.dash-dio { flex: none; width: 22px; height: 22px; margin-top: 1px; }

.dash-controls { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.dash-live {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: 32px; padding: 0 var(--sp-3);
  border: 1px solid var(--accent-line); border-radius: var(--r-full);
  background: var(--accent-wash); color: var(--accent-ink);
  font-size: var(--text-xs); font-weight: 650; white-space: nowrap;
}
.dash-pulse {
  flex: none; width: 8px; height: 8px; border-radius: var(--r-full); background: var(--accent);
  animation: dash-pulse 2s var(--ease-out) infinite;
}
@keyframes dash-pulse {
  0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 55%, transparent); }
  70% { box-shadow: 0 0 0 7px color-mix(in srgb, var(--accent) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 transparent; }
}
@media (prefers-reduced-motion: reduce) { .dash-pulse { animation: none; } }

/* A segmented control of links: the choice is a URL. */
.seg {
  display: inline-flex; gap: 2px; padding: 3px;
  border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface-sunk);
}
.seg-option {
  display: inline-flex; align-items: center; min-height: 30px; padding: 0 var(--sp-3);
  border-radius: 7px; color: var(--ink-muted); font-size: var(--text-sm); font-weight: 600;
  text-decoration: none; white-space: nowrap;
}
.seg-option:hover { color: var(--ink); background: var(--surface); }
.seg-option[aria-current="true"] {
  background: var(--surface); color: var(--ink); font-weight: 650;
  box-shadow: var(--shadow-xs), var(--ring);
}
.seg-option:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }
.dash-customize { min-height: 38px; }
.dash-customize[aria-expanded="true"] { --btn-bg: var(--accent-wash); --btn-line: var(--accent-line); --btn-fg: var(--accent-ink); }

/* ══ Customize ═══════════════════════════════════════════════════════════════ */

.dash-customize-bar {
  display: grid; gap: var(--sp-3);
  margin-bottom: var(--sp-4); padding: var(--sp-4) var(--sp-5);
  border: 1px solid var(--accent-line); border-radius: var(--r-md);
  background: var(--surface); box-shadow: var(--shadow-sm);
}
.dash-customize-bar[hidden] { display: none; }
.dash-customize-copy h2 { font-size: var(--text-md); font-weight: 680; }
.dash-customize-copy p { margin: 2px 0 0; color: var(--ink-muted); font-size: var(--text-sm); }
.dash-customize-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.dash-customize-label {
  min-width: 96px; color: var(--ink-muted); font-size: var(--text-xs); font-weight: 700;
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
}
.dash-customize-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--sp-2); }
.dash-form, .dash-pin-form { display: contents; }
.dash-restore .i { color: var(--accent); }

/* ══ The grid ════════════════════════════════════════════════════════════════ */

.dash-grid {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--sp-4); align-items: stretch;
}
.dash-card, .dash-placeholder { grid-column: span 12; min-width: 0; }
.dash-card.w-quarter, .dash-placeholder.w-quarter { grid-column: span 3; }
.dash-card.w-third, .dash-placeholder.w-third { grid-column: span 4; }
.dash-card.w-half, .dash-placeholder.w-half { grid-column: span 6; }
.dash-card.w-two-thirds, .dash-placeholder.w-two-thirds { grid-column: span 8; }
.dash-card.w-full, .dash-placeholder.w-full { grid-column: span 12; }

@media (max-width: 1180px) {
  .dash-card.w-quarter, .dash-placeholder.w-quarter,
  .dash-card.w-third, .dash-placeholder.w-third,
  .dash-card.w-half, .dash-placeholder.w-half { grid-column: span 6; }
  .dash-card.w-two-thirds, .dash-placeholder.w-two-thirds { grid-column: span 12; }
}
@media (max-width: 720px) {
  .dash-grid { gap: var(--sp-3); }
  .dash-card, .dash-placeholder,
  .dash-card.w-third, .dash-placeholder.w-third,
  .dash-card.w-half, .dash-placeholder.w-half { grid-column: span 12; }
  .dash-card.w-quarter, .dash-placeholder.w-quarter { grid-column: span 6; }
  .dash-hello h1 { font-size: var(--text-xl); }
  .dash-controls { width: 100%; }
}
@media (max-width: 400px) {
  .dash-card.w-quarter, .dash-placeholder.w-quarter { grid-column: span 12; }
}

.dash-card {
  position: relative;
  display: flex; flex-direction: column;
  padding: var(--sp-4) var(--sp-5) var(--sp-5);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface); box-shadow: var(--shadow-sm);
  transition: border-color var(--t-fast) var(--ease-out), box-shadow var(--t-base) var(--ease-out);
}
.dash-card-head {
  display: flex; align-items: center; gap: var(--sp-2);
  min-height: 28px; margin-bottom: var(--sp-2);
}
.dash-card-head h2 {
  flex: 1 1 auto; min-width: 0;
  font-size: var(--text-md); font-weight: 680; color: var(--ink);
}
.dash-card.w-quarter .dash-card-head h2 { color: var(--ink-muted); font-size: var(--text-sm); font-weight: 620; }
.dash-card-body { display: flex; flex: 1 1 auto; flex-direction: column; gap: var(--sp-2); min-width: 0; }
.dash-head-link {
  display: inline-flex; align-items: center; gap: var(--sp-1); flex: none;
  font-size: var(--text-sm); font-weight: 620; text-decoration: none; white-space: nowrap;
}
.dash-head-link .i-arrow { transition: transform var(--t-base) var(--ease-out); }
.dash-head-link:hover .i-arrow { transform: translateX(2px); }

/* The handle: quiet until the card is hovered or focused inside, always shown while
 * customizing, and hidden on touch screens outside Customize so a scroll is not a drag. */
.dash-grip {
  display: inline-grid; place-items: center; flex: none;
  width: 28px; height: 28px; padding: 0;
  border: 1px solid transparent; border-radius: var(--r-xs);
  background: transparent; color: var(--ink-faint);
  cursor: grab; touch-action: none; opacity: 0;
  transition: opacity var(--t-fast) var(--ease-out), background var(--t-fast) var(--ease-out);
}
.dash-grip[hidden] { display: none; }
.dash-card:hover .dash-grip, .dash-card:focus-within .dash-grip,
.dash.is-editing .dash-grip { opacity: 1; }
.dash-grip:hover { background: var(--surface-sunk); color: var(--ink-soft); }
.dash-grip:focus-visible { opacity: 1; outline: 2px solid var(--focus); outline-offset: 1px; }
.dash-grip[aria-pressed="true"] { opacity: 1; background: var(--accent-wash); color: var(--accent-ink); border-color: var(--accent-line); }
@media (hover: none) {
  .dash:not(.is-editing) .dash-grip { display: none; }
}

.dash-tools { display: none; flex-wrap: wrap; gap: 4px; margin-bottom: var(--sp-3); }
.dash.is-editing .dash-tools { display: flex; }
.dash.is-editing .dash-card { border-style: dashed; border-color: var(--accent-line); }
.dash-tool {
  display: inline-grid; place-items: center; width: 32px; height: 30px; padding: 0;
  border: 1px solid var(--line-strong); border-radius: var(--r-xs);
  background: var(--surface); color: var(--ink-soft); cursor: pointer;
}
.dash-tool:hover:not(:disabled) { border-color: var(--accent-line); color: var(--accent-ink); background: var(--accent-wash); }
.dash-tool:disabled { opacity: .4; cursor: not-allowed; }
.dash-tool:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }

/* Dragging. The card follows the pointer on its own layer; the gap it left is drawn. */
.dash-placeholder {
  border: 2px dashed var(--accent-line); border-radius: var(--r-md);
  background: color-mix(in srgb, var(--accent-wash) 60%, transparent);
}
.dash-card.is-dragging {
  position: fixed; z-index: var(--z-overlay); margin: 0;
  box-shadow: var(--shadow-lift); pointer-events: none; opacity: .96;
  transition: none; will-change: transform;
}
.dash-card.is-grabbed { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-wash), var(--shadow-md); }
.dash-drag-active, .dash-drag-active * { cursor: grabbing !important; user-select: none; }
@media (prefers-reduced-motion: no-preference) {
  .dash-card.is-settling { transition: transform var(--t-base) var(--ease-out); }
}

/* ══ Stat cards ══════════════════════════════════════════════════════════════ */

.dash-figure { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2); margin: 0; }
.dash-value {
  font-family: var(--font-display); font-size: 1.875rem; font-weight: 700;
  letter-spacing: var(--tracking-tight); line-height: 1.05; color: var(--ink);
}
.dash-figure-of { color: var(--ink-muted); font-size: var(--text-md); font-weight: 600; }
.dash-delta { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px; font-size: var(--text-xs); font-weight: 650; color: var(--ink-soft); }
.dash-delta .muted { font-weight: 500; }
.delta-up, .delta-down { display: inline-flex; align-items: center; gap: 2px; }
.delta-up .i { transform: rotate(-90deg); }
.delta-down .i { transform: rotate(90deg); }
.dash-sub { margin: 0; color: var(--ink-soft); font-size: var(--text-sm); }
.dash-foot { margin: auto 0 0; padding-top: var(--sp-1); color: var(--ink-muted); font-size: var(--text-xs); }
.dash-foot a { display: inline-flex; align-items: center; gap: var(--sp-1); font-weight: 620; text-decoration: none; }

.dash-spark { display: block; width: 100%; height: 40px; margin-top: var(--sp-1); border-bottom: 1px solid var(--line); overflow: visible; }
.spark-prev { fill: var(--line-strong); }
.spark-cur { fill: var(--accent); }
.spark-zero { fill: var(--line); }
.dash-spark rect:hover { opacity: .75; }
.dash-axis { display: flex; justify-content: space-between; margin: 0; color: var(--ink-muted); font-size: var(--text-2xs); }

.dash-meter, .dash-tiers { display: block; width: 100%; height: 8px; margin-top: var(--sp-1); border-radius: var(--r-full); overflow: hidden; }
.meter-track { fill: var(--accent-wash); }
.meter-fill { fill: var(--accent); }
.tier-high { fill: var(--score-high-fill); background: var(--score-high-fill); }
.tier-mid { fill: var(--score-mid-fill); background: var(--score-mid-fill); }
.tier-low { fill: var(--score-low-fill); background: var(--score-low-fill); }
.tier-na { fill: var(--tier-na); background: var(--tier-na); }

.dash-legend, .dash-rows { display: grid; gap: 3px var(--sp-4); margin: var(--sp-1) 0 0; padding: 0; list-style: none; }
.dash-legend { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.dash-legend li, .dash-rows li { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--text-xs); color: var(--ink-soft); }
.dash-rows li { font-size: var(--text-sm); }
.dash-legend li span:nth-child(2), .dash-rows li span { flex: 1 1 auto; min-width: 0; }
.dash-legend b, .dash-rows b { color: var(--ink); font-weight: 650; font-variant-numeric: tabular-nums; }
.dash-swatch { flex: none; width: 8px; height: 8px; border-radius: 2px; }

/* ══ Hiring flow ═════════════════════════════════════════════════════════════ */

.flow { display: grid; gap: 2px; margin: var(--sp-2) 0 0; padding: 0; list-style: none; }
.flow-row {
  display: grid; grid-template-columns: 96px minmax(0, 1fr) 44px minmax(0, 150px);
  align-items: center; gap: var(--sp-3); min-height: 32px;
}
.flow-label { font-size: var(--text-sm); font-weight: 600; color: var(--ink-soft); }
.flow-label a { color: inherit; text-decoration: underline; text-decoration-color: var(--line-strong); text-underline-offset: 3px; }
.flow-label a:hover { color: var(--accent-ink); text-decoration-color: currentColor; }
.flow-bar { display: block; width: 100%; height: 14px; }
.flow-track { fill: var(--surface-sunk); }
.flow-f1 { fill: var(--flow-1); }
.flow-f2 { fill: var(--flow-2); }
.flow-f3 { fill: var(--flow-3); }
.flow-f4 { fill: var(--flow-4); }
.flow-f5 { fill: var(--flow-5); }
.flow-count { text-align: right; font-size: var(--text-md); font-weight: 700; font-variant-numeric: tabular-nums; }
.flow-conv { color: var(--ink-muted); font-size: var(--text-xs); }
.flow-stops {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
  margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--line);
}
.dash-chip {
  display: inline-flex; align-items: center; gap: 5px; min-height: 26px; padding: 0 var(--sp-3);
  border: 1px solid var(--line); border-radius: var(--r-full);
  color: var(--ink-soft); font-size: var(--text-xs); font-weight: 600; text-decoration: none;
}
.dash-chip b { color: var(--ink); }
a.dash-chip:hover { border-color: var(--accent-line); background: var(--accent-wash); color: var(--accent-ink); }
@media (max-width: 720px) {
  .flow-row { grid-template-columns: 80px minmax(0, 1fr) 36px; }
  .flow-conv { display: none; }
}

/* ══ Needs attention and the feed share one mark ═════════════════════════════ */

.dash-mark {
  position: relative; display: grid; place-items: center; flex: none;
  width: 32px; height: 32px; border-radius: var(--r-sm);
  background: var(--surface-sunk); color: var(--ink-muted);
}
.dash-mark.tone-bad { background: var(--bad-bg); color: var(--bad-fg); }
.dash-mark.tone-warn { background: var(--warn-bg); color: var(--warn-fg); }
.dash-mark.tone-accent { background: var(--accent-wash); color: var(--accent-ink); }

/* One column that may shrink: an `auto` track is as wide as the longest unbroken line in
   it, which pushed the action button out of a narrow card. */
.dash-alerts { display: grid; grid-template-columns: minmax(0, 1fr); margin: 0; padding: 0; list-style: none; }
.alert-row { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) 0; border-top: 1px solid var(--line); }
.alert-row:first-child { border-top: 0; padding-top: var(--sp-1); }
.alert-copy { display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0; font-size: var(--text-sm); }
.alert-copy b { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); font-weight: 650; color: var(--ink); }
.alert-copy .muted { font-size: var(--text-xs); overflow-wrap: anywhere; }
.alert-row .btn, .alert-row form { flex: none; }
.dash-tag {
  padding: 0 6px; border: 1px solid var(--line-strong); border-radius: var(--r-full);
  color: var(--ink-muted); font-size: 10.5px; font-weight: 650; line-height: 16px;
}
.dash-clear { display: grid; justify-items: center; gap: var(--sp-2); margin: auto 0; padding: var(--sp-5) var(--sp-3); text-align: center; }
.dash-clear-mark { display: grid; place-items: center; width: 48px; height: 48px; border-radius: var(--r-full); background: var(--accent-wash); color: var(--accent-ink); }
.dash-clear b { font-size: var(--text-md); }
.dash-clear p { max-width: 280px; margin: 0; color: var(--ink-muted); font-size: var(--text-sm); }

/* ══ Roles ═══════════════════════════════════════════════════════════════════ */

.dash-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: var(--sp-3); }
.dash-tile {
  display: flex; flex-direction: column; gap: var(--sp-3); min-width: 0;
  padding: var(--sp-4); border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface);
  transition: border-color var(--t-fast) var(--ease-out), box-shadow var(--t-fast) var(--ease-out);
}
.dash-tile:hover { border-color: var(--line-strong); box-shadow: var(--shadow-sm); }
.dash-tile.is-pinned { border-color: var(--accent-line); }
.dash-tile-head { display: flex; align-items: flex-start; gap: var(--sp-2); }
.dash-tile-title { flex: 1 1 auto; min-width: 0; color: var(--ink); font-size: var(--text-md); font-weight: 680; text-decoration: none; overflow-wrap: anywhere; }
.dash-tile-title:hover { color: var(--accent-ink); }
.dash-pin {
  display: inline-grid; place-items: center; flex: none; width: 28px; height: 28px; padding: 0;
  border: 1px solid transparent; border-radius: var(--r-xs); background: transparent;
  color: var(--ink-faint); cursor: pointer;
}
.dash-pin:hover { background: var(--surface-sunk); color: var(--ink-soft); }
.dash-pin.is-pinned { color: var(--accent); }
.dash-pin.btn { width: auto; padding: 0 var(--sp-3); gap: var(--sp-2); color: var(--ink-soft); }
.dash-pin.btn.is-pinned { color: var(--accent-ink); --btn-bg: var(--accent-wash); --btn-line: var(--accent-line); }
.dash-pin:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }
.dash-tile-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.dash-badge { gap: 6px; }
.dash-tile-counts {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3); border-radius: var(--r-sm); background: var(--surface-sunk);
}
.dash-tile-counts div { display: flex; flex-direction: column; }
.dash-tile-counts b { font-size: var(--text-lg); font-weight: 700; line-height: 1.2; font-variant-numeric: tabular-nums; }
.dash-tile-counts span { color: var(--ink-muted); font-size: var(--text-xs); }
.dash-tile-foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3);
  margin-top: auto; padding-top: var(--sp-3); border-top: 1px solid var(--line);
  font-size: var(--text-xs); color: var(--ink-muted);
}
.dash-owner { display: inline-flex; align-items: center; gap: var(--sp-2); }
.dash-owner .avatar { width: 22px; height: 22px; font-size: 9px; }
.dash-link-line { display: flex; align-items: center; gap: var(--sp-1); flex: 1 1 auto; min-width: 0; }
.dash-link-text { min-width: 0; }
.dash-link-line .link-copy { flex: none; margin-left: var(--sp-1); }
.dash-link-line.is-warn { color: var(--warn-fg); font-weight: 600; }
.dash-ghost {
  flex-direction: row; align-items: center; justify-content: center; gap: var(--sp-3);
  min-height: 120px; border: 1.5px dashed var(--line-strong); background: transparent;
  color: var(--ink-soft); text-decoration: none;
}
.dash-ghost:hover { border-color: var(--accent-line); background: var(--accent-wash); color: var(--accent-ink); box-shadow: none; }
.dash-ghost > span:last-child { display: flex; flex-direction: column; }
.dash-ghost b { color: var(--ink); font-size: var(--text-sm); }
.dash-ghost > span:last-child span { color: var(--ink-muted); font-size: var(--text-xs); }
.dash-ghost-mark { display: grid; place-items: center; width: 36px; height: 36px; border-radius: var(--r-full); background: var(--accent-wash); color: var(--accent-ink); }

/* ══ The feed, on Home and on the activity page ══════════════════════════════ */

.feed-days, .feed { margin: 0; padding: 0; list-style: none; }
.feed-day + .feed-day { margin-top: var(--sp-3); }
.feed-day h3 {
  margin: 0 0 var(--sp-1); color: var(--ink-muted);
  font-size: var(--text-2xs); font-weight: 700; letter-spacing: var(--tracking-wide); text-transform: uppercase;
}
.feed-item { display: flex; gap: var(--sp-3); padding: var(--sp-2) 0; border-bottom: 1px solid var(--line); }
.feed-item:last-child { border-bottom: 0; }
.feed-item .dash-mark { width: 28px; height: 28px; border-radius: var(--r-full); }
.feed-new {
  position: absolute; top: -2px; right: -2px; width: 10px; height: 10px;
  border: 2px solid var(--surface); border-radius: var(--r-full); background: var(--accent);
}
.feed-copy { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.feed-copy p { margin: 0; color: var(--ink-soft); font-size: var(--text-sm); line-height: 1.45; }
.feed-copy b { color: var(--ink); font-weight: 650; }
.feed-link { color: inherit; text-decoration: none; }
.feed-link:hover b { color: var(--accent-ink); }
.feed-extra { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.feed-score { display: inline-flex; align-items: center; gap: var(--sp-2); font-size: var(--text-xs); }
.feed-copy time { color: var(--ink-muted); font-size: var(--text-xs); }
.dash-new-pill { flex: none; }
.activity-feed { margin-top: var(--sp-3); padding: var(--sp-2) var(--sp-5); border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); box-shadow: var(--shadow-sm); }
.activity-feed .feed-day { padding-top: var(--sp-3); }

/* ══ Team and workspace ══════════════════════════════════════════════════════ */

.dash-table table { font-size: var(--text-sm); }
.dash-person { display: flex; align-items: center; gap: var(--sp-3); }
.dash-person > span:last-child { display: flex; flex-direction: column; line-height: 1.3; }
.avatar.is-empty { border-style: dashed; background: transparent; color: var(--ink-muted); }

.dash-usage { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2); }
.dash-usage div { display: flex; flex-direction: column; padding: var(--sp-3); border-radius: var(--r-sm); background: var(--surface-sunk); }
.dash-usage b { font-size: var(--text-xl); font-weight: 700; letter-spacing: var(--tracking-tight); }
.dash-usage span { color: var(--ink-muted); font-size: var(--text-xs); }
.dash-facts { display: grid; margin: var(--sp-2) 0 0; }
.dash-facts div { display: flex; justify-content: space-between; gap: var(--sp-3); padding: var(--sp-2) 0; border-top: 1px solid var(--line); font-size: var(--text-sm); }
.dash-facts dt { color: var(--ink-muted); }
.dash-facts dd { margin: 0; font-weight: 620; text-align: right; }

/* ══ Getting started ═════════════════════════════════════════════════════════ */

.check-progress { display: flex; align-items: center; gap: var(--sp-3); color: var(--ink-muted); font-size: var(--text-sm); }
.check-progress .dash-meter { flex: 0 1 220px; margin: 0; }
.check-steps {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: var(--sp-2);
  margin: var(--sp-2) 0 0; padding: 0; list-style: none;
}
.check-step {
  display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3);
  border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface);
}
.check-step.is-next { border-color: var(--accent-line); background: var(--accent-wash); }
.check-mark {
  display: grid; place-items: center; flex: none; width: 26px; height: 26px;
  border: 1.5px solid var(--line-strong); border-radius: var(--r-full);
  color: var(--ink-muted); font-size: var(--text-xs); font-weight: 700;
}
.check-step.is-done .check-mark { border-color: var(--accent); background: var(--accent); color: var(--on-accent); }
.check-step.is-next .check-mark { border: 2px solid var(--accent); color: var(--accent-ink); }
.check-copy { display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0; font-size: var(--text-xs); color: var(--ink-muted); }
.check-copy b { color: var(--ink); font-size: var(--text-sm); font-weight: 650; }
.check-step.is-done .check-copy b { color: var(--ink-muted); }
.check-step .btn { flex: none; }

/* 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 .newbtn span,
.sidebar-collapsed .accountbtn-copy {
  width: 0;
  opacity: 0;
  overflow: hidden;
  white-space: nowrap;
  pointer-events: none;
}
.sidebar-collapsed .sidebar { padding-inline: 10px; }
.sidebar-collapsed .newbtn { justify-content: center; padding: 0; }
.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; }

/* ── new interview ── */

/* The one creating action, under the search box and above the pages. Filled in the
 * accent so it reads as the action and not as a fifth page; the same height as the
 * search trigger so the two stack as a pair. */
.newbtn {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  width: 100%;
  min-height: 38px;
  margin-top: var(--sp-2);
  padding: 0 var(--sp-3);
  border-radius: var(--r-sm);
  background: var(--accent);
  box-shadow: var(--shadow-accent);
  color: var(--on-accent);
  font-size: var(--text-sm);
  font-weight: 620;
  text-decoration: none;
  transition: background var(--t-fast) var(--ease-out);
}
.newbtn:hover { background: var(--accent-hover); color: var(--on-accent); }
.newbtn svg { flex: none; }
.newbtn span { flex: 1; text-align: left; white-space: nowrap; }
.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; }
}

/* ───────────────────────────────────────────────────────── the bell ── */

/* At the far right of the appbar, after the page's own actions. Without the bundle it
 * is a link to the notifications page; with it, the same button opens a panel. */
.bell-wrap { position: relative; flex: none; }
.appbar-bell { position: relative; flex: none; text-decoration: none; }
.bell-count {
  position: absolute;
  top: 2px;
  right: 1px;
  min-width: 17px;
  height: 17px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--surface);
  font-size: 10.5px;
  font-weight: 700;
  line-height: 17px;
  text-align: center;
  pointer-events: none;
}
.bell-panel {
  position: absolute;
  top: 100%;
  right: 0;
  z-index: var(--z-overlay);
  width: min(380px, calc(100vw - 2 * var(--sp-4)));
  margin-top: 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;
}
.bell-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--line);
}
.bell-list { max-height: min(420px, 60vh); overflow-y: auto; }
.bell-note { margin: 0; padding: var(--sp-4) var(--sp-3); color: var(--ink-muted); font-size: var(--text-sm); }
.bell-foot {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border-top: 1px solid var(--line);
  font-size: var(--text-sm);
}
.bell-foot a { color: var(--ink-muted); text-decoration: none; }
.bell-foot a:hover { color: var(--ink); }

/* ─────────────────────────────────────────────── 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; }
/* The dialog is the whole viewport and the scrim is its `::backdrop`. The browser's
 * own dialog rules — `width: fit-content`, `max-width: calc(100% - 6px - 2em)`, a
 * solid border, `margin: auto` — are reset here, because with `inset: 0` alone they
 * won: the scrim drew as a bordered box a little larger than the panel, floating over
 * the page, instead of dimming the page behind it. The width and height are set out
 * loud rather than left to `inset` for the same reason. */
.cmdk-root[open] {
  position: fixed;
  inset: 0;
  z-index: var(--z-toast);
  display: grid;
  align-items: start;
  justify-items: center;
  width: 100vw;
  height: 100vh;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: clamp(48px, 12vh, 140px) var(--sp-4) var(--sp-4);
  border: 0;
  background: transparent;
  color: inherit;
  animation: fade-in var(--t-fast) var(--ease-out) both;
}
.cmdk-root::backdrop {
  background: rgba(6, 13, 12, .45);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}

.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); }
}
