Brand Palette — 16-stop hue rotation
Verdigris
0.75 0.13 191.6
mix-1
0.64 0.13 216.0
mix-2
0.52 0.14 240.5
mix-3
0.41 0.15 264.9
Midnight Purple
0.29 0.15 289.3
mp-step-1
0.39 0.16 313.0
mp-step-2
0.50 0.17 336.7
mp-step-3
0.60 0.18 0.4
Pastel Red
0.70 0.19 24.1
pr-step-1
0.74 0.19 41.1
pr-step-2
0.79 0.18 58.2
pr-step-3
0.83 0.18 75.2
Cyber Yellow
0.87 0.18 92.2
cy-step-1
0.81 0.17 113.3
cy-step-2
0.77 0.16 137.1
cy-step-3
0.75 0.14 163.9
Neutral Scale — zinc-tinted (hue ~286)
50
0.985 0 0
100
0.967 0.001 286
200
0.920 0.004 286
400
0.705 0.015 286
500
0.552 0.016 286
800
0.274 0.006 286
900
0.210 0.006 286
950
0.141 0.005 286
Brand Gradient
Contrast Check — brand teal on backgrounds
Teal on dark  PASS 7.2 : 1
Teal on white  FAIL 2.5 : 1
Semantic Tokens — Light vs Dark
Light Mode
background: white
foreground: neutral.950
card: white
muted: neutral.100
border: neutral.200
Dark Mode
background: neutral.950
foreground: neutral.50
card: neutral.900
muted: neutral.800
border: white/10%
Documentation

Color System

Why OKLch

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.

Brand Palette

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.

Gradient Logic

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.

Palette Semantics — What the Colors Mean

The brand palette has 16 tokens but the design system must define what they mean, not just what they are. This is critical for AI agents and evaluator pipelines that select colors without human visual judgment.

The palette divides into 6 semantic regions based on content category:

Trust (Teal → Blue, hue 191°–240°)

Tokens: verdigris, mix-step-1, mix-step-2 Content: Technology, platform capabilities, data quality, primary brand expression Why: The anchor of the Verdigris brand. Bright, authoritative, technically precise. This is what a customer should associate with the company name.

  • Use as section accents for technology and platform content
  • Safe as text on dark backgrounds (12.3:1 contrast on neutral.950)
  • NOT safe as text on white (fails WCAG at ~2.9:1)
  • Dark mode tint: oklch(0.75 0.1286 191.57 / 15%) over neutral.950

Depth (Deep Blue → Purple, hue 265°–289°)

Tokens: mix-step-3, midnight-purple Content: AI/intelligence features, premium sections, dark hero backgrounds, footer Why: The darkest region (L=0.29–0.41). Creates gravitas and sophistication. Works best as backgrounds, not foreground elements.

  • Use for dark section backgrounds and hero overlays
  • NOT as text — too dark, invisible on dark backgrounds
  • Dark mode tint: use 18%+ opacity — below 15%, midnight-purple (chroma 0.15) is indistinguishable from neutral gray
  • Excellent for gradient endpoints paired with teal

Energy (Purple → Magenta, hue 313°–0°)

Tokens: midnight-purple-step-1, midnight-purple-step-2, midnight-purple-step-3 Content: Fault detection, real-time monitoring, anomaly indicators, alerting Why: High chroma, vibrant mid-range. These colors demand attention without being aggressive — appropriate for detection and signal content.

  • mp-step-2 (L=0.50) and mp-step-3 (L=0.60) work as text on both light and dark backgrounds
  • Use as accent borders, icon tints, alert section backgrounds
  • Dark mode tint: oklch(0.495 0.1708 336.72 / 12%) over neutral.950

Warmth (Red → Coral, hue 24°–41°)

Tokens: pastel-red, pastel-red-step-1 Content: Contact/conversation, CTA hover states, team sections, customer stories Why: Warm tones invite human connection. The sidebar-primary color in Patina. Appropriate for sections where the brand becomes personal.

  • Use for CTA hover shifts (teal → warm on hover)
  • Pastel red (L=0.70) works as text on dark backgrounds only
  • Dark mode tint: oklch(0.7 0.1909 24.11 / 10%) over neutral.950

Results (Orange → Yellow, hue 58°–92°)

Tokens: pastel-red-step-2, pastel-red-step-3, cyber-yellow Content: Metrics, ROI, stranded capacity recovery, financial outcomes, proof points Why: Bright, optimistic tones (L=0.79–0.87) that say “look at these numbers.” Natural for stats and outcomes.

  • HIGH CONTRAST RISK — very light tokens. Only use on dark backgrounds.
  • Use as metric/stat highlights, warm section accents
  • Dark mode tint: oklch(0.87 0.1786 92.23 / 8%) — visible despite low opacity due to high lightness

Growth (Yellow → Green, hue 113°–164°)

Tokens: cyber-yellow-step-1, cyber-yellow-step-2, cyber-yellow-step-3 Content: M&V results, capacity recovery, sustainability, environmental impact, completion Why: Green-teal tones that close the chromatic loop back to brand teal. Natural for sustainability and recovery outcomes.

  • Light tokens (L=0.75–0.81) — dark backgrounds only
  • Dark mode tint: oklch(0.7698 0.1588 137.1 / 10%) over neutral.950
  • Bridges back to the trust region — use for sections that resolve/conclude

Neutral (Breathing Room)

Tokens: neutral.50 through neutral.950 Content: Body text, structural sections, form backgrounds, breathing room between colored sections Rule: At least 30% of page sections should use neutral backgrounds to prevent chromatic fatigue.

Taste Boundaries — Restraint Rules

The palette semantics without ceilings will produce a rainbow. The brand pillars define the boundaries:

  • “Controlled color palette, no visual clutter.” (Masterful)
  • “Subtle use of the brand gradient.” (Refined)
  • “Every element earns its place.” (Precision)
  • “Credibility through restraint. Sophisticated buyers, not impulse shoppers.”

Color is earned, not assigned by lookup table. An accent region appears because it makes the page better, not because a mapping table says it should.

Teal dominance: Teal + neutrals must comprise at least 70% of any surface’s color expression. Other palette regions are rare accents, not co-primaries. The brand IS teal.

Maximum regions per surface:

Surface Max non-neutral regions Rationale
Web page (homepage) 2 (trust + 1 accent) Controlled palette; 2 accents only for 10+ section pages with justification
Landing page 1 (brand teal only) Focused message, no chromatic distraction
Ad banner 1 (brand teal only) Instant recognition, not variety
Email 1 (brand teal only) Inbox is noisy — stay clean
White paper 2 (trust + 1 accent for data) Professional restraint
Physical goods 1 (brand teal only) Hardware/packaging: maximum brand clarity
Data visualization 6 (full palette) This is what the gradient was designed for
Slide deck 2 per slide One accent per point

Section limits (web pages):

  • No more than 30% of sections should have non-neutral palette accents — the rest should breathe
  • Never place two colored sections adjacent — always separate with neutral
  • Accents are subtle (background tints and label colors) — NOT full-saturation backgrounds

Section Flow — Lightness Rhythm

Pages have a lightness direction. Alternating dark and light sections creates a strobe — the eye has to re-adapt at every boundary. Commit to a direction and vary within it.

Light-mode page flow:

Dark hero → white → neutral.100 → white → [one dark accent] → white → footer
  • Content sections flow through white and neutral.100 (subtle tonal shift, not a contrast flip)
  • At most ONE dark-background section as a deliberate accent moment (e.g., detection callout, CTA strip)
  • Hero and footer are always dark — they don’t count toward the limit

Dark-mode page flow:

neutral.950 → neutral.900 → neutral.950 → [tinted accent] → neutral.900 → footer
  • Content sections flow through neutral.950 and neutral.900
  • Brand-tinted sections provide variety without lightness jumps

Rules:

  • No strobe — never alternate dark/light/dark/light across consecutive sections
  • Max lightness jump in content flow: 0.15 OKLch L* — white (L=1.0) to neutral.100 (L=0.967) is fine; white to neutral.900 (L=0.21) is not
  • Consistent text color — light flow = dark text throughout; dark flow = light text throughout. Don’t force the reader to re-adapt.

Usage Rules

  1. Teal first — teal + neutrals dominate every surface (70%+ minimum)
  2. Max 2 regions on a web page — trust + at most 1 accent region (earned, not automatic)
  3. No random assignment — section accent colors must match the content category above
  4. Breathing room — at least 70% neutral sections; never two colored sections adjacent
  5. Subtlety — palette accents are tints and labels, not saturated backgrounds
  6. Section flow — commit to a lightness direction; max one dark accent moment per light page
  7. Dark tint minimum — depth region needs 18%+ opacity; all others need 10%+
  8. Verify contrast — text on brand-tinted backgrounds must still pass WCAG AA (4.5:1)

See rules/visual-rules.ymlcolor.palette_semantics for the machine-consumable version of this guidance.

Neutral Scale

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

Dark Mode Strategy

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.

WCAG Contrast

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.

Multi-Format Output

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

Known Discrepancies (www vs Patina)

Token www Patina Resolution
Color space HSL OKLch OKLch is canonical; HSL output available for compatibility
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...) Neutral ring is canonical
Brand teal hsl(178,86%,42%) oklch(0.75,0.1286,191.57) Equivalent values — confirmed