Skip to main content
Executive Support by Beige Threat

Spacing & Layout

Every measure in the system is a multiple of 4 px. That cadence gives us clean 8s, 16s, 24s, and 32s without ever needing a half-pixel, and it stays sharp at any zoom or device-pixel ratio. A 12-column editorial grid carries the page; named slots – inline, stack, inset, section – carry the rhythm inside it.

The base unit

Seventeen stops, from 0 to 192 px. Pick from the scale for any padding, margin, or gap. If a measure feels wrong, try a different stop – never a fractional one.

Token
Value
Visual
Typical use
--es-space-0
0px
No spacing
--es-space-px
1px
Borders only – never spacing
--es-space-0-5
2px
Half-step – exceptional only
--es-space-1
4px
Base unit, icon nudges
--es-space-2
8px
Tight inline gap
--es-space-3
12px
Default inline, small inset
--es-space-4
16px
Default stack, default inset
--es-space-5
20px
Comfortable inline
--es-space-6
24px
Large stack, card inset, mobile margin
--es-space-8
32px
Generous inset, tablet margin
--es-space-10
40px
Tight section break
--es-space-12
48px
Section sm, desktop margin
--es-space-16
64px
Section md
--es-space-20
80px
Section lg
--es-space-24
96px
Section xl, hero
--es-space-32
128px
Editorial whitespace
--es-space-40
160px
Page-scale rhythm
--es-space-48
192px
Marketing hero rhythm

Spacing slots

Components consume semantic spacing, never primitives directly. Four families, each with t-shirt sizes. That’s what makes the system tunable: change --es-spacing-stack-md once and every form on the site reflows to match.

Inline – horizontal grouping
Gap between siblings on a row – icon to label, button group, breadcrumb.
Find your level
—es-spacing-inline-xs · 4px
—es-spacing-inline-sm · 8px
—es-spacing-inline-md · 12px ← shown
—es-spacing-inline-lg · 16px
Stack – vertical rhythm
Gap between stacked elements – label to input, list rows, paragraphs.
Name
Email
Role
—es-spacing-stack-xs · 8px
—es-spacing-stack-sm · 12px
—es-spacing-stack-md · 16px ← shown
—es-spacing-stack-lg · 24px
—es-spacing-stack-xl · 32px
Inset – padding inside containers
Equal padding on all sides of a card, button, input, panel.
content
—es-spacing-inset-xs · 8px
—es-spacing-inset-sm · 12px
—es-spacing-inset-md · 16px
—es-spacing-inset-lg · 24px ← shown
—es-spacing-inset-xl · 32px
Section – page-scale rhythm
Whitespace between major page sections. Heroes get xl, body content md, related groups sm.
Section A
48px
Section B
—es-spacing-section-sm · 48px ← shown
—es-spacing-section-md · 64px
—es-spacing-section-lg · 80px
—es-spacing-section-xl · 96px

The 12-column grid

Twelve divides cleanly into 2, 3, 4, and 6 – every classic editorial split. Gutter and outer margin scale with the viewport: tight on phones, generous on desktop. Mobile-first, so design from sm upward.

12 – full-bleed hero
6 – half
6 – half
4
4
4
8 – main
4 – side

Breakpoints

Mobile-first. Multi-column layouts kick in at md; full sidebars and dashboards arrive at lg. The xl step is the design-canvas baseline.

TokenMin-widthTarget
--es-bp-xs0pxDefault – phones, narrow viewports
--es-bp-sm640pxLarge phones, small tablets in portrait
--es-bp-md768pxTablets – first multi-column layouts
--es-bp-lg1024pxSmall laptops – nav, sidebars, dashboards
--es-bp-xl1280pxStandard desktop – design-canvas baseline
--es-bp-2xl1536pxLarge desktops, wide-bleed layouts

Gutter and margin

Both scale with the viewport. The grid stays at 12 columns; the breathing room around it grows.

BreakpointGutterPage margin
Mobile (default)--es-space-4 · 16px--es-space-6 · 24px
md (768px+)--es-space-6 · 24px--es-space-8 · 32px
lg (1024px+)--es-space-8 · 32px--es-space-12 · 48px

Container widths

Five widths cover every layout. Long-form caps at prose for readable line lengths; product UI sits inside page; hero spreads stretch to wide.

prose65ch · long-form reading
narrow768px · forms, single column
page1280px · default app and marketing
wide1440px · hero, dashboard
full100% · edge-to-edge

Radii

The brand is editorial. Surfaces stay close to square (sm is 4 px), with pill reserved for the actions where the wireframes already use it – CTAs, tags, chips. Avatars and dots use full.

none
0
xs
2
sm
4
md
8
lg
12
xl
20
pill
999
full

Semantic mapping

Components reach for the semantic alias, not the primitive. Buttons stay pill, cards stay sm – swap the alias once and every consumer follows.

TokenResolves toUse
--es-radius-controlsm · 4pxInputs, selects, checkboxes
--es-radius-cardsm · 4pxCards, panels – the magazine feel
--es-radius-surfacemd · 8pxModals, sheets
--es-radius-actionpill · 999pxButtons, tags, chips
--es-radius-mediasm · 4pxImages, video – sharp, editorial
--es-radius-circularfull · ∞Avatars, status dots

Borders

The system favours hairlines. Elevation is the exception, the rule is line – that’s the magazine in it. heavy is the editorial accent: a 4 px rule above a section opener, in teal or orange.

hairline · 1px
—es-border-hairline
Default rule – dividers, card borders, table rows.
thin · 1px
—es-border-thin
Same width, an alias for clarity in code.
thick · 2px
—es-border-thick
Focus rings, emphasised input states.
heavy · 4px
—es-border-heavy
Editorial accent rules – section openers, callouts.

Semantic mapping

TokenResolves toUse
--es-border-defaulthairline · 1pxCards, dividers, table rows
--es-border-focusthick · 2pxFocus rings, emphasised inputs
--es-border-accentheavy · 4pxEditorial rules above section opens

Elevation

Two-layer shadows for natural depth. The ramp is short and discreet – the page should feel like a printed spread, not a stack of cards. Reach for elevation only when an element physically leaves the surface: overlays, dialogs, dropdowns.

xs
elevation-raised (input)
sm
card resting
md
hover, dropdown
lg
popover, tooltip
xl
modal, sheet

Semantic mapping

TokenResolves toUse
--es-elevation-flatnoneDefault – no shadow
--es-elevation-raisedsmCards at rest
--es-elevation-floatingmdHover states, dropdown menus
--es-elevation-overlaylgPopovers, tooltips
--es-elevation-dialogxlModals, sheets, command palette
--es-elevation-focusfocus ring3 px teal ring – keyboard accessibility

Usage rules

Common patterns and the mistakes to avoid. Spacing discipline is what separates a system from a stylesheet.

Do · Multiples of 4
16px stack · 24px inline

Pick from the scale. --es-space-4 (16px) and --es-space-6 (24px) compose without surprises.

Don't · Magic numbers
13px stack · 19px inline

Off-grid values cascade. One 13 px decision becomes ten across the codebase, and the rhythm is gone.

Do · Semantic slots in components
.card { padding: var(—es-spacing-inset-lg); }

Components reference semantic tokens. Tune the system once; every consumer updates with it.

Don't · Primitives in components
.card { padding: var(—es-space-6); }

Primitives are the alphabet. Components should speak in words – semantic slots – not letters.

Do · Stack and inset for rhythm
Name
Email

Use stack for vertical gaps inside a group and inset for the padding around it. Both stay in sync.

Don't · Arbitrary margin chains
Name
Email

Per-element margin overrides break the rhythm and fight the next person who edits the file.

Do · Cap long-form at prose

For three years she ran the calendar of the man who ran the building. The lines fall where the eye expects them, because the column is capped at sixty-five characters.

Reading copy stays inside --es-container-prose (65ch). Lines longer than that lose the reader between sentences.

Don't · Edge-to-edge body copy

For three years she ran the calendar of the man who ran the building. When body copy stretches to the page edge, the eye loses its place returning from one line to the next, and reading slows.

Full-bleed prose belongs in feature spreads, not paragraphs. Hold the line length.

Do · One radius per family
Card

Buttons are pill, cards are sm. The two never trade places.

Don't · Mixed radii in one block
Card

Three or four radii in the same view reads as a prototype, not a publication.

Do · Line over lift
A card at rest sits flat on the page.

Default to a 1 px border. Editorial brands feel printed when surfaces sit flat to the page.

Don't · Shadow as decoration
A resting card lifted off the page for no reason.

Reserve elevation for elements that physically lift – modals, hover states – not the resting state.

Tokens to ship

Six namespaces cover every layout decision. Components reach for the semantic alias; primitives exist to be tuned, not consumed directly.

NamespaceExample tokensPurpose
Spacing primitives--es-space-0--es-space-48The 4-px base scale. 17 stops, 0 to 192 px.
Spacing slots--es-spacing-inline-*, --es-spacing-stack-*, --es-spacing-inset-*, --es-spacing-section-*Semantic gaps and padding for components and layouts.
Grid--es-grid-columns, --es-grid-gutter, --es-grid-margin, --es-bp-*, --es-container-*The 12-column grid, breakpoints, and container widths.
Radii--es-radius-none--es-radius-full, --es-radius-control, --es-radius-card, --es-radius-action, --es-radius-circularCorner shapes – primitives plus six semantic roles.
Borders--es-border-hairline, --es-border-thick, --es-border-heavy, --es-border-default, --es-border-focus, --es-border-accentLine widths – primitive and semantic.
Elevation--es-shadow-xs--es-shadow-xl, --es-elevation-raised, --es-elevation-floating, --es-elevation-overlay, --es-elevation-dialog, --es-elevation-focusTwo-layer shadows for the five elevation roles.