Foundations

Tokens

Every color, size, radius, shadow, and duration is a CSS custom property on :root. Dark mode overrides those values under :root[data-theme="dark"]. Components read tokens — they never hardcode values.

Animation

Spring easing for entrances. Standard ease for micro-interactions. Four duration tiers from snappy to deliberate.

Easings
--ease-springcubic-bezier(0.16, 1, 0.3, 1) — overshoots slightly, feels alive
--ease-outease-out — clean deceleration
--ease-standardease — general-purpose transitions
Durations
--duration-fast0.15s — hover states, micro color changes
--duration-base0.22s — filter entrances, focus rings
--duration-moderate0.30s — modals, expandable regions
--duration-slow0.40s — page transitions, large surfaces

Colors

A warm neutral base with a cobalt brand, green reserved strictly for success/trust states, orange-red danger, and categorical data colors. All hues share a muted, slightly desaturated quality. Toggle the theme in the sidebar to see dark values.

Surfaces
Surface
--surface
Surface Subtle
--surface-subtle
Surface Page
--surface-page
Surface Muted
--surface-muted
Surface Inset
--surface-inset
Borders
Border
--border
Border Light
--border-light
Border Strong
--border-strong
Border Dashed
--border-dashed
Text
Primary
--text-primary
Secondary
--text-secondary
Tertiary
--text-tertiary
Disabled
--text-disabled
Inverse
--text-inverse
Brand — Cobalt
Brand
--brand
Brand Light
--brand-light
Brand Mid
--brand-mid
Brand Dark
--brand-dark
Logo mark
--logo
Status — Success (Green, reserved)
Success
--success
Success Light
--success-light
Success Mid
--success-mid
Success Dark
--success-dark
Status — Danger
Danger
--danger
Danger Light
--danger-light
Danger Mid
--danger-mid
Status — Warning
Warning
--warning
Warning Light
--warning-light
Warning Mid
--warning-mid
Status — Info & Accent
Info
--info
Info Light
--info-light
Info Mid
--info-mid
Accent
--accent
Accent Light
--accent-light
Data & Charts
Inflow
--data-inflow
Outflow
--data-outflow
Target
--data-target
Chart Blue
--chart-blue
Chart Azure
--chart-azure
Chart Amber
--chart-amber
Chart Violet
--chart-violet
Color conventions

Keep accents semantic, not decorative — every color should mean something:

Radius

Six steps from sharp to pill. --radius (10px) is the default card radius; --radius-md (8px) is the default container radius.

--radius-xs
4px
--radius-sm
6px
--radius-md
8px
--radius
10px
--radius-lg
12px
--radius-full
9999px

Shadows

Subtle, layered shadows — never solid black, always transparent washes. Shadow tokens lift to higher opacity in dark mode to stay legible against the dark surface.

--shadow-card
--shadow-nav
--shadow-toggle
--shadow-hover
--shadow-modal
--shadow-dropdown
--shadow-overlay

Spacing

A tight scale built for dense UI. Px-named so the value is always obvious. Used for padding, gap, margin, and any other length.

--space-22px
--space-44px
--space-66px
--space-88px
--space-1010px
--space-1212px
--space-1616px
--space-2020px
--space-2424px
--space-3232px
--space-4848px
--space-6464px

Typography

Bricolage Grotesque for headings, display, and numerics. DM Sans for all body and UI text. Both loaded from Google Fonts in a single request.

Font Families
--font-heading
Bricolage Grotesque
Display · Numerics · Headings · Slider values
--font-body
DM Sans
Body · Labels · UI text · Captions
Size Scale
--text-5xl
48px
Sg
--text-4xl
34px
The quick brown fox
--text-3xl
26px
The quick brown fox
--text-2xl
20px
The quick brown fox
--text-xl
18px
The quick brown fox
--text-lg
16px
The quick brown fox
--text-base
13px
The quick brown fox jumps over the lazy dog
--text-md
12px
The quick brown fox jumps over the lazy dog
--text-sm
11px
Label caps · Section heading
--text-xs
10px
Caption · Overline
--text-2xs
9px
Tag · Badge
Weights
--weight-lightLight 300 — light by definition
--weight-regularRegular 400 — body default
--weight-mediumMedium 500 — buttons, links
--weight-semiboldSemibold 600 — section headings
--weight-boldBold 700 — page titles, hero

Every token

The sections above explain the tokens that matter most. This table is all of them — rendered from lib/tokens.css by scripts/render-docs.py, so it cannot fall behind the file. Dark shows only where it differs from light.

Tier 1 — Primitives
TokenLightDark
--warm-0#FFFFFF—
--warm-50#F7F4F2—
--warm-100#F1EDEB—
--warm-150#EBE6E3—
--warm-200#E5DFDC—
--warm-300#D6CFCB—
--warm-400#C2B9B5—
--warm-500#A89E99—
--warm-600#8A7F7B—
--warm-700#6E625F—
--warm-800#5C504F—
--warm-900#3A302E—
--warm-950#1E1918—
--cobalt-50#EEF1FB#1A2342
--cobalt-100#DBE2F4—
--cobalt-200#BCC9EA#2E3F6B
--cobalt-300#93A8DE—
--cobalt-400#6E86D2—
--cobalt-500#4761BE—
--cobalt-600#2F4BA6#8AA0DE
--cobalt-700#243B83#7E96D8
--cobalt-800#1C2F66—
--cobalt-900#16244E—
--green-100#F2F6F2#1F2A1F
--green-300#C8D9C7#3F603E
--green-500#629460#8FB68D
--green-700#3F603E#C8D9C7
--clay-100#F4EFEA#251D19
--clay-300#DCC9B5#4A3A24
--clay-600#9A6B33#C9A063
--clay-700#6B4B3E—
--red-100#FBEFEB#2E1C13
--red-300#EBB39D#6E3217
--red-500#CE430A#E66B36
--azure-500#0EA5E9#3DBEF5
--azure-light#EBF7FD—
--amber-chart#B98326#D4A04A
--violet-chart#6B4B8A#9F7CBC
--elevation-sm0 1px 2px rgba(30,25,24,0.05), 0 1px 1px rgba(30,25,24,0.04)0 1px 2px rgba(0,0,0,0.40), 0 1px 1px rgba(0,0,0,0.30)
--elevation-md0 2px 4px rgba(30,25,24,0.05), 0 6px 16px rgba(30,25,24,0.06)0 2px 4px rgba(0,0,0,0.40), 0 6px 16px rgba(0,0,0,0.40)
--elevation-lg0 8px 24px rgba(30,25,24,0.10)0 8px 24px rgba(0,0,0,0.50)
--elevation-xl0 16px 40px rgba(30,25,24,0.14), 0 2px 6px rgba(30,25,24,0.06)0 16px 40px rgba(0,0,0,0.60), 0 2px 6px rgba(0,0,0,0.30)
Tier 2 — Semantic
TokenLightDark
--surfacevar(--warm-0)#1F1A18
--surface-subtlevar(--warm-50)#19130F
--surface-pagevar(--warm-50)#16110F
--surface-mutedvar(--warm-100)#2A211E
--surface-insetvar(--warm-150)#322924
--bordervar(--warm-300)#3A312D
--border-lightvar(--warm-200)#2E2722
--border-dashedvar(--warm-500)#6B5C57
--border-strongvar(--warm-400)#4D423D
--border-hairlinecolor-mix(in srgb, var(--warm-950) 8%, transparent)color-mix(in srgb, #F4EEEC 9%, transparent)
--text-primaryvar(--warm-950)#F4EEEC
--text-secondaryvar(--warm-800)#C5B6B2
--text-tertiaryvar(--warm-700)#A0928E
--text-inverse#FFFFFF#1E1918
--text-disabled#B5ABA8#756763
--brandvar(--cobalt-600)—
--brand-lightvar(--cobalt-50)—
--brand-midvar(--cobalt-200)—
--brand-darkvar(--cobalt-700)—
--brand-fg#FFFFFF#03131C
--successvar(--green-500)—
--success-lightvar(--green-100)—
--success-midvar(--green-300)—
--success-darkvar(--green-700)—
--success-fg#FFFFFF#0E1A0D
--logovar(--brand)var(--text-primary)
--dangervar(--red-500)—
--danger-lightvar(--red-100)—
--danger-midvar(--red-300)—
--danger-fg#FFFFFF#190B05
--warningvar(--clay-600)—
--warning-lightvar(--clay-100)—
--warning-midvar(--clay-300)—
--warning-fg#FFFFFF#1A100C
--infovar(--cobalt-700)—
--info-lightvar(--cobalt-50)—
--info-midvar(--cobalt-200)—
--info-fg#FFFFFF#06101F
--accentvar(--cobalt-600)—
--accent-lightvar(--cobalt-50)—
--accent-fg#FFFFFF#03131C
--data-inflowvar(--red-500)—
--data-outflowvar(--green-500)—
--data-targetvar(--warm-500)#847671
--chart-bluevar(--cobalt-700)—
--chart-azurevar(--azure-500)—
--chart-ambervar(--amber-chart)—
--chart-violetvar(--violet-chart)—
--ringcolor-mix(in srgb, var(--accent) 55%, transparent)—
--ring-offsetvar(--surface)—
--font-heading'Bricolage Grotesque', system-ui, sans-serif—
--font-body'DM Sans', system-ui, sans-serif—
--font-monoui-monospace, 'SF Mono', Menlo, Consolas, monospace—
--text-2xs9px—
--text-xs10px—
--text-sm11px—
--text-md12px—
--text-base13px—
--text-lg16px—
--text-xl19px—
--text-2xl23px—
--text-3xl28px—
--text-4xl33px—
--text-5xl48px—
--weight-light300—
--weight-regular400—
--weight-medium500—
--weight-semibold600—
--weight-bold700—
--leading-tight1—
--leading-snug1.1—
--leading-compact1.3—
--leading-normal1.5—
--tracking-tight-0.02em—
--tracking-snug-0.01em—
--tracking-slight-0.005em—
--tracking-caps0.07em—
--numeric-tabular"tnum" 1, "lnum" 1—
--space-00px—
--space-22px—
--space-44px—
--space-54px—
--space-66px—
--space-78px—
--space-88px—
--space-1010px—
--space-1212px—
--space-1414px—
--space-1616px—
--space-1818px—
--space-2020px—
--space-2424px—
--space-3232px—
--space-4040px—
--space-4848px—
--space-6464px—
--radius-2xs2px—
--radius-xs4px—
--radius-sm6px—
--radius-md8px—
--radius8px—
--radius-lg12px—
--radius-full9999px—
--shadow-cardvar(--elevation-sm)—
--shadow-navvar(--elevation-sm)—
--shadow-togglevar(--elevation-sm)—
--shadow-hovervar(--elevation-md)—
--shadow-modalvar(--elevation-xl)—
--shadow-dropdownvar(--elevation-lg)—
--shadow-overlayvar(--elevation-lg)—
--shadow-focus0 0 0 3px var(--ring)—
--size-icon-sm13px—
--size-icon-base18px—
--size-icon-lg22px—
--size-avatar-sm24px—
--size-avatar-md30px—
--size-avatar-lg34px—
--size-control-sm24px—
--size-control-md32px—
--size-control-lg40px—
--size-status-dot-sm6px—
--size-status-dot-base7px—
--size-status-dot-lg8px—
--sidebar-w56px—
--topbar-h56px—
--ease-springcubic-bezier(0.16, 1, 0.3, 1)—
--ease-outease-out—
--ease-standardease—
--duration-fast0.15s—
--duration-base0.22s—
--duration-moderate0.30s—
--duration-slow0.40s—
--z-dropdown50—
--z-sticky100—
--z-overlay200—
--z-modal300—
--z-toast400—
--z-tooltip500—
Tier 3 — Component
TokenLightDark
--button-bgvar(--brand)—
--button-fgvar(--brand-fg)—
--card-bgvar(--surface)—
--card-shadowvar(--shadow-card)—
--input-bgvar(--surface)—
--input-bordervar(--border)—