    /* ────────────────────────────────────────────────────────────────
       TOKENS — single source of truth.
       Nibomont navy is the brand commitment (#1A2F50).
       Pure paper-white body. Near-black ink with a navy undertone so
       the document feels of-a-piece, not stitched.
       Verified for WCAG AA+ at body sizes; see brief.
       ──────────────────────────────────────────────────────────────── */
    :root {
      /* ── GCP CLOUD CONSOLE palette (Material 3, light).
         The original semantic token NAMES are kept so every existing
         component re-skins in place; only the VALUES are remapped to
         Google's console "greyscale UI, blue used sparingly" system.
         Accent hue is overridable per-surface (see --accent below). ── */

      /* Accent — Nibomont navy. The ONE saturated colour: links, the single
         primary button per view, active nav + selected-row wash. Aliased to
         --brand* so legacy component rules pick it up unchanged.
         --accent is the brand navy lifted one step so a link reads as a
         link and not as body ink (10.4:1 on white); PRESSED lands exactly
         on the flagship #1A2F50, which is also the chrome fill. */
      --accent:       #22406e;   /* navy 600 */
      --accent-hover: #1d3860;   /* navy 700 */
      --accent-press: #1a2f50;   /* NIBOMONT NAVY — the brand commitment */
      --brand:        var(--accent);
      --brand-deep:   var(--accent-press);
      --brand-soft:   #34558a;                  /* navy 500 */
      --brand-on:     #ffffff;                  /* on a filled accent */
      --brand-on-mu:  #c3d0e4;                  /* muted on-accent (8.6:1 on navy) */
      --brand-on-fa:  #a3b4cd;                  /* faint on-accent (6.4:1 on navy) */
      --brand-tint:   #e9edf4;                  /* navy 50 — active-nav / selected wash */
      --brand-tint-2: #d3dbe8;                  /* navy 100 — hover on tint */
      --accent-overlay: rgba(34,64,110,.06);    /* text/outlined btn hover wash */

      /* Surfaces & neutrals — grey canvas, white cards is the core contrast */
      --surface:      #ffffff;                  /* cards, tables, top bar, nav */
      --canvas:       #f8f9fa;                  /* main content background (grey 50) */
      --paper:        #ffffff;                  /* legacy: card/surface white */
      --paper-warm:   #f8f9fa;                  /* legacy warm band → canvas grey */
      --paper-sunk:   #f1f3f4;                  /* sunken / hover fill (grey 100) */
      --hover:        #f1f3f4;                  /* row/item hover */
      --hover-strong: #e8eaed;                  /* grey 200 */

      /* Text — three greys do the hierarchy work */
      --ink:          #202124;                  /* grey 900 — primary text, H1 */
      --ink-body:     #3c4043;                  /* grey 800 — body / nav labels */
      --ink-muted:    #5f6368;                  /* grey 700 — secondary, icons, captions */
      --ink-faint:    #80868b;                  /* grey 600 — tertiary / disabled */

      /* Borders — the #dadce0 hairline is THE console tell */
      --rule:         #dadce0;                  /* grey 300 — hairlines everywhere */
      --rule-soft:    #f1f3f4;                  /* faint row divider */
      --rule-deep:    #bdc1c6;                  /* grey 400 — heavier lines */

      /* Semantic state — small colour + text, or a tinted pill */
      --state-pass:   #188038;   --state-pass-tint: #e6f4ea;   /* green 700 / bg */
      --state-deny:   #d93025;   --state-deny-tint: #fce8e6;   /* red 600 / bg */
      --state-gov:    #1a73e8;   --state-gov-tint:  #e8f0fe;   /* info blue / bg */
      --state-near:   #ea8600;   --state-near-tint: #fef7e0;   /* warning amber / bg */

      /* Evidence source — the one hue the four state tokens above leave
         unclaimed, reserved for "a model read this" on the case ledger. */
      --ev-ai:        #8430c8;   --ev-ai-tint:      #f4e9fd;   /* purple 700 / bg */

      /* Unread notification badge — GCP uses a red dot */
      --attention:    #d93025;
      --attention-on: #ffffff;

      /* Typography — Roboto runs the console UI; Montserrat is reserved
         for BRAND surfaces only (wordmarks / lockups), per the logo
         package (SemiBold for NIBOMONT, Medium for TECHNOLOGIES). */
      --font-sans:  'Roboto', system-ui, Arial, sans-serif;
      --font-mono:  'Roboto Mono', ui-monospace, monospace;
      --font-brand: 'Montserrat', 'Roboto', system-ui, Arial, sans-serif;

      /* Material elevation — Google's grey-tinted (rgba(60,64,67,…)) ramp */
      --elev-1: 0 1px 2px 0 rgba(60,64,67,.30), 0 1px 3px 1px rgba(60,64,67,.15);
      --elev-2: 0 1px 2px 0 rgba(60,64,67,.30), 0 2px 6px 2px rgba(60,64,67,.15);
      --elev-3: 0 1px 3px 0 rgba(60,64,67,.30), 0 4px 8px 3px rgba(60,64,67,.15);
      --elev-4: 0 2px 3px 0 rgba(60,64,67,.30), 0 6px 10px 4px rgba(60,64,67,.15);
      --elev-5: 0 4px 4px 0 rgba(60,64,67,.30), 0 8px 12px 6px rgba(60,64,67,.15);

      /* Motion — Material standard easing */
      --ease-standard: cubic-bezier(.4, 0, .2, 1);
      --ease-decel:    cubic-bezier(0, 0, .2, 1);
      --ease-accel:    cubic-bezier(.4, 0, 1, 1);
      --dur-fast: 150ms; --dur-med: 250ms; --dur-slow: 300ms;

      /* Shell geometry */
      --topbar-h: 48px;
      --rail-w: 256px;
      --rail-w-collapsed: 72px;

      --z-base: 0; --z-sticky: 30; --z-overlay: 40; --z-toast: 50;
    }

    /* Nibomont passenger-portal surfaces carry the deepest navy as the
       hand-off brand cue (verify / status / interrogate). One design
       language, a second accent — flip a single variable. */
    [data-portal="nibomont"] {
      --accent:       #1a2f50;
      --accent-hover: #152740;
      --accent-press: #101e34;
      --brand-soft:   #34558a;
      --brand-tint:   #e9edf4;
      --brand-tint-2: #d3dbe8;
      --accent-overlay: rgba(26,47,80,.06);
    }

    /* ── GCP CONSOLE DARK THEME (Material 3 dark). Toggled via the header
       button → html[data-theme="dark"]. Same token names, dark values;
       navy accent lightens to navy-200 (#9cb6dc) and filled buttons go
       tonal (dark text on light-navy). ── */
    html[data-theme="dark"] {
      --accent:       #9cb6dc;   /* navy 200 — navy itself is invisible here */
      --accent-hover: #b8cbe8;
      --accent-press: #7e9cc9;
      --brand:        var(--accent);
      --brand-deep:   var(--accent-press);
      --brand-soft:   #7e9cc9;
      --brand-on:     #202124;   /* dark text on a tonal (light-navy) fill */
      --brand-on-mu:  #1f3a5f;
      --brand-on-fa:  #3c5a80;
      --brand-tint:   rgba(156,182,220,.18);   /* active-nav / selected wash */
      --brand-tint-2: rgba(156,182,220,.28);
      --accent-overlay: rgba(156,182,220,.10);

      --surface:      #2d2e31;   /* cards, top bar, nav */
      --canvas:       #202124;   /* app background */
      --paper:        #2d2e31;
      --paper-warm:   #202124;
      --paper-sunk:   #35363a;   /* search fill / sunken */
      --hover:        #3c4043;
      --hover-strong: #45484d;

      --ink:          #e8eaed;   /* primary text */
      --ink-body:     #e8eaed;
      --ink-muted:    #9aa0a6;   /* secondary / icons */
      --ink-faint:    #80868b;   /* tertiary */

      --rule:         #3c4043;   /* dark hairline */
      --rule-soft:    #303134;   /* faint row divider */
      --rule-deep:    #5f6368;

      --state-pass:   #81c995;   --state-pass-tint: rgba(129,201,149,.16);
      --state-deny:   #f28b82;   --state-deny-tint: rgba(242,139,130,.16);
      --state-gov:    #8ab4f8;   --state-gov-tint:  rgba(138,180,248,.16);
      --state-near:   #fdd663;   --state-near-tint: rgba(253,214,99,.16);
      --ev-ai:        #d7aefb;   --ev-ai-tint:      rgba(215,174,251,.16);
      --attention:    #f28b82;   --attention-on: #202124;

      /* Elevation reads as black on dark surfaces, not grey */
      --elev-1: 0 1px 2px 0 rgba(0,0,0,.30), 0 1px 3px 1px rgba(0,0,0,.15);
      --elev-2: 0 1px 2px 0 rgba(0,0,0,.30), 0 2px 6px 2px rgba(0,0,0,.15);
      --elev-3: 0 1px 3px 0 rgba(0,0,0,.30), 0 4px 8px 3px rgba(0,0,0,.15);
      --elev-4: 0 2px 3px 0 rgba(0,0,0,.30), 0 6px 10px 4px rgba(0,0,0,.15);
      --elev-5: 0 4px 4px 0 rgba(0,0,0,.30), 0 8px 12px 6px rgba(0,0,0,.15);
    }
    /* Native form controls + scrollbars follow the theme in dark mode. */
    html[data-theme="dark"] { color-scheme: dark; }

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

    html, body {
      background: var(--canvas);
      color: var(--ink);
      font-family: var(--font-sans);
      -webkit-font-smoothing: antialiased;
      text-rendering: optimizeLegibility;
    }
    /* Grey content canvas; white cards/tables sit on top (core GCP contrast). */
    .app-content { background: var(--canvas); }

    /* Sticky footer — short pages (e.g. /admin/users) used to end where
       their content ended, leaving the footer floating with a bare band
       of page background below it. Body becomes a full-viewport flex
       column; <main> absorbs the slack so the footer always sits at the
       bottom edge. margin:0 is required — the UA default 8px body margin
       otherwise adds a bar outside the flex box. */
    body {
      margin: 0;
      min-height: 100vh;
      min-height: 100dvh;
      display: flex;
      flex-direction: column;
    }
    .app-shell { flex: 1; display: flex; align-items: stretch; min-width: 0; }
    .app-content { flex: 1; min-width: 0; display: flex; flex-direction: column; }
    main#main { flex: 1 0 auto; width: 100%; }
    .app-content > footer { margin-top: auto; }
    /* Small screens: the immersive brand canvas (solid navy / blue in light
       mode) must not fill the leftover viewport under short pages — a phone
       sees a huge empty colour slab and reads it as a half-rendered page.
       Let the page's last content section absorb the slack instead, so the
       brand colour is only ever the slim footer band. */
    @media (max-width: 899.98px) {
      main#main { display: flex; flex-direction: column; }
      main#main > section:last-of-type { flex: 1 0 auto; }
    }

    /* Arabic mode: IBM Plex stays the single voice — Latin glyphs from
       IBM Plex Sans, Arabic glyphs from IBM Plex Sans Arabic (via
       unicode-range). Lift line-height a hair so Plex Arabic sits
       comfortably. */
    html[dir="rtl"], html[dir="rtl"] body {
      font-family: 'IBM Plex Sans Arabic', 'Roboto', system-ui, sans-serif;
      line-height: 1.6;
    }
    /* Inside RTL mode, things tagged .ar are already Arabic — make sure they
       inherit and don't re-flip direction unnecessarily. */
    html[dir="rtl"] .ar { direction: rtl; }
    /* Latin-only artifacts (codes, hashes, mono) keep their LTR direction
       even inside an RTL document. */
    html[dir="rtl"] .t-mono, html[dir="rtl"] code, html[dir="rtl"] pre {
      direction: ltr;
      unicode-bidi: isolate;
    }
    /* Arabic script must never be letter-spaced — tracking (positive or
       negative) visibly breaks the cursive letter joins. In RTL mode zero
       the tracking on every tracked style: headings (negative tracking),
       label/meta styles and inline tracking-[…] utilities (wide positive
       tracking), and the Arabic verdict stamp. Latin runs inside RTL
       pages lose their decorative tracking too — acceptable. */
    html[dir="rtl"] :is(h1, h2, h3,
        .t-display, .t-h1, .t-h2, .t-h3, .t-meta,
        .field-label, .pill, .page-meta, .kv-label,
        .eyebrow, .col-label,
        .side-group-label, .mobile-nav-group-label,
        .verdict-stamp-ar, [class*="tracking-"]) {
      letter-spacing: 0;
    }

    body { font-size: 16px; line-height: 1.5; }

    h1, h2, h3 { text-wrap: balance; letter-spacing: 0; }
    p { text-wrap: pretty; }

    /* Arabic helper — RTL direction + a hair of extra line-height for the
       IBM Plex Sans Arabic for Arabic glyphs via unicode-range; IBM Plex
       Sans as Latin fallback for any mixed content. */
    .ar {
      font-family: 'IBM Plex Sans Arabic', 'Roboto', system-ui, sans-serif;
      direction: rtl;
      unicode-bidi: isolate;
      line-height: 1.6;
      font-feature-settings: 'kern', 'liga';
    }

    /* ────────────────────────────────────────────────────────────────
       BILINGUAL PAIRED-TEXT GRID
       Architecture, not garnish (Design Principle #2).
       Default LTR: Latin on the start side, Arabic on the end side,
       both on the same baseline. Reverses cleanly under `dir="rtl"`.
       ──────────────────────────────────────────────────────────────── */
    .pair {
      display: grid;
      grid-template-columns: 1fr auto;
      column-gap: clamp(1rem, 2vw, 2rem);
      align-items: baseline;
    }
    .pair > .ar { text-align: end; }
    .pair-block { display: grid; row-gap: 0.25rem; }
    .pair-block > .ar { justify-self: end; }

    /* Long-form bilingual rows used in the ledger: two columns share a row
       but each holds full text in its language. */
    .pair-row {
      display: grid;
      grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
      column-gap: clamp(1rem, 2.5vw, 2.5rem);
      align-items: baseline;
    }
    .pair-row > .ar { text-align: end; }

    /* ────────────────────────────────────────────────────────────────
       SURFACES
       ──────────────────────────────────────────────────────────────── */
    .surface-brand {
      background: var(--brand);
      color: var(--brand-on);
    }
    /* Legacy brand-slab surface → now a light GCP surface with a hairline. */
    .surface-brand-deep { background: var(--surface); color: var(--ink-muted); border-top: 1px solid var(--rule); }
    .surface-brand-deep a { color: var(--ink-muted); }
    .surface-brand-deep a:hover { color: var(--accent); }

    /* App footer — blend into the shell background (blue / navy / dark) so it
       never reads as a floating white box below short pages. It already pins
       to the bottom via `.app-content > footer { margin-top: auto }`; here we
       just drop the white fill + hairline and keep the brand mark legible on
       every shell (white works on blue, navy, and the dark canvas alike). */
    .app-content > footer.surface-brand-deep {
      background: transparent;
      border-top: 0;
      color: #fff;
    }
    .app-content > footer.surface-brand-deep .mw-brand-on,
    .app-content > footer.surface-brand-deep .mw-brand-on span,
    .app-content > footer.surface-brand-deep .seal { color: #fff; }
    .surface-paper {
      background: var(--paper);
      color: var(--ink);
    }
    .surface-warm {
      background: var(--paper-warm);
      color: var(--ink);
    }

    .on-brand-muted     { color: var(--brand-on-mu); }
    .ink-muted          { color: var(--ink-muted); }
    .ink-faint          { color: var(--ink-faint); }

    /* ────────────────────────────────────────────────────────────────
       TYPE SCALE
       Modular, fluid; weight contrast inside one Latin family carries
       hierarchy. No display serif (the editorial-typographic reflex).
       ──────────────────────────────────────────────────────────────── */
    /* GCP page titles: Google Sans 22px / weight 400 / normal tracking.
       The old editorial display scale is retired for the console look. */
    .t-display {
      font-family: var(--font-sans);
      font-weight: 400;
      font-size: 1.5rem;          /* 24px — page H1 */
      line-height: 1.3;
      letter-spacing: 0;
      color: var(--ink);
    }
    .t-display-ar {
      font-family: 'IBM Plex Sans Arabic', var(--font-sans);
      direction: rtl;
      unicode-bidi: isolate;
      font-weight: 500;
      font-size: 1.25rem;
      line-height: 1.6;
    }
    .t-h1 {
      font-weight: 400;
      font-size: 1.375rem;        /* 22px */
      line-height: 1.3;
      letter-spacing: 0;
    }
    .t-h2 {
      font-weight: 500;
      font-size: 1.125rem;        /* 18px */
      line-height: 1.4;
      letter-spacing: 0;
    }
    .t-h2-ar {
      font-family: 'IBM Plex Sans Arabic', var(--font-sans);
      direction: rtl;
      unicode-bidi: isolate;
      font-weight: 500;
      font-size: 1rem;
      line-height: 1.6;
    }
    .t-h3 {
      font-weight: 500;
      font-size: 1rem;            /* 16px */
      line-height: 1.5;
      letter-spacing: 0.1px;
    }
    .t-lead {
      font-size: 0.875rem;
      line-height: 1.5;
      color: var(--ink-muted);
      max-width: 80ch;
    }
    .t-body { font-size: 0.875rem; line-height: 1.43; max-width: 80ch; }
    .t-meta { font-size: 0.75rem; letter-spacing: 0.3px; color: var(--ink-muted); }
    /* Plex Mono has no Arabic glyphs — without the Sans Arabic fallback,
       Arabic label text in mono slots falls to the system monospace and
       renders as disconnected per-cell letters. Latin/digits still hit
       Plex Mono first; only Arabic glyphs fall through. */
    .t-mono { font-family: 'Roboto Mono', 'IBM Plex Sans Arabic', ui-monospace, monospace; font-feature-settings: 'tnum'; }

    /* ────────────────────────────────────────────────────────────────
       INPUTS — registry-form, bottom-border discipline.
       No rounded card chrome. The desk does not bevel its forms.
       ──────────────────────────────────────────────────────────────── */
    .field {
      display: grid;
      row-gap: 0.5rem;
    }
    .field-label {
      font-size: 0.75rem;
      letter-spacing: 0.1px;
      text-transform: none;
      font-weight: 500;
      color: var(--ink-muted);
      display: flex;
      gap: 0.75rem;
      align-items: baseline;
      justify-content: space-between;
    }
    .field-label .ar {
      font-size: 0.8125rem;
      letter-spacing: 0;
      text-transform: none;
      color: var(--ink-muted);
      font-weight: 500;
    }
    /* Stacked bilingual label — Latin over Arabic on its own line, no cramping. */
    .field-label.is-stacked {
      flex-direction: column;
      align-items: stretch;
      gap: 0.2rem;
    }
    .field-label.is-stacked .ar { align-self: flex-start; }
    /* GCP Material outlined text field — white box, #dadce0 hairline,
       4px radius; focus thickens the outline to 2px accent (no fill glow). */
    .field-input,
    .field input[type="text"],
    .field input[type="number"],
    .field input[type="email"],
    .field input[type="password"],
    .field input[type="date"],
    .field input[type="search"],
    .field input:not([type]),
    .field select,
    .field textarea {
      width: 100%;
      background: var(--surface);
      border: 1px solid var(--rule);
      border-radius: 4px;
      padding: 0.5rem 0.75rem;
      min-height: 36px;
      font-size: 0.875rem;
      font-family: inherit;
      color: var(--ink);
      transition: border-color var(--dur-fast) var(--ease-standard),
                  box-shadow var(--dur-fast) var(--ease-standard);
    }
    .field select { min-height: 36px; }
    /* is-filled keeps a subtle grey fill but the same outlined geometry. */
    .field.is-filled input,
    .field.is-filled select,
    .field.is-filled textarea {
      background: var(--paper-sunk);
      border: 1px solid var(--rule);
    }
    .field.is-filled input:focus,
    .field.is-filled select:focus,
    .field.is-filled textarea:focus {
      background: var(--surface);
    }
    .field input::placeholder,
    .field textarea::placeholder { color: var(--ink-faint); }
    .field input:focus,
    .field select:focus,
    .field textarea:focus,
    .field-input:focus {
      outline: none;
      border-color: var(--accent);
      box-shadow: inset 0 0 0 1px var(--accent);
    }
    .field input:hover:not(:focus),
    .field select:hover:not(:focus),
    .field textarea:hover:not(:focus) { border-color: var(--ink-faint); }
    .field input[type="checkbox"] { accent-color: var(--accent); width: auto; min-height: 0; }
    .field-mono input { font-family: 'Roboto Mono', ui-monospace, monospace; font-feature-settings: 'tnum'; letter-spacing: 0.02em; }

    /* Inputs on the brand surface need ivory rules. */
    .surface-brand .field-label,
    .surface-brand .field-input { color: var(--brand-on); }
    .surface-brand .field-label .ar { color: var(--brand-on-mu); }
    .surface-brand .field-input,
    .surface-brand .field input,
    .surface-brand .field select,
    .surface-brand .field textarea {
      border-bottom-color: oklch(1 0 0 / 0.42);
      color: var(--brand-on);
    }
    .surface-brand .field input::placeholder { color: oklch(1 0 0 / 0.62); }
    .surface-brand .field input:focus,
    .surface-brand .field select:focus,
    .surface-brand .field textarea:focus {
      border-bottom-color: var(--brand-on);
      background: linear-gradient(to top, oklch(1 0 0 / 0.08), transparent 60%);
    }
    .surface-brand select { color-scheme: dark; }
    .surface-brand select option { background: var(--brand-deep); color: var(--brand-on); }

    /* Checkbox row presented as a discrete field with the same baseline. */
    .check-row {
      display: flex;
      align-items: center;
      gap: 0.625rem;
      padding: 0.625rem 0;
      border-bottom: 1.5px solid var(--rule-deep);
      cursor: pointer;
      user-select: none;
    }
    .surface-brand .check-row { border-bottom-color: oklch(1 0 0 / 0.42); }
    .check-row input { width: 1rem; height: 1rem; accent-color: var(--brand); }
    .surface-brand .check-row input { accent-color: var(--brand-on); }

    /* ────────────────────────────────────────────────────────────────
       BUTTONS — verbs, not affordance theatre.
       ──────────────────────────────────────────────────────────────── */
    /* GCP/Material buttons — 36px, radius 4px, 14px/500, sentence case,
       letter-spacing .15px. Filled (primary) · Outlined (ghost) · Text. */
    .btn {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 0.5rem;
      height: 36px;
      font-family: var(--font-sans);
      font-size: 0.875rem;
      font-weight: 500;
      letter-spacing: 0.15px;
      text-transform: none;
      padding: 0 1rem;
      border-radius: 4px;
      border: 1px solid transparent;
      cursor: pointer;
      white-space: nowrap;
      transition: background-color var(--dur-fast) var(--ease-standard),
                  border-color var(--dur-fast) var(--ease-standard),
                  box-shadow var(--dur-med) var(--ease-standard), color var(--dur-fast) var(--ease-standard);
    }
    .btn:focus-visible {
      outline: 2px solid var(--accent);
      outline-offset: 2px;
    }
    /* Filled — the single primary action per view. */
    .btn-primary {
      background: var(--accent);
      color: var(--brand-on);
      border-color: var(--accent);
    }
    .btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); box-shadow: var(--elev-1); }
    .btn-primary:active { background: var(--accent-press); }
    .surface-paper .btn-primary, .surface-warm .btn-primary { background: var(--accent); color: var(--brand-on); border-color: var(--accent); }
    .surface-paper .btn-primary:hover, .surface-warm .btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }

    /* Outlined — secondary action. */
    .btn-ghost {
      background: transparent;
      color: var(--accent);
      border-color: var(--rule);
    }
    .btn-ghost:hover { border-color: var(--brand-tint-2); background: var(--accent-overlay); }
    .surface-paper .btn-ghost, .surface-warm .btn-ghost { color: var(--accent); border-color: var(--rule); }
    .surface-paper .btn-ghost:hover, .surface-warm .btn-ghost:hover { border-color: var(--brand-tint-2); background: var(--accent-overlay); }

    /* Text — tertiary; also used for inline row actions. */
    .btn-text {
      display: inline-flex;
      align-items: center;
      gap: 0.4rem;
      white-space: nowrap;
      height: 32px;
      font: 500 0.875rem var(--font-sans);
      letter-spacing: 0.15px;
      text-transform: none;
      color: var(--accent);
      background: transparent;
      border: 0;
      padding: 0 0.5rem;
      cursor: pointer;
      border-radius: 4px;
      transition: background-color var(--dur-fast) var(--ease-standard), color var(--dur-fast) var(--ease-standard);
    }
    .btn-text:hover { background: var(--accent-overlay); }
    .btn-text.is-danger { color: var(--state-deny); }
    .btn-text.is-danger:hover { background: var(--state-deny-tint); }
    .btn-text.is-go { color: var(--state-pass); }
    .btn-text.is-go:hover { background: var(--state-pass-tint); }

    /* ────────────────────────────────────────────────────────────────
       STATE WORDS — Design Principle #4 in CSS form.
       No pills. No coloured backgrounds. The state is a WORD with a
       leading glyph (a paragraph mark / pilcrow analogue), in a single
       deep-saturated ink. Colorblind-safe because the word carries it.
       ──────────────────────────────────────────────────────────────── */
    .state {
      display: inline-flex;
      align-items: baseline;
      gap: 0.4rem;
      font-weight: 600;
      letter-spacing: 0.02em;
      font-size: 0.8125rem;
    }
    .state::before {
      content: '';
      width: 6px; height: 6px;
      border-radius: 1px;
      display: inline-block;
      background: currentColor;
      align-self: center;
    }
    .state-pass { color: var(--state-pass); }
    .state-deny { color: var(--state-deny); }
    .state-gov  { color: var(--state-gov); }
    .state-near { color: var(--state-near); }
    .state-pend { color: var(--ink-muted); }
    .state-pend::before { background: transparent; border: 1.5px solid currentColor; border-radius: 0; }

    /* ────────────────────────────────────────────────────────────────
       LEGACY pill class kept for templates we haven't migrated yet.
       Minimised; will be removed when interview/admin/audit are refit.
       ──────────────────────────────────────────────────────────────── */
    .pill {
      display: inline-flex; align-items: center; gap: 0.375rem;
      padding: 0.125rem 0.5rem;
      font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.04em;
      border: 1px solid var(--rule); border-radius: 1px;
      color: var(--ink-muted);
    }
    .pill-ok    { color: var(--state-pass); border-color: oklch(0.38 0.10 150 / 0.4); }
    .pill-no    { color: var(--state-deny); border-color: oklch(0.40 0.13 25 / 0.45); }
    .pill-gov   { color: var(--state-gov);  border-color: oklch(0.30 0.08 260 / 0.4); }
    .pill-rev   { color: var(--ink); border-color: var(--rule-deep); }
    .pill-pend  { color: var(--ink-muted); }
    .pill-admin { color: var(--brand-on); background: var(--brand-deep); border-color: var(--brand-deep); }
    .pill-user  { color: var(--brand-on); background: var(--brand);      border-color: var(--brand); }
    .chain-ok      { color: var(--state-pass); border-color: oklch(0.38 0.10 150 / 0.4); }
    .chain-tamper  { color: var(--state-deny); border-color: oklch(0.40 0.13 25 / 0.45); }

    /* ────────────────────────────────────────────────────────────────
       INTAKE CARD — landing "new check-in" panel.
       White paper card on a warm wash. Rounded soft inputs replace the
       bottom-border discipline used elsewhere; the card is a focused
       task surface, not a register row.
       ──────────────────────────────────────────────────────────────── */
    .intake-shell {
      background: var(--paper-warm);
    }
    .intake-card {
      background: var(--paper);
      border: 1px solid var(--rule);
      border-radius: 24px;
      padding: clamp(1.75rem, 3.2vw, 2.75rem);
      box-shadow:
        0 1px 2px oklch(0.18 0.014 264 / 0.04),
        0 18px 40px -18px oklch(0.18 0.014 264 / 0.10);
    }
    .intake-title {
      font-family: 'Roboto', system-ui, sans-serif;
      font-weight: 400;
      font-size: clamp(1.875rem, 2.6vw, 2.375rem);
      line-height: 1.05;
      letter-spacing: -0.015em;
      color: var(--ink);
    }
    /* Ledger tag, not a pill: squared corners + inline-start accent bar
       (stadium chips with a leading dot are banned on this project). */
    .intake-badge {
      display: inline-flex;
      align-items: center;
      gap: 0.4rem;
      padding: 0.4rem 0.75rem;
      border-radius: 6px;
      border-inline-start: 3px solid var(--state-pass);
      background: var(--paper-sunk);
      color: var(--ink-muted);
      font-size: 0.75rem;
      font-weight: 500;
      letter-spacing: 0.005em;
    }
    /* Soft rounded input field — pill border, internal padding. */
    .field-soft {
      display: grid;
      row-gap: 0.5rem;
    }
    .field-soft > .field-label {
      font-size: 0.875rem;
      font-weight: 500;
      letter-spacing: 0;
      text-transform: none;
      color: var(--ink);
      gap: 0.5rem;
      /* Keep icon + label together at the start edge: a label that sits
         at the far end of its column loses its visual bond with the
         input below it. Inline actions (e.g. "use today") opt back into
         the end edge with ms-auto. */
      justify-content: flex-start;
    }
    .field-soft input,
    .field-soft select,
    .field-soft textarea {
      width: 100%;
      background: var(--paper);
      border: 1px solid var(--rule);
      border-radius: 10px;
      padding: 0.75rem 0.9rem;
      font-size: 0.9375rem;
      font-family: inherit;
      color: var(--ink);
      transition: border-color 120ms ease, box-shadow 120ms ease;
      appearance: none;
    }
    .field-soft select {
      background-image: url("data:image/svg+xml,%3Csvg width='12' height='8' viewBox='0 0 12 8' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1.5l5 5 5-5' stroke='%237A8A82' fill='none' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
      background-repeat: no-repeat;
      background-position: right 0.9rem center;
      padding-right: 2.25rem;
    }
    /* RTL: flip chevron to the logical start (left) side. */
    html[dir="rtl"] .field-soft select {
      background-position: left 0.9rem center;
      padding-right: 0.9rem;
      padding-left: 2.25rem;
    }
    .field-soft input::placeholder { color: var(--ink-faint); }
    .field-soft input:focus,
    .field-soft select:focus,
    .field-soft textarea:focus {
      outline: none;
      border-color: var(--brand);
      box-shadow: 0 0 0 3px oklch(0.34 0.075 264 / 0.16);
    }
    /* Field-pair: stack two inputs inside one rounded box (Airline + flight). */
    .field-pair {
      display: grid;
      grid-template-columns: 1fr 7rem;
      align-items: stretch;
      border: 1px solid var(--rule);
      border-radius: 10px;
      background: var(--paper);
      overflow: hidden;
      transition: border-color 120ms ease, box-shadow 120ms ease;
    }
    .field-pair:focus-within {
      border-color: var(--brand);
      box-shadow: 0 0 0 3px oklch(0.34 0.075 264 / 0.16);
    }
    .field-pair input {
      border: 0;
      background: transparent;
      padding: 0.75rem 0.9rem;
      font-size: 0.9375rem;
      font-family: inherit;
      color: var(--ink);
    }
    .field-pair input:focus { outline: none; }
    .field-pair input + input {
      border-inline-start: 1px solid var(--rule);
      font-family: 'Roboto', system-ui, sans-serif;
      font-feature-settings: 'tnum';
      letter-spacing: 0.02em;
    }

    /* Checkbox row card — same border language as a rounded field. */
    .intake-check {
      display: flex;
      align-items: center;
      gap: 0.75rem;
      padding: 0.85rem 1rem;
      background: var(--paper);
      border: 1px solid var(--rule);
      border-radius: 10px;
      cursor: pointer;
      user-select: none;
      transition: border-color 120ms ease, background-color 120ms ease;
    }
    .intake-check:hover { border-color: var(--rule-deep); }
    .intake-check input {
      width: 1.05rem;
      height: 1.05rem;
      accent-color: var(--brand);
      margin: 0;
    }
    .intake-check.is-on { border-color: var(--brand); background: oklch(0.34 0.075 264 / 0.05); }

    /* Go button — solid navy, rounded. */
    .btn-go {
      display: inline-flex;
      align-items: center;
      gap: 0.55rem;
      padding: 0.85rem 1.4rem;
      background: var(--brand);
      color: var(--brand-on);
      border: 1px solid var(--brand);
      border-radius: 12px;
      font-family: inherit;
      font-size: 0.9375rem;
      font-weight: 500;
      letter-spacing: 0;
      cursor: pointer;
      transition: background-color 120ms ease, border-color 120ms ease, transform 120ms ease;
    }
    .btn-go:hover { background: var(--brand-soft); border-color: var(--brand-soft); }
    .btn-go:active { transform: translateY(1px); }

    /* ────────────────────────────────────────────────────────────────
       LEDGER — the table aesthetic for Zone C.
       A real register, not a card grid.
       ──────────────────────────────────────────────────────────────── */
    /* GCP data table — white surface, 12px/500 grey header on a #dadce0
       underline, 48px rows on faint #f1f3f4 hairlines, #f8f9fa hover. */
    .ledger {
      width: 100%;
      border-collapse: separate;
      border-spacing: 0;
      font-size: 0.8125rem;
      color: var(--ink);
    }
    .ledger thead th {
      text-align: start;
      padding: 0 1rem;
      height: 40px;
      font-size: 0.75rem;
      letter-spacing: 0.3px;
      text-transform: none;
      font-weight: 500;
      color: var(--ink-muted);
      border-bottom: 1px solid var(--rule);
      vertical-align: middle;
      white-space: nowrap;
    }
    .ledger thead th .ar {
      display: block;
      text-transform: none;
      letter-spacing: 0;
      font-size: 0.6875rem;
      color: var(--ink-faint);
      font-weight: 400;
      margin-top: 0.05rem;
    }
    .ledger tbody td {
      padding: 0 1rem;
      height: 48px;
      border-bottom: 1px solid var(--rule-soft);
      vertical-align: middle;
    }
    .ledger tbody tr { transition: background-color var(--dur-fast) var(--ease-standard); }
    .ledger tbody tr:hover { background: var(--hover); }
    .ledger tbody tr[aria-selected="true"] { background: var(--brand-tint); }
    .ledger tbody tr.is-empty td {
      text-align: center;
      color: var(--ink-faint);
      padding: 3rem 1rem;
      height: auto;
    }
    .ledger a { color: inherit; text-decoration: none; display: block; }
    /* First-cell resource name reads as a blue link (GCP convention). */
    .ledger tbody td a.ledger-link, .ledger a.ledger-link { color: var(--accent); }
    .ledger tbody td a.ledger-link:hover { text-decoration: underline; }

    .ledger-grid { display: grid; align-items: center; }

    /* Div-grid ledger row (redesigned landing / list pages). */
    .ledger-row {
      padding: 0 1rem;
      min-height: 48px;
      display: grid; align-items: center;
      border-bottom: 1px solid var(--rule-soft);
      color: inherit;
      text-decoration: none;
      transition: background-color var(--dur-fast) var(--ease-standard);
    }
    .ledger-row:hover { background: var(--hover); }

    /* ────────────────────────────────────────────────────────────────
       PANEL — paper-surface block with a single hairline frame.
       The desk doesn't shadow its documents; it rules them.
       ──────────────────────────────────────────────────────────────── */
    /* GCP card — white surface, #dadce0 hairline, 8px radius, no shadow. */
    .panel {
      background: var(--surface);
      border: 1px solid var(--rule);
      border-radius: 8px;
      padding: 1.5rem;
    }
    .panel-sunk { background: var(--paper-sunk); border: 1px solid var(--rule); border-radius: 8px; }
    .panel-head {
      padding: 1rem 1.5rem;
      border-bottom: 1px solid var(--rule);
      background: var(--surface);
      border-radius: 8px 8px 0 0;
    }
    .panel-body { padding: 1.5rem; }

    /* GCP page header — breadcrumb/title + right-aligned actions, no heavy
       underline. Sentence-case meta in secondary grey. */
    .page-head {
      display: grid;
      grid-template-columns: 1fr auto;
      column-gap: 2rem;
      row-gap: 0.5rem;
      align-items: center;
      padding-block: 1.25rem;
    }
    .page-meta {
      font: 400 0.75rem/1.4 var(--font-sans);
      letter-spacing: 0.3px;
      text-transform: none;
      color: var(--ink-muted);
      text-align: end;
    }

    /* ────────────────────────────────────────────────────────────────
       VERDICT BAND — used on the decision page header.
       Tints are deliberately whisper-thin so the word still carries it.
       A giant rotated stamp (.verdict-stamp) sits behind the headline
       on the side opposite the confidence number, like a rubber stamp
       impressed on the registry page after the verdict was written.
       ──────────────────────────────────────────────────────────────── */
    .verdict {
      padding: clamp(2.5rem, 5vw, 4rem) clamp(1.75rem, 4vw, 3rem);
      border-block: 1.5px solid currentColor;
      position: relative;
      overflow: hidden;     /* keeps the rotated stamp from leaking out */
    }
    .verdict-pass { background: var(--state-pass-tint); color: var(--state-pass); }
    .verdict-deny { background: var(--state-deny-tint); color: var(--state-deny); }
    .verdict-gov  { background: var(--state-gov-tint);  color: var(--state-gov); }

    /* Rubber-stamp impression behind the verdict headline. Hollow letters
       (transparent fill + thick stroke) inside a heavy bordered box,
       rotated and offset toward the right edge so it whispers behind the
       headline rather than crowding it. Animates in on page load with a
       tiny "stamp down" gesture — translate + scale + opacity. */
    .verdict-stamp {
      position: absolute;
      top: 50%;
      inset-inline-end: clamp(-1rem, -2vw, 1rem);
      transform: translateY(-50%) rotate(-12deg) scale(1);
      display: grid;
      gap: 0.1em;
      justify-items: center;
      padding: 0.45em 0.85em;
      border: 0.18em solid currentColor;
      border-radius: 14px;
      color: currentColor;
      opacity: 0.16;
      pointer-events: none;
      user-select: none;
      white-space: nowrap;
      line-height: 1;
      filter: blur(0.4px);  /* soft 'inked impression' */
      animation: mw-stamp 700ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
      animation-delay: 380ms;
    }
    .verdict-stamp-en {
      font-size: clamp(3.5rem, 9vw, 7.5rem);
      font-weight: 700;
      letter-spacing: 0.08em;
      -webkit-text-stroke: 0.05em currentColor;
      color: transparent;
    }
    .verdict-stamp-ar {
      font-size: clamp(1.5rem, 3vw, 2.25rem);
      font-weight: 600;
      /* No tracking: Arabic joins break under letter-spacing, and this
         span is Arabic in BOTH language modes. */
      letter-spacing: 0;
      direction: rtl;
      unicode-bidi: isolate;
      -webkit-text-stroke: 0.04em currentColor;
      color: transparent;
    }
    @keyframes mw-stamp {
      0%   { opacity: 0; transform: translateY(-50%) rotate(-12deg) scale(2.6);     filter: blur(8px); }
      55%  { opacity: 0.32; transform: translateY(-50%) rotate(-12deg) scale(1.04); filter: blur(0px); }
      80%  { opacity: 0.20; transform: translateY(-50%) rotate(-12deg) scale(0.98); }
      100% { opacity: 0.16; transform: translateY(-50%) rotate(-12deg) scale(1);    filter: blur(0.4px); }
    }
    /* RTL: mirror the stamp to the opposite side so the confidence
       number on the leading edge still has clear air around it.
       The @keyframes block CANNOT nest under html[dir="rtl"] — that is
       invalid CSS. Instead we define a separate named keyframe and point
       the RTL stamp at it via animation-name. */
    html[dir="rtl"] .verdict-stamp {
      inset-inline-end: auto;
      inset-inline-start: clamp(-1rem, -2vw, 1rem);
      transform: translateY(-50%) rotate(12deg);
      animation-name: mw-stamp-rtl;
    }
    @keyframes mw-stamp-rtl {
      0%   { opacity: 0; transform: translateY(-50%) rotate(12deg) scale(2.6);     filter: blur(8px); }
      55%  { opacity: 0.32; transform: translateY(-50%) rotate(12deg) scale(1.04); filter: blur(0px); }
      80%  { opacity: 0.20; transform: translateY(-50%) rotate(12deg) scale(0.98); }
      100% { opacity: 0.16; transform: translateY(-50%) rotate(12deg) scale(1);    filter: blur(0.4px); }
    }
    @media (max-width: 760px) {
      .verdict-stamp { display: none; }   /* would crowd the small-screen verdict */
    }
    @media (prefers-reduced-motion: reduce) {
      .verdict-stamp { animation: none; filter: blur(0.4px); }
    }

    /* ────────────────────────────────────────────────────────────────
       AUDIT CHAIN ENTRY ANIMATION
       Each event panel fades up in sequence (the chain "lays itself
       down"), and within each panel the row_hash glyph types in via a
       width-clipping animation. Reads as the registry being written
       in real time — fits the audit-chain aesthetic. Staggered via
       inline --i custom property (0..N) set in the template.
       ──────────────────────────────────────────────────────────────── */
    @keyframes mw-chain-in {
      from { opacity: 0; transform: translateY(8px); }
      to   { opacity: 1; transform: translateY(0); }
    }
    @keyframes mw-hash-type {
      from { clip-path: inset(0 100% 0 0); }
      to   { clip-path: inset(0 0 0 0); }
    }
    .chain-row {
      animation: mw-chain-in 520ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
      animation-delay: calc(var(--i, 0) * 90ms + 120ms);
      position: relative;
    }
    .chain-row::before {
      /* a hairline tick that connects rows visually — a slim leading
         rule between consecutive cards, like the index lines of a ledger */
      content: '';
      position: absolute;
      top: -0.6rem;
      inset-inline-start: 1.25rem;
      width: 1px;
      height: 0.6rem;
      background: var(--rule-deep);
      opacity: 0;
      animation: mw-chain-in 520ms ease both;
      animation-delay: calc(var(--i, 0) * 90ms + 60ms);
    }
    .chain-row:first-child::before { display: none; }
    .chain-hash {
      display: inline-block;
      overflow: hidden;
      vertical-align: bottom;
      animation: mw-hash-type 700ms cubic-bezier(0.7, 0, 0.3, 1) both;
      animation-delay: calc(var(--i, 0) * 90ms + 380ms);
    }
    @media (prefers-reduced-motion: reduce) {
      .chain-row, .chain-row::before, .chain-hash { animation: none; }
    }

    /* ────────────────────────────────────────────────────────────────
       EMPTY STATE — for ledgers with zero records.
       A stamped 'no entries on this register' card that uses the
       brand's registry-form language: hairline frame, an inset paper
       stamp at the top, a single line of copy, an optional hint, and
       an optional CTA. Looks like a blank registry page, not a 404.
       ──────────────────────────────────────────────────────────────── */
    .empty-state {
      display: grid;
      justify-items: center;
      gap: 0.75rem;
      padding: clamp(2.5rem, 5vw, 4rem) clamp(1.5rem, 3vw, 2.5rem);
      text-align: center;
      background: var(--surface);
      border: 1px solid var(--rule);
      border-radius: 8px;
      position: relative;
      color: var(--ink);
      animation: mw-page-in 420ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
    }
    .empty-state-mark {
      display: inline-flex;
      align-items: center;
      gap: 0.5rem;
      padding: 0.35rem 0.75rem;
      border-radius: 9999px;
      color: var(--ink-muted);
      font-size: 0.6875rem;
      font-weight: 500;
      letter-spacing: 0.3px;
      text-transform: none;
      background: var(--paper-sunk);
    }
    .empty-state-mark .ico, .empty-state-mark svg { width: 1.1rem; height: 1.1rem; color: var(--ink-faint); }
    .empty-state-title {
      font-size: 1rem;
      font-weight: 500;
      letter-spacing: 0.1px;
      max-width: 40ch;
      color: var(--ink);
    }
    .empty-state-hint {
      font-size: 0.875rem;
      color: var(--ink-muted);
      max-width: 52ch;
      line-height: 1.5;
    }
    .empty-state-cta {
      margin-top: 0.5rem;
    }

    /* Verdict band — used on the decision page header. (See above for the full block.) */
    .verdict-headline {
      font: 500 clamp(2.5rem, 5vw, 4rem)/0.98 'Roboto', system-ui, sans-serif;
      letter-spacing: -0.032em;
      color: currentColor;
    }
    .verdict-ar {
      font: 500 clamp(1.5rem, 2.4vw, 2rem)/1.4 'Roboto', system-ui, sans-serif;
      direction: rtl;
      unicode-bidi: isolate;
      color: currentColor;
      opacity: 0.78;
    }

    /* ────────────────────────────────────────────────────────────────
       META GRID — KV pairs used on decision / audit cards.
       ──────────────────────────────────────────────────────────────── */
    .kv-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
      gap: 1.5rem 2rem;
    }
    .kv-label {
      font: 600 0.6875rem/1 'Roboto', system-ui, sans-serif;
      letter-spacing: 0.14em;
      text-transform: uppercase;
      color: var(--ink-faint);
      margin-bottom: 0.5rem;
      display: block;
    }
    .kv-value { font-size: 0.9375rem; color: var(--ink); line-height: 1.4; }
    .kv-value .ar { color: var(--ink-muted); font-size: 0.8125rem; }

    /* ────────────────────────────────────────────────────────────────
       EYEBROW LABEL ROLES — a designed hierarchy of quiet.
       Audit A8: one identical `uppercase tracking-[…]` micro-label was
       pasted ~156× app-wide, flattening every section kicker, column
       header and datum label into the same shout. These two semantic
       roles (plus the existing .kv-label / .field-label) replace that
       utility-soup with typographic *character by role*:

         .eyebrow   — REGISTER KICKER, the loudest micro-label. Mono
                      caps, widest tracking — reads like a stamped date
                      atop a section.               (mono · 0.14em)
         .col-label — COLUMN / DATUM HEADER, quieter and tighter than the
                      kicker. Sans caps, mid tracking.  (sans · 0.08em)
         .kv-label  — datum label above a value (existing). (sans · 0.14em, faint)
         .field-label — input label (existing), the quietest. (sans · 0.06em)

       Colour is intentionally NOT baked in — kickers ride `ink-faint`
       on paper but `mw-opacity-75` on the brand/verdict surface, so the
       role classes carry type only and leave the ink to a utility. ──── */
    .eyebrow {
      font: 500 0.75rem/1.3 var(--font-sans);
      letter-spacing: 0.3px;
      text-transform: none;
      color: var(--ink-muted);
    }
    .col-label {
      font: 500 0.75rem/1 var(--font-sans);
      letter-spacing: 0.3px;
      text-transform: none;
      color: var(--ink-muted);
    }

    /* A column header that is also a sort link. It must keep reading as a
       HEADER, not as body copy that happens to be clickable — so no anchor
       colour, no underline until hover. The caret is always in the flow
       (dimmed on the inactive columns) so nothing shifts when the sort
       moves from one column to the next. */
    .ledger-sort {
      display: inline-flex;
      align-items: center;
      gap: 0.25rem;
      text-decoration: none;
      cursor: pointer;
    }
    .ledger-sort:hover { text-decoration: underline; color: var(--ink); }
    .ledger-sort.is-sorted { color: var(--ink); font-weight: 600; }
    .ledger-sort-caret { font-size: 0.625rem; line-height: 1; opacity: 0.25; }
    .ledger-sort.is-sorted .ledger-sort-caret { opacity: 1; }

    /* One header cell holding a sort link plus a trailing affordance (the
       evidence-score info dot). Needed because the header is a CSS grid:
       two bare siblings would claim two columns and shear the head off
       the rows beneath it. */
    .ledger-head-cell { display: flex; align-items: center; min-width: 0; }

    /* ────────────────────────────────────────────────────────────────
       TIMELINE — vertical audit trail with rail and dots.
       ──────────────────────────────────────────────────────────────── */
    .timeline { position: relative; padding-inline-start: 1.25rem; }
    .timeline::before {
      content: '';
      position: absolute;
      inset-inline-start: 4px;
      top: 6px;
      bottom: 6px;
      width: 1px;
      background: var(--rule-deep);
    }
    .timeline-item { position: relative; padding-bottom: 1.5rem; }
    .timeline-item:last-child { padding-bottom: 0; }
    .timeline-item::before {
      content: '';
      position: absolute;
      inset-inline-start: -1.25rem;
      top: 6px;
      width: 9px;
      height: 9px;
      background: var(--paper);
      border: 1.5px solid var(--ink);
      transform: translateX(-1px);
    }
    .timeline-item.is-pass::before { border-color: var(--state-pass); }
    .timeline-item.is-deny::before { border-color: var(--state-deny); }
    .timeline-item.is-gov::before  { border-color: var(--state-gov); }
    /* Not-yet-reached step in the passenger status tracker. */
    .timeline-item.is-todo::before { border-color: var(--rule-deep); }

    /* Inline separators used by the status-page progress panels. */
    .hairline-top { border-top: 1px solid var(--rule); }
    .mw-gap-tag   { margin-inline-start: 0.5rem; }

    /* ────────────────────────────────────────────────────────────────
       LAYOUT helpers (used sparingly; most layout via Tailwind utilities)
       ──────────────────────────────────────────────────────────────── */
    .wrap { max-width: 1240px; margin-inline: auto; padding-inline: clamp(1.25rem, 4vw, 2.5rem); }
    .wrap-narrow { max-width: 920px; margin-inline: auto; padding-inline: clamp(1.25rem, 4vw, 2.5rem); }

    .hairline      { height: 1px; background: var(--rule); }
    .hairline-ink  { height: 1px; background: var(--ink); }
    .hairline-on   { height: 1px; background: oklch(1 0 0 / 0.35); }

    /* ────────────────────────────────────────────────────────────────
       NAV
       ──────────────────────────────────────────────────────────────── */


    /* ────────────────────────────────────────────────────────────────
       MOBILE NAV — below md the primary nav collapses behind a
       hamburger. The panel is absolutely anchored to the sticky header
       so opening it overlays the page instead of reflowing it. Links
       stack full-width with the same grouping as the desktop nav.
       ──────────────────────────────────────────────────────────────── */
    /* Mobile top bar — explicit GCP light surface (don't inherit the legacy
       surface-brand-deep border-top; a top bar wants a bottom hairline). */
    .mobile-topbar {
      background: var(--surface); color: var(--ink);
      border-top: 0; border-bottom: 1px solid var(--rule);
    }
    /* Mobile bar wordmark — the bar is now a light GCP surface, so the
       brand text must be ink, not the (now white) on-accent colour. */
    .mobile-topbar .mw-brand-on { color: var(--ink); }
    .mobile-topbar .mw-brand-on .header-mark { color: var(--accent); }
    .mobile-topbar #mw-nav-toggle, .mobile-topbar [data-palette-open] { color: var(--ink-muted); border-color: var(--rule); }

    .mobile-nav {
      position: absolute;
      top: 100%;
      left: 0; right: 0;
      display: none;
      background: var(--surface);
      color: var(--ink-body);
      border-top: 1px solid var(--rule);
      box-shadow: var(--elev-2);
      max-height: calc(100vh - 68px);
      overflow-y: auto;
      z-index: var(--z-sticky);
    }
    .mobile-nav.is-open { display: block; }
    /* Breakpoint split — one rule for everyone: below 900px the compact
       top bar + hamburger panel; at 900px+ the sidebar takes over and the
       mobile chrome is hidden. (display:none here beats tw.css utilities
       of equal specificity because this sheet loads later.) */
    @media (min-width: 900px) {
      .mobile-topbar { display: none !important; }
      #mw-mobile-nav { display: none !important; }
    }

    .mobile-nav-group-label {
      display: block;
      padding: 0.9rem clamp(1.25rem, 2.5vw, 2rem) 0.35rem;
      font: 500 0.6875rem/1 var(--font-sans);
      letter-spacing: 0.06em;
      text-transform: uppercase;
      color: var(--ink-faint);
    }
    .mobile-nav-link {
      display: flex;
      align-items: center;
      gap: 0.9rem;
      padding: 0.8rem clamp(1.25rem, 2.5vw, 2rem);
      font-size: 0.9375rem;
      font-weight: 400;
      color: var(--ink-body);
      border-bottom: 1px solid var(--rule-soft);
      text-decoration: none;
    }
    .mobile-nav-link .ico { color: var(--ink-muted); }
    .mobile-nav-link:hover { color: var(--ink); background: var(--hover); }
    .mobile-nav-link.active {
      color: var(--accent); font-weight: 500;
      background: var(--brand-tint);
      box-shadow: inset 3px 0 0 var(--accent);
    }
    .mobile-nav-link.active .ico { color: var(--accent); }
    html[dir="rtl"] .mobile-nav-link.active { box-shadow: inset -3px 0 0 var(--accent); }

    /* ────────────────────────────────────────────────────────────────
       SMALL-SCREEN LEDGERS — below md every multi-column register row
       (annotated with .mw-card-row) collapses from its inline
       grid-template-columns spec into a wrapping card so no value is
       crushed to an unreadable sliver:
         .mw-full-sm  cell takes its own full line
         .mw-push-sm  cell rides the end of its line
         .mw-hide-sm  cell (or the column-header row) is dropped —
                      only for values repeated in the expanded detail
       The !important display flips are deliberate: they must beat both
       the Tailwind .grid class and the per-page inline column specs.
       ──────────────────────────────────────────────────────────────── */
    @media (max-width: 767px) {
      .mw-hide-sm { display: none !important; }
      .mw-card-row {
        display: flex !important;
        flex-wrap: wrap;
        align-items: baseline;
        gap: 0.3rem 0.75rem;
        padding-block: 0.9rem;
      }
      .mw-card-row > * { min-width: 0; }
      .mw-full-sm { flex-basis: 100%; }
      .mw-push-sm { margin-inline-start: auto; }

      /* Page header — the meta column drops under the title instead of
         squeezing it from the side. */
      .page-head { grid-template-columns: 1fr; align-items: start; }
      .page-meta { text-align: start; margin-top: 0.35rem; }
    }

    /* ── Sidebar-aware companion breakpoint ──────────────────────────
       The block above keys off VIEWPORT width, but on desktop the
       content column is viewport minus the 250px expanded rail — so a
       900–1017px window with the rail open leaves the content under
       768px of real room and the multi-column ledgers crush without
       ever hitting the "small screen" rules. The rail state lives on
       <html> (data-side-collapsed, applied pre-paint), which lets CSS
       compute the true content width: expanded rail + viewport below
       250+768 = 1018px ⇒ apply the same collapse. (The collapsed 72px
       rail never brings content under 768px at a ≥900px viewport, so
       it needs no companion.) Keep this block in lockstep with the
       767px block above. */
    @media (min-width: 900px) and (max-width: 1017.98px) {
      html:not([data-side-collapsed]) .mw-hide-sm { display: none !important; }
      html:not([data-side-collapsed]) .mw-card-row {
        display: flex !important;
        flex-wrap: wrap;
        align-items: baseline;
        gap: 0.3rem 0.75rem;
        padding-block: 0.9rem;
      }
      html:not([data-side-collapsed]) .mw-card-row > * { min-width: 0; }
      html:not([data-side-collapsed]) .mw-full-sm { flex-basis: 100%; }
      html:not([data-side-collapsed]) .mw-push-sm { margin-inline-start: auto; }
      html:not([data-side-collapsed]) .page-head { grid-template-columns: 1fr; align-items: start; }
      html:not([data-side-collapsed]) .page-meta { text-align: start; margin-top: 0.35rem; }
    }

    /* ── Dense registers — earlier collapse ──────────────────────────
       The 5–9-column reference ledgers (visa / passport / watchlist /
       national-id / sources / inbox / rules registers) carry ~21–47rem
       of fixed column width, so the generic 768px threshold leaves
       them crushed long before it fires. They need ~900px of CONTENT
       room; the content column falls under that in three windows:
         · any viewport below 900px (no rail),
         · a collapsed 72px rail until viewport 972px,
         · an expanded 250px rail until viewport 1150px.
       The rows already carry .mw-card-row, so "collapse" is the same
       flex flip as the 767px block; the matching column-header row
       carries .mw-hide-sm + the same .mw-cols-* class, which is how
       it is targeted here without new markup. */
    @media (max-width: 899.98px) {
      .mw-hide-sm:is(.mw-cols-visa, .mw-cols-passport, .mw-cols-watchlist,
        .mw-cols-nationalid, .mw-cols-sources, .mw-cols-iam,
        .mw-cols-rules-intake, .mw-cols-rules-llm) { display: none !important; }
      .mw-card-row:is(.mw-cols-visa, .mw-cols-passport, .mw-cols-watchlist,
        .mw-cols-nationalid, .mw-cols-sources, .mw-cols-iam,
        .mw-cols-rules-intake, .mw-cols-rules-llm) {
        display: flex !important;
        flex-wrap: wrap;
        align-items: baseline;
        gap: 0.3rem 0.75rem;
        padding-block: 0.9rem;
      }
      .mw-card-row:is(.mw-cols-visa, .mw-cols-passport, .mw-cols-watchlist,
        .mw-cols-nationalid, .mw-cols-sources, .mw-cols-iam,
        .mw-cols-rules-intake, .mw-cols-rules-llm) > * { min-width: 0; }
      .mw-card-row:is(.mw-cols-visa, .mw-cols-passport, .mw-cols-watchlist,
        .mw-cols-nationalid, .mw-cols-sources, .mw-cols-iam,
        .mw-cols-rules-intake, .mw-cols-rules-llm) .mw-full-sm { flex-basis: 100%; }
      .mw-card-row:is(.mw-cols-visa, .mw-cols-passport, .mw-cols-watchlist,
        .mw-cols-nationalid, .mw-cols-sources, .mw-cols-iam,
        .mw-cols-rules-intake, .mw-cols-rules-llm) .mw-push-sm { margin-inline-start: auto; }
    }
    @media (min-width: 900px) and (max-width: 971.98px) {
      html[data-side-collapsed] .mw-hide-sm:is(.mw-cols-visa, .mw-cols-passport,
        .mw-cols-watchlist, .mw-cols-nationalid, .mw-cols-sources, .mw-cols-iam,
        .mw-cols-rules-intake, .mw-cols-rules-llm) { display: none !important; }
      html[data-side-collapsed] .mw-card-row:is(.mw-cols-visa, .mw-cols-passport,
        .mw-cols-watchlist, .mw-cols-nationalid, .mw-cols-sources, .mw-cols-iam,
        .mw-cols-rules-intake, .mw-cols-rules-llm) {
        display: flex !important;
        flex-wrap: wrap;
        align-items: baseline;
        gap: 0.3rem 0.75rem;
        padding-block: 0.9rem;
      }
      html[data-side-collapsed] .mw-card-row:is(.mw-cols-visa, .mw-cols-passport,
        .mw-cols-watchlist, .mw-cols-nationalid, .mw-cols-sources, .mw-cols-iam,
        .mw-cols-rules-intake, .mw-cols-rules-llm) > * { min-width: 0; }
      html[data-side-collapsed] .mw-card-row:is(.mw-cols-visa, .mw-cols-passport,
        .mw-cols-watchlist, .mw-cols-nationalid, .mw-cols-sources, .mw-cols-iam,
        .mw-cols-rules-intake, .mw-cols-rules-llm) .mw-full-sm { flex-basis: 100%; }
      html[data-side-collapsed] .mw-card-row:is(.mw-cols-visa, .mw-cols-passport,
        .mw-cols-watchlist, .mw-cols-nationalid, .mw-cols-sources, .mw-cols-iam,
        .mw-cols-rules-intake, .mw-cols-rules-llm) .mw-push-sm { margin-inline-start: auto; }
    }
    @media (min-width: 1018px) and (max-width: 1149.98px) {
      html:not([data-side-collapsed]) .mw-hide-sm:is(.mw-cols-visa, .mw-cols-passport,
        .mw-cols-watchlist, .mw-cols-nationalid, .mw-cols-sources, .mw-cols-iam,
        .mw-cols-rules-intake, .mw-cols-rules-llm) { display: none !important; }
      html:not([data-side-collapsed]) .mw-card-row:is(.mw-cols-visa, .mw-cols-passport,
        .mw-cols-watchlist, .mw-cols-nationalid, .mw-cols-sources, .mw-cols-iam,
        .mw-cols-rules-intake, .mw-cols-rules-llm) {
        display: flex !important;
        flex-wrap: wrap;
        align-items: baseline;
        gap: 0.3rem 0.75rem;
        padding-block: 0.9rem;
      }
      html:not([data-side-collapsed]) .mw-card-row:is(.mw-cols-visa, .mw-cols-passport,
        .mw-cols-watchlist, .mw-cols-nationalid, .mw-cols-sources, .mw-cols-iam,
        .mw-cols-rules-intake, .mw-cols-rules-llm) > * { min-width: 0; }
      html:not([data-side-collapsed]) .mw-card-row:is(.mw-cols-visa, .mw-cols-passport,
        .mw-cols-watchlist, .mw-cols-nationalid, .mw-cols-sources, .mw-cols-iam,
        .mw-cols-rules-intake, .mw-cols-rules-llm) .mw-full-sm { flex-basis: 100%; }
      html:not([data-side-collapsed]) .mw-card-row:is(.mw-cols-visa, .mw-cols-passport,
        .mw-cols-watchlist, .mw-cols-nationalid, .mw-cols-sources, .mw-cols-iam,
        .mw-cols-rules-intake, .mw-cols-rules-llm) .mw-push-sm { margin-inline-start: auto; }
    }

    .role-select {
      appearance: none;
      background: transparent;
      color: var(--brand-on);
      border: 1px solid oklch(1 0 0 / 0.35);
      border-radius: 1px;
      padding: 0.375rem 1.5rem 0.375rem 0.625rem;
      font-size: 0.75rem;
      font-weight: 500;
      letter-spacing: 0.02em;
      background-image: url("data:image/svg+xml,%3Csvg width='8' height='5' viewBox='0 0 8 5' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1l3 3 3-3' stroke='%23F5FAF7' fill='none' stroke-width='1.4'/%3E%3C/svg%3E");
      background-repeat: no-repeat;
      background-position: right 0.5rem center;
      color-scheme: dark;
    }
    .role-select option { background: var(--brand-deep); color: var(--brand-on); }
    .role-select:focus { outline: none; border-color: var(--brand-on); }

    /* Language toggle pill — two segments, the active one inverted. */
    .lang-toggle {
      display: inline-flex;
      border: 1px solid oklch(1 0 0 / 0.35);
      border-radius: 2px;
      overflow: hidden;
      background: transparent;
    }
    /* Hairline divider between the two segments (house segmented-control
       pattern, cf. .rf-seg) — the squared outer edge does the rest. */
    .lang-toggle button + button {
      border-inline-start: 1px solid oklch(1 0 0 / 0.25);
    }
    .lang-toggle button {
      font: 600 0.6875rem/1 'Roboto', system-ui, sans-serif;
      letter-spacing: 0.08em;
      color: var(--brand-on-mu);
      background: transparent;
      border: 0;
      padding: 0.35rem 0.7rem;
      cursor: pointer;
      transition: background-color 120ms ease, color 120ms ease;
    }
    .lang-toggle button:hover { color: var(--brand-on); }
    .lang-toggle button.is-active {
      background: var(--brand-on);
      color: var(--brand-deep);
    }

    /* ────────────────────────────────────────────────────────────────
       FIELD HELP POPOVER — a single floating chip that follows focus
       on text inputs / textareas and hover on <select> elements.
       Drives from data-help (required) and data-help-example (optional)
       on the input. Vanishes the moment the field has a value, so once
       the user types or picks an option the chrome gets out of the way.
       Position is set in JS via top/left and one of these orientation
       classes (so the arrow lands on the correct edge).
       ──────────────────────────────────────────────────────────────── */
    .field-help {
      position: fixed;
      top: 0; left: 0;
      max-width: 280px;
      min-width: 180px;
      padding: 0.7rem 0.85rem;
      background: var(--ink);
      color: var(--paper);
      font-family: 'Roboto', system-ui, sans-serif;
      font-size: 0.8125rem;
      line-height: 1.45;
      letter-spacing: 0.005em;
      border-radius: 8px;
      box-shadow:
        0 1px 2px oklch(0.18 0.014 264 / 0.20),
        0 12px 28px -12px oklch(0.18 0.014 264 / 0.45);
      z-index: var(--z-toast);
      pointer-events: none;
      opacity: 0;
      visibility: hidden;
      transform: translate(-4px, 0);
      transition:
        opacity 160ms ease,
        transform 160ms ease,
        visibility 0s linear 160ms;
    }
    .field-help.is-on {
      opacity: 1;
      visibility: visible;
      transform: translate(0, 0);
      transition-delay: 0s;
    }
    .field-help.is-left  { transform: translate(4px, 0); }     /* incoming-from-right slide */
    .field-help.is-left.is-on { transform: translate(0, 0); }

    .field-help-text {
      display: block;
      font-weight: 500;
    }
    .field-help-example {
      display: block;
      margin-top: 0.45rem;
      padding-top: 0.45rem;
      border-top: 1px solid oklch(1 0 0 / 0.14);
      font-size: 0.75rem;
      font-weight: 500;
      letter-spacing: 0.02em;
      color: oklch(1 0 0 / 0.80);
    }
    .field-help-example::before {
      content: 'e.g. ';
      letter-spacing: 0.08em;
      text-transform: uppercase;
      font-size: 0.68rem;
      font-weight: 600;
      opacity: 0.55;
      margin-inline-end: 0.35rem;
    }
    html[dir="rtl"] .field-help-example::before { content: 'مثال: '; }

    /* Arrow — a small triangle that visually anchors the chip to its
       field. Rendered as a rotated square so border-radius doesn't
       break it. Placed on the side opposite the chip's offset. */
    .field-help::after {
      content: '';
      position: absolute;
      width: 10px;
      height: 10px;
      background: var(--ink);
      transform: rotate(45deg);
      top: 50%;
      margin-top: -5px;
      inset-inline-start: -4px;
      border-bottom-left-radius: 2px;
    }
    .field-help.is-left::after {
      inset-inline-start: auto;
      inset-inline-end: -4px;
      border-bottom-left-radius: 0;
      border-top-right-radius: 2px;
    }
    /* Vertical-anchor variant: when there's no horizontal room, the chip
       drops below the field and the arrow swings to the top edge. */
    .field-help.is-below::after {
      top: -4px;
      margin-top: 0;
      left: 18px;
      inset-inline-start: 18px;
      inset-inline-end: auto;
    }
    @media (prefers-reduced-motion: reduce) {
      .field-help { transition: opacity 0s, visibility 0s; transform: none; }
    }

    /* ────────────────────────────────────────────────────────────────
       TOOLTIP — CSS-only, attached via data-tip="..." (no JS).
       Renders a small dark chip below the trigger after a short hover
       delay; appears on keyboard focus too. Stays inside the viewport
       via the data-tip-align="end|start" modifier when needed.
       ──────────────────────────────────────────────────────────────── */
    [data-tip] { position: relative; }
    [data-tip]::after {
      content: attr(data-tip);
      position: absolute;
      top: calc(100% + 8px);
      inset-inline-start: 50%;
      transform: translateX(-50%) translateY(-2px);
      background: var(--ink);
      color: var(--paper);
      font-family: 'Roboto', system-ui, sans-serif;
      font-size: 0.6875rem;
      font-weight: 500;
      /* Explicit, not inherited: the info-dot trigger is italic (its glyph is
         a typographic "i"), and without this the whole chip renders italic. */
      font-style: normal;
      letter-spacing: 0.02em;
      line-height: 1.25;
      padding: 0.4rem 0.6rem;
      border-radius: 4px;
      white-space: nowrap;
      max-width: 18rem;
      pointer-events: none;
      opacity: 0;
      visibility: hidden;
      transition: opacity 120ms ease 0s, transform 120ms ease 0s, visibility 0s linear 120ms;
      z-index: var(--z-toast);
      box-shadow: 0 6px 16px -6px oklch(0.18 0.014 264 / 0.35);
    }
    html[dir="rtl"] [data-tip]::after {
      transform: translateX(50%) translateY(-2px);
    }
    [data-tip]:hover::after,
    [data-tip]:focus-visible::after {
      opacity: 1;
      visibility: visible;
      transform: translateX(-50%) translateY(0);
      transition-delay: 350ms, 350ms, 0s;
    }
    html[dir="rtl"] [data-tip]:hover::after,
    html[dir="rtl"] [data-tip]:focus-visible::after {
      transform: translateX(50%) translateY(0);
    }
    /* Right-anchor variant so tooltips near the right edge stay on-screen. */
    [data-tip][data-tip-align="end"]::after {
      inset-inline-start: auto;
      inset-inline-end: 0;
      transform: translateY(-2px);
    }
    [data-tip][data-tip-align="end"]:hover::after,
    [data-tip][data-tip-align="end"]:focus-visible::after {
      transform: translateY(0);
    }
    /* Left-anchor variant. */
    [data-tip][data-tip-align="start"]::after {
      inset-inline-start: 0;
      transform: translateY(-2px);
    }
    [data-tip][data-tip-align="start"]:hover::after,
    [data-tip][data-tip-align="start"]:focus-visible::after {
      transform: translateY(0);
    }
    /* Above-trigger variant — for footer-anchored controls. */
    [data-tip][data-tip-side="top"]::after {
      top: auto;
      bottom: calc(100% + 8px);
    }
    @media (prefers-reduced-motion: reduce) {
      [data-tip]::after { transition: none; }
    }

    /* Wrapping variant — the base chip is `white-space: nowrap` (which makes
       its `max-width` inert), right for a two-word hint and useless for an
       explanation. Opt in with data-tip-wrap; do NOT relax the base rule, or
       every one-line tooltip in the app reflows. */
    [data-tip][data-tip-wrap]::after {
      white-space: normal;
      width: min(22rem, 60vw);
      text-align: start;
      font-weight: 400;
      line-height: 1.45;
      padding: 0.55rem 0.7rem;
    }

    /* ────────────────────────────────────────────────────────────────
       INFO DOT — the circled "i" that opens an explanatory tooltip next
       to a number whose meaning is not self-evident (the inbox evidence
       score). A real <button type="button"> so the tooltip's
       :focus-visible reveal reaches keyboard users; it carries no action,
       so nothing is lost when JS is off. currentColor throughout, so it
       tints to whatever panel it sits in (the verdict card recolours per
       outcome) without a per-surface rule.
       ──────────────────────────────────────────────────────────────── */
    .info-dot {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      width: 1rem;
      height: 1rem;
      flex: none;
      border: 1px solid currentColor;
      border-radius: 50%;
      background: transparent;
      color: inherit;
      font-family: 'Roboto', system-ui, sans-serif;
      font-size: 0.6875rem;
      font-weight: 700;
      font-style: italic;
      line-height: 1;
      letter-spacing: 0;
      padding: 0;
      cursor: help;
      vertical-align: middle;
      margin-inline-start: 0.35rem;
      transition: background-color 120ms ease;
    }
    /* No opacity fade on the dot itself. It rides surfaces that are ALREADY
       dimmed (the case verdict panel wraps its label in .mw-opacity-75, and
       opacity compounds down the subtree) — at 0.6 the glyph on the pale
       green APPROVE panel came out at an effective 0.45 and was illegible.
       Full currentColor puts it at exactly the legibility of the "97%" it
       annotates. */
    .info-dot:hover,
    .info-dot:focus-visible {
      background: color-mix(in oklch, currentColor 16%, transparent);
    }

    /* ────────────────────────────────────────────────────────────────
       LOADERS — spinner, skeleton, top-of-page nav progress bar.
       Skeletons reuse the paper-sunk colour so they sit in the page
       without flashing. Spinners use currentColor so they tint to
       whatever button or surface they're embedded in.
       ──────────────────────────────────────────────────────────────── */
    @keyframes mw-spin { to { transform: rotate(360deg); } }
    @keyframes mw-skel {
      0%   { background-position: 100% 0; }
      100% { background-position: -100% 0; }
    }
    @keyframes mw-bar {
      0%   { transform: translateX(-100%); }
      60%  { transform: translateX(20%); }
      100% { transform: translateX(100%); }
    }

    .spinner {
      display: inline-block;
      width: 1rem;
      height: 1rem;
      border: 2px solid currentColor;
      border-right-color: transparent;
      border-radius: 50%;
      animation: mw-spin 720ms linear infinite;
      vertical-align: -0.18em;
    }
    .spinner-sm { width: 0.75rem; height: 0.75rem; border-width: 1.5px; }
    .spinner-lg { width: 1.5rem;  height: 1.5rem;  border-width: 2.5px; }

    /* Page-level loader used on long-running screens (verdict computing,
       chain verifying, large list mount). Centered, with a caption slot. */
    .loader-block {
      display: grid;
      place-items: center;
      gap: 0.85rem;
      padding: clamp(2rem, 5vw, 3.5rem) 1rem;
      color: var(--ink-muted);
      font-size: 0.8125rem;
      letter-spacing: 0.02em;
    }
    .loader-block .spinner { color: var(--brand); }

    /* Skeleton — shimmer-on-sunken-paper. Use .skel as a placeholder shape;
       size via Tailwind width/height utilities or inline width/height. */
    .skel {
      display: block;
      background: linear-gradient(
        90deg,
        var(--paper-sunk) 0%,
        oklch(0.99 0.005 264) 50%,
        var(--paper-sunk) 100%
      );
      background-size: 200% 100%;
      animation: mw-skel 1400ms ease-in-out infinite;
      border-radius: 4px;
      min-height: 0.85rem;
      color: transparent !important;
      user-select: none;
      pointer-events: none;
    }
    .skel-line   { height: 0.85rem; width: 100%; }
    .skel-line-sm{ height: 0.65rem; width: 60%; }
    .skel-title  { height: 1.4rem;  width: 50%; }
    .skel-circle { border-radius: 50%; }
    .skel-card   { height: 8rem; border-radius: 12px; }

    /* Skeleton row inside the ledger — matches the row anatomy so the
       layout doesn't jump when real data lands. */
    .skel-row {
      display: grid;
      grid-template-columns: minmax(0,1.6fr) minmax(0,1fr) minmax(0,1fr) 6rem;
      gap: 1.5rem;
      padding: 1rem 0;
      border-bottom: 1px solid var(--rule);
      align-items: center;
    }

    /* Submit-disabled state used by the form-loader JS hook below. */
    .is-loading[disabled],
    [data-loading-form].is-submitting button[type="submit"],
    [data-loading-form].is-submitting .btn,
    [data-loading-form].is-submitting .btn-go {
      opacity: 0.7;
      cursor: progress;
      pointer-events: none;
    }
    [data-loading-form].is-submitting button[type="submit"] .btn-label,
    [data-loading-form].is-submitting .btn .btn-label,
    [data-loading-form].is-submitting .btn-go .btn-label {
      visibility: hidden;
    }
    /* When a button is mid-submit, we drop a centered spinner over it. */
    .btn, .btn-go { position: relative; }
    /* The scenario bar's rows are the other thing an answer is submitted with.
       They are not .btn/.btn-go, so without this a pick showed no sign of
       having been pressed. No label-hiding spinner here — a pick row carries a
       name and a hint over two lines and blanking it looks like the option
       vanished; dimming plus the full-screen overlay says "working" without
       taking the text away. */
    [data-loading-form].is-submitting .mw-pick,
    [data-loading-form].is-submitting .mw-pick-other .btn {
      opacity: 0.6;
      cursor: progress;
      pointer-events: none;
    }

    /* ── Touch press feedback ────────────────────────────────────────────
       Tailwind's preflight sets `-webkit-tap-highlight-color: transparent`
       on <html>, and `:hover` never fires on touch. So on a phone these
       controls had NO press feedback of any kind, and the turn behind an
       interview answer runs fact extraction and judging — seconds during
       which a passenger tapped and nothing whatsoever changed.

       This fires on touch-down, before any network round-trip, which is why
       it is worth having on top of the overlay: the overlay proves the
       request started, this proves the finger landed. */
    .btn:active,
    .btn-go:active,
    .mw-pick:active:not([disabled]) {
      transform: translateY(1px) scale(0.985);
      filter: brightness(0.95);
    }
    @media (prefers-reduced-motion: reduce) {
      .btn:active, .btn-go:active, .mw-pick:active:not([disabled]) {
        transform: none;
      }
    }

    [data-loading-form].is-submitting .btn::after,
    [data-loading-form].is-submitting .btn-go::after {
      content: '';
      position: absolute;
      top: 50%; left: 50%;
      width: 1rem; height: 1rem;
      margin: -0.5rem 0 0 -0.5rem;
      border: 2px solid currentColor;
      border-right-color: transparent;
      border-radius: 50%;
      animation: mw-spin 720ms linear infinite;
    }

    /* Top-of-page navigation progress bar (fires on link clicks / form
       submits, hidden after pageshow). Pure CSS animation; JS only adds
       the .is-on class to start it. */
    .nav-progress {
      position: fixed;
      top: 0; left: 0; right: 0;
      height: 2px;
      background: transparent;
      z-index: var(--z-toast);
      pointer-events: none;
      overflow: hidden;
    }
    .nav-progress::before {
      content: '';
      position: absolute;
      inset: 0;
      background: linear-gradient(
        90deg,
        transparent,
        var(--brand) 30%,
        var(--brand-soft) 60%,
        transparent
      );
      transform: translateX(-100%);
    }
    .nav-progress.is-on::before {
      animation: mw-bar 900ms ease-in-out infinite;
    }

    @media (prefers-reduced-motion: reduce) {
      .spinner, .skel, .nav-progress.is-on::before { animation: none; }
      .skel { background: var(--paper-sunk); }
    }

    /* ────────────────────────────────────────────────────────────────
       PAGE TRANSITIONS — native cross-document View Transitions where
       supported (Chrome/Edge/Safari ≥18), graceful CSS fade-up fallback
       everywhere else (gated behind @supports so motion never doubles).

       One motion language, three dialects — the DESTINATION's
       data-vt-zone on <html> (set server-side from the route) picks the
       choreography, so every kind of movement through the app reads
       differently:

         desk    · passenger flow — inline "page-turn": the next form is
                   slid across the counter. Axis honours the reading
                   direction (--vt-x flips under RTL) and reverses on
                   history back-traversal (--vt-flow, set by the
                   pagereveal handler in <head>).
         verdict · decision & contact-gov — "the settle": the incoming
                   document starts a hair oversized and settles flat
                   onto the desk. Slower on purpose; the verdict-stamp
                   animation then lands on top of a still page.
         ledger  · admin & audit — "drawer riffle": a short block-axis
                   slide, quick and clerical.

       Same-path navigations (language switch, form re-renders) crossfade
       only — movement would lie about where the user went.
       Sticky header stays fixed across all of it (own snapshot group).
       ──────────────────────────────────────────────────────────────── */
    @view-transition { navigation: auto; }

    :root {
      --vt-x: 1;        /* inline axis sign — flipped by dir="rtl" */
      --vt-flow: 1;     /* -1 on back-traversal (data-vt-dir="back") */
      --vt-ease-out: cubic-bezier(0.55, 0, 0.58, 0.24); /* exits: accelerate away */
      --vt-ease-in:  cubic-bezier(0.16, 1, 0.3, 1);     /* entries: long settle */
    }
    html[dir="rtl"] { --vt-x: -1; }
    html[data-vt-dir="back"] { --vt-flow: -1; }

    /* desk — inline page-turn (the default zone) */
    @keyframes mw-vt-desk-out {
      to { opacity: 0; transform: translateX(calc(var(--vt-x) * var(--vt-flow) * -18px)); }
    }
    @keyframes mw-vt-desk-in {
      from { opacity: 0; transform: translateX(calc(var(--vt-x) * var(--vt-flow) * 26px)); }
    }
    ::view-transition-old(root) {
      animation: mw-vt-desk-out 160ms var(--vt-ease-out) both;
    }
    ::view-transition-new(root) {
      animation: mw-vt-desk-in 300ms var(--vt-ease-in) both;
    }

    /* verdict — the settle */
    @keyframes mw-vt-verdict-out {
      to { opacity: 0; }
    }
    @keyframes mw-vt-verdict-in {
      from { opacity: 0; transform: scale(1.015) translateY(calc(var(--vt-flow) * 6px)); }
    }
    html[data-vt-zone="verdict"]::view-transition-old(root) {
      animation: mw-vt-verdict-out 200ms ease both;
    }
    html[data-vt-zone="verdict"]::view-transition-new(root) {
      animation: mw-vt-verdict-in 380ms var(--vt-ease-in) both;
    }

    /* ledger — drawer riffle */
    @keyframes mw-vt-ledger-out {
      to { opacity: 0; transform: translateY(calc(var(--vt-flow) * -8px)); }
    }
    @keyframes mw-vt-ledger-in {
      from { opacity: 0; transform: translateY(calc(var(--vt-flow) * 12px)); }
    }
    html[data-vt-zone="ledger"]::view-transition-old(root) {
      animation: mw-vt-ledger-out 130ms var(--vt-ease-out) both;
    }
    html[data-vt-zone="ledger"]::view-transition-new(root) {
      animation: mw-vt-ledger-in 240ms var(--vt-ease-in) both;
    }

    /* Same-path navigation — crossfade only. Declared last so it wins
       the equal-specificity contest against the zone rules above. */
    html[data-vt-same]::view-transition-old(root) {
      animation: mw-vt-verdict-out 140ms ease both;
    }
    html[data-vt-same]::view-transition-new(root) {
      animation: mw-vt-fade-in 200ms ease both;
    }
    @keyframes mw-vt-fade-in {
      from { opacity: 0; }
    }

    /* Pin the persistent chrome so it doesn't re-animate — only the page
       beneath moves. Each piece has a stable, identical viewport box on
       every route, which is what makes freezing it safe:
         · mw-side   — the desktop left rail (.app-side, sticky full-height,
                       shown ≥900px). Without this it rides inside the root
                       snapshot and slides/fades on every navigation.
         · mw-header — the mobile sticky top bar (shown <900px).
         · mw-progress — the top-of-page loading bar.
       On viewports where a piece is display:none it has no box, so its
       freeze rule is simply inert — desktop and mobile never both apply. */
    .app-side { view-transition-name: mw-side; }
    header.surface-brand-deep { view-transition-name: mw-header; }
    .nav-progress { view-transition-name: mw-progress; }
    ::view-transition-group(mw-side),
    ::view-transition-group(mw-header),
    ::view-transition-group(mw-progress) {
      animation-duration: 0ms;
    }
    /* Zeroing the group only freezes the geometry morph — the UA still
       cross-fades the old/new snapshot images over ~250ms, so the whole
       rail visibly re-materialised on every navigation (and any snapshot
       mismatch read as a jump). Kill the image animations too: the new
       snapshot sits on top at full opacity, so the chrome just IS there,
       instantly, every navigation. */
    ::view-transition-old(mw-side),
    ::view-transition-new(mw-side),
    ::view-transition-old(mw-header),
    ::view-transition-new(mw-header),
    ::view-transition-old(mw-progress),
    ::view-transition-new(mw-progress) {
      animation: none;
    }

    /* Fallback page-in for browsers without View Transitions (Firefox at
       time of writing). Gated so supporting browsers don't run BOTH the
       snapshot slide and this one — that would double every offset.
       (mw-page-in stays global: .empty-state reuses it.) */
    @keyframes mw-page-in {
      from { opacity: 0; transform: translateY(6px); }
      to   { opacity: 1; transform: translateY(0); }
    }
    @supports not (view-transition-name: none) {
      main { animation: mw-page-in 320ms cubic-bezier(0.2, 0.7, 0.2, 1) both; }
    }

    @media (prefers-reduced-motion: reduce) {
      ::view-transition-old(root),
      ::view-transition-new(root),
      html[data-vt-zone]::view-transition-old(root),
      html[data-vt-zone]::view-transition-new(root) { animation: none; }
      main { animation: none; }
    }

    /* ────────────────────────────────────────────────────────────────
       HERO REVEAL — one deliberate animation per Design Principle #5.
       Latin lands, Arabic follows; equal voice in two beats.
       Page is fully visible without it (no opacity:0 gate).
       ──────────────────────────────────────────────────────────────── */
    @keyframes lift {
      from { transform: translateY(6px); opacity: 0.6; }
      to   { transform: translateY(0); opacity: 1; }
    }
    .lift     { animation: lift 600ms cubic-bezier(0.2, 0.7, 0.2, 1) both; }
    .lift-1   { animation-delay: 80ms; }
    .lift-2   { animation-delay: 280ms; }
    .lift-3   { animation-delay: 460ms; }

    @media (prefers-reduced-motion: reduce) {
      .lift, .lift-1, .lift-2, .lift-3 { animation: none; }
      * { transition: none !important; }
    }

    /* ────────────────────────────────────────────────────────────────
       FOCUS — visible, on-brand, never browser default only.
       ──────────────────────────────────────────────────────────────── */
    :focus-visible {
      outline: 2px solid var(--brand);
      outline-offset: 2px;
    }

    /* Skip link (WCAG 2.4.1) — parked above the viewport until focused. */
    .skip-link {
      position: absolute;
      inset-inline-start: 1rem;
      top: -3.5rem;
      z-index: var(--z-toast);
      padding: 0.6rem 1rem;
      background: var(--ink);
      color: var(--paper);
      font-size: 0.8125rem;
      text-decoration: none;
      border-radius: 0 0 6px 6px;
      transition: top 120ms ease;
    }
    .skip-link:focus {
      top: 0;
      outline: 2px solid var(--brand-on);
      outline-offset: -4px;
    }
    .surface-brand :focus-visible,
    .surface-brand-deep :focus-visible {
      outline-color: var(--brand-on);
    }

    a { color: inherit; }
    a.link {
      color: var(--brand);
      text-decoration: underline;
      text-underline-offset: 3px;
      text-decoration-thickness: 1px;
      text-decoration-color: var(--rule-deep);
    }
    a.link:hover { text-decoration-color: var(--brand); }

    /* ────────────────────────────────────────────────────────────────
       Logo seal — recoloured to read on either surface via currentColor.
       ──────────────────────────────────────────────────────────────── */
    .seal { display: inline-block; color: currentColor; }
    /* The mountain mark is WIDER than tall (168x146 in its own space), so
       the boxes below carry that ratio — a square box would letterbox it. */
    .seal-nav { width: 34px; height: 30px; }

    /* Header mark — the mountain triangle from the official logo, no
       wordmark. The live header supplies the Arabic / Latin label next
       to it in the active language, so the SVG stays mark-only. Box
       ratio matches the mark (1.125:1) so nothing letterboxes. */
    .header-mark {
      display: inline-block;
      width: 42px;
      height: 37px;
      color: currentColor;
      flex-shrink: 0;
    }

    /* ────────────────────────────────────────────────────────────────
       APP DIALOG — replaces window.confirm()/alert() console-wide.
       Native <dialog> for focus trap + Escape; styled as registry paper.
       ──────────────────────────────────────────────────────────────── */
    dialog.mw-dialog {
      border: 1px solid var(--rule);
      border-radius: 8px;
      padding: 1.5rem;
      width: min(92vw, 28rem);
      background: var(--paper);
      color: var(--ink);
      box-shadow: 0 24px 60px oklch(0.18 0.014 264 / 0.18);
    }
    dialog.mw-dialog::backdrop { background: oklch(0.18 0.014 264 / 0.45); }
    dialog.mw-dialog[open] { animation: mw-dialog-in 160ms ease-out; }
    @keyframes mw-dialog-in {
      from { opacity: 0; transform: translateY(6px); }
      to   { opacity: 1; transform: none; }
    }
    @media (prefers-reduced-motion: reduce) {
      dialog.mw-dialog[open] { animation: none; }
    }

    /* ────────────────────────────────────────────────────────────────
       INLINE SVG ICON SYSTEM — server-side sprite, no CDN dependency.
       Icons are <svg><use href="#icon-name"></svg> rendered by the
       icon() macro from _macros.html. Inherits currentColor so they
       adapt to any surface automatically.
       Size with .ico-* or Tailwind width/height utilities.
       ──────────────────────────────────────────────────────────────── */
    .ico   { width: 1rem;     height: 1rem;     stroke-width: 1.75; vertical-align: -0.15em; flex-shrink: 0; }
    .ico-sm{ width: 0.875rem; height: 0.875rem; stroke-width: 1.75; vertical-align: -0.15em; flex-shrink: 0; }
    .ico-lg{ width: 1.25rem;  height: 1.25rem;  stroke-width: 1.75; vertical-align: -0.18em; flex-shrink: 0; }
    .ico-xl{ width: 1.5rem;   height: 1.5rem;   stroke-width: 1.75; vertical-align: -0.2em;  flex-shrink: 0; }
    /* In RTL, directional glyphs (arrow-right, chevron-right) flip to
       match reading flow. Target the <svg> inside .ico-* wrappers whose
       use-href ends in "-right". */
    html[dir="rtl"] .ico-sm[class*="right"] use,
    html[dir="rtl"] .ico[class*="right"] use { transform: scaleX(-1); }
    html[dir="rtl"] #icon-arrow-right use,
    html[dir="rtl"] #icon-chevron-right use,
    html[dir="rtl"] #icon-move-right use { transform: scaleX(-1); }
    html[dir="rtl"] svg.ico-sm:has(use[href="#icon-arrow-right"]),
    html[dir="rtl"] svg.ico-sm:has(use[href="#icon-chevron-right"]),
    html[dir="rtl"] svg.ico-sm:has(use[href="#icon-move-right"]),
    html[dir="rtl"] svg.ico:has(use[href="#icon-arrow-right"]),
    html[dir="rtl"] svg.ico:has(use[href="#icon-chevron-right"]),
    html[dir="rtl"] svg.ico:has(use[href="#icon-move-right"]) { transform: scaleX(-1); }

    /* Orange unread-count badge on the Inbox nav link. Rendered
       server-side (ctx.inbox_unread) and kept live by polling
       /admin/inbox/feed.json — see the inline script near the footer. */
    .inbox-dot{
      display:inline-flex; align-items:center; justify-content:center;
      min-width:1.05rem; height:1.05rem; padding:0 0.28rem;
      border-radius:999px; background:var(--attention); color:var(--attention-on);
      font-size:0.625rem; font-weight:700; line-height:1;
      font-variant-numeric: tabular-nums;
      margin-inline-start:0.2rem;
    }
    .inbox-dot[hidden]{ display:none; }

    /* ────────────────────────────────────────────────────────────────
       CLERICAL NOTICE — boxed, square-cornered, full hairline border.
       (Deliberately NOT the rounded-card-with-accent-side-border
       pattern; a notice on this surface reads as a stamped slip.)
       ──────────────────────────────────────────────────────────────── */
    .notice {
      border: 1px solid var(--rule-deep);
      background: var(--paper);
      color: var(--ink);
      padding: 0.75rem 1rem;
      font-size: 0.875rem;
      line-height: 1.5;
    }
    .notice-deny {
      border-color: var(--state-deny);
      background: var(--state-deny-tint);
    }
    /* Degraded-mode slip — burnt-amber "partial service" tone, deliberately
       calmer than deny-red: the desk keeps working on deterministic rules. */
    .notice-degraded {
      border-color: var(--state-near);
      background: var(--state-near-tint);
    }
    .notice-degraded strong { color: var(--state-near); }
    .mw-notice-degraded-ico {
      color: var(--state-near);
      flex-shrink: 0;
      margin-top: 0.2rem;
    }

    /* ────────────────────────────────────────────────────────────────
       INBOX — filter tabs + wait-age chips (list page).
       ──────────────────────────────────────────────────────────────── */
    .inbox-tabs {
      display: flex;
      gap: 0;
      border-bottom: 1.5px solid var(--rule);
      margin-bottom: 1.5rem;
      overflow-x: auto;
    }
    .inbox-tab {
      display: inline-flex;
      align-items: center;
      gap: 0.45rem;
      padding: 0.75rem 1rem;
      font: 500 0.875rem/1 var(--font-sans);
      letter-spacing: 0.15px;
      text-transform: none;
      color: var(--ink-muted);
      text-decoration: none;
      border-bottom: 2px solid transparent;
      margin-bottom: -1.5px;
      white-space: nowrap;
      transition: color 120ms ease, border-color 120ms ease;
    }
    .inbox-tab:hover { color: var(--ink); }
    .inbox-tab.is-active {
      color: var(--accent);
      border-bottom-color: var(--accent);
    }
    .inbox-tab-count {
      font: 500 0.6875rem/1 var(--font-sans);
      font-feature-settings: 'tnum';
      padding: 0.1rem 0.4rem;
      min-width: 1.15rem; text-align: center;
      border-radius: 9999px;
      background: var(--paper-sunk);
      color: var(--ink-muted);
      border: 0;
    }
    .inbox-tab.is-active .inbox-tab-count {
      background: var(--brand-tint);
      color: var(--accent);
    }
    .inbox-tabs-note {
      margin-inline-start: auto;
      align-self: center;
      font-size: 0.75rem;
      text-transform: none;
      letter-spacing: 0.3px;
      color: var(--ink-faint);
      padding-inline-start: 1rem;
      white-space: nowrap;
    }

    /* Wait-age chip — how long an unresolved case has been sitting.
       Filled in client-side; .is-hot past the 30-minute SLA. */
    .inbox-age {
      font: 600 0.68rem/1 'Roboto Mono', ui-monospace, monospace;
      font-variant-numeric: tabular-nums;
      color: var(--ink-faint);
      padding-inline-start: 0.5rem;
    }
    .inbox-age.is-hot {
      color: var(--state-deny);
    }

    /* ────────────────────────────────────────────────────────────────
       APP SIDEBAR — desktop navigation (≥900px). Vertical, grouped,
       one selection theme per category via --grp. The aside sits at
       the inline-start edge, so it lands on the right automatically
       under dir="rtl".
       ──────────────────────────────────────────────────────────────── */
    /* ══════════════════════════════════════════════════════════════════
       GCP CONSOLE SHELL — full-width top app bar + white left rail over a
       grey canvas. Replaces the former forest-green slab rail (now navy).
       ══════════════════════════════════════════════════════════════════ */

    /* ── Top app bar (48px, surface white, one hairline underline).
       Desktop only (≥900px); the compact mobile bar takes over below. ── */
    .app-topbar { display: none; }
    @media (min-width: 900px) { .app-topbar { display: flex; } }
    .app-topbar {
      position: sticky; top: 0; z-index: var(--z-sticky);
      align-items: center; gap: 0.5rem;
      height: var(--topbar-h); min-height: var(--topbar-h);
      padding: 0 0.5rem 0 0.25rem;
      background: var(--surface); color: var(--ink-body);
      border-bottom: 1px solid var(--rule);
    }
    .tb-menu {
      display: inline-flex; align-items: center; justify-content: center;
      width: 40px; height: 40px; flex: none;
      border: 0; border-radius: 50%;
      background: transparent; color: var(--ink-muted); cursor: pointer;
      transition: background var(--dur-fast) var(--ease-standard);
    }
    .tb-menu:hover { background: var(--hover); }
    html[dir="rtl"] .tb-menu .ico { transform: scaleX(-1); }
    .tb-brand {
      display: inline-flex; align-items: center; gap: 0.6rem;
      text-decoration: none; color: var(--ink-muted);
      padding: 0 0.35rem; min-width: 0; white-space: nowrap;
    }
    .tb-brand .header-mark { width: 30px; height: 26px; color: var(--accent); flex: none; }
    /* Wordmark — the ONE Montserrat slot in the console chrome. Tracked
       out per the brand package; the trailing <b> ("Console" / the Arabic
       twin) stays the lighter Medium weight so the brand name leads. */
    .tb-brand-word {
      font-family: var(--font-brand); font-size: 1.16rem; font-weight: 600;
      letter-spacing: 0.055em; color: var(--ink-muted);
    }
    .tb-brand-word b { font-weight: 500; letter-spacing: 0.02em; color: var(--ink); }
    .tb-pill {
      display: inline-flex; align-items: center; gap: 0.45rem;
      height: 32px; padding: 0 0.5rem 0 0.85rem;
      border: 1px solid var(--rule); border-radius: 9999px;
      background: transparent; color: var(--ink-body);
      font-size: 0.8125rem; font-weight: 500; white-space: nowrap;
      cursor: default; text-decoration: none;
      transition: background var(--dur-fast) var(--ease-standard);
    }
    .tb-pill .ico { color: var(--ink-faint); width: 1.05rem; height: 1.05rem; }
    a.tb-pill:hover { background: var(--hover); }
    /* Global search — reuses the ⌘K palette trigger, styled as GCP search. */
    .tb-search {
      flex: 1 1 auto; min-width: 0; max-width: 720px;
      display: flex; align-items: center; gap: 0.6rem;
      height: 40px; margin: 0 auto; padding: 0 0.9rem;
      border: 0; border-radius: 8px;
      background: var(--paper-sunk); color: var(--ink-muted);
      font: 400 0.875rem var(--font-sans); text-align: start; cursor: text;
      transition: background var(--dur-fast) var(--ease-standard),
                  box-shadow var(--dur-fast) var(--ease-standard);
    }
    .tb-search:hover { background: var(--hover-strong); }
    .tb-search:focus-visible { background: var(--surface); box-shadow: var(--elev-1); outline: none; }
    .tb-search .ico { color: var(--ink-muted); flex: none; }
    .tb-search-label { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .tb-search kbd {
      font: 500 0.6875rem var(--font-sans); color: var(--ink-faint);
      background: transparent; border: 0; padding: 0;
    }
    .tb-actions { display: flex; align-items: center; gap: 0.1rem; flex: none; margin-inline-start: auto; }
    .tb-icon {
      position: relative;
      display: inline-flex; align-items: center; justify-content: center;
      width: 40px; height: 40px;
      border: 0; border-radius: 50%;
      background: transparent; color: var(--ink-muted); cursor: pointer;
      text-decoration: none;
      transition: background var(--dur-fast) var(--ease-standard);
    }
    .tb-icon:hover { background: var(--hover); color: var(--ink-body); }
    .tb-avatar {
      display: inline-flex; align-items: center; justify-content: center;
      width: 30px; height: 30px; margin-inline-start: 0.35rem;
      border-radius: 50%; background: var(--accent); color: var(--brand-on);
      font: 500 0.8125rem var(--font-sans); text-decoration: none; flex: none;
    }
    /* Header theme toggle — show the moon in light mode (→ go dark),
       the sun in dark mode (→ go light). */
    .theme-ico { display: none; }
    .theme-ico-dark { display: inline-flex; }
    html[data-theme="dark"] .theme-ico-dark { display: none; }
    html[data-theme="dark"] .theme-ico-light { display: inline-flex; }
    .tb-icon .inbox-dot {
      position: absolute; top: 6px; inset-inline-end: 6px;
      margin: 0; min-width: 0.9rem; height: 0.9rem; font-size: 0.5625rem;
    }
    @media (max-width: 899px) {
      .tb-brand-word, .tb-pill { display: none; }
      .tb-search { max-width: none; }
    }

    /* ── Left rail (white surface, ≥900px) ── */
    .app-side { display: none; }
    @media (min-width: 900px) {
      .app-side {
        display: flex;
        flex-direction: column;
        width: var(--rail-w);
        flex: none;
        position: sticky;
        top: var(--topbar-h);
        height: calc(100dvh - var(--topbar-h));
        overflow-y: auto;
        overflow-x: hidden;
        background: var(--surface);
        color: var(--ink-body);
        padding: 0.5rem 0.5rem 0.75rem;
        border-inline-end: 1px solid var(--rule);
        z-index: var(--z-base);
        scrollbar-width: thin;
        transition: width 160ms var(--ease-standard), padding 160ms var(--ease-standard);
      }
      .app-side::-webkit-scrollbar { width: 8px; }
      .app-side::-webkit-scrollbar-thumb { background: var(--rule); border-radius: 8px; }
      @media (prefers-reduced-motion: reduce) {
        .app-side { transition: none; }
      }
    }
    /* .side-top / .side-brand / .side-search now live in the top bar; keep
       harmless fallbacks so any residual markup doesn't break layout. */
    .side-top { display: none; }
    .side-nav { display: flex; flex-direction: column; padding-top: 0.25rem; }

    .side-group { margin-bottom: 0.5rem; }
    .side-group + .side-group { border-top: 1px solid var(--rule-soft); padding-top: 0.5rem; }

    .side-group-label {
      display: block;
      font: 500 0.6875rem/1.4 var(--font-sans);
      letter-spacing: 0.06em; text-transform: uppercase;
      color: var(--ink-faint);
      padding: 0.5rem 1.5rem 0.35rem;
    }
    .side-link {
      position: relative;
      display: flex; align-items: center; gap: 1rem;
      padding: 0 1.5rem; height: 40px;
      border-radius: 0 20px 20px 0;
      font: 400 0.875rem var(--font-sans); letter-spacing: 0.1px;
      color: var(--ink-body); text-decoration: none; white-space: nowrap;
      transition: background var(--dur-fast) var(--ease-standard),
                  color var(--dur-fast) var(--ease-standard);
    }
    html[dir="rtl"] .side-link { border-radius: 20px 0 0 20px; }
    .side-link .ico-sm { color: var(--ink-muted); flex: none; width: 20px; height: 20px; }
    .side-link:hover { background: var(--hover); }
    .side-link.active {
      color: var(--accent); font-weight: 500;
      background: var(--brand-tint);
    }
    .side-link.active .ico-sm { color: var(--accent); }
    @media (prefers-reduced-motion: reduce) {
      .side-link { transition: none; }
    }

    .side-foot {
      margin-top: auto;
      padding: 0.75rem 0.75rem 0;
      border-top: 1px solid var(--rule);
      display: grid; gap: 0.6rem;
    }
    .side-account {
      display: flex; align-items: center; justify-content: space-between;
      gap: 0.5rem; min-width: 0;
    }
    .side-account-id {
      display: inline-flex; align-items: center; gap: 0.4rem; min-width: 0;
      font-size: 0.6875rem; letter-spacing: 0.04em; text-transform: uppercase;
      color: var(--ink-muted);
    }
    .side-account-email {
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
      max-width: 8.5rem;
    }

    /* ── Collapsed rail — narrows to a 72px icon strip. ── */
    @media (min-width: 900px) {
      html[data-side-collapsed] .app-side { width: var(--rail-w-collapsed); padding: 0.5rem 0.4rem 0.75rem; }
      html[data-side-collapsed] .side-group-label {
        height: 1px; padding: 0; margin: 0.4rem 0.5rem 0.5rem;
        font-size: 0; line-height: 0; letter-spacing: 0;
        background: var(--rule); overflow: hidden;
      }
      html[data-side-collapsed] .side-group + .side-group { border-top: 0; padding-top: 0; }
      html[data-side-collapsed] .side-label { display: none; }
      html[data-side-collapsed] .side-link {
        justify-content: center; gap: 0; padding: 0;
        width: 48px; height: 48px; margin: 2px auto; border-radius: 50%;
      }
      html[data-side-collapsed] .inbox-dot {
        position: absolute; top: 4px; inset-inline-end: 6px;
        margin-inline-start: 0; min-width: 0.9rem; height: 0.9rem; font-size: 0.5625rem;
      }
      html[data-side-collapsed] .side-foot { justify-items: center; }
      html[data-side-collapsed] .side-foot .lang-toggle { flex-direction: column; border-radius: 10px; }
      html[data-side-collapsed] .side-foot .lang-toggle button { padding: 0.35rem 0.55rem; }
      html[data-side-collapsed] .side-account { flex-direction: column; justify-content: center; gap: 0.4rem; }
      html[data-side-collapsed] .side-account-email { display: none; }
    }

/* ═══════════════════════════════════════════════════════════════════════
   CSP hardening — externalised inline styles (roadmap 1.7 residual close)
   Every rule below replaces a former inline style="…" attribute or a
   page-scoped <style> block so the CSP can drop style-src 'unsafe-inline'.
   Selectors are page-unique or explicitly scoped; nothing here is a new
   Tailwind utility (tw.css is a frozen prebuilt subset).
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Themed staff-gate pages (admin login / MFA): scoped brand override.
   Formerly a per-page :root block; now keyed off a body class so it does
   not leak onto the rest of the app.
   Hue note (audit A6): 264 (staff-gate) / 260 (--state-gov) are OKLCH
   *blue* — in Tailwind-v4 OKLCH terms blue≈259, indigo starts ≈277,
   violet≈293. At this low L (0.24–0.36) and modest C (0.075–0.10) that is
   a desaturated navy / customs-seal ink-blue, NOT the flagged SaaS indigo.
   Conscious keep — nudging pure-blue toward 250 would be perceptually
   invisible at this chroma and cuts against the "be conservative" brief. ─── */
body.theme-staff-gate {
  /* Inherits the GCP palette; no per-page hue override under the console
     redesign (the standalone sign-in shell keeps its own auth.css). */
}
body.theme-staff-gate header nav,
body.theme-staff-gate header #mw-nav-toggle { display: none !important; }

/* ── Airline DCS shell — demo separation of the selling system.
   Passenger-side intake pages (intake / interview / decision / status /
   contact-gov portal 1) are presented as the AIRLINE'S OWN departure-
   control tool, not the Nibomont product. Keyed off
   <html data-shell="airline"> (set per page via the `shell` template
   block) so the whole shell — rail, buttons, tints, footer — flips to
   the vendor palette in one place. Hue 250 at real chroma: a commercial
   airline blue, deliberately NOT the desaturated 264 staff-gate navy
   above, and far from --state-gov (260) prose ink. */
/* ── AeroDesk airline shell — ALWAYS blue (in light AND dark), the airline's
   own departure-control identity. Blue background + blue chrome, white cards
   for content. Fixed hues so it stays blue regardless of the theme toggle. ── */
/* Airline content stays light (white cards, dark ink) in BOTH themes — the
   AeroDesk tool is a fixed blue-on-white identity, so it must NOT follow the
   dark toggle. Declared after the dark block so it wins on airline pages. */
/* Blue accent for links + primary buttons (both themes); lighter blue tonal
   accent in dark. Surface/ink/rule tokens are inherited from :root (light) or
   the dark block (dark), so the theme toggle now works on airline pages too. */
html[data-shell="airline"] {
  --accent:       #1a73e8;
  --accent-hover: #1b66c9;
  --accent-press: #185abc;
  --brand-soft:   #4285f4;
  --brand-tint:   #e8f0fe;
  --brand-tint-2: #d2e3fc;
  --accent-overlay: rgba(26,115,232,.04);
  --state-gov:  #1a73e8; --state-gov-tint: #e8f0fe;
}
html[data-shell="airline"][data-theme="dark"] {
  --accent: #8ab4f8; --accent-hover: #aecbfa; --accent-press: #669df6;
  --brand-tint: rgba(138,180,248,.18); --brand-tint-2: rgba(138,180,248,.28);
  --accent-overlay: rgba(138,180,248,.10);
}
/* Immersive blue page background + white content — LIGHT mode only. In dark
   the canvas/content follow the dark tokens while the chrome stays blue. */
html[data-shell="airline"]:not([data-theme="dark"]) { --canvas: #1a73e8; }
html[data-shell="airline"]:not([data-theme="dark"]) body,
html[data-shell="airline"]:not([data-theme="dark"]) .app-content { background: #1a73e8; }

/* Blue top app bar */
html[data-shell="airline"] .app-topbar {
  background: #1a73e8; color: #fff; border-bottom-color: rgba(255,255,255,.22);
}
html[data-shell="airline"] .app-topbar .tb-brand,
html[data-shell="airline"] .app-topbar .tb-brand-word,
html[data-shell="airline"] .app-topbar .tb-brand-word b { color: #fff; }
html[data-shell="airline"] .app-topbar .tb-brand .header-mark { color: #fff; }
html[data-shell="airline"] .tb-menu,
html[data-shell="airline"] .tb-icon { color: rgba(255,255,255,.92); }
html[data-shell="airline"] .tb-menu:hover,
html[data-shell="airline"] .tb-icon:hover { background: rgba(255,255,255,.15); color: #fff; }
html[data-shell="airline"] .tb-search {
  background: rgba(255,255,255,.16); color: #eef4fe;
}
html[data-shell="airline"] .tb-search:hover { background: rgba(255,255,255,.24); }
html[data-shell="airline"] .tb-search:focus-visible { background: #fff; color: var(--ink); box-shadow: var(--elev-2); }
html[data-shell="airline"] .tb-search .ico,
html[data-shell="airline"] .tb-search kbd,
html[data-shell="airline"] .tb-search-label { color: #dce8fc; }
html[data-shell="airline"] .tb-search:focus-visible .ico,
html[data-shell="airline"] .tb-search:focus-visible .tb-search-label { color: var(--ink-muted); }
html[data-shell="airline"] .tb-avatar { background: #fff; color: #1a73e8; }

/* Blue nav rail */
html[data-shell="airline"] .app-side {
  background: #1a73e8; color: #fff; border-inline-end-color: rgba(255,255,255,.18);
}
html[data-shell="airline"] .side-group-label { color: rgba(255,255,255,.7); }
html[data-shell="airline"] .side-group + .side-group { border-top-color: rgba(255,255,255,.14); }
html[data-shell="airline"] .side-link { color: rgba(255,255,255,.9); }
html[data-shell="airline"] .side-link .ico-sm { color: rgba(255,255,255,.8); }
html[data-shell="airline"] .side-link:hover { background: rgba(255,255,255,.12); color: #fff; }
html[data-shell="airline"] .side-link.active { background: rgba(255,255,255,.2); color: #fff; }
html[data-shell="airline"] .side-link.active .ico-sm { color: #fff; }
html[data-shell="airline"] .side-foot { border-top-color: rgba(255,255,255,.18); }
html[data-shell="airline"] .side-account-id,
html[data-shell="airline"] .side-account-id .ico-sm { color: rgba(255,255,255,.85); }
html[data-shell="airline"] .side-foot .btn-ghost { color: #fff; border-color: rgba(255,255,255,.45); }
html[data-shell="airline"] .side-foot .btn-ghost:hover { background: rgba(255,255,255,.12); border-color: #fff; }
html[data-shell="airline"] .side-foot .lang-toggle { background: rgba(255,255,255,.12); }
html[data-shell="airline"] .side-foot .lang-toggle button { color: rgba(255,255,255,.85); }
html[data-shell="airline"] .side-foot .lang-toggle button.is-active { background: #fff; color: #1a73e8; }
/* Keep the collapsed-rail active pill readable on blue */
html[data-shell="airline"] .side-scrim { background: rgba(0,0,0,.2); }

/* Blue mobile chrome */
html[data-shell="airline"] .mobile-topbar { background: #1a73e8; color: #fff; border-bottom-color: rgba(255,255,255,.22); }
html[data-shell="airline"] .mobile-topbar .mw-brand-on { color: #fff; }
html[data-shell="airline"] .mobile-topbar .mw-brand-on .header-mark { color: #fff; }
html[data-shell="airline"] .mobile-topbar #mw-nav-toggle,
html[data-shell="airline"] .mobile-topbar [data-palette-open] { color: #fff; border-color: rgba(255,255,255,.4); }
html[data-shell="airline"] .mobile-nav { background: #1557b0; color: #fff; border-top-color: rgba(255,255,255,.18); }
html[data-shell="airline"] .mobile-nav-group-label { color: rgba(255,255,255,.7); }
html[data-shell="airline"] .mobile-nav-link { color: rgba(255,255,255,.9); border-bottom-color: rgba(255,255,255,.1); }
html[data-shell="airline"] .mobile-nav-link .ico { color: rgba(255,255,255,.82); }
html[data-shell="airline"] .mobile-nav-link.active { background: rgba(255,255,255,.16); color: #fff; box-shadow: inset 3px 0 0 #fff; }

/* ══════════════════════════════════════════════════════════════════════
   NIBOMONT SHELL — NAVY identity across the whole product (admin console +
   passenger portal), the counterpart to the blue AeroDesk shell. Navy
   chrome in BOTH themes; an immersive navy background in light mode; in
   dark mode the content goes console-dark (so the theme toggle still does
   something) while the chrome stays navy. Content sits on white
   surface-paper / intake-card sections, so it's readable on the navy.
   ══════════════════════════════════════════════════════════════════════ */

/* Navy accent for links + primary buttons inside content. */
html[data-shell="nibomont"] {
  --accent: #22406e; --accent-hover: #1d3860; --accent-press: #1a2f50;
  --brand-soft: #34558a;
  --brand-tint: #e9edf4; --brand-tint-2: #d3dbe8;
  --accent-overlay: rgba(34,64,110,.06);
  --state-gov: #22406e; --state-gov-tint: #e9edf4;
}
html[data-shell="nibomont"][data-theme="dark"] {
  --accent: #9cb6dc; --accent-hover: #b8cbe8; --accent-press: #7e9cc9;
  --brand-tint: rgba(156,182,220,.18); --brand-tint-2: rgba(156,182,220,.28);
  --accent-overlay: rgba(156,182,220,.10);
}

/* Immersive navy page background — light mode only. */
html[data-shell="nibomont"]:not([data-theme="dark"]) { --canvas: #1a2f50; }
html[data-shell="nibomont"]:not([data-theme="dark"]) body,
html[data-shell="nibomont"]:not([data-theme="dark"]) .app-content { background: #1a2f50; }

/* Navy top app bar (both themes) */
html[data-shell="nibomont"] .app-topbar {
  background: #1a2f50; color: #fff; border-bottom-color: rgba(255,255,255,.22);
}
html[data-shell="nibomont"] .app-topbar .tb-brand,
html[data-shell="nibomont"] .app-topbar .tb-brand-word,
html[data-shell="nibomont"] .app-topbar .tb-brand-word b { color: #fff; }
html[data-shell="nibomont"] .app-topbar .tb-brand .header-mark { color: #fff; }
html[data-shell="nibomont"] .tb-menu,
html[data-shell="nibomont"] .tb-icon { color: rgba(255,255,255,.92); }
html[data-shell="nibomont"] .tb-menu:hover,
html[data-shell="nibomont"] .tb-icon:hover { background: rgba(255,255,255,.15); color: #fff; }
html[data-shell="nibomont"] .tb-search { background: rgba(255,255,255,.16); color: #e4eaf3; }
html[data-shell="nibomont"] .tb-search:hover { background: rgba(255,255,255,.24); }
html[data-shell="nibomont"] .tb-search:focus-visible { background: #fff; color: var(--ink); box-shadow: var(--elev-2); }
html[data-shell="nibomont"] .tb-search .ico,
html[data-shell="nibomont"] .tb-search kbd,
html[data-shell="nibomont"] .tb-search-label { color: #c3d0e4; }
html[data-shell="nibomont"] .tb-search:focus-visible .ico,
html[data-shell="nibomont"] .tb-search:focus-visible .tb-search-label { color: var(--ink-muted); }
html[data-shell="nibomont"] .tb-avatar { background: #fff; color: #1a2f50; }

/* Navy nav rail (both themes) */
html[data-shell="nibomont"] .app-side {
  background: #1a2f50; color: #fff; border-inline-end-color: rgba(255,255,255,.18);
}
html[data-shell="nibomont"] .side-group-label { color: rgba(255,255,255,.72); }
html[data-shell="nibomont"] .side-group + .side-group { border-top-color: rgba(255,255,255,.14); }
html[data-shell="nibomont"] .side-link { color: rgba(255,255,255,.9); }
html[data-shell="nibomont"] .side-link .ico-sm { color: rgba(255,255,255,.8); }
html[data-shell="nibomont"] .side-link:hover { background: rgba(255,255,255,.12); color: #fff; }
html[data-shell="nibomont"] .side-link.active { background: rgba(255,255,255,.2); color: #fff; }
html[data-shell="nibomont"] .side-link.active .ico-sm { color: #fff; }
html[data-shell="nibomont"] .side-foot { border-top-color: rgba(255,255,255,.18); }
html[data-shell="nibomont"] .side-account-id,
html[data-shell="nibomont"] .side-account-id .ico-sm { color: rgba(255,255,255,.85); }
html[data-shell="nibomont"] .side-foot .btn-ghost { color: #fff; border-color: rgba(255,255,255,.45); }
html[data-shell="nibomont"] .side-foot .btn-ghost:hover { background: rgba(255,255,255,.12); border-color: #fff; }
html[data-shell="nibomont"] .side-foot .lang-toggle { background: rgba(255,255,255,.12); }
html[data-shell="nibomont"] .side-foot .lang-toggle button { color: rgba(255,255,255,.85); }
html[data-shell="nibomont"] .side-foot .lang-toggle button.is-active { background: #fff; color: #1a2f50; }

/* Navy mobile chrome */
html[data-shell="nibomont"] .mobile-topbar { background: #1a2f50; color: #fff; border-bottom-color: rgba(255,255,255,.22); }
html[data-shell="nibomont"] .mobile-topbar .mw-brand-on { color: #fff; }
html[data-shell="nibomont"] .mobile-topbar .mw-brand-on .header-mark { color: #fff; }
html[data-shell="nibomont"] .mobile-topbar #mw-nav-toggle,
html[data-shell="nibomont"] .mobile-topbar [data-palette-open] { color: #fff; border-color: rgba(255,255,255,.4); }
html[data-shell="nibomont"] .mobile-nav { background: #101e34; color: #fff; border-top-color: rgba(255,255,255,.18); }
html[data-shell="nibomont"] .mobile-nav-group-label { color: rgba(255,255,255,.7); }
html[data-shell="nibomont"] .mobile-nav-link { color: rgba(255,255,255,.9); border-bottom-color: rgba(255,255,255,.1); }
html[data-shell="nibomont"] .mobile-nav-link .ico { color: rgba(255,255,255,.82); }
html[data-shell="nibomont"] .mobile-nav-link.active { background: rgba(255,255,255,.16); color: #fff; box-shadow: inset 3px 0 0 #fff; }

/* Verification-portal nav group keeps the deepest navy as the hand-off cue. */
.side-group[data-theme="verify"] .side-link.active { color: #1a2f50; background: #e9edf4; }
.side-group[data-theme="verify"] .side-link.active .ico-sm { color: #1a2f50; }

/* Brand wordmark surfaces — Montserrat, tracked. These are the sidebar,
   mobile top bar and footer lockups; every other label stays Roboto. */
.side-brand-word,
.mobile-topbar .mw-brand-on span,
.app-content > footer .brand-word {
  font-family: var(--font-brand);
  letter-spacing: 0.05em;
}

/* Two-line sidebar brand: product name over a small role line
   ("Departure Control" on airline pages, unused on Nibomont pages). */
.side-brand-sub {
  display: block;
  font-family: var(--font-brand);
  font-size: 0.575rem; font-weight: 500;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--brand-on-fa);
  margin-top: 0.2rem;
}
html[data-side-collapsed] .side-brand-sub { display: none; }

/* ── Small shared utility classes (from repeated static inline styles) ─── */
.mw-measure-32ch  { max-width: 32ch; }
.mw-measure-36ch  { max-width: 36ch; }
.mw-measure-42ch  { max-width: 42ch; }
.mw-measure-48ch  { max-width: 48ch; }
.mw-measure-52ch  { max-width: 52ch; }
.mw-measure-60ch  { max-width: 60ch; }
.mw-measure-62ch  { max-width: 62ch; }
.mw-measure-64ch  { max-width: 64ch; }
.mw-measure-70ch  { max-width: 70ch; }
.mw-measure-76ch  { max-width: 76ch; }
.mw-measure-100ch { max-width: 100ch; }
.mw-measure-32rem { max-width: 32rem; }
.mw-measure-36rem { max-width: 36rem; }
.mw-italic-note   { font-style: italic; max-width: 60ch; }

.mw-ink        { color: var(--ink); }
.mw-ink-strong { color: var(--ink); font-weight: 600; }
.mw-ink-faint  { color: var(--ink-faint); }
.mw-brand      { color: var(--brand); }
.mw-brand-on   { color: var(--brand-on); }
.mw-state-gov  { color: var(--state-gov); }
.mw-state-deny { color: var(--state-deny); }

.mw-fs-sm   { font-size: 0.8125rem; }
.mw-fs-xs   { font-size: 0.72rem; }
.mw-fs-base { font-size: 0.875rem; }
.mw-display { font-size: clamp(2rem, 3.2vw, 2.75rem); }

.mw-opacity-75    { opacity: 0.75; }
.mw-vmiddle       { vertical-align: middle; }
.mw-word-break    { word-break: break-all; }
.mw-nocaps        { text-transform: none; letter-spacing: 0.02em; }
.mw-overflow-x    { overflow-x: auto; }
.mw-white-bg      { background: var(--paper); }
.mw-nomargin      { margin: 0; }
.mw-nopad         { padding: 0; }
.mw-pad-md        { padding: 1rem 1.25rem; }
.mw-pad-lg        { padding: 1.25rem; }
.mw-gap-16        { gap: 1.6rem; }
.mw-minw-220      { min-width: min(220px, 100%); }
.mw-minw-16       { min-width: 1.6rem; }

.mw-rule-border   { border: 1px solid var(--rule); }
.mw-rule-outline  { border-color: var(--rule); }
.mw-ink-outline   { border-color: var(--ink); }
.mw-top-rule      { border-top: 1px solid var(--rule); }
.mw-bottom-rule   { border-bottom: 1px solid var(--rule); }
.mw-card-white    { border: 1px solid var(--rule); background: var(--paper); border-radius: 0.5rem; }
.mw-card-white-lg { border: 1px solid var(--rule); background: var(--paper); border-radius: 0.75rem; }
.mw-card-warm     { border: 1px solid var(--rule); background: var(--paper-warm); }

.mw-code-block    { padding: 1rem 1.25rem; overflow-x: auto; font-size: 0.8125rem; line-height: 1.7; }

/* Field-level error hint (was inline color/size/margin) */
.mw-field-error {
  color: var(--state-deny); font-size: 0.75rem;
  margin-top: 0.25rem; display: block;
}

/* Deny / pass verdict pills (were inline border/bg/color triples) */
.mw-pill-deny { border: 1px solid var(--state-deny-tint); background: var(--state-deny-tint); color: var(--state-deny); }
.mw-pill-pass { border: 1px solid var(--state-pass-tint); background: var(--state-pass-tint); color: var(--state-pass); }
.mw-btn-deny  { background: var(--state-deny); color: white; border-color: var(--state-deny); }

/* Deny-tinted callout / notice band (was an 8-property inline style) */
.mw-notice-deny {
  background: var(--state-deny-tint, #fef2f2);
  border-inline-start: 3px solid var(--state-deny);
  padding: 0.625rem 1rem; border-radius: 6px;
  margin-bottom: 1.25rem; color: var(--ink); font-size: 0.875rem;
}

/* QR container + injected SVG (was inline width/height + a page <style>) */
.qr-box     { width: 170px; height: 170px; display: block; }
.qr-box-sm  { width: 96px;  height: 96px;  display: block; }
.qr-box-180 { width: 180px; height: 180px; }
.qr-svg svg { width: 100% !important; height: 100% !important; display: block; }
.qr-svg svg path { fill: var(--ink) !important; }

/* Field error-border toggle (was inline --field-border set only on error) */
.field.is-error { --field-border: var(--state-deny); }

/* Register toolbar status filter pills (was inline active/inactive style) */
.mw-filter-pill      { border-radius: 2px; background: var(--paper-warm); color: var(--ink-muted); border-color: var(--rule); }
.mw-filter-pill.is-on { background: var(--brand); color: var(--paper); border-color: var(--brand); }

/* ── Fixed ledger/table grid templates (were {% set cols %} inline) ───────
   Each ledger's column track list is a compile-time constant; encoded here
   as a class instead of an inline grid-template-columns. ─────────────────── */
.mw-cols-sources        { grid-template-columns: minmax(0, 1.1fr) 4.5rem minmax(0, 1.6fr) 6rem 7rem 8rem 7rem; column-gap: 0.85rem; }
.mw-cols-visa           { grid-template-columns: 9rem minmax(0, 1.4fr) minmax(0, 7rem) 5.5rem 6rem 6rem 7rem minmax(0, 9rem) 5rem; column-gap: 0.85rem; }
.mw-cols-watchlist      { grid-template-columns: 9rem minmax(0, 1.3fr) 5.5rem 7rem minmax(0, 1.3fr) minmax(0, 1fr) 5rem; column-gap: 0.85rem; }
.mw-cols-passport       { grid-template-columns: 9rem minmax(0, 1.4fr) 5.5rem 7rem 6.5rem 7rem 7rem minmax(0, 1fr) 5rem; column-gap: 0.85rem; }
.mw-cols-nationalid     { grid-template-columns: 9rem minmax(0, 1.4fr) 5.5rem 7rem 6rem minmax(0, 8rem) 5rem; column-gap: 0.85rem; }
.mw-cols-ledger         { grid-template-columns: 3rem minmax(0, 1.4fr) minmax(0, 1.4fr) minmax(0, 1.6fr) 5rem; column-gap: 1.5rem; }
.mw-cols-rules-bi       { grid-template-columns: 3.5rem 13rem minmax(0, 1fr) 11rem; column-gap: 1.25rem; }
.mw-cols-rules-intake   { grid-template-columns: minmax(0, 3fr) 7rem 4.5rem 9rem 6rem minmax(0, 9rem); column-gap: 1.25rem; }
.mw-cols-rules-llm      { grid-template-columns: minmax(0, 3fr) 6.5rem 7.5rem 4.5rem 9rem 6rem minmax(0, 9rem); column-gap: 1.25rem; }
.mw-ledger-head-ink     { border-color: var(--ink); }
.mw-ledger-head-rule    { border-color: var(--rule-deep); }
.mw-ledger-row-rule     { border-color: var(--rule); }
.mw-rule-row-anim       { transition: opacity 130ms ease; }

/* ── Audit chain stagger + verdict confidence bar (dynamic numerics) ─────
   Set via nibomont.js from data-* attributes so no inline style is needed.
   These carry the CSS custom properties the animation/width read. ───────── */
.mw-badrow { border-color: var(--state-deny); box-shadow: 0 0 0 1px var(--state-deny); }
.mw-ink-muted { color: var(--ink-muted); }
.chain-hash { color: var(--brand); font-weight: 500; }
.mw-bg-warm { background: var(--paper-warm); }

/* ═══════════════════════════════════════════════════════════════════════
   Externalised page-scoped <style> blocks
   ═══════════════════════════════════════════════════════════════════════ */

/* ── audit_view.html — hash-link chips + chain summary ─────────────────── */
.chain-chip {
  display: inline-flex; align-items: center; gap: 0.3rem;
  font: 500 0.6rem/1 'Roboto Mono', ui-monospace, monospace;
  letter-spacing: 0.06em; padding: 0.15rem 0.45rem; border-radius: 2px;
  border: 1px solid var(--rule); color: var(--ink-faint);
  background: var(--paper-warm);
  transition: color 150ms ease, border-color 150ms ease, background 150ms ease;
  user-select: all;
}
.chain-chip.chip-top { border-style: dashed; }
.chain-chip.chip-bot { border-style: solid; color: var(--brand); border-color: oklch(from var(--brand) l c h / 0.35); }
.chain-chip.chip-bad { color: var(--state-deny) !important; border-color: var(--state-deny) !important; background: var(--state-deny-tint) !important; }
.chain-row-wrap:first-child .chain-row::before { display: none; }
.chain-row-wrap:hover .chip-bot,
.chain-row-wrap:hover + .chain-row-wrap .chip-top {
  color: var(--brand) !important; border-color: var(--brand) !important;
  background: oklch(from var(--brand) l c h / 0.06) !important;
}
@media (prefers-reduced-motion: reduce) { .chain-chip { transition: none; } }
.chain-summary {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem 1.25rem;
  padding: 0.65rem 1rem; border: 1px solid var(--rule);
  background: var(--paper-warm); font-size: 0.78rem; margin-bottom: 1.25rem;
}
.chain-summary-sep { color: var(--rule-deep); }

/* ── _loading_overlay.html — spinner keyframes ────────────────────────── */
@keyframes mwLoadingSpin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .mwLoadingSpinner { animation: none !important; } }

/* ── interview.html — thinking pulse ──────────────────────────────────── */
@keyframes mw_pulse { from { transform: scale(0.65); opacity: 0.4; } to { transform: scale(1); opacity: 1; } }
@media (prefers-reduced-motion: reduce) { #thinking span:first-child { animation: none !important; } }

/* ── admin_inbox_detail.html — inbox side list + system verdict + conf bar ─ */
.inbox-side-item { display: block; padding: 0.6rem 0.7rem; border-inline-start: 3px solid transparent; border-bottom: 1px solid var(--rule); }
.inbox-side-item:hover { background: rgba(0,0,0,0.035); }
.inbox-side-item.is-active { border-inline-start-color: var(--ink); background: rgba(0,0,0,0.05); }
.sys-verdict { border: 1.5px solid currentColor; border-radius: 14px; padding: 1.25rem 1.5rem; position: relative;
               /* NOT overflow:hidden. The panel has no bleeding child to clip
                  (nothing here reaches the rounded corners), and hiding
                  overflow amputated the confidence info tooltip: the chip is
                  taller than the panel, so two thirds of the explanation was
                  cut off at the panel's bottom edge. */
               overflow: visible; }
.sys-verdict-word { font-weight: 700; font-size: clamp(1.75rem, 2.6vw, 2.375rem); line-height: 1; letter-spacing: -0.01em; }

/* ── Case decision header (2026-08-20) ─────────────────────────────────
   Verdict and confidence on one row. Read alone, a 99% reads as certainty
   about the passenger rather than as fit to a rule, so the note under it
   says which it is. All colour comes from the state tokens, so both themes
   follow without a second rule.

   A third cell (evidence strength, "0/N government-verified") shipped here
   earlier the same day and was removed with the rest of the evidentiary
   record, which now lives on the case-ledger record — so the track is two
   columns, not three. Leaving the 16rem column behind would strand the
   confidence cell against a dead gap. ── */
.dec-row { display: grid; gap: 1.25rem; align-items: start; }
@media (min-width: 900px) {
  .dec-row { grid-template-columns: minmax(0, 1fr) 13rem; gap: 1.75rem; }
}
.dec-metric { display: flex; align-items: baseline; justify-content: space-between;
              gap: 0.75rem; margin-bottom: 0.4rem; }
/* Label + info dot as one flex child, so the metric stays a two-item
   space-between row and the number keeps its edge. */
.dec-metric-label { display: inline-flex; align-items: center; min-width: 0; }
.dec-num { font-family: var(--font-mono); font-weight: 700; font-size: 1.125rem; }
.dec-note { font-size: 0.8125rem; line-height: 1.5; margin-top: 0.55rem; }

/* Four-cell context strip: why the case exists, what would clear it, how
   long the interview ran, whether intake matched the registers. */
.case-strip { display: grid; gap: 1px; background: var(--rule);
              border: 1px solid var(--rule); border-radius: 8px; overflow: hidden;
              grid-template-columns: 1fr; }
@media (min-width: 640px)  { .case-strip { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1100px) { .case-strip { grid-template-columns: repeat(4, 1fr); } }
.case-strip > div { background: var(--surface); padding: 0.8rem 1.1rem; }
.case-strip .v { font-size: 0.875rem; font-weight: 500; margin-top: 0.3rem; }
.case-strip .s { font-size: 0.75rem; color: var(--ink-faint); margin-top: 0.15rem; }

/* Intake-vs-register comparison, now rendered in the inbox and not only
   on /audit/{id}. Narrower than the audit page's five-column version: the
   per-row explanation moves under its verdict chip so the table fits the
   officer's column without a horizontal scroll on a laptop. */
.cmp-table { width: 100%; border-collapse: collapse; font-size: 0.8125rem;
             min-width: 26rem; }
.cmp-table th { text-align: start; padding: 0.5rem 0.7rem; font-family: var(--font-mono);
                font-size: 0.625rem; letter-spacing: 0.12em; text-transform: uppercase;
                color: var(--ink-faint); font-weight: 400;
                border-bottom: 1px solid var(--rule); }
.cmp-table td { padding: 0.55rem 0.7rem; border-bottom: 1px solid var(--rule-soft);
                vertical-align: top; }
.cmp-table tr:last-child td { border-bottom: 0; }
.cmp-table .cmp-note { font-size: 0.75rem; color: var(--ink-faint); margin-top: 0.2rem;
                       line-height: 1.4; }
.conf-bar { height: 6px; border-radius: 999px; background: oklch(0.18 0.014 264 / 0.12); overflow: hidden; }
.conf-bar > span { display: block; height: 100%; background: currentColor; border-radius: 999px; width: 0; }

/* ═══════════════════════════════════════════════════════════════════════
   admin_rules.html — rules workbench (formerly a 244-line page <style>)
   ═══════════════════════════════════════════════════════════════════════ */
.wrap-wide { max-width: 1760px; margin-inline: auto; padding-inline: clamp(1.25rem, 3vw, 3rem); }
.rules-layout { display: grid; grid-template-columns: clamp(240px, 20vw, 300px) minmax(0, 1fr); gap: clamp(1.5rem, 3vw, 3.5rem); align-items: start; }
@media (max-width: 1023px) {
  .rules-layout { grid-template-columns: 1fr; }
  .rules-rail { position: static !important; }
  .rail-pipe, .rail-note { display: none; }
  .rail-tabs { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; }
  .rail-tab { border-inline-start-width: 0 !important; border-block-end: 3px solid transparent; }
  .rail-tab.is-active { border-block-end-color: var(--brand); }
}
/* Sidebar-aware companion — expanded 250px rail eats the same room the
   1023px viewport breakpoint guards, so the two-column workbench must
   also fold while viewport < 1024 + 250. Mirror of the block above. */
@media (min-width: 1024px) and (max-width: 1273.98px) {
  html:not([data-side-collapsed]) .rules-layout { grid-template-columns: 1fr; }
  html:not([data-side-collapsed]) .rules-rail { position: static !important; }
  html:not([data-side-collapsed]) .rail-pipe,
  html:not([data-side-collapsed]) .rail-note { display: none; }
  html:not([data-side-collapsed]) .rail-tabs { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; }
  html:not([data-side-collapsed]) .rail-tab { border-inline-start-width: 0 !important; border-block-end: 3px solid transparent; }
  html:not([data-side-collapsed]) .rail-tab.is-active { border-block-end-color: var(--brand); }
}
.rules-rail { position: sticky; top: 92px; }
.rail-label { font: 600 0.625rem/1 'Roboto', system-ui, sans-serif; letter-spacing: 0.18em; text-transform: uppercase; color: var(--ink-faint); padding-block: 0.25rem 0.75rem; }
.rail-tab { display: flex; align-items: flex-start; gap: 0.75rem; width: 100%; text-align: start; background: transparent; border: 1px solid var(--rule); border-inline-start: 3px solid transparent; padding: 0.9rem 1rem; cursor: pointer; font-family: inherit; color: var(--ink-muted); transition: border-color 130ms ease, background-color 130ms ease, color 130ms ease; }
.rail-tab + .rail-tab { margin-top: 0.5rem; }
.rail-tab:hover { background: var(--paper-warm); color: var(--ink); }
.rail-tab.is-active { background: var(--paper-warm); border-color: var(--rule-deep); border-inline-start-color: var(--brand); color: var(--ink); }
.rail-tab .ico { margin-top: 0.1rem; flex-shrink: 0; }
.rail-tab.is-active .ico { color: var(--brand); }
.rail-tab-title { font-size: 0.9rem; font-weight: 600; letter-spacing: -0.01em; }
.rail-tab-sub { font-size: 0.72rem; color: var(--ink-faint); margin-top: 0.2rem; line-height: 1.4; }
.rail-count { margin-inline-start: auto; font-feature-settings: 'tnum'; font-size: 0.9rem; font-weight: 600; color: var(--ink-faint); padding-top: 0.05rem; }
.rail-tab.is-active .rail-count { color: var(--brand); }
.rail-pipe { list-style: none; margin: 0; padding: 0; counter-reset: pipe; }
.rail-pipe li { counter-increment: pipe; position: relative; padding: 0.45rem 0 0.45rem 2rem; font-size: 0.78rem; color: var(--ink-faint); line-height: 1.35; }
html[dir="rtl"] .rail-pipe li { padding: 0.45rem 2rem 0.45rem 0; }
.rail-pipe li::before { content: counter(pipe); position: absolute; inset-inline-start: 0; top: 0.45rem; width: 1.25rem; height: 1.25rem; display: grid; place-items: center; font: 600 0.62rem/1 'Roboto', system-ui, sans-serif; font-feature-settings: 'tnum'; border: 1px solid var(--rule-deep); border-radius: 1px; color: var(--ink-muted); background: var(--paper); }
.rail-pipe li::after { content: ''; position: absolute; inset-inline-start: 0.6rem; top: calc(0.45rem + 1.25rem); bottom: -0.45rem; width: 1px; background: var(--rule); }
.rail-pipe li:last-child::after { display: none; }
.rail-pipe li.pipe-branch { counter-increment: none; display: flex; align-items: center; gap: 0.6rem; padding: 0.65rem 0; font: 600 0.56rem/1.3 'Roboto', system-ui, sans-serif; letter-spacing: 0.13em; text-transform: uppercase; color: var(--state-gov); white-space: nowrap; }
.rail-pipe li.pipe-branch::before, .rail-pipe li.pipe-branch::after { content: ''; position: static; display: block; flex: 1; width: auto; height: 1px; min-width: 0.75rem; border: 0; background: oklch(0.30 0.08 260 / 0.35); }
.rail-pipe li.is-here { color: var(--ink); font-weight: 600; }
.rail-pipe li.is-here::before { background: var(--brand); border-color: var(--brand); color: var(--brand-on); }
.rail-pipe li.is-here .pipe-you { display: inline-block; font: 600 0.56rem/1 'Roboto', system-ui, sans-serif; letter-spacing: 0.14em; text-transform: uppercase; color: var(--brand); border: 1px solid var(--brand); border-radius: 2px; padding: 0.15rem 0.45rem; margin-inline-start: 0.4rem; vertical-align: 0.1em; }
.rail-pipe li .pipe-you { display: none; }
.rail-note { margin-top: 1.25rem; padding: 0.85rem 1rem; border: 1px dashed var(--rule-deep); font-size: 0.75rem; line-height: 1.5; color: var(--ink-muted); background: var(--paper-warm); }
.stat-strip { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); border: 1px solid var(--rule); background: var(--paper); margin-bottom: 1.75rem; }
.stat { padding: 1rem 1.25rem 0.9rem; border-inline-start: 1px solid var(--rule); }
.stat:first-child { border-inline-start: 0; }
.stat-num { display: block; font-size: clamp(1.5rem, 2vw, 2rem); font-weight: 600; font-feature-settings: 'tnum'; letter-spacing: -0.02em; line-height: 1.1; color: var(--ink); }
.stat-num.is-live { color: var(--state-pass); }
.stat-num.is-pend { color: var(--state-gov); }
.stat-label { display: block; margin-top: 0.3rem; font: 600 0.625rem/1.3 'Roboto', system-ui, sans-serif; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-faint); }
.rule-row.is-archived { opacity: 0.45; }
.rule-row.is-archived:hover { opacity: 0.8; }
.rule-modal { border: 1px solid var(--rule-deep); border-radius: 2px; padding: 0; width: min(920px, calc(100vw - 2rem)); max-height: min(88vh, 1000px); background: var(--paper); color: var(--ink); box-shadow: 0 40px 80px -24px oklch(0.15 0.04 152 / 0.45); }
.rule-modal::backdrop { background: oklch(0.2 0.05 152 / 0.55); }
.rule-modal[open] { animation: mw-modal-in 300ms cubic-bezier(0.2, 0.9, 0.25, 1) both; }
@keyframes mw-modal-in { from { opacity: 0; transform: translateY(14px) scale(0.985); } to { opacity: 1; transform: translateY(0) scale(1); } }
@media (prefers-reduced-motion: reduce) { .rule-modal[open] { animation: none; } }
.rule-modal-head { position: sticky; top: 0; z-index: 2; display: flex; align-items: center; gap: 1rem; padding: 1.1rem clamp(1.25rem, 3vw, 2rem); background: var(--brand-deep); color: var(--brand-on); }
.rule-modal-title { font-size: 1.05rem; font-weight: 600; letter-spacing: -0.01em; }
.rule-modal-sub { font-size: 0.75rem; color: var(--brand-on-fa); margin-top: 0.15rem; }
.rule-modal-close { margin-inline-start: auto; display: grid; place-items: center; width: 2.1rem; height: 2.1rem; background: transparent; border: 1px solid oklch(1 0 0 / 0.35); border-radius: 2px; color: var(--brand-on); cursor: pointer; transition: background-color 120ms ease, border-color 120ms ease; }
.rule-modal-close:hover { background: oklch(1 0 0 / 0.1); border-color: var(--brand-on); }
.rule-modal-body { padding: clamp(1.5rem, 3vw, 2.25rem); overflow-y: auto; max-height: calc(min(88vh, 1000px) - 4.4rem); }

/* ═══════════════════════════════════════════════════════════════════════
   _rule_form.html — condition/rule builder (formerly a 164-line page <style>)
   ═══════════════════════════════════════════════════════════════════════ */
#ruleForm [hidden] { display: none !important; }
.rf-form { display: flex; flex-direction: column; gap: 1.6rem; }
.rf-q { font-size: 0.95rem; font-weight: 600; letter-spacing: -0.01em; color: var(--ink); margin-bottom: 0.2rem; }
.rf-hint { font-size: 0.78rem; line-height: 1.5; color: var(--ink-muted); }
.rf-sect > .rf-hint { margin-bottom: 0.75rem; }
.rf-types { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; }
@media (max-width: 767px) { .rf-types { grid-template-columns: 1fr; } }
.rf-type { position: relative; display: block; cursor: pointer; border: 1px solid var(--rule-deep); border-radius: 2px; background: var(--paper); padding: 0.95rem 1.05rem; transition: background-color 140ms ease, border-color 140ms ease, box-shadow 140ms ease; }
.rf-type input { position: absolute; opacity: 0; pointer-events: none; }
.rf-type:hover { background: var(--paper-warm); }
.rf-type:has(input:checked) { border-color: var(--brand); box-shadow: inset 0 0 0 1px var(--brand); background: var(--brand-tint); }
.rf-type:has(input:focus-visible) { outline: 2px solid var(--brand); outline-offset: 2px; }
.rf-type-head { display: flex; align-items: center; gap: 0.5rem; font-weight: 600; font-size: 0.9rem; color: var(--ink); }
.rf-type:has(input:checked) .rf-type-head .ico-sm { color: var(--brand); }
.rf-type-badge { margin-inline-start: auto; font-family: 'Roboto Mono', ui-monospace, monospace; font-size: 0.6rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-faint); border: 1px solid var(--rule); border-radius: 1px; padding: 0.15rem 0.4rem; white-space: nowrap; }
.rf-type-sub { display: block; margin-top: 0.4rem; font-size: 0.78rem; line-height: 1.5; color: var(--ink-muted); }
.rf-row { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 0.6rem 1rem; padding: 0.65rem 0.85rem; border: 1px solid var(--rule); background: var(--paper-warm); }
.rf-row + .rf-row { margin-top: 0.5rem; }
.rf-conn { flex: 0 0 3.4rem; padding-top: 0.45rem; font-size: 0.8125rem; font-weight: 600; color: var(--ink-muted); }
.rf-conn select { border: 0; border-bottom: 1px solid var(--rule-deep); background: transparent; padding: 0.35rem 0; font: inherit; font-weight: 600; color: var(--ink-muted); width: 100%; cursor: pointer; }
.rf-conn select:focus { outline: none; border-color: var(--brand); }
.rf-ctl { border: 0; border-bottom: 1px solid var(--rule-deep); background: transparent; padding: 0.35rem 0; font-size: 0.875rem; font-family: inherit; color: var(--ink); }
.rf-ctl:focus { outline: none; border-bottom-color: var(--brand); }
select.rf-ctl { min-width: 130px; cursor: pointer; }
input.rf-ctl { min-width: 150px; }
.rf-remove { flex: 0 0 auto; margin-inline-start: auto; padding-top: 0.45rem; color: var(--ink-faint); background: none; border: 0; cursor: pointer; transition: color 130ms ease; }
.rf-remove:hover { color: var(--state-deny); }
.rf-chips { display: flex; flex-wrap: wrap; gap: 0.35rem; align-items: center; }
.rf-chip { display: inline-flex; align-items: center; gap: 0.35rem; border: 1px solid var(--rule-deep); background: var(--paper); padding: 0.2rem 0.3rem 0.2rem 0.55rem; font-size: 0.75rem; }
html[dir="rtl"] .rf-chip { padding: 0.2rem 0.55rem 0.2rem 0.3rem; }
.rf-chip button { border: 0; background: none; cursor: pointer; color: var(--ink-faint); line-height: 1; padding: 0.1rem; }
.rf-chip button:hover { color: var(--state-deny); }
.rf-checkchip { display: inline-flex; align-items: center; gap: 0.3rem; border: 1px solid var(--rule); padding: 0.25rem 0.5rem; font-size: 0.75rem; cursor: pointer; background: var(--paper); transition: background-color 130ms ease, border-color 130ms ease; }
.rf-checkchip:has(:checked) { background: var(--brand-tint); border-color: var(--brand); }
.rf-checkchip input { accent-color: var(--brand); width: 0.85rem; height: 0.85rem; }
.rf-dec { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.6rem; }
.rf-dec.rf-dec-4 { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 767px) { .rf-dec, .rf-dec.rf-dec-4 { grid-template-columns: 1fr; } }
.rf-dec label { position: relative; display: block; cursor: pointer; border: 1px solid var(--rule-deep); border-radius: 2px; background: var(--paper); padding: 0.7rem 0.9rem; transition: background-color 140ms ease, border-color 140ms ease, box-shadow 140ms ease; }
.rf-dec input { position: absolute; opacity: 0; pointer-events: none; }
.rf-dec label:hover { background: var(--paper-warm); }
.rf-dec label:has(input:focus-visible) { outline: 2px solid var(--brand); outline-offset: 2px; }
.rf-dec-word { font-weight: 600; font-size: 0.85rem; color: var(--ink); }
.rf-dec-sub { display: block; margin-top: 0.2rem; font-size: 0.7rem; line-height: 1.4; color: var(--ink-muted); }
.rf-dec label[data-tone="deny"]:has(input:checked) { border-color: var(--state-deny); box-shadow: inset 0 0 0 1px var(--state-deny); background: var(--state-deny-tint); }
.rf-dec label[data-tone="deny"]:has(input:checked) .rf-dec-word { color: var(--state-deny); }
.rf-dec label[data-tone="pass"]:has(input:checked) { border-color: var(--state-pass); box-shadow: inset 0 0 0 1px var(--state-pass); background: var(--state-pass-tint); }
.rf-dec label[data-tone="pass"]:has(input:checked) .rf-dec-word { color: var(--state-pass); }
.rf-dec label[data-tone="gov"]:has(input:checked) { border-color: var(--state-gov); box-shadow: inset 0 0 0 1px var(--state-gov); background: var(--state-gov-tint); }
.rf-dec label[data-tone="gov"]:has(input:checked) .rf-dec-word { color: var(--state-gov); }
.rf-dec label[data-tone="ask"]:has(input:checked) { border-color: var(--brand); box-shadow: inset 0 0 0 1px var(--brand); background: var(--brand-tint); }
.rf-dec label[data-tone="ask"]:has(input:checked) .rf-dec-word { color: var(--brand); }
.rf-seg { display: inline-flex; border: 1px solid var(--rule-deep); border-radius: 2px; overflow: hidden; }
.rf-seg label { position: relative; display: inline-flex; align-items: center; gap: 0.4rem; padding: 0.45rem 0.85rem; font-size: 0.8125rem; cursor: pointer; color: var(--ink-muted); background: var(--paper); transition: background-color 140ms ease, color 140ms ease; }
.rf-seg label + label { border-inline-start: 1px solid var(--rule-deep); }
.rf-seg input { position: absolute; opacity: 0; pointer-events: none; }
.rf-seg label:has(input:checked) { background: var(--brand); color: var(--brand-on); font-weight: 600; }
.rf-seg label:has(input:focus-visible) { outline: 2px solid var(--brand); outline-offset: 2px; z-index: 1; }
.rf-summary { border: 1px solid var(--rule-deep); background: var(--paper-sunk); padding: 0.85rem 1.05rem; }
.rf-sum-k { display: block; font-family: 'Roboto Mono', ui-monospace, monospace; font-size: 0.6rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-faint); margin-bottom: 0.3rem; }
.rf-sum-txt { font-size: 0.875rem; line-height: 1.6; color: var(--ink); }
.rf-sum-txt .rf-sum-pending { color: var(--ink-muted); font-style: italic; }
.rf-adv { border: 1px solid var(--rule); }
.rf-adv summary { display: flex; align-items: center; gap: 0.5rem; padding: 0.7rem 0.95rem; cursor: pointer; list-style: none; font-size: 0.8125rem; font-weight: 600; color: var(--ink-muted); transition: background-color 130ms ease; }
.rf-adv summary::-webkit-details-marker { display: none; }
.rf-adv summary:hover { background: var(--paper-warm); }
.rf-adv summary .rf-adv-chev { margin-inline-start: auto; transition: transform 160ms ease; }
.rf-adv[open] summary .rf-adv-chev { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { .rf-adv summary .rf-adv-chev { transition: none; } }
.rf-adv-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.25rem 2rem; padding: 0.35rem 0.95rem 1.1rem; }
@media (max-width: 767px) { .rf-adv-grid { grid-template-columns: 1fr; } }
.rf-adv-grid .rf-span2 { grid-column: 1 / -1; }
.rf-err { font-size: 0.8125rem; color: var(--state-deny); }
.rf-jsonbar { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 0.75rem; margin-top: 0.75rem; }

/* ── CSP hardening — tail of unique static inline styles ────────────────── */
.mw-measure-18ch { max-width: 18ch; }
.mw-measure-20ch { max-width: 20ch; }
.mw-measure-28ch { max-width: 28ch; }
.mw-measure-40ch { max-width: 40ch; }
.mw-measure-56ch { max-width: 56ch; }
.mw-measure-72ch { max-width: 72ch; }
.mw-measure-80ch { max-width: 80ch; }
.mw-measure-30ch-med { max-width: 30ch; font-weight: 500; }
.mw-measure-44rem { max-width: 44rem; }
.mw-measure-240px { max-width: 240px; }
.mw-measure-280px { max-width: 280px; }
.mw-measure-none  { max-width: none; }
.mw-minw-16rem { min-width: min(16rem, 100%); }
.mw-minw-125rem { min-width: 1.25rem; }
.mw-minw-110 { min-width: min(110px, 100%); }
.mw-minw-150 { min-width: min(150px, 100%); }
.mw-minw-240 { min-width: min(240px, 100%); }
.mw-clamp-90-120 { min-width: 90px; max-width: 120px; }

.mw-lh-15 { line-height: 1.5; }
.mw-lh-19 { line-height: 1.9; }
.mw-list-disc  { list-style: disc inside; line-height: 1.9; max-width: 76ch; }
.mw-list-decimal { list-style: decimal inside; line-height: 1.9; max-width: 76ch; }
.mw-cols2-decimal { columns: 2; column-gap: 3rem; list-style: decimal inside; line-height: 2; }

.mw-fs-sm-56 { font-size: 0.8125rem; max-width: 56ch; }
.mw-fs-875 { font-size: 0.875rem; }
.mw-fs-875-note { font-size: 0.875rem; margin-top: 0.35rem; line-height: 1.5; }
.mw-fs-1-05-bold { font-size: 1.05rem; font-weight: 600; }
.mw-fs-1-0625 { font-size: 1.0625rem; }
.mw-fs-tiny-dim { font-size: 0.4em; opacity: 0.6; }
.mw-hero-xl { font-size: clamp(3.5rem, 7vw, 5.5rem); line-height: 1; letter-spacing: -0.04em; }
.mw-hero-lg { font-size: clamp(2.5rem, 5vw, 4rem); max-width: 16ch; }
.mw-hero-md { font-size: clamp(1.75rem, 2.6vw, 2.25rem); }

.mw-ink-strong-sp { color: var(--ink); font-weight: 600; }
.mw-brand-500 { color: var(--brand); font-weight: 500; }
.mw-state-pass { color: var(--state-pass); }
.mw-deny-hidden { color: var(--state-deny); display: none; }
.mw-pass-hidden { color: var(--state-pass); display: none; }

.mw-opacity-70 { opacity: 0.7; }
.mw-opacity-85 { opacity: 0.85; }
.mw-iconbtn { opacity: 0.7; border: none; background: transparent; cursor: pointer; padding: 0; }
.mw-wrap-any { overflow-wrap: anywhere; }

.mw-pad-block-hero { padding-block: clamp(4rem, 10vh, 8rem); }
.mw-pad-1520 { padding: 1.25rem 1.5rem; }
.mw-pad-top { padding: 1rem 0 0; }
.mw-relative-z1 { position: relative; z-index: 1; }
.mw-abs { position: absolute; }
.mw-sticky-panel { position: sticky; top: 1rem; max-height: calc(100vh - 2rem); overflow-y: auto; }
.mw-scroll-anchor { scroll-margin-top: 92px; }

.mw-ico-085 { width: 0.85em; height: 0.85em; stroke-width: 1.6; }
.mw-flag-box { width: 22px; height: 26px; }

.mw-border-collapse { border-collapse: collapse; }
.mw-th-ink { border-bottom: 1px solid var(--ink); text-align: start; }
.mw-bottom-rule-thin { border-bottom: 1px solid var(--rule); }
.mw-blk-rule { border-inline-start: 3px solid var(--rule-deep); padding-inline-start: 1rem; }
.mw-blk-rule-sm { border-inline-start: 3px solid var(--rule-deep); padding-inline-start: 0.75rem; overflow-wrap: anywhere; }
.mw-blk-pass { border-inline-start: 3px solid var(--state-pass); padding-inline-start: 0.75rem; color: var(--ink); }
.mw-blk-gov { border-inline-start: 3px solid var(--state-gov); padding-inline-start: 0.75rem; color: var(--ink); }
/* Escalation reason gate — hidden until the officer clicks Escalate with an
   empty note; JS flips display to block. */
.mw-escalate-warn { display: none; border-inline-start: 3px solid var(--state-deny); padding-inline-start: 0.75rem; color: var(--ink); }
.mw-hairline-hidden { display: none; border-inline-start: 3px solid var(--rule); }
.mw-callout-warm { background: var(--paper-warm); border: 1px solid var(--rule); }
.mw-row-flex { border: 1px solid var(--rule); display: flex; align-items: center; gap: 0.75rem; }
.mw-textarea-mono { border: 1px solid var(--rule); resize: vertical; font-family: 'Roboto Mono', ui-monospace, monospace; }
.mw-btn-deny-off { background: var(--state-deny); color: white; border-color: var(--state-deny); opacity: 0.5; }
.mw-chip-deny { background: var(--state-deny-tint); color: var(--state-deny); border: 1px solid var(--state-deny); }
.mw-notice-deny-inline { background: var(--state-deny-tint, #fef2f2); border-inline-start: 3px solid var(--state-deny); padding: 0.625rem 1rem; border-radius: 6px; margin: 0.75rem 0; color: var(--ink); font-size: 0.875rem; }
.mw-chip-deny-out { background: transparent; color: var(--state-deny); border-color: var(--state-deny); }
.mw-chip-gov-out { background: transparent; color: var(--state-gov); border-color: var(--state-gov); }
.mw-chip-pass-fill { background: var(--state-pass); border-color: var(--state-pass); }
.mw-gov-tint { border: 1px solid var(--rule); background: var(--state-gov-tint); }
.mw-gov-tint-full { border: 1px solid var(--rule); background: var(--state-gov-tint); color: var(--state-gov); }
.mw-gov-tint-solid { border: 1px solid var(--state-gov-tint); background: var(--state-gov-tint); color: var(--state-gov); }
.mw-arrow-start { color: var(--brand); font-size: 1.25em; line-height: 0; vertical-align: -0.1em; margin-inline-start: 0.1em; }
.mw-arrow-end { color: var(--brand); font-size: 1.25em; line-height: 0; vertical-align: -0.1em; margin-inline-end: 0.1em; }
.mw-cols-iam { grid-template-columns: 6rem minmax(0,2fr) minmax(0,3fr) 7rem 8rem; column-gap: 1.25rem; }
.mw-cols-autofill16 { grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); }

/* ── _loading_overlay.html — full-screen loading overlay (was inline) ───── */
.mw-loading-overlay {
  position: fixed; inset: 0;
  background: oklch(0.18 0.014 264 / 0.55);
  display: none; align-items: center; justify-content: center;
  z-index: var(--z-toast, 50); opacity: 0;
  transition: opacity 220ms ease;
}
.mw-loading-card {
  background: var(--paper); color: var(--ink);
  padding: 2rem 2.5rem; border-radius: 8px; text-align: center;
  max-width: 24rem; box-shadow: 0 24px 64px -12px rgba(0,0,0,0.35);
  display: flex; flex-direction: column; align-items: center; gap: 1.25rem;
}
.mwLoadingSpinner {
  width: 52px; height: 52px; border-radius: 50%;
  border: 4px solid rgba(0,0,0,0.08);
  border-top-color: var(--brand);
  animation: mwLoadingSpin 0.8s linear infinite;
}

/* ── _flash.html — flash banner tones (bucketed pass/deny) ─────────────── */
.mw-flash {
  padding: 0.625rem 1rem; border-radius: 6px; margin-bottom: 1.25rem;
  color: var(--ink); font-size: 0.875rem; line-height: 1.5;
  border-inline-start: 3px solid var(--rule);
}
.mw-flash.is-pass { background: var(--state-pass-tint, #ecfdf5); border-inline-start-color: var(--state-pass); }
.mw-flash.is-deny { background: var(--state-deny-tint, #fef2f2); border-inline-start-color: var(--state-deny); }

/* ── interview.html — "thinking" pulse dot (was inline) ────────────────── */
.mw-think-dot {
  display: inline-block; width: 0.75rem; height: 0.75rem; border-radius: 50%;
  background: var(--brand);
  animation: mw_pulse 0.9s ease-in-out infinite alternate;
}

/* ────────────────────────────────────────────────────────────────
   IAM — GCP-console-style layout (admin_iam.html, admin_iam_roles.html,
   admin_iam_role.html): IAM bindings page with view-by tabs + grant-access
   drawer; Roles table; role editor with an add-permissions dialog.
   Structure mirrors Google Cloud IAM; the skin stays Nibomont paper-ledger.
   ──────────────────────────────────────────────────────────────── */
.iam-sr {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}

.ledger .iam-num-col   { text-align: end; }
.ledger td.iam-num-col { font-size: 0.8125rem; font-feature-settings: 'tnum'; }
.iam-actions-cell      { text-align: end; white-space: nowrap; }
/* tw.css subset has no .inline-block — keep per-row action forms inline. */
.iam-actions-cell form { display: inline-block; }
/* .ledger a is display:block (row links) — these are inline controls. */
.iam-actions-cell a.btn { display: inline-flex; }
.ledger a.iam-role-link {
  display: inline-block;
  color: var(--brand);
  font-weight: 500;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Client-side row filtering — .is-filtered beats the selection state. */
tr.is-filtered { display: none; }

/* Tab bar — GCP's underlined view switcher. */
.iam-tabs {
  display: flex;
  gap: 0.25rem;
  border-bottom: 1px solid var(--rule);
  margin-bottom: 1.25rem;
}
.iam-tab {
  appearance: none;
  background: none;
  border: none;
  font: 500 0.875rem var(--font-sans);
  letter-spacing: 0.15px;
  text-transform: none;
  color: var(--ink-muted);
  padding: 0.75rem 1rem;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color 120ms ease, border-color 120ms ease;
}
.iam-tab:hover { color: var(--ink); background: var(--hover); }
.iam-tab.is-active { color: var(--accent); border-bottom-color: var(--accent); }

/* Filter field above tables. */
.iam-filter {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  border: 1px solid var(--rule);
  border-radius: 10px;
  padding: 0.55rem 0.9rem;
  margin-bottom: 1rem;
  max-width: 34rem;
  background: var(--paper);
  color: var(--ink-faint);
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.iam-filter:focus-within {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px oklch(0.34 0.075 264 / 0.16);
  color: var(--ink-muted);
}
.iam-filter svg { flex: none; }
.iam-filter input {
  border: none; background: none; outline: none;
  font: inherit; font-size: 0.875rem;
  width: 100%; color: var(--ink);
}
.iam-filter input::placeholder { color: var(--ink-faint); }

/* Inline icon actions (pencil / remove / delete). */
.iam-pencil {
  padding: 0.35rem;
  border-radius: 6px;
  transition: background-color 100ms ease, opacity 100ms ease;
}
.iam-pencil:hover { background: var(--paper-sunk); opacity: 1; }

/* View-by-roles expanders. */
.iam-chevron-col { width: 2.25rem; }
.iam-role-row { cursor: pointer; }
.iam-role-row:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.iam-chevron { transition: transform 150ms ease; vertical-align: middle; }
.iam-role-row[aria-expanded="true"] .iam-chevron { transform: rotate(180deg); }
.iam-member-row td { background: var(--paper-warm); }

/* Grant-access drawer (GCP side panel). */
.iam-drawer { position: fixed; inset: 0; z-index: var(--z-overlay); }
.iam-drawer[hidden] { display: none; }
.iam-drawer-scrim {
  position: absolute; inset: 0;
  background: oklch(0.18 0.014 264 / 0.4);
}
.iam-drawer-panel {
  position: absolute;
  inset-block: 0;
  inset-inline-end: 0;
  width: min(430px, 100%);
  background: var(--paper);
  box-shadow: 0 0 44px oklch(0.18 0.014 264 / 0.3);
  padding: 1.75rem 1.75rem 2rem;
  overflow-y: auto;
  animation: iamDrawerIn 160ms ease;
}
@keyframes iamDrawerIn {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* Group header rows inside permission tables. */
.iam-group-row th {
  text-align: start;
  padding: 1.1rem 1rem 0.4rem;
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--brand);
  border-bottom: 1px solid var(--rule-deep);
  background: var(--paper);
}

/* Add-permissions dialog (GCP permission picker). */
.perm-dialog {
  border: 1px solid var(--rule);
  border-radius: 16px;
  padding: 1.5rem 1.75rem;
  width: min(680px, calc(100vw - 2rem));
  background: var(--paper);
  color: var(--ink);
  box-shadow: 0 30px 70px -30px oklch(0.18 0.014 264 / 0.45);
}
.perm-dialog::backdrop { background: oklch(0.18 0.014 264 / 0.4); }
.perm-dialog-scroll {
  max-height: min(52vh, 30rem);
  overflow-y: auto;
  border: 1px solid var(--rule);
  border-radius: 10px;
}
.perm-dialog-scroll .ledger td { padding: 0.6rem 1rem; }
.iam-checkbox-col { width: 2.5rem; }
.iam-checkbox-col input,
.iam-drawer-panel input[type="checkbox"] {
  width: 1.05rem; height: 1.05rem;
  accent-color: var(--brand);
  margin: 0;
  vertical-align: middle;
}

/* Advisory note — squared ledger tone, amber ink (never blocking). */
.iam-sod-note {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.85rem 1rem;
  border-radius: 10px;
  border: 1px solid var(--state-near-tint);
  border-inline-start: 3px solid var(--state-near);
  background: var(--state-near-tint);
  color: var(--state-near);
  font-size: 0.8125rem;
  line-height: 1.55;
  max-width: 70ch;
}
.iam-sod-note svg { flex: none; margin-top: 0.1rem; }
/* display:flex would beat the UA [hidden] rule — re-assert it. */
.iam-sod-note[hidden] { display: none; }

.mw-ms-2 { margin-inline-start: 0.5rem; }

.iam-impact {
  margin-inline-start: 0.45rem;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  color: var(--state-near);
}

/* ────────────────────────────────────────────────────────────────
   SESSIONS LEDGER — GCP-console-style resource list.
   Contextual selection bar + slim filter row + dense table.
   ──────────────────────────────────────────────────────────────── */
.selbar {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  background: var(--brand);
  color: #fff;
  border-radius: 10px;
  padding: 0.45rem 0.75rem;
  margin-bottom: 1rem;
}
.selbar[hidden] { display: none; }
.selbar-x {
  display: inline-flex;
  border: none; background: transparent; cursor: pointer;
  color: inherit; padding: 0.3rem; border-radius: 6px;
}
.selbar-x:hover { background: oklch(1 0 0 / 0.14); }
.selbar-count { font-size: 0.875rem; font-weight: 600; }
.selbar-action {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  border: none; background: transparent; cursor: pointer;
  color: inherit;
  font-size: 0.8125rem;
  font-weight: 600;
  padding: 0.35rem 0.6rem;
  border-radius: 8px;
}
.selbar-action:hover { background: oklch(1 0 0 / 0.14); }

.gcp-filterrow {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}
.gcp-filterrow .iam-filter { flex: 1 1 24rem; max-width: none; margin-bottom: 0; }
.iam-filter .filt-sep { width: 1px; align-self: stretch; background: var(--rule); flex: none; }
.filt-group { display: inline-flex; align-items: center; gap: 0.45rem; flex: none; }
.filt-label {
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--ink-faint);
  white-space: nowrap;
}
.iam-filter select,
.iam-filter input.filt-days {
  border: none; background: none; outline: none;
  font: inherit; font-size: 0.875rem; color: var(--ink);
  cursor: pointer;
}
.iam-filter input.filt-days { width: 3.5rem; cursor: text; }
/* Small screens: search + status + days can't share one line — wrap the
   groups inside the pill instead of overflowing the page sideways. */
@media (max-width: 767.98px) {
  .gcp-filterrow .iam-filter { flex-wrap: wrap; row-gap: 0.4rem; }
  .gcp-filterrow .iam-filter .filt-sep { display: none; }
}

.ledger-scroll { overflow-x: auto; }
.ledger-dense tbody td { padding: 0.65rem 1rem; vertical-align: middle; }
tr.session-row { cursor: pointer; }
.ledger tbody tr.is-selected td { background: var(--paper-warm); }

/* ── MRZ passport capture (shared partial templates/_mrz_field.html) ──
   The textarea takes a keyboard-wedge scanner burst or two pasted TD3
   lines; static/mrz.js autofills the surrounding form. Monospace + LTR
   regardless of UI direction — the zone itself is always Latin. */
.mrz-field .mrz-input {
  font-family: 'Roboto Mono', ui-monospace, monospace;
  font-size: 0.8125rem;
  letter-spacing: 0.04em;
  line-height: 1.5;
  min-height: 3.4rem;
  resize: vertical;
  text-transform: uppercase;
  white-space: pre;
  overflow-x: auto;
}
.mrz-field .mrz-optional {
  font-size: 0.625rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--ink-faint);
  border: 1px solid var(--rule);
  padding: 0.1rem 0.4rem;
}
.mrz-note {
  display: block;
  margin-top: 0.45rem;
  font-size: 0.8125rem;
  line-height: 1.45;
}
.mrz-note.is-ok { color: var(--state-pass); }
.mrz-note.is-warn { color: var(--state-near); }

/* ═══════════════════════════════════════════════════════════════════════
   admin_analytics.html — aggregate dashboard (pure-SVG charts, no JS libs)
   ═══════════════════════════════════════════════════════════════════════ */
.ana-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.25rem; }
@media (max-width: 900px) { .ana-grid { grid-template-columns: 1fr; } }
/* Sidebar-aware companion — see the .mw-card-row note: expanded rail
   means content < 900px of real room until viewport 900 + 250. */
@media (min-width: 900.02px) and (max-width: 1149.98px) {
  html:not([data-side-collapsed]) .ana-grid { grid-template-columns: 1fr; }
}
.ana-panel { border: 1px solid var(--rule); background: var(--paper); padding: 1.25rem 1.5rem 1.4rem; }
.ana-panel .ledger { width: 100%; }
.ana-chart { width: 100%; height: auto; display: block; }
/* Segment fills key off the same state palette the status words use. */
.ana-seg-pass { fill: var(--state-pass); }
.ana-seg-deny { fill: var(--state-deny); }
.ana-seg-gov  { fill: var(--state-gov); }
.ana-seg-other { fill: var(--rule-deep); }
.ana-axis { stroke: var(--rule-deep); stroke-width: 1; }
.ana-label { font: 500 0.55rem 'Roboto Mono', ui-monospace, monospace; fill: var(--ink-faint); }
.ana-legend { display: flex; gap: 1.25rem; flex-wrap: wrap; margin-top: 0.85rem; }

/* ═══════════════════════════════════════════════════════════════════════
   Tools palette (⌘K) — sidebar trigger + modal. The trigger reads as an
   input on the dark rail; the modal is a paper card in the ledger idiom
   (hairline rules, squared corners, no chips).
   ═══════════════════════════════════════════════════════════════════════ */
.side-search {
  display: flex; align-items: center; gap: 0.55rem;
  width: 100%;
  margin-block-end: 0.9rem;
  padding: 0.45rem 0.65rem;
  border: 1px solid oklch(1 0 0 / 0.18);
  background: oklch(1 0 0 / 0.06);
  color: inherit;
  font-size: 0.8125rem;
  cursor: pointer;
  text-align: start;
}
.side-search:hover { background: oklch(1 0 0 / 0.11); }
.side-search .side-label { flex: 1 1 auto; opacity: 0.85; }
.side-search-kbd {
  font: 500 0.625rem 'Roboto Mono', ui-monospace, monospace;
  letter-spacing: 0.06em;
  border: 1px solid oklch(1 0 0 / 0.22);
  padding: 0.1rem 0.3rem;
  opacity: 0.75;
  white-space: nowrap;
}
@media (min-width: 900px) {
  html[data-side-collapsed] .side-search { justify-content: center; padding-inline: 0; }
  html[data-side-collapsed] .side-search-kbd { display: none; }
}

dialog.mw-palette {
  width: min(38rem, 92vw);
  margin: 12vh auto auto;
  padding: 0;
  border: 1px solid var(--rule-deep);
  background: var(--paper);
  color: var(--ink);
  box-shadow: 0 24px 48px -12px oklch(0.18 0.014 264 / 0.28);
}
dialog.mw-palette::backdrop { background: oklch(0.18 0.014 264 / 0.45); }

.pal-head {
  display: flex; align-items: center; gap: 0.6rem;
  padding: 0.8rem 1rem;
  border-bottom: 1px solid var(--rule);
  color: var(--ink-muted);
}
.pal-head input {
  flex: 1 1 auto;
  border: 0; outline: 0; background: transparent;
  font-size: 0.9375rem;
  color: var(--ink);
  min-width: 0;
}
.pal-kbd {
  font: 500 0.625rem 'Roboto Mono', ui-monospace, monospace;
  border: 1px solid var(--rule);
  color: var(--ink-faint);
  padding: 0.1rem 0.35rem;
  text-transform: uppercase; letter-spacing: 0.08em;
}
.pal-list {
  list-style: none; margin: 0; padding: 0;
  max-height: 50vh; overflow-y: auto;
}
.pal-item {
  display: flex; align-items: baseline; gap: 0.75rem;
  padding: 0.6rem 1rem;
  border-top: 1px solid var(--rule);
  border-inline-start: 2px solid transparent;
  text-decoration: none;
  color: var(--ink);
  font-size: 0.875rem;
}
.pal-list li:first-child .pal-item { border-top: 0; }
.pal-item:hover,
.pal-item.is-active { background: var(--paper-warm); }
.pal-item.is-active { border-inline-start-color: var(--state-pass); }
.pal-label { flex: 1 1 auto; }
.pal-label .pal-hit {
  background: transparent;
  color: inherit;
  font-weight: 650;
  text-decoration: underline;
  text-decoration-color: var(--rule-deep);
  text-underline-offset: 0.18em;
}
.pal-path {
  direction: ltr;
  font-size: 0.6875rem;
  color: var(--ink-faint);
  white-space: nowrap;
}
.pal-empty {
  padding: 1rem;
  font-size: 0.8125rem;
  color: var(--ink-muted);
  border-top: 1px solid var(--rule);
}

/* ── Case-search match-reason tag (sessions ledger + inbox) ──────────
   Which field the typo-tolerant search matched on; "≈" precedes the
   label on fuzzy hits. Quieter than the verdict state words — an
   annotation, not a status. */
.state.state-why {
  color: var(--ink-faint);
  font-weight: 500;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  border: 1px solid var(--rule);
  padding: 0.05rem 0.35rem;
}
.state.state-why::before { display: none; }

/* ── § GCP rules console (/admin/rules) ──────────────────────────────
   The rules desk rebuilt in the same GCP-console idiom as the IAM
   pages: tab bar, toolbar with blue-ink text actions + filter box,
   flat ledger tables, and right-hand side-panel drawers for every
   create/edit surface. Uses the app palette (brand green), not
   Google's blue — structure is GCP, skin stays Nibomont. */

.rules-sect-head { margin-top: 2rem; }
[data-view-panel] > .rules-sect-head:first-child { margin-top: 1.5rem; }

/* Toolbar: primary text action · hairline separator · filter box. */
.rules-toolbar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin: 0.9rem 0 0.25rem;
}
.rules-toolbar .iam-filter { flex: 1 1 22rem; max-width: 34rem; margin-bottom: 0.5rem; }
.rules-toolbar-sep { width: 1px; height: 1.4rem; background: var(--rule); flex: none; margin-bottom: 0.5rem; }

/* GCP-style text button (the console's "+ Create" affordance). */
.gcp-textbtn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.45rem 0.7rem;
  margin-bottom: 0.5rem;
  border-radius: 6px;
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--brand);
  transition: background-color 120ms ease;
}
.gcp-textbtn:hover { background: var(--brand-tint); }
.gcp-textbtn svg { flex: none; }

/* Tab badge count. */
.rules-tab-count {
  display: inline-block;
  min-width: 1.4rem;
  margin-inline-start: 0.4rem;
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  background: var(--paper-sunk);
  color: var(--ink-muted);
  font-size: 0.6875rem;
  font-weight: 600;
  text-align: center;
  font-feature-settings: 'tnum';
}
.iam-tab.is-active .rules-tab-count { background: var(--brand-tint); color: var(--brand); }

/* Ledger tweaks for the rules tables. */
.rules-ledger td { vertical-align: top; }
.rules-order-col { width: 3.5rem; }
.rules-name-cell { min-width: 12rem; }
.rules-name-link {
  text-align: start;
  cursor: pointer;
  font: inherit;
  font-weight: 500;
}
.rules-name-link:disabled { color: var(--ink-muted); cursor: default; text-decoration: none; }
.rules-row-archived td { opacity: 0.55; }
.rules-row-archived td.iam-actions-cell { opacity: 1; }
.rules-row-slot td { background: var(--paper-warm); }

/* Match column — the stored condition as a one-line expression. */
.cond-expr {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 0.75rem;
  line-height: 1.6;
  color: var(--ink-muted);
  word-break: break-word;
  background: none;
  padding: 0;
}

/* Row overflow menu (⋮) — details-based, CSP-clean. */
.gcp-menu { position: relative; display: inline-block; }
.gcp-menu > summary { list-style: none; cursor: pointer; }
.gcp-menu > summary::-webkit-details-marker { display: none; }
.gcp-menu[open] > summary { background: var(--paper-sunk); opacity: 1; }
.gcp-menu-pop {
  position: absolute;
  inset-inline-end: 0;
  top: calc(100% + 4px);
  z-index: 60;
  min-width: 13.5rem;
  padding: 0.35rem;
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 8px;
  box-shadow: 0 10px 30px -10px oklch(0.18 0.014 264 / 0.35);
  text-align: start;
}
.gcp-menu-pop form { display: block; }
.gcp-menu-item {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  width: 100%;
  padding: 0.5rem 0.7rem;
  border-radius: 6px;
  font-size: 0.8125rem;
  color: var(--ink);
  text-align: start;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color 100ms ease;
}
.gcp-menu-item:hover { background: var(--paper-sunk); }
.gcp-menu-item.is-danger { color: var(--state-deny); }
.gcp-menu-item.is-go { color: var(--brand); }
.gcp-menu-item svg { flex: none; opacity: 0.75; }

/* The create/edit rule panel needs room for the condition builder. */
.rules-drawer .iam-drawer-panel { width: min(760px, 100%); }

/* GCP-style "Learn more" doc link — appended to one-line page/section
   descriptions; deep-links into the in-app handbook (/admin/docs). */
.learn-more {
  color: var(--brand);
  font-weight: 600;
  white-space: nowrap;
}
.learn-more:hover { text-decoration: underline; }

/* ── Verification chat thread (passenger scenario interview) ──────────────
   A Claude/Gemini-style dialog: assistant questions on the leading edge,
   the passenger's answers on the trailing edge. Squared, ledger-flat — no
   pill bubbles — to hold the brand's stamp/register vocabulary. */
.mw-chat { display: flex; flex-direction: column; gap: 0.6rem; }
.mw-chat-row { display: flex; }
.mw-chat-row.is-user { justify-content: flex-end; }
.mw-bubble {
  max-width: min(46ch, 90%);
  padding: 0.7rem 0.9rem;
  border: 1px solid var(--rule);
  background: var(--paper-sunk);
  line-height: 1.5;
  animation: mw-bubble-in 0.18s var(--vt-ease-out, ease-out) both;
}
.mw-bubble.is-assistant { border-inline-start: 3px solid var(--brand); }
.mw-bubble.is-user {
  background: var(--brand-tint);
  border-color: color-mix(in oklch, var(--brand) 32%, var(--rule));
}
.mw-bubble-who {
  font-size: 0.6875rem; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink-faint); margin-bottom: 0.2rem;
}
@keyframes mw-bubble-in {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) { .mw-bubble { animation: none; } }
/* The answer composer sits under the thread as a chip tray. */
/* Keeps the question clear of the sticky header when nibomont.js scrolls
   it to the top of the viewport after a turn. */
[data-mw-scroll-to-latest] { scroll-margin-top: 1.5rem; }

/* Pending assistant turn — the inline replacement for the full-screen
   scrim. See the "Inline pending state" block in templates/interrogate.html
   for why the wait is painted here rather than over the whole page. */
.mw-pending { display: flex; flex-direction: column; gap: 0.35rem; }
.mw-pending-title { font-weight: 600; }
.mw-pending-body { font-size: 0.875rem; color: var(--ink-muted, inherit); opacity: 0.8; }
.mw-typing { display: inline-flex; gap: 0.28rem; align-items: center; padding: 0.15rem 0; }
.mw-typing i {
  width: 0.42rem; height: 0.42rem; border-radius: 50%;
  background: var(--brand); opacity: 0.35;
  animation: mw-typing-pulse 1.2s ease-in-out infinite;
}
.mw-typing i:nth-child(2) { animation-delay: 0.16s; }
.mw-typing i:nth-child(3) { animation-delay: 0.32s; }
@keyframes mw-typing-pulse {
  0%, 60%, 100% { opacity: 0.3; transform: translateY(0); }
  30%           { opacity: 1;   transform: translateY(-0.18rem); }
}
@media (prefers-reduced-motion: reduce) {
  .mw-typing i { animation: none; opacity: 0.55; }
}

.mw-composer { border-top: 1px solid var(--rule); padding-top: 1rem; margin-top: 1rem; }

/* "The pen" — revise an earlier answer. A <details> disclosure inside the
   passenger's own bubble: the trigger stays quiet until hover/focus so the
   thread still reads as a conversation, not a form. JS-free by design (kiosk
   browsers, CSP). */
.mw-edit-tag {
  margin-inline-start: 0.4rem;
  font-size: 0.625rem; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--brand);
  border: 1px solid color-mix(in oklch, var(--brand) 40%, var(--rule));
  padding: 0.05rem 0.3rem;
}
.mw-edit { margin-top: 0.45rem; }
.mw-edit-pen {
  display: inline-flex; align-items: center; gap: 0.3rem;
  font-size: 0.75rem; color: var(--ink-faint);
  cursor: pointer; list-style: none; user-select: none;
  border-top: 1px solid transparent; padding-top: 0.35rem;
}
.mw-edit-pen::-webkit-details-marker { display: none; }
.mw-edit-pen:hover, .mw-edit-pen:focus-visible,
.mw-edit[open] > .mw-edit-pen { color: var(--brand); }
.mw-edit[open] > .mw-edit-pen {
  border-top-color: color-mix(in oklch, var(--brand) 30%, var(--rule));
  margin-bottom: 0.5rem;
}
.mw-edit-form textarea { width: 100%; }
.mw-edit-note {
  font-size: 0.75rem; color: var(--ink-faint);
  line-height: 1.45; margin-top: 0.4rem;
}
.mw-edit-actions { display: flex; justify-content: flex-end; margin-top: 0.6rem; }

/* Officer side of the same feature: a revised answer is flagged in the case
   transcript, and the branch it superseded is one disclosure away. Squared
   ledger tags — never pill-with-dot chips. */
.mw-revised-flag {
  display: inline-block;
  margin-inline-start: 0.4rem;
  font-size: 0.625rem; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--warn, var(--brand));
  border: 1px solid color-mix(in oklch, var(--warn, var(--brand)) 45%, var(--rule));
  padding: 0.05rem 0.3rem;
  vertical-align: middle;
}
.mw-superseded { margin-top: 0.5rem; margin-inline-start: 2rem; }
.mw-superseded > summary {
  font-size: 0.75rem; color: var(--ink-faint);
  cursor: pointer; list-style: none;
}
.mw-superseded > summary::-webkit-details-marker { display: none; }
.mw-superseded > summary::before { content: "▸ "; }
.mw-superseded[open] > summary::before { content: "▾ "; }
.mw-superseded > summary:hover { color: var(--brand); }
.mw-superseded-edit {
  margin-top: 0.5rem; padding: 0.6rem 0.8rem;
  border: 1px dashed var(--rule);
  background: var(--paper-sunk);
}
.mw-superseded-turn {
  padding-inline-start: 0.6rem;
  border-inline-start: 2px solid var(--rule);
}

/* ────────────────────────────────────────────────────────────────
   SCENARIOS — GCP list page: compact rows, expandable detail, a
   create/edit panel that opens from the header (not a bottom dump).
   ──────────────────────────────────────────────────────────────── */
.sc-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1.5rem; flex-wrap: wrap; }
.sc-head-text { min-width: 0; }
.sc-head-actions { display: flex; align-items: center; gap: 1rem; flex: none; padding-top: 0.35rem; }

.sc-table .sc-expand-col { width: 44px; padding-inline: 0.35rem 0; text-align: center; }
.sc-expand-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border: 0; border-radius: 50%;
  background: transparent; color: var(--ink-muted); cursor: pointer;
  transition: background var(--dur-fast) var(--ease-standard), transform var(--dur-fast) var(--ease-standard);
}
.sc-expand-btn:hover { background: var(--hover); }
.sc-expand-btn[aria-expanded="true"] { transform: rotate(90deg); }
html[dir="rtl"] .sc-expand-btn[aria-expanded="true"] { transform: rotate(-90deg); }

.sc-detail-row > td { height: auto; padding: 0; background: var(--paper-warm); border-bottom: 1px solid var(--rule); }
.sc-detail { padding: 1rem 1.25rem 1.25rem; }
.sc-detail-when { color: var(--ink-muted); }

.sc-steps { display: grid; gap: 0.6rem; }
.sc-step { background: var(--surface); border: 1px solid var(--rule); border-radius: 8px; padding: 0.7rem 0.9rem; }
.sc-step-q { display: flex; align-items: baseline; gap: 0.5rem; font-size: 0.875rem; color: var(--ink); flex-wrap: wrap; }
.sc-step-n {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.4rem; height: 1.4rem; border-radius: 50%;
  background: var(--brand-tint); color: var(--accent);
  font: 500 0.75rem/1 var(--font-sans); flex: none;
}
.sc-step-kind {
  font: 500 0.625rem/1 var(--font-sans); letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--ink-faint); border: 1px solid var(--rule); border-radius: 4px;
  padding: 0.15rem 0.4rem; margin-inline-start: auto; white-space: nowrap;
}
.sc-step-a { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.55rem; }
.sc-chip {
  display: inline-flex; align-items: center; gap: 0.35rem;
  font: 400 0.75rem var(--font-sans); color: var(--ink-body);
  background: var(--paper-sunk); border-radius: 6px; padding: 0.2rem 0.55rem;
}
.sc-chip-lookup { font-family: var(--font-mono); color: var(--ink-muted); }

/* ── Draft-with-AI honest progress tracker ────────────────────────────
   A 5-step vertical checklist that replaces #scenario-draft-status while a
   compile is in flight. Estimated (client-only) — the markers advance on a
   decelerating timer but step 5 only completes when the real fetch lands
   (see spec §4). House style: SQUARED ledger markers (no pill-dots), tokens
   only, no inline styles. Prefix `sc-prog-*` — distinct from the pre-existing
   `.sc-step*` requirement-preview tree above, which it must not collide with. */
.sc-prog { margin-top: 0.75rem; }
/* Off-screen polite live region — narrates the active step to screen readers
   without painting anything (the visible progress is the markers themselves). */
.sc-prog-live {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
.sc-prog-list { display: grid; gap: 0.15rem; margin: 0; padding: 0; list-style: none; }
.sc-prog-step {
  display: grid; grid-template-columns: auto 1fr; align-items: start;
  column-gap: 0.6rem; padding: 0.28rem 0;
  color: var(--ink-faint);
  transition: color 240ms var(--ease-standard);
}
/* Squared ledger marker: a filled tick for done, a brand-tint square for
   active, a hollow hairline square for pending. */
.sc-prog-mark {
  position: relative; flex: none;
  width: 0.95rem; height: 0.95rem; margin-top: 0.15rem;
  border: 1.5px solid var(--rule-deep); border-radius: 3px;
  background: transparent;
  transition: background 240ms var(--ease-standard),
              border-color 240ms var(--ease-standard),
              transform 240ms var(--ease-standard);
}
/* The tick glyph — drawn as a rotated box-corner, revealed on `is-done`. */
.sc-prog-mark::after {
  content: ""; position: absolute;
  left: 50%; top: 46%;
  width: 0.22rem; height: 0.46rem;
  border: solid var(--brand-on); border-width: 0 1.5px 1.5px 0;
  transform: translate(-50%, -55%) rotate(45deg) scale(0.4);
  opacity: 0;
  transition: opacity 200ms var(--ease-standard), transform 240ms var(--ease-standard);
}
.sc-prog-body { min-width: 0; }
.sc-prog-label { font: 400 0.8125rem/1.3 var(--font-sans); }
.sc-prog-sub {
  font: 400 0.75rem/1.35 var(--font-sans); color: var(--ink-faint);
  margin-top: 0.1rem;
}

/* pending — dim, hollow (the default above already reads pending) */
.sc-prog-step.is-pending .sc-prog-mark { border-color: var(--rule); }

/* active — brand-tint square, brand label, gentle pulse, trailing "…" */
.sc-prog-step.is-active { color: var(--ink); }
.sc-prog-step.is-active .sc-prog-label { color: var(--accent); font-weight: 500; }
.sc-prog-step.is-active .sc-prog-label::after { content: "…"; }
.sc-prog-step.is-active .sc-prog-mark {
  border-color: var(--accent); background: var(--brand-tint);
  animation: sc-prog-pulse 1.6s var(--ease-standard) infinite;
}

/* done — filled accent square, muted label, tick revealed */
.sc-prog-step.is-done { color: var(--ink-muted); }
.sc-prog-step.is-done .sc-prog-label { color: var(--ink-muted); }
.sc-prog-step.is-done .sc-prog-mark {
  border-color: var(--state-pass); background: var(--state-pass);
}
.sc-prog-step.is-done .sc-prog-mark::after {
  opacity: 1; transform: translate(-50%, -55%) rotate(45deg) scale(1);
}

/* The pulse breathes the active marker — one clean ring per cycle: a colored
   halo hugs the marker, expands to 5px AS it fades, then holds clear. (Spread
   must GROW while the colour is still present — a zero-spread shadow is
   occluded by the marker itself.) Decorative only; state lives in the marker
   fill + the aria-live narration, so reduced-motion can drop it. */
@keyframes sc-prog-pulse {
  0%   { box-shadow: 0 0 0 0 var(--brand-tint-2); }
  70%  { box-shadow: 0 0 0 5px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .sc-prog-step, .sc-prog-mark, .sc-prog-mark::after { transition: none; }
  .sc-prog-step.is-active .sc-prog-mark { animation: none; }
}

/* Drag-to-reorder fact rows — DOM order IS the interview ask order. The
   order badge is a CSS counter (renumbers itself on any reorder); the grip
   is the only drag-arming surface so the row's inputs keep normal text
   selection. The dragged row stays in flow as a dashed brand-tint "slot"
   (the browser paints the flying snapshot), and a short settle flash marks
   where a row landed after a drop or an Arrow-key move. */
#sc-rf-rows { counter-reset: rf-ord; }
.sc-rf-row {
  border-radius: 6px;
  transition: background var(--dur-fast) var(--ease-standard),
              box-shadow var(--dur-fast) var(--ease-standard),
              opacity var(--dur-fast) var(--ease-standard);
}
.rf-ordgrip { display: inline-flex; align-items: center; gap: 0.1rem; }
.rf-ord {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.4rem; height: 1.4rem; border-radius: 50%;
  background: var(--brand-tint); color: var(--accent);
  font: 500 0.75rem/1 var(--font-sans); flex: none;
}
.rf-ord::before { counter-increment: rf-ord; content: counter(rf-ord); }
.rf-grip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.5rem; height: 2rem; border: 0; border-radius: 4px;
  background: transparent; color: var(--ink-faint);
  cursor: grab; touch-action: none; flex: none;
  transition: color var(--dur-fast) var(--ease-standard),
              background var(--dur-fast) var(--ease-standard);
}
.rf-grip:hover { color: var(--accent); background: var(--hover); }
.rf-grip:active { cursor: grabbing; }
.rf-grip:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; color: var(--accent); }
.sc-rf-row.is-dragging {
  opacity: 0.5;
  background: var(--brand-tint);
  outline: 2px dashed var(--accent);
  outline-offset: 2px;
}
#sc-rf-rows.is-reordering .sc-rf-row:not(.is-dragging) { opacity: 0.85; }
@keyframes rf-settle {
  from { background: var(--brand-tint); box-shadow: 0 2px 10px rgba(0, 0, 0, 0.12); }
  to { background: transparent; box-shadow: none; }
}
.sc-rf-row.is-settling { animation: rf-settle 0.45s var(--ease-standard); }

/* Passenger-question card — the editable ask-preview under each fact row.
   Framed like the chat bubble the passenger will actually see, with an
   unmissable "this is editable" affordance: dashed underline at rest,
   brand-solid on hover/focus/customized. */
.sc-ask-card {
  grid-column: 1 / -1;
  margin: 0.15rem 0 0.4rem;
  border: 1px solid var(--rule-soft);
  border-inline-start: 3px solid var(--accent);
  background: var(--paper-sunk);
  border-radius: 6px;
  padding: 0.55rem 0.75rem 0.65rem;
  display: grid;
  gap: 0.4rem;
}
.sc-ask-head { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.sc-ask-kicker {
  display: inline-flex; align-items: center; gap: 0.35rem;
  font: 500 0.6875rem/1 var(--font-mono);
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--accent);
}
.sc-ask-tag {
  font: 500 0.625rem/1 var(--font-mono); letter-spacing: 0.06em;
  text-transform: uppercase; padding: 0.15rem 0.4rem; border-radius: 4px;
  border: 1px solid var(--rule); color: var(--ink-faint); background: var(--paper);
}
.sc-ask-card.is-custom .sc-ask-tag { border-color: var(--accent); color: var(--accent); }
.sc-ask-ladder { font-size: 0.75rem; color: var(--ink-muted); margin-inline-start: auto; }
.sc-ask-quote { display: flex; align-items: center; gap: 0.5rem; }
.sc-ask-quote > .sc-ask-pencil { flex: none; color: var(--ink-faint); cursor: pointer; }
.sc-ask-quote > .sc-ask-pencil:hover { color: var(--accent); }
.sc-ask-lead { font-size: 0.75rem; color: var(--ink-faint); }
.sc-ask-input {
  flex: 1; min-width: 14rem;
  font: 600 0.9375rem/1.3 var(--font-sans); color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--rule-soft);
  border-bottom: 2px dashed var(--rule);
  border-radius: 4px 4px 0 0;
  padding: 0.45rem 0.6rem;
  transition: border-color var(--dur-fast) var(--ease-standard),
              box-shadow var(--dur-fast) var(--ease-standard);
}
.sc-ask-input:hover { border-bottom-color: var(--accent); }
.sc-ask-input:focus {
  outline: none; border-color: var(--accent); border-bottom-style: solid;
  box-shadow: 0 0 0 3px var(--brand-tint);
}
.sc-ask-card.is-custom .sc-ask-input {
  border-bottom-style: solid; border-bottom-color: var(--accent);
}
.sc-ask-meta { font-size: 0.75rem; color: var(--ink-faint); }
.sc-ask-warn { font-size: 0.75rem; color: var(--ink-muted); }

/* CSP is style-src 'self' — inline style="" attributes are DROPPED, so every
   scenario-authoring/test-drive layout rule lives here as a class. */
.sc-adv-sum { display: inline-flex; align-items: center; gap: 0.4rem; vertical-align: middle; }
.sc-test-wrap { border-top: 1px solid var(--rule-soft); padding-top: 1.25rem; }
.sc-test-col { max-width: 46rem; }
.sc-test-answer { flex: 1; min-width: 0; }
.sc-test-inline-label { display: flex; align-items: center; gap: 0.35rem; }
.sc-test-ol { padding-inline-start: 1.2rem; display: grid; gap: 0.15rem; }
.sc-test-out { text-decoration: line-through; opacity: 0.6; }
.sc-test-sm { font-size: 0.8125rem; }
.sc-test-pointer { cursor: pointer; }
.sc-newfact-tag { padding: 0.15rem 0.4rem; border-radius: 0.25rem; }
.sc-mbv-label { white-space: nowrap; }

/* Checkbox dropdown (deny-rule scope) — a select-shaped trigger opening a
   scrollable checkbox panel. Deliberately NOT .gcp-menu: that handler
   portals + closes on any scroll, which would dismiss this list mid-scroll. */
.sc-dd { position: relative; }
.sc-dd > summary { list-style: none; }
.sc-dd > summary::-webkit-details-marker { display: none; }
.sc-dd-btn {
  display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
  border: 1px solid var(--rule); border-radius: 4px; background: var(--paper);
  padding: 0.55rem 0.7rem; cursor: pointer; user-select: none;
  font-size: 0.875rem; color: var(--ink);
}
.sc-dd-btn:hover { border-color: var(--accent); }
.sc-dd[open] > .sc-dd-btn { border-color: var(--accent); }
.sc-dd[open] > .sc-dd-btn > svg { transform: rotate(180deg); }
.sc-dd-pop {
  position: absolute; top: calc(100% + 4px); inset-inline-start: 0; z-index: 60;
  min-width: 100%; max-height: 16rem; overflow: auto;
  background: var(--paper); border: 1px solid var(--rule); border-radius: 4px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.14);
  padding: 0.25rem; display: grid; gap: 1px;
}
.sc-dd-opt {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.4rem 0.55rem; border-radius: 4px; cursor: pointer;
  font-size: 0.8125rem; color: var(--ink-body); white-space: nowrap;
}
.sc-dd-opt:hover { background: var(--paper-sunk); }
.sc-dd-opt input { accent-color: var(--accent); flex: none; }

/* "Must be verified" — a stamped toggle tag, not a bare checkbox. The real
   <input type=checkbox> stays inside (hidden) for a11y + form JS. */
.sc-verify-toggle {
  position: relative; display: inline-flex; align-items: center; gap: 0.35rem;
  font: 500 0.6875rem/1 var(--font-mono); letter-spacing: 0.06em;
  text-transform: uppercase; white-space: nowrap;
  padding: 0.4rem 0.6rem; border: 1px solid var(--rule); border-radius: 4px;
  color: var(--ink-muted); background: var(--paper);
  cursor: pointer; user-select: none;
  transition: background var(--dur-fast) var(--ease-standard),
              border-color var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard);
}
.sc-verify-toggle:hover { border-color: var(--accent); color: var(--accent); }
.sc-verify-toggle input {
  position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer;
}
.sc-verify-toggle:focus-within {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
.sc-verify-toggle.is-on {
  background: var(--accent); border-color: var(--accent);
  color: var(--brand-on, #fff);
}

.sc-form-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.75rem; }

/* ── any_of group cluster (editor + detail view) ── */
/* Editor: bordered cluster with a tinted left rule — squared ledger style. */
.sc-anyof {
  border: 1px solid var(--rule);
  border-inline-start: 3px solid var(--brand-tint-2);
  border-radius: 4px;
  background: var(--paper-sunk);
  padding: 0.5rem 0.75rem 0.6rem;
  display: grid;
  gap: 0.5rem;
}
.sc-anyof.is-dragging {
  opacity: 0.55;
  box-shadow: 0 4px 14px rgba(0,0,0,.18);
}
.sc-anyof-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.sc-anyof-label {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.sc-anyof-grip-wrap { display: flex; align-items: center; }
.sc-anyof-rows { display: grid; gap: 0.4rem; }
.sc-anyof-add {
  align-self: start;
  font-size: 0.8125rem;
  padding: 0.2rem 0.5rem;
}

/* Detail (read-only) view: same family — box + tinted left rule. */
.sc-anyof-view {
  border: 1px solid var(--rule);
  border-inline-start: 3px solid var(--brand-tint-2);
  border-radius: 4px;
  background: var(--paper-sunk);
  padding: 0.5rem 0.75rem 0.6rem;
  display: grid;
  gap: 0.35rem;
}
.sc-anyof-tag {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-bottom: 0.1rem;
}
.sc-anyof-view-row {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  font-size: 0.875rem;
  color: var(--ink);
  flex-wrap: wrap;
}

/* ────────────────────────────────────────────────────────────────────────
   DRAFT-BOX STATES — clarify round, warning/assumption chips, mismatch
   panel, AI-review question tag. Added v=gcp0020 (amendment §9.2).
   ──────────────────────────────────────────────────────────────────────── */

/* Warning and assumption chips — squared ledger tags, no pill-dots */
.sc-warn-tag, .sc-assume-tag {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.15rem 0.45rem;
  border-radius: 2px;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.4;
}
.sc-warn-tag {
  /* Translucent amber reads on both light + dark surfaces (no amber token
     exists in the palette); ink-body text keeps it legible either way. */
  background: rgba(230, 150, 0, 0.15);
  color: var(--ink-body);
  border: 1px solid rgba(230, 150, 0, 0.45);
}
.sc-assume-tag {
  background: var(--paper-sunk);
  color: var(--ink-muted);
  border: 1px solid var(--rule);
}

/* Clarify-round container */
.sc-clarify-q {
  margin-bottom: 0.6rem;
}
.sc-clarify-lbl {
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--ink);
  margin-bottom: 0.35rem;
}
.sc-clarify-opt {
  display: inline-flex;
  align-items: center;
  padding: 0.2rem 0.65rem;
  margin-right: 0.35rem;
  margin-bottom: 0.25rem;
  border-radius: 2px;
  border: 1px solid var(--rule);
  background: var(--paper-sunk);
  color: var(--ink-body);
  font-size: 0.8rem;
  cursor: pointer;
  transition: background 0.1s, border-color 0.1s, color 0.1s;
}
.sc-clarify-opt:hover { background: var(--brand-tint); border-color: var(--accent); color: var(--ink); }
.sc-clarify-opt.is-picked {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--brand-on);
  font-weight: 600;
}

/* Mismatch panel */
.sc-mismatch {
  border: 1px solid rgba(230, 150, 0, 0.45);
  border-radius: 4px;
  background: rgba(230, 150, 0, 0.12);
  padding: 0.75rem 1rem;
}
.sc-mismatch-msg {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 0.5rem;
}
.sc-mismatch-pre {
  font-family: var(--font-mono, 'Roboto Mono', monospace);
  font-size: 0.75rem;
  color: var(--ink-body);
  white-space: pre-wrap;
  word-break: break-word;
  margin: 0 0 0.25rem;
}

/* AI draft — review tag modifier on the question state badge */
.sc-ask-card.is-review .rf-q-state {
  background: rgba(230, 150, 0, 0.18);
  color: var(--ink-body);
  border-color: rgba(230, 150, 0, 0.5);
}

/* Source-why rationale line below the declaration select */
.rf-src-why {
  font-size: 0.75rem;
  color: var(--ink-faint, #94a3b8);
  font-style: italic;
  flex-basis: 100%;
}

/* ────────────────────────────────────────────────────────────────────────
   SMALL-SCREEN POLICY TABLES — the safety ladder (.rules-ledger) and the
   scenario list (.sc-table) carry 5–7 columns of prose; at phone width a
   horizontal swipe strip reads as a clipped, broken table. Collapse each
   row into a stacked card: identity line first, then the descriptive
   cells, then state + actions. The header row is dropped — every cell is
   self-describing prose or a labelled chip. `tr:not([hidden])` keeps the
   collapsed scenario detail rows hidden until their toggle opens them.
   ──────────────────────────────────────────────────────────────────────── */
@media (max-width: 767.98px) {
  .rules-ledger, .rules-ledger tbody,
  .sc-table, .sc-table tbody { display: block; width: 100%; min-width: 0; }
  .rules-ledger thead, .sc-table thead { display: none; }
  .rules-ledger tbody tr:not([hidden]),
  .sc-table tbody tr:not([hidden]) {
    display: block;
    padding: 0.9rem 0 0.8rem;
    border-bottom: 1px solid var(--rule);
  }
  .rules-ledger tbody td, .sc-table tbody td {
    display: block;
    padding: 0.2rem 0;
    height: auto;
    border-bottom: 0;
  }
  /* Step number + rule id share the leading line. */
  .rules-ledger td.rules-order-col {
    display: inline-block; width: auto;
    padding: 0 0.6rem 0.1rem 0; text-align: start; font-weight: 600;
  }
  html[dir="rtl"] .rules-ledger td.rules-order-col { padding: 0 0 0.1rem 0.6rem; }
  .rules-ledger td.rules-order-col + td { display: inline-block; width: auto; padding: 0 0 0.1rem; }
  /* The chevron expander duplicates the name link — drop it; priority is
     visible in the edit form. */
  .sc-table td.sc-expand-col, .sc-table td.iam-num-col { display: none; }
  .rules-ledger td.iam-actions-cell, .sc-table td.iam-actions-cell {
    text-align: start; padding-top: 0.45rem;
  }
  /* Detail rows keep their full-width panel; the colspan cell is a block. */
  .sc-table tr.sc-detail-row:not([hidden]) { padding-top: 0; border-bottom: 1px solid var(--rule); }
}

/* --- Voice assist (interrogation chat) ------------------------------------
   Mic + speaker controls are hidden until static/voice.js proves the browser
   can actually do the job (MediaRecorder / an OS voice for the page lang). */
.mw-voice {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  margin-top: 0.75rem;
}
.mw-voice-status {
  font-size: 0.8125rem;
  color: var(--ink-muted, #5f6368);
}
.mw-voice-mic.is-recording {
  outline: 2px solid #b3261e;
  outline-offset: 1px;
  animation: mw-voice-pulse 1.4s ease-in-out infinite;
}
@keyframes mw-voice-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(179, 38, 30, 0.35); }
  50% { box-shadow: 0 0 0 7px rgba(179, 38, 30, 0); }
}
.mw-voice-speak {
  background: none;
  border: 0;
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
  padding: 0;
  margin-inline-start: 0.5rem;
  vertical-align: middle;
}
.mw-voice-autoread {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 1rem;
  font-size: 0.8125rem;
  cursor: pointer;
}
.mw-voice-notice {
  margin-top: 0.6rem;
  font-size: 0.75rem;
  color: var(--ink-faint, #80868b);
}

/* Live input-level meter (shown while recording) */
.mw-voice-meter {
  display: inline-block;
  width: 88px;
  height: 8px;
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.08);
  overflow: hidden;
  vertical-align: middle;
}
.mw-voice-meter-fill {
  display: block;
  width: 0%;
  height: 100%;
  background: #9aa0a6;
  transition: width 80ms linear;
}
.mw-voice-meter-fill.is-live { background: #1a73e8; }
.mw-voice-pick {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.75rem;
  font-size: 0.8125rem;
}
.mw-voice-select {
  font-size: 0.8125rem;
  padding: 0.15rem 0.35rem;
  max-width: 14rem;
}

.mw-voice-original {
  margin-top: 0.35rem;
  font-size: 0.75rem;
  color: var(--ink-faint, #80868b);
  font-style: italic;
}


/* --- Evidence attachments (spec 2026-08-16) -------------------------------
   The inbox button that opens a passenger's uploaded photos, and the lightbox
   itself. Squared ledger treatment, never a pill-with-dot. No inline styles
   anywhere — the CSP forbids style="" outright. */
.mw-evidence-btn {
  display: inline-flex; align-items: center; gap: 0.35rem;
  font-size: 0.75rem; letter-spacing: 0.02em;
  color: var(--ink-muted, #5f6368);
  border: 1px solid var(--rule, #dadce0);
  background: var(--surface-sunk, transparent);
  padding: 0.15rem 0.45rem;
  cursor: pointer;
}
.mw-evidence-btn:hover { color: var(--brand); border-color: var(--brand); }
.mw-evidence-btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }

.mw-evidence-field input[type="file"] {
  font-size: 0.8125rem; color: var(--ink-muted, #5f6368);
  padding: 0.4rem 0;
}

/* Passenger-side evidence PICKER (spec 2026-08-25 patch) — an app-themed
   button + icon, replacing the browser's bare native file input. The input
   stays in the DOM and keeps the passenger's upload working with zero JS
   (a <label for="…"> opens the file picker natively); it is only visually
   hidden. A clip rect, NOT display:none / visibility:hidden — either of
   those drops the control from the tab order and the passenger loses
   keyboard access entirely. */
.mw-evidence-input {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
/* The native control had a visible focus ring; a clipped input silently
   loses it unless the sibling button carries it instead. */
.mw-evidence-input:focus-visible + .mw-evidence-picker {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.mw-evidence-picker {
  /* `.field` (the parent) is `display: grid` (see the GCP outlined-field
     rules above), not flex — `align-self` is a FLEX property and does
     nothing here, which is why this control used to stretch the full grid
     column and centre its own label via `.btn`'s `justify-content: center`,
     out of step with the left-aligned label/hint around it. `justify-self`
     is the grid equivalent. Do not re-add `align-self` here. */
  justify-self: start;
  margin-top: 0.35rem;
}
.mw-evidence-picked {
  margin-inline-start: 0.5rem;
}

.mw-evidence-modal {
  position: fixed; inset: 0; z-index: 90;
  display: flex; align-items: center; justify-content: center;
  background: rgb(0 0 0 / 0.72);
  padding: 1.5rem;
}
.mw-evidence-modal[hidden] { display: none; }
.mw-evidence-shell {
  display: flex; flex-direction: column; gap: 0.5rem;
  max-width: min(96vw, 1100px); max-height: 92vh;
}
.mw-evidence-bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; color: #fff;
}
.mw-evidence-close,
.mw-evidence-nav {
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid rgb(255 255 255 / 0.35);
  background: rgb(0 0 0 / 0.35);
  color: #fff; cursor: pointer;
  padding: 0.4rem;
}
.mw-evidence-close:hover,
.mw-evidence-nav:hover { background: rgb(255 255 255 / 0.18); }
.mw-evidence-close:focus-visible,
.mw-evidence-nav:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.mw-evidence-nav[hidden] { display: none; }

.mw-evidence-figure {
  display: flex; align-items: center; gap: 0.75rem;
  margin: 0; min-height: 0;
}
.mw-evidence-figure img {
  max-width: 100%; max-height: 78vh;
  object-fit: contain;
  background: rgb(255 255 255 / 0.06);
}
.mw-evidence-figure img[hidden] { display: none; }
.mw-evidence-gone {
  color: #fff; font-size: 0.875rem; font-style: italic;
  padding: 3rem 2rem; text-align: center;
}
.mw-evidence-count {
  color: rgb(255 255 255 / 0.75);
  font-size: 0.75rem; letter-spacing: 0.08em; text-align: center;
}

/* --- Scenario picker bar (spec 2026-08-16) --------------------------------
   The passenger chooses which scenario they are assessed under. Options the
   facts already rule out stay VISIBLE but disabled, with a squared ledger tag
   saying why — the officer's transcript records the same trail, so hiding
   them here would tell the passenger a different story than the record. */
/* ── Scenario confirmation (the yes/no that precedes the bar) ─────────── */
.mw-confirm-card {
  display: flex; flex-direction: column; gap: 0.35rem;
  padding: 1rem 1.1rem;
  border: 1px solid var(--brand); border-radius: 8px;
  background: var(--brand-tint);
}
.mw-confirm-eyebrow {
  font: 500 0.6875rem/1 var(--font-sans);
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--brand);
}
.mw-confirm-name { font-size: 1.0625rem; font-weight: 600; color: var(--ink); }
.mw-confirm-hint { font-size: 0.8125rem; color: var(--ink-muted); line-height: 1.5; }
/* Yes and No get equal width and stack on a phone. Equal weight is the point:
   a wide primary beside a small secondary reads as "press the big one", and
   the whole value of this step is an agent actually reading the name first. */
.mw-confirm-actions {
  display: flex; gap: 0.5rem; margin-top: 0.85rem; flex-wrap: wrap;
}
.mw-confirm-actions > .btn,
.mw-confirm-actions > .btn-go {
  flex: 1 1 12rem; justify-content: center; min-height: 46px;
}
.mw-confirm-note {
  margin-top: 0.6rem; font-size: 0.8125rem; color: var(--ink-faint);
}

.mw-pick-list { display: flex; flex-direction: column; gap: 0.5rem; }
.mw-pick {
  display: block; width: 100%; text-align: start;
  padding: 0.75rem 0.9rem;
  border: 1px solid var(--rule); border-radius: 2px;
  background: var(--surface, transparent);
  font: 500 0.9375rem/1.35 var(--font-sans);
  color: var(--ink); cursor: pointer;
}
.mw-pick:hover:not([disabled]) { border-color: var(--brand); }
.mw-pick[disabled] { cursor: not-allowed; opacity: 0.5; }
.mw-pick-hint {
  display: block; margin-top: 0.25rem;
  font-weight: 400; font-size: 0.8125rem; color: var(--ink-faint);
}
.mw-pick-tag {
  display: inline-block; margin-top: 0.4rem;
  padding: 0.1rem 0.4rem; border: 1px solid var(--rule); border-radius: 0;
  font: 600 0.625rem/1.4 var(--font-sans);
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-faint);
}
.mw-pick-other { margin-top: 0.75rem; }

/* ── Deployment banner (staging only) ─────────────────────────────────────────
   Rendered by templates/_env_banner.html when NIBOMONT_ENV_LABEL is set. Absent
   everywhere else, so prod and dev are unchanged.

   Pinned to the BOTTOM, not the top: the app's topbar is `position: sticky;
   top: 0` and a fixed top strip would either sit under it or need every page's
   layout re-tuned. pointer-events:none so the strip can never swallow a click
   on whatever is beneath it; the body padding below keeps it from covering
   page content at the end of a scroll.

   Deliberately hand-written rather than Tailwind utilities: static/tw.css is a
   prebuilt subset and a class not already in it silently does nothing. */
.env-banner {
  position: fixed;
  /* Bottom-CENTRE, not full width: the app sidebar is position:fixed with its
     own footer (language switcher + Staff sign-in) at the bottom LEFT, which a
     full-width strip sits on top of and which body padding cannot move. A
     centred tag clears it. Squared, not a pill — house style. */
  left: 50%;
  transform: translateX(-50%);
  bottom: 0;
  max-width: min(92vw, 640px);
  z-index: 2147483000;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  min-height: 28px;
  padding: 0.25rem 0.75rem;
  background: repeating-linear-gradient(
    45deg, #7a3d00, #7a3d00 12px, #8f4a00 12px, #8f4a00 24px);
  color: #fff8ef;
  font-family: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.76rem;
  line-height: 1.2;
  letter-spacing: 0.04em;
  text-align: center;
  box-shadow: 0 -1px 0 rgba(0, 0, 0, 0.35);
  pointer-events: none;
}
.env-banner-tag {
  font-weight: 700;
  text-transform: uppercase;
  padding: 0.05rem 0.45rem;
  background: #fff8ef;
  color: #7a3d00;
}
.env-banner-note { opacity: 0.92; }
body:has(.env-banner) { padding-bottom: 32px; }

@media (max-width: 480px) {
  .env-banner-note { display: none; }
}

/* ── Case chat — desk agent ↔ duty officer ───────────────────────────────
   Rendered by both ends: the officer's case page and the interview page
   once the scenario bot hands over. Deliberately quieter than the interview
   bubbles above it — this is a side channel between two staff, not the
   record of the interview itself, and it should not compete with it.
   ------------------------------------------------------------------ */

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

.chat-presence {
  display: inline-flex; align-items: center; gap: .5rem;
  font-size: .6875rem; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-muted);
}
.chat-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--ink-faint); flex: none;
}
.chat-dot.is-live { background: var(--state-pass); }

.chat-thread {
  display: flex; flex-direction: column; gap: .875rem;
  max-height: 26rem; overflow-y: auto;
  padding-inline-end: .25rem;
}

.chat-msg {
  border: 1px solid var(--rule);
  border-radius: 10px;
  padding: .75rem .875rem;
  background: var(--paper);
  max-width: 42rem;
}
/* The reader's own messages sit on the trailing edge and carry the brand
   tint, so a glance separates "what I said" from "what they asked". */
.chat-msg.is-mine {
  margin-inline-start: auto;
  background: var(--state-gov-tint);
  border-color: transparent;
}

.chat-msg-head {
  display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap;
  margin-bottom: .35rem;
  font-size: .75rem;
}
.chat-who { font-weight: 600; color: var(--ink); }
.chat-role {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .625rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--state-gov);
  border: 1px solid currentColor; border-radius: 3px;
  padding: 0 .3rem;
}
.chat-when { color: var(--ink-faint); margin-inline-start: auto; }

.chat-body { margin: 0; line-height: 1.55; color: var(--ink); white-space: pre-wrap; }

/* The translation reads as the message; what was actually typed stays one
   click away, because the record is always the original. */
.chat-original { margin-top: .5rem; }
.chat-original > summary {
  cursor: pointer; font-size: .75rem; color: var(--ink-muted);
}
.chat-original > p {
  margin-top: .375rem; padding-inline-start: .625rem;
  border-inline-start: 2px solid var(--rule);
  color: var(--ink-muted); font-size: .875rem; white-space: pre-wrap;
}

.chat-photos { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .625rem; }
.chat-photos img {
  width: 92px; height: 92px; object-fit: cover;
  border: 1px solid var(--rule); border-radius: 6px; display: block;
}
.chat-photo-gone {
  font-size: .75rem; color: var(--ink-faint); font-style: italic;
}

.chat-divider { margin: .5rem 0; text-align: center; }
.chat-divider-label {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .625rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--state-gov);
  border-top: 1px solid var(--rule);
  padding-top: .5rem;
}
.chat-divider-reason {
  margin-top: .25rem; font-size: .8125rem; color: var(--ink-muted);
}

.chat-composer { margin-top: 1rem; }
.chat-composer textarea {
  width: 100%; resize: vertical; min-height: 3.25rem;
  border: 1px solid var(--rule); border-radius: 8px;
  padding: .625rem .75rem; font: inherit; color: var(--ink);
  background: var(--paper);
}
.chat-composer textarea:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-overlay);
}
.chat-composer-actions {
  display: flex; align-items: center; gap: .75rem; margin-top: .625rem;
  flex-wrap: wrap;
}
.chat-attach {
  display: inline-flex; align-items: center; gap: .5rem;
  font-size: .8125rem; color: var(--ink-muted); cursor: pointer;
}
.chat-attach input[type="file"] { max-width: 13rem; font-size: .75rem; }
.chat-composer-actions .btn-go { margin-inline-start: auto; }

/* The officer-conversation panel on the interview page. Deliberately not
   `.mw-composer` — see the comment in interrogate.html. */
.mw-officer-chat { margin-top: 1.25rem; }

/* Pass-tinted panel. The sheet had gov and deny tints but no pass one, and
   a cleared case needs to read as cleared. Mirrors .mw-gov-tint. */
.mw-pass-tint { border: 1px solid var(--rule); background: var(--state-pass-tint); }

/* Read-only interview recap that heads the officer conversation. Quieter
   than the live transcript: it is context for the exchange below it, not
   the thing being acted on. */
.mw-recap {
  display: flex; flex-direction: column; gap: .625rem;
  max-height: 22rem; overflow-y: auto;
  padding: .875rem; margin-bottom: .875rem;
  border: 1px solid var(--rule); border-radius: 10px;
  background: var(--paper-sunk);
}
.mw-recap .mw-bubble { font-size: .9375rem; }
.mw-recap-seam {
  display: flex; align-items: center; gap: .75rem;
  margin: 0 0 1.25rem; color: var(--ink-faint);
  font-size: .75rem; font-style: italic;
}
.mw-recap-seam::before, .mw-recap-seam::after {
  content: ""; flex: 1; height: 1px; background: var(--rule);
}

/* ── Bundle verifier (/verify-bundle) ─────────────────────────────────────────
   A public page a sceptic reads. The finding is set as a SENTENCE in the serif
   face, because a tick is a UI affordance and a sentence is something a
   recipient can quote in a filing; every machine value beside it is mono, the
   same human-voice/machine-voice split the printed pack uses. Rules live here
   rather than inline because style-src is 'self'. */
.verify-finding {
  font-family: 'IBM Plex Serif', Georgia, serif;
  font-size: 1.0625rem;
  line-height: 1.55;
  color: var(--ink);
}
.mono-val {
  font-family: var(--font-mono);
  font-size: .8125rem;
  word-break: break-all;
  color: var(--ink-body);
}
.verify-facts {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: .35rem 1.25rem;
  margin: 0;
}
.verify-facts dt {
  font-size: .75rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.verify-facts dd { margin: 0; }
.verify-files { list-style: none; margin: 0; padding: 0; }
.verify-files li {
  display: flex;
  flex-wrap: wrap;
  gap: .25rem .75rem;
  padding: .35rem 0;
  border-top: 1px solid var(--rule-soft);
  font-size: .8125rem;
}
.verify-paste {
  font-family: var(--font-mono);
  font-size: .75rem;
  min-height: 9rem;
  white-space: pre;
  overflow-x: auto;
}
.verify-paste-short { min-height: 6rem; }
.verify-code {
  font-family: var(--font-mono);
  font-size: .75rem;
  line-height: 1.6;
  padding: 1rem 1.25rem;
  overflow-x: auto;
  background: var(--paper-sunk);
  border: 1px solid var(--rule);
  border-radius: 4px;
  color: var(--ink-body);
}
@media (max-width: 640px) {
  .verify-facts { grid-template-columns: 1fr; gap: 0 0; }
  .verify-facts dd { margin-bottom: .5rem; }
}


/* ── _desk_cases.html — the desk agent's own recent cases ───────────────────
   Reuses the ledger grid rather than a <table>, like every other case list in
   the app. CSP is `style-src 'self'`, so nothing here may move to an inline
   style attribute — it would be dropped silently. */
.mw-cols-desk { grid-template-columns: 7rem minmax(0,2fr) 7rem minmax(0,1fr); column-gap: 1.25rem; }

.desk-cases-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  flex-wrap: wrap;
}
.desk-cases-sub { margin-bottom: 1rem; }
.desk-cases-limit { display: block; color: var(--ink-muted); font-size: .8125rem; margin-top: .25rem; }
.desk-cases-empty { color: var(--ink-muted); padding: 1rem 0; }

.mw-btn-sm { padding: .25rem .625rem; font-size: .8125rem; }

.desk-cell-ref { display: flex; align-items: center; gap: .5rem; }
.desk-case-link { color: var(--accent); font-variant-numeric: tabular-nums; }
.desk-case-link:hover { text-decoration: underline; }

/* The unread dot reuses .inbox-dot's shape; it only needs to sit inline. */
.desk-unread-dot { position: static; }

.desk-cell-name { min-width: 0; overflow-wrap: anywhere; }
.desk-cell-flight { display: block; color: var(--ink-muted); font-size: .8125rem; }
.desk-cell-when { color: var(--ink-muted); font-size: .8125rem; font-variant-numeric: tabular-nums; }
.desk-resume-form { margin-top: .375rem; }

@media (max-width: 720px) {
  /* Below this the four columns stop being readable, so each row becomes a
     stacked card — the treatment the other ledgers get at phone width. The
     header row is already hidden by `mw-hide-sm`. */
  .mw-cols-desk { grid-template-columns: 1fr; row-gap: .25rem; }
  .ledger-row.mw-cols-desk { padding: .75rem 1rem; align-items: start; }
}

/* ── § Evidence-source tags (case ledger /audit/{id}) ─────────────────
   The officer's first question about any fact is "was this CHECKED, or
   did somebody just say it?". The engine has always known — every fact
   carries a provenance tier — but the ledger printed that as faint grey
   prose, so on a long page it was invisible.

   Two channels, deliberately, so neither colour vision nor a monochrome
   printout is load-bearing:
     · BORDER — solid means a register found the record and bound it to
       this passenger. Dashed means nothing did. That is the binary.
     · COLOUR + WORD — which kind of source it was.

   Squared ledger treatment, never a pill-with-dot. Tokens only, so the
   dark theme follows for free; no inline styles (the CSP forbids them). */

.ev {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  vertical-align: middle;
  padding: 0.05rem 0.35rem;
  border: 1px dashed var(--ev-line, var(--rule));
  border-inline-start: 3px solid var(--ev-ink, var(--ink-muted));
  border-radius: 2px;
  background: var(--ev-bg, var(--paper-sunk));
  color: var(--ev-ink, var(--ink-muted));
  font: 600 0.625rem/1.5 var(--font-sans);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* Checked against a register and identity-bound — the only solid border. */
.ev-gov {
  --ev-ink: var(--state-pass);
  --ev-bg: var(--state-pass-tint);
  --ev-line: color-mix(in oklch, var(--state-pass) 45%, var(--rule));
  border-style: solid;
}

/* Same family, confirmation not landed: an Integration-layer source handed
   over an ID number and no register has bound it to this passenger yet.
   Hollow, so it can never be mistaken at a glance for the solid tag above. */
.ev-gov_unconfirmed {
  --ev-ink: var(--state-pass);
  --ev-bg: transparent;
  --ev-line: color-mix(in oklch, var(--state-pass) 45%, var(--rule));
}

.ev-passenger {
  --ev-ink: var(--state-gov);
  --ev-bg: var(--state-gov-tint);
  --ev-line: color-mix(in oklch, var(--state-gov) 45%, var(--rule));
}

.ev-ai {
  --ev-ink: var(--ev-ai);
  --ev-bg: var(--ev-ai-tint);
  --ev-line: color-mix(in oklch, var(--ev-ai) 45%, var(--rule));
}

.ev-app {
  --ev-ink: var(--ink-muted);
  --ev-bg: var(--paper-sunk);
  --ev-line: var(--rule-deep);
}

/* A tier the ledger does not recognise. Renders VISIBLY: a missing tag
   would read as "no claim about the source" when the classification is
   what failed. */
.ev-unknown {
  --ev-ink: var(--state-deny);
  --ev-bg: var(--state-deny-tint);
  --ev-line: color-mix(in oklch, var(--state-deny) 45%, var(--rule));
}

/* The concrete origin under a tag — WHICH register, WHICH endpoint, WHICH
   interview pass. The tag says the category; this says the instance. */
.ev-origin {
  font-size: 0.6875rem;
  color: var(--ink-faint);
}

/* ═══════════════════════════════════════════════════════════════════════
   Case page (/audit/{id}) — the four-tab reorder
   ═══════════════════════════════════════════════════════════════════════

   The page this replaced ran almost entirely at 0.8125rem/1.43 and opened
   with a wrapping row of eight-plus action buttons and forms, so an officer
   could not tell at a glance what the decision rested on or where a fact
   came from. The type scale below IS the redesign: reading matter gets a
   reading measure.

   Tokens only — never a literal hex. The dark theme re-skins every one of
   these variables, and the CSP forbids the inline styles the design
   prototype used. Logical properties throughout (padding-inline,
   border-inline-start) so the Arabic RTL mirror is free.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Header ────────────────────────────────────────────────────────────── */

/* Narrower than .wrap (1240px): this is reading matter, not a table. */
.case-wrap {
  max-width: 1120px;
  margin-inline: auto;
  padding: 2.5rem clamp(1.25rem, 4vw, 2.5rem) 4rem;
}
.case-head-wrap {
  max-width: 1120px;
  margin-inline: auto;
  padding: 1.75rem clamp(1.25rem, 4vw, 2.5rem) 0;
}

.case-crumbs {
  display: flex; align-items: center; gap: 0.35rem;
  font-size: 0.8125rem; color: var(--ink-faint); margin-bottom: 0.75rem;
}
.case-crumbs a { color: var(--ink-muted); text-decoration: none; }
.case-crumbs a:hover { color: var(--accent); text-decoration: underline; }

.case-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 1.5rem; flex-wrap: wrap;
}
.case-title {
  font-weight: 400; font-size: 2rem; line-height: 1.25;
  letter-spacing: -0.01em; color: var(--ink); margin: 0;
}
.case-title-row {
  display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap;
}

/* Status as a filled chip, not a bare state word — the one place on this
   page where the verdict is allowed to raise its voice. */
.case-status {
  display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.3rem 0.6rem; border-radius: 4px;
  font: 600 0.875rem/1.2 var(--font-sans);
  background: var(--case-state-tint, var(--paper-sunk));
  color: var(--case-state, var(--ink-muted));
  white-space: nowrap;
}
.case-status::before {
  content: ""; width: 6px; height: 6px; flex: none;
  background: currentColor;
}
.case-status-pass { --case-state: var(--state-pass); --case-state-tint: var(--state-pass-tint); }
.case-status-deny { --case-state: var(--state-deny); --case-state-tint: var(--state-deny-tint); }
.case-status-gov  { --case-state: var(--state-gov);  --case-state-tint: var(--state-gov-tint); }
.case-status-pend { --case-state: var(--ink-muted);  --case-state-tint: var(--paper-sunk); }

.case-subtitle {
  margin: 0.75rem 0 0; max-width: 62ch;
  font-size: 0.9375rem; line-height: 1.7; color: var(--ink-body);
}

.case-head-actions { display: flex; align-items: center; gap: 0.5rem; }

/* ── The ⋮ overflow menu ───────────────────────────────────────────────── */

.case-menu { position: relative; }
.case-menu-btn {
  appearance: none; background: none; border: 1px solid transparent;
  width: 36px; height: 36px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--ink-muted); cursor: pointer;
  transition: background var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard);
}
.case-menu-btn:hover,
.case-menu-btn[aria-expanded="true"] { background: var(--hover); color: var(--ink); }

.case-menu-panel {
  position: absolute; inset-inline-end: 0; top: 42px; z-index: 40;
  width: 22rem; max-width: calc(100vw - 2rem);
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: 8px; box-shadow: var(--elev-3);
  padding: 0.4rem 0;
}
.case-menu-panel[hidden] { display: none; }
.case-menu-label {
  padding: 0.5rem 1rem 0.25rem;
  font: 500 0.6875rem/1.4 var(--font-sans);
  letter-spacing: 0.09em; text-transform: uppercase; color: var(--ink-faint);
}
.case-menu-sep { height: 1px; background: var(--rule); margin: 0.35rem 0; }
.case-menu-item {
  appearance: none; background: none; border: none; width: 100%;
  display: flex; align-items: center; gap: 0.75rem; text-align: start;
  padding: 0.6rem 1rem; cursor: pointer;
  font: 400 0.875rem/1.4 var(--font-sans); color: var(--ink-body);
  text-decoration: none;
  transition: background var(--dur-fast) var(--ease-standard);
}
.case-menu-item:hover { background: var(--hover); }
.case-menu-item .ico-sm { color: var(--ink-muted); flex: none; }
.case-menu-item-deny { color: var(--state-deny); }
.case-menu-item-deny:hover { background: var(--state-deny-tint); }
.case-menu-item-deny .ico-sm { color: var(--state-deny); }
.case-menu-foot {
  padding: 0.6rem 1rem 0.4rem; border-top: 1px solid var(--rule);
  margin-top: 0.35rem;
  font-size: 0.75rem; line-height: 1.5; color: var(--ink-faint);
}

/* ── Tab bar ───────────────────────────────────────────────────────────── */
/* The same GCP underlined switcher as .iam-tabs, one step larger because
   this is the page's primary navigation rather than a panel filter. A
   separate class, not a change to .iam-tab: that one is shared with the IAM
   and rules pages (see `.iam-tab.is-active .rules-tab-count`). */

.case-tabs {
  display: flex; gap: 0.25rem; flex-wrap: wrap;
  border-bottom: 1px solid var(--rule);
  margin-top: 1.5rem;
}
.case-tab {
  appearance: none; background: none;
  border-top: 0; border-inline: 0;
  /* Longhands, not the `border-bottom: 2px solid transparent` shorthand —
     the shorthand re-sets all three every time one of them is overridden. */
  border-bottom-width: 2px;
  border-bottom-style: solid;
  border-bottom-color: transparent;
  margin-bottom: -1px;
  font: 500 0.9375rem/1.4 var(--font-sans); letter-spacing: 0.15px;
  color: var(--ink-muted); padding: 0.85rem 1.1rem;
  cursor: pointer; text-decoration: none; white-space: nowrap;
  transition: color var(--dur-fast) var(--ease-standard),
              border-bottom-color var(--dur-fast) var(--ease-standard);
}
.case-tab:hover { color: var(--ink); background: var(--hover); }
.case-tab.is-active { color: var(--accent); border-bottom-color: var(--accent); }

/* ── Panel scaffolding ─────────────────────────────────────────────────── */

.case-panel { display: grid; gap: 2.5rem; }
.case-h2 {
  font: 500 1.125rem/1.4 var(--font-sans); color: var(--ink);
  margin: 0 0 0.5rem;
}
.case-lede {
  margin: 0 0 1.25rem; max-width: 68ch;
  font-size: 0.9375rem; line-height: 1.7; color: var(--ink-muted);
}
.case-eyebrow {
  font: 500 0.6875rem/1.4 var(--font-sans);
  letter-spacing: 0.09em; text-transform: uppercase; color: var(--ink-faint);
}
.case-prose {
  font-size: 0.9375rem; line-height: 1.7; color: var(--ink-body);
  max-width: 68ch; text-wrap: pretty;
}

/* Cards are ruled, never shadowed — "the desk doesn't shadow its documents;
   it rules them". Elevation is reserved for the overflow menu. */
.case-card {
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: 8px; padding: 1.25rem 1.5rem;
}
.case-card-feature { padding: 1.5rem 1.75rem; }
.case-card-flush { padding: 0; overflow: hidden; }
.case-card-foot {
  background: var(--paper-warm); border-top: 1px solid var(--rule);
  padding: 0.85rem 1.5rem;
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap;
  font-size: 0.8125rem; color: var(--ink-muted);
}

/* ── 1a. Evidence strength band ────────────────────────────────────────── */

.case-strength-head {
  display: flex; align-items: baseline; gap: 0.6rem;
  flex-wrap: wrap; margin: 0.4rem 0 1rem;
}
.case-strength-figure {
  font: 400 2.25rem/1 var(--font-sans); letter-spacing: -0.02em;
  color: var(--ink); font-feature-settings: 'tnum';
}
.case-strength-of { font-size: 1.0625rem; color: var(--ink-body); }

.case-tierbar {
  display: flex; gap: 3px; height: 10px; margin-bottom: 0.75rem;
}
.case-tierbar-seg { border-radius: 2px; min-width: 6px; }

/* Segment width is proportional to that tier's row count. Enumerated
   classes rather than an inline `flex` — the CSP forbids inline styles, and
   `style="--n:3"` is still a style attribute. Twelve is well past the
   requirement count any real scenario carries; the template clamps to it,
   so a 40-row scenario renders a slightly flattened bar rather than a
   segment with no width at all. */
.case-flex-1  { flex: 1; }
.case-flex-2  { flex: 2; }
.case-flex-3  { flex: 3; }
.case-flex-4  { flex: 4; }
.case-flex-5  { flex: 5; }
.case-flex-6  { flex: 6; }
.case-flex-7  { flex: 7; }
.case-flex-8  { flex: 8; }
.case-flex-9  { flex: 9; }
.case-flex-10 { flex: 10; }
.case-flex-11 { flex: 11; }
.case-flex-12 { flex: 12; }

/* Visually hidden, still read aloud. The stylesheet has three private
   copies of this rule already (.sc-prog-live, .chat-hidden, …); this is the
   case page's, named so it is obvious which page owns it. */
.case-sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* One class per tier, shared by the bar segment and the legend swatch.
   Deliberately NOT the `.ev-*` classes: those are the TAG treatment
   (border, uppercase word) and a bare colour block is not a tag. */
.case-tier-gov             { background: var(--state-pass); }
.case-tier-gov_unconfirmed {
  background: var(--state-pass-tint);
  border: 1px solid color-mix(in oklch, var(--state-pass) 45%, var(--rule));
}
.case-tier-passenger { background: var(--state-gov); }
.case-tier-ai        { background: var(--ev-ai); }
.case-tier-app       { background: var(--ink-muted); }
.case-tier-unknown   { background: var(--state-deny); }
.case-tier-absent    { background: var(--rule); }

.case-legend {
  display: flex; flex-wrap: wrap; gap: 0.35rem 1.1rem;
  font-size: 0.8125rem; color: var(--ink-muted); margin-bottom: 1rem;
}
.case-legend-item { display: inline-flex; align-items: center; gap: 0.4rem; }
.case-legend-dot { width: 10px; height: 10px; border-radius: 2px; flex: none; }

/* ── 1b. The verdict, and why ──────────────────────────────────────────── */

.case-verdict-grid { display: grid; gap: 1.25rem; }
@media (min-width: 60rem) {
  .case-verdict-grid { grid-template-columns: 1.35fr 1fr; }
}

.case-rule-card { border-inline-start: 3px solid var(--case-state, var(--rule)); }
.case-rule-id {
  font: 500 1rem/1.4 var(--font-mono); color: var(--ink);
  margin: 0.35rem 0 0.6rem;
}
.case-figures {
  display: flex; flex-wrap: wrap; gap: 1.75rem;
  border-top: 1px solid var(--rule-soft); margin-top: 1.25rem; padding-top: 1rem;
}
.case-figure-label { font-size: 0.75rem; color: var(--ink-faint); }
.case-figure-value {
  font: 400 1.125rem/1.3 var(--font-mono); color: var(--ink);
  font-feature-settings: 'tnum'; margin-top: 0.15rem;
}

.case-status-col { display: grid; gap: 0.75rem; align-content: start; }
.case-status-card { padding: 1rem 1.25rem; }
.case-status-title {
  display: inline-flex; align-items: center; gap: 0.45rem;
  font: 500 0.9375rem/1.4 var(--font-sans); color: var(--case-state, var(--ink));
}
.case-status-title .ico-sm { color: var(--case-state, var(--ink-muted)); }
.case-status-body {
  margin: 0.35rem 0 0; font-size: 0.8125rem; line-height: 1.6;
  color: var(--ink-muted);
}
.case-status-pass-card { --case-state: var(--state-pass); }
.case-status-deny-card {
  --case-state: var(--state-deny);
  background: var(--state-deny-tint);
  border-inline-start: 3px solid var(--state-deny);
}
.case-status-near-card {
  --case-state: var(--state-near);
  background: var(--state-near-tint);
  border-inline-start: 3px solid var(--state-near);
}

/* ── 1c. "Why the case ran this way" — the flow timeline ───────────────── */

.case-flow { display: grid; }
.case-step { display: grid; grid-template-columns: 3.5rem 1fr; padding-bottom: 2rem; }
.case-step:last-child { padding-bottom: 0; }
.case-step-gutter {
  display: flex; flex-direction: column; align-items: center; gap: 0.5rem;
}
.case-step-num {
  width: 28px; height: 28px; border-radius: 50%; flex: none;
  background: var(--case-state, var(--accent)); color: #fff;
  display: inline-flex; align-items: center; justify-content: center;
  font: 500 0.8125rem/1 var(--font-sans); font-feature-settings: 'tnum';
}
.case-step-line { width: 2px; flex: 1 1 auto; background: var(--rule); }
.case-step-title {
  font: 500 1rem/1.4 var(--font-sans); color: var(--ink); margin-bottom: 0.35rem;
}
.case-step-body { padding-bottom: 0.25rem; }

/* One consulted register per row. */
.case-lookups { list-style: none; margin: 0; padding: 0; }
.case-lookup {
  display: grid; gap: 0.15rem 0.9rem; align-items: baseline;
  background: var(--surface); border: 1px solid var(--rule); border-radius: 6px;
  padding: 0.6rem 0.875rem; margin-top: 0.5rem;
  font-size: 0.875rem;
}
@media (min-width: 48rem) {
  .case-lookup { grid-template-columns: 11rem 8rem 1fr; }
}
.case-lookup-src { font-family: var(--font-mono); font-size: 0.8125rem; color: var(--ink); }
.case-lookup-out { font-weight: 500; color: var(--case-state, var(--ink-muted)); }
.case-lookup-why { color: var(--ink-muted); }
.case-out-pass { --case-state: var(--state-pass); }
.case-out-deny { --case-state: var(--state-deny); }
.case-out-near { --case-state: var(--state-near); }
.case-out-mute { --case-state: var(--ink-muted); }

/* One asked question per card, in the three lines the flow narrates. */
.case-ask {
  background: var(--surface); border: 1px solid var(--rule); border-radius: 6px;
  padding: 0.7rem 0.9rem; margin-top: 0.5rem;
}
.case-ask-because { font-size: 0.8125rem; color: var(--ink-faint); }
.case-ask-q { font-size: 0.9375rem; line-height: 1.5; color: var(--ink); margin-top: 0.2rem; }
.case-ask-got { font-size: 0.8125rem; line-height: 1.6; color: var(--ink-muted); margin-top: 0.25rem; }

/* ── 2a. Requirement rows — the provenance format ──────────────────────── */

.case-reqs { display: grid; gap: 0.75rem; list-style: none; margin: 0; padding: 0; }
.case-req {
  background: var(--surface); border: 1px solid var(--rule); border-radius: 8px;
  border-inline-start: 3px solid var(--case-state, var(--rule));
  padding: 1.25rem 1.5rem;
}
.case-req-gov             { --case-state: var(--state-pass); }
.case-req-gov_unconfirmed { --case-state: color-mix(in oklch, var(--state-pass) 45%, var(--rule)); }
.case-req-passenger       { --case-state: var(--state-gov); }
.case-req-ai              { --case-state: var(--ev-ai); }
.case-req-app             { --case-state: var(--ink-muted); }
.case-req-unknown         { --case-state: var(--state-deny); }
.case-req-absent          { --case-state: var(--rule); }

.case-req-head {
  display: flex; align-items: baseline; gap: 0.75rem; flex-wrap: wrap;
}
.case-req-key { font: 400 0.9375rem/1.4 var(--font-mono); color: var(--ink-muted); }
.case-req-val { font: 500 0.9375rem/1.4 var(--font-mono); color: var(--ink); }
.case-req-absent-val { font-size: 0.9375rem; color: var(--ink-faint); font-style: italic; }

/* The definition list that IS the provenance format. */
.case-dl {
  display: grid; gap: 0.5rem 1.25rem; margin: 0.9rem 0 0;
  font-size: 0.9375rem; line-height: 1.7;
}
@media (min-width: 48rem) {
  .case-dl { grid-template-columns: 11rem 1fr; }
}
.case-dl dt {
  font-size: 0.8125rem; letter-spacing: 0.3px; color: var(--ink-faint);
  line-height: 1.7;
}
.case-dl dd { margin: 0; color: var(--ink-body); }
@media (max-width: 47.99rem) {
  .case-dl dd { margin-bottom: 0.35rem; }
}

/* The model's own words, never presented as the file's. */
.case-quote {
  background: var(--ev-ai-tint); border-radius: 4px;
  padding: 0.5rem 0.75rem; max-width: 56ch;
  font-size: 0.9375rem; line-height: 1.6; color: var(--ink-body);
}

/* ── 2b. Tag legend ────────────────────────────────────────────────────── */

.case-taglegend {
  background: var(--paper-sunk); border: 1px solid var(--rule);
  border-radius: 8px; padding: 1.25rem 1.5rem; margin-top: 1.25rem;
}
.case-taglegend-grid { display: grid; gap: 0.6rem 1.25rem; margin-top: 0.75rem; }
@media (min-width: 48rem) {
  .case-taglegend-grid { grid-template-columns: 12rem 1fr; }
}
.case-taglegend-def { font-size: 0.875rem; line-height: 1.6; color: var(--ink-muted); }

/* ── 2c. Comparison table ──────────────────────────────────────────────── */

.case-table { width: 100%; border-collapse: collapse; font-size: 0.9375rem; }
.case-table th {
  text-align: start; padding: 0.9rem 1.25rem;
  border-bottom: 1px solid var(--rule);
  font: 500 0.8125rem/1.4 var(--font-sans); letter-spacing: 0.3px;
  color: var(--ink-faint); white-space: nowrap;
}
.case-table td {
  padding: 0.9rem 1.25rem; border-bottom: 1px solid var(--rule-soft);
  vertical-align: top; color: var(--ink-body);
}
.case-table tr:last-child td { border-bottom: 0; }
.case-table-scroll { overflow-x: auto; }
.case-table-min { min-width: 44rem; }

/* ── 3. Passenger's story ──────────────────────────────────────────────── */

.case-turns { display: grid; gap: 1rem; }
.case-turn-head { display: flex; align-items: baseline; gap: 0.75rem; flex-wrap: wrap; }
.case-turn-n {
  font: 400 0.8125rem/1.5 var(--font-mono); color: var(--ink-faint); flex: none;
}
.case-turn-q { font: 500 1.0625rem/1.5 var(--font-sans); color: var(--ink); }
.case-turn-because {
  font-size: 0.8125rem; color: var(--ink-faint);
  margin: 0.35rem 0 0; padding-inline-start: 2.5rem;
}
.case-answer {
  margin: 0.75rem 0 0 2.5rem; padding-inline-start: 1rem;
  border-inline-start: 3px solid var(--rule-deep);
  font-size: 1rem; line-height: 1.75; max-width: 62ch; color: var(--ink-body);
}
.case-turn-aside { margin: 0.75rem 0 0; padding-inline-start: 2.5rem; }
.case-fills {
  background: var(--paper-warm); border: 1px solid var(--rule-soft);
  border-radius: 6px; padding: 0.9rem 1.1rem;
}
.case-fill { display: grid; gap: 0.3rem; }
.case-fill + .case-fill {
  margin-top: 0.75rem; border-top: 1px solid var(--rule-soft); padding-top: 0.75rem;
}
.case-fill-head { display: flex; align-items: baseline; gap: 0.6rem; flex-wrap: wrap; }
.case-fill-how { font-size: 0.875rem; line-height: 1.6; color: var(--ink-muted); }
.case-known {
  display: grid; gap: 0.5rem 1.25rem; margin-top: 0.75rem; font-size: 0.9375rem;
}
@media (min-width: 48rem) {
  .case-known { grid-template-columns: 12rem 1fr; }
}
.case-divider { border-top: 1px solid var(--rule-soft); margin-top: 0.9rem; padding-top: 0.75rem; }

/* ── 4. Chain & rules ──────────────────────────────────────────────────── */

.case-fire {
  background: var(--surface); border: 1px solid var(--rule); border-radius: 8px;
  border-inline-start: 3px solid var(--case-state, var(--rule));
  padding: 1.1rem 1.4rem;
}
.case-fire-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap;
}
.case-fire-name { font: 500 1rem/1.4 var(--font-sans); color: var(--ink); }
.case-fire-meta {
  font: 400 0.8125rem/1.5 var(--font-mono); color: var(--ink-muted); margin-top: 0.2rem;
}

/* One event per compact row: a human sentence, then the hash line. The old
   page spent ~300px of vertical space per event on two hash chips and an
   open payload block. */
.case-event {
  background: var(--surface); border: 1px solid var(--rule); border-radius: 6px;
  padding: 0.8rem 1.1rem;
}
.case-event + .case-event { margin-top: 0.5rem; }
.case-event-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap;
}
.case-event-what { font-size: 0.9375rem; line-height: 1.5; color: var(--ink); }
.case-event-detail { color: var(--ink-muted); }
.case-event-when {
  font: 400 0.75rem/1.5 var(--font-mono); color: var(--ink-faint); white-space: nowrap;
}
.case-event-hashes {
  display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;
  margin-top: 0.55rem;
}
.case-event-hashes .ico-sm { color: var(--rule-deep); }
.case-payload {
  margin-top: 0.6rem;
  font: 400 0.7rem/1.6 var(--font-mono); color: var(--ink-muted);
  background: var(--paper-sunk); border: 1px solid var(--rule);
  border-radius: 4px; padding: 0.9rem; overflow: auto;
}
.case-more { margin-top: 0.75rem; }

/* ── Shared bits ───────────────────────────────────────────────────────── */

.case-textbtn {
  appearance: none; background: none; border: none; padding: 0.35rem 0.5rem;
  display: inline-flex; align-items: center; gap: 0.4rem;
  font: 500 0.8125rem/1.4 var(--font-sans); color: var(--accent);
  border-radius: 4px; cursor: pointer; text-decoration: none;
  transition: background var(--dur-fast) var(--ease-standard);
}
.case-textbtn:hover { background: var(--accent-overlay); }
.case-inline-link { color: var(--accent); text-decoration: underline; }
.case-note {
  font-size: 0.875rem; line-height: 1.6; color: var(--ink-muted);
  max-width: 68ch; margin-top: 0.6rem;
}
/* The fields the PDPL actions need, laid out inside a menu-opened dialog
   rather than in the page-wide grid the old button row used. */
.case-form { display: grid; gap: 0.75rem; margin-top: 0.9rem; }
@media (min-width: 40rem) {
  .case-form-2 { grid-template-columns: 1fr 1fr; }
}
.case-form-wide { grid-column: 1 / -1; }
.case-dialog-actions {
  display: flex; align-items: center; justify-content: flex-end;
  gap: 0.75rem; margin-top: 1.25rem;
}

@media (prefers-reduced-motion: reduce) {
  .case-tab, .case-menu-item, .case-menu-btn, .case-textbtn { transition: none; }
}
