Skip to content
GPS

Design System v1.0

GPS Speedometer — Style Guide

Home

Dark is default · Light is AA mirror

Precision instrument, not a landing page.

Near-black canvas #0a0c0e+ electric cyan #00d0ff+ generous negative space. Numbers are the hero — tabular mono so digits never jitter. Hover glows are restrained, focus rings are always visible.

GPS locked ≤15m Weak signal ±32m Permission denied

1 — Background layers

Near-black base → panel → elevated → hover → inset. Light theme swaps to off-white/white but keeps the same stack.

background

#0a0c0e

light: #f8f9fa

surface

#14181c

light: #ffffff

surface-elevated

#1c2329

light: #f1f5f9

surface-hover

#242e38

light: #e2e8f0

surface-inset

#070a0c

light: #eef2f6

border

#1e252c / light #e2e8f0

border-strong

#2a3440 / light #cbd5e1

border-subtle

#161c22 / light #f1f5f9

2 — Text

foreground

#eef2f6

Aa 123

15.8:1 on bg

muted

#8a9aa8

Aa 123

7.1:1

muted-strong

#a3b2bf

Aa 123

9.2:1

faint

#6b7d8c

Aa 123

4.6:1 AA

disabled

#3d4b57

Aa 123

placeholder #4a5d6b

3 — Accent: electric cyan (motion)

One hue drives: speed number, primary button, active toggle, focus ring, links. Three steps + tints. Glow is restrained — instrument, not flashy.

accent

#00d0ff

base — button fill, speed digits (dark), links

accent-hover

#33daff

hover — 160ms ease-out-expo + glow

accent-active

#00a6cc

active/pressed — scale 0.98

accent-muted

#00d0ff14 (8%) — wash

accent-subtle

#00d0ff0a (4%) — ghost hover

accent-ring

#00d0ff66 (40%) — focus glow

accent-foreground

#00141a (dark) / #ffffff (light)

text on accent

Light mirror: accent #0096bf (4.6:1 on white AA), hover #00a6cc, active #007a9c, ring #0096bf4d.

Warning — amber

Weak GPS, low accuracy, stale fix — only warnings.

Weak GPS — accuracy ±32m
#ffb700hover #ffca33active #cc9200

Light: #b45309 (5.2:1), hover #d97706, active #92400e

Success — GPS locked

≤15m accuracy, live dot, good signal.

GPS locked — ±4m
#10b981hover #34d399active #059669

Light: #059669 (4.8:1), hover #10b981

Error — permission denied

Blocked, critical error.

Location blocked — enable in settings
#ff3b30hover #ff5c52active #cc2f26

Light: #dc2626 (4.6:1)

4 — Typography

Geist / Inter (sans, grotesk) for UI + Geist Mono / JetBrains Mono for every numeric readout — tabular-nums so digits never jitter.

Hero — speed display (largest element)

88.4km/htabular-nums · clamp 56→96 mobile, 96→168 desktop · -0.04em tracking
42.7km/h — stat
12.345 kmdistance (mono-sm 12px/16px)

Type scale — sans

3xl 30px/36px 700 -0.035em — Page heading

2xl 24px/32px 600 — Section

xl 20px/28px 600 — Card title

lg 18px/26px 500 — Card title sm

md 16px/24px — Lead

base 14px/20px — Default body

sm 13px/18px — Toolbar, toggle labels

xs 12px/16px — Helper, accuracy ±4m

caption 11px/14px 500 0.06em — Eyebrow, kbd hint

mono-sm 12px/16px 500 — metadata

Tabular-nums — jitter test

All numbers below use tabular-nums + tnum and fixed ch width — they should not shift as digits change.

00.0 km/h
88.8 km/h
111.1 km/h
99.9 km/h
0.00 km9.99 km00:00:00± 3 m59.9 mph

Spacing scale (4px base)

4px (1)
8px (2)
12px (3)
16px (4)
24px (6)
32px (8)
40px (10)
64px (16)

Container max-w-5xl (1024px), gutters 16px mobile / 24px desktop. Section bands 96–128px vertical.

Radius — soft-rounded + pill

sm 8px — inputs, kbd
md 12px — tiles
lg 16px — panels
xl 20px — hero
2xl 24px — modal
pill 9999 — buttons/toggles

Buttons/toggles are always rounded-pill. Speed card is rounded-lg–xl. Hairline is 1px solid border.

5 — Motion

Short, instrument-like. Respects prefers-reduced-motion.

instant 100ms

ease-out-expo

Number tick, dot pulse

fast 160ms

ease-out-expo

Button, toggle, theme flip

normal 240ms

cubic-bezier(0.32,0.72,0,1)

Accordion, banner, toast

slow 400ms

same ease

Page transition

glitch 80ms

linear

Speed jump crossfade

6 — Interactive-color behavior

Every clickable has 5 states driven by accent tokens — not just opacity. Hover gets a subtle accent glow/ring; focus-visible gets 2px ring + outer glow.

Primary button

default bg-accent text-accent-foreground · hover bg-accent-hover + glow-accent · focus ring-2 ring-ring · active bg-accent-active scale-[0.98]

Ghost / secondary

Segmented control · unit switcher

Track bg-surface-inset border rounded-pill p-1 · active bg-accent text-accent-foreground + glow · inactive text-muted hover:text-foreground

Icon button · link · input

7 — Component states vocabulary

Every control supports these 7 states (via data-state + aria). Banners use role="status" aria-live="polite".

idle

--:-- km/h

Speed --, stats --, button Start tracking — prompt “Press Start to begin”.

permission-pending

Button disabled + spinner — “Requesting location permission…”

permission-denied

Location blocked — enable in browser settings

Banner bg-error-muted border-error-border + help link.

locating

“Searching for satellites…” — speed -- shimmer, accuracy —, button Cancel (ghost).

tracking-good-signal

64.2 km/h

Dot solid + success glow, accuracy ±4m, button Pause + Stop.

tracking-weak-signal

48.1 km/h

Amber pulse — “Weak GPS — accuracy ±32m — move outdoors” — speed still live, smoothing ↑.

paused

54.0 km/h frozen + dimmed

Dot gray static, banner “Paused” surface-elevated, button Resume + Reset.

Accuracy thresholds: ≤15m = success · 16–50m = warning · >50m = error-tinged (still tracking-weak). Stale fix >5s → warning “GPS signal lost — last fix Xs ago”.

Preview — speed card (instrument)

GPS locked · ±5m00:04:22
72.8km/h

Avg

48.2

km/h

Max

88.4

km/h

Distance

3.42

km

Space pause