Skip to content
Facade UI
Colour mode
GitHub (opens in a new tab)

Theme customiser

Start from one of the three presets, adjust it, and export the CSS. The palette is scored live against the same pairs and thresholds that scripts/check-contrast.ts enforces on every commit — so a theme that shows all-green here is one the build would accept.

Colours are edited in OKLCH on purpose. Lightness is the axis contrast actually depends on, so dragging L moves the ratio predictably, where nudging a hex value is guesswork.

Starting preset
Editing which mode
All contrast checks pass

Tokens — light

  • Background#ffffff100°
  • Foreground#0101010.14500°
  • Card#ffffff100°
  • Card foreground#0101010.14500°
  • Popover#ffffff100°
  • Popover foreground#0101010.14500°
  • Primary#0202020.20500°
  • Primary foreground#f4f4f40.98500°
  • Secondary#e9e9e90.9700°
  • Secondary foreground#0202020.20500°
  • Muted#e9e9e90.9700°
  • Muted foreground#2121210.50500°
  • Accent#e9e9e90.9700°
  • Accent foreground#0202020.20500°
  • Destructive#cc00010.5770.24527°
  • Destructive foreground#f4f4f40.98500°
  • Border#c8c8c80.92200°
  • Input border#7979790.7800°
  • Focus ring#1717170.4500°

Preview

A section heading

Supporting copy, which is where a muted foreground usually stops meeting 4.5:1.

PrimarySecondaryOutline
A form field borderA focused card

Contrast — light

The same pairs and thresholds scripts/check-contrast.ts enforces in CI.

Contrast results for the light palette
PairRatioResult
Body text20.90:1 (min 4.5)Passes
Supporting copy16.13:1 (min 4.5)Passes
Copy on muted panels13.26:1 (min 4.5)Passes
Card text20.90:1 (min 4.5)Passes
Popover text20.90:1 (min 4.5)Passes
Primary button label18.79:1 (min 4.5)Passes
Secondary button label17.03:1 (min 4.5)Passes
Accent surface text17.03:1 (min 4.5)Passes
Destructive button label5.33:1 (min 4.5)Passes
Primary as a surface or icon20.72:1 (min 3)Passes
Focus ring17.89:1 (min 3)Passes
Focus ring on cards17.89:1 (min 3)Passes
Form field border4.35:1 (min 3)Passes
Form field border on cards4.35:1 (min 3)Passes

Export

Paste this into your stylesheet after the Facade tokens, then set data-facade-theme="custom" on <html>.

app/globals.css
[data-facade-theme="custom"] {
  --background: oklch(1 0 0);
  --foreground: oklch(0.145 0 0);
  --card: oklch(1 0 0);
  --card-foreground: oklch(0.145 0 0);
  --popover: oklch(1 0 0);
  --popover-foreground: oklch(0.145 0 0);
  --primary: oklch(0.205 0 0);
  --primary-foreground: oklch(0.985 0 0);
  --secondary: oklch(0.97 0 0);
  --secondary-foreground: oklch(0.205 0 0);
  --muted: oklch(0.97 0 0);
  --muted-foreground: oklch(0.505 0 0);
  --accent: oklch(0.97 0 0);
  --accent-foreground: oklch(0.205 0 0);
  --destructive: oklch(0.577 0.245 27.325);
  --destructive-foreground: oklch(0.985 0 0);
  --border: oklch(0.922 0 0);
  --input: oklch(0.78 0 0);
  --ring: oklch(0.45 0 0);
}

.dark {
  --background: oklch(0.145 0 0);
  --foreground: oklch(0.985 0 0);
  --card: oklch(0.205 0 0);
  --card-foreground: oklch(0.985 0 0);
  --popover: oklch(0.269 0 0);
  --popover-foreground: oklch(0.985 0 0);
  --primary: oklch(0.922 0 0);
  --primary-foreground: oklch(0.205 0 0);
  --secondary: oklch(0.269 0 0);
  --secondary-foreground: oklch(0.985 0 0);
  --muted: oklch(0.269 0 0);
  --muted-foreground: oklch(0.782 0 0);
  --accent: oklch(0.371 0 0);
  --accent-foreground: oklch(0.985 0 0);
  --destructive: oklch(0.704 0.191 22.216);
  --destructive-foreground: oklch(0.145 0 0);
  --border: oklch(1 0 0 / 12%);
  --input: oklch(0.74 0 0);
  --ring: oklch(0.78 0 0);
}