blog.git

blog

~ Personal research notes. blog.sqzer.com
git clone https://github.com/debuman/blog.git
commit ab516d6a4f6338bd28a107eda58ab9fed62355a3
parent 081303f45cb37c39022d82747768c6d75aeb2eaa
Author: sqzer <110329244+sqzer-x@users.noreply.github.com>
Date: Fri, 25 Sep 2026 21:24:19 +0900

docs: bring the stylesheet comments in line with the code they sit beside

Comments only; the built site is byte-identical.

- Claims the code no longer matches. The link notes said prose links
carry weight and an underline and that there is no hover rule; they
are crimson at inherited weight with a colour step on hover. The
header row is calc() against --fs-nav, not --fs-body (26.70px at a
1440px window, a 59.70px bar). The code line-height is 1.5 x
--fs-code, not 24px. --wp-large is a 16->19 ramp, not --fs-body.
--fs-small and --fs-medium no longer drive the nav. The footnote
label is an h2. Changing KoBody's factor moves two numbers, not one.
.toc-rail__link restates its own text-decoration, so it is not why
`nav a` stays unscoped. The header rule is full-bleed, so --root-pad
moves no hairline. The canonical padding ramp would cost 6px, not 12.
The footer rule's one-pixel lift leaves it two pixels under an auto
underline, not on it. A post with an h1 renders its #### as h5, so h5
is not only the index entry title.
- Things that no longer exist: .hover-wipe and the seven sites it was
written for, the rail on "nine articles", the 19px body, the 64/88px
headings, KoDisplay, the three KoFallback rules.
- Counts re-measured on the current build and corpus: 52 plates and
2,230 token spans, 14 <em>, 49 fi and 46 fl with diagram labels, $ x22, inline code
median 13.5, 387 B / 176 B of diagram rules, the header and nav-gap
sizes, the nav rule's offset under the baseline. The type ladder
table is given against the 16px body. The measure table is re-run at
16px with the same greedy wrap (122.2 English cpl, 71.2 syllables at
928px). The 132, 701 and 1,639-column lines are named for what they
are: a wget command, sysmon XML config, a syslog line. Counts that
drift with every post (pages that paint Hangul, headings per level)
are stated as rules instead.
- Process narration rewritten as present-tense reasons: "An earlier note
here claimed", "What stood here", "used to", "The reader said so",
"Two corrections against the earlier draft", the Korean quotation in
the --fs-body note, and the probe history in the hover note.
- Location by line distance ("two rules up") replaced with the section
name, and a truncated sentence ("What closes the gap") completed.

Diffstat:
Msrc/styles/base.css | 609+++++++++++++++++++++++++++++++++++++------------------------------------------
Msrc/styles/fonts.css | 134++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/styles/tokens.css | 320++++++++++++++++++++++++++++++++++++++++---------------------------------------
3 files changed, 514 insertion(+), 549 deletion(-)

diff --git a/src/styles/base.css b/src/styles/base.css
@@ -1,23 +1,27 @@
-/* Baseline typography. Layout specifics live with each template. */
+/* Baseline typography, the pieces every route shares (the shell, the header and footer
+   bars), and the code plates and diagrams any Markdown page can carry. Page layout lives
+   with each template. */
 *, *::before, *::after { box-sizing: border-box; }
 
 /* `scrollbar-gutter: stable` is load-bearing, not a polish detail: it is half of what
    makes the header sit in the same place on every route.
 
    The header pads itself with max(--root-pad, (100% - --w-page) / 2), and that `100%` is
-   the body's content width, which a classic scrollbar narrows by 15px. /papers/, /talk/,
-   /code/ and /404 are short enough not to scroll; / , /writing/ and all 30 articles do.
-   So the bar was centring against two different widths and landed 7.5px apart between a
-   scrolling page and a non-scrolling one — measured 338 against 330.5 of padding at a
-   1700px window, at every width, which is visible the moment you click from /papers/ to
-   /writing/. Reserving the gutter everywhere makes the two cases one case: every page now
-   lays out in the same 1685px, scrollbar painted or not.
-
-   What it costs. The four short pages give up 15px of usable width and their content
-   steps 7.5px left — which is the point, since that is the step that puts them on the
-   same edge as everything else. It reserves nothing where the scrollbar is an overlay
-   (every touch browser, and macOS unless "always show" is set), so no mobile width pays
-   for it. And it cannot create horizontal overflow: it narrows the ICB, and every box on
+   the body's content width, which a classic scrollbar narrows by 15px. /papers/, /talk/
+   and /404 are short enough never to scroll; /writing/ and the long articles scroll at
+   any common window height; /, /code/ and the short articles scroll or not depending on
+   the window's height. Without the reserved gutter the
+   bar centres against two different widths and lands 7.5px apart between a scrolling
+   page and a non-scrolling one — 338 against 330.5 of padding at a 1700px window, which
+   is visible the moment you click from /papers/ to /writing/. Reserving the gutter
+   everywhere makes the two cases one case: every page lays out in the same 1685px,
+   scrollbar painted or not.
+
+   What it costs. A short page gives up 15px of usable width and its content steps 7.5px
+   left — which is the point, since that is the step that puts it on the same edge as
+   everything else. It reserves nothing where the scrollbar is an overlay (every touch
+   browser, and macOS unless "always show" is set), so no mobile width pays for it.
+   And it cannot create horizontal overflow: it narrows the ICB, and every box on
    this site is sized from that width rather than from 100vw — verified 0px of
    documentElement.scrollWidth overhang on all seven routes at 320 through 2560.
 
@@ -33,9 +37,9 @@ body {
   font-family: var(--font-body);
   font-size: var(--fs-body);
   line-height: var(--lh-large);
-  /* font-optical-sizing was here for Newsreader's opsz axis. Lora has no opsz axis and
-     neither does Pretendard, so the declaration is now provably inert - and `auto` is
-     the initial value in any case. Removed rather than left implying an axis exists. */
+  /* No font-optical-sizing: neither Lora nor Pretendard has an opsz axis, so it would be
+     inert - and `auto` is the initial value in any case. Left out rather than implying an
+     axis exists. */
   -webkit-font-smoothing: antialiased;
 }
 
@@ -54,55 +58,43 @@ h5 { font-size: var(--fs-h5); line-height: var(--lh-medium); }
 h6 { font-size: var(--fs-h6); line-height: var(--lh-medium); }
 
 p { margin: 0; }
-/* See --sp-para in tokens.css: 0.7em, the reference's own paragraph gap, replacing the
-   flat 24px this held. Written as a top margin on the second of a pair rather than as a
+/* See --sp-para in tokens.css: 0.7em, the reference's own paragraph gap, rather than the
+   24px of --sp-24. Written as a top margin on the second of a pair rather than as a
    bottom margin on every paragraph, so a paragraph that ends a block contributes nothing
    to the gap below it and the block rhythm stays the one thing that sets it. */
 p + p { margin-block-start: var(--sp-para); }
 
-/* Prose links carry no colour: weight and underline only. */
-/* Links are crimson at the weight of the text around them, and carry no rule at rest —
-   the reference's own treatment, measured on its article pages: rgb(160,32,32), weight
-   400 against a 400 paragraph, text-decoration none. What stood here was weight 700 plus
-   an underline, which made a link a different piece of type from the sentence holding it.
+/* Links are crimson at the weight of the text around them, and carry no rule at rest or on
+   hover — the reference's own treatment, measured on its article pages: rgb(160,32,32),
+   weight 400 against a 400 paragraph, text-decoration none. Weight 700 plus an underline
+   would make a link a different piece of type from the sentence holding it.
 
    One thing to know about this, stated rather than discovered later. Colour alone is a
    weaker signal than an underline, and WCAG's technique for colour-only links wants 3:1
    between the link and the text beside it. --crimson on this site's black body measures
    2.81:1 — under that line, though the same crimson is 7.25:1 against the page and so
-   never hard to read. The reference is further under it at 2.06:1. What closes the gap
-   There is deliberately no hover or focus rule here to close that gap, because the
-   reference has none either: driven over CDP on its own article page, its body links
-   compute text-decoration none at rest AND on hover, with no background, no border, and
-   zero `a:hover` rules anywhere in its stylesheets. An earlier version of this file added
-   an animated rule on hover on the assumption that it did; that was measured from the
-   rest state alone and was wrong.
-
-   Keyboard users are still served: the global :focus-visible ring near the top of this
-   file rings these links like every other control on the site. The 2.81:1 is the honest
-   cost of the change for a reader who only looks. */
+   never hard to read. The reference is further under it at 2.06:1. Nothing here closes
+   the gap at rest, by design: the hover step below lifts a hovered prose link to 3.84:1,
+   and keyboard users get the global :focus-visible ring near the top of this file, which
+   rings these links like every other control on the site. The 2.81:1 at rest is the
+   accepted cost for a reader who only looks.
+
+   Because `font-weight` is `inherit`, a link in a heading takes the heading's own 500
+   with no rule of its own. */
 a { color: var(--crimson); font-weight: inherit; text-decoration: none; }
 
-/* The reference does change on hover, and the earlier note here said it did not. That was
-   wrong twice over: the first probe never hovered at all — the page sets
-   `scroll-behavior: smooth`, so the rect was read before the scroll finished and the
-   pointer landed on nothing, which is also why `document.querySelectorAll(':hover')` came
-   back empty and the reading looked like a null result. Driven properly, the chain ends in
-   the <a> and the colour moves rgb(160,32,32) -> rgb(192,48,48).
-
-   So: colour only, still no rule and no background, and no transition — every other colour
-   change on this site is instant. Gated on a real pointer, because a bare :hover latches
-   after a tap and would leave the last link touched sitting in the hover colour. Keyboard
-   users get the global :focus-visible ring rather than this, which is the stronger signal
-   of the two. */
+/* Hover is a colour step, the reference's own: driven over CDP on its article page, its
+   body links move rgb(160,32,32) -> rgb(192,48,48), with no rule and no background.
+   --crimson-lift is the same step applied to --crimson (see tokens.css).
+
+   So: colour only, and no transition — the step is instant, as the header nav's colour
+   step is. Gated on a real pointer, because a bare :hover latches after a tap and would
+   leave the last link touched sitting in the hover colour. Keyboard users get the global
+   :focus-visible ring rather than this, which is the stronger signal of the two. */
 @media (hover: hover) {
   :is(.prose, .about) a:hover { color: var(--crimson-lift); }
 }
 
-/* The rule that used to sit here held linked headings at their own 500 against the
-   global `a { font-weight: 700 }`. That global is `inherit` now, so a link in a heading
-   already takes the heading's weight and the override has nothing left to override. */
-
 :focus-visible { outline: 3px solid var(--ppc-ui); outline-offset: 2px; }
 
 .skip { position: absolute; left: -9999px; }
@@ -110,14 +102,15 @@ a { color: var(--crimson); font-weight: inherit; text-decoration: none; }
   background: var(--page-bg); padding: var(--sp-30) var(--sp-40);
   border: 2px solid var(--ppc-ui); }
 
-/* Read by assistive tech, drawn nowhere. Two callers, and only one of them is new:
-   the code plate's copy control announces its result through a .sr-only live region,
-   and the Markdown processor already emits <h3 class="sr-only" id="footnote-label">
-   Footnotes</h3> above the footnote list. With no definition in the sheet that second
-   one has been shipping as a visible 24.5px English headline in the middle of a Korean
-   article. `clip-path` alone would do it in every engine this site targets; the width,
-   height and margin are the belt that keeps the box from being a focus-scroll target.
-   Not `display: none`, which would take it out of the accessibility tree as well. */
+/* Read by assistive tech, drawn nowhere. The callers: the <h1> of each top-level page
+   (About, Papers, Talk, Code, Writing); the comma between the byline's name and date;
+   the live region through which the code plate's copy control announces its result;
+   and the <h2 class="sr-only" id="footnote-label">Footnotes</h2> the Markdown
+   processor emits above the footnote list, which without this rule would draw as a
+   visible English headline in the middle of a Korean article. `clip-path` alone would do it in
+   every engine this site targets; the width, height and margin are the belt that keeps
+   the box from being a focus-scroll target. Not `display: none`, which would take it out
+   of the accessibility tree as well. */
 .sr-only {
   position: absolute;
   inline-size: 1px;
@@ -131,14 +124,13 @@ a { color: var(--crimson); font-weight: inherit; text-decoration: none; }
 }
 
 /* Shell */
-/* box-sizing is border-box, so `max-width: 728px` plus the then 32px maximum of
-   --root-pad left a 664px content box — the measure of the day was never actually reached,
-   and on the index the rail then ate another 96px, leaving a 568px title column. The
-   shell is sized to the page box (rail + gap + measure) with the padding added on top
-   of it, which is why --root-pad (now 16→24px) cannot shrink the measure however it is
-   retuned — and, by the same token, cannot shrink the side gutter either: it lives
-   inside this max-width, so it moves where the hairline below ends, not where the text
-   starts. See the --w-content note in tokens.css for the cancellation. */
+/* The shell is sized to the page box (rail + gap + measure) with the padding added on top
+   of it. box-sizing is border-box, so a max-width of the page box alone would take
+   --root-pad out of the measure; added on top, --root-pad cannot shrink the measure however
+   it is tuned — and, by the same token, cannot shrink the side gutter either: it lives
+   inside this max-width, so it moves only the edge of main's own box, which paints
+   nothing, not where the text starts. See the --w-content note in tokens.css for the
+   cancellation. */
 main {
   max-width: calc(var(--w-page) + 2 * var(--root-pad));
   margin-inline: auto;
@@ -146,64 +138,63 @@ main {
 }
 
 /* The header is full-bleed, `main` is not.
-   Both used to share the rule above, which capped the header at the same width and left
-   its bottom rule floating in from each edge — a short line across the middle of the
-   screen rather than a boundary. The box now spans the viewport so the rule and the
-   shadow reach both edges, while the padding reproduces what the shared max-width used
-   to do: above `--w-page` + 2 × `--root-pad` it resolves to (100% − --w-page) / 2 and
-   centres a --w-page content box, below it falls back to --root-pad.
+   Capped at main's width, the header's bottom rule would float in from each edge — a
+   short line across the middle of the screen rather than a boundary. The box spans the
+   viewport so the rule and the shadow reach both edges, while the padding reproduces
+   main's max-width: above `--w-page` + 2 × `--root-pad` it resolves to
+   (100% − --w-page) / 2 and centres a --w-page content box, below it falls back to
+   --root-pad.
 
    THE CONTRACT IS THAT THIS BAR NEVER MOVES. Same left edge, same right edge, symmetric
    padding, on every route and at every width — that is what a reader crossing from
    /papers/ to an article is entitled to, and it is the only thing this expression owes.
-   Two things used to break it and both are gone:
-
-     - the scrollbar. `100%` is the body's content width, so the bar centred against 1700
-       on a short page and 1685 on a scrolling one. `scrollbar-gutter: stable` at the top
-       of this file reserves the gutter on every page, so there is one width now.
-     - the article template. It restated this padding against its own --page-left, so the
-       whole bar slid ~50px right and went asymmetric (280 left / 181 right at 1500)
-       inside the 1440–1584 band, on article pages only. That override is deleted.
-
-   An earlier version of this note promised something stronger and no longer true: that
-   the wordmark always sits on `main`'s left edge. It cannot, because between 1440 and
-   1584 an article pushes `main` right to seat the contents rail. Only `main` moves now;
-   the bar stays where it is, and the two edges part by 79.5px at a 1440px window, 49.5
-   at 1500, 7.5 at 1584 and 0.00 everywhere else. That was the trade the fixed bar was
-   chosen over the shared edge for. See the "which presentation" block in
-   src/pages/writing/[year]/[slug].astro. */
+   Two things can break it, and both are handled:
+
+     - the scrollbar. `100%` is the body's content width, so without a reserved gutter
+       the bar centres against 1700 on a short page and 1685 on a scrolling one.
+       `scrollbar-gutter: stable` at the top of this file reserves the gutter on every
+       page, so there is one width.
+     - a page restating this padding. The article template must not restate it against
+       its own --page-left: that slides the whole bar ~50px right and makes it asymmetric
+       (280 left / 181 right at 1500) inside the 1440–1584 band, on article pages only.
+
+   What the bar does not promise is that the wordmark always sits on `main`'s left edge.
+   It cannot, because between 1440 and 1584 an article pushes `main` right to seat the
+   contents rail. Only `main` moves; the bar stays where it is, and the two edges part by
+   79.5px at a 1440px window, 49.5 at 1500, 7.5 at 1584, and 0.00 from a 1599px window up
+   and below 1440. That is the trade the fixed bar was chosen over the shared edge for.
+   See the "which presentation" block in src/pages/writing/[year]/[slug].astro. */
 /* Height follows the reference: 16px of padding above and below a single ~27px row, for a
-   60px bar. The old 48/16 split made it 88px, which read as a section of the page rather
-   than a rule across the top of it.
+   60px bar. Padded 48px above instead of 16 it would pass 90px, which reads as a section
+   of the page rather than a rule across the top of it.
 
    That row is ONE line box shared by two type sizes, and the line-height below is what
    makes it one. The reference declares `line-height: 170%` on body, which computes to a
    fixed 27.2px at the declaring element and inherits as a LENGTH, so its 24px title and
    its 19.2px nav sit in the same 27.2px row and the bar is 16 + 27.2 + 16 + 1 = 60.2px.
    Our --lh-large is a ratio: it resolves per element, the larger slot then sets the row,
-   and a 1.25x title would have pushed this bar to 70px. calc() against --fs-body
-   reproduces the reference's inheritance instead — 18.88 x 1.4 = 26.4px at 1440, for a
-   59.4px bar.
+   and a 1.25x title would push this bar to about 71px. calc() against --fs-nav
+   reproduces the reference's inheritance instead — 19.07 x 1.4 = 26.70px at a 1440px
+   window, for a 59.70px bar.
 
-   align-items is centre rather than baseline, and that is deliberate: both slots now have
+   align-items is centre rather than baseline, and that is deliberate: both slots have
    the same line box, so centre, start and stretch are the same pixel, while baseline
    would step one of them off the row. The reference does not baseline-align either — its
    title and nav are floats in a shared line box, and their baselines are measurably 1.5px
    apart.
 
-   row-gap is smaller than column-gap because the wrapped state is a real state here (the
-   nav drops under the slot below ~24em) and it should not inherit the desktop gap. See
-   the note on the nav gap below.
+   row-gap is smaller than column-gap because the wrapped state is a real state here
+   (below 450px the nav always takes a row of its own; see the max-width: 449px query
+   below) and it should not inherit the desktop gap. See the note on the nav gap below.
 
    The rule itself is the Gazette's, measured off news.harvard.edu/gazette: 1px solid
    #a51c30 — the same crimson this site already carries as its brand, and the Gazette's
    masthead ground is rgb(255,251,244), the identical cream to --page-bg here. It is
    --crimson rather than --ppc-ui on purpose: --ppc-ui is the per-section token, and the
-   Gazette's rule does not change colour by section. An earlier version of this note said
-   --ppc-ui "turns blue on /code/ and ochre on /talk/"; measured on the built output it
-   does not — only the article template passes `section`, so every other route renders
-   is-slate and --ppc-ui there is slate, which is also the resting nav colour. Even if
-   those pages did pass one, a header accent that changes per section is the thing this
+   Gazette's rule does not change colour by section. Nor would --ppc-ui vary here the way
+   its name suggests: only the article template passes `section`, so every other route
+   renders is-slate and --ppc-ui there is slate, which is also the resting nav colour. Even
+   if those pages did pass one, a header accent that changes per section is the thing this
    line is avoiding. The hover rule further down follows the same reasoning. */
 body > header { padding-block: var(--sp-40);
   padding-inline: max(var(--root-pad), calc((100% - var(--w-page)) / 2));
@@ -217,14 +208,14 @@ main { padding-block: var(--sp-64) var(--sp-120); }
 
 /* Site footer. No rule above it and no pushing to the bottom of the viewport.
 
-   Both were tried and both were wrong. The rule repeated a mark the crimson line under the
-   header already owns, on a copyright notice that does not carry that weight. The bottom
-   pinning needed `body` to be a flex column, and that broke /writing/ outright: `main`
+   Neither works here. A rule would repeat a mark the crimson line under the header
+   already owns, on a copyright notice that does not carry that weight. Pinning it to the
+   bottom needs `body` to be a flex column, and that breaks /writing/ outright: `main`
    carries `margin-inline: auto`, an auto cross-axis margin cancels `align-items: stretch`,
-   so `main` collapsed to fit-content — and `.index` inside it is a `container-type:
-   inline-size` box, which may not size from its contents, so it computed to width 0 and the
-   entry titles wrapped one word per line. On a short page the notice simply follows the
-   content now, which is what the reference does too.
+   so `main` collapses to fit-content — and `.index` inside it is a `container-type:
+   inline-size` box, which may not size from its contents, so it computes to width 0 and
+   the entry titles wrap one word per line. On a short page the notice simply follows the
+   content, which is what the reference does too.
 
    Padding is --sp-40 rather than --sp-48: one line of --fs-small needs air, not a band. */
 .site-foot {
@@ -247,12 +238,13 @@ main { padding-block: var(--sp-64) var(--sp-120); }
    header nav's, derived from the same token so the two rows of links stay in step. */
 .site-foot p { margin: 0; }
 .site-foot__social { display: flex; flex-wrap: wrap; column-gap: calc(var(--fs-nav) * 0.8); }
-/* Size and case come back from .site-foot, not from the global `nav a` two rules up.
-   That selector is unscoped — it reaches every <nav> on the site — so these links were
-   arriving at --fs-nav (19.2px) in small-caps beside a 14px copyright line. Overridden
-   here rather than by scoping `nav a` to the header, because .toc-rail reads its
-   `text-decoration: none`, and narrowing it would underline every rail link at rest. small-caps is dropped with the size: at one shared font-size its
-   lowercase would still draw shorter than the line it is meant to match. */
+/* Size and case come back from .site-foot, not from the global `nav a` rule in the
+   page-name and navigation section below. That selector is unscoped — it reaches every
+   <nav> on the site — so without this these links would arrive at --fs-nav (19.2px) in
+   small-caps beside a 14px copyright line. Each nav it reaches restates what it needs:
+   these links here, and .toc-rail__link in the article template. small-caps is dropped
+   with the size: at one shared font-size its lowercase would still draw shorter than the
+   line it is meant to match. */
 .site-foot__social a {
   color: inherit;
   font-size: inherit;
@@ -261,17 +253,15 @@ main { padding-block: var(--sp-64) var(--sp-120); }
   font-weight: 400;
   text-decoration: none;
 }
-/* The rule under these is the header's wipe now, drawn by .hover-wipe further down. This
-   link is the one of the seven that cannot carry that class — it is written in
-   Base.astro — so the shared rule names the selector instead of the markup carrying it.
-   --wipe-y pulls the rule up to where the auto underline used to sit. Measured on the live
-   footer at 1700: the old 1px underline's top row was 801.20 and the unlifted background's
-   was 802.20, so the lift is one pixel, written as 0.07em so it tracks --fs-small's clamp
-   instead of drifting against it down to 11px. (0.21em was the first guess, from the
-   padding box being 4px under the baseline; it put the rule two pixels too high.)
-   The colour step stays, and moves inside the pointer gate together with the rule: this
-   is the header's "the item takes the accent" gesture, and a colour that latches after a
-   tap on a touch screen is exactly the defect the gate exists for. */
+/* The rule under these is the header nav's gesture, drawn by the wipe rule further down
+   (see "The wipe"). --wipe-y lifts it one pixel, written as 0.07em so it tracks
+   --fs-small's clamp instead of drifting against it down to 11px. Measured at 1700, the
+   lifted rule's top row is still two pixels under the row a 1px auto underline would
+   take: these links are flex items, so the box the rule hangs from ends at the bottom of
+   the line box rather than at the bottom of the glyphs.
+   The colour step sits inside the pointer gate together with the rule: this is the
+   header's "the item takes the accent" gesture, and a colour that latches after a tap on
+   a touch screen is exactly the defect the gate exists for. */
 .site-foot__social a { --wipe-y: calc(100% - 0.07em); }
 .site-foot__social a:focus-visible { color: var(--crimson-dark); background-size: 100% 2px; }
 
@@ -280,52 +270,53 @@ main { padding-block: var(--sp-64) var(--sp-120); }
 }
 
 /* Page name and navigation.
-   One family, one weight, one small-caps texture — and TWO sizes, which is the half that
-   was wrong here. The note this replaces claimed the reference "sets its title and its nav
-   identically - 19.2px, weight 400, letter-spacing normal". Measured, it does not: the
-   title is 24px with .15em (3.6px) of tracking and the nav is 19.2px with none — a 1.25x
-   step, with the tracking on the title alone. Flattening the two removed the only size
-   contrast in the bar and left the left slot at 42px of ink against the reference's 108;
-   a quarter of that reference width is letter-spacing. 1.25x of --fs-body lands 23.6px at
-   1440 and 20.2px at 375, against the reference's flat 24 at both.
-
-   The tracked size is written as calc(--fs-body * 1.25) rather than picked off the heading
-   ladder: --fs-h4 is close at 1440 but the ladder's steps are not parallel, so it drifts
-   to 1.21x at 375. The relationship is the thing being matched, not a number.
-
-   Lora ships no `smcp`, so the browser synthesises these, and an earlier note refused
-   small-caps for that reason. The stroke argument behind that refusal does not survive
-   measurement: at 400 Lora's 'o' is 2.69 contrast with a .0380em thin stroke, which at
-   19px is a 0.72px hairline, and the reference ships exactly this - synthesised Lora
-   small-caps - at exactly this size. Synthesis alone was never a reason; it is how
-   small-caps reach the screen on most faces. Lora has no opsz axis, so one measurement
-   covers every size here. */
+   One family, one weight, one small-caps texture — and TWO sizes. The reference does not
+   set its title and its nav identically: measured, the title is 24px with .15em (3.6px)
+   of tracking and the nav is 19.2px with none — a 1.25x step, with the tracking on the
+   title alone. Flattening the two would remove the only size contrast in the bar and
+   leave the left slot at 42px of ink against the reference's 108; a quarter of that
+   reference width is letter-spacing. 1.25x of --fs-nav lands 23.8px at a 1440px window
+   and 20.2px on a 375px phone, against the reference's flat 24 at both.
+
+   The tracked size is written as calc(--fs-nav * 1.25) rather than picked off the
+   heading ladder: the ladder's steps are not parallel to --fs-nav, so no step holds
+   1.25x across widths — --fs-h3 is 1.28x of it at 1440 and 1.31x at 375, --fs-h4 1.15x
+   and 1.21x. The relationship is the thing being matched, not a number.
+
+   Lora ships no `smcp`, so the browser synthesises these. That is not a reason to avoid
+   them: synthesis is how small-caps reach the screen on most faces, and the stroke holds
+   up — at 400 Lora's 'o' is 2.69 contrast with a .0380em thin stroke, which at 19px is a
+   0.72px hairline, and the reference ships exactly this - synthesised Lora small-caps -
+   at exactly this size. Lora has no opsz axis, so one measurement covers every size
+   here. */
 body > header > .page-name, nav a { font-family: var(--font-body); font-size: var(--fs-nav);
   font-variant-caps: small-caps; letter-spacing: normal; font-weight: 400;
   text-transform: none; text-decoration: none; }
 body > header > .page-name { font-size: calc(var(--fs-nav) * 1.25); letter-spacing: 0.15em; }
 nav { display: flex; gap: var(--sp-50); flex-wrap: wrap; }
 /* .8em is the reference's own nav spacing (`div.links a { margin-right: .8em }`), and as
-   an em it tracks the type instead of drifting against it: 15.1px at 1440, 12.9px at 375,
-   where the site gap's flat 24px was 1.27em of this type at 1440 and 1.49em at 375 —
-   loosest exactly where the row is tightest. Scoped to this header rather than edited into
-   the rule above, because `nav` is an element selector and the article page has one more
-   nav, .toc-rail, which escapes it with display:block. */
+   an em it tracks the type instead of drifting against it: 15.3px at a 1440px window,
+   12.9px at 375, where the flat 24px gap of `nav` would be 1.26em of this type at 1440
+   and 1.49em at 375 — loosest exactly where the row is tightest. Scoped to this header
+   rather than edited into the rule above, because `nav` is an element selector and it
+   reaches the other navs too: the footer's .site-foot__social, and on an article the
+   .toc-rail, which escapes it with display: block. */
 /* The reference's own spacing, .8em, but resolved against the size it is .8em OF.
-   Written as `0.8em` here it resolved against <nav>'s inherited font-size, which is body's
-   16px because --fs-nav is set on `nav a` and not on `nav` — so the gap sat at 12.8px while
-   the links beside it rendered 19.07px, and the measured 0.671em read as cramped. The
-   reference puts its .8em on the link itself (`div.links a { margin-right: .8em }`) at
-   19.2px, which is 15.36px; calc against the token reproduces that at every width. */
+   Written as `0.8em` here it would resolve against <nav>'s inherited font-size, which is
+   body's 16px because --fs-nav is set on `nav a` and not on `nav` — a 12.8px gap beside
+   19px links, 0.67em of their type, which reads as cramped. The reference puts its .8em
+   on the link itself (`div.links a { margin-right: .8em }`) at 19.2px, which is 15.36px;
+   calc against the token keeps that ratio at every width. */
 body > header nav { column-gap: calc(var(--fs-nav) * 0.8); row-gap: calc(var(--fs-nav) * 0.4); }
 
-/* The bar's height must not depend on which page is open, and between 375 and 430px it did.
-   The page name and the nav are two flex items in one wrapping row, so whether the nav folds
-   to a second line is decided by how wide the name is — and the name changes per route
-   ("Code" against "Hyukjin An" is 6 characters and about 80px). Measured across all seven
-   routes: identical two-row bars at 320 and 360, identical one-row bars from 450 up, and a
-   375-430 band where the short names fit beside the nav and the long ones do not — 55.55px
-   against 88.81px depending on the page.
+/* The bar's height must not depend on which page is open, and between 375 and 430px,
+   left to wrap on its own, it does. The page name and the nav are two flex items in one
+   wrapping row, so whether the nav folds to a second line is decided by how wide the name
+   is — and the name changes per route ("Code" against "Hyukjin An" is 6 characters and
+   about 80px). Measured across all seven routes without this query: identical two-row
+   bars at 320 and 360, identical one-row bars from 450 up, and a 375-430 band where the
+   short names fit beside the nav and the long ones do not — 55.55px against 88.81px
+   depending on the page.
 
    Below the width where the LONGEST name still fits, every route stacks. The nav taking a
    full row is not a fallback here; it is the narrow layout, and applying it to all seven is
@@ -337,16 +328,16 @@ body > header nav { column-gap: calc(var(--fs-nav) * 0.8); row-gap: calc(var(--f
 nav a { color: var(--page-meta); }
 
 /* The current page is named in the left slot, so the nav does not mark it a second time.
-   What used to be here — a 4px rule in --ppc-ui plus a colour change, laid down
-   transparent on every item — fails on four counts. It is a duplicate of a signal the
-   slot now carries; the reference marks nothing in its nav for exactly that reason (all
-   five of its links measure identical on the page they point at). It occupied the bottom
-   edge the hover rule needs, so the current item would have grown a 2px rule on top of a
-   4px one. Its 4px + 2px of padding was 6px of header height on every item on every page,
-   which is most of what put this bar over 60px. And --ppc-ui resolves to slate on five of
-   six routes, i.e. it drew the "you are here" mark in precisely the colour of the links
-   that are not current. aria-current stays in the markup: it is the programmatic state,
-   and it is not the same question as whether the state is painted twice. */
+   A painted mark — a 4px rule in --ppc-ui plus a colour change, laid down transparent on
+   every item — fails on four counts. It duplicates a signal the slot already carries; the
+   reference marks nothing in its nav for exactly that reason (all five of its links
+   measure identical on the page they point at). It takes the bottom edge the hover rule
+   needs, so the current item would grow a 2px rule on top of a 4px one. Its 4px + 2px of
+   padding is 6px of header height on every item on every page, enough to put this bar
+   over 60px. And --ppc-ui resolves to slate on every route but the articles, i.e. it
+   would draw the "you are here" mark in precisely the colour of the links that are not
+   current. aria-current stays in the markup: it is the programmatic state, and it is not
+   the same question as whether the state is painted twice. */
 
 /* Hover and focus: a 2px rule that grows out of the centre — the reference's one piece of
    motion, and the detail that reads first in a side-by-side. transform-origin is left at
@@ -355,22 +346,23 @@ nav a { color: var(--page-meta); }
    decision, so this goes to a full 1.
 
    It costs nothing in layout: absolutely positioned against the padding box, which with
-   the shared line box above puts it 4.3px under the baseline at 1440 — the reference's is
-   4px under, crossing the descenders of "Writing" by about a pixel. It is a rule through
-   the type, not a clearance underline, and both are that on purpose.
+   the shared line box above puts its top edge 4.7px under the baseline at a 1440px
+   window — the reference's is 4px under, crossing the descenders of "Writing" by about a
+   pixel. It is a rule through the type, not a clearance underline, and both are that on
+   purpose.
 
    --crimson rather than --ppc-ui, for the reason given above the header rule: this bar's
    accent is the brand crimson at every route, and --ppc-ui here would be the resting nav
-   grey on five of six of them. The reference's own rule (#c44) is likewise a step off its
-   link red, not the link colour itself.
+   grey on every route but the articles. The reference's own rule (#c44) is likewise a
+   step off its link red, not the link colour itself.
 
    Reduced motion needs nothing here. The guard at the foot of this file already selects
    *, *::before, *::after — the transition degrades to an instant appear, which is the
    right outcome. Do not add a second query.
 
    Focus keeps the global 3px outline as well; the rule is additive, not a replacement.
-   On its own it would be 127px² of indicator against the ~383px² WCAG 2.4.13 asks for,
-   and a keyboard user could not tell focus from hover. */
+   On its own it would be about 128px² of indicator on "Writing", roughly a third of the
+   area WCAG 2.4.13 asks for, and a keyboard user could not tell focus from hover. */
 body > header nav a { position: relative; }
 body > header nav a::before {
   content: ''; position: absolute; inset-inline: 0; bottom: 0; block-size: 2px;
@@ -391,88 +383,61 @@ body > header nav a:focus-visible { color: var(--crimson-dark); }
   body > header nav a:hover::before { transform: scaleX(1); }
 }
 
-/* --- The same wipe, everywhere else a rule appears on hover --------------------
-   Seven more links grow an underline on hover and used to do it with
-   `text-decoration: underline`, which has no in-between state to animate: the rule is
-   either absent or whole. This gives them the header's gesture -- a 2px crimson rule
-   opening from the centre over 0.3s -- without giving them the header's technique.
-
-   The header draws its rule with an absolutely positioned ::before at `bottom: 0`. That
-   is right for a nav item and wrong for most of these, because an absolute bar is one
-   rectangle spanning the element's whole padding box. Four of the six wrap in the corpus
-   as it stands -- entry titles on the Writing index (2 lines at 375), rail entries (2 at
-   1440, 4 once hover lifts the clamp), inline contents
-   headings (3 at 320), project names on /code/ (2 lines from 360 down: one name at 360,
-   two at 320, three at 280) -- and on a wrapped link that rectangle lands under the last
-   line only at the width of the widest, reading as a bottom border rather than an
-   underline. The project names are the narrow escape: at 375 the longest still fits, by
-   6.45px -- 321.55px in a 328px column -- and it is the 360px column, 313px wide, that
-   takes it to two lines. One is worse than wrapping: .toc-rail__link is a block box that
-   fills its column, so the bar would be 265px wide under 87px of text even on a single
-   line.
-
-   A background gradient sized 0% -> 100% fails the same way by default, because the
-   background positioning area of an inline box is the union of its fragments. What fixes
-   it is `box-decoration-break: clone`, which hands every line fragment its own copy of
-   the background, each opening from its own centre. Measured on this site's own worst
-   cases: 2 rules of 186 and 235px on a two-line entry title, 3 of 221/231/156 on a
-   three-line contents heading, 4 on a rail entry lifted out of its clamp -- one per line,
-   each the width of its own line. The two blockified sites get one inline wrapper in the
-   markup so they have fragments to clone, and the wrappers cost nothing measurable --
-   clamp, ellipsis, the rail's clamp-lift, the scroll spy's querySelectorAll and every
-   layout figure come out unchanged.
-
-   On a single-line inline link the two techniques are pixel-identical, which is worth
-   knowing before anyone tries to unify them: the absolute bar's containing block and the
-   background positioning area are both the fragment's padding box. Both drawn on the same
-   project name and scanned out of the captured frames, they occupy rows 148.88 and 149.88,
-   x 330.50, width 104 -- the same pixels. So the header keeps its ::before rather than
-   being folded in here: converting it would trade a compositor-driven transform for a
-   repainting background animation to save one declaration, and the header is the reference
-   everything else is being matched to.
+/* --- The wipe: the header's rule, drawn as a background -----------------------------
+   The footer's profile links take the header nav's gesture -- a 2px crimson rule opening
+   from the centre over 0.3s -- without taking the header's technique. They are the only
+   links outside the header that take this animated rule: body links step colour instead
+   (see the `a` rules near the top of this file), the way the reference's body links do.
+   `text-decoration: underline` cannot do this, because it has no in-between state to
+   animate: the rule is either absent or whole.
+
+   The header draws its rule with an absolutely positioned ::before at `bottom: 0`, which
+   is one rectangle spanning the element's whole padding box. That is right for a nav
+   item and wrong for any inline link that wraps: the rectangle lands under the last line
+   only, at the width of the widest, and reads as a bottom border rather than an
+   underline. A background gradient sized 0% -> 100% fails the same way by default,
+   because the background positioning area of an inline box is the union of its
+   fragments; `box-decoration-break: clone` hands every line fragment its own copy of the
+   background, each opening from its own centre. The footer's links are flex items, so
+   each is one block box and the clone has nothing to split, but it keeps the rule right
+   on any inline link that takes it.
+
+   On a single-line link the two techniques are pixel-identical, which is worth knowing
+   before anyone tries to unify them: the absolute bar's containing block and the
+   background positioning area are both the padding box. So the header keeps its
+   ::before rather than being folded in here: converting it would trade a
+   compositor-driven transform for a repainting background animation to save one
+   declaration, and the header is the reference everything else is being matched to.
 
    The cost, stated plainly: a rule you draw yourself cannot skip ink. Where
-   `text-decoration` used to break around a descender this runs straight through it --
-   the same look as `text-decoration-skip-ink: none`. On the 21 Korean titles nothing
-   changes; on the Latin ones (journalctl, AI Odyssey, ARP Spoofing) the rule crosses the
-   descender. That is the price of the gesture, and there is no third option: skip-ink
-   belongs to text-decoration, and text-decoration has nothing to animate.
-
-   Each site then puts the rule back where its own `text-underline-offset` had it, because
-   100% -- the bottom of the padding box -- sits a different distance under the baseline at
-   every type size and family here. Those distances are not flattened to one number on
-   purpose: the header's own rule sits 0.254em under its baseline, deeper than six of these
-   sit today, because a flex item's bar hangs at the line-box bottom rather than the
-   glyph-box bottom. What is being copied is the motion, not the distance.
+   `text-decoration` breaks around a descender this runs straight through it -- the same
+   look as `text-decoration-skip-ink: none`. That is the price of the gesture, and there is
+   no third option: skip-ink belongs to text-decoration, and text-decoration has nothing
+   to animate.
 
    There are two knobs and they are not interchangeable, which is a fact about
    `background-clip` rather than a matter of taste. --wipe-y moves the rule UP: the
    background is clipped to the border box, so a position past 100% is not drawn at all.
-   Measured, before this was understood: `calc(100% + 0.14em)` on the kicker rendered
-   nothing, and `calc(100% + 0.07em)` on the rail rendered the rule 1px thick instead of
-   2px, silently clipped. To sit LOWER, a site adds `padding-block-end`, which moves the
-   bottom of the box the background is clipped to.
-
-   On an inline box that is free, and "free" here is an A/B measurement rather than a
-   claim about the spec: with the padding removed from each of the four sites that use it,
-   every containing block, every sibling and document.scrollHeight come back byte-identical
-   to three decimals, and the single number that changes is the link's own border box
-   (project 26 -> 25, kicker 19.97 -> 18.00, contents 19 -> 18). Vertical padding on an
-   inline box does not enter its line box, so nothing around it moves; it grows only the
-   box the background is clipped to, and incidentally the link's own hit target by a pixel
-   or two downward. On a BLOCK box the same padding would move everything below it, which
-   is why the footer link -- the only block-level site of the seven -- is tuned with
-   --wipe-y instead.
-
-   Where the old and the new position disagree by a pixel and there is no exact answer, the
-   rule goes a pixel lower rather than a pixel higher: it no longer skips ink, so the extra
-   pixel is the one that keeps it off a descender.
+   Measured at 14px: `calc(100% + 0.14em)` renders nothing, and `calc(100% + 0.07em)`
+   renders the rule 1px thick instead of 2px, silently clipped. To sit LOWER, a link adds
+   `padding-block-end`, which moves the bottom of the box the background is clipped to.
+
+   On an inline box that is free, and "free" is an A/B measurement rather than a claim
+   about the spec: with the padding removed, every containing block, every sibling and
+   document.scrollHeight come back identical to three decimals, and the single number that
+   changes is the link's own border box. Vertical padding on an inline box does not enter
+   its line box, so nothing around it moves; it grows only the box the background is
+   clipped to, and incidentally the link's own hit target by a pixel or two downward. On a
+   BLOCK box the same padding would move everything below it, which is why the footer
+   links -- block-level, as flex items -- are tuned with --wipe-y instead.
+
+   Where there is no exact position to match, the rule goes a pixel lower rather than a
+   pixel higher: it cannot skip ink, so the extra pixel is the one that keeps it off a
+   descender.
 
    No local reduced-motion query. The guard at the foot of this file already selects
    *, *::before and *::after, the transition degrades to an instant appear, and a second
    query here would be dead code. */
-/* The footer bar is the only place left that takes this; the body links that used to
-   carry .hover-wipe now step colour instead, the way the reference's body links do. */
 .site-foot__social a {
   background-image: linear-gradient(var(--crimson), var(--crimson));
   background-repeat: no-repeat;
@@ -485,35 +450,35 @@ body > header nav a:focus-visible { color: var(--crimson-dark); }
 
 /* The one mode the background rule cannot reach, handed back.
 
-   Forced colours drop `background-image` outright -- measured in every one of the seven
-   sites with forced-colors emulated, `background-image` computes to `none`, so the rule
-   that marks a hovered link is simply not painted. The colour step goes with it: `color`
-   is forced to LinkText at rest and on hover alike. What these seven had before this
-   change was `text-decoration: underline`, which the UA paints in the forced text colour
-   and survives the mode intact -- the prose links on this site still draw theirs there
-   today. Without a fallback a High Contrast reader gets no hover or focus affordance at
-   all on any of the seven, where they had one before.
-
-   Same trade [slug].astro already makes twice, for the task-list checkbox and the
-   :target footnote: what is a background elsewhere is a real border or a real decoration
-   here.
-
-   Only the footer pair lives in this file. The other six are written beside their own
-   trigger rules in the page that owns them, because an Astro page scopes a rule by adding
-   its attribute to EVERY compound -- `.project__name[cid] a[cid]` -- which ties with a
-   selector of the same shape written here and then wins on stylesheet order. Measured
-   before the move: .project__name and .entry__title computed `text-decoration-line: none`
-   on hover in this mode while the other five computed `underline`. Inside the page the
-   same scope lands on both rules and the pseudo-class settles it. .site-foot__social a
-   cannot move -- its markup is Base.astro's -- and does not need to: its rest rule is in
-   this file, above this block.
+   Forced colours drop `background-image` outright -- with forced-colors emulated,
+   `background-image` computes to `none` -- so the rule that marks a hovered link is simply
+   not painted. A colour step goes with it: `color` is forced to LinkText at rest and on
+   hover alike. `text-decoration: underline` is what survives the mode, painted by the UA
+   in the forced text colour, so it comes back here for hover and focus. Without it a High
+   Contrast reader gets no hover affordance on these links at all, and no focus mark
+   beyond the ring.
+
+   The same trade [slug].astro makes for the task-list checkbox, the :target footnote and
+   the rail's hairline: what is a background elsewhere is handed back as something the
+   mode still paints.
+
+   Only the footer pair lives in this file. The other forced-colours underlines -- on the
+   Writing index's entry titles, the article's kicker, contents list and rail, and the
+   project names on /code/ -- are written beside their own rules in the page that owns
+   them, because an Astro page scopes a rule by adding its
+   attribute to EVERY compound -- `.project__name[cid] a[cid]` -- which ties with a
+   selector of the same shape written here and then wins on stylesheet order. Written
+   here, the .project__name and .entry__title underlines compute
+   `text-decoration-line: none` on hover in this mode. Inside the page the same scope
+   lands on both rules and the pseudo-class settles it. .site-foot__social a has its rest
+   rule in this file, above this block, so its pair belongs here.
 
    Two queries rather than one nested pair: the pointer half keeps the (hover: hover)
    gate, because a latched underline after a tap is the same defect in this mode as in
    any other.
 
-   Not applied to the header nav, which shares the blind spot and predates this work: its
-   bar is a pseudo-element background and disappears here too. Changing the reference is a
+   Not applied to the header nav, which shares the blind spot: its bar is a
+   pseudo-element background and disappears here too. Changing the reference is a
    separate decision from matching it. */
 @media (forced-colors: active) {
   .site-foot__social a:focus-visible { text-decoration: underline; }
@@ -533,11 +498,11 @@ body > header nav a:focus-visible { color: var(--crimson-dark); }
    stylesheet can outrank without !important, so it is steered through the
    --astro-code-* custom properties in tokens.css instead of being overridden.
 
-   Two corrections against the earlier draft:
-   1. The UA sheet gives `figure` `margin-inline: 40px`. Left unreset, all 55 code
-      blocks sit 40px right of the one left edge the whole page is built on.
-   2. No negative bleed. The bleed existed to compensate a shell whose content box
-      was 664px; base.css now sizes the shell to the 1024px page box, so the prose
+   Two things the plate must not do:
+   1. Keep the UA margin. The UA sheet gives `figure` `margin-inline: 40px`; left
+      unreset, every code block sits 40px right of the one left edge the whole page is
+      built on.
+   2. Bleed. The shell is sized to the 1024px page box (see `main` above), so the prose
       column really is 928px and the block is already the full measure. Bleeding
       -root-pad on top of that gives a 976px box that lines up with nothing —
       neither the rail's left edge nor the page box's right edge — and pushes the
@@ -557,7 +522,7 @@ body > header nav a:focus-visible { color: var(--crimson-dark); }
    is the transformer's contract, not a guess: a figcaption is emitted for every language
    except plaintext, which is what a fence with no language becomes. Measured on the built
    output: 52 code plates, 7 of them uncaptioned (6 fences carry no language and one is
-   written ```plaintext). The three terms are the same three the captioned path already spends
+   written ```plaintext). The three terms are the same three the captioned path spends
    (padding, row, caption margin), so both kinds of block open their first line of code at
    exactly the same depth. */
 .code[data-language='plaintext'] {
@@ -571,8 +536,8 @@ body > header nav a:focus-visible { color: var(--crimson-dark); }
   display: flex;
   align-items: center;
   gap: var(--sp-30);
-  /* The control sits at the right end of this row. align-items is already center, so the
-     label stays optically where it was and the row grows around it. */
+  /* The control sits at the right end of this row. align-items is center, so the label
+     stays optically centred and the row grows around it. */
   min-block-size: var(--copy-size);
   padding-inline: var(--code-pad);
   margin-block-end: var(--sp-40);
@@ -597,7 +562,7 @@ body > header nav a:focus-visible { color: var(--crimson-dark); }
   padding-inline: var(--code-pad);   /* rule's left end = first character's left end */
   font-family: var(--font-mono);
   font-size: var(--fs-code);
-  line-height: var(--lh-base);       /* 16 x 1.5 = 24 = --sp-24, on the paragraph grid */
+  line-height: var(--lh-base);       /* 1.5 x --fs-code: 21.6px at 14.4 */
   font-variant-ligatures: none;
   tab-size: 2;
 
@@ -625,14 +590,15 @@ body > header nav a:focus-visible { color: var(--crimson-dark); }
 .code pre::-webkit-scrollbar-track { background: transparent; }
 
 /* The `<code>` inside the plate carries the text, and the UA sheet gives it its own
-   `font-family: monospace` — which beats what it would have inherited from the rule
-   above, so --font-mono never reached a single character of code. That is invisible
-   in English: Chrome resolves the `monospace` generic per the element's language, and
-   every article in this corpus is <article lang="ko">, where the generic is the Korean
-   fixed default (GulimChe on Windows) rather than Consolas. Measured on bind9's first
-   line, "sudo yum update -y" at --fs-code 16px: 144.00px as lang=ko, 158.34px with
-   this rule (= Consolas, and = what the same line already measured under lang=en).
-   Inherit rather than restate --font-mono, so the plate keeps one source of truth. */
+   `font-family: monospace` — which beats what it would inherit from the rule above, so
+   without this --font-mono would never reach a single character of code. That is
+   invisible in English: Chrome resolves the `monospace` generic per the element's
+   language, and an article whose prose is Korean is <article lang="ko">, where the
+   generic is the Korean fixed default (GulimChe on Windows) rather than Consolas.
+   Measured on bind9's first line, "sudo yum update -y" at 16px: 144.00px as lang=ko,
+   158.34px with this rule (= Consolas, and = what the same line measures under
+   lang=en). Inherit rather than restate --font-mono, so the plate keeps one source of
+   truth. */
 .code pre code { font-family: inherit; }
 
 /* The default outline-offset would draw the ring outside the plate. */
@@ -647,15 +613,14 @@ body > header nav a:focus-visible { color: var(--crimson-dark); }
    `color: var(--astro-code-token-*)` on every span inside it. That is the reason
    for choosing the css-variables theme: a transformer cannot do this.
 
-   Measured on the built DOM, not assumed. The earlier draft applied a punctuation
-   override to bash, sh and shellsession as well; against the real output that is
-   wrong on all three counts:
+   Measured on the built DOM, not assumed. A punctuation override on bash, sh or
+   shellsession as well would be wrong on all three counts:
      bash         punctuation = 1 span in 30 blocks, and it is ' &&' — a conjunction,
                   which the override would paint the colour reserved for "command
-                  starts here". bash's prompt is already token-function ($ x21 of 59).
+                  starts here". bash's prompt is already token-function ($ x22 of 59).
      sh           punctuation = 0 spans.
      shellsession never appears: the corpus writes ```console, and data-language keeps
-                  the author's word, so that selector matches no element.
+                  the author's word, so that selector would match no element.
    Only console earns it: punctuation = 17, of which 16 are prompt glyphs ($ x13, # x3). */
 .code[data-language='console'] { --astro-code-token-punctuation: var(--crimson-dark); }
 
@@ -665,7 +630,7 @@ body > header nav a:focus-visible { color: var(--crimson-dark); }
 .code[data-language='bash'],
 .code[data-language='sh'] { --astro-code-token-keyword: var(--slate); }
 
-/* Inline code. 52 spans across 2 documents, median 14 characters — sparse and short.
+/* Inline code. 52 spans across 2 documents, median 13.5 characters — sparse and short.
    No corner radius: this page's vocabulary is a 4px rule and a 1px hairline, not curves. */
 :not(pre) > code {
   font-family: var(--font-mono);
@@ -760,28 +725,27 @@ body > header nav a:focus-visible { color: var(--crimson-dark); }
    left is the frame, and the one thing the picture cannot do for itself: fit.
 
    A diagram is baked at intrinsic size and scaled down here to whatever width the column
-   has, which is the opposite of what this block did before. The old rule kept every drawing
-   at 100% and scrolled the frame, on the argument that scaling the widest one would render
-   its labels at 9.0px. The argument was sound and the trade was still wrong: a picture you
-   have to drag sideways inside a page you are scrolling down is not a picture you read, and
-   it hid a diagram's whole point - its shape - behind a 928px slot. The reader said so.
-
-   So the fix is two-sided, and only half of it is here. The other half is in
-   src/lib/diagrams.mjs: the two sequence diagrams are now baked with `sequence.wrap`, which
-   breaks long message labels instead of letting one label set the distance between two
-   lifelines. That is what makes fitting affordable - 1,103x660 becomes 660x780 and needs no
-   scaling at all, 1,540x874 becomes 1,194x958 and scales 0.75, so 16px labels land at 12px
-   rather than 9.3px. The flowchart is the one that does not come down: its width is four
-   boxes in a row, not one long line, so it still fits at 0.59 and its 15px labels land at
-   8.8px. It is a four-box pipeline whose shape survives that; its fine print does not, and
-   the honest answer there is the reader's own pinch-zoom, which on vector art costs nothing.
+   has. Keeping every drawing at 100% and scrolling the frame would keep the labels at full
+   size, but a picture you have to drag sideways inside a page you are scrolling down is not
+   a picture you read, and it hides a diagram's whole point - its shape - behind a 928px
+   slot.
+
+   So fitting is two-sided, and only half of it is here. The other half is in
+   src/lib/diagrams.mjs: the sequence diagrams are baked with `sequence.wrap`, which breaks
+   long message labels instead of letting one label set the distance between two lifelines.
+   That is what makes fitting affordable - one comes out 660x780 (1,103x660 unwrapped) and
+   needs no scaling at all, the other 1,194x958 (1,540x874 unwrapped) and scales 0.75, so
+   its 16px labels land at 12px rather than 9.3px. The flowchart is the one that does not
+   come down: its width is four boxes in a row, not one long line, so it fits at 0.59 and
+   its 15px labels land at 8.8px. It is a four-box pipeline whose shape survives that; its
+   fine print does not, and the honest answer there is the reader's own pinch-zoom, which
+   on vector art costs nothing.
 
    `max-inline-size: 100%` with `block-size: auto` is the replaced-element idiom: the root's
    width/height attributes give the intrinsic ratio, so the height follows the width and the
-   picture never grows past what mermaid measured. Nothing scrolls, so the scroll shadows,
-   the thin scrollbar and the print override that used to undo `overflow-x` are all gone with
-   it: the five rules this block compiles to measure 373 B raw in the built sheet, 173 B
-   brotli, where the scrolling version measured 1,036 B.
+   picture never grows past what mermaid measured. Nothing scrolls, so the frame needs no
+   scroll shadows, no thin scrollbar and no print override for `overflow-x`: the five rules
+   this block compiles to measure 387 B raw in the built sheet, 176 B brotli.
 
    Global rather than in the article template, because the article template is not the only
    page that renders Markdown: src/pages/index.astro puts about.md through this pipeline too.
@@ -795,13 +759,12 @@ body > header nav a:focus-visible { color: var(--crimson-dark); }
 }
 :is(h2, h3, h4, h5, h6) + .diagram { margin-block-start: var(--sp-32); }
 /* Inside the border, like .code pre, so the ring is not drawn over the prose beside it.
-   The figure keeps its tabindex: it is no longer a scroll region, but it is still the one
-   thing on the page a keyboard reader may want to land on before zooming into it. */
+   The figure keeps its tabindex: it is not a scroll region, but it is still the one thing
+   on the page a keyboard reader may want to land on before zooming into it. */
 .diagram:focus-visible { outline: 3px solid var(--ppc-ui); outline-offset: -3px; }
 
 /* `display: block` also drops the inline baseline gap under the frame; `margin-inline: auto`
-   centres a drawing narrower than the column, which is now the common case rather than the
-   impossible one. */
+   centres a drawing narrower than the column, as the 660px sequence diagram is. */
 .diagram > svg {
   display: block;
   margin-inline: auto;
diff --git a/src/styles/fonts.css b/src/styles/fonts.css
@@ -12,26 +12,25 @@
                                             OpenType features retained (Pretendard's
                                             GSUB carries no liga to keep)
 
-   That replaces a Newsreader/Inter pair costing 43,268B with one file at 22,300B, and
-   drops the English route from two font requests to one. Coverage does not shrink: the
-   retired masters carried 104 and 107 codepoints, this subset carries the 105 the built
-   corpus actually paints, and it adds U+2022 and U+2248, which no shipped face had
-   before. 27 codepoints in dist/ are covered by neither file - arrows, box drawing,
-   circled digits, three hiragana, one CJK ideograph and thirteen emoji - which is
-   exactly the set that fell back before the swap.
-
-   liga is kept, which the outgoing sans had no use for. Lora is a serif whose f hook
-   runs into a following dotted i, and the built text holds 60 `fi` and 51 `fl` pairs
-   (visible text of dist/, tags stripped). Lora ships exactly f+i and f+l; keeping both
-   costs 396B.
-
-   No italic is shipped. dist/ holds 10 <em>, 0 <i> and 0 <cite>; the 10 are on two
+   One Latin file at 22,300B, where the Newsreader/Inter pair it replaced cost 43,268B,
+   and one font request on an English route instead of two. Its 105 codepoints are
+   printable ASCII plus the ten non-ASCII marks the corpus painted when the subset was
+   cut, U+2022 and U+2248 among them (LATIN in scripts/subset-fonts.py). Codepoints the
+   built pages paint that neither file covers - arrows, box drawing, circled digits,
+   three hiragana, one CJK ideograph, a handful of emoji, and the footer's © - fall
+   back to a system face.
+
+   liga is kept. Lora is a serif whose f hook runs into a following dotted i, and the
+   built text holds 49 `fi` and 46 `fl` pairs outside code (visible text of dist/, tags
+   stripped, diagram labels included). Lora ships exactly f+i and f+l; keeping both costs 396B.
+
+   No italic is shipped. dist/ holds 14 <em>, 0 <i> and 0 <cite>; the 14 are on two
    articles, both <article class="post" lang="ko">, and [slug].astro sets
    `.post[lang='ko'] .prose em { font-style: normal; font-weight: 500 }` because
-   Pretendard has no italic to shear. So italic renders zero times in 36 pages, and
-   nothing is synthesised either, because nothing asks for it. Lora-Italic would be
-   ~23KB that is never fetched. To bring it back: drop Lora-Italic-wght.ttf in
-   fonts-src/ and add one JOBS row in scripts/subset-fonts.py.
+   Pretendard has no italic to shear. So italic renders on no built page, and nothing
+   is synthesised either, because nothing asks for it. Lora-Italic would be ~23KB that
+   is never fetched. To bring it back: drop Lora-Italic-wght.ttf in fonts-src/ and add
+   one JOBS row in scripts/subset-fonts.py.
 
    The Korean face is not sliced by unicode-range beyond the Hangul gate. Slicing was
    measured: cutting it into 4/8/12/16 frequency-ordered ranges and resolving each built
@@ -41,7 +40,8 @@
    file becomes ~152,000 across eight). 118KB is the price of the script.
 
    woff2 encoding is not byte-deterministic, so the ko figure drifts by ~100B per
-   rebuild; the filenames are content-hashed for exactly that reason. */
+   rebuild, and so does its content-hashed filename: re-running the script renames the
+   file even when its input has not changed. */
 
 /* One face, one axis, one @font-face. The display role needs 500 and the body role
    needs 400, 500 and 700; splitting them into two pinned faces would ship 36,180B in
@@ -49,14 +49,12 @@
    range. Lora's axis is exactly 400-700, so all three points are real instances and
    nothing is ever synthesised. There is no optical-size axis on this face: the 38px h1
    is the 16px letter enlarged, with identical stroke modulation. That is the look this
-   unification buys - and it is cheaper to live with since the retune, because the
-   ladder now tops out at 38px rather than 64px, where an unmodulated enlargement was
-   most visible.
-
-   No size-adjust. The retired display face carried 106% to reach a cap-height reference
-   it was not cut for; with a single Latin face there is no second Latin face to
-   reconcile with, and scaling the whole site up 6% is the opposite of what was asked
-   for. Lora ships at its own scale, and the Korean face is matched to it below. */
+   unification buys, and it is cheap to live with because the ladder tops out at 38px,
+   well short of display sizes, where an unmodulated enlargement shows most.
+
+   No size-adjust. With a single Latin face there is no second Latin face to reconcile
+   with, and the type scale in tokens.css is derived from Lora's own outlines at its own
+   scale. Lora ships at that scale, and the Korean face is matched to it below. */
 @font-face {
   font-family: 'Lora';
   src: url('/fonts/latin-9bba8f25.woff2') format('woff2-variations');
@@ -65,8 +63,8 @@
   font-display: swap;
 }
 
-/* Hangul only - no Latin outlines survive in this file. The unicode-range gate had
-   already made them unreachable; carrying them cost 12,316B.
+/* Hangul only - no Latin outlines survive in this file. The unicode-range gate makes
+   them unreachable, and carrying them would cost 12,316B.
 
    Read that first line before reading the arithmetic: this face draws 963 Hangul
    codepoints and nothing else, so its own Latin metrics never paint. What size-adjust
@@ -75,12 +73,12 @@
 
      Lora x-height .50000 / Pretendard x-height .53027 = 94.29%
 
-   Why that ratio and not another: Pretendard's Latin is Inter's, uniformly scaled, and
-   the retired 102.9% was exactly Inter .54590 / Pretendard .53027 = 102.95% - the scale
-   at which Pretendard's Latin equals Inter's, and therefore the scale at which its
-   Hangul sits as its designer drew it against that Latin. Substituting Lora for Inter
-   in that chain gives 102.95% x (.50000 / .54590) = .50000 / .53027, with the Inter
-   term cancelling. The new number is the old method, not a new one.
+   Why that ratio and not another: Pretendard's Latin is Inter's, uniformly scaled, so
+   Inter .54590 / Pretendard .53027 = 102.95% is the scale at which Pretendard's Latin
+   equals Inter's, and therefore the scale at which its Hangul sits as its designer drew
+   it against that Latin - the factor this face carried beside Inter. Substituting Lora
+   for Inter in that chain gives 102.95% x (.50000 / .54590) = .50000 / .53027, with the
+   Inter term cancelling. It is the same method, applied to Lora.
 
    Checked against what is actually drawn, measured on the shipped file at wght 400:
    Hangul ink tops at .7881em (median of 961 syllables, max .8027) and bottoms at
@@ -90,12 +88,13 @@
    (.70000 / .70703) is 99.01% and puts Hangul at .7803em, over Lora's ascenders;
    lowercase-ascender parity (.75500 / .70703) is 106.78% and is further still.
 
-   Note what this costs. Article prose in dist/ is 55,272 Hangul letters against 25,705
-   Latin, so 94.29% shrinks the two thirds of the site that is Korean to match the third
-   that is not: Hangul's ink top goes from .8109em under the old 102.9% to .7431em, 8.4%
-   smaller. That is the honest consequence of unifying on a face with no Hangul. If
-   Korean should give up less, o-height parity (.51600 / .53711) = 96.07% is the
-   defensible middle - and it is a one-line change, because the two KoFallback overrides
+   Note what this costs. Article prose in dist/, code excluded, is 53,523 Hangul letters
+   against 14,717 Latin, so 94.29% shrinks the four fifths of the prose that is Korean
+   to match the fifth that is not: Hangul's ink top is .7431em against .8109em at the
+   Inter-matched 102.9%, 8.4% smaller. That is the honest consequence of unifying on a
+   face with no Hangul. If Korean should give up less, o-height parity (.51600 / .53711)
+   = 96.07% is the defensible middle - and it is a two-number change, this size-adjust
+   and KoFallback's (.8642578 x the new factor), because the two KoFallback overrides
    below do not move with it. */
 @font-face {
   font-family: 'KoBody';
@@ -106,13 +105,13 @@
   size-adjust: 94.29%;
   unicode-range: U+1100-11FF, U+3130-318F, U+A960-A97F, U+AC00-D7A3, U+D7B0-D7FF;
 }
-/* There is no KoDisplay any more. It existed to track a separate Latin display face at
-   106%; with one Latin face, one Korean declaration serves headings and body alike. */
+/* One Korean declaration serves headings and body alike: with one Latin face there is no
+   separate display face for a second Korean face to track. */
 
 /* ── Fallback metrics ───────────────────────────────────────────────────────────────
-   118KB arrives after HTML, after CSS, after layout. Until it lands, 32 of the 36 built
-   pages paint in a system Korean face, and without these overrides the swap reflows
-   every Korean paragraph.
+   118KB arrives after HTML, after CSS, after layout. Until it lands, every page that
+   sets Hangul - each article and the Writing index - paints it in a system Korean face,
+   and without these overrides the swap reflows every Korean paragraph.
 
    The numbers are exact, not fitted. Measured on pretendard-var.woff2: all 963 Hangul
    codepoints advance 1770/2048 - the histogram has a single entry, no exceptions - with
@@ -130,24 +129,25 @@
      ascent-override  .8977807 / .8149080 = 110.17%
      descent-override .2274378 / .8149080 =  27.91%
 
-   Only the first number moved when KoBody went 102.9% -> 94.29%. The two overrides are
-   ratios in which the KoBody factor appears in both numerator and denominator and
-   cancels exactly - they reduce to 1950/1770 and 494/1770 - so 110.17% and 27.91% hold
-   for any KoBody value. Do not recompute them.
+   Only the first number depends on KoBody's size-adjust. The two overrides are ratios
+   in which the KoBody factor appears in both numerator and denominator and cancels
+   exactly - they reduce to 1950/1770 and 494/1770 - so 110.17% and 27.91% hold for any
+   KoBody value. Do not recompute them.
 
    One rule with every platform font in its src list, not one rule per platform. With
-   three same-family rules Chrome builds the fallback from every face whose local()
+   several same-family rules Chrome builds the fallback from every face whose local()
    resolves and loads each installed one again for every size and weight it sets Hangul
    at, before first paint. A machine with Malgun Gothic and Noto Sans KR both installed,
-   which recent Korean Windows is, paid for both. In a single src list only the first
+   which recent Korean Windows is, pays for both. In a single src list only the first
    local() that resolves is loaded.
 
-   The order keeps the face each platform got from the three rules, where the last
-   declared one won: Malgun Gothic wherever it is installed (Windows, and Macs with
+   The order puts Malgun Gothic first wherever it is installed (Windows, and Macs with
    Office), then Apple SD Gothic Neo (macOS, iOS), then Noto Sans KR or Nanum Gothic.
-   The overrides were the same on all three, so no metric moves. Malgun's hhea
-   (2229/-495) and typo (1638/-410) metrics disagree; the overrides make it irrelevant
-   which one the browser reads. */
+   One set of overrides serves all of them: the ascent and descent overrides carry
+   Pretendard's metrics whichever face they land on, and the size-adjust assumes the
+   1.0em Hangul advance the first three share. Malgun's hhea (2229/-495) and typo
+   (1638/-410) metrics disagree; the overrides make it irrelevant which one the browser
+   reads. */
 @font-face {
   font-family: 'KoFallback';
   src: local('Malgun Gothic'), local('Apple SD Gothic Neo'),
@@ -157,9 +157,9 @@
 }
 
 /* Latin fallback. Lora is preloaded on every route, so this is slow-link insurance -
-   but the stack used to name Helvetica, Arial and Segoe UI, which made the unstyled
-   flash sans and the swap sans-to-serif. Against a serif it has to be a serif. Georgia
-   ships on Windows and macOS both and is the closest of the system serifs.
+   but a sans stack (Helvetica, Arial, Segoe UI) would make the unstyled flash sans and
+   the swap sans-to-serif. Against a serif it has to be a serif. Georgia ships on
+   Windows and macOS both and is the closest of the system serifs.
 
    Matched on mean lowercase advance from hmtx, which is the criterion that keeps the
    swap from reflowing a line (x-height would give 103.85% and move line breaks). The
@@ -182,8 +182,8 @@
 
 :root {
   /* One stack under two names. The templates ask for a display face and a body face;
-     since the unification there is one Latin face, so both resolve to Lora and the
-     distinction survives only in the variable names the page templates already use. */
+     there is one Latin face, so both resolve to Lora and the distinction survives only
+     in the variable names the page templates use. */
   --font-display: 'Lora', 'KoBody', 'KoFallback', 'LatinFallback', Georgia, 'Times New Roman', serif;
   --font-body:    'Lora', 'KoBody', 'KoFallback', 'LatinFallback', Georgia, 'Times New Roman', serif;
   --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
@@ -191,11 +191,11 @@
   /* src/pages/writing/index.astro is written as a portable component: it re-declares
      --font-body and --font-display from `var(--font-sans, ...)` and `var(--font-serif,
      ...)`, whose fallbacks name Inter and Newsreader as *installed local families*, not
-     as the @font-face families this file defines. Nothing ever defined these two hooks,
-     so the Writing index - 30 titles, the largest type on the site - has been painting
-     in whatever Inter or Newsreader the reader happens to have installed, and otherwise
-     in system-ui and Georgia, while still paying for the preload. Defining them here is
-     what puts the index on the shipped face, without editing the component. */
+     as the @font-face families this file defines. Without these two hooks the Writing
+     index - every entry title on the site - would paint in whatever Inter or Newsreader
+     the reader happens to have installed, and otherwise in system-ui and Georgia, while
+     still paying for the preload. Defining them here is what puts the index on the
+     shipped face, without editing the component. */
   --font-sans:  'Lora', 'KoBody', 'KoFallback', 'LatinFallback', Georgia, 'Times New Roman', serif;
   --font-serif: 'Lora', 'KoBody', 'KoFallback', 'LatinFallback', Georgia, 'Times New Roman', serif;
 }
diff --git a/src/styles/tokens.css b/src/styles/tokens.css
@@ -1,5 +1,6 @@
-/* Design tokens. Type, spacing and grid values are measured from The Harvard Gazette;
-   the colour ladder is re-derived around a crimson anchor. Single light theme — neither
+/* Design tokens. Type, spacing and grid values are measured from two reference sites,
+   The Harvard Gazette and nicholas.carlini.com; the colour ladder is re-derived around a
+   crimson anchor. Single light theme — neither
    reference site ships a dark mode. */
 
 :root {
@@ -11,8 +12,8 @@
        base   -> --ppc-ui    (rules, quote bars, focus rings)
        bright -> on black only
        wash   -> emphasis backgrounds
-     All 24 pairs were contrast-checked: dark >= 4.5, base >= 3.0, bright >= 4.5 on black,
-     wash <= 1.25. */
+     All 20 steps are contrast-checked against --page-bg, bright against black: dark >= 4.5,
+     base >= 3.0, bright >= 4.5 on black, wash <= 1.25. */
   --crimson-dark:   #771120;  --crimson:   #a51c30;  --crimson-bright: #faa2a2;  --crimson-wash: #f7ebeb;
 
   /* Hover step for a link in running text, and the one colour here that is not a rung of
@@ -55,81 +56,76 @@
 
      so the middle term equals MIN at exactly 320px and MAX at exactly 1488px,
      rather than merely approaching them. Rounded to four decimals the residual at
-     either endpoint is under 0.002px on every row. This is worth stating because
-     the file shipped the other kind once: --root-pad below keeps a different shape
-     on purpose, and its factor used to put its documented maximum at vw = 1600, so
-     the token resolved 29.85px at 1488 while the comment beside it said 32. Fixed
-     there; checked here.
-
-     Retuned for Lora, and derived from Lora's outlines rather than scaled off the
-     retired Newsreader/Inter numbers by a constant. Measured on the shipped subset
+     either endpoint is under 0.002px on every row. Not every clamp in this file shares
+     these ends: --fs-code runs from 375 to 1440 and --root-pad has its own, each
+     explained at the token, and the spacing clamps (--sp-32 to --sp-120) keep theirs.
+
+     Derived from Lora's outlines rather than scaled by a constant off the
+     Newsreader/Inter ladder it replaced. Measured on the shipped subset
      (public/fonts/latin-9bba8f25.woff2, wght 400, upem 1000): x-height .500em,
-     cap .700em, b-ascender .755em, p-descender -.255em. Inter's x-height was
+     cap .700em, b-ascender .755em, p-descender -.255em. Inter's x-height is
      .5459em, so an unchanged px size already draws 8.4% less lowercase on Lora;
-     a constant-factor rescale would have buried that instead of spending it.
+     a constant-factor rescale would bury that instead of spending it.
 
      The anchor is apparent size, not px. The reference this design was pointed at
-     sets the same face at 14pt = 18.667px, which is 9.333px of x-height. --fs-body
-     reaches 19px = 9.500px of x-height, 1.8% above the reference and 13.0% below
-     the 20px Inter it replaces (10.92px) - a 13% cut in what the eye measures out
-     of a 5% cut in px. Below 1488 the ramp is unchanged at its 16px floor, where
-     Lora is already 8.4% smaller than the Inter that floor was set for.
+     sets the same face at 14pt = 18.667px, which is 9.333px of x-height. The ladder
+     is cut against a 19px body = 9.500px of x-height, 1.8% above the reference and
+     13.0% below a 20px Inter (10.92px) - a 13% cut in what the eye measures out of a
+     5% cut in px. Running text itself is a flat 16px (see --fs-body); the headings
+     keep the 19px anchor.
 
-     The ladder is then a multiple of that body. The reference renders nothing above
+     The ladder is then a multiple of that anchor. The reference renders nothing above
      1.50x body anywhere; ours has to carry a real page title on pages with no image
-     and no other display element, so h1 takes 2.0x, h2 takes the reference's own
-     1.50x, and the rest interpolates:
+     and no other display element, so at 1488 h1 is 2.0x the anchor (38px), h2 the
+     reference's own 1.50x (28.5px), and the rest interpolates. Against the 16px body
+     that ships:
 
                     h1     h2     h3     h4     h5     h6    body
-         1488px   38.0   28.5   24.5   22.0   20.0   17.0   19.0
-                 2.00x  1.50x  1.29x  1.16x  1.05x  0.89x
+         1488px   38.0   28.5   24.5   22.0   20.0   17.0   16.0
+                 2.38x  1.78x  1.53x  1.38x  1.25x  1.06x
           320px   27.0   23.0   21.0   19.5   18.0   17.0   16.0
                  1.69x  1.44x  1.31x  1.22x  1.13x  1.06x
 
-     The retired ladder reached h1 64px (3.2x body) and h1-large 88px (4.4x). h6
-     drops 18 -> 17 so the ladder stays strictly monotone at 320px now that h5's
-     floor is 18; no document in content/ uses h5 or h6 (39 h1, 72 h2, 46 h3,
-     14 h4, 0 below), but .entry__title on the Writing index is --fs-h5, so h5 is
-     really "index entry title" and 20px against a 19px body is deliberate - the
-     reference sets its own index entries at exactly body size.
-
-     --fs-small and --fs-medium are NOT changed. They drive the nav (11->14) and the
-     wordmark (12->16), both of which already land at or below the reference's body
-     size; they were never part of "the type is too big", and cutting them would push
-     the nav under 11px. Their share of body rises (small .70 -> .74, medium .80 -> .84)
-     purely because body fell. --fs-code was left out of that pass for the same reason and
-     cut later, on a complaint of its own - the code plates, not the prose, were the thing
-     reading too large once body stopped moving. 13->16 became 13->14.4; the arithmetic is
-     in the note at the token itself. */
-  --fs-small:    clamp(0.6875rem, 0.2568vw + 0.6361rem, 0.8750rem);  /* 11→14, unchanged */
-  --fs-medium:   clamp(0.7500rem, 0.3425vw + 0.6815rem, 1.0000rem);  /* 12→16, unchanged */
+     h6 is 17, not 18, so the ladder stays strictly monotone at 320px, where h5's
+     floor is 18. No post writes ##### or ######, but a post that contains an h1 has
+     every heading moved down one level (satteriProse), so its #### renders as h5.
+     .entry__title on the Writing index is --fs-h5 as well, so h5 is both the deepest
+     article heading and the index entry title: 20px at 1488 against the 16px body,
+     where the reference sets its own index entries at exactly body size.
+
+     --fs-small and --fs-medium sit outside the ladder. --fs-small sets the small print
+     (footer, byline, labels, the contents rail) and --fs-medium the secondary text
+     (captions, tables, footnotes, the inline contents list). Both already land at or
+     below body size, and cutting --fs-small would push the small print under 11px. They
+     keep the same 320-1488 shape, 11->14 and 12->16. The nav and the page name have their
+     own token, --fs-nav, and --fs-code has its own note at the token. */
+  --fs-small:    clamp(0.6875rem, 0.2568vw + 0.6361rem, 0.8750rem);  /* 11→14 */
+  --fs-medium:   clamp(0.7500rem, 0.3425vw + 0.6815rem, 1.0000rem);  /* 12→16 */
 
   /* Body is a flat 16px, not a clamp, because that is what the reference is.
      Measured on nicholas.carlini.com/writing/2025/regex-chess.html at a 1440px viewport:
-     body 16px, line-height 27.2px, paragraph box 928px — the same measure this site now
+     body 16px, line-height 27.2px, paragraph box 928px — the same measure this site
      uses. It never declares a font-size at all, so its body is the browser default and
-     does not move with the viewport. Ours reached 18.81px at 1440 against that 16, which
-     is the 17% the reader saw as "전체적으로 큰".
-
-     Growing body with the viewport was the thing being removed, so the replacement is not
-     a shallower clamp. The heading ladder above stays as it is: the complaint was about
-     running text, and the ladder's own clamps are unaffected by this line. What does
-     change is the ladder's ratios to body, since body no longer rises — h1 is 2.375x at
-     1488 where it was 2.00x, and the table above is written in absolute px for that
-     reason. */
+     does not move with the viewport. A body that grows with the viewport reads as too
+     large overall: a 16→19px ramp on the 320-1488 shape is already 18.9px at 1440, 18%
+     over the reference's 16.
+
+     Growth with the viewport is the thing avoided, so this is not a shallower clamp
+     either. The heading ladder above keeps its own clamps, which this line does not
+     touch; only its ratios to body differ from the 19px anchor it was cut against — h1
+     is 2.375x at 1488 rather than 2.00x — and the table above gives them against this
+     16px. */
   --fs-body:     1rem;                                               /* 16, fixed */
 
   /* The header is measured from the reference's own header, not from body.
-     It sets its title at 150% and its nav at 120% of a 16px root: 24px and 19.2px. Those
-     used to hang off --fs-body here, which was right only while body also topped out near
-     19px; with body fixed at 16 the same expression would have shrunk the bar to 20/16 and
-     undone the header work. This token carries the nav size and .page-name takes 1.25x of
-     it, which is the reference's own 24:19.2 ratio.
-
-     It stays a clamp where body does not, because the reference collapses its header into
-     a hamburger on a phone and this one wraps instead: a flat 19.2px nav wraps to a third
-     row at 320px. 16px at 320 is the same size the nav had before this change, so nothing
-     about the phone silhouette moves. */
+     It sets its title at 150% and its nav at 120% of a 16px root: 24px and 19.2px. Hung
+     off --fs-body instead, with the nav at body size and the name at 1.25x of it, the
+     bar would read 20/16 against the flat 16px body. This token carries the nav size and .page-name takes 1.25x of it, which is the
+     reference's own 24:19.2 ratio.
+
+     It is a clamp where body is not, because the reference collapses its header into a
+     hamburger on a phone and this one wraps instead: a flat 19.2px nav wraps to a third
+     row at 320px, where 16px keeps the bar to two. */
   --fs-nav:      clamp(1.0000rem, 0.2740vw + 0.9452rem, 1.2000rem);  /* 16→19.2 */
   --fs-h6:       1.0625rem;                                          /* 17, fixed */
   --fs-h5:       clamp(1.1250rem, 0.1712vw + 1.0908rem, 1.2500rem);  /* 18→20 */
@@ -138,36 +134,37 @@
   --fs-h2:       clamp(1.4375rem, 0.4709vw + 1.3433rem, 1.7813rem);  /* 23→28.5 */
   --fs-h1:       clamp(1.6875rem, 0.9418vw + 1.4991rem, 2.3750rem);  /* 27→38 */
 
-  /* Unreferenced by any selector in src/ - checked, not assumed. Kept because the
-     names are part of the token contract, and re-pegged onto the retuned ladder so
-     that anything which later picks one up lands inside the scale instead of
-     reinstating a 56px or 88px step. --fs-h1-large is named in a comment in
-     src/pages/writing/[year]/[slug].astro explaining why the article title does not
-     use it; that reasoning survives the retune. */
+  /* Unreferenced by any rule in src/. Kept because the names are part of the token
+     contract, and sized on the ladder's own 320-1488 shape so that anything which later
+     picks one up lands near the scale rather than on a display step far above it.
+     --fs-h1-large is also named in src/pages/writing/[year]/[slug].astro, where the
+     article title's note says why the title does not use it. */
   --fs-xlarge:   clamp(1.2500rem, 0.5137vw + 1.1473rem, 1.6250rem);  /* 20→26 */
   --fs-2xlarge:  clamp(1.6250rem, 0.5137vw + 1.5223rem, 2.0000rem);  /* 26→32 */
   --fs-h1-large: clamp(2.0000rem, 1.1986vw + 1.7603rem, 2.8750rem);  /* 32→46 */
 
   /* Hooks for src/pages/writing/index.astro, which is written as a portable
      component: it re-declares --fs-h1 / --fs-h5 / --fs-large from
-     var(--wp-*, <its own literal clamp>). Those literals are the pre-Lora ladder
-     (34→64 and 20→24), so without these three lines the Writing index would keep a
-     64px masthead and 24px entry titles while every article dropped to 38px - and
-     all 30 entry titles on the site are on that one page. This is the same
-     mechanism fonts.css already uses to put the index on the shipped face through
-     --font-sans / --font-serif.
+     var(--wp-*, <its own literal clamp>), and those literals are a larger ladder than
+     this one (34→64, 20→24 and 16→20). Without --wp-h5 the entry titles would set at
+     20→24 while article headings follow the ladder above - and every entry title on
+     the site is on that one page. --wp-h1 sizes only the index's .sr-only page title,
+     which is never drawn, and --wp-large only the empty-state line, which a build with
+     any post never renders. This is the same mechanism fonts.css uses to put the index
+     on the shipped face through --font-sans / --font-serif.
 
      Written as literal clamps, not var(--fs-h1). Substitution happens at the
      declaring element, so :root { --wp-h1: var(--fs-h1) } would in fact compute to
      :root's --fs-h1 and inherit down cleanly - but the index assigns the result
      back into --fs-h1 on .index, and handing a property to itself through an alias
-     is not a thing to be clever about when the failure mode is 30 titles losing
-     their font-size. Keep these three in step with the rows above. */
+     is not a thing to be clever about when the failure mode is every entry title
+     losing its font-size. Keep --wp-h1 and --wp-h5 in step with --fs-h1 and --fs-h5.
+     --wp-large is not --fs-body: it is a 16→19 ramp, not the flat 16px. */
   --wp-h1:       clamp(1.6875rem, 0.9418vw + 1.4991rem, 2.3750rem);  /* = --fs-h1 */
   --wp-h5:       clamp(1.1250rem, 0.1712vw + 1.0908rem, 1.2500rem);  /* = --fs-h5 */
-  --wp-large:    clamp(1.0000rem, 0.2568vw + 0.9486rem, 1.1875rem);  /* = --fs-body */
+  --wp-large:    clamp(1.0000rem, 0.2568vw + 0.9486rem, 1.1875rem);  /* 16→19, not --fs-body */
 
-  /* Line heights. Unchanged by the move to Lora, and that is a measurement, not an
+  /* Line heights. Cut for Newsreader and kept for Lora on measurement, not by
      oversight - the tempting number to react to is the wrong one.
 
      Lora's metrics box is sTypoAscender + sTypoDescender = 1.006 + 0.274 = 1.280em,
@@ -175,17 +172,16 @@
      like every step below 1.28 has become an overlap. It has not. Lines collide when
      ink meets ink, and ink is what barely moved: measured on the shipped subset,
      Lora's lowercase and parentheses run -0.271em to +0.760em, a 1.031em band, against
-     Newsreader's 0.9745em band at its shipped size-adjust of 106% = 1.033em. The
-     heading band shrank by 0.2%.
+     1.033em for Newsreader, the face the ladder was set against (its 0.9745em band at the
+     106% size-adjust it used): the band is 0.2% narrower than the one these steps assume.
 
      What the larger metrics box does is shift the half-leading. At --lh-tight the
      half-leading is (1.1 - 1.280) / 2 = -0.090em, so the line box spans +0.916em to
      -0.364em around the baseline and the ink sits inside it with room at both ends:
      nothing clips, and consecutive lines clear by 1.1 - 1.031 = 0.069em. That is
-     2.6px on the retuned 38px h1, down from 4.4px at 64px - the clearance is a
-     ratio, so shrinking the ladder shrinks it in px but never closes it. Korean
-     headings are looser still - Hangul ink spans at most 0.840em once KoBody's
-     94.29% is applied.
+     2.6px on the 38px h1 - the clearance is a ratio, so a smaller size shrinks it
+     in px but never closes it. Korean headings are looser still - Hangul ink spans
+     at most 0.840em once KoBody's 94.29% is applied.
 
      The one glyph that would break this is $, which tops out at 0.833em; it appears
      only inside code, which sets --lh-base. */
@@ -202,7 +198,7 @@
   --sp-24: 1.5rem;                                          /* heading-adjacent rhythm */
   /* Between paragraphs, and the one spacing token deliberately written in em rather than
      rem. The reference sets `p { margin-top: 0; margin-bottom: .7em }`, which is 11.2px
-     against its 16px body; --sp-24 was 24px, 2.1x that, and read as too much air. A
+     against its 16px body; --sp-24 is 24px, 2.1x that, and reads as too much air. A
      custom property substitutes as a token stream, so the em resolves against the font
      size of whichever element consumes it — which is what keeps the gap proportional to
      the type instead of frozen at one pixel value. Read by three rules and no others:
@@ -221,8 +217,8 @@
   --sp-120: clamp(4rem, 3.5vw + 3.3rem, 7.5rem);
 
   /* ── Grid ──────────────────────────────────────────────────────────────────
-     --w-content is 928px: Carlini parity, chosen deliberately over the 728px this
-     file used to hold, with the cost measured first and accepted.
+     --w-content is 928px: Carlini parity, chosen deliberately over a 728px column,
+     with the cost measured first and accepted.
 
      Where the side whitespace comes from. Above the width at which the shell stops
      growing (1024 + 2 x --root-pad, which --root-pad's own ramp puts at vw = 1063),
@@ -231,83 +227,85 @@
          left  = (vw - 96 - --w-content) / 2 + 96      right = (vw - 96 - --w-content) / 2
 
      --root-pad cancels out of both: it is inside the shell's own max-width, so it
-     moves where the header hairline ends, never where the text starts. At 1488px
-     that is 328px left and 232px right whatever the padding does, and --w-content
-     is the only token on the page that can change it. At 728px it was 428 / 332,
-     so this is exactly the 100px a side that was asked for.
+     moves only the edge of main's own box, which paints nothing, never where the text
+     starts. At 1488px that is 328px left and 232px right whatever the padding does,
+     and --w-content is the only token on the page that can change it. A 728px column
+     would put it at 428 / 332, so 928 takes exactly 100px from each side.
 
-     What it cost. Measured over the real corpus (42 English and 664 Korean
-     paragraphs out of content/writing/, greedy-wrapped on spaces only because
-     word-break is keep-all, with Lora's advances and its 2,439 GPOS kern pairs,
-     and Pretendard's uniform 1770/2048 Hangul advance at KoBody's 94.29%). cpl is
-     the mean of the lines that actually wrap; the syllable figure is what one full
-     line holds:
+     What it costs. Measured over the paragraphs of the built articles, greedy-wrapped
+     on spaces only because word-break is keep-all, with Lora's advances and its 2,439
+     GPOS kern pairs, and Pretendard's uniform 1770/2048 Hangul advance at KoBody's
+     94.29%. cpl is the mean of the lines that actually wrap; the syllable figure is
+     what one full line holds:
 
-         728px / 19px   English  76.7 cpl   Korean 55.3 cpl   47.0 syllables
-         928px / 19px   English 100.4 cpl   Korean 71.3 cpl   59.9 syllables
+         728px / 16px   English  94.5 cpl   Korean 66.2 cpl   55.8 syllables
+         928px / 16px   English 122.2 cpl   Korean 85.4 cpl   71.2 syllables
 
      The usual bands are 45-75 characters for English and 41-45 syllables for
-     Korean. 728px was already past the Korean one at 47.0; 928px sits a third past
-     it, and English clears 100 characters a line. The corpus is 79.6% Hangul by
-     letter count, so that is the cost on four fifths of the site, not an edge case.
-     Those were the numbers on the table when the width was picked, and the wider
-     column was picked anyway. This block records the trade. It is not an argument
-     to reverse it, and no narrower fallback is hiding below: 928px is the measure
-     at every viewport wide enough to reach it.
+     Korean. Either width is past both at the 16px body; 928px holds more than half
+     again the Korean band's top, and English runs past 120 characters a line. The
+     column was chosen at a 19px body, where 928px held 59.9 syllables and about 100
+     English characters; the flat 16px body (see --fs-body) puts more on every line.
+     Article prose is about four fifths Hangul by letter count (see the KoBody note in
+     fonts.css), so that is the cost on most of the site, not an edge case. This block
+     records the trade. It is not an argument to reverse it, and no narrower fallback
+     is hiding below: 928px is the measure at every viewport wide enough to reach it.
 
      Both pages hang off this token, and they do not share it. The Writing index
      keeps its own --content-w, capped at min(100%, rail + gap + --content-w), so
-     the 100% branch follows a narrowing but nothing follows a widening. Moving this
-     line alone was measured, not guessed: with the index pinned at 824px and the
-     article at 1024px, the article title lands 100px to the LEFT of the entry it was
-     clicked from at 1488px and 1920px, and 81px left at 1024px - the wider box is
-     centred, so its left edge moves outward, not inward. --content-w in
-     src/pages/writing/index.astro therefore reads this token through var() rather
-     than re-stating it: a rem literal there matched only at a 16px root, and at a
-     12px root the article <h1> sat 116px left of the entry title. Bound, the two
-     left offsets were compared in a browser at 320 / 768 / 1024 / 1488 / 1920 and
-     at 12 / 14 / 16 / 20 / 24px roots: identical to the pixel at every one.
-
-     One bounded exception to that, added later and named here because this is where
-     a reader will come looking for it. The nine articles that carry a contents rail
-     push their page box right when a centred gutter cannot seat the rail's 240px
-     floor - see the ── the rail ── block in src/pages/writing/[year]/[slug].astro.
-     Inside that band the article title leads the index entry instead of matching it:
-     measured at a 16px root, 72px at 1440, 48 at 1488, 24 at 1536, and 0.00px from
-     1584 up, at 1024 and below, and at every width for the other 21 articles. The
-     band tracks the root size, because the floor is expressed in rem along with the
-     type it exists to fit - measured 0.00px at every width at a 12px root, and at a
-     24px root it runs from 1440 to about 1912. Its worst case there is 195.91px at
-     1520, not the 156.80px it reads at the foot of the band: below 1521 the third,
-     room term of --toc-rail-w is what binds, so --page-left tracks the viewport and
-     the divergence RISES with it until the 15rem floor takes over. Sampling only the
-     usual 1440 / 1488 / 1536 / 1584 columns misses that peak by 8px and the foot of
-     the band by 39px. That is the whole of the divergence: no width, root size or
-     article overflows horizontally, and the page box never loses its full --w-page -
-     measured 928px of measure and 0 horizontal overflow at 12 / 14 / 16 / 20 / 24px
-     roots across 1400-2000px. */
+     the 100% branch follows a narrowing but nothing follows a widening. Were the
+     index to restate the width instead, moving this line alone would part the two:
+     with the index at 824px and the article at 1024px, the article title lands 100px
+     to the LEFT of the entry it was clicked from at 1488px and 1920px, and 81px left
+     at 1024px - the wider box is centred, so its left edge moves outward, not inward.
+     --content-w in src/pages/writing/index.astro therefore reads this token through
+     var() rather than re-stating it: a rem literal there matches only at a 16px root,
+     and at a 12px root the article <h1> sits 116px left of the entry title. Bound, the
+     two left offsets were compared in a browser at 320 / 768 / 1024 / 1488 / 1920 and
+     at 12 / 14 / 16 / 20 / 24px roots: identical to the pixel wherever the rail's band,
+     below, does not apply.
+
+     One bounded exception to that, named here because this is where a reader will
+     come looking for it. From 1440px, where the contents rail is shown, every article
+     pushes its page box right wherever a centred gutter cannot seat the rail's 240px
+     floor; the gutter is reserved whether or not the post has a rail - see the
+     ── the rail ── block in src/pages/writing/[year]/[slug].astro. Inside that band
+     the article title sits right of the index entry instead of matching it: measured
+     at a 16px root, 72px at 1440, 48 at 1488, 24 at 1536, and 0.00px from 1584 up and
+     below 1440. The band tracks the root size, because the floor is expressed in rem
+     along with the type it exists to fit - measured 0.00px at every width at a 12px
+     root, and at a 24px root it runs from 1440 to about 1912. Its worst case there is
+     195.91px at 1520, not the 156.80px it reads at the foot of the band: below 1521
+     the third, room term of --toc-rail-w is what binds, so --page-left tracks the
+     viewport and the divergence RISES with it until the 15rem floor takes over.
+     Sampling only the usual 1440 / 1488 / 1536 / 1584 columns misses that peak by 8px
+     and the foot of the band by 39px. That is the whole of the divergence: no width,
+     root size or article overflows horizontally, and the page box never loses its full
+     --w-page - measured 928px of measure and 0 horizontal overflow at 12 / 14 / 16 /
+     20 / 24px roots across 1400-2000px. */
   --w-content: 928px;
-  /* Page box: the 72px date rail, its 24px gutter, and the measure. The index and the
-     article both hang off this, which is what puts their text on one left edge. */
+  /* Page box: the 72px date rail, its 24px gutter, and the measure. The shell, the
+     header and footer padding and the rail geometry read it; the index and the article
+     compute the same sum from --w-content, which is what puts their text on one left
+     edge. */
   --w-page: calc(var(--w-content) + 4.5rem + 1.5rem);   /* 1024px */
   --w-wide: 1488px;
   /* Outer gutter, 16 -> 24px. The reference site runs a flat 1em at every width;
-     this halves the growth toward that without going fixed.
+     this starts there and grows only to 24px rather than going fixed.
 
      The shape is deliberate and differs from the type scale above: the middle term
      is pinned at the 1rem floor for every viewport up to exactly 768px (1vw =
      0.48rem there, so the bracket is zero and negative below it), and only then
      ramps. A phone gutter must not ride a desktop ramp - the canonical
      A vw + B rem form would put 19.1px of padding on a 768px screen and cost the
-     prose 12px it does not have. The factor is what was wrong before, not the
-     shape: at 1.923 the term reached 2rem only at vw = 1600, so the token resolved
-     29.85px at 1488 while the comment claimed 32. At 1.1111 it is exactly 1.5rem
-     at 1488 ((0.93 - 0.48) x 1.1111 = 0.5), and exactly 1rem at 320.
-
-     Cost of the change, stated because it runs against the whitespace complaint by
-     a hair: the shell is 1024 + 2 x --root-pad, so at 1488 the header hairline and
-     the shell box span 1072px instead of 1083.7px, 5.85px less page furniture a
-     side. The prose column does not move at all - see the cancellation above. */
+     prose 6px it does not have. The factor sets where the cap lands: at 1.1111 the
+     term is exactly 1.5rem at 1488 ((0.93 - 0.48) x 1.1111 = 0.5), and the floor
+     holds 1rem at 320.
+
+     Above the width where the shell stops growing, the pad reaches neither the prose
+     nor the header's full-bleed rule: it sets the width of main's own box, 1024 + 2 x
+     --root-pad = 1072px at 1488, which nothing paints. The prose column does not move
+     at all - see the cancellation above. */
   --root-pad: clamp(1rem, 1rem + ((1vw - 0.48rem) * 1.1111), 1.5rem);  /* 16→24 */
 
   /* ── Syntax highlighting ───────────────────────────────────────────────────
@@ -320,9 +318,9 @@
      inherited value, and the block renders as flat body text. They are not
      optional — they ARE the palette.
 
-     Placement measured on the built DOM (dist, 55 fences, 2,431 token spans):
-       foreground 24.9% · string 21.1% · keyword 16.6% · string-expression 13.6%
-       punctuation 11.3% · function 6.1% · comment 3.5% · constant 2.8% · parameter 0.04%
+     Placement measured on the built DOM (dist, 52 plates, 2,230 token spans):
+       foreground 24.3% · string 21.3% · string-expression 14.8% · keyword 14.1%
+       punctuation 12.3% · function 6.3% · comment 3.9% · constant 3.1% · parameter 0.04%
      Contrast recomputed against both surfaces, sand #faedda first (the real plate):
        black 18.19/20.36 · purple-dark 9.84/11.01 · blue-dark 8.94/10.00
        crimson-dark 9.65/10.80 · ochre-dark 9.11/10.19 · slate 5.93/6.63. */
@@ -338,7 +336,7 @@
   --astro-code-token-parameter:         var(--black);
   --astro-code-token-link:              var(--blue-dark);
 
-  /* Code body. The top of the ramp is 0.9 x the now-fixed --fs-body, not 1.0: a
+  /* Code body. The top of the ramp is 0.9 x the fixed --fs-body, not 1.0: a
      monospace face at the same em reads larger than the text face beside it, because
      every glyph carries the width of the widest one, so code set at body size looks
      like the loudest thing in the article. 14.4px is the correction, and it is a
@@ -346,23 +344,27 @@
      own <pre> inherits from the UA monospace default against its 16px body.
 
      It buys line width as well as quiet. The plate's inner box is 928 - 2*16 = 896px,
-     and a line's width is linear in the size, so dropping 16 -> 14.4 is +10% of column.
+     and a line's width is linear in the size, so 14.4 rather than 16 is +10% of column.
      Measured over the built corpus - 52 plates, longest rendered line each, Consolas:
        at 16.0px   4 plates overflow 896px
        at 14.4px   3 plates overflow 896px
      The one that stops scrolling is the widest line any author here would want kept
      whole, a 110-column jsonc route table: 955px at 16, 859px at 14.4, 37px of slack.
-     The three that remain are dumps, not code - a 132-column apt log (needs 12.4px), a
-     701-column sysmon XML event (2.3px) and a 1,639-column JSON event (1.0px). No
-     readable size fits those; they keep the scroller, or take ```<lang> wrap.
+     Of the three that remain, one is a 132-column wget command that would need 12.4px,
+     under the 13px floor, and two are dumps, not code: a 701-column line of sysmon XML
+     config (2.3px) and a 1,639-column syslog line holding a raw sysmon XML event
+     (1.0px). They keep the scroller, or take ```<lang> wrap.
 
      How many characters 896px is still depends on the face: 104 at 0.600em (JetBrains
      Mono, Menlo), 113 at 0.5498em (Consolas, measured off the built page - a 132-column
-     line renders 72.57px per 1px of font-size). Do not quote a character count until
-     public/fonts/jetbrains-mono-latin.woff2 actually ships.
-
-     The ramp's floor stays 13px: at 375 the plate's inner box is 294px, where every
-     fence scrolls whatever the size, and 13px is what ships there today. */
+     line renders 72.57px per 1px of font-size). No single character count holds until
+     the site ships a monospace face of its own.
+
+     The ramp runs 13px at 375 to 14.4px at 1440, and the floor is 13px because a phone
+     gains little below it: at 375 the plate's inner box is about 300px (311 on a phone,
+     296 beside a classic scrollbar), some 40 columns at 13px, and half the plates run
+     wider than that, most of them far wider, so a smaller size would not stop them
+     scrolling. */
   --fs-code:  clamp(0.8125rem, 0.1315vw + 0.7817rem, 0.9rem);  /* 13→14.4 */
   --code-pad: var(--sp-40);                                  /* 16px */
 }