public.supply
UI kit

One button, one overlay, one row.

Everything on this page is imported from @/components/kit. Tailwind’s stock palette is reset to initial, so text-gray-400 and rounded-2xl do not compile. That is the enforcement mechanism.

Tokens

Colour is semantic, never literal. Interaction states are alpha so a row reads identically on white and on the sidebar.

Surface
surfacePage, cards, overlays#ffffff
surface-sunkenSidebar, rails#fafafa
surface-insetFilled inputs, wells#f3f4f6
hoverRow hoverrgb(0 0 0 / 0.04)
activeRow selectedrgb(0 0 0 / 0.06)
Content
textPrimary copy — 19.2:1rgb(15 15 16)
mutedIdle labels — 6.20:1rgb(0 0 0 / 0.62)
subtlePlaceholders, counts — 4.76:1rgb(0 0 0 / 0.55)
lineDividersrgb(0 0 0 / 0.075)
line-strongControl bordersrgb(0 0 0 / 0.16)
Accent & status
accentFocus, brand moments#5200ff
successHealthy, settled#059669
warningDegraded, throttled#b45309
dangerFailed, destructive#dc2626

Type

Base is 14px, not 16px — this is an instrument, not an article. Nine steps; anything between them is drift.

display44 / 48Requests routed to anthropic/claude
text-3xl32 / 40Requests routed to anthropic/claude
text-2xl24 / 32Requests routed to anthropic/claude
text-xl20 / 28Requests routed to anthropic/claude
text-lg16 / 24Requests routed to anthropic/claude
text-base14 / 20Requests routed to anthropic/claude
text-sm13 / 18Requests routed to anthropic/claude
text-xs12 / 16Requests routed to anthropic/claude
text-label10 / 14Requests routed to anthropic/claude

Shape & elevation

Four radii and three shadows. Radius encodes scale: the bigger the surface, the rounder the corner.

chip6px
control8px
card12px
overlay16px
raised
popover
modal

Button

One primary per surface. Secondary is bordered and never filled. Accent is reserved for brand moments — not for save.

primary
secondary
ghost
soft
accent
danger
icon only
pill

Fields

Form inputs are bordered on white. Search is filled and borderless — it is chrome, not data entry.

Composer

The thread prompt. One per surface. 800px column, 24px radius, 18px field, circular send.

Badges & loading

A skeleton mirrors the element it replaces. A spinner means we are waiting on one thing; a skeleton means we are waiting on a list.

badge
gpt-5BYOKsettleddegradedfailed
status
HealthyThrottledDown
spinner
Reserving budget…

Skeleton rows

No requests yet

Point an OpenAI-compatible client at the gateway and the first receipt lands here.

Overlays

Three floating surfaces, three z-bands, one scrim. Tooltip labels, popover offers, dialog interrupts.

--z-sticky10
--z-dropdown100
--z-scrim200
--z-modal210
--z-popover300
--z-tooltip400
--z-toast500

Surfaces

Cards never nest. Panels own their own scroll — the page never scrolls behind a fixed header.

Routing

Healthy
Capability, price, latency and residency are hard filters, not hints.

Budgets

Hold
Interactive card. Reserves before it runs, settles on the last token.

Receipts

Model actually served, fallback reason, metering confidence.
ModelProviderp50Cost / 1MStatus
claude-sonnet-4.5Anthropic740 ms$3.00Healthy
gpt-5OpenAI910 ms$2.50Healthy
veo-3fal.ai38 s$0.40 / sDegraded

Outlawed

Each rule below is a pattern measured in PublicAI001. The counts are why the rule exists.

NeverMeasured in PublicAI001Instead
A second Button5 systems in PublicAI — bg-primary, bg-gray-900, #0D99FF, #ffffff+#d1d5db, CreateButtonButton with variant + size. Add a variant, never a component.
fixed inset-0 overlays6 dialog stacks, z-index from 80 to 100060, five different scrimsDialog. Scrim is bg-scrim, z comes from --z-scrim / --z-modal.
Raw hex in a component653 unique hex values across 405 filesA semantic token. If it is missing, add it to globals.css.
rounded-[10px] and inline borderRadius115 + ~74 occurrences fighting rounded-lg and rounded-xlchip 6 · control 8 · card 12 · overlay 16. Four values, no others.
onMouseEnter → style.backgroundColor30 files paint their own hover in JavaScripthover: utilities. Hover is CSS, always.
Ad-hoc Loader2 / animate-pulse10 files import the spinner; hundreds inline Loader2Spinner and Skeleton.
A local search input classlistSearchInputClass copied into 8+ panels, plus 2 dead SearchInput filesSearchField.
A hand-rolled theme object7 THEMES / COLORS consts, plus dark: in only 15% of filesTokens in :root. Dark mode will be one block, edited once.

Adding to the kit is encouraged. Forking it is not. If a surface needs something that is not here, extend components/kit and update this page in the same commit — the reference and the code ship together or the kit stops being true.