# Fonts — provenance
Self-hosted per `docs/02-design-system.md`. **No runtime Google Fonts request**:
the page collects legal inquiries, and a third-party font call costs a round trip
and adds a third party to that page.
These `.woff2` files are committed rather than pulled at build time so their
paths are stable — a `` needs a filename that does not change
between builds, and Astro's asset hashing would break that.
| File | Source package | Version | Licence |
|---|---|---|---|
| `instrument-serif-latin-400-normal.woff2` | `@fontsource/instrument-serif` | 5.3.0 | SIL OFL 1.1 |
| `instrument-serif-latin-ext-400-normal.woff2` | `@fontsource/instrument-serif` | 5.3.0 | SIL OFL 1.1 |
| `instrument-serif-latin-400-italic.woff2` | `@fontsource/instrument-serif` | 5.3.0 | SIL OFL 1.1 |
| `geist-latin-wght-normal.woff2` | `@fontsource-variable/geist` | 5.3.0 | SIL OFL 1.1 |
| `geist-latin-ext-wght-normal.woff2` | `@fontsource-variable/geist` | 5.3.0 | SIL OFL 1.1 |
| `geist-mono-latin-wght-normal.woff2` | `@fontsource-variable/geist-mono` | 5.3.0 | SIL OFL 1.1 |
**The `?v=1` on every font URL is load-bearing.** `scripts/deploy-local.sh`
serves `/fonts/*` with `max-age=31536000, immutable`, so a returning visitor
holds these bytes for a year and no CloudFront invalidation can reach their
browser cache. Replacing a file means bumping that query — in
`src/styles/global.css` **and** in the `` in
`BaseLayout.astro`, which must match character for character or the preload
fetches a second copy instead of warming the cache.
Fetched 2026-08-26 with `npm pack @5.3.0` and extracted from `package/files/`.
Subsetting is Fontsource's, not ours — the `latin` and `latin-ext` cuts are
exactly the "Latin + Latin Extended-A" the design system asks for.
**123,804 bytes across all six**, of which only two — Instrument Serif 400 latin
(21,032) and Geist latin (29,400) — are preloaded, so first paint pulls about
50 kB. Quote the byte figure, not `du -sh`, which reports 136K because it counts
disk blocks rather than what crosses the wire.
**Not covered by `AGENTS.md` R11.** R11 re-checks npm pins for currency and
advisories; these are static binaries with no runtime and no dependency tree.
Refresh them deliberately — when a face gains glyphs the site needs — by
repeating the `npm pack` above, not on a currency schedule.
**Deliberately absent:** the `latin-ext` italic cut of Instrument Serif, and
every non-Latin cut of all three faces. `.display .it` is one italic phrase in a
headline (`docs/02`), and D4 makes the site English-only. Add a cut when a page
needs it; do not add all of them pre-emptively.