Every token, chip and component
One page that renders the whole system in both themes, so a change can be reviewed in place rather than hunted for across screens. Nothing on this page invents styling: every colour comes from globals.css, every status from src/lib/status.ts, every value from src/lib/format.ts.
Cool, slightly blue-cast neutrals — galvanised steel in shade, not pure grey. The low but non-zero chroma is what stops this reading as a default install. Swatch values below are read live from the DOM, so the dark column reports the dark value.
Hi-vis yellow-green is the exact colour of a Class-3 safety vest and of the reflective panels on a roll-off truck’s rear bumper. It is loud, so it occupies about 2% of pixels — primary buttons, the focus ring, the active nav indicator, the logo bar — and it is never used for status, which is what lets it acquire one stable meaning: this is the thing you press. On white it measures ~1.4:1, so it is a fill or a ≥2px ring only, never text and never a hairline.
Each tone has a distinct lightness step as well as a hue, so the chips still form a readable ladder when hue collapses. Minimum ΔL between any two warm tones is 0.11 — plus a different icon, a different word, and a hazard stripe on overdue.
The atom of the system. Leading status bar, icon, label, optional trailing meta. Colour is never the only signal, the label is never omitted, and the aria-label is always the full sentence — “Bin RB-014, on site, day 12”.
Nothing physically changes about a bin on day 31, so nothing in the database changes either — and no background job is needed to flip a status.
Drop the icon before you drop the label. The short form is still a word, never a bare colour.
on_site escalates to the overdue tone when the snapshotted included period has passed.
dumped reads as READY TO INVOICE — the label says the action, because that is the cue.
unassigned is deliberately loud — a promised bin nobody is driving is the worst failure in this business.
past_due is a derived escalation of issued/partially_paid, never a stored value.
The signature component: the stencilled number painted on a container flank, rendered as a stamped steel tag with a clipped corner. Identical in every surface — manager table, driver card, customer portal, printed invoice — so a bin number is instantly recognisable as a thing you can click.
Barlow for the interface — a low-contrast grotesk rooted in Californian transport signage. Barlow Condensed for display, labels and asset plates, because condensed uppercase is the vernacular of stencilled container numbers. Azeret Mono for every numeral that sits in a column, because it reads like a scale-ticket printout and guarantees alignment.
- Dispatch.type-displayCondensed 700 · 34/34 · −0.015em · UPPER
- Order #1042.type-h1Barlow 600 · 24/30
- Proof of delivery.type-h2Barlow 600 · 19/26
- Scale ticket.type-h3Barlow 600 · 16/22
- The bin sat on site for fifty-two days..type-bodyBarlow 400 · 15/22
- Dense secondary text and table cells..type-smBarlow 400 · 13.5/20
- Days on site.type-labelCondensed 600 · 12/14 · 0.09em · UPPER
- Captured 08:12.type-label-smCondensed 600 · 11/13 · 0.10em · UPPER
- Priced with 40 yd config v3..type-microBarlow 500 · 11/15
- RB-014.type-plateCondensed 700 · 15/15 · 0.11em · UPPER
- RB-014.type-plate-lgCondensed 700 · 22/22 · 0.10em · UPPER
- $940.00.type-data-xlAzeret 500 · 30/32
- 8,220 lb.type-data-lgAzeret 500 · 20/24
- 0123456789 · $500.00.type-dataAzeret 500 · 13/18
- 30.2672, −97.7431.type-data-smAzeret 400 · 12/16
Never set Azeret Mono below 12px, and never set condensed uppercase below 11px. Inside a driver surface every text node has a 16px floor — anything smaller triggers iOS zoom-on-focus in an input and is unreadable in a cab.
4px base radius, deliberately flatter than the shadcn default — soft corners read as consumer SaaS. Hairlines carry structure; shadow is reserved for things that genuinely float. Nothing is a pill except an avatar.
Flat, bordered, no gradient, no icon in a coloured circle, and no animated count-up — a ticking figure is unreadable and unverifiable. The warning footer renders only when it is actionable and non-zero: an absent warning is the good state, and “0 overdue” is never rendered.
Every number that sits in a column is monospaced and tabular. Money is integer cents end to end and the formatter never receives a float; weight is integer pounds because that is what the scale prints, with short tons derived for display.
- Base
- $500.00
- Invoice total
- $940.00
- Driver payout
- −$150.00
- Disposal fee
- −$182.50
- Margin
- $607.50
- Margin, negative
- -$42.00
- Net, tons
- 4.11 t
- Net, pounds
- 8,220 lb
- Scale ticket net
- 8,220 lb · 4.11 t
- Over allowance
- 6.10 t
- Within allowance
- 2.40 t
- Neutral
- 12
- At risk
- 264D LEFT
- Overdue
- 47+3W
- Inline, overdue
- 47 days17 days past included
- Unknown
- —
The band changes the wording and the icon, not only the colour.
The order lifecycle drawn as a route, not a vertical stepper — a bin travels a physical line: yard → site → disposal → yard. The delivered-to-picked-up segment is drawn heavy because it is the billable clock, and on this page that is the money. Below md the rail turns vertical with the same node vocabulary.
- Requested02 JUN 202609:41
- Scheduled02 JUN 202614:20
- Delivered03 JUN 202608:12
- On siteDAY 52Billable — 52 d
- Picked up—
- At disposal—
- Invoiced—
- Requested02 JUN 202609:41
- Scheduled02 JUN 202614:20
- Delivered03 JUN 202608:12
- On siteDAY 52Billable — 52 d
- Picked up—
- At disposal—
- Invoiced—
- Scale ticket recordedD. Ramirez23 JUL 2026 · 11:22Ridgeline Transfer · TS-448120 · 8,220 lb net · fee $284.00
- Pickup confirmedD. Ramirez23 JUL 2026 · 09:04Photo + GPS captured 14 m from the recorded site.
- Pickup scheduledRobert H.22 JUL 2026 · 16:40
- Pickup requestedBergstrom Ridge Concrete22 JUL 2026 · 07:15“Bin is full, we're done — can you grab it Thursday?”
Driver-captured proof. The metadata is as important as the picture, because this is evidence in a billing dispute — so the timestamp, coordinates, accuracy, distance from the recorded site and the capturing driver are on the face of the card. A GPS mismatch is shown, never suppressed.
“Set on gravel pad, gate code 4417.”
Empty is an instruction, not a mood: icon in a hairline square, condensed headline, one sentence, one action. Errors state what failed and what to do — never “Oops!”, never “Something went wrong.” Skeletons are static blocks; a shimmer sweep implies progress that is not happening.
No runs scheduled
Nothing is going out today. Assign an order to a driver to build the run sheet.
Couldn't load the board
The database connection dropped. Nothing was lost — retry.
ref 7f3a19c2
Capture didn't upload
Your photo and notes are saved on this phone. Try again when you have bars.
Sorting, filtering, pagination and an empty state, with view state synced to the URL (?fleet_q=, ?fleet_sort=, ?fleet_page=) — never useState. A manager on the phone must be able to paste the URL of exactly what he is looking at, and a refresh must not lose the view. Structure comes from horizontal hairlines only: no zebra, no shadow, no row-enter animation.
The primitive set keeps its shadcn API and gets the industrial treatment in globals.css: Card loses its shadow for a hairline, Badge becomes a rectangle, table heads become condensed uppercase labels, and Button's default variant inherits the hi-vis fill through --primary.
Three archetypes, three densities. The console is compact and desktop-first; the driver view is touch-density, mobile-first and forced-daylight capable; the portal is comfortable and calm. Each is a full-viewport surface, so they are reviewed on their own pages.
AppShell — the console
Collapsible role-aware rail, 56px top bar, global search, notification bell, user menu, theme toggle. Density compact.
OpenDriverShell — the cab
48px+ targets, a 16px text floor, a bottom-anchored 64px primary action, an online indicator and the Daylight override. Density touch.
OpenRun these before signing off a change to any surface.
- Screenshot the dispatch board, desaturate it, and confirm every status is still identifiable. Greyscale review is a required step, not a nice-to-have.
- Tab through the page: the dual focus ring must be visible on every interactive element, on every background, in both themes.
- Zoom to 200%: the customer and driver views must not scroll the body horizontally. The manager board may — it is a data grid.
- Confirm no component hardcodes a colour, a status label or an icon. Colours live in globals.css; statuses live in src/lib/status.ts.
- Confirm every money value entered the formatter as integer cents and every weight as integer pounds.