Color

The palette is ink-led: black type on white surfaces, hairline borders, and one loud color, Miltinson Amber. Every value on this page is read live from the token stylesheets @elirobinson/tokens ships — tokens.css and the palettes.css it imports — so the swatches and contrast ratios below cannot drift from what the package ships. They are the default palette in its light theme; the palette is a data-palette attribute on the root element, and nothing on this page is hardcoded per brand.

How to think about it

  • Ink does the work. Headings are pure black, body text near-black, and hierarchy comes from the ink scale — not from adding color.
  • Amber is the only loud color. Primary CTAs, the dot in the wordmark, eyebrow underlines, key stats, link hovers. If two things on a screen are amber, one of them is wrong.
  • Forest is the quiet second. Trust marks and the earnest surfaces (coaching guides). It is no longer what success is made of — status has its own four hues, which stay put when the palette changes.
  • No gradients, no purple. Flat color only.

Reference semantic tokens (--fg, --surface, --accent) in components, never raw scale values (--ink-500) — the semantic layer is what makes a future dark theme possible without touching component code.

Ink — the neutral scale

TokenValueHexOn whiteOn black
--ink-0#ffffff#ffffff1.00:121.00:1
--ink-50oklch(98.4% calc(0.002 * 1) 247)
--ink-100oklch(96.2% calc(0.003 * 1) 247)
--ink-200oklch(92.8% calc(0.004 * 1) 247)
--ink-300oklch(86% calc(0.005 * 1) 247)
--ink-400oklch(70% calc(0.006 * 1) 247)
--ink-500oklch(55% calc(0.008 * 1) 247)
--ink-600oklch(42% calc(0.01 * 1) 247)
--ink-700oklch(30% calc(0.01 * 1) 247)
--ink-800oklch(20% calc(0.01 * 1) 247)
--ink-900oklch(12% calc(0.008 * 1) 247)
--ink-950oklch(6% calc(0.006 * 1) 247)
--ink-1000#000000#00000021.00:11.00:1

Signal — Miltinson Amber

Warm, craftsman, honest. --signal-500 is the brand amber; the darker steps exist because raw amber fails AA on white — anything amber a user has to read uses --accent-ink, which the default palette points at --signal-800.

TokenValueHexOn whiteOn black
--signal-50oklch(97.5% 0.025 75)#fff5e51.08:119.42:1
--signal-100oklch(94% 0.055 75)#ffe7c31.20:117.44:1
--signal-200oklch(89% 0.1 75)#ffd28f1.42:114.84:1
--signal-300oklch(83% 0.14 72)#ffb7551.72:112.18:1
--signal-400oklch(78% 0.16 68)#f9a1292.06:110.17:1
--signal-500oklch(72.5% 0.175 65)#ef8a002.53:18.30:1
--signal-600oklch(63% 0.165 55)#d267003.69:15.69:1
--signal-700oklch(52% 0.145 45)#a946085.86:13.59:1
--signal-800oklch(40% 0.115 40)#782c0c9.69:12.17:1
--signal-900oklch(28% 0.08 38)#48170715.00:11.40:1

Anchor — Miltinson Forest

TokenValueHexOn whiteOn black
--anchor-50oklch(96% 0.018 165)#e7f6ef1.12:118.82:1
--anchor-100oklch(91% 0.035 165)#cde9db1.29:116.29:1
--anchor-200oklch(82% 0.055 162)#a5d0b91.71:112.30:1
--anchor-300oklch(70% 0.075 160)#74ad8e2.58:18.13:1
--anchor-400oklch(55% 0.085 158)#42815e4.65:14.51:1
--anchor-500oklch(42% 0.08 156)#215a3a8.13:12.58:1
--anchor-600oklch(34% 0.065 156)#16422911.41:11.84:1
--anchor-700oklch(26% 0.05 156)#0b2b1a15.26:11.38:1
--anchor-800oklch(19% 0.035 156)#05180d18.32:11.15:1
--anchor-900oklch(13% 0.025 156)#010a0420.06:11.05:1
--anchor-hoveroklch(55% 0.085 158)#42815e4.65:14.51:1
--anchor-pressoklch(34% 0.065 156)#16422911.41:11.84:1
--anchor-fg#ffffff#ffffff1.00:121.00:1
--anchor-tintoklch(96% 0.018 165)#e7f6ef1.12:118.82:1
--anchor-inkoklch(34% 0.065 156)#16422911.41:11.84:1

Semantic tokens

These are the names components actually use. Each references a base-scale value, so retuning the palette is a one-line change per token.

Backgrounds and surfaces

TokenReferencesPurpose
--bgvar(--ink-0)page background
--bg-subtlevar(--ink-50)zebra / panel
--bg-mutedvar(--ink-100)code blocks, inset wells
--bg-inversevar(--ink-1000)dark hero, footer
--surfacevar(--ink-0)cards
--surface-2var(--ink-50)nested cards
--surface-3var(--ink-100)deeper inset

Text

TokenReferencesPurpose
--fgvar(--ink-1000)primary text
--fg-1var(--ink-1000)alias
--fg-2var(--ink-600)secondary text
--fg-3var(--ink-500)tertiary / meta
--fg-4var(--ink-400)decorative / non-informational grey — 2.67:1
--fg-disabledvar(--ink-500)4.85:1 — disabled control text
--fg-inversevar(--ink-0)on dark
--fg-inverse-2var(--ink-300)secondary on --bg-inverse — 13.73:1
--fg-inverse-3var(--ink-400)tertiary / meta on --bg-inverse — 7.87:1
--fg-on-signalvar(--accent-fg)

Borders

TokenReferencesPurpose
--bordervar(--ink-200)decorative hairline — 1.24:1
--border-strongvar(--ink-300)decorative, emphasized — 1.53:1
--border-inverseoklch(100% 0 0 / 0.12)on dark
--border-controloklch(62% calc(0.008 * var(--n-mult)) var(--n-h))3.64:1 on --bg — control edges, SC 1.4.11

Accent — the palette’s signal color

TokenReferencesPurpose
--accentvar(--signal-500)fill — 2.53:1, fill-only
--accent-hovervar(--signal-400)fill — 2.06:1, fill-only
--accent-pressvar(--signal-600)fill — 3.69:1
--accent-fgvar(--ink-1000)on the three fills: 8.30 / 10.17 / 5.69
--accent-tintvar(--signal-50)with --accent-ink: 8.96:1
--accent-inkvar(--signal-800)9.69:1
--accent-ink-inversevar(--signal-400)on --bg-inverse — 10.17:1

Anchor — the palette’s second color

TokenReferencesPurpose
--anchorvar(--anchor-500)fill — 8.13:1
--anchor-hovervar(--anchor-400)fill — 4.65:1
--anchor-pressvar(--anchor-600)fill — 11.41:1
--anchor-fgvar(--ink-0)on the three fills: 8.13 / 4.65 / 11.41
--anchor-tintvar(--anchor-50)with --anchor-ink: 10.23:1
--anchor-inkvar(--anchor-600)11.41:1

Links and focus

TokenReferencesPurpose
--focus-ringvar(--ink-1000)21:1 — high-contrast focus, ink-on-bg
--linkvar(--ink-1000)21:1
--link-hovervar(--signal-800)9.69:1 — was --signal-700 at 5.86:1
--link-visitedvar(--ink-700)13.62:1
--link-on-fillcurrentColor

Status

TokenReferencesPurpose
--status-successoklch(51.9% 0.145 150)fill — 5.17:1 light, 4.06:1 dark
--status-success-onvar(--ink-0)on the fill — 5.17:1
--status-success-fgoklch(44% 0.12 150)7.35:1 on --bg
--status-success-tintoklch(96.5% 0.03 150)with -fg: 6.71:1
--status-success-tint-edgeoklch(88% 0.06 150)decorative hairline on the tint
--status-warningoklch(80.25% 0.16 85)fill — 1.87:1 light, 11.22:1 dark — must be edged
--status-warning-borderoklch(61.9% 0.14 70)3.76:1 — the edge that carries SC 1.4.11
--status-warning-onvar(--ink-1000)on the fill — 11.22:1
--status-warning-fgoklch(47% 0.105 72)6.97:1 on --bg
--status-warning-tintoklch(96.5% 0.05 85)with -fg: 6.24:1
--status-warning-tint-edgeoklch(87% 0.1 85)decorative hairline on the tint
--status-dangeroklch(54.85% 0.2 27)fill — 5.41:1 light, 3.88:1 dark
--status-danger-onvar(--ink-0)on the fill — 5.41:1
--status-danger-fgoklch(47% 0.19 27)7.54:1 on --bg
--status-danger-tintoklch(96.5% 0.025 27)with -fg: 6.69:1
--status-danger-tint-edgeoklch(87% 0.07 27)decorative hairline on the tint
--status-infooklch(54% 0.155 250)fill — 5.06:1 light, 4.15:1 dark
--status-info-onvar(--ink-0)on the fill — 5.06:1
--status-info-fgoklch(46% 0.14 250)7.09:1 on --bg
--status-info-tintoklch(96.5% 0.03 250)with -fg: 6.38:1
--status-info-tint-edgeoklch(87% 0.07 250)decorative hairline on the tint

Charts — categorical, palette-independent

TokenReferencesPurpose
--chart-1oklch(62% 0.13 25)3.87:1
--chart-2oklch(62% 0.13 205)3.34:1
--chart-3oklch(62% 0.13 115)3.55:1
--chart-4oklch(62% 0.13 295)3.81:1
--chart-5oklch(62% 0.13 70)3.74:1
--chart-6oklch(62% 0.13 250)3.63:1
--chart-7oklch(62% 0.13 160)3.42:1
--chart-8oklch(62% 0.13 340)3.90:1
--chart-gridvar(--border-strong)decorative — 1.53:1
--chart-axisvar(--border-control)3.64:1 — the axis is a meaningful line

Overlays

TokenReferencesPurpose
--scrimoklch(0% 0 0 / 0.56)

Contrast

Computed from the live token values with WCAG 2.x math. Two pairings deserve a note. Raw amber (--accent) is a fill and fails AA as text on white — which is why button labels use --accent-fg and why anything amber that has to be read uses --accent-ink. And --status-warning is the documented exception: yellow cannot clear 3:1 on white and still read as yellow, so a warning fill or rule must be edged with --status-warning-border, which carries that 3:1 itself. Warning text is --status-warning-fg, never the fill.

ForegroundBackgroundSampleRatioWCAG AA
--fg
Body text on the page
--bgAa 16px21.00:1AA
--fg-2
Secondary text
--bgAa 16px
--fg-3
Tertiary / meta text
--bgAa 16px
--fg
Text on panels and zebra rows
--bg-subtleAa 16px
--accent-fg
Label on the accent fill
--accentAa 16px8.30:1AA
--anchor-fg
Label on the anchor fill
--anchorAa 16px8.13:1AA
--fg-inverse
Text on dark hero / footer
--bg-inverseAa 16px21.00:1AA
--accent
Accent fill on ink (stats, links on dark)
--bg-inverseAa 16px8.30:1AA
--accent-ink
Brand color at readable weight (marks, glyphs)
--bgAa 16px9.69:1AA
--link-hover
Link hover color
--bgAa 16px9.69:1AA
--status-success-fg
Success text
--bgAa 16px7.35:1AA
--status-warning-fg
Warning text
--bgAa 16px6.97:1AA
--status-danger-fg
Danger text
--bgAa 16px7.54:1AA
--status-info-fg
Info text
--bgAa 16px7.09:1AA
--status-success-on
Label on a success fill
--status-successAa 16px5.17:1AA
--status-warning-on
Label on a warning fill
--status-warningAa 16px11.22:1AA
--status-danger-on
Label on a danger fill
--status-dangerAa 16px5.41:1AA
--status-info-on
Label on an info fill
--status-infoAa 16px5.06:1AA
--status-warning-border
The edge a warning fill must carry (non-text, 3:1)
--bgAa 16px3.76:1AA large only