Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

323. An italic is a face, and the matrix closes

Date: 2026-09-15

Status

Accepted. Closes the other half of docs/gaps.md G27, which ADR-0321 left open. Extends ADR-0066 by one step, and takes the same trade it took.

Context

G27 asked for the three controls every board and document tool puts beside bold: italic, underline, strikethrough. ADR-0321 built the last two and said why the first was a different question:

Italic is a face, and a face is a file … it adds a megabyte of outlines, a licence line and a golden-image sweep to a change that has nothing else in common with the one below.

That is the cost, not an argument against paying it. The argument for paying it is that nothing else can. The entry is explicit:

brd cannot add a face to a bundle it does not own, and the alternative available to an application — shearing the glyphs in the painter — is a synthetic oblique, which is a decision about type design rather than a workaround.

Inter’s italic is drawn: a single-storey a, an f with a descending tail, different advances. Shearing the upright is a different typeface from the one the designer made, and the toolkit is the layer that gets to decide which typeface it ships.

Decision

Two more files, so the matrix closes.

uprightitalic
400UIUI_ITALIC
600UI_STRONGUI_STRONG_ITALIC

extras/ttf/Inter-Italic.ttf and extras/ttf/Inter-SemiBoldItalic.ttf, from the release the manifest already pins and the archive already in the cache — the same SHA-256, verified on the way in, so no new trust and no new network fact.

Two rather than one, and that is the decision inside the decision. A single italic would leave font-weight: 600; font-style: italic resolving to “the nearest of the three we shipped”, and a design system acquiring a weight nobody chose is exactly what ADR-0066 and §1.4’s two-weight rule exist to prevent. 830 KB buys a matrix with no wrong corner.

BundledFont.Style is the third thing that names a file, beside the family and the weight, and Typography carries it — because an italic is a face and a text-decoration is a mark, so one resolves where the font is chosen and the other where the paragraph is drawn.

Matching is CSS’s order: family, then style, then weight

BundledFont.of(family, weight, style). A family that has the style at another weight uses it — the slant is what a reader was told to look for — and a family with no such style falls back to the weight it was asked for, upright. JetBrains Mono ships one face, so italic code stays upright code.

oblique is refused, and visibly

CSS’s oblique asks for a slant. Answering it with Inter’s italic would answer a different question; answering it with a shear would be a type-design decision taken by a stylesheet. So font-style: oblique is dropped with the usual warning, which is how a stylesheet learns that this toolkit does not synthesize one.

Consequences

The jar grows by 830 KB, to about four megabytes of fonts. docs/ARCHITECTURE.md §6.1 already states the trade embedding is: identical rendering everywhere, paid for in bytes. This is the same trade at the same exchange rate.

Nothing renders differently until a stylesheet says font-style: italic. The faces are opened lazily like every other — an application that never writes it never parses one — so the cost of the two files is bytes on disk and nothing at runtime.

§2’s link widget is now unblocked twice over: ADR-0321 gave it the underline and this gives emphasis in running text somewhere to go. It is still unwritten.

What is not here: a font-synthesis switch, and any of the other six weights in the archive. Both are additions a specification would have to ask for first, which is Principle 3’s rule and the reason there are two weights rather than nine.

Alternatives considered

Instance the wght/slnt axes at runtime. The general answer, and ADR-0066 costed it: symbols in both HarfBuzz and Blend2D, a new struct layout, three export branches and a four-target CI run to prove them. It is the right change the day an intermediate weight is specified, and it buys nothing today that two files do not.

One italic face at 400 only. Half the bytes and a matrix with a wrong corner, where semibold italic silently renders at 400 — or, worse, upright at 600. A stylesheet cannot tell which it got.

Shear the upright glyphs. Free, available, and a different typeface. The gap names this one and refuses it in the same sentence.

InterVariable-Italic.ttf instead of two statics. One file of 910 KB against two of 415 — barely a saving, and it is a variable file whose wght axis nothing can instance, so it would render at a single weight anyway. The statics are what the upright side already ships.