Layout
A 4px base, a desktop-primary grid, and spacing that is not the grid. Rails sit outside the canvas. Panels span columns. Gutters stay empty.
Units
Base is 4px. It snaps 16/24 type, 24px icons, and density without remainder. No 3s, no 7s, no eyeballing.
| Token | Value | Notes |
|---|---|---|
--space-0 | 0 | Flush |
--space-px | 2px | Optical only — hairline offsets, icon nudge. Not a spacing step. |
--space-1 | 4px | Base |
--space-2 | 8px | |
--space-3 | 12px | |
--space-4 | 16px | |
--space-5 | 20px | |
--space-6 | 24px | Icon box, body line-height |
--space-8 | 32px | |
--space-10 | 40px | |
--space-12 | 48px | |
--space-16 | 64px | |
--space-20 | 80px | |
--space-24 | 96px |
Grid
Desktop-primary instrument. Compact is a companion, not the design target.
| Viewport | Width | Columns | Gutter | Margin | Max canvas |
|---|---|---|---|---|---|
| Compact companion | 0–767 | 4 | 16 | 16 | — |
| Standard | 768–1279 | 8 | 16 | 24 | — |
| Wide | 1280–1599 | 12 | 24 | 32 | 1440 |
| Ultrawide | 1600+ | 12 | 24 | 40 | 1600 |
- Rails sit outside the canvas grid. They are not a column.
- Panels span columns. They do not sit in the gutter.
- Gutters stay empty. Do not park icons, badges, or hairlines in the gap.
Grid is alignment. It is not padding.
Breakpoints
Named after the layout they unlock, not after devices.
| Token | Value |
|---|---|
--bp-compact-max | 767px |
--bp-standard-min | 768px |
--bp-wide-min | 1280px |
--bp-ultrawide-min | 1600px |
--grid-max-wide | 1440px |
--grid-max-ultrawide | 1600px |
Custom properties document the scale. Media queries still need the literal widths.
Density
Compact / standard / roomy is a padding multiplier: 0.75 / 1 / 1.25. It is orthogonal to viewport.
A wide on-call wall can be compact. A compact-width companion can be roomy. Density does not change type size, column count, or hit targets (44×44 holds).
| Token | Value |
|---|---|
--density-compact | 0.75 |
--density-standard | 1 |
--density-roomy | 1.25 |
--density | 1 (default) |
Default panel pad is --space-3 (12px) at standard density. Compact → 9px. Roomy → 15px (snap to 16). Compute as calc(var(--space-3) * var(--density)).
Control scale
The face is not the hit. Controls sit on a 28 / 32 / 36 face so the instrument stays dense. --hit stays 44 — buttons expand the target with a pseudo; compact-width companion uses the 44 face on fields, menus, and tabs.
| Token | Value | Use |
|---|---|---|
--hit | 44px | Minimum target. Always. |
--control-h-sm | 28px | Dense toolbars, icon + short label |
--control-h-md | 32px | Default button, field, select, menu item |
--control-h-lg | 36px | Emphasized action, lg field |
--control-pad-x-sm | 8px | sm button, field inline pad |
--control-pad-x | 12px | Default control inline pad |
Do not size a field to 44 on desktop just to pass the hit. Size the face to the control token and keep the hit.
Spacing
Stack and inline use space tokens. They are independent of the grid.
- Grid = alignment (columns, gutters, margins).
- Space = padding and gap.
Do not invent a 10px gap because the panel “looked tight.” Step to --space-2 or --space-3.
CSS custom properties
Space, breakpoint, and density names are in the tables above. Runtime grid tracks change with viewport. Import site/css/tokens.css.
| Token | Default (wide) | Notes |
|---|---|---|
--grid-columns | 12 | 4 compact, 8 standard |
--grid-gutter | 24px | 16 compact / standard |
--grid-margin | 32px | 16 compact, 24 standard, 40 ultrawide |
--grid-max | 1440px | none below wide; 1600 ultrawide |
--density | 1 | Multiplier on padding, not on type |
Media queries still need literal widths. Custom properties document the scale.
Live grid
Live columns follow --grid-columns: 4 under 768px, 8 to 1279, 12 from 1280. Gutters stay empty.
Control scale
Face 28 / 32 / 36. Hit stays 44. Desktop uses the face; compact-width companion uses the 44 face on fields and menus.
Spacing ladder
Stack and inline use space tokens. Independent of the grid. 4px base; no 3s, no 7s.
Related
- Typography — 16/24 body sits on the 4px grid
- Elevation
- Color
- Principles — Compose, don't template