Spacing & density
Six surfaces share every colour, type and radius token. They differ only in rhythm — and that difference is itself tokenised. A component never knows which surface it is on.
Named spacings
These seven names are what components use. [data-density] re-points them. The bars below are the comfortable register, which is what these docs render in. The two panels under The three densities show the same names re-pointed by compact.
The three densities
| Mode | Surfaces | section | block | row | Copy register |
|---|---|---|---|---|---|
compact | feedback app, dense panels | 1.5rem | 0.75rem | 0.375rem | Words. "Retry", "Skip", "Done". |
default | app, business dashboard | 2rem | 1rem | 0.5rem | Labels and fragments. One line of help. |
comfortable | www, /business/ | 3.5rem | 1.5rem | 0.625rem | Full sentences. Explain, then act. |
.ss-widget | third-party embeds | 1rem | 0.75rem | 0.375rem | Almost none. The data is the content. |
data-density differs — --spacing-block, --spacing-stack and --spacing-row re-point underneath it.data-density differs — --spacing-block, --spacing-stack and --spacing-row re-point underneath it.Density changes the space between things, never the type scale and never a hit target — the two panels above use identical font sizes and identical control heights.
Densities nest. A compact panel inside a comfortable page is legitimate and resolves correctly. A component that takes a density prop wins by setting the attribute on its own root.
<main data-density="comfortable">
<section className="py-section">…</section>
{/* a dense panel on a marketing page — legitimate */}
<aside data-density="compact" className="p-block">…</aside>
</main>Control heights & hit targets
control-height-smcontrol-height-mdcontrol-height-lg--spacing-touch is 44px and is the floor on anything a finger hits, in every density. WCAG asks 24px at AA and 44px at AAA; the feedback app is used on 4G after a race, by tired people, so the system takes the AAA number as its baseline.
theme.css.