/* ledger.css: the one shared Ovrture stylesheet (Ledger v2 tokens, type, components, chrome).
   Every static page under public/ and every Astro page links this file; no page carries its own
   copy. Edit here, then run `npm run sync-chrome` so the ?v= cache-buster on every page follows the
   file. `npm run check:consistency` fails if any page drifts. Extracted September 16, 2026 from the
   byte-identical inline block that 68 of 71 pages carried; page-specific rules stay inline on their
   own page, below this link. */

/* Ovrture, Ledger v2. Tokens re-read from tokens/figma-brand.css, tokens/ledger.css, tokens/type.css and tokens/categorical.css in the design project, 7 September 2026, after Chris's revision. Single theme by design: paper and ink. Teal is interactive only; figures, headings and rows are ink. */
  :root{
  --logo-ink:#001C17; --logo-teal:#07716E; /* the 2026 lockup, 10 September 2026 */
    --paper:#FCFCFB;--paper-raise:#F5F4F1;--paper-sink:#EFEEEA;
    --ink:#101614;
    /* READING COLOUR DARKENED 11 September 2026, on Chris's artifact comment (Home thread
       005f1a2a): the grey was too light at the rebuilt type sizes. Was #586360, measured
       6.07:1 on paper, 5.67:1 on paper-raise and 5.37:1 on paper-sink, so it cleared AA and
       missed AAA on all three grounds. Now #46504D: 8.13, 7.59 and 7.19. THE RULE THIS SETS,
       and it is the half worth taking centrally: the reading colour clears AAA on every
       ground the system defines, including the row-hover sink, rather than clearing AA on
       the lightest one. Hue held on the system's own axis, the same green-slate relationship
       as before (G above R by 10, B above R by 7), so it darkens without turning neutral.
       Heading ink stays 17.84:1, so the heading-to-body step is unchanged in kind and
       narrower in degree, which is the trade. Owed to the design system. */
    --ink-body:#46504D;
    --ink-muted:#7C837F;--ink-faint:#9A948A;
    --rule:#E4E2DD;--rule-soft:#EDEBE6;
    /* Brand truth (figma-brand.css) */
    --brand-teal-mark:#00AEAA;--brand-teal-deep:#00514C;--brand-teal-shade:#0B4644;--brand-teal-ink:#113132;
    --brand-orange:#C26416;--brand-orange-lit:#D06F1E;
    /* Ledger aliases (ledger.css) */
    --teal-ink:var(--brand-teal-ink);--teal-shade:var(--brand-teal-shade);--teal-deep:var(--brand-teal-deep);
    --callout:var(--teal-deep);--callout-hover:var(--teal-shade);--focus-ring:var(--callout);
    --surface-inverse:var(--teal-deep);
    --teal:var(--callout);--teal-lit:var(--callout-hover);
    --signal-deep:#8A3414;--signal:var(--brand-orange);--signal-lit:var(--brand-orange-lit);--signal-tint:#FBEFE9;--signal-wash:#FDF7F4;
    --rule-brand:rgba(0,81,76,0.22);
    /* Categorical (categorical.css): the only place the system holds more than two hues; badges only */
    --cat-neutral:oklch(44% 0.010 190);--cat-slate:oklch(44% 0.050 250);--cat-teal:oklch(44% 0.072 190);--cat-moss:oklch(44% 0.075 155);--cat-olive:oklch(44% 0.080 115);--cat-amber:oklch(44% 0.095 75);--cat-orange:oklch(44% 0.110 50);
    --radius:2px;--radius-panel:12px;--hairline:1px;--page-max:1280px;--gutter:48px;--gutter-tight:28px;
    /* --radius-panel added 22 September 2026, per Chris's 20-21 September Ledger revision (two
       radii, no others: --radius 2px for controls, --radius-panel 12px for surfaces -- the image
       Frame, article hero/body images, the hero evidence panel, the lightbox). Confirmed today by
       a design-system specimen for the final-mile video frame, which names this token directly. */
    /* --shadow-float added 20 September 2026 (Chris, folding the homepage artifact's design-system
       audit back into the repo): the token was referenced by name in two comments below (sticky
       nav, sub-nav panels) as "the one shadow Ledger permits, for dropdowns and modals," but was
       never actually declared -- the sub-nav dropdown below carried a literal value instead. Value
       from the design system (project/README.md, design system artifact Vk6XrqTZv31beeVB3QgMtt).
       This changes the dropdown's rendered shadow from the prior literal (0 8px 24px rgba(16,22,
       20,.07)) to the system's own value below -- a visible, if small, change to confirm.
       SCOPE WIDENED 21 September 2026 (Chris, piloted on Platform's hero panel then approved
       sitewide): the "dropdowns and modals only" restriction above no longer holds. The token
       now also carries the .hero .evidence panel's shadow, everywhere that component is used
       with its default background (see that rule below). Superseded, not deleted, so the
       pilot's own history stays legible.
       SECOND USE, same day (Chris, homepage final-mile panel redesign): the .video placeholder
       component below also carries this shadow. CORRECTED later the same day: not at .hero
       .evidence's 12px radius after all -- .video uses --radius (2px), matching the site's
       existing asset-placeholder standard (.arch a.row .th img and siblings), which this token's
       shadow was already part of. Two lineages converge on the same shadow token, not one. */
    --shadow-float:0px 2px 20px 0px rgba(0,0,0,.05);
    --ease:cubic-bezier(.22,.61,.36,1);--dur:180ms;
    --font-sans:"Instrument Sans",-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif;
    --font-mono:"Azeret Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
    --font-features:'ss01' on,'ss03' on,'ss06' on,'ss07' on;
    --chrome-h:150px;
    /* Desktop display scale corrected 20 September 2026 (Chris, folding the homepage artifact's
       design-system audit back into the repo): 56/45/36/30/25 -> 60/48/39/32/26, matching the
       design system's own current values (project/README.md #4.2, design system artifact
       Vk6XrqTZv31beeVB3QgMtt) from the 11 September type rebuild -- the lag Open Ruling 1 names.
       Line height and letter-spacing were already correct; only the sizes move. Mobile scale
       (--t-d1 etc. redeclared at max-width:400px below) already matches the rebuilt scale and is
       untouched. */
    --t-d1:60px;--t-d1-lh:1.05;--t-d1-ls:-0.03em;
    --t-d2:48px;--t-d2-lh:1.021;--t-d2-ls:-0.02em;
    --t-d3:39px;--t-d3-lh:1.256;--t-d3-ls:-0.012em;
    --t-d4:32px;--t-d4-lh:1.312;--t-d4-ls:-0.005em;
    --t-d5:26px;--t-d5-lh:1.346;--t-d5-ls:-0.007em;
    --t-lead:19px;--t-lead-lh:1.48;--t-lead-ls:-0.004em;
    --t-body:16.5px;--t-body-lh:1.6;--t-body-ls:0;
    --t-small:14.3px;--t-small-lh:1.469;--t-small-ls:0.01em;
    /* PARAGRAPH SPACING, added 11 September 2026, on Chris's artifact comment (Home thread
       b7eeedeb). Ledger's rhythm standard covers section, column, band, heading and block. It has
       no value for the space between two paragraphs of one thought, so every page invented one at
       the element: 20px in the inverse close, 16px on Results, 12px and 8px in the footer stacks.
       On Home the inline 20px sat on top of the copy column's 24px flex gap, so the break INSIDE
       the thought measured 44px while the break between the headline and its own first paragraph
       measured 24px. The paragraph outranked the heading. That is what reads as awkward.
       The test a paragraph break has to pass: larger than the line gap inside the paragraph, and
       smaller than the gap between the heading and its body. Lead sets a 28.00px line box
       (19.5 x 1.436) and body sets 28.00px too (16.5 x 1.697), so one line is 28px for both
       reading steps. Small sets 21.0px (14.3 x 1.469). These are measured, not chosen. */
    /* SECOND TYPE PASS, 11 September 2026 night. The design system answered the
       accessibility change request and moved the display scale a second time. What it
       took from us verbatim: --ink-body, --rhythm-para and --rhythm-para-small,
       --focus-ring-on-dark, the accent button filling --signal-deep, the page skeleton,
       and the chrome scale, the size floor and the measure tokens below. What it added
       that we asked for and could not supply: --signal-deep-hover, the darker orange the
       accent button had no hover partner without. */
    --signal-deep-hover:#6E2910;   /* paper on it 10.29:1 */
    --accent-fill:var(--signal-deep);
    --ink-unit:#5C6663;            /* the quiet unit beside a serif figure, its own token at last */
    --focus-width:2px; --focus-offset:2px;
    /* THE CHROME SCALE. Aliases, deliberately: they resolve to real steps, so the scale
       stays one scale and the chrome moves when the scale moves. Before this the nav ran
       at 15px, the panel links and footer at 14px and the legal row at 12.5px, none of
       them on any step, because the type rebuild moved the content and left the chrome. */
    --t-nav:var(--t-small); --t-button:var(--t-small); --t-arrow:var(--t-small);
    --t-footer:var(--t-small); --t-legal:var(--t-tag);
    --t-floor:11.6px;              /* a size below the floor is a defect, not a choice */
    /* MEASURE IN PIXELS, because the target is characters and ch does not deliver them:
       ch is the width of the digit zero, and max-width:64ch rendered 76 characters. */
    --measure-lead:620px; --measure-body:560px; --measure-small:480px;
    --target-pitch-min:38px;       /* WCAG 2.5.8 passes through the spacing exception, by 2px */
    --rhythm-para:28px;--rhythm-para-small:21px;
    /* APPLIED SO FAR only to the inverse close, the container Chris flagged. A blanket
       p + p rule was written and withdrawn the same hour: most reading stacks on this site are
       flex columns that already set a gap (.sh 20, .dlhead 16, .srow .scol 16, .tb-lede 14,
       .split .copy 32, .storytext 0), so a margin rule adds to the gap instead of replacing it,
       and the same declaration produced 28px in one place and 48px in another. Measured inventory
       of paragraph breaks still outside the token, all pages, 11 September 2026:
         Results  .srow .scol   16 gap + 16 inline = 32   passes the test, not on the token
         Results  .dlhead       16 gap + 0        = 16    fails, tighter than the 28px line box
         Results  .storytext     0 gap + 16 inline = 16   fails
         Results  .lesson        0 gap + 0        = 0     fails
         Results  .sh           20 gap + 16 inline = 36   passes, not on the token
         Security .tb-lede      14 gap            = 14    fails, three pairs
         90 days  .split .copy  32 gap            = 32    passes, not on the token
         all 7    footer        20 and 12 inline           caption stack, not reading copy
       Fixing these means converting those stacks to gap:0 with explicit margins, which moves
       heading-to-body spacing on every section of every page, so it is its own pass. */
    --t-label:12px;--t-label-lh:1.17;--t-label-ls:0.16em;--t-tag:11.6px;--t-tag-lh:1.1;--t-tag-ls:0.10em;--t-caption:12.8px;--t-caption-lh:1.64;--t-caption-ls:0.025em;
    /* Accessibility override, 6 September (Chris): small mono labels and tags fail WCAG AA at Ledger's ink-faint (2.9:1) and ink-muted (3.8:1). Page uses --ink-label #6A726D, 4.5:1 on paper-raise, 4.8:1 on paper. Proposed back to Ledger v2 as a token change. */
    --ink-label:#5C6663;
    color-scheme:light;
  }
  *{box-sizing:border-box}
  body{margin:0;background:var(--paper);color:var(--ink-body);font-family:var(--font-sans);font-size:var(--t-body);line-height:var(--t-body-lh);font-feature-settings:var(--font-features);-webkit-font-smoothing:antialiased}
  a{color:var(--teal);text-decoration:none;transition:color var(--dur) var(--ease)}
  a:hover{color:var(--teal-lit)}
  a:focus-visible,button:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}
  /* SKIP LINK, added 11 September 2026. Every page put 42 or 43 focusable controls before its first
     sentence, and three pages had no main landmark to route around them either. First in the tab
     order, off-screen until focused. */
  .skip{position:fixed;left:-9999px;top:8px;z-index:200;background:var(--paper);color:var(--callout);
        font-family:var(--font-sans);font-size:var(--t-body);font-weight:500;line-height:1;
        padding:14px 20px;border:var(--hairline) solid var(--rule);border-radius:var(--radius);text-decoration:none}
  .skip:focus{left:16px}
  main:focus{outline:none}
  h1,h2,h3,p{margin:0}
  .wrap{max-width:var(--page-max);margin:0 auto;padding:0 var(--gutter)}
  .d1{font-weight:520;font-size:var(--t-d1);line-height:var(--t-d1-lh);letter-spacing:var(--t-d1-ls);color:var(--ink);text-wrap:balance}
  .d2{font-weight:540;font-size:var(--t-d2);line-height:var(--t-d2-lh);letter-spacing:var(--t-d2-ls);color:var(--ink);text-wrap:balance}
  .d3{font-weight:560;font-size:var(--t-d3);line-height:var(--t-d3-lh);letter-spacing:var(--t-d3-ls);color:var(--ink);text-wrap:balance}
  .d4{font-weight:600;font-size:var(--t-d4);line-height:var(--t-d4-lh);letter-spacing:var(--t-d4-ls);color:var(--ink);text-wrap:balance}
  .lead{font-size:var(--t-lead);font-weight:460;line-height:var(--t-lead-lh);letter-spacing:var(--t-lead-ls);color:var(--ink-body);max-width:var(--measure-lead)}
  /* .subq added 22 September 2026: a new sub-head Chris asked for under #mile's H2, sitting
     between it and .lead in .sh's existing flex column (no new spacing rule needed -- it
     inherits the 20px gap already there). Sized at --t-d5, matching the weight/size the site
     already uses for an h3 under an h2 (.article .abody h3). Explicit 600 rather than
     var(--w-semibold): that token is referenced sitewide but never defined in :root, so it
     silently falls back to inherited weight wherever it's used -- a pre-existing gap, not
     introduced here, and not fixed here since it's outside what was asked. */
  .subq{font-weight:580;font-size:var(--t-d5);line-height:var(--t-d5-lh);letter-spacing:var(--t-d5-ls);color:var(--ink);text-wrap:balance}
  .body{font-size:var(--t-body);line-height:var(--t-body-lh);color:var(--ink-body)}
  .small{font-size:var(--t-small);line-height:var(--t-small-lh);color:var(--ink-body)}
  .label{font-family:var(--font-mono);font-feature-settings:normal;font-size:var(--t-label);line-height:var(--t-label-lh);letter-spacing:var(--t-label-ls);text-transform:uppercase;color:var(--ink-label);font-weight:400}
  /* THE EYEBROW IS GREY, second type pass. Ledger's .ovr-label now resolves to
     --text-label and there is no accent tone on it. Orange as text survives in exactly
     two places in the whole system: a serif figure at d1 to d3, and a numeral. So the
     eyebrow inverts: the number carries the accent and the word runs quiet. This is
     also what closes the two-orange clash Chris caught on the demo page, where a
     corrected eyebrow at #8A3414 sat above an uncorrected label at #C26416. */
  .label.signal{color:var(--ink-label)}
  .tag{display:inline-block;font-family:var(--font-mono);font-feature-settings:normal;font-size:var(--t-tag);line-height:var(--t-tag-lh);letter-spacing:var(--t-tag-ls);text-transform:uppercase;color:var(--ink-label);background:var(--paper-raise);border:var(--hairline) solid var(--rule);border-radius:var(--radius);padding:4px 8px 3px;white-space:normal;overflow-wrap:break-word}
  /* TAGS WRAP BY DEFAULT, second type pass. white-space:nowrap is a declaration of a
     minimum width, and Ledger's own rule is that a layout holding one must be sized from
     that number. A 189px nowrap tag inside the hero panel was the last thing keeping a
     page 3px wider than a 320px viewport. A tag that genuinely cannot break opts in, and
     opting in is the signal to go and check the container that holds it. */
  .tag.nowrap{white-space:nowrap}
  .tag.teal{color:var(--ink-body);background:var(--paper-raise);border-color:var(--rule)} /* no teal tints in Ledger v2; quiet chips sit on paper-raise */
  .badge{display:inline-block;font-family:var(--font-mono);font-feature-settings:normal;font-size:var(--t-tag);letter-spacing:var(--t-tag-ls);text-transform:uppercase;color:var(--paper);border-radius:var(--radius);padding:4px 8px 3px;white-space:nowrap;font-weight:400}
  .badge.slate{background:var(--cat-slate)}.badge.cteal{background:var(--cat-teal)}.badge.moss{background:var(--cat-moss)}.badge.amber{background:var(--cat-amber)}
  .tag.signal{color:var(--signal-deep);background:var(--signal-tint);border-color:var(--signal-tint)}  /* 7.21:1 on tint */
  .tag.ph{color:var(--signal-deep);background:var(--paper);border:var(--hairline) dashed var(--signal)}
  .figure{font-weight:500;font-size:var(--t-d3);line-height:1;letter-spacing:-0.03em;color:var(--ink);font-variant-numeric:tabular-nums;white-space:nowrap}
  .figure .u{font-size:0.8em} /* non-numeric runs at 0.8em, per Ledger */

  /* Wordmark: brackets are live mono type */
  /* Logo: the 2026 lockup, drawn artwork (design system export, 10 September 2026, components/brand/logo-2026.js).
     Supersedes the type-set lockup. Letters --logo-ink, brackets --logo-teal; both --paper on the inverse.
     Nav 26px, footer 28px; both below 32px so the registered mark is cropped by the system's default rule. */
  .lockup{display:inline-flex;align-items:center;text-decoration:none;line-height:0}
  .lockup .logo{display:block;flex-shrink:0}
  .lockup .l-ink{fill:var(--logo-ink)}
  .lockup .l-teal{fill:var(--logo-teal)}
  .inverse .lockup .l-ink,.inverse .lockup .l-teal{fill:var(--paper)}
  /* Dot device: square, never round, 0.163 x the adjacent lockup height */
  .dot{display:inline-block;width:0.5em;height:0.5em;background:var(--signal);vertical-align:middle;margin:0 0.6em}

  /* Buttons: one button, tones */
  .btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;font-family:var(--font-sans);font-weight:600;font-size:var(--t-button);line-height:1;padding:14px 20px;border-radius:var(--radius);border:var(--hairline) solid transparent;cursor:pointer;transition:background-color var(--dur) var(--ease),color var(--dur) var(--ease),border-color var(--dur) var(--ease);text-decoration:none}
  .btn.primary{background:var(--teal);color:var(--paper)}
  .btn.primary:hover{background:var(--teal-lit);color:var(--paper)}
  /* Accent button: fill --signal-deep, label --paper, 7.92:1. As --signal it was 3.99:1 and could
     not pass at any label colour. NOTE FOR THE DESIGN SYSTEM: the palette holds one orange that
     passes as a ground and nothing darker, so there is no hover partner for it. Hover goes to --ink
     (17.84:1) because a lighter orange fails again. A darker orange step would fix this properly. */
  .btn.accent{background:var(--signal-deep);color:var(--paper);border-color:var(--signal-deep)}
  .btn.accent:hover{background:var(--signal-deep-hover);color:var(--paper);border-color:var(--signal-deep-hover)}  /* the palette has a darker orange now */
  .btn.secondary{background:transparent;color:var(--ink);border-color:var(--ink)}
  .btn.secondary:hover{background:var(--paper-sink)}
  .btn.inverse{background:var(--paper);color:var(--teal-ink);border-color:var(--paper)}
  /* 8 September (Chris: "rollover color on this is wrong"). The old rule read background:var(--teal-tint),
     a token that is defined nowhere in Ledger v2, so on hover the declaration was invalid, the fill fell
     back to transparent, and the dark teal band showed through a button whose text is teal-ink. It read as
     a dark green swatch. Hover now goes paper to paper-sink: color only, still light, text still legible. */
  .btn.inverse:hover{background:var(--paper-sink);color:var(--teal-ink);border-color:var(--paper-sink)}
  .btn.sm{padding:10px 14px;font-size:var(--t-button)}

  /* LinkArrow */
  .la{display:inline-flex;align-items:center;gap:8px;color:var(--ink);font-weight:500;font-size:var(--t-arrow);padding-bottom:4px;border-bottom:2px solid transparent;text-decoration:none;transition:border-color var(--dur) var(--ease)}
  .la:hover{border-bottom-color:var(--ink)}
  .la .arr{display:inline-block;transition:transform var(--dur) var(--ease)}
  .la:hover{color:var(--ink)}
  .la:hover .arr{transform:translateX(3px)}
  .la.small{font-size:var(--t-small)}
  .inverse .la{color:var(--paper)}
  .inverse .la:hover{border-bottom-color:var(--paper)}
  .inverse .la:hover{color:var(--paper)}

  /* The lead as three statements: verb in teal, statement in ink, framed by two hairlines */
  .claims{display:flex;flex-direction:column;gap:18px;max-width:var(--measure-small);padding:8px 0}
  .claims p{font-size:22px;line-height:1.3;letter-spacing:-0.012em;color:var(--ink);font-weight:400;text-wrap:pretty}
  .claims p .v{color:var(--ink);font-weight:600} /* teal marks what a reader can act on, nothing else */
  /* Nav */
  .prototype{border-bottom:var(--hairline) solid var(--rule);background:var(--paper-raise)}
  .prototype .wrap{display:flex;flex-wrap:wrap;gap:8px 24px;align-items:center;min-height:32px}
  nav.top{border-bottom:var(--hairline) solid var(--rule)}
  nav.top .wrap{display:flex;align-items:center;justify-content:space-between;gap:24px;height:72px}
  nav.top ul{list-style:none;margin:0;padding:0;display:flex;gap:28px;align-items:center}
  nav.top ul a{color:var(--ink-body);font-size:var(--t-nav)}
  nav.top ul a:hover{color:var(--ink)}
  nav.top ul a.strong{color:var(--ink);font-weight:500}
  nav.top ul a[aria-current="page"]{color:var(--ink);font-weight:500} /* the current page's entry, set by the build, 11 September */
  .navright{display:flex;align-items:center;gap:20px}

  /* Hero: 1.35fr / 1fr, argument left, evidence right */
  .hero .wrap{display:grid;grid-template-columns:1.35fr 1fr;gap:0}
  /* HERO SPACING, 10 September (Chris, Home thread 6735a4f4), the rule Home, Platform and Results carry and
     the one to converge on; lifted into the template 11 September so Integrations and The first 90 days match.
     The hero is a section and takes 72 above and below; the argument column gives up its own 88px vertical
     padding for 32, the inside-a-section value. Panel inner padding unchanged.
     HERO ALIGNMENT, 13 September (Chris, Privacy thread f262fb76, option 2 of 3): both columns changed from
     justify-content:center to flex-start. Diagnosis that led here: the two columns share one row height, but
     .arg's content length varies a lot page to page (a full headline plus a lead paragraph versus, on a page
     like Privacy, a short "In brief" label plus three rows), so centering each column independently in the
     same box left their content starting at different heights whenever one side was shorter than the other.
     Top-aligning both means their first lines always land together regardless of how much either column
     holds. Flagged first on About (build notes, same defect, filed as a design-system question rather than a
     per-page fix) and confirmed a second time on Privacy; fixed here once, at the template, rather than a
     third time on whatever page finds it next. Applies to every page built from this template; ported to
     Home, Platform and Results is still open, since those three are edited at the artifact level and do not
     rebuild from this file (see PROJECT-STATE.md). */
  .hero{padding:72px 0}
  .hero .arg{padding:32px 64px 32px 0;display:flex;flex-direction:column;gap:32px;justify-content:flex-start}
  .hero .arg .ctas{display:flex;align-items:center;gap:28px;flex-wrap:wrap;margin-top:8px}
  /* Rounded corners, shadow and hairline added 21 September 2026 (Chris): piloted on the
     Platform page's Contents panel (border-radius:12px, well past the --radius:2px token used
     on buttons and tags, since a panel this size needs a scale of its own; box-shadow using
     --shadow-float, see that token's comment above for the scope change; a 1px --signal-deep
     rule so the panel doesn't read muddy against the raised ground it usually sits on), then
     approved sitewide. The homepage explicitly opts back out (its own page-local .hero .evidence
     override already drops the background box entirely for the illustration slot; it now also
     zeroes these three so no frame appears around that illustration). */
  .hero .evidence{background:var(--paper-raise);padding:72px 36px;display:flex;flex-direction:column;justify-content:flex-start;gap:8px;position:relative;border-radius:12px;box-shadow:var(--shadow-float);border:var(--hairline) solid var(--signal-deep)}
  /* Bracket watermark removed 6 September (Chris). */
  .hero .evidence > *{position:relative}

  /* MetricPanel and StatRow */
  .metric-panel{background:var(--paper-raise);padding:8px 0}
  .stat{display:grid;grid-template-columns:auto 1fr;gap:24px;align-items:baseline;padding:20px 0;border-bottom:var(--hairline) solid var(--rule-soft)}
  .stat:last-child{border-bottom:0}
  .stat .prov{text-align:right;color:var(--ink-body);font-size:var(--t-small);line-height:1.5}
  .stat .prov .tag{margin-left:8px;vertical-align:middle}
  .stat.signal .figure{color:var(--ink)}  /* SW-35, September 23, 2026 */

  /* Sections. THE RULE (Chris, 7 September): one separator per section boundary, full width, and inside a section only Ledger components draw their own lines (ModelRow stacks, StatRows). Nothing else.
     From 9 September the separator is a change of ground, not a hairline: see ALTERNATING GROUNDS below. Bands, the inverse block and the footer keep their hairlines because they are not sections. */
  html{overflow-x:hidden}
  @media (max-width:400px){:root{--gutter:var(--gutter-tight)}}
  section,.inverse,footer,.band{border-top:var(--hairline) solid var(--rule)}
  .inverse{border-top:0}
  /* VERTICAL RHYTHM STANDARD, ruled 9 September (Chris: "let's develop a standard and stick to it").
     Four values were in use across the page: 96, 72, 44 and 0. Now four rules, every value on Ledger's
     own space scale, and nothing between them:
       72px  section padding, top and bottom, every section without exception
       44px  band padding, for a full-bleed strip that is not a section (the client band, the Results
             facts band), and the section heading block (.sh) to the body beneath it
       32px  block to block inside a section, and body to closing link
       48px  any gap between columns inside a section
     Sections that set their own inner padding (the hero and the inverse band) use 72 as well.
     Applied values, checked 10 September against all three built pages: section 72, .sh 44, band 44,
     column gap 48. Spacing inside a component (a subhead after a table, a row's own padding) follows
     the component's tuning and is not governed here. If one of the four gaps above carries another
     number, it is a defect, not a choice. */
  section{padding:72px 0}
  section.tight{padding:72px 0} /* now identical to the default; retire the class on the next pass */
  .sh{display:flex;flex-direction:column;gap:20px;padding-bottom:44px;margin-bottom:0} /* was 44 + 8 = 52 on all three pages, a value outside the standard; 10 September */
  .sh .lead{max-width:var(--measure-lead)}
  .two{display:grid;grid-template-columns:1fr 1fr;gap:96px;align-items:start}

  /* ModelRow: index, name, sentence, tag on a ruled grid; bleeds 24px */
  .rows{list-style:none;margin:0;padding:0;border-top:var(--hairline) solid var(--rule-soft)}
  /* SW-34, September 23, 2026 (staging audit; README 9, "Ruled rows on pages use ModelRow; the 17px dense
     row and the serif-name row are refused"): the ModelRow, every property. Index 52px, name column 140 to
     200px, sentence, tag; 24px gaps; 20px by 24px padding. Name at d5 (26px, 580), sentence at lead (19px,
     460). Was 56 / 200 / 1fr / auto at 32px gaps and 28px padding, with a 17px, 600 name. */
  .row{display:grid;grid-template-columns:52px minmax(140px,200px) 1fr auto;gap:24px;align-items:center;padding:20px 24px;margin:0 -24px;border-bottom:var(--hairline) solid var(--rule-soft);transition:background-color var(--dur) var(--ease)}
  .row:hover{background:var(--paper-sink)}
  .row .idx{font-family:var(--font-mono);font-feature-settings:normal;font-size:var(--t-label);letter-spacing:var(--t-label-ls);color:var(--signal-deep)}  /* was --signal, 3.72:1 at 12.5px on paper-raise. Now 7.39:1. */
  .row .name{font-weight:580;font-size:var(--t-d5);line-height:var(--t-d5-lh);letter-spacing:var(--t-d5-ls);color:var(--ink)}
  .row .sent{font-size:var(--t-lead);font-weight:460;line-height:var(--t-lead-lh);letter-spacing:var(--t-lead-ls);color:var(--ink-body);max-width:var(--measure-lead)}
  .row .tags{display:flex;gap:8px}

  /* Section 1: illustration beside the quotes (Chris, 7 September) */
  .words-grid{display:grid;grid-template-columns:1fr 1.2fr;gap:0}
  .illo-wrap{display:flex;align-items:center;justify-content:center;padding:12px 48px 12px 0}
  .illo{display:block;width:100%;max-width:520px;height:auto}
  .words-grid .quotes{grid-template-columns:1fr;gap:32px;padding:44px 0 44px 56px}
  /* Quote: 2px signal edge */
  .quotes{display:grid;grid-template-columns:repeat(3,1fr);gap:48px}
  .quote{border-left:2px solid var(--signal);padding:4px 0 4px 24px;display:flex;flex-direction:column;gap:16px}
  .quote p{font-size:var(--t-lead);font-weight:460;line-height:1.30;color:var(--ink);letter-spacing:-0.004em}  /* SW-18, September 23, 2026: the Quote guide, lead at 1.30, because a quote is read as one object */
  .quote .who{font-family:var(--font-mono);font-feature-settings:normal;font-size:var(--t-tag);letter-spacing:var(--t-tag-ls);text-transform:uppercase;color:var(--ink-label)}  /* SW-18: attribution at tag, 11.6px at 0.10em */
  .quote .who span{color:var(--ink-label)}

  /* Thin ruled band, security */
  .band{border-top:var(--hairline) solid var(--rule);border-bottom:var(--hairline) solid var(--rule)}
  .band .wrap{display:grid;grid-template-columns:200px 1fr auto;gap:48px;align-items:center;padding-top:44px;padding-bottom:44px}

  /* Inverse band */
  .inverse{background:var(--surface-inverse);color:var(--paper)}
  .inverse .wrap{display:grid;grid-template-columns:1.35fr 1fr;gap:48px;align-items:center;padding-top:72px;padding-bottom:72px}
  .inverse .d2,.inverse .d3{color:var(--paper)}
  /* Bumped to full opacity and weight, 21 September 2026, on Chris's artifact comments (9541d71,
     f4079de) on The first 90 days' review: the documented .78-opacity value (6.13:1 on teal-deep,
     --label-on-teal) cleared AA but still read soft. Full opacity alone (8.97:1, clears AAA) was
     not enough either -- light text at the base .lead weight (460) suffers the halation effect
     light-on-dark type is known for even at high contrast ratios, reading thinner than the same
     weight does in dark-on-light. Weight up to 500 (one step under ModelRow's 600 .name treatment)
     compensates without turning the close's lead paragraph into a second heading. Site-wide: this
     lives in the one shared ledger.css, so every page's inverse close picks it up. */
  /* SW-30, September 23, 2026 (staging audit, ruled by Chris): back to the lead's own 460. This reverses
     the 21 September bump to 500 above; the most recent ruling wins. Paper on teal is 8.97:1 either way. */
  .inverse .lead{color:var(--paper);font-weight:460}
  .inverse .label{color:var(--label-on-dark)}  /* was --signal-lit, 2.62:1 on teal. The contrast table already barred it. --label-on-teal until September 23 (SW-08). */
  /* The inverse close's copy column (Results thread 8516cd26). REBUILT 11 September 2026 on
     Chris's comment (Home thread b7eeedeb). It was a flat 24px flex gap between every child, with
     an inline 20px on the second paragraph making that one break 44px. Now the three gaps are
     ordered and each is a named value: the eyebrow stays tight on its headline at 24, the headline
     clears its body at 44 (Ledger's heading-to-body value), and two paragraphs sit one line apart
     at 28. 44 > 28 > 24, so the reader gets the strongest break where the thought starts. */
  .inverse .copy{display:flex;flex-direction:column;gap:0}
  .inverse .copy .label{margin-bottom:24px}
  .inverse .copy h2{margin-bottom:44px}
  .inverse .copy p + p{margin-top:var(--rhythm-para)}
  .inverse .actions{display:flex;gap:16px;justify-content:flex-end;flex-wrap:wrap}
  .inverse a:focus-visible,.inverse button:focus-visible{outline-color:var(--focus-ring-on-dark)}  /* 8.97:1 on teal */
  .inverse .small{color:rgba(252,252,251,.55)}

  /* SectorRow */
  .sectors{display:grid;grid-template-columns:repeat(3,1fr);border-top:var(--hairline) solid var(--rule)}
  .sector{padding:44px 32px 40px;border-right:var(--hairline) solid var(--rule);display:flex;flex-direction:column;gap:12px}
  .sector:first-child{padding-left:0}
  .sector:last-child{border-right:0}
  .sector .idx{font-family:var(--font-mono);font-feature-settings:normal;font-size:var(--t-label);letter-spacing:var(--t-label-ls);color:var(--signal-deep)}

  /* Footer */
  footer{border-top:var(--hairline) solid var(--rule);padding:72px 0 40px}
  footer .cols{display:grid;grid-template-columns:1.6fr 1fr 1fr;gap:48px} /* three columns since 11 September: the lockup, the six pages, the resources */
  footer ul{list-style:none;margin:16px 0 0;padding:0;display:flex;flex-direction:column;gap:10px}
  footer ul a{color:var(--ink-body);font-size:var(--t-footer)}
  /* SW-17, September 23, 2026: the definition line and the audience line under the footer lockup carried
     inline max-width:40ch. Measures are px (README 4.4), and inline styles cannot be fanned out or checked. */
  footer .cols p.body{margin-top:20px;max-width:var(--measure-small);color:var(--ink)}
  footer .cols p.small{margin-top:12px;max-width:var(--measure-small);color:var(--ink-body)}
  footer address{font-style:normal;color:var(--ink-body);font-size:var(--t-footer);line-height:1.6;margin-top:20px}
  footer .legal{display:flex;justify-content:space-between;gap:24px;flex-wrap:wrap;border-top:var(--hairline) solid var(--rule);margin-top:56px;padding-top:24px}
  footer .legal .label{color:var(--ink-label);font-size:var(--t-legal);letter-spacing:var(--t-tag-ls)}  /* SW-13, September 23, 2026: the legal line is tag, 11.6px at 0.10em; it was carrying the label's 0.16em */
  /* Was margin-left:20px on each link, which held the row at 295px against 264px of available width
     at a 320px viewport and gave every page a 3px horizontal scroll, a WCAG 1.4.10 failure. Ledger
     already states the rule this broke: non-wrapping content sets a hard minimum width. */
  footer .legal .label:last-child{display:flex;flex-wrap:wrap;gap:4px 8px;min-width:0}
  footer .legal .label a{color:var(--ink-label);display:inline-flex;align-items:center;min-height:24px}  /* SW-03, September 23, 2026: 24px targets on phones, WCAG 2.5.8 */
  /* Separator dot added 21 September 2026, on Chris's instruction: the 21 September footer relabel
     (Terms of this website / Platform Privacy / Platform Accessibility, src/chrome/footer.html) swapped
     one-word links for two- and three-word ones, and pure whitespace no longer read as three distinct
     items at a glance (his own screenshot of the deployed row showed the problem). Reuses the site's
     one existing separator glyph rather than inventing a new one: the build-stamp script two lines
     below this rule already joins its two segments with the same middot ('\u00b7'). Lives on ::before
     so it's presentational only, not read by assistive tech as list content, and stays inside the
     wrapping <a> it's attached to, so it never forces the 320px-reflow failure the rule above this one
     already fixed once -- confirmed each label's own text (longest: "Platform Accessibility") is well
     under a 320px column on its own, so per-item wrap still carries the narrow-viewport case. Gap
     trimmed from 20px to 8px since the dot's own margin now supplies part of the visual spacing;
     unchanged total is roughly the old 20px, split across gap + dot margins. */
  footer .legal .label:last-child a:not(:first-child)::before{content:"\00b7";margin-right:8px;color:var(--ink-faint)}

  /* ---- Energy layer, revised 7 September against Ledger v2. Kept: running section numbers, chapter names at d4, first-row emphasis through scale steps only, color-only hover, the one accent CTA. Removed: signal ticks (orange budget), off-scale sizes, reveal-on-scroll and any lift (Ledger: nothing scales, lifts or fades in on scroll). ---- */
  .label .n{color:var(--signal-deep);margin-right:14px}  /* the numeral keeps the accent */
  .inverse .label .n{color:var(--label-on-dark)}
  /* 8 September (Chris): the three statements drop from d4 (26px) to lead (17px) with more space between
     them, to put calm and white space back into the hero. Lead is the step below d4 in Ledger v2; there is
     nothing between the two, so this is the in-system reduction rather than a chosen number. */
  .claims p{font-size:var(--t-lead);line-height:var(--t-lead-lh);letter-spacing:-0.004em;font-weight:460}  /* SW-30, September 23, 2026: the lead, every property (was 400 at 1.6) */
  .claims{gap:16px;padding:20px 0;max-width:var(--measure-small)}  /* SW-17, September 23, 2026: measures are px (README 4.4); was 46ch */
  .hero .metric-panel .figure{font-size:var(--t-d2);letter-spacing:var(--t-d2-ls)}
  .hero .metric-panel{padding-top:8px}
  /* 22 September 2026: rebuilt to the design-system specimen Chris supplied (image), replacing
     the prior hand-tuned 253/236/1fr + asymmetric-gap layout. 24px gap, 24px padding, -24px bleed
     (all already the row's inherited base), --rule-soft between rows, none on the last row (see
     #mile .row:last-child below).

     COLUMN ORDER REVERSED 22 September 2026, later the same day, on Chris's ruling, and this
     supersedes the specimen's 240/210/1fr. The videos became click-to-open destinations when the
     playback model was settled that afternoon: they open large and play once with the visitor's
     full attention. An illustration belongs beside what it illustrates; a destination belongs at
     the end of the path the reader takes. So the row now runs stage and name, sentence, then the
     video, and the DOM order matches, which also puts the video last when the row stacks on
     mobile. Chris ruled the opposite way this morning in 2f84b5a ("so it leads each row instead
     of trailing it"), before the playback question was settled; the most recent ruling wins, per
     the 10 September precedence rule, and the reason it changed is recorded here so the earlier
     arrangement is not restored as a fix.

     A side effect worth knowing: 210 + 240 + 48px of gaps is the same total as before, so the
     sentence column is unchanged at 686px and still capped by --measure-lead at 620px. Measured,
     not assumed. The row is also now the shape of Ledger's own badge-led ModelRow (badge, name,
     sentence, trailing column), which the video-first arrangement was a deviation from. */
  #mile .row{grid-template-columns:210px 1fr 240px;gap:24px;padding:28px 24px;align-items:center}
  #mile .row:last-child{border-bottom:0}
  /* ROW NAME RETURNED TO d5, 11 September 2026, on Chris's artifact comment (Home thread
     05281f78): too large at the rebuilt sizes. It was tuned at d4 when d4 was 26px; the type
     rebuild moved d4 to 32px and carried the row name with it, six pixels nobody chose. d5 is
     26px in the new scale, so this restores the rendered size that was approved, using a real
     scale step rather than an invented number, and weight follows d5 at 580. Applies to every
     row name that took the same jump. Owed to the design system as a note on ModelRow: a row
     name is a label inside a list, not a chapter name, and d5 is where it belongs. */
  #mile .row .name{font-size:var(--t-d5);font-weight:580;letter-spacing:var(--t-d5-ls);line-height:var(--t-d5-lh)}
  /* ROW SENTENCE MATCHED TO THE LEAD, 11 September 2026, on Chris's artifact comment (Home
     thread c91c9fd4): colour to match the copy under the headline, leading tightened, size at that
     paragraph or slightly smaller. The colour already matched exactly, both --ink-body, measured
     rgb(70,80,77) on each. What differed was weight (400 against the lead's 460), leading (1.697
     inherited from body against the lead's 1.436, 33.09px against 28.00px) and tracking (none
     against -0.004em). Size stays at lead: the scale's next step down is body at 16.5px, a 15%
     drop rather than a slight one, and 1.436 leading on 16.5px text falls under the 1.5 that
     WCAG 1.4.8 asks of paragraph text, where at 19.5px it is large text and does not. So the row
     sentence now IS the lead, every property, no new numbers. */
  #mile .row .sent{font-size:var(--t-lead);font-weight:460;line-height:var(--t-lead-lh);letter-spacing:var(--t-lead-ls);color:var(--ink-body);max-width:var(--measure-lead)}
  #mile .row .tags{align-self:center}
  #before .row .name{font-size:var(--t-d5);font-weight:580;letter-spacing:var(--t-d5-ls);line-height:var(--t-d5-lh)}
  .row{transition:background-color var(--dur) var(--ease)}
  .row:hover .idx{color:var(--ink)}  /* was --signal-lit, 3.03:1 on the hover sink. Now 15.77:1. */
  .inverse .wrap{padding-top:72px;padding-bottom:72px} /* was 112, off the standard */
  /* Mark field: the lockup past its frame, cropped to texture, burnt orange. One per view. Near the source's 321:190 frame. */
  .markfield{position:relative;overflow:hidden;aspect-ratio:321/190;background:var(--paper);border-right:var(--hairline) solid var(--rule)}
  .markfield svg{position:absolute;inset:0;width:100%;height:100%;display:block}
  .markfield text{font-family:var(--font-sans);font-weight:400;fill:var(--signal)}
  /* Video frame, rebuilt 22 September 2026 to a design-system specimen Chris supplied (image),
     replacing everything from the three prior rounds: no more per-category fill, no more play
     button on the live page. The specimen has two states -- this one (hatched, "video pending")
     is the actual current page content; a second state (ink-filled poster + a 44px play control)
     was in the same image explicitly labeled "specimen, not page content," so it is NOT built
     here. Build it when real video posters exist. Frame: 240x150 fixed (16:10, not the previous
     16:9), --radius-panel (12px, new token -- see :root) and --shadow-float, per the spec. */
  .mile-head{padding-bottom:32px;margin-bottom:0}
  /* .mile-cast, added 22 September 2026: the one line that introduces the donor before the four
     rows start. It reuses .lead's exact metrics rather than inventing a step, because it is the
     same register as the section lead above it and a second size here would read as a new level.
     A lead-in, not a heading: this section already runs h2.d2 then h3.subq then p.lead, and the
     ruling was to set the donor up without adding a fourth heading level. 48px above (16 here plus
     .mile-head's own 32) and 32px below, so the block sits closer to what it introduces than to
     the section head. The name takes --ink at 600 and the sentence stays --ink-body, the same
     name-then-sentence contrast .row .name and .row .sent already use one level down.
     Portrait added the same day: 180px square, 12px radius and --shadow-float, the identical
     frame the four .video slots carry below, so this block reads as the parent of that column
     rather than a new kind of object. The class year takes --signal-deep and is the only accent
     in the block. Mobile stacks and the portrait drops to 140px. */
  .mile-cast{display:grid;grid-template-columns:180px minmax(0,1fr);gap:28px;align-items:center;margin:16px 0 32px}
  .mile-cast-por{display:block;width:180px;height:180px;object-fit:cover;border-radius:var(--radius-panel);box-shadow:var(--shadow-float)}
  .mile-cast-copy{min-width:0}
  /* .mile-eyebrow: the Eyebrow component doing the job it is specified for, "above a heading or
     on a block." It moved down here from the section head on 22 September, where "One donor, one
     year" had been describing a definition paragraph that is not about one donor at all; above
     Diana it is true where it stands, and it is the gear change from the idea to the person. It
     takes the plain .label colour with no accent: the block already spends its one accent on the
     class year, and a second would break the 90/7/3 ratio the system tests a view against. */
  .mile-eyebrow{margin:0 0 10px}
  .mile-cast-name{margin:0 0 10px;font-size:var(--t-d4);font-weight:600;line-height:var(--t-d4-lh);letter-spacing:var(--t-d4-ls);color:var(--ink)}
  .mile-cast-name .yr{color:var(--signal-deep)}
  .mile-cast-sent{margin:0;max-width:var(--measure-body);font-size:var(--t-lead);font-weight:460;line-height:var(--t-lead-lh);letter-spacing:var(--t-lead-ls);color:var(--ink-body)}
  .mile-head .sh{border-bottom:0;padding-bottom:0;margin-bottom:0}
  /* margin:0 added 22 September 2026 (same-day fix): <figure> carries a UA default margin
     (1em 40px in Chrome) that nothing here reset. It pushed .video 40px right and let it
     overflow into the .mile-copy column, overlapping the stage label and name -- caught in
     a deployed screenshot. */
  .video{position:relative;width:240px;margin:0;aspect-ratio:16/10;display:block;overflow:hidden;border-radius:var(--radius-panel);box-shadow:var(--shadow-float)}
  /* .video.pending: hatch is the system's pending state, not a colour choice (Chris's own words
     on the spec) -- a diagonal --rule-soft stripe on --paper-raise, --rule hairline border, no
     brand colour of any kind. Two centered lines ("Gather" / "Video pending") in --ink-label, the
     token already adopted sitewide for small mono text needing AA contrast on paper-raise. */
  .video.pending{background-color:var(--paper-raise);background-image:repeating-linear-gradient(45deg,var(--rule-soft) 0,var(--rule-soft) 1px,transparent 1px,transparent 9px);border:var(--hairline) solid var(--rule)}
  .video .pending-copy{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;text-align:center;font-family:var(--font-mono);font-feature-settings:normal;text-transform:uppercase;color:var(--ink-label)}
  .video .pending-copy .stage{font-size:11.6px;letter-spacing:0.10em;font-weight:500}
  .video .pending-copy .status{font-size:11.6px;letter-spacing:0.10em;font-weight:400}
  /* Category fill on the video box itself: tried 22 September 2026, reverted same day (Chris:
     "make the Labels the colored box"). Boxes are back to the neutral pending hatch below; the
     color now lives on the stage badge instead (see .stage-badge and the mile-copy markup below). */
  @media (max-width:960px){.video{width:100%}}
  /* Stage label restored as its own element, 22 September 2026, per spec -- sitting above .name in
     a new .mile-copy column. First built as plain mono text in --signal-deep (uniform across all
     four rows); reverted same day to the sitewide .badge component, colored per category (Chris:
     "make the Labels the colored box"); rebuilt again same day, third pass, to a design-system
     README (v27): the sitewide filled .badge is retired for stage labels in favor of .stage-badge
     below. Renamed from .mile-badge on 22 September, later the same day, when the same design was
     applied to /platform/'s .caps4 columns: it is a two-page stage component now, not a #mile one.
     Filled .badge stays as-is for /integrations/, whose badges are connection status, not stages.
     align-items:flex-start added with the same rebuild: .badge (inline-block, but a flexblockified
     as a flex-column child) stretched to the column's full 210px instead of hugging its text --
     the README's own diagnosis of the retired class's drift. */
  .mile-copy{display:flex;flex-direction:column;align-items:flex-start;gap:6px}
  /* .stage-badge, added 22 September 2026 per the same README (section on "the ruling" and "what to
     build"): Chris ruled #C26416 (--signal) belongs to Steward but fails AA filled at every label
     colour tried (paper 3.99:1, --ink 4.47:1, --teal-ink 3.40:1, all under the 4.5:1 floor) -- so
     all four badges go outline instead of filled. Three carry one colour for both edge and label;
     Steward is the split pair the ruling calls for: --signal edge (3.99:1 against a 3:1 non-text
     floor -- a graphic/edge use is exempt from the text floor per section 3.3, in force since 11
     September) and --signal-deep label (7.92:1). Geometry precise to the README's measured render:
     26px tall (via box-sizing + explicit height, not derived from line-height, so it holds
     regardless of font metrics), 4px 8px padding, mono 12px/500 at 0.06em -- all three corrections
     to what .badge actually computed to (11.6px at 0.10em, 4px 8px 3px). Radius kept at --radius
     (2px): the README's drift list doesn't flag it, and it matches the site's own controls-radius
     rule. The optional step number (section "Optional") is dropped -- the README's own "what to
     build" code block ships without it, and the numbered version was shown only on the specimen
     row, not the live rows. */
  .stage-badge{display:inline-flex;align-items:center;box-sizing:border-box;height:26px;padding:4px 8px;background:var(--paper);border:2px solid;border-radius:var(--radius);font-family:var(--font-mono);font-feature-settings:normal;font-size:12px;font-weight:500;letter-spacing:0.06em;line-height:1;text-transform:uppercase;white-space:nowrap}
  .stage-badge.slate{border-color:var(--cat-slate);color:var(--cat-slate)}
  .stage-badge.signal{border-color:var(--signal);color:var(--signal-deep)}
  .stage-badge.teal{border-color:var(--cat-teal);color:var(--cat-teal)}
  .stage-badge.amber{border-color:var(--cat-amber);color:var(--cat-amber)}
  /* The four stage hues are fixed by the design system (README 3.6 and 17, ruled 22 September 2026):
     Gather slate, Steward signal, Cultivate teal, Learn amber, on any surface that shows the four
     stages. Steward carries the brand orange as an outline only, never filled. Home's #mile rows and
     /platform/'s .caps4 columns both use this; a fifth stage would take the next free hue in wheel
     order. No moss variant exists here on purpose: /platform/ read Steward as .badge.moss (filled)
     until 22 September, which was both the wrong hue and the failing filled treatment. */
  #before .row{grid-template-columns:56px 320px 1fr auto}
  #before .row .tags a{white-space:nowrap}
  /* .video .poster-side/.poster-body rules dropped 22 September 2026: that markup no longer
     exists (superseded by the pending-hatch frame above), so this override had nothing left to
     target. */
  @media (max-width:960px){#before .row{grid-template-columns:40px 1fr}}
  @media (prefers-reduced-motion:reduce){*{transition:none!important}}
  @media (max-width:960px){
    .wrap{padding:0 var(--gutter-tight)}
    :root{--t-d1:46px;--t-d2:37px;--t-d3:32px;--t-d4:27px;--t-d5:22px}
    .mile-cast{grid-template-columns:1fr;gap:18px}
    .mile-cast-por{width:140px;height:140px}
    #mile .row{grid-template-columns:1fr;gap:10px}
    #mile .row .sent{grid-column:1}
    /* Video is LAST in the DOM again as of 22 September 2026, so on mobile it stacks under the
       sentence with no order property, which is the reading order the reorder was made for: read
       the stage, read what happened, then open the video. The 21 September order:-1 hack and the
       margin-bottom that followed it are both gone. */
    #mile .row .video{margin-top:4px}
    .words-grid{grid-template-columns:1fr!important}
    .illo-wrap{padding:24px 0}
    .hero .wrap{grid-template-columns:1fr}
    .hero{padding:48px 0 64px} /* stacked: nav, 48 paper, argument, 48, the panel edge to edge, 64 paper, the dark strip */
    .hero .arg{padding:0 0 48px}
    .hero .evidence{margin:0 calc(-1 * var(--gutter-tight));padding:48px var(--gutter-tight)}
    .two{grid-template-columns:1fr;gap:48px}
    .row{grid-template-columns:40px 1fr;gap:12px 20px}
    .row .sent{grid-column:2}
    .row .tags{grid-column:2}
    .quotes{grid-template-columns:1fr}
    .band .wrap{grid-template-columns:1fr;gap:20px}
    .inverse .wrap{grid-template-columns:1fr}
    .inverse .actions{justify-content:flex-start}
    .sectors{grid-template-columns:1fr}
    .sector{border-right:0;border-bottom:var(--hairline) solid var(--rule);padding-left:0}
    footer .cols{grid-template-columns:1fr 1fr}
    section{padding:64px 0}
  }
  /* Hero facts, 8 September: 2x2 ruled grid replaces the StatRow stack (Chris: qualifiers too small and muted) */
  /* FactGrid redesigned 9 September. The old version drew a --rule-soft box around the grid and a hairline
     between every tile. On --paper-raise those lines measure 1.08:1, which is under the threshold where a line
     reads as a line at all, so it looked like an artefact rather than a decision (thread a57aef47: "a ghost of
     something"). Ledger's own idiom for a figure is StatRow, "one figure and its provenance, on a hairline",
     so the box is gone and each row of figures now sits on one continuous --rule line running the full width of
     the panel. No vertical divider: the 48px column gap does that, which is the standard column gap. The
     called-out figure keeps its 3px --signal left edge, and with the box gone that edge is the only outer mark
     on the panel, so it reads as emphasis rather than as part of a frame. */
  /* FactGrid, third pass, 9 September (thread ed9f44a9). Chris: drop the rules for the stats altogether, and
     either reverse the first stat out of a box or set its type in burnt orange. Taking the orange. The box would
     be a filled tile inside a panel, and Ledger's material rule is "no cards"; orange is the system's attention
     value and there is already precedent for it on this page, where the client band sets 65+ in orange inside an
     ink sentence. So: no rules anywhere in the panel, no callout edge, and the called-out figure carries the
     color. The raised panel ground is the only frame, which is what MetricPanel is for.
     Contrast: --signal #C26416 on --paper-raise is 3.72:1, which fails AA for normal text and passes the 3:1
     large-text floor, so the 44px figure may take it and the 17px qualifier may not. The qualifier stays ink.
     If the qualifier should be orange too it has to be --signal-deep, 7.39:1. */
  .facts2{display:grid;grid-template-columns:1fr 1fr;column-gap:36px;row-gap:32px;border:0;margin-top:12px}
  .fact2{display:flex;flex-direction:column;gap:10px;padding:0;border:0}
  /* 9 September (thread e291391e, Chris): the four hero figures are set in DM Serif Display. This is a
     deviation from Ledger v2, whose type rule is "Display and text: Instrument Sans. Mono: DM Mono. No serif."
     Scoped to .fact2 .figure, so it is these four numbers and nothing else on the site; every other figure,
     heading and label still runs Instrument Sans. It goes to the design system as either a scale addition
     (a display-figure face) or a recorded page exception. Andrew's call, not mine, and not the page's.
     Mechanics: DM Serif Display ships one weight, 400, so the figure's 500 does not apply and the face renders
     at its own single weight. Tracking eased from -0.030em to -0.012em because the sans figure's tighter
     setting closes up a high-contrast serif at 44px. Tabular numerals are kept in the declaration; the face
     may not carry the feature, in which case it is ignored rather than broken. */
  /* Serif face changed 9 September (thread e291391e). Chris kept the serif and asked for the best companion
     to DM Mono, so the choice was made on register and on weight range rather than on family branding.
     Source Serif 4 at 600: moderate contrast and a rational skeleton, which agrees with DM Mono instead of
     fighting it, and a real weight axis so the figure can be set for presence. DM Serif Display and Instrument
     Serif are both single-weight high-contrast display faces that read editorial; this page is read by a
     procurement officer. Measured at 58px: Source Serif 4 600 sets "25,000+" at 188px, against 177 for DM
     Serif Display, 195 Newsreader, 202 Instrument Serif and 174 Spectral, so the panel's padding and column
     gap came down from 48 to 36 to give it 198px of column. */
  .fact2 .figure{font-family:var(--font-serif);font-weight:600;font-size:var(--t-d1);letter-spacing:-0.014em}
  /* Units, 10 September, the Results rule applied to every FactGrid: a glyph that is part of the number
     (%, +, K, M, $) is set in the markup with no span and runs full size, weight and color; a context
     phrase (" / 5", "of 58") sits in .u and is quiet: 0.34em, weight 400, --ink-body (7.59:1 on
     paper-raise). Home carried "+" and "%" at 0.58em until this pass, which broke each number in half. */
  .fact2 .figure .u{font-size:0.5em;font-weight:400;letter-spacing:-0.002em;color:var(--ink-unit)}
  .fact2 .qual{font-size:var(--t-lead);line-height:1.4;color:var(--ink);font-weight:500;letter-spacing:-0.008em;max-width:16ch}
  /* 8 September (Chris: "stop caveating the hell out of this... we can show the receipts if challenged"):
     the four source lines are gone from the tiles and the panel label with them. Provenance is unchanged and
     still complete, in each tile's data-source attribute, which is where the Ledger content rule puts it
     ("every figure carries provenance in the page source"). The assumptions link below the grid is the
     visible receipt. The .src rule stays defined because the client band uses it. */
  .fact2 .src{font-family:var(--font-mono);font-feature-settings:normal;font-size:var(--t-tag);letter-spacing:var(--t-tag-ls);text-transform:uppercase;color:var(--ink-label);margin-top:auto;padding-top:6px} /* no longer used on the home page: the four source lines were removed from the markup 8 September. Rule kept for any future Stat that needs a visible source. */
  .fact2 .src .tag{margin-left:6px;vertical-align:middle}
  /* Desktop-only. Until September 16, 2026 this rule sat at top level after the 960px block above and
     silently overrode the mobile padding (48px 28px) on every page, so hero panels kept 96px of side
     padding at 320px. Scoped to widths above the mobile breakpoint; desktop rendering is unchanged. */
  @media (min-width:961px){.hero .evidence{padding:64px 48px}}
  nav.top ul{gap:24px}
  /* Between 960 and 1180 the 58px figure was setting the column width itself, with zero slack: the panel was
     being sized by the number rather than the reverse. Trimming the column gap 48 to 32 there returns 16px to
     each column, so a longer figure cannot push the layout. */
  @media (max-width:1180px){.facts2{column-gap:32px}}
  @media (max-width:960px){.facts2{grid-template-columns:1fr 1fr;column-gap:32px;row-gap:28px}}
  /* 9 September: figures at --t-d1 (58px) need 172px each. Below 640 the panel is too narrow to carry two of
     them side by side, so the grid goes to one column there rather than pushing the page sideways. */
  @media (max-width:640px){.facts2{grid-template-columns:1fr;row-gap:24px}}
  .fact2.callout{border:0;padding-left:0}
  .fact2.callout .figure{color:var(--ink)}  /* SW-35, September 23, 2026 (ruled by Chris): every figure is ink; the one --signal figure on the site is the Ovrture side of the Results cost comparison */
  /* Sticky nav, 8 September (Chris). No shadow (Ledger: --shadow-float is for dropdowns and modals only); the hairline carries the edge. */
  /* Moved to header.site September 23, 2026 (SW-06): the header now wraps the nav, and a sticky child
     cannot outlast a parent its own height. */
  header.site{position:sticky;top:0;z-index:50;background:var(--paper)}
  nav.top{background:var(--paper)}
  /* Video poster: a rendered platform frame fills the frame above the caption strip */
  .video .poster-img{position:absolute;top:0;left:0;right:0;bottom:44px;overflow:hidden;background:var(--paper-raise)}
  .video .poster-img img{display:block;width:100%;height:100%;object-fit:cover;object-position:top center}
  .video .cap .metatags{display:flex;gap:8px;align-items:center;flex-shrink:0}

  /* Final-mile rows, 8 September (Chris): the capability badge replaced the row index as the
     row's organizing label. REVISED 21 September 2026: badge removed, its word moved inside the
     video. REVISED AGAIN 22 September 2026 (twice, same day): design-system spec moved it out to
     a plain-text .stage-label above .name, then Chris asked for the badge back in that same spot
     -- now .badge.<category> inside .mile-copy (see above). Four layouts in two weeks; still a
     deviation from Ledger's ModelRow (index, name, sentence, tag); proposed back as a variant. */

  /* Client name band, 8 September: peer proof set in type where a logo bar would sit. */
  .band.names .wrap{display:grid;grid-template-columns:120px 1fr;gap:32px;align-items:baseline;padding-top:26px;padding-bottom:26px}
  .namelist{font-family:var(--font-mono);font-feature-settings:normal;font-size:var(--t-small);line-height:2.1;color:var(--ink);letter-spacing:0.01em}
  .namelist .dot{background:var(--signal);width:0.34em;height:0.34em;margin:0 0.85em}
  /* Section 1: eight quotes in two columns beside the illustration */
  .words-grid{grid-template-columns:1fr 2fr}
  .words-grid .quotes{grid-template-columns:1fr 1fr;gap:32px 48px;padding:32px 0 32px 48px}
  /* SW-18, September 23, 2026: the body-size override that stood here (16.5px at 1.55) is gone. */
  /* SW-40: the opening mark hangs outside the text edge by its own width at lead, so every line starts on one edge. */
  .quote p .hang{margin-left:-0.43em}
  .quote .who strong{color:var(--ink);font-weight:500}
  /* 8 September: attribution on two lines, name then client (Chris). */
  .quote .who{display:flex;flex-direction:column;gap:3px}
  .quote .who .nm2{color:var(--ink)}
  .quote .who .aff{color:var(--ink-label)}
  .quote{gap:12px}
  @media (max-width:960px){
    .band.names .wrap{grid-template-columns:1fr;gap:12px}
    .namelist{line-height:1.9}
    .words-grid .quotes{grid-template-columns:1fr;padding:24px 0 0}
  }
  .namestack .inst{white-space:normal}  /* HOME-01: was nowrap above 400px */
  @media (max-width:400px){.namestack .inst{white-space:normal}} /* 320px reflow, September 16, 2026: the longest name measures 297px in Azeret Mono and overflowed a 320px viewport by 5px. Ledger permits wrapping below 1024. */ /* .nm is the lockup name in components/brand; do not reuse it. Selector corrected 8 September: the markup is .namestack, so the old .namelist rule never applied and names wrapped mid-name once the claim column widened. */
  /* 9 September: the illustration column ran 756px tall against a 249px image, so 500px of it was blank
     (thread 2261849e: "Large blank space"). Three changes, no motion: the column is wider so the art renders
     nearer its intended size, the art is centerd against the quote stack instead of pinned to the top, and the
     section's outbound link moved in beneath it so the remaining space carries something. A scroll animation
     was asked for in the same thread and declined: Ledger v2 motion is color-only plus a 3px arrow, and
     nothing scales, lifts or fades in on scroll. */
  .illo-wrap{align-items:center;justify-content:center;flex-direction:column;gap:32px;padding:32px 48px 32px 0}
  .illo-wrap .la{align-self:flex-start}

  /* Sub-nav panels, 8 September. Hairline panel on paper, no motion on open; --shadow-float is the one shadow Ledger permits, and only for dropdowns. */
  nav.top ul li{position:relative}
  nav.top .sub{display:none;position:absolute;top:100%;left:-16px;min-width:250px;background:var(--paper);border:var(--hairline) solid var(--rule);border-radius:var(--radius);box-shadow:var(--shadow-float);padding:10px 0;z-index:60} /* evened 11 September once the panel label came off; shadow moved onto --shadow-float 20 September, see token comment above */
  /* SW-02, September 23, 2026. With the header script running (header.site.js), a panel opens and closes
     through li.open, so Escape can shut it and send focus back to its trigger, and it closes when focus
     leaves. Without the script, hover and focus-within still open it. Panels exist above 960px only. */
  @media (min-width:961px){
    header.site:not(.js) nav.top li.has-sub:hover .sub,header.site:not(.js) nav.top li.has-sub:focus-within .sub,
    nav.top li.has-sub.open .sub{display:block}
  }
  nav.top .sub .label{display:block;padding:0 18px 10px;color:var(--ink-label)}
  nav.top .sub a{display:block;padding:8px 18px;font-size:var(--t-nav);color:var(--ink-body);line-height:1.4}
  nav.top .sub a:hover{background:var(--paper-sink);color:var(--ink)}
  nav.top li.has-sub > a::after{content:"";display:inline-block;width:5px;height:5px;margin-left:7px;vertical-align:2px;border-right:1.5px solid var(--ink-muted);border-bottom:1.5px solid var(--ink-muted);transform:rotate(45deg) translateY(-1px)}

  /* ---------- SITE HEADER AT EVERY WIDTH, September 23, 2026 (staging audit SW-01, SW-12) ----------
     Before this, nav.top ul was display:none below 960px and nothing replaced it: a phone or tablet
     had the lockup, Sign in and Book a demo, and no route to any page. Built to Ledger's NavBar,
     TabletNav and MobileNav guides. One set of links serves every width, so localization (the current
     page's aria-current, its in-page anchors) happens once in sync-chrome and holds everywhere.
       Above 960   the NavBar: links 28px apart (24 on this site since September 10), panels on hover
                   and focus. .navmenu is display:contents, so the layout is the one that shipped.
       881 to 960  TabletNav: the same six links and Sign in and Book a demo inline, 20px apart, no
                   chevrons and no panels. Measured with the real faces: the row needs 863px with the
                   tablet gutter, so it fits on one line from 864 and the band starts at 881 for 17px of
                   slack. Below that the links do not fit on one line, so portrait tablets take the menu.
       880 down    MobileNav: the lockup and a 44 x 44 menu button. The button opens the same eight
                   entries under the bar: six pages at lead in rows of 52px, Sign in, and Book a demo as
                   the page's one accent button. Escape closes it and returns focus to the button; so
                   does a click outside it or on any entry. */
  .navmenu{display:contents}
  nav.top .navright a.strong{font-size:var(--t-nav)}   /* SW-12: was 16.5px, the body size; NavBar sets Sign in at --t-nav */
  .navtoggle{display:none;appearance:none;background:none;border:0;margin:0 -10px 0 0;padding:0;width:44px;height:44px;
    flex-direction:column;align-items:center;justify-content:center;gap:5px;cursor:pointer;color:var(--ink);border-radius:var(--radius)}
  .navtoggle span{display:block;width:20px;height:1.5px;background:currentColor}
  /* Open state drawn, not animated: the middle bar goes and the outer two cross. No transition, per Ledger motion. */
  .navtoggle[aria-expanded="true"] span:nth-child(2){visibility:hidden}
  .navtoggle[aria-expanded="true"] span:nth-child(1){transform:translateY(6.5px) rotate(45deg)}
  .navtoggle[aria-expanded="true"] span:nth-child(3){transform:translateY(-6.5px) rotate(-45deg)}
  @media (max-width:960px){
    nav.top .wrap{gap:20px}
    nav.top ul{gap:20px}
    nav.top li.has-sub > a::after{display:none}
    nav.top .sub{display:none!important}
    .navright{gap:16px}
  }
  @media (max-width:880px){
    .navtoggle{display:flex}
    .navmenu{display:none}
    header.site:not(.js) .navtoggle{display:none}
    header.site:not(.js) nav.top .wrap{height:auto;flex-wrap:wrap;padding-top:14px;padding-bottom:14px}
    header.site:not(.js){position:static}
    header.site:not(.js) .navmenu,header.site.menu-open .navmenu{display:block}
    header.site.menu-open .navmenu{position:absolute;top:100%;left:0;right:0;max-height:calc(100vh - 72px);overflow-y:auto;
      background:var(--paper);border-top:var(--hairline) solid var(--rule-soft);border-bottom:var(--hairline) solid var(--rule);
      box-shadow:var(--shadow-float)}
    header.site:not(.js) .navmenu{width:100%}
    nav.top .navmenu ul{display:block;padding:0}
    nav.top .navmenu ul li{border-bottom:var(--hairline) solid var(--rule-soft)}
    nav.top .navmenu ul a{display:flex;align-items:center;min-height:52px;padding:0 var(--gutter);
      font-size:var(--t-lead);font-weight:var(--w-medium);letter-spacing:-0.012em;color:var(--ink)}
    nav.top .navmenu ul a[aria-current="page"]{color:var(--signal-deep)}
    nav.top .navmenu .navright{display:flex;flex-direction:column;align-items:stretch;gap:0;padding:0 var(--gutter) 20px}
    nav.top .navmenu .navright a.strong{display:flex;align-items:center;min-height:52px;font-size:var(--t-lead);
      font-weight:var(--w-medium);letter-spacing:-0.012em;color:var(--ink);border-bottom:var(--hairline) solid var(--rule-soft);
      margin:0 calc(-1 * var(--gutter)) 20px;padding:0 var(--gutter)}
    nav.top .navmenu .navright .btn{padding:16px 20px}
  }

  /* Client band, 8 September: the count beside the names, three sectors */
  .band.names .wrap{display:grid;grid-template-columns:212px 1fr;gap:44px;align-items:start;padding-top:44px;padding-bottom:44px}
  .namemetric{display:flex;flex-direction:column;gap:8px}
  .namemetric .figure{font-size:var(--t-d3);letter-spacing:var(--t-d3-ls)}
  .namemetric .qual{font-size:var(--t-body);color:var(--ink);font-weight:500}
  .namemetric .src{display:block;font-family:var(--font-mono);font-feature-settings:normal;font-size:var(--t-tag);letter-spacing:var(--t-tag-ls);text-transform:uppercase;color:var(--ink-label);line-height:1.7}
  .namemetric .src .tag{display:inline-block;margin-top:6px}
  /* 9 September, third pass (thread c5ac7acd). auto-fit was wrong: it gave two columns at desktop and turned
     the band into a tall slab. Back to three fixed columns, with the breakpoint derived rather than guessed.
     The arithmetic: the longest institution name measures about 260px at --t-small in DM Mono, and the names
     region is the content width minus the claim column and the wrap gap. Three columns need 3x260 plus two
     28px gaps, so 836px of names region. Claim column trimmed 300 to 260 and the wrap gap 44 to 40 to buy it,
     which puts the three-column floor at 1240px of viewport: at 1280 the columns get 276px each, 16px of slack.
     Below 1240 it is two columns, and Education spans both rows of the left column so Healthcare and Change
     and culture stack in the right one, which keeps Chris's column order at every width. One column below 640. */
  .namecols{display:grid;grid-template-columns:repeat(3,1fr);gap:28px}
  @media (max-width:1250px){
    .namecols{grid-template-columns:1fr 1fr;gap:28px 32px}
    .namecols .namecol:nth-child(1){grid-column:1;grid-row:1 / span 2}
    .namecols .namecol:nth-child(2){grid-column:2;grid-row:1}
    .namecols .namecol:nth-child(3){grid-column:2;grid-row:2}
  }
  @media (max-width:640px){
    .namecols{grid-template-columns:1fr}
    .namecols .namecol:nth-child(1),.namecols .namecol:nth-child(2),.namecols .namecol:nth-child(3){grid-column:1;grid-row:auto}
  }
  .namecol{display:flex;flex-direction:column;gap:12px}
  .namestack{display:flex;flex-direction:column;gap:7px}
  .namestack .inst{font-family:var(--font-mono);font-feature-settings:normal;font-size:var(--t-small);color:var(--ink);line-height:1.4}
  /* 8 September (Chris): the band takes the Security section's ground so it separates from the hero above
     and section 01 below, and the count becomes a sentence rather than a stat. "65+" carries --signal-deep,
     the text-safe burnt orange (#8A3414, 7.4:1 on paper-raise); --signal itself is 3.2:1 and is reserved in
     Ledger v2 for edges, eyebrows and the accent button, never for running text. */
  /* Client band goes dark, 8 September (Chris): on a tablet the hero's evidence panel stacks directly on top
     of this band, and with both on paper-raise the two read as one gray block with a hairline through it.
     Ground is --ink, not --surface-inverse: the teal-deep inverse stays the page's single closing moment, and
     burnt orange is legible on near-black where it is not legible on teal (--signal on teal-deep is 1.9:1).
     Deviation from Ledger v2, which defines one inverse surface; proposed back as a second, neutral one.
     Contrast on --ink: paper 19:1; --signal-lit 4.1:1 at 26px, past the 3:1 large-text floor; labels at 62%
     white 6.8:1. --signal-deep is the emphasis on light grounds, --signal-lit on dark, matching .inverse .label. */
  .band.names{background:var(--ink);padding:44px 0;border-top-color:var(--ink);border-bottom-color:var(--ink)}
  
  /* NAMEBAND RE-MEASURED for Azeret Mono, 11 September 2026, type rebuild.
     The three-column floor was arithmetic off DM Mono: longest institution name
     about 260px at --t-small, claim column 260, wrap gap 40, floor 1240px of
     viewport. Azeret is wider and --t-small went 13.5 to 14.3, so the longest
     name now measures 297px. At 1280 the three 1fr columns grew to 233/297/297,
     which is 883px of an 884px names region: it fits with one pixel spare, and
     one pixel is not a build. Claim column 260 to 240 and wrap gap 40 to 32 buy
     29px back, and the two-column floor moves 1239 to 1250 to match. Measured,
     not guessed, with the real faces loaded. */
  .band.names .wrap{grid-template-columns:240px 1fr;gap:32px;padding-top:0;padding-bottom:0}
  /* HOME-01, September 23, 2026: the claim is a band headline, d5 at 580 (README 4.2), where it was 24px,
     on no step, at 500; its label takes --label-on-dark rather than a literal; and names wrap, so the
     band sizes from its content rather than from the longest name. */
  .band.names .claim{font-weight:580;font-size:var(--t-d5);line-height:var(--t-d5-lh);letter-spacing:var(--t-d5-ls);color:var(--paper);text-wrap:pretty;margin:0}
  .band.names .claim b{color:var(--signal-lit);font-weight:500}
  .band.names .namecol .label{color:var(--label-on-dark)}
  .band.names .namestack .inst{color:var(--paper)}
  /* 9 September (thread d7c214b9, tablet check). At <=960 the wrap stacks the claim above the names, which is
     right, but .namecols was collapsing straight to one column and turning the band into a 570px dark slab.
     Measured at 900px: content width 804px, so two columns give 382px each and the longest institution name
     needs about 300px at --t-small in DM Mono. Two columns fit with room; three do not. One column is held for
     phone width. */
  @media (max-width:960px){.band.names .wrap{grid-template-columns:1fr;gap:26px}}

  /* ---- Tokens that were used and undefined, and one that had two values. 9 September harmonization.
     --surface-inverse-neutral, --label-on-dark and --w-medium were referenced by the jump rail on two
     pages and fell back to literals (Results change request 4.1). --ink-label resolved to #6A726D on the
     shipped home page and #575E5A in the Platform outline (4.2); the shipped value wins and the local
     re-declaration on Results comes out. --font-serif carries the third face Chris ruled onto the hero
     and proof figures on 9 September (Results change request 1.1); the token lives here so no page
     hard-codes the family. Pending the design system agent's ruling on the face's permitted uses. */
  :root{
    --surface-inverse-neutral:#101614;
    /* SW-07 and SW-08, September 23, 2026: one mono label color for both dark grounds, paper at 75 percent,
       per README 3.4: 5.78:1 on teal, 10.2:1 on ink. --label-on-teal (78 percent, teal only) is gone; its
       uses point here. At .62 the old value measured 4.48:1 on teal and failed AA. */
    --label-on-dark:rgba(252,252,251,.75);
    --focus-ring-on-dark:var(--paper);       /* --focus-ring is --teal-deep, which is 1.00:1 on the teal close band. */
    /* SW-09, September 23, 2026: --w-regular and --w-semibold were used and never declared, so every
       font-weight:var(--w-semibold) fell back to the inherited weight. */
    --w-regular:400;--w-medium:500;--w-semibold:600;
    --ink-label:#5C6663;
    --font-serif:"Source Serif 4",Georgia,"Times New Roman",serif;
  }

  /* ---- JumpRail. Sticky anchor rail below the NavBar on the neutral inverse surface. Ruled onto
     Platform 8 September and Results 9 September, and until this pass hand-copied into both page
     stylesheets (Results change request 2.1: "a third hand-copy is coming"). One copy, here. The
     Results copy is the later of the two and is the one kept. */
  /* ---------- The jump rail ----------
   Seven labels, matching the nav panel and the hero index word for word
   (comment 6c6e0d2b). Indices dropped: seven capability names plus seven
   indices do not fit one row at 1280 and the numbering already lives in
   the hero index. Sticks under the 72px NavBar. Hairline, never a shadow. */
.wickets{position:sticky;top:72px;z-index:40;background:var(--paper);
         border-top:var(--hairline) solid var(--rule);
         border-bottom:var(--hairline) solid var(--rule)}
  .wickets .wrap{display:grid;grid-template-columns:auto 1fr;gap:20px;align-items:stretch;
               height:auto;padding-top:0;padding-bottom:0}
  .wickets .railhead{display:flex;align-items:center;white-space:nowrap;
                   border-right:var(--hairline) solid var(--rule);padding-right:20px}
  .wickets ul{list-style:none;margin:0;padding:0;display:flex;overflow-x:auto;scrollbar-width:thin}
  .wickets li{flex:0 0 auto}
  .wickets a{display:block;padding:16px 11px 14px;border-bottom:2px solid transparent;
           text-decoration:none;white-space:nowrap;font-size:var(--t-small);color:var(--ink-body);  /* SW-28, September 23, 2026: the small step, 14px to 14.3px */
           transition:color var(--dur) var(--ease),background-color var(--dur) var(--ease),border-color var(--dur) var(--ease)}
  .wickets a:hover{background:var(--paper-sink);color:var(--ink)}
  .wickets a.on{border-bottom-color:var(--signal);color:var(--ink);font-weight:var(--w-medium,500)}
  .wickets a:focus-visible{outline:2px solid var(--focus-ring);outline-offset:-3px}
  /* ---------- The jump rail goes black, 9 September (thread a68c1257) ----------
     Chris: "I would like to see this nav bar in black to pop away from the main
     nav." In-system: Ledger v2 defines a second, neutral inverse surface at
     --ink, and the home page already uses it for the client name band. This page
     has no name band, so the rail takes that allowance and the teal close stays
     the page's single teal moment.
     Contrast on --ink #101614, measured: paper 19:1 for the active item; white
     at 62 percent 6.8:1 for the rest; --signal-lit #D06F1E 5.21:1 for the active
     edge. --signal itself is 4.47:1 on ink and fails AA by 0.03, so the lit
     variant carries the edge, which is the same swap .inverse .label already
     makes on the teal band. */
  .wickets{background:var(--surface-inverse-neutral,#101614);
           border-top:var(--hairline) solid var(--ink);
           border-bottom:var(--hairline) solid var(--ink)}
  .wickets .railhead{border-right:var(--hairline) solid rgba(252,252,251,.20)}
  .wickets .railhead.label{color:var(--label-on-dark)}
  .wickets a{color:var(--label-on-dark)}
  .wickets a:hover{background:rgba(252,252,251,.09);color:var(--paper)}
  .wickets a.on{border-bottom-color:var(--signal-lit);color:var(--paper)}
  .wickets a:focus-visible{outline:2px solid var(--paper);outline-offset:-3px}

  /* Buttons inherit the page face. Without this the home page's video play control fell back to the
     browser default (Arial in Chromium), the only element on any of the three pages outside the type
     system. Found by the 9 September cross-page measurement. */
  button{font:inherit}
  /* SW-36, September 23, 2026: the system has no italics (README 4.1). The Instrument Sans italic face is
     no longer declared in fonts.css, and these elements set roman, so emphasis never synthesizes a slant. */
  em,i,cite,blockquote{font-style:normal}
  /* SW-32, September 23, 2026: strong is 600, the heaviest weight the system sets. The UA default is 700,
     which is how /privacy/ was rendering it. */
  strong{font-weight:var(--w-semibold)}
  /* Nav panel labels never wrap; a 250px panel cannot grow to fit a two-line label (Results build, 9 September). */
  nav.top .sub .label{white-space:nowrap}

/* ---------- ALTERNATING GROUNDS, site rule ----------
   Platform first (9 September, thread 7ff212da: eight sections is a long scroll for hairlines alone),
   Results the same day ("Alternate the background color of the blocks just like we did in the platform
   page"), Home on 10 September (Chris: alternate on all three). Lifted here from platform.css and
   results.css so one rule governs the three pages. Three consequences, unchanged from the Platform note:
   One. THE RULE puts one separator on a boundary; with strict alternation every boundary is a ground
   change, so the section hairline comes off rather than doubling it.
   Two. Anything that sits on paper-raise for contrast goes flat on a raised section and inverts: the
   image-frame hatch (paper-sink over paper-raise becomes paper-sink over paper) and the tag chip.
   Page-specific inversions (Platform's diagram blocks, Results' filter buttons and download panel)
   stay in their own stylesheets.
   Three. Order runs raised, paper, raised, paper from the top of the first section, so the dark strip
   above it (the client band on Home, the jump rail on Platform and Results) sits over a raised section
   and the hero's raised evidence panel never touches a raised ground, which is the gray-on-gray merge
   Ledger warns about. */
section.raised{background:var(--paper-raise)}
section{border-top:0}
section.raised .slot .frame{background:repeating-linear-gradient(135deg,var(--paper-sink) 0 7px,var(--paper) 7px 14px)}
section.raised .tag{background:var(--paper);border-color:var(--rule)}

/* ---------- Hero contents index (ReqIndex) ----------
   Built for Platform (8 September), copied verbatim to Results (9 September), one definition from
   10 September. A numbered list of a page's sections in the hero's raised panel, each with a one-line
   descriptor; entries match the jump rail and the nav panel word for word. */
.reqindex{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}
.reqindex li{border-bottom:var(--hairline) solid var(--rule)}
.reqindex li:last-child{border-bottom:0}
.reqindex a{display:grid;grid-template-columns:30px 1fr auto;gap:14px;align-items:baseline;
            padding:14px 0;text-decoration:none;border:0;transition:color var(--dur) var(--ease)}
.reqindex a i{font-style:normal;font-family:var(--font-mono);font-feature-settings:normal;font-size:var(--t-tag);
              letter-spacing:var(--t-tag-ls);color:var(--signal-deep);font-variant-numeric:tabular-nums}
.reqindex a .lbl{display:flex;flex-direction:column;gap:3px}
.reqindex a b{font-weight:600;font-size:var(--t-body);color:var(--ink);line-height:1.35}
.reqindex a s{text-decoration:none;font-size:var(--t-small);line-height:1.45;color:var(--ink-body)}
.reqindex a .arr{font-family:var(--font-mono);font-feature-settings:normal;color:var(--ink-label);align-self:center;
                 transition:transform var(--dur) var(--ease),color var(--dur) var(--ease)}
.reqindex a:hover b{color:var(--callout)}
.reqindex a:hover .arr{color:var(--callout);transform:translateX(3px)}
.reqindex a:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}

/* The jump rail distributes across the width above 960px. Ruled on Results 9 September (Chris: the
   navigation elements centered on the width of the page; space-between chosen over equal cells because
   it puts the first item flush to the JUMP TO divider and the last flush right, with even gaps). Applied
   to Platform 10 September under ruling 7, so the two rails are one component. Below 960 the railhead
   hides and the rail scrolls, which is what a phone needs. */
@media (min-width:961px){ .wickets ul{justify-content:space-between;width:100%} }

/* ---------------------------------------------------------------------------
   Ledger: Article and ArchiveList. New components, September 12, 2026.
   The system has no long-form reading type and no archive list. Both are built
   here and are owed back to the design system as one block.

   WRITTEN AGAINST THE SHIPPED ledger.css, NOT AGAINST THE DOCUMENTATION.
   The system's export documents --space-* and --rhythm-section / --rhythm-band /
   --rhythm-heading / --rhythm-stack. The shipped stylesheet carries none of them,
   so a rule written from the documentation resolves to zero and the gap vanishes.
   Measured September 12, 2026. Every value below uses a token the stylesheet
   really defines, or a literal from the vertical rhythm standard {72,48,44,32}.
   Tokens used here that do exist: --measure-lead 620, --rhythm-para 28,
   --rhythm-para-small 21, --hairline, --radius, --dur, --ease, --gutter.
   --------------------------------------------------------------------------- */

/* Article ------------------------------------------------------------------- */
.article .amast{display:flex;flex-direction:column;gap:20px;
  max-width:var(--measure-lead);padding-bottom:44px}
.article .akicker{display:flex;flex-wrap:wrap;gap:6px 18px;align-items:baseline;
  font-family:var(--font-mono);font-size:var(--t-label);line-height:var(--t-label-lh);
  letter-spacing:var(--t-label-ls);text-transform:uppercase;color:var(--ink-label)}
.article .akicker .cat{color:var(--signal-deep)}
.article .amast h1{font-weight:540;font-size:var(--t-d2);line-height:var(--t-d2-lh);
  letter-spacing:var(--t-d2-ls);color:var(--ink);text-wrap:balance}
.article .alede{font-size:var(--t-lead);line-height:var(--t-lead-lh);
  letter-spacing:var(--t-lead-ls);color:var(--ink-body)}
.article .ameta{display:flex;flex-wrap:wrap;gap:4px 16px;padding-top:4px;
  font-family:var(--font-mono);font-size:var(--t-tag);line-height:var(--t-tag-lh);
  letter-spacing:var(--t-tag-ls);text-transform:uppercase;color:var(--ink-label)}

/* gap:0 with explicit margins. The 11 September finding: six reading stacks each
   set a flex gap, so a margin added to the gap instead of replacing it, and the
   same declaration produced 28px in one place and 48px in another. */
.article .abody{display:flex;flex-direction:column;gap:0;max-width:var(--measure-lead)}
.article .abody > * + *{margin-top:var(--rhythm-para)}
.article .abody p{font-size:var(--t-body);line-height:var(--t-body-lh);
  letter-spacing:var(--t-body-ls);color:var(--ink-body)}
.article .abody h2{font-weight:var(--w-semibold);font-size:var(--t-d4);line-height:var(--t-d4-lh);
  letter-spacing:var(--t-d4-ls);color:var(--ink);margin-top:44px;text-wrap:balance}
.article .abody h3{font-weight:var(--w-semibold);font-size:var(--t-d5);line-height:var(--t-d5-lh);
  letter-spacing:var(--t-d5-ls);color:var(--ink);margin-top:32px;text-wrap:balance}
.article .abody h2 + *,.article .abody h3 + *{margin-top:var(--rhythm-para-small)}
.article .abody ul,.article .abody ol{margin-left:0;padding-left:0;list-style:none;
  display:flex;flex-direction:column;gap:var(--rhythm-para-small)}
.article .abody li{position:relative;padding-left:22px;font-size:var(--t-body);
  line-height:var(--t-body-lh);color:var(--ink-body)}
.article .abody ul > li::before{content:"";position:absolute;left:0;top:10px;
  width:5px;height:5px;background:var(--signal)}
.article .abody ol{counter-reset:a}
.article .abody ol > li{counter-increment:a;padding-left:32px}
.article .abody ol > li::before{content:counter(a,decimal-leading-zero);position:absolute;
  left:0;top:2px;font-family:var(--font-mono);font-size:var(--t-tag);
  letter-spacing:var(--t-tag-ls);color:var(--signal-deep)}
/* SW-04, September 23, 2026: the underline is the link's own color, not --rule-brand at 22 percent, which
   measured 1.2:1 against paper and so did not mark the link at all (README 3.2, WCAG 1.4.1). */
.article .abody a{color:var(--callout);text-decoration:none;
  border-bottom:var(--hairline) solid currentColor}
.article .abody a:hover{color:var(--callout-hover);border-bottom-color:currentColor}
.article .abody strong{color:var(--ink);font-weight:var(--w-semibold)}
.article .abody blockquote{margin:32px 0 0;border-left:2px solid var(--ink);padding-left:24px}
.article .abody blockquote > * + *{margin-top:12px}
.article .abody blockquote p{font-size:var(--t-lead);line-height:var(--t-lead-lh);
  letter-spacing:var(--t-lead-ls);color:var(--ink)}
.article .abody blockquote cite{display:block;font-style:normal;
  font-family:var(--font-mono);font-size:var(--t-tag);letter-spacing:var(--t-tag-ls);
  text-transform:uppercase;color:var(--ink-label)}
.article .abody figure{margin:32px 0 0}
.article .abody figure img{display:block;width:100%;max-width:100%;height:auto;
  border:var(--hairline) solid var(--rule)}
.article .abody figcaption{margin-top:12px;font-family:var(--font-mono);
  font-size:var(--t-caption);letter-spacing:var(--t-caption-ls);
  line-height:var(--t-caption-lh);color:var(--ink-label)}

.article .afoot{max-width:var(--measure-lead);margin-top:72px;padding-top:32px;
  border-top:var(--hairline) solid var(--rule);display:flex;flex-wrap:wrap;
  gap:16px 32px;align-items:baseline;justify-content:space-between}

/* Article/ArchiveList close-out links and demo band, added 13 September 2026
   (Resources build). a.arrow and .cta-band are used by every already-built
   blog post (tools/render-blog.py output, 49 pages, blog/post.template.html)
   and by all 8 new Resources pages, but the rules themselves were only ever
   defined in blog/_to_delete/_post-preview.html and _sample-post.html, scratch
   preview files, never merged into this shared sheet when .article/.amast/
   .akicker/.alede/.ameta/.abody were added on 12 September. Every page using
   them has been rendering with unstyled fallback links and an unstyled CTA row
   until now. Copied verbatim from _sample-post.html (the more complete of the
   two scratch copies); .btn.accent is not repeated here because the shared
   .btn/.btn.accent rules above already cover it. */
a.arrow{font-family:var(--font-mono);font-size:var(--t-small);letter-spacing:.06em;
  text-transform:uppercase;color:var(--callout);text-decoration:none}
a.arrow::after{content:" \2192"}
a.arrow:hover{color:var(--callout-hover)}
/* SW-23, September 23, 2026: the article foot's links are LinkArrows (README 9): Instrument Sans at
   --t-small and 500, sentence case, ink, the arrow a text character. A 2px underline shows on hover and
   the arrow steps 3px, the system's only link motion. */
nav.afoot a.arrow{display:inline-flex;align-items:baseline;gap:.3em;font-family:var(--font-sans);font-size:var(--t-small);font-weight:500;
  letter-spacing:0;text-transform:none;color:var(--ink);padding-bottom:4px;border-bottom:2px solid transparent;
  transition:border-color var(--dur) var(--ease)}
nav.afoot a.arrow::after{content:"\2192";display:inline-block;transition:transform var(--dur) var(--ease)}
nav.afoot a.arrow:hover{color:var(--ink);border-bottom-color:var(--ink)}
nav.afoot a.arrow:hover::after{transform:translateX(3px)}
.cta-band{display:flex;flex-wrap:wrap;gap:24px;align-items:center;justify-content:space-between}

/* FAQ accordion (.qa), added 13 September 2026: Chris's artifact comment on the
   Resources hub asked for the FAQ section to read as an accordion, expander
   icon, click to reveal the answer. Native <details>/<summary>: no JavaScript,
   keyboard- and screen-reader-operable by default, and consistent with the
   project's own drift toward a JS-free flat-HTML cutover (PROJECT-STATE.md,
   12 September, the Stage E / CMS entry). Deliberately a new component, not a
   retrofit of Privacy's existing static .faqlist (pages/privacy.body.html's
   own page-scoped CSS): Privacy's FAQ section went through 26 comment-driven
   revisions and is not touched here. Used on the FAQ page (all 46 questions)
   and, as a five-question preview, on the Resources hub's own Questions
   section, per the same comment; the FAQ page itself stays a separate
   artifact rather than fully embedding the hub, since the FAQPage JSON-LD
   schema and its own citable URL are the reason the 7 September ruling names
   it as its own Resources component. See the reply in that comment thread. */
.qa{display:flex;flex-direction:column;gap:0}  /* SW-17, September 23, 2026: no measure on the list; its answers carry --measure-lead */
.qa details{border-top:var(--hairline) solid var(--rule);padding:20px 0}
.qa details:last-child{border-bottom:var(--hairline) solid var(--rule)}
.qa summary{display:flex;align-items:center;justify-content:space-between;gap:16px;
  cursor:pointer;list-style:none;font-family:var(--font-sans);font-weight:500;
  font-size:var(--t-lead);color:var(--ink)}  /* SW-31, September 23, 2026: 500, was 600 */
.qa summary::-webkit-details-marker{display:none}
.qa summary::after{content:"+";font-family:var(--font-mono);font-weight:400;
  font-size:var(--t-d5);line-height:1;color:var(--ink-muted);flex:0 0 auto;
  transition:color var(--dur) var(--ease)}
.qa details[open] summary::after{content:"\2212"}
.qa summary:hover::after{color:var(--callout)}
.qa summary:hover{color:var(--callout)}
.qa summary:focus-visible{outline:2px solid var(--focus-ring);outline-offset:3px}
.qa .a{font-size:var(--t-body);line-height:var(--t-body-lh);color:var(--ink-body);
  margin:12px 0 0;max-width:var(--measure-lead)}
.qa .more{margin-top:24px}

/* ArchiveList --------------------------------------------------------------- */
/* No top hairline. The section already changes ground, and Ledger's separator
   rule is that a hairline on a ground change doubles the separator. */
.arch{--arch-date:150px;--arch-thumb:180px;display:flex;flex-direction:column}
/* The year sits in the same column as the dates beneath it, so the left edge
   reads as one spine of time: 2026, then August 27, July 13, June 25, then 2025.
   Set at d4 in the mono, which is the one place in the archive that carries a
   display size, and the reason the list has a rhythm instead of a texture. */
.arch .yr{display:grid;grid-template-columns:var(--arch-date) 1fr;gap:0 24px;
  padding:56px 0 10px;border-bottom:var(--hairline) solid var(--rule)}
.arch .yr:first-child{padding-top:8px}
.arch .yr b{grid-column:1;font-family:var(--font-sans);font-weight:600;  /* BLOG-01, September 23, 2026: Instrument Sans at 600, was the mono at 400 */
  font-size:var(--t-d4);line-height:1;letter-spacing:-.02em;color:var(--ink);
  font-variant-numeric:tabular-nums}
.arch a.row{display:grid;grid-template-columns:var(--arch-date) 1fr var(--arch-thumb);gap:5px 24px;
  padding:20px 0;min-height:var(--target-pitch-min);text-decoration:none;
  border-bottom:var(--hairline) solid var(--rule-soft);
  transition:background var(--dur) var(--ease)}
/* Ledger: a row bleeds 24px past its container so the hover fill reaches past
   the text, not to the viewport edge. A full-gutter bleed lands exactly on the
   edge and overflows the moment a scrollbar takes a few pixels. */
.arch a.row{margin-inline:-24px;padding-inline:24px}
.arch a.row:hover{background:var(--paper)}
.arch a.row .d{grid-row:1;font-family:var(--font-mono);font-size:var(--t-tag);
  line-height:1.7;letter-spacing:var(--t-tag-ls);text-transform:uppercase;
  color:var(--ink-label)}
.arch a.row .t{grid-column:2;grid-row:1;font-weight:580;font-size:var(--t-d5);
  line-height:var(--t-d5-lh);letter-spacing:var(--t-d5-ls);color:var(--ink);text-wrap:balance}
.arch a.row .x{grid-column:2;font-size:var(--t-small);line-height:var(--t-small-lh);
  color:var(--ink-body);max-width:var(--measure-body)}
.arch a.row .c{grid-column:2;font-family:var(--font-mono);font-size:var(--t-tag);
  line-height:var(--t-tag-lh);letter-spacing:var(--t-tag-ls);text-transform:uppercase;
  color:var(--ink-label)}
.arch a.row:hover .t{color:var(--callout)}
.arch a.row:focus-visible{outline:2px solid var(--callout);outline-offset:2px}

/* ArchiveList thumbnail, 12 September 2026, ruled by Chris. 180px wide at the
   set's own 1.90 ratio, not a square: a square crop would take 47 percent off
   every one of them. Served from 360x190 derivatives, 237KB for the whole
   column against 16MB of originals. */
/* SW-24, September 23, 2026: a thumbnail is a picture, so it takes --radius-panel, 12px (README 5); it
   carried the 2px control radius. */
.arch a.row .th{grid-column:3;grid-row:1 / span 3;align-self:start;
  display:block;width:100%;aspect-ratio:1.9;border-radius:var(--radius-panel)}
.arch a.row .th img{display:block;width:100%;height:100%;object-fit:cover;
  border:var(--hairline) solid var(--rule);border-radius:var(--radius-panel);
  box-shadow:var(--shadow-float);background:var(--paper-sink)}
/* No thumbnail yet. A placeholder rather than a hole, so the column holds its
   edge, carrying the bracket device as live mono type. */
/* Rounded corners + shadow extended from every .th asset container to the
   base .th img and .th.ph rules, 21 September 2026 (Chris, on the Blog Archive
   review copy): matches the treatment .th.ph.inverse already carries on the
   Resources hub, so a real photo, a bracket placeholder, and a branded
   placeholder all read as the same kind of object. */
.arch a.row .th.ph{display:flex;align-items:center;justify-content:center;
  background:var(--paper-sink);border:var(--hairline) solid var(--rule);
  border-radius:var(--radius-panel);box-shadow:var(--shadow-float)}
.arch a.row .th.ph i{font-family:var(--font-mono);font-style:normal;
  font-size:var(--t-label);letter-spacing:.34em;color:var(--ink-label);
  padding-left:.34em}
/* Placeholder thumbnail, September 23, 2026 (staging audit SW-37, ruled by Chris): the Frame's pending
   hatch, 12px corners, no mark. It replaces the reversed lockup on a teal-deep tile (September 21), which
   put the one teal ground a page is allowed (the closing band) into a list, ten times. The hatch inverts
   on a raised section, as the Frame's does. */
.arch a.row .th.ph.hatch{background:repeating-linear-gradient(135deg,var(--paper-sink) 0 7px,var(--paper-raise) 7px 14px);
  border:var(--hairline) solid var(--rule);border-radius:var(--radius-panel);box-shadow:var(--shadow-float)}
section.raised .arch a.row .th.ph.hatch{background:repeating-linear-gradient(135deg,var(--paper-sink) 0 7px,var(--paper) 7px 14px)}
.arch a.row:hover .th img{border-color:var(--rule-brand)}

@media (max-width:900px) and (min-width:721px){.arch{--arch-thumb:132px}}

@media (max-width:720px){
  .arch{--arch-date:auto;--arch-thumb:104px}
  .arch .yr{grid-template-columns:1fr;gap:6px}
  .arch a.row{grid-template-columns:1fr var(--arch-thumb);gap:6px 16px}
  .arch a.row .d,.arch a.row .t,.arch a.row .x,.arch a.row .c{grid-column:1;grid-row:auto}
  .arch a.row .th{grid-column:2;grid-row:1 / span 4}
}
@media (max-width:420px){
  .arch{--arch-thumb:80px}
  .arch a.row .x{display:none}
}

/* A link inside running text is distinguished by more than colour. Caught by
   axe on 12 September: the archive pointer link measured 1.1:1 against the
   text around it, which fails 1.4.1 Use of Color. */
.arch-note a,.article .alede a{color:var(--callout);text-decoration:none;
  border-bottom:var(--hairline) solid currentColor}
.arch-note a:hover,.article .alede a:hover{color:var(--callout-hover);
  border-bottom-color:currentColor}
/* SW-05, September 23, 2026: running-text links on the other text pages carried no mark but color. One rule
   for all of them, because Ledger scopes the underline to text containers and these are the containers:
   the legal pages' .stack, the Evidence footnote markers and reference list, the Resources hub's inline
   link arrow. */
.stack p a,.stack li a,a.fn,ol.refs a,p.small a.la{text-decoration:none;border-bottom:var(--hairline) solid currentColor}


/* Article hero image, 12 September 2026. The featured images are 1.90 banners,
   38 of 45 at exactly that ratio, so the reading column is the shape they were
   made for. They are deliberately not thumbnails: about twenty are typographic
   posters and the set runs six visual languages, which reads as a jumble at
   100px and as a poster at 620. Named .ahero, not .alede: .alede is already
   this component's standfirst paragraph. */
.article .ahero{margin:0 0 44px;max-width:var(--measure-lead)}
.article .ahero img{display:block;width:100%;height:auto;aspect-ratio:1.9;
  object-fit:cover;border:var(--hairline) solid var(--rule)}



/* ===== ARTICLE, LONG-FORM READING. Settled 2026-09-18 with Chris over ten
   versions on the blog post template (artifact 2z6sGzPqe4n9cEY5Pnu2Rt).

   The Article component was written 12 September 2026 and never rendered on a
   real page until 18 September, because all 47 blog posts shipped as stubs.
   This block is what that first real render exposed. It is appended rather than
   edited in place so the change is reviewable as one contiguous diff; every
   rule below supersedes an earlier one at equal specificity by source order.
   THE SUPERSEDED DECLARATIONS SHOULD BE DELETED in the design-system pass:
   lines 747 (.alede), 760/762 (h2/h3 text-wrap), 769 (bullet top), 788 (figure
   img width), 790 (figcaption), 929-931 (.ahero). The change request that
   carries the reasoning is deliverables/O - Internal - Ledger v2 Change Request
   from the Blog Build - September 18, 2026.md.

   WIDTH. The article is ONE column, 870px, and every element in it shares that
   width and those margins: breadcrumb, image, headline, standfirst, body, foot
   links and the closing band. Measured by counting rendered line boxes, 870px
   at 23px runs 71 characters average and 73 longest, against WCAG 2.1 AAA
   1.4.8's cap of 80. MEASURE LINE LENGTH WITH Range.getClientRects(). Do not
   estimate it from glyph width: a probe that copies the computed `font`
   shorthand onto a test span reads the page default instead, because Chromium
   serialises that shorthand as an empty string, and it reported 113 characters
   for this same column. Re-measure whenever type size, width or face changes.

   CONFORMANCE TARGET IS WCAG 2.1 LEVEL AA, per ovrture.com/accessibility.
   AA has no paragraph-spacing requirement; 1.4.8's 1.5x rule is AAA and is not
   applied here. 1.4.12 Text Spacing IS AA and is about surviving a reader's
   override, which this passes.                                          ===== */

:root{--measure-article:870px}

.article .ahero{margin:0 auto 32px;max-width:var(--measure-article)}
/* SW-21, September 23, 2026: a picture takes --radius-panel and --shadow-float (README 5), and the hero is
   width:auto, so it never renders wider than its own pixels. A 318px source had been stretched to 870. */
.article .ahero img{display:block;width:auto;max-width:100%;height:auto;aspect-ratio:auto;
  max-height:520px;object-fit:contain;margin-inline:auto;
  border:var(--hairline) solid var(--rule);background:var(--paper-raise);
  border-radius:var(--radius-panel);box-shadow:var(--shadow-float)}

/* Article hero placeholder, 21 September 2026 (Chris, on the Blog Archive review copy, thread
   de4c4828): "For new posts that we do not have an image for, simply use a field of dark teal
   with the Ovrture logo in the center, akin to what we did on the resources page." Reversed
   lockup on a teal-deep field -- the same device as .th.ph.inverse on the Resources hub -- sized
   for the article hero slot. Ratio held at 1.9, the majority real-hero ratio documented above (38
   of 45 posts), so a placeholder reads like the thing it is standing in for rather than inventing
   its own shape; 870 / 1.9 = 458px, under the 520px cap the real images use. Scoped to .ahero.ph
   so a post that already has a real .ahero img (ovrtureblackbaud: an SVG at
   /assets/blog/featured/mobile-partnership-network-r.svg) is untouched -- confirmed against the
   three gallery rows Chris pointed at before writing this, only two of which actually lack header
   art; the third's gallery thumbnail is placeholder only because no raster derivative was
   generated from that post's SVG. */
.article .ahero.ph{display:flex;align-items:center;justify-content:center;
  aspect-ratio:1.9;max-height:520px;background:var(--teal-deep);
  border:0;border-radius:var(--radius);box-shadow:var(--shadow-float)}
.article .ahero.ph .lockup{display:flex;align-items:center;justify-content:center}
.article .ahero.ph .lockup .logo{width:26%;max-width:260px;height:auto;flex-shrink:0}
.article .ahero.ph .lockup .l-ink,
.article .ahero.ph .lockup .l-teal{fill:var(--paper)}

.article .amast{gap:16px;padding-bottom:32px;max-width:var(--measure-article);margin-inline:auto}
.article .akicker{gap:6px 14px;font-size:13px;letter-spacing:.08em;line-height:1.4}
.article .akicker time{font-variant-numeric:tabular-nums}
/* was --t-lead (19px) in --ink-body: smaller and lighter than the 23px body
   copy it introduces, which reads as a caption. */
.article .alede{font-size:28px;line-height:1.38;letter-spacing:-.008em;
  font-weight:450;color:var(--ink);max-width:none}

/* Reading scale, separate from the display tokens, which are built for 16.5px
   marketing body copy and do not transfer. h3 was --t-d5 (25px) against 23px
   body: two pixels is emphasis, not a heading. Every level differs by size,
   weight AND colour so none depends on size alone. */
.article .abody{max-width:var(--measure-article);margin-inline:auto}
.article .abody p,.article .abody li{font-size:23px;line-height:1.6;color:var(--ink-body)}
.article .abody > * + *{margin-top:26px}
.article .abody p + p,
.article .abody p + ul,.article .abody p + ol,
.article .abody ul + p,.article .abody ol + p,
.article .abody p + blockquote,.article .abody blockquote + p{margin-top:1.6em}  /* SW-20, September 23, 2026: --rhythm-para-read, 1.6em (README 4.5). Was 1.25em, set September 18; this later ruling supersedes it. */
.article .abody h2{font-size:32px;line-height:1.312;font-weight:600;color:var(--ink);
  margin-top:48px;text-wrap:pretty}
.article .abody h3{font-size:26px;line-height:1.346;font-weight:600;color:var(--ink);
  margin-top:34px;text-wrap:pretty}
.article .abody h2 + *,.article .abody h3 + *{margin-top:16px}
.article .abody blockquote p{font-size:25px}
/* bullets were pinned at top:10px, correct for 16.5px text, 5px high at 23px */
.article .abody ul,.article .abody ol{gap:16px}
.article .abody ul > li::before{top:calc(.8em - 2.5px)}
.article .abody ol > li::before{top:.16em}
/* width:100% upscaled a 120px headshot to the full column. 42 of the 57 body
   images in the archive are 120 or 300px. Intrinsic size is the ceiling. */
.article .abody figure{margin-top:30px}
.article .abody figure img{width:auto;max-width:100%;height:auto;
  border-radius:var(--radius-panel);box-shadow:var(--shadow-float)}  /* SW-21 */
/* SW-39, September 23, 2026: a body image that would render taller than 520px at the column's width sits
   in a 520px letterbox, so it fits on one screen (README 8). The letterbox is added in the markup (a
   span.letterbox around the img) by measuring each file: rendered height is min(width, 870) x height /
   width. The audit states the rule as height/width > 0.598, which is that test for an image at least
   870px wide; for a narrower one, the height it would render at is its own height, and applying the ratio
   alone would letterbox, and so upscale, a 200px headshot. */
/* An image link is not running text: no underline under a picture (SW-04's rule is for text links). */
.article .abody figure > a{display:block;border-bottom:0}
.article .abody .letterbox{display:flex;align-items:center;justify-content:center;height:520px;max-width:100%;
  background:var(--paper-raise);border-radius:var(--radius-panel);box-shadow:var(--shadow-float);overflow:hidden}
.article .abody .letterbox img{height:100%;width:auto;max-width:100%;object-fit:contain;
  border:0;border-radius:0;box-shadow:none}
.article .abody figcaption{font-size:15px;line-height:1.5;letter-spacing:.025em;margin-top:10px}  /* SW-20: read-caption tracking, 0.025em */

.article > section{padding:44px 0 52px}
.article > section.raised{padding:48px 0}
.article .afoot{max-width:var(--measure-article);margin:48px auto 0;padding-top:26px;
  flex-direction:column;align-items:flex-start;gap:12px}
.article .afoot .all{margin-bottom:2px}
.article .cta-band{max-width:var(--measure-article);margin-inline:auto}

/* The column is capped, so characters fall as the viewport narrows. Below about
   480px the line drops under the 45-character comfort floor and the fix is
   smaller type, not a wider column. 320px lands at 30 characters, which is not
   a WCAG failure: 1.4.8 caps a line at 80 and sets no floor. */
/* SW-38, September 23, 2026: the phone steps are the reading scale's own (README 4.5), and no two
   neighboring levels share a size at either width. The headline was left at the display scale's
   37px, and at 320px "Where's the Magic in Donor Communications?" ran 12px past the viewport; it now
   steps down and may break a long word rather than push the page sideways. */
.article .amast h1{overflow-wrap:break-word}
@media (max-width:480px){
  .article .amast h1{font-size:37px}
  .article .alede{font-size:23px}
  .article .abody h2{font-size:27px;margin-top:38px}
  .article .abody h3{font-size:22px}
  .article .abody p,.article .abody li{font-size:20px}
  .article > section{padding:32px 0 40px}
  .article .ahero{margin-bottom:24px}
}
@media (max-width:380px){
  .article .amast h1{font-size:32px}
  .article .alede{font-size:20px}
  .article .abody h2{font-size:22px}
  .article .abody h3{font-size:19px}
  .article .abody p,.article .abody li{font-size:17px}
}

/* ===== BREADCRUMB. New component, 2026-09-18. Ledger v2 had none.
   Added because Blog is a footer link only and does not appear in the header,
   so a reader arriving on a post from search has no visible route back to the
   archive. Not blog-specific: any subpage under a section the header does not
   carry has the same problem. Four decisions, recorded so they are not
   re-derived: the trail is Home / Blog / this page; the current page is text
   and never a link, carrying aria-current="page"; its title is shortened,
   because a full listing title in a crumb reads as a second headline; and
   BreadcrumbList JSON-LD ships with it, saying exactly what the visible trail
   says, or Google ignores the markup. 13px rather than --t-tag's 11.6px:
   uppercase at 0.08em tracking is the hardest text on the page to read and it
   is the first text on the page.                                       ===== */
.crumb{margin:0 auto 24px;max-width:var(--measure-article)}
.crumb ol{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 8px;margin:0;padding:0;
  list-style:none;font-family:var(--font-mono);font-size:13px;line-height:1.4;
  letter-spacing:.08em;text-transform:uppercase;color:var(--ink-label)}
.crumb li{display:flex;align-items:baseline;gap:8px;padding:0;min-width:0}
.crumb li + li::before{content:"/";color:var(--rule)}
.crumb a{color:var(--ink-label);border-bottom:var(--hairline) solid transparent;text-decoration:none}
.crumb a:hover{color:var(--callout);border-bottom-color:var(--callout)}
/* max-width in ch was a guess and it overflowed a 320px viewport by 77px on the
   longest title, because a flex item will not shrink below its content unless
   min-width:0 says it may. 100% of the row plus min-width:0 on the li is the
   constraint that actually holds, at every width, with no magic number. Caught
   by measuring 1.4.10 reflow on a real post, 2026-09-18. */
/* SW-19, September 23, 2026: the current page wraps rather than clipping (Breadcrumb guide); its text is
   shortened in the markup instead, where each post carries its own short title. */
.crumb .here{color:var(--ink);font-weight:500;max-width:100%}
