/* ═══════════════════════════════════════════════════════════════════════════
   IOCE Voting Influence Corruption — International Typographic Style
   ---------------------------------------------------------------------------
   Grid, grotesque, hairline rules, zero radius. Red is the only loud colour and
   it is reserved for one meaning: money spent against a candidate. Blue marks
   figures that are MODELLED rather than measured, so epistemic status is legible
   before a word is read.
   Contrast verified: ink 18.9:1, ink-2 7.3:1, red 4.7:1, blue 6.6:1 on paper.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  --paper:    #FEFCF7;   /* warm; red holds 4.56:1 */
  --panel:    #F7F2E8;
  --ink:      #111111;
  --ink-2:    #565656;
  --rule:     #D5D5D5;
  --rule-hi:  #111111;
  --red:      #E2231A;   /* measured · attack spending · primary accent */
  --blue:     #0B5FA5;   /* modelled · scenario figures */
  --sand:     #E8E4D9;   /* neutral fill for low values */
  --purple:   #4C1D95;   /* authorial voice · reserved for the sidebar quotation
                            so it never competes with red (measured) or blue
                            (modelled) inside the data pages. 10.6:1 on paper,
                            9.0:1 for the dark counterpart. */
  --green:    #14532D;   /* publisher disclosure link · 9.1:1 on paper */
  --ochre:    #9A4A08;   /* money from INSIDE the electorate - 6.10:1 */
  --teal:     #0F766E;   /* money from OUTSIDE the electorate - 5.34:1 */
  --display: 'Fraunces', Georgia, 'Times New Roman', serif;
  --body:    'Inter', 'Helvetica Neue', Helvetica, Arial, sans-serif;

  --gutter: 28px;
  /* Outer page margin: the distance from the window edge to the first letter of
     the sidebar. ~3 character widths at the 15px body size. Set as a token so
     the header and the layout grid cannot drift apart — before 2026-08-11 the
     sidebar had no left padding at all and its text sat flush against the
     window edge on every page above 900px. Tried at 40px (~5 characters) the
     same day and narrowed to 24px. One value serves every width: at 40px a
     phone lost a fifth of its screen to margins and needed an override, which
     is exactly the kind of second hard-coded number that caused the earlier
     header-offset drift. */
  --edge: clamp(24px, 3.2vw, 56px);
  /* Measured height of .site-header. Was hard-coded twice, as 46px for the
     table head and 58px for the sidebar; both were guesses and disagreed. */
  --header-h: 46px;
  --unit: 8px;
}

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

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

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--body);
  font-size: 15px;
  line-height: 1.6;
  font-feature-settings: "tnum" 0;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.02em;
}

a { color: var(--ink); text-decoration: underline; text-underline-offset: 2px;
    text-decoration-thickness: 1px; text-decoration-color: var(--rule); }
a:hover { text-decoration-color: var(--red); color: var(--red); }
:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }

/* ── Header ───────────────────────────────────────────────────────────────── */
.site-header {
  border-bottom: 1px solid var(--rule-hi);
  padding: 12px var(--edge);
  display: flex; align-items: baseline; gap: 20px; flex-wrap: wrap;
  position: sticky; top: 0; z-index: 100; background: var(--paper);
}
.back-link, .breadcrumb {
  font-family: var(--display); font-size: 10px; font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase;
}
.back-link { color: var(--ink); text-decoration: none; }
.back-link::before { content: "\2190\00a0"; }
.back-link:hover { color: var(--red); }
.breadcrumb { color: var(--ink-2); }
.breadcrumb a { color: var(--ink-2); text-decoration: none; }
.breadcrumb a:hover { color: var(--red); }
.breadcrumb span { margin: 0 6px; }
/* Names the theme it switches *to*, so the label is an instruction rather than
   a status the reader has to decode. */
.theme-toggle {
  margin-left: auto; font-family: var(--display); font-size: 9px; font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-2);
  background: none; border: 1px solid var(--rule); padding: 4px 9px;
  cursor: pointer; border-radius: 0;
}
.theme-toggle:hover { color: var(--red); border-color: var(--red); }
/* Date stamp, right-justified alongside the theme toggle. The auto margin has
   to move onto the date — leaving it on BOTH would split the free space
   between them and strand the date mid-header instead of beside the button. */
.header-date {
  margin-left: auto; font-family: var(--display); font-size: 9px; font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-2);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.header-date + .theme-toggle { margin-left: 0; }

/* ── Pager ────────────────────────────────────────────────────────────────── */
/* Every page carried the same five footer links, which told a reader nothing
   about where they were in the section. This gives it a reading order. */
.pager {
  display: grid; grid-template-columns: 1fr 1fr; gap: 1px;
  background: var(--rule); border: 1px solid var(--rule); margin-top: 48px;
}
.pager a {
  background: var(--paper); padding: 14px 16px; text-decoration: none; color: var(--ink);
  display: block; min-width: 0;
}
.pager a:hover { color: var(--red); }
.pager-next { text-align: right; }
.pager span {
  display: block; font-family: var(--display); font-size: 9px; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-2);
  margin-bottom: 5px;
}
.pager b { font-weight: 600; font-size: 13.5px; line-height: 1.3; }
/* A lone "next" must stay in the right-hand cell, or the last page in the
   section reads as if it were the first. */
.pager-next:only-child { grid-column: 2; }
@media (max-width: 560px) {
  .pager { grid-template-columns: 1fr; }
  .pager-next, .pager-next:only-child { text-align: left; grid-column: 1; }
}

/* ── Mobile section nav ───────────────────────────────────────────────────── */
/* Desktop keeps the sidebar; this exists only for the widths where the sidebar
   is pushed below the article. Closed by default, so it costs one line. */
.mobile-nav { display: none; }
@media (max-width: 900px) {
  .mobile-nav {
    display: block; padding: 0 var(--edge) 4px;
    border-bottom: 1px solid var(--rule-hi); background: var(--paper);
  }
  .mobile-nav summary {
    font-family: var(--display); font-size: 10px; font-weight: 600;
    letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink);
    padding: 11px 0; cursor: pointer; list-style: none;
  }
  .mobile-nav summary::-webkit-details-marker { display: none; }
  .mobile-nav summary::after { content: "+"; float: right; font-size: 13px; line-height: 1; }
  .mobile-nav[open] summary::after { content: "\2212"; }
  .mn-group {
    font-family: var(--display); font-size: 9.5px; font-weight: 700;
    letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-2);
    margin: 10px 0 2px;
  }
  .mobile-nav .side-nav { margin-bottom: 6px; }
  .mn-pub a { color: var(--green); font-weight: 600; }
}

/* ── Layout: content first in DOM, sidebar placed left by grid ────────────── */
.layout {
  display: grid;
  grid-template-columns: 232px minmax(0, 1fr);
  gap: 0;
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 var(--edge);
  align-items: start;
}
/* Sticky and taller than the window is a trap: the column pins at the top and
   everything past the fold becomes unreachable. Since the disclosure block was
   added on 2026-08-15 the sidebar routinely exceeds viewport height, so it
   scrolls within itself. Released back to natural flow below 900px, where the
   column is static and sits under the content. */
.sidebar { order: 1; grid-column: 1; position: sticky; top: calc(var(--header-h) + 12px);
           max-height: calc(100vh - var(--header-h) - 24px); overflow-y: auto;
           overscroll-behavior: contain;
           border-right: 1px solid var(--rule); padding: 0 var(--gutter) 64px 0; }
.content { order: 2; grid-column: 2; min-width: 0; padding: 32px 0 96px var(--gutter); }
/* padding-top above is 0 by design: the column's first line sits up under the
   header rule. It was 32px, which held that line level with the .doc-eyebrow in
   the main column; that alignment was given up deliberately, on all pages. The
   mobile rule keeps its own top padding — below 900px this column sits UNDER the
   content behind a 2px rule, so the space there separates it from that rule
   rather than from the header, and zeroing it would jam the two together. */

.side-block { margin-bottom: 28px; }
.side-title {
  font-family: var(--display); font-size: 9.5px; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink);
  border-bottom: 2px solid var(--ink); padding-bottom: 5px; margin-bottom: 10px;
}
.side-block p { font-size: 12.5px; line-height: 1.5; color: var(--ink-2); }
/* The Foundation block sets its explanatory note BELOW its links, so the note
   would otherwise butt straight against the last link's hairline rule. */
.side-nav + p { margin-top: 11px; }
.side-nav { list-style: none; }
.side-nav a {
  display: block; padding: 4px 0; font-size: 13px; color: var(--ink);
  text-decoration: none; border-bottom: 1px solid var(--rule);
}
.side-nav a:hover { color: var(--red); }
.side-nav a.current { font-weight: 600; color: var(--red); }
.side-nav a.current::before { content: "\25A0\00a0"; font-size: 8px; vertical-align: middle; }

/* Author's statement. Longer prose than the rest of the column, so it drops a
   step in size and gets its own hairline separators rather than more rules. */
.side-disclosure { border-top: 1px solid var(--rule); padding-top: 20px; }
.side-disclosure p { font-size: 12px; margin-bottom: 10px; }
/* "My motives" is a peer of "Full disclosure" and "Voting Influence Corruption", so it reuses
   .side-title outright — same size, weight and rule — and only adds the space a
   mid-block heading needs. */
.side-title-sub { margin-top: 18px; }
/* Set at 12px to match the paragraphs around it: the quote carries by colour and
   weight, not by size. */
.side-quote {
  margin: 14px 0 6px; padding-left: 10px; border-left: 2px solid var(--purple);
  font-size: 12px; line-height: 1.5; font-weight: 600; color: var(--purple);
}
.side-source { margin-bottom: 14px; }
.side-source a { color: var(--ink-2); font-size: 11.5px; word-break: break-word; }
.side-source a:hover { color: var(--red); }
.side-signature { color: var(--ink); font-weight: 600; }
.side-signature a { color: var(--ink); text-decoration: none; border-bottom: 1px solid var(--rule-hi); }
.side-signature a:hover { color: var(--red); border-bottom-color: var(--red); }
.side-signature span { font-weight: 400; color: var(--ink-2); }
/* Publisher disclosure link, last block in the column on every page but the
   overview (where the statement itself sits there instead). Deliberately reuses
   .side-nav so its size and face match the section navigation above it; only the
   colour differs. */
.side-publisher { margin-bottom: 0; }
.side-publisher a { color: var(--green); font-weight: 600; }
.side-publisher a:hover { color: var(--red); }

/* ── Short version ────────────────────────────────────────────────────────── */
/* Entry ramp on the overview. Before this the page went from standfirst to a
   90-word caution to $2.56B, which gave a reader no way to find out what was
   found without committing to the whole thing. Deliberately carries the refuted
   hypothesis as its middle line: a summary that reported only the two supported
   findings would be the exact selective framing the register exists to prevent. */
.short-version {
  border-top: 2px solid var(--ink); border-bottom: 2px solid var(--ink);
  margin: 26px 0 30px; max-width: 62ch;
}
.short-version-title {
  font-family: var(--display); font-size: 9.5px; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-2);
  padding: 9px 0 11px;
}
.sv-row {
  display: grid; grid-template-columns: 106px minmax(0, 1fr); gap: 16px;
  padding: 12px 0; border-top: 1px solid var(--rule); align-items: baseline;
}
.sv-num {
  font-family: var(--display); font-size: 21px; font-weight: 800;
  letter-spacing: -0.025em; font-variant-numeric: tabular-nums; line-height: 1.1;
}
.sv-num.against { color: var(--red); }
.sv-text { font-size: 14px; line-height: 1.5; color: var(--ink); }

/* The figure column stops earning its width once the text beside it wraps to
   near-single words. */
@media (max-width: 560px) {
  .sv-row { grid-template-columns: 1fr; gap: 4px; }
}

/* ── Verdict strip ────────────────────────────────────────────────────────── */
/* The pre-registered register, compressed to one line per hypothesis. The whole
   argument for trusting this atlas is that two of its five predictions failed
   and are published as failed — that was previously only visible to a reader who
   clicked through to the register. */
.verdict-strip { border-top: 2px solid var(--ink); margin: 20px 0 18px; max-width: 62ch; }
.vs-item {
  display: grid; grid-template-columns: 30px minmax(0, 1fr) auto; gap: 12px;
  align-items: baseline; padding: 10px 0; border-bottom: 1px solid var(--rule);
  text-decoration: none; color: var(--ink);
}
.vs-item:hover { color: var(--red); }
.vs-item:hover .vs-claim { text-decoration: underline; text-underline-offset: 2px; }
.vs-claim { font-size: 13.5px; line-height: 1.4; }
/* .hyp-verdict carries an 8px left margin for its inline use in the register;
   in a grid cell that just pushes the badge off the right edge. */
.vs-item .hyp-verdict { margin-left: 0; }
@media (max-width: 560px) {
  .vs-item { grid-template-columns: 30px minmax(0, 1fr); gap: 4px 12px; }
  .vs-item .hyp-verdict { grid-column: 2; justify-self: start; margin-top: 2px; }
}

/* ── Money-flow figure ────────────────────────────────────────────────────── */
/* The one diagram in the section. Ribbon widths are the dollar figures at a
   single scale, so the 8.25:1 ratio is read rather than asserted. Colours match
   the bars directly above it: red against, blue for, ink accountable. */
.flow-fig { margin: 26px 0 30px; max-width: 760px; }
.flow-fig svg { width: 100%; height: auto; display: block; overflow: visible; }
.flow-cap {
  font-family: var(--display); font-size: 9.5px; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; fill: var(--ink-2);
}
.flow-tot { font-family: var(--display); font-size: 21px; font-weight: 800; fill: var(--ink); }
.flow-lbl { font-family: var(--body); font-size: 12.5px; fill: var(--ink); }
.flow-em  { font-style: italic; font-weight: 700; }
.flow-val {
  font-family: var(--display); font-size: 13px; font-weight: 700;
  fill: var(--ink-2); font-variant-numeric: tabular-nums;
}
.flow-note { font-family: var(--body); font-size: 10.5px; fill: var(--ink-2); }
.flow-brace { fill: none; stroke: var(--ink-2); stroke-width: 1; }
.flow-fig figcaption {
  font-size: 12px; line-height: 1.5; color: var(--ink-2);
  border-top: 1px solid var(--rule); padding-top: 10px; margin-top: 6px;
}

/* Below this the label column has no room left beside the ribbons, so the
   figure scrolls horizontally at a fixed legible width rather than shrinking
   its 12.5px labels into illegibility. */
@media (max-width: 620px) {
  .flow-fig { overflow-x: auto; }
  .flow-fig svg { width: 660px; }
}

/* ── Editorial type scale ─────────────────────────────────────────────────── */
.doc-eyebrow {
  font-family: var(--display); font-size: 9.5px; font-weight: 700;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--red);
  margin-bottom: 14px;
}
.doc-title {
  font-size: clamp(34px, 6vw, 62px); font-weight: 800;
  letter-spacing: -0.035em; margin-bottom: 18px; max-width: 16ch;
}
/* No border-bottom here. It was removed 2026-08-11: the rule inherited this
   element's max-width:46ch, so it stopped short of the full-width rules drawn
   by .content h2 below it — two ragged, disagreeing horizontal lines stacked a
   few dozen pixels apart at the top of all 11 /votes/ pages. The h2 rule below
   already separates the lead from the body, so the short one was redundant as
   well as misaligned. If a rule under the lead is ever wanted again, it must
   sit on a full-width wrapper, not on the text block itself. */
.doc-lead {
  font-size: 19px; line-height: 1.45; color: var(--ink); max-width: 46ch;
  margin-bottom: 30px;
  font-weight: 400;
}
.content h2 {
  font-size: 23px; margin: 46px 0 4px; padding-top: 10px;
  border-top: 1px solid var(--ink);
}
.content h2 + p, .content h2 + div { margin-top: 14px; }
.content h3 { font-size: 16px; margin: 28px 0 8px; letter-spacing: -0.01em; }
.content p { margin-bottom: 14px; max-width: 62ch; }
.content ul, .content ol { margin: 0 0 18px 18px; max-width: 62ch; }
.content li { margin-bottom: 6px; }

/* ── Stat blocks ──────────────────────────────────────────────────────────── */
.stat-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
  gap: 1px; background: var(--rule); border: 1px solid var(--rule);
  margin: 26px 0 30px;
}
.stat { background: var(--paper); padding: 14px 16px 16px; }
.stat-num {
  font-family: var(--display); font-size: 34px; font-weight: 800;
  letter-spacing: -0.04em; line-height: 1; font-variant-numeric: tabular-nums;
}
.stat-num.against { color: var(--red); }
.stat-num.accent  { color: var(--blue); }
/* Tiles bottom out at 168px wide, where anything past ~8 characters overruns
   the cell at 34px — "210,900,861" and "0.65 → 0.15" both do. One step down
   rather than a per-tile clamp, since the grid has no container query. */
.stat-num.wide { font-size: 24px; letter-spacing: -0.02em; }
.stat-label { font-size: 12.5px; color: var(--ink-2); margin-top: 8px; line-height: 1.4; }
.stat-src {
  font-family: var(--display); font-size: 9px; font-weight: 600; color: var(--ink-2);
  letter-spacing: 0.1em; margin-top: 8px; text-transform: uppercase;
  border-top: 1px solid var(--rule); padding-top: 6px;
}

/* ── Bars ─────────────────────────────────────────────────────────────────── */
.bars { margin: 22px 0 30px; border-top: 1px solid var(--ink); }
.bar-row { padding: 8px 0; border-bottom: 1px solid var(--rule); }
.bar-head {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: 13px; margin-bottom: 5px; gap: 12px;
}
.bar-val { font-variant-numeric: tabular-nums; font-weight: 600; white-space: nowrap; }
.bar-track { height: 10px; background: var(--panel); }
.bar-fill { height: 100%; background: var(--ink); }
.bar-fill.against { background: var(--red); }
.bar-fill.forx    { background: var(--blue); }
.bar-fill.direct  { background: var(--ink-2); }

/* ── Tables ───────────────────────────────────────────────────────────────── */
.table-wrap { overflow-x: auto; margin: 18px 0 30px; border-bottom: 1px solid var(--ink); }
table { border-collapse: collapse; width: 100%; font-size: 13px; min-width: 560px; }
th, td { text-align: left; padding: 7px 10px; border-bottom: 1px solid var(--rule); }
/* NO position:sticky here. It was removed 2026-08-11 after it caused two
   visible defects on every table on the site:

   1. The 2px rules above and below the header row vanished. Under
      border-collapse:collapse, borders belong to the TABLE, not the cell.
      Promoting th to a sticky positioned element paints it in its own layer
      and leaves its collapsed borders behind. That is why the line above the
      Column / Treatment header was missing.

   2. The header row sat on top of the first data rows. .table-wrap sets
      overflow-x:auto, which makes the WRAP the sticky scrollport rather than
      the viewport, so top:46px offset the header 46px down into the tbody —
      landing squarely on the first two rows (Nevada, Montana on the cost
      table).

   Sticky also bought nothing: the wrap has no height limit, so it never
   scrolls vertically and the header could never have followed page scroll.
   Restoring a working sticky header would mean giving .table-wrap a
   max-height, which is a different design decision — see the note below. */
thead th {
  font-family: var(--display); font-size: 9px; font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink);
  border-bottom: 2px solid var(--ink); border-top: 2px solid var(--ink);
  background: var(--paper);
  vertical-align: bottom;
  padding-top: 9px; padding-bottom: 7px;
}
/* Breathing room between the header rule and the first row, so the header
   reads as a header rather than as a tightly-packed first row. */
tbody tr:first-child td { padding-top: 10px; }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* The 10px cell padding is INTER-column spacing and must not appear on the two
   outer edges. With it applied all round, the first column ("Column", "State",
   "#") began 10px to the right of every paragraph on the page and the last
   column's figures stopped 10px short of the right edge — so no table lined up
   with the prose it sat between. Zeroing the outer sides puts the first column
   flush on the text column and flushes the final figures right, which is what
   the grid this stylesheet follows requires. */
th:first-child, td:first-child { padding-left: 0; }
th:last-child,  td:last-child  { padding-right: 0; }

tbody tr:hover { background: var(--panel); }

/* epistemic status columns */
.col-measured { color: var(--ink); font-weight: 600; }
.col-modelled { color: var(--blue); }
th.col-measured { border-bottom-color: var(--ink); }
th.col-modelled { color: var(--blue); border-bottom-color: var(--blue); }
.status-key {
  display: flex; gap: 20px; flex-wrap: wrap; font-size: 11.5px;
  color: var(--ink-2); margin: 0 0 14px;
}
.status-key b { font-weight: 600; }
.swatch { display: inline-block; width: 9px; height: 9px; margin-right: 5px; vertical-align: baseline; }
.swatch.m { background: var(--ink); }
.swatch.d { background: var(--blue); }
.swatch.r { background: var(--red); }

/* ── Table tools: filter + sort ───────────────────────────────────────────── */
.table-tools {
  display: flex; gap: 10px; align-items: stretch; flex-wrap: wrap;
  border-top: 2px solid var(--ink); padding-top: 12px; margin-top: 20px;
}
.table-tools input[type="search"] {
  font-family: var(--body); font-size: 13px; padding: 7px 10px;
  border: 1px solid var(--ink); background: var(--paper); color: var(--ink);
  min-width: 210px; flex: 1 1 210px; border-radius: 0; -webkit-appearance: none;
}
.table-tools input[type="search"]::placeholder { color: var(--ink-2); }
.sort-btn {
  font-family: var(--display); font-size: 9.5px; font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase;
  padding: 7px 12px; border: 1px solid var(--ink); background: var(--paper);
  color: var(--ink); cursor: pointer; border-radius: 0;
}
.sort-btn[aria-pressed="true"] { background: var(--ink); color: var(--paper); }
.sort-btn:hover { border-color: var(--red); color: var(--red); }
.sort-btn[aria-pressed="true"]:hover { background: var(--red); border-color: var(--red); color: var(--paper); }
.table-count { font-size: 11.5px; color: var(--ink-2); align-self: center; }
tr[hidden] { display: none; }
tr.hit td { background: #FFF6D6; }

/* ── Tile-grid cartogram ──────────────────────────────────────────────────── */
.cartogram { margin: 20px 0 8px; }
.cartogram svg { width: 100%; height: auto; display: block; max-width: 760px; }
.tile rect { stroke: var(--paper); stroke-width: 2px; }
.tile text.abbr { font-family: var(--display); font-size: 9.5px; font-weight: 700; }
.tile text.val  { font-family: var(--display); font-size: 7.5px; font-weight: 600; }
.tile:hover rect { stroke: var(--ink); stroke-width: 2px; }
.legend { display: flex; align-items: center; gap: 0; margin: 6px 0 4px; max-width: 760px; }
.legend-step { flex: 1; height: 13px; }
.legend-labels {
  display: flex; justify-content: space-between; max-width: 760px;
  font-family: var(--display); font-size: 9px; font-weight: 600;
  letter-spacing: 0.08em; color: var(--ink-2); text-transform: uppercase;
}

/* ── Callouts ─────────────────────────────────────────────────────────────── */
.callout { border-left: 4px solid var(--ink); padding: 14px 0 14px 16px; margin: 24px 0;
           background: var(--panel); padding-right: 16px; max-width: 66ch; }
.callout.warn      { border-left-color: var(--red); }
.callout.falsified { border-left-color: var(--red); }
.callout.ok        { border-left-color: var(--blue); }
.callout-title {
  font-family: var(--display); font-size: 9.5px; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase; margin-bottom: 7px;
}
.callout p { margin-bottom: 10px; max-width: none; }
.callout p:last-child { margin-bottom: 0; }

/* ── Boxed to match .stat-grid ────────────────────────────────────────────── */
/* The page openings ran several different devices in a row — an unruled lead, a
   2px-ink strip, a left-barred panel, then the hairline-boxed stat grid — at
   three different measures. They now share the grid's 1px hairline box and its
   16px inset, so a page reads as one system. Applied on all eleven pages.
   Placed AFTER the .callout rules above: the shorthand below sets all four
   borders, so it has to come later than the base .callout border-left or that
   4px bar would win and the box would be missing its left side. */
.doc-lead,
.short-version,
.callout {
  border: 1px solid var(--rule);
  max-width: none;
}
.doc-lead { padding: 14px 16px 16px; }
.callout  { padding: 14px 16px 16px; }

/* Padding moves onto the title and the rows rather than the container, so the
   dividers between rows run the full width of the box the way the grid's cell
   dividers do, instead of being inset by the container's padding. */
.short-version       { padding: 0; }
.short-version-title { padding: 11px 16px 12px; }
.sv-row              { padding: 12px 16px; }

/* The callout keeps its 4px semantic left bar — red for falsified/warn, blue
   for ok. That bar is the site's epistemic signal, not decoration, so only the
   other three sides take the hairline. */
.callout            { border-left-width: 4px; border-left-color: var(--ink); }
.callout.warn,
.callout.falsified  { border-left-color: var(--red); }
.callout.ok         { border-left-color: var(--blue); }

/* ── Hypothesis cards ─────────────────────────────────────────────────────── */
.hyp { border-top: 1px solid var(--ink); padding: 16px 0 18px; margin-bottom: 0; max-width: 66ch; }
.hyp-id {
  font-family: var(--display); font-size: 11px; font-weight: 800;
  letter-spacing: 0.08em; color: var(--red);
}
.hyp-verdict {
  display: inline-block; font-family: var(--display); font-size: 9px; font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase; padding: 2px 7px; margin-left: 8px;
  border: 1px solid currentColor;
}
.v-supported    { color: var(--ink); }
.v-refuted      { color: var(--red); }
.v-inconclusive { color: var(--ink-2); }
.hyp h3 { margin-top: 8px; }

/* ── Provenance rows ──────────────────────────────────────────────────────── */
.src-row { border-bottom: 1px solid var(--rule); padding: 11px 0;
           display: grid; grid-template-columns: 168px minmax(0,1fr); gap: 18px; }
.src-key {
  font-family: var(--display); font-size: 10px; font-weight: 700; color: var(--red);
  letter-spacing: 0.06em; text-transform: uppercase; word-break: break-word;
}
.src-body { font-size: 13px; color: var(--ink-2); }
.src-body a { word-break: break-word; }

code { font-family: ui-monospace, 'SF Mono', Menlo, monospace; font-size: 0.9em;
       background: var(--panel); padding: 1px 4px; }

/* ── Footer ───────────────────────────────────────────────────────────────── */
.doc-footer { margin-top: 56px; padding-top: 18px; border-top: 2px solid var(--ink);
              font-size: 12.5px; color: var(--ink-2); max-width: 66ch; }
.doc-footer-links { display: flex; gap: 18px; flex-wrap: wrap; margin-bottom: 12px; }
.doc-footer-links a {
  font-family: var(--display); font-size: 9.5px; font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase; text-decoration: none; color: var(--ink);
}
.doc-footer-links a:hover { color: var(--red); }
.doc-footer-note { font-size: 11.5px; line-height: 1.55; }

/* ── Responsive: content first on small screens ───────────────────────────── */
@media (max-width: 900px) {
  .layout { grid-template-columns: 1fr; }
  .content { order: 1; grid-column: 1; padding: 26px 0 40px; }
  .sidebar { order: 2; grid-column: 1; position: static;
             max-height: none; overflow-y: visible;
             border-right: 0; border-top: 2px solid var(--ink);
             padding: 26px 0 60px; }
  thead th { position: static; }
  .doc-lead { font-size: 17px; }
}

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

/* ── Dark ─────────────────────────────────────────────────────────────────── */
/* The media query is guarded so an explicit "light" choice beats the system
   preference. Before 2026-08-15 it was unguarded and paired with a
   [data-theme="light"] block that redeclared only some of the tokens — it never
   got --purple, --green or the --step ramp — so forcing light on a dark device
   would have left the sidebar quote, the disclosure link and the cartogram in
   dark-mode colours. With the guard, plain :root supplies the light palette and
   there is nothing to keep in sync. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper: #0E0E0E; --panel: #1A1A1A; --ink: #F2F2F2; --ink-2: #A8A8A8;
    --rule: #333333; --rule-hi: #F2F2F2; --red: #FF5247; --blue: #7FB3E8;
    --sand: #2A2820; --purple: #C4A2F0; --green: #6FD79B;
  }
  :root:not([data-theme="light"]) tr.hit td { background: #3A3216; }
  :root:not([data-theme="light"]) .table-tools input[type="search"] { background: var(--panel); }
}
:root[data-theme="dark"] {
  --paper: #0E0E0E; --panel: #1A1A1A; --ink: #F2F2F2; --ink-2: #A8A8A8;
  --rule: #333333; --rule-hi: #F2F2F2; --red: #FF5247; --blue: #7FB3E8;
  --sand: #2A2820; --purple: #C4A2F0; --green: #6FD79B;
}
:root[data-theme="dark"] tr.hit td { background: #3A3216; }
:root[data-theme="dark"] .table-tools input[type="search"] { background: var(--panel); }

/* ── Cartogram sequential ramp (single hue toward the accent red) ─────────── */
:root {
  --step0: #EDEBE4; --step1: #F3C9B8; --step2: #E8917A; --step3: #DC5240; --step4: #B3140B;
  --on0: #111111; --on1: #111111; --on2: #111111; --on3: #FFFFFF; --on4: #FFFFFF;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --step0: #26251F; --step1: #5E2A22; --step2: #8E3A2C; --step3: #C24A38; --step4: #FF5247;
    --on0: #F2F2F2; --on1: #F2F2F2; --on2: #FFFFFF; --on3: #FFFFFF; --on4: #14100F;
  }
}
:root[data-theme="dark"] {
  --step0: #26251F; --step1: #5E2A22; --step2: #8E3A2C; --step3: #C24A38; --step4: #FF5247;
  --on0: #F2F2F2; --on1: #F2F2F2; --on2: #FFFFFF; --on3: #FFFFFF; --on4: #14100F;
}
.s0 rect { fill: var(--step0); } .s0 text { fill: var(--on0); }
.s1 rect { fill: var(--step1); } .s1 text { fill: var(--on1); }
.s2 rect { fill: var(--step2); } .s2 text { fill: var(--on2); }
.s3 rect { fill: var(--step3); } .s3 text { fill: var(--on3); }
.s4 rect { fill: var(--step4); } .s4 text { fill: var(--on4); }
.legend .l0 { background: var(--step0); } .legend .l1 { background: var(--step1); }
.legend .l2 { background: var(--step2); } .legend .l3 { background: var(--step3); }
.legend .l4 { background: var(--step4); }

/* Correction notice. Deliberately loud: a retraction that reads like body text
   is a retraction nobody sees. Uses --red, which elsewhere on this site marks
   measured attack spending — here it marks a claim this project got wrong. */
p.correction {
  border-left: 3px solid var(--red);
  padding: 0.6rem 0 0.6rem 0.9rem;
  margin: 1rem 0;
  background: color-mix(in srgb, var(--red) 5%, transparent);
}
p.correction strong { color: var(--red); }


/* -- Warmth pass ---------------------------------------------------------- */
h1, h2, h3, h4 { letter-spacing: -0.012em; }
.doc-title { letter-spacing: -0.02em; }
.doc-eyebrow, .side-title, .mn-group, .flow-cap, .short-version-title,
.back-link, .breadcrumb, .stat-src { letter-spacing: 0.09em; }
.short-version-title { background: var(--panel); }
.swatch.inside { background: var(--ochre); }
.swatch.outside { background: var(--teal); }

/* -- Data figures --------------------------------------------------------- */
.fig { margin: 26px 0 34px; max-width: 760px; }
.fig svg { width: 100%; height: auto; display: block; overflow: visible; }
.fig-cap { font-family: var(--display); font-size: 9.5px; font-weight: 700;
  letter-spacing: 0.09em; text-transform: uppercase; color: var(--ink-2);
  margin-bottom: 8px; }
.fig-note { font-size: 11.5px; line-height: 1.5; color: var(--ink-2); margin-top: 9px; }
.fig-key { font-family: var(--display); font-size: 10px; font-weight: 600;
  letter-spacing: 0.06em; color: var(--ink-2); margin: 6px 0 2px; }
.fig-key .swatch { width: 9px; height: 9px; display: inline-block;
  margin: 0 5px 0 14px; vertical-align: baseline; }
.fig-key .swatch:first-child { margin-left: 0; }
