/* Block One — the visual system (P1a).
 *
 * One stylesheet, plain CSS, no build step. Everything is a token on :root;
 * components consume tokens and never restate a colour or a size.
 *
 * Reference: the Stripe Dashboard (user decision, 2026-09-22 — replaces the
 * FT/Bloomberg editorial brief). One sans, an indigo accent, white cards on
 * a cool grey page with 1px hairline borders, quiet greys for secondary text,
 * small dense type with tabular numbers. No gradients, shadows or glass.
 *
 * Chart colours live here too (--series-*, --regime-*) and static/js/charts.js
 * reads them off the computed style, so a palette change is a one-file edit.
 * The series palette is the dataviz reference instance (validated with its
 * six checks); regime colours were validated all-pairs / ordinal in P1a.
 */

:root {
  /* Type — one sans; a modular scale, ratio 1.2, base 14px. Steps are named
     by their exponent: fs-0 is body, fs-n1 one step down, fs-3 three up. */
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Ubuntu, sans-serif;
  --font-mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;
  --fs-n2: 0.786rem;   /* 11px — axis ticks, badges */
  --fs-n1: 0.857rem;   /* 12px — meta, table headers, small print */
  --fs-0:  1rem;       /* 14px — body, table cells */
  --fs-1:  1.143rem;   /* 16px — card titles */
  --fs-2:  1.429rem;   /* 20px — section headings */
  --fs-3:  1.714rem;   /* 24px — page title */
  --fs-4:  2rem;       /* 28px — the headline regime */
  --fs-5:  2.571rem;   /* 36px — hero figure */
  --lh-tight: 1.2;
  --lh-body: 1.5;

  /* Space — an 8px scale with one half-step. */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 16px;
  --sp-4: 24px;
  --sp-5: 32px;
  --sp-6: 48px;
  --sp-7: 64px;
  --measure: 72ch;      /* prose width */
  --page: 1200px;       /* content width */
  --radius: 6px;
  --radius-sm: 4px;

  /* Surfaces and ink: white cards on a cool grey page; ink in three weights;
     borders one shade off the surface. */
  --page-bg: #f6f8fa;
  --surface: #ffffff;
  --surface-2: #f7f8fa;   /* table header band, hover, chips */
  --ink: #30313d;
  --ink-2: #596171;
  --ink-3: #6b7280;   /* 4.83:1 on white, 4.54 on the page plane — AA for small text */
  --rule: #e3e8ee;
  --rule-strong: #d5dbe1;

  /* The one accent: Stripe's indigo. Links, the active control, focus. */
  --accent: #635bff;
  --accent-ink: #533afd;    /* the accent as text on white (AA) */
  --accent-wash: #eeedff;   /* the accent as a tint */

  /* Status — reserved meanings, never a series. Always paired with a word.
     Text on its own tint, as the Dashboard's badges do. */
  --status-good: #166b2e;
  --status-good-wash: #d7f7c2;
  --status-warn: #8f5000;
  --status-warn-wash: #fcedb9;
  --status-bad: #b3093c;
  --status-bad-wash: #ffe7f2;

  /* Chart series — the dataviz reference palette, fixed order, never cycled. */
  --series-1: #2a78d6;   /* blue */
  --series-2: #eb6834;   /* orange */
  --series-3: #1baf7a;   /* aqua */
  --series-4: #eda100;   /* yellow */
  --series-5: #e87ba4;   /* magenta */
  --series-6: #008300;   /* green */
  --series-7: #4a3aa7;   /* violet */
  --series-8: #e34948;   /* red */
  --series-wash: 0.10;   /* area fill opacity */

  /* Regime colours. The four-box maps (direction, surprise) share one set —
     same box, same colour — validated all-pairs: blue, orange, aqua, violet.
     Policy state is ordinal (a blue ramp, deeper = more extraordinary) with a
     neutral for the zero bound. The debt-cycle phases keep M15's intent:
     warm for the leveraging side, cool for the deleveraging side, lightness
     stepping with the phase, neutral for normalisation. */
  --regime-gu-iu: #eb6834;   /* growth up, inflation up — reflation, warm */
  --regime-gu-id: #1baf7a;   /* growth up, inflation down — the benign box */
  --regime-gd-iu: #4a3aa7;   /* growth down, inflation up — stagflation */
  --regime-gd-id: #2a78d6;   /* growth down, inflation down — cool */
  --regime-mp1: #86b6ef;
  --regime-mp2: #3987e5;
  --regime-mp3: #184f95;
  --regime-zero-bound: #c3c2b7;
  --regime-early-cycle: #f0a06e;
  --regime-bubble: #eb6834;
  --regime-top: #b8321a;
  --regime-contraction: #86b6ef;
  --regime-depression: #5598e7;
  --regime-pushing: #1c5cab;
  --regime-beautiful: #1baf7a;
  --regime-normalisation: #d9d8d0;
  /* M28, the short-term debt cycle. `contraction` is shared with the long
     cycle's phase map deliberately: it is the same condition read on a shorter
     horizon, and giving it two colours would imply two things. */
  --regime-expansion: #2f9e68;
  --regime-late-cycle: #e0913a;
  --regime-recovery: #3fa7a0;
}

/* --- Accessibility --------------------------------------------------------- */

.skip-link {
  position: absolute;
  left: -9999px;
  top: var(--sp-2);
  background: var(--surface);
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  padding: var(--sp-2) var(--sp-3);
  z-index: 100;
}
.skip-link:focus { left: var(--sp-3); }
.visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; }
}

/* --- Reset & base ------------------------------------------------------- */

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

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

body {
  margin: 0;
  background: var(--page-bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--fs-0);
  line-height: var(--lh-body);
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  font-weight: 600;
  line-height: var(--lh-tight);
  margin: 0;
  color: var(--ink);
  letter-spacing: -0.01em;
}
h1 { font-size: var(--fs-3); font-weight: 700; }
h2 { font-size: var(--fs-2); }
h3 { font-size: var(--fs-1); }
h4 { font-size: var(--fs-0); }

p { margin: 0 0 var(--sp-2); }
p:last-child { margin-bottom: 0; }

a { color: var(--accent-ink); text-decoration: none; }
a:hover, a:focus-visible { text-decoration: underline; text-underline-offset: 2px; }
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

small, .meta { font-size: var(--fs-n1); color: var(--ink-2); }
code { font-family: var(--font-mono); font-size: 0.92em; }
hr { border: 0; border-top: 1px solid var(--rule); margin: var(--sp-4) 0; }

button, input, select {
  font: inherit;
  color: inherit;
}
button, input[type="submit"] {
  background: var(--surface);
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  padding: var(--sp-1) var(--sp-3);
  font-weight: 500;
  cursor: pointer;
}
button:hover { border-color: var(--ink-3); }
button.primary { background: var(--accent); border-color: var(--accent); color: var(--surface); }
button.primary:hover { background: var(--accent-ink); border-color: var(--accent-ink); }
input[type="text"], input[type="email"], input[type="password"], select {
  background: var(--surface);
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  padding: var(--sp-1) var(--sp-2);
}

details > summary { cursor: pointer; color: var(--accent-ink); font-size: var(--fs-n1); font-weight: 500; }
details > summary:hover { text-decoration: underline; }
details[open] > summary { margin-bottom: var(--sp-2); }

/* --- Page frame ----------------------------------------------------------- */

.masthead {
  background: var(--surface);
  border-bottom: 1px solid var(--rule);
  /* Pinned (user, 2026-09-28): the long pages run to thousands of pixels and a
     reader deep in one had to scroll back to the top to go anywhere else.
     Opaque, because a translucent bar over a scrolling table is unreadable,
     and above the page so cards and charts do not ride over it. */
  position: sticky;
  top: 0;
  z-index: 50;
}
/* An in-page anchor otherwise lands with its heading hidden behind the pinned
   bar. 56px is the masthead's own min-height plus a little air. */
:target,
[id] { scroll-margin-top: calc(56px + var(--sp-3)); }
.masthead__inner {
  max-width: var(--page);
  margin: 0 auto;
  padding: var(--sp-2) var(--sp-4);
  min-height: 56px;
  display: flex;
  align-items: center;
  gap: var(--sp-3) var(--sp-4);
  flex-wrap: wrap;
}
.wordmark {
  font-weight: 700;
  font-size: var(--fs-1);
  color: var(--ink);
  letter-spacing: -0.02em;
  white-space: nowrap;
}
.wordmark:hover { text-decoration: none; }
.nav {
  display: flex;
  gap: var(--sp-1);
  align-items: center;
  margin-left: auto;
  font-size: var(--fs-n1);
  font-weight: 500;
  flex-wrap: wrap;
  justify-content: flex-end;
}
/* A hairline between the product pages and the staff ones. */
.nav__sep { width: 1px; align-self: stretch; margin: var(--sp-1) var(--sp-1); background: var(--rule); }
.nav a, .nav button {
  color: var(--ink-2);
  padding: var(--sp-1) var(--sp-2);
  border-radius: var(--radius);
}
.nav a:hover, .nav button:hover { color: var(--ink); background: var(--surface-2); text-decoration: none; }
.nav a[aria-current="page"] { color: var(--accent-ink); background: var(--accent-wash); }
.nav form { display: inline; }
.nav button { border: 0; background: none; font-weight: 500; }

main {
  max-width: var(--page);
  margin: 0 auto;
  padding: var(--sp-5) var(--sp-4) var(--sp-7);
}
footer.colophon {
  max-width: var(--page);
  margin: 0 auto;
  padding: var(--sp-4);
  color: var(--ink-3);
  font-size: var(--fs-n1);
}

/* Page head: title with its meta on the right. */
.page-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-4);
  flex-wrap: wrap;
  margin-bottom: var(--sp-4);
}
.page-head__text { max-width: var(--measure); }
.kicker {
  font-size: var(--fs-n1);
  font-weight: 500;
  color: var(--ink-3);
  margin-bottom: var(--sp-1);
}
.standfirst { color: var(--ink-2); margin: var(--sp-1) 0 0; }
.dateline { color: var(--ink-3); font-size: var(--fs-n1); text-align: right; }

/* Jump bar: in-page contents as a row of quiet links. */
.jumpbar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-3);
  padding: var(--sp-2) 0;
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  font-size: var(--fs-n1);
  font-weight: 500;
  margin-bottom: var(--sp-5);
}
.jumpbar a { color: var(--ink-2); }
.jumpbar a:hover { color: var(--accent-ink); }
.jumpbar__sep { color: var(--rule-strong); }

/* Sections: a heading and a one-line lede, then cards. */
.section { margin-bottom: var(--sp-6); }
.section__head { margin-bottom: var(--sp-3); }
.section__head h2 { margin-bottom: var(--sp-1); }
.section__lede { color: var(--ink-2); max-width: var(--measure); margin: 0; }
.section__head--row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; }
.section__head--row h2 a { color: inherit; }
.section__more { font-size: var(--fs-n1); font-weight: 500; }

/* Stat tiles: label, value, meta — the dashboard's gauge summary. */
.tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: var(--sp-3); }
.tiles--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }   /* six gauges read as two even rows */
.tiles--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }   /* a draft beside its citations */
.tile { display: flex; flex-direction: column; gap: var(--sp-1); color: inherit; }
.tile:hover { text-decoration: none; border-color: var(--rule-strong); }
.tile__label { font-size: var(--fs-n1); font-weight: 500; color: var(--ink-2); }
.tile__value { font-size: var(--fs-3); font-weight: 600; letter-spacing: -0.02em; line-height: 1.1; font-variant-numeric: normal; }
.tile__unit { font-size: var(--fs-n1); font-weight: 400; color: var(--ink-3); margin-left: 2px; }
.tile__meta { font-size: var(--fs-n1); color: var(--ink-3); }

/* Cards: white, hairline border, no shadow. */
.card {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: var(--sp-3) var(--sp-4);
  min-width: 0;
}
.card--table { padding: 0; overflow: hidden; }
.card--table > h3 { padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--rule); }
.section > .card + .card { margin-top: var(--sp-3); }

/* --- Tables --------------------------------------------------------------- */

table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-0);
  line-height: 1.35;
}
th, td {
  text-align: left;
  vertical-align: top;
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--rule);
}
thead th {
  font-size: var(--fs-n1);
  font-weight: 500;
  color: var(--ink-2);
  background: var(--surface-2);
  white-space: nowrap;
}
tbody tr:last-child td { border-bottom: 0; }
th.num, td.num { text-align: right; white-space: nowrap; }
tbody tr:hover td { background: var(--surface-2); }
td .meta { display: block; margin-top: 1px; }
.table--dense th, .table--dense td { padding: var(--sp-1) var(--sp-3); font-size: var(--fs-n1); }
.table-wrap { overflow-x: auto; }
.nowrap { white-space: nowrap; }

/* --- Badges --------------------------------------------------------------- */

.badge {
  display: inline-block;
  font-size: var(--fs-n2);
  font-weight: 500;
  line-height: 1.5;
  padding: 0 var(--sp-2);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--ink-2);
  white-space: nowrap;
}
.badge--accent { background: var(--accent-wash); color: var(--accent-ink); }
.badge--good { background: var(--status-good-wash); color: var(--status-good); }
.badge--warn { background: var(--status-warn-wash); color: var(--status-warn); }
.badge--bad { background: var(--status-bad-wash); color: var(--status-bad); }

/* --- Regime panels -------------------------------------------------------- */

.regime-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-3);
}
.regime-panel { min-width: 0; }
.regime-panel__head { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; margin-bottom: var(--sp-1); }
.regime-panel__head .meta { margin-left: auto; }
.regime-panel__question { color: var(--ink-2); font-size: var(--fs-n1); margin: 0 0 var(--sp-3); max-width: var(--measure); }

/* The current call: the label leads; the colour is a dot beside it. */
.regime-current {
  display: block;
  margin: 0 0 var(--sp-3);
  padding: 0;
  background: none;
}
.regime-current__lead { font-size: var(--fs-n1); color: var(--ink-3); display: block; }
.regime-current__label {
  display: block;
  font-size: var(--fs-2);
  font-weight: 600;
  line-height: var(--lh-tight);
  letter-spacing: -0.01em;
}
.regime-current__label::before {
  content: "";
  display: inline-block;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  margin-right: var(--sp-2);
  vertical-align: 0;
  background: var(--regime-c, var(--rule-strong));
}
.regime-current__meta { font-size: var(--fs-n1); color: var(--ink-2); display: block; margin-top: var(--sp-1); }

/* Axis readings: one row per axis — name and series, then value, direction
   and whether the call was carried inside the neutral band. */
.axes {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 2px var(--sp-3);
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-n1);
}
.axes__item { display: contents; }
.axes dt { color: var(--ink-2); font-weight: 500; }
.axes__series { color: var(--ink-3); font-weight: 400; margin-left: var(--sp-1); }
.axes dd { margin: 0; min-width: 0; }
.axes__value { font-weight: 600; color: var(--ink); }
.axes__carried { color: var(--ink-3); }

/* The strip: one cell per month, full history; thin, so full colour is a
   mark not a block. */
.regime-strip {
  display: flex;
  flex-wrap: nowrap;
  height: 12px;
  border: 0;
  border-radius: 2px;
  overflow: hidden;
}
.regime-cell { flex: 1 1 0; min-width: 0; background: var(--regime-c, var(--surface-2)); }
.regime-strip__range {
  display: flex;
  justify-content: space-between;
  font-size: var(--fs-n2);
  color: var(--ink-3);
  margin: var(--sp-1) 0 var(--sp-2);
}

/* Legend chips: a swatch beside a label, text in ink. */
.regime-legend { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3); margin: 0 0 var(--sp-2); font-size: var(--fs-n1); }
.regime-key { padding: 0; margin: 0; color: var(--ink-2); background: none; white-space: nowrap; }
.regime-key::before {
  content: "";
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 2px;
  margin-right: var(--sp-1);
  vertical-align: -1px;
  background: var(--regime-c, var(--surface-2));
}
td.regime-span { border-left: 3px solid var(--regime-c, var(--rule-strong)); }

/* The colour of each key. Every seeded regime key needs a rule here or its
   strip cells render blank (tests/test_regime_engine.py guards the set). */
.regime-growth_up_inflation_up { --regime-c: var(--regime-gu-iu); }
.regime-growth_up_inflation_down { --regime-c: var(--regime-gu-id); }
.regime-growth_down_inflation_up { --regime-c: var(--regime-gd-iu); }
.regime-growth_down_inflation_down { --regime-c: var(--regime-gd-id); }
.regime-growth_beat_inflation_beat { --regime-c: var(--regime-gu-iu); }
.regime-growth_beat_inflation_miss { --regime-c: var(--regime-gu-id); }
.regime-growth_miss_inflation_beat { --regime-c: var(--regime-gd-iu); }
.regime-growth_miss_inflation_miss { --regime-c: var(--regime-gd-id); }
.regime-mp1 { --regime-c: var(--regime-mp1); }
.regime-mp2 { --regime-c: var(--regime-mp2); }
.regime-mp3 { --regime-c: var(--regime-mp3); }
.regime-zero_bound_no_printing { --regime-c: var(--regime-zero-bound); }
.regime-early_cycle { --regime-c: var(--regime-early-cycle); }
.regime-bubble { --regime-c: var(--regime-bubble); }
.regime-top { --regime-c: var(--regime-top); }
.regime-contraction { --regime-c: var(--regime-contraction); }
.regime-depression { --regime-c: var(--regime-depression); }
.regime-pushing_on_a_string { --regime-c: var(--regime-pushing); }
.regime-beautiful_deleveraging { --regime-c: var(--regime-beautiful); }
.regime-normalisation { --regime-c: var(--regime-normalisation); }
.regime-expansion { --regime-c: var(--regime-expansion); }
.regime-late_cycle { --regime-c: var(--regime-late-cycle); }
.regime-recovery { --regime-c: var(--regime-recovery); }

/* About: the description paragraphs, prose width. */

/* --- Gauges & rules ------------------------------------------------------- */

.gauge-value { font-weight: 600; }

.rule-fired td { background: none; }
.rule-quiet .rule-message { color: var(--ink-2); }
.conditions { color: var(--ink-3); }
.conditions .true { color: var(--ink); }

/* --- Charts --------------------------------------------------------------- */

/* The container owns the height (Chart.js runs with maintainAspectRatio off),
   so a stacked panel gets the same plot area as the chart above it. */
:root { --chart-height: 300px; --chart-height-small: 210px; }
/* M25: the recession band. Deliberately weak. It is context behind the
   data, and anything stronger competes with the line it is there to
   explain. A token rather than a literal so a theme can retune it. */
:root { --recession-band: rgba(90, 98, 112, 0.12); }
.chart { position: relative; width: 100%; height: var(--chart-height); }
.chart--small { height: var(--chart-height-small); }   /* a change panel reads fine a little shorter */
.chart canvas { width: 100% !important; height: 100% !important; }
.chart-title { margin: var(--sp-4) 0 var(--sp-1); color: var(--ink-2); font-size: var(--fs-n1); font-weight: 500; }
.chart-note { margin: var(--sp-1) 0 0; color: var(--ink-3); }
.chart-help { margin-top: var(--sp-3); color: var(--ink-3); }

/* Control rows: one grid, so every label lines up in its own column. */
.controls {
  display: grid;
  grid-template-columns: 7.5rem minmax(0, 1fr);
  align-items: baseline;
  gap: var(--sp-1) var(--sp-3);
  font-size: var(--fs-n1);
  padding: var(--sp-1) 0;
}
.controls__label { color: var(--ink-3); }
.controls__field { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1) var(--sp-2); min-width: 0; }
.controls a { color: var(--ink-2); padding: 2px var(--sp-2); border-radius: var(--radius-sm); }
.controls a:hover { background: var(--surface-2); text-decoration: none; }
.controls a[aria-current="true"] { color: var(--accent-ink); background: var(--accent-wash); font-weight: 500; }
.controls .disabled { color: var(--rule-strong); padding: 2px var(--sp-2); }
.date-range, .compare-with { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.date-range label { display: inline-flex; align-items: center; gap: var(--sp-1); }
.date-range input[type="date"] { padding: 2px var(--sp-1); font-size: var(--fs-n1); }
.compare-with select { max-width: 22rem; font-size: var(--fs-n1); padding: 2px var(--sp-1); }
.compare-form input[type="text"] { min-width: 22rem; flex: 1 1 22rem; max-width: 40rem; }
.compare-form select { min-width: 10rem; }
button.small { padding: 2px var(--sp-2); font-size: var(--fs-n1); }
button.link { border: 0; background: none; padding: 0; color: var(--accent-ink); font-weight: 400; font-size: inherit; cursor: pointer; }
button.link:hover { text-decoration: underline; }

/* Chart page: the chart beside its About tile, tops aligned, same padding. */
.chart-layout { display: grid; grid-template-columns: minmax(0, 2.4fr) minmax(280px, 1fr); gap: var(--sp-3); align-items: start; }
.chart-main { display: flex; flex-direction: column; gap: var(--sp-3); min-width: 0; }   /* the chart and the Episodes card share the left column */
.chart-card { padding: var(--sp-3) var(--sp-4) var(--sp-4); }
.chart-card .controls + .controls { border-top: 1px solid var(--rule); }
.chart-card .chart { margin-top: var(--sp-3); }
.about { padding: var(--sp-3) var(--sp-4) var(--sp-4); margin: 0; }
.about h3 { margin-bottom: var(--sp-2); }
.about__description p { margin-bottom: var(--sp-2); }
.facts { margin: var(--sp-3) 0 0; font-size: var(--fs-n1); max-width: 44rem; }   /* a wide card must not fling dt and dd to opposite edges */
.facts > div { display: flex; justify-content: space-between; gap: var(--sp-3); padding: var(--sp-2) 0; border-top: 1px solid var(--rule); }
.facts dt { color: var(--ink-3); white-space: nowrap; }
.facts dd { margin: 0; text-align: right; }
.exports { margin-top: var(--sp-4); }
.exports dd { line-height: 1.6; }

/* Messages (Django messages framework) and the cockpit's capture forms. */
.messages { list-style: none; padding: 0; margin: 0 0 var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-1); }
.message { padding: var(--sp-2) var(--sp-3); border-radius: var(--radius); background: var(--surface-2); border: 1px solid var(--rule); font-size: var(--fs-n1); }
.message--success { background: var(--status-good-wash); color: var(--status-good); border-color: transparent; }
.message--error { background: var(--status-bad-wash); color: var(--status-bad); border-color: transparent; }
.message--info { background: var(--accent-wash); color: var(--accent-ink); border-color: transparent; }
.capture-item { padding: var(--sp-3) 0; border-top: 1px solid var(--rule); }
.capture-item__head { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2) var(--sp-3); margin-bottom: var(--sp-1); }
.capture-fields { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--sp-2); margin: var(--sp-2) 0; }
.capture-fields label { display: flex; flex-direction: column; gap: 2px; }
.capture-fields input { width: 100%; }
.capture-form { margin-top: var(--sp-2); }
.row-edit { display: flex; gap: var(--sp-1); align-items: center; }
.row-edit input[type="number"] { width: 7rem; }
.row-edit input[type="text"] { width: 10rem; }
.message--warning { background: var(--status-warn-wash); color: var(--status-warn); border-color: transparent; }

/* --- Forms (auth, billing) ------------------------------------------------
   Django's as_p output: <p><label/> <input/> <span class="helptext"/></p>.
   Labels stack above full-width inputs; help text and errors go quiet. */

.form-narrow { max-width: 26rem; margin: var(--sp-3) 0; }
.form-narrow p { margin: 0 0 var(--sp-3); }
.form-narrow label { display: block; font-weight: 500; margin-bottom: var(--sp-1); }
.form-narrow input:not([type="checkbox"]):not([type="submit"]) { display: block; width: 100%; }
.form-narrow .helptext { display: block; margin-top: var(--sp-1); font-size: var(--fs-n1); color: var(--ink-2); }
.form-narrow .helptext ul { margin: 0; padding-left: var(--sp-3); }
.form-narrow button[type="submit"] { background: var(--accent); border-color: var(--accent); color: var(--surface); }
.form-narrow button[type="submit"]:hover { background: var(--accent-ink); border-color: var(--accent-ink); }
.errorlist { color: var(--status-bad); list-style: none; padding: 0; margin: 0 0 var(--sp-2); font-size: var(--fs-n1); }

/* Home / marketing-ish bits: an even card row, a call to action, a price. */
.page-column { max-width: 46rem; margin-inline: auto; }
.page-column--auth { max-width: 30rem; }   /* the head and the form card share one centred width */
.card-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--sp-3); align-items: start; }
.cta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); margin-top: var(--sp-5); }
.button-link {
  display: inline-block;
  background: var(--accent);
  color: var(--surface);
  border-radius: var(--radius);
  padding: var(--sp-2) var(--sp-4);
  font-weight: 500;
}
.button-link:hover { background: var(--accent-ink); color: var(--surface); text-decoration: none; }
.price { font-size: var(--fs-1); margin-top: var(--sp-3); }

/* --- Responsive ----------------------------------------------------------- */

@media (max-width: 860px) {
  .table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .table-wrap table { min-width: 560px; }
  :root { --chart-height: 240px; --chart-height-small: 180px; }
  .controls { grid-template-columns: 1fr; row-gap: var(--sp-1); }
  .page-head { flex-direction: column; align-items: flex-start; }
  .tiles, .tiles--3 { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
  .chart-layout { grid-template-columns: 1fr; }
  main { padding: var(--sp-4) var(--sp-3) var(--sp-6); }
  .masthead__inner { padding: 0 var(--sp-3); }
  .nav { gap: 0; font-size: var(--fs-n1); }
  .regime-grid { grid-template-columns: 1fr; }
  .card { padding: var(--sp-3); }
  .dateline { text-align: left; }
}


/* --- A2: reports, the journal and the docket ------------------------------- */

/* Report bodies are a small Markdown subset (analysts/markdown.py), so only
   these tags can appear. Measure-limited: a brief is read, not scanned. */
.prose { max-width: var(--measure); }
.prose > * + * { margin-top: var(--sp-3); }
.prose h2 { font-size: var(--fs-2); margin-top: var(--sp-5); }
.prose h3 { font-size: var(--fs-1); margin-top: var(--sp-4); }
.prose ul { padding-left: var(--sp-4); }
.prose li + li { margin-top: var(--sp-1); }

.pager { display: flex; align-items: baseline; gap: var(--sp-3); margin-top: var(--sp-4); }
.pager .meta { margin-inline: auto; }

.empty { color: var(--ink-2); }

.status-good { color: var(--status-good); }
.status-bad { color: var(--status-bad); }

/* A reason field should take the room the short fields do not. */
.controls__field label.grow { flex: 1 1 22ch; }
.controls__field label.grow input { width: 100%; }

@media (max-width: 720px) {
  .tiles--2 { grid-template-columns: 1fr; }
}

/* --- Admin: the section bar and the home page's hierarchy ------------------
   Admin reached thirteen pages from a thirteen-tile grid, so any lateral move
   meant going back and scanning a wall. The bar makes any two pages one click
   apart; the home page leads with work and demotes inventory. */

.subnav {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-2) var(--sp-4);
  padding: var(--sp-2) 0 var(--sp-3);
  margin-bottom: var(--sp-4);
  border-bottom: 1px solid var(--rule);
  font-size: var(--fs-n1);
}
.subnav__home { font-weight: 600; }
.subnav__group { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2); }
/* Without a divider the four groups read as one long string of links, which
   is the wall again in a thinner font. */
.subnav__group + .subnav__group {
  border-left: 1px solid var(--rule);
  padding-left: var(--sp-4);
}
/* The group label orients without competing: this is a bar, not a menu. */
.subnav__label {
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: .04em;
  font-size: var(--fs-n2);
}
.subnav a { color: var(--ink-2); text-decoration: none; }
.subnav a:hover { color: var(--accent-ink); text-decoration: underline; }
.subnav a[aria-current="page"], .subnav .is-current {
  color: var(--ink);
  font-weight: 600;
  /* A hairline, not a shadow: P1's design system bans decoration outright,
     and a rule is the language this stylesheet already speaks. */
  border-bottom: 2px solid var(--accent);
  padding-bottom: 2px;
}

/* Work reads loud. Inventory reads quiet. That distinction is the whole fix. */
.needs-you { margin-bottom: var(--sp-5); }
.tile--alert { border-left: 3px solid var(--status-warn); }
.needs-you--clear { color: var(--ink-2); }
.needs-you--clear strong { color: var(--ink); }

.group__label { font-size: var(--fs-0); margin-bottom: var(--sp-1); }
.group__links { list-style: none; padding: 0; margin: var(--sp-3) 0 0; }
.group__links li + li { margin-top: var(--sp-2); }
.group__links li { display: flex; align-items: baseline; gap: var(--sp-2); }
/* The count sits after the link, in meta colour, so it can never be mistaken
   for the alert tiles' figure. */
.group__links .meta { margin-left: auto; }

@media (max-width: 720px) {
  .subnav { gap: var(--sp-1) var(--sp-3); }
  .subnav__label { width: 100%; }
}

/* The monthly ritual and the cadence notes are reference material on a page
   opened daily, so they collapse. Nothing is removed — frequency of use just
   stops fighting position on the page. */
.section__collapse > summary {
  cursor: pointer;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-2) var(--sp-3);
  padding: var(--sp-2) 0;
  border-bottom: 1px solid var(--rule);
}
.section__collapse > summary h2 { display: inline; margin: 0; }
.section__collapse > summary .meta { flex: 1 1 24ch; }
.section__collapse[open] > summary { margin-bottom: var(--sp-3); }

/* --- The move panel: an action names its consequence ----------------------
   It rendered raw database values in alphabetical order, so from review the
   first option was "send it back". Each move now states what it costs, and a
   blocked one is shown with its reason rather than hidden — an operator who
   cannot see "publish" never learns that claim-check is what stands in the
   way. */
.moves { list-style: none; padding: 0; margin: var(--sp-3) 0; }
.move + .move { margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--rule); }
.move label { display: flex; align-items: baseline; gap: var(--sp-2); cursor: pointer; }
.move__label { font-weight: 600; }
.move__hint,
.move__blocked { display: block; margin-left: var(--sp-4); font-size: var(--fs-n1); }
.move__hint { color: var(--ink-2); }
.move__blocked { color: var(--status-bad); margin-top: var(--sp-1); }
.move--blocked .move__label { color: var(--ink-3); }

/* The principal's notes form (/admin/notes/). A real form with sections, not
   the one-line filter bar `.controls` is for: labels sit above their fields
   and each section reads top to bottom. */
.note-form { display: flex; flex-direction: column; gap: var(--sp-4); }
.note-form h2 { margin: 0; }
.note-form__section { border: 0; margin: 0; padding: 0; min-width: 0;
  display: flex; flex-direction: column; gap: var(--sp-3); }
.note-form__section + .note-form__section { border-top: 1px solid var(--rule); padding-top: var(--sp-4); }
/* Floated, so the legend lays out like a heading inside the flex column. */
.note-form__section > legend { float: left; width: 100%; padding: 0;
  font-size: var(--fs-1); font-weight: 600; color: var(--ink); }
.note-form__field { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; max-width: 34rem; }
.note-form__field--wide { max-width: none; }
.note-form__label { font-size: var(--fs-n1); font-weight: 500; color: var(--ink-2); }
.note-form__hint { font-size: var(--fs-n1); font-weight: 400; color: var(--ink-3); margin: 0; }
.note-form textarea { width: 100%; font: inherit; line-height: var(--lh-body); }
.note-form__row { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: var(--sp-3); }
.note-form__choices { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4); }
.note-form__choices label { display: inline-flex; align-items: center; gap: var(--sp-1); cursor: pointer; }
.note-form__actions { display: flex; }
.note-errors { border-left: 3px solid var(--status-bad); }
.note-errors h2 { margin-top: 0; color: var(--status-bad); }

/* Show only what the chosen kind of call needs. Plain CSS: where :has is not
   supported every part simply shows, and the form still works. */
.note-form:has(#call-none:checked) .note-form__asset,
.note-form:has(#call-none:checked) .note-form__event,
.note-form:has(#call-none:checked) .note-form__timing,
.note-form:has(#call-none:checked) .note-form__basis,
.note-form:has(#call-asset:checked) .note-form__event,
.note-form:has(#call-event:checked) .note-form__asset { display: none; }

/* A dropdown that holds checkboxes: <details> so it opens and closes with no
   script, a floating panel so a long list never pushes the form down. */
.multi { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; position: relative; }
.multi__box { position: relative; }
/* The site's disclosure style (a link-like summary that gains a margin when
   open) is wrong for a dropdown: opening one would nudge the form down. */
.multi__box[open] > .multi__summary { margin-bottom: 0; }
.multi__summary { font-size: var(--fs-0); font-weight: 400; }
.multi__summary:hover { text-decoration: none; border-color: var(--ink-3); }
.multi__summary { list-style: none; cursor: pointer; display: flex; align-items: center;
  justify-content: space-between; gap: var(--sp-2); padding: 6px var(--sp-2);
  border: 1px solid var(--rule-strong); border-radius: var(--radius-sm); background: var(--surface);
  color: var(--ink-2); }
.multi__summary::-webkit-details-marker { display: none; }
.multi__summary::after { content: ""; width: 7px; height: 7px; border-right: 1.5px solid var(--ink-3);
  border-bottom: 1.5px solid var(--ink-3); transform: rotate(45deg) translateY(-2px); flex: none; }
.multi__box[open] .multi__summary { border-color: var(--accent); outline: 2px solid var(--accent-wash); }
.multi__box[open] .multi__summary::after { transform: rotate(-135deg) translateY(-2px); }
.multi__panel { position: absolute; z-index: 20; top: calc(100% + 4px); left: 0; right: 0;
  min-width: 18rem; max-height: 20rem; overflow-y: auto; padding: var(--sp-1) 0;
  background: var(--surface); border: 1px solid var(--ink-3); border-radius: var(--radius); }
.multi__group { margin: var(--sp-2) var(--sp-3) var(--sp-1); font-size: var(--fs-n2); font-weight: 600;
  letter-spacing: 0.02em; text-transform: uppercase; color: var(--ink-3); }
.multi__option { display: flex; align-items: baseline; gap: var(--sp-2); padding: 5px var(--sp-3);
  font-size: var(--fs-n1); cursor: pointer; }
.multi__option:hover { background: var(--surface-2); }
/* A choice that cannot be added to what is ticked (the compare page, M30): shown,
   so the reader sees it exists, but plainly unavailable, with the reason on hover. */
.multi__option.is-disabled { color: var(--ink-3); cursor: not-allowed; }
.multi__option.is-disabled:hover { background: none; }
/* One pill per chosen series in the compare page's series field (M30). */
.chips { display: flex; flex-wrap: wrap; gap: var(--sp-1); min-width: 0; }
.chip { display: inline-flex; align-items: center; gap: 2px; padding: 1px 4px 1px var(--sp-2);
  border-radius: 999px; background: var(--accent-wash); color: var(--accent-ink);
  font-size: var(--fs-n1); font-weight: 500; line-height: 1.6; white-space: nowrap; }
.chip:not(:has(.chip__remove)) { padding-right: var(--sp-2); }
.chip__remove { border: 0; background: none; color: inherit; cursor: pointer; padding: 0 4px;
  font-size: var(--fs-0); line-height: 1; border-radius: 999px; }
.chip__remove:hover, .chip__remove:focus-visible { background: var(--surface); }
.compare-series { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; width: 100%; }
.compare-series .multi { flex: 1 1 22rem; max-width: 40rem; }
.note-form select { max-width: 100%; }

/* M11 Scenarios: one small chart per gauge, as many to a row as fit. */
.projection-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
  gap: var(--sp-3); }
.projection-chart { margin: 0; min-width: 0; }
.projection-chart figcaption { font-size: var(--fs-n1); font-weight: 500; color: var(--ink-2);
  margin-bottom: var(--sp-1); }

/* M11 Scenarios, made lighter (user, 2026-10-11): the answer first, the
   depth folded into cards that open on demand, the form folded to one line
   once a scenario has run. */
.scenario-run, .scenario-answer, .scenario-answer ~ .card, .scenario-answer ~ details,
.note-errors { margin-top: var(--sp-3); }
.scenario-run > summary { display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-3); list-style: none; color: var(--ink); font-size: var(--fs-0); font-weight: 500; }
.scenario-run > summary::-webkit-details-marker { display: none; }
.scenario-run > summary:hover { text-decoration: none; }
.scenario-run__restated { min-width: 0; }
.scenario-run__change { color: var(--accent-ink); font-size: var(--fs-n1); white-space: nowrap; }
.scenario-run[open] .scenario-run__change { display: none; }
.scenario-run[open] > summary { margin-bottom: var(--sp-3); }
.scenario-form__steps { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: var(--sp-3) var(--sp-4); }
.scenario-form__steps .note-form__section + .note-form__section { border-top: 0; padding-top: 0; }

.scenario-answer { border-color: var(--rule-strong); }
.scenario-answer__head { display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-2); flex-wrap: wrap; }
.scenario-answer__head h2 { margin: 0; }
.scenario-answer__level { margin: var(--sp-2) 0 0; font-size: var(--fs-1); }
.scenario-answer__points { margin: var(--sp-3) 0 var(--sp-2); padding-left: 1.1em; display: grid;
  gap: var(--sp-2); line-height: 1.5; max-width: 72ch; }
.chip--moderate { background: var(--status-good-wash); color: var(--status-good); }
.chip--low { background: var(--status-warn-wash); color: var(--status-warn); }
.chip--verylow, .chip--none { background: var(--status-bad-wash); color: var(--status-bad); }

.chart-key { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4); margin: var(--sp-2) 0 var(--sp-3);
  padding: 0; list-style: none; font-size: var(--fs-n1); color: var(--ink-2); }
.chart-key li { display: inline-flex; align-items: center; gap: var(--sp-1); }
.chart-key__line { display: inline-block; width: 22px; border-top: 2px solid var(--series-1); }
.chart-key__line--without { border-top: 2px dashed var(--series-3); }
.chart-key__line--flat { border-top: 2px dotted var(--series-2); }
.chart-key__shade { display: inline-block; width: 14px; height: 10px; background: var(--surface-2);
  border-right: 1px solid var(--ink-3); }
.fold-inline { margin-top: var(--sp-3); }

details.fold > summary { display: flex; flex-direction: column; gap: 2px; list-style: none;
  color: var(--ink); font-size: var(--fs-0); }
details.fold > summary::-webkit-details-marker { display: none; }
details.fold > summary:hover { text-decoration: none; }
.fold__title { font-weight: 600; }
.fold__title::before { content: "\25B8"; display: inline-block; width: 1.1em; color: var(--ink-3);
  transition: transform 0.15s; }
details.fold[open] .fold__title::before { transform: rotate(90deg); }
.fold__hint { font-size: var(--fs-n1); font-weight: 400; color: var(--ink-3); padding-left: 1.1em; }
details.fold[open] > summary { margin-bottom: var(--sp-3); }
details.fold .table-wrap { overflow-x: auto; }
tr.is-muted td { color: var(--ink-3); }
@media (prefers-reduced-motion: reduce) { .fold__title::before { transition: none; } }

/* M31: the Episodes card. The in-progress episode's row carries the same
   weight as its line on the chart. */
.episodes h3 { margin: 0; }
.episodes tr.is-current td { font-weight: 600; }

/* The relationship map (user, 2026-10-11): every indicator as a node, the
   declared relationships as arrows, the calculated-from links faint. The
   canvas pans and zooms inside its own box, so the page never scrolls
   sideways. */
.relmap { display: flex; flex-direction: column; gap: var(--sp-3); }
.relmap h2 { margin: 0; }
.relmap__counts { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-5); font-variant-numeric: tabular-nums; }
.relmap__counts b { display: block; font-size: 1.25rem; font-weight: 600; color: var(--ink); }
.relmap__counts span { font-size: var(--fs-n1); color: var(--ink-3); }
.relmap__controls { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-4); font-size: var(--fs-n1); }
.relmap__controls label { display: inline-flex; align-items: center; gap: var(--sp-1); cursor: pointer; }
.relmap__controls input[type=search] { min-width: 0; width: 15rem; max-width: 100%; }
.relmap__zoom { display: inline-flex; gap: var(--sp-1); }
.relmap__legend { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4); font-size: var(--fs-n1); color: var(--ink-2); }
.relmap__legend i { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: var(--sp-1); vertical-align: -1px; }
.relmap__legend i.line { width: 20px; height: 0; border-radius: 0; border-top: 2px solid; vertical-align: 3px; }
.relmap__canvas { position: relative; height: min(75vh, 760px); min-height: 380px; border: 1px solid var(--rule); border-radius: var(--radius); background: var(--surface); overflow: hidden; touch-action: none; }
.relmap__canvas svg { display: block; width: 100%; height: 100%; cursor: grab; }
.relmap__canvas svg:active { cursor: grabbing; }
.relmap__hint { position: absolute; left: var(--sp-3); bottom: var(--sp-2); margin: 0; font-size: var(--fs-n1); color: var(--ink-3); pointer-events: none; }
.relmap__node { cursor: pointer; outline: none; }
.relmap__node text { font-size: 9px; fill: var(--ink-2); paint-order: stroke; stroke: var(--surface); stroke-width: 3px; pointer-events: none; }
.relmap__node:focus-visible path, .relmap__node.is-selected path { stroke: var(--ink); stroke-width: 2px; }
.relmap__cluster { font-weight: 600; fill: var(--ink-3); text-anchor: middle; letter-spacing: 0.04em; text-transform: uppercase; pointer-events: none; }
.relmap .is-dim { opacity: 0.1; }
.relmap__detail .cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); gap: var(--sp-4); }
.relmap__detail .cols > div { min-width: 0; }
.relmap__detail h3 { margin: 0 0 var(--sp-2); font-size: var(--fs-n1); text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-3); }
.relmap__detail ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
.relmap__detail li { line-height: 1.45; }
.relmap__detail button.link { background: none; border: 0; padding: 0; font: inherit; color: var(--accent-ink); text-decoration: underline; text-underline-offset: 2px; cursor: pointer; text-align: left; }

/* P2h: the Operations page. Four independent panels, spaced as sections. */
.ops { margin-top: var(--sp-5); }
.ops h2 { margin-bottom: var(--sp-1); }
