/*
 * VAC — design tokens.
 *
 * Near-monochrome cool slate. The instrument is grey; colour is a labelling device and is
 * spent only on data — direction, level, verdict, organelle identity — never on chrome.
 *
 * Elevation is luminance, not glow. Each --surface step is a real, measurable lift over
 * the one below, so a card reads as raised without a halo. The previous theme drew cards
 * at #0D1117 on a #060B12 ground behind an accent-tinted 8%-alpha border, which is a
 * 2-point luminance difference: invisible on any display that is not in a dark room.
 *
 * The legacy --ink-* / --bright / --glow-* names are kept as aliases at the end of this
 * block. Roughly a thousand declarations reference them; re-pointing the aliases restyles
 * all of them at once, and the names retire as each file is rewritten.
 */
:root {
  /* Elevation ladder — measurable steps, coolest at the bottom. */
  --surface-0: #0A0C11;   /* app ground */
  --surface-1: #10131A;   /* rails, bars */
  --surface-2: #171B24;   /* cards */
  --surface-3: #1F242F;   /* raised, hover */
  --surface-4: #29303C;   /* popovers, tooltips */

  /* Hairlines. Neutral, not accent-tinted: a border is structure, not decoration. */
  --line: rgba(180, 197, 224, 0.10);
  --line-strong: rgba(180, 197, 224, 0.18);
  --line-focus: rgba(122, 172, 214, 0.55);

  /* Text ramp. */
  --text-0: #E7ECF3;      /* primary */
  --text-1: #A9B4C4;      /* secondary */
  --text-2: #717E90;      /* muted, labels */
  --text-3: #4C5666;      /* faint, disabled */

  /* One restrained accent for interaction. Desaturated steel blue rather than the old
     saturated mint, which fought every data colour on the screen for attention. */
  --accent: #6BA8D6;
  --accent-hover: #86BCE4;
  --accent-dim: rgba(107, 168, 214, 0.16);
  --accent-faint: rgba(107, 168, 214, 0.07);
  --accent-ink: #0A0C11;  /* text on a filled accent */
  /* Channels, for the places that need a computed alpha — a heat scale, say — and so cannot
     use the pre-mixed --accent-dim / --accent-faint. */
  --accent-rgb: 107, 168, 214;

  /* Semantic data colours. Muted enough to sit on a grey ground without vibrating. */
  --up: #DD8A6C;          /* increased — warm */
  --down: #6EA3D4;        /* decreased — cool */
  --gain: #7FB08A;
  --cost: #CE8A6E;
  --caution: #C6A96B;
  --danger: #D2777A;

  --verdict-harmful: #D2777A;
  --verdict-protective: #7FB08A;
  --verdict-ambiguous: #C6A96B;
  --verdict-neutral: #717E90;

  /* Type. Sans for prose and headings; mono for data, identifiers and figures only. */
  --font-sans: 'Inter', ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-heading: 'Inter', ui-sans-serif, system-ui, sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, 'SFMono-Regular', Menlo, monospace;

  --radius: 10px;
  --radius-sm: 6px;
  --transition: 160ms cubic-bezier(0.4, 0, 0.2, 1);

  /* Shadows do the work the glows used to. Dark, tight, no colour. */
  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.40);
  --shadow-2: 0 4px 16px rgba(0, 0, 0, 0.45);
  --shadow-3: 0 12px 32px rgba(0, 0, 0, 0.55);

  /* ── Legacy aliases ── */
  --ink-950: var(--surface-0);
  --ink-900: var(--surface-1);
  --ink-850: var(--surface-2);
  --ink-800: var(--surface-3);
  --ink-700: var(--surface-4);
  --ink-600: var(--text-3);
  --ink-500: var(--text-2);
  --ink-400: var(--text-2);
  --ink-300: var(--text-1);
  --ink-200: var(--text-1);
  --ink-100: var(--text-0);

  --edge: var(--line);
  --edge-hover: var(--line-strong);
  --edge-active: var(--line-focus);

  --brand: var(--accent);
  --bright: var(--accent);
  --paper: var(--text-0);

  --glow-cyan: var(--accent);
  --glow-blue: var(--accent);
  --glow-purple: var(--accent);
  --glow-cyan-dim: var(--line);
  --glow-blue-dim: var(--line);
  --glow-purple-dim: var(--line);

  /* "Glass" in name only, and deliberately so: --glass-bg is an opaque surface, so the
     backdrop-filters that used to accompany it blurred a backdrop nobody could see. They are
     gone; see the note by #detail-panel.expanded for why they were worse than merely useless. */
  --glass-bg: var(--surface-2);
  --glass-border: var(--line);
  --glass-hover-border: var(--line-strong);

  color-scheme: dark;
}

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

/*
 * The UA's `[hidden] { display: none }` is a plain element-level rule, so *any* class that sets
 * `display` outranks it — and most of the things this UI hides and shows are flex or grid
 * containers. The failure is silent and looks like a data bug rather than a style one: the cell
 * legend kept announcing "99 findings" through a replay that had reset the cell to empty, because
 * `.cell-legend { display: flex }` beat the `hidden` the code had just set.
 *
 * `!important` because that is the whole point — `hidden` has to be the last word on visibility.
 */
[hidden] { display: none !important; }

html, body {
  height: 100%;
  font-family: var(--font-sans);
  font-size: 13px;
  color: var(--ink-100);
  /* A single static vignette, lightest at the top edge where the chrome sits. It replaces
     three blurred, drifting colour orbs that were the largest continuously-repainting
     layer on the page and tinted every surface behind them, so no two cards read as the
     same elevation. It belongs on the root rather than on an overlay element: an opaque
     fixed overlay paints above the unpositioned flex items and hid the whole app. */
  background: radial-gradient(120% 80% at 50% 0%, #11151D 0%, var(--surface-0) 62%) fixed;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
}

::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--edge); border-radius: 9999px; }
::-webkit-scrollbar-thumb:hover { background: var(--edge-hover); }

:focus-visible { outline: 2px solid var(--bright); outline-offset: 2px; }

/* ── Layout ── */

#app {
  display: flex;
  flex-direction: column;
  height: 100vh;
  width: 100vw;
}

#top-bar {
  display: flex;
  align-items: center;
  height: 52px;
  padding: 0 16px;
  background: var(--ink-900);
  border-bottom: 1px solid transparent;
  border-color: var(--line);
  flex-shrink: 0;
  gap: 16px;
  z-index: 100;
}

#control-bar {
  display: flex;
  align-items: center;
  height: 40px;
  padding: 0 16px;
  background: var(--ink-950);
  border-bottom: 1px solid var(--edge);
  flex-shrink: 0;
  gap: 4px;
}

#main-area {
  display: flex;
  flex: 1;
  min-height: 0;
}

#run-gallery {
  width: 240px;
  flex-shrink: 0;
  background: var(--ink-900);
  border-right: 1px solid var(--edge);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}

#view-frame {
  flex: 1;
  min-width: 0;
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

/* A flex item, not an overlay. As an absolutely-positioned layer it sat *under* the activity
   dock, so opening the dock hid the bottom 240px of the cell — and Chromium clipped the
   canvas's composited layer to the un-overlapped region, dropping an equal band off the top.
   In flow the canvas gets exactly the space the dock leaves, the ResizeObserver re-fits the
   camera to it, and nothing overlaps anything. `relative` because the label layer, the
   controls and the legend are all absolutely positioned inside it. */
#cell-canvas-container {
  position: relative;
  flex: 1;
  min-height: 0;
  display: none;
  z-index: 0;
}
#cell-canvas-container.visible { display: block; }
#cell-canvas-container canvas { width: 100% !important; height: 100% !important; }

#panel-container {
  flex: 1;
  overflow-y: auto;
  padding: 20px 24px;
}
#panel-container.hidden { display: none; }

#detail-panel {
  width: 44px;
  flex-shrink: 0;
  background: var(--ink-900);
  border-left: 1px solid var(--edge);
  overflow-y: auto;
  transition: width var(--transition);
}
/* The width is a variable so the drag handle can write it without an inline declaration that
   would outrank the collapsed rule above. The fallback is the default in `state.js`. */
#detail-panel.expanded {
  width: var(--detail-width, 360px);
  padding: 16px;
}

#status-bar {
  display: flex;
  align-items: center;
  height: 32px;
  padding: 0 16px;
  background: var(--ink-900);
  border-top: 1px solid var(--edge);
  flex-shrink: 0;
  gap: 12px;
  font-size: 11px;
  color: var(--ink-500);
  overflow: hidden;
}
#status-bar.running {
  border-top: 1px solid transparent;
  border-color: var(--line);
  animation: breathe 3s ease-in-out infinite;
}

/* ── Top Bar ── */

.top-logo {
  font-family: var(--font-heading);
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--bright);
}

.top-divider {
  width: 1px;
  height: 20px;
  background: var(--edge);
  flex-shrink: 0;
}

.header-field {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.header-field .eyebrow {
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--bright);
  line-height: 1;
}

.header-field .field-value {
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-100);
  white-space: nowrap;
}

.top-status {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 8px;
}

.status-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
}

.status-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  flex-shrink: 0;
}
.status-dot.running { background: var(--bright); animation: pulse-dot 2s ease-in-out infinite; }
.status-dot.completed { background: var(--gain); }
.status-dot.failed { background: var(--cost); }
.status-dot.pending { background: var(--caution); }

.top-btn {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  padding: 5px 14px;
  border-radius: 6px;
  border: 1px solid var(--edge);
  background: transparent;
  color: var(--ink-300);
  cursor: pointer;
  transition: all var(--transition);
}
.top-btn:hover { border-color: var(--edge-hover); color: var(--ink-100); }
.top-btn.primary { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
/* Was #00b871 — a mint green left over from the previous palette, which the button flashed
   on hover and nothing else in the app ever used. */
.top-btn.primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }

/* ── Control Bar (View Tabs) ── */

.tab-group {
  display: flex;
  align-items: center;
  gap: 2px;
}

.tab-group-label {
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-600);
  padding: 0 8px 0 4px;
}

.tab-divider {
  width: 1px;
  height: 20px;
  background: var(--edge);
  margin: 0 8px;
  flex-shrink: 0;
}

.tab-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 10px;
  border-radius: 6px;
  border: 1px solid transparent;
  background: transparent;
  font-family: var(--font-sans);
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-500);
  cursor: pointer;
  transition: all var(--transition);
  white-space: nowrap;
}
.tab-btn:hover { background: var(--ink-900); color: var(--ink-200); }
.tab-btn.active {
  background: var(--glass-bg);
  color: var(--bright);
  border-color: var(--edge-hover);
  box-shadow: var(--shadow-1);
}
.tab-btn.disabled { opacity: 0.3; pointer-events: none; }
.tab-btn svg { width: 14px; height: 14px; }

/* ── Run Gallery (Left Sidebar) ── */

.gallery-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px;
  border-bottom: 1px solid var(--edge);
  flex-shrink: 0;
}

.gallery-header h3 {
  font-family: var(--font-heading);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink-200);
}

.gallery-search {
  padding: 6px 10px;
  margin: 8px 12px;
  border-radius: 6px;
  border: 1px solid var(--edge);
  background: var(--ink-950);
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-200);
  outline: none;
  width: calc(100% - 24px);
}
.gallery-search:focus { border-color: var(--edge-hover); }

.run-list { flex: 1; overflow-y: auto; }

.run-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
  transition: background var(--transition);
}
.run-item:hover { background: var(--ink-850); }
.run-item.active { background: var(--accent-faint); border-left: 2px solid var(--bright); }

.run-item .run-status-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

.run-item .run-info {
  flex: 1;
  min-width: 0;
}

.run-item .run-drug {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-100);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.run-item .run-meta {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--ink-500);
  margin-top: 1px;
}
.demo-badge {
  display: inline-block;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.5px;
  padding: 1px 5px;
  border-radius: 3px;
  background: var(--accent-faint, rgba(99,179,237,0.15));
  color: var(--bright, #63b3ed);
  vertical-align: middle;
  margin-left: 4px;
}

.run-item .run-time {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--ink-600);
  white-space: nowrap;
}

/* ── Detail Panel (Right) ── */

.detail-rail {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding-top: 14px;
}

.detail-rail-label {
  writing-mode: vertical-rl;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-600);
  user-select: none;
}

.detail-close {
  background: none;
  border: none;
  color: var(--ink-500);
  cursor: pointer;
  font-size: 16px;
  padding: 4px;
  border-radius: 4px;
}
.detail-close:hover { color: var(--ink-200); background: var(--ink-850); }

.detail-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;
}

.detail-header h3 {
  font-family: var(--font-heading);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

/* ── Status Bar ── */

.status-counter {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.status-counter .count-value {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-200);
  font-variant-numeric: tabular-nums;
}

.status-counter .count-label {
  font-size: 10px;
  color: var(--ink-600);
}

.status-sep {
  width: 1px;
  height: 14px;
  background: var(--edge);
  flex-shrink: 0;
}

/* ── Console Panel (Cards) ── */

.console-panel {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  padding: 20px;
  transition: border-color var(--transition), box-shadow var(--transition);
}
.console-panel:hover { border-color: var(--glass-hover-border); box-shadow: var(--shadow-2); }

.console-panel h3 {
  font-family: var(--font-heading);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin-bottom: 12px;
}

/* ── Stat Cards ── */

.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 12px;
  margin-bottom: 20px;
}

.stat-card {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  padding: 18px;
  text-align: center;
  transition: border-color var(--transition), transform var(--transition);
}
.stat-card:hover {
  border-color: var(--glass-hover-border);
  transform: translateY(-2px);
}

.stat-card .stat-value {
  font-family: var(--font-heading);
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.2;
}

.stat-card .stat-label {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-500);
  margin-top: 4px;
}

/* ── Eyebrow ── */

.eyebrow {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--bright);
}

.section-eyebrow {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-500);
  margin-bottom: 10px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--edge);
}

/* ── Pill ── */

.pill {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.06em;
  border-radius: 9999px;
  padding: 2px 10px;
  border: 1px solid var(--edge);
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
}

.pill-bright { border-color: var(--bright); color: var(--bright); }
.pill-gain { border-color: var(--gain); color: var(--gain); }
.pill-cost { border-color: var(--cost); color: var(--cost); }
.pill-caution { border-color: var(--caution); color: var(--caution); }

/* ── Badge ── */

.badge {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: 4px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* ── Tables ── */

.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}

.data-table thead { position: sticky; top: 0; z-index: 1; }

.data-table th {
  background: var(--ink-900);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-500);
  padding: 8px 10px;
  text-align: left;
  border-bottom: 1px solid var(--edge);
  cursor: pointer;
  user-select: none;
}
.data-table th:hover { color: var(--ink-300); }

.data-table td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}

.data-table tr:hover td { background: var(--accent-faint); }

/* ── Form Elements ── */

.form-group { margin-bottom: 12px; }

.form-group label {
  display: block;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-500);
  margin-bottom: 4px;
}

.form-input {
  width: 100%;
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--edge);
  background: var(--ink-950);
  color: var(--ink-100);
  font-family: var(--font-sans);
  font-size: 13px;
  outline: none;
  transition: border-color var(--transition);
}
.form-input:focus { border-color: var(--bright); box-shadow: 0 0 0 3px var(--accent-dim); }

select.form-input {
  appearance: none;
  cursor: pointer;
}

.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }

textarea.form-input { resize: vertical; line-height: 1.5; min-height: 60px; }

.label-hint {
  font-family: var(--font-sans);
  font-size: 10px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text-3);
  margin-left: 6px;
}

/* Cell line + its "Look up" action share a line: the lookup acts on the field beside it, and
   putting it anywhere else made it read as a form-level button. */
.input-with-action { display: flex; gap: 6px; }
.input-with-action .form-input { flex: 1 1 auto; min-width: 0; }

.duration-field { display: grid; grid-template-columns: 1fr 1.15fr; gap: 6px; }

.btn-quiet {
  flex: 0 0 auto;
  font-family: var(--font-sans);
  font-size: 12px;
  padding: 0 12px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--edge);
  background: var(--surface-3);
  color: var(--text-1);
  cursor: pointer;
  white-space: nowrap;
  transition: border-color var(--transition), color var(--transition);
}
.btn-quiet:hover:not(:disabled) { border-color: var(--edge-hover); color: var(--text-0); }
.btn-quiet:disabled { opacity: 0.5; cursor: default; }

/* The previous Start button was a full-bleed saturated slab — the loudest object on a page
   whose subject is data. An outlined button in the accent reads as primary without shouting. */
.btn-primary {
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 500;
  padding: 10px 18px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--accent);
  background: var(--accent-dim);
  color: var(--accent-hover);
  cursor: pointer;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.btn-primary:hover:not(:disabled) { background: var(--accent); color: var(--accent-ink); }
.btn-primary:disabled {
  border-color: var(--edge);
  background: transparent;
  color: var(--text-3);
  cursor: default;
}
.btn-block { display: block; width: 100%; margin-top: 14px; }

.form-error {
  margin-top: 10px;
  padding: 8px 10px;
  border-left: 2px solid var(--danger);
  background: rgba(210, 119, 122, 0.09);
  font-size: 12px;
  color: var(--text-1);
}

/* ── Cell-line review card ── */

.context-card {
  margin-top: 14px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface-1);
}
.context-card.pending { padding: 14px; }

.context-pending-text { font-size: 12px; color: var(--text-2); }
.context-pending-text b { color: var(--text-0); font-weight: 500; }

.context-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 12px 14px;
  border-bottom: 1px solid var(--line);
}
.context-title { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; min-width: 0; }
.context-name { font-size: 14px; font-weight: 600; color: var(--text-0); }

/* Everything on this card came out of a model. Saying so once, in the header, is the whole
   reason the card is editable at all. */
.context-flag {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-3);
}
.context-head-right { display: flex; align-items: center; gap: 8px; }

.context-conf {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  padding: 2px 8px;
  border: 1px solid currentColor;
  border-radius: 999px;
  opacity: 0.9;
}

.context-warn {
  margin: 12px 14px 0;
  padding: 8px 10px;
  border-left: 2px solid var(--caution);
  background: rgba(198, 169, 107, 0.09);
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-1);
}

.context-summary {
  margin: 12px 14px 0;
  font-size: 12px;
  line-height: 1.6;
  color: var(--text-2);
}

.context-chips { display: flex; flex-wrap: wrap; gap: 6px; padding: 12px 14px; }
.context-chip {
  font-size: 11px;
  color: var(--text-1);
  background: var(--surface-3);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 3px 10px;
}
.chip-key {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-3);
  margin-right: 6px;
}

/* Collapsed by default: the chips answer "did it get this right", and only an operator who
   wants to change something needs eleven inputs and a mutation table. */
.context-body { display: none; padding: 0 14px 14px; }
.context-card.open .context-body { display: block; }

.ctx-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 10px;
  padding-top: 4px;
  border-top: 1px solid var(--line);
}
.ctx-field.wide { grid-column: 1 / -1; }
.ctx-field label {
  display: block;
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: 3px;
}
.ctx-field .req { color: var(--caution); margin-left: 3px; }
.ctx-field .form-input { padding: 6px 9px; font-size: 12px; }

.ctx-section { margin-top: 14px; }
.ctx-none { font-size: 12px; color: var(--text-3); margin: 4px 0 0; }

.mut-list { display: flex; flex-direction: column; gap: 6px; margin-top: 6px; }
.mut-row { display: flex; align-items: center; gap: 6px; }
.mut-row .form-input { padding: 5px 8px; font-size: 12px; font-family: var(--font-mono); }
.mut-gene { flex: 0 0 96px; }
.mut-variant { flex: 1 1 auto; min-width: 0; }
.mut-tag {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.06em;
  color: var(--text-3);
  white-space: nowrap;
}
.mut-remove {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  border: 1px solid var(--edge);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-3);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
}
.mut-remove:hover { color: var(--text-0); border-color: var(--edge-hover); }

.ctx-caveats { margin: 6px 0 0; padding-left: 16px; }
.ctx-caveats li { font-size: 11.5px; line-height: 1.55; color: var(--text-2); margin-bottom: 4px; }

/* ── Dashboard ── */

.dashboard-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  /* Panels size to their content. Stretch is the grid default, and it gave Overview — four
     stat cards — the full height of the form beside it, which is most of a 600px void. */
  align-items: start;
  animation: fadeIn 400ms ease;
}
.dashboard-grid .full-width { grid-column: 1 / -1; }

/* ── Dot Grid Background ── */

.dot-grid {
  background-image: radial-gradient(circle, var(--line) 1px, transparent 1.4px);
  background-size: 22px 22px;
}

/* ── Green Glow ── */

.green-glow {
  box-shadow: var(--shadow-3);
}

/* ── Verdict Cards ── */

.verdict-grid {
  display: grid;
  /* 200px left "Functional Capacity" wrapping under its own verdict badge and the outcome
     node ids breaking mid-token. These cards carry identifiers, so they need the width. */
  grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
  gap: 12px;
  margin-bottom: 20px;
}

.verdict-card {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  padding: 14px;
  cursor: pointer;
  transition: all var(--transition);
}
.verdict-card:hover { border-color: var(--glass-hover-border); box-shadow: var(--shadow-2); transform: translateY(-1px); }

.verdict-card .verdict-domain {
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: 13px;
  letter-spacing: -0.01em;
  margin-bottom: 8px;
  text-transform: capitalize;
}

.verdict-card .verdict-badge {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 4px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #fff;
  margin-bottom: 8px;
}

.confidence-meter { display: flex; gap: 2px; height: 4px; margin: 8px 0; }
.confidence-meter .seg { flex: 1; border-radius: 2px; background: var(--ink-800); }
.confidence-meter .seg.filled { background: var(--bright); }

.verdict-meta {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--ink-500);
}

/* ── Validation / Experiment Cards ── */

.validation-group { margin-bottom: 24px; }

.validation-group h4 {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-500);
  margin-bottom: 10px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--edge);
}

.experiment-card {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  padding: 12px 14px;
  margin-bottom: 8px;
  transition: border-color var(--transition);
}
.experiment-card:hover { border-color: var(--glass-hover-border); }

.experiment-card .exp-header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}

.experiment-card .exp-technique {
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: 13px;
  letter-spacing: -0.01em;
}

.experiment-card .exp-detail {
  font-size: 12px;
  color: var(--ink-400);
  margin: 3px 0;
  line-height: 1.5;
}
.experiment-card .exp-detail strong { color: var(--ink-200); }

/* ── Graph View ── */

/* Takes the height left below the filter bar. It used to subtract a hardcoded 60px, which is
   the filter bar's height only until something in it wraps. */
.graph-container {
  position: relative;
  width: 100%;
  flex: 1;
  min-height: 400px;
}

/* Pinned to the container rather than sized at `height: 100%`. The percentage resolved against
   `.view-fill`, whose own height comes from its content, so it fell back to `auto` and the canvas
   sat at its attribute height — 634px inside a 788px box, with the shortfall showing as dead space
   under the graph. Against a positioned ancestor the percentage has a definite box to resolve to. */
.graph-container canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border-radius: var(--radius);
  background: var(--ink-950);
}

/* No backdrop-filter: this floats directly over the WebGL canvas and follows the cursor, so
   it is the worst possible place to force a per-frame backdrop snapshot. See the note by
   `#detail-panel.expanded`. */
.node-popup {
  position: absolute;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-sm);
  padding: 10px 14px;
  font-size: 12px;
  max-width: 280px;
  z-index: 50;
  pointer-events: none;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
}

/*
 * A view whose last element is a scroller — a long table, a canvas — should be handed the
 * height that is left rather than pick one. Wrapping such a view in `.view-fill` makes it a
 * column that fills the panel; the child marked `flex: 1` takes the remainder.
 *
 * `height`, not `min-height`: with a minimum only the column still grows to fit its content, so
 * `flex: 1` on the scroller caps nothing and a long table runs hundreds of pixels past the bottom
 * of the panel instead of scrolling inside it. Every view using this ends in its own scroller, so
 * bounding the column here is what makes that scroller the one that moves.
 */
.view-fill {
  display: flex;
  flex-direction: column;
  height: 100%;
}

/*
 * Empty states. A view with nothing in it still owes the reader an explanation: whether the
 * run has not got there yet or genuinely produced nothing is the difference between waiting
 * and investigating. Centred in its container rather than top-packed, so an empty view reads
 * as deliberate instead of as a rendering failure.
 */

.view-empty {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 24px;
  text-align: center;
  pointer-events: none;
}

.view-empty-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-300);
}

.view-empty-body {
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-500);
  max-width: 340px;
}

.graph-count {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-500);
}

/* ── DEG View ── */

.volcano-container {
  width: 100%;
  height: 340px;
  flex: none;   /* a flex item defaults to shrinking; the plot needs its stated height */
  margin-bottom: 16px;
  position: relative;
}

/* Pinned rather than sized at `height: 100%`, for the same reason as the graph canvas: the
   percentage has no definite ancestor height to resolve against inside a `.view-fill` column. */
.volcano-container canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border-radius: var(--radius);
  background: var(--ink-950);
}

/* Scrolls to the bottom of the panel rather than stopping at an arbitrary 400px with empty
   space beneath it. */
.gene-table-wrapper {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  border: 1px solid var(--edge);
  border-radius: var(--radius);
}

/* ── Filter Bar ── */

.filter-bar {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-bottom: 14px;
  flex-wrap: wrap;
}

.filter-bar .form-input { width: auto; min-width: 140px; }

/* ── Toggle ── */

/*
 * A toggle's "on" state used to be a solid fill of the brand colour. Four of these sit in
 * the cell view and all four default to on, so the corner of the viewport was four
 * saturated slabs — which is why they read as blank boxes rather than as labelled
 * controls. On is now a tint plus a leading dot: unmistakable, and quiet enough that four
 * of them at once are still just controls.
 */
.toggle-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 11px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: transparent;
  color: var(--text-2);
  font-family: var(--font-sans);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.005em;
  cursor: pointer;
  transition: background var(--transition), color var(--transition),
              border-color var(--transition);
}

.toggle-btn::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.30;
  transition: opacity var(--transition);
}

.toggle-btn:hover {
  background: var(--surface-3);
  border-color: var(--line-strong);
  color: var(--text-1);
}

.toggle-btn.active {
  background: var(--accent-dim);
  border-color: var(--line-focus);
  color: var(--accent-hover);
}

.toggle-btn.active::before { opacity: 1; }

.toggle-btn:focus-visible {
  outline: 2px solid var(--line-focus);
  outline-offset: 2px;
}

/* ── Cell View Controls ── */

.cell-controls {
  position: absolute;
  top: 14px;
  left: 14px;
  z-index: 10;
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 10px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  /* Opaque, not translucent. This panel floats over a moving 3D scene; anything
     see-through means the label text is read against whatever organelle drifts behind
     it, which is exactly the condition under which a control stops being readable. */
  background: var(--surface-1);
  box-shadow: var(--shadow-2);
}

.cell-controls-title {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-3);
  padding: 0 3px 2px;
}

/*
 * Quality is one setting with two values, so it is a segmented control rather than two
 * toggles — a pair of independent switches would allow "both off", which is not a state
 * the renderer has.
 */
.cell-quality-switch {
  display: flex;
  gap: 2px;
  padding: 2px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--surface-0);
}

.seg-btn {
  flex: 1;
  padding: 4px 10px;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: var(--text-3);
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: 500;
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}

.seg-btn:hover { color: var(--text-1); }

.seg-btn.active {
  background: var(--surface-3);
  color: var(--text-0);
}

.seg-btn:focus-visible {
  outline: 2px solid var(--line-focus);
  outline-offset: 1px;
}

/* ── Cell View Legend ──
 *
 * Bottom-left, opposite the layer controls, because it describes the scene rather than
 * operating on it. Hidden entirely when the effect layer has nothing to explain.
 */
.cell-legend {
  position: absolute;
  bottom: 14px;
  left: 14px;
  z-index: 10;
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-width: 240px;
  padding: 10px 12px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--surface-1);
  box-shadow: var(--shadow-2);
  pointer-events: none;
}

.cell-legend-title {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-1);
  letter-spacing: 0.01em;
}

.cell-legend-rows {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
}

.cell-legend-row {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  color: var(--text-2);
  text-transform: capitalize;
}

.cell-legend-row i {
  width: 9px;
  height: 9px;
  border-radius: 2px;
  flex: none;
}

.cell-legend-note {
  font-size: 10px;
  color: var(--text-3);
}

.cell-tooltip {
  position: absolute;
  /* Moved with `transform`, like the labels — animating `left`/`top` would put a layout pass
     in the frame loop for every pixel the cursor travels. These pin the transform's origin. */
  left: 0;
  top: 0;
  pointer-events: none;
  z-index: 50;
  display: flex;
  flex-direction: column;
  gap: 1px;
  background: var(--surface-4);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  padding: 8px 11px;
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--text-0);
  line-height: 1.45;
  white-space: nowrap;
  box-shadow: var(--shadow-2);
}
.cell-tooltip-name { font-weight: 600; }
.cell-tooltip-meta { font-size: 11px; color: var(--text-3); }

/* ── Cell Labels ──
 *
 * Placed by cell3d-labels.js in screen space; everything here is presentation only. The
 * layer has no background of its own and does not take pointer events — the canvas
 * underneath must stay fully draggable, including the pixels a label happens to cover.
 */

.cell-label-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 8;
  overflow: hidden;
}

.cell-label-lines {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.cell-label-line {
  fill: none;
  stroke: var(--line-strong);
  stroke-width: 1;
  /* The leader is an aid, not a feature. It should be findable when you look for it and
     invisible when you are not — the previous version drew opaque white polylines that
     read as scratches across the cell. */
  opacity: 0.55;
  transition: opacity var(--transition);
}
.cell-label-line.is-far { opacity: 0.22; }

.cell-label {
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 3px 8px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--surface-1);
  color: var(--text-1);
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.01em;
  white-space: nowrap;
  box-shadow: var(--shadow-1);
  /* transform is set per frame, so it must not be transitioned — a transition here would
     make every label lag the camera by its own duration. */
  transition: opacity var(--transition), border-color var(--transition);
}

.cell-label.is-far {
  opacity: 0.45;
}

.cell-label.is-active {
  opacity: 1;
  border-color: var(--line-focus);
  color: var(--text-0);
}

/*
 * A label with nowhere to go: its anchor has turned behind the cell, or the collision solver
 * ran out of slots that do not sit on top of something else.
 *
 * It fades rather than being switched off. These come and go constantly while the cell
 * rotates, and a dozen elements blinking in and out is perceived as the whole scene
 * stuttering — the frames were arriving on time all along, the labels just looked like they
 * were not. Last of the three, so it outranks both `is-far` and `is-active`, which are
 * equally specific and would otherwise win on source order alone.
 */
.cell-label.is-off,
.cell-label-line.is-off {
  opacity: 0;
}

.cell-label-chip {
  display: inline-flex;
  align-items: center;
  width: 34px;
  height: 4px;
  border-radius: 2px;
  background: var(--surface-3);
  overflow: hidden;
}

.cell-label-chip i {
  display: block;
  height: 100%;
  border-radius: 2px;
  transition: width var(--transition);
}

/* ── Domain / Node lists ── */

.domain-item {
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
}
.domain-item:last-child { border-bottom: none; }

.domain-item .domain-name {
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: 13px;
  letter-spacing: -0.01em;
  margin-bottom: 4px;
}

.domain-item .domain-meta {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--ink-500);
  display: flex;
  gap: 8px;
  align-items: center;
}

.node-list { max-height: 280px; overflow-y: auto; margin-top: 8px; }

.node-list-item {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 0;
  font-size: 12px;
  border-bottom: 1px solid var(--line);
}

.node-list-item .node-entity {
  font-weight: 500;
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Expandable ── */

.expandable-header {
  display: flex;
  align-items: center;
  gap: 5px;
  cursor: pointer;
  padding: 4px 0;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-500);
  user-select: none;
}
.expandable-header:hover { color: var(--ink-300); }

.expandable-content { display: none; padding: 6px 0 6px 14px; }
.expandable-content.open { display: block; }

/* ── Event Log (in status bar region) ── */

.event-stream {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--bright);
  white-space: nowrap;
}

.event-stream .stream-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--bright);
  animation: pulse-dot 2s ease-in-out infinite;
  flex-shrink: 0;
}

/* ── Empty State ── */

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 48px 24px;
  text-align: center;
}

.empty-state .empty-icon {
  font-size: 36px;
  margin-bottom: 12px;
  opacity: 0.2;
}

.empty-state p {
  font-size: 13px;
  max-width: 320px;
  line-height: 1.6;
  color: var(--ink-500);
}

.empty-state .heading {
  font-family: var(--font-heading);
  font-size: 15px;
  font-weight: 600;
  color: var(--ink-300);
  margin-bottom: 6px;
}

/* ── Progress Sweep ── */

.progress-sweep {
  height: 2px;
  width: 30%;
  background: var(--bright);
  border-radius: 2px;
  animation: sweep 1.8s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}

/* ── Utilities ── */

.hidden { display: none !important; }
.mt-8 { margin-top: 8px; }
.mt-12 { margin-top: 12px; }
.mt-16 { margin-top: 16px; }
.mb-8 { margin-bottom: 8px; }
.mb-12 { margin-bottom: 12px; }
.mb-16 { margin-bottom: 16px; }

/* ── Animations ── */

@keyframes pulse-dot {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.4; }
}

/* Was a pulsing cyan halo on the live-run header. A glow that grows and shrinks reads as
   decoration; a border that brightens reads as "this is live" and costs no attention. */
@keyframes breathe {
  0%, 100% { border-color: var(--line); }
  50% { border-color: var(--line-strong); }
}

@keyframes sweep {
  0% { transform: translateX(-110%); }
  100% { transform: translateX(420%); }
}

@keyframes manifest-in {
  from { opacity: 0; filter: blur(6px); }
  to { opacity: 1; filter: blur(0); }
}

@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* ── Activity Dock ── */

.activity-dock {
  /* In flow at the foot of the view frame — see the note on #cell-canvas-container. */
  position: relative;
  flex-shrink: 0;
  background: var(--ink-900);
  border-top: 1px solid var(--edge);
  z-index: 20;
  transition: height var(--transition);
  height: var(--dock-height, 240px);
  display: flex;
  flex-direction: column;
}
.activity-dock.collapsed { height: 36px; overflow: hidden; }
/* Nothing to resize when there is nothing showing, and the strip would sit over the header's
   own click target. */
.activity-dock.collapsed .resize-handle { display: none; }

.activity-dock-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 12px;
  height: 36px;
  flex-shrink: 0;
  cursor: pointer;
  border-bottom: 1px solid var(--edge);
}
.activity-dock-header:hover { background: var(--ink-850); }

.activity-dock-left {
  display: flex;
  align-items: center;
  gap: 10px;
}

.activity-expand-btn {
  background: none;
  border: none;
  color: var(--ink-500);
  cursor: pointer;
  padding: 4px;
  border-radius: var(--radius-sm);
}
.activity-expand-btn:hover { color: var(--ink-200); }
.activity-expand-btn svg { display: block; }

/* The columns scroll individually, so the body must not become a scroller of its own. */
.activity-dock-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.activity-columns {
  display: flex;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

.activity-col {
  flex: 1;
  display: flex;
  flex-direction: column;
  border-right: 1px solid var(--edge);
  overflow: hidden;
}
.activity-col:last-child { border-right: none; }
.activity-col-wide { flex: 2; }

.activity-col-header {
  padding: 4px 10px;
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-600);
  border-bottom: 1px solid var(--edge);
  flex-shrink: 0;
}

.agent-board {
  flex: 1;
  overflow-y: auto;
  padding: 6px 8px;
}

.agent-level-group { margin-bottom: 6px; }

.agent-level-label {
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 3px;
}

.agent-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 3px 6px;
  border-radius: 4px;
  font-size: 10px;
  color: var(--ink-400);
  margin-bottom: 2px;
}
.agent-card.agent-active { background: var(--accent-faint); color: var(--ink-200); }

.agent-name {
  text-transform: capitalize;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
}

.agent-stats {
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--ink-600);
  flex-shrink: 0;
  margin-left: 6px;
}

.agent-empty {
  font-size: 10px;
  color: var(--ink-600);
  text-align: center;
  padding: 12px;
}

.activity-ticker {
  flex: 1;
  overflow-y: auto;
  padding: 4px 8px;
}

.ticker-item {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 2px 0;
  font-size: 10px;
  color: var(--ink-400);
  animation: manifest-in 0.2s ease;
}

.ticker-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  flex-shrink: 0;
}

.ticker-time {
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--ink-600);
  flex-shrink: 0;
}

.ticker-kind {
  font-weight: 500;
  color: var(--ink-300);
  text-transform: capitalize;
  flex-shrink: 0;
}

.ticker-msg {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
}

.activity-node-stream {
  display: flex;
  gap: 4px;
  padding: 4px 8px;
  overflow-x: auto;
  border-top: 1px solid var(--edge);
  flex-shrink: 0;
}

.node-stream-pill {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 2px 8px;
  border-radius: 9999px;
  border: 1px solid var(--edge);
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--ink-200);
  cursor: pointer;
  white-space: nowrap;
  animation: manifest-in 0.3s ease;
  flex-shrink: 0;
}
.node-stream-pill:hover { border-color: var(--edge-hover); }
.node-stream-pill.fading { opacity: 0; transition: opacity 0.3s; }

.node-pill-entity { font-weight: 500; }

.node-pill-dir {
  font-size: 9px;
  font-weight: 600;
  text-transform: uppercase;
}
.node-pill-dir.up { color: #ff4d6a; }
.node-pill-dir.down { color: #4da6ff; }
.node-pill-dir.present { color: #2ecc71; }

.activity-last-event {
  font-size: 10px;
  color: var(--ink-400);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Diff Cards ── */

.diff-cards {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.diff-card {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
}
.diff-card:hover { border-color: var(--edge-hover); }

/* ── Keyboard Help ── */

.kb-help-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}

.kb-help-card {
  background: var(--ink-900);
  border: 1px solid var(--edge);
  border-radius: var(--radius);
  padding: 20px;
  min-width: 320px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}

.kb-help-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
  font-family: var(--font-heading);
  font-size: 15px;
  font-weight: 600;
}

.kb-help-body { display: flex; flex-direction: column; gap: 6px; }

.kb-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--ink-300);
}

.kb-row kbd {
  display: inline-block;
  padding: 2px 7px;
  border-radius: 4px;
  border: 1px solid var(--edge);
  background: var(--ink-950);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  color: var(--ink-200);
  min-width: 24px;
  text-align: center;
}

/* The resize handles are defined once, further down — this was an earlier copy of the same
   three rules, overridden in full by the later block and so only a trap for the next edit. */

/* ── Coverage View ── */

.coverage-table {
  width: 100%;
  border-collapse: collapse;
}

.coverage-table th,
.coverage-table td {
  padding: 6px 8px;
  border: 1px solid var(--edge);
  font-size: 11px;
}

.coverage-table th {
  background: var(--ink-900);
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-500);
  text-align: left;
}

.coverage-cell {
  text-align: center;
  cursor: pointer;
  transition: background var(--transition);
}
.coverage-cell:hover { border-color: var(--edge-hover); }

/* The dock's own box is defined once, further up. What was here was an earlier version of the
   same six rules, and being later it won the cascade — its `.activity-dock-body` padding and
   `overflow-y: auto` wrapped the column layout in a second scroller. */

.activity-last-event {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--ink-500);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── Stream Pill ── */

.stream-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  padding: 2px 8px;
  border-radius: 9999px;
  border: 1px solid var(--edge);
  white-space: nowrap;
  color: var(--ink-500);
}
.stream-pill.connected { color: var(--bright); border-color: var(--line-focus); }
.stream-pill.reconnecting { color: var(--caution); border-color: rgba(210, 153, 34, 0.3); }
.stream-pill.stalled { color: var(--cost); border-color: rgba(219, 109, 40, 0.3); }
/* A finished run is a resting state, not a fault: readable, but with none of the urgency
   the caution/cost hues carry. */
.stream-pill.finished { color: var(--ink-400); border-color: var(--edge); }
.stream-pill.disconnected { color: var(--ink-600); }

.stream-pill-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}
.stream-pill.connected .stream-pill-dot { animation: pulse-dot 2s ease-in-out infinite; }

/* ── Stage Bar ── */

.activity-stage-bar {
  display: flex;
  align-items: center;
  gap: 0;
  padding: 6px 0;
  border-bottom: 1px solid var(--edge);
}

.stage-segment {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: 6px;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--ink-600);
  transition: all var(--transition);
}
.stage-segment.active { color: var(--bright); background: var(--accent-faint); }
.stage-segment.completed { color: var(--ink-400); }
/* Not reached, and never will be on this run — mechanism discovery only runs for an unknown
   molecule. Dimmed and struck through, so it reads as "not applicable", not "still pending". */
.stage-segment.skipped { color: var(--ink-600); }
.stage-segment.skipped .stage-label { text-decoration: line-through; }

.stage-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: 2px solid var(--ink-600);
  background: var(--ink-700);
  flex-shrink: 0;
  transition: all var(--transition);
}
.stage-segment.active .stage-dot { border-color: var(--bright); background: var(--bright); animation: pulse-dot 2s ease-in-out infinite; }
.stage-segment.completed .stage-dot { border-color: var(--ink-400); background: var(--ink-400); }

.stage-connector {
  width: 20px;
  height: 2px;
  background: var(--ink-700);
  flex-shrink: 0;
}

/* ── Activity Columns ── */

.activity-columns {
  display: flex;
  gap: 12px;
  flex: 1;
  min-height: 0;
}

.activity-col {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.activity-col-wide { flex: 2; }

.activity-col-header {
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-600);
  margin-bottom: 6px;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--edge);
}

/* ── Agent Board ── */

.agent-board {
  flex: 1;
  overflow-y: auto;
}

.agent-level-group { margin-bottom: 8px; }

.agent-level-label {
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin-bottom: 4px;
}

.agent-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 11px;
  border-left: 2px solid transparent;
  margin-bottom: 2px;
}
.agent-card.agent-active { background: var(--accent-faint); border-left-color: var(--bright); }

.agent-name {
  color: var(--ink-300);
  text-transform: capitalize;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.agent-stats {
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--ink-600);
  white-space: nowrap;
}

.agent-empty {
  font-size: 11px;
  color: var(--ink-600);
  padding: 12px 0;
}

/* ── Ticker ── */

.activity-ticker {
  flex: 1;
  overflow-y: auto;
  font-size: 11px;
}

.ticker-item {
  display: flex;
  align-items: baseline;
  gap: 6px;
  padding: 2px 0;
  border-bottom: 1px solid var(--line);
}

.ticker-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  flex-shrink: 0;
  margin-top: 4px;
}

.ticker-time {
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--ink-600);
  white-space: nowrap;
}

.ticker-kind {
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--ink-500);
  text-transform: capitalize;
  white-space: nowrap;
}

.ticker-msg {
  color: var(--ink-400);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── Node Stream ── */

.activity-node-stream {
  display: flex;
  gap: 6px;
  padding: 6px 0;
  overflow-x: auto;
  flex-shrink: 0;
  scrollbar-width: none;
}
.activity-node-stream::-webkit-scrollbar { display: none; }

.node-stream-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 8px;
  border-radius: 9999px;
  border: 1px solid var(--edge);
  font-size: 10px;
  white-space: nowrap;
  cursor: pointer;
  transition: all var(--transition);
  animation: pill-slide-in 300ms ease-out;
  flex-shrink: 0;
}
.node-stream-pill:hover { border-color: var(--edge-hover); background: var(--accent-faint); }
.node-stream-pill.fading { opacity: 0; transition: opacity 300ms ease-out; }

.node-pill-entity {
  font-weight: 500;
  color: var(--ink-200);
}

.node-pill-dir {
  font-family: var(--font-mono);
  font-size: 8px;
  font-weight: 600;
  text-transform: uppercase;
  padding: 1px 4px;
  border-radius: 3px;
}
.node-pill-dir.up { color: #ff4d6a; background: rgba(255, 77, 106, 0.15); }
.node-pill-dir.down { color: #4da6ff; background: rgba(77, 166, 255, 0.15); }
.node-pill-dir.present { color: #2ecc71; background: rgba(46, 204, 113, 0.15); }
.node-pill-dir.altered { color: #f59e0b; background: rgba(245, 158, 11, 0.15); }

/* ── Detail Panel Enhancements ── */

.detail-stats {
  display: flex;
  gap: 12px;
  margin-bottom: 12px;
}

.detail-stat {
  font-family: var(--font-heading);
  font-size: 16px;
  font-weight: 700;
  color: var(--ink-200);
}

.detail-stat-label {
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 500;
  color: var(--ink-600);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.detail-tabs {
  display: flex;
  gap: 2px;
  border-bottom: 1px solid var(--edge);
  padding-bottom: 0;
}

.detail-tab {
  padding: 6px 12px;
  border: none;
  background: none;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  color: var(--ink-500);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: all var(--transition);
}
.detail-tab:hover { color: var(--ink-200); }
.detail-tab.active { color: var(--bright); border-bottom-color: var(--bright); }

.detail-tab-content { margin-top: 12px; }

.detail-open-in {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

.open-in-btn {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  padding: 4px 10px;
  border-radius: 4px;
  border: 1px solid var(--edge);
  background: transparent;
  color: var(--ink-400);
  cursor: pointer;
  transition: all var(--transition);
}
.open-in-btn:hover { border-color: var(--edge-hover); color: var(--bright); }

/* ── Evidence ── */

.evidence-group { margin-bottom: 12px; }

.evidence-group-header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
}

.evidence-item {
  padding: 6px 0;
  border-bottom: 1px solid var(--line);
}

.evidence-entity {
  font-weight: 600;
  font-size: 12px;
  color: var(--ink-200);
}

.evidence-domain {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--ink-500);
  margin-left: 8px;
  text-transform: capitalize;
}

.evidence-text {
  font-size: 11px;
  color: var(--ink-400);
  margin-top: 3px;
  line-height: 1.5;
}

/* ── Connections ── */

.connection-count {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--ink-500);
  margin-bottom: 8px;
}

.connection-item {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 0;
  font-size: 11px;
  border-bottom: 1px solid var(--line);
}

.conn-source, .conn-target {
  padding: 2px 6px;
  border-radius: 3px;
  border-left: 2px solid;
  font-weight: 500;
  color: var(--ink-200);
}

.conn-arrow {
  color: var(--ink-600);
  font-size: 10px;
}

.conn-type {
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--ink-600);
  margin-left: auto;
}

/* ── Verdict View ── */

.verdict-level-group { margin-bottom: 20px; }

.verdict-level-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
  font-family: var(--font-heading);
  font-size: 13px;
}

.verdict-level-count { font-family: var(--font-mono); font-size: 10px; color: var(--ink-500); }

.verdict-summary {
  margin: 8px 0 0;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--ink-300);
  max-width: 78ch;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 6;
  line-clamp: 6;
  overflow: hidden;
}
.verdict-summary-wrap.open .verdict-summary {
  -webkit-line-clamp: unset;
  line-clamp: unset;
  overflow: visible;
}

.verdict-more {
  margin-top: 6px;
  padding: 0;
  border: 0;
  background: none;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-500);
  cursor: pointer;
}
.verdict-more:hover { color: var(--bright); }

.verdict-targets { margin-top: 14px; }

.verdict-target { padding: 7px 0; border-top: 1px solid var(--edge); }

.target-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
}

.target-entity { font-family: var(--font-mono); font-size: 11px; color: var(--ink-200); }
.target-observable { font-size: 11px; color: var(--ink-400); }
.target-domain {
  font-family: var(--font-mono);
  font-size: 9.5px;
  color: var(--ink-600);
  margin-left: auto;
}

.target-dir {
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.target-dir.up { color: var(--up); }
.target-dir.down { color: var(--down); }
.target-dir.altered, .target-dir.relocated { color: var(--verdict-ambiguous); }

.target-rationale {
  margin: 3px 0 0;
  font-size: 11.5px;
  line-height: 1.55;
  color: var(--ink-500);
  max-width: 78ch;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}

.verdict-open { margin-top: 14px; }

.verdict-question {
  padding: 6px 0 6px 10px;
  border-left: 2px solid var(--edge);
  margin-bottom: 6px;
}
.verdict-question p { margin: 0; font-size: 12px; line-height: 1.5; color: var(--ink-300); max-width: 78ch; }
.verdict-question .question-reason { margin-top: 3px; font-size: 11.5px; color: var(--ink-600); }

/* Both steps side by side down to the point where the tallies stop fitting. */
.verdict-steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 16px;
  margin-top: 10px;
}

.verdict-step-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 8px;
}

.verdict-step-name {
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: 13px;
}

.verdict-step-count { font-family: var(--font-mono); font-size: 10px; color: var(--ink-500); }

.verdict-bar {
  display: flex;
  gap: 2px;
  height: 6px;
  border-radius: 3px;
  overflow: hidden;
}
.verdict-bar-seg { display: block; min-width: 3px; }

.verdict-legend-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 8px 0 12px;
}

.verdict-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--ink-400);
}
.verdict-legend-item.muted { color: var(--ink-600); }
.verdict-legend-item b { color: var(--ink-200); font-weight: 600; }
.verdict-legend-dot { width: 7px; height: 7px; border-radius: 50%; }

.verdict-domain-table { width: 100%; border-collapse: collapse; }
.verdict-domain-table tr { border-top: 1px solid var(--edge); }
.verdict-domain-table td { padding: 5px 0; vertical-align: baseline; }

.vd-name { font-size: 12px; color: var(--ink-300); text-transform: capitalize; white-space: nowrap; }
.vd-tally { display: flex; flex-wrap: wrap; gap: 8px; padding-left: 12px !important; }
.vd-pill { font-family: var(--font-mono); font-size: 10px; }
.vd-total {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--ink-600);
  text-align: right;
  width: 2.5ch;
}

.verdict-note {
  font-size: 11px;
  line-height: 1.5;
  color: var(--ink-600);
  margin-top: 8px;
}

/* Provenance sits under the meta line, before the fold: whether an agent concluded this or
   the readout inferred it changes what the badge above is worth, so it is never hidden. */
.verdict-provenance {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-top: 6px;
}
.verdict-source {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.04em;
  padding: 1px 6px;
  border-radius: 3px;
  border: 1px solid var(--edge);
  color: var(--ink-600);
}
.verdict-source.assessed { color: var(--ink-300); border-color: var(--ink-600); }
.verdict-source.derived { color: var(--caution); border-color: currentColor; }
.verdict-dissent {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--caution);
}

.verdict-coverage { margin: 4px 0 0; padding-left: 14px; }
.verdict-coverage li { margin: 2px 0; }

/* What adoption left unsettled. Reads as a record, not a warning banner: these are findings
   a bench experiment resolves, and colouring them like errors would bury them under the
   run's real errors. */
.adoption-step { margin-top: 12px; }
.adoption-step-head {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-600);
  padding-bottom: 4px;
  border-bottom: 1px solid var(--edge);
}
.adoption-group { margin-top: 8px; }
.adoption-group-head {
  font-size: 11px;
  line-height: 1.5;
  color: var(--ink-300);
  margin-bottom: 4px;
}
.adoption-list {
  margin: 0;
  padding-left: 16px;
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1.7;
  color: var(--ink-600);
  word-break: break-all;
}
.adoption-contested {
  border-left: 2px solid var(--caution);
  padding: 4px 0 4px 8px;
  margin-bottom: 6px;
}
.adoption-contested-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  font-size: 10px;
}
.adoption-round {
  font-family: var(--font-mono);
  color: var(--ink-600);
}
.adoption-route { color: var(--ink-300); }
.adoption-decision {
  font-family: var(--font-mono);
  letter-spacing: 0.04em;
  padding: 1px 5px;
  border-radius: 3px;
  border: 1px solid var(--edge);
  color: var(--ink-600);
}
.adoption-decision.reject { color: var(--danger); border-color: currentColor; }
.adoption-decision.accept,
.adoption-decision.accept_edge_only { color: var(--caution); border-color: currentColor; }
.adoption-node {
  display: block;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--ink-600);
  margin-top: 3px;
  word-break: break-all;
}
.adoption-reason {
  font-size: 11px;
  line-height: 1.5;
  color: var(--ink-300);
  margin-top: 3px;
}

/* The card head is the click target; the body is what unfolds. */
.verdict-card-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
}
.verdict-card-head .verdict-domain { margin-bottom: 0; }

.verdict-card-body { display: none; margin-top: 10px; }
.verdict-card.open .verdict-card-body { display: block; }

.verdict-nodes { margin-top: 10px; }
.verdict-node-id {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 9.5px;
  color: var(--ink-400);
  background: var(--ink-900, rgba(255, 255, 255, 0.03));
  border-radius: 3px;
  padding: 1px 5px;
  margin: 2px 3px 0 0;
  word-break: break-all;
}

.verdict-chains { margin-top: 4px; }

.verdict-chain {
  border-left: 2px solid var(--edge);
  padding-left: 10px;
  margin-bottom: 10px;
}

.chain-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--ink-600);
  margin-bottom: 4px;
}
.chain-rank { font-weight: 700; color: var(--ink-400); }
.chain-len { margin-left: auto; }

.chain-step {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 5px;
  font-size: 10px;
  padding: 2px 0;
}
.chain-step code { font-family: var(--font-mono); color: var(--ink-300); word-break: break-all; }
.chain-arrow { color: var(--ink-600); }
.chain-arrow.positive { color: var(--up); }
.chain-arrow.negative { color: var(--down); }
.chain-arrow.biphasic, .chain-arrow.context_dependent { color: var(--verdict-ambiguous); }
.chain-mech { flex-basis: 100%; color: var(--ink-600); line-height: 1.45; }

.verdict-paths { padding-left: 8px; }

.causal-path {
  display: flex;
  align-items: baseline;
  gap: 6px;
  padding: 3px 0;
  font-size: 10px;
}

.path-rank {
  font-family: var(--font-mono);
  font-weight: 600;
  color: var(--ink-500);
}

.path-chain {
  font-family: var(--font-mono);
  color: var(--ink-300);
  word-break: break-all;
}

.path-conf {
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--ink-600);
  white-space: nowrap;
  margin-left: auto;
}

.verdict-open-in {
  margin-top: 8px;
  font-family: var(--font-mono);
  font-size: 9px;
  padding: 3px 8px;
  border-radius: 4px;
  border: 1px solid var(--edge);
  background: transparent;
  color: var(--ink-500);
  cursor: pointer;
  transition: all var(--transition);
}
.verdict-open-in:hover { border-color: var(--edge-hover); color: var(--bright); }

/* ── Synthesis ── */

.synthesis-row {
  display: flex;
  gap: 8px;
  padding: 4px 0;
  font-size: 12px;
}

.synthesis-label {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  color: var(--ink-500);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  min-width: 90px;
}

.synthesis-value { color: var(--ink-200); }
.synthesis-value.mono { font-family: var(--font-mono); font-size: 11px; }

.synthesis-findings { padding-left: 8px; }

.finding-item {
  font-size: 12px;
  color: var(--ink-300);
  padding: 3px 0;
  border-left: 2px solid var(--edge);
  padding-left: 10px;
  margin-bottom: 4px;
}

/* ── Coverage Table ── */

/*
 * The table scrolls to the bottom of the panel, not to an arbitrary 600px. The fixed height
 * cut the last visible row in half and left the space beneath it empty — the reader could see
 * there was more, but not that the view had simply stopped short of its own container.
 */
.coverage-table-wrapper {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  border: 1px solid var(--edge);
  border-radius: var(--radius);
}

.coverage-level-row td {
  padding: 10px !important;
  font-family: var(--font-heading) !important;
  font-size: 12px !important;
  background: var(--ink-950) !important;
  border-bottom: 1px solid var(--edge) !important;
}

.coverage-domain-row { cursor: pointer; transition: background var(--transition); }
.coverage-domain-row:hover { background: var(--accent-faint) !important; }

.coverage-domain-name {
  text-transform: capitalize;
  font-weight: 500;
}

/* ── Diff View ── */

.diff-selector { max-width: 400px; }

.diff-row.diff-changed { border-left: 3px solid #e8a127; }
.diff-row.diff-added { border-left: 3px solid #5bbd74; }
.diff-row.diff-removed { border-left: 3px solid #FF5252; }

.verdict-diff-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 12px;
}

.verdict-diff-card {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  padding: 14px;
}

.verdict-diff-domain {
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: 13px;
  text-transform: capitalize;
  margin-bottom: 6px;
}

.verdict-diff-comparison {
  display: flex;
  align-items: center;
  gap: 8px;
}

.verdict-diff-side {
  display: flex;
  align-items: center;
  gap: 4px;
  flex: 1;
}

.verdict-diff-label {
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 600;
  color: var(--ink-600);
  text-transform: uppercase;
}

.verdict-diff-arrow {
  color: var(--ink-600);
  font-size: 14px;
}

/* ── Resize Handles ── */

.resize-handle {
  position: absolute;
  z-index: 30;
  background: transparent;
  transition: background var(--transition);
}
.resize-handle:hover { background: var(--accent-dim); }

.resize-handle-left {
  left: 0;
  top: 0;
  bottom: 0;
  width: 4px;
  cursor: col-resize;
}

.resize-handle-right {
  right: 0;
  top: 0;
  bottom: 0;
  width: 4px;
  cursor: col-resize;
}

.resize-handle-top {
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  cursor: row-resize;
}

/* ── Keyboard Shortcut Help ── */

.kb-help-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: center;
}

.kb-help-card {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  padding: 20px 24px;
  max-width: 380px;
  width: 90%;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
}

.kb-help-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;
  font-family: var(--font-heading);
  font-size: 15px;
  font-weight: 600;
  color: var(--ink-100);
}

.kb-help-body { display: flex; flex-direction: column; gap: 6px; }

.kb-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--ink-300);
}

kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 22px;
  padding: 0 6px;
  border-radius: 4px;
  border: 1px solid var(--ink-700);
  background: var(--ink-850);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  color: var(--ink-300);
}

/* ── Domain Verdict (in detail panel) ── */

.domain-verdict {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
}

@keyframes pill-slide-in {
  from { transform: translateX(20px); opacity: 0; }
  to { transform: translateX(0); opacity: 1; }
}

/* ── Run Cards (Dashboard) ── */

.run-cards-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 14px;
}

.run-card {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  overflow: hidden;
  cursor: pointer;
  transition: border-color var(--transition), transform var(--transition), box-shadow var(--transition);
  animation: fadeInUp 400ms ease both;
}
.run-card:hover {
  border-color: var(--glass-hover-border);
  transform: translateY(-3px);
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
}

.run-card-status {
  height: 3px;
  width: 100%;
}

.run-card-body {
  padding: 14px 16px;
}

.run-card-drug {
  font-weight: 600;
  font-size: 14px;
  color: var(--ink-100);
  margin-bottom: 4px;
}

.run-card-meta {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-400);
}

.run-card-footer {
  display: flex;
  justify-content: space-between;
  margin-top: 10px;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--ink-600);
}

/* ── Staggered Run Items ── */

.run-item { animation: fadeInUp 300ms ease both; }
.run-item:nth-child(1) { animation-delay: 0ms; }
.run-item:nth-child(2) { animation-delay: 30ms; }
.run-item:nth-child(3) { animation-delay: 60ms; }
.run-item:nth-child(4) { animation-delay: 90ms; }
.run-item:nth-child(5) { animation-delay: 120ms; }
.run-item:nth-child(6) { animation-delay: 150ms; }
.run-item:nth-child(7) { animation-delay: 180ms; }
.run-item:nth-child(8) { animation-delay: 210ms; }
.run-item:nth-child(9) { animation-delay: 240ms; }
.run-item:nth-child(10) { animation-delay: 270ms; }

/*
 * No `backdrop-filter` on either of these. `--glass-bg` is an opaque surface, so the filter
 * blurred nothing visible — but a backdrop-filter at *any* radius still promotes the element to its own
 * compositing layer and makes the compositor re-snapshot everything behind it every frame.
 * Behind both of these is the live WebGL cell. That cost bought zero pixels of difference,
 * and on some GPU/driver pairs the re-snapshot of a canvas mid-draw is what paints the
 * black rectangle over the cell while it is being dragged.
 */

#detail-panel.expanded {
  background: var(--glass-bg);
  border-left: 1px solid var(--glass-border);
}

.activity-dock {
  background: var(--glass-bg);
  border-top: 1px solid var(--glass-border);
}

/* ── Empty State (Enhanced) ── */

.empty-icon-large {
  color: var(--ink-700);
  margin-bottom: 16px;
}

/* ── Responsive ── */

@media (max-width: 1100px) {
  #detail-panel { display: none; }
}

@media (max-width: 900px) {
  #run-gallery { width: 56px; }
  .run-item .run-info, .run-item .run-time, .gallery-search { display: none; }
  .run-item { justify-content: center; padding: 10px; }
  .gallery-header h3 { display: none; }
  .activity-columns { flex-direction: column; }
}

@media (max-width: 600px) {
  #run-gallery { display: none; }
  .dashboard-grid { grid-template-columns: 1fr; }
  .activity-dock { display: none; }
}

/* ══ Node exploration, run log and replay ══════════════════════════════════════════════
 *
 * Three views and one transport control, added so that the three thousand findings a run
 * produces are individually reachable and the run itself is watchable after the fact.
 *
 * All of them are list-shaped and all of them are long, so they share one structural idea:
 * a fixed header and filter bar, then a single scroller that takes the rest of the height.
 * Nothing here paginates — the scrollbar is the honest indicator of how much there is.
 */

/* ── View header, shared by the list views ── */

/* The container scrolls for document-shaped views; the list views scroll their own body
   instead, so that their header and filters stay fixed above a very long list. */
#panel-container.fill {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
#panel-container.fill > .filter-bar { flex-shrink: 0; }

.view-header {
  flex-shrink: 0;
  margin-bottom: 14px;
}

.view-title {
  font-family: var(--font-heading);
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text-0);
  margin: 0 0 4px;
}

.view-subtitle {
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-2);
  margin: 0;
  max-width: 70ch;
}

/* ── Node explorer ──
 *
 * Windowed: #nx-spacer carries the full height of the filtered list so the scrollbar tells
 * the truth, and #nx-rows holds only the visible slice, translated into place. Row height is
 * fixed at 54px in both the stylesheet and node-explorer.js — they must agree, or the slice
 * drifts out from under the scroll position.
 */

.nx-body {
  position: relative;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-1);
}

.nx-spacer { position: relative; }
.nx-rows { position: absolute; top: 0; left: 0; right: 0; will-change: transform; }

.nx-row {
  display: grid;
  grid-template-columns: 4px 1fr auto;
  align-items: center;
  gap: 12px;
  padding: 0 14px;
  box-sizing: border-box;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
  transition: background var(--transition);
}
.nx-row:hover { background: var(--surface-2); }
.nx-row:focus-visible { outline: 2px solid var(--line-focus); outline-offset: -2px; }

/* The direction stripe. A bar rather than a dot: at 54px rows a dot is lost, and the bar
   doubles as the row's left rule. */
.nx-dir { width: 4px; height: 26px; border-radius: 2px; }

.nx-main { min-width: 0; }

.nx-name {
  font-size: 13px;
  color: var(--text-0);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The real identifier, in the case the pipeline wrote it. This is the point of the view. */
.nx-id {
  display: block;
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--text-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.nx-meta { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }

.nx-chip {
  font-size: 10px;
  font-family: var(--font-mono);
  padding: 2px 6px;
  border-radius: var(--radius-sm);
  background: var(--surface-3);
  white-space: nowrap;
}
.nx-chip-mag { color: var(--text-1); }
.nx-chip-warn { color: var(--caution); background: rgba(198, 169, 107, 0.12); }

.nx-none { position: absolute; inset: 0; }

@media (max-width: 1400px) {
  /* The chips are the first thing to go: the name and the identifier are the content. */
  .nx-meta .nx-chip:nth-child(n+3) { display: none; }
}

/* ── Node inspector (right panel) ── */

.ni-title {
  font-family: var(--font-heading);
  font-size: 14px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--text-0);
  margin: 0;
}

.ni-id-row {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin: 8px 0 12px;
}

.ni-id {
  flex: 1;
  min-width: 0;
  font-family: var(--font-mono);
  font-size: 10.5px;
  line-height: 1.5;
  color: var(--text-1);
  background: var(--surface-0);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 5px 7px;
  /* Wrapped, not truncated: an identifier you cannot read in full is not an identifier. */
  word-break: break-all;
  user-select: all;
}

.ni-copy {
  flex-shrink: 0;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-2);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 5px 8px;
  cursor: pointer;
  transition: color var(--transition), border-color var(--transition);
}
.ni-copy:hover { color: var(--text-0); border-color: var(--line-strong); }

.ni-badges { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 14px; }

.ni-section {
  padding-top: 12px;
  margin-top: 12px;
  border-top: 1px solid var(--line);
}

.ni-field {
  display: grid;
  /* minmax(0,…) so a long value wraps inside the panel instead of widening the grid
     and running out past the panel's right edge. */
  grid-template-columns: 96px minmax(0, 1fr);
  gap: 8px;
  align-items: baseline;
  padding: 3px 0;
  font-size: 12px;
}
.ni-field-label { color: var(--text-2); font-size: 11px; }
.ni-field-value { color: var(--text-0); word-break: break-word; }
/* A layer key is one unbreakable token (`perturbation:trametinib@100nm/24h`) and the panel is
   narrow, so the pills wrap as a group and each one breaks internally if it has to. */
.ni-field-value .pill { display: inline-block; white-space: normal; word-break: break-all; }
.ni-field-value.mono { font-family: var(--font-mono); font-size: 11px; }

.ni-count {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-2);
  background: var(--surface-3);
  border-radius: 8px;
  padding: 1px 6px;
  margin-left: 6px;
}

.ni-empty { font-size: 11.5px; line-height: 1.55; color: var(--text-2); margin: 6px 0 0; }

/* ── Evidence ── */

.ni-obs {
  background: var(--surface-1);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 8px 10px;
  margin-top: 8px;
}

.ni-obs-head { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }

.ni-obs-index {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-3);
}

.ni-obs-meta { font-size: 10.5px; color: var(--text-2); }

.ni-obs-link { font-size: 10.5px; color: var(--accent); text-decoration: none; }
.ni-obs-link:hover { text-decoration: underline; }

/* Whether a PMID was checked is the difference between a citable claim and a remembered
   one, so it is stated rather than implied by the presence of a link. */
.ni-verified { font-size: 9.5px; color: var(--gain); }
.ni-unverified { font-size: 9.5px; color: var(--caution); }

.ni-obs-quote {
  font-size: 11.5px;
  line-height: 1.55;
  color: var(--text-1);
  border-left: 2px solid var(--line-strong);
  margin: 6px 0 0;
  padding: 0 0 0 8px;
}

/* ── Run log ── */

.lg-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-1);
  position: relative;
}

.lg-row {
  display: grid;
  grid-template-columns: 62px 130px 130px 1fr 14px;
  gap: 10px;
  align-items: baseline;
  padding: 4px 12px;
  font-size: 11.5px;
  border-bottom: 1px solid var(--line);
}
.lg-row[data-expandable] { cursor: pointer; }
.lg-row[data-expandable]:hover { background: var(--surface-2); }
.lg-row.open { background: var(--surface-2); }

/* The pipeline's own scaffolding is structure, not content — dimmed so the agent turns and
   graph writes between them are what the eye lands on. */
.lg-run { color: var(--text-3); }

.lg-time { font-family: var(--font-mono); font-size: 10px; color: var(--text-3); }
.lg-kind { font-family: var(--font-mono); font-size: 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lg-domain { font-size: 10.5px; color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lg-text { color: var(--text-1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lg-more { font-family: var(--font-mono); font-size: 11px; color: var(--text-3); text-align: center; }
.lg-row.open .lg-more { color: var(--accent); }

.lg-payload {
  margin: 0;
  padding: 10px 12px 12px 74px;
  background: var(--surface-0);
  border-bottom: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 10.5px;
  line-height: 1.55;
  color: var(--text-1);
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 320px;
  overflow-y: auto;
}

@media (max-width: 1400px) {
  .lg-row { grid-template-columns: 62px 110px 1fr 14px; }
  .lg-domain { display: none; }
  .lg-payload { padding-left: 12px; }
}

/* ── Replay transport ──
 *
 * In the dock header, which is the one strip visible in every view and while the dock is
 * collapsed — a replay is watched in the cell view, not in a panel of its own.
 */

.replay-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  max-width: 420px;
  margin: 0 16px;
  /* The header is a click target for collapsing the dock; the transport is not part of it. */
  cursor: default;
}

.replay-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text-1);
  cursor: pointer;
  transition: color var(--transition), border-color var(--transition), background var(--transition);
}
.replay-btn:hover { color: var(--text-0); background: var(--surface-3); border-color: var(--line-strong); }
.replay-bar.playing #replay-toggle { color: var(--accent); border-color: var(--line-focus); }

.replay-speed {
  width: auto;
  padding: 0 7px;
  font-family: var(--font-mono);
  font-size: 10px;
}

/*
 * The scrubber and its round ticks share one box: the ticks are positioned as a percentage of
 * the track, so they have to be measured against exactly the element the thumb travels along.
 */
.replay-track {
  position: relative;
  flex: 1;
  min-width: 60px;
  display: flex;
  align-items: center;
}

.replay-marks {
  position: absolute;
  /* Above the track, clear of the thumb — a tick under the thumb is a tick you cannot click. */
  bottom: 100%;
  left: 0;
  right: 0;
  height: 9px;
  pointer-events: none;
}

.replay-mark {
  position: absolute;
  bottom: 1px;
  /* `left` is the boundary's position along the log; the shift centres the tick on it. */
  transform: translateX(-50%);
  width: 7px;
  height: 7px;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  pointer-events: auto;
}
.replay-mark::before {
  content: '';
  display: block;
  width: 1px;
  height: 7px;
  margin: 0 auto;
  background: var(--text-3);
  transition: background var(--transition);
}
.replay-mark:hover::before { background: var(--accent); }

.replay-scrub {
  flex: 1;
  min-width: 0;
  height: 3px;
  appearance: none;
  background: var(--surface-3);
  border-radius: 2px;
  cursor: pointer;
  outline: none;
}
.replay-scrub::-webkit-slider-thumb {
  appearance: none;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--accent);
  cursor: grab;
}
.replay-scrub::-moz-range-thumb {
  width: 11px;
  height: 11px;
  border: none;
  border-radius: 50%;
  background: var(--accent);
  cursor: grab;
}

.replay-pos {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-2);
  white-space: nowrap;
  min-width: 62px;
  text-align: right;
}

@media (max-width: 1100px) {
  /* The scrubber needs room the narrow header does not have; play/pause still does not. */
  .replay-track, .replay-pos { display: none; }
  .replay-bar { flex: 0 0 auto; max-width: none; }
}

/* ── Cell tooltip additions, for the per-node markers ── */

.cell-tooltip-swatch {
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 2px;
  margin-right: 5px;
  vertical-align: middle;
}

.cell-tooltip-hint {
  font-size: 10px;
  color: var(--text-3);
  margin-top: 2px;
}
