Elevation & depth
Sheets on the drafting table: controls and cards rest on the white page with a crisp edge, fields sit a hair below it, and only overlays float.
Principle
Depth tells you what you can touch. The page is the drafting table; anything interactive is a sheet laid on it, with a crisp edge and the faintest shadow underneath.
- White means touchableThe ground is white too, so a touchable thing is marked by its edge, not by a fill color.
- Edges before shadowsA crisp 1px edge does the work. The shadow under it is a hint you notice only when it is missing.
- One step at a timeHover and press move one level, never two. Nothing lifts on hover; only overlays leave the table.
Levels
Four levels, counted from the table. Fields sit a hair below it, controls and cards rest on it, and only overlays leave it. Never invent a fifth: if something needs more emphasis, use type or space, not a bigger shadow.
- Family Rev.
- W-Wide Flange 4
| Level | Token | Value | Used by |
|---|---|---|---|
| Raised · control | shadow-edge | 0 1px 0 0 rgb(14 17 22 / 0.04) | Buttons, chips, the selected segment, the account chip |
| Raised · sheet | shadow-resting | 0 1px 1px 0 rgb(14 17 22 / 0.04), 0 1px 3px 0 rgb(14 17 22 / 0.05) | Cards, panels, drawing sheets |
| Overlay | shadow-overlay | 0 0 0 1px rgb(14 17 22 / 0.08), 0 8px 16px -4px rgb(14 17 22 / 0.08), 0 4px 32px -4px rgb(14 17 22 / 0.08), 0 24px 48px -12px rgb(14 17 22 / 0.08) | Menus, dialogs, sheets, the command palette, toasts. No border |
| Recessed | inset-shadow-recessed | inset 0 1px 0 0 rgb(14 17 22 / 0.06) | Fields (input, textarea, select) and the segmented track |
| State · selected | inset-shadow-selected | inset 0 1px 0 0 rgb(14 17 22 / 0.12) | Selected chips |
| State · pressed | inset-shadow-pressed | inset 0 1px 0 0 rgb(14 17 22 / 0.2) | Buttons while pressed (active:) |
Modal overlays dim the page with one backdrop everywhere: bg-foreground/40 (ink at 40%), no blur.
Edges
Three edges, from firm to faint. The edge, not the shadow, tells you a thing can be pressed, typed into, or is simply a boundary.
border-strongFirm. Anything you type into: fields, selects. Passes 3:1 for non-text contrast.
border-edgeRaised. Anything you press: buttons, chips, the selected segment. Translucent, so it reads on white and on vellum.
border-borderFaint. Boundaries, not affordances: card borders, rules between rows, the rail edge.
States
Hover and press are small steps, not color swaps. Hover changes the fill one notch, press adds an inset, focus adds cyan, and disabled drops to half opacity.
| Control | rest | hover | Pressed / selected | focus | disabled |
|---|---|---|---|---|---|
| Primary button | bg-primary · edge | bg-primary-hover | + inset-shadow-pressed | outline-ring, 2px offset | opacity-50 |
| Secondary button | bg-muted · edge | fill +3% ink | + inset-shadow-pressed | outline-ring, 2px offset | opacity-50 |
| Input | border-strong · recessed | border graphite | invalid (no pressed): border-destructive | border-ring · ring 3px at 25% | opacity-50 |
Segmented control · live
Do & don't
Depth is a signal, so it only works if it stays rare. When in doubt, take the shadow away and see whether the edge alone still reads.