
    /* === Skin: "After Hours" — museum noir. A lamplit room after closing. === */
    /* Layer 1 — tokens. Every surface/colour traces back here. */
    :root {
      --bg: #15120d;            /* warm near-black — the room beyond the lamp */
      --bg-raised: #1f1b14;     /* cards, history, NPC bubbles — paper in lamplight */
      --bg-raised-2: #2a2418;   /* detective bubble, hover */
      --ink: #ece4d4;           /* primary text — ivory */
      --ink-soft: #b6ab93;      /* secondary */
      --ink-mute: #837a66;      /* tertiary / muted */
      --brass: #cda349;         /* accent — brass lamp */
      --brass-dim: #8c7330;
      --border: #322c20;
      --border-soft: #271f17;
      --cork: #181410;          /* the board surface — felt/blotter base, darker than bg-raised */
      --sticky: #2b2410;        /* player sticky note — warm dark amber, >=3:1 against the board */
      --radius: 10px;
      --font-display: "Playfair Display", "Iowan Old Style", Georgia, serif;
      --font-read: "Newsreader", "Iowan Old Style", Georgia, serif;  /* reading serif: even stroke, legible italic (vs Playfair display hairlines) */
      --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
      --font-mono: "SFMono-Regular", ui-monospace, Menlo, Consolas, monospace;
      --font-oswald: "Oswald", "Arial Narrow", var(--font-body);
      --font-jbmono: "JetBrains Mono", var(--font-mono);
    }
    *, *::before, *::after { box-sizing: border-box; }
    body { font-family: var(--font-body); max-width: 720px; margin: 0 auto; padding: 16px; color: var(--ink); background: var(--bg); }
    /* Layer 2 — atmosphere: brass lamp pooling from the top, dark vignette below. */
    body::before {
      content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
      background:
        radial-gradient(125% 75% at 50% -12%, rgba(205,163,73,0.12), transparent 58%),
        radial-gradient(100% 90% at 50% 118%, rgba(0,0,0,0.55), transparent 72%);
    }
    h1 { font-family: var(--font-display); font-weight: 700; font-size: 22px; letter-spacing: 0.01em; margin: 0 0 2px; color: var(--ink); }
    .subhead { color: var(--ink-soft); margin: 0 0 16px; font-size: 12.5px; font-style: italic; letter-spacing: 0.02em; }
    .cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 12px; margin-top: 8px; }
    .card { background: var(--bg-raised); border: 1px solid var(--border); border-radius: var(--radius); padding: 16px; cursor: pointer; transition: border-color 0.18s, box-shadow 0.18s, transform 0.18s; text-align: left; width: 100%; font-family: inherit; color: var(--ink); }
    .card:hover { border-color: var(--brass); box-shadow: 0 6px 22px rgba(0,0,0,0.45); transform: translateY(-1px); }
    .card-name { font-family: var(--font-display); font-weight: 700; font-size: 17px; margin: 0 0 3px; color: var(--ink); }
    .card-role { font-size: 10.5px; color: var(--brass); margin: 0 0 9px; text-transform: uppercase; letter-spacing: 0.13em; }
    .card-teaser { font-size: 13px; color: var(--ink-soft); line-height: 1.5; margin: 0; }
    .card-momentum { margin-top: 12px; }
    .interview-header { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
    .back-btn { font-size: 12px; padding: 8px 12px; border: 1px solid var(--border); background: transparent; color: var(--ink-soft); cursor: pointer; border-radius: 6px; white-space: nowrap; font-family: inherit; flex-shrink: 0; min-height: 38px; transition: border-color 0.15s, color 0.15s; }
    .back-btn:hover { border-color: var(--brass); color: var(--ink); }
    .portrait-stage { display: flex; justify-content: center; margin: 2px 0 14px; }
    .portrait-bust { height: min(30vh, 220px); width: auto; aspect-ratio: 4 / 5; object-fit: cover; object-position: center top; border: 1px solid var(--border); border-radius: var(--radius); background: #0d0b08; box-shadow: 0 8px 26px rgba(0,0,0,0.55); opacity: 1; transition: opacity 0.35s ease; }
    .portrait-bust[data-state="Pressured"] { border-color: #4a3a16; }
    .portrait-bust[data-state="Cracking"] { border-color: #4d211c; box-shadow: 0 8px 30px rgba(120,30,24,0.35); }
    #history { display: flex; flex-direction: column; gap: 10px; min-height: 170px; max-height: calc(100vh - 470px); overflow-y: auto; padding: 14px; background: rgba(0,0,0,0.18); border: 1px solid var(--border-soft); border-radius: var(--radius); margin-bottom: 12px; }
    .turn { padding: 9px 13px; border-radius: 10px; max-width: 84%; display: flex; flex-direction: column; gap: 3px; }
    .you { align-self: flex-end; background: var(--bg-raised-2); color: var(--ink); border: 1px solid var(--border); border-bottom-right-radius: 3px; }
    .npc { align-self: flex-start; background: var(--bg-raised); color: var(--ink); border-left: 2px solid var(--brass-dim); border-bottom-left-radius: 3px; }
    .turn-label { font-size: 9.5px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--brass); opacity: 0.85; }
    .turn-text { white-space: pre-wrap; word-break: break-word; font-size: 14px; line-height: 1.55; min-height: 1em; }
    .turn-text.typing::after { content: "..."; animation: blink 1.2s steps(3, end) infinite; color: var(--brass); }
    @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.15; } }
    .row { display: flex; gap: 8px; align-items: flex-end; }
    textarea { flex: 1; font-family: inherit; font-size: 14px; padding: 11px 13px; border: 1px solid var(--border); border-radius: 8px; resize: vertical; min-height: 44px; max-height: 120px; line-height: 1.45; background: var(--bg-raised); color: var(--ink); }
    textarea::placeholder { color: var(--ink-mute); }
    textarea:focus { outline: none; border-color: var(--brass); box-shadow: 0 0 0 2px rgba(205,163,73,0.22); }
    button.send { font-size: 14px; font-weight: 600; padding: 10px 20px; border: 1px solid var(--brass); background: var(--brass); color: #1a1306; cursor: pointer; border-radius: 8px; min-height: 44px; white-space: nowrap; font-family: inherit; transition: filter 0.15s; }
    button.send:hover { filter: brightness(1.08); }
    button.send:disabled { opacity: 0.4; cursor: wait; }
    .meta { color: var(--ink-mute); font-size: 10px; margin-top: 8px; font-family: var(--font-mono); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    details { margin-top: 10px; }
    summary { font-family: var(--font-mono); font-size: 11px; color: var(--ink-mute); cursor: pointer; user-select: none; list-style: none; display: flex; align-items: center; gap: 5px; }
    summary::before { content: "▶"; font-size: 9px; transition: transform 0.15s; color: var(--brass-dim); }
    details[open] summary::before { transform: rotate(90deg); }
    summary:hover { color: var(--ink-soft); }
    .cost-grid { display: grid; grid-template-columns: auto 1fr auto 1fr; column-gap: 14px; row-gap: 4px; padding: 9px 11px; background: rgba(0,0,0,0.22); border: 1px solid var(--border-soft); border-radius: 6px; margin-top: 6px; font-family: var(--font-mono); font-size: 11px; }
    .cl { color: var(--ink-mute); white-space: nowrap; }
    .cv { color: var(--ink-soft); font-weight: 500; }
    /* === Notebook → corkboard (2026-06-04). System supplies cards; player supplies the threads. === */
    #notebook-panel { margin-top: 10px; }
    .board-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 8px 0 6px; }
    .nb-add { min-height: 44px; padding: 8px 14px; font-size: 12.5px; font-weight: 600; font-family: var(--font-body); color: #1a1306; background: var(--brass); border: 1px solid var(--brass); border-radius: 7px; cursor: pointer; }
    .nb-add:hover { filter: brightness(1.08); }
    .nb-add:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
    .nb-tip { font-size: 11px; font-style: italic; color: var(--ink-mute); flex: 1 1 160px; }
    /* The board surface — felt/blotter via layered gradients, never a flat fill. */
    .corkboard { position: relative; display: flex; flex-wrap: wrap; gap: 10px; padding: 14px; min-height: 120px; max-height: 360px; overflow-y: auto; border: 1px solid var(--border-soft); border-radius: 8px;
      background:
        radial-gradient(120% 80% at 30% 0%, rgba(205,163,73,0.05), transparent 60%),
        repeating-linear-gradient(135deg, rgba(0,0,0,0.16) 0 2px, rgba(0,0,0,0.10) 2px 4px),
        var(--cork); }
    .board-card { position: relative; flex: 1 1 150px; min-width: 150px; max-width: 230px; display: flex; flex-direction: column; gap: 6px; padding: 12px 11px 9px; background: var(--bg-raised); border: 1px solid var(--border); border-top: 3px solid var(--brass-dim); border-radius: 4px; box-shadow: 0 3px 10px rgba(0,0,0,0.45); }
    /* A pin tack at the top; a subtle deterministic tilt by position (static layout, not animation). */
    .board-card::before { content: ""; position: absolute; top: -5px; left: 50%; width: 9px; height: 9px; margin-left: -4.5px; border-radius: 50%; background: radial-gradient(circle at 35% 30%, #e6c876, var(--brass-dim)); box-shadow: 0 1px 2px rgba(0,0,0,0.6); }
    .board-card:nth-child(3n) { transform: rotate(-1.1deg); }
    .board-card:nth-child(3n+1) { transform: rotate(0.8deg); }
    .board-card.connecting { border-color: var(--brass); box-shadow: 0 0 0 2px var(--brass), 0 3px 10px rgba(0,0,0,0.5); }
    .kind-crack { border-top-color: #4f9d68; }
    .kind-note { border-top-color: var(--brass); }
    .kind-sticky { background: var(--sticky); border-top-color: var(--brass-dim); }
    .kind-case { border-top-color: var(--brass); border-top-width: 4px; }
    .kind-suspect { border-top-color: var(--ink-soft); }
    .kind-lead { border-top-color: var(--brass-dim); }
    .bc-tag { font-family: var(--font-mono); font-size: 8.5px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--brass); }
    .bc-tag-crack { color: #74d18d; }
    .bc-tag-suspect { color: var(--ink-soft); }
    .bc-tag-lead { color: var(--ink-mute); }
    .bc-thumb { width: 100%; height: 62px; object-fit: cover; object-position: center 22%; border-radius: 3px; border: 1px solid var(--border); }
    .kind-case .bc-body { font-family: var(--font-display); font-size: 15px; color: var(--ink); }
    .bc-body { margin: 0; font-size: 12.5px; line-height: 1.45; color: var(--ink-soft); word-break: break-word; }
    .bc-sticky-text { width: 100%; font-family: var(--font-body); font-size: 12.5px; line-height: 1.4; color: var(--ink); background: rgba(0,0,0,0.18); border: 1px solid var(--border-soft); border-radius: 4px; padding: 6px 7px; resize: vertical; min-height: 44px; }
    .bc-sticky-text:focus { outline: none; border-color: var(--brass); box-shadow: 0 0 0 2px rgba(205,163,73,0.22); }
    /* Read-only note preview on the card (tap opens the fullscreen editor). pointer-events:none so the
       tap/drag lands on the tile uniformly; text clamps to a few lines. */
    .bc-sticky-preview { width: 100%; font-family: var(--font-body); font-size: 12.5px; line-height: 1.4; color: var(--ink); background: rgba(0,0,0,0.18); border: 1px solid var(--border-soft); border-radius: 4px; padding: 6px 7px; min-height: 44px; max-height: 84px; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; white-space: pre-wrap; word-break: break-word; pointer-events: none; }
    .bc-sticky-preview.is-empty { color: var(--ink-soft); opacity: 0.75; font-style: italic; }
    .bc-actions { display: flex; gap: 6px; flex-wrap: wrap; }
    .bc-connect, .bc-del { min-height: 32px; padding: 4px 10px; font-size: 10.5px; font-weight: 600; font-family: var(--font-body); border-radius: 5px; cursor: pointer; }
    .bc-connect { color: var(--ink-soft); background: transparent; border: 1px solid var(--border); }
    .bc-connect:hover { border-color: var(--brass-dim); color: var(--ink); }
    .bc-connect[aria-pressed="true"] { border-color: var(--brass); color: var(--brass); }
    .bc-del { color: var(--ink-mute); background: transparent; border: 1px solid var(--border); }
    .bc-del:hover { border-color: #56221d; color: #f08a7c; }
    .bc-connect:focus-visible, .bc-del:focus-visible, .nb-conn-del:focus-visible { outline: 2px solid var(--brass); outline-offset: 2px; }
    .nb-conn-wrap { margin-top: 10px; }
    .nb-conn-label { font-family: var(--font-mono); font-size: 9.5px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-mute); margin: 0 0 5px; }
    .connection-list { display: flex; flex-direction: column; gap: 5px; }
    .nb-conn { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--ink-soft); }
    .nb-conn span { flex: 1; }
    .nb-conn span::before { content: "✦ "; color: var(--brass); }
    .nb-conn-del { min-width: 28px; min-height: 28px; border: none; background: transparent; color: var(--ink-mute); font-size: 15px; cursor: pointer; line-height: 1; }
    .nb-conn-del:hover { color: #f08a7c; }
    .nb-empty { color: var(--ink-mute); font-size: 11px; font-style: italic; }
    /* === Board Layer B: pannable/zoomable canvas + red yarn threads (positions persist as 0-1 fractions). === */
    /* #corkboard = fixed viewport; #cork-canvas = the larger board, translated + scaled inside it. */
    .corkboard.is-free { display: block; position: relative; height: clamp(360px, 56vh, 560px); max-height: none; overflow: hidden; padding: 0; touch-action: none; }
    .corkboard.is-free .cork-canvas { position: absolute; top: 0; left: 0; width: 1040px; height: 2200px; transform-origin: 0 0; will-change: transform; }
    .corkboard.is-free .nb-empty { position: absolute; top: 28px; left: 20px; width: 280px; text-align: left; }
    /* Zoom controls — fixed in the viewport corner, above the threads, never transformed. */
    .cork-zoom { position: absolute; right: 10px; bottom: 10px; z-index: 80; display: flex; flex-direction: column; gap: 6px; }
    .cork-zoom button { width: 40px; height: 40px; border-radius: 8px; border: 1px solid #6b5d3f; background: rgba(22,18,11,0.9); color: var(--brass); font-size: 19px; line-height: 1; cursor: pointer; display: flex; align-items: center; justify-content: center; }
    .cork-zoom button:hover { border-color: var(--brass); background: #1c1810; }
    .cork-zoom button:focus-visible { outline: 2px solid var(--brass); outline-offset: 2px; }
    .corkboard.is-free .board-card { position: absolute; flex: none; width: clamp(132px, 40vw, 158px); min-width: 0; max-width: none; z-index: 1; touch-action: none; cursor: grab; }
    .corkboard.is-free .board-card.dragging { z-index: 60; box-shadow: 0 12px 30px rgba(0,0,0,0.6); cursor: grabbing; }
    /* Grip dots (top-right) so it's clear the card can be dragged. */
    .corkboard.is-free .board-card::after { content: ""; position: absolute; top: 6px; right: 6px; width: 13px; height: 9px; background: radial-gradient(circle, rgba(58,47,18,0.55) 1px, transparent 1.4px) 0 0 / 4.5px 4.5px; pointer-events: none; }
    /* The pin (brass tack) IS the connect control: tap/Enter arms it, drag pulls a thread. It replaces
       the old CSS ::before pin, with a larger invisible touch target around the tack. */
    .corkboard.is-free .board-card::before { display: none; }
    .corkboard.is-free .board-card .bc-pin { position: absolute; top: -14px; left: 50%; transform: translateX(-50%); z-index: 3; width: 52px; height: 34px; padding: 0; border: none; background: transparent; cursor: crosshair; display: flex; justify-content: center; align-items: flex-start; }
    .corkboard.is-free .board-card .bc-pin::before { content: ""; width: 14px; height: 14px; border-radius: 50%; background: radial-gradient(circle at 35% 30%, #d8d2c4, #2b2620); border: 1px solid #4a4338; box-shadow: 0 2px 3px rgba(0,0,0,0.6); }
    .corkboard.is-free .board-card .bc-pin:hover::before { box-shadow: 0 0 0 3px rgba(205,163,73,0.45), 0 2px 3px rgba(0,0,0,0.6); }
    .corkboard.is-free .board-card .bc-pin.connecting::before, .corkboard.is-free .board-card .bc-pin[aria-pressed="true"]::before { box-shadow: 0 0 0 3px var(--brass), 0 2px 3px rgba(0,0,0,0.6); }
    .corkboard.is-free .board-card .bc-pin:focus-visible { outline: 2px solid var(--brass); outline-offset: 2px; border-radius: 8px; }
    /* The textarea + action buttons keep normal touch behaviour so editing/tapping isn't hijacked by drag. */
    .corkboard.is-free .bc-sticky-text, .corkboard.is-free .bc-actions { touch-action: auto; }
    /* Threads render IN FRONT of the cards (real red string over the board); they anchor at the pins. */
    #board-threads { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 70; pointer-events: none; overflow: visible; }
    #board-threads .yarn { fill: none; stroke: #b5483a; stroke-width: 2.5; stroke-linecap: round; filter: drop-shadow(0 1px 1px rgba(0,0,0,0.5)); }
    #board-threads .yarn-tack { fill: #d8c7a0; stroke: #4a3a16; stroke-width: 0.6; }
    #board-threads .yarn-preview { stroke-dasharray: 6 5; opacity: 0.85; }
    /* A wide, invisible hit-line over each thread so it can be tapped to cut it (base SVG is pointer-events:none). */
    #board-threads .yarn-hit { fill: none; stroke: transparent; stroke-width: 34; stroke-linecap: round; pointer-events: stroke; cursor: pointer; }
    /* Two-step cut: tapping a thread shows this X badge at its midpoint; tapping the X confirms. */
    #board-threads .yarn-cut { pointer-events: auto; cursor: pointer; }
    #board-threads .yarn-cut-bg { fill: #2a1512; stroke: #b5483a; stroke-width: 1.5; filter: drop-shadow(0 2px 4px rgba(0,0,0,0.6)); }
    #board-threads .yarn-cut-x { stroke: #ecd9a0; stroke-width: 2.4; stroke-linecap: round; }
    /* Delete is now a trash icon, not text. */
    .corkboard.is-free .bc-del { padding: 6px 9px; }
    .corkboard.is-free .bc-del svg { display: block; width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
    /* === Evidence inventory (2026-06-04) — lighting, not locking. No padlocks anywhere. === */
    #evidence-panel { margin-top: 10px; }
    .ev-hint { color: var(--ink-mute); font-size: 11px; font-style: italic; margin: 4px 0 9px; }
    /* In hand — a graphical icon grid (the inventory feel). */
    .ev-inhand { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 8px; }
    .ev-inhand .ev-empty { grid-column: 1 / -1; }
    .ev-tile { display: flex; flex-direction: column; align-items: center; gap: 6px; text-align: center; min-height: 96px; padding: 11px 8px; background: var(--bg-raised); border: 1px solid var(--border); border-top: 2px solid var(--brass-dim); border-radius: 8px; cursor: pointer; font-family: var(--font-body); color: var(--ink); box-shadow: 0 2px 8px rgba(0,0,0,0.4); transition: border-color 0.15s, box-shadow 0.15s, transform 0.15s; }
    .ev-tile:hover { border-color: var(--brass-dim); }
    .ev-tile:focus-visible { outline: 2px solid var(--brass); outline-offset: 2px; }
    .ev-glyph { width: 28px; height: 28px; color: var(--brass); flex-shrink: 0; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
    .ev-tile-title { font-size: 11px; line-height: 1.3; color: var(--ink-soft); }
    .ev-tile[data-presented="1"] { border-color: var(--brass); background: rgba(205,163,73,0.10); box-shadow: 0 8px 24px rgba(0,0,0,0.5); transform: translateY(-2px); }
    .ev-tile[data-presented="1"] .ev-tile-title::after { content: " ✓"; color: var(--brass); font-weight: 700; }
    .ev-empty { color: var(--ink-mute); font-size: 11px; font-style: italic; }
    .ev-retry { width: 100%; min-height: 44px; background: transparent; border: 1px dashed var(--brass-dim); border-radius: 8px; color: var(--ink-soft); font-family: var(--font-body); font-size: 12px; cursor: pointer; }
    /* Leads — heard of, not in hand. Faintness via dashed border + outline icon, NEVER low-contrast text. */
    .ev-leads-wrap { margin-top: 10px; }
    .ev-leads { display: flex; flex-direction: column; gap: 7px; margin-top: 4px; }
    .ev-lead { display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 7px 10px; background: var(--bg); border: 1px dashed var(--brass-dim); border-radius: 7px; }
    .ev-lead-icon { width: 22px; height: 22px; color: var(--ink-soft); filter: saturate(0.6); flex-shrink: 0; }
    .ev-lead-title { flex: 1; font-size: 12.5px; color: var(--ink-soft); }
    .ev-lead-note { font-size: 10.5px; font-style: italic; color: var(--ink-mute); }
    .ev-obtain { min-height: 36px; padding: 6px 12px; font-size: 11.5px; font-weight: 600; font-family: var(--font-body); color: var(--ink); background: var(--bg-raised-2); border: 1px solid var(--border); border-radius: 6px; cursor: pointer; white-space: nowrap; flex-shrink: 0; }
    .ev-obtain:hover { border-color: var(--brass-dim); }
    .ev-obtain:focus-visible { outline: 2px solid var(--brass); outline-offset: 2px; }
    .ev-obtain.ev-pending { opacity: 0.7; cursor: wait; }
    .ev-obtain.ev-obtain-failed { border-color: #56221d; color: #f08a7c; }
    /* Obtain reveal — the lamp swings onto a clue. GPU-only; armed via .ev-revealed after render (gotcha #60). */
    .ev-tile.ev-revealed { animation: ev-reveal 0.5s cubic-bezier(0.4,0,0.2,1) both; }
    @keyframes ev-reveal { from { opacity: 0; transform: translateY(6px) scale(0.96); } to { opacity: 1; transform: none; } }
    /* Presenting tray — chips above the input show what's about to be handed over. */
    .ev-tray { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin: 8px 0 2px; }
    .ev-tray-label { font-size: 11px; color: var(--ink-mute); font-style: italic; }
    .tray-chip { display: inline-flex; align-items: center; gap: 6px; font-size: 11.5px; padding: 4px 6px 4px 9px; background: rgba(205,163,73,0.12); border: 1px solid var(--brass-dim); border-radius: 12px; color: var(--ink); }
    .tray-chip button { min-width: 28px; min-height: 28px; line-height: 1; border: none; background: transparent; color: var(--brass); font-size: 15px; cursor: pointer; padding: 0; }
    /* Undo toast (sticky delete) — inline, top-right, never a modal. */
    #toast-root { position: fixed; top: 14px; right: 14px; z-index: 60; display: flex; flex-direction: column; gap: 8px; }
    .toast { display: flex; align-items: center; gap: 12px; background: var(--bg-raised); border: 1px solid var(--brass-dim); border-radius: 8px; padding: 10px 14px; font-size: 12.5px; color: var(--ink); box-shadow: 0 8px 24px rgba(0,0,0,0.5); }
    .toast-undo { background: none; border: none; color: var(--brass); font-weight: 700; font-size: 12.5px; cursor: pointer; min-height: 28px; }
    .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
    .skip-link { position: absolute; left: 8px; top: -44px; z-index: 100; background: var(--brass); color: #1a1306; padding: 9px 14px; border-radius: 8px; font-weight: 700; font-size: 13px; text-decoration: none; transition: top 0.15s; }
    .skip-link:focus { top: 8px; outline: 2px solid var(--ink); }
    .turn-presented { font-style: italic; }
    html[data-reduce="1"] .ev-tile, html[data-reduce="1"] .ev-obtain, html[data-reduce="1"] .tray-chip, html[data-reduce="1"] .board-card { transition: none; }
    html[data-reduce="1"] .ev-tile.ev-revealed { animation: none; }
    html[data-reduce="1"] .board-card { transform: none; }
    .momentum-pill { display: inline-block; font-size: 9.5px; font-weight: 700; padding: 3px 9px; border-radius: 10px; letter-spacing: 0.08em; text-transform: uppercase; background: #221e16; color: var(--ink-mute); border: 1px solid var(--border-soft); vertical-align: middle; }
    .momentum-pill[data-state="Guarded"] { background: #1e2630; color: #9fb6d2; border-color: #2a3540; }
    .momentum-pill[data-state="Stable"] { background: #16291c; color: #7fc995; border-color: #234a30; }
    .momentum-pill[data-state="Pressured"] { background: #2e2410; color: #e6b84e; border-color: #4a3a16; }
    .momentum-pill[data-state="Cracking"] { background: #2f1512; color: #f0897c; border-color: #4d211c; }
    /* Prelude — the cold open. The one cinematic beat before the work begins. */
    #prelude-view { max-width: 560px; margin: 0 auto; padding: 7vh 4px 24px; animation: prelude-in 0.7s ease both; }
    @keyframes prelude-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
    .prelude-kicker { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.24em; text-transform: uppercase; color: var(--brass); margin: 0 0 16px; }
    .prelude-title { font-family: var(--font-display); font-weight: 700; font-size: clamp(30px, 9vw, 38px); line-height: 1.04; margin: 0 0 24px; color: var(--ink); }
    .prelude-body p { font-size: 15.5px; line-height: 1.64; color: var(--ink-soft); margin: 0 0 15px; }
    .prelude-body p.lede { color: var(--ink); font-size: 16.5px; }
    .begin-btn { font-family: var(--font-body); font-size: 15px; font-weight: 600; padding: 13px 26px; margin-top: 12px; border: 1px solid var(--brass); background: var(--brass); color: #1a1306; border-radius: 8px; cursor: pointer; min-height: 48px; transition: filter 0.15s; position: relative; overflow: hidden; }
    .begin-btn:hover { filter: brightness(1.08); }
    /* Inviting idle-loop (Shimmer sweep, chosen 2026-07-11) — a light sweep crossing the advance CTA
       to draw the tap. Reduce-gated: no ::after at all under data-reduce. */
    html:not([data-reduce="1"]) .begin-btn::after {
      content: ""; position: absolute; top: 0; bottom: 0; left: -70%; width: 55%; pointer-events: none;
      background: linear-gradient(100deg, transparent, rgba(255,245,220,0.55), transparent);
      transform: skewX(-18deg); animation: cta-shimmer 3.2s ease-in-out infinite;
    }
    /* translateX (GPU) instead of `left` (per-frame layout) — 373% of the 55%-wide band == the old
       left -70% → 135% sweep. */
    @keyframes cta-shimmer { 0% { transform: translateX(0) skewX(-18deg); } 55%, 100% { transform: translateX(373%) skewX(-18deg); } }
    /* Lamp swings on (chosen 2026-07-11) — entering an interview, an interrogation-lamp cone sweeps
       across the suspect. Fired from interview.js via the showOnly onShown hook. Reduce-gated. */
    .iv-lampswing { position: absolute; top: -8%; left: 50%; width: 120%; height: 92%; margin-left: -60%;
      background: linear-gradient(180deg, rgba(240,199,94,0.42), rgba(240,199,94,0.05) 60%, transparent);
      clip-path: polygon(42% 0, 58% 0, 100% 100%, 0 100%); transform-origin: top center;
      transform: rotate(-40deg); opacity: 0; pointer-events: none; z-index: 3; }
    html:not([data-reduce="1"]) #iv-screen.lampswing .iv-lampswing { animation: iv-lamp-swing 1s cubic-bezier(0.3, 0.7, 0.3, 1); }
    @keyframes iv-lamp-swing { 0% { transform: rotate(-40deg); opacity: 0; } 22% { opacity: 1; } 100% { transform: rotate(0deg); opacity: 0; } }
    .ghost-btn { font-family: var(--font-body); font-size: 14px; font-weight: 600; padding: 12px 20px; min-height: 48px; border: 1px solid var(--border); background: transparent; color: var(--ink-soft); border-radius: 8px; cursor: pointer; }
    .ghost-btn:hover { border-color: var(--brass-dim); color: var(--ink); }
    /* === Surprise 6: Sister Thea's corridor note === */
    .thea-note { margin: 16px 0; padding: 13px 16px; background: rgba(205,163,73,0.04); border: 1px solid var(--border); border-left: 2px solid var(--brass-dim); border-radius: var(--radius); }
    .thea-note-from { display: block; font-family: var(--font-mono); font-size: 10px; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: var(--brass-dim); margin-bottom: 8px; }
    .thea-note-text { margin: 0; color: var(--ink-soft); font-size: 14px; line-height: 1.55; font-style: italic; }
    .thea-note { animation: thea-in 0.4s ease both; }
    @keyframes thea-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
    html[data-reduce="1"] .thea-note { animation: none; }
    /* === Endgame: accusation bar, accusation screen, ending + valence reveal === */
    .accuse-bar { margin-top: 22px; padding: 16px; background: rgba(205,163,73,0.06); border: 1px solid var(--border); border-left: 2px solid var(--brass); border-radius: var(--radius); display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
    .accuse-bar .ab-copy { flex: 1 1 200px; }
    .accuse-bar .ab-title { font-family: var(--font-display); font-weight: 700; font-size: 15px; color: var(--ink); margin: 0 0 2px; }
    .accuse-bar .ab-sub { font-size: 12px; color: var(--ink-soft); margin: 0; }
    .accuse-btn { font-family: var(--font-body); font-size: 14px; font-weight: 600; padding: 11px 20px; border: 1px solid var(--brass); background: var(--brass); color: #1a1306; border-radius: 8px; cursor: pointer; min-height: 44px; transition: filter 0.15s; }
    .accuse-btn:hover { filter: brightness(1.08); }
    .link-btn { background: none; border: none; color: var(--ink-mute); cursor: pointer; font-size: 12px; font-family: inherit; text-decoration: underline; min-height: 44px; padding: 0 4px; }
    .link-btn:hover { color: var(--ink-soft); }
    .ax-section-label { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--brass); margin: 20px 0 10px; }
    .suspects { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; }
    .suspect { background: var(--bg-raised); border: 1px solid var(--border); border-radius: 8px; padding: 11px 13px; cursor: pointer; text-align: left; font-family: inherit; color: var(--ink); min-height: 44px; transition: border-color 0.15s, background 0.15s; }
    .suspect:hover { border-color: var(--brass-dim); }
    .suspect[aria-pressed="true"] { border-color: var(--brass); background: rgba(205,163,73,0.12); }
    .suspect .s-name { font-family: var(--font-display); font-weight: 700; font-size: 14px; display: block; }
    .suspect .s-role { font-size: 10px; color: var(--brass); text-transform: uppercase; letter-spacing: 0.1em; }
    .evidence-list { display: flex; flex-direction: column; gap: 7px; }
    .ev-chip { display: flex; gap: 9px; align-items: flex-start; background: var(--bg-raised); border: 1px solid var(--border); border-radius: 8px; padding: 9px 11px; cursor: pointer; text-align: left; font-family: inherit; color: var(--ink); transition: border-color 0.15s, background 0.15s; }
    .ev-chip[aria-pressed="true"] { border-color: var(--brass); background: rgba(205,163,73,0.1); }
    .ev-check { width: 16px; height: 16px; border: 1.5px solid var(--ink-mute); border-radius: 4px; flex-shrink: 0; margin-top: 2px; display: grid; place-items: center; font-size: 11px; color: #1a1306; }
    .ev-chip[aria-pressed="true"] .ev-check { background: var(--brass); border-color: var(--brass); }
    .ev-body { font-size: 12.5px; line-height: 1.45; }
    .ev-who { font-family: var(--font-display); font-weight: 700; color: var(--ink); }
    .ev-empty { color: var(--ink-mute); font-size: 12px; font-style: italic; }
    .ax-actions { display: flex; align-items: center; gap: 12px; margin-top: 22px; flex-wrap: wrap; }
    .ax-actions .accuse-btn:disabled { opacity: 0.4; cursor: not-allowed; filter: none; }
    /* Modal — reserved for the one genuinely irreversible boundary (closing the case). */
    .modal-scrim { position: fixed; inset: 0; background: rgba(0,0,0,0.62); display: grid; place-items: center; z-index: 50; padding: 20px; }
    /* Card spotlight: tap a card to pop it enlarged to the centre of the screen (keeps the card look).
       A note is a big, clean, scrollable, editable sticky; other cards show enlarged + readable. */
    .spot-scrim { padding: 24px; }
    .spot-card { display: flex; flex-direction: column; width: min(92vw, 520px); max-height: 86vh; border-radius: 12px; overflow: hidden; box-shadow: 0 24px 60px rgba(0,0,0,0.7); background: var(--panel, #1a1712); border: 1px solid var(--border-soft); }
    .spot-card.kind-sticky { background: linear-gradient(180deg, #e8d69a, #dcc27f); border-color: #b9a25c; }
    .spot-head { display: flex; align-items: center; justify-content: space-between; padding: 14px 18px; }
    .spot-card.kind-sticky .spot-head { border-bottom: 1px solid rgba(74,58,22,0.22); }
    .spot-tag { font-family: var(--font-mono); font-size: 10px; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: var(--brass); }
    .spot-card.kind-sticky .spot-tag { color: #6b551d; }
    .spot-close { font-family: var(--font-body); font-size: 14px; font-weight: 600; color: #241f16; background: var(--brass); border: none; border-radius: 6px; padding: 9px 20px; min-height: 44px; cursor: pointer; }
    .spot-note-text { flex: 1; width: 100%; min-height: 220px; resize: none; border: none; outline: none; background: transparent; color: #241f16; font-family: var(--font-body); font-size: 18px; line-height: 1.65; padding: 10px 20px 20px; overflow-y: auto; }
    .spot-note-text::placeholder { color: rgba(36,31,22,0.5); }
    .spot-label { flex: 1; overflow-y: auto; color: var(--ink); font-family: var(--font-body); font-size: 17px; line-height: 1.6; padding: 6px 18px 18px; }
    .spot-img { padding: 0 18px 12px; }
    .spot-img img { width: 100%; height: auto; border-radius: 6px; display: block; }
    .spot-foot { padding: 12px 18px 16px; }
    .spot-card.kind-sticky .spot-foot { border-top: 1px solid rgba(74,58,22,0.2); }
    .spot-del { font-family: var(--font-body); font-size: 13px; color: #8a2f26; background: transparent; border: 1px solid rgba(138,47,38,0.5); border-radius: 6px; padding: 9px 16px; min-height: 44px; cursor: pointer; }
    .modal { background: var(--bg-raised); border: 1px solid var(--brass-dim); border-radius: var(--radius); padding: 22px; max-width: 380px; box-shadow: 0 18px 50px rgba(0,0,0,0.6); }
    .modal h2 { font-family: var(--font-display); font-size: 18px; margin: 0 0 10px; color: var(--ink); }
    .modal p { font-size: 13.5px; line-height: 1.5; color: var(--ink-soft); margin: 0 0 18px; }
    .modal .m-row { display: flex; gap: 10px; justify-content: flex-end; }
    .modal .m-cancel { background: transparent; border: 1px solid var(--border); color: var(--ink-soft); border-radius: 8px; padding: 10px 16px; cursor: pointer; font-family: inherit; min-height: 44px; }
    .modal .m-confirm { background: var(--brass); border: 1px solid var(--brass); color: #1a1306; border-radius: 8px; padding: 10px 16px; cursor: pointer; font-family: inherit; font-weight: 600; min-height: 44px; }
    /* Onboarding modal: stack the tool buttons full-width so all three fit any phone width. */
    .modal .ob-actions { display: flex; flex-direction: column; gap: 10px; }
    .modal .ob-actions button { width: 100%; text-align: center; }
    /* Ending screen */
    #ending-view { max-width: 600px; margin: 0 auto; padding: 5vh 4px 28px; }
    .ending-kicker { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.22em; text-transform: uppercase; color: var(--brass); margin: 0 0 12px; }
    .ending-title { font-family: var(--font-display); font-weight: 700; font-size: clamp(28px, 8vw, 36px); line-height: 1.06; margin: 0 0 20px; color: var(--ink); }
    .ending-body p { font-size: 15.5px; line-height: 1.62; color: var(--ink-soft); margin: 0 0 14px; }
    .ending-body p.lede { color: var(--ink); }
    .notes-card { background: rgba(0,0,0,0.2); border: 1px solid var(--border-soft); border-left: 2px solid var(--brass-dim); border-radius: 8px; padding: 13px 15px; margin: 18px 0; }
    .notes-card h3 { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--brass); margin: 0 0 8px; }
    .notes-card ul { margin: 0; padding-left: 17px; }
    .notes-card li { font-size: 13px; line-height: 1.5; color: var(--ink-soft); margin-bottom: 5px; }
    /* Valence reveal (Surprise 4) — the data model becomes the final UI. */
    .valence-wrap { margin-top: 26px; }
    .valence-wrap h2 { font-family: var(--font-display); font-size: 20px; margin: 0 0 4px; color: var(--ink); }
    .valence-wrap .vw-sub { font-size: 12.5px; color: var(--ink-soft); font-style: italic; margin: 0 0 16px; }
    .vmatrix-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
    table.vmatrix { border-collapse: separate; border-spacing: 4px; margin: 0 auto; }
    table.vmatrix th { font-family: var(--font-display); font-size: 11px; font-weight: 700; color: var(--ink-soft); padding: 4px 5px; white-space: nowrap; }
    table.vmatrix th.corner { color: var(--ink-mute); font-family: var(--font-mono); font-size: 9px; font-weight: 400; text-transform: uppercase; letter-spacing: 0.08em; }
    table.vmatrix td { width: 46px; height: 40px; text-align: center; border-radius: 7px; font-size: 12px; font-weight: 600; color: var(--ink); vertical-align: middle; }
    td.v-diag { background: transparent; color: var(--ink-mute); }
    td.v-positive { background: #18331f; color: #80d295; border: 1px solid #2a5436; }
    td.v-negative { background: #361816; color: #f08a7c; border: 1px solid #56221d; }
    td.v-complex  { background: #332912; color: #e6b84e; border: 1px solid #54421a; }
    td.v-neutral  { background: #232a31; color: #9fb6d2; border: 1px solid #313d47; }
    td.v-cell .v-glyph { display: block; font-size: 13px; line-height: 1; }
    td.v-cell .v-int { display: block; font-size: 9px; opacity: 0.8; font-family: var(--font-mono); margin-top: 1px; }
    td.v-cascaded { box-shadow: 0 0 0 2px var(--brass), 0 0 12px rgba(205,163,73,0.5); position: relative; }
    td.v-cascaded::after { content: "✦"; position: absolute; top: -6px; right: -4px; font-size: 10px; color: var(--brass); }
    .vlegend { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 14px; font-size: 11px; color: var(--ink-soft); }
    .vlegend span { display: inline-flex; align-items: center; gap: 5px; }
    .vlegend i { width: 11px; height: 11px; border-radius: 3px; display: inline-block; }
    .cascade-lines { margin-top: 16px; }
    .cascade-lines p { font-size: 13px; line-height: 1.55; color: var(--ink-soft); margin: 0 0 7px; padding-left: 18px; position: relative; }
    .cascade-lines p::before { content: "✦"; position: absolute; left: 0; color: var(--brass); }
    /* Valence reveal moved to #en-grid.reveal .en-vcell (screens.css, 2026-07-11). The old
       .reveal-armed td.v-cell / valence-in rule was dead (targeted a <table> ending.js no longer builds). */
    html[data-reduce="1"] .turn-text.typing::after { animation: none; }
    html[data-reduce="1"] .card { transition: none; }
    html[data-reduce="1"] .card:hover { transform: none; }
    html[data-reduce="1"] #prelude-view { animation: none; }

    /* === Interview screen — locked visual-novel design (2026-06-08) ===
       Full-bleed portrait, compose in depth not length. One viewport, no scroll.
       The latest NPC answer is a subtitle; the full exchange lives in the record overlay. */
    .iv-screen {
      position: fixed; inset: 0; margin: 0 auto; max-width: 480px; height: 100dvh;
      overflow: hidden; background: #0d0b07; z-index: 5;
      display: flex; flex-direction: column; justify-content: flex-end;
    }
    /* 4:5 busts fill the tall frame by width (cover crops the sides, not the top), so object-position
       can't lift the head — a zoom from an upper origin crops the headroom + table and enlarges the face. */
    .iv-portrait { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 50% 50%; transform: scale(var(--port-zoom, 1.16)); transform-origin: 50% 26%; opacity: 1; filter: contrast(1.05) brightness(1.02); transition: opacity 0.35s ease; }
    .iv-scrim, .iv-vignette, .iv-grain { position: absolute; pointer-events: none; }
    .iv-scrim { left: 0; right: 0; }
    .iv-scrim-top { top: 0; height: 21%; background: linear-gradient(to bottom, rgba(13,11,7,0.82), transparent); }
    /* Chiaroscuro: the lamp carves the face out of deep shadow; the answer lives in the dark pool below.
       Contrast for the dialogue comes from this lighting (a near-solid bed under the text), not a flat plate. */
    .iv-scrim-bottom { top: 34%; bottom: 0; background: linear-gradient(to bottom, transparent 0%, rgba(13,11,7,0.82) 30%, rgba(13,11,7,0.97) 64%, #0d0b07 82%); }
    .iv-vignette { inset: 0; background: radial-gradient(118% 82% at 50% 30%, transparent 38%, rgba(0,0,0,0.9) 96%); }
    .iv-grain { inset: 0; opacity: 0.06; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); }
    /* Layered portrait (parallax diorama, Marlene spike) — a clean background plate behind an
       alpha-cut figure. The figure parallaxes MORE than the background (pointer/gyro/idle drive
       --px/--py on #iv-screen), giving 2.5D depth (the SNAP look). Only the FIGURE breathes — the
       flat-whole-image breathing read as a photo zooming, so it was removed from .iv-portrait. The
       single-image bust (.iv-portrait) is the static fallback for characters with no layered set. */
    .iv-layers { position: absolute; inset: 0; }
    .iv-layers[hidden] { display: none; }
    .iv-layer { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 50% 50%; }
    /* Dust motes drifting in the lamp light — rendered by portrait-life.js. z-index:1 lifts it ABOVE the
       scrims/vignette (otherwise the noir darkening swallows it) but below the HUD/stage/foot (z>=2) so it
       never sits over text/controls. Parallax-aware, frozen under reduced motion. */
    .iv-dust { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 1; }
    .iv-bg {
      transform-origin: 50% 50%;
      transform: translate3d(calc(var(--px, 0) * 7px), calc(var(--py, 0) * 7px), 0) scale(1.14);
      transition: transform 0.18s ease-out;
    }
    /* Figure shares the bust's zoom + headroom crop; parallax rides the transform, breathing rides
       the individual scale/translate/rotate properties (they compose, no clobber). */
    .iv-figure {
      transform-origin: 50% 26%;
      transform: translate3d(calc(var(--px, 0) * -15px), calc(var(--py, 0) * -16px), 0) scale(var(--port-zoom, 1.16));
      transition: transform 0.18s ease-out;
      animation: iv-breathe 4.6s ease-in-out infinite, iv-drift 9.5s ease-in-out infinite;
    }
    /* Amplitudes kept small — on the figure-only layer a big scale reads as a head bob ("exaggerated"). */
    @keyframes iv-breathe { 0%, 100% { scale: 1; } 50% { scale: 1.006; } }
    @keyframes iv-drift {
      0% { translate: 0 0; rotate: 0deg; }
      33% { translate: 0.22% -0.14%; rotate: 0.14deg; }
      66% { translate: -0.18% 0.12%; rotate: -0.12deg; }
      100% { translate: 0 0; rotate: 0deg; }
    }
    @keyframes iv-tremble {
      0%, 100% { translate: 0 0; rotate: 0deg; }
      25% { translate: 0.22% 0.12%; rotate: 0.32deg; }
      50% { translate: -0.18% -0.12%; rotate: -0.28deg; }
      75% { translate: 0.16% 0.18%; rotate: 0.22deg; }
    }
    /* Held breath when Guarded, quicker when Pressured, a nervous tremble when Cracking. */
    .iv-figure[data-state="Guarded"]   { animation-duration: 5.8s, 11.5s; }
    .iv-figure[data-state="Pressured"] { animation-duration: 3.4s, 7s; }
    .iv-figure[data-state="Cracking"]  {
      animation-name: iv-breathe, iv-tremble; animation-duration: 2.5s, 0.24s;
      animation-timing-function: ease-in-out, linear;
    }
    /* Deliberation beat (send to first-token): a slower, deeper "considering" breath that reads as
       weighing the answer. Wins over the per-state rules via specificity (3 classes). Momentum flavour
       during the wait comes from the JS blink cadence + Marco's smoke, not here. Reduced motion still
       kills it via the !important .iv-figure off-switch below. */
    @keyframes iv-breathe-deep { 0%, 100% { scale: 1; } 50% { scale: 1.012; } }
    .iv-screen.thinking .iv-figure {
      animation-name: iv-breathe-deep, iv-drift; animation-duration: 3.2s, 9.5s;
      animation-timing-function: ease-in-out;
    }
    /* Blink overlay: the cut closed/half-eye figure stacked on the open figure; same transform +
       breathing so it stays in phase. opacity isn't in .iv-figure's transition, so the blink snaps
       crisply (eyelid frames, not a fade). portrait-life.js cycles it. */
    .iv-blink { opacity: 0; }
    /* Thinking-pose overlay: the character's held gaze-aside "considering" figure (portrait-eyes.js
       cross-fades it in over the base momentum figure from question-send to first-token, for personas
       that have a figure-think set). Unlike the snappy blink overlay, this one FADES (a soft swap), so
       it carries its own opacity transition. Shares the figure transform + breathing so it stays in
       phase with the base underneath. */
    .iv-pose { opacity: 0; transition: opacity 0.26s ease-in-out; }
    /* Top HUD */
    .iv-hud { position: absolute; top: 0; left: 0; right: 0; z-index: 4; display: flex; align-items: center; gap: 10px; padding: 14px 14px 0; }
    .iv-back { flex-shrink: 0; width: 40px; height: 40px; border-radius: 8px; border: 1px solid var(--border); background: rgba(0,0,0,0.35); color: var(--ink-soft); font-size: 18px; cursor: pointer; line-height: 1; }
    .iv-back:hover { border-color: var(--brass); color: var(--ink); }
    .iv-kicker { flex: 1; min-width: 0; font-family: var(--font-jbmono); font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--brass); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .iv-rec { flex-shrink: 0; display: inline-flex; align-items: center; gap: 6px; min-height: 40px; padding: 5px 11px; border-radius: 7px; border: 1px solid var(--border); background: rgba(0,0,0,0.4); color: var(--ink-soft); font-family: var(--font-jbmono); font-size: 11px; cursor: pointer; }
    .iv-rec:hover { border-color: var(--brass-dim); color: var(--ink); }
    .iv-rec-dot { width: 7px; height: 7px; border-radius: 50%; background: #f0897c; flex-shrink: 0; }
    .iv-screen.speaking .iv-rec-dot { animation: rec-blink 1.1s steps(2, end) infinite; }
    @keyframes rec-blink { 50% { opacity: 0.25; } }
    /* Stage: speaker + answer, bottom-anchored above the foot */
    .iv-stage { position: relative; z-index: 2; padding: 0 20px 12px; }
    .iv-speaker { display: flex; align-items: flex-end; gap: 11px; }
    .iv-wave { display: flex; align-items: flex-end; gap: 3px; height: 16px; flex-shrink: 0; padding-bottom: 4px; }
    .iv-wave i { width: 2px; border-radius: 1px; background: var(--brass); height: 5px; }
    .iv-wave i:nth-child(odd) { height: 9px; }
    .iv-wave i:nth-child(3n) { height: 13px; }
    .iv-wave i:nth-child(4n) { height: 6px; }
    .iv-screen.speaking .iv-wave i { animation: iv-wave 0.85s ease-in-out infinite; }
    .iv-wave i:nth-child(2n) { animation-delay: 0.12s; }
    .iv-wave i:nth-child(3n) { animation-delay: 0.24s; }
    .iv-wave i:nth-child(5n) { animation-delay: 0.36s; }
    @keyframes iv-wave { 0%, 100% { height: 4px; } 50% { height: 15px; } }
    .iv-speaker-text { flex: 1; min-width: 0; }
    .iv-name { font-family: var(--font-oswald); font-weight: 700; font-size: 24px; letter-spacing: 0.02em; text-transform: uppercase; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.05; margin: 0; color: var(--ink); }
    .iv-role { font-family: var(--font-jbmono); font-size: 9.5px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-mute); margin: 5px 0 0; }
    .momentum-stamp { flex-shrink: 0; align-self: center; display: inline-block; font-family: var(--font-oswald); font-weight: 700; font-size: 13px; letter-spacing: 0.1em; text-transform: uppercase; padding: 4px 9px; border: 2px solid var(--ink-mute); color: var(--ink-mute); background: rgba(18,13,8,0.78); border-radius: 3px; transform: rotate(-7deg); white-space: nowrap; }
    .momentum-stamp[data-state="Guarded"] { color: #9fb6d2; border-color: #9fb6d2; }
    .momentum-stamp[data-state="Stable"] { color: #7fc995; border-color: #7fc995; }
    .momentum-stamp[data-state="Pressured"] { color: #e6b84e; border-color: #e6b84e; }
    .momentum-stamp[data-state="Cracking"] { color: #f0897c; border-color: #f0897c; }
    .momentum-stamp[data-state=""] { display: none; }
    /* Momentum move (US-05/06): a one-shot pulse when the state changes on a turn. Preserves the
       stamp's -7deg rotation. Under reduced motion, a static outline replaces the pulse. */
    .momentum-stamp.moved { animation: mom-pulse 1.2s ease-out; }
    @keyframes mom-pulse {
      0% { transform: rotate(-7deg) scale(1); box-shadow: 0 0 0 0 currentColor; }
      28% { transform: rotate(-7deg) scale(1.22); box-shadow: 0 0 12px 2px currentColor; }
      100% { transform: rotate(-7deg) scale(1); box-shadow: 0 0 0 0 transparent; }
    }
    html[data-reduce="1"] .momentum-stamp.moved { animation: none; outline: 2px solid currentColor; outline-offset: 2px; }
    /* One-time momentum micro-copy, pinned under the pill (position set inline by momentum-coach.js). */
    .momentum-coach { position: fixed; z-index: 60; max-width: min(280px, 78vw);
      background: #17130c; color: var(--ink-soft); border: 1px solid var(--border-soft);
      border-radius: 10px; padding: 10px 34px 10px 12px; box-shadow: 0 10px 30px #000a;
      font-family: var(--font-read); font-size: 13.5px; line-height: 1.42; }
    .momentum-coach-msg { margin: 0; }
    .momentum-coach-x { position: absolute; top: 4px; right: 6px; background: none; border: none;
      color: var(--ink-mute); font-size: 18px; line-height: 1; cursor: pointer; padding: 2px 6px; }
    /* Per-turn micro-tell (UX audit B1 / DDR #7): ambient + diegetic. The waveform under the name
       flares gold when a question landed, slumps flat-gray when it slid off; the stamp gives a tiny
       press on landed. Never overlays the portrait or dialogue, never competes with the dubbing.
       Id selectors outrank the .speaking wave animation. Reduce-mode drops the motion; turn-tell.js
       holds the class 2s so the static color change alone carries the cue (gotcha #96 convention). */
    #iv-wave.tell-landed i { background: #f0c75e; animation: tell-flare 1.1s ease-out; transform-origin: bottom; }
    #iv-wave.tell-slid i { background: #59524a; animation: tell-slump 1.1s ease-out; transform-origin: bottom; }
    @keyframes tell-flare { 0% { transform: scaleY(1.9); filter: brightness(1.5); } 100% { transform: scaleY(1); filter: none; } }
    @keyframes tell-slump { 0% { transform: scaleY(0.35); } 100% { transform: scaleY(1); } }
    html[data-reduce="1"] #iv-wave.tell-landed i, html[data-reduce="1"] #iv-wave.tell-slid i { animation: none; }
    /* Echo on landed: a tiny press-pulse on the stamp. A state FLIP pulse (.moved) outranks it. */
    .momentum-stamp.tell-press:not(.moved) { animation: tell-press 0.55s ease-out; }
    @keyframes tell-press { 0% { transform: rotate(-7deg) scale(1); } 35% { transform: rotate(-6deg) scale(0.9); } 100% { transform: rotate(-7deg) scale(1); } }
    html[data-reduce="1"] .momentum-stamp.tell-press { animation: none; }
    /* One-line, once-ever discovery caption, pinned under the pill (position set inline by turn-tell.js). */
    .tell-caption { position: fixed; z-index: 60; max-width: min(260px, 72vw); margin: 0;
      background: #17130c; color: var(--ink-soft); border: 1px solid var(--border-soft);
      border-radius: 10px; padding: 8px 12px; box-shadow: 0 10px 30px #000a;
      font-family: var(--font-read); font-style: italic; font-size: 13px; line-height: 1.4; }
    .iv-rule { width: 56px; height: 2px; background: var(--brass); margin: 13px 0; }
    /* Long answers used to be hard-clamped to 5 lines (cut off). Now the block is bounded but scrolls
       internally, and interview.js keeps it pinned to the newest streamed text — the full answer is
       always reachable without breaking the single-viewport (no page-scroll) layout. */
    .iv-answer { font-family: var(--font-read); font-style: normal; font-weight: 400; font-size: 20px; line-height: 1.5; text-align: left; color: var(--ink); margin: 0; min-height: 2.4em; text-shadow: 0 0 20px rgba(0,0,0,0.92), 0 1px 3px rgba(0,0,0,0.95);
      max-height: 28vh; overflow-y: auto; overflow-x: hidden; -webkit-overflow-scrolling: touch; scrollbar-width: thin; scrollbar-color: var(--brass-dim) transparent; }
    .iv-answer::-webkit-scrollbar { width: 4px; }
    .iv-answer::-webkit-scrollbar-thumb { background: var(--brass-dim); border-radius: 2px; }
    .iv-answer.typing::after { content: "▌"; color: var(--brass); margin-left: 2px; animation: iv-caret 1s steps(2, end) infinite; }
    @keyframes iv-caret { 50% { opacity: 0; } }
    /* Foot: evidence tray + input bar */
    .iv-foot { position: relative; z-index: 3; padding: 0 14px 14px; }
    /* In-hand evidence now lives behind the Evidence button (frees vertical space so the keyboard
       doesn't crop the portrait). The only main-screen evidence UI is a compact "on the table" chip
       row, shown by renderTray() only when something is staged. */
    .iv-polaroids, .iv-ev-label { display: none !important; }
    .iv-foot .ev-tray { margin: 0 0 9px; }
    .iv-ev-label { font-family: var(--font-jbmono); font-size: 9px; letter-spacing: 0.15em; color: var(--ink-mute); margin: 0 0 7px; }
    .iv-ev-label[hidden] { display: none; }
    .iv-polaroids { display: flex; gap: 10px; padding: 0 0 11px; }
    .iv-polaroids[hidden] { display: none; }
    .iv-pol { flex: 0 0 auto; width: 78px; display: flex; flex-direction: column; gap: 4px; padding: 5px 5px 7px; background: #e6ddca; border: none; border-radius: 2px; cursor: pointer; box-shadow: 0 4px 12px rgba(0,0,0,0.5); transition: transform 0.15s, box-shadow 0.15s; }
    .iv-pol:nth-child(1) { transform: rotate(-4deg); }
    .iv-pol:nth-child(2) { transform: rotate(3deg); }
    .iv-pol:nth-child(3) { transform: rotate(-2deg); }
    .iv-pol-thumb { display: flex; align-items: center; justify-content: center; height: 50px; background: #20190f; border-radius: 1px; }
    .iv-pol-thumb .ev-glyph, .iv-pol-thumb svg { width: 24px; height: 24px; color: var(--brass-dim); }
    .iv-pol-cap { font-family: var(--font-jbmono); font-size: 7.5px; letter-spacing: 0.04em; color: #2a2012; text-align: center; line-height: 1.2; }
    .iv-pol.on { box-shadow: 0 0 0 2px var(--brass), 0 6px 16px rgba(0,0,0,0.6); }
    .iv-pol.on .iv-pol-cap::after { content: " ✓"; color: var(--brass-dim); }
    /* Case-tools row — discoverable labelled icon buttons (Evidence / Board / Record). */
    .iv-tools { display: flex; gap: 8px; margin-bottom: 9px; }
    .iv-tool { flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 7px; min-height: 40px; padding: 0 8px; border-radius: 9px; border: 1px solid var(--border); background: rgba(0,0,0,0.42); color: var(--ink-soft); cursor: pointer; font-family: var(--font-jbmono); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; }
    .iv-tool svg { width: 16px; height: 16px; flex-shrink: 0; fill: none; stroke: var(--brass-dim); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
    .iv-tool:hover { border-color: var(--brass-dim); color: var(--ink); }
    .iv-tool:hover svg { stroke: var(--brass); }
    .iv-tool:focus-visible { outline: 2px solid var(--brass); outline-offset: 2px; }
    /* === Universal press feedback + tool-button idle (game-feel, 2026-07-11) ===
       Every actionable button answers the tap (Pulp squash); the interview tools breathe
       a faint brass glow so they read as alive. Both reduce-aware. Toggles opt out (press.js). */
    /* Press via the independent `scale` property so it COMPOSES with buttons that own `transform`
       (e.g. the tilted roster polaroids) instead of being overridden by them. */
    button { transition: scale 0.12s cubic-bezier(0.2, 0.8, 0.2, 1); }
    .pressing { scale: 0.93; filter: brightness(1.12); }
    html[data-reduce="1"] .pressing { scale: 0.97; filter: none; }
    /* Idle glow rides a pseudo-element's opacity (compositor), not the button's box-shadow (per-frame
       repaint on the most-used screen). */
    .iv-tool { position: relative; }
    .iv-tool::after { content: ""; position: absolute; inset: 0; border-radius: 9px; pointer-events: none;
      box-shadow: 0 0 8px 0 rgba(205, 163, 73, 0.3); opacity: 0; }
    html:not([data-reduce="1"]) .iv-tool::after { animation: iv-tool-idle 4.2s ease-in-out infinite; }
    html:not([data-reduce="1"]) .iv-tool:nth-of-type(2)::after { animation-delay: 0.6s; }
    html:not([data-reduce="1"]) .iv-tool:nth-of-type(3)::after { animation-delay: 1.2s; }
    @keyframes iv-tool-idle { 0%, 100% { opacity: 0; } 50% { opacity: 1; } }
    .iv-inputbar { display: flex; align-items: flex-end; gap: 7px; }
    .iv-inputbar #input { flex: 1; min-height: 44px; max-height: 96px; height: 44px; padding: 11px 13px; border-radius: 10px; border: 1px solid var(--brass); background: rgba(16,12,7,0.82); color: var(--ink); font-family: var(--font-body); font-size: 14px; line-height: 1.35; resize: none; overflow-y: hidden; }
    .iv-inputbar #input:focus { outline: none; box-shadow: 0 0 0 2px rgba(205,163,73,0.3); }
    .iv-inputbar #input::placeholder { color: var(--ink-mute); }
    .iv-inputbar #input.has-suggestion::placeholder { color: var(--brass); opacity: 0.92; }
    .iv-inputbar #input.has-suggestion { animation: suggestGlow 1.7s ease-in-out infinite; }
    @keyframes suggestGlow { 0%, 100% { box-shadow: 0 0 0 0 rgba(205,163,73,0); } 50% { box-shadow: 0 0 0 3px rgba(205,163,73,0.32); } }
    html[data-reduce="1"] .iv-inputbar #input.has-suggestion { animation: none; box-shadow: 0 0 0 2px rgba(205,163,73,0.34); }
    .iv-send { flex-shrink: 0; min-height: 44px; padding: 0 18px; border-radius: 9px; border: 1px solid var(--brass); background: var(--brass); color: #1a1306; font-family: var(--font-oswald); font-weight: 700; font-size: 13px; letter-spacing: 0.1em; text-transform: uppercase; cursor: pointer; }
    .iv-send:hover { filter: brightness(1.08); }
    .iv-send:disabled { opacity: 0.45; cursor: wait; }
    /* Turn-failure notice (UX audit A1/A7): a system-styled cut-line under any partial answer,
       deliberately NOT .iv-answer typography so a failure never reads as the character speaking. */
    .iv-cutline { margin: 8px 0 0; padding-left: 9px; border-left: 2px solid var(--brass-dim); font-family: var(--font-body); font-style: italic; font-size: 13px; line-height: 1.45; color: var(--ink-mute); text-shadow: 0 1px 3px rgba(0,0,0,0.9); }
    /* Retry chip: re-asks the failed question for free (the server billed nothing on the failure). */
    .iv-retry { display: block; margin: 0 0 8px; min-height: 44px; padding: 0 16px; border-radius: 9px; border: 1px solid var(--brass-dim); background: rgba(16,12,7,0.82); color: var(--brass); font-family: var(--font-body); font-size: 13px; font-weight: 600; letter-spacing: 0.04em; cursor: pointer; }
    .iv-retry:hover { border-color: var(--brass); filter: brightness(1.1); }
    .iv-retry:focus-visible { outline: 2px solid var(--brass); outline-offset: 2px; }
    .iv-retry[hidden] { display: none; }
    /* Overlays — record / evidence / board. The no-scroll rule governs the main screen; these scroll. */
    .iv-overlay { position: fixed; inset: 0; z-index: 20; display: flex; align-items: flex-end; justify-content: center; background: rgba(0,0,0,0.6); padding: 0; }
    .iv-overlay[hidden] { display: none; }
    .iv-sheet { width: 100%; max-width: 480px; max-height: 88dvh; overflow-y: auto; -webkit-overflow-scrolling: touch; background: var(--bg-raised); border: 1px solid var(--border); border-bottom: none; border-radius: 14px 14px 0 0; padding: 16px 16px 24px; box-shadow: 0 -14px 40px rgba(0,0,0,0.6); }
    .iv-sheet-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
    .iv-sheet-title { font-family: var(--font-display); font-weight: 700; font-size: 17px; color: var(--ink); margin: 0; }
    .iv-sheet-close { flex-shrink: 0; width: 36px; height: 36px; border-radius: 8px; border: 1px solid var(--border); background: transparent; color: var(--ink-soft); font-size: 19px; line-height: 1; cursor: pointer; }
    .iv-sheet-close:hover { border-color: var(--brass); color: var(--ink); }
    /* Record sheet — the case-file panel */
    .rec-sheet { border-top: 3px solid var(--brass-dim); }
    .rec-tab { font-family: var(--font-jbmono); font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--brass); }
    .rec-sheet #history { display: flex; flex-direction: column; gap: 10px; max-height: 60dvh; overflow-y: auto; padding: 4px 2px; }
    html[data-reduce="1"] .iv-pose { transition: none; }
    html[data-reduce="1"] .iv-portrait { transition: none; }
    html[data-reduce="1"] .iv-answer.typing::after { animation: none; }
    html[data-reduce="1"] .iv-pol { transition: none; }
    /* Authoritative motion off-switch: the player's Reduced-motion choice (Settings, defaulting to the
       OS pref) drives html[data-reduce]. Gating here — not on the media query alone — lets a player on a
       reduce-by-default OS (e.g. Windows "Show animations" off) turn motion back ON. Mirrors transitions.js.
       Freezes the figure breathing and zeroes the parallax (portrait-life.js also stops feeding --px/--py). */
    html[data-reduce="1"] .iv-figure,
    html[data-reduce="1"] .iv-blink {
      animation: none !important; scale: 1; translate: 0 0; rotate: 0deg;
    }
    html[data-reduce="1"] .iv-bg,
    html[data-reduce="1"] .iv-figure { transition: none; }
    html[data-reduce="1"] .iv-screen { --px: 0; --py: 0; }
    html[data-reduce="1"] .iv-screen.speaking .iv-wave i,
    html[data-reduce="1"] .iv-screen.speaking .iv-rec-dot { animation: none !important; }

    /* Evidence receipt: a just-received clue settles into the on-screen polaroid strip with a brass
       highlight, so the player sees what they got. One-shot; render() clears justObtained after. */
    @keyframes iv-receipt {
      0%   { opacity: 0; transform: translateY(12px) scale(0.84) rotate(-5deg); }
      55%  { opacity: 1; transform: translateY(-3px) scale(1.05) rotate(1.5deg); }
      100% { opacity: 1; transform: translateY(0) scale(1) rotate(0); }
    }
    @keyframes iv-receipt-glow {
      0%, 100% { box-shadow: 0 4px 16px rgba(0,0,0,0.5); }
      40%      { box-shadow: 0 0 0 2px var(--brass), 0 0 16px 2px rgba(205,163,73,0.55), 0 4px 16px rgba(0,0,0,0.5); }
    }
    .iv-pol-new { animation: iv-receipt 640ms cubic-bezier(0.2, 0.8, 0.2, 1) both; }
    .iv-pol-new .iv-pol-thumb { animation: iv-receipt-glow 1100ms ease-out 1; }
    /* Reduced motion: appear instantly, no movement or pulse — still on screen. */
    html[data-reduce="1"] .iv-pol-new,
    html[data-reduce="1"] .iv-pol-new .iv-pol-thumb { animation: none; }
