Foundations
Colour
Brand colours, semantic roles in light and dark, status tones and live contrast ratios.
Brand colours
Five named colours. Everything else is derived from them in OKLCH.
Signal Amber
#e69431 · oklch(0.734 0.146 66.1)
The live dot: the app icon’s dot, “you are here”, things that need the patient
Harbour Blue
#0c6091 · oklch(0.469 0.107 242.3)
Primary actions, links, focus — the calm, trustworthy working colour
Ink
#191713 · oklch(0.205 0.008 84.6)
Primary text on light surfaces
Deep Navy
#003554 · oklch(0.315 0.075 242.1)
Logo square and “flow” on light, app icon field, deep brand surfaces
Paper
#fbfaf8 · oklch(0.985 0.003 84.6)
Light backgrounds — warm, never clinical white
Semantic roles
Every role in light and dark, with its CSS variable. Components use roles, never raw values.
| Role | Variable | Light | Dark |
|---|---|---|---|
| accent | --accent | #f0f8ff | #272e37 |
| accentForeground | --accent-foreground | #003554 | #fbfaf8 |
| background | --background | #fbfaf8 | #0f141b |
| border | --border | #e9e6e1 | #272e37 |
| borderStrong | --border-strong | #d7d4ce | #414853 |
| brand | --brand | #003554 | #fbfaf8 |
| brandForeground | --brand-foreground | #ffffff | #070b11 |
| card | --card | #ffffff | #181f27 |
| cardForeground | --card-foreground | #191713 | #fbfaf8 |
| chart1 | --chart-1 | #0061a2 | #4391d7 |
| chart2 | --chart-2 | #e48e00 | #cf8100 |
| chart3 | --chart-3 | #d85891 | #db6397 |
| chart4 | --chart-4 | #c0b529 | #a09600 |
| chart5 | --chart-5 | #49b3d8 | #32a0c5 |
| chart6 | --chart-6 | #c53829 | #d64938 |
| chart7 | --chart-7 | #5d3fa8 | #846cd1 |
| chart8 | --chart-8 | #00896d | #00896d |
| destructive | --destructive | #c72e2b | #ff7c70 |
| destructiveForeground | --destructive-foreground | #ffffff | #070b11 |
| foreground | --foreground | #191713 | #fbfaf8 |
| glass | --glass | #fbfaf8b8 | #181f27b8 |
| glassBorder | --glass-border | #ffffff99 | #ffffff1f |
| glow | --glow | #e69431 | #e69431 |
| glowForeground | --glow-foreground | #191713 | #191713 |
| glowSoft | --glow-soft | #ffe8d3 | #3d3429 |
| input | --input | #8a867f | #848d98 |
| link | --link | #0c6091 | #99cdf4 |
| muted | --muted | #f5f3f0 | #272e37 |
| mutedForeground | --muted-foreground | #69655f | #a7afb9 |
| overlay | --overlay | #19171373 | #070b1199 |
| popover | --popover | #ffffff | #272e37 |
| popoverForeground | --popover-foreground | #191713 | #fbfaf8 |
| primary | --primary | #0c6091 | #99cdf4 |
| primaryForeground | --primary-foreground | #ffffff | #070b11 |
| ring | --ring | #4895cc | #6eb1e2 |
| secondary | --secondary | #f5f3f0 | #272e37 |
| secondaryForeground | --secondary-foreground | #292622 | #f5f3f0 |
| sidebar | --sidebar | #f5f3f0 | #070b11 |
| sidebarAccent | --sidebar-accent | #e9e6e1 | #181f27 |
| sidebarAccentForeground | --sidebar-accent-foreground | #191713 | #fbfaf8 |
| sidebarBorder | --sidebar-border | #e9e6e1 | #181f27 |
| sidebarForeground | --sidebar-foreground | #3c3933 | #c8ced7 |
| sidebarPrimary | --sidebar-primary | #0c6091 | #99cdf4 |
| sidebarPrimaryForeground | --sidebar-primary-foreground | #ffffff | #070b11 |
| sidebarRing | --sidebar-ring | #4895cc | #6eb1e2 |
| surfaceInverse | --surface-inverse | #181f27 | #f5f3f0 |
| surfaceInverseForeground | --surface-inverse-foreground | #fbfaf8 | #0f141b |
| surfaceSunken | --surface-sunken | #f5f3f0 | #070b11 |
| statusNeutralFg | --status-neutral-fg | #524e48 | #c8ced7 |
| statusNeutralBg | --status-neutral-bg | #f5f3f0 | #283038 |
| statusNeutralBorder | --status-neutral-border | #e9e6e1 | #434b54 |
| statusNeutralSolid | --status-neutral-solid | #69655f | #a7afb9 |
| statusNeutralSolidForeground | --status-neutral-solid-foreground | #ffffff | #070b11 |
| statusInfoFg | --status-info-fg | #0c6091 | #99cdf4 |
| statusInfoBg | --status-info-bg | #ddf0ff | #223748 |
| statusInfoBorder | --status-info-border | #bde2fe | #3a5972 |
| statusInfoSolid | --status-info-solid | #2177ad | #6eb1e2 |
| statusInfoSolidForeground | --status-info-solid-foreground | #ffffff | #070b11 |
| statusProgressFg | --status-progress-fg | #5e499d | #c6bbff |
| statusProgressBg | --status-progress-bg | #edeaff | #30324b |
| statusProgressBorder | --status-progress-border | #dcd6ff | #535177 |
| statusProgressSolid | --status-progress-solid | #735dba | #ab9bee |
| statusProgressSolidForeground | --status-progress-solid-foreground | #ffffff | #070b11 |
| statusHighlightFg | --status-highlight-fg | #653b00 | #f9b671 |
| statusHighlightBg | --status-highlight-bg | #ffd3a9 | #503c1b |
| statusHighlightBorder | --status-highlight-border | #f9b671 | #6a4e2b |
| statusHighlightSolid | --status-highlight-solid | #c77900 | #e69431 |
| statusHighlightSolidForeground | --status-highlight-solid-foreground | #191713 | #070b11 |
| statusSuccessFg | --status-success-fg | #006c45 | #94d7b3 |
| statusSuccessBg | --status-success-bg | #d9f5e4 | #1f3a36 |
| statusSuccessBorder | --status-success-border | #bbe9cf | #385f52 |
| statusSuccessSolid | --status-success-solid | #008556 | #67be92 |
| statusSuccessSolidForeground | --status-success-solid-foreground | #ffffff | #070b11 |
| statusWarningFg | --status-warning-fg | #715700 | #e0c279 |
| statusWarningBg | --status-warning-bg | #f9eccd | #36341f |
| statusWarningBorder | --status-warning-border | #f0daa8 | #5f5431 |
| statusWarningSolid | --status-warning-solid | #af8800 | #caa43f |
| statusWarningSolidForeground | --status-warning-solid-foreground | #191713 | #070b11 |
| statusDangerFg | --status-danger-fg | #a8181a | #ffada3 |
| statusDangerBg | --status-danger-bg | #ffe6e3 | #422a2e |
| statusDangerBorder | --status-danger-border | #ffcfc9 | #744444 |
| statusDangerSolid | --status-danger-solid | #c72e2b | #ff7c70 |
| statusDangerSolidForeground | --status-danger-solid-foreground | #ffffff | #070b11 |
Status tones
Seven tones shared by every status map. Subtle for most states; solid for one high-emphasis mark per row.
| Tone | Background | Text | Border | Solid | Example |
|---|---|---|---|---|---|
| neutral | neutral | ||||
| info | info | ||||
| progress | progress | ||||
| highlight | highlight | ||||
| success | success | ||||
| warning | warning | ||||
| danger | danger |
Data visualisation
Eight categorical slots in a fixed order; the dark palette is chosen, not inverted.
light
dark
Contrast
Every pair the tokens test, computed live. Text needs 4.5:1, interface marks 3:1 (WCAG 2.2 AA).
| Foreground | Background | Use | Light | Light AA | Dark | Dark AA |
|---|---|---|---|---|---|---|
| foreground | background | normal | 17.15:1 | Pass | 17.71:1 | Pass |
| foreground | card | normal | 17.89:1 | Pass | 15.92:1 | Pass |
| foreground | popover | normal | 17.89:1 | Pass | 13.13:1 | Pass |
| foreground | muted | normal | 16.16:1 | Pass | 13.13:1 | Pass |
| foreground | secondary | normal | 16.16:1 | Pass | 13.13:1 | Pass |
| foreground | accent | normal | 16.68:1 | Pass | 13.13:1 | Pass |
| foreground | sidebar | normal | 16.16:1 | Pass | 18.90:1 | Pass |
| foreground | sidebarAccent | normal | 14.37:1 | Pass | 15.92:1 | Pass |
| foreground | surfaceSunken | normal | 16.16:1 | Pass | 18.90:1 | Pass |
| foreground | glowSoft | normal | 15.11:1 | Pass | 11.69:1 | Pass |
| mutedForeground | background | normal | 5.54:1 | Pass | 8.33:1 | Pass |
| mutedForeground | card | normal | 5.78:1 | Pass | 7.49:1 | Pass |
| mutedForeground | popover | normal | 5.78:1 | Pass | 6.18:1 | Pass |
| mutedForeground | muted | normal | 5.22:1 | Pass | 6.18:1 | Pass |
| mutedForeground | secondary | normal | 5.22:1 | Pass | 6.18:1 | Pass |
| mutedForeground | accent | normal | 5.39:1 | Pass | 6.18:1 | Pass |
| mutedForeground | sidebar | normal | 5.22:1 | Pass | 8.89:1 | Pass |
| mutedForeground | sidebarAccent | normal | 4.65:1 | Pass | 7.49:1 | Pass |
| mutedForeground | surfaceSunken | normal | 5.22:1 | Pass | 8.89:1 | Pass |
| mutedForeground | glowSoft | normal | 4.88:1 | Pass | 5.50:1 | Pass |
| cardForeground | card | normal | 17.89:1 | Pass | 15.92:1 | Pass |
| popoverForeground | popover | normal | 17.89:1 | Pass | 13.13:1 | Pass |
| primaryForeground | primary | normal | 6.77:1 | Pass | 11.63:1 | Pass |
| secondaryForeground | secondary | normal | 13.59:1 | Pass | 12.37:1 | Pass |
| accentForeground | accent | normal | 11.95:1 | Pass | 13.13:1 | Pass |
| destructiveForeground | destructive | normal | 5.44:1 | Pass | 7.85:1 | Pass |
| sidebarForeground | sidebar | normal | 10.38:1 | Pass | 12.45:1 | Pass |
| sidebarForeground | sidebarAccent | normal | 9.24:1 | Pass | 10.49:1 | Pass |
| sidebarPrimaryForeground | sidebarPrimary | normal | 6.77:1 | Pass | 11.63:1 | Pass |
| sidebarAccentForeground | sidebarAccent | normal | 14.37:1 | Pass | 15.92:1 | Pass |
| surfaceInverseForeground | surfaceInverse | normal | 15.92:1 | Pass | 16.68:1 | Pass |
| brandForeground | brand | normal | 12.82:1 | Pass | 18.90:1 | Pass |
| glowForeground | glow | normal | 7.36:1 | Pass | 7.36:1 | Pass |
| link | background | normal | 6.49:1 | Pass | 10.90:1 | Pass |
| link | card | normal | 6.77:1 | Pass | 9.80:1 | Pass |
| link | popover | normal | 6.77:1 | Pass | 8.08:1 | Pass |
| primary | background | normal | 6.49:1 | Pass | 10.90:1 | Pass |
| primary | card | normal | 6.77:1 | Pass | 9.80:1 | Pass |
| primary | popover | normal | 6.77:1 | Pass | 8.08:1 | Pass |
| destructive | background | normal | 5.22:1 | Pass | 7.36:1 | Pass |
| destructive | card | normal | 5.44:1 | Pass | 6.62:1 | Pass |
| destructive | popover | normal | 5.44:1 | Pass | 5.46:1 | Pass |
| statusNeutralFg | statusNeutralBg | normal | 7.45:1 | Pass | 8.44:1 | Pass |
| statusNeutralFg | background | normal | 7.91:1 | Pass | 11.67:1 | Pass |
| statusNeutralFg | card | normal | 8.26:1 | Pass | 10.49:1 | Pass |
| statusNeutralFg | popover | normal | 8.26:1 | Pass | 8.65:1 | Pass |
| statusNeutralSolidForeground | statusNeutralSolid | normal | 5.78:1 | Pass | 8.89:1 | Pass |
| statusInfoFg | statusInfoBg | normal | 5.80:1 | Pass | 7.25:1 | Pass |
| statusInfoFg | background | normal | 6.49:1 | Pass | 10.90:1 | Pass |
| statusInfoFg | card | normal | 6.77:1 | Pass | 9.80:1 | Pass |
| statusInfoFg | popover | normal | 6.77:1 | Pass | 8.08:1 | Pass |
| statusInfoSolidForeground | statusInfoSolid | normal | 4.87:1 | Pass | 8.49:1 | Pass |
| statusProgressFg | statusProgressBg | normal | 6.10:1 | Pass | 7.10:1 | Pass |
| statusProgressFg | background | normal | 6.90:1 | Pass | 10.52:1 | Pass |
| statusProgressFg | card | normal | 7.20:1 | Pass | 9.45:1 | Pass |
| statusProgressFg | popover | normal | 7.20:1 | Pass | 7.80:1 | Pass |
| statusProgressSolidForeground | statusProgressSolid | normal | 5.24:1 | Pass | 8.12:1 | Pass |
| statusHighlightFg | statusHighlightBg | normal | 6.94:1 | Pass | 5.96:1 | Pass |
| statusHighlightFg | background | normal | 9.23:1 | Pass | 10.52:1 | Pass |
| statusHighlightFg | card | normal | 9.63:1 | Pass | 9.45:1 | Pass |
| statusHighlightFg | popover | normal | 9.63:1 | Pass | 7.80:1 | Pass |
| statusHighlightSolidForeground | statusHighlightSolid | normal | 5.25:1 | Pass | 8.11:1 | Pass |
| statusSuccessFg | statusSuccessBg | normal | 5.61:1 | Pass | 7.35:1 | Pass |
| statusSuccessFg | background | normal | 6.23:1 | Pass | 11.11:1 | Pass |
| statusSuccessFg | card | normal | 6.49:1 | Pass | 9.99:1 | Pass |
| statusSuccessFg | popover | normal | 6.49:1 | Pass | 8.24:1 | Pass |
| statusSuccessSolidForeground | statusSuccessSolid | normal | 4.67:1 | Pass | 8.78:1 | Pass |
| statusWarningFg | statusWarningBg | normal | 5.84:1 | Pass | 7.29:1 | Pass |
| statusWarningFg | background | normal | 6.56:1 | Pass | 10.70:1 | Pass |
| statusWarningFg | card | normal | 6.85:1 | Pass | 9.62:1 | Pass |
| statusWarningFg | popover | normal | 6.85:1 | Pass | 7.93:1 | Pass |
| statusWarningSolidForeground | statusWarningSolid | normal | 5.40:1 | Pass | 8.35:1 | Pass |
| statusDangerFg | statusDangerBg | normal | 6.29:1 | Pass | 7.33:1 | Pass |
| statusDangerFg | background | normal | 7.16:1 | Pass | 10.34:1 | Pass |
| statusDangerFg | card | normal | 7.47:1 | Pass | 9.30:1 | Pass |
| statusDangerFg | popover | normal | 7.47:1 | Pass | 7.67:1 | Pass |
| statusDangerSolidForeground | statusDangerSolid | normal | 5.44:1 | Pass | 7.85:1 | Pass |
| input | background | ui | 3.47:1 | Pass | 5.49:1 | Pass |
| input | card | ui | 3.62:1 | Pass | 4.93:1 | Pass |
| input | popover | ui | 3.62:1 | Pass | 4.07:1 | Pass |
| ring | background | ui | 3.12:1 | Pass | 7.96:1 | Pass |
| ring | card | ui | 3.25:1 | Pass | 7.15:1 | Pass |
| ring | popover | ui | 3.25:1 | Pass | 5.90:1 | Pass |
| statusNeutralSolid | card | ui | 5.78:1 | Pass | 7.49:1 | Pass |
| statusInfoSolid | card | ui | 4.87:1 | Pass | 7.15:1 | Pass |
| statusProgressSolid | card | ui | 5.24:1 | Pass | 6.84:1 | Pass |
| statusHighlightSolid | card | ui | 3.40:1 | Pass | 6.83:1 | Pass |
| statusSuccessSolid | card | ui | 4.67:1 | Pass | 7.40:1 | Pass |
| statusWarningSolid | card | ui | 3.30:1 | Pass | 7.03:1 | Pass |
| statusDangerSolid | card | ui | 5.44:1 | Pass | 6.62:1 | Pass |