/* ============================================
   Overlay Tribunal — Design #32
   Fullscreen video + floating overlays
   ============================================ */

:root {
  --bg: #2a2a2a;
  --border: rgba(255, 255, 255, 0.12);
  --text: #f0efe8;
  --muted: rgba(240, 239, 232, 0.55);
  --gold: #ffd000;
  --gold-dark: #ffd23f;
  --green: #34d399;
  --blue: #8FD0C5;
  --red: #EFCB9E;
  --purple: #A9B6E3;
  --panel: rgba(14, 14, 18, 0.42);
  --panel-solid: rgba(14, 14, 18, 0.62);
  --header: #232830;   /* the shared Assembly header colour — matches --os-header in css/os.css,
                          so the tribunal's own title bar reads as the same chrome as the shell */
  --chrome: rgba(14, 14, 18, 0.5);
  --gold-line: 1px solid rgba(255, 208, 0, 0.55);
  --rim: inset 0 0 0 1px rgba(255, 255, 255, 0.22);
  --lift-shadow: 0 12px 40px rgba(0, 0, 0, 0.5), 0 2px 10px rgba(0, 0, 0, 0.35);
  --lift-shadow-hover: 0 18px 56px rgba(0, 0, 0, 0.6), 0 2px 10px rgba(0, 0, 0, 0.4);
  --sans: 'Roboto', -apple-system, system-ui, sans-serif;
  --mono: 'Roboto', -apple-system, system-ui, sans-serif;
}

/* Frosted surface shared by the glass overlays below. Grouped selector
   list (no markup edits needed); each selector's specificity equals its
   former single-rule declaration, so the cascade is unchanged. */
#titlebar .vol-popup,
#settings-menu,
#decision-overlay,
#decision-overlay .ov-tab,
#playback-bar .pb-controls,
#messenger,
.mess-toggle,
#judgment-panel {
  backdrop-filter: blur(18px) saturate(1.15);
  -webkit-backdrop-filter: blur(18px) saturate(1.15);
}

html, body {
  height: 100%;
  overflow: hidden;
  background: #fff;
  color: var(--text);
  font-family: var(--sans);
  font-size: 14px;
}

/* ---------- Layout ---------- */
#app {
  display: flex;
  flex-direction: column;
  height: 100vh;
  width: 100vw;
}
#content {
  flex: 1;
  display: flex;
  position: relative;
  min-height: 0;
}
#video-section {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  position: relative;
}

/* ---------- Ubuntu Title Bar ---------- */
#titlebar {
  height: 40px;
  background: var(--header);
  border-bottom: 1px solid rgba(255, 208, 0, 0.4);
  display: flex;
  align-items: center;
  padding: 0 16px;
  flex-shrink: 0;
  user-select: none;
  -webkit-user-select: none;
  border-radius: 12px 12px 0 0;
  box-shadow: var(--lift-shadow), var(--rim);
}
#titlebar .window-controls {
  display: flex;
  gap: 10px;
  flex-shrink: 0;
}
#titlebar .window-controls span {
  width: 19px;
  height: 19px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  color: #2a2a2a;
  cursor: pointer;
  transition: opacity 0.15s;
}
#titlebar .window-controls span:hover { opacity: 0.8; }
#titlebar .wc-close { background: var(--gold); }
#titlebar .wc-min { background: var(--gold); opacity: 0.7; }
#titlebar .wc-max { background: var(--gold); opacity: 0.5; }
#titlebar .window-title {
  flex: 1;
  text-align: center;
  font-size: 16px;
  font-weight: 500;
  color: var(--text);
  letter-spacing: 0.02em;
}
#titlebar .titlebar-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}
#titlebar .cog-btn {
  background: none;
  border: none;
  color: var(--muted);
  font-size: 30px;
  cursor: pointer;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  transition: all 0.15s;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}
#titlebar .cog-btn:hover {
  color: var(--text);
  background: rgba(255, 255, 255, 0.1);
}
/* The cog's highlighted state while the settings menu is open — js/app.js
   toggles .open on #cog-btn and every menu-close path removes it. */
#titlebar .cog-btn.open {
  color: var(--gold);
  background: rgba(255, 208, 0, 0.12);
  box-shadow: 0 0 8px rgba(255, 208, 0, 0.35);
}
#titlebar .cog-btn.open:hover {
  color: var(--gold);
  background: rgba(255, 208, 0, 0.18);
}

/* ---------- Volume control ---------- */
#titlebar .vol-wrap {
  position: relative;
  display: flex;
  align-items: center;
}
#titlebar .vol-btn .vol-icon {
  display: none;
  /* Glyph-aligned with the cog: the speaker ink spans 73.1% of the 24-unit
     viewBox (centred), so a 25px box gives the same ink height as the ⚙ ink
     at 30px font (18.25px); the 0.88px nudge centres it on the gear ink's
     optical centre, which sits 0.875px below the line-box centre. */
  width: 25px;
  height: 25px;
  fill: currentColor;
  transform: translateY(0.88px);
}
#titlebar .vol-btn .vol-icon-on {
  display: block;
}
#titlebar .vol-btn.muted .vol-icon-on {
  display: none;
}
#titlebar .vol-btn.muted .vol-icon-off {
  display: block;
}
#titlebar .vol-popup {
  position: absolute;
  top: calc(100% + 10px);
  right: -6px;
  width: 58px;
  padding: 14px 10px 10px;
  background: var(--panel-solid);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: var(--lift-shadow), var(--rim);
  display: none;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  z-index: 200;
}
#titlebar .vol-popup.visible {
  display: flex;
  animation: volFadeIn 0.15s ease-out;
}
@keyframes volFadeIn {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: translateY(0); }
}
#titlebar .vol-track {
  position: relative;
  width: 6px;
  height: 120px;
  background: rgba(255, 255, 255, 0.15);
  border-radius: 3px;
  cursor: pointer;
  touch-action: none;
}
#titlebar .vol-fill {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 100%;
  background: var(--gold);
  border-radius: 3px;
}
#titlebar .vol-thumb {
  position: absolute;
  left: 50%;
  bottom: calc(100% - 6px);
  transform: translateX(-50%);
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--gold);
  border: 2px solid rgba(14, 14, 18, 0.9);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
  pointer-events: none;
}
#titlebar .vol-value {
  font-size: 11px;
  color: var(--muted);
  font-family: var(--mono);
  letter-spacing: 0.04em;
}

/* ---------- Settings Menu (the cog's dropdown, 2026-09-18) ----------
   The RULINGS OVERVIEW panel is gone: #settings-menu is a small dropdown
   that drops BELOW THE COG (top-right, under the 40px titlebar) with three
   rows — sound-mute toggle, killchain guide, case-info re-open (js/app.js).
   Same glass surface as before. */
#settings-menu {
  position: absolute;
  top: 46px;
  right: 12px;
  width: 290px;
  background: var(--panel);
  border: var(--gold-line);
  border-radius: 10px;
  z-index: 100;
  display: none;
  flex-direction: column;
  overflow: hidden;
  box-shadow: var(--lift-shadow), var(--rim);
  animation: fadeIn 0.2s ease-out;
}
#settings-menu.visible {
  display: flex;
}
@keyframes fadeIn {
  from { opacity: 0; transform: scale(0.96); }
  to { opacity: 1; transform: scale(1); }
}
.settings-header {
  display: flex;
  align-items: center;
  padding: 12px 16px;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  border-bottom: 1px solid var(--border);
  background: var(--panel-solid);
  flex-shrink: 0;
}
.settings-body {
  flex: 1;
  overflow-y: auto;
  padding: 8px 0;
}
/* Dropdown rows (settings dropdown, 2026-09-18) — the old .settings-ruling-*
   rulings-readout rules were removed with the readout. */
.settings-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 16px;
  cursor: pointer;
  transition: background 0.15s;
}
.settings-row:hover {
  background: rgba(255, 255, 255, 0.06);
}
.settings-row-label {
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
}
.settings-row-state {
  font-size: 12px;
  font-family: var(--mono);
  color: var(--muted);
  flex-shrink: 0;
}
.settings-row-state.on {
  color: var(--gold);
  font-weight: 600;
}

/* ---------- Video fullscreen ---------- */
#video-container {
  flex: 1;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #000;
  min-height: 0;
  overflow: hidden; /* letterbox: clip the stage to the container */
}
/* Canonical virtual stage (game host only). The take is a recording at a
   fixed 1920×1080 (meta.viewport). The game renders it on a FIXED 1920×1080
   CSS stage and uniformly scales that stage to fit the (non-16:9) container
   — the letterbox bars are the container's black background around it. Only
   the transform scale k (set by js/app.js on resize) changes; the stage
   offset size never does, so Leaflet keeps its 1920×1080 layout and the
   host-% replay cursor lands on the recorded element layout. Higher
   specificity (#video-container #scene-host) beats css/maven/scene.css's
   #scene-host {inset:0}; suite.html never loads overlay.css and its
   #scene-host sits outside any #video-container, so this is game-only. */
#video-container #scene-host {
  position: absolute;
  inset: auto;
  left: 50%;
  top: 50%;
  width: 1920px;
  height: 1080px;
  transform: translate(-50%, -50%) scale(var(--stage-k, 1));
  transform-origin: center center;
}
#video-container video {
  width: 100%;
  height: 100%;
  object-fit: contain;
  pointer-events: none;
}

/* Closed captions (YouTube CC style) — tribunal chrome, OUTSIDE the
   simulated stage: a sibling of #scene-host in #video-container, above the
   stage z-wise (the stage's transform owns its stacking context at z-auto;
   z-5 wins), pinned to the stage top edge: stage top = 50% − 540px·k of the
   container (k = --stage-k, set on #video-container by app.js fitStage). The
   box top sits ON the stage top, so the caption straddles the Maven topbar's
   lower half / bottom edge — visibly overlapping the simulated UI, signalling
   the captions belong to the tribunal interface. The box never extends above
   the stage top, so letterboxing can't clip it at any window size. */
#scene-captions {
  position: absolute;
  left: 50%;
  top: calc(50% - 540px * var(--stage-k, 1));
  transform: translateX(-50%);
  z-index: 5;
  box-sizing: border-box;
  max-width: 70%;
  padding: 6px 14px;
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.8);
  color: #ffffff;
  font-family: var(--sans);
  font-size: 22px;
  line-height: 1.2;
  text-align: center;
  visibility: hidden;
  opacity: 0;
  transition: opacity 0.12s ease;
  pointer-events: none;
}
#scene-captions.visible {
  visibility: visible;
  opacity: 1;
}
/* Lattice mount only (launchLatticeCase stamps .replay-mode on #scene-host):
   lattice.css's #scene-captions rule is position:fixed, so the same
   stage-top pinning is computed against the VIEWPORT — when the stage fills
   the container height the box top lands ~20px + half the playbar from the
   viewport top, i.e. under the 40px tribunal titlebar. Offset by the
   titlebar height so the box stays clear of it (the id+class specificity
   beats lattice.css's id-only rule regardless of stylesheet order). */
#scene-host.replay-mode ~ #scene-captions {
  top: calc(40px + 50% - 540px * var(--stage-k, 1));
}
/* ---------- Case-begin aggressive dim ----------
   Covers the stage on the first (paused) moment of the case so the paused
   state is unmistakable; js/app.js adds .on on BEGIN and removes it on the
   first play (it does not return on later pauses). Lands INSTANTLY (no
   fade): the case UI must appear already darkened the moment the
   PLAY FOOTAGE composite shows, not darken after the fact. z-4: above the
   stage, below the captions (z-5) and the pause overlay (z-6) so the
   bug/arrow stay readable on top of the dim. pointer-events:none. */
#case-dim {
  position: absolute;
  inset: 0;
  z-index: 4;
  background: rgba(0, 0, 0, 0.68);
  pointer-events: none;
  opacity: 0;
}
#case-dim.on {
  opacity: 1;
}

/* ---------- "Paused footage" bug ----------
   Persistent while the take is PAUSED (hidden while playing): a tribunal bug
   (state dot + PAUSED + live timecode + source label) pinned to the stage's
   top-left corner. It tells the player this is captured footage, not a live
   interface. Driven by js/app.js (setPlaybackChrome toggles .on from the play
   state). z-6: above the captions (z-5) and the dim (z-4), below every panel.
   (The centre-screen play/pause symbol is #scrub-flash, below.) */
#pause-overlay {
  position: absolute;
  inset: 0;
  z-index: 6;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.25s ease;
}
#pause-overlay.on {
  opacity: 1;
}
.po-bug {
  position: absolute;
  /* Diagonal down-right from the top-left corner so it clears Maven's top
     toolbar (and the LAYERS header) instead of sitting over it. */
  top: 56px;
  left: 56px;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 14px;
  border-radius: 8px;
  background: var(--panel-solid);
  -webkit-backdrop-filter: blur(18px);
  backdrop-filter: blur(18px);
  border: var(--gold-line);
  box-shadow: var(--rim), var(--lift-shadow);
  font-family: var(--sans);
  font-size: 13px;
  color: var(--text);
  letter-spacing: 0.4px;
}
.po-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--gold);
  box-shadow: 0 0 8px rgba(255, 208, 0, 0.8);
}
.po-state {
  color: var(--text);
}
.po-tc {
  font-family: ui-monospace, Menlo, Consolas, monospace;
  letter-spacing: 1px;
  color: var(--gold);
}
.po-src {
  color: var(--muted);
  font-size: 11px;
  letter-spacing: 1.5px;
}
/* ---------- Centre-screen play/pause symbol ----------
   A large gold glyph centred on the scene that appears on play/pause and fades
   out (play ▶ over 1 s, 2 s for the first play after BEGIN; pause ⏸ over 2 s).
   On the case-begin moment it is a PERSISTENT ▶ with a "PLAY FOOTAGE" caption
   (no fade) until the first play. Driven by js/app.js: .on shows it (opacity
   1); .on.f2s/.on.f1s run the one-shot fade animation (keyframes start at
   opacity 1, so a re-trigger mid-fade always plays from visible); app.js
   clears the classes on animationend. The caption is positioned absolutely
   below the glyph so an empty caption never offsets the glyph's centre.
   pointer-events:none — a click falls through to #video-container's click
   toggle, so "click the arrow" == "click the scene". z-6, same band as the
   bug. */
#scrub-flash {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 6;
  pointer-events: none;
  visibility: hidden;
  opacity: 0;
}
#scrub-flash.on {
  visibility: visible;
  opacity: 1;
}
@keyframes scrub-flash-fade {
  from { opacity: 1; }
  to   { opacity: 0; }
}
#scrub-flash.on.f2s {
  animation: scrub-flash-fade 2s linear forwards;
}
#scrub-flash.on.f1s {
  animation: scrub-flash-fade 1s linear forwards;
}
#scrub-flash-glyph {
  font-size: 140px;
  line-height: 1;
  color: var(--gold);
  text-shadow: 0 2px 24px rgba(0, 0, 0, 0.55);
}
#scrub-flash-cap {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  top: calc(50% + 90px);
  font-family: var(--sans);
  font-size: 13px;
  letter-spacing: 3px;
  color: var(--gold);
  white-space: nowrap;
}
/* ---------- Decision overlay ---------- */
#decision-overlay {
  position: absolute;
  bottom: 100%;
  margin-bottom: 4px;
  width: 420px;
  background: var(--panel);
  border: var(--gold-line);
  border-radius: 12px 12px 0 0;
  z-index: 20;
  display: none;
  overflow: visible;
  box-shadow: var(--lift-shadow), var(--rim);
  transform: translateX(-50%);
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
#decision-overlay:hover {
  transform: translateX(-50%) translateY(-2px);
  box-shadow: var(--lift-shadow-hover), var(--rim);
  border-color: rgba(255, 208, 0, 0.95);
}
#decision-overlay.visible {
  display: block;
  animation: slideUp 0.25s ease-out;
}
@keyframes slideUp {
  from { opacity: 0; transform: translateX(-50%) translateY(12px); }
  to { opacity: 1; transform: translateX(-50%) translateY(0); }
}
#decision-overlay .ov-tab {
  position: absolute;
  top: -22px;
  left: 50%;
  transform: translateX(-50%);
  width: 64px;
  height: 22px;
  background: var(--panel);
  border-top: 1px solid rgba(255, 208, 0, 0.55);
  border-left: 1px solid rgba(255, 208, 0, 0.55);
  border-right: 1px solid rgba(255, 208, 0, 0.55);
  border-bottom: none;
  border-radius: 8px 8px 0 0;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  font-size: 13px;
  font-weight: 700;
  padding: 0;
  line-height: 1;
  transition: background 0.2s, color 0.2s;
}
#decision-overlay .ov-tab:hover {
  color: var(--text);
}
#decision-overlay:not(.minimized) .ov-tab::after { content: '\2304'; }
#decision-overlay.minimized .ov-tab::after { content: '\2303'; }
#decision-overlay .ov-head {
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
  border-radius: 11px 11px 0 0;
  background: var(--panel-solid);
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
}
#decision-overlay .ov-id {
  font-size: 16px;
  color: var(--gold);
  font-family: var(--mono);
  letter-spacing: 0.08em;
  font-weight: 600;
}
#decision-overlay.minimized .ov-body { display: none; }
#decision-overlay .ov-body { padding: 16px 18px; }
#decision-overlay .ov-summary {
  font-size: 15px;
  line-height: 1.55;
  color: var(--text);
  margin-bottom: 14px;
}
#decision-overlay .ov-label {
  font-size: 12px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin-bottom: 8px;
}
#decision-overlay .ov-buttons {
  display: flex;
  gap: 8px;
}
.ov-btn {
  flex: 1;
  padding: 10px 0;
  border: 1px solid rgba(255, 255, 255, 0.25);
  background: transparent;
  color: var(--muted);
  font-family: var(--mono);
  font-size: 14px;
  cursor: pointer;
  border-radius: 5px;
  transition: all 0.15s;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.ov-btn:hover {
  border-color: var(--gold);
  color: var(--gold);
}
.ov-btn.sel-operator {
  background: var(--blue);
  border-color: var(--blue);
  color: #2a2a2a;
}
.ov-btn.sel-soldier {
  background: var(--red);
  border-color: var(--red);
  color: #2a2a2a;
}
.ov-btn.sel-designer {
  background: var(--purple);
  border-color: var(--purple);
  color: #2a2a2a;
}
/* ---------- Floating playback bar (QuickTime style) ---------- */
#playback-bar {
  position: absolute;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  z-index: 15;
  min-width: 780px;
  max-width: 900px;
  transition: opacity 0.3s;
}
#playback-bar .pb-controls {
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--panel);
  border: var(--gold-line);
  border-radius: 12px;
  box-shadow: var(--lift-shadow), var(--rim);
  padding: 10px 14px;
}
#playback-bar .pb-scrubber-wrap {
  position: relative;
  flex: 1;
  display: flex;
  align-items: center;
}
#playback-bar .pb-scrubber-wrap input[type="range"] {
  width: 100%;
  position: relative;
  z-index: 1;
}
#playback-bar .pb-markers {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 100%;
  z-index: 3;
  pointer-events: none;
}
/* orientation: the playbar reveals with no markers — they pop in on the
   markers step (the ticks stay built; this just holds them out of sight) */
#pb-markers.hide-markers .pb-marker {
  visibility: hidden;
}
/* the '1' marker's attention pulse until the player reaches it */
@keyframes markerAttention {
  0%, 100% { box-shadow: 0 0 4px 1px rgba(255, 208, 0, 0.35); }
  50% { box-shadow: 0 0 16px 4px rgba(255, 208, 0, 0.75); }
}
.pb-marker.orient-attention {
  animation: markerAttention 1.1s ease-in-out infinite;
}
/* Tick markers: a thin vertical line (20% of the old 27px circle) with the
   entry number above it, so events close together on the timeline stay
   legible instead of overlapping circles. Outline and number are permanently
   gold — state (.active) only adds a glow, nothing recolors the tick. */
.pb-marker {
  position: absolute;
  top: 50%;
  margin-top: -10px;
  margin-left: -2.7px; /* centre the tick on its timestamp */
  width: 5.4px;
  height: 20px;
  border: 1px solid var(--gold);
  border-radius: 1px;
  cursor: pointer;
  transition: box-shadow 0.2s, border-color 0.2s;
  pointer-events: auto;
  background: rgba(24, 24, 28, 0.9);
}
.pb-marker > span {
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  margin-bottom: 2px;
  font-size: 10px;
  font-weight: 600;
  line-height: 1;
  color: var(--gold);
}
/* transparent hit area — the tick itself is too thin to click reliably */
.pb-marker::before {
  content: '';
  position: absolute;
  left: -7px;
  right: -7px;
  top: -8px;
  bottom: -6px;
}
.pb-marker.active {
  box-shadow: 0 0 10px rgba(255, 208, 0, 0.5);
}
@keyframes markerGlow {
  0% { box-shadow: 0 0 0 0 rgba(52, 211, 153, 0); }
  35% { box-shadow: 0 0 12px 2px rgba(52, 211, 153, 0.5); }
  100% { box-shadow: 0 0 0 0 rgba(52, 211, 153, 0); }
}
.pb-marker.glow {
  animation: markerGlow 0.6s ease-out;
}
/* ruled tick state — the documented playbar contract (gold = active,
   green = ruled, shown on the line and its number) */
.pb-marker.ruled {
  border-color: var(--green);
}
.pb-marker.ruled > span {
  color: var(--green);
}
#playback-bar .pb-controls .t-btn {
  background: none;
  border: 1px solid var(--border);
  color: var(--text);
  font-size: 16px;
  padding: 5px 11px;
  cursor: pointer;
  border-radius: 5px;
  transition: all 0.15s;
  flex-shrink: 0;
}
#playback-bar .pb-controls .t-btn:hover {
  border-color: var(--gold);
  color: var(--gold);
}
#playback-bar .pb-controls .t-btn.primary {
  background: var(--gold);
  border-color: var(--gold);
  color: #2a2a2a;
}
#playback-bar .pb-controls .t-btn.active {
  background: var(--gold);
  border-color: var(--gold);
  color: #2a2a2a;
}
/* Fixed 40×32 box shared by the play/rewind/loop trio (#btn-play, #btn-prev,
   #btn-loop) with a flex-centred glyph, so the buttons are all the SAME size
   and the ▶↔⏸ glyph swap never reflows the box (glyph metrics no longer
   drive the box). */
#playback-bar .pb-controls #btn-play,
#playback-bar .pb-controls #btn-prev,
#playback-bar .pb-controls #btn-loop {
  width: 40px;
  height: 32px;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  line-height: 1;
}
/* Loop glyph: an inline SVG figure-8 (two mirrored lobes, crossing centre) at
   double the rewind glyph's ink. Colour follows .t-btn's currentColor, so the
   .active gold state above still reads; the 40x32 box is unchanged. */
#playback-bar .pb-controls #btn-loop svg {
  width: 36px;
  height: 24px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.4;
  stroke-linecap: round;
}
#playback-bar .pb-controls input[type="range"] {
  flex: 1;
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
  cursor: pointer;
  height: 4px;
  outline: none;
}
#playback-bar .pb-controls input[type="range"]::-webkit-slider-runnable-track {
  height: 3px;
  background: rgba(255, 208, 0, 0.7);
  border-radius: 2px;
}
#playback-bar .pb-controls input[type="range"]::-moz-range-track {
  height: 3px;
  background: rgba(255, 208, 0, 0.7);
  border-radius: 2px;
}
#playback-bar .pb-controls input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: var(--gold);
  border: 2px solid rgba(14, 14, 18, 0.9);
  margin-top: -6px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
}
#playback-bar .pb-controls input[type="range"]::-moz-range-thumb {
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: var(--gold);
  border: 2px solid rgba(14, 14, 18, 0.9);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
}
#playback-bar .pb-controls #time-lbl {
  font-size: 13px;
  color: var(--muted);
  font-family: var(--mono);
  min-width: 85px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}

/* ---------- Messenger ----------
   WIDE but playbar-safe: the playbar is centred in the viewport
   (left:50%, effective width 780px), so its right edge rests at
   50% + 390px. --mess-w widens the panel right up to that edge at any
   viewport (50% − 390px) — no overlap with the playbar — and floors at
   240px so it stays usable on narrow windows. The toggle tab rides the
   panel's left edge via the same variable. */
:root {
  --mess-w: max(240px, calc(50% - 390px));
}
#messenger {
  position: absolute;
  right: 0;
  bottom: 0;
  top: auto;
  width: var(--mess-w);
  height: calc(79% + 50px);
  background: var(--panel);
  border-left: var(--gold-line);
  border-top: var(--gold-line);
  border-radius: 12px 0 0 0;
  display: flex;
  flex-direction: column;
  z-index: 10;
  box-shadow: var(--lift-shadow), var(--rim);
  transition: transform 0.18s ease, width 0.3s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
#messenger:hover {
  transform: translateY(-2px);
  box-shadow: var(--lift-shadow-hover), var(--rim);
  border-left-color: rgba(255, 208, 0, 0.95);
  border-top-color: rgba(255, 208, 0, 0.95);
}
#messenger.collapsed {
  width: 48px;
}
#messenger.collapsed .mess-inner {
  opacity: 0;
  pointer-events: none;
}
.mess-toggle {
  position: absolute;
  right: var(--mess-w);
  top: 50%;
  transform: translateY(-50%);
  width: 22px;
  height: 64px;
  background: rgba(14, 14, 18, 0.35);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  border-left: var(--gold-line);
  border-right: none;
  border-radius: 8px 0 0 8px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  font-size: 18px;
  font-weight: 700;
  transition: right 0.3s ease, transform 0.18s ease, background 0.2s, color 0.2s, border-color 0.18s ease;
  z-index: 11;
}
.mess-toggle:hover {
  background: var(--panel-solid);
  color: var(--text);
  transform: translateY(-50%) translateX(-2px);
  border-left-color: rgba(255, 208, 0, 0.95);
}
.mess-toggle::after { content: '\203A'; }
.mess-toggle.show-back::after { content: '\2039'; }
.mess-toggle .toggle-unread {
  display: none;
  position: absolute;
  top: 6px;
  right: 4px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #ff3b30;
}
.mess-toggle .toggle-unread.visible {
  display: block;
}
/* orientation: the collapse tab glows (gold left-edge pulse) during the
   collapse-tab coach-mark step — the same gold pulse family the coach marks
   use on the messenger's back arrow and the reply box */
#mess-toggle.ori-glow {
  animation: toggleGlow 1.1s ease-in-out infinite;
}
#mess-toggle.ori-glow::after { color: var(--gold); }
@keyframes toggleGlow {
  0%, 100% { box-shadow: 0 0 0 rgba(255, 208, 0, 0); border-left-color: rgba(255, 208, 0, 0.5); }
  50% { box-shadow: -4px 0 12px rgba(255, 208, 0, 0.55); border-left-color: rgba(255, 208, 0, 0.95); }
}
#messenger .mess-inner {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transition: opacity 0.2s;
}
.mess-header {
  display: flex;
  align-items: center;
  padding: 10px 12px;
  border-radius: 11px 0 0 0;
  font-size: 14px;
  font-weight: 600;
  color: var(--muted);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  border-bottom: 1px solid var(--border);
  gap: 8px;
  flex-shrink: 0;
  background: var(--panel-solid);
}
.mess-header-back {
  background: none;
  border: none;
  color: var(--gold);
  font-size: 20px;
  cursor: pointer;
  padding: 0 4px;
  flex-shrink: 0;
}
.mess-header-back:hover { color: var(--gold); }
/* orientation: the < arrow glows while the messenger step waits on NEXT */
@keyframes backArrowGlow {
  0%, 100% { text-shadow: 0 0 4px rgba(255, 208, 0, 0.4); }
  50% { text-shadow: 0 0 12px 3px rgba(255, 208, 0, 0.9); }
}
.mess-header-back.glow {
  animation: backArrowGlow 1.1s ease-in-out infinite;
}
.mess-header-title {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 16px;
  color: var(--gold);
}
.mess-badge {
  display: none;
  background: #ff3b30;
  color: var(--bg);
  font-size: 11px;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 10px;
  min-width: 18px;
  text-align: center;
}

/* Contacts list */
.mess-contacts {
  display: flex;
  flex-direction: column;
  flex: 1;
  overflow-y: auto;
}
.mess-contact {
  display: flex;
  flex-direction: column;
  padding: 20px 12px;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  transition: background 0.15s;
}
.mess-contact:hover { background: rgba(255, 255, 255, 0.06); }
.mess-contact.unread { background: rgba(255, 208, 0, 0.08); }
.mess-contact-name-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.mess-contact-name {
  font-size: 22px;
  font-weight: 600;
  color: var(--gold-dark);
  margin-bottom: 1px;
}
.mess-contact-preview {
  font-size: 16px;
  color: rgba(240, 239, 232, 0.6);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.mess-contact-dot {
  display: none;
  flex-shrink: 0;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #ff3b30;
}

/* Empty state — "Awaiting Messages" alert. Always the last child of
   .mess-contacts (see Messenger._showContacts): with flex:1 it centres
   itself in whatever space remains below the delivered contacts, so as
   jurors arrive it drifts further down the panel. The panel's height is
   reserved for 7 slots (messenger.js _setPanelHeight), so the alert has
   room for the whole case. */
.mess-empty-state {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  color: var(--muted);
  user-select: none;
  pointer-events: none;
}
.mess-empty-state .empty-signal {
  width: 9.6px;
  height: 9.6px;
  border-radius: 50%;
  background: var(--gold);
  opacity: 0.35;
  box-shadow: 0 0 19.2px rgba(255, 208, 0, 0.35);
  animation: mess-signal-pulse 2.6s ease-in-out infinite;
}
.mess-empty-state .empty-label {
  font-size: 19.2px;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  white-space: nowrap;
  opacity: 0.7;
}
@keyframes mess-signal-pulse {
  0%, 100% { opacity: 0.2; transform: scale(0.85); }
  50%      { opacity: 0.6; transform: scale(1.2); }
}

/* Conversation view */
.mess-conversation {
  display: none;
  flex-direction: column;
  flex: 1;
  overflow: hidden;
}
.mess-messages {
  flex: 1;
  overflow-y: auto;
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
/* Tribunal-styled scrollbar inside the messenger: the global white thumb
   (shared.css) reads white-on-white against the light glass — a muted
   gold thumb keeps the tribunal accent language (width/track/radius are
   inherited from the global ::-webkit-scrollbar rules). */
#messenger ::-webkit-scrollbar-thumb { background: rgba(255, 208, 0, 0.35); }
#messenger ::-webkit-scrollbar-thumb:hover { background: rgba(255, 208, 0, 0.6); }
.mess-msg {
  max-width: 85%;
  padding: 8px 12px;
  font-size: 15px;
  line-height: 1.5;
  border-radius: 4px;
}
.mess-msg.juror {
  align-self: flex-start;
  background: rgba(255, 255, 255, 0.08);
  color: var(--text);
  border-bottom-left-radius: 0;
}
.mess-msg.player {
  align-self: flex-end;
  background: rgba(255, 208, 0, 0.2);
  color: #f0efe8;
  border-bottom-right-radius: 0;
}
/* Read receipt under the player's own sent bubble (flag on the history
   entry, revealed ~200 ms after send; persists across re-renders) */
.mess-read {
  align-self: flex-end;
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  opacity: 0;
  transition: opacity 0.25s ease;
  pointer-events: none;
  user-select: none;
}
.mess-read.visible {
  opacity: 0.5;
}

/* Typing indicator */
.mess-typing {
  align-self: flex-start;
  background: rgba(255, 255, 255, 0.08);
  padding: 10px 16px;
  border-radius: 4px;
  border-bottom-left-radius: 0;
  display: flex;
  gap: 4px;
  align-items: center;
}
.mess-typing-dot {
  width: 6px;
  height: 6px;
  background: var(--muted);
  border-radius: 50%;
  animation: mess-typing-bounce 1.2s ease-in-out infinite;
}
.mess-typing-dot:nth-child(2) { animation-delay: 0.2s; }
.mess-typing-dot:nth-child(3) { animation-delay: 0.4s; }
@keyframes mess-typing-bounce {
  0%, 60%, 100% { transform: translateY(0); opacity: 0.4; }
  30% { transform: translateY(-4px); opacity: 1; }
}

/* Reply options pinned bottom */
.mess-replies {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 8px 12px;
  border-top: 1px solid var(--border);
  background: var(--chrome);
  flex-shrink: 0;
}
/* Each reply option is a stacked, click-to-send card. The left accent bar and
   the small uppercase role label are both driven by --reply-role (set inline
   per card in messenger.js from the option's lean). No lean (e.g. the rethink
   "GO BACK" option) falls back to --muted. */
.mess-reply-btn {
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 7px 11px 7px 12px;
  background: rgba(255, 255, 255, 0.08);
  color: var(--text);
  border: 1px solid var(--border);
  border-left: 3px solid var(--reply-role, var(--muted));
  border-radius: 3px;
  cursor: pointer;
  text-align: left;
  font-size: 15px;
  line-height: 1.5;
  max-height: 112px;
  overflow-y: auto;
  transition: all 0.15s;
  font-family: var(--sans);
}
.mess-reply-btn:hover {
  background: rgba(255, 208, 0, 0.1);
  border-color: var(--gold);
  border-left-color: var(--reply-role, var(--gold));
  color: #fff;
}
.mess-reply-plain {
  font-size: 15px;
  line-height: 1.5;
  padding: 0;
  color: var(--text);
  cursor: pointer;
  transition: color 0.15s;
  font-family: var(--sans);
}
.mess-reply-plain:hover { color: var(--gold); }
/* The role label is a ::before (not a text node) so the button's textContent
   stays exactly the reply text — keeps text-based reply matching working. It
   is colored by --reply-role to match the left accent bar; --reply-label is
   'none' when the card has no label (no lean, and not the rethink option). */
.mess-reply-btn::before {
  content: var(--reply-label, none);
  display: block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  line-height: 1.2;
  color: var(--reply-role, var(--muted));
}
.mess-reply-btn:hover::before { color: var(--gold); }
.mess-reply-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-bottom: 6px;
}
.mess-reply-nav-btn {
  background: rgba(255, 255, 255, 0.06);
  color: var(--gold);
  border: 1px solid var(--border);
  border-radius: 4px;
  width: 30px;
  height: 28px;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  transition: all 0.15s;
}
.mess-reply-nav-btn:hover {
  color: var(--gold);
  border-color: var(--gold);
  background: rgba(255, 208, 0, 0.1);
}
.mess-reply-nav-label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold);
  font-family: var(--mono);
}
/* The empty reply section (no reply pending): the structure stands —
   the 'select response' row (no arrows, no label) + the reply box (no
   text) — so the chat pane's footprint is identical with or without a
   pending reply. */
.mess-reply-nav.empty { min-height: 28px; }
.mess-reply-btn.empty { cursor: default; }
.mess-reply-btn.empty:hover {
  background: rgba(255, 255, 255, 0.08);
  border-color: var(--border);
  color: var(--text);
}
/* orientation prelude: the reply prompt + buttons glow while the player
   picks — the same gold text pulse the coach marks use on the messenger's
   back arrow (backArrowGlow, 1.1s ease-in-out infinite). The class is only
   applied while the orientation owns the tribunal (messenger.js), so the
   in-game juror chat reply box keeps its plain look. */
.mess-reply-nav-label.ori-glow,
.mess-reply-nav-btn.ori-glow,
.mess-reply-btn.ori-glow,
.mess-reply-plain.ori-glow {
  animation: backArrowGlow 1.1s ease-in-out infinite;
}

/* Juror note banner */
.mess-note-banner {
  padding: 6px 12px;
  font-size: 13px;
  font-style: italic;
  color: var(--muted);
  background: rgba(255, 208, 0, 0.06);
  border-bottom: 1px solid var(--border);
  text-align: center;
  letter-spacing: 0.04em;
  flex-shrink: 0;
}

/* Meta-move buttons — small interjections below replies */
.mess-meta-moves {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  padding: 4px 12px 8px;
  flex-shrink: 0;
}
.mess-meta-btn {
  font-size: 12px;
  line-height: 1.3;
  padding: 5px 9px;
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 3px;
  cursor: pointer;
  font-family: var(--sans);
  font-style: italic;
  transition: all 0.15s;
}
.mess-meta-btn:hover {
  color: var(--text);
  border-color: rgba(255, 208, 0, 0.5);
  background: rgba(255, 208, 0, 0.1);
}

.mess-msg.juror.room-event {
  border-left: 2px solid rgba(100, 130, 180, 0.5);
  padding-left: 10px;
}

/* Blame vector display in settings menu */
.settings-vector {
  padding: 8px 14px;
  border-bottom: 1px solid var(--border);
  font-size: 12px;
  color: var(--muted);
}
.settings-vector-label {
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: 4px;
}
.settings-vector-bars {
  display: flex;
  gap: 6px;
}
.settings-vector-bar {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}
.settings-vector-bar-fill {
  width: 100%;
  height: 4px;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 2px;
  overflow: hidden;
}
.settings-vector-bar-fill-inner {
  height: 100%;
  border-radius: 2px;
  transition: width 0.3s;
}
.settings-vector-bar-fill-inner.operator { background: #8FD0C5; }
.settings-vector-bar-fill-inner.soldier { background: #EFCB9E; }
.settings-vector-bar-fill-inner.designer { background: #A9B6E3; }
.settings-vector-bar-label {
  font-size: 10px;
  text-transform: capitalize;
}

/* ---------- Standing judgment ---------- */
#titlebar .judgment-btn {
  background: none;
  border: var(--gold-line);
  color: var(--gold);
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.12em;
  cursor: pointer;
  padding: 6px 12px;
  border-radius: 5px;
  transition: all 0.15s;
}
#titlebar .judgment-btn:hover {
  background: rgba(255, 208, 0, 0.12);
  box-shadow: 0 0 10px rgba(255, 208, 0, 0.3);
}
#titlebar .judgment-btn.active {
  background: var(--gold);
  color: #2a2a2a;
}
/* Docket-complete flash (2026-10-19): the button alternates this inverted
   state (gold body, grey text + outline) and the default every 1.5 s until
   the player clicks it — toggled by js/app.js startJudgmentFlash. Placed
   after :hover so the solid body holds while hovered. */
#titlebar .judgment-btn.flashing {
  background: var(--gold);
  border-color: #8a8a8a;
  color: #8a8a8a;
}


/* ---------- Standing judgment (card panel) ---------- */
#judgment-panel {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 440px;
  max-width: calc(100% - 32px);
  max-height: calc(100% - 32px);
  background: var(--panel);
  border: var(--gold-line);
  border-radius: 12px;
  box-shadow: var(--lift-shadow), var(--rim);
  z-index: 25;
  display: none;
}
#judgment-panel.visible {
  display: flex;
  flex-direction: column;
  animation: judgmentIn 0.25s ease-out;
}
@keyframes judgmentIn {
  from { opacity: 0; transform: translate(-50%, -50%) translateY(12px); }
  to { opacity: 1; transform: translate(-50%, -50%) translateY(0); }
}
#judgment-panel .judgment-inner {
  display: flex;
  flex-direction: column;
  min-height: 0;
}
#judgment-panel .judgment-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 16px;
  border-bottom: 1px solid var(--border);
  background: var(--panel-solid);
  border-radius: 11px 11px 0 0;
  flex-shrink: 0;
}
#judgment-panel .judgment-header-title {
  font-size: 17px;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: var(--gold);
  font-family: var(--mono);
}
#judgment-panel .judgment-close {
  margin-left: auto;
  background: none;
  border: none;
  color: var(--muted);
  font-size: 21px;
  cursor: pointer;
  padding: 0 4px;
  line-height: 1;
}
#judgment-panel .judgment-close:hover {
  color: var(--text);
}
#judgment-panel .judgment-body {
  padding: 10px 16px 8px;
  overflow-y: auto;
  font-size: 16px;
  line-height: 1.45;
  color: var(--text);
  flex: 1;
  min-height: 0;
}
#judgment-panel .judgment-case {
  font-size: 13px;
  font-family: var(--mono);
  letter-spacing: 0.1em;
  color: var(--muted);
  text-transform: uppercase;
  margin-bottom: 2px;
}
#judgment-panel .judgment-title {
  font-size: 17px;
  font-weight: 600;
  margin-bottom: 1px;
  line-height: 1.3;
}
#judgment-panel .judgment-source {
  font-size: 13px;
  font-family: var(--mono);
  letter-spacing: 0.06em;
  color: var(--muted);
  margin-bottom: 10px;
}
#judgment-panel .judgment-cards {
  display: flex;
  flex-direction: column;
  gap: 7px;
}
#judgment-panel .judgment-card {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 10px;
  border-left: 2px solid rgba(255, 255, 255, 0.2);
  background: rgba(255, 255, 255, 0.03);
  border-radius: 0 6px 6px 0;
  min-width: 0;
}
#judgment-panel .judgment-card.assigned {
  border-left-color: var(--gold);
}
#judgment-panel .judgment-card.flash {
  animation: judgmentFlash 1.6s ease-out;
}
@keyframes judgmentFlash {
  0% { background: rgba(255, 208, 0, 0.14); }
  100% { background: rgba(255, 255, 255, 0.03); }
}
#judgment-panel .judgment-card-text {
  flex: 1;
  min-width: 0;
  font-size: 14.5px;
  line-height: 1.4;
  color: var(--text);
}
#judgment-panel .judgment-role-btn {
  flex-shrink: 0;
  padding: 4px 9px;
  border: 1px solid rgba(255, 255, 255, 0.25);
  background: transparent;
  color: var(--muted);
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.08em;
  cursor: pointer;
  border-radius: 4px;
  transition: all 0.15s;
  text-transform: uppercase;
  white-space: nowrap;
}
#judgment-panel .judgment-role-btn:hover {
  border-color: var(--gold);
  color: var(--gold);
}
#judgment-panel .judgment-role-btn:disabled {
  cursor: default;
  opacity: 0.55;
}
#judgment-panel .judgment-role-btn:disabled:hover {
  border-color: rgba(255, 255, 255, 0.25);
  color: var(--muted);
}
#judgment-panel .judgment-role-btn.operator {
  background: var(--blue);
  border-color: var(--blue);
  color: #2a2a2a;
}
#judgment-panel .judgment-role-btn.soldier {
  background: var(--red);
  border-color: var(--red);
  color: #2a2a2a;
}
#judgment-panel .judgment-role-btn.designer {
  background: var(--purple);
  border-color: var(--purple);
  color: #2a2a2a;
}
#judgment-panel .judgment-role-btn.unassigned {
  background: rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.25);
  color: var(--muted);
}
#judgment-panel .judgment-footer {
  display: flex;
  justify-content: flex-end;
  padding: 10px 16px 12px;
  border-top: 1px solid var(--border);
  background: var(--panel-solid);
  border-radius: 0 0 11px 11px;
  flex-shrink: 0;
}
#judgment-panel .judgment-submit {
  background: var(--gold);
  border: none;
  color: #2a2a2a;
  font-family: var(--mono);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.12em;
  cursor: pointer;
  padding: 9px 18px;
  border-radius: 5px;
  transition: all 0.15s;
}
#judgment-panel .judgment-submit:hover {
  background: var(--gold-dark);
  box-shadow: 0 0 10px rgba(255, 208, 0, 0.3);
}

/* ============================================
   Case intro (Case One) — 2026-09-13
   A full-viewport scrim behind a centered Tribunal-style judgment window
   (the #judgment-panel recipe: gold outline, 12px radius, lift-shadow +
   rim). The scrim is SOLID BLACK and lands instantly (no fade-in): it is
   the case-transition background that must be up BEFORE the case
   interface renders beneath it, so the old/next interface never loads in
   visibly unblurred (the 0.5-alpha fade used to let it through). It leaves
   the 40px titlebar strip visible (the in-app chrome; inert while up via
   body.case-intro-open). Toggled by js/app.js window.caseIntro
   (showScrim() blacks out on the handoff reply click, before the async
   case-2 mount).
   z: scrim 46 / window 47 — above #app (40) and #os-desktop (45, the R1
   prelude windows), below #os-topbar (60). Body-level so it works in both
   the OS-shell and ?no-shell boots.
   ============================================ */
#case-intro-scrim {
  position: fixed;
  inset: 0;
  /* the tribunal's titlebar strip (40px, the app chrome) stays visible over
     the black so the case reads as in-app, not a fullscreen takeover; the
     titlebar is opaque, so the cutout exposes only it */
  top: 40px;
  z-index: 46;
  background: #000;
  backdrop-filter: blur(18px) saturate(1.15);
  -webkit-backdrop-filter: blur(18px) saturate(1.15);
}
#case-intro-scrim[hidden] { display: none; }
/* the intro is a modal moment (BEGIN is the only way through): the visible
   titlebar stays inert while the scrim is up — same as when the old
   translucent scrim sat over it and captured the clicks */
body.case-intro-open #titlebar { pointer-events: none; }
#case-intro {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 47;
  /* wide enough that at a 13" laptop ratio (16:10, down to 1280×800 with
     browser chrome) the body's content fits without its internal scroll —
     the legal-defense quote wraps to five lines instead of six and the
     two single-line values stop wrapping */
  width: 980px;
  max-width: calc(100vw - 32px);
  /* at max height the centred card's top edge sits 48px from the viewport
     top — clear of the 40px titlebar, so the card never overlaps the
     tribunal chrome on short screens */
  max-height: calc(100vh - 96px);
  display: flex;
  flex-direction: column;
  /* near-opaque dark (the panel hue, 14/14/18) so the legal text reads over
     the frosted scrim; gold outline + rim + lift from the :root tokens */
  background: rgba(14, 14, 18, 0.92);
  border: var(--gold-line);
  border-radius: 12px;
  box-shadow: var(--lift-shadow), var(--rim);
  animation: ciWinIn 0.25s ease-out;
}
#case-intro[hidden] { display: none; }
@keyframes ciWinIn {
  from { opacity: 0; transform: translate(-50%, -50%) scale(0.985); }
  to { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}
#case-intro .ci-header {
  flex-shrink: 0;
  padding: 11px 18px;
  border-bottom: 1px solid var(--border);
  background: var(--panel-solid);
  border-radius: 11px 11px 0 0;
}
#case-intro .ci-header-title {
  font-size: 19px;
  font-weight: 700;
  letter-spacing: 0.16em;
  color: var(--gold);
  font-family: var(--mono);
}
#case-intro .ci-body {
  padding: 14px 18px 10px;
  overflow-y: auto;
  flex: 1;
  min-height: 0;
  font-size: 18px;
  line-height: 1.5;
  color: var(--text);
}
#case-intro .ci-heading {
  font-size: 22px;
  font-weight: 700;
  letter-spacing: 0.01em;
  margin-bottom: 14px;
  color: var(--text);
}
/* the blurred year digits: a strong digital blur + a scanline overlay so the
   specific year is not legible (the digits are the real ones, just smeared) */
.ci-blur {
  position: relative;
  display: inline-block;
  filter: blur(4px);
  color: var(--gold);
}
.ci-blur::after {
  content: "";
  position: absolute;
  inset: -2px;
  background: repeating-linear-gradient(0deg, rgba(255, 208, 0, 0.35) 0 1px, transparent 1px 3px);
  pointer-events: none;
}
#case-intro .ci-label {
  font-size: 15px;
  font-family: var(--mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gold);
  margin: 12px 0 3px;
}
#case-intro .ci-value {
  font-size: 17.5px;
  line-height: 1.5;
  color: var(--text);
}
#case-intro .ci-quote {
  margin: 8px 0 4px;
  padding: 8px 12px;
  /* the gold left-border highlight is gone — the block reads as a plain
     inset panel; the text lightens from --muted (0.55) so it reads over
     the dark card background */
  background: rgba(255, 208, 0, 0.05);
  border-radius: 6px;
  font-size: 16.5px;
  line-height: 1.5;
  color: rgba(240, 239, 232, 0.8);
  font-style: italic;
}
#case-intro .ci-footer {
  flex-shrink: 0;
  display: flex;
  justify-content: flex-end;
  padding: 11px 18px 13px;
  border-top: 1px solid var(--border);
  background: var(--panel-solid);
  border-radius: 0 0 11px 11px;
}
#case-intro .ci-begin {
  background: var(--gold);
  border: none;
  color: #2a2a2a;
  font-family: var(--mono);
  font-size: 17px;
  font-weight: 700;
  letter-spacing: 0.14em;
  cursor: pointer;
  padding: 9px 22px;
  border-radius: 5px;
  transition: all 0.15s;
}
#case-intro .ci-begin:hover {
  background: var(--gold-dark);
  box-shadow: 0 0 10px rgba(255, 208, 0, 0.3);
}

/* ============================================
   Orientation (?orient=1 — js/orientation.js)
   The automatic interface walkthrough: chrome parked until revealed,
   a loading bar over the scene, a skip control, and one repositioned
   coach-mark bubble. All of it is inert without the flag.
   ============================================ */
.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}

/* chrome parked while the orientation owns the tribunal: the scene host,
   live-feed HUD and the Maven opening captions stay warm but invisible
   (handoff reveals them) */
body.orientation-active #scene-host,
body.orientation-active .live-feed-hud,
body.orientation-active #scene-captions {
  visibility: hidden;
}
/* the module toggles [hidden] on elements whose display the author CSS
   sets (the bar is flex; the cog is flex) — the UA default can't win */
#playback-bar[hidden],
#titlebar [hidden] {
  display: none !important;
}

/* loading bar — centered over the scene */
#ori-loading {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  pointer-events: none;
}
.ori-load-txt {
  font-family: var(--mono);
  font-size: 16px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}
.ori-bar {
  width: 260px;
  height: 3px;
  border-radius: 2px;
  background: rgba(255, 208, 0, 0.15);
  overflow: hidden;
}
.ori-fill {
  height: 100%;
  width: 0%;
  background: var(--gold);
}
#ori-loading.busy .ori-fill {
  transition: width 3s linear;
}
#ori-loading[hidden] {
  display: none !important;
}
#ori-loading[hidden] {
  display: none !important;
}

/* skip control — bottom-left, muted */
.ori-skip {
  position: fixed;
  left: 16px;
  bottom: 16px;
  z-index: 90;
  background: none;
  border: 1px solid var(--border);
  color: var(--muted);
  font-family: var(--mono);
  font-size: 15px;
  letter-spacing: 0.14em;
  padding: 8px 15px;
  border-radius: 8px;
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s;
}
.ori-skip:hover {
  color: var(--text);
  border-color: rgba(255, 208, 0, 0.5);
}
.ori-skip[hidden] {
  display: none !important;
}

/* coach-mark bubble — one element, repositioned per step; body-level
   fixed so its JS-resolved anchors are viewport coordinates */
#coach-bubble {
  position: fixed;
  z-index: 95;
  max-width: 280px;
  padding: 12px 14px;
  border-radius: 10px;
  background: var(--panel-solid);
  border: var(--gold-line);
  box-shadow: var(--lift-shadow), var(--rim);
  backdrop-filter: blur(18px) saturate(1.15);
  -webkit-backdrop-filter: blur(18px) saturate(1.15);
  font-size: 15px; /* matches the messenger chat text (.mess-msg) */
  line-height: 1.5;
  color: var(--text);
}
#coach-bubble.pop {
  animation: coachIn 0.3s cubic-bezier(0.2, 0.7, 0.3, 1) both;
}
@keyframes coachIn {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}
#coach-bubble::after {
  content: '';
  position: absolute;
  width: 10px;
  height: 10px;
  background: inherit;
  border: 1px solid rgba(255, 208, 0, 0.55);
  transform: rotate(45deg);
}
#coach-bubble.pos-messenger::after {
  right: -5px;
  top: 26px;
  border-left: none;
  border-bottom: none;
}
#coach-bubble.pos-mess-toggle::after {
  right: -5px;
  top: 50%;
  margin-top: -5px;
  border-left: none;
  border-bottom: none;
}
#coach-bubble.pos-playbar::after,
#coach-bubble.pos-scrub::after {
  bottom: -5px;
  left: 50%;
  margin-left: -5px;
}
#coach-bubble.pos-overlay::after {
  left: -5px;
  bottom: 26px;
  border-right: none;
  border-top: none;
}
/* the decision card's minimise tab: the bubble floats above the tab, so its
   arrow points DOWN from the bubble's bottom edge, centred (pos-overlay aims at
   the card's body from the right — beside the tab it would cover the header) */
#coach-bubble.pos-ov-tab::after {
  bottom: -5px;
  left: 50%;
  margin-left: -5px;
}
#coach-bubble.pos-judgment::after {
  top: -5px;
  right: 44px;
  border-left: none;
  border-bottom: none;
}
#coach-bubble.pos-judgment-panel::after {
  left: -5px;
  top: 26px;
  border-right: none;
  border-bottom: none;
}
/* the amendment-window step: the bubble rides the left gutter beside the
   centred window, so its arrow points RIGHT from the bubble's right edge
   (every other pos-* anchors to chrome at a viewport edge) */
#coach-bubble.pos-final::after {
  right: -5px;
  top: 26px;
  border-left: none;
  border-bottom: none;
}
#coach-bubble .cb-btns {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 10px;
}
/* BACK sits bottom-left of the bubble (NEXT stays bottom-right): the auto
   margin eats the free space between them. With BACK hidden, NEXT alone
   right-aligns via flex-end */
#coach-bubble .cb-back {
  margin-right: auto;
}
/* BACK — same size/style family as NEXT: gold outline, black background,
   gold text, the left arrow stacked above the word */
#coach-bubble .cb-back {
  display: flex;
  flex-direction: column;
  align-items: center;
  line-height: 1;
  background: #000;
  color: var(--gold);
  border: 1px solid var(--gold);
  border-radius: 5px;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.12em;
  padding: 4px 16px 5px;
  cursor: pointer;
}
#coach-bubble .cb-back .cb-back-arrow {
  font-size: 13px;
  line-height: 1;
  margin-bottom: 2px;
}
#coach-bubble .cb-back:hover {
  background: rgba(255, 208, 0, 0.12);
}
#coach-bubble .cb-back:disabled {
  color: var(--muted);
  border-color: var(--border);
  cursor: default;
  background: none;
}
#coach-bubble .cb-back[hidden] {
  display: none !important;
}
#coach-bubble .cb-next {
  background: var(--gold);
  color: #2a2a2a;
  border: none;
  border-radius: 5px;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.12em;
  padding: 7px 16px;
  cursor: pointer;
}
#coach-bubble .cb-next:hover:not(:disabled) {
  background: var(--gold-dark);
}
#coach-bubble .cb-next:disabled {
  background: rgba(255, 208, 0, 0.25);
  color: var(--muted);
  cursor: default;
}
#coach-bubble[hidden] {
  display: none !important;
}

/* scrubber highlight pulse (the scrub step) */
.pb-scrubber-wrap.hl-pulse {
  border-radius: 4px;
  animation: scrubPulse 1.5s ease-in-out infinite;
}
@keyframes scrubPulse {
  0%, 100% { box-shadow: 0 0 0 1px rgba(255, 208, 0, 0.6); }
  50% { box-shadow: 0 0 0 3px rgba(255, 208, 0, 0.9), 0 0 16px rgba(255, 208, 0, 0.35); }
}

/* ============================================
   Final judgment — amendment window + end sequence (case end, 2026-09-16)
   Port of archive/judgment-final-window-demo.html (js/judgment-final.js
   auto-runs it; js/epilogue.js owns #end-fade + #thanks-card).
   #final-scrim = the case-intro scrim recipe, but a 2 s fade-in
    (transition, not the 0.25 s animation); the window shows at 3 s.
    z: window 47 / end-fade 48 / thanks-card 49 — above #app (40) and
    #os-desktop (45), below #os-topbar (60). The SCRIM is not in that band:
    it lives inside #app at z 30 (above #content's panels — judgment 25 /
    playback 15 / messenger 10 — below #settings-menu 100, which belongs to
    the titlebar and stays lit with it).
    The background blur is a real CSS filter on the tribunal content
    itself (body.final-veil #content below), toggled by js/judgment-final.js.
    ============================================ */
#final-scrim {
  position: absolute;
  /* Inside #app, starting under the titlebar (40px bar + 1px border): the
     tribunal's own chrome stays lit and sharp, so the fade reads as the app
     dimming its own content rather than the whole screen. In the shell's
     windowed state #app's overflow:hidden clips it to the window; in the
     ?no-shell boot #app fills the viewport, so it covers everything below
     the bar exactly as before. */
  top: 41px;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 30;
  /*
   * Pure dim: background-color transparent → rgba(0,0,0,0.72) over 2 s
   * (animated via background-color, not opacity — the element stays at
   * opacity 1 whenever displayed). Deliberately strong (0.72, not 0.5)
   * so the tribunal reads as OBSCURED on its own.
   *
   * The blur lives on the CONTENT, not on this scrim: backdrop-filter
   * on the scrim samples the tribunal behind it, but in the shell boot
   * #app is position:fixed with overflow:hidden — a composited surface
   * that backdrop-filter cannot reliably sample (and the compositor drops
   * backdrop filters under GPU load), so the scrim dimmed while the
   * tribunal stayed sharp. A real filter on #content is deterministic.
   *
   * The transition is declared ONLY on the veil state: the blur-in is a
   * smooth 2 s, and on close the after-change style (no transition)
   * governs → the unblur is instant. That asymmetry is intentional.
   *
   * Safety: the filter sits on #content, so its containing-block effect
   * reaches only #content's own descendants (all absolute, all inside a
   * nearer positioned ancestor) — never the scrim, which is a sibling.
   */
  background-color: rgba(0, 0, 0, 0);
  transition: background-color 2s ease;
  pointer-events: none;
}
#final-scrim.visible {
  background-color: rgba(0, 0, 0, 0.72);
}
#final-scrim.fast { transition-duration: 0.25s; }
#final-scrim[hidden] { display: none; }
/* The veil blurs the tribunal content itself (see the #final-scrim note
   above — backdrop-filter on a composited surface is unreliable). Scoped to
   #content so the titlebar stays sharp with it; overflow:hidden clips the
   blur's ~8px bleed at the bar's lower edge. */
body.final-veil #content {
  filter: blur(8px);
  transition: filter 2s ease;
  overflow: hidden;
}
#final-judgment {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 47;
  width: 840px;
  max-width: calc(100vw - 32px);
  max-height: calc(100vh - 32px);
  display: flex;
  flex-direction: column;
  /* near-opaque dark (the panel hue, 14/14/18) so the legal text reads over
     the frosted scrim; gold outline + rim + lift from the :root tokens */
  background: rgba(14, 14, 18, 0.92);
  border: var(--gold-line);
  border-radius: 12px;
  box-shadow: var(--lift-shadow), var(--rim);
  animation: fjWinIn 0.25s ease-out;
}
#final-judgment[hidden] { display: none; }
#final-judgment.closing { animation: fjWinOut 0.25s ease-in forwards; }
@keyframes fjWinIn {
  from { opacity: 0; transform: translate(-50%, -50%) scale(0.985); }
  to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}
@keyframes fjWinOut {
  from { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  to   { opacity: 0; transform: translate(-50%, -50%) scale(0.985); }
}
/* header / footer: the ci-header / ci-footer recipe */
#final-judgment .fj-header {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 11px 18px;
  border-bottom: 1px solid var(--border);
  background: var(--panel-solid);
  border-radius: 11px 11px 0 0;
}
#final-judgment .fj-header-title {
  font-size: 16px;
  font-weight: 700;
  letter-spacing: 0.16em;
  color: var(--gold);
  font-family: var(--mono);
}
#final-judgment .fj-footer {
  flex-shrink: 0;
  display: flex;
  justify-content: flex-end;
  padding: 11px 18px 13px;
  border-top: 1px solid var(--border);
  background: var(--panel-solid);
  border-radius: 0 0 11px 11px;
}
#final-judgment .fj-btn {
  background: var(--gold);
  border: none;
  color: #2a2a2a;
  font-family: var(--mono);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.14em;
  cursor: pointer;
  padding: 9px 22px;
  border-radius: 5px;
  transition: all 0.15s;
}
#final-judgment .fj-btn:hover {
  background: var(--gold-dark);
  box-shadow: 0 0 10px rgba(255, 208, 0, 0.3);
}
#final-judgment .fj-btn[disabled] { opacity: 0.4; cursor: default; }
/* body */
#final-judgment .fj-body {
  padding: 14px 18px 10px;
  overflow-y: auto;
  flex: 1;
  min-height: 0;
}
#final-judgment .fj-label {
  font-size: 12px;
  font-family: var(--mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gold);
  margin: 0 0 10px;
}
/* the decision banner (highlighted while its clause is rewritten) */
#final-judgment .fj-decision {
  border: 1px solid var(--border);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.03);
  padding: 10px 12px;
  margin-bottom: 10px;
  transition: border-color 0.2s, box-shadow 0.2s;
}
#final-judgment .fj-decision[hidden] { display: none; }
#final-judgment .fj-decision.active {
  border-color: rgba(255, 208, 0, 0.55);
  box-shadow: 0 0 14px rgba(255, 208, 0, 0.12);
  animation: fjDPulse 0.8s ease-out;
}
@keyframes fjDPulse {
  0%   { box-shadow: 0 0 0 rgba(255, 208, 0, 0); }
  40%  { box-shadow: 0 0 22px rgba(255, 208, 0, 0.35); }
  100% { box-shadow: 0 0 14px rgba(255, 208, 0, 0.12); }
}
#final-judgment .fj-d-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 4px;
}
#final-judgment .fj-d-count {
  font: 14px var(--mono);
  letter-spacing: 0.12em;
  color: var(--muted);
}
#final-judgment .fj-role {
  font: 700 14px var(--mono);
  letter-spacing: 0.14em;
  padding: 2px 8px;
  border-radius: 4px;
  border: 1px solid currentColor;
  color: var(--muted); /* unassigned: grey */
}
#final-judgment .fj-role.op  { color: var(--blue); }
#final-judgment .fj-role.sol { color: var(--red); }
#final-judgment .fj-role.des { color: var(--purple); }
#final-judgment .fj-d-title {
  font-size: 17px;
  font-weight: 700;
  margin-bottom: 2px;
}
#final-judgment .fj-d-sum {
  font-size: 15.5px;
  color: var(--muted);
  line-height: 1.45;
}
/* the killchain rail (2026-10-09 — replaces the six-bar progress ticks):
   one labeled stage chip per case entry, in play (killchain) order —
   FIND → FIX → TRACK → TARGET → ENGAGE → ASSESS (stageWord() in
   js/judgment-final.js extracts the word from the entry title). The chip
   rests dim while pending, glows gold while its clause is being rewritten
   (the deciding stage), then wears the ruling's colour — the same op/sol/
   des role tokens as the banner's .fj-role badge (grey UNASSIGNED). The
   arrows light green as the stage on their left is decided (the old
   .fj-tick.done green). setStage() in js/judgment-final.js drives chip+arrow. */
#final-judgment .fj-rail {
  display: flex;
  align-items: stretch;
  margin: 0 0 12px;
}
#final-judgment .fj-stage {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  padding: 7px 12px 6px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.02);
  transition: border-color 0.3s, background 0.3s, box-shadow 0.3s;
}
#final-judgment .fj-stage-name {
  font: 700 11px var(--mono);
  letter-spacing: 0.14em;
  color: var(--muted);
  transition: color 0.3s;
}
/* the state line under the word — reserves its height so chips never shift */
#final-judgment .fj-stage-sub {
  font: 9px var(--mono);
  letter-spacing: 0.12em;
  line-height: 10px;
  color: transparent;
}
#final-judgment .fj-arrow {
  flex: 1 1 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  font: 12px var(--mono);
  color: rgba(255, 255, 255, 0.16);
  transition: color 0.3s;
}
#final-judgment .fj-stage.now {
  border-color: rgba(255, 208, 0, 0.6);
  background: rgba(255, 208, 0, 0.05);
  box-shadow: 0 0 14px rgba(255, 208, 0, 0.18);
  animation: fjStagePulse 0.8s ease-out;
}
#final-judgment .fj-stage.now .fj-stage-name,
#final-judgment .fj-stage.now .fj-stage-sub { color: var(--gold); }
@keyframes fjStagePulse {
  0%   { box-shadow: 0 0 0 rgba(255, 208, 0, 0); }
  40%  { box-shadow: 0 0 22px rgba(255, 208, 0, 0.35); }
  100% { box-shadow: 0 0 14px rgba(255, 208, 0, 0.18); }
}
#final-judgment .fj-stage.done.op {
  border-color: color-mix(in srgb, var(--blue) 55%, transparent);
  background: color-mix(in srgb, var(--blue) 5%, transparent);
}
#final-judgment .fj-stage.done.op .fj-stage-name,
#final-judgment .fj-stage.done.op .fj-stage-sub { color: var(--blue); }
#final-judgment .fj-stage.done.sol {
  border-color: color-mix(in srgb, var(--red) 55%, transparent);
  background: color-mix(in srgb, var(--red) 5%, transparent);
}
#final-judgment .fj-stage.done.sol .fj-stage-name,
#final-judgment .fj-stage.done.sol .fj-stage-sub { color: var(--red); }
#final-judgment .fj-stage.done.des {
  border-color: color-mix(in srgb, var(--purple) 55%, transparent);
  background: color-mix(in srgb, var(--purple) 5%, transparent);
}
#final-judgment .fj-stage.done.des .fj-stage-name,
#final-judgment .fj-stage.done.des .fj-stage-sub { color: var(--purple); }
#final-judgment .fj-stage.done.unassigned { border-color: rgba(255, 255, 255, 0.22); }
#final-judgment .fj-stage.done.unassigned .fj-stage-name { color: var(--muted); }
#final-judgment .fj-stage.done.unassigned .fj-stage-sub { color: rgba(240, 239, 232, 0.4); }
#final-judgment .fj-arrow.done { color: var(--green); }
/* the judgment document: the original v0 paragraph, six segments */
#final-judgment .fj-doc {
  border: 1px solid var(--border);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.02);
  padding: 14px 16px;
  transition: opacity 0.25s;
}
#final-judgment .fj-doc.fading { opacity: 0.25; }
#final-judgment .fj-doc-label {
  font: 11px var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--gold);
  margin: 0 0 6px;
}
#final-judgment .fj-judgment-text {
  font-size: 15.5px;
  line-height: 1.6;
  margin: 0;
  font-style: italic;
  color: var(--text);
}
#final-judgment .fj-judgment-text .fj-seg { transition: color 0.3s; }
#final-judgment .fj-judgment-text .fj-seg.amend.op  { color: var(--blue); font-style: normal; }
#final-judgment .fj-judgment-text .fj-seg.amend.sol { color: var(--red); font-style: normal; }
#final-judgment .fj-judgment-text .fj-seg.amend.des { color: var(--purple); font-style: normal; }
#final-judgment .fj-judgment-text .fj-seg.typing { color: var(--gold); font-style: normal; }
#final-judgment .fj-judgment-text .fj-seg.hl {
  background: rgba(255, 208, 0, 0.07);
  outline: 1px solid rgba(255, 208, 0, 0.35);
  outline-offset: 2px;
  border-radius: 3px;
}
#final-judgment .fj-caret { color: var(--gold); }
/* Phase B (post-FINISH): the document rebuilds as the whole standing
   judgment — three paragraphs. Para 1 (Maven) is re-typed PLAIN (no
   .op/.sol/.des colour); paras 2-3 (Lattice / Helsing) stay at their
   original v0 ("two more paragraphs yet to edit"). */
#final-judgment .fj-judgment-text .fj-para {
  margin: 0 0 14px;
}
#final-judgment .fj-judgment-text .fj-para:last-child { margin-bottom: 0; }

/* end sequence (js/epilogue.js): black fade, then the thanks card */
#end-fade {
  position: fixed;
  inset: 0;
  z-index: 48;
  background: #000;
  opacity: 0;
  pointer-events: none;
  transition: opacity 1s;
}
#end-fade.visible {
  opacity: 1;
  pointer-events: auto;
}
#thanks-card {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 49;
  width: 560px;
  max-width: calc(100vw - 32px);
  padding: 40px;
  text-align: center;
  background: rgba(14, 14, 18, 0.92);
  border: var(--gold-line);
  border-radius: 12px;
  box-shadow: var(--lift-shadow), var(--rim);
  opacity: 0;
  pointer-events: none;
}
#thanks-card.visible { opacity: 1; }
#thanks-card .thanks-small {
  font: 12px var(--mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 8px;
}
#thanks-card .thanks-big {
  font: 700 28px var(--mono);
  letter-spacing: 0.16em;
  color: var(--gold);
}
