/* =====================================================================
   fonts.css — self-hosted Fraunces + Plus Jakarta Sans (WP-S2, roadmap
   §2.9/§4 P16).
   ---------------------------------------------------------------------
   Replaces the render-blocking third-party fetch to fonts.googleapis.com
   (+ a fonts.gstatic.com round-trip behind it) with same-origin woff2
   files under assets/vendor/fonts/ — offline-capable once the service
   worker precaches them (see the WP-S2 report's orchestrator wiring
   instructions for the exact sw.js PRECACHE additions needed) and no
   third-party request/cookie at all once the commented Google Fonts
   fallback (kept one release per P16) is removed.

   WHY ONE FILE PER FAMILY (not one per weight): Fraunces and Plus Jakarta
   Sans are both shipped by Google Fonts as true variable fonts — every
   static weight in the ranges below (Fraunces 500/600/700, Jakarta
   400/500/600/700/800) resolves to the SAME physical file from Google's
   own css2 API (verified 2026-07-23 by requesting each weight combo and
   diffing the returned URLs). So each @font-face below declares a
   `font-weight` RANGE and points at one file — exactly what Google itself
   does, just self-hosted. Only Fraunces italic is a separate physical
   file (roman vs italic are genuinely different outlines).

   THAI (P16 — the careful part): Plus Jakarta Sans ships NO Thai glyphs.
   Verified 2026-07-23 by requesting the family from Google Fonts' css2 API
   and enumerating every @font-face subset returned — only latin,
   latin-ext, vietnamese, and cyrillic-ext come back, never thai (unlike a
   font with real multi-script support, e.g. Noto Sans, which returns a
   /* thai */ block). Today that's silently fine: Plus Jakarta Sans simply
   doesn't match Thai codepoints, so the browser falls through the
   --font-sans stack to the OS's own Thai font (Noto Sans Thai on Android,
   the platform default elsewhere) — see styles.css's --font-sans list.
   Self-hosting the Latin file alone, WITHOUT a matching unicode-range,
   would break that fallback (the browser would think this face covers
   Thai and render .notdef boxes instead of skipping to the next font in
   the stack). Two ways to keep this safe were on the table:
     1. Rely on the same implicit fallback (do nothing extra) — keeps
        today's behavior, but ties Thai rendering to whatever font the
        OS/browser happens to ship, which is NOT guaranteed offline on
        every device this PWA targets.
     2. Register a Noto Sans Thai file under the SAME font-family name
        ("Plus Jakarta Sans"), scoped to the Thai unicode-range only —
        the standard multi-script @font-face pattern (this is literally
        how Google's own API serves a multi-script family: one name,
        several physical files, routed per-character by unicode-range).
   Went with (2): it's self-hosted (works offline, no regression vs.
   today), additive (never intercepts non-Thai text — the unicode-range
   guarantees that), and there is currently no live Thai-script text
   anywhere in the site to visually regress (verified via a repo-wide
   Unicode Thai-block grep) — this file exists so the day Thai content
   IS added, it renders correctly and offline on the first try instead of
   depending on an unverified system fallback. See the WP-S2 report for
   how this was verified without a live Thai page to screenshot.

   2026-08-26: Material Symbols IS self-hosted now, and JetBrains Mono is
   gone. Both were render-blocking cross-origin <link rel=stylesheet> in
   every page's <head>, and they cost /index.html 4.8s of FCP and 4.6s of
   LCP under Lighthouse's simulated throttling (measured: 7.3s/8.5s as
   shipped, 2.5s/3.9s with fonts.googleapis.com blocked).

   The icon font is SUBSET to the 47 icons the site actually uses, via
   Google's own `icon_names=` parameter: 17KB instead of the 889KB full
   variable font. The icon list was gathered by static sweep AND by reading
   the rendered DOM — the static sweep alone missed `more_horiz` and
   `settings`, and a missed icon renders as its literal ligature name, so
   both passes matter. `test/icon-subset-coverage.test.mjs` now guards it.

   ADDING A NEW ICON MEANS RE-SUBSETTING, AND RE-SUBSETTING MEANS A NEW
   FILENAME. The hash in the name is not decoration: the service worker serves
   fonts cache-first on the assumption that a font's bytes never change in
   place, and the first re-subset broke that assumption — the origin served the
   new file, every returning visitor kept the old one, and five icons rendered
   as the words "restart_alt", "photo_camera", "save", "chevron_left", "undo"
   in the middle of the UI. A content change gets a new URL, and the problem
   cannot recur. test/icon-subset-coverage.test.mjs checks the name matches the
   file. The test will fail and tell you.
   Re-fetch with the updated list from
   https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@20..48,400,0,0&icon_names=<comma,list>&display=block

   font-display is `block`, not `swap`, and deliberately: an icon font that
   swaps shows the ligature NAME as text first. Blocking briefly shows
   nothing, which is the right trade for a glyph.

   JetBrains Mono was a render-blocking request on 15 pages for exactly one
   rule — `.menu__version`, a 0.68rem string at 35% opacity. The
   --font-mono chain already falls back to ui-monospace/SFMono-Regular, and
   the sims never used it at all (they define their own mono stack). The
   family name stays first in the chain, so anyone who has it installed
   still gets it; nothing is downloaded for it.
   ===================================================================== */

@font-face {
  font-family: "Fraunces";
  font-style: normal;
  font-weight: 500 700; /* variable font — one file covers 500/600/700, all three used by styles.css */
  font-display: swap;
  src: url("vendor/fonts/fraunces-latin-variable.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: "Fraunces";
  font-style: italic;
  font-weight: 500;
  font-display: swap;
  src: url("vendor/fonts/fraunces-italic-latin-500.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: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 400 800; /* variable font — one file covers every weight styles.css uses (400/500/600/700/800) */
  font-display: swap;
  src: url("vendor/fonts/plus-jakarta-sans-latin-variable.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;
}

/* Thai fallback subset — see the long comment above. Same family name as
   the Latin face above; unicode-range keeps the two from ever competing
   for the same character. Noto Sans Thai is itself a variable font (400
   and 700 both resolve to this one file, verified the same way). */
@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("vendor/fonts/noto-sans-thai-variable.woff2") format("woff2");
  unicode-range: U+02D7, U+0303, U+0331, U+0E01-0E5B, U+200C-200D, U+25CC;
}

/* =====================================================================
   Material Symbols Rounded — the site icon system, self-hosted and subset.
   The @font-face and the class rules both live here because Google's
   stylesheet used to supply BOTH: styles.css only ever set the variation
   axes and sizing, and would render nothing without the family and the
   ligature feature below.
   ===================================================================== */
@font-face {
  font-family: "Material Symbols Rounded";
  font-style: normal;
  font-weight: 400;
  font-display: block;   /* never show the ligature name as text */
  src: url("vendor/fonts/material-symbols-rounded.ad1b0ab3.woff2") format("woff2");
}
.material-symbols-rounded {
  font-family: "Material Symbols Rounded";
  font-weight: normal;
  font-style: normal;
  line-height: 1;
  letter-spacing: normal;
  text-transform: none;
  display: inline-block;
  white-space: nowrap;
  word-wrap: normal;
  direction: ltr;
  font-feature-settings: "liga";
  -webkit-font-feature-settings: "liga";
  -webkit-font-smoothing: antialiased;
}
