/* Verified Edge — trust-first product UI (UNIT-50 design system).
   Two-tier tokens: brand PRIMITIVES (--ve-*) → SEMANTIC tokens the rest of the sheet consumes
   (--bg, --surface, --text, --accent, --trust, --danger …). Restyle the whole app by editing
   these tokens only. Verified Green is bound to --trust and used ONLY on verification chrome
   (never as the generic interactive accent — that stays blue, to avoid the fintech-green cliché).
   CSP-safe: self-hosted, no inline styles, no external assets. Inter / JetBrains Mono are
   self-hosted variable woff2s (latin subset only) in /fonts — see the @font-face block below —
   with a system fallback for any glyph outside that subset. Light + dark via [data-theme] on
   <html> (server-set, no FOUC). */

/* Inter (SIL OFL 1.1) / JetBrains Mono (Apache 2.0), latin-subset variable woff2s fetched from
   Google Fonts and self-hosted here (CSP `default-src 'self'` allows no external font origin).
   `font-weight: 400 700` / `100 800` declares the variable weight axis so the browser picks the
   right instance from the one file rather than needing a static file per weight. */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/fonts/inter-latin-variable.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
    U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url("/fonts/jetbrains-mono-latin-variable.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
    U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* --- Brand primitives (Verified Edge palette) --- */
  --ve-navy: #0a1628; /* Deep Navy — dominant surface */
  --ve-navy-2: #0c1a2e;
  --ve-green: #00c853; /* Verified Green — trust signals ONLY */
  --ve-green-dim: #00a344;
  --ve-orange: #ff6b35; /* Alert Orange */
  --ve-blue: #4d8dff; /* interactive accent */
  --ve-blue-hi: #74a6ff;

  /* --- Semantic tokens: DARK (default) --- */
  --bg: var(--ve-navy);
  --bg-2: var(--ve-navy-2);
  --surface: #101f38;
  --surface-2: #16294a;
  --surface-3: #1d3357;
  --border: #24344f;
  --border-strong: #33496b;

  --text: #eaf1fb;
  --muted: #9fb2cc;
  --muted-2: #6b7f9c;
  --heading: #ffffff;

  --accent: var(--ve-blue);
  --accent-hover: var(--ve-blue-hi);
  --accent-contrast: #06101f;
  --accent-soft: rgba(77, 141, 255, 0.15);
  --violet: #a78bfa;
  --teal: #2dd4bf;

  /* Trust — verification badges/checkmarks only */
  --trust: var(--ve-green);
  --trust-soft: rgba(0, 200, 83, 0.14);

  /* Status */
  --danger: #ff6b6b;
  --danger-bg: #2a1618;
  --success: #34d17e;
  --success-bg: #10241b;
  --warning: var(--ve-orange);
  --warning-bg: rgba(255, 107, 53, 0.12);

  --header-bg: rgba(14, 18, 25, 0.85);
  /* The site header is `position: sticky; top: 0` and 56px tall. Anything else that sticks to the
     viewport must clear it, so the height is a token rather than a number each rule re-guesses
     (the lab's facet rail and the help sidebar both used `top: 1rem` and sat UNDER the header;
     .admin-nav had the right idea with a hardcoded 72px). */
  --header-h: 56px;
  --sticky-top: calc(var(--header-h) + 1rem);

  --radius: 10px;
  --radius-sm: 7px;
  --radius-lg: 16px;
  --ring: 0 0 0 3px var(--accent-soft);
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 24px rgba(0, 0, 0, 0.28);
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.35);
  --maxw: 78rem;
  /* Data-dense pages (the research workbench) opt into this via `main.main-wide`: the 78rem cap
     left ~9 metric columns fighting for space. Capped so an ultrawide monitor doesn't produce
     unreadably long rows. */
  --maxw-wide: 108rem;
  /* Type — 8px spacing base lives in components; fonts prefer Inter/JetBrains, system fallback. */
  --font-sans: Inter, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, monospace;
  --glow: rgba(77, 141, 255, 0.06);
  color-scheme: dark;
}

/* --- Semantic tokens: LIGHT --- */
:root[data-theme="light"] {
  --bg: #f4f7fb;
  --bg-2: #eaf0f7;
  --surface: #ffffff;
  --surface-2: #f2f6fb;
  --surface-3: #e7edf5;
  --border: #d5deea;
  --border-strong: #b9c6d8;

  --text: #0a1628;
  --muted: #4a5b73;
  --muted-2: #6b7f9c;
  --heading: #0a1628;

  --accent: #1f6feb;
  --accent-hover: #1a5fd0;
  --accent-contrast: #ffffff;
  --accent-soft: rgba(31, 111, 235, 0.1);

  --trust: var(--ve-green-dim); /* darker green for ≥4.5:1 on white */
  --trust-soft: rgba(0, 163, 68, 0.12);

  --danger: #d92d2d;
  --danger-bg: #fdeaea;
  --success: #128a4e;
  --success-bg: #e7f6ee;
  --warning: #c85a1e;
  --warning-bg: rgba(255, 107, 53, 0.12);

  --header-bg: rgba(255, 255, 255, 0.85);

  --shadow: 0 1px 2px rgba(10, 22, 40, 0.08), 0 8px 24px rgba(10, 22, 40, 0.08);
  --shadow-sm: 0 1px 2px rgba(10, 22, 40, 0.08);
  --glow: rgba(31, 111, 235, 0.05);
  color-scheme: light;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  background:
    radial-gradient(1200px 600px at 80% -10%, var(--glow), transparent 60%),
    var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
}

a {
  color: var(--accent);
  text-decoration: none;
}
a:hover {
  color: var(--accent-hover);
  text-decoration: underline;
}

h1,
h2,
h3 {
  color: var(--heading);
  line-height: 1.2;
  margin: 0 0 0.5em;
  letter-spacing: -0.01em;
}
h1 {
  font-size: 1.6rem;
  font-weight: 680;
}
h2 {
  font-size: 1.15rem;
  margin-top: 0;
}
h3 {
  font-size: 0.95rem;
}
p {
  margin: 0 0 0.75rem;
}

.muted {
  color: var(--muted);
}
.small {
  font-size: 0.85rem;
}

/* ---------------------------------------------------------------- App shell */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  gap: 1.25rem;
  padding: 0 1.5rem;
  height: var(--header-h);
  background: var(--header-bg);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
}
.site-header .brand {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  font-weight: 700;
  color: var(--heading);
  font-size: 1rem;
  letter-spacing: -0.02em;
  white-space: nowrap;
}
/* Verified Edge mark: a rounded navy tile with a Verified-Green check (the "V" checkmark). */
.brand-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 7px;
  background: var(--surface-2);
  box-shadow: 0 0 0 1px var(--border-strong) inset;
}
.brand-mark svg {
  width: 15px;
  height: 15px;
  stroke: var(--trust);
  fill: none;
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* Theme toggle (UNIT-50): icon button; glyph swaps on aria-pressed (no JS-set styles → CSP-safe). */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--muted);
  cursor: pointer;
}
.theme-toggle:hover {
  color: var(--text);
  border-color: var(--border-strong);
}
.theme-toggle .theme-toggle-icon::before {
  content: "\2600"; /* ☀ shown in dark mode = "switch to light" */
  font-size: 1rem;
  line-height: 1;
}
.theme-toggle[aria-pressed="true"] .theme-toggle-icon::before {
  content: "\263D"; /* ☽ shown in light mode = "switch to dark" */
}
.site-header .spacer {
  flex: 1;
}
.site-nav {
  display: flex;
  align-items: center;
  gap: 0.15rem;
}
.nav-link {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.4rem 0.7rem;
  border-radius: var(--radius-sm);
  color: var(--muted);
  font-weight: 550;
  font-size: 0.9rem;
  white-space: nowrap;
}
.nav-link:hover {
  color: var(--text);
  background: var(--surface-2);
  text-decoration: none;
}
.nav-link.active {
  color: var(--heading);
  background: var(--accent-soft);
}
.header-right {
  display: flex;
  align-items: center;
  gap: 0.85rem;
}
.header-user {
  color: var(--muted);
  font-size: 0.85rem;
}

/* ------------------------------------------------- Top bar menus (UNIT-91)
   Three controls only: menu, account switcher, user. Both menus are <details>, so
   open/close needs no javascript; the app-nav island only adds Esc + click-outside.
   `position: relative` on the <details> anchors its panel; the header itself must NOT
   clip (no overflow: hidden) or the panels would be cut off. */
.hdr-menu {
  position: relative;
}
.hdr-menu > summary {
  list-style: none;
  cursor: pointer;
}
.hdr-menu > summary::-webkit-details-marker,
.hdr-menu > summary::marker {
  display: none;
  content: "";
}
.hdr-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--muted);
}
/* The icon buttons are <a> as well as <summary> now (UNIT-113 Dashboard/Calendar), so kill the
   link underline and give the inline SVGs a consistent stroke + size. */
.hdr-icon-btn {
  text-decoration: none;
  flex: 0 0 auto;
}
.hdr-icon {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.hdr-icon-btn.active {
  color: var(--text);
  border-color: var(--accent);
  background: var(--accent-soft);
}
.hdr-icon-btn:hover {
  color: var(--text);
  border-color: var(--border-strong);
}
/* Three bars drawn from one element: two pseudo-elements plus a border. */
.hdr-burger,
.hdr-burger::before,
.hdr-burger::after {
  display: block;
  width: 16px;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
}
.hdr-burger {
  position: relative;
}
.hdr-burger::before,
.hdr-burger::after {
  content: "";
  position: absolute;
  left: 0;
}
.hdr-burger::before {
  top: -5px;
}
.hdr-burger::after {
  top: 5px;
}
/* Shared panel treatment for both menus. */
.hdr-drawer-panel,
.hdr-user-panel {
  position: absolute;
  top: calc(100% + 8px);
  z-index: 60;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: 0 18px 40px rgb(0 0 0 / 35%);
  padding: 0.85rem;
}
.hdr-drawer-panel {
  left: 0;
  width: min(19rem, calc(100vw - 2rem));
  max-height: calc(100vh - 5rem);
  overflow-y: auto;
}
.hdr-user-panel {
  right: 0;
  width: min(16rem, calc(100vw - 2rem));
}
.hdr-drawer-panel .brand {
  margin-bottom: 0.75rem;
}
.hdr-drawer-search {
  margin-bottom: 0.5rem;
}
.hdr-drawer-search input {
  width: 100%;
}
.hdr-group-label {
  margin: 0.85rem 0 0.35rem;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
}
.hdr-group {
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.hdr-item {
  display: block;
  padding: 0.45rem 0.6rem;
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: 0.9rem;
  font-weight: 500;
}
.hdr-item:hover {
  background: var(--surface-2);
  text-decoration: none;
}
.hdr-item.active {
  color: var(--heading);
  background: var(--accent-soft);
  font-weight: 600;
}
.hdr-drawer-foot,
.hdr-user-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-top: 0.85rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--border);
}
.hdr-user-email {
  margin: 0 0 0.5rem;
  padding: 0 0.6rem;
  color: var(--muted);
  font-size: 0.8rem;
  overflow-wrap: anywhere;
}
.hdr-user-btn {
  display: inline-flex;
  align-items: center;
  position: relative;
}
.hdr-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--heading);
  font-size: 0.85rem;
  font-weight: 700;
  border: 1px solid var(--border-strong);
}
.hdr-user-btn:hover .hdr-avatar {
  border-color: var(--trust);
}
/* Bell + theme toggle are bar-level again (UNIT-92), so the avatar needs no unread dot —
   the bell shows its own count. */
/* Account switcher (island-rendered). */
.hdr-accounts {
  display: flex;
  align-items: center;
  min-width: 0;
}
.hdr-account-select {
  max-width: 15rem;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font-size: 0.85rem;
}
.hdr-account-select:hover {
  border-color: var(--border-strong);
}
.hdr-accounts-empty {
  color: var(--muted);
  font-size: 0.85rem;
}

main {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 1.75rem 1.5rem 4rem;
}
main.main-wide {
  max-width: var(--maxw-wide);
}

/* Page header: title + subtitle + right-aligned actions */
.page-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1.25rem;
}
.page-head .titles h1 {
  margin: 0;
}
.page-head .subtitle {
  color: var(--muted);
  margin: 0.25rem 0 0;
}
.page-head .actions {
  display: flex;
  gap: 0.6rem;
  flex-wrap: wrap;
}

/* ---------------------------------------------------------------- Compute pill */
.compute-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.28rem 0.65rem;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 600;
  border: 1px solid var(--border);
  color: var(--muted);
  background: var(--surface);
}
.compute-pill .dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--muted-2);
}
.compute-pill.online {
  color: var(--success);
  border-color: rgba(86, 214, 138, 0.4);
}
.compute-pill.online .dot {
  background: var(--success);
  box-shadow: 0 0 0 3px rgba(86, 214, 138, 0.18);
}
.compute-pill.offline {
  color: var(--warning);
  border-color: rgba(245, 158, 11, 0.4);
}
.compute-pill.offline .dot {
  background: var(--warning);
}

/* ---------------------------------------------------------------- Cards */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.25rem 1.4rem;
  margin: 0 0 1.1rem;
  box-shadow: var(--shadow-sm);
}
.card > h2:first-child,
.card > h3:first-child {
  margin-top: 0;
}
.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin: -0.25rem 0 1rem;
}
.card-head h2,
.card-head h3 {
  margin: 0;
}

.slot {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.75rem 1rem;
  margin: 0.75rem 0;
  color: var(--text);
}

/* Layout helpers */
.grid-2 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1.1rem;
}
.grid-3 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1.1rem;
}

/* ---------------------------------------------------------------- Stat tiles */
.stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 0.9rem;
  margin: 0 0 1.1rem;
}
.stat {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.95rem 1.1rem;
  box-shadow: var(--shadow-sm);
}
.stat .stat-label {
  color: var(--muted);
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.stat .stat-value {
  color: var(--heading);
  font-size: 1.65rem;
  font-weight: 680;
  line-height: 1.2;
  margin-top: 0.3rem;
  font-variant-numeric: tabular-nums;
}
.stat .stat-sub {
  color: var(--muted-2);
  font-size: 0.8rem;
  margin-top: 0.15rem;
}
.stat.pos .stat-value {
  color: var(--success);
}
.stat.neg .stat-value {
  color: var(--danger);
}

/* ---------------------------------------------------------------- Quick actions */
.action-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 1rem;
}
.action-card {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  padding: 1.1rem 1.2rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  box-shadow: var(--shadow-sm);
  transition:
    border-color 120ms ease,
    transform 120ms ease,
    background 120ms ease;
}
.action-card:hover {
  text-decoration: none;
  border-color: var(--border-strong);
  background: var(--surface-2);
  transform: translateY(-2px);
}
.action-card .ac-icon {
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  border-radius: 10px;
  background: var(--accent-soft);
  font-size: 1.2rem;
  margin-bottom: 0.35rem;
}
.action-card .ac-title {
  color: var(--heading);
  font-weight: 650;
  font-size: 1rem;
}
.action-card .ac-desc {
  color: var(--muted);
  font-size: 0.85rem;
}

/* ---------------------------------------------------------------- Empty states */
.empty {
  text-align: center;
  padding: 2.5rem 1.5rem;
  color: var(--muted);
}
.empty .empty-icon {
  font-size: 1.8rem;
  opacity: 0.7;
}
.empty h3 {
  color: var(--text);
  margin: 0.6rem 0 0.3rem;
}
.empty p {
  max-width: 32rem;
  margin: 0 auto 1rem;
}

/* ---------------------------------------------------------------- Forms */
label {
  display: block;
  margin: 0 0 0.35rem;
  color: var(--text);
  font-weight: 600;
  font-size: 0.9rem;
}
input,
select,
textarea {
  width: 100%;
  padding: 0.55rem 0.7rem;
  background: var(--bg-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font: inherit;
}
input::placeholder {
  color: var(--muted-2);
}
input:focus,
select:focus,
textarea:focus,
button:focus-visible,
.btn:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--ring);
}
.field {
  margin: 0 0 1rem;
}
.field .hint {
  color: var(--muted-2);
  font-size: 0.8rem;
  font-weight: 400;
  margin-top: 0.25rem;
}

/* ---------------------------------------------------------------- Buttons */
button,
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  font: inherit;
  font-weight: 600;
  font-size: 0.9rem;
  padding: 0.5rem 0.95rem;
  color: var(--accent-contrast);
  background: var(--accent);
  border: 1px solid var(--accent);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition:
    background 120ms ease,
    border-color 120ms ease;
}
button:hover,
.btn:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
  text-decoration: none;
  /* MUST be restated. `.btn` is often an <a>, and the global `a:hover { color: var(--accent-hover) }`
     has HIGHER specificity (0,1,1) than `.btn` (0,1,0) — so without this the label turned
     accent-coloured on an accent background and vanished on hover. */
  color: var(--accent-contrast);
}
button:disabled,
.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.btn-secondary {
  background: var(--surface-2);
  color: var(--text);
  border-color: var(--border-strong);
}
.btn-secondary:hover {
  background: var(--surface-3);
  color: var(--text);
  border-color: var(--border-strong);
}
.btn-ghost {
  background: transparent;
  color: var(--text);
  border-color: transparent;
}
.btn-ghost:hover {
  background: var(--surface-2);
  color: var(--text);
}
.btn-danger {
  background: transparent;
  color: var(--danger);
  border-color: rgba(255, 107, 107, 0.5);
}
.btn-danger:hover {
  background: var(--danger-bg);
  border-color: var(--danger);
  color: var(--danger);
}
.btn-sm {
  padding: 0.3rem 0.6rem;
  font-size: 0.82rem;
}
.btn-lg {
  padding: 0.65rem 1.3rem;
  font-size: 1rem;
}
/* A row of related buttons — wraps and stays vertically centred so mixed sizes (a primary
   `.btn` beside `.btn-sm` links) align cleanly instead of sitting on the text baseline. */
.btn-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}
/* Utilities replacing inline style="" attributes, which this app's CSP blocks outright: the
   strict policy is style-src 'self' 'nonce-…' and a nonce cannot whitelist an ATTRIBUTE, so
   style="" silently did nothing on every non-TV page. (TV compat pages run a separate legacy
   policy with 'unsafe-inline' — src/tv/routes/pages.ts — and keep their inline styles.) */
.btn-row.end {
  justify-content: flex-end;
}
.pre-wrap {
  white-space: pre-wrap;
}

/* ---------------------------------------------------------------- Alerts */
.alert {
  border-radius: var(--radius-sm);
  padding: 0.7rem 1rem;
  margin: 0 0 1rem;
  border: 1px solid transparent;
}
.alert-error {
  color: var(--danger);
  background: var(--danger-bg);
  border-color: rgba(255, 107, 107, 0.5);
}
.alert-success {
  color: var(--success);
  background: var(--success-bg);
  border-color: rgba(86, 214, 138, 0.5);
}
.alert-warning {
  color: var(--warning);
  background: var(--warning-bg);
  border-color: rgba(245, 158, 11, 0.5);
}
.banner-offline {
  font-weight: 600;
}

.auth-wrap {
  max-width: 23rem;
  margin: 4rem auto;
}
.auth-wrap .card {
  padding: 1.75rem;
}
/* Google sign-in (UNIT-72): GIS button container + the "or" divider above the password form. */
.google-signin {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  margin: 1rem 0;
}
/* Fail-safe box for Google's button (UNIT-87). GIS writes its own markup and styles it from
   accounts.google.com/gsi/style; if that stylesheet never applies (privacy/content blocker,
   blocked fetch, failed init) the raw markup lays out as a full-width logo hundreds of pixels
   tall. The island detects that and removes the button, but these caps keep the page sane for
   the frame before it does — and if scripting is off entirely. */
.google-signin-host {
  max-width: 320px;
  max-height: 60px;
  overflow: hidden;
}
.google-signin-host svg {
  max-width: 24px;
  max-height: 24px;
}
.auth-divider {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 1rem 0;
  color: var(--muted);
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.auth-divider::before,
.auth-divider::after {
  content: "";
  flex: 1;
  border-top: 1px solid var(--border);
}

/* ---------------------------------------------------------------- Tables */
.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
table {
  width: 100%;
  border-collapse: collapse;
}
.table-wrap table {
  margin: 0;
}
th,
td {
  text-align: left;
  padding: 0.6rem 0.85rem;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
tbody tr:last-child td {
  border-bottom: none;
}
tbody tr {
  transition: background 90ms ease;
}
tbody tr:hover {
  background: var(--surface-2);
}
th {
  color: var(--muted);
  font-weight: 600;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  background: var(--bg-2);
  position: sticky;
  top: 0;
}
td.num,
th.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
code {
  background: var(--surface-2);
  padding: 0.1rem 0.4rem;
  border-radius: 5px;
  font-size: 0.88em;
  font-family: var(--font-mono);
}

/* Audit-log Detail column: long JSON must wrap (and break) rather than push the table wide. */
.detail-cell {
  max-width: 34rem;
}
.detail-cell code {
  display: block;
  white-space: pre-wrap;
  word-break: break-word;
  background: none;
  padding: 0;
  color: var(--muted);
}

/* ---------------------------------------------------------------- Admin subnav */
.admin-layout {
  display: grid;
  grid-template-columns: 190px 1fr;
  gap: 1.5rem;
  align-items: start;
}
.admin-nav {
  list-style: none;
  padding: 0.5rem;
  margin: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  position: sticky;
  top: var(--sticky-top);
}
.admin-nav li {
  padding: 0;
}
.admin-nav a {
  display: block;
  padding: 0.45rem 0.7rem;
  border-radius: var(--radius-sm);
  color: var(--muted);
  font-weight: 550;
  font-size: 0.9rem;
}
.admin-nav a:hover,
.admin-nav a.active {
  background: var(--surface-2);
  color: var(--text);
  text-decoration: none;
}
@media (max-width: 720px) {
  .admin-layout {
    grid-template-columns: 1fr;
  }
  .admin-nav {
    position: static;
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
  }
}

/* ---------------------------------------------------------------- Pager / toolbars */
.pager {
  display: flex;
  gap: 0.75rem;
  align-items: center;
  margin-top: 0.85rem;
  color: var(--muted);
  font-size: 0.85rem;
}
.filters {
  display: flex;
  gap: 0.75rem;
  flex-wrap: wrap;
  align-items: end;
}
.filters .field {
  margin: 0;
}
.filters-center {
  justify-content: center;
}
.inline-form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr));
  gap: 0.6rem;
  align-items: end;
}
.row-actions form,
.row-actions {
  display: inline;
}
form.inline {
  display: inline;
}
.linklike {
  background: none;
  border: none;
  color: var(--accent);
  padding: 0;
  font: inherit;
  cursor: pointer;
}
.linklike:hover {
  color: var(--accent-hover);
  text-decoration: underline;
  background: none;
}

/* ---------------------------------------------------------------- Tags / badges / pills */
.tag,
.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.72rem;
  font-weight: 650;
  padding: 0.15rem 0.55rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--muted);
  vertical-align: middle;
  white-space: nowrap;
}
.tag-danger,
.badge-fail {
  color: var(--danger);
  background: var(--danger-bg);
  border-color: rgba(255, 107, 107, 0.4);
}
.tag-ok,
.badge-pass {
  color: var(--success);
  background: var(--success-bg);
  border-color: rgba(86, 214, 138, 0.4);
}

/* Job/status pills (by state) */
.status {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.75rem;
  font-weight: 600;
  padding: 0.15rem 0.55rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  text-transform: capitalize;
}
.status::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}
.status-done {
  color: var(--success);
  border-color: rgba(86, 214, 138, 0.4);
}
.status-running,
.status-claimed {
  color: var(--accent);
  border-color: rgba(91, 157, 255, 0.4);
}
.status-queued {
  color: var(--warning);
  border-color: rgba(245, 158, 11, 0.4);
}
.status-failed,
.status-canceled {
  color: var(--danger);
  border-color: rgba(255, 107, 107, 0.4);
}
/* Conditionals suite review states (UNIT-69) */
.status-approved {
  color: var(--success);
  border-color: rgba(86, 214, 138, 0.4);
}
.status-pending_review {
  color: var(--warning);
  border-color: rgba(245, 158, 11, 0.4);
}
.status-rejected {
  color: var(--danger);
  border-color: rgba(255, 107, 107, 0.4);
}
.status-disabled {
  color: var(--muted);
}
.field-check label {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 500;
}
.field-check input[type="checkbox"] {
  width: auto;
}

/* ---------------------------------------------------------------- Progress */
/* SSE status line ("Queued — waiting for a worker…", "simulating — 45%"). This was styled as an
   8px bar TRACK with overflow:hidden long after anything rendered a fill inside it — every page
   that put its status text here showed a clipped sliver (owner screenshot, 2026-08-02). Live
   fills are native <progress class="job-bar"> elements; this class only ever holds text now. */
.progress {
  padding: 0.55rem 0.9rem;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--muted);
  font-size: 0.9rem;
}

/* Quota meters (UNIT-59) — native <meter> so widths are attribute-driven under strict CSP. */
.usage-meters {
  display: grid;
  gap: 16px;
}
.usage-meter meter {
  width: 100%;
  height: 10px;
}
.usage-meter-head {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 4px;
}
.usage-meter-label {
  font-weight: 600;
}
.usage-meter-value {
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.usage-meter.warn .usage-meter-value {
  color: var(--warning);
}
.usage-meter.crit .usage-meter-value {
  color: var(--danger);
}
.usage-meter-reset {
  margin: 4px 0 0;
  font-size: 0.85em;
}

/* Version diff (UNIT-55) — class-based, no island, no nonce. */
pre.diff {
  margin: 0;
  padding: 8px 0;
  font-size: 0.85rem;
  line-height: 1.5;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow-x: auto;
}
.diff-line {
  display: block;
  padding: 0 12px;
  white-space: pre;
}
.diff-line.diff-add {
  background: rgba(46, 160, 67, 0.18);
}
.diff-line.diff-del {
  background: rgba(248, 81, 73, 0.18);
}
.delta-pos {
  color: var(--trust, #2ea043);
}
.delta-neg {
  color: var(--danger);
}

/* Analytics grid (UNIT-57) */
.analytics-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
.analytics-grid .analytics-wide {
  grid-column: 1 / -1;
}
.analytics-card h3 {
  margin: 0 0 8px;
  font-size: 0.95rem;
}
.result-chart-sm {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 8px;
}
@media (max-width: 800px) {
  .analytics-grid {
    grid-template-columns: 1fr;
  }
}

/* Marketplace reviews (UNIT-46 follow-up) */
.review-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.review {
  padding: 12px 0;
  border-top: 1px solid var(--border);
}
.review-head {
  display: flex;
  gap: 8px;
  align-items: baseline;
  flex-wrap: wrap;
}
.review-stars {
  color: var(--warning);
  letter-spacing: 1px;
}
.review-title {
  font-weight: 600;
  margin: 4px 0;
}
.review-response {
  margin: 8px 0 0;
  padding: 8px 12px;
  border-left: 3px solid var(--accent);
  background: var(--surface-2);
  border-radius: 0 var(--radius) var(--radius) 0;
}
.review-respond input[type="text"] {
  min-width: 260px;
}
.review-form {
  margin-bottom: 8px;
}

/* ---------------------------------------------------------------- Charts / islands */
.mc-band-chart,
.wf-matrix-heatmap,
.optprofile-surface,
.spp-distribution,
.equity-chart,
.result-chart {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 8px;
}
.equity-chart,
.mc-band-chart,
.spp-distribution,
.result-chart {
  min-height: 240px;
}
.wf-matrix-heatmap {
  min-height: 320px;
}
.optprofile-surface {
  min-height: 200px;
}

/* Period tabs on the result page */
.period-tabs {
  display: inline-flex;
  gap: 0.25rem;
  padding: 0.25rem;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  margin-bottom: 1rem;
}
.period-tabs .tab {
  padding: 0.3rem 0.75rem;
  border-radius: 6px;
  color: var(--muted);
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
}
.period-tabs .tab:hover {
  color: var(--text);
  text-decoration: none;
}
.period-tabs .tab.active {
  background: var(--accent);
  color: var(--accent-contrast);
}

/* Pseudocode / source blocks */
.pseudocode,
pre {
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 1rem 1.15rem;
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: 0.85rem;
  line-height: 1.55;
  color: var(--text);
}

/* ---------------------------------------------------------------- Landing hero */
.hero {
  text-align: center;
  max-width: 46rem;
  margin: 2.5rem auto 2rem;
}
.hero-badge {
  display: inline-block;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--accent);
  background: var(--accent-soft);
  border: 1px solid rgba(91, 157, 255, 0.3);
  border-radius: 999px;
  padding: 0.25rem 0.75rem;
  margin-bottom: 1.1rem;
}
.hero-title {
  font-size: 2.4rem;
  line-height: 1.1;
  margin: 0 0 0.75rem;
  background: linear-gradient(180deg, var(--heading), var(--muted));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.hero-sub {
  color: var(--muted);
  font-size: 1.05rem;
  margin: 0 auto 1.5rem;
}
.hero-cta {
  display: flex;
  gap: 1rem;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
}
@media (max-width: 640px) {
  .hero-title {
    font-size: 1.8rem;
  }
}

/* ---------------------------------------------------------------- Strategy editor */
.editor-widget {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1rem;
  box-shadow: var(--shadow-sm);
}
.editor-toolbar {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  margin-bottom: 0.9rem;
  padding-bottom: 0.9rem;
  border-bottom: 1px solid var(--border);
}
.editor-panes {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}
@media (max-width: 900px) {
  .editor-panes {
    grid-template-columns: 1fr;
  }
}
.editor-host {
  min-height: 340px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-2);
  overflow: hidden;
}
.editor-host .cm-editor {
  height: 100%;
  min-height: 340px;
}
.editor-preview h4 {
  margin: 0 0 0.4rem;
  color: var(--muted);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.editor-preview pre {
  margin: 0 0 1rem;
  max-height: 220px;
}
.editor-diagnostics {
  border-color: rgba(255, 107, 107, 0.35);
}
.llm-explain-panel {
  margin-top: 1.1rem;
}
#llm-explain-output {
  margin-top: 0.75rem;
  white-space: pre-wrap;
}

/* HTMX request indicators (served here because CSP blocks HTMX's injected inline <style>;
   paired with htmx-config includeIndicatorStyles:false in layout.njk). */
.htmx-indicator {
  opacity: 0;
  transition: opacity 200ms ease-in;
}
.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator {
  opacity: 1;
}

/* Stage pages (UNIT-133): one lifecycle stage per page, with the progression as the navigation.
   The chips are the reason to move between pages — a count IS the argument for going there — so they
   are sized for scanning, and `.empty` is dimmed rather than hidden (a zero is information: the stage
   exists and nothing has reached it). */
.progression {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem;
  margin: 0 0 1rem;
}
.progression-step {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4rem;
  padding: 0.35rem 0.7rem;
  border-radius: 999px;
  text-decoration: none;
  color: var(--text-secondary, inherit);
  border: 1px solid transparent;
}
.progression-step:hover { background: var(--surface-2, rgba(127, 127, 127, 0.12)); }
.progression-step.current {
  font-weight: 600;
  color: var(--text-primary, inherit);
  border-color: currentColor;
}
.progression-step.empty { opacity: 0.55; }
.progression-count {
  font-variant-numeric: tabular-nums;
  font-size: 0.85em;
  opacity: 0.8;
}
.progression-sep { opacity: 0.4; }

.stage-page .page-head { align-items: flex-start; }
.stage-session { display: flex; flex-direction: column; align-items: flex-end; gap: 0.2rem; }
.stage-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.9rem;
}
.stage-actions-decide { margin-top: 0.5rem; opacity: 0.95; }

/* An expanded row shows its result IN PLACE, so comparing three candidates does not mean three
   navigations (the failure the retired wizard had). */
.row-result summary { cursor: pointer; }
.row-result-body { padding: 0.6rem 0 0.2rem; }
.row-result-grid {
  display: grid;
  grid-template-columns: minmax(12rem, 20rem) 1fr;
  gap: 1rem;
  align-items: start;
}
.equity-chart-inline { min-height: 160px; }
.kv-tight dt { font-size: 0.8em; opacity: 0.75; }
.row-result-links { display: flex; flex-wrap: wrap; gap: 1rem; margin: 0.5rem 0 0; }
@media (max-width: 800px) {
  .row-result-grid { grid-template-columns: 1fr; }
}

/* Pending state for the compute-spending action buttons (UNIT-131).
   Deliberately display-based rather than reusing `.htmx-indicator` (opacity): an always-present
   invisible " — queuing…" would widen the button by its own width and shift the whole action bar.
   htmx puts `.htmx-request` on the triggering element, so this shows only on the button that was
   actually clicked, and `hx-disabled-elt="this"` stops a second click landing while it is in flight.
   Why it exists: enqueueing a cross-pair fan-out takes ~13 seconds (3 candidates x 102 pairs), and a
   button that looks inert for that long gets clicked again — which is exactly what happened. */
.pending-note {
  display: none;
  font-weight: 400;
  opacity: 0.85;
}
.htmx-request .pending-note,
.htmx-request.pending-note {
  display: inline;
}
/* A disabled in-flight button must LOOK unavailable, or "disabled" is invisible to the person
   deciding whether to click again. */
button[disabled] {
  cursor: progress;
  opacity: 0.7;
}

/* Responsive nav: collapse labels on small screens */
@media (max-width: 800px) {
  .site-header {
    gap: 0.5rem;
    padding: 0 0.85rem;
  }
  .nav-link {
    padding: 0.4rem 0.5rem;
  }
  .header-user {
    display: none;
  }
}

/* ---------------------------------------------------------------- Notifications (UNIT-52) */
.notif-sse {
  display: inline-flex;
}
.bell {
  position: relative;
  padding: 0.35rem 0.5rem;
}
.bell-icon {
  font-size: 1.05rem;
  line-height: 1;
}
.bell-badge {
  position: absolute;
  top: -2px;
  right: -2px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 8px;
  background: var(--danger);
  color: #fff;
  font-size: 0.66rem;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
}
.notif-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.notif-item {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.6rem 0.25rem;
  border-bottom: 1px solid var(--border);
}
.notif-item:last-child {
  border-bottom: 0;
}
.notif-item.unread {
  border-left: 3px solid var(--accent);
  padding-left: 0.6rem;
}
.notif-main {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.notif-title {
  font-weight: 550;
}
.notif-empty {
  padding: 0.75rem 0.25rem;
}

.section-gap {
  margin-top: 1.5rem;
}

/* ---------------------------------------------------------------- Onboarding (UNIT-53) */
.onboarding {
  border-left: 3px solid var(--trust);
}
.onboarding-steps {
  list-style: none;
  margin: 0.5rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.5rem;
}
.ob-step {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
.ob-check {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  flex: 0 0 20px;
  border-radius: 50%;
  border: 2px solid var(--border-strong);
  color: transparent;
  font-size: 0.7rem;
  font-weight: 800;
}
.ob-step.ob-done .ob-check {
  border-color: var(--trust);
  background: var(--trust-soft);
  color: var(--trust);
}
.ob-step.ob-done .ob-check::before {
  content: "\2713"; /* ✓ */
}
.ob-step.ob-done > a {
  color: var(--muted);
  text-decoration: line-through;
}

/* ---------------------------------------------------------------- Marketplace (UNIT-46) */
.search-row {
  display: flex;
  gap: 0.5rem;
  margin: 0 0 1rem;
}
.search-row input[type="search"] {
  flex: 1;
  max-width: 28rem;
}
.marketplace-grid .listing-card {
  position: relative;
}
.listing-seller {
  display: block;
  margin: 0.15rem 0 0.35rem;
}
.verified-chip {
  display: inline-block;
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  background: var(--trust-soft);
  color: var(--trust);
  font-size: 0.72rem;
  font-weight: 700;
}
.listing-price {
  margin-top: 0.5rem;
  font-weight: 700;
  color: var(--heading);
}
.listing-price-lg {
  font-size: 1.3rem;
  font-weight: 800;
  color: var(--heading);
}
.lead {
  font-size: 1.05rem;
  color: var(--text);
  margin: 0 0 1rem;
}

/* Account security page (UNIT-60) */
.totp-secret {
  font-size: 1.05rem;
  letter-spacing: 0.12em;
  user-select: all;
}
.totp-details dt {
  font-weight: 600;
  margin-top: 0.5rem;
}
.totp-details dd {
  margin: 0.15rem 0 0;
}
.totp-form {
  margin-top: 0.75rem;
  max-width: 22rem;
}

/* Referral dashboard card (UNIT-61) */
.referral-stats {
  display: flex;
  gap: 1.25rem;
  flex-wrap: wrap;
  margin: 0.5rem 0 0.75rem;
}

/* Global search (UNIT-54) */
.header-search input {
  width: 11rem;
  padding: 0.3rem 0.6rem;
  border-radius: 6px;
}
.search-form .field {
  margin-bottom: 0.5rem;
}
.search-facets {
  display: flex;
  gap: 1rem;
  align-items: center;
  flex-wrap: wrap;
}
.search-facet {
  display: inline-flex;
  gap: 0.35rem;
  align-items: center;
  text-transform: capitalize;
}
.search-hits {
  list-style: none;
  margin: 0;
  padding: 0;
}
.search-hits li {
  padding: 0.3rem 0;
  border-bottom: 1px solid var(--border, rgba(128, 128, 128, 0.15));
}
.search-hits li:last-child {
  border-bottom: none;
}
.saved-searches {
  list-style: none;
  margin: 0.5rem 0 0;
  padding: 0;
}
.saved-searches li {
  padding: 0.25rem 0;
  display: flex;
  gap: 0.6rem;
  align-items: baseline;
}

/* Forward testing (UNIT-56) */
.forward-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
}
.forward-actions {
  display: flex;
  gap: 1rem;
  margin-top: 0.6rem;
  align-items: baseline;
}
.drift-flag td {
  color: var(--danger, #ff6b6b);
  font-weight: 600;
}
.result-forward {
  margin: 0.75rem 0;
}

/* Strategy Pipeline wizard (UNIT-67) */
.status-cancelled {
  color: var(--danger);
  border-color: rgba(255, 107, 107, 0.4);
}
.status-waiting_user {
  color: var(--warning);
  border-color: rgba(245, 158, 11, 0.4);
}
.pipeline-layout {
  display: grid;
  grid-template-columns: 240px 1fr;
  gap: 1rem;
  align-items: start;
}
@media (max-width: 860px) {
  .pipeline-layout {
    grid-template-columns: 1fr;
  }
}
.pipeline-steps {
  list-style: none;
  margin: 0;
  padding: 0;
  border-left: 2px solid var(--border);
}
.pipeline-step {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.55rem 0 0.55rem 0.9rem;
  margin-left: -2px;
  border-left: 2px solid transparent;
  color: var(--muted);
}
.pipeline-step .step-marker {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  border: 1px solid var(--border);
  font-size: 0.75rem;
  font-weight: 700;
  flex: none;
}
.pipeline-step.is-done {
  color: var(--text);
}
.pipeline-step.is-done .step-marker {
  color: var(--success);
  border-color: rgba(86, 214, 138, 0.4);
  background: var(--success-bg);
}
.pipeline-step.is-active {
  color: var(--text);
  border-left-color: var(--accent);
  font-weight: 600;
}
.pipeline-step.is-active .step-marker {
  color: var(--accent);
  border-color: var(--accent);
}
.pipeline-step.is-failed {
  color: var(--danger);
  border-left-color: var(--danger);
}
.pipeline-step.is-failed .step-marker {
  color: var(--danger);
  border-color: rgba(255, 107, 107, 0.4);
  background: var(--danger-bg);
}
.pipeline-members {
  list-style: none;
  margin: 0.5rem 0;
  padding: 0;
}
.pipeline-members li {
  padding: 0.35rem 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: baseline;
}
/* Override the global `label { display:block }` so the checkbox sits inline beside its text
   (same treatment as `.field-check`); the global `input { width:100% }` would otherwise make
   the checkbox a full-width block and push the label underneath it. */
.pipeline-members label {
  display: inline-flex;
  align-items: flex-start;
  gap: 0.5rem;
  margin: 0;
  font-weight: 500;
}
.pipeline-members input[type="checkbox"] {
  width: auto;
  margin-top: 0.15rem;
  flex: none;
}
/* An abandoned/cancelled run's cleanup panel is a third child of the 2-col `.pipeline-layout`
   grid; without this it lands in the narrow 240px steps column. Span the full width instead. */
.pipeline-abandoned {
  grid-column: 1 / -1;
  margin-top: 1rem;
}
.pipeline-members li.gate-failed,
tr.gate-failed td:first-child {
  opacity: 0.65;
}
.pipeline-cancel {
  margin-top: 1rem;
}
.pipeline-notices ul {
  margin: 0;
  padding-left: 1.1rem;
}
details.advanced {
  margin: 0.75rem 0;
}
details.advanced summary {
  cursor: pointer;
  color: var(--muted);
  font-weight: 600;
}

/* ── Help centre (UNIT-102) ─────────────────────────────────────────────────
   The manual is markdown rendered to HTML, so these rules style plain tags
   (h2/p/ul/table) rather than classes — the content carries no markup of ours. */
.help-layout {
  display: grid;
  grid-template-columns: minmax(200px, 260px) minmax(0, 1fr);
  gap: 2rem;
  align-items: start;
}
.help-nav {
  position: sticky;
  top: var(--sticky-top);
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  padding: 0.75rem 0.5rem;
}
.help-nav ol {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: chapter;
}
.help-nav a {
  display: block;
  padding: 0.4rem 0.6rem;
  border-radius: 6px;
  color: var(--muted);
  text-decoration: none;
  font-size: 0.92rem;
  line-height: 1.35;
}
.help-nav a:hover {
  background: var(--bg-2);
  color: var(--text);
}
.help-nav a[aria-current="page"] {
  background: var(--accent-soft);
  color: var(--text);
  font-weight: 600;
}
/* Readable measure: long-form prose, not a dashboard. */
.markdown {
  max-width: 72ch;
  line-height: 1.65;
}
.markdown > h1:first-child {
  margin-top: 0;
}
.markdown h2 {
  margin-top: 2rem;
  padding-bottom: 0.3rem;
  border-bottom: 1px solid var(--border);
}
.markdown h3 {
  margin-top: 1.5rem;
}
.markdown blockquote {
  margin: 1.25rem 0;
  padding: 0.75rem 1rem;
  border-left: 3px solid var(--accent);
  background: var(--bg-2);
  border-radius: 0 6px 6px 0;
  color: var(--muted);
}
.markdown code {
  background: var(--bg-2);
  padding: 0.1rem 0.35rem;
  border-radius: 4px;
}
/* Tables in the manual can be wide; scroll them rather than the page. */
.markdown table {
  display: block;
  overflow-x: auto;
  max-width: 100%;
  border-collapse: collapse;
}
.markdown th,
.markdown td {
  border: 1px solid var(--border);
  padding: 0.45rem 0.7rem;
  text-align: left;
}
@media (max-width: 800px) {
  .help-layout {
    grid-template-columns: 1fr;
  }
  .help-nav {
    position: static;
  }
}

/* ===========================================================================
   Research sessions — the cohort workbench (UNIT-108/110/111)
   ---------------------------------------------------------------------------
   Built entirely on the semantic tokens above, so light mode and dark mode both
   work with no extra rules. The layout has one job: keep the facet rail, the
   cohort, and the detail drawer visible together, because the whole point of the
   redesign is that you never have to leave one to look at another.
   =========================================================================== */

.session-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 1.5rem;
}
.session-title {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
.session-title h1 {
  margin: 0;
}
.session-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.4rem;
  margin: 0;
}
.session-meta > div {
  display: flex;
  flex-direction: column;
}
.session-meta dt {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted-2);
}
.session-meta dd {
  margin: 0;
  font-weight: 650;
  color: var(--text);
}
.session-actions {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  margin-left: auto;
}
.inline-form {
  display: inline;
}
.danger-link {
  color: var(--danger);
}

/* Two-column workbench: facet rail + cohort. Collapses to one column on narrow
   screens, rail first, so the counts stay the first thing you see. */
.cohort-layout {
  display: grid;
  grid-template-columns: minmax(10rem, 12rem) minmax(0, 1fr);
  gap: 1.1rem;
  align-items: start;
}
/* The drawer normally sits full-width beneath both columns. */
.cohort-layout > #drawer {
  grid-column: 1 / -1;
}
@media (max-width: 60rem) {
  .cohort-layout {
    grid-template-columns: 1fr;
  }
}
/* On a wide screen an OPEN drawer becomes a third column beside the table, sticky and
   independently scrollable, so inspecting a candidate never moves the cohort out of view. `:has`
   keeps the column from existing while the drawer is empty; browsers without it simply get the
   full-width-row fallback above. */
@media (min-width: 96rem) {
  .cohort-layout:has(> #drawer:not(:empty)) {
    grid-template-columns: minmax(10rem, 12rem) minmax(0, 1fr) minmax(24rem, 30rem);
  }
  .cohort-layout:has(> #drawer:not(:empty)) > #drawer {
    grid-column: 3;
    grid-row: 1;
    position: sticky;
    top: var(--sticky-top);
    max-height: calc(100vh - var(--sticky-top) - 1rem);
    overflow-y: auto;
  }
  .cohort-layout:has(> #drawer:not(:empty)) > #drawer .drawer {
    margin-top: 0;
  }
}
.cohort-main {
  min-width: 0; /* let wide tables scroll instead of blowing out the grid */
}

/* --- Workflow guide: the loop, stated on the page (UNIT-115) --- */
.workflow-guide > summary {
  cursor: pointer;
  font-size: 0.9rem;
  color: var(--muted);
}
.workflow-guide > summary strong {
  color: var(--text);
}
.workflow-steps {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 0.5rem 1.1rem;
  margin: 0.9rem 0 0;
  padding: 0;
  counter-reset: none;
}
.workflow-step {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.35rem 0;
  border-top: 1px solid var(--border);
}
.ws-n {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.35rem;
  height: 1.35rem;
  border-radius: 999px;
  background: var(--surface-3);
  color: var(--muted);
  font-size: 0.72rem;
  font-weight: 700;
  flex: 0 0 auto;
}
.ws-body {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}
.ws-title {
  font-weight: 650;
  font-size: 0.88rem;
}
.ws-desc {
  font-size: 0.78rem;
  line-height: 1.35;
}
.ws-count {
  font-family: var(--font-mono);
  font-size: 0.85rem;
  text-decoration: none;
  color: var(--text);
}
.ws-count-none {
  color: var(--muted-2);
}
.workflow-note {
  margin: 0.9rem 0 0;
  font-size: 0.82rem;
  line-height: 1.5;
  border-top: 1px solid var(--border);
  padding-top: 0.7rem;
}

/* --- Collapsible filter builder --- */
.filters-summary {
  cursor: pointer;
  font-size: 0.85rem;
  color: var(--muted);
  padding: 0.15rem 0;
}
.filters-wrap[open] .filters-summary {
  margin-bottom: 0.5rem;
}

/* --- Action groups: RUN spends compute, DECIDE is free and reversible, ASSEMBLE keeps things --- */
/* Each group is a COLUMN — label above its buttons — and groups sit side by side with a real
   gap between them (owner, 2026-08-02). */
.action-groups {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 0.85rem 2.25rem;
  padding-bottom: 0.7rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0.55rem;
}
.action-group {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  border-bottom: none;
  margin-bottom: 0;
  padding: 0;
}
.action-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.45rem;
}
.action-label {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 700;
  color: var(--muted-2);
  margin-right: 0.15rem;
}
.field-inline {
  display: inline-flex;
  gap: 0.3rem;
  align-items: center;
}

/* --- Facet rail: "which ones survived?" is one click, always --- */
.facet-rail {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.7rem;
  position: sticky;
  top: var(--sticky-top);
  /* Never taller than the space under the header, or a long rail scrolls its own bottom off. */
  max-height: calc(100vh - var(--sticky-top) - 1rem);
  overflow-y: auto;
}
.facet {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.6rem;
  padding: 0.4rem 0.6rem;
  border-radius: var(--radius-sm);
  color: var(--muted);
  text-decoration: none;
  border: 1px solid transparent;
}
.facet:hover {
  background: var(--surface-2);
  color: var(--text);
}
.facet.active {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--text);
  font-weight: 650;
}
.facet-count {
  font-family: var(--font-mono);
  font-size: 0.85rem;
  color: var(--text);
}

/* --- Action bars --- */
.action-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.45rem;
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0.5rem;
}
.action-bar-compute {
  border-bottom: 1px dashed var(--border-strong);
}
.action-bar button[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
}
.num-sm {
  width: 5.5rem;
}
.txt-sm {
  width: 11rem;
}

/* --- Cohort grid --- */
.grid-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.88rem;
}
.grid-table th,
.grid-table td {
  padding: 0.4rem 0.55rem;
  text-align: left;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}
.grid-table th {
  color: var(--muted-2);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 650;
  white-space: nowrap;
}
.grid-table th a {
  color: inherit;
  text-decoration: none;
}
.cohort-table {
  display: block;
  overflow-x: auto; /* wide metric sets scroll here, never the page body */
  width: 100%;
}
/* Numbers scan vertically only when they are right-aligned and share a tabular figure width. */
.cohort-table td.metric,
.cohort-table th.metric {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.cohort-table td.cand-name {
  min-width: 12rem;
}
.cohort-table td.cand-note {
  max-width: 16rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* The header row stays visible while a long cohort page scrolls inside its own container. */
.cohort-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--surface);
}
.cohort-row.in-flight {
  background: var(--accent-soft);
}
.row-warn {
  background: var(--warning-bg);
}
.cohort-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.8rem;
  padding-top: 0.7rem;
}

/* Lifecycle badges. Only `promoted` may use the trust green — it is reserved for
   verification signals, and promotion is the only state that asserts one. */
.badge-state {
  text-transform: capitalize;
}
.badge-promoted {
  color: var(--trust);
  background: var(--trust-soft);
  border-color: rgba(0, 200, 83, 0.4);
}
.badge-shortlisted {
  color: var(--accent);
  background: var(--accent-soft);
  border-color: rgba(77, 141, 255, 0.4);
}
.badge-rejected,
.badge-parked {
  color: var(--muted-2);
}
.badge-working {
  color: var(--accent);
  background: var(--accent-soft);
  border-color: rgba(77, 141, 255, 0.35);
}

/* UNIT-122 "×N alike": a caution, not a failure. Warning-toned because a cohort that is really
   a handful of repeated ideas inflates every count the owner reads, but it is report-only —
   nothing is blocked — so it must not look like the red `badge-fail`. */
.badge-alike {
  color: var(--warning);
  background: var(--warning-bg);
  border-color: rgba(255, 107, 53, 0.35); /* matches --warning's hue in both themes */
  cursor: help;
}

/* The app.css alert set has error/success/warning but no info variant; the jobs strip is
   informational, not a warning — a running job is the system working. */
.alert-info {
  color: var(--accent);
  background: var(--accent-soft);
  border-color: rgba(77, 141, 255, 0.4);
}

/* --- Detail drawer: opens over the cohort, never navigates away --- */
.drawer {
  margin-top: 1rem;
  border-color: var(--border-strong);
  box-shadow: var(--shadow);
  /* The drawer is scrolled into view by HTMX (`hx-swap="… show:top"`). Without this the scroll
     lands its top edge at viewport 0 — i.e. behind the sticky header — hiding the very heading
     and close button that tell you it opened. */
  scroll-margin-top: var(--sticky-top);
}
#drawer {
  scroll-margin-top: var(--sticky-top);
}
.drawer-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  padding-bottom: 0.7rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0.9rem;
}
.drawer-header h2 {
  margin: 0 0 0.25rem;
}
.drawer-close {
  background: none;
  border: 1px solid var(--border);
  color: var(--muted);
  border-radius: var(--radius-sm);
  line-height: 1;
  padding: 0.2rem 0.5rem;
  font-size: 1.1rem;
}
.drawer-body > section {
  margin-bottom: 1.2rem;
}
.drawer-body h3 {
  margin: 0 0 0.5rem;
  font-size: 0.95rem;
}
.kv {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.6rem;
  margin: 0;
}
.kv > div {
  display: flex;
  flex-direction: column;
}
.kv dt {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted-2);
}
.kv dd {
  margin: 0;
}
/* UNIT-122 behaviour fingerprint: 38 chars in a narrow drawer column. Break on the band
   separators rather than overflowing the panel or forcing a horizontal scrollbar. */
.fingerprint {
  font-size: 0.78em;
  word-break: break-all;
}
.timeline {
  list-style: none;
  padding: 0;
  margin: 0;
  font-size: 0.85rem;
}
.timeline li {
  padding: 0.2rem 0;
  border-bottom: 1px solid var(--border);
}
.metrics-table {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  display: block;
  max-height: 18rem;
  overflow-y: auto;
}

/* --- Promotion review: the numbers that make selection bias concrete --- */
.promotion-review .caveat {
  color: var(--warning);
  font-size: 0.78rem;
}
.holdout-row {
  background: var(--surface-2);
}
.metric-chip {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  padding: 0.1rem 0.45rem;
  margin: 0 0.25rem;
  border-radius: var(--radius-sm);
  background: var(--surface-3);
}

/* --- Purge: the only destructive path, and it should look like it --- */
.purge-confirm {
  border-color: var(--danger);
}
.purge-confirm button.danger {
  background: var(--danger);
  border-color: var(--danger);
  color: #1a0c0d;
}

/* The "searchable period only" notice above a holdout session's cohort. */
.period-note {
  margin: 0 0 0.5rem;
  font-size: 0.82rem;
}

/* ---------------------------------------------------------------------------
   Session job progress (UNIT-114)
   Native <progress> so the value rides an ATTRIBUTE, not an inline style — the
   strict CSP (style-src 'self') drops inline styles, so a div-with-width fill
   would have rendered as an empty track. Omitting @value gives the indeterminate
   state, which is what "waiting for a compute node" looks like.
   --------------------------------------------------------------------------- */
.jobs-strip {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin-bottom: 0.8rem;
}
.job-progress {
  padding: 0.6rem 0.75rem;
  border: 1px solid rgba(77, 141, 255, 0.4);
  background: var(--accent-soft);
  border-radius: var(--radius-sm);
}
.job-progress.job-waiting {
  border-color: var(--border-strong);
  background: var(--surface-2);
}
.job-progress-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.88rem;
}
.job-progress-head strong {
  font-weight: 600;
}
.job-counts {
  margin: 0.35rem 0 0;
  font-size: 0.8rem;
}

/* A spinner is the cheapest honest signal that the page is still watching. */
.job-spinner {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: 2px solid var(--accent);
  border-top-color: transparent;
  animation: job-spin 0.9s linear infinite;
  flex: 0 0 auto;
}
@keyframes job-spin {
  to {
    transform: rotate(360deg);
  }
}
@media (prefers-reduced-motion: reduce) {
  .job-spinner {
    animation: none;
    border-top-color: var(--accent);
    opacity: 0.5;
  }
}

.job-bar {
  display: block;
  width: 100%;
  height: 6px;
  margin-top: 0.45rem;
  border: none;
  border-radius: 999px;
  background: var(--surface-3);
  appearance: none;
  -webkit-appearance: none;
  overflow: hidden;
  color: var(--accent); /* IE/legacy fallback for the fill */
}
.job-bar::-webkit-progress-bar {
  background: var(--surface-3);
  border-radius: 999px;
}
.job-bar::-webkit-progress-value {
  background: var(--accent);
  border-radius: 999px;
}
.job-bar::-moz-progress-bar {
  background: var(--accent);
  border-radius: 999px;
}
/* Indeterminate (no @value): a moving sliver, since there is no meaningful percentage yet.
   Chrome renders its own indeterminate animation; this covers the plain-background case. */
.job-bar:not([value]) {
  background: linear-gradient(
    90deg,
    var(--surface-3) 0%,
    var(--accent) 50%,
    var(--surface-3) 100%
  );
  background-size: 200% 100%;
  animation: job-sweep 1.4s ease-in-out infinite;
}
@keyframes job-sweep {
  0% {
    background-position: 100% 0;
  }
  100% {
    background-position: -100% 0;
  }
}
@media (prefers-reduced-motion: reduce) {
  .job-bar:not([value]) {
    animation: none;
  }
}

/* ===========================================================================
   Research workbench tabs (UNIT-116)
   ---------------------------------------------------------------------------
   The page was reported as "very overwhelming" — header, guide, facet rail,
   filter builder, three button rows, an eleven-column grid and a drawer, all
   at once. Tabs split it by question. They are plain links, so a tab survives a
   refresh, a bookmark and the back button, and needs no JS under the CSP.

   NB: `grid-table` has no CSS anywhere in this repo — the app leans on element
   selectors — but NEW layout classes DO need rules. That caught UNIT-108 out.
   =========================================================================== */

.tab-strip {
  display: flex;
  gap: 0.25rem;
  margin: 0 0 1rem;
  border-bottom: 1px solid var(--border);
}
.tab {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.55rem 1rem;
  color: var(--muted);
  text-decoration: none;
  font-weight: 600;
  border: 1px solid transparent;
  border-bottom: none;
  border-radius: 0.4rem 0.4rem 0 0;
  /* Reserve the active row's 2px lift so switching tabs doesn't nudge the page. */
  margin-bottom: -1px;
}
.tab:hover {
  color: var(--text);
  background: var(--surface-2);
}
.tab.active {
  color: var(--text);
  background: var(--surface);
  border-color: var(--border);
  border-bottom: 1px solid var(--surface);
}
.tab-count {
  font-size: 0.75rem;
  font-weight: 650;
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--muted);
}
.tab.active .tab-count {
  background: var(--accent-bg, var(--surface-2));
  color: var(--text);
}

/* The identity line: pair, timeframe, entry shape, seed. Sits above the tabs
   because it is true on every one of them. */
.session-anchor {
  flex-basis: 100%;
  margin: 0;
  font-size: 0.95rem;
  color: var(--text);
}
.session-anchor .sep {
  margin: 0 0.45rem;
  color: var(--muted-2);
}

.gen-tab,
.session-tab {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* Label/value pairs for the configuration and accounting panels. auto-fit so a
   narrow screen stacks them without a media query. */
.anchor-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: 0.9rem 1.5rem;
  margin: 0 0 0.75rem;
}
.anchor-grid > div {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.anchor-grid dt {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted-2);
}
.anchor-grid dd {
  margin: 0;
  color: var(--text);
}
.anchor-grid dd p {
  margin: 0.3rem 0 0;
  font-size: 0.85rem;
}

.gen-form,
.verdict-form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.75rem 1.25rem;
  margin-bottom: 0.75rem;
}
.gen-form label,
.verdict-form label {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.gen-form label > .muted,
.verdict-form label > .muted {
  max-width: 26rem;
  font-size: 0.8rem;
}
.verdict-form input[type="text"] {
  min-width: 22rem;
}

/* "N in the cohort · N got past the first cut · …" — the evidence the dead-end
   decision rests on, so it reads as one sentence rather than a stat grid. */
.health-line {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.25rem;
  margin: 0 0 0.75rem;
  padding: 0;
  list-style: none;
  color: var(--muted);
}
.health-line strong {
  color: var(--text);
  font-size: 1.05rem;
}

/* --- The lab (UNIT-136): options + Generate on top, results below. The template
   detail sits in a panel BESIDE the dropdown (scales to any number of templates,
   unlike the radio cards it replaced) and demonstrates what choosing it searches. */
.lab-grid {
  display: grid;
  grid-template-columns: minmax(18rem, 1fr) minmax(20rem, 1.2fr);
  gap: 1rem 2rem;
  align-items: start;
}
@media (max-width: 55rem) {
  .lab-grid {
    grid-template-columns: 1fr;
  }
}
.lab-controls {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.lab-controls label {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.lab-controls label > .muted {
  max-width: 28rem;
  font-size: 0.8rem;
}
.lab-advanced {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.5rem 0.85rem;
}
.lab-advanced[open] {
  padding-bottom: 0.85rem;
}
.lab-advanced summary {
  cursor: pointer;
  color: var(--muted);
}
.btn-generate {
  font-size: 1.15rem;
  font-weight: 650;
  padding: 0.7rem 2.5rem;
  align-self: flex-start;
}
.template-detail {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.85rem;
  padding: 0.85rem 1rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface-2);
}
.template-detail p {
  margin: 0;
}
.template-title {
  font-size: 1rem;
}
.lab-current-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem 1.25rem;
}
.lab-current-head h2 {
  margin: 0;
}
/* The lab trims the action bar to the generate→check→regenerate loop: screening, the
   cross-pair fan-out and portfolio/promotion assembly live on the workbench instead.
   CSS-scoped (not template logic) so it survives every HTMX swap of #cohort. */
.lab-cohort [data-step="screen"],
.lab-cohort input[name="saveAs"],
.lab-cohort [data-step="xval"],
.lab-cohort .action-group-assemble {
  display: none;
}
.template-tagline {
  color: var(--muted);
}
.template-section {
  margin-top: 0.35rem;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted-2);
}
.template-text {
  color: var(--text);
}
.template-searches {
  margin: 0;
  padding-left: 1.1rem;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  color: var(--text);
}

.danger-zone {
  border-color: rgba(239, 68, 68, 0.35);
}
.session-lifecycle .inline-form {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
}

/* ---------------------------------------------------------------------------
   Selection bar + next-step recommendation (UNIT-117)
   ---------------------------------------------------------------------------
   The six actions were peers grouped by cost, which answered "what will this
   charge me" but not "what do I press next". The recommendation is stated in
   words here and highlights its button below, so the sentence and the control
   are visibly the same thing.
   --------------------------------------------------------------------------- */

.select-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1rem;
  padding: 0.5rem 0.75rem;
  margin-bottom: 0.6rem;
  border: 1px solid var(--border);
  border-radius: 0.45rem;
  background: var(--surface-2);
}
.select-count {
  font-weight: 650;
  color: var(--text);
  /* Fixed floor so the bar does not jitter as the count changes width. */
  min-width: 7rem;
}
.next-step {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.4rem;
}
.next-step-arrow {
  color: var(--muted-2);
}
.next-step .muted {
  font-size: 0.85rem;
}

/* The button the recommendation names. An outline rather than a fill: it is a
   suggestion, and a filled primary would read as "the only thing you may do". */
.step-recommended {
  outline: 2px solid var(--accent, #4c8dff);
  outline-offset: 1px;
}

/* Header select-all sits in a narrow column; keep it from stretching. */
.cohort-table thead input[type="checkbox"] {
  cursor: pointer;
}

/* ---------------------------------------------------------------------------
   Result page: breadcrumb + robustness explainers (UNIT-119)
   --------------------------------------------------------------------------- */

.result-breadcrumb {
  margin-bottom: 0.6rem;
  font-size: 0.9rem;
}

.robustness-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: 1rem;
  margin: 0.75rem 0;
}
.robustness-card {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.9rem;
  border: 1px solid var(--border);
  border-radius: 0.45rem;
  background: var(--surface-2);
}
.robustness-card h3 {
  margin: 0;
  font-size: 1rem;
}
/* The question the test answers, in plain language — it carries more weight than
   the name above it, which is jargon by necessity. */
.rb-summary {
  margin: 0;
  color: var(--text);
  font-size: 0.9rem;
}
.robustness-card details {
  font-size: 0.85rem;
  color: var(--muted);
}
.robustness-card details > summary {
  cursor: pointer;
  color: var(--accent);
}
.robustness-card details p {
  margin: 0.5rem 0 0;
}
.rb-gate {
  margin: 0;
  font-size: 0.8rem;
}
/* Push the button to the bottom so cards of differing text length line up. */
.robustness-card form {
  margin-top: auto;
}

/* Gate cell doubles as the way into the detail panel (UNIT-120): the name now goes
   straight to the result, so this is the remaining door to per-test verdicts. */
.gate-link {
  text-decoration: none;
}
.gate-link:hover .badge {
  outline: 1px solid var(--border);
}
