Skip to content

Colour

Every value below is bound to a variable — these are not pictures of the palette, they are the palette. Names are ramp + number: a number is a shared language, “Lightning Yellow” is not.

One grey ramp.

Token Value Its job
color/neutral/0 #ffffff page surface
color/neutral/100 #f2f2f2 wells
color/neutral/200 #dad9d9 borders
color/neutral/300 #b5b3b3 disabled only
color/neutral/400 #858080 subheading ink
color/neutral/500 #6c6666 derived
color/neutral/600 #544d4d muted text
color/neutral/700 #3b3333 derived
color/neutral/800 #231b1b inverse surface
color/neutral/900 #0b0202 default text
color/neutral/1000 #000000 masks, print

Persian Blue. 400 is the brand main.

Token Value Its job
color/blue/100 #e9e9fb accent bg
color/blue/200 #d4d3f7
color/blue/300 #6a66e4 subtitle ink
color/blue/400 #2b25d9 BRAND MAIN
color/blue/500 #221dad
color/blue/600 #110e56
color/blue/700 #0c0b41 table header

Alizarin Crimson. 400 is the logo fill.

Token Value Its job
color/red/100 #fce9e8 accent bg
color/red/200 #f9d3d2
color/red/300 #ec6663 subtitle ink
color/red/400 #e42521 BRAND MAIN
color/red/500 #b61d1a
color/red/600 #5b0e0d
color/red/700 #440b09 table header

Lightning Yellow. Never a text colour.

Token Value Its job
color/yellow/100 #fef9e9 accent bg
color/yellow/200 #fdf3d3
color/yellow/300 #fad567 too pale at 24px
color/yellow/400 #f9c426 BRAND MAIN
color/yellow/500 #c79c1e
color/yellow/600 #634e0f warning text
color/yellow/700 #4a3a0b table header

Not an accent.

Token Value Its job
color/green/100 #d4f2de success bg
color/green/400 #74af36 solid
color/green/600 #1a6b36 success text

Not an accent and not the brand red: color/red/400 is the brand, this is a failure. Three values, the ones the status/danger roles resolve to.

Token Value Its job
color/red/100 #fce9e8 danger bg
color/status/danger #da4144 solid
color/red/600 #5b0e0d danger text

Values with no ramp home, kept because each has exactly one job.

Token Value Its job
color/light-blue/100 #f2f2f7 THE card surface
color/status/danger #da4144 error state
color/gradient-stop/pink #f24288 gradient only
color/gradient-stop/orchid #ebb8fc gradient only
color/gradient-stop/magenta #d947d6 gradient only

Tier 2 — the roles a component binds to, never a ramp step. Every swatch is bound to its semantic variable and reads its alias live from the Primitives; the text roles are shown as ‘Aa’ on the ground they are read on.

Role Aliases Its job
text/default color/neutral/900 body and headings on light surfaces
text/muted color/neutral/600 secondary text
text/subtle color/neutral/400 subheadings at 24 px and over; captions read text/caption
text/on-accent color/neutral/0 on a filled accent
text/on-inverse color/neutral/0 on surface/inverse
text/link color/blue/400 links — brand blue in every accent mode
text/disabled color/neutral/300 the one job neutral/300 has
text/error color/red/400 field errors
text/caption color/neutral/600 captions, axes and placeholders
Role Aliases Its job
surface/page color/neutral/0 the ground
surface/card color/light-blue/100 #f2f2f7, not neutral/100 — two colours, two jobs
surface/sunken ground/sunken wells — neutral/100 on white, neutral/200 on surface/card
surface/inverse color/neutral/800 dark blocks — 800, not the text black
surface/slot color/neutral/0 the inversion rule: white on a card, card on the page
overlay/scrim color/alpha/neutral-800-50 behind a dialog, sheet or drawer
Role Aliases Its job
border/default color/neutral/200 cards and inputs
border/strong color/neutral/400 dividers that must be seen — decorative ones are banned
border/focus color/blue/300 the ring, every mode
border/error color/red/400 the error border and ring
Role Aliases Its job
action/primary/bg color/neutral/900 the black button
action/primary/bg-hover color/neutral/700 the black button’s hover
action/primary/fg color/neutral/0 the black button’s label
action/secondary/bg color/neutral/0 the outlined button
action/secondary/bg-hover color/neutral/100 its hover
action/secondary/fg color/neutral/900 its label
action/secondary/border color/neutral/200 its outline
action/disabled/bg color/neutral/100 disabled ground
action/disabled/fg color/neutral/300 disabled label
Role Aliases Its job
status/success/bg color/green/100 badge ground
status/success/fg color/green/600 badge text
status/success/solid color/green/400 dots and fills
status/danger/bg color/red/100 badge ground
status/danger/fg color/red/600 badge text — red/600, not the solid
status/danger/solid color/status/danger the one real #da4144
status/warning/bg color/yellow/100 badge ground
status/warning/fg color/yellow/600 badge text
status/warning/solid color/yellow/400 fills and icons, never text
status/info/bg color/blue/100 badge ground
status/info/fg color/blue/600 badge text
status/info/solid color/blue/400 the brand blue
Role Aliases Its job
tint/neutral/bg color/neutral/200 label ground
tint/neutral/fg color/neutral/600 label text
tint/blue/bg color/blue/200 label ground — the hue at 200, every mode
tint/blue/fg color/blue/300 label text — the hue at 300
tint/red/bg color/red/200 label ground
tint/red/fg color/red/300 label text — 2.3:1 on its tint, below the floor (open)
tint/yellow/bg color/yellow/300 label ground — 300, the one tone tinted one step up
tint/yellow/fg color/yellow/600 label text — yellow/600
tint/green/bg color/green/100 label ground — the success pair, its own role
tint/green/fg color/green/600 label text

Role-aware, not a cross-product: every row is a pair the system actually puts together, checked at the floor its role gets — 4.5 for body text under 24px, 3.0 for large text, 3.0 for icons and rings. 41 pass · 4 exempt with a recorded reason · 2 below the floor when copied — both neutral/400 at 15px caption size, since moved to their own role, text/caption.

Exempt, with the reason recorded in the matrix: disabled text (WCAG-exempt); the red subtitle on a card at 2.83 (an accepted exception, 6% under on one colour in one role); .icon-chip--soft in yellow (dead CSS nothing renders); the yellow icon-list glyph (the glyph always sits beside its own label). Below the floor: neutral/400 as a 15px caption ink, 3.89 on the page and 3.49 on a card — the same token passes as a 26px subheading; one token, two roles, two floors — so captions moved to their own role, text/caption, and neutral/400 keeps the subheading job at 24 px and over.

One accent per surface, all three across a document

Section titled “One accent per surface, all three across a document”

A surface takes its accent from the mode, and a component never chooses a hue — it binds a role and the mode resolves it. The four columns are one set of ten bindings, each column’s frame set to its mode; what differs between columns is the rule, not the component.

Role Its job
accent/main the hue itself — solid fills, the primary of a coloured card
accent/light the 300 step
accent/lighter the 200 step — soft chips
accent/bg the 100 step — tinted grounds
accent/dark the table header bar — grey in multicolor
accent/on-accent text and icons on main — ink on yellow (white on #f9c426 is 1.8:1)
accent/heading the subtitle — the light step, or neutral/400 on yellow and multicolor
accent/icon-ink the Icon list’s glyph, its only reader — the main hue on yellow, where the light step is too pale
accent/text the accent as ink on a light surface — the Insight block; ink on yellow
accent/pill-tint the Table’s row-header pill — grey in multicolor
Role blue red yellow multicolor
accent/main blue/400 red/400 yellow/400 red/400
accent/light blue/300 red/300 yellow/300 red/300
accent/lighter blue/200 red/200 yellow/200 red/200
accent/bg blue/100 red/100 yellow/100 red/100
accent/dark blue/700 red/700 yellow/700 neutral/800
accent/on-accent neutral/0 neutral/0 neutral/900 neutral/0
accent/heading blue/300 red/300 neutral/400 neutral/400
accent/icon-ink blue/300 red/300 yellow/400 red/300
accent/text blue/400 red/400 neutral/900 red/400
accent/pill-tint blue/200 red/200 yellow/300 neutral/200

Two things never follow the accent: a link (text/link — the brand blue in every mode) and the focus ring (border/focus, blue/300), because a link and a ring have to stay recognisable on a red or yellow slide. Multicolor is solid red for any single-accent element; its charts cycle the three hues, its table goes grey. Yellow is never text at its main step — every text-shaped role flips to ink or grey there, which is why on-accent, heading and text exist per mode at all. A component that needs a colour the ten roles do not give has found a missing role, not a reason for a hex: add it to tokens/semantic.json accent.*, rebuild, then bind.

The same page in the Figma library: Colour.

Pepper UI v1.5.0

The Mobupps design system. 386 tokens, 88 components, 65 pages in the workshop — every page of this site generated from the repository, so nothing here is typed twice.