Spacing

Proximity signals relationship; distance signals importance. The spacing scale encodes this — small gaps within components, large gaps between sections.

Space Scale

Base unit is 12px. The scale runs from 6px (half-unit, for tight intra-component gaps) to 96px (hero breathing room).

Padding in context

Each token applied as vertical padding around a content block, so you can judge the breathing room each step provides.

Reference — Space Scale
TokenrempxUse
--space-xs0.375rem6pxIcon-to-label gap, tag padding
--space-sm0.75rem12pxTight grouping within a component
--space-sm-plus1rem16pxOff-scale optical step — compact component padding (button/nav-CTA horizontal padding)
--space-md1.5rem24pxStandard gap — when in doubt, start here
--space-lg2.25rem36pxBetween distinct content blocks
--space-xl3rem48pxSection breathing room, major transitions
--space-2xl3.75rem60pxBetween page sections
--space-3xl4.5rem72pxHero padding, top-of-page breathing room
--space-4xl6rem96pxMaximum section gap — use sparingly

Usage rules

  • xs / sm — intra-component only. Never use to separate independent elements.
  • md — the default gap. When in doubt, start here.
  • lg / xl — between content blocks within a section.
  • 2xl / 3xl — between named page sections. The visual pause that lets sections breathe.
  • 4xl — reserved for hero areas. More than one use per page usually signals restructuring is needed.

Layout Widths

The page container can be wide, but readable text should always be constrained to ~70ch. These two values operate independently — a wide layout can contain narrow prose.

Reference — Layout Widths
TokenValueUse
--width-content1080pxOuter page container
--width-prose70chBody copy, articles, long-form text
--width-narrow640pxForms, focused UI, modals

Page Structure

A standard page skeleton with spacing tokens at each level. Use this as a starting blueprint — the gaps between sections give the page its rhythm.

site header / nav — sticky, full-width
padding-top: --space-3xl
hero / page header
--space-2xl between sections
content section · max-width: --width-prose or --width-content
--space-2xl
content section
padding-top: --space-xl
Reference — Page Structure
[site header / nav]       — sticky or static, full-width
[hero / page header]      — padding-top: --space-3xl
[content sections]        — gap between sections: --space-2xl
  [section heading]
  [section body]          — max-width: --width-prose or --width-content
[site footer]             — padding: --space-xl top

Grid Pattern

auto-fit with minmax produces a responsive layout without breakpoint queries. Resize your browser — the columns collapse automatically when there is not enough room.

Reference — Grid Pattern
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--space-md); /* 24px */
}

Use CSS Grid for two-dimensional layouts, flexbox for one-dimensional. Never go beyond 3 columns at --width-content.

Border Radius

Each radius maps to a specific element type. The progression creates implicit hierarchy — larger surfaces have larger radii, signalling containment without needing a border.

Reference — Border Radius
TokenValueUse
--radius-sm4pxBadges, tags, nav link focus ring, checkboxes
--radius-md6pxButtons, inputs, selects, textarea, icon containers
--radius-lg8pxCards, dropdowns, popovers, drawers
--radius-xl12pxLarge panels, featured sections
--radius-full9999pxAvatar circles (one-off use — not for badges)

A badge (4px) sits inside a card (8px) — the radius difference signals containment. The system does not use pill-shaped badges.

Z-index Scale

Always reference a token — never use raw numbers. Each layer is designed to sit cleanly above the one before it. Never skip levels.

Reference — Z-index Scale
TokenValueUse
--z-base0Default page content
--z-raised1Sticky elements in flow (sub-nav tab row)
--z-content10Sticky sub-nav — above page, below fixed nav
--z-dropdown100Dropdowns, popovers
--z-sticky200Sticky nav bar, fixed header
--z-overlay300Overlays, mobile nav drawer
--z-modal400Modals
--z-toast500Toast notifications

The nav (--z-sticky: 200) sits below overlays (--z-overlay: 300) — dropdowns triggered inside the nav render correctly above it without adjustment.

Elevation

Three shadow tiers for raised surfaces — dropdowns, popovers, raised cards. Each tier is an opacity token layered under a fixed offset/blur, so dark mode can boost the alpha without redeclaring the whole shadow.

Reference — Elevation
TokenLight opacityDark opacityUse
--shadow-sm0.060.18Hover rows, inline chips
--shadow-md0.100.28Dropdowns, popovers, tooltips
--shadow-lg0.140.40Modals, raised cards

Dark mode needs a higher opacity for the same shadow to read against an already-dark background — override only the --shadow-opacity-* token, not the full --shadow-* value, if you need a fourth tier. --overlap-card-shadow-raised (used by .overlap-card) reuses --shadow-opacity-lg for its own upward-facing shadow.

Breakpoints

Two reference values marking layout transitions. Use min(), max(), and clamp() within components — only reach for breakpoints at the page layout level.

Reference — Breakpoints
TokenValueBehaviour
--breakpoint-mobile640pxSingle column; horizontal padding: --space-md
--breakpoint-tablet768pxSingle column centered; horizontal padding: --space-lg
(--width-content)1080pxCentered container, auto horizontal margins

CSS custom properties cannot be used directly in @media queries. Use the token value as a reference comment.

/* --breakpoint-mobile: 640px */
@media (max-width: 640px) {
  .layout { flex-direction: column; }
}