# 06 · Layout and form

> Space, grid, radius, elevation. The quiet decisions that make two screens
> built by two people look like one product.

---

## 6.1 Space

A **4px base scale**. Everything lands on it.

`2 · 4 · 6 · 8 · 12 · 16 · 20 · 24 · 32 · 40 · 56 · 72`

| Gap | Between |
|---|---|
| 4–6px | Icon and its label; a dot and its chip text |
| 8–12px | Related controls in a row; form field and its label |
| 16px | Cards in a grid; fields in a form |
| 20–24px | Panel padding; card padding |
| 32px | Page gutter; between major sections |
| 40–56px | Between page regions |

**Whitespace is the design.** The brand's warmth comes from the paper being
allowed to show. When a layout feels wrong, the answer is almost always more
space, not more border.

---

## 6.2 Containers

| Container | Width | Use |
|---|---|---|
| Page | `max-width: 1280px`, `padding: 32px` | Every product page |
| Reading | `max-width: 768px` | Single-column form or prose pages — account, settings |
| Prose | `max-width: 62ch` | A block of running text inside any page |
| Auth card | `max-width: 440px` | Sign-in, set password, invite |
| Command palette | `max-width: 520px` | ⌘K |

```tsx
<div className="mx-auto w-full max-w-[1280px] px-8 py-8">
```

The page container is centred, never full-bleed. A table that needs more room
scrolls inside its own box — it does not widen the page.

---

## 6.3 The app frame

```
┌──────────┬────────────────────────────────────────┐
│          │                                        │
│ Sidebar  │  Main — scrolls independently          │
│ 264px    │  bg: paper #F7F5F2                     │
│ bg: base │                                        │
│ #F4F3F1  │  ┌──────────────────────────────────┐  │
│          │  │ max-w-1280 · px-8 py-8           │  │
│  ── nav  │  │  PageHeader                      │  │
│          │  │  content                         │  │
│  ── user │  │                                  │  │
└──────────┴──┴──────────────────────────────────┴──┘
```

- Sidebar is **264px**, `paper-base`, with a `border` right edge.
- Below `lg` (1024px) it becomes a drawer behind a 56px top bar.
- The main column scrolls; the sidebar does not.
- The sidebar's own footer holds the account block and sign-out — never in the nav list.

---

## 6.4 Radius

Radius encodes **scale**: the bigger the surface, the rounder the corner.

| Token | Value | Applies to |
|---|---|---|
| `xs` | 5px | Keyboard hints, tiny tags |
| `sm` | 7px | Inline inputs, compact fields |
| `md` | 9px | Nav rows, icon buttons, avatar tiles — the interface default |
| `lg` | 12px | Buttons, dropdowns |
| `xl` | 14px | App cards, dashboard tiles |
| `2xl` | 16px | Panels, modals, primary cards |
| `full` | 9999px | Status chips, dots, avatars, pill CTAs |

Nothing is square. Nothing is rounder than 16px except a pill.

---

## 6.5 Elevation

**Surfaces are separated by a border, not by floating.** This is the single
biggest reason the product reads as calm.

| Level | Shadow | Use |
|---|---|---|
| Flat | none | The default. Most things |
| Raised | `0 1px 2px rgba(26,25,23,0.04)` | Cards and panels. A hint of a seam |
| Lifted | `0 2px 8px rgba(26,25,23,0.06)` | Hover on an interactive card |
| Overlay | `0 16px 48px rgba(26,25,23,0.16)` | Modals, ⌘K, popovers. The only real shadow |

Shadows are **warm-tinted** — `rgba(26,25,23,…)`, the ink, never
`rgba(0,0,0,…)`. A neutral-black shadow on a cream ground goes grey and dirty.

**Order of preference for separating two things:** space → a hairline → a
background change → a shadow. Reach for the shadow last.

---

## 6.6 Borders

- **1px, always.** There is no 2px border in this system except the focus ring and the `Alert` left edge.
- `border` `#E5E2DE` for structure — card edges, table rules, dividers.
- `border-strong` `#D8D5D0` for anything interactive — inputs, secondary buttons.
- Dashed `border-strong` for an empty drop target or a placeholder region. Nowhere else.

**Note:** neither border colour reaches 3:1 against white (1.29:1 and 1.46:1).
That is acceptable for *decorative* separation, but a border must never be the
**only** thing identifying a control. Inputs get a label and a focus ring;
buttons get a fill or a text colour. See [accessibility](/guide/accessibility/).

---

## 6.7 Control sizes

| Size | Height | Use |
|---|---|---|
| `sm` | 32px | Table-row and toolbar controls |
| `md` | 38px | Nav rows, inline buttons in page chrome |
| `lg` | 48px | Form inputs and primary form buttons |

**Hit area is 44px minimum**, including padding, even when the visible control is
32px. A 32px button in a table row needs vertical padding around it, not a
smaller finger.

---

## 6.8 Grid and responsive

Cards go **1 → 2 → 3** across `sm` (640) and `lg` (1024). Stat tiles go
**1 → 2 → 4** across `sm` and `xl` (1280).

| Breakpoint | Width | What changes |
|---|---|---|
| base | <640 | Single column. Sidebar is a drawer. Page gutter 24px |
| `sm` | 640 | Two-column card grids |
| `lg` | 1024 | Sidebar becomes static. Page gutter 32px |
| `xl` | 1280 | Four-column stat grids; the page container caps |

**Mobile is not an afterthought.** The primary audience reads on a phone in a
truck. Every table must scroll inside its own box; every modal must fit a
375px viewport; every tap target must be 44px.

---

## 6.9 Do and don't

**Do**
- ✅ Land every dimension on the 4px scale
- ✅ Separate with space first, a hairline second
- ✅ Use warm-tinted shadows
- ✅ Let a wide table scroll inside its own container

**Don't**
- ❌ Use `rgba(0,0,0,…)` shadows
- ❌ Stack shadows to create depth — use one border
- ❌ Invent a radius outside the scale
- ❌ Go full-bleed on a product page
- ❌ Ship a control below a 44px hit area
