This file provides context for AI coding agents generating on-brand Verdigris visuals.
When generating UI components, pages, or visual assets for Verdigris:
- Read
tokens/color/base.json— the canonical brand palette in OKLch - Read
tokens/typography/— font families and scale - Read
foundations/docs for rationale behind decisions - Check
rules/visual-rules.ymlfor machine-enforceable constraints - Review
examples/for annotated good/bad references
| Name | OKLch | Hex | Usage |
|---|---|---|---|
| Verdigris (primary teal) | oklch(0.75 0.1286 191.57) |
#0fc8c3 | Decorative brand color |
| Midnight Purple | oklch(0.29 0.1506 289.33) |
~#1a0a4a | Deep accent |
| Pastel Red | oklch(0.7 0.1909 24.11) |
~#e85d3a | Warm accent |
| Cyber Yellow | oklch(0.87 0.1786 92.23) |
~#d4c520 | Highlight |
Do NOT use brand teal as text on white — it fails WCAG AA (2.8:1 ratio). Use near-black (oklch(0.21 0.006 285.885)) for text.
| Element | Font | Size | Weight |
|---|---|---|---|
| Body text | Inter | 1rem (16px) | 400 |
| Headings (marketing) | Lato | 4rem/3rem/2rem | 700 |
| Headings (app) | Inter | (Tailwind defaults) | 700 |
| Code/metrics | JetBrains Mono | — | 400 |
| Buttons | Inter | 1rem | 600 |
- Grid: 4px base (0.25rem increments)
- Container max-width: 80rem (1280px)
- Page padding: 2.5rem (40px), 1.5rem on mobile
- Section padding: 4rem vertical (standard), 8rem (large)
- Border radius: 0.625rem (10px) — Patina canonical
- Use OKLch values from
tokens/color/base.json - Neutral scale has a zinc tint (hue ~286) — not pure gray
- Dark mode: near-black background (not pure
#000000) - Dark mode borders: semi-transparent white (
oklch(1 0 0 / 10%))
- Body: Inter, headings (marketing): Lato
- H1: 4rem with -0.02em letter-spacing and weight 700
- All body text: 1.6 line-height
- This repo is the canonical source for all visual values
These are the CSS variable names generated by the build pipeline. Use these for all UI surfaces — they automatically adapt to light/dark mode.
| Variable | Light value | Dark value | Usage |
|---|---|---|---|
--color-semantic-background |
white | neutral.950 | Page background |
--color-semantic-foreground |
neutral.950 | neutral.50 | Body text |
--color-semantic-card |
white | neutral.900 | Card/surface background |
--color-semantic-card-foreground |
neutral.950 | neutral.50 | Card text |
--color-semantic-primary |
neutral.900 | neutral.200 | Primary buttons/actions |
--color-semantic-primary-foreground |
neutral.50 | neutral.900 | Primary button text |
--color-semantic-secondary |
neutral.100 | neutral.800 | Secondary surfaces |
--color-semantic-muted |
neutral.100 | neutral.800 | Muted backgrounds |
--color-semantic-muted-foreground |
neutral.500 | neutral.400 | Muted text |
--color-semantic-border |
neutral.200 | oklch(1 0 0 / 10%) | Borders |
--color-semantic-ring |
neutral.400 | neutral.500 | Focus rings |
--color-semantic-destructive |
status.destructive-light | status.destructive-dark | Error states |
CSS variable naming: token path color.brand.verdigris → CSS var --color-brand-verdigris (dots become hyphens, prefixed with --).
Dark mode pattern:
@import '@verdigristech/design-tokens/css/oklch';
/* :root {} block = light mode, .dark {} block = dark mode */
/* Toggle dark mode by adding class="dark" to <html> */- Use shadcn/ui + Radix UI patterns
- Dark mode via
.darkclass on<html>— CSS vars swap automatically - Radius: 0.625rem base
- Tailwind: use
bg-background,text-foreground,bg-card,text-muted-foreground, etc. (from preset) - Component guides: see
categories/web-components/for buttons, cards, modals, tables, tabs, sidebar, etc.
- Gate hover effects behind
(hover: hover) and (pointer: fine) - Always provide
prefers-reduced-motion: reducefallback - Entrance:
ease-out, 500ms. Interaction:ease, 200ms.
- WCAG 2.1 AA minimum
- All images need
alttext - All interactive elements need focus indicators
- Never communicate with color alone
| File | Contains |
|---|---|
tokens/color/base.json |
Primitive palette (OKLch) |
tokens/color/semantic-light.json |
Light mode semantic mappings |
tokens/color/semantic-dark.json |
Dark mode overrides |
tokens/typography/font-family.json |
Font stacks |
tokens/typography/scale.json |
Sizes, weights, line-heights |
tokens/spacing/base.json |
4px grid scale |
tokens/spacing/layout.json |
Container, sections, hero |
tokens/motion/duration.json |
Animation durations |
tokens/motion/easing.json |
Easing curves |
tokens/radius.json |
Border radius scale |
tokens/breakpoints.json |
Responsive breakpoints |
rules/visual-rules.yml |
Machine-enforceable rules |
Patina (the application UI) is the primary source of truth. When in doubt about a design decision, default to Patina's implementation. The www marketing site converges toward Patina, not the other way around.
Justified deviations from Patina:
- Lato as display font (Patina has no display font — marketing needs font contrast)
- Hero/marketing-specific patterns (Patina is an app dashboard)
- Ad/collateral templates (Patina has no ads)
All deviations must be documented in foundations/ docs.