Spacing and rhythm

Loom Base's spacing scale (2 to 80 px) and the section rhythm: one padding per template.

Foundation · stable · v1.0.0 · owner: Site system lead · contract 19 of 20 points (open: figma)

Reference

Source reference; not an executed check.

--space-0
space.scale.0
--space-1
space.scale.1
--space-2
space.scale.2
--space-3
space.scale.3
--space-4
space.scale.4
--space-5
space.scale.5
--space-6
space.scale.6
--space-7
space.scale.7
--space-8
space.scale.8
--space-9
space.scale.9
--space-10
space.scale.10
--space-11
space.scale.11
--space-12
space.scale.12
--space-13
space.scale.13

Do and don't

2 positive / 2 negative authored documentation examples (2 each required); 1 reference (1 required); 0 failed. References and failures do not count; this is not behavior acceptance.

Do: The section owns one padding

Authored by spacing.ts

Rendered consumer example; not an executed correctness check. titled-section Isolated document follows the browser's colour and contrast preferences. The outer theme toolbar does not control this document.

Open example: Spacing and rhythm · Do: The section owns one padding Use the full-page example to follow page links.

The actual template supplies one declared section padding and native heading spacing; no empty paragraphs manufacture a visual gap.

Do: Use the recorded scale for a real gap

Authored by spacing.ts

Rule illustration; not an executed check. spacing / spacing.scale

A component declares its content gap from an existing --space-* semantic binding, such as var(--space-4).
The gap changes in the system rather than becoming a per-page pixel nudge.
This positive rule illustration explains the scale's use without pretending that a token-list row demonstrates physical spacing.

Don't: Empty paragraphs create section separation

Authored by spacing.ts

Rule illustration; not an executed check. spacing / spacing.one-padding

<p>The argument ends.</p><p>&nbsp;</p><p>&nbsp;</p><h2>The next section</h2>
Blank content substitutes for the owning template's spacing.
Content used as layout creates arbitrary rhythm and extra reading nodes instead of one declared template padding.

Don't: A one-off gap replaces the scale

Authored by spacing.ts

Rule illustration; not an executed check. spacing / spacing.scale

.local-heading-group { gap: 10px; }
The consumer inserts a raw off-scale value instead of its existing component binding.
The source proposal bypasses the recorded spacing decisions; this inert illustration does not run or claim a brand-gate result.

Rules

RuleWhyCheck
Spacing uses the scale tokens only.Consistent rhythm; the brand gate checks it.Automated: scripts/site/check-brand.ts
Each template has one padding, declared in its contract.Templates that each chose their own padding made the page lurch (D-SITE-005).Automated: scripts/site/system/check.ts (spacing point)

API

No props.

Contract details

The full contract: identity, anatomy, variants, states, tokens, layout, motion, accessibility, content, tests

Identity

AspectValue
Idspacing
LayerFoundations
Categoryfoundation
OwnerSite system lead
Statusstable
Version1.0.0
Sourceapps/showcase/site/system/foundations/spacing.ts (private repository; the contract and the render function are this one module)
VersionDateChange
1.0.02026-10-26Spacing and rhythm as one module: its markup moved out of the page builder (scripts/site) into the system.

Use when

  • Every gap, padding and margin. Why: A fixed scale makes the rhythm consistent across pages.

Do not use when

  • Pixel nudges. Why: An off-scale value is a one-off nobody can maintain.

Anatomy

PartWhat it is
scale--space-0 … --space-13
section--section: clamp(64 px, 10vw, 160 px)
rhythmOne padding per template (D-SITE-005)

Made of: nothing (a base element).

Used in: library-overview.

Variants

VariantWhenWhy
light and darkEvery page, following the reader's setting.The same roles resolve to light or dark values, so no element chooses its own.

States

StateRendered or not applicable
defaultThe specimen.
hoverNot applicable: A foundation is not interactive.
focus-visibleNot applicable: Not focusable.
activeNot applicable: Not interactive.
disabledNot applicable: Nothing to disable.
loadingNot applicable: Values are built into the stylesheet.
emptyNot applicable: The build fails if a value is missing.
errorNot applicable: Unresolved values fail the brand gate, not the reader.
currentNot applicable: No current item.
visitedNot applicable: Not a link.
expandedNot applicable: Does not open.

Tokens

PartToken
--space-*The scale
--sectionSection padding
--section-smSmaller section padding

Layout

AspectValue
breakpointsRequired review at 390, 768, 1024 and 1440 px; execution is not implied by this declaration; columns stack under 768 px; the wrap keeps a 16 px gutter on phones.
wrappingText wraps; nothing scrolls sideways.
textExpansionJapanese runs 20 to 40% longer; headings break between phrases (jaBreaks) and blocks grow downwards.

Spacing and rhythm

AspectValue
internalNot applicable: a foundation has no box of its own.
externalNot applicable.
rhythmApplies to every element that reads it.

Motion

AspectValue
NoneA foundation does not move.

Runtime and reuse

  1. Render-only element; mount any registered child enhancements separately. Preserve required Site CSS, fonts, responsive and locale rules from nativeElement.

Accessibility passport

AspectValue
roleNot rendered on the site; its specimen in the Library is a list
nameThe foundation's name
keyboardNot interactive.
focusNot focusable.
screenReaderThe specimen is a plain list of names and values.
contrastEvery text and ground pair in the palette is checked (check-brand).
targetNot a target.

Content

SlotLengthVoice
heading, body and action groups (consumer-owned)The consuming element's content budget, not a fixed-height text boxKeep a heading closer to its following text than the preceding section. Use the declared rhythm around meaningful groups rather than blank paragraphs or repeated spaces.
spacing token/value rows (fixed Library specimen)Every SPACE entry with its --space-* index; no editable propShow the native scale exactly. Token indices and values are technical reference content, not new spacing choices for one page.

Good: “One --section padding per template (spacing.one-padding / D-SITE-005)” · “An h2 with more space above than below (BRAND.md)”

Bad: “Empty paragraphs inserted to push the next heading down” · “A 10 px one-off gap between a heading and its copy (BRAND.md rejects off-scale spacing)”

Japanese: Japanese text retains the same spacing scale and section rhythm while its actual lines grow. Do not add spaces between Japanese characters or empty paragraphs to copy an English line height. Token identifiers stay unchanged; actual Japanese reflow and native review remain separate checks.

Icons and illustrations

None: this element uses no icon or illustration of its own.

Decisions and exceptions

Usage

23 owned-class occurrences in built pages plus metadata-token references in built CSS (measured by npm run site:system).

No application mechanism is declared.

Current check result: not assessed by this report. Declarations and source-file presence do not establish executed enforcement or accepted coverage.

Tests

AspectValue
unittests/unit/site-system.test.ts: renders every do and don't example through the registry and checks the classes it owns
visualNot yet: there are no screenshot baselines; the Library page is checked for sideways scroll at 1440 px by tests/site/system.spec.ts
a11ytests/site/system.spec.ts: axe (0 serious or critical) on the element's Library page in light and dark
parityscripts/site/system/check.ts: Library examples are rendered by the same render function the site imports

Figma

not-yet: The Loom Site Figma library is the last stage of the plan; this element is not mapped yet.

Open in Storybook

Start with a conversation about your system.

We read your system, show you what we found, and agree with your team what to fix first.