Spacing & grid
Everything on an 8px base grid. Spacing tokens are multiples of 4px — the minimum step — with 8px as the workhorse. The grid is 12 columns with 16px gutters, 32px margins, and a 1240px max-width container. Radius tokens match the component scale: small radius for small things, pill for CTAs.
Spacing scale
The scale starts at 4px and doubles in familiar increments. Steps 2 (8px), 4 (16px), 6 (24px), and 8 (32px) are the most commonly used — they form the inner rhythm of cards, forms, and list items. Steps above 16 (64px) are layout-level gaps between sections.
12-column grid
The grid is 12 columns with 16px gutters and 32px page margins, capped at 1240px. On mobile (below 520px), margins shrink to 20px and the grid collapses to 4 columns. On tablet (520–900px), 8 columns are available. The 12-column system divides cleanly into halves, thirds, quarters, and sixths — all the splits a friend group needs.
/* Container */ .container { max-width: 1240px; margin: 0 auto; padding: 0 32px; /* --grid-margin */ } @media (max-width: 520px) { .container { padding: 0 20px; } /* --grid-margin-mobile */ } /* 12-column CSS grid */ .grid { display: grid; grid-template-columns: repeat(12, 1fr); gap: var(--grid-gutter); /* 16px */ } /* Responsive collapse */ @media (max-width: 720px) { .grid { grid-template-columns: repeat(8, 1fr); } } @media (max-width: 520px) { .grid { grid-template-columns: repeat(4, 1fr); } }
Breakpoints
Four breakpoints, named for device classes not pixel values — so they stay meaningful when device categories shift. Mobile-first: start at full width, add constraints as the viewport grows. The 900px breakpoint is where the sidebar navigation appears and single-column stacks become two-column grids.
| Name | Value | Token | Behavior |
|---|---|---|---|
| sm | 520px | --bp-sm | 4 → 8 columns, mobile nav visible, single-column cards |
| md | 720px | --bp-md | 8 columns, full grid starts, some 2-column layouts |
| lg | 900px | --bp-lg | Sidebar nav appears, 12 full columns, content max-width in effect |
| xl | 1240px | --bp-xl | Container max-width reached, centered layout |
Radius scale
Radius scales with component size. Small components get small corners. Cards get the generous lg radius. Pill is for CTAs and nav items where full rounding creates a distinct button language. Never mix large radius on small components — a 24px corner on a 13px tag looks bloated.
--r-xsTags, inner pills
--r-smChips, mini inputs
--r-mdInner cards, inputs
--r-lgCards, sheets
--r-xlComposer, settle card
--r-pillNav pills, CTAs
Z-index scale
The z-index scale is named, not arbitrary. Using raw numbers like z-index: 9999 creates stacking order bugs that are invisible until a tooltip appears under a modal. Always use the named tokens.
| Token | Value | Used for |
|---|---|---|
--z-base | 0 | Default document flow |
--z-card | 1 | Elevated cards, hover shadows |
--z-sticky | 10 | Sticky headers, pinned rows |
--z-nav | 50 | Tab bar, floating nav |
--z-modal | 100 | Modals, sheets, drawers |
--z-toast | 200 | Toast notifications — above modals |
--z-tooltip | 300 | Tooltips — above everything interactive |
--z-grain | 1000 | Paper grain overlay — always topmost, pointer-events:none |
Usage
--r-xs. Cards get --r-lg. The settle CTA button gets --r-pill. Scale radius with component scale.
border-radius: 8px on a full-screen modal — it clips the corners visibly on mobile. Don't use --r-lg on a small chip — it makes the radius larger than the element's own height.