/*
 * The two typefaces of the design system, served from our own origin (phase 2.5a).
 *
 * Planning/06-Clients.md decided against web fonts, and the comment that decision left
 * behind in Theme/FlurfunkProTheme.cs and in index.html said why: a chat window is read
 * all day, and the first paint should not have to wait for a download. Planning/design/
 * overrules the *choice* - the design system names Domine and Source Sans 3 by name,
 * and a headline set in whatever serif the machine happens to have is not that design
 * system. It does not overrule the reason. Both are answered here rather than one of
 * them being traded away:
 *
 *   - font-display: swap, so a line of text is painted at once, in a fallback, exactly
 *     as it is today. Nothing is ever invisible waiting for a font.
 *   - And the fallback is metric-matched, so the swap is not a jump. That is the whole
 *     second half of this file, and it is the part that earns the reversal: the old
 *     decision protected the first paint, and the first paint stays protected.
 *
 * Why the files are in this repository rather than on a CDN: the four reference screens
 * in Planning/design/ (each screen's code.html) load both families from
 * fonts.googleapis.com. We
 * deliberately do not copy that. It hands the IP address and the User-Agent of every
 * reader to a third party on every visit, for a font, and there is no line in
 * Planning/09-Sicherheit-und-Datenschutz.md that such a transfer could be filed under.
 * Self-hosting also removes a second origin from the critical path - no extra DNS
 * lookup, no extra TLS handshake - which is the cheapest performance win in the file.
 *
 * What is shipped, and what is not. Only the cuts Planning/design/.../DESIGN.md names
 * under `typography`: Domine 700 (display-kpi and every headline style; 400 and 600 are
 * never asked for), and Source Sans 3 400 (body), 600 (labels) and 700 (the one bold
 * the reference screens request). Each is instanced from the upstream variable font,
 * subset to the Latin range, and compressed to woff2 - 60 KB for all four together,
 * less than one avatar. No italics: the design system does not use them, and the
 * browser's synthetic oblique is good enough for the rare <em>. Latin only: FlurfunkPro
 * is a German workspace, and anyone who pastes Greek or Cyrillic gets the system font
 * for it, which is a correct rendering rather than a missing one.
 *
 * Both families are licensed under the SIL Open Font License 1.1. The licence texts are
 * next to the files in ../fonts/, and NOTICE in the repository root points at them.
 *
 * Rebuilding the files. Sources are the upstream variable fonts in google/fonts,
 * ofl/domine/Domine[wght].ttf and ofl/sourcesans3/SourceSans3[wght].ttf. Pin the weight
 * with fontTools' instancer, then, per weight:
 *
 *   pyftsubset <weight>.ttf --flavor=woff2 --no-hinting --desubroutinize \
 *     --drop-tables+=DSIG --name-IDs='*' \
 *     --layout-features=kern,liga,clig,calt,ccmp,mark,mkmk,locl \
 *     --unicodes=<the unicode-range below, commas instead of spaces>
 *
 * Hinting is dropped because no shipping browser uses TrueType hints any more and it is
 * a third of the file; the layout features are the ones that affect Latin text, and
 * everything else in GSUB/GPOS goes with the characters it belonged to.
 */

/* --- The design system's faces -------------------------------------------- */

/*
 * Domine, the serif. DESIGN.md gives it headings and stand-alone metric figures, and
 * only ever at 700 - which is why there is exactly one file here and not a family.
 */
@font-face {
    font-family: "Domine";
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url("../fonts/domine-700-latin.woff2") format("woff2");
    /* The Latin range Google's css2 API defines for this subset, kept verbatim so the
       file and the declaration cannot drift apart. Anything outside it never triggers a
       download and falls through to the stack below. */
    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;
}

/*
 * Source Sans 3, the sans. Everything that is read rather than scanned: message bodies,
 * channel names, tables, buttons. 400 carries almost the whole screen, which is why it
 * is the one preloaded next to Domine in index.html.
 */
@font-face {
    font-family: "Source Sans 3";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("../fonts/source-sans-3-400-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;
}

/* 600 is DESIGN.md's label weight (label-md, label-sm) - the sender name above a
   message, a column header, a button. It is a separate file rather than synthetic bold
   because those labels sit next to 400 body text all day and the difference shows. */
@font-face {
    font-family: "Source Sans 3";
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url("../fonts/source-sans-3-600-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;
}

/* 700 is not in DESIGN.md's `typography` table, but all four reference screens request
   it (Source+Sans+3:wght@400;600;700) and use it for emphasis inside running text. Kept
   so that <strong> is a real bold and not a smeared 600. */
@font-face {
    font-family: "Source Sans 3";
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url("../fonts/source-sans-3-700-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;
}

/* --- Fallback metrics ----------------------------------------------------- */

/*
 * This is the part that makes `swap` safe to use.
 *
 * With font-display: swap the browser draws the whole screen in a fallback font first
 * and replaces it when the download lands. If the fallback has different proportions -
 * and it always does - every line rewraps and everything below it moves. In a chat that
 * is worse than in a document: the reader is already reading, the list is already
 * scrolled, and a reflow at the wrong moment moves the message under the cursor. That
 * jump, not the download, was the real cost behind the old decision against web fonts.
 *
 * The fix is to make the fallback lie about its own dimensions until it matches:
 *
 *   size-adjust        scales every glyph so the fallback occupies the same horizontal
 *                      space as the real font, which is what stops the rewrap.
 *   ascent-override    \
 *   descent-override    > pin the line box, which is what stops the vertical shift.
 *   line-gap-override  /
 *
 * How the numbers below were derived (all of it reproducible from the upstream files):
 *
 *   size-adjust = avg(target) / avg(fallback), where avg is the mean advance width of
 *       a-z plus the space, weighted by their frequency in German and English prose and
 *       divided by unitsPerEm. The space is included because it is the most frequent
 *       character in any text and dominates the width of a line. The same weighting is
 *       applied to every font, so only the ratio matters, not the absolute value.
 *
 *   ascent/descent/line-gap-override = the target's own vertical metrics, divided by
 *       size-adjust. The division is the step that is easy to miss: size-adjust rescales
 *       the em these percentages are relative to, so an undivided ascent lands in the
 *       wrong place. Taken from OS/2 sTypoAscender/Descender/LineGap where the font sets
 *       USE_TYPO_METRICS (Source Sans 3 does), otherwise from hhea (Domine), which is
 *       the same rule the browsers use to pick a font's line box.
 *
 * One face per fallback family rather than one generic face, because Georgia and Times
 * are 10% apart and a single average would be wrong for both. The browser takes the
 * first family in the stack whose local() actually resolves, so the order below is the
 * order the platforms are likely to answer in: macOS, Windows, Android, then whatever.
 * Fonts that are metric-compatible clones share a face with their original - Liberation
 * Serif for Times, Liberation Sans and Arimo for Arial - because their advance widths
 * are identical by design.
 *
 * DESIGN.md names Cambria and Calibri as the mappings for desktop shells. Neither could
 * be measured here, so neither gets a face of its own; Windows always has Arial and
 * Times New Roman, so nobody is left on an unadjusted fallback. Bold text during the
 * swap is drawn as synthetic bold from the regular local file and is a shade wider than
 * the numbers below assume - a headline may still move a hair. Fixing that would need a
 * second face per family per weight, which is not worth the file.
 */

/* Domine 700 vs Georgia: 0.4964 / 0.4419 = 1.1235. */
@font-face {
    font-family: "Domine Fallback Georgia";
    src: local("Georgia");
    size-adjust: 112.35%;
    ascent-override: 80.11%;
    descent-override: 21.36%;
    line-gap-override: 0%;
}

/* Domine 700 vs Times New Roman: 0.4964 / 0.4025 = 1.2333. Times is the narrower of the
   two, so it needs the larger correction. */
@font-face {
    font-family: "Domine Fallback Times";
    src: local("Times New Roman"), local("Liberation Serif"), local("Tinos");
    size-adjust: 123.33%;
    ascent-override: 72.97%;
    descent-override: 19.46%;
    line-gap-override: 0%;
}

/*
 * The sans overrides are all computed against Source Sans 3 *400*, not 600 or 700: body
 * text is what fills the window and what rewraps expensively. Against Arial the ratio is
 * 93.85% at 400, 96.63% at 600 and 99.28% at 700, so the heavier cuts are corrected
 * slightly too far - a few tenths of a percent on the handful of labels on screen,
 * against getting every message body right.
 *
 * Source Sans 3's line box is unusually tall (ascent 1.024, descent 0.400 em). The
 * overrides reproduce that faithfully, which is the point: matching the real font is the
 * goal, not producing a pretty number.
 */

/* Source Sans 3 400 vs Helvetica Neue: 0.4178 / 0.4497 = 0.9289. macOS and iOS. */
@font-face {
    font-family: "Source Sans 3 Fallback Helvetica";
    src: local("Helvetica Neue"), local("Helvetica");
    size-adjust: 92.89%;
    ascent-override: 110.23%;
    descent-override: 43.06%;
    line-gap-override: 0%;
}

/* Source Sans 3 400 vs Arial: 0.4178 / 0.4452 = 0.9385. Windows, and every Linux with
   the Liberation or Croscore families installed. */
@font-face {
    font-family: "Source Sans 3 Fallback Arial";
    src: local("Arial"), local("Liberation Sans"), local("Arimo");
    size-adjust: 93.85%;
    ascent-override: 109.11%;
    descent-override: 42.62%;
    line-gap-override: 0%;
}

/* Source Sans 3 400 vs Roboto: 0.4178 / 0.4461 = 0.9366. Android and ChromeOS, where
   neither Helvetica nor Arial exists. Roboto is measured, not shipped - only local(). */
@font-face {
    font-family: "Source Sans 3 Fallback Roboto";
    src: local("Roboto");
    size-adjust: 93.66%;
    ascent-override: 109.34%;
    descent-override: 42.71%;
    line-gap-override: 0%;
}

/* --- The stacks ----------------------------------------------------------- */

/*
 * The two families as tokens, so that no component ever writes a font name. The theme in
 * Theme/FlurfunkProTheme.cs and the component-scoped stylesheets read these; the Flutter
 * side mirrors the same two families in phase 3 (Planning/10-Roadmap-und-Aufwand.md,
 * epic "Typografie").
 *
 * A stack ends in an unadjusted generic on purpose. A fallback face whose local() finds
 * nothing is skipped entirely, so on a machine with none of the measured fonts the text
 * still renders - just without the metric correction, which is the situation everybody
 * was in before this file existed.
 */
:root {
    --ffp-font-serif: "Domine", "Domine Fallback Georgia", "Domine Fallback Times", Georgia, Cambria, serif;
    --ffp-font-sans: "Source Sans 3", "Source Sans 3 Fallback Helvetica", "Source Sans 3 Fallback Arial", "Source Sans 3 Fallback Roboto", system-ui, -apple-system, "Segoe UI", sans-serif;
}
