: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; }
/* Wide artwork (a product lineup, say) cannot share a row with the copy:
   at the inline 96px it is a ~54px strip and its labels are unreadable.
   Banner ads stack instead, image full-width above the text. */
.promo--banner .promo-link { flex-direction: column; align-items: stretch; gap: .75rem; }
.promo--banner .promo-image { width: 100%; }
.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); }

/* ---- Press review ------------------------------------------------------
   A press-review site lists other people's work. The outlet and date are
   given the same visual weight as the headline, because which outlet
   published something and when is most of what tells a reader how to read
   it. The note is set apart: it is the only text on these pages written in
   this site's own voice. */
.press-list { list-style: none; padding: 0; }
.press-item { border-top: 1px solid var(--line); padding: 1.25rem 0; }
.press-item h3 { margin: .25rem 0 .5rem; font-size: 1.05rem; }
.press-meta { margin: 0; font-size: .8rem; color: var(--muted);
              text-transform: uppercase; letter-spacing: .04em; }
.press-outlet { font-weight: 600; }
.press-note { border-left: 3px solid var(--line); padding-left: .75rem;
              margin: .75rem 0 0; color: var(--muted); font-size: .9rem; }
