Color
Pick a color by its role, not its value. Every color token follows the theme and the primary color, so the same names work everywhere.
Principles
- Neutral first. Surfaces, text, and borders are gray and white. Color is rare, so where it appears it means something: the main action, a status, a category.
- Choose by role. Use a role token such as
text/defaultorfill/accent. The raw palette (gray-100,blue-500) doesn't follow the theme. - Themes and primary colors change values, not names. The same token works in light, dark, and high contrast, and with every primary color.
- Never rely on color alone. Pair a status, a selection, or an error with an icon, text, or shape.
Token names
A color token reads as role / intent / level / state. Parts that don't apply are left out.
- Role:
surface,text,icon,border,fill,state. - Intent:
accent,success,warning,error,info. Neutral has no intent in the name:text/default, nottext/neutral/default. - Level: for example
secondary,subtle,strong,raised. - State: for example
hover,active,disabled,on-fill.
In CSS, replace the slashes with hyphens:
| Token | CSS variable |
|---|---|
text/default |
var(--text-default) |
text/secondary |
var(--text-secondary) |
fill/accent/hover |
var(--fill-accent-hover) |
surface/error |
var(--surface-error) |
text/accent/on-fill |
var(--text-accent-on-fill) |
.card {
background: var(--surface-default);
color: var(--text-default);
border: 1px solid var(--border-default);
}Themes
- Light: a neutral frame on white. Depth comes from gray steps.
- Dark: its own calibration, not inverted light. Higher layers are lighter: the page is darkest, floating panels lightest.
- High contrast: stronger text, borders, and fills, and hover, press, and selected look different from each other. It meets WCAG contrast throughout.
Choosing a theme
Set data-theme on <html> to light, dark, or high-contrast.
<html data-theme="dark">
Without the attribute, the page is light, unless the operating system asks for more contrast: then it gets high contrast automatically. A value you set always wins.
data-theme |
OS asks for more contrast | OS says nothing |
|---|---|---|
| not set | high contrast | light |
light |
light | light |
dark |
dark | dark |
high-contrast |
high contrast | high contrast |
data-theme also works on part of a page:
<div data-theme="dark" style="background: var(--surface-page); color: var(--text-default); padding: var(--space-16)"> <tk-button variant="primary">Publish</tk-button> <tk-button>Save draft</tk-button> </div>
Forced colors mode (Windows High Contrast) is separate from these themes: the operating system replaces the colors with the user's own.
Primary color and accent
The accent (the primary button, links, checked controls, the focus ring) takes its hue from
one primary color. Set data-primary on <html>, next to data-theme:
<html data-theme="light" data-primary="purple">
Values: blue (the default), orange, green, mint, teal, indigo, purple,
brown, gray, black.
<tk-button variant="primary">Publish</tk-button> <tk-button variant="ghost">Preview</tk-button> <tk-checkbox checked>Email me updates</tk-checkbox>
blackis a monochrome accent: a black primary button with a white label in light and high contrast, a white one with a black label in dark.- The label on an accent fill (
text/accent/on-fill) is white for every primary color exceptorange, where it is black. infois not the accent.infois always blue; the accent follows the primary color. Don't swap them, even when the primary color is blue.
The numbers are weights of the primary color's ramp in light, dark, and high contrast.
| Token | Use | Light | Dark | High contrast |
|---|---|---|---|---|
fill/accent |
primary button, checked checkbox, radio and switch, slider | 500 | 500 | 600 |
fill/accent/hover |
hover on an accent fill | 600 | 400 | 700 |
fill/accent/active |
press on an accent fill | 600 | 400 | 800 |
fill/accent/disabled |
not used: disabled controls take surface/disabled |
200 | 800 | 300 |
text/accent |
links, ghost button labels | 600 | 400 | 800 |
text/accent/hover |
link and ghost label hover | 800 | 200 | 900 |
text/accent/on-fill |
text on fill/accent |
white or black | white or black | white or black |
icon/accent |
accent icons | 600 | 400 | 700 |
icon/accent/on-fill |
icons on fill/accent |
as text/accent/on-fill |
||
border/accent |
an accent edge, such as a resize handle while dragging | 500 | 500 | 700 |
border/accent/focus |
the focus ring and a focused field's border | 500 | 500 | 800 |
state/accent/hover |
accent hover layer | 600 at 10% | 500 at 10% | 800 at 18% |
state/accent/press |
accent press layer | 600 at 10% | 500 at 10% | 800 at 46% |
state/accent/on |
accent selected layer | 600 at 10% | 500 at 10% | 800 at 46% |
In light and dark, fill/accent/active equals fill/accent/hover, so a primary button has
no separate press look there. The focus ring has its own page:
Roles
| Role | What it colors |
|---|---|
surface |
backgrounds: the page, cards, panels, popovers |
text |
anything people read |
icon |
icons that stand on their own |
border |
outlines, dividers, selection |
fill |
small controls with their own fill, such as a switch track or a solid badge |
state |
translucent hover, press, and selected layers over any of the above |
Surface
| Token | Use | Light | Dark | High contrast |
|---|---|---|---|---|
surface/page |
the page canvas | white |
gray-950 |
gray-50 |
surface/default |
content blocks and cards | white |
gray-900 |
gray-50 |
surface/subtle |
a slightly recessed area inside a block | gray-50 |
gray-800 |
gray-100 |
surface/raised |
floating panels: menus, popovers, dialogs | white |
gray-900 |
gray-50 |
surface/sunken |
wells and tracks, such as a progress track | gray-100 |
gray-950 |
gray-200 |
surface/inverse |
a panel in the opposite tone: tooltip, toast | gray-900 |
gray-50 |
gray-950 |
surface/disabled |
the fill of a disabled control | gray-50 |
gray-900 |
gray-100 |
surface/backdrop |
the dimmed page behind a modal dialog, nothing else | gray-950 at 50% |
black at 60% |
gray-950 at 60% |
Surfaces have no hover or selected tokens: use the state layers below.
Text
| Token | Use | Light | Dark | High contrast |
|---|---|---|---|---|
text/default |
headings and body | gray-950 |
gray-50 |
gray-950 |
text/secondary |
captions, metadata | gray-700 |
gray-300 |
gray-900 |
text/tertiary |
timestamps, counters | gray-600 |
gray-400 |
gray-800 |
text/placeholder |
placeholder text in an empty field | gray-500 |
gray-500 |
gray-600 |
text/disabled |
text of a disabled control | gray-400 |
gray-600 |
gray-500 |
text/inverse |
text on surface/inverse |
gray-50 |
gray-950 |
gray-50 |
text/on-fill |
text on fill/default |
gray-950 |
white |
gray-950 |
Icon
Each icon/* token pairs with the text/* token of the same level. Icons need 3:1 rather
than 4.5:1, so in light and high contrast an icon is one step lighter than its text; in dark
it matches its text.
| Token | Light | Dark | High contrast |
|---|---|---|---|
icon/default |
gray-900 |
gray-50 |
gray-900 |
icon/secondary |
gray-600 |
gray-300 |
gray-800 |
icon/tertiary |
gray-500 |
gray-400 |
gray-700 |
icon/disabled |
gray-300 |
gray-600 |
gray-400 |
icon/inverse |
gray-50 |
gray-950 |
gray-50 |
icon/on-fill |
as text/on-fill |
Border
| Token | Use | Light | Dark | High contrast |
|---|---|---|---|---|
border/subtle |
dividers inside a block; the border of fields and outline buttons | gray-100 |
gray-700 |
gray-600 |
border/default |
outlines of containers and controls | gray-200 |
gray-600 |
gray-700 |
border/strong |
edges that must stand out, such as a split button's divider | gray-300 |
gray-400 |
gray-800 |
border/selected |
a selected item | gray-800 |
gray-200 |
gray-900 |
border/inverse |
a border or focus ring on surface/inverse |
gray-50 |
gray-950 |
gray-50 |
border/disabled |
the border of a disabled control | gray-100 |
gray-900 |
gray-300 |
The focus ring is border/accent/focus, in
Fill
| Token | Use | Light | Dark | High contrast |
|---|---|---|---|---|
fill/default |
a neutral control fill, such as an off switch track | gray-100 |
gray-800 |
gray-200 |
fill/hover |
its hover | gray-200 |
gray-700 |
gray-300 |
fill/active |
its press | gray-300 |
gray-600 |
gray-400 |
fill/selected |
a selected neutral fill | gray-300 |
gray-600 |
gray-400 |
fill/disabled |
a disabled fill | gray-100 |
gray-900 |
gray-200 |
Text and icons on a fill take its on-fill partner: text/on-fill on fill/default,
text/accent/on-fill on fill/accent, text/error/on-fill on fill/error.
State layers
Hover, press, and selected are translucent layers drawn over whatever the element already
shows. Paint them with background-image and keep the element's own background-color.
Each layer has a ready gradient: --state-layer-hover, --state-layer-press,
--state-layer-on, --state-layer-on-hover, the accent ones
(--state-layer-accent-hover, -press, -on), and the error ones
(--state-layer-error-hover, -press).
.row:hover { background-image: var(--state-layer-hover); }
.row[aria-selected='true'] { background-image: var(--state-layer-on); }Don't set the background shorthand on that element: it resets background-image and
removes the layer.
| Token | Use | Light | Dark | High contrast |
|---|---|---|---|---|
state/hover |
under the pointer | gray-950 at 5% |
gray-50 at 5% |
gray-950 at 13% |
state/press |
while pressed | gray-950 at 5% |
gray-50 at 5% |
gray-950 at 26% |
state/on |
selected, pressed on, or current | gray-950 at 5% |
gray-50 at 5% |
gray-950 at 38% |
state/on-hover |
an on item under the pointer | gray-950 at 9.75% |
gray-50 at 9.75% |
gray-950 at 38% |
In light and dark, hover, press, and on are the same tint. Mark a selected item with
something more: border/selected, a check, or a bolder label. High contrast tells them
apart.
Status colors
Statuses keep their hue whatever the primary color: success is green, warning orange, error red, info blue.
<tk-section-message tone="success">Payment received.</tk-section-message> <tk-section-message tone="warning">Your trial ends in 3 days.</tk-section-message> <tk-section-message tone="error">The upload failed. Try again.</tk-section-message> <tk-section-message tone="info">Reports update every hour.</tk-section-message>
<tk-badge tone="success">Paid</tk-badge> <tk-badge tone="warning">Due soon</tk-badge> <tk-badge tone="error" treatment="solid">Overdue</tk-badge> <tk-badge tone="info" treatment="solid">New</tk-badge>
Each cell gives the weight of the status hue in light · dark · high contrast.
| Token | success (green) |
warning (orange) |
error (red) |
info (blue) |
|---|---|---|---|---|
surface/{status}: a tinted background |
50 · 900 · 100 | 50 · 900 · 100 | 50 · 900 · 100 | 50 · 900 · 100 |
text/{status} |
600 · 400 · 800 | 600 · 400 · 800 | 600 · 400 · 800 | 600 · 400 · 800 |
icon/{status} |
600 · 400 · 700 | 600 · 400 · 700 | 600 · 400 · 700 | 600 · 400 · 700 |
border/{status} |
300 · 500 · 600 | 300 · 500 · 600 | 600 · 400 · 600 | 300 · 500 · 600 |
fill/{status}: a solid fill |
600 · 500 · 700 | 500 · 500 · 700 | 600 · 500 · 700 | 600 · 600 · 700 |
text/{status}/on-fill, icon/{status}/on-fill |
white | black · black · white | white | white |
error also has interaction tokens:
| Token | Use | Light | Dark | High contrast |
|---|---|---|---|---|
state/error/hover |
hover on a danger button or menu item | red-600 at 10% |
red-500 at 10% |
red-800 at 18% |
state/error/press |
press on the same; equals hover | red-600 at 10% |
red-500 at 10% |
red-800 at 18% |
fill/error/hover |
hover on a solid red fill; no component uses it | red-700 |
red-600 |
red-800 |
fill/error/active |
press on a solid red fill; no component uses it | red-800 |
red-700 |
red-900 |
Categorical palette
Thirteen colors tell categories apart: tags, labels, chart series, avatars. They carry no status: a red tag is not an error.
<tk-tag color="purple">Research</tk-tag> <tk-tag color="teal">Design</tk-tag> <tk-tag color="orange">Marketing</tk-tag> <tk-tag color="green">Sales</tk-tag> <tk-tag color="gray">Unassigned</tk-tag>
The colors: red, orange, yellow, green, mint, teal, cyan, blue, indigo,
purple, pink, brown, gray. Each has three tokens; the numbers are weights of that
color in light · dark · high contrast.
| Token | CSS variable | Use | Weights |
|---|---|---|---|
categorical/{color}/surface |
--{color}-surface |
the label background | 100 · 900 · 100 |
categorical/{color}/text |
--{color}-text |
the label text | 700 · 300 · 900; 800 in light for orange, yellow, green, mint, teal, cyan |
categorical/{color}/border |
--{color}-border |
an optional outline | 400 · 500 · 700 |
- The text on its surface is at least 5:1 in every theme.
- The border is decorative: under 3:1 in light. Don't let it carry meaning.
- Keep to five or six categorical colors on one screen; more are hard to tell apart.
- Take a chart's axes and labels from the neutral tokens.
Syntax palette
syntax/* tokens. Like the
categorical palette, they carry no status: a string is green, but it isn't success.
// Show a price in dollars
function formatPrice(amount) {
return '$' + amount.toFixed(2);
}<tk-code-block language="js"><pre>// Show a price in dollars
function formatPrice(amount) {
return '$' + amount.toFixed(2);
}</pre></tk-code-block>| Token | Light | Dark | High contrast |
|---|---|---|---|
syntax/surface |
gray-50 |
gray-950 |
white |
syntax/keyword |
purple-700 |
purple-300 |
purple-800 |
syntax/string |
green-700 |
green-300 |
green-800 |
syntax/comment |
gray-700 |
gray-400 |
gray-700 |
syntax/number |
orange-700 |
orange-300 |
orange-800 |
syntax/function |
blue-700 |
blue-300 |
blue-800 |
syntax/class |
teal-700 |
teal-300 |
teal-800 |
syntax/variable |
red-700 |
red-300 |
red-800 |
syntax/punctuation |
gray-800 |
gray-300 |
gray-800 |
Every syntax color is at least 4.5:1 on syntax/surface in every theme.
Pairing
Take a background and its partner tokens together, and the contrast is built in.
| Recipe | Background | Text | Icon | Border |
|---|---|---|---|---|
| Card | surface/default |
text/default |
icon/default |
border/default |
| Selected row | its surface + the state/on layer |
text/default |
icon/default |
border/selected or a check |
| Neutral fill | fill/default |
text/on-fill |
icon/on-fill |
none |
| Primary button | fill/accent |
text/accent/on-fill |
icon/accent/on-fill |
none |
| Link | any surface | text/accent |
none | none |
| Status message | surface/{status} |
text/{status} |
icon/{status} |
border/{status} |
| Solid badge | fill/{status} |
text/{status}/on-fill |
icon/{status}/on-fill |
none |
| Tooltip, toast | surface/inverse |
text/inverse |
icon/inverse |
border/inverse |
| Disabled control | surface/disabled |
text/disabled |
icon/disabled |
border/disabled |
| Tag | categorical/{color}/surface |
categorical/{color}/text |
none | categorical/{color}/border, optional |
Accessibility
Built in:
- Every background role has partner text and icon tokens; the pairs above meet their contrast targets, except the limits below.
- High contrast meets WCAG contrast throughout, and people who ask their operating system for more contrast get it automatically.
- Disabled looks come from their own tokens, not
opacity. - Placeholder and disabled text sit under 4.5:1 on purpose: they aren't content.
Your part:
- Don't carry meaning by color alone; add an icon, text, or shape.
- Check any pair not on this page: 4.5:1 for text; 3:1 for large text (24px, or 18.66px bold), icons, and borders that carry meaning.
- Use
text/*for text andicon/*for icons. Icon colors only need 3:1 and can be too light for text.
Measured pairs
Light theme, blue primary.
| Background | Foreground | Ratio |
|---|---|---|
surface/default |
text/default |
17.36:1 |
surface/default |
text/secondary |
6.66:1 |
surface/default |
text/tertiary |
4.59:1 |
surface/default |
text/accent |
5.49:1 |
surface/error |
text/error |
4.63:1 |
surface/info |
text/info |
5.05:1 |
fill/default |
text/on-fill |
13.06:1 |
fill/accent |
text/accent/on-fill |
4.02:1 |
fill/success |
text/success/on-fill |
4.66:1 |
fill/warning |
text/warning/on-fill |
9.55:1 |
fill/error |
text/error/on-fill |
5.07:1 |
fill/info |
text/info/on-fill |
5.49:1 |
Contrast limits
These fall short in light or dark. High contrast meets the minimums.
- Status text on its tint:
text/success4.29:1 andtext/warning3.02:1 in light, under 4.5:1.text/warningis 3.30:1 even on white. - Accent text:
text/accentis 3.30:1 on white with theorangeprimary. In dark, onsurface/subtleandsurface/raised, it is under 4.5:1 with every primary color exceptorangeandblack;indigois lowest, at 2.47:1. - Label on the accent fill: at least 3:1 with every primary color (lowest
gray, 3.26:1), but under 4.5:1 with several, such asblueat 4.02:1. - Field and outline-button border (
border/subtle): 1.33:1 in light and 2.00:1 in dark, under 3:1; 4.22:1 in high contrast. In light it disappears onsurface/sunken. border/strong: 2.02:1 on white in light, under 3:1.- Danger button label on hover and press: 3.94:1 in light.
- Focus ring: under 3:1 with some primary colors on some surfaces. See
Focus . - Selected and hovered look the same in light and dark. Mark selection with a border, a check, or a bolder label.
Do / Don't
| ✅ Do | ❌ Don't |
|---|---|
Put text/accent/on-fill on fill/accent |
Put text/default on an accent fill |
Keep fill/* to small controls |
Use a fill as a page or panel background |
Show a disabled control with the */disabled tokens |
Dim it with opacity |
Take status colors from success, warning, error, info |
Use the accent for a status |
| Tell labels apart with a categorical color | Use a red tag to signal an error |
Mark a selected item with border/selected or a check |
Rely on the state/on tint alone |
Paint state layers with background-image |
Set background on an element with a state layer |
| Use the same token in every theme | Put the theme in a name, like surface-default-dark |
Primitives
Under the roles sits the palette: 13 hues (red, orange, yellow, green, mint,
teal, cyan, blue, indigo, purple, pink, brown, gray), each in 11 weights
from 50 to 950, plus white and black. In CSS: var(--blue-500).
Primitives don't change with the theme or the primary color, so use a role token wherever
one fits. The same weight looks about equally heavy in every hue, but contrast still
differs: orange and yellow are lighter than blue or gray at the same weight.
Every value, with its contrast against white and black:
Related
Focus : the focus ring and its color.Elevation : shadows that lift raised surfaces.Badge ,Section message , andBanner : the status colors in use.Tag : the categorical palette in use.
Primary color
The accent follows one of ten hues, set once on the html element with data-primary. Choose one to see this site in it.
Primitive colors
The raw palette under the color roles: 13 hues in 11 weights, plus white and black. Use a role token in your interface; primitives don't change with the theme.
How to read a ramp
Weight 50 is the lightest and 950 the darkest; 500 is the hue at full strength. The same weight looks about equally heavy in every hue.
| Weight | Lightness | Typical use |
|---|---|---|
| 50 | near white | background / subtle surface |
| 100–200 | very light | backgrounds, thin borders |
| 300–400 | light | borders, secondary accents |
| 500 | anchor | main color accent |
| 600–700 | saturated | accents, link text on light |
| 800–900 | dark | text, strong contrast |
| 950 | near black | deep background / maximum-contrast text |
Each table gives the CSS variable, the value in hex, hsl, and oklch, and the contrast against white and against black with its WCAG level for normal text (AA at 4.5:1, AAA at 7:1).
red
| Token | CSS variable | hex | hsl | oklch | Use | vs white | vs black |
|---|---|---|---|---|---|---|---|
red-50 |
--red-50 |
#fff2ef |
hsl(11 100% 97%) |
oklch(0.970 0.015 28.7) |
background / subtle surface | 1.09:1 —/— | 19.20:1 AA/AAA |
red-100 |
--red-100 |
#ffd5ce |
hsl(9 100% 90%) |
oklch(0.907 0.048 28.7) |
background / hover surface | 1.34:1 —/— | 15.66:1 AA/AAA |
red-200 |
--red-200 |
#ffb7ac |
hsl(8 100% 84%) |
oklch(0.844 0.086 28.7) |
borders / dividers | 1.66:1 —/— | 12.62:1 AA/AAA |
red-300 |
--red-300 |
#ff9688 |
hsl(7 100% 77%) |
oklch(0.780 0.128 28.7) |
borders / disabled elements | 2.11:1 —/— | 9.97:1 AA/AAA |
red-400 |
--red-400 |
#ff7161 |
hsl(6 100% 69%) |
oklch(0.717 0.177 28.7) |
secondary accent / icons on dark | 2.70:1 —/— | 7.79:1 AA/AAA |
red-500 |
--red-500 |
#ff3b30 |
hsl(3 100% 59%) |
oklch(0.654 0.232 28.7) |
main accent (anchor) | 3.55:1 —/— | 5.92:1 AA/— |
red-600 |
--red-600 |
#dc1312 |
hsl(0 85% 47%) |
oklch(0.567 0.225 28.7) |
hover accent / saturated | 5.07:1 AA/— | 4.15:1 —/— |
red-700 |
--red-700 |
#b20004 |
hsl(359 100% 35%) |
oklch(0.480 0.197 28.7) |
accent text on light background | 7.25:1 AA/AAA | 2.89:1 —/— |
red-800 |
--red-800 |
#880002 |
hsl(359 100% 27%) |
oklch(0.394 0.162 28.7) |
text / strong accent | 10.26:1 AA/AAA | 2.05:1 —/— |
red-900 |
--red-900 |
#600001 |
hsl(359 100% 19%) |
oklch(0.307 0.126 28.7) |
high-contrast text | 14.02:1 AA/AAA | 1.50:1 —/— |
red-950 |
--red-950 |
#3b0000 |
hsl(0 100% 12%) |
oklch(0.220 0.091 28.7) |
near-black text / deep background | 17.71:1 AA/AAA | 1.19:1 —/— |
orange
| Token | CSS variable | hex | hsl | oklch | Use | vs white | vs black |
|---|---|---|---|---|---|---|---|
orange-50 |
--orange-50 |
#fff3e8 |
hsl(29 100% 95%) |
oklch(0.970 0.019 62.6) |
background / subtle surface | 1.09:1 —/— | 19.24:1 AA/AAA |
orange-100 |
--orange-100 |
#ffe1c8 |
hsl(27 100% 89%) |
oklch(0.929 0.047 62.6) |
background / hover surface | 1.25:1 —/— | 16.86:1 AA/AAA |
orange-200 |
--orange-200 |
#ffd0a7 |
hsl(28 100% 83%) |
oklch(0.888 0.076 62.6) |
borders / dividers | 1.42:1 —/— | 14.83:1 AA/AAA |
orange-300 |
--orange-300 |
#ffbd82 |
hsl(28 100% 75%) |
oklch(0.847 0.107 62.6) |
borders / disabled elements | 1.63:1 —/— | 12.85:1 AA/AAA |
orange-400 |
--orange-400 |
#ffaa58 |
hsl(29 100% 67%) |
oklch(0.806 0.140 62.6) |
secondary accent / icons on dark | 1.88:1 —/— | 11.14:1 AA/AAA |
orange-500 |
--orange-500 |
#ff9500 |
hsl(35 100% 50%) |
oklch(0.765 0.175 62.6) |
main accent (anchor) | 2.20:1 —/— | 9.55:1 AA/AAA |
orange-600 |
--orange-600 |
#d07800 |
hsl(35 100% 41%) |
oklch(0.656 0.150 62.6) |
hover accent / saturated | 3.30:1 —/— | 6.37:1 AA/— |
orange-700 |
--orange-700 |
#a35d00 |
hsl(34 100% 32%) |
oklch(0.547 0.125 62.6) |
accent text on light background | 5.09:1 AA/— | 4.12:1 —/— |
orange-800 |
--orange-800 |
#784300 |
hsl(34 100% 24%) |
oklch(0.438 0.101 62.6) |
text / strong accent | 8.07:1 AA/AAA | 2.60:1 —/— |
orange-900 |
--orange-900 |
#502b00 |
hsl(32 100% 16%) |
oklch(0.329 0.076 62.6) |
high-contrast text | 12.45:1 AA/AAA | 1.69:1 —/— |
orange-950 |
--orange-950 |
#2b1400 |
hsl(28 100% 8%) |
oklch(0.220 0.051 62.6) |
near-black text / deep background | 17.46:1 AA/AAA | 1.20:1 —/— |
yellow
| Token | CSS variable | hex | hsl | oklch | Use | vs white | vs black |
|---|---|---|---|---|---|---|---|
yellow-50 |
--yellow-50 |
#fbf5e0 |
hsl(47 77% 93%) |
oklch(0.970 0.029 95.0) |
background / subtle surface | 1.09:1 —/— | 19.24:1 AA/AAA |
yellow-100 |
--yellow-100 |
#faefc5 |
hsl(48 84% 88%) |
oklch(0.949 0.055 95.0) |
background / hover surface | 1.15:1 —/— | 18.22:1 AA/AAA |
yellow-200 |
--yellow-200 |
#fbe79e |
hsl(47 92% 80%) |
oklch(0.928 0.094 95.0) |
borders / dividers | 1.23:1 —/— | 17.03:1 AA/AAA |
yellow-300 |
--yellow-300 |
#fcdf71 |
hsl(47 96% 72%) |
oklch(0.907 0.133 95.0) |
borders / disabled elements | 1.32:1 —/— | 15.93:1 AA/AAA |
yellow-400 |
--yellow-400 |
#fbd847 |
hsl(48 96% 63%) |
oklch(0.886 0.159 95.0) |
secondary accent / icons on dark | 1.40:1 —/— | 15.02:1 AA/AAA |
yellow-500 |
--yellow-500 |
#f4d038 |
hsl(49 90% 59%) |
oklch(0.865 0.163 95.0) |
main accent (anchor) | 1.51:1 —/— | 13.93:1 AA/AAA |
yellow-600 |
--yellow-600 |
#c8a700 |
hsl(50 100% 39%) |
oklch(0.736 0.151 95.0) |
hover accent / saturated | 2.34:1 —/— | 8.98:1 AA/AAA |
yellow-700 |
--yellow-700 |
#9a8000 |
hsl(50 100% 30%) |
oklch(0.607 0.125 95.0) |
accent text on light background | 3.84:1 —/— | 5.46:1 AA/— |
yellow-800 |
--yellow-800 |
#6f5c00 |
hsl(50 100% 22%) |
oklch(0.478 0.098 95.0) |
text / strong accent | 6.55:1 AA/— | 3.21:1 —/— |
yellow-900 |
--yellow-900 |
#463900 |
hsl(49 100% 14%) |
oklch(0.349 0.072 95.0) |
high-contrast text | 11.38:1 AA/AAA | 1.85:1 —/— |
yellow-950 |
--yellow-950 |
#211a00 |
hsl(47 100% 6%) |
oklch(0.220 0.046 95.0) |
near-black text / deep background | 17.32:1 AA/AAA | 1.21:1 —/— |
green
| Token | CSS variable | hex | hsl | oklch | Use | vs white | vs black |
|---|---|---|---|---|---|---|---|
green-50 |
--green-50 |
#eff8ef |
hsl(120 39% 95%) |
oklch(0.970 0.015 145.5) |
background / subtle surface | 1.09:1 —/— | 19.34:1 AA/AAA |
green-100 |
--green-100 |
#b5f0bb |
hsl(126 66% 83%) |
oklch(0.901 0.094 147.4) |
background / hover surface | 1.30:1 —/— | 16.15:1 AA/AAA |
green-200 |
--green-200 |
#6de682 |
hsl(130 71% 66%) |
oklch(0.832 0.176 147.4) |
borders / dividers | 1.58:1 —/— | 13.29:1 AA/AAA |
green-300 |
--green-300 |
#3ad35f |
hsl(135 63% 53%) |
oklch(0.763 0.202 147.3) |
borders / disabled elements | 1.97:1 —/— | 10.66:1 AA/AAA |
green-400 |
--green-400 |
#18bc4b |
hsl(139 77% 42%) |
oklch(0.695 0.199 147.3) |
secondary accent / icons on dark | 2.52:1 —/— | 8.33:1 AA/AAA |
green-500 |
--green-500 |
#00a43d |
hsl(142 100% 32%) |
oklch(0.626 0.184 147.3) |
main accent (anchor) | 3.29:1 —/— | 6.38:1 AA/— |
green-600 |
--green-600 |
#008731 |
hsl(142 100% 26%) |
oklch(0.543 0.160 147.4) |
hover accent / saturated | 4.66:1 AA/— | 4.51:1 AA/— |
green-700 |
--green-700 |
#006c26 |
hsl(141 100% 21%) |
oklch(0.463 0.136 147.5) |
accent text on light background | 6.62:1 AA/— | 3.17:1 —/— |
green-800 |
--green-800 |
#08511d |
hsl(137 82% 17%) |
oklch(0.381 0.107 147.4) |
text / strong accent | 9.52:1 AA/AAA | 2.21:1 —/— |
green-900 |
--green-900 |
#103718 |
hsl(132 55% 14%) |
oklch(0.300 0.070 147.6) |
high-contrast text | 13.28:1 AA/AAA | 1.58:1 —/— |
green-950 |
--green-950 |
#0a200e |
hsl(131 52% 8%) |
oklch(0.220 0.045 147.8) |
near-black text / deep background | 17.13:1 AA/AAA | 1.23:1 —/— |
mint
| Token | CSS variable | hex | hsl | oklch | Use | vs white | vs black |
|---|---|---|---|---|---|---|---|
mint-50 |
--mint-50 |
#ecf8f6 |
hsl(170 46% 95%) |
oklch(0.970 0.013 185.1) |
background / subtle surface | 1.09:1 —/— | 19.32:1 AA/AAA |
mint-100 |
--mint-100 |
#a3f0e4 |
hsl(171 72% 79%) |
oklch(0.902 0.078 183.8) |
background / hover surface | 1.30:1 —/— | 16.14:1 AA/AAA |
mint-200 |
--mint-200 |
#6ddfd0 |
hsl(172 64% 65%) |
oklch(0.833 0.107 184.1) |
borders / dividers | 1.60:1 —/— | 13.12:1 AA/AAA |
mint-300 |
--mint-300 |
#3acbbb |
hsl(173 58% 51%) |
oklch(0.763 0.122 184.2) |
borders / disabled elements | 2.01:1 —/— | 10.44:1 AA/AAA |
mint-400 |
--mint-400 |
#18b4a5 |
hsl(174 76% 40%) |
oklch(0.694 0.119 184.2) |
secondary accent / icons on dark | 2.59:1 —/— | 8.11:1 AA/AAA |
mint-500 |
--mint-500 |
#009d8f |
hsl(175 100% 31%) |
oklch(0.625 0.111 183.8) |
main accent (anchor) | 3.38:1 —/— | 6.22:1 AA/— |
mint-600 |
--mint-600 |
#008276 |
hsl(174 100% 25%) |
oklch(0.545 0.097 183.6) |
hover accent / saturated | 4.71:1 AA/— | 4.45:1 —/— |
mint-700 |
--mint-700 |
#00675e |
hsl(175 100% 20%) |
oklch(0.462 0.082 184.5) |
accent text on light background | 6.77:1 AA/— | 3.10:1 —/— |
mint-800 |
--mint-800 |
#084e47 |
hsl(174 81% 17%) |
oklch(0.383 0.065 184.2) |
text / strong accent | 9.58:1 AA/AAA | 2.19:1 —/— |
mint-900 |
--mint-900 |
#103530 |
hsl(172 54% 14%) |
oklch(0.301 0.043 183.1) |
high-contrast text | 13.34:1 AA/AAA | 1.57:1 —/— |
mint-950 |
--mint-950 |
#0a1f1c |
hsl(171 51% 8%) |
oklch(0.221 0.028 183.3) |
near-black text / deep background | 17.13:1 AA/AAA | 1.23:1 —/— |
teal
| Token | CSS variable | hex | hsl | oklch | Use | vs white | vs black |
|---|---|---|---|---|---|---|---|
teal-50 |
--teal-50 |
#f1f6f8 |
hsl(197 33% 96%) |
oklch(0.970 0.006 223.5) |
background / subtle surface | 1.09:1 —/— | 19.28:1 AA/AAA |
teal-100 |
--teal-100 |
#c4e5ef |
hsl(194 57% 85%) |
oklch(0.901 0.037 218.0) |
background / hover surface | 1.33:1 —/— | 15.80:1 AA/AAA |
teal-200 |
--teal-200 |
#7ed7f0 |
hsl(193 79% 72%) |
oklch(0.832 0.092 217.9) |
borders / dividers | 1.63:1 —/— | 12.87:1 AA/AAA |
teal-300 |
--teal-300 |
#39c4e6 |
hsl(192 78% 56%) |
oklch(0.762 0.123 218.3) |
borders / disabled elements | 2.06:1 —/— | 10.21:1 AA/AAA |
teal-400 |
--teal-400 |
#18aece |
hsl(191 79% 45%) |
oklch(0.694 0.121 217.8) |
secondary accent / icons on dark | 2.63:1 —/— | 7.98:1 AA/AAA |
teal-500 |
--teal-500 |
#0097b5 |
hsl(190 100% 35%) |
oklch(0.625 0.113 218.5) |
main accent (anchor) | 3.45:1 —/— | 6.09:1 AA/— |
teal-600 |
--teal-600 |
#007d96 |
hsl(190 100% 29%) |
oklch(0.544 0.098 218.3) |
hover accent / saturated | 4.80:1 AA/— | 4.37:1 —/— |
teal-700 |
--teal-700 |
#006478 |
hsl(190 100% 24%) |
oklch(0.464 0.083 217.8) |
accent text on light background | 6.79:1 AA/— | 3.09:1 —/— |
teal-800 |
--teal-800 |
#084b5a |
hsl(191 84% 19%) |
oklch(0.382 0.065 218.0) |
text / strong accent | 9.70:1 AA/AAA | 2.16:1 —/— |
teal-900 |
--teal-900 |
#10333d |
hsl(193 58% 15%) |
oklch(0.301 0.043 219.9) |
high-contrast text | 13.44:1 AA/AAA | 1.56:1 —/— |
teal-950 |
--teal-950 |
#0a1e23 |
hsl(192 56% 9%) |
oklch(0.221 0.028 216.2) |
near-black text / deep background | 17.17:1 AA/AAA | 1.22:1 —/— |
cyan
| Token | CSS variable | hex | hsl | oklch | Use | vs white | vs black |
|---|---|---|---|---|---|---|---|
cyan-50 |
--cyan-50 |
#f2f6f8 |
hsl(200 30% 96%) |
oklch(0.971 0.005 228.8) |
background / subtle surface | 1.09:1 —/— | 19.31:1 AA/AAA |
cyan-100 |
--cyan-100 |
#cde2ef |
hsl(203 52% 87%) |
oklch(0.901 0.029 234.9) |
background / hover surface | 1.34:1 —/— | 15.72:1 AA/AAA |
cyan-200 |
--cyan-200 |
#9ad0f0 |
hsl(202 74% 77%) |
oklch(0.831 0.072 234.8) |
borders / dividers | 1.66:1 —/— | 12.65:1 AA/AAA |
cyan-300 |
--cyan-300 |
#4dbff8 |
hsl(200 92% 64%) |
oklch(0.763 0.130 234.1) |
borders / disabled elements | 2.07:1 —/— | 10.12:1 AA/AAA |
cyan-400 |
--cyan-400 |
#17a9e6 |
hsl(198 82% 50%) |
oklch(0.693 0.141 234.2) |
secondary accent / icons on dark | 2.67:1 —/— | 7.85:1 AA/AAA |
cyan-500 |
--cyan-500 |
#0093ca |
hsl(196 100% 40%) |
oklch(0.625 0.131 234.0) |
main accent (anchor) | 3.48:1 —/— | 6.03:1 AA/— |
cyan-600 |
--cyan-600 |
#0079a7 |
hsl(197 100% 33%) |
oklch(0.543 0.114 234.0) |
hover accent / saturated | 4.89:1 AA/— | 4.29:1 —/— |
cyan-700 |
--cyan-700 |
#006186 |
hsl(197 100% 26%) |
oklch(0.464 0.096 233.4) |
accent text on light background | 6.88:1 AA/— | 3.05:1 —/— |
cyan-800 |
--cyan-800 |
#084965 |
hsl(198 85% 21%) |
oklch(0.383 0.076 233.8) |
text / strong accent | 9.76:1 AA/AAA | 2.15:1 —/— |
cyan-900 |
--cyan-900 |
#0f3243 |
hsl(200 63% 16%) |
oklch(0.301 0.050 233.1) |
high-contrast text | 13.48:1 AA/AAA | 1.56:1 —/— |
cyan-950 |
--cyan-950 |
#091d27 |
hsl(200 63% 9%) |
oklch(0.220 0.032 232.6) |
near-black text / deep background | 17.26:1 AA/AAA | 1.22:1 —/— |
blue
| Token | CSS variable | hex | hsl | oklch | Use | vs white | vs black |
|---|---|---|---|---|---|---|---|
blue-50 |
--blue-50 |
#eff6ff |
hsl(214 100% 97%) |
oklch(0.970 0.014 257.4) |
background / subtle surface | 1.09:1 —/— | 19.30:1 AA/AAA |
blue-100 |
--blue-100 |
#c8dfff |
hsl(215 100% 89%) |
oklch(0.897 0.051 257.4) |
background / hover surface | 1.36:1 —/— | 15.45:1 AA/AAA |
blue-200 |
--blue-200 |
#a1c7ff |
hsl(216 100% 82%) |
oklch(0.823 0.089 257.4) |
borders / dividers | 1.73:1 —/— | 12.13:1 AA/AAA |
blue-300 |
--blue-300 |
#78afff |
hsl(216 100% 74%) |
oklch(0.750 0.130 257.4) |
borders / disabled elements | 2.24:1 —/— | 9.37:1 AA/AAA |
blue-400 |
--blue-400 |
#4b96ff |
hsl(215 100% 65%) |
oklch(0.676 0.173 257.4) |
secondary accent / icons on dark | 2.96:1 —/— | 7.11:1 AA/AAA |
blue-500 |
--blue-500 |
#007aff |
hsl(211 100% 50%) |
oklch(0.603 0.218 257.4) |
main accent (anchor) | 4.02:1 —/— | 5.23:1 AA/— |
blue-600 |
--blue-600 |
#0065d5 |
hsl(212 100% 42%) |
oklch(0.526 0.190 257.4) |
hover accent / saturated | 5.49:1 AA/— | 3.82:1 —/— |
blue-700 |
--blue-700 |
#0050ad |
hsl(212 100% 34%) |
oklch(0.450 0.163 257.4) |
accent text on light background | 7.63:1 AA/AAA | 2.75:1 —/— |
blue-800 |
--blue-800 |
#003d86 |
hsl(213 100% 26%) |
oklch(0.373 0.135 257.4) |
text / strong accent | 10.44:1 AA/AAA | 2.01:1 —/— |
blue-900 |
--blue-900 |
#002a61 |
hsl(214 100% 19%) |
oklch(0.297 0.108 257.4) |
high-contrast text | 13.96:1 AA/AAA | 1.50:1 —/— |
blue-950 |
--blue-950 |
#00183f |
hsl(217 100% 12%) |
oklch(0.220 0.081 257.4) |
near-black text / deep background | 17.46:1 AA/AAA | 1.20:1 —/— |
indigo
| Token | CSS variable | hex | hsl | oklch | Use | vs white | vs black |
|---|---|---|---|---|---|---|---|
indigo-50 |
--indigo-50 |
#f3f4ff |
hsl(235 100% 98%) |
oklch(0.970 0.014 278.3) |
background / subtle surface | 1.09:1 —/— | 19.20:1 AA/AAA |
indigo-100 |
--indigo-100 |
#cfd5ff |
hsl(232 100% 91%) |
oklch(0.882 0.058 278.3) |
background / hover surface | 1.44:1 —/— | 14.61:1 AA/AAA |
indigo-200 |
--indigo-200 |
#acb5ff |
hsl(233 100% 84%) |
oklch(0.794 0.105 278.3) |
borders / dividers | 1.94:1 —/— | 10.81:1 AA/AAA |
indigo-300 |
--indigo-300 |
#8b94ff |
hsl(235 100% 77%) |
oklch(0.706 0.156 278.3) |
borders / disabled elements | 2.70:1 —/— | 7.78:1 AA/AAA |
indigo-400 |
--indigo-400 |
#7073f2 |
hsl(239 83% 69%) |
oklch(0.618 0.187 278.3) |
secondary accent / icons on dark | 3.87:1 —/— | 5.42:1 AA/— |
indigo-500 |
--indigo-500 |
#5856d6 |
hsl(241 61% 59%) |
oklch(0.529 0.191 278.3) |
main accent (anchor) | 5.65:1 AA/— | 3.72:1 —/— |
indigo-600 |
--indigo-600 |
#4944be |
hsl(242 48% 51%) |
oklch(0.468 0.185 278.3) |
hover accent / saturated | 7.36:1 AA/AAA | 2.85:1 —/— |
indigo-700 |
--indigo-700 |
#3b34a0 |
hsl(244 51% 42%) |
oklch(0.406 0.168 278.3) |
accent text on light background | 9.61:1 AA/AAA | 2.18:1 —/— |
indigo-800 |
--indigo-800 |
#2d287f |
hsl(243 52% 33%) |
oklch(0.344 0.141 278.3) |
text / strong accent | 12.20:1 AA/AAA | 1.72:1 —/— |
indigo-900 |
--indigo-900 |
#201e5c |
hsl(242 51% 24%) |
oklch(0.282 0.107 278.3) |
high-contrast text | 14.98:1 AA/AAA | 1.40:1 —/— |
indigo-950 |
--indigo-950 |
#141242 |
hsl(243 57% 16%) |
oklch(0.220 0.088 278.3) |
near-black text / deep background | 17.57:1 AA/AAA | 1.19:1 —/— |
purple
| Token | CSS variable | hex | hsl | oklch | Use | vs white | vs black |
|---|---|---|---|---|---|---|---|
purple-50 |
--purple-50 |
#faf2ff |
hsl(277 100% 97%) |
oklch(0.970 0.020 312.4) |
background / subtle surface | 1.09:1 —/— | 19.21:1 AA/AAA |
purple-100 |
--purple-100 |
#edd1ff |
hsl(277 100% 91%) |
oklch(0.899 0.069 312.4) |
background / hover surface | 1.38:1 —/— | 15.17:1 AA/AAA |
purple-200 |
--purple-200 |
#e1b0ff |
hsl(277 100% 85%) |
oklch(0.828 0.120 312.4) |
borders / dividers | 1.77:1 —/— | 11.86:1 AA/AAA |
purple-300 |
--purple-300 |
#d58cff |
hsl(278 100% 77%) |
oklch(0.757 0.175 312.4) |
borders / disabled elements | 2.33:1 —/— | 9.02:1 AA/AAA |
purple-400 |
--purple-400 |
#c56bf5 |
hsl(279 87% 69%) |
oklch(0.686 0.209 312.4) |
secondary accent / icons on dark | 3.09:1 —/— | 6.80:1 AA/— |
purple-500 |
--purple-500 |
#af52de |
hsl(280 68% 60%) |
oklch(0.615 0.213 312.4) |
main accent (anchor) | 4.13:1 —/— | 5.08:1 AA/— |
purple-600 |
--purple-600 |
#953ac1 |
hsl(280 54% 49%) |
oklch(0.536 0.206 312.4) |
hover accent / saturated | 5.75:1 AA/— | 3.65:1 —/— |
purple-700 |
--purple-700 |
#7928a0 |
hsl(280 60% 39%) |
oklch(0.457 0.187 312.4) |
accent text on light background | 8.00:1 AA/AAA | 2.62:1 —/— |
purple-800 |
--purple-800 |
#5d1b7c |
hsl(281 64% 30%) |
oklch(0.378 0.158 312.4) |
text / strong accent | 10.98:1 AA/AAA | 1.91:1 —/— |
purple-900 |
--purple-900 |
#411357 |
hsl(281 64% 21%) |
oklch(0.299 0.119 312.4) |
high-contrast text | 14.43:1 AA/AAA | 1.46:1 —/— |
purple-950 |
--purple-950 |
#29053a |
hsl(281 84% 12%) |
oklch(0.220 0.098 312.4) |
near-black text / deep background | 17.84:1 AA/AAA | 1.18:1 —/— |
pink
| Token | CSS variable | hex | hsl | oklch | Use | vs white | vs black |
|---|---|---|---|---|---|---|---|
pink-50 |
--pink-50 |
#fff1f1 |
hsl(0 100% 97%) |
oklch(0.970 0.015 17.9) |
background / subtle surface | 1.10:1 —/— | 19.10:1 AA/AAA |
pink-100 |
--pink-100 |
#ffd4d4 |
hsl(0 100% 92%) |
oklch(0.906 0.049 17.9) |
background / hover surface | 1.34:1 —/— | 15.62:1 AA/AAA |
pink-200 |
--pink-200 |
#ffb5b6 |
hsl(359 100% 85%) |
oklch(0.842 0.087 17.9) |
borders / dividers | 1.68:1 —/— | 12.54:1 AA/AAA |
pink-300 |
--pink-300 |
#ff9397 |
hsl(358 100% 79%) |
oklch(0.778 0.131 17.9) |
borders / disabled elements | 2.13:1 —/— | 9.87:1 AA/AAA |
pink-400 |
--pink-400 |
#ff6b77 |
hsl(355 100% 71%) |
oklch(0.714 0.181 17.9) |
secondary accent / icons on dark | 2.76:1 —/— | 7.62:1 AA/AAA |
pink-500 |
--pink-500 |
#ff2d55 |
hsl(349 100% 59%) |
oklch(0.650 0.238 17.9) |
main accent (anchor) | 3.65:1 —/— | 5.76:1 AA/— |
pink-600 |
--pink-600 |
#da0040 |
hsl(342 100% 43%) |
oklch(0.564 0.226 17.9) |
hover accent / saturated | 5.18:1 AA/— | 4.06:1 —/— |
pink-700 |
--pink-700 |
#af0031 |
hsl(343 100% 34%) |
oklch(0.478 0.192 17.9) |
accent text on light background | 7.32:1 AA/AAA | 2.87:1 —/— |
pink-800 |
--pink-800 |
#860023 |
hsl(344 100% 26%) |
oklch(0.392 0.157 17.9) |
text / strong accent | 10.30:1 AA/AAA | 2.04:1 —/— |
pink-900 |
--pink-900 |
#5e0016 |
hsl(346 100% 18%) |
oklch(0.306 0.123 17.9) |
high-contrast text | 14.12:1 AA/AAA | 1.49:1 —/— |
pink-950 |
--pink-950 |
#3a000a |
hsl(350 100% 11%) |
oklch(0.220 0.089 17.9) |
near-black text / deep background | 17.73:1 AA/AAA | 1.18:1 —/— |
brown
| Token | CSS variable | hex | hsl | oklch | Use | vs white | vs black |
|---|---|---|---|---|---|---|---|
brown-50 |
--brown-50 |
#faf4ed |
hsl(32 57% 95%) |
oklch(0.970 0.012 72.8) |
background / subtle surface | 1.09:1 —/— | 19.23:1 AA/AAA |
brown-100 |
--brown-100 |
#e8ddcf |
hsl(34 35% 86%) |
oklch(0.902 0.022 72.8) |
background / hover surface | 1.34:1 —/— | 15.67:1 AA/AAA |
brown-200 |
--brown-200 |
#d8c6af |
hsl(34 34% 77%) |
oklch(0.835 0.037 72.8) |
borders / dividers | 1.66:1 —/— | 12.62:1 AA/AAA |
brown-300 |
--brown-300 |
#c8af8f |
hsl(34 34% 67%) |
oklch(0.767 0.053 72.8) |
borders / disabled elements | 2.10:1 —/— | 9.98:1 AA/AAA |
brown-400 |
--brown-400 |
#b79973 |
hsl(34 32% 58%) |
oklch(0.700 0.063 72.8) |
secondary accent / icons on dark | 2.69:1 —/— | 7.82:1 AA/AAA |
brown-500 |
--brown-500 |
#a2845e |
hsl(34 27% 50%) |
oklch(0.632 0.064 72.8) |
main accent (anchor) | 3.50:1 —/— | 6.00:1 AA/— |
brown-600 |
--brown-600 |
#886c48 |
hsl(34 31% 41%) |
oklch(0.550 0.062 72.8) |
hover accent / saturated | 4.90:1 AA/— | 4.29:1 —/— |
brown-700 |
--brown-700 |
#6e5535 |
hsl(34 35% 32%) |
oklch(0.467 0.057 72.8) |
accent text on light background | 6.97:1 AA/— | 3.01:1 —/— |
brown-800 |
--brown-800 |
#534026 |
hsl(35 37% 24%) |
oklch(0.385 0.048 72.8) |
text / strong accent | 9.86:1 AA/AAA | 2.13:1 —/— |
brown-900 |
--brown-900 |
#3a2c1a |
hsl(34 38% 16%) |
oklch(0.302 0.036 72.8) |
high-contrast text | 13.50:1 AA/AAA | 1.56:1 —/— |
brown-950 |
--brown-950 |
#23180a |
hsl(34 56% 9%) |
oklch(0.220 0.030 72.8) |
near-black text / deep background | 17.41:1 AA/AAA | 1.21:1 —/— |
gray
| Token | CSS variable | hex | hsl | oklch | Use | vs white | vs black |
|---|---|---|---|---|---|---|---|
gray-50 |
--gray-50 |
#f5f5f8 |
hsl(240 18% 97%) |
oklch(0.970 0.004 286.2) |
background / subtle surface | 1.09:1 —/— | 19.30:1 AA/AAA |
gray-100 |
--gray-100 |
#dfdfe2 |
hsl(240 5% 88%) |
oklch(0.906 0.004 286.2) |
background / hover surface | 1.33:1 —/— | 15.79:1 AA/AAA |
gray-200 |
--gray-200 |
#cacace |
hsl(240 4% 80%) |
oklch(0.841 0.005 286.2) |
borders / dividers | 1.63:1 —/— | 12.85:1 AA/AAA |
gray-300 |
--gray-300 |
#b6b6ba |
hsl(240 3% 72%) |
oklch(0.777 0.006 286.2) |
borders / disabled elements | 2.02:1 —/— | 10.39:1 AA/AAA |
gray-400 |
--gray-400 |
#a2a2a6 |
hsl(240 2% 64%) |
oklch(0.713 0.006 286.2) |
secondary accent / icons on dark | 2.54:1 —/— | 8.26:1 AA/AAA |
gray-500 |
--gray-500 |
#8e8e92 |
hsl(240 2% 56%) |
oklch(0.648 0.006 286.2) |
main accent (anchor) | 3.26:1 —/— | 6.43:1 AA/— |
gray-600 |
--gray-600 |
#757579 |
hsl(240 2% 47%) |
oklch(0.563 0.006 286.2) |
hover accent / saturated | 4.59:1 AA/— | 4.58:1 AA/— |
gray-700 |
--gray-700 |
#5c5c60 |
hsl(240 2% 37%) |
oklch(0.477 0.006 286.2) |
accent text on light background | 6.66:1 AA/— | 3.15:1 —/— |
gray-800 |
--gray-800 |
#454548 |
hsl(240 2% 28%) |
oklch(0.391 0.006 286.2) |
text / strong accent | 9.55:1 AA/AAA | 2.20:1 —/— |
gray-900 |
--gray-900 |
#2f2f32 |
hsl(240 3% 19%) |
oklch(0.306 0.006 286.2) |
high-contrast text | 13.35:1 AA/AAA | 1.57:1 —/— |
gray-950 |
--gray-950 |
#1a1a1d |
hsl(240 5% 11%) |
oklch(0.220 0.006 286.2) |
near-black text / deep background | 17.36:1 AA/AAA | 1.21:1 —/— |
white
A single value, not a ramp. The light theme's page, card, and panel surfaces are white.
| Token | CSS variable | hex | hsl | oklch | Use | vs white | vs black |
|---|---|---|---|---|---|---|---|
white |
--white |
#ffffff |
hsl(0 0% 100%) |
oklch(1.000 0 0) |
true-white surface base / reference point | 1.00:1 —/— | 21.00:1 AA/AAA |
gray-50 is a slightly cool near-white for muted surfaces such as surface/subtle.
black
A single value, not a ramp. It is the label color on light, saturated fills, such as fill/warning and the orange primary's accent fill.
| Token | CSS variable | hex | hsl | oklch | Use | vs white | vs black |
|---|---|---|---|---|---|---|---|
black |
--black |
#000000 |
hsl(0 0% 0%) |
oklch(0.000 0 0) |
true-black pole for on-fill / reference point | 21.00:1 AA/AAA | 1.00:1 —/— |
gray-950 is a slightly cool near-black for text and deep backgrounds.
Opacity
Thykes has no opacity scale. Disabled looks, hover tints, and dimming come from color tokens.
- Disabled: use the
*/disabledcolor tokens, notopacity. They keep the contrast under control. - Hover, press, selected: use the
state/*layers. - Dimming behind a dialog:
surface/backdrop.
All three are on the
Values
| Token | CSS variable | Value | Use |
|---|---|---|---|
opacity-icon-duotone-body |
--opacity-icon-duotone-body |
0.12 | no Thykes component uses it |