Skip to content

Design System

This page is a summary with pointers, deliberately. The canonical files live in the repository and are enforced by tests and npm run design:guard:

This page used to restate the whole token table, and the copy drifted: it documented System Blue #007AFF, Satoshi and a hex palette for weeks after all three were retired. A third copy of a token table is a third thing to keep true, so this one does not have a token table any more.

Last reviewed: 2026-09-11.

ClinicFlow runs two visual languages on purpose, and most of the system’s rules exist to stop one leaking into the other.

The dashboard is Operate — a calm instrument somebody looks at all day. One card, one control, one button, a 14px-based type scale, three elevation steps, and a hover that is a colour change.

The marketing tree is Editorial Instrument + Product Film — twelve rooms, an ivory canvas rotation with two inverted rooms (portal, the patient’s own screen, and the empiece close — never adjacent), a serif display face in five sanctioned roles, and product imagery that is always a render of the real components, never a mockup.

Fully OKLCH. --accent is Hue 290 (Tyrian Violet); --success is Hue 152 (Sage); --background is a cool ivory in light and a deep violet charcoal in dark. The palette is mathematically locked and contract-tested.

Retired and blocked: System Blue (#007AFF), indigo hue 272, gold (#CA8A04), literal emerald hex, and --accent-copper. Never hardcode a hex — use the Tailwind token.

UI and body text use the Apple native stack (-apple-system, SF Pro Text, SF Pro Display) — zero download, vendor-tuned optical sizing. Fraunces Variable at weight 450 is the display face, scoped to the landing page’s display type. Monospace (SF Mono, Fira Code) is for machine values: timestamps, DTE codes, NIT/NRC, counts, tooth numbers, content hashes.

Satoshi, Bricolage Grotesque, DM Sans and Georgia are retired and hard-banned.

Two scales, quarantined from each other: text-dash-* (24 · 18 · 15 · 14 · 13 · 12 · 11px) in the dashboard and text-landing-* on marketing. Using one inside the other compiles perfectly and ships the wrong product, so a contract test enforces the split.

  • Borders: 1px razor-thin (border-border). No 2px+.
  • Shadows: ambient glows only. No directional drop shadows — this bans Tailwind’s shadow-md/lg/xl/2xl and any filter: drop-shadow(...). The dashboard has three steps: card, popover, overlay.
  • Radius: dashboard 8 / 12 / 16px; marketing 12 / 16 / 24px plus pill. Snap to the scale.
  • Hover is colour, never elevation, and every hover is gated behind the hoverable: variant (@media (hover: hover) and (pointer: fine)) — hover: fires on tap, which leaves rows lit on the clinic tablets this product runs on.
  • Motion is a vocabulary, not a quantity: springs for gesture- and scroll-driven motion that must stay interruptible, duration plus a strong curve for static entrances, never ease-in, and reduced motion honoured everywhere.
  • Focus: focus:outline-none focus:ring-4 focus:ring-accent/20 on every interactive element.
  • Icons: @phosphor-icons/react only.

npm run design:guard is the local linter. Because it is not in CI, every rule that matters is mirrored by a contract test under frontend/src/__tests__/ — the palette, the two type scales, the card recipe, the hover variant, the serif scope, the canvas rotation and the landing claim audit all fail there.