Skip to main content
Gremorie
Semantic

Colors

The intent-to-value mapping for the seven Gremorie themes, in light and dark mode.

Semantic tokens are intents: primary, foreground, border. Each theme fills those intents with different values, and each mode (light / dark) brings its own mapping. This page is the truth table for the seven bundled themes: Default, Claude, ChatGPT, Gemini, Perplexity, Mistral and Purple.

How to read the tables

  • The Light and Dark columns render the exact declared value as a chip over that theme's own light or dark background, so both are faithful no matter which mode you are reading in.
  • The Value columns show what the theme declares: a primitive name (an alias in the DTCG source, written to CSS as var(--color-<token>)) or, where the theme matches a product surface that has no primitive equivalent, a literal OKLCH value.
  • A base badge means the theme does not override that token; it inherits the value from the base layer (semantic/light.json and semantic/dark.json). That inheritance is the shipped behavior, not an omission.

If you are auditing a component that looks "wrong" in some theme, start here. Comparing the intent (e.g. --primary) with the value it resolves to in each theme tells you whether the inconsistency comes from the component chrome or from the theme mapping.

Default

The base semantic layer itself, on the neutralized gray ramp. Conservative and brand-free; every other theme is an override layer on top of it.

--radius-base: 0.625rem · selector :root

LightDarkTokenValue (light)Value (dark)
--backgroundgray-50basegray-950base
--foregroundgray-950basegray-50base
--cardgray-0basegray-900base
--card-foregroundgray-950basegray-50base
--popovergray-0basegray-900base
--popover-foregroundgray-950basegray-50base
--primarygray-900basegray-100base
--primary-foregroundgray-50basegray-900base
--secondarygray-100basegray-800base
--secondary-foregroundgray-900basegray-50base
--mutedgray-100basegray-800base
--muted-foregroundgray-500basegray-400base
--accentgray-100basegray-800base
--accent-foregroundgray-900basegray-50base
--destructivered-600basered-400base
--destructive-foregroundgray-50basegray-50base
--warningamber-500baseamber-400base
--warning-foregroundgray-950basegray-950base
--successgreen-700basegreen-400base
--success-foregroundgray-50basegray-950base
--bordergray-200baseoklch(1 0 0 / 10%)base
--inputgray-200baseoklch(1 0 0 / 15%)base
--ringgray-400basegray-500base
--chart-1blue-500baseblue-600base
--chart-2amber-500baseamber-600base
--chart-3green-500basegreen-600base
--chart-4cyan-500basecyan-600base
--chart-5pink-500basepink-600base
--sidebargray-50basegray-900base
--sidebar-foregroundgray-950basegray-50base
--sidebar-primarygray-900basegray-100base
--sidebar-primary-foregroundgray-50basegray-900base
--sidebar-accentgray-100basegray-800base
--sidebar-accent-foregroundgray-900basegray-50base
--sidebar-bordergray-200baseoklch(1 0 0 / 10%)base
--sidebar-ringgray-400basegray-500base

Claude

Warm clay (coral terracotta) on cream surfaces, taupe support, serif display. Dark mode sits on the warm charcoal of the real product.

--radius-base: 0.5rem · selector [data-theme='claude']

LightDarkTokenValue (light)Value (dark)
--backgroundoklch(0.965 0.011 92)oklch(0.235 0.006 100)
--foregroundgray-950gray-50
--cardoklch(0.985 0.008 92)oklch(0.268 0.005 100)
--card-foregroundgray-950gray-50
--popoveroklch(0.985 0.008 92)oklch(0.268 0.005 100)
--popover-foregroundgray-950gray-50
--primaryclay-500clay-400
--primary-foregroundgray-50gray-950
--secondaryoklch(0.95 0.012 80)oklch(0.28 0.012 58)
--secondary-foregroundclay-900gray-50
--mutedoklch(0.95 0.012 80)oklch(0.28 0.012 58)
--muted-foregroundtaupe-600taupe-300
--accentclay-100clay-900
--accent-foregroundclay-900clay-50
--destructivered-600basered-400base
--destructive-foregroundgray-50basegray-50base
--warningamber-500baseamber-400base
--warning-foregroundgray-950basegray-950base
--successgreen-700basegreen-400base
--success-foregroundgray-50basegray-950base
--borderoklch(0.9 0.014 78)oklch(1 0 0 / 10%)
--inputoklch(0.9 0.014 78)oklch(1 0 0 / 15%)
--ringclay-500clay-400
--chart-1blue-500baseblue-600base
--chart-2amber-500baseamber-600base
--chart-3green-500basegreen-600base
--chart-4cyan-500basecyan-600base
--chart-5pink-500basepink-600base
--sidebaroklch(0.97 0.01 84)oklch(0.24 0.012 60)
--sidebar-foregroundgray-950gray-50
--sidebar-primaryclay-600clay-400
--sidebar-primary-foregroundgray-50gray-950
--sidebar-accentclay-100oklch(0.28 0.012 58)
--sidebar-accent-foregroundclay-900gray-50
--sidebar-borderoklch(0.9 0.014 78)oklch(1 0 0 / 10%)
--sidebar-ringclay-500clay-400

ChatGPT

Emerald accent on a flat, low-shadow surface. Dark mode uses the flat graphite of the real product; surfaces otherwise inherit the neutral base.

--radius-base: 0.75rem · selector [data-theme='chatgpt']

LightDarkTokenValue (light)Value (dark)
--backgroundgray-50baseoklch(0.248 0 0)
--foregroundgray-950basegray-50base
--cardgray-0baseoklch(0.278 0 0)
--card-foregroundgray-950basegray-50base
--popovergray-0baseoklch(0.278 0 0)
--popover-foregroundgray-950basegray-50base
--primaryemerald-700emerald-400
--primary-foregroundgray-50gray-950
--secondarygray-100basegray-800base
--secondary-foregroundgray-900basegray-50base
--mutedgray-100basegray-800base
--muted-foregroundgray-500basegray-400base
--accentemerald-100emerald-900
--accent-foregroundemerald-900emerald-50
--destructivered-600basered-400base
--destructive-foregroundgray-50basegray-50base
--warningamber-500baseamber-400base
--warning-foregroundgray-950basegray-950base
--successgreen-700basegreen-400base
--success-foregroundgray-50basegray-950base
--bordergray-200baseoklch(1 0 0 / 10%)base
--inputgray-200baseoklch(1 0 0 / 15%)base
--ringemerald-500emerald-400
--chart-1blue-500baseblue-600base
--chart-2amber-500baseamber-600base
--chart-3green-500basegreen-600base
--chart-4cyan-500basecyan-600base
--chart-5pink-500basepink-600base
--sidebargray-50basegray-900base
--sidebar-foregroundgray-950basegray-50base
--sidebar-primaryemerald-700emerald-400
--sidebar-primary-foregroundgray-50gray-950
--sidebar-accentgray-100basegray-800base
--sidebar-accent-foregroundgray-900basegray-50base
--sidebar-bordergray-200baseoklch(1 0 0 / 10%)base
--sidebar-ringemerald-500emerald-400

Gemini

Google blue with a blue-to-purple brand ramp and the roundest radius of the set. Dark mode sits on the cool graphite of the real product.

--radius-base: 1rem · selector [data-theme='gemini']

LightDarkTokenValue (light)Value (dark)
--backgroundgray-50baseoklch(0.239 0.002 248)
--foregroundgray-950basegray-50base
--cardgray-0baseoklch(0.274 0.002 248)
--card-foregroundgray-950basegray-50base
--popovergray-0baseoklch(0.274 0.002 248)
--popover-foregroundgray-950basegray-50base
--primaryoklch(0.55 0.19 258)oklch(0.75 0.11 258)
--primary-foregroundgray-50gray-950
--secondarygray-100basegray-800base
--secondary-foregroundgray-900basegray-50base
--mutedgray-100basegray-800base
--muted-foregroundgray-500basegray-400base
--accentindigo-100indigo-900
--accent-foregroundindigo-900indigo-50
--destructivered-600basered-400base
--destructive-foregroundgray-50basegray-50base
--warningamber-500baseamber-400base
--warning-foregroundgray-950basegray-950base
--successgreen-700basegreen-400base
--success-foregroundgray-50basegray-950base
--bordergray-200baseoklch(1 0 0 / 10%)base
--inputgray-200baseoklch(1 0 0 / 15%)base
--ringoklch(0.63 0.18 260)oklch(0.75 0.11 258)
--chart-1blue-500baseblue-600base
--chart-2amber-500baseamber-600base
--chart-3green-500basegreen-600base
--chart-4cyan-500basecyan-600base
--chart-5pink-500basepink-600base
--sidebargray-50basegray-900base
--sidebar-foregroundgray-950basegray-50base
--sidebar-primaryoklch(0.55 0.19 258)oklch(0.75 0.11 258)
--sidebar-primary-foregroundgray-50gray-950
--sidebar-accentgray-100basegray-800base
--sidebar-accent-foregroundgray-900basegray-50base
--sidebar-bordergray-200baseoklch(1 0 0 / 10%)base
--sidebar-ringoklch(0.63 0.18 260)oklch(0.75 0.11 258)

Perplexity

True turquoise on offblack, sober and tight, with the smallest radius of the set. The light primary is the brand turquoise #20808D.

--radius-base: 0.375rem · selector [data-theme='perplexity']

LightDarkTokenValue (light)Value (dark)
--backgroundgray-50baseoklch(0.192 0.02 195.6)
--foregroundgray-950basegray-50base
--cardgray-0baseoklch(0.225 0.018 196)
--card-foregroundgray-950basegray-50base
--popovergray-0baseoklch(0.225 0.018 196)
--popover-foregroundgray-950basegray-50base
--primaryoklch(0.553 0.086 208.5)oklch(0.72 0.11 205)
--primary-foregroundgray-0gray-950
--secondarygray-100basegray-800base
--secondary-foregroundgray-900basegray-50base
--mutedgray-100basegray-800base
--muted-foregroundgray-500basegray-400base
--accentteal-100teal-900
--accent-foregroundteal-900teal-50
--destructivered-600basered-400base
--destructive-foregroundgray-50basegray-50base
--warningamber-500baseamber-400base
--warning-foregroundgray-950basegray-950base
--successgreen-700basegreen-400base
--success-foregroundgray-50basegray-950base
--bordergray-200baseoklch(1 0 0 / 10%)base
--inputgray-200baseoklch(1 0 0 / 15%)base
--ringoklch(0.553 0.086 208.5)oklch(0.72 0.11 205)
--chart-1blue-500baseblue-600base
--chart-2amber-500baseamber-600base
--chart-3green-500basegreen-600base
--chart-4cyan-500basecyan-600base
--chart-5pink-500basepink-600base
--sidebargray-50basegray-900base
--sidebar-foregroundgray-950basegray-50base
--sidebar-primaryoklch(0.553 0.086 208.5)oklch(0.72 0.11 205)
--sidebar-primary-foregroundgray-0gray-950
--sidebar-accentgray-100basegray-800base
--sidebar-accent-foregroundgray-900basegray-50base
--sidebar-bordergray-200baseoklch(1 0 0 / 10%)base
--sidebar-ringoklch(0.553 0.086 208.5)oklch(0.72 0.11 205)

Mistral

Flame orange with a black-on-orange primary, matching Mistral brand usage. Surfaces inherit the neutral base in both modes.

--radius-base: 0.5rem · selector [data-theme='mistral']

LightDarkTokenValue (light)Value (dark)
--backgroundgray-50basegray-950base
--foregroundgray-950basegray-50base
--cardgray-0basegray-900base
--card-foregroundgray-950basegray-50base
--popovergray-0basegray-900base
--popover-foregroundgray-950basegray-50base
--primaryorange-600orange-400
--primary-foregroundgray-950gray-950
--secondarygray-100basegray-800base
--secondary-foregroundgray-900basegray-50base
--mutedgray-100basegray-800base
--muted-foregroundgray-500basegray-400base
--accentorange-100orange-900
--accent-foregroundorange-900orange-50
--destructivered-600basered-400base
--destructive-foregroundgray-50basegray-50base
--warningamber-500baseamber-400base
--warning-foregroundgray-950basegray-950base
--successgreen-700basegreen-400base
--success-foregroundgray-50basegray-950base
--bordergray-200baseoklch(1 0 0 / 10%)base
--inputgray-200baseoklch(1 0 0 / 15%)base
--ringorange-500orange-400
--chart-1blue-500baseblue-600base
--chart-2amber-500baseamber-600base
--chart-3green-500basegreen-600base
--chart-4cyan-500basecyan-600base
--chart-5pink-500basepink-600base
--sidebargray-50basegray-900base
--sidebar-foregroundgray-950basegray-50base
--sidebar-primaryorange-600orange-400
--sidebar-primary-foregroundgray-950gray-950
--sidebar-accentgray-100basegray-800base
--sidebar-accent-foregroundgray-900basegray-50base
--sidebar-bordergray-200baseoklch(1 0 0 / 10%)base
--sidebar-ringorange-500orange-400

Purple

Violet on lavender surfaces, adapted from the Fumadocs Purple preset (MIT). Two pairs are corrected for WCAG AA: a near-white primary foreground in light mode and a near-black destructive foreground in dark mode.

--radius-base: 0.625rem · selector [data-theme='purple']

LightDarkTokenValue (light)Value (dark)
--backgroundoklch(0.9491 0.0278 298.05)oklch(0.1605 0.013 297.13)
--foregroundoklch(0.3035 0.1296 288.37)oklch(0.8926 0.0424 297.73)
--cardoklch(0.9142 0.0337 297.92)oklch(0.1992 0.0236 296.44)
--card-foregroundoklch(0.2481 0.1513 278.88)oklch(0.8926 0.0424 297.73)
--popoveroklch(0.9572 0.0166 298.26)oklch(0.1592 0.015 296.89)
--popover-foregroundoklch(0.2481 0.1513 278.88)oklch(0.8926 0.0424 297.73)
--primaryoklch(0.5379 0.2912 295.26)oklch(0.8366 0.1046 307.06)
--primary-foregroundoklch(0.9764 0.0145 308.3)oklch(0.1434 0.0399 294.09)
--secondaryoklch(0.8983 0.0444 307.91)oklch(0.2979 0.0443 306.78)
--secondary-foregroundoklch(0.1783 0.0597 291.44)oklch(0.8926 0.0424 297.73)
--mutedoklch(0.9357 0.0251 298.1)oklch(0.1992 0.0236 296.44)
--muted-foregroundoklch(0.4838 0.1888 289.71)oklch(0.7413 0.0922 296.32)
--accentoklch(0.8876 0.0356 308.02)oklch(0.3093 0.0463 295.83)
--accent-foregroundoklch(0.2757 0.1499 296.78)oklch(0.8687 0.0418 307.93)
--destructivered-600basered-400base
--destructive-foregroundgray-50basegray-950
--warningamber-500baseamber-400base
--warning-foregroundgray-950basegray-950base
--successgreen-700basegreen-400base
--success-foregroundgray-50basegray-950base
--borderoklch(0.8116 0.0606 307.63 / 0.5)oklch(0.4403 0.1603 303.37 / 0.3)
--inputoklch(0.8116 0.0606 307.63 / 0.5)oklch(0.4403 0.1603 303.37 / 0.3)
--ringoklch(0.5379 0.2912 295.26)oklch(0.8366 0.1046 307.06)
--chart-1blue-500baseblue-600base
--chart-2amber-500baseamber-600base
--chart-3green-500basegreen-600base
--chart-4cyan-500basecyan-600base
--chart-5pink-500basepink-600base
--sidebaroklch(0.9491 0.0278 298.05)oklch(0.1605 0.013 297.13)
--sidebar-foregroundoklch(0.3035 0.1296 288.37)oklch(0.8926 0.0424 297.73)
--sidebar-primaryoklch(0.5379 0.2912 295.26)oklch(0.8366 0.1046 307.06)
--sidebar-primary-foregroundoklch(0.9764 0.0145 308.3)oklch(0.1434 0.0399 294.09)
--sidebar-accentoklch(0.8876 0.0356 308.02)oklch(0.3093 0.0463 295.83)
--sidebar-accent-foregroundoklch(0.2757 0.1499 296.78)oklch(0.8687 0.0418 307.93)
--sidebar-borderoklch(0.8116 0.0606 307.63 / 0.5)oklch(0.4403 0.1603 303.37 / 0.3)
--sidebar-ringoklch(0.5379 0.2912 295.26)oklch(0.8366 0.1046 307.06)

About the sidebar tokens

The --sidebar-* tokens are a parallel family covering the side navigation chrome. They exist because sidebars are surfaces often painted differently from background (darker, lighter, contrasting). Keeping dedicated intents avoids the "tinted background" trick that breaks when the theme changes.

About the chart tokens

--chart-1 through --chart-5 alias the categorical scale (--chart-cat-1..5), which is not themeable: every theme shows the same series colors. See Chart tokens.

Editing or adding themes

Themes are override layers on top of the base semantic layer. Their source is DTCG JSON in packages/tokens/tokens/themes/<id>.json; the CSS in packages/tokens/styles/ is generated from it. The short recipe:

  1. Create packages/tokens/tokens/themes/<id>.json with a light and a dark group, and add <id> to THEMES in packages/tokens/pipeline/model.ts.
  2. Override only what differs from the base, as DTCG tokens: an alias names the token path ({color.emerald.700}); a literal is an OKLCH color object. Whatever the light group declares as a literal color, the dark group must declare again, because :root[data-theme] outranks .dark.
  3. Build with nx build tokens. The theme gets its CSS file, its @import in theme.css, and its JSON, TypeScript, Kotlin and Swift outputs.
  4. Audit with nx test tokens: the contrast test fails on any text pair under 4.5:1 and any focus ring under 3:1, unless the pair is listed in contrast-deviations.json with a reason.

Reach for primitives first. Reference the ramps by alias ({color.<ramp>.<step>}) so a primitive edit cascades into every theme. The shipped themes hardcode OKLCH only where they match a product surface that has no primitive equivalent (e.g. the Claude cream background or the Gemini graphite). If your value is reusable, add it as a primitive instead.

On this page