design token

Colors

Color system with five base palettes and semantic tokens that adapt to light and dark themes.

The Pindoba color system uses custom color ramps stored as W3C Design Tokens (DTCG format) with automatic light and dark mode adaptation. Five base palettes feed into five semantic color groups.

Base Ramps

Five base color families, each with 11 shades (50–950). Each family has independent light and dark ramps; semantic tokens pick the right one automatically.

blue · primary
dark
50
100
200
300
400
500
600
700
800
900
950
light
50
100
200
300
400
500
600
700
800
900
950
gray · neutral
dark
50
100
200
300
400
500
600
700
800
900
950
light
50
100
200
300
400
500
600
700
800
900
950
green · success
dark
50
100
200
300
400
500
600
700
800
900
950
light
50
100
200
300
400
500
600
700
800
900
950
orange · warning
dark
50
100
200
300
400
500
600
700
800
900
950
light
50
100
200
300
400
500
600
700
800
900
950
red · danger
dark
50
100
200
300
400
500
600
700
800
900
950
light
50
100
200
300
400
500
600
700
800
900
950

Semantic Groups

Every group exposes the same shape: solid fills, text steps, borders, and a five-step surface micro-ramp. Reach for these by intent rather than raw shade.

palette · neutral
surface
surface.soft
surface.step.1
surface.step.2
surface.step.3
surface.deep
text
Aa Bb 01 text
Aa Bb 01 text.bold
Aa Bb 01 text.muted
Aa Bb 01 text.contrast
border
border
border.muted
border.bold
palette · primary
surface
surface.soft
surface.step.1
surface.step.2
surface.step.3
surface.deep
text
Aa Bb 01 text
Aa Bb 01 text.bold
Aa Bb 01 text.muted
Aa Bb 01 text.contrast
border
border
border.muted
border.bold
palette · success
surface
surface.soft
surface.step.1
surface.step.2
surface.step.3
surface.deep
text
Aa Bb 01 text
Aa Bb 01 text.bold
Aa Bb 01 text.muted
Aa Bb 01 text.contrast
border
border
border.muted
border.bold
palette · warning
surface
surface.soft
surface.step.1
surface.step.2
surface.step.3
surface.deep
text
Aa Bb 01 text
Aa Bb 01 text.bold
Aa Bb 01 text.muted
Aa Bb 01 text.contrast
border
border
border.muted
border.bold
palette · danger
surface
surface.soft
surface.step.1
surface.step.2
surface.step.3
surface.deep
text
Aa Bb 01 text
Aa Bb 01 text.bold
Aa Bb 01 text.muted
Aa Bb 01 text.contrast
border
border
border.muted
border.bold

How Colors Are Generated

Color ramps are generated in the OKLCH color space using a contrast-based approach:

  • Shade 500 is the anchor — the user-defined color for each family (lightness, chroma, hue)
  • Lighter shades (50–400) progressively reduce WCAG contrast toward 1:1 against the mode background
  • Darker shades (600–950) progressively increase contrast toward 21:1
  • A binary search finds the exact lightness value for each shade that meets its target contrast ratio

Text tokens are contrast-solved against the worst-case surface — both the neutral and own-family surface.deep — so text always meets its target ratio regardless of which surface it sits on.

Surfaces are a 5-step micro-ramp interpolated between shade 50 and shade 100, providing fine-grained background variation without jumping to the next full shade.

Per-mode palettes: light and dark modes have independent color family inputs. A lightness reference family (default: blue) shares its solved lightness curve with all other families, keeping them visually consistent. Neutral (gray) always uses its own independent lightness curve.

Contrast Colors

Two fixed contrast values are available for cases where you need guaranteed light or dark:

contrast.darkest; // #181818
contrast.lightest; // #f9fbff

Usage

With Panda CSS

import { css } from "@pindoba/styled-system/css";

// Semantic surface and text
<div className={css({
  backgroundColor: "neutral.surface.soft",
  color: "neutral.text.bold",
})}>
  Card content
</div>

// Solid fill button
<button className={css({
  backgroundColor: "primary",
  color: "primary.text.contrast",
  _hover: { backgroundColor: "primary.hover" },
  _active: { backgroundColor: "primary.active" },
})}>
  Submit
</button>

// Subtle surface button
<button className={css({
  backgroundColor: "primary.surface.soft",
  color: "primary.text",
  _hover: { backgroundColor: "primary.surface.step.2" },
  _active: { backgroundColor: "primary.surface.deep" },
})}>
  Secondary action
</button>

// Status feedback
<div className={css({
  backgroundColor: "danger.surface.soft",
  color: "danger.text.bold",
  borderWidth: "1px",
  borderColor: "danger.border.muted",
})}>
  Error message
</div>

With colorPalette

The colorPalette utility lets components switch between semantic groups without duplicating styles:

<div className={css({ colorPalette: "success" })}>
  <span className={css({ color: "colorPalette.text.bold" })}>
    Status text
  </span>
</div>

<div className={css({ colorPalette: "danger" })}>
  <span className={css({ color: "colorPalette.text.bold" })}>
    Error text
  </span>
</div>

Best Practices

  • Use semantic tokens (primary.surface.soft, neutral.text.bold) rather than raw base colors (blue.light.500)
  • Use .text.contrast for text on solid-colored backgrounds (primary, primary.hover, primary.active)
  • Use .text.muted for helper text and secondary content
  • Use .border.muted for subtle separators and .border.bold for emphasis
  • Use surface.soft for light backgrounds and surface.deep for deeper emphasis — they automatically adapt to the active theme mode
  • Borders use alpha-blended variants of the text color: .border (30%), .border.muted (15%), .border.bold (65%)