Brik Design System
Foundation

Color

Semantic color tokens, interaction states, status colors, and the primitive palettes they reference.

Color tokens define the visual identity across all BDS themes. The system separates primitive color scales (raw hex values) from semantic color roles (purpose-bound aliases). Components reference the semantic roles only.

Never use a token outside its semantic category. --text-* is for text. --background-* is for backgrounds. --border-* is for borders. No --text-primary on a background-color. The cascade is a contract — bypassing it leaks brand drift everywhere it isn't caught.

Click any swatch to copy var(--token-name) to your clipboard.

Page and surface

page-primary
...
page-secondary
...
page-brand-primary
...
surface-primary
...
surface-secondary
...
surface-muted
...
surface-brand-primary
...

Background

background-brand-primary
...
background-brand-secondary
...
background-primary
...
background-secondary
...
background-inverse
...
background-input
...
background-muted
...

Text

Aa
text-primary
...
Aa
text-secondary
...
Aa
text-muted
...
Aa
text-brand-primary
...
Aa
text-inverse
...
Aa
text-on-color-dark
...
Aa
text-on-color-light
...

Border

border-primary
...
border-secondary
...
border-muted
...
border-brand-primary
...
border-input
...
border-inverse
...

Interaction states

Hover, press, and disabled. These replace filter: brightness() and opacity hacks — the proper tokens compose with the rest of the cascade.

background-brand-primary-hover
...
background-brand-primary-pressed
...
background-primary-hover
...
background-primary-pressed
...
background-secondary-hover
...
background-secondary-pressed
...
background-disabled
...
Aa
text-disabled
...
border-disabled
...

Status

Canonical Figma tokens for positive, negative, and warning states. Background variants are saturated; surface variants are subtle tints.

background-positive
...
background-negative
...
background-warning
...
surface-positive
...
surface-negative
...
surface-warning
...
Aa
text-positive
...
Aa
text-negative
...
Aa
text-warning
...
border-positive
...
border-negative
...
border-warning
...

The info signal — blue, and one of the five valence values. It came from Figma under the status- segment until #1959 freed the name: the gray family that used to hold --*-info is now --*-neutral, so info means blue and only blue. The --*-status-info* spellings still resolve as deprecated aliases for one minor (#1958 deletes them). There is no --border-info — the gray one retired with the rename and blue has no border counterpart.

background-info
...
surface-info
...
Aa
text-info
...

The neutral intent family — gray, Figma-sourced across all four purposes since #1959. Note the purpose split the rename made honest: --background-neutral is the saturated charcoal, --surface-neutral the subtle tint. A gray Badge or Tag chip wants --surface-neutral.

background-neutral
...
surface-neutral
...
Aa
text-neutral
...
border-neutral
...

Hues with no valencepurple and orange are hue names, not valence values, so ADR-033 § 1's five words have no slot for them. They belong to the hue-source scope documented under Accent below and are Figma-sourced there, so #1958 retired the --background-status-{purple,orange} spellings into it rather than amending the ADR.

background-accent-purple
...
background-accent-orange
...

Accent

The scope-stable accent — one brand highlight that stays fixed regardless of [data-audience] scope (brik fills it from tan; each Brand Kit fills its own). Use it for audience-independent affordances such as an active carousel dot or an eyebrow rule.

It is distinct from two neighbours it is easy to confuse:

  • --*-brand-primary re-tints per audience scope (Vale: land → gold, healthcare → olive). The accent must not shift, so it is its own role — not a brand-tier token.
  • The per-color status accents (--background-accent-blue, --text-accent-green, …) encode state/category, not the brand highlight.
page-accent
...
surface-accent
...
background-accent
...
Aa
text-accent
...
border-accent
...

Brand Kits fill --*-accent per client (brik → tan, Vale Partners → gold). Because the audience scopes re-bind only the brand-primary tier, the accent stays constant across every [data-audience] — that scope-stability is the whole point of the role.

Presence

Online/offline indicator tokens used by Avatar and Dot components.

presence-online
...
presence-away
...
presence-busy
...
presence-offline
...

The 11-step scale

Every family is an 11-step numeric ramp50, 100, 200, … 900, 950, lightest to darkest. 50 and 950 bracket the ends; the middle nine carry the working values. The scale is generated, not hand-tuned per family: scripts/generate-color-ramps.mjs pins the six historical swatches as anchors and interpolates the other five stops as OKLCh midpoints, writing design-tokens/color-ramps.generated.json (#1737). Shipped in v0.152.0.

Reach for a stop by its number. --color-{family}-{stop} is the Primitive-tier name; components still consume Semantic tokens only.

Deprecated 6-step aliases

The old ladder (lightest → lighter → light → dark → darker → darkest) still resolves — #1739 aliased each name onto its stop so nothing broke on upgrade. The aliases are deprecated and land at these positions in every family:

Deprecated aliasResolves toAnchor?
--color-{family}-lightest100anchor
--color-{family}-lighter300anchor
--color-{family}-light500anchor
--color-{family}-dark700anchor
--color-{family}-darker800anchor
--color-{family}-darkest950anchor

Note the ladder was never evenly spaced: dark and darker sit one stop apart (700/800) while darker to darkest skips 900. Prose that said "one step deeper" under the 6-step names does not translate to one numeric stop — count stops, don't translate names.

Don't write a deprecated alias into new code. npm run lint-mdx-tokens fails the build on one in a docs code block or table, and lint-tokens Rule 12 covers component CSS. Consumer migration is tracked in #1740; the aliases are removed only once it closes.

The two new stops that matter

Five stops per family are new. Two of them close specific, filed gaps:

StopValueWhy it exists
--color-poppy-600#c944284.84:1 on white — clears AA (4.5:1). The near-Poppy step ADR-015/ADR-016 said did not exist, unblocking #479
--color-grayscale-400#b0b0b0Fills the #828282#e0e0e0 gap from #1726. It is not #bdbdbd — no even OKLCh ramp lands there, so consumers that hand-pinned #bdbdbd are migrating to this value, not matching it

Primitives

Raw color scales from the Figma Brand Kit, rendered from color-ramps.generated.json. Components reference these via semantic tokens — never directly. The primitives change rarely; the semantic mappings change per theme.

Grayscale

--color-grayscale-50
#f8f8f8
--color-grayscale-100
#f2f2f2
--color-grayscale-200
#e9e9e9
--color-grayscale-300
#e0e0e0
--color-grayscale-400
#b0b0b0
--color-grayscale-500
#828282
--color-grayscale-600
#6e6e6e
--color-grayscale-700
#5a5a5a
--color-grayscale-800
#333333
--color-grayscale-900
#272727
--color-grayscale-950
#1b1b1b

Poppy (brand primary)

--color-poppy-50
#fff7f5
--color-poppy-100
#ffefeb
--color-poppy-200
#ffccc0
--color-poppy-300
#ffa693
--color-poppy-400
#f27e66
--color-poppy-500
#e35335
--color-poppy-600
#c94428
--color-poppy-700
#b0351b
--color-poppy-800
#7d1d09
--color-poppy-900
#631503
--color-poppy-950
#4a0d00

Tan

--color-tan-50
#f8f7f5
--color-tan-100
#f1f0ec
--color-tan-200
#e0ded8
--color-tan-300
#cfcdc5
--color-tan-400
#bebbb2
--color-tan-500
#adaaa0
--color-tan-600
#9c998e
--color-tan-700
#8b887d
--color-tan-800
#69665c
--color-tan-900
#58554c
--color-tan-950
#47453c

Orange

--color-orange-50
#fff4ee
--color-orange-100
#ffe8dc
--color-orange-200
#ffccb6
--color-orange-300
#ffad92
--color-orange-400
#f48865
--color-orange-500
#e76134
--color-orange-600
#cd5127
--color-orange-700
#b4411a
--color-orange-800
#812608
--color-orange-900
#5f1b02
--color-orange-950
#3f1000

Yellow

--color-yellow-50
#fffff0
--color-yellow-100
#fffee1
--color-yellow-200
#fef6c7
--color-yellow-300
#ffecac
--color-yellow-400
#f9e08a
--color-yellow-500
#f4d364
--color-yellow-600
#dabb53
--color-yellow-700
#c1a443
--color-yellow-800
#8e7729
--color-yellow-900
#795e1f
--color-yellow-950
#634716

Green

--color-green-50
#fcfff9
--color-green-100
#f8fff3
--color-green-200
#eaffda
--color-green-300
#daffc0
--color-green-400
#ccffa8
--color-green-500
#bcff8c
--color-green-600
#abec7c
--color-green-700
#9ada6c
--color-green-800
#71a74a
--color-green-900
#437f4e
--color-green-950
#2a5542

Blue

--color-blue-50
#fcfeff
--color-blue-100
#f8fdff
--color-blue-200
#d6f0fa
--color-blue-300
#b2e3f5
--color-blue-400
#a0cfe0
--color-blue-500
#8ebbcc
--color-blue-600
#7da8b7
--color-blue-700
#6c95a3
--color-blue-800
#4d6e7b
--color-blue-900
#3f5b66
--color-blue-950
#314952

Purple

--color-purple-50
#f8f7fb
--color-purple-100
#f2f0f7
--color-purple-200
#dad0f2
--color-purple-300
#c4b0eb
--color-purple-400
#b19dd6
--color-purple-500
#9e8bc2
--color-purple-600
#8b7aad
--color-purple-700
#796999
--color-purple-800
#574a71
--color-purple-900
#403758
--color-purple-950
#2b2440

Pink

--color-pink-50
#fff4fa
--color-pink-100
#ffe9f6
--color-pink-200
#ffcaea
--color-pink-300
#ffa8dd
--color-pink-400
#ff8ad1
--color-pink-500
#ff67c3
--color-pink-600
#ff4db7
--color-pink-700
#ff25aa
--color-pink-800
#d20080
--color-pink-900
#af006b
--color-pink-950
#8e0057

On this page

💬