/* ==========================================================================
   CCAI design system — "Broadcast Desk"
   Source: specs/039-admin-ui-design-system/design.html
   ========================================================================== */

:root {
  /* Surfaces — warm paper neutrals */
  --paper: oklch(0.985 0.004 80);
  --vellum: oklch(0.965 0.006 80);
  --surface: oklch(1 0 0);
  --surface-sunk: oklch(0.955 0.006 80);

  /* Ink — text + borders */
  --ink-900: oklch(0.18 0.006 60);
  --ink-800: oklch(0.26 0.006 60);
  --ink-700: oklch(0.36 0.006 60);
  --ink-500: oklch(0.55 0.005 60);
  --ink-400: oklch(0.66 0.005 60);
  --ink-300: oklch(0.80 0.004 60);
  --ink-200: oklch(0.90 0.004 60);
  --ink-100: oklch(0.94 0.003 60);

  /* Ember — reserved for LIVE / record / signal */
  --ember-700: oklch(0.50 0.18 32);
  --ember-600: oklch(0.58 0.20 32);
  --ember-500: oklch(0.66 0.20 32);
  --ember-100: oklch(0.94 0.04 32);
  --ember-50:  oklch(0.97 0.02 32);

  /* Functional */
  --signal-600: oklch(0.55 0.13 155);
  --signal-100: oklch(0.95 0.03 155);
  --caution-600: oklch(0.68 0.14 75);
  --caution-100: oklch(0.96 0.04 75);
  --halt-600: oklch(0.55 0.19 25);
  --halt-100: oklch(0.95 0.04 25);
  --cobalt-600: oklch(0.5 0.14 250);
  --cobalt-100: oklch(0.95 0.03 250);

  /* Radii */
  --r-xs: 4px;
  --r-sm: 6px;
  --r-md: 10px;
  --r-lg: 14px;
  --r-xl: 20px;
  --r-pill: 999px;

  /* Spacing (4-base) */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px;
  --s-5: 24px; --s-6: 32px; --s-7: 48px; --s-8: 64px;

  /* Elevation */
  --e-0: 0 0 0 1px var(--ink-200);
  --e-1: 0 1px 0 0 var(--ink-200), 0 1px 2px -1px oklch(0.18 0.006 60 / 0.06);
  --e-2: 0 2px 4px -2px oklch(0.18 0.006 60 / 0.08), 0 4px 12px -4px oklch(0.18 0.006 60 / 0.06), 0 0 0 1px var(--ink-200);
  --e-3: 0 8px 24px -8px oklch(0.18 0.006 60 / 0.14), 0 0 0 1px var(--ink-200);

  /* Type */
  --f-display: "Bricolage Grotesque", ui-serif, Georgia, serif;
  --f-sans: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --f-mono: "Geist Mono", ui-monospace, "SF Mono", Menlo, monospace;
}

* { box-sizing: border-box; }
html, body {
  margin: 0;
  background: var(--paper);
  color: var(--ink-900);
  font-family: var(--f-sans);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  font-feature-settings: "ss01", "cv11";
}

/* ==========================================================================
   App shell
   ========================================================================== */
.app {
  display: grid;
  grid-template-columns: 260px minmax(0, 1fr);
  min-height: 100vh;
}

.nav {
  position: sticky;
  top: 0;
  height: 100vh;
  border-right: 1px solid var(--ink-200);
  padding: var(--s-5) var(--s-4);
  background: var(--surface);
  display: flex;
  flex-direction: column;
  gap: var(--s-5);
  overflow-y: auto;
}
.nav-brand {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-2) var(--s-2);
}
.brand-mark {
  width: 28px;
  height: 28px;
  border-radius: 8px;
  background: var(--ink-900);
  position: relative;
  display: grid;
  place-items: center;
  flex-shrink: 0;
}
.brand-mark::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--ember-500);
  box-shadow: 0 0 0 3px oklch(0.66 0.20 32 / 0.25);
}
/* Ember pulse only animates when body has data-live="1" (PR4 sets it from the server when a BroadcastJob is live). */
body[data-live="1"] .brand-mark::before {
  animation: ember-pulse 2.4s ease-in-out infinite;
}
@keyframes ember-pulse {
  0%, 100% { box-shadow: 0 0 0 3px oklch(0.66 0.20 32 / 0.25); }
  50%      { box-shadow: 0 0 0 6px oklch(0.66 0.20 32 / 0.05); }
}
.brand-name {
  font-family: var(--f-display);
  font-weight: 700;
  font-size: 18px;
  letter-spacing: -0.02em;
  color: var(--ink-900);
}
.brand-sub {
  font-family: var(--f-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-500);
  margin-top: 2px;
}

.nav-section { display: flex; flex-direction: column; gap: 2px; }
.nav-section-label {
  font-family: var(--f-mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-500);
  padding: var(--s-2) var(--s-2);
}
.nav a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px var(--s-2);
  color: var(--ink-700);
  text-decoration: none;
  font-size: 13.5px;
  border-radius: var(--r-sm);
  transition: background .12s;
}
.nav a:hover { background: var(--ink-100); color: var(--ink-900); }
.nav a.active { background: var(--ink-100); color: var(--ink-900); font-weight: 500; }
.nav a .n { font-family: var(--f-mono); font-size: 11px; color: var(--ink-400); }

main {
  padding: var(--s-7) var(--s-8) var(--s-8) var(--s-7);
  max-width: 1200px;
}
@media (max-width: 900px) {
  .app { grid-template-columns: 1fr; }
  .nav { position: static; height: auto; }
  main { padding: var(--s-5); }
}

/* ==========================================================================
   Section primitives (used by the design-system reference page)
   ========================================================================== */
.section { padding-top: var(--s-8); padding-bottom: var(--s-6); border-bottom: 1px solid var(--ink-200); }
.section:first-of-type { padding-top: 0; }
.section:last-of-type { border-bottom: 0; }

.eyebrow {
  font-family: var(--f-mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ember-700);
  margin: 0 0 var(--s-2);
}
h1.disp {
  font-family: var(--f-display);
  font-weight: 600;
  font-size: clamp(40px, 5.6vw, 64px);
  line-height: 1.02;
  letter-spacing: -0.025em;
  margin: 0 0 var(--s-4);
  color: var(--ink-900);
  text-wrap: balance;
}
h2.sec {
  font-family: var(--f-display);
  font-weight: 600;
  font-size: 32px;
  line-height: 1.1;
  letter-spacing: -0.02em;
  margin: 0 0 var(--s-2);
  color: var(--ink-900);
}
h3.sub {
  font-family: var(--f-sans);
  font-weight: 600;
  font-size: 15px;
  margin: var(--s-6) 0 var(--s-3);
  color: var(--ink-900);
  display: flex;
  align-items: center;
  gap: var(--s-2);
}
h3.sub::before {
  content: "";
  display: inline-block;
  width: 16px; height: 1px;
  background: var(--ink-400);
}
.lede {
  font-size: 17px;
  line-height: 1.55;
  color: var(--ink-700);
  max-width: 68ch;
  text-wrap: pretty;
}
.grid { display: grid; gap: var(--s-4); }
.g-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.g-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.g-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 760px) {
  .g-3, .g-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.caption {
  font-family: var(--f-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-500);
}
.row { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; }

/* ==========================================================================
   Color — swatches (reference page only)
   ========================================================================== */
.swatch-row { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: var(--s-3); }
@media (max-width: 760px) { .swatch-row { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.swatch {
  border-radius: var(--r-md);
  overflow: hidden;
  border: 1px solid var(--ink-200);
  background: var(--surface);
}
.swatch .chip { height: 96px; }
.swatch .meta { padding: var(--s-3); }
.swatch .name { font-weight: 600; font-size: 13.5px; }
.swatch .code { font-family: var(--f-mono); font-size: 10.5px; color: var(--ink-500); margin-top: 2px; word-break: break-all; }

.palette-strip {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  border-radius: var(--r-md);
  overflow: hidden;
  border: 1px solid var(--ink-200);
}
.palette-strip > div {
  aspect-ratio: 1 / 1.1;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 8px 10px;
  color: var(--ink-100);
  font-family: var(--f-mono);
  font-size: 10px;
  line-height: 1.2;
  letter-spacing: 0.04em;
}
.palette-strip > div small { display: block; opacity: .7; font-size: 9px; }
.palette-strip .light { color: var(--ink-800); }

/* ==========================================================================
   Type specimen (reference page only)
   ========================================================================== */
.type-row {
  display: grid;
  grid-template-columns: 140px 1fr;
  align-items: baseline;
  gap: var(--s-5);
  padding: var(--s-4) 0;
  border-top: 1px dashed var(--ink-200);
}
.type-row:first-of-type { border-top: 0; }
.type-row .label .l1 { font-weight: 600; font-size: 13px; color: var(--ink-800); }
.type-row .label .l2 { font-family: var(--f-mono); font-size: 11px; color: var(--ink-500); margin-top: 2px; }

.specimen-display { font-family: var(--f-display); font-weight: 600; font-size: 56px; line-height: 1.05; letter-spacing: -0.025em; }
.specimen-h1 { font-family: var(--f-sans); font-weight: 600; font-size: 30px; line-height: 1.2; letter-spacing: -0.015em; }
.specimen-h2 { font-family: var(--f-sans); font-weight: 600; font-size: 22px; line-height: 1.25; letter-spacing: -0.01em; }
.specimen-h3 { font-family: var(--f-sans); font-weight: 600; font-size: 17px; line-height: 1.35; }
.specimen-body { font-family: var(--f-sans); font-weight: 400; font-size: 15px; line-height: 1.55; max-width: 60ch; }
.specimen-small { font-family: var(--f-sans); font-weight: 400; font-size: 13px; line-height: 1.5; color: var(--ink-700); }
.specimen-cap { font-family: var(--f-mono); font-weight: 500; font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-500); }
.specimen-data { font-family: var(--f-mono); font-weight: 500; font-size: 28px; font-feature-settings: "tnum"; }

/* ==========================================================================
   Card
   ========================================================================== */
.card {
  background: var(--surface);
  border-radius: var(--r-lg);
  box-shadow: var(--e-1);
  padding: var(--s-5);
}
.card.flat { box-shadow: var(--e-0); }
.card-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: var(--s-4);
}
.card-title {
  font-family: var(--f-sans);
  font-weight: 600; font-size: 16px;
  letter-spacing: -0.005em;
}

/* ==========================================================================
   Spacing / radii / elevation samplers (reference page only)
   ========================================================================== */
.sampler-row { display: flex; gap: var(--s-4); flex-wrap: wrap; }
.radius-sample {
  width: 84px; height: 84px;
  background: var(--ink-900);
  color: var(--paper);
  display: flex; align-items: flex-end; justify-content: center;
  padding: 6px;
  font-family: var(--f-mono); font-size: 11px;
}
.space-sample {
  background: var(--surface);
  border: 1px solid var(--ink-200);
  border-radius: var(--r-md);
  padding: var(--s-3);
  display: flex; align-items: center; gap: var(--s-3);
  font-family: var(--f-mono); font-size: 11px; color: var(--ink-700);
}
.space-sample .bar { background: var(--ember-500); height: 12px; border-radius: 2px; }

.elev-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s-4); }
@media (max-width: 760px) { .elev-row { grid-template-columns: repeat(2, 1fr); } }
.elev-card {
  background: var(--surface);
  border-radius: var(--r-md);
  padding: var(--s-5);
  text-align: center;
  font-family: var(--f-mono); font-size: 11px; color: var(--ink-700);
}

/* ==========================================================================
   Footer (reference page)
   ========================================================================== */
.ds-footer { color: var(--ink-500); padding: var(--s-7) 0 var(--s-5); font-family: var(--f-mono); font-size: 11px; letter-spacing: 0.08em; }
.ds-footer .line { display: flex; gap: var(--s-3); align-items: center; }
.ds-footer .rule { flex: 1; height: 1px; background: var(--ink-200); }

section[id] { scroll-margin-top: 24px; }

/* ==========================================================================
   Components — Buttons (§07)
   ========================================================================== */
.btn {
  --bg: var(--ink-900);
  --fg: var(--paper);
  --bd: var(--ink-900);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 14px;
  font-family: var(--f-sans);
  font-weight: 500;
  font-size: 13.5px;
  letter-spacing: -0.005em;
  color: var(--fg);
  background: var(--bg);
  border: 1px solid var(--bd);
  border-radius: var(--r-md);
  cursor: pointer;
  transition: transform .08s, background .12s, box-shadow .12s, color .12s, border-color .12s;
  line-height: 1;
}
.btn:hover:not([disabled]) { transform: translateY(-1px); }
.btn:active:not([disabled]) { transform: translateY(0); }
.btn .ic { width: 15px; height: 15px; }

.btn.primary  { --bg: var(--ink-900); --fg: var(--paper); --bd: var(--ink-900); }
.btn.primary:hover:not([disabled]) { background: var(--ink-800); }
.btn.secondary { --bg: var(--surface); --fg: var(--ink-900); --bd: var(--ink-300); }
.btn.secondary:hover:not([disabled]) { --bd: var(--ink-700); background: var(--ink-100); }
.btn.ghost { --bg: transparent; --fg: var(--ink-800); --bd: transparent; padding: 8px 10px; }
.btn.ghost:hover:not([disabled]) { background: var(--ink-100); }
.btn.live { --bg: var(--ember-600); --fg: #fff; --bd: var(--ember-600); }
.btn.live:hover:not([disabled]) { background: var(--ember-700); --bd: var(--ember-700); }
.btn.halt { --bg: var(--surface); --fg: var(--halt-600); --bd: oklch(0.55 0.19 25 / 0.4); }
.btn.halt:hover:not([disabled]) { background: var(--halt-100); }
.btn[disabled] { opacity: .45; cursor: not-allowed; }
.btn.sm { padding: 6px 10px; font-size: 12.5px; }
.btn.lg { padding: 12px 18px; font-size: 14.5px; border-radius: var(--r-lg); }
/* Keyboard-only focus ring — cobalt for AA contrast against any button surface
   (paper, ink, ember, halt). `:focus-visible` keeps mouse-click :focus quiet. */
.btn:focus-visible { outline: 2px solid var(--cobalt-600); outline-offset: 2px; }

/* Anchor focus ring — keep dashboard links / nav items legible when keyed in. */
.nav a:focus-visible,
.upcoming-list > a:focus-visible {
  outline: 2px solid var(--cobalt-600);
  outline-offset: -2px;
}

/* Global icon helper — stroke-width 1.5 inherits into `<use>`-referenced symbols. */
.ic { stroke-width: 1.5; }

/* Loading indicator — replaces inline `style="animation: spin..."` in markup. */
@keyframes spin { to { transform: rotate(360deg); } }
.spin { animation: spin 1s linear infinite; }

/* ==========================================================================
   Components — Status pills (§08)
   ========================================================================== */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px 12px 4px 10px;
  border-radius: var(--r-pill);
  font-family: var(--f-mono);
  font-weight: 500;
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  border: 1px solid transparent;
  line-height: 1;
}
/* PR6 — the dot's `currentColor` matches the pill text color exactly, so a
   too-small gap visually merges the dot with the first letter (e.g.
   "COMPLETED" reads as "OMPLETED"). 8px / 5px gives the leading character
   visible breathing room. */
.pill .dot {
  width: 5px; height: 5px; border-radius: 50%; background: currentColor;
  flex-shrink: 0;
}
.pill.live   { background: var(--ember-50); color: var(--ember-700); border-color: oklch(0.66 0.20 32 / 0.25); }
.pill.live .dot { background: var(--ember-500); box-shadow: 0 0 0 3px oklch(0.66 0.20 32 / 0.25); animation: ember-pulse 2s ease-in-out infinite; }
.pill.monitor{ background: var(--signal-100); color: oklch(0.36 0.13 155); border-color: oklch(0.55 0.13 155 / 0.25); }
.pill.idle   { background: var(--ink-100); color: var(--ink-700); border-color: var(--ink-200); }
.pill.done   { background: var(--signal-100); color: oklch(0.36 0.13 155); border-color: oklch(0.55 0.13 155 / 0.2); }
.pill.proc   { background: var(--caution-100); color: oklch(0.44 0.14 75); border-color: oklch(0.68 0.14 75 / 0.25); }
.pill.fail   { background: var(--halt-100); color: var(--halt-600); border-color: oklch(0.55 0.19 25 / 0.25); }
.pill.info   { background: var(--cobalt-100); color: var(--cobalt-600); border-color: oklch(0.5 0.14 250 / 0.2); }

/* Tag — lower-key alternative to pill (post-processing markers) */
.tag {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 8px;
  border-radius: var(--r-sm);
  font-size: 11.5px;
  font-weight: 500;
  color: var(--ink-700);
  background: var(--ink-100);
  border: 1px solid var(--ink-200);
}
.tag .ic { width: 11px; height: 11px; opacity: .7; }

/* ==========================================================================
   Components — Stat tile (§09)
   ========================================================================== */
.stat {
  background: var(--surface);
  border: 1px solid var(--ink-200);
  border-radius: var(--r-lg);
  padding: var(--s-4) var(--s-5);
  display: flex; flex-direction: column; gap: 6px;
  position: relative;
}
.stat .lab {
  font-family: var(--f-mono);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-500);
}
.stat .num {
  font-family: var(--f-display);
  font-weight: 600;
  font-size: 40px;
  line-height: 1;
  letter-spacing: -0.025em;
  color: var(--ink-900);
  font-feature-settings: "tnum";
}
.stat .num .unit { font-size: 18px; color: var(--ink-500); margin-left: 4px; font-family: var(--f-mono); font-weight: 500; }
.stat .delta {
  font-family: var(--f-mono);
  font-size: 11.5px;
  color: var(--signal-600);
}
.stat .delta.down { color: var(--halt-600); }

/* ==========================================================================
   Components — Forms (§10)
   ========================================================================== */
.field { display: flex; flex-direction: column; gap: 6px; }
.field label { font-size: 12.5px; font-weight: 500; color: var(--ink-800); }
.input, .select {
  font: 500 14px var(--f-sans);
  padding: 9px 12px;
  background: var(--surface);
  border: 1px solid var(--ink-300);
  border-radius: var(--r-md);
  color: var(--ink-900);
  outline: none;
  transition: border-color .12s, box-shadow .12s;
}
.input:focus, .select:focus {
  border-color: var(--ink-900);
  box-shadow: 0 0 0 4px oklch(0.18 0.006 60 / 0.08);
}
.input.invalid, .select.invalid { border-color: var(--halt-600); }
.input.invalid:focus, .select.invalid:focus { box-shadow: 0 0 0 4px oklch(0.55 0.19 25 / 0.12); }
.input.valid, .select.valid { border-color: var(--signal-600); }

/* Toggle */
.toggle {
  position: relative; width: 36px; height: 20px;
  background: var(--ink-300); border-radius: 999px;
  cursor: pointer; transition: background .15s, box-shadow .12s;
  flex-shrink: 0;
}
.toggle.on { background: var(--ink-900); }
.toggle::after {
  content: ""; position: absolute; top: 2px; left: 2px;
  width: 16px; height: 16px; background: #fff; border-radius: 50%;
  transition: transform .18s; box-shadow: 0 1px 2px rgba(0,0,0,.18);
}
.toggle.on::after { transform: translateX(16px); }
.toggle:focus-visible { outline: none; box-shadow: 0 0 0 4px oklch(0.5 0.14 250 / 0.25); }

/* ==========================================================================
   Components — Recording row (§11)
   ========================================================================== */
.rec-row {
  display: grid;
  grid-template-columns: 18px 1fr auto auto;
  align-items: center;
  gap: var(--s-4);
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  border-bottom: 1px solid var(--ink-200);
}
.rec-row:last-child { border-bottom: 0; }
.rec-row:hover { background: var(--ink-100); }
.rec-row .ic { color: var(--ink-500); width: 16px; height: 16px; }
.rec-row .title { font-weight: 500; }
.rec-row .meta { font-family: var(--f-mono); font-size: 11px; color: var(--ink-500); letter-spacing: 0.04em; }
.rec-row .right { display: flex; align-items: center; gap: var(--s-2); }

/* Recordings list variant — wider status pill column + roomier padding for the
   operator surface (`templates/recordings.html`). The §11 default geometry is
   tuned for the dense table on dashboards; this variant trades density for
   legible status pills + multi-button action stacks. */
.rec-row.recordings-list {
  grid-template-columns: auto 1fr auto auto;
  padding: var(--s-4) var(--s-5);
}

/* ==========================================================================
   Components — Pipeline progress (§12)
   Segmented bar where each segment maps to a transcription pipeline step.
   ========================================================================== */
.pipeline { display: flex; gap: 6px; }
.pipeline .seg {
  flex: 1;
  height: 5px;
  border-radius: 999px;
  background: var(--ink-200);
  position: relative;
  overflow: hidden;
}
.pipeline .seg.done { background: var(--ink-900); }
.pipeline .seg.active { background: var(--ink-200); }
.pipeline .seg.active::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent 0%, var(--ink-900) 50%, transparent 100%);
  animation: stream 1.6s linear infinite;
  width: 50%;
}
@keyframes stream { from { transform: translateX(-100%); } to { transform: translateX(300%); } }
.pipeline-labels { display: flex; gap: 6px; margin-top: 6px; font-family: var(--f-mono); font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-500); }
.pipeline-labels > span { flex: 1; }
.pipeline-labels > span.done { color: var(--ink-800); }
.pipeline-labels > span.active { color: var(--ink-900); font-weight: 600; }

/* ==========================================================================
   Patterns — LIVE hero (§13)
   Ink-black telemetry slab. Renders only above the fold when a BroadcastJob
   is in state `live`. The page template also sets `data-live="1"` on <body>
   so the sidebar brand-mark ember-pulse activates in lockstep.
   ========================================================================== */
.live-hero {
  background: var(--ink-900);
  color: var(--paper);
  border-radius: var(--r-xl);
  padding: var(--s-6);
  position: relative;
  overflow: hidden;
}
.live-hero::before {
  content: "";
  position: absolute; inset: 0;
  background:
    radial-gradient(circle at 92% 22%, oklch(0.66 0.20 32 / 0.30) 0%, transparent 40%),
    radial-gradient(circle at 12% 88%, oklch(0.66 0.20 32 / 0.10) 0%, transparent 50%);
  pointer-events: none;
}
.live-hero > * { position: relative; }
.live-hero .row-top {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--s-4);
  flex-wrap: wrap;
}
.live-hero .pill.live {
  background: oklch(0.66 0.20 32 / 0.15);
  color: oklch(0.85 0.12 32);
  border-color: oklch(0.66 0.20 32 / 0.4);
}
.live-hero h2 {
  font-family: var(--f-display);
  font-size: clamp(24px, 3.4vw, 36px);
  line-height: 1.05;
  letter-spacing: -0.02em;
  font-weight: 600;
  margin: var(--s-3) 0 var(--s-2);
  text-wrap: balance;
  color: var(--paper);
}
.live-hero .sub { color: oklch(0.78 0.005 60); font-size: 14px; }
.live-hero .sub a { color: var(--paper); text-decoration: underline; }
.live-hero .meter {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: oklch(0.28 0.006 60);
  border-radius: var(--r-md);
  overflow: hidden;
  margin-top: var(--s-5);
}
.live-hero .meter > div { padding: 12px 14px; background: oklch(0.22 0.006 60); }
.live-hero .meter .k {
  font-family: var(--f-mono);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: oklch(0.66 0.005 60);
  margin-bottom: 4px;
}
.live-hero .meter .v {
  font-family: var(--f-mono);
  font-weight: 500;
  font-size: 18px;
  color: var(--paper);
  font-feature-settings: "tnum";
}
/* Open-stream button uses dark-on-dark variant — overrides .btn.secondary tokens
   when nested inside .live-hero so the same button class reads on either surface. */
.live-hero .btn.secondary {
  --bg: oklch(0.28 0.006 60);
  --fg: var(--paper);
  --bd: oklch(0.36 0.006 60);
}
.live-hero .btn.secondary:hover:not([disabled]) {
  background: oklch(0.32 0.006 60);
  --bd: oklch(0.45 0.006 60);
}

.waveform {
  margin-top: var(--s-5);
  display: flex;
  align-items: flex-end;
  gap: 3px;
  height: 36px;
}
.waveform span {
  flex: 1;
  background: oklch(0.66 0.20 32 / 0.7);
  border-radius: 2px;
  animation: wave-bar 1.4s ease-in-out infinite;
}
@keyframes wave-bar { 0%, 100% { height: 20%; } 50% { height: 100%; } }

/* ==========================================================================
   Patterns — Dashboard composition (§14)
   Tight on the dashboard route only — page-level header, two-column grid,
   list-style upcoming meetings. Kept as utility classes (not page-scoped IDs)
   so the design-system reference page can mirror the same composition.
   ========================================================================== */
.page-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--s-4);
  flex-wrap: wrap;
  margin-bottom: var(--s-5);
}
.page-header .title { font-family: var(--f-display); font-size: 28px; line-height: 1.1; letter-spacing: -0.02em; font-weight: 600; margin: 0; color: var(--ink-900); }
.page-header .actions { display: flex; gap: var(--s-2); flex-wrap: wrap; }

.upcoming-list {
  display: flex;
  flex-direction: column;
  gap: 1px;
  background: var(--ink-200);
  border-radius: var(--r-md);
  overflow: hidden;
}
.upcoming-list > a, .upcoming-list > .item {
  background: var(--surface);
  padding: 10px 12px;
  text-decoration: none;
  color: inherit;
  display: block;
  transition: background .12s;
}
.upcoming-list > a:hover { background: var(--ink-100); }
.upcoming-list .title { font-weight: 500; font-size: 14px; color: var(--ink-900); }
.upcoming-list .when { font-family: var(--f-mono); font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-500); margin-top: 2px; }

.empty-state {
  text-align: center;
  padding: var(--s-6);
  color: var(--ink-500);
  font-size: 13.5px;
}

/* Active-pipeline row — pipeline bar with a label header above. Same primitive
   as §12; only the .pipe-row wrapper is new. */
.pipe-row .pipe-head {
  display: flex; justify-content: space-between; align-items: center;
  font-size: 13px;
  margin-bottom: 6px;
}
.pipe-row .pipe-head .name { font-weight: 500; color: var(--ink-900); }

/* Reduced motion — also stop the waveform when users opt out. */
@media (prefers-reduced-motion: reduce) {
  .waveform span { animation: none !important; height: 50% !important; }
}

/* ==========================================================================
   Iconography reference (§06) — used by the design-system reference page
   to display the full icon grid. Not used elsewhere; the actual `<svg use>`
   refs throughout the app inherit size/stroke from their parent context.
   ========================================================================== */
.ico-grid { display: grid; grid-template-columns: repeat(8, 1fr); gap: var(--s-3); }
@media (max-width: 760px) { .ico-grid { grid-template-columns: repeat(4, 1fr); } }
.ico-tile {
  aspect-ratio: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
  border-radius: var(--r-md);
  border: 1px solid var(--ink-200);
  background: var(--surface);
  color: var(--ink-800);
}
.ico-tile svg { width: 22px; height: 22px; }
.ico-tile .nm { font-family: var(--f-mono); font-size: 10px; letter-spacing: 0.04em; color: var(--ink-500); text-transform: lowercase; }

/* ==========================================================================
   Utilities
   ========================================================================== */
/* JS-toggled visibility — replaces Tailwind's `.hidden` for templates that
   call `classList.add('hidden')` / `classList.remove('hidden')`. Used by
   `static/js/recording-detail.js` to toggle btn-text vs. btn-loading. */
.hidden { display: none !important; }

/* Inline-flex wrapper for button text/loading swap spans (used by
   transcription_progress_card.html alongside `.hidden`). */
.btn-loading { display: inline-flex; align-items: center; gap: 6px; }

/* Screen-reader-only text — visually hidden but announced by assistive tech.
   Used to label dot-only status pills, icon-only buttons, etc. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ==========================================================================
   Reduced motion — disable design-system animations for users who request it
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  body[data-live="1"] .brand-mark::before,
  .pill.live .dot,
  .pipeline .seg.active::after,
  .spin {
    animation: none !important;
  }
}

/* ==========================================================================
   Download dropdown (PR6)
   The transcript card's "Download" menu (Transcript JSON / Pyannote /
   Gemini refined). The toggle is a `.btn primary` button; the menu is a
   floating panel anchored under it.
   ========================================================================== */
.download-dropdown { position: relative; }
.download-dropdown a {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-radius: var(--r-sm);
  color: var(--ink-800);
  text-decoration: none;
  font-size: 13.5px;
}
.download-dropdown a:hover { background: var(--ink-100); }
.download-dropdown a:focus-visible {
  outline: 2px solid var(--cobalt-600);
  outline-offset: -2px;
}

/* ==========================================================================
   HTMX helpers (carried forward from old base.html)
   ========================================================================== */
.htmx-indicator { display: none; }
.htmx-request .htmx-indicator { display: inline; }
.htmx-request.htmx-indicator { display: inline; }

/* ==========================================================================
   Detail-page header (PR6)
   Eyebrow + display title + meta lines + right-aligned action stack.
   Used by meeting_detail / recording_detail. Distinct from `.page-header`
   (list pages) because detail pages lean on the display serif to anchor
   the page subject; list pages use the sans h1.
   ========================================================================== */
.detail-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--s-5);
  flex-wrap: wrap;
  margin-bottom: var(--s-6);
}
.detail-header .title {
  font-family: var(--f-display);
  font-weight: 600;
  font-size: clamp(28px, 3.4vw, 38px);
  line-height: 1.05;
  letter-spacing: -0.02em;
  color: var(--ink-900);
  margin: 0 0 var(--s-3);
  text-wrap: balance;
}
.detail-header .meta { display: flex; flex-direction: column; gap: 4px; color: var(--ink-700); font-size: 13.5px; }
.detail-header .meta a { color: var(--cobalt-600); text-decoration: none; border-bottom: 1px solid oklch(0.5 0.14 250 / 0.3); }
.detail-header .meta a:hover { border-bottom-color: var(--cobalt-600); }
.detail-header .actions { display: flex; gap: var(--s-2); flex-wrap: wrap; align-items: center; }

/* ==========================================================================
   Key/Value tile (PR6)
   Compact label-on-top tile used on detail pages for status / start time /
   duration / size cards. Replaces the bg-gray-50 blocks from the legacy
   recording_info_card.
   ========================================================================== */
.kv-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-3); }
@media (max-width: 760px) { .kv-grid { grid-template-columns: 1fr; } }
.kv-tile {
  background: var(--vellum);
  border: 1px solid var(--ink-200);
  border-radius: var(--r-md);
  padding: var(--s-3) var(--s-4);
  display: flex; flex-direction: column; gap: 4px;
}
.kv-tile .k {
  font-family: var(--f-mono);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-500);
}
.kv-tile .v { font-weight: 500; color: var(--ink-900); }
.kv-tile .v.mono { font-family: var(--f-mono); font-size: 12px; word-break: break-all; }
.kv-tile.info { background: var(--cobalt-100); border-color: oklch(0.5 0.14 250 / 0.25); }
.kv-tile.info .k { color: var(--cobalt-600); }

/* ==========================================================================
   Data table (PR6)
   Storage & Files table styling — dense, mono cells, hover row, no zebra.
   ========================================================================== */
.data-table-wrap { overflow-x: auto; }
.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
}
.data-table th {
  text-align: left;
  font-family: var(--f-mono);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-500);
  font-weight: 500;
  padding: var(--s-2) var(--s-3);
  border-bottom: 1px solid var(--ink-200);
  background: var(--vellum);
}
.data-table td {
  padding: var(--s-3);
  border-bottom: 1px solid var(--ink-200);
  vertical-align: middle;
  color: var(--ink-800);
}
.data-table tbody tr:last-child td { border-bottom: 0; }
.data-table tbody tr:hover { background: var(--ink-100); }
.data-table td.mono { font-family: var(--f-mono); font-size: 11.5px; word-break: break-all; }
.data-table td .ok { color: var(--signal-600); display: inline-flex; align-items: center; gap: 4px; font-weight: 500; }
.data-table td .miss { color: var(--halt-600); display: inline-flex; align-items: center; gap: 4px; font-weight: 500; }
.data-table td .ic { width: 14px; height: 14px; }

/* ==========================================================================
   Console (PR6)
   Dark log block used by `logs_card.html` and the post-processing log tail.
   ========================================================================== */
.console {
  background: var(--ink-900);
  color: oklch(0.85 0.005 60);
  border-radius: var(--r-md);
  padding: var(--s-3) var(--s-4);
  font-family: var(--f-mono);
  font-size: 12px;
  line-height: 1.55;
  overflow: auto;
  max-height: 24rem;
}
.console .line { display: flex; gap: var(--s-3); padding: 2px 0; }
.console .line .ts { color: oklch(0.55 0.005 60); flex-shrink: 0; font-size: 11px; }
.console .line .lvl { flex-shrink: 0; font-weight: 600; font-size: 11px; color: var(--cobalt-600); }
.console .line.error .lvl { color: oklch(0.7 0.14 25); }
.console .line.error .msg { color: oklch(0.78 0.14 25); }
.console .line.warning .lvl,
.console .line.warn .lvl { color: oklch(0.78 0.14 75); }
.console .line.warning .msg,
.console .line.warn .msg { color: oklch(0.85 0.10 75); }
.console .line .msg { word-break: break-word; }

/* ==========================================================================
   Disclosure (`<details>`) chevron rotation (PR6)
   Replaces the Tailwind `transform rotate-180` inline pattern. Mark the
   chevron with `class="ic chev"` inside the `<summary>` and it animates
   when the disclosure opens.
   ========================================================================== */
details summary { list-style: none; cursor: pointer; }
details summary::-webkit-details-marker { display: none; }
details summary .ic.chev { transition: transform .15s ease; }
details[open] summary .ic.chev { transform: rotate(90deg); }

/* ==========================================================================
   Progress bar (PR6)
   Linear determinate bar used during download. Pulses when status flips to
   stream mode (no granular % available).
   ========================================================================== */
.progress {
  width: 100%;
  height: 6px;
  background: var(--ink-200);
  border-radius: 999px;
  overflow: hidden;
}
.progress .bar {
  height: 100%;
  background: var(--ink-900);
  width: 0%;
  transition: width .3s ease;
}
.progress .bar.pulse { animation: progress-pulse 1.4s ease-in-out infinite; opacity: .7; }
@keyframes progress-pulse { 0%, 100% { opacity: .35; } 50% { opacity: .9; } }
.progress-row {
  display: flex;
  justify-content: space-between;
  font-family: var(--f-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--ink-500);
  margin-bottom: 6px;
}

/* ==========================================================================
   Step row (PR6)
   JS-rendered transcription pipeline step (download / extraction / diarize /
   refine / consolidate / merge). Replaces the bg-green-50/30 + bg-blue-50/30
   Tailwind soup in recording-detail.js. The `.step-row` row swaps tint via
   modifier classes (.done / .processing / .failed / .skipped / .pending);
   the leading `.dot` mirrors the same modifier.
   ========================================================================== */
.step-row {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  border: 1px solid var(--ink-200);
  background: var(--surface);
  transition: border-color .12s, background .12s;
}
.step-row:hover { border-color: var(--ink-300); }
.step-row .step-dot {
  flex-shrink: 0;
  width: 28px; height: 28px;
  border-radius: 50%;
  display: grid; place-items: center;
  background: var(--ink-100);
  color: var(--ink-400);
  font-weight: 600;
  font-size: 13px;
}
.step-row .step-body { flex: 1; min-width: 0; }
.step-row .step-name { font-weight: 500; color: var(--ink-900); }
.step-row .step-aux { font-size: 12px; color: var(--ink-500); margin-top: 2px; }
.step-row .step-actions { display: flex; gap: var(--s-2); }
.step-row.done    .step-dot { background: var(--signal-100); color: var(--signal-600); }
.step-row.processing .step-dot { background: var(--cobalt-100); color: var(--cobalt-600); }
.step-row.failed  .step-dot { background: var(--halt-100); color: var(--halt-600); }
.step-row.skipped .step-dot { background: var(--ink-100); color: var(--ink-400); }
.step-row.skipped { opacity: .7; }
.step-row.failed .step-aux { color: var(--halt-600); }

/* ==========================================================================
   Background-task row (PR6)
   JS-rendered active background task. Same vellum tone as `.kv-tile` so
   the cards above (post-processing) and below (transcription steps) read
   as part of the same surface family.
   ========================================================================== */
.bg-task {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  background: var(--vellum);
  border: 1px solid var(--ink-200);
}
.bg-task .name { font-weight: 500; color: var(--ink-900); font-size: 13.5px; }
.bg-task .desc { font-size: 12px; color: var(--ink-500); margin-top: 2px; }
.bg-task .status {
  font-family: var(--f-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-700);
  display: inline-flex; align-items: center; gap: 6px;
}

/* ==========================================================================
   Speaker tile (PR6)
   Used by meeting_detail (council/public speaker cards) and the JS-rendered
   recording-detail speaker editor. Compact vellum tile + name + optional
   role/organization line.
   ========================================================================== */
.speaker-tile {
  background: var(--vellum);
  border: 1px solid var(--ink-200);
  border-radius: var(--r-md);
  padding: var(--s-3) var(--s-4);
}
.speaker-tile .name { font-weight: 600; color: var(--ink-900); }
.speaker-tile .role { font-size: 12.5px; color: var(--ink-700); margin-top: 2px; }
.speaker-tile .org { font-size: 12.5px; color: var(--cobalt-600); margin-top: 2px; }
.speaker-tile .src { font-family: var(--f-mono); font-size: 10.5px; color: var(--ink-500); margin-top: 4px; letter-spacing: 0.06em; }
.speaker-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-3); }
@media (max-width: 760px) { .speaker-grid { grid-template-columns: 1fr; } }
@media (min-width: 1100px) { .speaker-grid.dense { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* ==========================================================================
   Modal (PR6)
   Used by add-recording modal and JSON viewer. The dimmed overlay sits
   above app chrome; the inner panel uses the card primitive on top.
   ========================================================================== */
.modal-overlay {
  position: fixed; inset: 0;
  background: oklch(0.18 0.006 60 / 0.55);
  display: grid; place-items: center;
  padding: var(--s-4);
  z-index: 60;
}
.modal {
  background: var(--surface);
  border-radius: var(--r-lg);
  box-shadow: var(--e-3);
  width: 100%;
  max-width: 640px;
  max-height: 90vh;
  display: flex; flex-direction: column;
  overflow: hidden;
}
.modal.lg { max-width: 960px; }
.modal-head, .modal-foot {
  padding: var(--s-4) var(--s-5);
  background: var(--vellum);
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-3);
}
.modal-head { border-bottom: 1px solid var(--ink-200); }
.modal-foot { border-top: 1px solid var(--ink-200); justify-content: flex-end; }
.modal-title {
  font-family: var(--f-sans);
  font-weight: 600;
  font-size: 16px;
  letter-spacing: -0.005em;
  color: var(--ink-900);
  margin: 0;
}
.modal-body { padding: var(--s-5); overflow: auto; }
.modal-close {
  background: transparent;
  border: 0;
  cursor: pointer;
  color: var(--ink-500);
  display: grid; place-items: center;
  width: 28px; height: 28px;
  border-radius: var(--r-sm);
  font-size: 20px;
  line-height: 1;
}
.modal-close:hover { background: var(--ink-100); color: var(--ink-900); }
.modal-close:focus-visible { outline: 2px solid var(--cobalt-600); outline-offset: 2px; }
.json-pre {
  background: var(--ink-900);
  color: oklch(0.85 0.13 155);
  border-radius: var(--r-sm);
  padding: var(--s-4);
  font-family: var(--f-mono);
  font-size: 12px;
  line-height: 1.55;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 60vh;
}

/* ==========================================================================
   Inline error / inline note (PR6)
   Small inline alert blocks — replaces the bg-red-100 / bg-blue-100 inline
   Tailwind soup in the JS-driven detail page.
   ========================================================================== */
.inline-alert {
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  font-size: 13px;
  border: 1px solid transparent;
}
.inline-alert.error  { background: var(--halt-100);   color: var(--halt-600);   border-color: oklch(0.55 0.19 25 / 0.25); }
.inline-alert.info   { background: var(--cobalt-100); color: var(--cobalt-600); border-color: oklch(0.5 0.14 250 / 0.2); }
.inline-alert.ok     { background: var(--signal-100); color: oklch(0.34 0.13 155); border-color: oklch(0.55 0.13 155 / 0.25); }
.inline-alert.warn   { background: var(--caution-100); color: oklch(0.44 0.14 75); border-color: oklch(0.68 0.14 75 / 0.25); }

/* ==========================================================================
   Toast (PR6)
   Folded in from the retired `static/css/recording-detail.css`. The previous
   stylesheet styled toasts with raw hex (#10b981 / #ef4444 / #3b82f6); we
   reuse the design-system OKLCH tokens instead.
   ========================================================================== */
.toast-container {
  position: fixed;
  top: var(--s-4);
  right: var(--s-4);
  z-index: 70;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  pointer-events: none;
}
.toast {
  pointer-events: auto;
  min-width: 260px;
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  box-shadow: var(--e-3);
  color: var(--paper);
  font-weight: 500;
  font-size: 13.5px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  animation: toast-in .25s ease-out;
}
.toast .close {
  background: transparent;
  border: 0;
  color: inherit;
  cursor: pointer;
  opacity: .8;
  font-size: 18px;
  line-height: 1;
}
.toast .close:hover { opacity: 1; }
.toast.success { background: var(--signal-600); }
.toast.error   { background: var(--halt-600); }
.toast.info    { background: var(--cobalt-600); }
@keyframes toast-in {
  from { transform: translateX(100%); opacity: 0; }
  to   { transform: translateX(0);    opacity: 1; }
}

/* ==========================================================================
   Reduced motion — also calm the progress-bar pulse and toast slide-in
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .progress .bar.pulse,
  .toast { animation: none !important; }
}
