Colors

Two layers, like Material 3. Tonal scales are the raw paint. Semantic roles say what a color is for. Components only ever use roles, so you can retheme by remapping roles without touching a single component.

Semantic roles

Every role ships as four tokens: the color, on- (text on it), -container (a soft tint) and on-*-container.

primary
primary-container

Main actions, active states. Coral.

secondary
secondary-container

Supporting actions, links. Blue.

tertiary
tertiary-container

Highlights and special moments. Grape.

accent
accent-container

Playful pops, celebratory states. Lime.

Status

success
success-container

Completed, saved, live.

warning
warning-container

Needs attention, not broken.

danger
danger-container

Destructive or failed.

info
info-container

Neutral announcements.

Surfaces

Clay is about depth, so surfaces are defined by elevation, not by color alone. In dark mode raised surfaces get lighter and wells get darker, so depth still reads.

backgroundPage canvas
surfaceRaised: cards, navbar, sidebar
surface-sunkenWells: inputs, tab tracks
surface-inverseCode blocks, tooltips

Usage

Pick a role with color, and an emphasis with variant.

primarysoft primarysuccesssoft warning
<Button color="primary">Save</Button>
<Button variant="soft" color="danger">Delete</Button>
<Badge variant="soft" color="success">Live</Badge>

{/* Or straight from Tailwind */}
<div className="bg-primary-container text-on-primary-container" />

Tonal scales

Generated in OKLCH by scripts/palette.mjs. The brand hex is pinned to its step (marked ●) and the rest is interpolated, so scales stay perceptually even. Use them as bg-coral-200 etc.

coral
50
100
200
300
400
●
500
600
700
800
900
950
blue
50
100
200
300
400
●
500
600
700
800
900
950
lime
50
100
200
300
●
400
500
600
700
800
900
950
grape
50
100
200
300
400
●
500
600
700
800
900
950
sun
50
100
200
300
●
400
500
600
700
800
900
950
clay
50
100
200
300
400
500
600
700
800
●
900
950

Contrast

Every pair is checked by scripts/contrast.mjs against WCAG 2. Light and dark themes are both audited. One deliberate call: text on coral is dark clay, because white on our coral is only 2.95:1.

ThemeSamplePairRatioWCAG
lightAaprimary / on-primary5.71AA
lightAaprimary-container / on-primary-container7.27AAA
lightAasecondary / on-secondary5.85AA
lightAasecondary-container / on-secondary-container8.05AAA
lightAatertiary / on-tertiary5.58AA
lightAatertiary-container / on-tertiary-container8.04AAA
lightAaaccent / on-accent9.75AAA
lightAaaccent-container / on-accent-container6.99AA
lightAasuccess / on-success4.90AA
lightAasuccess-container / on-success-container6.99AA
lightAawarning / on-warning8.27AAA
lightAawarning-container / on-warning-container7.04AAA
lightAadanger / on-danger6.16AA
lightAadanger-container / on-danger-container10.42AAA
lightAainfo / on-info5.85AA
lightAainfo-container / on-info-container8.05AAA
lightAabackground / on-surface13.75AAA
lightAasurface / on-surface14.57AAA
lightAasurface / on-surface-muted5.76AA
lightAasurface-sunken / on-surface12.08AAA
lightAasurface-sunken / on-surface-muted4.78AA
lightAasurface-inverse / on-surface-inverse13.75AAA
darkAaprimary / on-primary5.71AA
darkAaprimary-container / on-primary-container9.10AAA
darkAasecondary / on-secondary5.46AA
darkAasecondary-container / on-secondary-container8.32AAA
darkAatertiary / on-tertiary5.66AA
darkAatertiary-container / on-tertiary-container8.32AAA
darkAaaccent / on-accent11.30AAA
darkAaaccent-container / on-accent-container10.43AAA
darkAasuccess / on-success7.88AAA
darkAasuccess-container / on-success-container10.43AAA
darkAawarning / on-warning9.58AAA
darkAawarning-container / on-warning-container9.85AAA
darkAadanger / on-danger7.23AAA
darkAadanger-container / on-danger-container9.10AAA
darkAainfo / on-info5.46AA
darkAainfo-container / on-info-container8.32AAA
darkAabackground / on-surface16.68AAA
darkAasurface / on-surface15.03AAA
darkAasurface / on-surface-muted7.85AAA
darkAasurface-sunken / on-surface17.66AAA
darkAasurface-sunken / on-surface-muted9.21AAA
darkAasurface-inverse / on-surface-inverse18.05AAA