/* Hindsight evidence console
   ---------------------------------------------------------------------------
   Design tokens first, then layout. Both themes are authored explicitly rather
   than by inverting one palette, so contrast is deliberate in each. Colour is
   never the sole carrier of meaning: every status also has a label or an icon.
*/

/* -- Tokens --------------------------------------------------------------- */

:root {
  /* Type scale, 1.25 ratio, fluid at the display sizes */
  --step--1: 0.8125rem;
  --step-0: 0.9375rem;
  --step-1: 1.0625rem;
  --step-2: 1.375rem;
  --step-3: 1.75rem;
  --step-4: clamp(2rem, 1.4rem + 2.6vw, 3rem);
  --step-5: clamp(2.6rem, 1.4rem + 5.2vw, 4.75rem);

  /* Spacing scale */
  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.5rem;
  --sp-6: 2rem;
  --sp-7: 3rem;
  --sp-8: 4rem;

  --radius-sm: 8px;
  --radius: 14px;
  --radius-lg: 20px;

  --measure: 68ch;
  --shell: 1180px;

  --font-sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", "Cascadia Code", Consolas, monospace;

  --ring: 0 0 0 3px color-mix(in srgb, var(--accent) 45%, transparent);
  --transition: 160ms cubic-bezier(0.2, 0, 0.2, 1);
}

/* Dark theme (default)
   The brand accent is deliberately NOT green. Green means clear_for_release and
   red means confirmed leakage; keeping the accent off both scales means every
   coloured verdict on the page carries meaning instead of decoration. */
:root,
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #0b0f17;
  --bg-elev: #0f141f;
  --surface: #121826;
  --surface-2: #171e2e;
  --border: #232b3d;
  --border-strong: #323c52;

  --text: #e8ecf5;
  --text-muted: #9aa5bd;
  --text-faint: #808eac;

  --accent: #7c86ff;
  --accent-ink: #070a12;
  --accent-soft: #1a1f3a;

  --danger: #ff6b6b;
  --danger-soft: #2a1216;
  --warn: #f5b544;
  --warn-soft: #2a2110;
  --ok: #3ddc97;
  --ok-soft: #10281f;

  --shadow: 0 1px 2px rgb(0 0 0 / 0.4), 0 12px 32px -12px rgb(0 0 0 / 0.65);
  --grid-line: rgb(124 134 255 / 0.05);
}

/* Light theme */
:root[data-theme="light"] {
  color-scheme: light;
  --bg: #eaeef5;
  --bg-elev: #ffffff;
  --surface: #ffffff;
  --surface-2: #f4f6fb;
  --border: #d3dae7;
  --border-strong: #b6bfd2;

  --text: #0f1420;
  --text-muted: #4f5771;
  --text-faint: #5d647a;

  --accent: #4f46e5;
  --accent-ink: #ffffff;
  --accent-soft: #ecebfd;

  --danger: #c2251f;
  --danger-soft: #fdecea;
  --warn: #8a5a00;
  --warn-soft: #fdf3e0;
  --ok: #067a4a;
  --ok-soft: #e3f5eb;

  --shadow: 0 1px 2px rgb(15 20 32 / 0.07), 0 10px 24px -12px rgb(15 20 32 / 0.20);
  --grid-line: rgb(79 70 229 / 0.05);
}

/* Honour the OS when the visitor has expressed no preference. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme]) {
    color-scheme: light;
    --bg: #eaeef5;
    --bg-elev: #ffffff;
    --surface: #ffffff;
    --surface-2: #f4f6fb;
    --border: #d3dae7;
    --border-strong: #b6bfd2;
    --text: #0f1420;
    --text-muted: #4f5771;
    --text-faint: #5d647a;
    --accent: #4f46e5;
    --accent-ink: #ffffff;
    --accent-soft: #ecebfd;
    --danger: #c2251f;
    --danger-soft: #fdecea;
    --warn: #8a5a00;
    --warn-soft: #fdf3e0;
    --ok: #067a4a;
    --ok-soft: #e3f5eb;
    --shadow: 0 1px 2px rgb(15 20 32 / 0.07), 0 10px 24px -12px rgb(15 20 32 / 0.20);
    --grid-line: rgb(79 70 229 / 0.05);
  }
}

/* -- Base ----------------------------------------------------------------- */

*,
*::before,
*::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background:
    linear-gradient(var(--grid-line) 1px, transparent 1px) 0 0 / 100% 56px,
    var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--step-0);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { line-height: 1.15; letter-spacing: -0.02em; margin: 0; text-wrap: balance; }
h1 { font-size: var(--step-5); font-weight: 800; }
h2 { font-size: var(--step-3); font-weight: 700; }
h3 { font-size: var(--step-2); font-weight: 650; }
p { margin: 0; text-wrap: pretty; }
code, pre, .mono { font-family: var(--font-mono); font-size: 0.92em; }

a { color: var(--accent); }

:where(a, button, input, summary, [tabindex]):focus-visible {
  outline: none;
  box-shadow: var(--ring);
  border-radius: var(--radius-sm);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

.skip-link {
  position: absolute;
  left: var(--sp-4);
  top: -100px;
  z-index: 100;
  background: var(--accent);
  color: var(--accent-ink);
  padding: var(--sp-2) var(--sp-4);
  border-radius: var(--radius-sm);
  font-weight: 600;
  transition: top var(--transition);
}
.skip-link:focus { top: var(--sp-4); }

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}

/* -- App shell ------------------------------------------------------------ */

.app {
  display: grid;
  grid-template-columns: 232px minmax(0, 1fr);
  min-height: 100vh;
}

.sidebar {
  display: flex;
  flex-direction: column;
  gap: var(--sp-6);
  padding: var(--sp-5) var(--sp-4);
  background: var(--bg-elev);
  border-right: 1px solid var(--border);
  position: sticky;
  top: 0;
  height: 100vh;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  font-weight: 700;
  color: var(--text);
  text-decoration: none;
  letter-spacing: -0.01em;
}
.brand-mark {
  display: grid;
  place-items: center;
  width: 28px; height: 28px;
  border-radius: 8px;
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 800;
}

.nav { display: grid; gap: 2px; flex: 1; align-content: start; }
.nav-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin: var(--sp-4) 0 var(--sp-2) var(--sp-3);
}
.nav-label:first-child { margin-top: 0; }

.nav-item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  text-decoration: none;
  font-size: var(--step-0);
  transition: background var(--transition), color var(--transition);
}
.nav-item:hover { background: var(--surface-2); color: var(--text); }
.nav-item.is-active { background: var(--accent-soft); color: var(--accent); font-weight: 600; }

.nav-dot {
  width: 5px; height: 5px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.55;
  flex: none;
}
.nav-item.is-active .nav-dot { opacity: 1; }
.nav-count {
  margin-left: auto;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text-muted);
}

.sidebar-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
}
.version { font-size: var(--step--1); color: var(--text-faint); }

.theme-toggle {
  display: inline-grid;
  place-items: center;
  width: 32px; height: 32px;
  border-radius: 9px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-muted);
  cursor: pointer;
  transition: color var(--transition), border-color var(--transition);
}
.theme-toggle:hover { color: var(--text); border-color: var(--border-strong); }
.theme-toggle svg { width: 16px; height: 16px; }
:root[data-theme="light"] .icon-moon { display: none; }
:root:not([data-theme="light"]) .icon-sun { display: none; }
@media (prefers-color-scheme: light) {
  :root:not([data-theme]) .icon-moon { display: none; }
  :root:not([data-theme]) .icon-sun { display: block; }
}

.frame { display: flex; flex-direction: column; min-width: 0; }

.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  padding: var(--sp-3) var(--sp-6);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border);
  min-height: 52px;
}
.topbar-spacer { flex: 1; }

.crumbs { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--step--1); color: var(--text-muted); }
.crumbs a { color: var(--text-muted); text-decoration: none; }
.crumbs a:hover { color: var(--accent); }
.crumbs .sep { color: var(--text-faint); }

/* Connection state is probed, not asserted. Each state gets its own colour AND
   its own label, so meaning never depends on colour alone. */
.connection {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--step--1);
  padding: var(--sp-1) var(--sp-3);
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-muted);
}
.connection .pulse { width: 7px; height: 7px; border-radius: 50%; background: var(--text-faint); flex: none; }
.connection[data-state="connected"] { color: var(--ok); border-color: var(--ok); background: var(--ok-soft); }
.connection[data-state="connected"] .pulse {
  background: var(--ok);
  box-shadow: 0 0 0 0 color-mix(in srgb, var(--ok) 60%, transparent);
  animation: pulse 2.4s ease-out infinite;
}
.connection[data-state="degraded"] { color: var(--warn); border-color: var(--warn); background: var(--warn-soft); }
.connection[data-state="degraded"] .pulse { background: var(--warn); }
.connection[data-state="offline"] { color: var(--danger); border-color: var(--danger); background: var(--danger-soft); }
.connection[data-state="offline"] .pulse { background: var(--danger); }
.connection[data-state="not_configured"] .pulse { background: var(--text-faint); }

@keyframes pulse {
  70% { box-shadow: 0 0 0 7px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}

.content {
  flex: 1;
  padding: var(--sp-6);
  display: grid;
  gap: var(--sp-5);
  align-content: start;
  max-width: 1240px;
  width: 100%;
}

.page-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--sp-5);
  align-items: center;
}
.page-head h1 { font-size: var(--step-4); }
.page-head .accent { color: var(--accent); }

.eyebrow {
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: var(--sp-2);
}
.lede { font-size: var(--step-1); color: var(--text-muted); max-width: var(--measure); }
.prose { color: var(--text-muted); max-width: var(--measure); }
.fine { color: var(--text-faint); font-size: var(--step--1); max-width: var(--measure); margin-top: var(--sp-4); }

.panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--sp-5);
  box-shadow: var(--shadow);
}

.section-heading {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-4);
  flex-wrap: wrap;
  margin-bottom: var(--sp-5);
}

/* -- Banner, cards, empty, table ------------------------------------------ */

.banner {
  display: flex;
  gap: var(--sp-3);
  align-items: baseline;
  flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius);
  border: 1px solid var(--border-strong);
  background: var(--surface-2);
  font-size: var(--step--1);
  color: var(--text-muted);
}
.banner[data-state="offline"] { border-color: var(--danger); background: var(--danger-soft); }
.banner[data-state="degraded"] { border-color: var(--warn); background: var(--warn-soft); }
.banner strong { color: var(--text); }
.banner a { margin-left: auto; }

.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: var(--sp-4); }
.card {
  padding: var(--sp-4) var(--sp-5);
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  display: grid;
  gap: var(--sp-1);
}
.card-label { font-size: var(--step--1); text-transform: uppercase; letter-spacing: 0.07em; color: var(--text-muted); font-weight: 700; }
.card-value { font-size: var(--step-3); font-weight: 800; line-height: 1.1; font-variant-numeric: tabular-nums; }
.card-value.small { font-size: var(--step-1); font-weight: 700; }
.card-note { font-size: var(--step--1); color: var(--text-faint); }
.card.is-block { border-color: var(--danger); background: var(--danger-soft); }
.card.is-block .card-value { color: var(--danger); }
.card.is-clear { border-color: var(--ok); background: var(--ok-soft); }
.card.is-clear .card-value { color: var(--ok); }

.empty {
  display: grid;
  gap: var(--sp-4);
  justify-items: center;
  text-align: center;
  padding: var(--sp-8) var(--sp-5);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--surface);
}
.empty p { color: var(--text-muted); max-width: 52ch; }

.table-wrap { overflow-x: auto; }
.table { width: 100%; border-collapse: collapse; font-size: var(--step--1); }
.table th, .table td { text-align: left; padding: var(--sp-3); border-bottom: 1px solid var(--border); }
.table thead th {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--text-muted); font-weight: 700; white-space: nowrap;
}
.table tbody tr:hover { background: var(--surface-2); }
.table tbody th { font-weight: 500; }
.table .num { font-variant-numeric: tabular-nums; }
.table a { text-decoration: none; }
.table a:hover { text-decoration: underline; }

.kv { display: grid; gap: 0; margin: 0; }
.kv > div {
  display: grid;
  grid-template-columns: 190px minmax(0, 1fr);
  gap: var(--sp-4);
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--border);
}
.kv > div:last-child { border-bottom: 0; }
.kv dt { color: var(--text-muted); font-size: var(--step--1); }
.kv dd { margin: 0; overflow-wrap: anywhere; }

.checks { margin: 0; padding-left: var(--sp-5); display: grid; gap: var(--sp-3); color: var(--text-muted); }
.checks strong { color: var(--text); }


/* -- Explainer ------------------------------------------------------------ */

.explainer { display: grid; gap: var(--sp-5); }

.explainer-steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: var(--sp-4);
  counter-reset: step;
}

.step {
  position: relative;
  padding: var(--sp-5) var(--sp-4) var(--sp-4);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.step::before {
  counter-increment: step;
  content: counter(step);
  position: absolute;
  top: calc(-1 * var(--sp-3));
  left: var(--sp-4);
  display: grid;
  place-items: center;
  width: 26px; height: 26px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: var(--step--1);
  font-weight: 800;
}
.step h3 { font-size: var(--step-1); margin-bottom: var(--sp-2); }
.step p { color: var(--text-muted); font-size: var(--step--1); }

.callout {
  border-left: 3px solid var(--accent);
  background: var(--accent-soft);
  padding: var(--sp-4) var(--sp-5);
  border-radius: 0 var(--radius) var(--radius) 0;
}
.callout p { max-width: var(--measure); }

/* -- Hero ----------------------------------------------------------------- */

.hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--sp-6);
  align-items: center;
}
.hero h1 span { color: var(--accent); display: block; }

.decision-card {
  display: grid;
  gap: var(--sp-1);
  padding: var(--sp-5) var(--sp-6);
  border-radius: var(--radius);
  border: 1px solid var(--danger);
  background: var(--danger-soft);
  min-width: 230px;
}
.decision-card p {
  font-size: var(--step--1);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  font-weight: 700;
}
.decision-card strong { font-size: var(--step-4); color: var(--danger); line-height: 1; font-weight: 800; }
.decision-card small { color: var(--text-muted); }

.facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface);
}
.facts > div {
  padding: var(--sp-4) var(--sp-5);
  border-right: 1px solid var(--border);
  display: grid;
  gap: var(--sp-1);
}
.facts > div:last-child { border-right: 0; }
.facts span { font-size: var(--step--1); color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.06em; }
.facts strong { font-size: var(--step-1); }

/* -- Info control --------------------------------------------------------- */

.info {
  display: inline-grid;
  place-items: center;
  width: 18px; height: 18px;
  margin-left: 6px;
  padding: 0;
  vertical-align: middle;
  border-radius: 50%;
  border: 1px solid var(--border-strong);
  background: var(--surface-2);
  color: var(--text-muted);
  font: 700 11px/1 var(--font-sans);
  cursor: pointer;
  transition: all var(--transition);
}
.info:hover,
.info[aria-expanded="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}

.popover {
  position: absolute;
  z-index: 50;
  width: min(340px, calc(100vw - 2rem));
  padding: var(--sp-4);
  background: var(--bg-elev);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  display: grid;
  gap: var(--sp-2);
}
.popover[hidden] { display: none; }
.popover h4 { margin: 0; font-size: var(--step-0); }
.popover .short { color: var(--accent); font-weight: 600; font-size: var(--step--1); }
.popover p { font-size: var(--step--1); color: var(--text-muted); line-height: 1.55; }

/* -- Lineage -------------------------------------------------------------- */

.lineage {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: var(--sp-4);
  align-items: center;
}
.asset {
  display: grid;
  gap: var(--sp-1);
  padding: var(--sp-4);
  border-radius: var(--radius);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-left: 3px solid var(--border-strong);
}
.asset.source { border-left-color: var(--danger); }
.asset.target { border-left-color: var(--warn); }
.asset span { font-size: var(--step--1); text-transform: uppercase; letter-spacing: 0.07em; color: var(--text-muted); }
.asset strong { font-size: var(--step-1); }
.asset code { color: var(--accent); }

.lineage-edge { display: grid; justify-items: center; gap: var(--sp-1); color: var(--danger); }
.lineage-edge span { font-size: var(--step--1); color: var(--text-muted); white-space: nowrap; }
.lineage-edge i { font-style: normal; font-size: var(--step-2); }

.finding {
  align-self: flex-start;
  padding: var(--sp-1) var(--sp-3);
  border-radius: 999px;
  font-size: var(--step--1);
  font-weight: 700;
  border: 1px solid transparent;
  white-space: nowrap;
}
.finding.danger { background: var(--danger-soft); color: var(--danger); border-color: var(--danger); }
.finding.ok { background: var(--ok-soft); color: var(--ok); border-color: var(--ok); }
.finding.warn { background: var(--warn-soft); color: var(--warn); border-color: var(--warn); }

/* -- Ablation trap -------------------------------------------------------- */

.trap { display: grid; grid-template-columns: 1fr auto 1fr; gap: var(--sp-4); align-items: stretch; }
.trap-card {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: var(--sp-4);
  padding: var(--sp-5);
  border-radius: var(--radius);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-left: 3px solid var(--danger);
}
.trap-card.safe { border-left-color: var(--ok); }
.trap-card p { font-size: var(--step--1); color: var(--text-muted); }
.trap-card .value { font-size: var(--step-4); font-weight: 800; color: var(--danger); line-height: 1; }
.trap-card.safe .value { color: var(--ok); }
.trap-card .state { font-size: var(--step--1); font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--danger); }
.trap-card.safe .state { color: var(--ok); }
.trap-op { display: grid; place-items: center; font-size: var(--step-3); color: var(--text-faint); font-weight: 700; }

/* -- Meters --------------------------------------------------------------- */

.metric { display: grid; gap: var(--sp-2); margin-bottom: var(--sp-4); }
.metric-head { display: flex; justify-content: space-between; gap: var(--sp-4); align-items: baseline; }
.metric-head span { color: var(--text-muted); font-size: var(--step--1); }
.metric-head strong { font-variant-numeric: tabular-nums; }
.meter { height: 8px; border-radius: 999px; background: var(--surface-2); overflow: hidden; border: 1px solid var(--border); }
.meter > i { display: block; height: 100%; border-radius: 999px; }
.meter.bad > i { background: var(--danger); }
.meter.mid > i { background: var(--warn); }
.meter.good > i { background: var(--ok); }

.headline-stat { font-size: var(--step-4); font-weight: 800; color: var(--danger); line-height: 1; }

.pairs { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: var(--sp-3); margin-top: var(--sp-4); }
.pair { padding: var(--sp-3) var(--sp-4); border-radius: var(--radius-sm); background: var(--surface-2); border: 1px solid var(--border); display: grid; gap: 2px; }
.pair span { font-size: var(--step--1); color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.06em; }
.pair strong { font-variant-numeric: tabular-nums; }

/* -- Activity log --------------------------------------------------------- */

.log-shell { display: grid; gap: var(--sp-4); }
.log-controls { display: flex; gap: var(--sp-3); align-items: center; flex-wrap: wrap; }

.log {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--sp-4);
  max-height: 420px;
  overflow-y: auto;
  display: grid;
  gap: 2px;
  align-content: start;
}

.log-line {
  display: grid;
  grid-template-columns: auto auto 1fr auto;
  gap: var(--sp-3);
  padding: var(--sp-2);
  border-radius: var(--radius-sm);
  align-items: baseline;
  animation: logIn 260ms ease-out both;
}
.log-line:hover { background: var(--surface); }
@keyframes logIn { from { opacity: 0; transform: translateY(-3px); } to { opacity: 1; transform: none; } }

.log-line .chan {
  text-transform: uppercase;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.07em;
  padding: 2px 7px;
  border-radius: 5px;
  background: var(--surface-2);
  color: var(--text-muted);
  border: 1px solid var(--border);
  white-space: nowrap;
}
.log-line .chan[data-channel="datahub"],
.log-line .chan[data-channel="mcp"] { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); }
.log-line .chan[data-channel="writeback"] { color: var(--warn); border-color: var(--warn); background: var(--warn-soft); }

.log-line .mark { font-weight: 700; }
.log-line[data-ok="true"] .mark { color: var(--ok); }
.log-line[data-ok="false"] .mark { color: var(--danger); }
.log-line[data-ok="null"] .mark { color: var(--text-faint); }

.log-line .body { display: grid; gap: 1px; min-width: 0; }
.log-line .msg { color: var(--text); }
.log-line .detail { color: var(--text-faint); overflow-wrap: anywhere; }

.log-line .src {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-faint);
  white-space: nowrap;
}
.log-line .src[data-source="live"] { color: var(--ok); }

.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-5);
  border-radius: 999px;
  border: 1px solid transparent;
  background: var(--accent);
  color: var(--accent-ink);
  font: 600 var(--step-0) var(--font-sans);
  cursor: pointer;
  transition: filter var(--transition), transform var(--transition);
}
.btn:hover { filter: brightness(1.08); }
.btn:active { transform: translateY(1px); }
.btn.ghost { background: transparent; color: var(--text); border-color: var(--border-strong); }
.btn.ghost:hover { border-color: var(--accent); color: var(--accent); }
.btn[disabled] { opacity: 0.5; cursor: not-allowed; }

/* -- Trace and remediation ------------------------------------------------ */

.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: var(--sp-5); }

.trace { list-style: none; margin: 0; padding: 0; display: grid; }
.trace li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-4);
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--border);
}
.trace li:last-child { border-bottom: 0; }
.trace .n { font-family: var(--font-mono); color: var(--text-faint); font-size: var(--step--1); }
.trace strong { display: block; font-weight: 650; }
.trace em { font-style: normal; color: var(--text-muted); font-size: var(--step--1); }

pre.sql {
  margin: 0;
  padding: var(--sp-4);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow-x: auto;
  color: var(--accent);
}

/* -- Form ----------------------------------------------------------------- */

.publish { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: var(--sp-6); }
.field { display: grid; gap: var(--sp-2); margin-bottom: var(--sp-4); }
.field label { font-size: var(--step--1); font-weight: 650; }
.field input[type="text"],
.field input[type="url"] {
  width: 100%;
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong);
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: var(--step--1);
}
.consent { display: flex; gap: var(--sp-3); align-items: flex-start; margin-bottom: var(--sp-4); }
.consent input { margin-top: 4px; width: 16px; height: 16px; accent-color: var(--accent); }
.consent label { font-size: var(--step--1); color: var(--text-muted); }

.result {
  margin-top: var(--sp-4);
  padding: var(--sp-4);
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface-2);
  font-family: var(--font-mono);
  font-size: var(--step--1);
}
.result.ok { border-color: var(--ok); background: var(--ok-soft); }
.result.err { border-color: var(--danger); background: var(--danger-soft); }

/* -- Footer --------------------------------------------------------------- */

.footer {
  max-width: var(--shell);
  margin: 0 auto;
  padding: var(--sp-5);
  border-top: 1px solid var(--border);
  display: flex;
  justify-content: space-between;
  gap: var(--sp-4);
  flex-wrap: wrap;
  color: var(--text-faint);
  font-size: var(--step--1);
}

/* -- Responsive ----------------------------------------------------------- */

@media (max-width: 860px) {
  .hero { grid-template-columns: 1fr; }
  .lineage, .trap { grid-template-columns: 1fr; }
  .lineage-edge, .trap-op { transform: rotate(90deg); padding: var(--sp-2) 0; }
  .facts > div { border-right: 0; border-bottom: 1px solid var(--border); }
}

@media (max-width: 560px) {
  .shell { padding: var(--sp-5) var(--sp-4) var(--sp-7); }
  .panel { padding: var(--sp-5) var(--sp-4); }
  .log-line { grid-template-columns: auto 1fr; }
  .log-line .src { display: none; }
}

/* -- Print ----------------------------------------------------------------
   A release audit is a record, and records get printed, attached to a change
   request, or filed as a PDF. That page should look deliberate rather than
   like a web page someone hit Ctrl+P on.

   It prints what is on screen: whichever reading level you chose is the one
   you get, because a printout that silently differs from the page you were
   reading is worse than no printout.
------------------------------------------------------------------------- */

@media print {
  /* Dark mode on paper is unreadable and empties a cartridge. Force the light
     token set regardless of the visitor's theme. */
  :root, :root[data-theme="dark"], :root[data-theme="light"] {
    --bg: #ffffff;
    --surface: #ffffff;
    --surface-2: #ffffff;
    --border: #c8cdd8;
    --border-strong: #9aa2b4;
    --text: #000000;
    --text-muted: #33384a;
    --text-faint: #4a5164;
    --accent: #2a2f8f;
    --accent-ink: #ffffff;
    --accent-soft: #eeeefb;
    --shadow: none;
    --grid-line: transparent;
  }

  /* Verdict colour is evidence, not decoration - a printed BLOCK that came out
     grey has lost the thing the reader needs first. */
  * { print-color-adjust: exact; -webkit-print-color-adjust: exact; }

  @page { margin: 16mm 14mm; }

  html, body { background: #fff; font-size: 10.5pt; }

  /* Navigation, controls and anything that only exists to be clicked. */
  .sidebar, .topbar, .jumpnav, .mode-switch, .theme-toggle,
  .log-controls, .btn, form, .info, .scenario-picker, .skip-link { display: none !important; }

  .app { display: block; }
  .content { display: block; max-width: none; padding: 0; }
  .content > * { animation: none !important; margin-bottom: 10mm; }

  /* Panels are the natural page unit; keep each one whole where it fits. */
  .panel, .story-verdict, .analogy, .how-we-knew, .routes, .trust-item,
  .story-card, .beat, .card, .story-timeline {
    break-inside: avoid;
    box-shadow: none;
  }
  .panel::before, .story-verdict::before, .analogy::before,
  .how-we-knew::before, .routes::before, .trust::before,
  .story-timeline::before { display: none; }

  h1, h2, h3 { break-after: avoid; }

  /* Collapsed detail is invisible on paper, and the timeline's table twin is
     the accessible copy of the chart - it should be in the record. */
  details { display: block; }
  details > summary { display: none; }
  details > *:not(summary) { display: revert; }

  /* A citation the reader cannot follow is not a citation. */
  a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 8.5pt;
    color: #33384a;
    word-break: break-all;
  }

  /* Loose pages need to say which run they came from. */
  .print-slug { display: block !important; }
}

/* On screen this is redundant with the breadcrumb; on paper it is the only
   thing tying the sheet to a run. */
.print-slug { display: none; }

/* -- App shell responsive -------------------------------------------------- */

@media (max-width: 900px) {
  .app { grid-template-columns: 1fr; }
  .sidebar {
    position: static;
    height: auto;
    flex-direction: row;
    align-items: center;
    gap: var(--sp-4);
    border-right: 0;
    border-bottom: 1px solid var(--border);
    overflow-x: auto;
    padding: var(--sp-3) var(--sp-4);
  }
  .nav { display: flex; gap: var(--sp-1); flex: 1; }
  .nav-label { display: none; }
  .nav-item { white-space: nowrap; }
  .sidebar-foot { padding-top: 0; border-top: 0; }
  .version { display: none; }
  .content { padding: var(--sp-5) var(--sp-4); }
  .page-head { grid-template-columns: 1fr; }
  .kv > div { grid-template-columns: 1fr; gap: var(--sp-1); }
}

/* -- The cutoff timeline ---------------------------------------------------
   The product's whole thesis, drawn: a hard vertical rule at the moment of
   decision, data that stays left of it, and one feature reaching across.
   Colour is never the only signal - every track carries a label, a marker
   glyph, and a text note, and a table view repeats every value.
------------------------------------------------------------------------- */

.timeline {
  position: relative;
  display: grid;
  gap: var(--sp-2);
  padding: var(--sp-5) 0 0;
}

/* Zones: knowable to the left of the rule, not-yet-knowable to the right. */
.tl-zones {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.tl-zone {
  position: absolute;
  top: 0;
  bottom: 26px;
  border-radius: var(--radius-sm);
}
.tl-zone.past { left: 0; background: color-mix(in srgb, var(--ok) 5%, transparent); }
.tl-zone.future {
  right: 0;
  background:
    repeating-linear-gradient(
      135deg,
      color-mix(in srgb, var(--danger) 9%, transparent) 0 2px,
      transparent 2px 8px
    );
}

/* The cutoff rule itself - the single most important line on the page. */
.tl-cutoff {
  position: absolute;
  top: 0;
  bottom: 26px;
  width: 0;
  border-left: 2px solid var(--danger);
  z-index: 2;
}
.tl-cutoff::before {
  content: attr(data-label);
  position: absolute;
  top: -22px;
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  font: 700 10px/1 var(--font-sans);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--danger);
  background: var(--surface);
  padding: 0 var(--sp-2);
}

.tl-zone-label {
  position: absolute;
  top: -22px;
  font: 600 10px/1 var(--font-sans);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.tl-zone-label.left { left: 0; }
.tl-zone-label.right { right: 0; }

/* One row per asset. */
.tl-track {
  position: relative;
  display: grid;
  grid-template-columns: 250px minmax(0, 1fr);
  gap: var(--sp-4);
  align-items: center;
  min-height: 34px;
  z-index: 1;
}
.tl-name { display: grid; gap: 1px; min-width: 0; }
.tl-name strong {
  font: 500 var(--step--1)/1.3 var(--font-mono);
  color: var(--text);
  overflow-wrap: anywhere;
}
.tl-name span { font-size: 11px; color: var(--text-faint); }

.tl-lane { position: relative; height: 100%; }

/* The availability bar: thin mark, rounded data-ends, anchored to real time. */
.tl-bar {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  height: 8px;
  border-radius: 4px;
  background: var(--border-strong);
}
.tl-track[data-kind="source"] .tl-bar { background: color-mix(in srgb, var(--text-faint) 55%, transparent); }
.tl-track[data-kind="safe"] .tl-bar { background: var(--ok); }
.tl-track[data-kind="leak"] .tl-bar { background: var(--danger); }

/* The violation: a bar that continues past the rule, hatched to mark that this
   data did not exist when the prediction was made. */
.tl-reach {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  height: 8px;
  border-radius: 0 4px 4px 0;
  background:
    repeating-linear-gradient(135deg, var(--danger) 0 2px, transparent 2px 5px),
    color-mix(in srgb, var(--danger) 22%, transparent);
  /* a 2px surface gap so the reach reads as separate from the bar */
  border-left: 2px solid var(--surface);
}
.tl-reach::after {
  content: "";
  position: absolute;
  right: -3px;
  top: 50%;
  transform: translateY(-50%);
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--danger);
  box-shadow: 0 0 0 2px var(--surface);
}

.tl-flag {
  position: absolute;
  top: 50%;
  transform: translate(var(--sp-3), -50%);
  white-space: nowrap;
  font: 700 10px/1 var(--font-sans);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--danger);
}

.tl-note {
  grid-column: 2;
  font-size: 11px;
  color: var(--text-faint);
  margin-top: -6px;
}
.tl-track[data-kind="leak"] .tl-note { color: var(--danger); }
.tl-track[data-kind="safe"] .tl-note { color: var(--ok); }

/* Axis: solid hairline ticks, one shade off the surface. */
.tl-axis {
  position: relative;
  height: 26px;
  margin-left: calc(250px + var(--sp-4));
  border-top: 1px solid var(--border);
}
.tl-tick {
  position: absolute;
  top: 0;
  transform: translateX(-50%);
  padding-top: var(--sp-2);
  font: 500 10px/1 var(--font-mono);
  color: var(--text-faint);
  white-space: nowrap;
}
.tl-tick.is-cutoff { color: var(--danger); font-weight: 700; }

.tl-legend {
  display: flex;
  gap: var(--sp-5);
  flex-wrap: wrap;
  margin-top: var(--sp-4);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
  font-size: var(--step--1);
  color: var(--text-muted);
}
.tl-key { display: inline-flex; align-items: center; gap: var(--sp-2); }
.tl-swatch { width: 18px; height: 8px; border-radius: 4px; flex: none; }
.tl-swatch.safe { background: var(--ok); }
.tl-swatch.leak { background: var(--danger); }
.tl-swatch.future {
  background: repeating-linear-gradient(135deg, var(--danger) 0 2px, transparent 2px 5px),
              color-mix(in srgb, var(--danger) 22%, transparent);
}

@media (max-width: 820px) {
  .tl-track { grid-template-columns: 1fr; gap: var(--sp-1); }
  .tl-lane { height: 26px; }
  .tl-axis { margin-left: 0; }
  .tl-note { grid-column: 1; }
}

/* -- Data-ink pass ---------------------------------------------------------
   Tufte: erase non-data ink. Boxes around numbers are chrome competing with
   the numbers. Stat rows are separated by hairlines instead, so the figures
   carry the display and the container disappears.
------------------------------------------------------------------------- */

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
.stat {
  padding: var(--sp-4) var(--sp-5) var(--sp-4) 0;
  display: grid;
  gap: 2px;
  align-content: start;
  border-right: 1px solid var(--border);
}
.stat:last-child { border-right: 0; }
.stat-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-faint);
}
/* Hero and stat figures use proportional digits: tabular-nums makes large
   standalone numbers look loose. Tabular is for columns only. */
.stat-value { font-size: var(--step-3); font-weight: 750; line-height: 1.05; letter-spacing: -0.02em; }
.stat-value.is-block { color: var(--danger); }
.stat-value.is-clear { color: var(--ok); }
.stat-note { font-size: var(--step--1); color: var(--text-faint); }

/* -- Ablation comparison ---------------------------------------------------
   Two boxes with numbers in them is a one-bar bar chart twice over. The point
   is the COMPARISON, so draw one shared scale and let the bars do the arguing:
   the safe feature is visibly longer, and still cleared.
------------------------------------------------------------------------- */

.compare { display: grid; gap: var(--sp-5); }
.compare-row { display: grid; grid-template-columns: 200px minmax(0, 1fr) auto; gap: var(--sp-4); align-items: center; }
.compare-name { display: grid; gap: 1px; }
.compare-name strong { font-size: var(--step-0); font-weight: 600; }
.compare-name span { font-size: 11px; color: var(--text-faint); font-family: var(--font-mono); }

.compare-track { position: relative; height: 10px; background: var(--surface-2); border-radius: 5px; }
.compare-fill { position: absolute; inset-block: 0; left: 0; border-radius: 5px; }
.compare-row[data-kind="leak"] .compare-fill { background: var(--danger); }
.compare-row[data-kind="safe"] .compare-fill { background: var(--ok); }

.compare-value {
  font-size: var(--step-2);
  font-weight: 750;
  font-variant-numeric: tabular-nums;
  min-width: 4ch;
  text-align: right;
}
.compare-row[data-kind="leak"] .compare-value { color: var(--danger); }
.compare-row[data-kind="safe"] .compare-value { color: var(--ok); }

.compare-verdicts { display: grid; grid-template-columns: 200px minmax(0, 1fr); gap: var(--sp-4); }
.compare-punch {
  grid-column: 2;
  padding: var(--sp-4) var(--sp-5);
  border-left: 3px solid var(--danger);
  background: var(--danger-soft);
  border-radius: 0 var(--radius) var(--radius) 0;
  font-size: var(--step-0);
}
.compare-punch strong { color: var(--text); }

/* -- Table view twin ------------------------------------------------------- */

.table-view { margin-top: var(--sp-5); }
.table-view summary {
  cursor: pointer;
  font-size: var(--step--1);
  color: var(--text-muted);
  padding: var(--sp-2) 0;
  list-style: none;
}
.table-view summary::-webkit-details-marker { display: none; }
.table-view summary::before { content: "> "; font-family: var(--font-mono); color: var(--text-faint); }
.table-view[open] summary::before { content: "v "; }
.table-view summary:hover { color: var(--accent); }

/* -- Sparkline -------------------------------------------------------------
   Small multiples for run history: one mark per run, so the trend is visible
   without a second chart.
------------------------------------------------------------------------- */

.spark { display: inline-flex; align-items: flex-end; gap: 2px; height: 22px; }
.spark-bar { width: 5px; border-radius: 2px 2px 0 0; background: var(--ok); opacity: 0.85; }
.spark-bar[data-decision="block"] { background: var(--danger); }
.spark-bar:hover { opacity: 1; }

@media (max-width: 820px) {
  .compare-row, .compare-verdicts { grid-template-columns: 1fr; gap: var(--sp-2); }
  .compare-punch { grid-column: 1; }
  .stat { border-right: 0; border-bottom: 1px solid var(--border); padding-right: 0; }
}

/* -- Plain-English story ---------------------------------------------------
   Someone with no ML background must be able to follow the whole argument.
   This block carries the explanation; the technical evidence sits below it and
   can be hidden entirely.
------------------------------------------------------------------------- */

.story { display: grid; gap: var(--sp-5); }

.story-verdict {
  padding: var(--sp-6);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  background:
    radial-gradient(120% 140% at 0% 0%, var(--accent-soft) 0%, transparent 60%),
    var(--surface);
}
.story-verdict.is-block {
  border-color: color-mix(in srgb, var(--danger) 45%, var(--border));
  background:
    radial-gradient(120% 140% at 0% 0%, var(--danger-soft) 0%, transparent 62%),
    var(--surface);
}
.story-verdict h2 { font-size: var(--step-4); letter-spacing: -0.03em; }
.story-verdict.is-block h2 { color: var(--danger); }
.story-verdict.is-clear h2 { color: var(--ok); }
.story-sub { margin-top: var(--sp-3); font-size: var(--step-1); color: var(--text-muted); max-width: 62ch; }

/* The exam analogy, drawn. Two scores side by side is the whole idea. */
.analogy {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--sp-6);
  align-items: center;
  padding: var(--sp-5);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
}
.analogy-visual { display: flex; align-items: center; gap: var(--sp-4); }

.exam {
  display: grid;
  justify-items: center;
  gap: var(--sp-1);
  padding: var(--sp-4) var(--sp-5);
  min-width: 132px;
  border-radius: var(--radius);
  border: 1px solid var(--danger);
  background: var(--danger-soft);
  position: relative;
}
.exam.is-honest { border-color: var(--ok); background: var(--ok-soft); }
.exam-label { font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-muted); font-weight: 700; }
.exam-score { font-size: var(--step-4); font-weight: 800; line-height: 1; color: var(--danger); }
.exam-score em { font-style: normal; font-size: 0.45em; font-weight: 600; }
.exam.is-honest .exam-score { color: var(--ok); }
.exam-cheat { font-size: 10px; color: var(--text-faint); text-align: center; }
.exam-arrow { font-size: var(--step-3); color: var(--text-faint); }

.analogy-text h3 { font-size: var(--step-1); margin-bottom: var(--sp-2); }
.analogy-text p { color: var(--text-muted); max-width: var(--measure); }

.mapping { display: grid; gap: 0; margin: var(--sp-4) 0 0; }
.mapping > div {
  display: grid;
  grid-template-columns: 160px minmax(0, 1fr);
  gap: var(--sp-4);
  padding: var(--sp-2) 0;
  border-top: 1px solid var(--border);
  font-size: var(--step--1);
}
.mapping dt { color: var(--text-faint); }
.mapping dd { margin: 0; color: var(--text); }

/* The story as beats on a day-by-day sequence. */
.story-steps { display: grid; gap: var(--sp-3); }
.beats {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: var(--sp-4);
  counter-reset: beat;
}
.beat {
  position: relative;
  display: grid;
  gap: var(--sp-2);
  padding: var(--sp-4);
  padding-top: var(--sp-5);
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
}
.beat::before {
  content: "";
  position: absolute;
  top: 0; left: var(--sp-4); right: var(--sp-4);
  height: 2px;
  background: var(--border-strong);
  border-radius: 0 0 2px 2px;
}
.beat.is-violation { border-color: color-mix(in srgb, var(--danger) 40%, var(--border)); }
.beat.is-violation::before { background: var(--danger); }
.beat-when {
  font: 700 10px/1 var(--font-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.beat.is-violation .beat-when { color: var(--danger); }
.beat strong { font-size: var(--step-0); font-weight: 600; line-height: 1.35; }
.beat-note { font-size: var(--step--1); color: var(--text-muted); }

.story-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--sp-4); }
.story-card {
  padding: var(--sp-5);
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
}
.story-card p { color: var(--text-muted); }
.story-card.is-stakes { border-left: 3px solid var(--warn); }
.story-card.is-action { border-left: 3px solid var(--accent); }
.do-list { margin: 0; padding-left: var(--sp-5); color: var(--text-muted); display: grid; gap: var(--sp-2); }

/* -- Plain / technical toggle ---------------------------------------------- */

.mode-switch {
  display: inline-flex;
  padding: 3px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  gap: 2px;
}
.mode-switch button {
  border: 0;
  background: transparent;
  color: var(--text-muted);
  font: 600 var(--step--1) var(--font-sans);
  padding: var(--sp-2) var(--sp-4);
  border-radius: 999px;
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
.mode-switch button[aria-pressed="true"] { background: var(--accent); color: var(--accent-ink); }

/* Technical sections collapse away in plain mode. */
body[data-mode="plain"] .tech-only { display: none; }
body[data-mode="technical"] .plain-only { display: none; }

/* -- Scenario picker ------------------------------------------------------- */

/* Capped at three: with five scenarios an auto-fit grid put four in a row and
   left the fifth alone in a wide empty band. */
.scenarios {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(268px, 1fr));
  gap: var(--sp-4);
}
@media (min-width: 1100px) { .scenarios { grid-template-columns: repeat(3, 1fr); } }
.scenario-card {
  display: grid;
  gap: var(--sp-3);
  align-content: start;
  padding: var(--sp-5);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  background: var(--surface);
  text-decoration: none;
  color: inherit;
  transition: border-color var(--transition), transform var(--transition);
}
.scenario-card:hover { border-color: var(--accent); transform: translateY(-2px); }
.scenario-card.is-active { border-color: var(--accent); background: var(--accent-soft); }
.scenario-icon {
  display: grid; place-items: center;
  width: 36px; height: 36px;
  border-radius: 10px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 17px;
}
.scenario-card.is-active .scenario-icon { background: var(--accent); color: var(--accent-ink); }
.scenario-domain { font-size: 10px; letter-spacing: 0.09em; text-transform: uppercase; color: var(--text-faint); font-weight: 700; }
.scenario-card h3 { font-size: var(--step-1); }
.scenario-card p { font-size: var(--step--1); color: var(--text-muted); }
.scenario-q {
  font-size: var(--step--1);
  font-style: italic;
  color: var(--text);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
}

@media (max-width: 860px) {
  .analogy { grid-template-columns: 1fr; }
  .analogy-visual { justify-content: center; }
  .mapping > div { grid-template-columns: 1fr; gap: var(--sp-1); }
}

/* Scenario cards are submit buttons, so reset button chrome. */
.scenario-form { display: contents; }
button.scenario-card { font: inherit; text-align: left; cursor: pointer; width: 100%; }

/* Plain mode is the default before JS runs, so the beginner view never flashes
   the technical one. */
body:not([data-mode]) .tech-only { display: none; }

/* -- How we knew ----------------------------------------------------------
   In plain mode this is the only place DataHub is named, so it is deliberately
   prominent: a finding without its source is just an assertion.
------------------------------------------------------------------------- */

.how-we-knew {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--sp-5);
  align-items: start;
  padding: var(--sp-5);
  border-radius: var(--radius-lg);
  border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--border));
  background:
    radial-gradient(90% 130% at 0% 0%, var(--accent-soft) 0%, transparent 65%),
    var(--surface);
}
.how-icon {
  display: grid; place-items: center;
  width: 38px; height: 38px;
  border-radius: 11px;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 19px;
}
.how-we-knew p { color: var(--text-muted); max-width: var(--measure); }
.how-we-knew strong { color: var(--text); }
.how-we-knew code {
  color: var(--accent);
  background: var(--accent-soft);
  padding: 1px 6px;
  border-radius: 5px;
}
.how-note {
  margin-top: var(--sp-3);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
  font-size: var(--step--1);
}

@media (max-width: 700px) {
  .how-we-knew { grid-template-columns: 1fr; }
}

/* -- Confirmation routes --------------------------------------------------- */

.routes {
  padding: var(--sp-5);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  background: var(--surface);
}
.route-list { display: grid; gap: var(--sp-3); }
.route {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--sp-4);
  align-items: start;
  padding: var(--sp-4);
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface-2);
  opacity: 0.55;
}
.route.is-fired {
  opacity: 1;
  border-color: var(--ok);
  background: var(--ok-soft);
}
.route-mark {
  display: grid; place-items: center;
  width: 24px; height: 24px;
  border-radius: 50%;
  background: var(--border-strong);
  /* Both subtle steps land near 4.46:1 on this chip, just under AA. The glyph
     is decorative, but low-vision readers still use it to tell the two routes
     apart, so it wears full-strength ink. */
  color: var(--text);
  font-weight: 800;
  font-size: 13px;
}
.route.is-fired .route-mark { background: var(--ok); color: var(--bg); }
.route strong { display: block; font-size: var(--step-0); font-weight: 650; margin-bottom: 2px; }
/* Scoped to the description column: `.route span` also matched the mark,
   and being a descendant selector it quietly outranked `.route-mark`. */
.route > div > span { font-size: var(--step--1); color: var(--text-muted); }

/* -- Landing hero ----------------------------------------------------------
   A first-time visitor gets the problem in ordinary words and a picture of it
   before anything else. Status and history live further down, for people who
   already know what they are looking at.
------------------------------------------------------------------------- */

.hero-explain {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  gap: var(--sp-7);
  align-items: center;
  padding: var(--sp-6) 0 var(--sp-5);
}
.hero-copy { display: grid; gap: var(--sp-4); align-content: start; }
.hero-copy h1 { font-size: var(--step-5); letter-spacing: -0.035em; }
.hero-copy h1 .accent { color: var(--accent); }
.hero-copy .lede { font-size: var(--step-2); color: var(--text); font-weight: 500; }
.hero-cta { display: flex; gap: var(--sp-3); flex-wrap: wrap; margin-top: var(--sp-2); }

.hero-visual {
  margin: 0;
  display: grid;
  gap: var(--sp-4);
  justify-items: center;
  padding: var(--sp-6);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  background:
    radial-gradient(120% 120% at 50% 0%, var(--accent-soft) 0%, transparent 65%),
    var(--surface);
}
.hero-visual figcaption {
  font-size: var(--step--1);
  color: var(--text-muted);
  text-align: center;
  max-width: 46ch;
}
.hero-visual .exam { min-width: 148px; }
.hero-visual .exam-score { font-size: var(--step-5); }

.activity-strip { padding-top: var(--sp-4); border-top: 1px solid var(--border); }

@media (max-width: 900px) {
  .hero-explain { grid-template-columns: 1fr; gap: var(--sp-5); }
}

/* -- Mobile ----------------------------------------------------------------
   Measured at 390px: the page overflowed by 44px and clipped text mid-word.
   The causes were a fixed 250px timeline label column, non-wrapping display
   type, and side-by-side exam cards. Nothing may exceed the viewport.
------------------------------------------------------------------------- */

@media (max-width: 640px) {
  html, body { overflow-x: hidden; }

  h1, h2, h3 { overflow-wrap: anywhere; hyphens: auto; }
  .hero-copy h1 { font-size: clamp(2.1rem, 10vw, 3rem); }
  .hero-copy .lede { font-size: var(--step-1); }

  /* Exam cards stack rather than overflow. */
  .analogy-visual { flex-direction: column; width: 100%; }
  .hero-visual { padding: var(--sp-4); width: 100%; }
  .hero-visual .exam, .exam { width: 100%; min-width: 0; }
  .exam-arrow { transform: rotate(90deg); }

  .hero-cta { width: 100%; }
  .hero-cta .btn { flex: 1 1 auto; justify-content: center; }

  /* The timeline's fixed label column is the main overflow source. */
  .tl-track { grid-template-columns: 1fr; }
  .tl-axis { margin-left: 0; }
  .tl-cutoff { left: 50% !important; }
  .tl-name strong { font-size: 11px; }

  /* Long identifiers must wrap, not push the page wide. */
  code, .mono, .log-line .detail, .kv dd { overflow-wrap: anywhere; }
  pre.sql { font-size: 11px; }

  .compare-row, .trap { grid-template-columns: 1fr; }
  .cards, .scenarios, .beats, .story-grid { grid-template-columns: 1fr; }
  .content { padding: var(--sp-4) var(--sp-3); }
  .panel { padding: var(--sp-4) var(--sp-3); border-radius: var(--radius); }

  /* Tables scroll inside their own container, never the page. */
  .table-wrap { max-width: 100%; }
}

/* -- Action feedback ------------------------------------------------------- */

.story-timeline { display: grid; gap: var(--sp-2); padding: var(--sp-5); border-radius: var(--radius-lg); border: 1px solid var(--border); background: var(--surface); }
.story-timeline h3 { font-size: var(--step-2); }

.is-running { position: relative; opacity: 0.75; cursor: progress; }
.is-running::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  height: 3px;
  border-radius: 0 0 var(--radius) var(--radius);
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  background-size: 40% 100%;
  animation: runningBar 900ms linear infinite;
}
@keyframes runningBar { from { background-position: -40% 0; } to { background-position: 140% 0; } }

/* -- In-page navigation ---------------------------------------------------- */

/* The row is what sticks now: section links on the left, reading level on the
   right. Both change what you are looking at, so they travel together. */
.pagebar {
  position: sticky;
  top: 52px;
  z-index: 15;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  flex-wrap: wrap;
  margin-bottom: calc(-1 * var(--sp-2));
}

.jumpnav {
  display: flex;
  gap: var(--sp-1);
  flex-wrap: wrap;
  padding: var(--sp-2);
  border-radius: 999px;
  border: 1px solid var(--border);
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  backdrop-filter: blur(12px);
  width: fit-content;
  max-width: 100%;
}
.jumpnav a {
  padding: var(--sp-2) var(--sp-4);
  border-radius: 999px;
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--text-muted);
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--transition), color var(--transition);
}
.jumpnav a:hover { background: var(--surface-2); color: var(--text); }
/* Links to technical sections are pointless while those sections are hidden. */
body[data-mode="plain"] .jumpnav .tech-link { display: none; }

html { scroll-behavior: smooth; scroll-padding-top: 108px; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

/* -- Artifact blocks ------------------------------------------------------- */

pre.artifact {
  margin: 0;
  padding: var(--sp-4);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow-x: auto;
  font-size: var(--step--1);
  line-height: 1.6;
  color: var(--text-muted);
  max-height: 420px;
  overflow-y: auto;
}
pre.artifact.is-bad { border-left: 3px solid var(--danger); }
pre.artifact.is-good { border-left: 3px solid var(--ok); }

details.table-view.panel { padding: var(--sp-4) var(--sp-5); }
details.table-view.panel summary { font-weight: 600; }

/* -- Trust panel -----------------------------------------------------------
   The strongest signals (a control that must clear, a frozen generator, a
   disclosed margin) all require reflection to notice. Under three minutes
   nobody reflects, so they are stated as objections and answers.
------------------------------------------------------------------------- */

.trust {
  padding: var(--sp-5);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  background: var(--surface);
}
.trust .section-heading { margin-bottom: var(--sp-4); }
.trust h3 { font-size: var(--step-2); }
.trust-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(268px, 1fr)); gap: var(--sp-4); }
.trust-item {
  padding: var(--sp-4);
  border-radius: var(--radius);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-left: 3px solid var(--ok);
}
.trust-q {
  font-size: var(--step-0);
  font-weight: 650;
  color: var(--text-faint);
  font-style: italic;
  margin-bottom: var(--sp-2);
}
.trust-a { font-size: var(--step--1); color: var(--text-muted); }
.trust-a strong { color: var(--text); }

@media (max-width: 640px) { .trust-grid { grid-template-columns: 1fr; } }

/* -- Jump nav: plain vs technical -----------------------------------------
   Links must point at something the reader can actually see. In plain mode the
   technical sections are hidden, so their links are too - and plain-mode
   anchors take their place rather than leaving a single orphaned pill.
------------------------------------------------------------------------- */


/* ==========================================================================
   Craft pass
   The page read as loose rather than airy: inconsistent vertical rhythm, a
   verdict card using half its width, flat surfaces, and no motion. Fixed here
   rather than by adding decoration.
   ========================================================================== */

/* -- Typography ------------------------------------------------------------
   One family, but used properly: optical sizing, tightened tracking as size
   increases, and tabular figures only where numbers align in columns.
------------------------------------------------------------------------- */

:root {
  --font-sans: "Inter var", "Inter", ui-sans-serif, system-ui, -apple-system,
    "Segoe UI Variable Text", "Segoe UI", Roboto, sans-serif;
  --measure-tight: 58ch;
}

body {
  font-optical-sizing: auto;
  font-feature-settings: "cv05" 1, "ss03" 1;  /* single-storey l, rounded quotes */
  text-rendering: optimizeLegibility;
}

/* Tracking tightens as type grows. Display sizes set loose look amateurish. */
h1 { letter-spacing: -0.035em; }
h2 { letter-spacing: -0.025em; }
h3 { letter-spacing: -0.015em; }
.lede { letter-spacing: -0.005em; }

/* Body copy reads better a little narrower than the container allows. */
.prose, .story-sub, .trust-a, .route > div > span { max-width: var(--measure-tight); }

/* -- Vertical rhythm -------------------------------------------------------
   The old spacing came from whatever each block happened to set. One scale,
   applied at the seams, so the page has a pulse instead of gaps.
------------------------------------------------------------------------- */

.content { gap: var(--sp-6); }
.story { gap: var(--sp-5); }
.story > * + * { margin-top: 0; }
.section-heading { margin-bottom: var(--sp-4); }
.panel { padding: var(--sp-6); }

@media (max-width: 900px) {
  .content { gap: var(--sp-5); }
  .panel { padding: var(--sp-5) var(--sp-4); }
}

/* -- The verdict card ------------------------------------------------------
   Was a wide box with a narrow text column and dead space on the right. The
   decision now occupies that space, so the card carries both the sentence and
   the number a reviewer is looking for.
------------------------------------------------------------------------- */

.story-verdict {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--sp-7);
  align-items: center;
  padding: var(--sp-6) var(--sp-7);
}
.verdict-copy { display: grid; gap: var(--sp-3); }
.story-verdict h2 { font-size: var(--step-4); }

.verdict-figure {
  display: grid;
  justify-items: center;
  gap: 2px;
  padding-left: var(--sp-7);
  border-left: 1px solid var(--border);
  min-width: 190px;
}
.verdict-stamp {
  font-size: var(--step-3);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1;
}
.story-verdict.is-block .verdict-stamp { color: var(--danger); }
.story-verdict.is-clear .verdict-stamp { color: var(--ok); }
.verdict-meta {
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
  font-weight: 600;
  text-align: center;
}
.verdict-rule {
  width: 34px;
  height: 1px;
  background: var(--border-strong);
  margin: var(--sp-3) 0;
}
.verdict-lost {
  font-size: var(--step-4);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.03em;
}
.story-verdict.is-block .verdict-lost { color: var(--danger); }
.story-verdict.is-clear .verdict-lost { color: var(--ok); }

@media (max-width: 860px) {
  .story-verdict { grid-template-columns: 1fr; gap: var(--sp-5); padding: var(--sp-5); }
  .verdict-figure {
    padding-left: 0; border-left: 0;
    padding-top: var(--sp-5); border-top: 1px solid var(--border);
    width: 100%;
  }
}

/* -- Depth ----------------------------------------------------------------
   Layering rather than drop shadows. A hairline top highlight reads as a
   surface catching light; the shadow stays tight and low-contrast.
------------------------------------------------------------------------- */

:root[data-theme="dark"], :root:not([data-theme="light"]) {
  --shadow: 0 1px 2px rgb(0 0 0 / 0.28), 0 8px 24px -14px rgb(0 0 0 / 0.55);
}
:root[data-theme="light"] {
  --shadow: 0 1px 2px rgb(15 20 32 / 0.07), 0 10px 24px -12px rgb(15 20 32 / 0.20);
}

.panel, .story-verdict, .analogy, .how-we-knew, .routes, .trust, .story-timeline {
  position: relative;
}
.panel::before, .story-verdict::before, .analogy::before,
.how-we-knew::before, .routes::before, .trust::before, .story-timeline::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 1px;
  border-radius: inherit;
  background: linear-gradient(
    90deg, transparent, color-mix(in srgb, var(--text) 8%, transparent), transparent
  );
  pointer-events: none;
}

/* -- Motion ---------------------------------------------------------------
   Entrance only, once, and short. Anything that repeats or animates on scroll
   becomes noise on a page someone is trying to read carefully.
------------------------------------------------------------------------- */

@media (prefers-reduced-motion: no-preference) {
  .content > * {
    animation: riseIn 380ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
  }
  .content > *:nth-child(1) { animation-delay: 0ms; }
  .content > *:nth-child(2) { animation-delay: 40ms; }
  .content > *:nth-child(3) { animation-delay: 80ms; }
  .content > *:nth-child(n+4) { animation-delay: 110ms; }

  @keyframes riseIn {
    from { opacity: 0; transform: translateY(6px); }
    to { opacity: 1; transform: none; }
  }

  .card, .scenario-card, .trust-item, .beat, .step {
    transition:
      border-color var(--transition),
      background var(--transition),
      transform var(--transition);
  }
  .card:hover, .trust-item:hover, .beat:hover { border-color: var(--border-strong); }
}

/* -- Focus ----------------------------------------------------------------
   A visible, consistent ring on every interactive element. Keyboard users get
   the same affordances as everyone else, not an afterthought.
------------------------------------------------------------------------- */

:where(a, button, input, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  box-shadow: none;
  border-radius: var(--radius-sm);
}
.scenario-card:focus-visible { outline-offset: 3px; }

/* Selection should look chosen, not accidental. */
::selection { background: color-mix(in srgb, var(--accent) 28%, transparent); }

/* Scrollbars inside dense panels, so they stop looking like OS chrome. */
.log, .artifact, .table-wrap { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
.log::-webkit-scrollbar, .artifact::-webkit-scrollbar { width: 10px; height: 10px; }
.log::-webkit-scrollbar-thumb, .artifact::-webkit-scrollbar-thumb {
  background: var(--border-strong); border-radius: 999px;
  border: 3px solid transparent; background-clip: content-box;
}

/* -- Hierarchy corrections -------------------------------------------------
   Three things in the verdict card were competing for first read: the headline,
   the decision, and the figure, all in the same red at similar weight. The
   decision becomes a filled stamp - a different material, not a fourth red - so
   the eye lands on it, then the sentence, then the number.
------------------------------------------------------------------------- */

.verdict-stamp {
  padding: 6px 14px 7px;
  border-radius: var(--radius-sm);
  font-size: var(--step-1);
  letter-spacing: 0.06em;
  color: #fff;
}
.story-verdict.is-block .verdict-stamp { background: var(--danger); color: #fff; }
.story-verdict.is-clear .verdict-stamp { background: var(--ok); color: #06210f; }
.verdict-figure { gap: var(--sp-2); }
.verdict-rule { margin: var(--sp-2) 0; }

/* The page title and the verdict headline were the same size, which flattened
   the order of reading. The question comes first; the answer is one step down. */
.story-verdict h2 { font-size: clamp(1.7rem, 1.2rem + 2.1vw, 2.5rem); }

/* Short trailing lines like "to approve." on their own row look like a mistake. */
.lede, .story-sub, .prose { text-wrap: pretty; }

/* A filled chip needs an ink colour chosen per theme, not a fixed white. In
   dark mode --danger is a light red, so white-on-red measures about 2.4:1 and
   fails WCAG AA outright. These pair each fill with ink above 4.5:1. */
:root, :root[data-theme="dark"] { --on-danger: #2b0709; --on-ok: #04210f; }
:root[data-theme="light"] { --on-danger: #ffffff; --on-ok: #ffffff; }
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) { --on-danger: #ffffff; --on-ok: #ffffff; }
}
.story-verdict.is-block .verdict-stamp { color: var(--on-danger); }
.story-verdict.is-clear .verdict-stamp { color: var(--on-ok); }

/* The main column is a grid, and grid items default to min-width: auto - so a
   single wide table or code block stretched the track and scrolled the whole
   page sideways. Clamping the track makes wide content scroll inside its own
   wrapper, which is where it belonged. */
.content { grid-template-columns: minmax(0, 1fr); }
.content > *, .page-head > * { min-width: 0; }

/* Same failure one level down: the run controls sat beside the title and forced
   the row wider than a phone. Below the fold-out width they stack. */
@media (max-width: 640px) {
  .page-head { grid-template-columns: minmax(0, 1fr); }
  .page-head .mode-switch, .page-head form { justify-self: start; }
}

/* On a phone the run id wrapped onto three lines and made the breadcrumb taller
   than the page title. It is an identifier, not prose - keep it on one line and
   let the row scroll if it has to. */
.crumbs { min-width: 0; flex-wrap: nowrap; white-space: nowrap; overflow: hidden; }
.crumbs code { overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 640px) {
  .crumbs { font-size: var(--step--2, 0.75rem); }
  .crumbs > *:not(:last-child):not(.sep) { display: none; }
  .crumbs > .sep { display: none; }
}

/* The pill you are standing in. Filled rather than tinted, so it reads at a
   glance while scrolling past. */
.jumpnav a.is-current {
  background: var(--accent);
  color: var(--accent-ink);
}
.jumpnav a.is-current:hover { background: var(--accent); color: var(--accent-ink); }

.print-slug {
  font-size: 9.5pt;
  color: var(--text-muted);
  padding-bottom: 3mm;
  margin-bottom: 6mm;
  border-bottom: 1px solid var(--border);
}

.head-controls { display: grid; gap: var(--sp-2); justify-items: end; }
.btn.is-print { font-size: var(--step--1); padding: var(--sp-2) var(--sp-4); }
@media (max-width: 640px) { .head-controls { justify-items: start; } }

/* The demo banner states a deliberate condition, not a fault, so it wears the
   accent rather than a warning colour. */
.banner[data-state="info"] { border-color: var(--accent); background: var(--accent-soft); }

/* -- What is being audited -------------------------------------------------
   The page used to render a verdict about "this model" and never name one.
   Three zones: the artifact, the timing, then the bookkeeping. The first
   version laid six equal cells in a grid, which was accurate and unreadable -
   the two dates carry the whole argument and were sized like everything else.
------------------------------------------------------------------------- */

.subject {
  padding: var(--sp-5) var(--sp-6);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  display: grid;
  gap: var(--sp-5);
}
.subject-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  flex-wrap: wrap;
}
.subject-head .eyebrow { margin: 0; }

/* -- The artifact ---------------------------------------------------------- */

.subject-what {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--sp-5) var(--sp-6);
}
.subject-item { min-width: 0; display: grid; gap: 2px; align-content: start; }
.subject-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-weight: 700;
  color: var(--text-faint);
  margin: 0 0 var(--sp-1);
}
.subject-name {
  margin: 0;
  font-size: var(--step-1);
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.25;
  overflow-wrap: anywhere;
}
.subject-sub { margin: 0; font-size: var(--step--1); color: var(--text-muted); }
.subject-sub code { font-size: 0.95em; }
/* The URN is provenance, not reading material: present, findable, quiet, and
   never allowed to wrap into three lines of noise. */
.subject-urn {
  margin-top: var(--sp-2);
  font-size: 11px;
  color: var(--text-faint);
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* -- The timing ------------------------------------------------------------
   Two dates and the distance between them. This is the argument, so it gets
   the space the six-cell grid was spending on labels.
------------------------------------------------------------------------- */

.subject-when {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--sp-5);
  padding: var(--sp-5);
  border-radius: var(--radius);
  background: var(--surface-2);
  border: 1px solid var(--border);
}
.when-point { display: grid; gap: 3px; min-width: 0; }
.when-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-weight: 700;
  color: var(--text-faint);
}
.when-date { font-size: var(--step-0); font-weight: 650; line-height: 1.3; }
.when-note { font-size: var(--step--1); color: var(--text-muted); }

.when-gap { display: grid; justify-items: center; gap: var(--sp-2); min-width: 120px; }
.when-gap-line {
  width: 100%;
  min-width: 60px;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--border-strong), var(--text-faint));
}
.subject-when.is-late .when-gap-line {
  background: repeating-linear-gradient(
    90deg, var(--danger) 0 6px, transparent 6px 10px
  );
}
.when-gap-value {
  font-size: var(--step--1);
  font-weight: 700;
  color: var(--text-muted);
  text-align: center;
}
.subject-when.is-late .when-gap-value { color: var(--danger); }
.subject-when.is-late { border-color: color-mix(in srgb, var(--danger) 35%, var(--border)); }

/* -- The bookkeeping ------------------------------------------------------- */

.subject-meta {
  margin: 0;
  font-size: var(--step--1);
  color: var(--text-muted);
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-3);
  align-items: baseline;
}
.subject-meta .meta-label { color: var(--text-faint); }
.subject-meta .meta-sep { color: var(--text-faint); }

@media (max-width: 720px) {
  .subject { padding: var(--sp-5) var(--sp-4); }
  /* Stacked, the arrow between two dates stops meaning anything, so the gap
     becomes a labelled row of its own. */
  .subject-when { grid-template-columns: 1fr; gap: var(--sp-4); }
  .when-gap { justify-items: start; min-width: 0; }
  .when-gap-line { width: 40px; }
}

/* The demo banner states a deliberate condition, not a fault, so it wears the
   accent rather than a warning colour. */
.banner[data-state="info"] { border-color: var(--accent); background: var(--accent-soft); }

/* -- What is being audited -------------------------------------------------
   The page used to render a verdict about "this model" and never name one.
   This is the identity strip that answers it: which model, which feature, as
   of when, and how much later the offending fact arrived.
------------------------------------------------------------------------- */

.subject {
  padding: var(--sp-5) var(--sp-6);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
.subject-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  flex-wrap: wrap;
  margin-bottom: var(--sp-4);
}
.subject-head .eyebrow { margin: 0; }

/* Auto-fit rather than a fixed count: a scenario with no recorded source date
   has five facts, not six, and should not leave a hole. */
.subject-facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: var(--sp-5) var(--sp-6);
  margin: 0;
}
.subject-fact { min-width: 0; }
.subject-fact dt {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-weight: 700;
  color: var(--text-faint);
  margin-bottom: var(--sp-2);
}
.subject-fact dd { margin: 0; display: grid; gap: 2px; }

.subject-value {
  font-size: var(--step-0);
  font-weight: 650;
  color: var(--text);
  line-height: 1.3;
  /* Model names and URNs are long and unbreakable; wrap rather than overflow. */
  overflow-wrap: anywhere;
}
.subject-detail {
  font-size: var(--step--1);
  color: var(--text-muted);
  font-family: var(--font-mono, ui-monospace, monospace);
  overflow-wrap: anywhere;
}
/* The gap between the decision and the fact is the entire defect. Say it in
   the colour the rest of the page uses for the violation. */
.subject-detail.is-violation {
  color: var(--danger);
  font-weight: 700;
  font-family: inherit;
}
.subject-note {
  font-size: var(--step--1);
  color: var(--text-faint);
  margin-top: 2px;
}

@media (max-width: 640px) {
  .subject { padding: var(--sp-5) var(--sp-4); }
  .subject-facts { gap: var(--sp-4); }
}

/* The one line on the first screen that says what this is built on. Set apart
   from the surrounding prose without shouting. */
.hero-source {
  border-left: 2px solid var(--accent);
  padding-left: var(--sp-4);
  color: var(--text-muted);
}

/* Visible to assistive tech only. */
.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;
}

/* -- The lineage chain ----------------------------------------------------
   What DataHub supplied, drawn. The page argued from this path in prose and
   never showed it, which for a project whose whole claim is "the catalog knew"
   was the wrong thing to leave implicit.

   Status colour ships with a glyph and a label, never colour alone, and the
   <details> table below repeats every value.
------------------------------------------------------------------------- */

.chain { display: grid; gap: var(--sp-3); }

.chain-flow {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: var(--sp-2);
}

.chain-node {
  flex: 1 1 200px;
  min-width: 0;
  display: grid;
  gap: 2px;
  align-content: start;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
}
/* The model is the thing being judged, so it reads as the terminus. */
.chain-node.is-model { border-color: var(--border-strong); background: var(--surface-2); }
.chain-node.is-violation {
  border-color: var(--danger);
  background: color-mix(in srgb, var(--danger) 7%, var(--surface));
}

.chain-kind {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 700;
  color: var(--text-faint);
}
.chain-table {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: var(--step--1);
  font-weight: 600;
  overflow-wrap: anywhere;
}
.chain-col {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: var(--step--1);
  color: var(--text-muted);
  overflow-wrap: anywhere;
}
.chain-flag {
  margin-top: var(--sp-2);
  font-size: var(--step--1);
  font-weight: 700;
  color: var(--danger);
}

/* One connector, laid along the flow rather than stacked across it. The list
   items stretch to card height, so the arrow has to centre itself inside that. */
.chain-arrow {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 1px;
  padding: 0 var(--sp-1);
  color: var(--text-faint);
}
.chain-arrow-head { font-size: var(--step-0); line-height: 1; margin-left: -2px; }
.chain-arrow-line { width: 20px; height: 2px; border-radius: 2px; background: var(--border-strong); }
/* The hop that carries the defect forward, dashed like the timing connector so
   the two visuals on this page agree with each other. */
.chain-arrow-line.is-violation {
  background: repeating-linear-gradient(90deg, var(--danger) 0 5px, transparent 5px 9px);
}
.chain-arrow:has(.is-violation) .chain-arrow-head { color: var(--danger); }

.chain-table-view summary {
  cursor: pointer;
  font-size: var(--step--1);
  color: var(--text-muted);
  width: fit-content;
}
.chain-table-view summary:hover { color: var(--text); }
.chain-table-view .table-wrap { margin-top: var(--sp-3); }

/* Stacked, a horizontal arrow means nothing; rotate it. */
@media (max-width: 760px) {
  .chain-flow { flex-direction: column; align-items: stretch; }
  .chain-node { flex: 1 1 auto; }
  /* Stacked, a horizontal arrow points at nothing. Turn the whole connector. */
  .chain-arrow { flex-direction: column; align-self: flex-start; padding: 0 0 0 var(--sp-5); }
  .chain-arrow-head { transform: rotate(90deg); margin: -2px 0 0; }
  .chain-arrow-line { width: 2px; height: 14px; }
}

.head-actions { display: flex; gap: var(--sp-2); flex-wrap: wrap; justify-content: flex-end; }
@media (max-width: 640px) { .head-actions { justify-content: flex-start; } }

/* -- The evidence record, in place ---------------------------------------- */

.evidence-record {
  display: grid;
  gap: var(--sp-4);
  padding: var(--sp-5) var(--sp-6);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
.evidence-record[hidden] { display: none; }
.evidence-record-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-4);
  flex-wrap: wrap;
}
.evidence-record-head .eyebrow { margin: 0 0 var(--sp-1); }
.evidence-record-head .fine { margin: 0; }
/* Tall enough to be worth opening, short enough not to bury the page. */
.evidence-record .artifact { max-height: 460px; }

@media (max-width: 640px) { .evidence-record { padding: var(--sp-5) var(--sp-4); } }

/* The URN, labelled. It is provenance, so it stays visible, but a bare
   urn:li:... string means nothing to a reader who has not seen one before. */
.subject-urn-row { margin: var(--sp-2) 0 0; display: grid; gap: 1px; min-width: 0; }
.subject-urn-label {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-weight: 700;
  color: var(--text-faint);
}

/* Sticky, so it needs the same treatment as the pills beside it rather than
   sitting transparent over scrolling content. */
.pagebar .mode-switch {
  backdrop-filter: blur(12px);
  background: color-mix(in srgb, var(--bg) 92%, transparent);
}
@media (max-width: 720px) {
  .pagebar { justify-content: flex-start; }
}

/* -- Light mode depth ------------------------------------------------------
   A dark UI gets depth for free: a lighter panel on a darker page reads as
   raised. A light UI cannot do that, because a panel is already white. So the
   canvas has to sit back and the shadow has to carry the lift - previously the
   page was #f7f8fa against white panels, a ratio of 1.06, which is no
   separation at all, and the shadow was too faint to make up for it.
------------------------------------------------------------------------- */

:root[data-theme="light"] .panel,
:root[data-theme="light"] .subject,
:root[data-theme="light"] .story-verdict,
:root[data-theme="light"] .analogy,
:root[data-theme="light"] .how-we-knew,
:root[data-theme="light"] .routes,
:root[data-theme="light"] .story-timeline,
:root[data-theme="light"] .evidence-record,
:root[data-theme="light"] .story-card,
:root[data-theme="light"] .card,
:root[data-theme="light"] .trust-item,
:root[data-theme="light"] .scenario-card {
  box-shadow: var(--shadow);
}

/* The top highlight is a dark-mode idea - a surface catching light from above.
   On white it just muddies the edge. */
:root[data-theme="light"] .panel::before,
:root[data-theme="light"] .subject::before,
:root[data-theme="light"] .story-verdict::before,
:root[data-theme="light"] .analogy::before,
:root[data-theme="light"] .how-we-knew::before,
:root[data-theme="light"] .routes::before,
:root[data-theme="light"] .story-timeline::before {
  display: none;
}

/* The sticky bars sit over a tinted canvas now, so they need to be opaque
   enough to read as chrome rather than as a smudge of the content behind. */
:root[data-theme="light"] .topbar,
:root[data-theme="light"] .jumpnav,
:root[data-theme="light"] .pagebar .mode-switch {
  background: color-mix(in srgb, #ffffff 82%, transparent);
}

@media (prefers-color-scheme: light) {
/* Same, for visitors who never touch the toggle ------------------------------------------------------
   A dark UI gets depth for free: a lighter panel on a darker page reads as
   raised. A light UI cannot do that, because a panel is already white. So the
   canvas has to sit back and the shadow has to carry the lift - previously the
   page was #f7f8fa against white panels, a ratio of 1.06, which is no
   separation at all, and the shadow was too faint to make up for it.
------------------------------------------------------------------------- */

:root:not([data-theme="dark"]) .panel,
:root:not([data-theme="dark"]) .subject,
:root:not([data-theme="dark"]) .story-verdict,
:root:not([data-theme="dark"]) .analogy,
:root:not([data-theme="dark"]) .how-we-knew,
:root:not([data-theme="dark"]) .routes,
:root:not([data-theme="dark"]) .story-timeline,
:root:not([data-theme="dark"]) .evidence-record,
:root:not([data-theme="dark"]) .story-card,
:root:not([data-theme="dark"]) .card,
:root:not([data-theme="dark"]) .trust-item,
:root:not([data-theme="dark"]) .scenario-card {
  box-shadow: var(--shadow);
}

/* The top highlight is a dark-mode idea - a surface catching light from above.
   On white it just muddies the edge. */
:root:not([data-theme="dark"]) .panel::before,
:root:not([data-theme="dark"]) .subject::before,
:root:not([data-theme="dark"]) .story-verdict::before,
:root:not([data-theme="dark"]) .analogy::before,
:root:not([data-theme="dark"]) .how-we-knew::before,
:root:not([data-theme="dark"]) .routes::before,
:root:not([data-theme="dark"]) .story-timeline::before {
  display: none;
}

/* The sticky bars sit over a tinted canvas now, so they need to be opaque
   enough to read as chrome rather than as a smudge of the content behind. */
:root:not([data-theme="dark"]) .topbar,
:root:not([data-theme="dark"]) .jumpnav,
:root:not([data-theme="dark"]) .pagebar .mode-switch {
  background: color-mix(in srgb, #ffffff 82%, transparent);
}

}

/* A card you can click should answer the pointer. Kept to a lift and a border
   change so it reads as pressable without moving the page around it. */
@media (prefers-reduced-motion: no-preference) {
  .scenario-card { transition: transform var(--transition), box-shadow var(--transition),
                               border-color var(--transition); }
  .scenario-card:hover { transform: translateY(-2px); border-color: var(--border-strong); }
}
:root[data-theme="light"] .scenario-card:hover,
:root:not([data-theme="dark"]) .scenario-card:hover {
  box-shadow: 0 2px 4px rgb(15 20 32 / 0.08), 0 16px 32px -14px rgb(15 20 32 / 0.26);
}

/* -- The benchmark sweep --------------------------------------------------
   Part-to-whole columns: one band per defect reach, every bar full because the
   defect was always caught, the composition showing which route caught it.

   Two categorical hues, chosen with the dataviz palette validator rather than by
   eye - CVD deltaE 29.1 dark, 31.7 light, against a target of 8. Deliberately not
   the status colours: these are two methods, not two states, and reusing
   green/red here would say "good route / bad route" which is false.
------------------------------------------------------------------------- */

:root, :root[data-theme="dark"] {
  --series-statistical: #7c86ff;
  --series-deterministic: #c9762a;
}
:root[data-theme="light"] {
  --series-statistical: #4f46e5;
  --series-deterministic: #b45309;
}
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --series-statistical: #4f46e5;
    --series-deterministic: #b45309;
  }
}

.bench { margin: var(--sp-5) 0 0; }

.bench-plot {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: var(--sp-2);
  align-items: end;
}
.bench-band { display: grid; justify-items: center; gap: var(--sp-2); min-width: 0; }

/* Thin marks, anchored to a baseline. */
.bench-bar {
  display: flex;
  flex-direction: column-reverse;   /* statistics grows from the baseline */
  width: 100%;
  /* Thin marks: a 54px column of saturated fill reads loud at this size, and
     saturated fills belong on small marks rather than large blocks. */
  max-width: 34px;
  height: 150px;
  border-radius: var(--radius-sm);
  overflow: hidden;
  /* A 2px surface gap between stacked segments, per the mark spec. */
  gap: 2px;
  background: var(--surface-2);
}
.bench-seg { display: block; width: 100%; }
.bench-seg.is-statistical { background: var(--series-statistical); }
.bench-seg.is-deterministic { background: var(--series-deterministic); }

.bench-reach { font-size: var(--step--1); font-weight: 700; color: var(--text); }
/* A second measure, in text ink - never in a series colour. Only the endpoints
   are labelled: a number under all seven bands is a number on every data point,
   which goes unread. The table view carries the rest. */
.bench-delta {
  font-size: 11px;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
  visibility: hidden;
}
.bench-band:first-child .bench-delta,
.bench-band:last-child .bench-delta { visibility: visible; }

.bench-axis {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-4);
  flex-wrap: wrap;
  margin-top: var(--sp-3);
  font-size: var(--step--1);
  color: var(--text-muted);
}
.bench-axis-note { color: var(--text-faint); }

/* A legend is always present for two series, so identity is never colour alone. */
.bench-legend {
  display: flex;
  gap: var(--sp-5);
  flex-wrap: wrap;
  margin-top: var(--sp-4);
  font-size: var(--step--1);
  color: var(--text-muted);
}
.bench-key { display: inline-flex; align-items: center; gap: var(--sp-2); }
.bench-swatch { width: 12px; height: 12px; border-radius: 3px; flex: 0 0 auto; }
.bench-swatch.is-statistical { background: var(--series-statistical); }
.bench-swatch.is-deterministic { background: var(--series-deterministic); }

.bench figcaption {
  margin-top: var(--sp-4);
  font-size: var(--step--1);
  color: var(--text-muted);
  max-width: var(--measure-tight);
}
.bench-table { margin-top: var(--sp-5); }
.bench-table summary {
  cursor: pointer;
  font-size: var(--step--1);
  color: var(--text-muted);
  width: fit-content;
}
.bench-table summary:hover { color: var(--text); }
.bench-table .table-wrap { margin-top: var(--sp-3); }

/* Forced-colors and print: colour is gone, so the segments need a texture to
   stay distinguishable. The legend and table carry the rest. */
@media (forced-colors: active), print {
  .bench-seg.is-deterministic {
    background: repeating-linear-gradient(135deg, currentColor 0 2px, transparent 2px 5px);
    border: 1px solid currentColor;
  }
  .bench-seg.is-statistical { border: 1px solid currentColor; }
}

@media (max-width: 640px) {
  .bench-bar { height: 110px; }
  .bench-plot { gap: 4px; }
  .bench-delta { display: none; }   /* keeps the band labels legible */
}

/* -- Impact ---------------------------------------------------------------
   Second question after "what is it" is "does this matter to me". Citations
   rather than adjectives, and a table that names who this does not serve -
   which is what makes the rest of the page believable.
------------------------------------------------------------------------- */

.impact { display: grid; gap: var(--sp-5); }

.impact-figures {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: var(--sp-4);
}
.impact-fig {
  padding: var(--sp-5);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  display: grid;
  gap: var(--sp-2);
  align-content: start;
}
.impact-value {
  margin: 0;
  font-size: var(--step-4);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--accent);
}
.impact-label { margin: 0; font-size: var(--step-0); color: var(--text); }
.impact-source { margin: 0; font-size: var(--step--1); color: var(--text-faint); }

.impact-fit {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--sp-4);
}
.impact-fit-col {
  padding: var(--sp-5);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
/* The fit column carries a status meaning, so it gets a heading and a border,
   never colour alone. */
.impact-fit-col.is-good { border-color: color-mix(in srgb, var(--ok) 40%, var(--border)); }
.impact-fit-head {
  margin: 0 0 var(--sp-3);
  font-size: var(--step-0);
  font-weight: 700;
}
.impact-fit-col ul { margin: 0 0 var(--sp-3); padding-left: var(--sp-5); }
.impact-fit-col li { font-size: var(--step--1); color: var(--text-muted); margin-bottom: 2px; }
.impact-fit-col .fine { margin: 0; }

.impact-sub { margin: var(--sp-2) 0 0; font-size: var(--step-1); }
.impact .callout pre.artifact { margin-top: var(--sp-3); }

@media (max-width: 640px) {
  .impact-fig, .impact-fit-col { padding: var(--sp-4); }
}

/* -- Built on DataHub -----------------------------------------------------
   A surface checklist proves breadth; one real answer proves depth. The trace
   is the centrepiece for that reason.
------------------------------------------------------------------------- */

.stack { display: grid; gap: var(--sp-5); }

.stack-trace {
  display: grid;
  gap: var(--sp-4);
  padding: var(--sp-5);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
.stack-trace-cmd { margin: 0; font-size: var(--step--1); color: var(--text-muted); }
.stack-trace-cmd code { overflow-wrap: anywhere; }

.stack-path {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  align-items: stretch;
  flex-wrap: wrap;
  gap: var(--sp-2);
}
.stack-node {
  flex: 1 1 190px;
  min-width: 0;
  display: grid;
  gap: 2px;
  align-content: start;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
/* The query entity is the point of the diagram, so it is the one that is marked. */
.stack-node.is-query {
  border-color: var(--accent);
  background: var(--accent-soft);
}
.stack-kind {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 700;
  color: var(--text-faint);
}
.stack-node code { font-size: var(--step--1); overflow-wrap: anywhere; }
.stack-hop {
  display: flex;
  align-items: center;
  color: var(--text-faint);
  font-size: var(--step-0);
}

.stack-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: var(--sp-4);
}
.stack-item {
  padding: var(--sp-4) var(--sp-5);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
.stack-head { margin: 0 0 var(--sp-2); font-weight: 700; font-size: var(--step-0); }
.stack-item p:last-child { margin: 0; font-size: var(--step--1); color: var(--text-muted); }

@media (max-width: 760px) {
  .stack-path { flex-direction: column; }
  .stack-hop { transform: rotate(90deg); justify-content: flex-start; padding-left: var(--sp-4); }
}
