Dye field

A full-bleed block of one dye (indigo, madder, saffron, teal), ink or the quiet band. It carries section identity; every template that stands on colour uses it.

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

Do and don't

Do: Saffron call to action

Rendered by dye-field.ts

Open example: Dye field · Do: Saffron call to action Use the full-page example to follow page links.

Saffron always means the one action.

Do: Ink founder field

Rendered by dye-field.ts

Open example: Dye field · Do: Ink founder field Use the full-page example to follow page links.

Ink for who we are.

Don't: A red field for an error

Rendered by dye-field.ts

Open example: Dye field · Don't: A red field for an error Use the full-page example to follow page links.

States are marks with words; a field is structure.

Don't: Two fields touching

Rendered by dye-field.ts

Open example: Dye field · Don't: Two fields touching Use the full-page example to follow page links.

A field is always followed by cotton.

Rules

RuleWhyCheck
A dye or ink field is always followed by cotton; two fields never touch. The four-jobs band is one template (a grid of dye tiles inside the hero), so it counts as one field.Adjacent fields blur into one block and the page loses its rhythm; the tiles of one band are one piece of structure, not four sections.Automated: scripts/site/system/check-pages.ts (adjacent fields)
Text on a field uses the field's own tokens.Each field's text colour is chosen for 4.5:1 or better.Automated: npm run site:brand (check-brand contrast)

API

PropTypeRequiredDefaultWhat it does
colourindigo | madder | saffron | teal | ink | quietYesThe field's colour.
htmlhtmlYesWhat stands on the field.
tagdiv | sectionNo"div"The wrapping element.

Contract details

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

Identity

AspectValue
Iddye-field
LayerTemplates
Categoryground
OwnerSite system lead
Statusstable
Version1.0.0
Sourceapps/showcase/site/system/templates/dye-field.ts (private repository; the contract and the render function are this one module)
VersionDateChange
1.0.02026-10-26Dye field as one module: its markup moved out of the page builder (scripts/site) into the system.

Use when

  • The hero, page heads, the lead, the founder and the call to action. Why: Colour as structure: a field tells the reader a new part of the argument starts (D-SITE-004).

Do not use when

  • Directly after another field. Why: Two fields touching read as one muddy block; a field is always followed by cotton (D-SITE-002).
  • To show a state. Why: States are small marks with their word, never a field.

Anatomy

PartWhat it is
rootAny block with the field-<colour> class
textText inside uses the field's own --field-fg and --field-fg-2 tokens

Made of: tokens:colour.

Used in: library-overview, roles-grid, tile, cta-section, founder-section, hero, lead-section, page-head, persona-strip.

Variants

VariantWhenWhy
indigoThe hero and Product pages.Indigo is the brand's lead colour.
madderSolutions and roles; the 404.A warm field for people and problems.
saffronThe call to action and Demos.The one action colour: the reader learns saffron means 'do this'.
tealThe UX Ops lead, Resources and articles.The calm field for learning.
inkThe founder and Company.The quiet authority of ink for who we are.
quietThe persona strip.A tinted band that is not a dye, so it may sit near a field.

States

StateRendered or not applicable
defaultdefault
hoverNot applicable: The dye field is not interactive, so it has no hover state.
focus-visibleNot applicable: The dye field does not take focus; links and buttons inside it carry their own focus ring.
activeNot applicable: The dye field cannot be pressed.
disabledNot applicable: The dye field has nothing to disable.
loadingNot applicable: The dye field is rendered at build time and is complete when the page loads.
emptyNot applicable: The dye field is not rendered without content; the builder skips it.
errorNot applicable: The dye field shows no data that can fail.
currentNot applicable: The dye field has no current item.
visitedNot applicable: The dye field is not a link.
expandedNot applicable: The dye field does not open or close.

Tokens

PartToken
root.background--field-bg (from the dye's primitive)
text.color--field-fg; secondary --field-fg-2
link.color--field-link

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
internalSet by the template that uses it.
externalFull bleed: no margin.
rhythmField, then cotton (D-SITE-002).

Motion

AspectValue
NoneNo intrinsic element animation. The optional claude-entrance consumer profile may translate below-fold structure once (20px, --dur-weave, --ease-enter, --stagger); reduced motion disables it. This preserved baseline entrance is separate from element playback.

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
roleregion (section) named by its heading
nameIts h2, by aria-labelledby
keyboardLinks and buttons inside, in reading order.
focusThe --focus ring on every link and button inside.
screenReaderRead in source order; decorative weaving is aria-hidden.
contrastInk on cotton 14:1; text on every dye field 4.5:1 or better (checked by check-brand).
targetLinks and buttons are 44 px tall.

Content

SlotLengthVoice
htmlAs the templateAs the template

Good: “The hero on indigo”

Bad: “A status shown as a red field”

Japanese: No text of its own.

Icons and illustrations

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

Decisions and exceptions

Usage

496 uses across the built pages (measured by npm run site:system).

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.