Foundations
One ladder for margin, padding and gap, named by value — --space-16 is always 16px. The step size changes once:
The ladder. Derived from the codebase rather than imposed on it — 726 of 727 spacing uses across both projects already obeyed the rule. Every step is in use; legal-but-unused values (52, 68, 76, 84 …) get added on demand. Emitted in rem, and the px column is measured off each rendered bar rather than restated.
Three families, grouped by what the space DOES: inset inside a container, stack between vertical siblings, inline between horizontal ones. Each is an intent-grouped pass-through to the ladder, so components never bind to a raw value. Derived, not imposed — the steps are the values the designs already used; legal ladder values that no family needs are deliberately absent.
--spacing-stack-md will happily generate px-stack-md. That is why direction lives one tier down, on the component tokens, mirroring Figma’s padding.inline / padding.block. The three families here are vocabulary for size; the component tier is where an axis gets chosen.Page- and region-level structural space: viewport gutters, page rhythm, section breaks. These encode a product-level layout decision rather than component rhythm, so they get names. All fluid — clamp() ramps between real ladder steps. Bars are measured at the current viewport, so resize and they move.
Where direction is chosen and where a relationship gets a name. Each of these binds to an alias step above — nothing here invents a value. Two kinds live side by side: a component’s own padding, and the gap between two things that belong together, which is a judgement about coupling rather than a size.
px-control-inline stutter. Tailwind’s axis prefix plus the token’s own axis name reads twice, the same way text-text-primary does. It is kept on purpose: it leaves the CSS variable readable on its own and keeps the Figma names exact.