:root {
  --ink: #1a1a1a; --muted: #5a5a5a; --line: #e2e2e2;
  --bg: #ffffff; --accent: #1f5f4f; --promo-bg: #f6f6f4;
}
@media (prefers-color-scheme: dark) {
  :root { --ink: #ececec; --muted: #a0a0a0; --line: #303030;
          --bg: #141414; --accent: #6fbfa8; --promo-bg: #1e1e1e; }
}
* { box-sizing: border-box; }
body { margin: 0; background: var(--bg); color: var(--ink);
       font: 17px/1.65 ui-serif, Georgia, serif; }
main, .site-header, .site-footer { max-width: 44rem; margin: 0 auto; padding: 0 1rem; }
.site-header { display: flex; justify-content: space-between; align-items: baseline;
               gap: 1rem; padding-top: 1.5rem; flex-wrap: wrap; }
.wordmark { font-weight: 700; text-decoration: none; color: var(--ink); }
nav a { margin-left: 1rem; color: var(--muted); text-decoration: none; font-size: .9rem; }
a { color: var(--accent); }
.promo { border: 1px solid var(--line); background: var(--promo-bg);
         border-radius: 8px; padding: 1rem; margin: 2rem 0; }
.promo-label { display: block; font-size: .7rem; letter-spacing: .08em;
               text-transform: uppercase; color: var(--muted); margin-bottom: .5rem; }
.promo-link { display: flex; gap: 1rem; align-items: center; text-decoration: none; }
.promo-image { flex: 0 0 auto; width: 96px; height: auto; border-radius: 6px; }
.promo-text { display: block; }
.promo-text span { display: block; color: var(--muted); font-size: .9rem; }
.limitations { border-left: 3px solid var(--line); padding-left: 1rem; color: var(--muted); }
.site-footer { border-top: 1px solid var(--line); margin-top: 3rem;
               padding-top: 1.5rem; padding-bottom: 3rem; }
.disclosure { font-size: .85rem; }
.small { font-size: .8rem; color: var(--muted); }
table { border-collapse: collapse; width: 100%; }
th, td { border-bottom: 1px solid var(--line); text-align: left; padding: .5rem 0; }

/* ---- Blog ---------------------------------------------------------------
   Blog pages carry no promo. That is the mechanic, not a style choice: the
   buy-link is what establishes intended use, so a page that sells nothing can
   report what other people claim. See shared/scripts/posts.js. */
.post-list { list-style: none; padding: 0; }
.post-list > li { border-bottom: 1px solid var(--line); padding-bottom: 1rem; margin-bottom: 1.5rem; }
.post-list h2 { margin-bottom: .25rem; }
.post-list h2 a { text-decoration: none; }
.post-meta { color: var(--muted); font-size: .85rem; margin-top: 0; }
.post h2 { margin-top: 2.5rem; }
.post blockquote { margin: 1.5rem 0; padding-left: 1rem;
                   border-left: 3px solid var(--line); color: var(--muted); }
.sources { font-size: .9rem; color: var(--muted); padding-left: 1.25rem; }
.sources li { margin-bottom: .5rem; }

/* ---- Data figures -------------------------------------------------------
   Inline SVG only: no image files and no page JavaScript (CLAUDE.md — the
   calculator is the only script that ships). Colour comes from the tokens at
   the top of this file, so both figures follow light/dark with no duplicated
   palette.

   PALETTE NOTE. These figures encode identity by SHAPE, never by hue, and
   that is a measured decision rather than a preference. Running the data-viz
   validator on the only two-colour pair the site's tokens can offer
   (--accent against --muted) hard-fails in both modes: normal-vision OKLab
   dE 7.5 light / 9.6 dark against a floor of 15, i.e. readers with full
   colour vision cannot reliably tell the two apart. Re-stepping is not
   available when the palette is the site's own. So every mark is one hue
   (--accent: 7.48:1 on white, 8.50:1 on the dark surface, both well clear of
   the 3:1 mark minimum) and the open-ring / filled-disc distinction carries
   the meaning — a channel that survives colour-blindness, greyscale print and
   forced-colors alike. Each figure also ships a table twin, so no value is
   reachable only through the graphic. */
.figure { margin: 2rem auto; max-width: 30rem; }
.figure svg { width: 100%; height: auto; display: block; }
.figure figcaption { font-size: .82rem; color: var(--muted); margin-top: .75rem; line-height: 1.5; }
.figure details { margin-top: .75rem; font-size: .82rem; }
.figure summary { color: var(--accent); cursor: pointer; }
.figure table { margin-top: .5rem; font-size: .82rem; }
.figure th, .figure td { padding: .35rem .5rem .35rem 0; vertical-align: top; }

/* The data-viz convention is a system sans for chart text, which also sets
   the figures apart from the serif body copy. Sizes are in viewBox units;
   .figure is capped at 30rem so they land between ~12px and ~16px rendered,
   from a 320px phone up to the 44rem body measure. */
.viz text { font-family: system-ui, -apple-system, "Segoe UI", sans-serif; }
.viz-title { fill: var(--ink); font-size: 16px; font-weight: 600; }
.viz-label { fill: var(--ink); font-size: 15px; }
.viz-date { fill: var(--ink); font-size: 15px; font-weight: 600; }
.viz-sub { fill: var(--muted); font-size: 13.5px; }
.viz-axis { fill: var(--muted); font-size: 13px; font-variant-numeric: tabular-nums; }
/* Hairline, solid, one step off the surface — never dashed. */
.viz-rule { stroke: var(--line); stroke-width: 1; fill: none; }
.viz-leader { stroke: var(--line); stroke-width: 1; fill: none; }
/* Area wash, ~12% — never a saturated block. */
.viz-band { fill: var(--accent); opacity: .12; }
.viz-stem { stroke: var(--accent); stroke-width: 2; stroke-linecap: round; }
/* 2px surface ring keeps a mark legible where it crosses the band or a rule. */
.viz-dot { fill: var(--accent); stroke: var(--bg); stroke-width: 2; }
.viz-ring { fill: var(--bg); stroke: var(--accent); stroke-width: 2; }

@media (forced-colors: active) {
  .viz-title, .viz-label, .viz-date, .viz-sub, .viz-axis { fill: CanvasText; }
  .viz-rule, .viz-leader { stroke: GrayText; }
  .viz-band { fill: GrayText; opacity: .25; }
  .viz-stem { stroke: CanvasText; }
  .viz-dot { fill: CanvasText; stroke: Canvas; }
  .viz-ring { fill: Canvas; stroke: CanvasText; }
}

/* "The quick version" summary box that opens a post: a three-sentence answer a
   phone reader can stop after. Tinted surface plus an accent rule so it reads
   as distinct from body copy without looking like the (absent) promo slot. */
.quick-version { border-left: 4px solid var(--accent); background: var(--promo-bg);
                 border-radius: 0 8px 8px 0; padding: .9rem 1.1rem; margin: 1.5rem 0 2rem; }
.quick-version p { margin: .4rem 0; }
.quick-version-label { font: 600 .75rem/1.2 system-ui, -apple-system, "Segoe UI", sans-serif;
                       letter-spacing: .08em; text-transform: uppercase; color: var(--accent); }
