Variation

Palette Options

No entries yet

Palette options

Palette options are generated per client and presented for approval. Client-facing.

3 options, exactly one marked recommended.

An entry must satisfy PaletteOption

export type PaletteRole =
  | "primary"
  | "ink"
  | "paper"
  | "rule"
  | "muted";

export type PaletteOption = {
  id: string;
  name: string;                       // semantic, never descriptive
  recommended: boolean;               // exactly one option is true
  reasoning: string;                  // why this one is recommended
  uxRationale: string;                // client-facing benefit framing
  /** oklch only — never hex, rgb or HSL. */
  roles: Record<PaletteRole, string>;
  contrast: {
    bodyOnPaper: number;              // >= 4.5
    largeOnPaper: number;             // >= 3
    uiOnPaper: number;                // >= 3
  };
  audience: "client";
};

Generator

Palette generator

Run this once per client, with the client's inputs pasted in. The shared constraints travel with it automatically when you copy.

Placeholder — replace on remixRecommended

Neutral Blueprint — role assignment only

The blueprint's own five roles, unchanged: --ink, --paper, --accent, --rule, --muted. No fifth hue. Present so the contrast table format is visible before any brand colour arrives.

Specification

--ink
oklch(0.22 0 0) — text, deep surfaces
--paper
oklch(1 0 0) — primary background
--accent
oklch(0.955 0 0) — CTA fill, links, highlights
--rule
oklch(0.9 0 0) — borders, dividers, muted surfaces
--muted
oklch(0.5 0 0) — secondary text (alpha of ink)
BB Global Colors prefix
jcd-color (no leading dashes)

Why it works

Five fixed roles keep every surface decision pre-made — Nielsen's consistency and standards heuristic. --muted is an alpha of --ink rather than a separate grey, so secondary text stays correct on a tinted ground instead of drifting light.

On every device

The same five colours carry the whole site, so a page reads the same on a laptop in an office and a phone in daylight — nothing washes out at one size and not the other.

Why recommended

The only entry in the set. A generated set replaces it with three options and moves this flag to whichever palette carries the client's brand colour in the accent role without a text-contrast exception.

Contrast — computed from token values

  • --ink on --paper17.3:1AAA
  • --muted on --paper6.0:1AA
  • --rule on --paper1.4:1FAIL
  • --paper on --ink17.3:1AAA
  • --rule on --ink12.9:1AAA
  • CTA: --accent-foreground on --accent16.4:1AAA

Notes

  • --rule fails 4.5:1 by design: it is a border and surface token, never a text colour. Stated rather than hidden, because a FAIL with no explanation is the row that gets ignored.
  • Neutral greys stand in for brand hues. If a supplied brand colour fails 4.5:1 as a text ground, the generator states the failure and offers the three documented remedies — it never substitutes silently.