/* ==========================================================================
   fonts.css — EditingTools.pro
   Self-hosted webfonts. No third-party request, on any page.

   These were served from fonts.googleapis.com until it was pointed out that
   the site claims to make no external calls. It did make one — on every page
   load, before anything else, to a third party. That is worth removing for
   three separate reasons:

     1. PRIVACY. A Google Fonts request sends the visitor's IP address and
        User-Agent to Google on every page view, before they have consented to
        anything. For a site whose entire promise is "your files never leave
        your browser", an unconditional third-party beacon is a contradiction.

     2. SPEED. The old setup needed a DNS lookup, TCP connect and TLS handshake
        to two hosts (googleapis for the CSS, gstatic for the font files) before
        a single glyph could render — and the second host was not even known
        until the first response came back. Self-hosted, the fonts come from
        a connection that is already open.

     3. OFFLINE. Phase 9 adds a service worker. A cached page that still needs
        Google to render its text is not actually offline.

   All three families are SIL Open Font License 1.1, which permits
   redistribution. Files come from the @fontsource packages and live in
   /assets/fonts/. Latin subset only — the site is English-language in four
   markets, so Cyrillic and Greek would be ~200KB nobody downloads for a
   reason.

   font-display: swap means text renders immediately in the fallback and
   re-renders when the webfont arrives. The alternative, blocking, is a blank
   page for as long as the font takes.

   THE FAMILIES CHANGED, AND THE OLD FILES ARE GONE.

   Display was Space Grotesk and body was Inter. Both were replaced: Space
   Grotesk's wide geometric caps gave every heading an experimental character
   that worked against a site asking to be trusted with your documents, and
   Inter has become the default sans of the entire web — near-invisible as a
   choice, and close enough to a geometric display face that headings and body
   blurred into one texture.

   Plus Jakarta Sans sets the headings now, Source Sans 3 the body. They are
   deliberately unalike: one geometric and confident, one humanist and narrow,
   so a paragraph reads as a different voice from the heading above it rather
   than a smaller size of the same one.

   The replacement is also cheaper — 112KB across seven files, against 142KB
   before, because Jakarta and Source Sans subset more efficiently than the
   two they replaced.

   The old .woff2 files were DELETED rather than left in place. An unused font
   file on a server is a file some page still links to by accident and nobody
   notices, because a missing font fails silently into the fallback stack.
   ========================================================================== */

/* Display — headings only, so just the two weights that get used. */
@font-face {
  font-family: 'Plus Jakarta Sans';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/plus-jakarta-sans-latin-600-normal.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+2074, 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: 700;
  font-display: swap;
  src: url('/assets/fonts/plus-jakarta-sans-latin-700-normal.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+2074, U+20AC,
                 U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Body — 400, 500 and 600. */
@font-face {
  font-family: 'Source Sans 3';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/source-sans-3-latin-400-normal.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+2074, U+20AC,
                 U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Source Sans 3';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/assets/fonts/source-sans-3-latin-500-normal.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+2074, U+20AC,
                 U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Source Sans 3';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/source-sans-3-latin-600-normal.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+2074, U+20AC,
                 U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Mono — every number on the site. Unchanged: the numerals were never the problem. */
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/jetbrains-mono-latin-400-normal.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+2074, U+20AC,
                 U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/assets/fonts/jetbrains-mono-latin-500-normal.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+2074, U+20AC,
                 U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ==========================================================================
   METRIC-MATCHED FALLBACKS — the layout-shift fix

   THE PROBLEM, MEASURED

   Source Sans 3 is a narrow humanist face. Arial — which is what almost every
   visitor sees for the fraction of a second before the webfont arrives — is
   not. Their OS/2 xAvgCharWidth values, normalised to the em, differ by
   nineteen per cent, so the same paragraph occupies a different number of
   lines in each. On the home page that showed up as the sub-headline going
   from four lines to three, the search box and drop zone jumping fifty pixels
   up the page, and a Cumulative Layout Shift of 0.096 — inside Google's
   "good" band, but only just, and visible.

   `font-display: swap` is what makes the text appear immediately, and it is
   still the right choice. The shift is not caused by swapping; it is caused
   by swapping between two fonts of different widths.

   THE FIX, AND WHERE THE NUMBERS CAME FROM

   A second @font-face per family that is not a font at all: it points at a
   font the visitor already has, and then rescales it so its average character
   width matches the webfont's. Text laid out in the fallback occupies the
   same space as text laid out in the real face, so the swap changes what the
   letters look like and nothing about where they sit.

     size-adjust     = width of a sample paragraph in the webfont
                       ÷ width of the same paragraph in the fallback
     ascent-override = webfont ascender/upm ÷ size-adjust   (and likewise
     descent-override, line-gap-override)

   size-adjust was MEASURED IN A BROWSER rather than derived from the fonts'
   OS/2 xAvgCharWidth, and the difference was not academic. xAvgCharWidth
   averages every advance width in the font, including symbols and box-drawing
   characters that no English sentence contains, and for Source Sans 3 it says
   81% where a real paragraph of this site's own copy measures 93%. The first
   version of this block used the 81% figure and made the layout shift WORSE
   in the other direction — the page grew by the same fifty pixels it used to
   shrink by. So the ratio below is the rendered width of an actual sample of
   the site's text, and it is reproducible: tools/test/measure-fonts.html renders the
   sample in each family and prints the ratios.

   The vertical figures come from the OS/2 and hhea tables of the .woff2 files
   in /assets/fonts/. The reference face was Liberation Sans, which is
   metrically compatible with Arial by design and was the measurable stand-in
   for it — 2048 units per em, ascender 1854, descender -434.

   The overrides are stated as a percentage of the ADJUSTED em, which is why
   ascent-override exceeds 100% for the narrow faces: the em was scaled down
   by size-adjust first.

   WHY local() AND NOT A URL

   Nothing is downloaded for this. `local()` matches a font already installed
   on the device; if none of the listed names is present the face simply fails
   to match and the browser moves on to the next entry in the stack, which is
   exactly the behaviour there was before. It cannot make anything worse and
   it costs no request — which matters on a site that makes none.
   ========================================================================== */

/* Display — Plus Jakarta Sans */
@font-face {
  font-family: 'Plus Jakarta Sans Fallback';
  font-style: normal;
  font-weight: 600;
  src: local('Arial'), local('Helvetica Neue'), local('Liberation Sans'),
       local('Roboto'), local('Segoe UI');
  size-adjust: 99.69%;
  ascent-override: 104.12%;
  descent-override: 22.27%;
  line-gap-override: 0%;
}
@font-face {
  font-family: 'Plus Jakarta Sans Fallback';
  font-style: normal;
  font-weight: 700;
  src: local('Arial Bold'), local('Arial'), local('Helvetica Neue'),
       local('Liberation Sans Bold'), local('Roboto'), local('Segoe UI');
  size-adjust: 100.84%;
  ascent-override: 102.94%;
  descent-override: 22.02%;
  line-gap-override: 0%;
}

/* Body — Source Sans 3. The widest gap of the three, and the one that was
   moving the home page. */
@font-face {
  font-family: 'Source Sans 3 Fallback';
  font-style: normal;
  font-weight: 400;
  src: local('Arial'), local('Helvetica Neue'), local('Liberation Sans'),
       local('Roboto'), local('Segoe UI');
  size-adjust: 92.79%;
  ascent-override: 110.36%;
  descent-override: 43.11%;
  line-gap-override: 0%;
}
@font-face {
  font-family: 'Source Sans 3 Fallback';
  font-style: normal;
  font-weight: 500;
  src: local('Arial'), local('Helvetica Neue'), local('Liberation Sans'),
       local('Roboto'), local('Segoe UI');
  size-adjust: 94.16%;
  ascent-override: 108.75%;
  descent-override: 42.48%;
  line-gap-override: 0%;
}
@font-face {
  font-family: 'Source Sans 3 Fallback';
  font-style: normal;
  font-weight: 600;
  src: local('Arial Bold'), local('Arial'), local('Helvetica Neue'),
       local('Liberation Sans Bold'), local('Roboto'), local('Segoe UI');
  size-adjust: 88.98%;
  ascent-override: 115.08%;
  descent-override: 44.95%;
  line-gap-override: 0%;
}

/* Mono — JetBrains Mono. Numbers are usually short enough that a reflow here
   costs little, but a table of figures is exactly where a column jumping
   width is most obvious. */
@font-face {
  font-family: 'JetBrains Mono Fallback';
  font-style: normal;
  font-weight: 400;
  src: local('Courier New'), local('Liberation Mono'), local('Menlo'),
       local('Consolas'), local('monospace');
  size-adjust: 99.98%;
  ascent-override: 102.02%;
  descent-override: 30.01%;
  line-gap-override: 0%;
}
@font-face {
  font-family: 'JetBrains Mono Fallback';
  font-style: normal;
  font-weight: 500;
  src: local('Courier New'), local('Liberation Mono'), local('Menlo'),
       local('Consolas'), local('monospace');
  size-adjust: 99.98%;
  ascent-override: 102.02%;
  descent-override: 30.01%;
  line-gap-override: 0%;
}
