Layout grid
Two columns below 640, six from 640, with a 20px gutter. Sections place their content on the grid with column tokens; nested content lines up with subgrid.
Breakpoints
390 · 640 · 744 · 1024 · 1440 · 1920. The base values are for
phones narrower than 390. They're set only in tokens.css; the site is optimised
first for a 1496 × 848 laptop viewport (MacBook Pro 16").
| Width | Columns | Margin | Name in Figma |
|---|---|---|---|
| < 390 | 2 | 20 | Mobile S |
| 390–639 | 2 | 40 | Mobile |
| 640–1919 | 6 | 64 (--spacing-3xl) | Tablet–Laptop |
| ≥ 1920 | 6 | 128 (--spacing-edge) | Wide |
The mobile margins (20 and 40) are deliberately off the spacing scale: 24 / 48 would wrap the hero subtitle. There are no 80 or 200px margins anywhere.
| Token | Base | ≥ 390 | ≥ 640 | ≥ 1920 | Note |
|---|---|---|---|---|---|
--grid-columns | 2 | 6 | |||
--grid-gutter | 20px | ||||
--grid-margin | 20px | 40px | var(--spacing-3xl) | var(--spacing-edge) |
Utilities
.layout-grid: a full-width section with the page margins and the column grid..layout-columns: the column grid only, inside an already padded section.- Children place themselves with
grid-column: var(--…-column), a token that changes per breakpoint. Nested alignment usessubgrid.
Responsive by tokens
Components don't contain media queries (apart from (hover: hover)). A component
reads tokens such as --work-card-column or --footer-top-direction,
and tokens.css redefines them per breakpoint:
/* tokens.css */
:root { --work-card-column: 1 / -1; } /* mobile: one card per row */
@media (min-width: 1024px) {
:root { --work-card-column: span 3; } /* two per row */
}
@media (min-width: 1920px) {
:root { --work-card-column: span 2; } /* three per row */
}
/* WorkCard grid (component) */
.work-grid > * { grid-column: var(--work-card-column); }