Semantic tokens

The site's roles (48 colour roles plus type, space, layout, radius, rule, motion), each a path into Loom Base, resolved into 350 CSS variables.

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

Reference

Source reference; not an executed check.

--cotton
#f3eee3
--surface
#fbf8f1
--surface-2
#ebe4d6
--surface-3
#e2d9c8
--ink
#17140f
--ink-2
#4a443a
--line
#d1c6b2
--line-strong
#716856
--focus
#1e2a78
--link
#1e2a78
--indigo
#1e2a78
--madder
#b02a1e
--saffron
#e9a21b
--teal
#0b6b66
--field-ink
#17140f
--on-dye
#f3eee3
--on-dye-2
#e2d9c8
--on-saffron
#17140f
--on-saffron-2
#26221c
--indigo-ink
#1e2a78
--madder-ink
#b02a1e
--teal-ink
#0b6b66
--saffron-ink
#7a5206
--indigo-2
#6f7fe0
--madder-2
#d4574a
--saffron-2
#f3bb4c
--teal-2
#1d948c
--indigo-soft
#eceefa
--madder-soft
#fbecea
--saffron-soft
#fdf4e1
--teal-soft
#e3f3f1
--band-woven
#1e2a78
--band-holding
#0b6b66
--band-shape
#9e6b08
--band-loose
#b02a1e
--ai
#826bab
--ai-ink
#4d386f
--term-bg
#17140f
--term-fg
#ebe4d6
--term-muted
#b3a892
--term-accent
#c3c9ef
--term-add
#94d1ca
--term-del
#efb3ab
--sample-1
#0d1c58
--sample-2
#3f6bdc
--sample-3
#f5ab77
--sample-4
#f6f1e7
--sample-on
#ffffff
--font-display
Archivo, "Archivo Wide Fallback", "Noto Sans JP", "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Yu Gothic UI", "Yu Gothic", Meiryo, system-ui, sans-serif
--font-text
"Loom Figures", "Atkinson Hyperlegible Next", "Atkinson Fallback", "Noto Sans JP", "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Yu Gothic UI", "Yu Gothic", Meiryo, system-ui, sans-serif
--font-mono
"Martian Mono", ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace
--font-display-ja
"Loom JP Display", "Noto Sans JP", "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Yu Gothic UI", "Yu Gothic", Meiryo, sans-serif
--font-sample
"Helvetica Neue", "Segoe UI", Arial, "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Noto Sans JP", "Yu Gothic", Meiryo, system-ui, sans-serif
--fs-display
clamp(2.25rem, 7.2vw, 6rem)
--fs-h2
clamp(1.875rem, 4.4vw, 3.5rem)
--fs-h3
clamp(1.25rem, 1.2rem + .4vw, 1.5rem)
--fs-body
clamp(1rem, .95rem + .2vw, 1.125rem)
--fs-small
0.875rem
--fs-label
0.75rem
--type-display
expanded 900 var(--fs-display)/0.9 var(--font-display)
--ls-display
-0.02em
--type-h1
expanded 900 var(--fs-display)/0.9 var(--font-display)
--ls-h1
-0.02em
--type-h2
expanded 800 var(--fs-h2)/1 var(--font-display)
--ls-h2
-0.02em
--type-h3
semi-expanded 800 var(--fs-h3)/1.2 var(--font-display)
--ls-h3
-0.01em
--type-lede
normal 400 var(--fs-h3)/1.4 var(--font-text)
--ls-lede
0em
--type-body
normal 400 var(--fs-body)/1.6 var(--font-text)
--ls-body
0em
--type-strong
normal 700 var(--fs-body)/1.4 var(--font-text)
--ls-strong
0em
--type-small
normal 400 var(--fs-small)/1.5 var(--font-text)
--ls-small
0em
--type-small-strong
normal 700 var(--fs-small)/1.4 var(--font-text)
--ls-small-strong
0em
--type-label
normal 600 var(--fs-label)/1.4 var(--font-mono)
--ls-label
0em
--type-figure
normal 500 var(--fs-small)/1.6 var(--font-mono)
--ls-figure
0em
--weight-strong
700
--weight-heavy
800
--space-0
0px
--space-1
2px
--space-2
4px
--space-3
6px
--space-4
8px
--space-5
12px
--space-6
16px
--space-7
20px
--space-8
24px
--space-9
32px
--space-10
40px
--space-11
48px
--space-12
64px
--space-13
80px
--columns
12
--w-max
1240px
--w-text
720px
--w-narrow
560px
--gutter
16px
--grid-gap
24px
--header-h
64px
--section
clamp(48px, 5vw, 72px)
--radius
2px
--radius-round
9999px
--radius-sample
6px
--rule-hair
2px
--rule
4px
--rule-frame
6px
--rule-heavy
8px
--shadow-float
0px 16px 48px 0px #13110f1f
--ease-standard
cubic-bezier(0.2, 0, 0, 1)
--ease-enter
cubic-bezier(0, 0, 0, 1)
--ease-exit
cubic-bezier(0.3, 0, 1, 1)
--dur-fast
100ms
--dur-moderate
160ms
--dur-slow
240ms
--dur-weave
360ms
--stagger
60ms
--selvedge-row
6px
--selvedge-square
12px
--selvedge-height
18px
--header-h
80px
--gutter
40px
--grid-gap
32px
--cotton
#17140f
--surface
#26221c
--surface-2
#0d0b08
--surface-3
#38332b
--ink
#ebe4d6
--ink-2
#b3a892
--line
#38332b
--line-strong
#8f8571
--focus
#9aa5e6
--link
#9aa5e6
--field-ink
#0d0b08
--indigo-ink
#9aa5e6
--madder-ink
#e3877a
--teal-ink
#94d1ca
--saffron-ink
#f3bb4c
--indigo-soft
#151d55
--madder-soft
#4c110b
--saffron-soft
#3a2603
--teal-soft
#042a28
--ai
#a18bca
--ai-ink
#dfd0ff
--term-bg
#0d0b08
--shadow-float
0px 16px 48px 0px #00000099
--cotton
#17140f
--surface
#26221c
--surface-2
#0d0b08
--surface-3
#38332b
--ink
#ebe4d6
--ink-2
#b3a892
--line
#38332b
--line-strong
#8f8571
--focus
#9aa5e6
--link
#9aa5e6
--field-ink
#0d0b08
--indigo-ink
#9aa5e6
--madder-ink
#e3877a
--teal-ink
#94d1ca
--saffron-ink
#f3bb4c
--indigo-soft
#151d55
--madder-soft
#4c110b
--saffron-soft
#3a2603
--teal-soft
#042a28
--ai
#a18bca
--ai-ink
#dfd0ff
--term-bg
#0d0b08
--shadow-float
0px 16px 48px 0px #00000099
--cotton
#ffffff
--surface
#ffffff
--surface-2
#ebe4d6
--surface-3
#e2d9c8
--ink
#000000
--ink-2
#26221c
--line
#38332b
--line-strong
#000000
--focus
#000000
--link
#1e2a78
--indigo
#151d55
--madder
#6e1810
--saffron
#e9a21b
--teal
#063e3b
--field-ink
#000000
--on-dye
#ffffff
--on-dye-2
#ffffff
--on-saffron
#000000
--on-saffron-2
#000000
--indigo-ink
#1e2a78
--madder-ink
#b02a1e
--teal-ink
#0b6b66
--saffron-ink
#7a5206
--indigo-2
#6f7fe0
--madder-2
#d4574a
--saffron-2
#f3bb4c
--teal-2
#1d948c
--indigo-soft
#eceefa
--madder-soft
#fbecea
--saffron-soft
#fdf4e1
--teal-soft
#e3f3f1
--band-woven
#151d55
--band-holding
#063e3b
--band-shape
#7a5206
--band-loose
#6e1810
--ai
#372553
--ai-ink
#24143a
--term-bg
#17140f
--term-fg
#ebe4d6
--term-muted
#b3a892
--term-accent
#c3c9ef
--term-add
#94d1ca
--term-del
#efb3ab
--sample-1
#0d1c58
--sample-2
#3f6bdc
--sample-3
#f5ab77
--sample-4
#f6f1e7
--sample-on
#ffffff
--shadow-float
0px 16px 48px 0px #13110f1f
--identity-art-ink
var(--ink)
--identity-art-lettering
var(--font-display)
--identity-art-indigo
var(--indigo-ink)
--identity-art-teal
var(--teal-ink)
--identity-art-saffron
var(--saffron)
--identity-art-madder
var(--madder-ink)
--identity-art-seam
var(--cotton)
--identity-art-duration
var(--dur-weave)
--identity-art-easing
var(--ease-standard)
--identity-sticker-surface
var(--cotton)
--identity-sticker-ink
var(--ink)
--identity-sticker-on-ink
var(--cotton)
--identity-sticker-lettering
var(--font-display)
--identity-sticker-cutout
var(--on-dye)
--identity-sticker-fixed-ink
var(--field-ink)
--identity-sticker-mark-indigo
var(--indigo-ink)
--identity-sticker-mark-madder
var(--madder-ink)
--identity-sticker-mark-teal
var(--teal-ink)
--identity-sticker-on-dye
var(--on-dye)
--identity-sticker-on-saffron
var(--on-saffron)
--identity-sticker-indigo
var(--indigo)
--identity-sticker-madder
var(--madder)
--identity-sticker-saffron
var(--saffron)
--identity-sticker-teal
var(--teal)
--identity-sticker-caption
var(--type-small)
--identity-sticker-gap
var(--space-4)
--identity-motion-surface
var(--cotton)
--identity-motion-ink
var(--ink)
--identity-motion-ink-muted
var(--ink-2)
--identity-motion-control-surface
var(--surface)
--identity-motion-control-hover
var(--surface-2)
--identity-motion-line
var(--line-strong)
--identity-motion-rule
var(--rule-hair)
--identity-motion-focus-width
var(--rule)
--identity-motion-focus
var(--focus)
--identity-motion-focus-offset
var(--space-2)
--identity-motion-title
var(--type-h3)
--identity-motion-caption
var(--type-small)
--identity-motion-mono
var(--font-mono)
--identity-motion-accent
var(--indigo-ink)
--identity-motion-route
var(--madder-ink)
--identity-motion-gap
var(--space-4)
--identity-motion-gap-small
var(--space-3)
--identity-motion-gap-section
var(--space-6)
--identity-motion-padding
var(--space-8)
--identity-motion-scene-space
var(--space-9)
--identity-motion-status-gap
var(--space-5)
--identity-motion-target
var(--space-11)
--identity-motion-scene-unit
var(--space-13)
--identity-motion-duration
var(--dur-weave)
--identity-motion-easing
var(--ease-standard)
--identity-playground-label
var(--type-label)
--identity-playground-tracking
var(--ls-label)
--identity-playground-gap-caption
var(--space-5)
--identity-playground-surface
var(--cotton)
--identity-playground-ink
var(--ink)
--identity-playground-ink-muted
var(--ink-2)
--identity-playground-line
var(--line-strong)
--identity-playground-rule
var(--rule-hair)
--identity-playground-link
var(--link)
--identity-playground-caption
var(--type-small)
--identity-playground-title
var(--type-h3)
--identity-playground-gap
var(--space-6)
--identity-playground-gap-small
var(--space-3)
--identity-playground-padding
var(--space-8)
--identity-playground-margin
var(--space-9)
--identity-playground-target
var(--space-11)
--identity-playground-focus
var(--focus)
--identity-playground-focus-width
var(--rule)
--identity-playground-focus-offset
var(--space-2)
--identity-playground-gap-medium
var(--space-4)
--state-badge-field-ink
var(--field-ink)
--state-badge-padding-large
var(--space-6)
--state-badge-mark-large
var(--space-12)
--state-badge-surface
var(--cotton)
--state-badge-ink
var(--ink)
--state-badge-healthy
var(--teal-ink)
--state-badge-attention
var(--saffron)
--state-badge-broken
var(--madder-ink)
--state-badge-action
var(--indigo-ink)
--state-badge-gap
var(--space-4)
--state-badge-caption
var(--type-small)
--state-badge-mark
var(--space-11)
--state-badge-rule
var(--rule-hair)
--state-badge-line
var(--line-strong)
--state-badge-padding
var(--space-5)
--job-map-gap-medium
var(--space-5)
--job-map-mark
var(--type-h2)
--job-map-surface
var(--cotton)
--job-map-ink
var(--ink)
--job-map-see
var(--teal-ink)
--job-map-shape
var(--madder-ink)
--job-map-govern
var(--saffron-ink)
--job-map-run
var(--indigo-ink)
--job-map-gap
var(--space-6)
--job-map-margin
var(--space-8)
--job-map-gap-small
var(--space-4)
--job-map-title
var(--type-h3)
--job-map-caption
var(--type-small)
--job-map-rule
var(--rule-hair)
--job-map-line
var(--line-strong)
--job-map-target
var(--space-11)
--job-map-focus
var(--focus)
--job-map-focus-width
var(--rule)
--job-map-focus-offset
var(--space-2)
--atomic-guide-preview-min-width
var(--w-text)
--atomic-guide-cotton
var(--cotton)
--atomic-guide-surface
var(--surface)
--atomic-guide-ink
var(--ink)
--atomic-guide-ink-muted
var(--ink-2)
--atomic-guide-line
var(--line)
--atomic-guide-line-strong
var(--line-strong)
--atomic-guide-rule
var(--rule-hair)
--atomic-guide-gap
var(--space-6)
--atomic-guide-gap-small
var(--space-3)
--atomic-guide-gap-medium
var(--space-4)
--atomic-guide-margin
var(--space-9)
--atomic-guide-title
var(--type-h3)
--atomic-guide-caption
var(--type-small)
--atomic-guide-link
var(--link)
--atomic-guide-target
var(--space-11)
--atomic-guide-indigo
var(--indigo)
--atomic-guide-teal
var(--teal)
--atomic-guide-saffron
var(--saffron)
--atomic-guide-madder
var(--madder)
--atomic-guide-focus
var(--focus)
--atomic-guide-focus-width
var(--rule)
--atomic-guide-focus-offset
var(--space-2)

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: A reading role travels through native Text

Authored by tokens.ts

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

Open example: Semantic tokens · Do: A reading role travels through native Text Use the full-page example to follow page links.

The native consumer resolves the existing reading context; the separate generated-variable list is a source reference, not an effective-mode inspector.

Do: An action uses its existing role bindings

Authored by tokens.ts

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

Open example: Semantic tokens · Do: An action uses its existing role bindings Use the full-page example to follow page links.

The native action reaches semantic colour/type/spacing through its actual component bindings rather than a page-defined role.

Don't: A generated role is edited by hand

Authored by tokens.ts

Rule illustration; not an executed check. tokens-semantic / tokens.generated

Edit --cotton directly in apps/showcase/site/brand/tokens.css after generation.
Leave brand.ts and the underlying token authority unchanged.
The next build would overwrite the unreviewed fork; proposed role changes belong in their actual source and generation workflow.

Don't: A private page-local role bypasses the source

Authored by tokens.ts

Rule illustration; not an executed check. tokens-semantic / tokens.generated

Append a new page-only semantic role to generated tokens.css by hand.
Its purpose, source mapping and supported modes are absent from brand.ts.
A generated output cannot become a second role catalogue; a local addition would have no maintained source identity.

Rules

RuleWhyCheck
tokens.css is generated; never edited by hand.The CSS must match the brand data and Loom Base.Automated: npm run site:build (regenerates tokens.css)

API

No props.

Contract details

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

Identity

AspectValue
Idtokens-semantic
LayerTokens
Categorytokens
OwnerSite system lead
Statusstable
Version1.0.0
Sourceapps/showcase/site/system/tokens/tokens.ts (private repository; the contract and the render function are this one module)
VersionDateChange
1.0.02026-10-26Semantic tokens as one module: its markup moved out of the page builder (scripts/site) into the system.

Use when

  • Component-token bindings and product composition. Why: MVDS §5.1 requires components to consume their component tier. Scoped component bindings retain the same semantic defaults at their actual selector and state; source agreement and rendered checks remain separate obligations.

Do not use when

  • Defining a role inside an element. Why: Roles change in brand.ts, for every element at once.

Anatomy

PartWhat it is
rolesapps/showcase/site/brand/brand.ts
outputapps/showcase/site/brand/tokens.css (generated by scripts/site/brand-tokens.ts)

Made of: tokens-primitive.

Used in: tokens-component.

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
--cotton#f3eee3
--surface#fbf8f1
--surface-2#ebe4d6
--surface-3#e2d9c8
--ink#17140f
--ink-2#4a443a
--line#d1c6b2
--line-strong#716856
--focus#1e2a78
--link#1e2a78

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
specimen: CSS role and resolved valueGenerated role/value pairs from tokens.css; no hand-edited output or new element-local role.Name the role's purpose and preserve its source identity.

Good: “A component background alias reads the existing semantic cotton role.”

Bad: “Edit the generated --cotton value in tokens.css for one page.”

Japanese: CSS identifiers and source paths are locale independent. Translate role explanations; Japanese typography uses the existing named language rules, not renamed tokens.

Icons and illustrations

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

Decisions and exceptions

  • None.

Usage

640 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.