# Design System (/docs/reference/design)

The visual language, semantic tokens, geometry, depth, typography, and motion of 4AF.

4AF uses warm-neutral greys, a single amber accent, compact controls, and short, physical
motion. Fill and elevation show whether something is sunk into the page, anchored to it, or
floating above it.

## Color palette and roles

Components consume semantic roles by default. Direct palette ramps are reserved for status
accents and fixed neutral control states. A consuming project can reskin the semantic roles;
it must also remap the relevant ramps to change those exceptions.

| Role | Light treatment | Dark treatment | Purpose |
| --- | --- | --- | --- |
| Background | Warm near-white (`oklch(0.985 0.002 70)`) | Neutral near-black (`oklch(0.1448 0 0)`) | Page ground and sunk wells |
| Surface | White (`oklch(1 0 0)`) | Soft black (`oklch(0.178 0 0)`) | Chrome and anchored popups |
| Raised surface | White (`oklch(1 0 0)`) | Deep black (`oklch(0.130 0 0)`) | Dialogs, sheets, and palettes |
| Foreground | Warm near-black (`oklch(0.155 0.006 70)`) | Warm near-white (`oklch(0.985 0.002 70)`) | Primary text and neutral actions |
| Focus ring | Amber (`oklch(0.702 0.176 52)`) | The same amber | Focus and deliberate emphasis |
| Destructive | Vivid red (`oklch(0.6 0.225 26)`) | The same red | Irreversible and failed actions |
| Success | Deep green (`oklch(0.52 0.13 152)`) | The same green | Confirmed outcomes only |

Primary is ink, not colour. Amber is used for focus and rare emphasis; destructive red and
success green appear only when they mean something. Quiet destructive actions, such as menu and
toolbar rows, use red text without a red hover fill.

The destructive fill deliberately favors a brighter red with white text. This pairing falls
below the 4.5:1 contrast target for normal text; OKLCH lightness alone is not a contrast check.

A component's fill communicates its layer. `background` is the page and sunk wells such as
Input, Checkbox, Radio, and Sidebar Inset. `surface` is chrome and anchored popups such as
Sidebar, Dropdown Menu, Popover, and Hover Card. `surface-raised` belongs to elements floating
over everything: Dialog, Alert Dialog, Sheet, and Command Palette. A consuming project
decides what those semantic roles resolve to.

## Typography

Geist Sans is the interface voice: compact, neutral, and highly legible. Geist Mono is reserved
for code, command examples, keyboard hints, and small technical labels.

The scale: 11px technical labels, 12px compact text, 13px default UI, 15px body copy, then
18px, 22px, 28px, and 36px headings. Larger sizes tighten their leading and tracking; body copy
gets more. Numbers that update in place use tabular figures so the text around them doesn't
shift.

## Geometry and shape

Radii range from 3px to 28px. Nested shapes are concentric: the outer radius equals the inner
radius plus the padding between them, so a 14px shell with 4px of padding holds a 10px child.

Controls are compact by default. Icons remain geometrically centered inside their boxes;
leading and trailing icons beside text receive optical spacing through component attributes
rather than one-off margins.

Button controls share a 24px/30px/34px/38px scale for `xs`/`sm`/`md`/`lg`; component-specific
objects such as badges, checkboxes, radios, sliders, and table density keep their own geometry.
Their corner radii follow two tiers: 6px for `xs`/`sm` and 8px for `md`/`lg`.
Labeled button content uses an 8px icon-label gap at `xs`/`sm`, 10px at `md`, and 12px at `lg`;
leading and trailing icons receive a small optical edge adjustment.
Checkbox is fixed at 16px with a 4px radius. Other rectangular controls follow the same tiers:
6px for compact controls and 8px for form rows. Circular, pill-shaped, status, and list-row
elements keep their own geometry.

### Optical alignment

Center icon-only controls by their SVG box. If a glyph appears off-center, inspect its ink with
`getBBox()` before adding an offset: a glyph may already be optically balanced within the box,
so a blanket shift can misalign it. Correct a custom glyph inside its SVG rather than moving
every icon-only button.

Beside text, leading and trailing icons use `data-icon-start` / `data-icon-end` to reduce the
padding on their side by 2px. Keep this text-button spacing separate from icon-only centering.

## Depth and elevation

Buttons and cards use `shadow-border`: a translucent hairline ring, a close lift, and a soft
ambient shadow, which works over any background. Raised and overlay surfaces add more
separation.

In dark mode, most drop shadows are replaced by faint light rings, since shadows barely show on
near-black. Real borders are kept for dividers and table cells.

## Component styling

- **Buttons** use neutral ink for the primary action, with optical icon spacing and press
  feedback. Joined buttons keep their outer box still while pressed, so seams don't open.
- **Fields** sit on the background layer and strengthen their ring on focus. Invalid state is
  exposed to assistive technology, not only shown in red.
- **Anchored panels** use the surface layer and enter with a scale, blur, and fade from the
  trigger.
- **Overlays** use the raised layer and stronger elevation, with behaviour and focus management
  from Base UI.
- **Status** colours are shared by alerts, badges, and action outcomes, so a state looks the
  same as a sentence or a label.

## Layout principles

Spacing is compact. Related controls sit in close groups, and sections are separated more
clearly than individual fields. Page shells keep navigation fixed and let the content region
scroll. Popups open next to the control that opened them.

## Motion language

CSS handles hover, focus, ordinary press feedback, and simple entrances and exits. Button and
Toggle use Motion for spring presses. Motion also handles retained exits such as Morph's outgoing
content, gestures, springs, and layout animation. Transitions name the exact properties they
change and prefer compositor-friendly motion; Collapsible and Sidebar have documented layout-motion
exceptions.

Four CSS durations, fast, base, slow, and slower, cover focus feedback through sheets. JavaScript
duration and easing defaults mirror the CSS tokens and must be updated together; runtime CSS
overrides do not change JavaScript animations. Under reduced motion, CSS transitions collapse to
1ms so lifecycle events still fire, and Motion transitions run with zero duration. Looping loaders
keep their own speed rather than collapsing into a strobe.