/* Self-hosted fonts. Two families only — Newsreader (headings) and Hanken
   Grotesk (body/UI) — plus one metric-matched fallback face for each.

   The woff2 files here are GENERATED. Re-run `python3 scripts/build-variable-fonts.py`
   after touching them; do not drop an untrimmed Google Fonts download in place.
   Newsreader's full two-axis variable file is 132 KB latin / 147 KB italic, roughly
   double what the site needs, and the trim is what keeps the payload flat.

   Both families are SIL Open Font License 1.1 — see THIRD-PARTY-NOTICES.md. */

/* ============================================================ NEWSREADER
   Variable: wght 400–600 × opsz 14–72. The optical-size axis is the point, not a
   side effect — it is what lets the hero be a display cut rather than a 16pt text
   master scaled to 96px. Driven by `font-optical-sizing: auto` in global.css. */
@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('fonts/newsreader-var-latin.woff2') format('woff2');
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Needed by the founder names — "Kabaciński" carries U+0144. */
@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('fonts/newsreader-var-latin-ext.woff2') format('woff2');
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
    U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}
@font-face {
  font-family: 'Newsreader';
  font-style: italic;
  font-weight: 400 600;
  font-display: swap;
  src: url('fonts/newsreader-var-italic-latin.woff2') format('woff2');
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Newsreader';
  font-style: italic;
  font-weight: 400 600;
  font-display: swap;
  src: url('fonts/newsreader-var-italic-latin-ext.woff2') format('woff2');
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
    U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}

/* ============================================================ HANKEN GROTESK
   Variable: wght 100–900, one file.

   ⚠ This directory previously held `hanken-400/500/600/700-latin.woff2` as four
   separate @font-face sources. They were **byte-identical** — Google only ships
   Hanken as a variable font, so all four names pointed at the same 34,704-byte
   file and the browser fetched it four times (138 KB over 4 requests to get 35 KB
   over 1). Never re-split a variable family into per-weight files. */
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('fonts/hanken-var-latin.woff2') format('woff2');
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('fonts/hanken-var-latin-ext.woff2') format('woff2');
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
    U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}

/* ============================================================ FALLBACK FACES
   `font-display: swap` means the fallback paints first and the webfont replaces
   it — every metric difference between the two becomes layout shift. These faces
   re-shape the fallback to occupy the webfont's box, so the swap changes
   letterforms and not layout.

   Every number below was MEASURED, not recalled:

   - Vertical overrides come from the generated woff2 themselves, printed by
     `scripts/build-variable-fonts.py --report`: Newsreader ascent 0.735 /
     descent 0.265 / line-gap 0 · Hanken ascent 1.0 / descent 0.303 / line-gap 0.
     Each is divided by its own `size-adjust`, which is what the descriptor
     expects once the em has been rescaled.
   - `size-adjust` is the advance-width ratio of the real webfont against the real
     fallback, measured in Chromium with `canvas.measureText` over 304 characters
     of this site's own hero and Technology copy — not a lorem string, because the
     copy is what actually reflows. Newsreader ran 9.54% wider than Times New
     Roman; Hanken ran 0.48% wider than Arial.

   ⚠ Calibration reference, stated because it bounds the accuracy: Times New Roman
   and Arial are not installed in the build environment, so the ratios were taken
   against **Tinos** and **Arimo** — metric-compatible clones of exactly those two,
   built to the same advance widths as the Chrome OS substitutes. Georgia,
   nominally the first serif fallback on Windows and macOS, has no
   metric-compatible clone available here, so it is deliberately NOT the
   calibration target and sits after the fallback face in the stack rather than
   inside it. A visitor whose stack resolves to Georgia gets the uncalibrated
   fallback — the status quo, not a regression. */
@font-face {
  font-family: 'Newsreader Fallback';
  src: local('Times New Roman'), local('Tinos'), local('Liberation Serif'), local('Nimbus Roman');
  size-adjust: 109.54%;
  ascent-override: 67.12%;
  descent-override: 24.19%;
  line-gap-override: 0%;
}
/* ⚠ A SECOND SERIF FALLBACK, FOR DISPLAY SIZES ONLY — and it is not a duplicate.
   One `size-adjust` cannot serve both ends of this family, because the whole point
   of the `opsz` axis is that Newsreader is not the same shape at 19px and at 82px.
   Measured with the same canvas method over the same kind of copy (the six display
   strings this site actually sets), Newsreader against Tinos:

       48px → 1.0904   60px → 1.1147   72px → 1.1390   82px → 1.1390

   The ratio climbs with size and then PLATEAUS, because the axis is trimmed to
   `opsz 14–72` and stops widening past 72. So the text-calibrated 109.54% leaves
   the fallback ~4% narrow at 48px and ~8.7% narrow at the hero's 81.7px.

   What that cost, concretely: at the hero's step the fallback set "from seed to
   harvest." in 695px against Newsreader's 760px in a 730px column — so the fallback
   fitted it on one line and the webfont did not, and everything below the headline
   dropped a full 82px line at swap. The disagreement covered viewports ~1132–1372px
   wide, which includes 1280 and 1366. Widening the column instead would only have
   moved that window somewhere else (1→9 columns moves it to 874–1034, i.e. onto
   1024), because a column edge can only ever sit on one side of a break boundary.

   Correcting the FONT rather than the column fixes it at every width at once and
   survives a copy edit, which a tuned breakpoint would not. Above 72px the two
   faces now measure the same, so where the line falls no longer matters.

   The verticals are Newsreader's own (ascent 0.735 / descent 0.265) divided by this
   face's own size-adjust, exactly as for the text face. */
@font-face {
  font-family: 'Newsreader Display Fallback';
  src: local('Times New Roman'), local('Tinos'), local('Liberation Serif'), local('Nimbus Roman');
  /* ⚠ 113.9% IS CALIBRATED AGAINST NEWSREADER AT WEIGHT 500, and it must stay in step
     with whatever weight `[data-band='hero'] h1` actually uses. Changing the hero to
     weight 400 was tried on 2026-07-26 and reverted; the reason is recorded in
     Hero.astro. Short version: at 400 the required ratio is not a single number —
     measured in the browser it runs 1.0693 at 50.8px to 1.1096 at 81.7px, and no value
     between 105.5% and 110.74% makes the fallback's line count match Newsreader's at
     every tested width. If the hero weight ever changes, re-measure this. */
  size-adjust: 113.9%;
  ascent-override: 64.53%;
  descent-override: 23.27%;
  line-gap-override: 0%;
}
@font-face {
  font-family: 'Hanken Fallback';
  src:
    local('Arial'), local('Arimo'), local('Liberation Sans'), local('Helvetica Neue'),
    local('Helvetica');
  size-adjust: 100.48%;
  ascent-override: 99.52%;
  descent-override: 30.16%;
  line-gap-override: 0%;
}
