/* Self-hosted webfonts — OFL. Static instanced latin-first subsets.
   Filenames are content-stable; served immutable. Generated 2026-07-20. */
@font-face {
  font-family: "Literata";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/literata-400i-sub5dcdda.woff2) format("woff2");
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: "Literata";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/literata-400i-cyrillic-ext.woff2) format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: "Literata";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/literata-400i-greek-ext.woff2) format("woff2");
  unicode-range: U+1F00-1FFF;
}
@font-face {
  font-family: "Literata";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/literata-400i-greek.woff2) format("woff2");
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
@font-face {
  font-family: "Literata";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/literata-400i-vietnamese.woff2) format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
  font-family: "Literata";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/literata-400i-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Literata";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/literata-400i-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Literata";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/literata-400-sub5dcdda.woff2) format("woff2");
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: "Literata";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/literata-400-cyrillic-ext.woff2) format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: "Literata";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/literata-400-greek-ext.woff2) format("woff2");
  unicode-range: U+1F00-1FFF;
}
@font-face {
  font-family: "Literata";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/literata-400-greek.woff2) format("woff2");
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
@font-face {
  font-family: "Literata";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/literata-400-vietnamese.woff2) format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
  font-family: "Literata";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/literata-400-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Literata";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/literata-400-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Literata";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/assets/fonts/literata-600-sub5dcdda.woff2) format("woff2");
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: "Literata";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/assets/fonts/literata-600-cyrillic-ext.woff2) format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: "Literata";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/assets/fonts/literata-600-greek-ext.woff2) format("woff2");
  unicode-range: U+1F00-1FFF;
}
@font-face {
  font-family: "Literata";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/assets/fonts/literata-600-greek.woff2) format("woff2");
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
@font-face {
  font-family: "Literata";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/assets/fonts/literata-600-vietnamese.woff2) format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
  font-family: "Literata";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/assets/fonts/literata-600-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Literata";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/assets/fonts/literata-600-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Public Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/public-sans-400-vietnamese.woff2) format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
  font-family: "Public Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/public-sans-400-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Public Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/public-sans-400-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Public Sans";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/assets/fonts/public-sans-600-vietnamese.woff2) format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
  font-family: "Public Sans";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/assets/fonts/public-sans-600-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Public Sans";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/assets/fonts/public-sans-600-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/plex-mono-400-sub5dcdda.woff2) format("woff2");
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/plex-mono-400-cyrillic-ext.woff2) format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/plex-mono-400-vietnamese.woff2) format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/plex-mono-400-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/plex-mono-400-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ============================================================
   Pheme semantic tokens — single source for every surface.
   Two environments: the record (paper) and the instrument (night).
   Contrast-certified 2026-07-25: every text token ≥4.5:1 against BOTH paper
   surfaces (--paper AND --paper-deep), enforced by tests/design-tokens.test.js.
   The 07-20 pass certified against --paper only; when --paper-deep was
   deepened, --ink-faint/--ev-input/--ev-unknown all silently fell under AA on
   the tinted surface and axe saw only the one pair that happened to render.
   Canonical source: pheme-backend/site/tokens.css (build:site emits /tokens.css).
   ============================================================ */

:root {
  /* --- surfaces: the record (paper) --- */
  --paper: #f6f1e6;
  /* Structure has to clear the perceptual floor, not just exist. Measured on
     the shipped site: panels and table zebra sat at 1.11:1 against the page and
     rules at 1.57:1 — present in the CSS, invisible to the eye, which is why
     "elements read as separate" kept failing however many dividers were added.
     A surface needs ~1.2:1 to register as its own plane and a divider ~3:1 to
     read as deliberate. These stay in the same cream family; they are the same
     hues carried far enough to be seen.
       --paper-deep  1.11 -> 1.26 vs --paper   (ink on it still 11.9:1)
       --rule        1.57 -> 2.53 vs --paper */
  --paper-deep: #e3d8ba;
  --ink: #211c14;
  --ink-soft: #57503f;
  --ink-faint: #5f5846;      /* 6.28:1 on paper · 4.98:1 on --paper-deep */
  --rule: #a8977a;
  --rule-strong: #211c14;

  /* --- surfaces: the instrument (night) --- */
  --night: #0d1118;
  --night-panel: #131a24;
  --bone: #e9e2d3;
  --bone-soft: #a9a393;
  --night-rule: #2b3542;

  /* --- evidence grammar (chrome only: labels, rules, badges; never map fills) --- */
  --ev-observed: #211c14;         /* observed prints in ink · solid rule */
  --ev-modeled: #5b3fae;          /* the color of the hypothetical · dotted rule (6.74:1 paper) */
  --ev-modeled-night: #a48ae8;    /* night variant (6.64:1 night) */
  --ev-input: #754e00;            /* hypothetical input · dashed rule (6.55:1 paper · 5.20:1 deep) */
  --ev-input-fill: #e2b13c;
  --ev-unknown: #5e594b;          /* rendered as the word "unknown" · hollow rule (6.20:1 paper · 4.92:1 deep) */

  /* --- partisan (legend-bound data-viz fills/text only) --- */
  /* Certified against BOTH paper surfaces, not just --paper. Deepening
     --paper-deep to clear the perceptual floor dropped the old --dem (#2f5fa8)
     to 4.45:1 on a zebra row — a real AA failure axe caught on 10 lean cells in
     the state table — and left the old --rep (#a63a30) passing by 0.03. Both
     are carried deeper so each has genuine headroom on the tinted row, and the
     pair stays balanced so D and R read at the same visual weight. */
  --dem: #2b579c;                 /* 6.33:1 on paper · 5.02:1 on --paper-deep */
  --rep: #9c362d;                 /* 6.26:1 on paper · 4.97:1 on --paper-deep */

  /* Direction of a COST, which is not a direction of politics.
     /cost previously drew "costs more work" in --rep and "costs less work" in
     --dem. Those are the party-lean tokens (.lean.d/.lean.r, the partisan
     dashboard fills), and on a site whose whole subject is political opinion a
     table of red and blue bars reads as Democrat and Republican. It was a
     latent misread when it coloured six figures; the ranked table draws
     twenty-three bars and makes it the dominant visual on the page.
     Rust and teal carry no partisan reading, and both clear AA as text on both
     paper surfaces so the ratio figures can use them too. */
  --cost-more: #7d4a24;           /* 6.48:1 on paper · 5.14:1 on --paper-deep */
  --cost-less: #26635a;           /* 6.18:1 on paper · 4.91:1 on --paper-deep */

  /* --- data-viz ramps (read by atlas scales; only under a legend) --- */
  --ramp-ink-1: #f0e8d9; --ramp-ink-2: #dccfb2; --ramp-ink-3: #c0a87e;
  --ramp-ink-4: #9d7f52; --ramp-ink-5: #6f5836; --ramp-ink-6: #463522;
  --ramp-violet-1: #efe9fb; --ramp-violet-2: #cfc0f0; --ramp-violet-3: #a893dd;
  --ramp-violet-4: #8266c4; --ramp-violet-5: #5d43a0; --ramp-violet-6: #3a2a72;
  --ramp-lean-r3: #a63a30; --ramp-lean-r2: #c96a58; --ramp-lean-r1: #e2a58f;
  --ramp-lean-0: #efe6d4;
  --ramp-lean-d1: #9db8dd; --ramp-lean-d2: #5b86c4; --ramp-lean-d3: #2f5fa8;

  /* --- type --- */
  --serif: "Literata", "Literata-fallback", "Iowan Old Style", Georgia, serif;
  --sans: "Public Sans", "PublicSans-fallback", -apple-system, "Helvetica Neue", Arial, sans-serif;
  --mono: "IBM Plex Mono", "PlexMono-fallback", ui-monospace, "SF Mono", Menlo, monospace;

  /* --- rhythm --- */
  --measure: 68ch;
  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px;
  --s5: 24px; --s6: 32px; --s7: 48px; --s8: 64px;
  --radius-control: 2px;          /* controls only; rules and tables stay square */
}

/* Local metric-matched fallbacks so swapped text does not shift layout — now
   actually wired into --serif/--sans/--mono above (they were defined but never
   referenced, and backed by Georgia/Helvetica Neue, which don't exist on Linux —
   so the swap reflowed ~0.2 CLS on CI). Backed instead by Times New Roman / Arial
   / Courier New, whose metrics Linux's Liberation Serif/Sans/Mono clone, so one
   set of overrides matches on every platform. Calibrated to a 0px paragraph-height
   delta against each real font; font-display stays "swap" because with the
   fallback boxes matched, swapping to the loaded font shifts nothing. */
@font-face {
  font-family: "Literata-fallback";
  src: local("Times New Roman"), local("Liberation Serif");
  size-adjust: 112.66%;
  ascent-override: 104.5%;
  descent-override: 27.3%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "PublicSans-fallback";
  src: local("Arial"), local("Liberation Sans");
  size-adjust: 103.45%;
  ascent-override: 91.8%;
  descent-override: 21.7%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "PlexMono-fallback";
  src: local("Courier New"), local("Liberation Mono");
  size-adjust: 99.98%;
  ascent-override: 102.5%;
  descent-override: 27.5%;
  line-gap-override: 0%;
}
