Design System · Foundations

Foundations

The non-negotiable base layer — color, type, spacing and borders. Motion, iconography and overlays live on their own linked pages. Everything else in the system is built on these tokens, and every swatch and ramp below renders from the registry — the same data that generates the stylesheet and feeds consumer apps.

01

Color system

A compact semantic palette. Brand is rationed; neutrals do the heavy lifting; status and module hues are the only other colors allowed, and each has a fixed job.

Brand — use sparingly

Locked. This orange + black is the approved internal brand for the Design Manager. (Krown’s public mark is yellow/gold; internal tools use this.) Orange appears on the brand mark and wayfinding; black gives the app its spine; everything sits on a warm off-white canvas. Orange is never a button fill.

--brand
#EC6A1E
Primary brand orange — brand mark, wayfinding
--brand-press
#C9540F
Pressed / hover-dark brand
--brand-tint
#FCEBDD
Faint wash behind brand things
--brand-ink
#2A1606
Near-black text used ON orange

Ink & neutral surfaces

--ink-900
#1B1A18
Primary text
--ink-700
#3B3833
Strong body / headings on surface
--ink-500
#6B6862
Secondary text
--ink-400
#8C887F
Muted / placeholder
--ink-800
#322E29
Hover lift on ink-900 fills (primary button hover)
--ink-inverse
#FFFFFF
Text on ink-900 fills
--bg
#F6F5F1
App canvas
--surface
#FFFFFF
Cards, panels
--surface-2
#FBFAF7
Alt rows, inset wells
--surface-3
#F1EFEA
Deeper inset / hover
--border
#E6E3DD
Hairline
--border-strong
#D4D0C8
Emphasized divider / input edge

On-dark — the header’s inverted neutrals

The ink-900 header and nav are the one place the UI sits on near-black, so the usual neutrals invert. Tokenised so chrome on dark is never inline-styled with raw hex — this very app’s left nav uses exactly these tokens for its labels, hover and selection states.

--ondark-line
#3A3833
Outlined control border / hairline on dark
--ondark-edge
#000000
Hard edge under the ink-900 header
--ondark-ink
#FFFFFF
Primary text & icons on dark
--ondark-ink-2
#CFCCC4
Secondary text on dark — nav links, header actions
--ondark-ink-dim
#B6B2A9
Tertiary / inactive text on dark (resting tabs)
--ondark-ink-mute
#7D7A72
Muted meta / group labels on dark
--ondark-hover
rgba(255,255,255,0.07)
Subtle fill on hover
--ondark-active
rgba(255,255,255,0.11)
Selected / active fill on dark

Status — color + always a word

Four states cover the whole tool. Status is never color-only: it always ships with a label and (in chips) a dot, so it survives colorblindness and grayscale printing.

--ok
#1E7A48
Published / live / done
--ok-tint
#E3F2E9
Tint behind ok status
--ok-tint-hover
#D6EBDD
Hover on ok-tint fills (live platform tile)
--manual
#9A6608
Manual desk task / pending
--manual-tint
#FAEFD3
Tint behind manual status
--manual-ink
#6B480A
Readable manual text on manual-tint (banners)
--manual-line
#EAD49B
Manual banner border
--block
#B42318
Blocked / error
--block-tint
#FBE7E4
Tint behind blocked status
--block-ink
#7D1A12
Readable blocked text on block-tint (banners)
--block-line
#E3B6B1
Blocked banner / danger button border
--skip
#6B6862
Neutral / skipped / draft
--skip-tint
#ECEAE4
Tint behind neutral status
Published Manual task Blocked Draft

Module accents — quiet wayfinding

Each module gets one muted hue, used only in section headers, the active label, or a 4px card left-spine — never as a fill. They share a quiet register so no module shouts over another; Locations is the one bright note, carrying the Krown brand yellow. Intake reuses the brand mark behind the scenes (the front door) and isn’t shown as its own module hue.

--m-reviews
#2C7A6E
Reviews module accent
--m-reviews-tint
#E2F0ED
Reviews tint
--m-photos
#6A53AE
Photos module accent
--m-photos-tint
#ECE8F6
Photos tint
--m-translation
#A23E63
Translation module accent
--m-translation-tint
#F6E6ED
Translation tint
--m-locations
#E0A100
Locations accent — Krown brand yellow
--m-locations-tint
#FBF0CE
Locations tint
--m-updates
#9A5B2A
Updates module accent
--m-updates-tint
#F3E9DF
Updates tint
02

Typography

The native system font (San Francisco · Segoe · Roboto) for everything readable; the matching system monospace (SF Mono · Consolas) for IDs, labels, timestamps, and technical metadata. Headings run heavy (800) with a deliberate size jump to body — but body and labels never drop below 400. Mono signals “machine fact, secondary”. No web fonts load — the UI feels instant and native.

Aa Display
Display · 48/50 · 800
Page title — Locations
Page · 30/36 · 800
Section title
Section · 19/25 · 800
Card title — Montréal · Plateau
Card · 14/20 · 800
Body text. The quick rep checks twenty locations before lunch.
Body · 14/21 · 400
Small body — supporting detail inside dense rows.
Small · 13/19 · 400
Subtext — captions, descriptions & metric labels.
Subtext · 13/19 · 400 · ink-500
Row label
Label · mono 12 · 500 · caps
LOC-0421 · updated 2h ago
Meta · mono 12/16

Real headings vs styled labels

  • Use one real <h1> per route (the page title) and <h2> for genuine sections.
  • Card titles are <h3> only when the card is a true content section; in dense lists, render them as styled text to avoid a heading-soup outline.
  • Row labels, chips, and timestamps are never headings — they’re mono labels.

Reducing heading clutter

  • In a location card, the name is the only “title.” Address, ID, status are labels and metadata — not sub-headings.
  • Prefer a mono caps label + value pair over a bold sub-heading for every field.
  • Cap visible weight: at most one 600 element per card. If everything is bold, nothing is.
  • Secondary captions, descriptions & metric labels use .km-subtext — a named role, so secondary text is never hand-styled per surface.
03

Spacing & radius

A 4px base scale with two micro steps. Lists live at the tight end (8–12px); detail and intake breathe at 16–24px. Consistency matters more than the exact number.

--space-05 · 2px
--space-1 · 4px
--space-15 · 6px
--space-2 · 8px
--space-3 · 12px
--space-4 · 16px
--space-5 · 20px
--space-6 · 24px
--space-8 · 32px
--space-10 · 40px
--space-12 · 48px
--space-16 · 64px
xs · 4px
sm · 9px
md · 13px
lg · 18px
  • xs chips, dots, platform tiles.
  • sm buttons, inputs.
  • md cards, panels (the default container).
  • lg large shells, dialogs, the intake column.

Density targets. Location list rows: 12px vertical padding, 16px gutters. Card internal gap: 12px. Detail field rows: 12px vertical. Page gutters: 24–32px. A location card should comfortably show name, address, ID, four platforms, and status without scrolling inside the card.

04

Borders & elevation

Borders first, shadows almost never. A flat, bordered UI scans better at density and prints cleanly. Shadow is reserved for things that float above the page.

Default container — --border-w hairline in --border, no shadow. This is 95% of the UI.
Floating only — menus, popovers, the active intake confirmation. --shadow-pop.

Rules

  • Static cards & rows: border only. Never a resting shadow.
  • Hover on interactive cards: border darkens to --border-strong + optional --shadow-sm.
  • Overlays (dropdowns, dialogs, toasts): --shadow-pop, because they genuinely float.
  • Separation inside a panel: a hairline divider, not a gap-and-shadow.

Elevation tokens

Use sparingly — borders first. Shadows are reserved for things that float.

TokenValueUse
--shadow-sm0 1px 2px rgba(27,26,24,0.05)Resting card
--shadow-md0 4px 12px rgba(27,26,24,0.10), 0 1px 3px rgba(27,26,24,0.06)Hover lift
--shadow-pop0 8px 28px rgba(27,26,24,0.16)Floating overlays

Glass material

The premium translucent surface for things that FLOAT over the page — dialogs, menus, popovers. The page behind stays sharp; only a floating surface frosts what is directly beneath it. The input and inset values were promoted to tokens in V2 — they were previously hardcoded inside the dialog stylesheet.

The premium translucent surface for things that FLOAT over the page: dialogs, menus, popovers. The page behind stays sharp; only a floating surface frosts what is directly beneath it.

TokenValueUse
--glass-bgrgba(252,251,249,0.78)Balanced — glassy yet soft over busy content
--glass-bg-solidrgba(252,251,249,0.92)Denser, for tall / legible bodies
--glass-blur50pxBackdrop blur radius
--glass-saturate135%Backdrop saturation boost
--glass-borderrgba(255,255,255,0.6)Bright glass edge
--glass-hirgba(255,255,255,0.6)Inset top highlight
--glass-shadow0 1px 0 var(--glass-hi) inset, 0 16px 44px rgba(27,26,24,0.16), 0 2px 8px rgba(27,26,24,0.06)Composite glass shadow — highlight + deep soft drop
--glass-input-bgrgba(255,255,255,0.62)Frosted input resting on glass
--glass-input-bg-focusrgba(255,255,255,0.92)Frosted input focused — denser
--glass-input-linergba(27,26,24,0.12)Hairline input edge on glass
--glass-inset-linergba(27,26,24,0.07)Hairline divider inside glass (receipt rows)
--glass-inset-bgrgba(255,255,255,0.16)Inset well on glass (receipt card)
05

Structure tokens

V2 finished the token layer: stroke weights, control heights, stacking order and the focus ring are decisions, not magic numbers. All were promoted from previously-hardcoded values.

Border widths

Stroke weights are a decision, not a magic number.

TokenValueUse
--border-w1pxStandard stroke — borders, dividers, outlines
--border-w-hairline0.5pxHairline on glass surfaces
--border-w-focus2pxFocus ring line weight

Control sizes

The few fixed heights everything aligns to — header, controls, tiles.

TokenValueUse
--size-header56pxApp header height
--size-ctl34pxStandard control height — buttons, inputs, facets
--size-ctl-sm28pxSmall control height
--size-tile26pxPlatform tile / brand mark
--size-sidenav232pxLeft rail width — the .km-sidenav column

Z-index

Stacking order is a named scale, not an arms race.

TokenValueUse
--z-shell100App shell chrome — header, nav
--z-pop600Popovers, dropdown menus
--z-overlay1000Dialog scrim + dialog
--z-toast1400Toasts / audit badges above everything

Focus

One focus ring everywhere — surface gap + brand line.

TokenValueUse
--focus-ring0 0 0 2px var(--surface), 0 0 0 4px var(--brand)One focus ring everywhere — surface gap + brand line
06

More foundations

Three foundations have grown large enough to earn their own pages. They follow the same token discipline as everything above.