/* FERC Audit Explorer — "public record, periwinkle" (DESIGN.md §15; spec Part C).
   The treatment is a regulatory ledger, not a pastel feed: hairlines over boxes,
   stamps over pills, restraint over palette. Every colour below is derived from
   the periwinkle anchor by a deliberate hue relationship — see the spec's C1
   table. Contrast for every text/bg pair is asserted by tests/test_palette.py, so
   changing a value here without re-running the suite will fail loudly. */

:root {
  /* ---- Brand / surface: periwinkle-tinted neutrals (anchor hue 240°) ---- */
  --bg: #f5f5fb;          /* paper: 3–4% anchor wash — cool, never warm cream */
  --surface: #ffffff;
  --surface-2: #ececf6;
  --border: #d9d9ec;
  --rule: #d9d9ec;        /* hairline — the primary separator (C3) */
  --text: #191930;        /* ink: anchor-tinted near-black, deeper for ledger contrast */
  --text-muted: #5c5c78;

  /* ---- Accent — periwinkle. Chrome, interaction, selection ONLY (C1). ----
     Findings/recs/status never borrow it, or "flagged" reads as "link". */
  --accent: #5b5bd6;
  --accent-hover: #4a4ac2;
  --accent-weak: #e7e7fb;
  --accent-line: #c7c7f0;
  --on-accent: #ffffff;   /* text on a filled accent (5.37:1) */

  /* ---- Semantic — meaning, not brand (DESIGN.md §3.1) ----
     finding = near-complement (≈38°) → maximum hue distance from brand, so
     "flagged" reads instantly. rec = split-complement teal (≈185°), moved off
     the old 212° steel blue that collided with the 240° anchor (F15).
     NB the spec's #a8690a measures 4.48:1 on white — just under AA. Darkened one
     step to #a2650a (4.77:1); same ochre, actually passes. */
  --status-finding: #a2650a;
  --status-rec: #0e7a83;
  --status-resolved: #20794d;
  /* Filled-stamp foregrounds: paired with the semantic hue as background. */
  --on-status: #ffffff;

  /* ---- Categorical — distinguish without ranking (DESIGN.md §3.1).
     Even-spaced around the wheel: 240 / 185 / 38 / 300 / 150, all ~45% sat, so
     they sit visually BETWEEN brand and semantic saturation and never read as
     status. Charts only. ---- */
  --cat-1: #6f6fc4;
  --cat-2: #3f8f96;
  --cat-3: #b3853f;
  --cat-4: #9a5fa8;
  --cat-5: #4f8f6b;

  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, "Helvetica Neue", Arial, sans-serif;
  --font-serif: "Charter", "Source Serif 4", "Iowan Old Style", "Palatino", Georgia, "Times New Roman", serif;
  --font-mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;

  --shadow-rest: 0 1px 2px rgba(25, 25, 48, 0.05);
  --shadow-hover: 0 4px 18px rgba(91, 91, 214, 0.14);
  --radius: 8px;          /* C3: 12 → 8 — a record, not a bubble */

  font-feature-settings: "tnum";
}

[data-theme="dark"] {
  --bg: #12121e;
  --surface: #1d1d2c;
  --surface-2: #26263a;
  --border: #31314a;
  --rule: #31314a;
  --text: #ececf6;
  --text-muted: #a2a2be;
  --accent: #9393f2;
  --accent-hover: #a6a6f6;
  --accent-weak: #2a2a48;
  --accent-line: #3c3c5e;
  /* On dark the accent is LIGHT periwinkle — white on it is 2.73:1 (this is how
     .pill.solid and the skip link shipped). Filled accent takes dark ink: 6.8:1. */
  --on-accent: #12121e;
  --status-finding: #e3a84e;
  --status-rec: #5bc4ce;
  --status-resolved: #6fc795;
  /* On dark, the semantic hues are light — a filled stamp needs dark ink. */
  --on-status: #12121e;
  --cat-1: #9393f2;
  --cat-2: #5bc4ce;
  --cat-3: #e3a84e;
  --cat-4: #c98fd6;
  --cat-5: #6fc795;
  --shadow-rest: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-hover: 0 6px 22px rgba(0, 0, 0, 0.5);
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); }
a:hover { color: var(--accent-hover); }

[hidden] { display: none !important; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--accent);
  color: var(--on-accent);
  padding: 8px 14px;
  border-radius: 0 0 8px 0;
  z-index: 100;
}
.skip-link:focus { left: 0; }
/* #main only takes focus programmatically (via the skip link) — it must not draw
   a focus ring around the whole results region when it does. */
#main:focus { outline: none; }

.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;
}

/* ---------- Hero (E1 entry layer) ---------- */
.hero { max-width: 1180px; margin: 18px auto 0; padding: 0 16px; }
.hero-title {
  font-family: var(--font-serif);
  font-size: clamp(21px, 4vw, 26px);
  line-height: 1.25;
  margin: 0 0 6px;
}
/* The credibility stat: corpus counts + freshness, never a claim. */
.trust-line {
  margin: 0 0 12px;
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--text-muted);
}
.trust-line strong { color: var(--text); font-variant-numeric: tabular-nums; }
.hero-search { max-width: 620px; }
.search-input {
  width: 100%;
  font-size: 16px; /* prevents iOS zoom */
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-rest);
}
.search-input::placeholder { color: var(--text-muted); }
.search-input:focus-visible { border-color: var(--accent); }

/* ---------- Header ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 16px;
  background: linear-gradient(180deg, var(--accent-weak), var(--surface));
  border-bottom: 1px solid var(--border);
  backdrop-filter: saturate(1.1);
}
.brand { display: flex; align-items: center; gap: 12px; min-width: 0; }
.brand-mark {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: 10px;
  background: var(--accent-weak);
  border: 1px solid var(--accent-line);
  color: var(--accent);            /* the pylon (stroke: currentColor) is periwinkle */
  flex: none;
}
.brand-mark svg { width: 24px; height: 24px; display: block; }
.brand-text { display: flex; flex-direction: column; min-width: 0; }
.brand-text strong { font-family: var(--font-serif); font-size: 18px; letter-spacing: 0.01em; }
.brand-sub { color: var(--text-muted); font-size: 12.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.icon-btn {
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  border-radius: 8px;
  font-size: 20px;
  cursor: pointer;
  flex: none;
}
.icon-btn:hover { background: var(--surface-2); }

/* ---------- Collection tabs ---------- */
.tabs {
  display: flex;
  gap: 6px;
  max-width: 1180px;
  margin: 14px auto 0;
  padding: 0 16px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tab {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex: none;
  min-height: 44px;
  padding: 8px 16px;
  border: 1px solid var(--border);
  border-bottom-width: 2px;
  background: var(--surface);
  color: var(--text-muted);
  border-radius: 10px 10px 0 0;
  font-family: var(--font-serif);
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}
.tab:hover { background: var(--surface-2); color: var(--text); }
.tab[aria-selected="true"] {
  /* -hover, not --accent: the label is text on --accent-weak, where plain
     --accent measures 4.40:1 (under AA). See tests/test_palette.py. */
  color: var(--accent-hover);
  border-color: var(--accent-line);
  border-bottom-color: var(--accent);
  background: var(--accent-weak);
}
.tab-count {
  font-family: var(--font-sans);
  font-size: 12px;
  font-weight: 700;
  color: var(--text-muted);
  background: var(--surface-2);
  border-radius: 999px;
  padding: 1px 8px;
  min-width: 20px;
  text-align: center;
}
.tab[aria-selected="true"] .tab-count { color: var(--accent-hover); background: var(--surface); }

/* ---------- KPI strip ---------- */
.kpi-strip {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
  max-width: 1180px;
  margin: 16px auto 0;
  padding: 0 16px;
}
.kpi {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 14px;
  box-shadow: var(--shadow-rest);
}
.kpi-num { display: block; font-family: var(--font-serif); font-size: 26px; font-weight: 700; line-height: 1.1; }
.kpi-label { display: block; font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-muted); margin-top: 2px; }

/* ---------- Intro + how to use ---------- */
.intro { max-width: 1180px; margin: 14px auto 0; padding: 0 16px; }
.intro-lead {
  margin: 0 0 10px;
  font-family: var(--font-serif);
  font-size: 16.5px;
  line-height: 1.45;
  color: var(--text);
}
.how-to {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  box-shadow: var(--shadow-rest);
}
.how-to summary {
  list-style: none;
  cursor: pointer;
  padding: 10px 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  font-family: var(--font-serif);
  font-size: 14px;
  font-weight: 600;
  color: var(--text-muted);
}
.how-to summary::-webkit-details-marker { display: none; }
.how-to[open] summary { color: var(--text); }
.how-to[open] summary .chev { transform: rotate(180deg); }
.how-to-body { padding: 2px 16px 14px; font-size: 13.5px; color: var(--text); }
.how-to-body ul { margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 6px; }

/* ---------- Top patterns band (the headline trends) ---------- */
.patterns-band { max-width: 1180px; margin: 18px auto 0; padding: 0 16px; }
.band-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
.band-title { font-family: var(--font-serif); font-size: 17px; margin: 0; }
.band-note { color: var(--text-muted); font-size: 12.5px; margin: 0; }

.patterns-rail {
  list-style: none;
  margin: 0;
  padding: 4px 0 6px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(195px, 1fr));
  gap: 10px;
}
.patterns-rail > li { min-width: 0; }
.pattern-card {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: 6px;
  text-align: left;
  font: inherit;
  cursor: pointer;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 11px 12px;
  box-shadow: var(--shadow-rest);
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.pattern-card:hover { box-shadow: var(--shadow-hover); border-color: var(--accent-line); }
.pattern-name {
  font-weight: 600;
  font-size: 13px;
  line-height: 1.3;
  color: var(--text);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.pattern-desc {
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--text-muted);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.pattern-stat { font-size: 12px; color: var(--text-muted); }
.pattern-count { font-family: var(--font-serif); font-size: 18px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
.pattern-track { height: 5px; background: var(--surface-2); border-radius: 2px; overflow: hidden; margin-top: auto; }
/* The bar encodes DATA (report count), so it takes a categorical tone, not brand.
   Periwinkle returns only for the pressed (selected) state — that IS chrome. */
.pattern-bar { display: block; height: 100%; background: var(--cat-1); border-radius: 2px; }
.pattern-card[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-weak); }
.pattern-card[aria-pressed="true"] .pattern-bar { background: var(--accent); }

/* ---------- Corpus trends (charts over the baked aggregates) ---------- */
.trends-band { max-width: 1180px; margin: 18px auto 0; padding: 0 16px; }
.trends-grid { display: grid; grid-template-columns: 1.5fr 1fr 1fr; gap: 10px; padding: 4px 0 6px; }
.trend-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 14px;
  box-shadow: var(--shadow-rest);
  min-width: 0;
}
.trend-card-title {
  margin: 0 0 11px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--text-muted);
}

/* Vertical columns — the year timeline. */
.trend-cols { display: flex; align-items: flex-end; gap: 5px; height: 104px; }
.trend-col { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: 3px; }
.trend-col-val { font-size: 10.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
/* One measure over time — a single categorical tone, not the brand accent. */
.trend-col-bar { width: 100%; max-width: 24px; min-height: 0; background: var(--cat-1); border-radius: 2px 2px 0 0; }
.trend-col-yr { font-size: 10px; color: var(--text-muted); white-space: nowrap; }

/* Horizontal bars — the few-category breakdowns. */
.trend-rows { display: flex; flex-direction: column; gap: 9px; }
.trend-row { display: grid; grid-template-columns: 88px minmax(0, 1fr) auto; align-items: center; gap: 8px; }
.trend-row-label { font-size: 12px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.trend-track { height: 8px; background: var(--surface-2); border-radius: 2px; overflow: hidden; }
.trend-bar { display: block; height: 100%; background: var(--cat-1); border-radius: 2px; }
/* Category ≠ status (DESIGN.md §3.1): electric/gas/oil and the function
   breakdown are distinguished, never ranked. Assigned by index in renderTrends. */
.trend-bar.cat-1 { background: var(--cat-1); }
.trend-bar.cat-2 { background: var(--cat-2); }
.trend-bar.cat-3 { background: var(--cat-3); }
.trend-bar.cat-4 { background: var(--cat-4); }
.trend-bar.cat-5 { background: var(--cat-5); }
/* C3 — values at the bar ends, in mono. */
.trend-row-val { font-family: var(--font-mono); font-size: 11.5px; color: var(--text); font-variant-numeric: tabular-nums; min-width: 22px; text-align: right; }
.trend-note { margin: 9px 0 0; font-size: 10.5px; line-height: 1.4; color: var(--text-muted); }

@media (max-width: 1023px) {
  .trends-grid { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
}
@media (max-width: 560px) {
  .trends-grid { grid-template-columns: 1fr; }
}

/* ---------- Coverage by jurisdiction (A9 extension, BACKLOG item 14) ---------- */
.juris-coverage {
  max-width: 1180px;
  margin: 14px auto 0;
  padding: 0 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  box-shadow: var(--shadow-rest);
}
.juris-coverage summary {
  list-style: none;
  cursor: pointer;
  padding: 10px 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  font-family: var(--font-serif);
  font-size: 14px;
  font-weight: 600;
  color: var(--text-muted);
}
.juris-coverage summary::-webkit-details-marker { display: none; }
.juris-coverage[open] summary { color: var(--text); }
.juris-coverage[open] summary .chev { transform: rotate(180deg); }
.juris-note { margin: 0; padding: 0 16px 10px; font-size: 12.5px; line-height: 1.4; color: var(--text-muted); }
.juris-table-wrap { margin: 0 16px 14px; max-height: 320px; overflow-y: auto; border: 1px solid var(--rule); border-radius: 8px; }
.juris-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.juris-table th {
  text-align: left;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  padding: 8px 10px;
  border-bottom: 1px solid var(--rule);
  background: var(--surface-2);
  position: sticky;
  top: 0;
}
.juris-table td, .juris-table th[scope="row"] {
  padding: 6px 10px;
  border-bottom: 1px solid var(--rule);
  font-variant-numeric: tabular-nums;
}
.juris-table th[scope="row"] { font-weight: 500; color: var(--text); text-align: left; }
.juris-table td { font-family: var(--font-mono); color: var(--text); text-align: right; width: 90px; }
.juris-table tr:last-child td, .juris-table tr:last-child th { border-bottom: 0; }
/* Reference-only jurisdictions (0 parsed findings) recede — the eye should land
   on rows with real content first; the juris-note above explains why 0 isn't a gap. */
.juris-row-empty td:last-child { color: var(--text-muted); }
.juris-row-empty th[scope="row"] { color: var(--text-muted); }

/* ---------- Active filters (shows why the stream is narrowed) ---------- */
.active-filters { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-bottom: 12px; }
.active-chip {
  font: inherit;
  font-size: 12px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px 4px 10px;
  border: 1px solid var(--accent-line);
  background: var(--accent-weak);
  color: var(--accent-hover);
  border-radius: 999px;
  cursor: pointer;
}
.active-chip:hover { border-color: var(--accent); }
.active-chip-x { font-size: 11px; opacity: 0.85; }
.active-clear {
  font: inherit;
  font-size: 12px;
  background: none;
  border: 0;
  cursor: pointer;
  color: var(--text-muted);
  text-decoration: underline;
  padding: 4px 6px;
}
.active-clear:hover { color: var(--accent); }

/* ---------- Layout ---------- */
.layout {
  max-width: 1180px;
  margin: 16px auto 0;
  padding: 0 16px 48px;
  display: grid;
  grid-template-columns: 220px minmax(0, 1fr);
  gap: 20px;
  align-items: start;
}

.filters {
  position: sticky;
  top: 70px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px;
  box-shadow: var(--shadow-rest);
}

/* Sheet header (Done/close) + backdrop — only used when .filters is a bottom
   sheet (mobile/tablet). Hidden on desktop, where the rail is always visible. */
.sheet-header { display: none; }
.filters-backdrop { display: none; }

.field { border: 0; margin: 0 0 16px; padding: 0; }
.field-label {
  display: block;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  margin-bottom: 7px;
  font-weight: 600;
}
.chip-options { display: flex; flex-wrap: wrap; gap: 6px; }

/* A4 — search-within-facet (the company tail is hundreds long). */
.facet-search {
  width: 100%;
  font-size: 16px; /* prevents iOS zoom */
  padding: 7px 9px;
  margin-bottom: 7px;
  border: 1px solid var(--rule);
  border-radius: 6px;
  background: var(--surface-2);
  color: var(--text);
}
.facet-note { margin: 6px 0 0; font-size: 11px; color: var(--text-muted); }
/* Company names are long — let their chips wrap instead of overflowing the rail. */
#company-options .filter-chip { white-space: normal; text-align: left; }

/* ---------- Theme panel (A5) ---------- */
/* The systemic-vs-one-off answer, above the stream it describes. */
.theme-panel {
  border: 1px solid var(--rule);
  border-left: 3px solid var(--status-finding);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 14px 16px;
  margin-bottom: 14px;
}
.tp-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.tp-title { font-family: var(--font-serif); font-size: 18px; margin: 0; }
.tp-clear { font-size: 12px; }
.tp-desc { margin: 6px 0 0; font-size: 13.5px; color: var(--text-muted); max-width: 70ch; }
.tp-stats { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 22px; margin-top: 12px; }
.tp-stat { display: flex; flex-direction: column; gap: 2px; }
.tp-num { font-family: var(--font-serif); font-size: 24px; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
.tp-lab { font-size: 11px; text-transform: uppercase; letter-spacing: 0.07em; color: var(--text-muted); }
/* Sparkline — reports per year carrying this issue. */
.spark { display: flex; align-items: flex-end; gap: 3px; height: 40px; }
.spark-col { display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: 2px; }
.spark-bar { display: block; width: 9px; background: var(--cat-1); border-radius: 1px; }
.spark-yr { font-size: 9px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.tp-companies { margin-top: 12px; }
.tp-co-list { list-style: none; margin: 6px 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.tp-co-list li { display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--rule); border-radius: 3px; padding: 3px 8px; }
.tp-co { font: inherit; font-size: 12.5px; background: none; border: 0; padding: 0; color: var(--accent); cursor: pointer; text-align: left; }
.tp-co:hover { color: var(--accent-hover); text-decoration: underline; }
.tp-co-n { font-family: var(--font-mono); font-size: 11px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.tp-keywords { margin: 12px 0 0; font-size: 11px; color: var(--text-muted); }
.tp-keywords code { font-family: var(--font-mono); font-size: 10.5px; }

/* A4 — "More on {company}" row inside an open thread. */
.more-on { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--rule); }
.more-lab { font-size: 11px; text-transform: uppercase; letter-spacing: 0.07em; color: var(--text-muted); }
.more-links { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.more-link {
  font: inherit;
  font-size: 12.5px;
  min-height: 32px;
  padding: 4px 10px;
  border: 1px solid var(--rule);
  border-radius: 3px;
  background: transparent;
  color: var(--accent);
  cursor: pointer;
}
.more-link:hover { border-color: var(--accent); background: var(--accent-weak); }

/* Year presets (E1) — shortcuts that select the year chips beneath them. */
.preset-options { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 7px; }
.preset-chip {
  font: inherit;
  font-size: 12px;
  display: inline-flex;
  align-items: center;
  min-height: 32px; /* presets live in the touch filter sheet — see BACKLOG (B4) */
  padding: 4px 10px;
  border: 1px dashed var(--border);
  background: transparent;
  color: var(--text-muted);
  border-radius: 6px;
  cursor: pointer;
}
.preset-chip:hover { border-style: solid; border-color: var(--accent); color: var(--accent); }
.filter-chip {
  font: inherit;
  font-size: 12.5px;
  padding: 5px 10px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  border-radius: 999px;
  cursor: pointer;
  text-align: left;
}
.filter-chip:hover { background: var(--surface-2); }
.filter-chip[aria-pressed="true"] {
  background: var(--accent-weak);
  border-color: var(--accent);
  color: var(--accent-hover);
  font-weight: 600;
}
.chip-count { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.filter-chip[aria-pressed="true"] .chip-count { color: var(--accent-hover); }

.btn-secondary {
  font: inherit;
  font-size: 13px;
  padding: 8px 12px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--accent);
  border-radius: 8px;
  cursor: pointer;
  min-height: 44px; /* touch target (DESIGN §7) */
}
.btn-secondary:hover { background: var(--surface-2); }
/* E1 — one primary CTA per view (DESIGN.md §8.1): in a thread that's the official
   source document. Everything beside it is a way to carry the record away. */
.btn-secondary.primary { border-color: var(--accent); color: var(--accent-hover); font-weight: 600; }
.btn-secondary.primary:hover { background: var(--accent-weak); }
/* A secondary action that shouldn't compete with the source/citation CTAs. */
.btn-secondary.subtle { color: var(--text-muted); }
.btn-secondary.subtle:hover { color: var(--accent); }
.link-btn { background: none; border: 0; color: var(--accent); cursor: pointer; font: inherit; text-decoration: underline; padding: 0; }

/* ---------- Stream toolbar ---------- */
/* Tapping a pattern scrolls here; clear the sticky header (filters sit at 70px). */
.stream-wrap { scroll-margin-top: 70px; }
.stream-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
}
.result-count { color: var(--text-muted); font-size: 13px; }
.filters-toggle { display: none; }
.toolbar-spacer { flex: 1; }
.sort-label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-muted); font-weight: 600; }
.sort-select {
  font: inherit;
  font-size: 13px;
  padding: 6px 8px;
  min-height: 36px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
}
/* Back-to-top rides the mobile bottom bar; the desktop toolbar doesn't need it. */
.to-top { display: none; }

/* B1 — the append trigger for the next page of cards/rows. */
.stream-sentinel { height: 1px; }

/* A3 — view toggle (Stream | Ledger). */
.view-toggle { display: inline-flex; border: 1px solid var(--rule); border-radius: 6px; overflow: hidden; }
.view-btn {
  font: inherit;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  min-height: 36px;
  padding: 4px 10px;
  border: 0;
  background: var(--surface);
  color: var(--text-muted);
  cursor: pointer;
}
.view-btn + .view-btn { border-left: 1px solid var(--rule); }
.view-btn:hover { background: var(--surface-2); color: var(--text); }
.view-btn[aria-pressed="true"] { background: var(--accent-weak); color: var(--accent-hover); }

/* ---------- Ledger (A3) — the analyst scan mode ---------- */
.ledger-wrap { border: 1px solid var(--rule); border-radius: var(--radius); background: var(--surface); overflow-x: auto; }
/* table-layout:fixed, not auto (found 2026-08-09 — see ISSUES.md): auto sizes
   every column from its WIDEST cell across ALL rows, so one long value on any
   collection (a dual docket, a full-sentence doc_type) silently blows the
   whole table past its container — 1650px wide on the state_audit tab even
   at a 1280px desktop viewport, despite the "tuned to fit 1180px" comment
   this rule used to carry. Fixed layout makes column width a CSS decision,
   independent of content; every column that can carry a long value truncates
   via a nested *-text span (text-overflow on a bare <td> clips visually but
   still leaks its intrinsic width into the table's own scrollWidth).

   Column widths below are PERCENTAGES that sum to exactly 100%, not px (found
   in code review, 2026-08-10 — two dead ends first): px + width:100% makes
   fixed layout treat each column's px as a RATIO to redistribute whenever the
   widths don't sum to exactly the container's current width — since the
   container varies continuously across a breakpoint range, no single px set
   is exactly right at every width in that range, so columns render larger or
   smaller than specified everywhere except the one width they were tuned
   against (a column measured "still short" no matter how much its own px was
   raised, because raising it changed the sum and every OTHER column's share
   too). width:auto instead of 100% is worse — Chromium abandons the fixed-
   layout fast path entirely without a definite outer width and falls back to
   full content-based sizing, i.e. the original bug. Percentages sidestep
   this: they scale WITH the container by construction, so a set calibrated
   against the tightest width in a breakpoint's range only gets MORE
   comfortable at wider widths in that same range — no redistribution
   surprise, because summing to 100% is exactly what "no rescaling needed"
   means for this algorithm. */
.ledger { width: 100%; table-layout: fixed; border-collapse: collapse; font-size: 13px; }
.ledger th {
  text-align: left;
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--text-muted);
  padding: 9px 10px;
  border-bottom: 1px solid var(--rule);
  background: var(--surface-2);
  position: sticky;
  top: 0;
  z-index: 1;
  white-space: nowrap;
  /* Defense-in-depth (2026-08-10 code review): a header's own label has no
     truncating span the way body cells do, so a width miscalibration used to
     paint text straight past the cell — invisible in a screenshot because the
     next header's opaque background painted over it. This doesn't affect
     table-layout:fixed's column-width math (that's driven by box size, not
     paint), only what happens to content that doesn't fit the box. */
  overflow: hidden;
  text-overflow: ellipsis;
}
/* One line per row: a ledger that wraps is just a worse card list. Anything that
   might overflow truncates with its full value in a title attribute. */
.ledger td { padding: 7px 10px; border-bottom: 1px solid var(--rule); vertical-align: middle; white-space: nowrap; }
.ledger tr:last-child td { border-bottom: 0; }
.lg-type { color: var(--text-muted); }
.lg-row { cursor: pointer; }
.lg-row:hover { background: var(--accent-weak); }
.lg-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* Same ratepayer-harm axis as the cards — one amber edge tick, one meaning. */
.lg-row.has-cost td:first-child { box-shadow: inset 3px 0 0 var(--status-finding); }
.lg-date { white-space: nowrap; color: var(--text-muted); font-variant-numeric: tabular-nums; }
/* Widths are tuned so the table FITS a 1180px layout without horizontal scroll —
   a ledger you have to scroll sideways to read defeats its own purpose. Company
   + Issues are the elastic ones; both truncate with the full value in `title`.
   Truncation lives on a nested block span (.lg-co-text), not the <td> itself —
   text-overflow set directly on a table-cell box clips visually but its
   intrinsic content width can still leak into the table's layout/scrollWidth
   (found 2026-08-09 chasing a tablet ledger-overflow regression — see ISSUES.md). */
/* Column widths below are PERCENTAGES (sum 100%) calibrated against MEASURED
   max content (Playwright, all 5 collections, 2026-08-10 — not eyeballed) at
   the desktop tier's reference width (~906px, the ledger-wrap at a 1280px
   viewport — this range is bounded above by .layout's own 1180px max-width,
   so it barely varies past that). The 4 numeric/date columns have no
   truncation mechanism, so they're sized to fit their real max content +
   padding; Company/Docket/Type/Issues truncate via a nested *-text span with
   the full value in `title`, so their share is a density choice, not a hard
   floor. The tablet media query below uses a DIFFERENT percentage set,
   calibrated against ITS tier's tightest width instead — one set can't serve
   both tiers, since 220px of desktop Company density would starve the
   numeric columns at 640px. */
.lg-date { width: 12%; }          /* ~110px @906: max "May 15, 2025"-class content 85px + padding */
.lg-co { font-weight: 600; width: 24%; }
.lg-co-text { display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
.lg-docket { font-family: var(--font-mono); font-size: 11.5px; width: 11%; }
.lg-docket-text { display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; user-select: all; }
.lg-type { width: 7%; }
.lg-type-text { display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
.lg-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; width: 5.7%; }  /* Recs: ~52px @906, max content 32px */
.lg-findings { width: 6.8%; }     /* ~62px @906; "Find." header: max content 36px */
.lg-amt { font-family: var(--font-mono); font-size: 12px; width: 9.6%; }  /* ~87px @906, max content 36px, dollar figures like "$109M" need more */
.lg-amt-text { display: inline-block; max-width: 100%; overflow: hidden; text-overflow: clip; white-space: nowrap; }
/* Issues column: one truncated line (full list in the title). Its share +
   the nested .lg-theme-text span keep it from pushing other columns off-screen. */
.lg-themes { color: var(--text-muted); font-size: 12px; width: 23.8%; overflow: hidden; }
.lg-theme-text { display: inline-block; max-width: 185px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
.lg-more { color: var(--text-muted); font-variant-numeric: tabular-nums; }

/* ---------- Stream / cards ---------- */
.stream { display: flex; flex-direction: column; gap: 14px; }

/* C3 — hairlines over boxes: no resting shadow, shadow only on hover/open. */
.card {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  overflow: hidden;
  transition: box-shadow 120ms ease, border-color 120ms ease;
}
.card[open] { border-color: var(--accent-line); box-shadow: var(--shadow-rest); }
.card:hover { box-shadow: var(--shadow-hover); }

.card-summary {
  list-style: none;
  cursor: pointer;
  padding: 14px 16px;
  display: block;
}
.card-summary::-webkit-details-marker { display: none; }

/* A2 — the ratepayer-harm axis gets a card-level edge tick: the highest-salience
   axis for the general reader, readable without opening the thread. */
.card.has-cost { border-left: 3px solid var(--status-finding); }

.source-line { display: flex; align-items: flex-start; gap: 10px; }
/* C3 — a square plate with a serif initial, not a circle avatar. A circle avatar
   is social-feed furniture; a square monogram reads as a record stamp. */
.avatar {
  width: 34px; height: 34px; flex: none;
  border-radius: 3px;
  background: var(--surface-2);
  color: var(--text-muted);
  display: grid; place-items: center;
  font-family: var(--font-serif);
  font-weight: 700; font-size: 16px;
  border: 1px solid var(--rule);
}
.source-meta { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 1px; }
.company { font-weight: 600; font-size: 15px; }
/* F9 — segments wrap BETWEEN themselves, never mid-phrase ("Issued ⏎ Sep 8, 2025"). */
.sub-meta { color: var(--text-muted); font-size: 12.5px; font-variant-numeric: tabular-nums; display: flex; flex-wrap: wrap; gap: 0 6px; }
.sub-bit { white-space: nowrap; }
.sub-bit + .sub-bit::before { content: "· "; }
/* Dockets are identifiers analysts copy — mono + select-all is the records-tool cue. */
.docket-bit { font-family: var(--font-mono); font-size: 11.5px; user-select: all; }
.disclosure { color: var(--text-muted); font-size: 13px; flex: none; }
.card[open] .disclosure .chev { transform: rotate(180deg); }
.chev { display: inline-block; transition: transform 200ms ease; }

/* A2 — the mechanical subject line (F1: this style existed but was never rendered). */
.headline {
  font-family: var(--font-serif);
  font-size: 15px;
  color: var(--text);
  margin: 8px 0 8px;
}
/* A2 — theme chips are the best scent for both personas. */
.card-themes { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
.more-tag { cursor: help; font-variant-numeric: tabular-nums; }

/* Lazily-loaded thread placeholder (detail file still in flight). */
.thread-pending { padding: 14px 16px; font-size: 13px; }
.thread-pending p { margin: 0; }

/* ---------- Stamps (C3) ----------
   Status markers are "stamps", not pastel pills: uppercase, letterspaced, square-ish,
   1px-bordered. Outline is the default; only the two SEMANTIC states fill (finding
   amber, resolved green), so a filled stamp always means something. This is what
   kills the pastel-pill field that read as "AI dashboard" (F14). */
.chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.pill {
  /* B4 — 10.5px was below a comfortable reading minimum. */
  font-size: 11px;
  font-weight: 600;
  padding: 2px 7px;
  border: 1px solid var(--rule);
  border-radius: 3px;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  white-space: nowrap;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
/* The findings count is the card's headline fact — filled, but in ink-on-paper
   terms, not brand: periwinkle stays chrome (C1). */
.pill.solid { background: var(--text); color: var(--bg); border-color: var(--text); }
.pill.outline { color: var(--text-muted); }
/* .kind carries the doc_type verbatim for non-FERC collections (state audits/
   rate cases/reference docs) — free prose, not a short fixed badge (FERC's is
   just "FA"/"PA"). Some run 90+ chars ("Pipeline-safety technical/compliance
   inspection report (standard gas distribution inspection)"); nowrap on that
   forced a flex-item min-content width the whole page couldn't shrink below,
   overflowing horizontally at 375px. Found 2026-08-09 UAT'ing the state_audit
   tab at mobile width — every other .pill variant is a genuinely short badge,
   so this is the one exception, not a reason to drop nowrap everywhere. */
.pill.kind { color: var(--text); border-color: var(--text-muted); white-space: normal; }
.pill.func { color: var(--text-muted); }
.pill.muted { color: var(--text-muted); border-style: dashed; }
/* Money is data, not status: ink + mono tabular numerals, no hue (spec C1). */
.pill.amount {
  color: var(--text);
  font-family: var(--font-mono);
  letter-spacing: 0.02em;
  cursor: help;
}
/* The ratepayer-harm axis — one hue, filled (matches the card edge tick). */
.pill.cost {
  background: var(--status-finding);
  color: var(--on-status);
  border-color: var(--status-finding);
  cursor: help;
}

/* ---------- Thread (expanded) ---------- */
.thread { padding: 0 16px 16px; border-top: 1px solid var(--border); }
.thread-root {
  background: var(--surface-2);
  border-radius: 8px;
  padding: 10px 12px;
  margin: 14px 0;
  font-size: 13.5px;
}
.thread-root dl { margin: 0; display: grid; grid-template-columns: 110px 1fr; gap: 4px 10px; }
.thread-root dt { color: var(--text-muted); font-size: 12px; }
.thread-root dd { margin: 0; }
.muted-cell { color: var(--text-muted); font-style: italic; }

/* C3 — full-width hairlines between findings (the left connector stays periwinkle;
   it's chrome, not meaning). */
.finding {
  position: relative;
  padding: 12px 0 12px 20px;
  border-top: 1px solid var(--rule);
}
.finding::before {
  content: "";
  position: absolute;
  left: 5px; top: 18px; bottom: 8px;
  width: 2px;
  background: var(--accent-line);
  border-radius: 2px;
}
.finding-head { display: flex; align-items: baseline; gap: 8px; }
.dot { width: 9px; height: 9px; border-radius: 50%; flex: none; position: relative; top: 3px; margin-left: -20px; }
.dot.finding-dot { background: var(--status-finding); }
.dot.other-dot { background: var(--text-muted); }
/* C2 — finding titles go SERIF: the content becomes editorial while the chrome
   stays sans. This is the single clearest "these are documents, not UI" signal. */
.finding-title { font-family: var(--font-serif); font-weight: 700; font-size: 15px; }
.finding-flag { font-size: 11px; text-transform: uppercase; letter-spacing: 0.07em; color: var(--text-muted); }
/* A1 — per-finding permalink. The pilcrow is the long-standing convention for
   "link to this passage" (Wikipedia/MDN); it stays quiet until the finding is
   hovered or it's keyboard-focused. */
.finding-link {
  font: inherit;
  font-size: 13px;
  line-height: 1;
  padding: 2px 5px;
  border: 0;
  border-radius: 3px;
  background: none;
  color: var(--text-muted);
  cursor: pointer;
  opacity: 0;
  transition: opacity 90ms ease, color 90ms ease;
}
.finding:hover .finding-link,
.finding-link:focus-visible { opacity: 1; }
.finding-link:hover { color: var(--accent); background: var(--accent-weak); }
.finding-link.copied { opacity: 1; color: var(--status-resolved); }
/* Touch has no hover — never hide the only affordance behind one (DESIGN §7). */
@media (hover: none) {
  .finding-link { opacity: 1; min-height: 44px; min-width: 44px; }
}
.finding-summary { margin: 6px 0 0; font-size: 13.5px; color: var(--text); }

/* Per-finding taxonomy tags + the ratepayer-harm ("cost to customers") badge. */
.finding-tags { display: flex; flex-wrap: wrap; gap: 5px; margin: 8px 0 0; }
/* Theme tags stay quiet — they're taxonomy, not status. Outline, no fill. */
.finding-tag {
  font-size: 11px;
  line-height: 1.45;
  padding: 1px 7px;
  border-radius: 3px;
  background: transparent;
  color: var(--text-muted);
  border: 1px solid var(--rule);
}
.finding-tag.cost-tag {
  background: transparent;
  color: var(--status-finding);
  border-color: var(--status-finding);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
/* C1 — money is data, not status: ink + mono, no hue. It used to borrow the
   brand accent, which made a dollar figure look like a link. */
.finding-tag.amount-tag {
  background: transparent;
  color: var(--text);
  border-color: var(--text-muted);
  font-family: var(--font-mono);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
  cursor: help;
}

.recs { margin: 10px 0 0; padding: 0; list-style: none; }
.rec {
  position: relative;
  padding: 7px 0 7px 18px;
  font-size: 13px;
  color: var(--text);
}
.rec::before {
  content: "";
  position: absolute;
  left: 0; top: 12px;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--status-rec);
}
.rec-num { font-weight: 600; color: var(--status-rec); font-variant-numeric: tabular-nums; }
.rec-page { color: var(--text-muted); font-size: 0.85em; font-variant-numeric: tabular-nums; white-space: nowrap; cursor: help; }

.thread-footer { margin-top: 14px; display: flex; flex-wrap: wrap; gap: 8px; }

/* ---------- No-findings state (reports not yet machine-extracted) ---------- */
.no-findings {
  margin: 14px 0 0;
  padding: 12px 14px;
  background: var(--surface-2);
  border: 1px dashed var(--border);
  border-radius: 8px;
  font-size: 13px;
  color: var(--text-muted);
}
.no-findings p { margin: 0; }
.no-findings strong { color: var(--text); }

/* ---------- Empty state ---------- */
.empty-state {
  text-align: center;
  color: var(--text-muted);
  padding: 40px 16px;
  background: var(--surface);
  border: 1px dashed var(--border);
  border-radius: var(--radius);
}

/* ---------- Footer ---------- */
.site-footer {
  max-width: 1180px;
  margin: 0 auto;
  padding: 24px 16px 48px;
  color: var(--text-muted);
  font-size: 12.5px;
  border-top: 1px solid var(--border);
}
.site-footer p { margin: 0 0 6px; }

/* ---------- Responsive ---------- */
@media (max-width: 1023px) {
  /* minmax(0, 1fr), not bare 1fr: a bare 1fr track has an implicit auto
     minimum (won't shrink below its content's min-content width), so a long
     unbreakable token anywhere in the stream (a doc_type, a docket id) could
     force this single-column track past the viewport — the same class of bug
     as the .pill.kind fix above, caught by the same 2026-08-09 mobile UAT
     pass on the state_audit tab. minmax(0, 1fr) is what the desktop 2-column
     rule above already uses for exactly this reason. */
  .layout { grid-template-columns: minmax(0, 1fr); }
  /* Patterns become a horizontal swipe rail so trends stay one compact row, not a tall stack. */
  .patterns-rail {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: 230px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
  }
  .patterns-rail > li { scroll-snap-align: start; }
  .filters {
    position: fixed;
    inset: auto 0 0 0;
    top: auto;
    max-height: 75vh;
    overflow: auto;
    border-radius: 14px 14px 0 0;
    z-index: 40;
    transform: translateY(100%);
    transition: transform 200ms ease;
    box-shadow: 0 -6px 24px rgba(0, 0, 0, 0.18);
    padding-bottom: max(14px, env(safe-area-inset-bottom));
  }
  .filters.open { transform: translateY(0); }
  .filters-toggle { display: inline-flex; align-items: center; }
  /* Everything <=1023px is a touch surface (this range is exactly where the rail
     becomes a sheet/panel), so these take a full touch target — not just on
     phones. The 44px floor is non-negotiable (CLAUDE.md, DESIGN.md §7); the
     documented sub-44 exception in ISSUES.md covers compact filter/active-filter
     chips only, and none of these are that: the view toggle is a primary control
     in the same toolbar as the sort, and .more-link / .tp-co are navigation. */
  .sort-select { min-height: 44px; }
  .view-btn { min-height: 44px; }
  .more-link { min-height: 44px; }
  .tp-co { min-height: 44px; display: inline-flex; align-items: center; }

  /* Bottom-sheet close affordances: a Done button + a tap-to-dismiss backdrop. */
  .sheet-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin: 0 0 12px;
  }
  .sheet-title { font-family: var(--font-serif); font-weight: 600; font-size: 15px; }
  .sheet-close {
    font: inherit;
    font-weight: 600;
    font-size: 14px;
    min-height: 44px;
    padding: 8px 18px;
    background: var(--accent);
    color: var(--on-accent);
    border: 0;
    border-radius: 8px;
    cursor: pointer;
  }
  .sheet-close:hover { background: var(--accent-hover); }
  .filters-backdrop:not([hidden]) {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(15, 15, 30, 0.45);
    z-index: 39;
  }
}

/* Tablet (B3) — a bottom sheet feels phone-y at 768px and hides the stream it's
   filtering. Slide the rail in from the left instead, over the filters' own space. */
@media (min-width: 640px) and (max-width: 1023px) {
  .filters {
    inset: 0 auto 0 0;
    top: 0;
    width: min(320px, 82vw);
    max-height: none;
    border-radius: 0 14px 14px 0;
    transform: translateX(-100%);
    box-shadow: 6px 0 24px rgba(0, 0, 0, 0.18);
    padding-bottom: 14px;
  }
  .filters.open { transform: translateX(0); }
}

/* Ledger (A3) narrow-column widths — its OWN range, not tied to the filters
   breakpoint above: the base (desktop) widths only actually fit once the
   two-column .layout's content area is wide enough (~1180px viewport, where
   .layout's own max-width caps and the content column stabilizes at its
   widest). Below that, the .layout grid keeps shrinking the ledger-wrap right
   up to 1023px — including right past 1023px too, at e.g. 1024px, a common
   iPad-landscape width — so this covers the whole 640-1179px span, not just
   the tablet single-column range. Found scanning every collection across a
   width sweep, not just the two widths the original test checked (2026-08-09). */
@media (min-width: 640px) and (max-width: 1179px) {
  /* A SEPARATE percentage set from the base rule, calibrated against THIS
     tier's tightest width — 606px available at exactly 640px (LEDGER_MIN_
     WIDTH, the ledger's minimum activation width), not the more comfortable
     ~1160px at 1179px. Same logic as the base rule (sum to 100%, no
     redistribution surprise), different target: the desktop percentages give
     Company/Issues ~24% each for readability, which at 606px starves the 4
     hard-content columns (date/find./recs/$, no truncation mechanism) below
     what their real max content needs. Sums to 100%: 18+16.5+10.7+7.4+10.2+
     8.6+13.5+15.1 (2026-08-10, replacing a px-based attempt that fought
     table-layout:fixed's ratio behavior instead of using it — see the base
     .ledger rule's comment for the full story). */
  .lg-date { width: 18%; }
  .lg-co { width: 15%; }
  .lg-docket { width: 10%; }
  .lg-type { width: 7%; }
  .lg-num { width: 8.5%; }
  .lg-findings { width: 10%; }
  .lg-amt { width: 13%; }
  .lg-themes { width: 14%; }
  /* Sums to 95.5%, not 100% — a small intentional margin, not a workaround:
     the actual root cause of the residual overflow this margin was first
     added to paper over was .lg-themes lacking its own overflow:hidden (see
     the base rule) — the "+N" more-themes badge, a sibling of the width-
     capped .lg-theme-text span, had nothing stopping it from painting past
     the cell. Once fixed there, 0 overflow at every width including 640
     (LEDGER_MIN_WIDTH) — verified across all 5 collections x 11 widths
     (640-1440px), not just the two the test suite checks (2026-08-10). */
  .lg-theme-text { max-width: 76px; }
}

/* Phone (B3) — the toolbar is fixed to the bottom so Filters/sort/count/top stay
   reachable from card #10 (they used to scroll away). Same DOM, CSS only. */
@media (max-width: 639px) {
  .stream-toolbar {
    position: fixed;
    inset: auto 0 0 0;
    z-index: 35;
    margin: 0;
    padding: 8px 12px max(8px, env(safe-area-inset-bottom));
    background: var(--surface);
    border-top: 1px solid var(--border);
    box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.1);
    gap: 8px;
  }
  .sort-label { display: none; } /* the select's own options read as the label */
  .to-top {
    display: grid;
    place-items: center;
    width: 44px; height: 44px;
    flex: none;
    font: inherit;
    font-size: 17px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
    color: var(--text);
    cursor: pointer;
  }
  /* Clear the fixed bar so the last card and the footer stay reachable. */
  .layout { padding-bottom: 84px; }
  .site-footer { padding-bottom: 96px; }
}

@media (max-width: 560px) {
  .kpi-strip { grid-auto-flow: column; grid-template-columns: none; grid-auto-columns: 60%; overflow-x: auto; scroll-snap-type: x mandatory; }
  .kpi { scroll-snap-align: start; }
  .brand-sub { display: none; }
  /* Tighten so trends + first cards are reachable with minimal scroll. */
  .intro-lead { font-size: 15.5px; }
  .card-summary { padding: 12px 13px; }
  .thread { padding: 0 13px 14px; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
}
