All new UI uses tokens and components from this page. If a primitive does not exist here, add it here first. Teal is healthy and the only accent — do not invent a second green. Buyer install, env, and screens live in Documentation.
Page contract
Every screen is a table, timeline, split inbox, or kanban — not a card grid. Radius is 6px on controls and 8px on panels. No 16px+ marketing cards, no gradients, no emoji icons.
Layout
Phone is under 768. Tablet is 768–1023. Desktop is 1024 and up. The rail is a charcoal drawer below desktop. KPI strips go 1 / 2 / 3. Split pages stack. Inbox is list or thread on the phone, two panes on tablet, three on desktop. Pipeline scrolls sideways until desktop. Tables scroll sideways — never squash columns. Header forms open in a Sheet, never inside the title row.
Red = money-losing. Bounce pause, DNS fail, blocked launch.
Status chips
Inbox readyRamp day 3VerifyingBounce pauseNeutral
Ready states map 1:1: inbox ready, list clean, sequence ready, campaign sending, deal won → teal. Anything still working → orange (pulse if in-progress). Anything that loses money or blocks send → red.
Type
Page titles only
Sans for humans. Never serif inside a card, table, or form.
Row 40px. Mono for emails, counts, DNS. Selection tint is interaction state, not health — status is carried by the chip only. Do not tint danger rows red.
Fields
Machine-truthful value
Max 40/day — higher volumes on a new inbox trigger spam filters.
File lives inside Field — no second browser box.
Field is the only box. Input, Select, Textarea, FileInput, and CheckList have no border of their own. Focus ring sits on the field, not a second inner control.
Multi-select is a CheckList inside Field — never select multiple.
Meters
Ramp cap20 / 40
Daily used8 / 20
Bounce rate1.2% / 3.0% limit
Bounce rate4.1% / 3.0% limit
Meter fill inherits the status color of what it measures — ramp/pending = orange, healthy usage = teal, red only for bounce/danger. Bounce is rate vs the 3% pause limit; fill is distance-to-pause, not a 0–100 vanity bar.
Welcome, invite, and password reset share one chrome: src/emails/ledger.tsx. Same tokens as this page. Campaigns never use this template — those leave on the customer's SMTP.
From is OutboundOS <hello@outboundos.org>. Reply-to is the same inbox.
Header uses the product seal, not a blank teal tile.
Canvas wash, charcoal rail header, paper panel, 8px radius. Button is 6px teal.
Serif only on the title. Mono for kicker, facts, and the raw URL.
Facts stack label over value so a phone never clips an address.
No open pixel, no click wrapper, no second green, no emoji, no shadow.
Inbox preview under 90 characters. One primary action. Expire in the footnote.
Web-safe stack in the MIME: Georgia for the title, system sans, ui-monospace.
OutboundOS
Ledger · account
Workspace
Ready to send from your domain.
WebBuddy is live. Add an inbox you own, pass DNS, then launch. OutboundOS never sends from outboundos.org on your behalf.
`/` and the auth panes are the only marketing surface. Same tokens, same 40px controls. ButtonLink is the link-shaped Button. No second palette, no shadow cards, no stock photos.
Disabled vs locked vs busy
Disabled = not applicable. Busy = the click landed and the network is still working.
Busy disables the control, swaps the label to the verb in progress, and pulses with the verifying token. Locked = blocked by a gate, always shows why and the fix. Never use a grayed primary for a deliverability gate.
Toast
Imported 48 leads
Bottom-right, 3.2s, one at a time (replace, do not stack). Only copied / test sent / imported n. Failures use banners or field errors.
Skeleton
Tables and meters while polling. Pulse token is the same as verifying; it respects prefers-reduced-motion.
Sheet
Add inbox
Bottom sheet on the phone, centered panel from tablet up. Close on backdrop. This is the only place a create form may live — never in the page header.
Events
Motion is 120ms opacity or translate only. No page wipes.
Press drops opacity. Hover tints rows. Selection tint is not health.
Escape and backdrop close Sheet, palette, and the rail drawer.
Overlays trap focus and lock body scroll. Nested locks stack.
⌘K opens the palette. Arrows move, Enter runs, Escape closes.
Inbox: j/k move, e interested, u suppress, r reply, p poll — never while typing.
Table rows that navigate are keyboard links — Enter and Space.
Buttons default to type=button. Submit is explicit.
Toast allowlist: copied / test sent / imported n. Failures stay on the field.
Focus
One focus style: teal 2px ring, 2px offset. Do not invent another.
Voice
Errors state the rule and the reason. “Max 40/day — higher volumes on a new inbox trigger spam filters.” That is the product, not Instantly-generic validation.
Empty state
No inboxes yet.
Add a Mailpit inbox to send the first test.
Banner
Inbox paused — bounce rate 4.1%
Red banner. Orange is only for in-progress work, never this.