/* ==========================================================================
   Yiertek — foundations
   ==========================================================================

   THE ONLY PLACE ON THIS SITE WHERE A COLOUR, A TYPE SIZE OR A SPACE VALUE IS
   WRITTEN AS A LITERAL. Everything in site.css reads out of here.

   The reasoning for every number below is in docs/design-foundations.md; this
   file carries the values and the one-line version of the rule. Two probes
   enforce it — `tokenDiscipline` (no literal colour outside :root) and
   `serifBudget` (the display serif on at most two blocks per page), both in
   scripts/probe-home.mjs.

   Three families, three jobs, no overlap:
     Newsreader  the display serif — H1, and at most one more moment per page
     Archivo     the structural voice — H2/H3, figures, eyebrows, buttons, nav
     Inter       text — body, leads, forms, meta, footer
   ========================================================================== */

:root {
  /* ------------------------------------------------------------------------
     1 · TYPE — three families, seven named steps
     ------------------------------------------------------------------------
     Hierarchy is carried by FAMILY and WEIGHT first and size second. Two
     headings that differ only in points are one heading printed twice.

     Newsreader is variable on `opsz` (6–72) as well as `wght`. Every heading
     here is sized with clamp(), so its rendered size is not known when the CSS
     is written — `font-optical-sizing: auto` (the browser default) drives the
     axis from the size actually painted. That axis is why this face is here:
     measured, its display end sets 13.7% narrower with a 14.6% thinner stem
     than its text end. A single-cut display serif cannot do it at all. */

  --font-display: 'Newsreader', 'Noto Serif SC', Georgia, serif;
  --font-structure: 'Archivo', 'Noto Sans SC', system-ui, -apple-system, sans-serif;
  --font-text: 'Inter', 'Noto Sans SC', system-ui, -apple-system, sans-serif;

  /* -- display · the full-bleed hero headline ---------------------------- */
  /* A2 — the two DISPLAY steps are 6% larger than the ramp that shipped, and
     nothing else on the ramp moved. The calibration plate set A1 (the shipped
     step), A2 (+6%) and A3 (+12%) side by side at 1440 and 390 on the real
     headline, and +6% is the step where the h1 stops sharing a weight class
     with the h2 under it without becoming a poster. The whole clamp is rescaled
     — minimum, base, slope and maximum — so the growth is the same 6% at every
     viewport rather than a ceiling that only a 1600px screen ever sees.

     Tracking goes with it: -0.020em → -0.022em. Optical tracking is a function
     of size, and a step that grows and keeps its tracking sets looser than it
     did, which reads as the same headline printed larger instead of as a
     display size. */
  --type-display-family: var(--font-display);
  --type-display-weight: 400;
  --type-display-size: clamp(2.915rem, 1.431rem + 6.36vw, 5.83rem); /* 46.6 → 93.3px */
  --type-display-track: -0.022em;
  --type-display-leading: 1.02;

  /* -- h1 · the hero headline in a column, and any other page h1 --------- */
  --type-h1-family: var(--font-display);
  --type-h1-weight: 400;
  --type-h1-size: clamp(2.385rem, 1.219rem + 4.876vw, 4.505rem); /* 38.2 → 72.1px */
  --type-h1-track: -0.022em;
  --type-h1-leading: 1.06;

  /* -- h2 · the section statement. Archivo, because a fact wants a
        structural voice and not an editorial one. 48px is the ceiling the two
        stylesheets that used to disagree (64 in site.css, 48 in home.css) are
        merged onto: the smaller number was the more recently reasoned one. */
  --type-h2-family: var(--font-structure);
  --type-h2-weight: 600;
  --type-h2-size: clamp(1.75rem, 1.05rem + 2.6vw, 3rem);        /* 28 → 48px */
  --type-h2-track: -0.02em;
  --type-h2-leading: 1.15;

  /* -- h3 · the sub-head inside a section -------------------------------- */
  --type-h3-family: var(--font-structure);
  --type-h3-weight: 600;
  --type-h3-size: clamp(1.25rem, 1.05rem + 0.9vw, 1.75rem);     /* 20 → 28px */
  --type-h3-track: -0.01em;
  --type-h3-leading: 1.25;

  /* -- lead · the sentence under a heading ------------------------------- */
  --type-lead-family: var(--font-text);
  --type-lead-weight: 300;
  --type-lead-size: clamp(1.125rem, 0.98rem + 0.75vw, 1.4375rem); /* 18 → 23px */
  --type-lead-track: -0.005em;
  --type-lead-leading: 1.5;

  /* -- body · running text. Its line box is the space scale (see §3). ----- */
  --type-body-family: var(--font-text);
  --type-body-weight: 400;
  --type-body-size: clamp(1rem, 0.96rem + 0.2vw, 1.125rem);     /* 16 → 18px */
  --type-body-track: 0em;
  --type-body-leading: 1.5;

  /* -- caption · meta, labels, table cells, footnotes --------------------- */
  --type-caption-family: var(--font-text);
  --type-caption-weight: 400;
  --type-caption-size: 0.875rem;                                 /* 14px */
  --type-caption-track: 0.01em;
  --type-caption-leading: 1.5;

  /* The eyebrow is not a ramp step — it is one fixed label style, and it is
     Archivo because it is structure, not prose. */
  --type-eyebrow-size: 0.75rem;
  --type-eyebrow-track: 0.24em;
  --type-eyebrow-weight: 600;

  /* Maximum measures, by role. A heading that runs the full 1600px is not a
     heading, it is a paragraph in a large size. */
  --measure-h1: 14ch;
  --measure-h2: 24ch;
  --measure-lead: 55ch;
  --measure-body: 70ch;

  /* ------------------------------------------------------------------------
     2 · COLOUR — built in OKLCH, so one step is one step everywhere
     ------------------------------------------------------------------------
     Every value below was derived numerically, not picked. The dark and the
     light ramps both move in steps of ΔL = 0.075 in OKLab, which is what makes
     "one plane up" mean the same thing on both. Chroma rises with L along a
     warm hue (H 67–85 by rung, at C 0.002–0.014), so a surface that lifts also
     warms — a plate coming out of the black, not a grey getting lighter.

     That hue used to be described as "the copper's own", and as of 2026-08-31
     it is not: the copper moved to H 60 and the SURFACES DELIBERATELY DID NOT.
     At C 0.0025 a rung is 1/48th of the accent's chroma — a warm cast, not a
     colour — and rotating a cast nobody can name to chase the accent would be
     a change measured in nothing and risked on every plane on the site. What
     the sentence describes is still true; only the claim about where the
     number came from was corrected.

     E2 — the step was 0.060 until 2026-08-31. The plate put both ramps side by
     side under real copy; 0.075 is where a card stops needing its hairline to
     be found. Each rung is recomputed from --bg-0 with only L moving: the
     chroma and the hue of the rung of the same index are exactly what the
     0.060 ramp already carried, so the ramp changed in one variable and only
     one.

     Contrast is measured in Lc (APCA) and written in docs/design-foundations.md
     next to the pairing rule it licenses; WCAG 2.1 is printed beside it as the
     FLOOR. Both come out of scripts/lib/color.mjs, which self-tests against
     nine published reference vectors before it is trusted. */

  /* Dark planes — L 0.1448 · 0.2185 · 0.2945 · 0.3683, C 0 → 0.0075.
     The `-dark` names hold the literals and are NEVER re-pointed; --bg-0..3 are
     what components read and ARE re-pointed inside .band--light. A dark card
     nested in the light band gets the dark scale back by naming the `-dark`
     tokens, which is the only way to reach past an inherited override. */
  --bg-0-dark: #0A0A0A;   /* the page ground — the brand's Rich Black       */
  --bg-1-dark: #1B1A19;   /* the alternate band; a card on the ground       */
  --bg-2-dark: #2E2C2A;   /* a raised well — inputs, panels                 */
  --bg-3-dark: #413F3B;   /* a control plane — chips, hover, pressed        */
  --bg-0: var(--bg-0-dark);
  --bg-1: var(--bg-1-dark);
  --bg-2: var(--bg-2-dark);
  --bg-3: var(--bg-3-dark);

  /* Light planes — L 0.9591 · 0.8834 · 0.8101, H 80.7. Planes RISE on the dark
     ground and RECEDE on the light one, which is how paper behaves. Same ΔL
     0.075, same "only L moves" derivation. */
  --bg-light-0: #F4F1EC;  /* the light band                                 */
  --bg-light-1: #DCD8D1;  /* a card or well on the light band               */
  --bg-light-2: #C6C0B7;  /* the control plane — chips, hover fills          */
  /* The neutral plate a white-backdrop product render sits on. It is not
     --bg-light-*: those are warm, and a warm card behind a neutral studio
     white shows the seam. L 0.9291, C 0.0020. */
  --bg-plate: #E8E7E6;

  /* Text on the dark planes.
     ------------------------------------------------------------------------
     THE CORRECTION OF 2026-08-31, AND IT IS A REPAIR AND NOT A PREFERENCE.
     Every one of these pairs cleared AAA under WCAG 2.1 — --fg-2 measured
     9.13:1 on the ground — and the body of this site still read thin. WCAG's
     ratio is a ratio of relative luminances and is blind to polarity, so it
     scores light-on-dark exactly as it scores dark-on-light. Measured in Lc
     (APCA), which is not blind to it, the same body pair came out at **59
     against a body target of 75**, and meta at **40 against 60**. That gap is
     the whole diagnosis.

     Both were solved in OKLCH by moving ONLY L, so the hue and the chroma of
     the greys — and therefore their temperature against the copper — are
     untouched:

       --fg-2  Lc 79.7 / 78.5 / 75.6  on bg-0 / bg-1 / bg-2   (target 75)
       --fg-3  Lc 64.2 / 63.0 / 60.1  on the same three       (target 60)

     WCAG rose with them (fg-2 to 13.23 / 11.61 / 9.29:1, fg-3 to 10.04 / 8.82
     / 7.06:1) — no pair regressed, which is the floor this round holds itself
     to.

     THE HIERARCHY STILL READS AS A HIERARCHY. fg-1 > fg-2 > fg-3 is
     L 0.9851 > 0.8668 > 0.7847: 15.5 Lc between body and meta, 25 between
     heading and body. Raising meta to its floor did not collapse it onto body.

     bg-3 is a CONTROL plane and its figures are stated rather than assumed:
     fg-1 Lc 95.1, fg-2 Lc 70.4, fg-3 Lc 54.9. Meta on bg-3 now clears the
     non-text floor of 45 with room, so the old prohibition on it is lifted —
     see docs/design-foundations.md. */
  --fg-1-dark: #FAFAFA;   /* headings           Lc 104.4 · 18.97:1 on bg-0 */
  --fg-2-dark: #D4D3D0;   /* body                Lc 79.7 · 13.23:1 on bg-0 */
  --fg-3-dark: #BCB8B4;   /* meta, captions      Lc 64.2 · 10.04:1 on bg-0 */
  --fg-1: var(--fg-1-dark);
  --fg-2: var(--fg-2-dark);
  --fg-3: var(--fg-3-dark);

  /* Text on the light planes — the same correction, the same targets, solved
     downward. Both clear their floor on bg-light-0 AND the new bg-light-1, so
     a card on the band needs no exception of its own.
       --fg-light-2  Lc 89.6 / 75.2   (target 75)   10.78 / 8.55:1
       --fg-light-3  Lc 74.6 / 60.1   (target 60)    5.87 / 4.65:1 */
  --fg-light-1: #151412;  /* headings           Lc 96.9 / 82.5 · 16.34:1 */
  --fg-light-2: #393532;  /* body               Lc 89.6 / 75.2 · 10.78:1 */
  --fg-light-3: #615C57;  /* meta               Lc 74.6 / 60.1 ·  5.87:1 */

  /* Text lying ON a photograph. The dark-ground greys were tuned for a flat
     #0A0A0A and drop below AA over a lit plate, so the two roles that do it —
     the hero lead and the hero's market list — got their own step up the same
     hue: L 0.8698 and L 0.8258.

     LEFT AT THEIR SHIPPED VALUES, AND THAT IS NOW A LOOSE END. They were a
     step UP from --fg-2 at L 0.7564; the APCA correction took --fg-2 to
     L 0.8668. Re-lifted at integration so the pair sits a step ABOVE the
     body grey again (L ~0.936 / ~0.888): an "over image" step darker than
     the flat-ground step it exists to improve on. Both belong to the hero,
     which is another round's file, so they are flagged here rather than
     changed. The contrastOnImage probe measures the real pixels either way and
     is the thing that would catch it going wrong. */
  --fg-over-image: #EDEBE8;
  --fg-over-image-2: #DDDBD8;

  /* Channel triplets, for the alphas. A colour that appears both solid and at
     an alpha is written once, as channels, so the two can never drift. */
  --fg-1-rgb: 250 250 250;
  --fg-light-rgb: 21 20 18;
  --accent-light-rgb: 140 78 9;
  --shadow-rgb: 0 0 0;

  /* Print only: a real white sheet and real black ink, which is the one place
     on this site the palette does not apply. */
  --paper: #FFFFFF;
  --paper-ink: #000000;

  /* -- the accent -------------------------------------------------------- */
  /* THE RULE: copper marks ACTION and INTERACTION — links, buttons, the focus
     ring, hover — plus the eyebrow, which is the one label that names the
     section a reader is entering. It is not emphasis. Emphasis in running
     prose is --fg-1 and a weight, never a colour (see .em in site.css).

     THE HUE CORRECTION OF 2026-08-31, AND IT IS A REPAIR AND NOT A PREFERENCE.
     The owner looked at this accent through two rounds of calibration and said
     "I only see beige". He was right, and the measurement says so: the shipped
     #C9A87C is L 0.7504 C 0.0705 H 74.4 — H 74 is a yellow-gold, not a copper,
     and C 0.07 is barely off the grey axis. Metallic copper (#B87333, the
     reference swatch) is L 0.6180 C 0.1171 H 60.4: ~14° redder and with 66%
     more chroma. A hue in the seventies at a chroma in the sevenths is the
     definition of beige, whatever the token is called.

     THE FIX, AND WHY IT COSTS NO CONTRAST. Every tone in the accent family is
     re-derived in OKLCH with ITS OWN L HELD EXACTLY, H → 60 and C → 0.12
     (capped per tone at the sRGB gamut with 0.004 of margin, so no channel sits
     on the wall — the caps are noted on each token below). APCA and WCAG are
     both functions of luminance, so holding L holds the calibration every
     previous round measured. It was re-measured anyway rather than assumed:
     the whole family moves by |ΔLc| <= 0.98 and no pair crosses a floor. The
     one tone that IS re-solved is --accent-num-2, because its L was never
     chosen — see its block below.

     The hover still moves +0.045 in L along the accent's own hue rather than
     sliding toward a second metal, so the button reads as the same object lit,
     not as a different object. The light ground still gets its own pair because
     copper at L 0.75 measures 1.99:1 on an off-white and cannot be used there
     at any size. */
  --accent-dark: #E59B5B;         /* L 0.7504 C 0.1197 H 60.3   Lc 57.0 ·  8.65:1 on bg-0
                                     was #C9A87C (C 0.0705 H 74.4, Lc 57.9 · 8.84:1)   */
  --accent-hover-dark: #F5A969;   /* L 0.7954 C 0.1205 H 59.9   Lc 65.0 · 10.15:1 on bg-0
                                     was #D8B68A                (Lc 65.8 · 10.35:1)    */
  --accent: var(--accent-dark);
  --accent-hover: var(--accent-hover-dark);
  /* --accent-light took ΔL −0.010 with E2 and for E2's sake alone: it is solved
     to a 4.5:1 floor on --bg-light-1, and E2 took that plane down 0.015 in L,
     which would have left the shipped #7A5D32 at 4.30:1 — a pair regressing
     below what it already was. THAT L IS STILL THE SOLVED ONE: the hue
     correction moved H and C only, and on this side of the ramp it moved the
     ratios UP (4.52 → 4.61:1 on --bg-light-1), because a dark tone gaining
     chroma at a fixed L loses a little luminance against a light plane.
     The gamut is tighter down here than at L 0.75, so C lands at its ceiling
     rather than at 0.12 — the ceiling is written beside each tone. */
  --accent-light: #8C4E09;        /* L 0.4879 C 0.1105 H 60.0 (gamut ceiling 0.1106)
                                     Lc 73.9 / 59.4 / 67.9 · 5.81 / 4.61 / 5.30:1
                                     was #765A2F (C 0.0700 H 76.6, 5.69 / 4.52 / 5.19) */
  --accent-light-hover: #693906;  /* L 0.3966 C 0.0895 H 59.6 (ceiling 0.0893)
                                     Lc 83.7 / 69.3 · 8.52 / 6.76:1 · was #5D4015 */
  /* The channel triplet, for the alphas below. A hairline is the accent at low
     alpha, not a grey — it is what keeps the structure warm. `--accent-rgb` is
     re-pointed inside .band--light; `--accent-rgb-base` never is, so a dark
     card nested in the light band can get the dark accent back. */
  --accent-rgb-base: 229 155 91;
  --accent-rgb: var(--accent-rgb-base);
  /* The label on a copper fill is the ground, not white: 8.65:1 against 2.19:1. */
  --accent-on: var(--bg-0);

  /* -- the copper FILL, which is a gradient and not a flat plane ---------- */
  /* A solid across a 200px pill reads as flat paint. The fill is the same
     copper LIT: two stops on the accent's own hue (H 60) and its own chroma
     (C 0.12), symmetric about it at ΔL ±0.040 in OKLab — so the mean of the
     fill IS --accent and the identity does not move. 135deg, i.e. the light
     stop at the top-left corner, because that is where light comes from on
     every other surface on this site.
       #F3A868  L 0.7912   Lc 65.7   10.00:1 under the label   was #D6B588
       #D88F4F  L 0.7112   Lc 52.7    7.51:1 under the label   was #BC9C70
     THE GRADIENT WAS THE FIRST PLACE THE BEIGE SHOWED. The paragraph above
     used to open "a solid #C9A87C reads as beige paint" and treat that as a
     problem the gradient solved — but two beige stops are still two beiges,
     and lighting a wrong hue does not make it copper. The 2026-08-31 hue
     correction moves both stops to H 60 / C 0.12, so the pill now runs lit
     copper → deep copper. The ΔL ±0.040 span, the 135deg and both L values are
     exactly what they were, which is why the label's ratios move by 0.2.
     Both ends still clear AA for --accent-on with the whole of AAA to spare;
     measured on the painted pixels, not on the tokens.

     ±0.040 is the subtlety threshold: half of it and the fill is flat again,
     twice it and the eye reads "gradient" instead of "metal". It is just
     inside one --accent-hover step (0.045), so no point of the fill is further
     from the copper than its own hover is. */
  /* The `-dark` names hold the literals and are never re-pointed, exactly as
     --accent-dark does, so a dark card nested in the light band can reach past
     the inherited override and get the dark pair back. */
  --accent-grad-1-dark: #F3A868;  /* L 0.7912 C 0.1197 H 60.3 */
  --accent-grad-2-dark: #D88F4F;  /* L 0.7112 C 0.1195 H 60.2 */
  --accent-grad-1: var(--accent-grad-1-dark);
  --accent-grad-2: var(--accent-grad-2-dark);
  --accent-grad: linear-gradient(135deg, var(--accent-grad-1), var(--accent-grad-2));
  /* Hover moves the WHOLE pair down 0.045 in L — the same step size the accent's
     hover uses, in the other direction. A fill that lightens under the pointer
     washes out; a fill that deepens reads as the object taking the press. The
     shape of the gradient is unchanged, so it never snaps to a flat colour.
       #E39959  L 0.7441 C 0.1198 H 60.2   Lc 57.8   8.45:1 under the label
       #C98140  L 0.6661 C 0.1199 H 60.3   Lc 45.7   6.31:1 under the label
     (was #C7A67A / #AE8E63 at 8.64 and 6.46:1 — same two L values, H 74 → 60.) */
  --accent-grad-hover-1-dark: #E39959;
  --accent-grad-hover-2-dark: #C98140;
  /* The MEAN of each pair, as a solid, painted UNDER the gradient. Not
     decoration: a gradient is a background-IMAGE, so
     `getComputedStyle(el).backgroundColor` on a fill that has only a gradient
     reports `transparent` — audit-a11y.mjs reads exactly that property and
     scored the button's label at 1.00:1 the first time this shipped, and so
     would any other tool a reviewer points at it. A solid underneath is the
     honest answer to that question, because it IS the fill's own average, and
     it is the fallback for any renderer that drops the image.
       --accent-fill        = --accent, the mean of the rest pair   8.65:1
       --accent-fill-hover  = --accent at −0.045 L, the hover step  7.33:1 */
  --accent-fill-hover-dark: #D68D4D;   /* L 0.7054 C 0.1196 H 60.2 · was #BB9A6E (7.50:1) */
  --accent-fill: var(--accent);
  --accent-fill-hover: var(--accent-fill-hover-dark);
  --accent-light-fill: #814708;        /* L 0.4586 C 0.1042 H 59.6 (ceiling 0.1038)
                                          6.57 / 5.99:1 on light-0 / plate · was #6E5227 */
  --accent-light-fill-hover: #593004;  /* L 0.3551 C 0.0796 H 60.4 (ceiling 0.0797)
                                          10.08:1 on light-0        · was #523507 */
  --accent-grad-hover-1: var(--accent-grad-hover-1-dark);
  --accent-grad-hover-2: var(--accent-grad-hover-2-dark);
  --accent-grad-hover: linear-gradient(135deg, var(--accent-grad-hover-1), var(--accent-grad-hover-2));

  /* -- G3 · the copper the FIGURES are set in ----------------------------- */
  /* The third role the calibration plate proposed and the owner took: the big
     numerals — monthly capacity, the statistics beside it — stop being white
     and become the metal. They are the strongest facts the company owns and
     they were set in the same grey as the sentence explaining them.

     Same family as everything else copper here: --accent's own chroma (0.12)
     and hue (60), with only L moving.

     THE INTERVAL IS NOT THE PLATE'S. The plate ran cu95 → cu75 and measured its
     dark end at Lc 48.5 over the well, i.e. below the display floor of 60 — a
     figure you cannot read is not a fact. The dark stop is therefore solved
     rather than chosen: it is the lowest rung that clears Lc 60 on bg-2 AND on
     bg-1 AND on bg-0, so the treatment is safe on every dark plane rather than
     only on the one well it was drawn for.

     THIS IS THE ONE TONE THE HUE CORRECTION MOVED IN L, AND IT HAD TO. Every
     other tone in the family kept its L exactly, because its L was a choice.
     --accent-num-2's L was not a choice, it was the ANSWER to "Lc 60 on bg-2",
     and rotating the hue costs ~0.3 Lc there — which would have left the stop
     at 59.8 and quietly broken the guarantee this block exists to state. So it
     was re-solved by the same rule that produced it: L 0.7874 → 0.7902, the
     lowest rung still clearing 60 at H 60 / C 0.12.

       --accent-num-1  #FEBA83  L 0.8404 C 0.1059 H 59.6 (gamut ceiling 0.1054)
                                Lc 73.4 / 72.2 / 69.2 on bg-0/1/2 · was #E6C598
       --accent-num-2  #F3A868  L 0.7902 C 0.1197 H 60.3
                                Lc 64.2 / 63.0 / 60.1          · was #D5B487
       ΔL 0.050 — narrower than the plate's 0.130, wider than the button's
       ±0.040 pair, so the figures read as lit metal and not as a graphic.
       (It was 0.053; the re-solved dark stop closed it by 0.003.)

     --accent-num is the MEAN of the two, as a solid, and it is not decoration:
     `background-clip: text` needs the glyph fill transparent, and every audit
     tool on earth reads `getComputedStyle(el).color` — audit-a11y.mjs included,
     which is how the primary button once scored 1.00:1. So `color` stays the
     honest average of the fill (Lc 64.7, 7.67:1 on bg-2) and only
     `-webkit-text-fill-color` goes transparent. A renderer with no
     background-clip paints the solid and loses nothing but the rake.

     Dark planes only, deliberately: the figures this dresses live in
     .hp-capacity, which is a --bg-2 well. There is no light-band pair because
     there is no light-band figure, and inventing one would be a colour nobody
     measured. */
  --accent-num-1-dark: #FEBA83;
  --accent-num-2-dark: #F3A868;
  --accent-num-dark: #FCB070;   /* L 0.8153, the mean of the pair · was #DEBC90 */
  --accent-num-1: var(--accent-num-1-dark);
  --accent-num-2: var(--accent-num-2-dark);
  --accent-num: var(--accent-num-dark);
  --accent-num-grad: linear-gradient(135deg, var(--accent-num-1), var(--accent-num-2));

  /* The light ramp's pair. It is NOT symmetric, and that is the point: the
     light copper is already solved to its 4.5:1 floor (4.51 on --bg-light-1),
     so a stop above it would break the floor the whole light ramp is built on.
     On a light ground the fill therefore RECEDES instead of rising — the same
     paper rule §2 uses for the surfaces — ΔL −0.080 downward from the base:
       --accent-light  L 0.4879   5.30 / 5.81 / 4.61:1 on plate / light-0 / light-1
       #713E06         L 0.4193   7.10 / 7.79 / 6.18:1
     Hover takes the same span down from --accent-light-hover. Both stops took
     the 2026-08-31 hue correction with their L untouched, so the span, the
     direction and the floors are the ones this paragraph already argued for —
     only the hue under them changed, H 76 → 60. */
  --accent-light-grad-1: var(--accent-light);
  --accent-light-grad-2: #713E06;       /* L 0.4193 C 0.0945 H 60.1 (ceiling 0.0946) · was #63471B */
  --accent-light-grad-hover-1: var(--accent-light-hover);
  --accent-light-grad-hover-2: #4B2803; /* L 0.3164 C 0.0705 H 61.0 (ceiling 0.0707) · was #472B00 */

  /* The partner marks are white PNGs, so a tint is a multiply on a flat white
     and brightness() is the whole of it. The multiplier is not a taste
     setting — it is pinned to --fg-3's own luminance, so the marks land at the
     weight of META TEXT rather than at the weight of a headline. --fg-3 moved
     on 2026-08-31, so this moved with it, or the sentence above stops being
     true and the strip quietly becomes the quietest thing on the page instead
     of the second quietest.

     0.724 x 255 = 184.6 → #B9B9B9, luminance 0.4851 against --fg-3's 0.4827
     (10.09:1 on bg-0 against fg-3's 10.04:1). It was brightness(0.546) → #8B8B8B
     while --fg-3 was #8E8B87.

     It is a filter and not an opacity on purpose: the logoStrip probe requires
     computed opacity >= 0.9, and an opacity would also let the band show
     through the marks — which over a photograph is ten different greys instead
     of one. */
  --logo-strip-tint: brightness(0.724);

  /* The marquee the strip becomes when the reader has not asked for less
     motion. Three values, and each one is a decision:

       --logo-marquee-gap       the space between two marks, and — because the
                                gap is carried as the strip's own trailing
                                padding rather than as a flex `gap` — also the
                                space across the seam between the two copies.
                                One value, so the loop has no joint.
       --logo-marquee-duration  35s for one lap. A lap is one full set of ten
                                passing the window, which at 1440 is ~2.050px
                                of travel: ~59px/s, slower than a reader's eye
                                sweeps a line, which is what stops it reading
                                as a slideshow.
       --logo-marquee-fade      how far the mask takes a mark from invisible to
                                whole at each edge. Wider than a mark's own
                                width would fade the middle of the row; this is
                                about one mark's worth of travel.

     The mask itself is written here rather than in site.css because it is
     built out of colour literals — an alpha ramp, but literals all the same,
     and site.css is not allowed to hold one. Nothing about the ramp is a
     colour decision: #0000 is "hide" and #000 is "show". */
  --logo-marquee-gap: clamp(2rem, 3.4vw, 3.25rem);
  --logo-marquee-duration: 35s;
  --logo-marquee-fade: clamp(2.5rem, 7vw, 6rem);
  --logo-marquee-mask: linear-gradient(
    to right,
    #0000 0,
    #000 var(--logo-marquee-fade),
    #000 calc(100% - var(--logo-marquee-fade)),
    #0000 100%
  );

  /* -- error ------------------------------------------------------------- */
  /* One red, derived the same way: H 27 (the warm end, so it belongs to the
     same family as the copper), C 0.115, L solved for 4.5:1.
     Both moved with E2 and by exactly as much as E2 forced: the dark red was
     solved to 4.51:1 on the old bg-2 and would have landed at 4.11 on the new
     one, and the light red to 4.51:1 on the old bg-light-1 and would have
     landed at 4.30. Only L moved, and only far enough to hold the floor.

     A KNOWN DEBT, WRITTEN DOWN RATHER THAN QUIETLY SHIPPED: measured in Lc the
     pair is 44.1 / 42.9 / 39.9 and 73.2 / 58.8 — under the 60 that --fg-3 now
     holds. This round was scoped to body and meta; error text is the next
     candidate and lifting it is a one-line change here. */
  --danger: #D57970;        /* 6.41 / 5.63 / 4.50:1 on bg-0/1/2 · Lc 44.1 */
  --danger-light: #99453E;  /* 5.69 / 4.51:1 on the light ramp  · Lc 73.2 */

  /* -- hairlines and scrims ---------------------------------------------- */
  /* Hairlines replace shadows entirely. Alpha matters: at 0.08 it is a seam,
     at 0.14 it is structure, at 0.26 it is an edge you can act on. */
  --line-soft: rgb(var(--accent-rgb) / 0.08);
  --line: rgb(var(--accent-rgb) / 0.14);
  --line-strong: rgb(var(--accent-rgb) / 0.26);
  --line-light-soft: rgb(var(--fg-light-rgb) / 0.07);
  --line-light: rgb(var(--fg-light-rgb) / 0.12);
  --line-light-strong: rgb(var(--fg-light-rgb) / 0.22);
  /* Every veil over a photograph is the page ground at an alpha. One triplet,
     so a scrim can never be a slightly different black from the band under it. */
  --scrim-rgb: 10 10 10;

  /* -- interaction, defined once ------------------------------------------ */
  --focus-ring: 2px solid var(--accent);
  --focus-offset: 3px;
  --hover-wash: rgb(var(--accent-rgb) / 0.10);
  --hover-wash-strong: rgb(var(--accent-rgb) / 0.16);
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --transition: 0.3s var(--ease);
  --transition-slow: 0.4s var(--ease);

  /* ------------------------------------------------------------------------
     3 · SPACE — derived from the body line box, not from a favourite number
     ------------------------------------------------------------------------
     Body is 16px at the root with --type-body-leading 1.5, so ONE LINE OF BODY
     TEXT IS 24px TALL. That box is --space-4, and every other step is a whole
     or simple fraction of it:

        --space-1   4px   ⅙ line
        --space-2   8px   ⅓ line          (the unit: everything is a multiple)
        --space-3  16px   ⅔ line
        --space-4  24px   1 line
        --space-5  32px   1⅓ lines
        --space-6  48px   2 lines
        --space-7  64px   2⅔ lines
        --space-8  96px   4 lines

     Fluid type means the rhythm is nominal at the 16px root and scales with it
     above; no fluid page can hold a hard baseline grid, and pretending
     otherwise is how half-pixel drift gets shipped. */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 1rem;
  --space-4: 1.5rem;
  --space-5: 2rem;
  --space-6: 3rem;
  --space-7: 4rem;
  --space-8: 6rem;

  /* ONE rule owns vertical band rhythm: space-7 → space-8. A band that wants
     less air asks for --section-y-tight (space-5 → space-6); it never writes a
     padding of its own, because the moment two bands carry hand-written
     numbers the page has no rhythm left to break. */
  --section-y: clamp(var(--space-7), 7vw, var(--space-8));
  --section-y-tight: clamp(var(--space-5), 4vw, var(--space-6));
  --block-gap: clamp(var(--space-6), 1.5rem + 4vw, var(--space-8));

  /* ------------------------------------------------------------------------
     4 · GRID — a 12-column field, gutters on the same scale
     ------------------------------------------------------------------------
     Twelve because it divides by 2, 3, 4 and 6 — which is every split this
     site actually uses (.grid--2, .grid--3, .grid--4, .split, .row-3, the
     footer's four columns). The one set whose count is not a divisor of 12 is
     the five product lines, and .grid--5 is laid out on its own six-unit
     sub-grid for exactly that reason (see site.css).

     The gutter is a space step, not a number of its own: space-3 on a phone,
     space-4 from tablet up. The page gutter is space-4 throughout. */
  --grid-cols: 12;
  --grid-gutter: clamp(var(--space-3), 2vw, var(--space-4));
  --gutter: var(--space-4);
  --max: 1600px;
  --max-text: 1024px;

  /* ------------------------------------------------------------------------
     5 · SHAPE
     ------------------------------------------------------------------------ */
  --radius-1: 2px;     /* buttons, chips, inputs — almost square */
  --radius-2: 16px;    /* image wells */
  --radius-pill: 999px;

  /* The lockup, and the bar built around it. Everything that has to clear the
     header reads --header-h rather than repeating a number. */
  --logo-h: 72px;
  --logo-h-mobile: 52px;
  --logo-h-scrolled: 56px;
  --header-h: 96px;
  --header-h-scrolled: 80px;
}

/* ==========================================================================
   TRANSITION ALIASES — the pre-foundations names, pointing at the new values.
   ==========================================================================
   Nothing outside this block may use them. They exist so that a component not
   yet migrated cannot render the wrong colour, and the re-skin round deletes
   this block once nothing references it:

       grep -rn -- '--ground\|--surface\|--copper\|--bronze\|--white\|--muted\|--faint\|--ink\|--radius-img\|--fs-' src/styles/site.css
   ========================================================================== */
:root {
  --ground: var(--bg-0);
  --surface: var(--bg-1);
  --copper: var(--accent);
  --bronze: var(--accent-hover);
  --white: var(--fg-1);
  --muted: var(--fg-2);
  --faint: var(--fg-3);
  --surface-light: var(--bg-light-0);
  --ink: var(--fg-light-1);
  --ink-muted: var(--fg-light-2);
  --ink-faint: var(--fg-light-3);
  --copper-ink: var(--accent-light);
  --bronze-ink: var(--accent-light-hover);
  --serif: var(--font-display);
  --sans: var(--font-text);
  --radius: var(--radius-1);
  --radius-img: var(--radius-2);
  --fs-hero: var(--type-display-size);
  --fs-h2: var(--type-h2-size);
  --fs-h3: var(--type-h3-size);
  --fs-h4: 1.0625rem;
  --fs-lead: var(--type-lead-size);
  --fs-body: var(--type-body-size);
  --fs-small: var(--type-caption-size);
  --fs-eyebrow: var(--type-eyebrow-size);
  /* Figures are a display role set in the STRUCTURAL family, so they take the
     h2 step rather than a step of their own: Archivo 600 at 48px carries more
     ink than the serif did at 56px, and the weight does the work the extra
     points used to do. */
  --fs-stat: var(--type-h2-size);
}

/* ==========================================================================
   CHINESE — the same seven steps, in the one family that has the glyphs
   ==========================================================================
   Noto Sans SC is not a serif and has no display cut, so the ramp cannot be
   translated by family; it is translated by WEIGHT. The two display steps take
   500 and the two structural steps take 700, which reproduces the latin
   ramp's jump from an editorial voice to a structural one using the only lever
   a single CJK family gives. Body stays 400.

   The subset in public/assets/fonts/noto-sans-sc-var.woff2 keeps the wght axis
   and is declared `font-weight: 300 700`, so 500 and 700 are inside the range
   the committed file already covers — no re-subset, no size change.

   Sizes: the latin steps are set for Newsreader's cap height. Chinese glyphs
   fill their em box, so the same numbers set 8% too large; the display steps
   are taken down accordingly. Declared on :root:lang(zh) rather than on the
   headings because these are the tokens the whole page reads. */
:root:lang(zh) {
  /* A2 applies here too, and it has to: these two steps are the latin ones
     taken down ~8%, so leaving them where they were would turn a stated −8%
     relation into a −13% one and the Chinese h1 would quietly stop matching
     the English page. Same 1.06, same whole-clamp rescale. The tracking stays
     positive: A2's −0.022em is a latin display decision, and a CJK glyph that
     fills its em box wants air between characters, not less of it. */
  --type-display-family: var(--font-structure);
  --type-display-weight: 500;
  --type-display-size: clamp(2.65rem, 1.325rem + 5.724vw, 5.3rem);
  --type-display-track: 0.01em;

  --type-h1-family: var(--font-structure);
  --type-h1-weight: 500;
  --type-h1-size: clamp(2.12rem, 1.113rem + 4.346vw, 4.1075rem);
  --type-h1-track: 0.01em;

  --type-h2-weight: 700;
  --type-h2-size: clamp(1.625rem, 1rem + 2.4vw, 2.75rem);
  --type-h2-track: 0.01em;

  --type-h3-weight: 700;
  --type-h3-size: clamp(1.1875rem, 1rem + 0.8vw, 1.625rem);
  --type-h3-track: 0.01em;

  --type-lead-weight: 400;
  --type-body-leading: 1.8;
  --type-eyebrow-track: 0.16em;
  /* Measures are in `ch`, the width of a zero — meaningless for a script whose
     glyphs are one em wide. */
  --measure-h1: 14em;
  --measure-h2: 22em;
  --measure-lead: 34em;
  --measure-body: 40em;
}
