Spacing System
The theme uses a token-driven spacing system built with SCSS maps and CSS variables. A small numeric scale is the single source of truth; intent-based semantic tokens point at that scale, and consumers reference a semantic name where one fits — never a raw rem value.
Overview
Section titled “Overview”The spacing setup has two layers:
- Primitives — the raw numeric scale (the only place a rem value is written).
- Semantics — intent-based aliases that point at a primitive, optionally per breakpoint.
Components consume spacing through the space() / space-value() functions, which accept either a semantic token or a raw primitive key. Reach for a semantic when one fits the intent; fall back to a primitive for one-off values.
Primitives
Section titled “Primitives”$spacing-scale: ( 0: 0, 4: rem(4px), 8: rem(8px), 12: rem(12px), 16: rem(16px), 24: rem(24px), 32: rem(32px), 48: rem(48px), 64: rem(64px), 96: rem(96px),);Keyed by the pixel value, valued in the rem equivalent. Reference a step directly when no semantic fits — e.g. space(12).
Semantics
Section titled “Semantics”$spacing-semantic: ( nav-gap: 12, prose-gap: 16,);Each entry is either:
- a primitive key directly (e.g.
nav-gap: 12), or - a map with:
base— the primitive key used by default.breakpoint— optional responsive overrides, repointing the token at a different primitive key per breakpoint.
section-gap: ( base: 48, breakpoint: ( tablet: 32, mobile: 24, ),),Breakpoints are defined in abstracts/variables/_media-queries.scss and are max-width (so scale down for smaller screens). This mirrors the typography responsive model.
Functions
Section titled “Functions”Two functions resolve a spacing token. Both accept a semantic name or a raw primitive key.
.main-menu { gap: space(nav-gap); // → var(--space-nav-gap)}
.toolbar { gap: space(12); // → var(--space-12)}| Function | Returns | Use when |
|---|---|---|
space($name) | var(--space-#{$name}) | the normal case — a runtime CSS variable. Follows responsive overrides automatically. |
space-value($name) | the literal rem value | a custom property can’t be used (e.g. inside calc() math, or where the value must be known at compile time). Resolves to the token’s base primitive. |
.sidebar { width: calc(100% - space-value(prose-gap)); // → calc(100% - 1rem)}Errors
Section titled “Errors”A key that matches no primitive and no semantic fails the build:
space(does-not-exist); // ✗ "Unknown spacing token `does-not-exist`."Validating at compile time means a typo’d token never silently ships as a missing value.
Generated CSS Variables
Section titled “Generated CSS Variables”:root { /* primitives */ --space-0: 0; --space-4: 0.25rem; --space-8: 0.5rem; /* … */
/* semantics → reference a primitive */ --space-nav-gap: var(--space-12); --space-prose-gap: var(--space-16);}Every token generates a CSS variable on :root automatically (from assets/src/scss/generate/_spacing.scss) — you never write these by hand. Semantic variables reference their primitive, so retuning a primitive cascades everywhere.
Responsive overrides
Section titled “Responsive overrides”When a semantic token defines breakpoint overrides, the generator re-emits only that variable inside the matching media query — widest-first so the narrowest wins the cascade:
@media screen and (max-width: 46rem) { :root { --space-section-gap: var(--space-24); }}Anything using space(section-gap) follows along with no recompile of consumers.
Adding a Token
Section titled “Adding a Token”-
Open the token file
Edit
assets/src/scss/abstracts/variables/_spacing.scss. -
Add a primitive (only if the value isn’t on the scale yet)
$spacing-scale: (// …20: rem(20px),); -
Add a semantic alias
$spacing-semantic: (nav-gap: 12,prose-gap: 16,card-padding: (base: 24,breakpoint: (mobile: 16,),),); -
Use it via
space().card {padding: space(card-padding);}
From Figma
Section titled “From Figma”Designer provided a spacing scale
Section titled “Designer provided a spacing scale”- Open the Spacing / Layout board in Figma
- Copy the raw step values into
$spacing-scale - Map each repeated usage to a semantic token by intent (
nav-gap,card-padding,section-gap), not by number
No spacing board
Section titled “No spacing board”- Go page by page and collect padding / margin / gap values
- Identify repeating values and group them by intent
- Add the distinct values as primitives, then create semantic aliases for each intent
- Replace hardcoded values with
space(...)

