Design Tokens

Single source of visual truth for TrackItPilot's frontend. Tokens are plain CSS custom properties in app/frontend/src/styles/tokens/ (colors.css, typography.css, spacing.css, effects.css, animation.css), imported by app/frontend/src/styles.css. That same file also defines a Tailwind v4 @theme block that maps Tailwind's utility scale onto the exact same values, so hand-written component CSS (which references the --tip-*/semantic vars directly) and Tailwind utility classes never drift apart. Change a token in one place (tokens/*.css); update the mirrored @theme entry in styles.css if the value changed.

Colors — scales

Scale Steps (light → dark / value)
Ink (neutral) --tip-ink-50 #f9f9f9 · 100 #f4f4f5 · 150 #ececec · 200 #e4e4e7 · 300 #c2c2c6 · 400 #9a9aa2 · 500 #6a6a72 · 600 #52525b · 700 #38383a · 800 #26262a · 900 #171719 · --tip-white #fff
Emerald (positive/live) --tip-emerald-50 #eafaf2 · 100 #c5f9e0 · 300 #7cc6a9 · 500 #00b573 · 700 #077451
Gold / Amber (attention) --tip-gold-500 #ffb400 · --tip-gold-600 #bd5814 · --tip-orange-500 #f97316 · --tip-amber-100 #fffdf4 · --tip-amber-200 #fdf3c1 · --tip-amber-border #f2e2ad
Red (critical) --tip-red-100 #fde7ed · --tip-red-600 #d31f4a

Colors — semantic aliases

Components should reference these, not raw scale steps, wherever a semantic meaning (page background, heading text, positive status) applies:

Alias Value Alias Value
--surface-page --tip-ink-50 --text-heading --tip-ink-900
--surface-card --tip-white --text-body --tip-ink-800
--surface-card-alt --tip-amber-100 --text-muted --tip-ink-500
--surface-inverse --tip-ink-900 --text-inverse --tip-white
--surface-hover --tip-ink-100 --text-on-inverse-muted --tip-ink-400
--border-hairline --tip-ink-150 --accent-primary --tip-emerald-500
--border-default --tip-ink-200 --accent-primary-strong --tip-emerald-700
--border-focus --tip-ink-900

Status semantics (drive tip-badge's tone and related accents): --status-positive-fg/bg (emerald-700/100), --status-warning-fg/bg (gold-600/amber-200), --status-critical-fg/bg (red-600/100), --status-neutral-fg/bg (ink-600/200). Tone (core/models/enums.ts) is 'positive' | 'warning' | 'critical' | 'neutral' | 'emerald'emerald is a fifth, brand-forward tone (--tip-emerald-100/700) distinct from positive's status alias.

Typography

Token Value Token Value
--font-display Poppins (headings) --font-ui Inter (body/controls)
--font-mono JetBrains Mono (IDs, container numbers)
--fs-display-xl 34px (hero heading) --fs-h3 15px
--fs-display-lg 28px (big stat numbers) --fs-body 14px (default UI)
--fs-h1 22px (page title) --fs-body-sm 13px
--fs-h2 18px (card heading) --fs-label 12px (table headers)
--fs-micro 11px (badges, captions)
--fw-regular/medium/semibold/bold 400/500/600/700 --lh-tight/snug/normal 1.1/1.3/1.5
--ls-label 0.04em (uppercase labels) --ls-tight -0.01em (display numbers)

Spacing & radii

4px base grid: --space-1 (4px) through --space-16 (64px) — 1:4 2:8 3:12 4:16 5:20 6:24 8:32 10:40 12:48 16:64. Radii: --radius-sm 6px (chips) · --radius-md 10px (buttons/inputs/controls) · --radius-lg 14px (cards) · --radius-xl 20px (menus, modals) · --radius-pill 999px. Control heights: --control-h-sm 28px · --control-h-md 36px · --control-h-lg 44px.

Effects (shadows, focus ring)

--shadow-xs/sm/md/lg — increasingly soft/deep low-contrast black shadows (rgba(23,23,25,…)). --shadow-hero — the dark hero/inverse-surface shadow. --ring-focus0 0 0 3px rgba(0,181,115,0.28) (emerald-tinted focus ring, used on inputs/menus/modal close). --border-width1px.

Motion & reduced motion

@keyframes tip-skeleton-shimmer (loading shimmer, 1.4s ease infinite) and tip-spin live in animation.css so they're available wherever styles.css is linked. Interactive transitions are short and restrained: 0.12s ease for hover/focus/press (buttons scale to 0.97 on :active), 0.16s ease for menu/modal/toast enter animations. Every component with an animation wraps it in @media (prefers-reduced-motion: reduce) to disable it (see .tip-skeleton in animation.css, plus per-component overrides in modal, toast, save-bar). styles.css also sets a global reduced-motion fallback (animation-duration/transition-duration: 0.001ms !important).