Verdigris uses OKLch as the canonical color space. All color tokens are defined in OKLch; other formats (HSL, hex, RGB) are generated by the build pipeline.
Why not HSL?
HSL is perceptually non-uniform — hsl(60, 100%, 50%) (yellow) appears far brighter than hsl(240, 100%, 50%) (blue) despite identical L values. This makes palette interpolation unpredictable and accessibility auditing unreliable.
OKLch fixes this:
- L (lightness) is perceptually linear — equal numeric changes produce equal visual changes
- C (chroma) controls saturation without shifting perceived brightness
- h (hue) rotates through the color wheel
This means Patina's gradient palette (teal → purple → red → yellow) was generated by rotating the hue while keeping lightness and chroma in controlled ranges. The result is a harmonious palette that "feels" balanced across all hues.
Browser support: OKLch is supported in all evergreen browsers since 2023. The build pipeline generates HSL fallbacks for email clients and legacy contexts.
The palette is a hue-rotation gradient anchored at four points:
| Name | OKLch | Approx Hex | Role |
|---|---|---|---|
| Verdigris (teal) | oklch(0.75 0.1286 191.57) |
#0fc8c3 | Primary brand, CTAs, links |
| Midnight Purple | oklch(0.29 0.1506 289.33) |
~#1a0a4a | Deep accent, dark sections |
| Pastel Red | oklch(0.7 0.1909 24.11) |
~#e85d3a | Warm accent, sidebar active |
| Cyber Yellow | oklch(0.87 0.1786 92.23) |
~#d4c520 | Highlight, attention |
Between each anchor, three interpolation steps create a smooth 16-color chart palette. See tokens/color/base.json for all values.
Teal (191°) → step1 (216°) → step2 (240°) → step3 (265°)
→ Purple (289°) → step1 (313°) → step2 (337°) → step3 (0°)
→ Red (24°) → step1 (41°) → step2 (58°) → step3 (75°)
→ Yellow (92°) → step1 (113°) → step2 (137°) → step3 (164°)
→ (back to Teal)
This creates a full-spectrum palette from a single generative rule — add or remove steps by interpolating between the anchors.
The neutral scale is zinc-tinted (hue ~286°) rather than pure gray. This gives surfaces a subtle warmth that complements the teal brand color. Extracted from Patina's production CSS.
| Token | OKLch | Role |
|---|---|---|
| neutral.50 | oklch(0.985 0 0) |
Near-white |
| neutral.100 | oklch(0.967 0.001 286.375) |
Secondary/muted bg |
| neutral.200 | oklch(0.92 0.004 286.32) |
Borders, inputs |
| neutral.400 | oklch(0.705 0.015 286.067) |
Ring, muted-fg (dark) |
| neutral.500 | oklch(0.552 0.016 285.938) |
Muted-fg (light), ring (dark) |
| neutral.800 | oklch(0.274 0.006 286.033) |
Dark mode secondary |
| neutral.900 | oklch(0.21 0.006 285.885) |
Light primary, dark card |
| neutral.950 | oklch(0.141 0.005 285.823) |
Light foreground, dark bg |
Both codebases use the same mechanism: CSS custom properties toggled via a .dark class on the HTML element. The semantic tokens (background, foreground, primary, etc.) swap values between light and dark.
Key dark mode choices:
- Background swaps from white to neutral.950 (near-black)
- Primary inverts from near-black to light gray — ensuring contrast in both modes
- Borders become semi-transparent white (
oklch(1 0 0 / 10%)) for a subtle glass effect - Sidebar primary stays pastel-red in both modes — brand consistency
See tokens/color/semantic-dark.json for all overrides.
The www site darkened the brand teal from hsl(178, 86%, 42%) to hsl(178, 86%, 28%) for WCAG AA text contrast on white backgrounds (~4.9:1 ratio). This is documented as legacy.www-primary-light in the token set.
Recommendation: Use the original bright teal (brand.verdigris) for decorative/non-text use (backgrounds, illustrations, data viz). Use neutral.900 (Patina's approach) or the darkened teal (www's approach) for text/interactive elements where contrast matters.
The build pipeline generates:
| Format | File | Consumer |
|---|---|---|
| OKLch CSS vars | css/oklch.css |
Patina, modern browsers |
| HSL CSS vars | css/hsl.css |
www (until OKLch migration) |
| Hex JSON | hex/colors.json |
Email templates, Figma, print |
| Tailwind preset | tailwind/preset.js |
Both codebases via config |
| Token | www | Patina | Resolution |
|---|---|---|---|
| Color space | HSL | OKLch | www should migrate to OKLch |
| Primary (light) | Darkened teal hsl(178,86%,28%) |
Near-black oklch(0.21...) |
Different strategies — both valid |
| Ring/focus | Green-shifted hsl(153,67%,38%) |
Neutral oklch(0.705...) |
www should adopt Patina's neutral ring |
| Brand teal | hsl(178,86%,42%) |
oklch(0.75,0.1286,191.57) |
Equivalent values — confirmed |