A financial-infrastructure design language: deep ink type, hairline structure, thin display headlines, pill buttons, and tabular figures wherever money appears.
Field and SettingsSection both require one, so an ambiguous control can't be written without deliberately working around the API. Field also requires htmlFor and wires the description to the control with aria-describedby — a description nobody hears is not a description.title tooltip — that reaches a mouse and nothing else. Every state says what it is in words, visibly or for a screen reader.tnum so columns line up — the quiet signal that this is financial software.Advanced disclosure rather than being hidden or removed.display-xxl/xl/lg/md (56/48/32/26) · heading-lg/md/sm (22/20/18) · body-lg/md (16/15, body-md is the page default) · body-tabular (14, figures) · button-md/sm (16/14) · caption (13, figures) · micro (11) · micro-cap (10, uppercase eyebrow). Tailwind's own sizes, and any arbitrary pixel value, are not this scale and do not pass review.lucide-react only, no emoji in chrome. 16px inside controls, 20px in feature spots.shadow-e1 for cards on white, shadow-e2 for floating panels. The gradient mesh, not shadow, is the depth medium on marketing surfaces.animate-fade-up for page and step entry. Everything respects prefers-reduced-motion, including animate-spin and animate-pulse.sm breakpoint. The desktop scale is unchanged; only the touch floor moves.The mesh accents — --teal, --ochre, --violet, --coral — are decorative. They are tuned to read inside a 28px blur and sit between 2.3:1 and 4:1 against white, so they are never a button and never a state fill; --success, --warning and --destructive own state and carry the contrast to be read.
Defined as CSS variables in globals.css (light + .dark) and mapped into Tailwind via @theme inline — use classes like bg-card, text-muted-foreground, border-border:
--backgroundPage canvas and the deep-navy ink used for all type--canvasWhite panels, the cool band under heroes, the warm interlude--cardElevated surfaces: cards, tables, sidebars--primaryBrand blue: filled buttons, links, active states, press--primary-subduedPale fill behind tags and eyebrow pills--brand-darkDeep navy fill for inverted bands and code blocks, and the light type that sits on it--ink-secondaryBody copy that sits one step below the headline--mutedSubdued fills and helper text--borderHairlines — inputs sit on a slightly cooler line than cards--destructiveOutcome colors--chart-1 … chart-5Categorical data-viz paletteshadcn-style components live in src/components/ui/ (Button with cva variants, Card, Skeleton, AlertDialog, Command); the shared kit in src/components/ui.tsx carries the clarity primitives.
import { Button } from "@/components/ui/button";
<Button>Book now</Button>
<Button variant="secondary" size="sm">Details</Button>
<Button variant="destructive">Cancel booking</Button>Group decisions with SettingsSection, describe every control with Field, and push expert options into Advanced. Labels name the decision in the operator's words (“Free-cancellation cutoff”), the description says what it changes, and the hint carries the unit and an example.
<SettingsSection
title="Booking rules"
description="These decide which times customers are offered on your booking form."
>
<Field
label="Minimum notice"
description="How far ahead someone must book. With 4, a customer at noon
cannot pick a time before 4pm today."
htmlFor="bookingLeadHours"
hint="In hours. Raise it if same-day jobs catch you short-staffed."
>
<input id="bookingLeadHours" name="bookingLeadHours" type="number" className={input} />
</Field>
<Advanced description="Travel time and how far ahead bookings open.">
…
</Advanced>
</SettingsSection>?ok= / ?error=; the global FlashToaster converts those to toasts, scales the duration to the message length, and strips the params from the URL.⌘K anywhere in admin: jump to a page (each listed with its description) or search bookings, customers, and providers.ConfirmButton, which spells out the consequence and blocks Enter-key submission of the underlying form./api/live (server-sent events) and refresh the server-component tree when data changes.LiveRefresh, search, bulk selection, and the tracking timeline.The .bb-mesh class paints the gradient-mesh backdrop used on the marketing hero: soft organic washes of brand blue, warm sand, and teal across the upper third of the page, with content floating above on white. It dims automatically in dark mode.
next-themes toggles a .dark class (system-aware). Token-based components adapt automatically; a small compatibility layer in globals.css remaps the status-color literals (bg-emerald-100, text-amber-700…) that badges still use.
tests/unit/interface-rules.test.ts enforces the parts of this page a machine can see — emoji in chrome, a colour literal with no dark-mode value, a bolded display tier, a bare outline-none, an unnamed nav, a missing skip link, three dots where an ellipsis belongs, a size or radius off the scale. It also parses DESIGN.md and fails when globals.css drifts from it, role by role and colour by colour, so the document and the stylesheet cannot quietly describe different systems. It needs nothing running. tests/e2e/accessibility.spec.ts runs axe over every route in both themes for what only the rendered page shows.
--chart-* so they follow the theme too. Note that --brand-dark pairs with --brand-dark-foreground, never --primary-foreground: the first stays dark in both themes while the second flips, so that pairing goes dark-on-dark.