Baseline

Design system

Instrument at first light

The reference object is a precision measuring instrument — a barometer, a Braun weather station — not a hospital and not a fitness tracker. Neutral graphite surfaces, mono numerals that read like a readout, and saturated colour held back almost entirely for clinical state.

Every colour on this page is verified by tools/verify-contrast.mjs — 47 checks, 0 failures, all values inside sRGB gamut. Use the toggle above to inspect both themes.

Colour

assets/css/tokens.css

Strategy is restrained. Surfaces carry chroma exactly 0 — the mood lives in the brand colour and the typography, never in a tinted background. No cream, no warm near-white.

Surfaces & ink

canvas0.155 0 0
surface-10.205 0 0
surface-20.245 0 0
border0.530 0 03:1 min
ink0.970 0 017.9:1
ink-20.760 0 09.1:1
ink-3 · floor0.660 0 06.3:1
brand0.800 0.155 11310.7:1
ink-3 is the floor
Nothing lighter than --ink-3 is permitted on real text, placeholders included. Light grey “for elegance” is the single most common reason an interface becomes unreadable, and this product’s users are over 50.

Clinical status ramp

Blue → sand → amber → orange → red. Deliberately no green. A green→red ramp is indistinguishable under protanopia and deuteranopia — roughly 8% of men, which is precisely the demographic that develops hypertension — and it collapses in greyscale. Running the scale along the blue↔orange axis survives both.

● Normal<120 and <8012.9:1
◐ Elevated120–129 and <8010.8:1
◑ Stage 1130–139 or 80–898.8:1
◕ Stage 2≥140 or ≥907.0:1
▲ Crisis>180 or >1205.6:1
Greyscale checkLuminance descends monotonically, so the scale survives monochrome
Green is reserved for effort, not results
Because green is out of the clinical ramp, --brand is free to mean you did the thing — streak, check-in complete, synced, adherent. It never describes a blood-pressure value.

Typography

Instrument Sans · Azeret Mono

Two families on a real contrast axis — humanist sans against grotesk mono. Fixed rem scale at ratio ~1.2; product UI is viewed at consistent DPI, so a fluid heading that shrinks inside a sidebar looks worse, not better.

--fs-display128/79
--fs-xxl · 32pxKnow what moves your numbers
--fs-xl · 24pxYour personal drivers
--fs-lg · 19pxThis morning
--fs-md · 16pxBody text. The mobile floor — never smaller for prose.
--fs-sm · 14pxSecondary text and table cells.
--fs-xs · 12.5pxLabels, captions, badge text.
Why mono numerals

Tabular figures mean a value changing from 98 to 102 doesn’t shove the layout around it — and a mono readout is the whole “instrument” concept in one element.

Tabular (correct)
128 → 132 → 98
Proportional (wrong)
128 → 132 → 98

Space & radius

4px base
--sp-1 · 4px
--sp-2 · 8px
--sp-3 · 12px
--sp-4 · 16px
--sp-6 · 24px
--sp-7 · 32px
--sp-9 · 48px
--sp-10 · 64px
r-sm 8
r-md 12
r-lg 16
r-xl 22
pill

Buttons

all seven states

Minimum 44px tall. :active scales to 0.97 for instant confirmation the interface heard the tap. Transitions name their properties — never all.

Status & data

colour is never the only signal

Every state carries a glyph and a word alongside its colour, so a greyscale screenshot and a screen-reader description both still work.

● Normal ◐ Elevated ◑ Stage 1 ◕ Stage 2 ▲ Crisis ✓ Logged Draft
128/79This morning
130/8030-day average−5 vs baseline
±5.6Variability
23Day streakunchanged
Check-in complete
You’ve logged 23 days running.
Still learning
Movement shows a possible effect, but the interval still crosses zero.
Cuff battery low
Replace before your next reading.
Seek care now
A reading this high needs same-day medical attention.

Form controls

44px targets, no typing where a tap will do

The daily check-in has to close in under 60 seconds or the data stops arriving and the model starves. That budget is why chips, steppers and sliders carry the questionnaire and text inputs barely appear.

Hints sit at --fs-xs in ink-3.
Systolic must be between 60 and 250.
Choice chips — single select
Stepper
7.0 hours
Slider
Evening reminder
Segmented control

Surfaces

cards, rows, tables, empty & loading
CardLive

Used only where a card is genuinely the best affordance. Never nested.

Building your baseline

4 of 7 readings logged. Two more mornings and your first insights unlock.

Loading — skeletons, not spinners
Member Reading Category Adherence
Sipho Nkosi128/79◐ Elevated92%
Johan Venter164/98◕ Stage 241%
Zanele Khoza116/74● Normal98%

Column headers sort. Try clicking one.

Charts

13 types · hand-rolled SVG · zero dependencies

Every chart carries role="img" and an aria-label summarising what it shows. Line weights use vector-effect: non-scaling-stroke so they stay constant as the viewBox scales.

bp-timeline — with AHA category bands
SystolicDiastolicGoal

Hover for the reading and its category.

bp-scatter — position on the plane is the category
driver-bars — effect size with 95% CI
lag-strip — where the effect lands
band — projection with confidence
ring
hbar
vbar
funnel
stacked · calendar-heat · spark
Sparkline 128
gantt — delivery plan

Motion

custom curves only

ease-in never appears. It delays the initial movement — the exact moment the user is watching — and makes an interface feel sluggish at identical duration.

--ease-outcubic-bezier(0.23, 1, 0.32, 1)entrances, exits
--ease-in-outcubic-bezier(0.77, 0, 0.175, 1)on-screen movement
--dur-press140msbutton feedback
--dur-screen220msscreen change
--dur-sheet280mssheets, drawers
Rules that are enforced, not aspirational
Nothing animates from scale(0) — entrances start at 0.96 with opacity, because nothing in the physical world appears from nothing. Screen changes use CSS transitions rather than keyframes, so a rapid double-tap retargets instead of restarting. prefers-reduced-motion drops every transform to a crossfade.

Accessibility

WCAG 2.1 AA floor, AAA on body

A genuine requirement rather than a compliance box: the target user is over 50, often reading a small screen in a dim room before their first coffee.

Enforced
  • Body text ≥ 4.5:1; large text ≥ 3:1; placeholders held to the body threshold
  • Touch targets ≥ 44×44px
  • Visible 3px focus ring on every interactive element — tab through this page
  • Every input has a <label for>; icon-only buttons carry aria-label
  • Colour is never the sole carrier of meaning
  • Charts expose a text summary to assistive technology
Banned outright
  • Coloured side-stripe borders as accents
  • Gradient text
  • Glassmorphism as a default surface
  • Tiny uppercase tracked eyebrows above every section
  • Numbered section markers as default scaffolding
  • Display fonts in UI labels, buttons or data
  • Emoji standing in for icons
  • Modal as the first thought

Icons

—

One hand-authored sprite at a single visual weight, injected once and referenced with <use href="#i-name">. No icon library, no emoji.