Colors

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 semantic color groups.

Color Palette

Blue (Primary)

Light
50100200300400500600700800900950 Dark

Gray (Neutral)

Light
50100200300400500600700800900950 Dark

Green (Success)

Light
50100200300400500600700800900950 Dark

Orange (Warning)

Light
50100200300400500600700800900950 Dark

Red (Danger)

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

const containerStyle = css({
  display: "grid",
  gridTemplateColumns: "1fr",
  gap: "lg",
  width: "100%",
});

const colorSectionStyle = css.raw({
  display: "grid",
  gridTemplateColumns: "auto repeat(11, 1fr)",
  gap: "4xs",
  alignItems: "center",
  backgroundColor: "neutral.surface",
  borderRadius: "lg",
  padding: "lg",
  border: "1px solid",
  borderColor: "neutral.border.muted",
});

const sectionTitleStyle = css.raw({
  fontSize: "md",
  fontWeight: "bold",
  marginBottom: "sm",
  color: "neutral.text.bold",
  gridColumn: "1 / -1",
});

const modeLabelStyle = css.raw({
  fontSize: "2xs",
  fontFamily: "mono",
  color: "neutral.text",
  textTransform: "uppercase",
  letterSpacing: "wide",
  paddingRight: "sm",
});

const swatchBoxStyle = css.raw({
  width: "full",
  aspectRatio: "1 / 1",
  borderRadius: "md",
  border: "1px solid",
  borderColor: "neutral.border",
});

const shadeLabelStyle = css.raw({
  fontSize: "2xs",
  fontFamily: "mono",
  color: "neutral.text",
  textAlign: "center",
});

// Light mode color ramp styles
const lightBgStyles = {
  "blue.50": css.raw({ backgroundColor: "blue.light.50" }),
  "blue.100": css.raw({ backgroundColor: "blue.light.100" }),
  "blue.200": css.raw({ backgroundColor: "blue.light.200" }),
  "blue.300": css.raw({ backgroundColor: "blue.light.300" }),
  "blue.400": css.raw({ backgroundColor: "blue.light.400" }),
  "blue.500": css.raw({ backgroundColor: "blue.light.500" }),
  "blue.600": css.raw({ backgroundColor: "blue.light.600" }),
  "blue.700": css.raw({ backgroundColor: "blue.light.700" }),
  "blue.800": css.raw({ backgroundColor: "blue.light.800" }),
  "blue.900": css.raw({ backgroundColor: "blue.light.900" }),
  "blue.950": css.raw({ backgroundColor: "blue.light.950" }),
  "gray.50": css.raw({ backgroundColor: "gray.light.50" }),
  "gray.100": css.raw({ backgroundColor: "gray.light.100" }),
  "gray.200": css.raw({ backgroundColor: "gray.light.200" }),
  "gray.300": css.raw({ backgroundColor: "gray.light.300" }),
  "gray.400": css.raw({ backgroundColor: "gray.light.400" }),
  "gray.500": css.raw({ backgroundColor: "gray.light.500" }),
  "gray.600": css.raw({ backgroundColor: "gray.light.600" }),
  "gray.700": css.raw({ backgroundColor: "gray.light.700" }),
  "gray.800": css.raw({ backgroundColor: "gray.light.800" }),
  "gray.900": css.raw({ backgroundColor: "gray.light.900" }),
  "gray.950": css.raw({ backgroundColor: "gray.light.950" }),
  "green.50": css.raw({ backgroundColor: "green.light.50" }),
  "green.100": css.raw({ backgroundColor: "green.light.100" }),
  "green.200": css.raw({ backgroundColor: "green.light.200" }),
  "green.300": css.raw({ backgroundColor: "green.light.300" }),
  "green.400": css.raw({ backgroundColor: "green.light.400" }),
  "green.500": css.raw({ backgroundColor: "green.light.500" }),
  "green.600": css.raw({ backgroundColor: "green.light.600" }),
  "green.700": css.raw({ backgroundColor: "green.light.700" }),
  "green.800": css.raw({ backgroundColor: "green.light.800" }),
  "green.900": css.raw({ backgroundColor: "green.light.900" }),
  "green.950": css.raw({ backgroundColor: "green.light.950" }),
  "orange.50": css.raw({ backgroundColor: "orange.light.50" }),
  "orange.100": css.raw({ backgroundColor: "orange.light.100" }),
  "orange.200": css.raw({ backgroundColor: "orange.light.200" }),
  "orange.300": css.raw({ backgroundColor: "orange.light.300" }),
  "orange.400": css.raw({ backgroundColor: "orange.light.400" }),
  "orange.500": css.raw({ backgroundColor: "orange.light.500" }),
  "orange.600": css.raw({ backgroundColor: "orange.light.600" }),
  "orange.700": css.raw({ backgroundColor: "orange.light.700" }),
  "orange.800": css.raw({ backgroundColor: "orange.light.800" }),
  "orange.900": css.raw({ backgroundColor: "orange.light.900" }),
  "orange.950": css.raw({ backgroundColor: "orange.light.950" }),
  "red.50": css.raw({ backgroundColor: "red.light.50" }),
  "red.100": css.raw({ backgroundColor: "red.light.100" }),
  "red.200": css.raw({ backgroundColor: "red.light.200" }),
  "red.300": css.raw({ backgroundColor: "red.light.300" }),
  "red.400": css.raw({ backgroundColor: "red.light.400" }),
  "red.500": css.raw({ backgroundColor: "red.light.500" }),
  "red.600": css.raw({ backgroundColor: "red.light.600" }),
  "red.700": css.raw({ backgroundColor: "red.light.700" }),
  "red.800": css.raw({ backgroundColor: "red.light.800" }),
  "red.900": css.raw({ backgroundColor: "red.light.900" }),
  "red.950": css.raw({ backgroundColor: "red.light.950" }),
} as const;

// Dark mode color ramp styles
const darkBgStyles = {
  "blue.50": css.raw({ backgroundColor: "blue.dark.50" }),
  "blue.100": css.raw({ backgroundColor: "blue.dark.100" }),
  "blue.200": css.raw({ backgroundColor: "blue.dark.200" }),
  "blue.300": css.raw({ backgroundColor: "blue.dark.300" }),
  "blue.400": css.raw({ backgroundColor: "blue.dark.400" }),
  "blue.500": css.raw({ backgroundColor: "blue.dark.500" }),
  "blue.600": css.raw({ backgroundColor: "blue.dark.600" }),
  "blue.700": css.raw({ backgroundColor: "blue.dark.700" }),
  "blue.800": css.raw({ backgroundColor: "blue.dark.800" }),
  "blue.900": css.raw({ backgroundColor: "blue.dark.900" }),
  "blue.950": css.raw({ backgroundColor: "blue.dark.950" }),
  "gray.50": css.raw({ backgroundColor: "gray.dark.50" }),
  "gray.100": css.raw({ backgroundColor: "gray.dark.100" }),
  "gray.200": css.raw({ backgroundColor: "gray.dark.200" }),
  "gray.300": css.raw({ backgroundColor: "gray.dark.300" }),
  "gray.400": css.raw({ backgroundColor: "gray.dark.400" }),
  "gray.500": css.raw({ backgroundColor: "gray.dark.500" }),
  "gray.600": css.raw({ backgroundColor: "gray.dark.600" }),
  "gray.700": css.raw({ backgroundColor: "gray.dark.700" }),
  "gray.800": css.raw({ backgroundColor: "gray.dark.800" }),
  "gray.900": css.raw({ backgroundColor: "gray.dark.900" }),
  "gray.950": css.raw({ backgroundColor: "gray.dark.950" }),
  "green.50": css.raw({ backgroundColor: "green.dark.50" }),
  "green.100": css.raw({ backgroundColor: "green.dark.100" }),
  "green.200": css.raw({ backgroundColor: "green.dark.200" }),
  "green.300": css.raw({ backgroundColor: "green.dark.300" }),
  "green.400": css.raw({ backgroundColor: "green.dark.400" }),
  "green.500": css.raw({ backgroundColor: "green.dark.500" }),
  "green.600": css.raw({ backgroundColor: "green.dark.600" }),
  "green.700": css.raw({ backgroundColor: "green.dark.700" }),
  "green.800": css.raw({ backgroundColor: "green.dark.800" }),
  "green.900": css.raw({ backgroundColor: "green.dark.900" }),
  "green.950": css.raw({ backgroundColor: "green.dark.950" }),
  "orange.50": css.raw({ backgroundColor: "orange.dark.50" }),
  "orange.100": css.raw({ backgroundColor: "orange.dark.100" }),
  "orange.200": css.raw({ backgroundColor: "orange.dark.200" }),
  "orange.300": css.raw({ backgroundColor: "orange.dark.300" }),
  "orange.400": css.raw({ backgroundColor: "orange.dark.400" }),
  "orange.500": css.raw({ backgroundColor: "orange.dark.500" }),
  "orange.600": css.raw({ backgroundColor: "orange.dark.600" }),
  "orange.700": css.raw({ backgroundColor: "orange.dark.700" }),
  "orange.800": css.raw({ backgroundColor: "orange.dark.800" }),
  "orange.900": css.raw({ backgroundColor: "orange.dark.900" }),
  "orange.950": css.raw({ backgroundColor: "orange.dark.950" }),
  "red.50": css.raw({ backgroundColor: "red.dark.50" }),
  "red.100": css.raw({ backgroundColor: "red.dark.100" }),
  "red.200": css.raw({ backgroundColor: "red.dark.200" }),
  "red.300": css.raw({ backgroundColor: "red.dark.300" }),
  "red.400": css.raw({ backgroundColor: "red.dark.400" }),
  "red.500": css.raw({ backgroundColor: "red.dark.500" }),
  "red.600": css.raw({ backgroundColor: "red.dark.600" }),
  "red.700": css.raw({ backgroundColor: "red.dark.700" }),
  "red.800": css.raw({ backgroundColor: "red.dark.800" }),
  "red.900": css.raw({ backgroundColor: "red.dark.900" }),
  "red.950": css.raw({ backgroundColor: "red.dark.950" }),
} as const;

type BgKey = keyof typeof lightBgStyles;

const colorPalettes = [
  { name: "Blue (Primary)", colorKey: "blue" as const },
  { name: "Gray (Neutral)", colorKey: "gray" as const },
  { name: "Green (Success)", colorKey: "green" as const },
  { name: "Orange (Warning)", colorKey: "orange" as const },
  { name: "Red (Danger)", colorKey: "red" as const },
];

const shades = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950] as const;
---

<div class={containerStyle}>
  {
    colorPalettes.map(({ name, colorKey }) => (
      <div class={css(colorSectionStyle)}>
        <h3 class={css(sectionTitleStyle)}>{name}</h3>

        {/* Light row: label + 11 swatches */}
        <span class={css(modeLabelStyle)}>Light</span>
        {shades.map((shade) => {
          const bgKey = `${colorKey}.${shade}` as BgKey;
          return <div class={css(swatchBoxStyle, lightBgStyles[bgKey])} />;
        })}

        {/* Labels row: empty cell + 11 shade labels */}
        <span />
        {shades.map((shade) => (
          <span class={css(shadeLabelStyle)}>{shade}</span>
        ))}

        {/* Dark row: label + 11 swatches */}
        <span class={css(modeLabelStyle)}>Dark</span>
        {shades.map((shade) => {
          const bgKey = `${colorKey}.${shade}` as BgKey;
          return <div class={css(swatchBoxStyle, darkBgStyles[bgKey])} />;
        })}
      </div>
    ))
  }
</div>

Base Colors

Five base color families, each with 11 shades (50–950):

  • Blue — maps to the primary semantic group
  • Gray — maps to the neutral semantic group
  • Green — maps to the success semantic group
  • Orange — maps to the warning semantic group
  • Red — maps to the danger semantic group

Each color has separate light and dark ramps. Tokens reference these ramps through semantic tokens that resolve to the correct mode automatically.

Semantic Tokens

Semantic tokens provide structured access to colors by intent rather than raw shade. Each semantic group exposes the same set of sub-tokens:

{
  // Text colors
  primary.text            // Default text
  primary.text.bold       // High-emphasis text
  primary.text.contrast   // Text on solid backgrounds
  primary.text.contrast.bold

  // Borders (rendered at 65% opacity)
  primary.border          // Default border
  primary.border.muted    // Subtle separation
  primary.border.bold     // Strong emphasis

  // Surfaces
  primary.surface         // Default surface fill
  primary.surface.hover   // Hover state
  primary.surface.active  // Active/pressed state

  // Sunken (recessed backgrounds)
  primary.sunken
  primary.sunken.hover
  primary.sunken.active

  // Interactive states
  primary.hover
  primary.active
}

The same structure applies to neutral, success, warning, and danger.

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",
  color: "neutral.text.bold",
})}>
  Card content
</div>

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

// Status feedback
<div className={css({
  backgroundColor: "danger.surface",
  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, neutral.text.bold) rather than raw base colors (blue.light.500)
  • Use .text.contrast for text on solid-colored backgrounds
  • Use .border.muted for subtle separators and .border.bold for emphasis
  • Use .surface / .sunken for background fills — they automatically adapt to the active theme mode
  • Borders are rendered at 65% opacity by default for a natural look