Skip to contentWolf-Rayet

Decision records

ADR-0109 The ladder is narrower than it was

Accepted2026-09-18Phase 7

Amends ADR-0012. Does not supersede it: the scale is still modular, still generated, still selected by index and never authored.

#Context

The type scale ran at ratio 1.25 from a 1rem base. Comfortable selected step 1 for text-body, so the system's primary reading size was 20px, and step 6 for text-display, so the largest size was 61px.

A control binds text-body for its label. Button, tag, input field, number input and the rest all render their text at the reading size, which is correct: a label is read, and the system has one size for reading. The consequence was not correct. On /incident a button drew a 20px label inside a 54px box beside prose the page rendered at 16px, and the control was visibly louder than the sentence it belonged to. Nothing had gone wrong in the component. The two numbers simply had no reason to agree, because the product never bound the token at all: apps/proof/app/proof.css set a family on body and no size, so the prose was the browser's default and the label was the system's.

Two faults, one symptom. The product was not consuming the reading size it shipped, and the reading size was too large to want to consume.

The reference the project measures itself against makes the second point plainly. the reference runs its whole ladder from 12px to 35px. r136 ran from 16px to 61px, and a 61px display in an operational console is a size nothing has a use for.

#Decision

  • spatial.type.ratio drops from 1.25 to 1.125. No selection index moves

and no token is added or removed. Comfortable becomes 16 / 18 / 20.3 / 25.6 / 32.4px and compact becomes 16 / 16 / 18 / 22.8 / 28.8px. Every rung still rounds to a distinct value, so the collision check in spatial.js holds.

  • text-body keeps step 1 in comfortable. The alternative was selecting

step 0, which the maintainer's own framing put first because compact already binds body and caption to the same step. Rejected below.

  • The proof app binds font-size: var(--wr-text-body) on body. This is

the half of the fix that stops the symptom returning at any ratio. A control and the prose around it now take their size from one token, so they agree by construction rather than by coincidence.

#Consequences

Every emitted spatial primitive moves, and with it every fixture, both budget baselines and all 47 receipts. Regenerated in this order, which is the only order that is honest: tokens, then fixtures, then baselines. A baseline recorded against fixtures that still embed the old sizes is a measurement of the previous system.

tokens:verify, budget, react:test and status:check pass against the new values. The budget's 32 intentionally red fixtures stay red and the two intentional violation scenes stay the only two over ceiling.

The hero's calc(display * 1.7) now lands near 55px rather than 104px, which is the size a hero wanted.

Corrected 2026-09-18, the same day. This section first said the docs site inherited the change without edit, because its stylesheet binds tokens on all 23 of its size rules. That was wrong about the rule that matters. .page bound font-size: var(--wr-text-caption), so the whole site rendered at the smallest size the system permits anything to be read at, and every control drawn on it still took text-body for its label. The docs site had the identical fault the proof app had, stated in a different way: not an unbound reading size, but one bound to the wrong rung. .page now binds text-body, and the two agree for the same reason they agree in the product.

ADR-0099's display floor now binds in both densities rather than one. The heading voice lifts to text-lead in the field themes, and the floor holds the display face at 24px. At 1.25 that floor caught compact only, because comfortable's text-lead was 25px and cleared it; at 1.125 both densities resolve below 24px, so a field heading is the floor in both. The lift between text-body and text-lead consequently does nothing in the field themes and still does its work indoors, where the floor is 0rem.

This is the floor behaving as ADR-0099 declared it, not a value escaping the scale: it is an absolute legibility minimum for signage conditions, the same kind of number as the 44px and 48px interactive targets, and it is authored in family.config.json for that reason. It does mean a field heading is 24px against 18px body where it was 25px against 20px, so the heading is now the more separated of the two, which is the direction signage wants.

Measured live on /incident in field-night at comfortable: body 18px, button label 18px in a 94x54 box, headings 24px. Before the change the same page drew 16px prose beside a 20px label.

#Alternatives

Select step 0 for text-body in comfortable. Lands body exactly on 16px and needs no ratio change. Rejected because it collapses text-body into text-caption in the default density, and the two are then one size with two names in the mode almost everything is read in. Compact gets away with it because compact is a squeeze and says so; making the default density do it leaves the system with no secondary reading size at the density where the secondary reading size does the most work.

Bind the app's body size and leave the ratio at 1.25. Removes the disagreement by making the prose 20px. Rejected: it fixes the symptom by making everything loud rather than making the control quiet, and it spends screen a dense console does not have.

Make compact the default density. Ruled out by the maintainer before this record. It answers the type question by answering a different one, and it moves every spacing and target value to fix a type problem.