Design System · v1.0 · August 2026
The single source of truth

Infrastructure for how the built world gets made.

The Atelier Design System governs every pixel of app.atelier.inc — the platform connecting clients, project teams, and factories across custom fabrication. This book documents what ships in production, and sets the standard for everything that ships next.

TypefaceRoobert + Roobert Mono
Accent#F1613A
Ink#171512
GeometryRectangular · Never Pill
Sections18
StatusProduction Canon
Foreword

Why this book exists

Atelier sits between design intent and fabrication reality. Our interface has to carry contract-grade information — budgets, shop drawings, production stages, freight — with the calm confidence of a luxury product and the precision of an engineering document. That tension defines everything in this system.

One system, three portals. Admin, client, and factory experiences share a single design language. Firewalls strip data, never design — a factory sees fewer numbers than an admin, but the register, the status spine, and the type scale are identical. The admin production register is the standard every portal inherits.

Documented, not imagined. Every value in this book is cross-checked against production code — client-shell.css, button.css, ItemStatusBar.module.css, DropZone.tsx, globals.css. Where the platform had drift, this book codifies the approved standard and marks the source.

Category-defining, quietly. We don't decorate. Warm near-white surfaces, a single disciplined accent, mono microtype for machine-truth (IDs, stages, dates), and generous whitespace. The result should read like infrastructure: inevitable, exact, expensive to imitate.

02 · Foundations

Typography

One family, two voices. Roobert carries everything human — headings, body, data. Roobert Mono carries everything machine — eyebrows, labels, IDs, meta. Mono is never body copy. Since 2026-08-04, all mono text ships with zero letter-spacing and small mono is always UPPERCASE.

Type ramp

Display sizes use weight 300, line-height 1.0, tracking −0.015em. Body is 16px / 300 / 1.6. Bold within body renders Medium (500), never 700.

Display / H1Roobert 300 · clamp(2.1–2.9rem)
lh 1.0 · ls −0.015em
Five Houston Center
H2 / SectionRoobert 300 · 1.9rem
lh 1.05 · ls −0.015em
Production Items
H3 / Card titleRoobert 400 · 1.2rem
lh 1.15 · ls −0.01em
Reception Desk — White Oak
H4 / Row titleRoobert 400 · 0.95rem
lh 1.2 · ls −0.005em
Fireplace. Unit A & Unit C
BodyRoobert 300 · 16px · lh 1.6
strong = 500
Shop drawings for the reception desk are ready for review. Approval is required before the item enters production at Fábrica Norte.
Card textRoobert 300 · 0.75rem (12px)
var(--at-card-text)
Qty 2 · $18,400 unit · White oak, brushed brass · Due Oct 14, 2026
Label / EyebrowRoobert Mono 400 · 10px
UPPERCASE · ls 0
Production Status · AT-HOU-2026-0001
Micro metaRoobert Mono 400 · 8.5px
UPPERCASE · ls 0
Updated Aug 4 · 12 files · 2.4 MB
Button labelRoobert Mono 400 · 0.7rem
UPPERCASE · ls 0
Source: client-shell.css .atelier-client · globals.css @font-face · button.css .abtn

Weights & files

FileMaps to weightsRole
Roobert-Regular.woff2300–400Body, display headings, data — the default voice
Roobert-Medium.woff2500–700Emphasis (b/strong), row titles, current-stage labels
RoobertMono-Regular.woff2300–400All mono labels — Regular is the working weight
RoobertMono-Medium.woff2500–700Available; unused by default

Self-hosted woff2, font-display: swap, loaded in globals.css so every route renders Roobert. ⚠️ Roobert is a paid face (Displaay); webfont license must be secured for long-term production.

Tracking & casing rules

ContextTrackingCaseRule
Display / headings−0.015emSentence caseTight, editorial. Never uppercase display type.
Body0Sentence case16px floor for reading text.
All mono (labels, chips, meta, buttons)0UPPERCASE🔴 Kerning removed platform-wide 2026-08-04 — supersedes the old 0.1–0.12em convention. Do not reintroduce tracking on mono.
Names, emails, filenames, user data0As enteredNever transformed. IDs/codes (SKU, RFI-###) stay as-is.
Marketing wordmark / homepage buttons0.14–0.28emUPPERCASEHomepage (atelier.inc) only — not platform UI.

Do & Don't

✓ Do
Shop Drawings · Rev C
Reception Desk — White Oak

Mono for the eyebrow, Roobert for the title and copy.

Mono = metadata voice. Roobert = content voice.
✕ Don't

Shop drawings for the reception desk are ready for review and approval before production begins.

Never set body copy in Roobert Mono. Mono is for labels ≤12px.
✕ Don't
P R O D U C T I O N   S T A T U S
No tracking on mono — letter-spacing is 0 everywhere since 2026-08-04.
✕ Don't
Draft  ·  Shop Dwg  ·  Approved  ·  Production  ·  Shipped
Stage labels below 10px are illegible. 10px is the mono label floor (register spine fix, 2026-08-04).
03 · Foundations

Color

Warm near-white paper, deep warm ink, one orange accent. Color is rationed: the accent marks the primary action and live production state; status hues are muted, tinted, and always paired with text. Bone backgrounds are banned from the platform.

Core palette

Ink#171512 · text, dark UI
Ink 2#3A362F · secondary text
Muted#757575 · labels ≥12px
Muted 2#6D675F · small-text safe
Paper#FAFAF8 · app background
White#FFFFFF · cards, panels
Dark#14120E · rail, heroes
Line#EEEEEE · hairlines

Accent

Accent#F1613A · primary action, live state
Accent Light#F4845F · on-dark highlights
Accent Dark#D94E2A · hover, text on light
Accent Tintrgba(241,97,58,.08) · fills

Rationing rule: one accent-filled primary action per view. Everything else is secondary, quiet, or ghost. The accent also owns "in production" state and the current-stage marker — never decorative.

Status palette

Green#3D7A4E · approved / connected
Green Spine#6E9B6F · shipped bar (dk #4B7A4E)
Green Dot#7FBF8A · done tag dot
Amber#9C6F1C · revise / pending review
Gold Dot#E7B84B · review / build dot
Red#C0392B · rejected / destructive (dk #A93226)
Blue#6E93C9 · in transit
Draft#CFC9BC · draft spine (dot #C8C2B6)

Each status hue has a tint + line pair for chips: green #EAF3EC / #CFE4D4, amber #FAF3E3 / #EEE0BD, red rgba(192,57,43,.07) / .25, neutral #F1F0EE / #E3E1DD. Status text is never bare — always chip, tag-with-dot, or spine bar.

Source: button.css .achip-* · client-shell.css .tag · admin-v3.css .pis-*

Banned: the bone family

Bone#E9E5DC · legacy homepage only
Bone 2#EFECE4 · legacy homepage only
Bone 3#F5F2EB · legacy homepage only

⛔ Bone backgrounds belong to the marketing homepage era. Platform UI surfaces are #FAFAF8 and white — nothing else. Legacy --cream/--bone variables still exist in client-shell.css for old sub-pages; do not use them in new work.

Contrast (WCAG 2.1)

PairRatioAA Normal (4.5:1)AA Large / UI (3:1)
Ink #171512 on Paper #FAFAF8~16.9:1Pass (AAA)Pass
Ink-2 #3A362F on White~11.9:1Pass (AAA)Pass
Muted #757575 on White~4.6:1PassPass
Muted #757575 on Paper~4.4:1Borderline — use ≥12px or Muted-2Pass
Muted-2 #6D675F on Paper~5.3:1PassPass
White on Accent #F1613A~3.2:1FailPass
White on Accent Dark #D94E2A~4.1:1Large text onlyPass
Accent Dark #D94E2A on White~4.1:1Large text / links with contextPass
Green #3D7A4E on tint #EAF3EC~4.9:1PassPass
Red #C0392B on White~5.9:1PassPass
White on Dark #14120E~18.4:1Pass (AAA)Pass

Known exception: accent-filled button labels are uppercase mono ~11px on #F1613A (3.2:1). They pass the 3:1 UI-component bar; treat the label as part of a 44px component, and never set paragraphs in white-on-accent. Prefer accent-dark when accent is used as text.

04 · Foundations

Spacing & Layout

A 4/8px rhythm, fluid gutters, and a small closed radius scale. Density is earned: registers run tight (10–18px paddings), reading surfaces breathe (24–64px). Nothing is ever fully round.

Spacing scale

4
8
12
16
20
24
32
40
48
64
TokenValueTypical use
--at-s-1 … --at-s-24 / 8pxChip gaps, icon-to-label, label-to-value
--at-s-3 … --at-s-412 / 16pxRow padding, form gaps, card grids on mobile
--at-s-5 … --at-s-620 / 24pxCard padding (18–26px band), register cells
--at-s-8 … --at-s-1632–64pxSection spacing, hero padding, page rhythm
--at-gutterclamp(22px, 4vw, 64px)Page-level horizontal gutters (journey rows)
Source: client-shell.css --gut · .g-modrow padding 26px clamp(20px,3.4vw,48px)

Radius scale — rectangular, never pill

2px
bars · strips
4px
chips · tracks
6px
buttons · inputs
8px
menus
10px
cards · modals
⛔ pill
never
StepValueApplies to
Micro2pxDense-row status tracks, progress bars, spine strips
Chip4pxStatus chips (.achip), detail bar track, count badges (3–4px band)
Control6pxButtons, inputs, selects, toggles, dropzone, thumbnails, kebab
Menu8pxDropdown menus, popovers, toasts
Card10pxCards, panels, modals, demo surfaces (legacy 14px --r-card exists on older client cards; new work standardizes on 10px)

No pills, capsules, or stadium shapes — ever. Not on buttons, not on chips, not on bars. Segmented bars use 0 radius inside, small radius on outer ends only.

Source: button.css (6px) · achip (4px) · pis-menu (8px) · --r: 10px · statusbar densities (2–4px)

Grid & breakpoints

BreakpointValueWhat changes
Wide≤1360pxRegister/spine labels tighten (admin 9-phase bar)
Tablet≤900pxRegister drops qty/cost columns; spine labels shrink; rail may collapse
Mobile nav≤767pxDesktop nav hides; fixed bottom MobileNav appears; body gains clearance padding
Narrow≤640pxStatus bars keep first/last/current labels only; single-pane messaging
Design floor390pxEverything must work at 390×844 (iPhone 12–14) with safe-area insets

Safe-area rule (2026-08-05): on mobile the body carries padding-bottom: calc(3.5rem + 12px + env(safe-area-inset-bottom)) so content never sits under the fixed bottom nav or the iOS home indicator.

Source: globals.css @media (max-width:767px) · ItemStatusBar.module.css @media 900/640

Elevation

LevelShadowUse
Flatnone — 1px hairline borderDefault. Cards, registers, inputs sit on borders, not shadows.
Menu0 14px 34px -18px rgba(23,21,18,.35)Dropdowns, popovers
Icon chip0 2px 7px -2px rgba(217,78,42,.55)Orange gradient card-header icon tiles
Modal0 30px 80px -30px rgba(20,18,14,.5)Dialogs over glass overlay
05 · Elements

Buttons

One closed set — six variants, three sizes — defined in src/components/ui/Button.tsx + button.css (standard, 2026-08-04). Rectangular 6px radius, Roobert Mono UPPERCASE labels, zero tracking. The accent fill is reserved for the primary action of a view. No hand-rolled buttons, ever.

Variants

VariantRecipeWhen
Primary#F1613A fill · white label · hover #D94E2ATHE action of the view (Save, Send, Invite). Max one per view.
SecondaryWhite · 1px ink border · hover #F4F3F1Edit, Export, Cancel — real actions that aren't the headline
QuietBorderless accent link · optional trailing →Navigational "View all" conventions
GhostTransparent · ink-muted · hover ink tintInline row actions (Resend, View Portal)
DestructiveRed outline rgba(192,57,43,.4) · red textRow-level danger (Remove, Revoke)
Danger#C0392B fill · white · hover #A93226Confirm-modal commits only (Delete Project)

Sizes

States

● Connected
Focus ring: 2px rgba(241,97,58,.45), offset 2px · Disabled: opacity .45 · "Connected" is a CHIP, never a green button
Source: src/components/ui/button.css (verbatim) — use <Button variant=…> / buttonClasses()

Do & Don't

✓ Do
Rectangular 6px, mono uppercase, accent reserved for the primary action.
✕ Don't — pill shapes
The pill "+ New Conversation" button (flagged Aug 2026) violates the geometry canon. No rounded-full, no stadium shapes.
✕ Don't — competing primaries
One accent fill per view. Demote the rest to secondary/ghost.
✕ Don't — sentence-case sans labels
Platform button labels are Roobert Mono UPPERCASE. (Sentence-case Roobert buttons are legacy/homepage.)
06 · Elements

Forms

Quiet fields on white: 1px warm-gray borders, 6px radius, mono uppercase labels above. Focus is an accent border plus soft tint ring. Errors speak twice — red border on the field, inline red banner for the message (invite-flow pattern).

Text inputs

This email already has a pending invite. Resend or revoke the existing invite first.
Inline error banner — invite-flow pattern
PropertyValue
FieldWhite bg · 1px #DCD9D3 · radius 6px · padding 10×12 · Roobert 300 0.9rem
LabelRoobert Mono 10px UPPERCASE · #6D675F · 7px below-gap
Placeholder#B4AEA2
FocusBorder #F1613A + ring 0 0 0 3px rgba(241,97,58,.12)
ErrorBorder #C0392B + mono helper or inline banner (tint rgba(192,57,43,.07), 6px radius)
HelperRoobert Mono 9px UPPERCASE #B4AEA2 · success #3D7A4E

Search · Select · Textarea

Toggles · Radios · Checkboxes · Sliders

Deposit — 55%
Toggle knob is 4px radius on a 6px track — rectangular even in motion. Radio is the one permitted circle (convention for single-choice).

File upload — DropZone canon

The ONE shared upload shell (src/components/ui/DropZone.tsx, used on ~17 surfaces). Never the native "Choose File" chrome. Full-width dashed 1px panel, centered outline glyph, helper + accent mono BROWSE FILES, gray mono hint. Accent border + 4% tint on dragover only.

Drop a PDF or image here, orBrowse FilesPDF · PNG · JPG — up to 25 MB
Drop to uploadRelease
Drop attachment here, orBrowse Files
Top: default · Middle: dragover (accent border + rgba(241,97,58,.04) tint) · Bottom: compact strip for inline attachment rows
Source: src/components/ui/DropZone.tsx (canonical shell, fcbcb98)
08 · Elements

Cards & Content

White surfaces on paper, hairline borders, 10px radius, no default shadows. Hero areas are editorial: full-bleed imagery with glass overlays — never white boxes with text inside. Registers are the platform's signature content pattern.

Project card

In Production
AT-HOU-2026-0001 · Houston TX
Five Houston Center
24 ItemsPhase 5 of 9Oct 2026
Full-bleed cover, glass status chip overlaid ON the image, hover lift −2px + soft shadow.

Production register — the standard

The admin production register is the canonical list pattern for every portal. Item photo thumbnails ALWAYS (via image-URL endpoint, never base64), type chips with status dots, and the 5-stage spine (Draft → Shop Dwg → Approved → Production → Shipped) with 10px labels. Firewalls strip columns (client hides cost; factory hides client identity) — never the design.

ItemNameQty / CostProduction Stage
IMG
56×56
2
$18,400 / unit
DraftShop DwgProductionShipped
IMG
56×56
2
$32,750 / unit
DraftShipped
No Image
Banquette Seating — Lobby
UpholsteryPL-A-118
6
Pending pricing
DraftApprovedShipped

Row anatomy: 3px left status spine bar (draft #CFC9BC / production #F1613A / shipped #6E9B6F) · 56px thumb, 6px radius · grid 56px / 1.6fr / 1fr / 2.6fr / 40px, 20px gaps · row hover rgba(23,21,18,.02) · after ~5 rows the list scrolls.

Source: admin-v3.css .pis-* · ItemStatusBar.module.css row density

Empty states · Skeletons · Timeline

No drawings yet
Upload the first shop drawing to start the approval cycle.
Rev C approved by client
Today · 09:42 · J. Albertini
Factory uploaded Rev C
Aug 3 · Fábrica Norte
Revision requested on Rev B
Jul 29 · grain direction note

Empty states: icon tile + one-line title + ≤34ch subcopy + a single primary action. Skeletons shimmer at 1.4s on #EFEDE9→#F7F5F1. Timeline dots: hollow past, accent current.

09 · Elements

Icons & Visual Language

Outline icons, 1.4–1.6px stroke, round caps, 24px grid. Card-title icons render in accent orange; overview card headers use the approved orange-gradient "cube" chip. Chips and tags are rectangular; avatars are the circle exception.

Stroke & sizes

14 inline 16 rows 18 nav 22 feature Card chip 30px
Card-header icon chip: 30px tile, 7px radius, gradient accent→accent-dark, white glyph, icon-chip shadow. Card-title icons elsewhere: accent stroke. Project Status icon = clock.
Source: admin-v3.css .cticon · decisions 2026-08-02 (orange icons, clock)

Avatars

JA RB FN MT +4 JARB+3
Circle, accent or ink-2 fill, mono initials. Sizes 26 / 34 / 46. Stacks overlap −10px with 2px white ring.

Badges · Chips · Tags — always rectangular

Approved Revise & Resubmit Rejected Pending In Production 3 12
Production In Transit In Review Complete Draft Millwork
.achip = mono uppercase, 4px radius, tint+line+text triads · .tag = dot + label, 7px radius · count badges 5px radius. Health lines are chips, never bare "● ON TRACK" text.
10 · Elements

Motion

Motion is quiet and purposeful: fast color transitions, one slow confident fill, a single persistent pulse marking "now". Nothing bounces except the celebration toast. Respect prefers-reduced-motion.

Timing tokens

TokenValueUsed for
--at-t-fast0.15s easeButton bg/color/border, row hover, tab color
--at-t-ui0.18s easeKebab borders, toggle knob, quiet hovers
--at-t-med0.25s easeArrow nudges (→ +3px), legacy button fills
--at-t-slow0.3s easeCard hover lift, overlay fades
--at-t-fill0.7s easeStatus-bar fill width — the signature move
--at-pulse1.8s infiniteCurrent-stage dot ring (scale 1→1.9, fade out)
--at-toast-in200msToast slide-in from right + fade
Source: button.css 0.15s · client-shell.css 0.18/0.25/0.3s · ItemStatusBar fill 0.7s + mtbPulse 1.8s · Toast.tsx duration-200

Live examples

The pulse — current stage marker (1.8s, infinite)
Production StatusIn Production
62%
DraftMay 02Shop DwgJun 10ApprovedJul 08ProductionNowShippedOct 14
Hover the buttons and cards throughout this book — every transition uses the tokens above. Dot and fill are ALWAYS paired: the fill edge ends exactly at the current-stage dot.

Motion rules

RuleDetail
Color moves fastHover/active feedback ≤180ms. Users should never wait for a hover.
Progress moves slowThe 0.7s fill communicates weight — production state is earned, not instant.
One pulse per viewThe current-stage ring is the only looping animation on a surface.
Transform disciplineLifts ≤2px, arrow nudges ≤3px, active press = translateY(1px). No large parallax in-app.
Dragover is stateful, not animatedDropZone switches border/tint instantly via transition-colors.
Reduced motionUnder prefers-reduced-motion: kill pulse + shimmer, keep instant state changes.
11 · Patterns

Dashboard Components

Dashboards state facts: mono eyebrow, big light number, quiet delta. The Project Status spine is the platform's signature instrument — dissected below. Dark heroes carry borderless glass stat strips.

KPI cards

Items Complete
18 / 24
▲ 3 this week
Days to Delivery
68
Target Oct 14
Budget Committed
$2.1M / 2.45
On track
Open RFIs
4
2 overdue

Value: Roobert 300, 2rem, tracking −0.015em. Units and denominators drop to 1rem muted. Deltas are mono 8.5px — green up, red down, gray neutral.

Status spine — anatomy

Mono eyebrow 10px + stage name Roobert 500 13px Percent · Roobert 300 · 24px
Production StatusIn Production
62%
DraftMay 02Shop DwgJun 10ApprovedJul 08ProductionNowShippedOct 14
Labels: Roobert 400, current = 500 ink · dates mono 8px First/last labels edge-aligned
PartSpec
Track26px tall (detail) · #ECECEC · 1px #EEEEEE border · 4px radius
FillGradient #D94E2A → #F1613A (90deg) · width animates 0.7s ease · SAME gradient family as the project bar
Phase dividers1px rgba(0,0,0,.15) at each stage boundary
Stage dots8px, half-hanging off the bottom edge · done = #C74A2E fill · upcoming = white + 25% ink border
Current dot11px #C74A2E + 1.5px pulsing ring (1.8s, scale 1→1.9)
Pairing rule🔴 Fill edge ends EXACTLY at the current dot — both derive from one current-phase source
Densitiesdetail 26px / card 18px / row 12px · admin register spine labels = 10px (never 6px)
Source: ItemStatusBar.module.css (statusbar-v2, approved 2026-08-04)

Glass stats strip (dark hero)

Items Complete
18 / 24
Phase
5 of 9
Days to Delivery
68
Budget
$2.1M
Open RFIs
4

Glass standing rule (2026-08-02): rgba(10,10,8,.30) + backdrop-filter: blur(16px), no border. Cells split by 7% white hairlines inside the strip.

Activity feed

Rev C approved — Reception Desk
09:42 · J. Albertini · Shop Drawings
Payment received — Deposit 2 ($540,000)
Yesterday · Finance
RFI-014 answered by Atelier PM
Aug 3 · ball-in-court → Client
Banquette Seating moved to Shop Drawings
Aug 2 · Fábrica Norte
12 · Patterns

Modals & Overlays

Overlays are borderless glass: rgba(10,10,8,.30) + 16px backdrop blur — no strokes, ever. Dialogs are white 10px-radius panels with a mono eyebrow, hairline-separated footer, and right-aligned actions. The drawings viewer modal is the exemplar.

Dialog on glass

PartSpec
Overlayrgba(10,10,8,.30) + backdrop-filter: blur(16px) · borderless (glass rule) · click closes non-destructive dialogs
PanelWhite · 10px radius · modal shadow token · width min(480–720px, 100% − 2×gutter)
HeaderMono eyebrow (context) + Roobert 400 title · ✕ ghost close, ESC closes
FooterPaper bg + hairline top · actions right, primary LAST · danger fill only for destructive commits
MotionOverlay fades 0.3s · panel fades + rises ~8px · no bounce
FocusTrap inside dialog · return focus to trigger on close
Source: glass standing rule 2026-08-02 · drawings viewer modal (fcbcb98 reskin)

Drawers · Tooltips · Popovers

Download Rev C
Tooltip: ink bg, mono 9px uppercase, 5px radius, 8px offset. Popovers share the menu recipe (8px radius + menu shadow). Drawers: right-anchored white panel, same glass overlay, 10px radius on the leading edge only.

Do & Don't

✓ Do
Borderless glass — blur does the work.
Glass = rgba(10,10,8,.30) + blur. Nothing else.
✕ Don't
Stroked, too-opaque glass.
No borders on glass; ~30% opacity, not 55%+. (Standing rule 2026-08-02.)
13 · Patterns

Feedback

Toasts confirm, banners warn, skeletons wait, empty states invite. Feedback is brief, placed where the action happened, and auto-dismisses when nothing is required of the user.

Toasts

Invite sent to rburd@tourmalinecp.com
Upload failed — file exceeds 25 MB
Rev B has unsaved markup
Calendar sync will resume automatically
Fixed top-right · slide-in from right + fade, 200ms · auto-dismiss 4s · stack gap 8px · max-width 24rem.
Source: src/components/ui/Toast.tsx

Banners

Loading & progress

Uploading Rev C — 64%
Progress bars reuse the status gradient at 6px height, 2px radius. Page-level waits use skeletons (§08), never full-screen spinners.
14 · Standards

Accessibility

WCAG 2.1 AA is the floor. The warm palette passes comfortably for text; the accent is managed as a large-text/UI color. Every interactive element has a visible focus ring, a 44px touch target on mobile, and a real name for assistive tech.

Contrast summary

UsagePairRatioVerdict
Body textInk on Paper / White16.9 / 17.6AAA
Secondary textInk-2 on White11.9AAA
Labels ≥12pxMuted #757575 on White4.6AA
Small labels on paperMuted-2 #6D675F on Paper5.3AA — prefer over #757575 on paper
Primary button labelWhite on Accent3.2UI-component pass (3:1) — labels only, never paragraphs
Accent as textAccent-dark on White4.1Large text / paired with icon+underline
Destructive textRed #C0392B on White5.9AA
Rail text72% White on Dark≥9AA

Focus & keyboard

Ring: 2px rgba(241,97,58,.45), 2px offset — :focus-visible only. Destructive controls swap to the red ring rgba(192,57,43,.45).
RuleRequirement
Keyboard orderDOM order = visual order. Rail → header → content. Skip-link to main on every portal.
ModalsFocus trapped; ESC closes; focus returns to trigger. role="dialog" + aria-modal + labelled title.
Touch targets≥44×44px on mobile. Small visual controls (kebab 32px) carry padding to reach 44px hit area.
Icon-only controlsAlways aria-label (kebab = "Item actions", ✕ = "Close").
Status ≠ color aloneChips pair color with text; spine pairs fill with labels + dates; deltas pair color with ▲▼.
ImagesItem thumbs get item-name alt; decorative heroes alt="".
Motionprefers-reduced-motion: disable pulse + shimmer, keep state changes instant.
Uppercase labelsApplied via CSS text-transform, never typed — screen readers get natural casing.
15 · Standards

Responsive

Desktop-first density, mobile-first respect. Every core component has a defined path from 1440px down to the 390px floor. On mobile the rail becomes a fixed bottom nav and the body reserves clearance for it — content never hides under the home indicator.

Adaptation map

ComponentDesktop ≥1360Laptop/Tablet ≤1360/900Mobile ≤767 → 390
Nav rail248px dark rail, collapsibleCollapsed icon rail (state persists)Hidden → fixed bottom MobileNav (3.5rem) + safe-area clearance
Production register5-col grid, spine visible≤900: drops qty/cost column, tighter gapsThumb + name + kebab; spine collapses to stage chip + %
Status spine (detail)All labels + dates≤900: labels tighten (7.5px/64px)≤640: only first / last / CURRENT labels; dots remain for every stage
TabsInline rowInline, may wrap groupsHorizontal scroll + edge fade + active tab auto-centers
KPI grid4-up2-up1–2-up, value scales to 1.6rem
ModalsCentered 480–720pxCentered, gutter marginsFull-width sheet, footer actions stack full-width
MessagesTwo-pane (list + thread)Two-pane narrowSingle pane — list OR thread, never squeezed panes
FormsTwo-column where relatedSingle columnSingle column, 16px field font (blocks iOS zoom)
Glass stats stripOne row of cellsWraps 2–3 per row2-up grid, same glass
Dark heroFull editorial heroReduced heightCompact hero, glass info card goes full-width

Mobile hard rules

RuleSpec
Design floor390×844 (iPhone 12–14). Everything must be usable and unclipped here.
Bottom-nav clearancebody { padding-bottom: calc(3.5rem + 12px + env(safe-area-inset-bottom)) } ≤767px (audit fix 2026-08-05) — the last content block never sits under the fixed nav
Viewportviewport-fit=cover + safe-area insets respected on fixed elements
Type floorBody never below 16px in inputs; labels never below 10px
Touch44px targets; row tap areas span the full row
Source: globals.css safe-area block · ItemStatusBar.module.css responsive sweep 2026-08-04
16 · Standards

Design Principles

Ten commitments that make the platform feel like category-defining infrastructure — kept short enough to be enforceable in review.

01 · Hierarchy

One headline per surface

Every view has one dominant element — a number, a title, a status. Size contrast is steep (24px values over 10px labels); everything else recedes into mono microtype.

02 · Density

Registers tight, reading loose

Operational lists earn 12px meta and 18px rows. Narrative surfaces (approvals, foreword-class pages) breathe at 24–64px. Never mix the two registers on one card.

03 · Consistency

One pattern, every portal

Admin, client, and factory share components verbatim. Firewalls strip data, not design. If a portal needs a "special" version, the component is wrong.

04 · Legibility

Machine text is mono, human text is not

IDs, stages, dates, sizes → Roobert Mono uppercase. Sentences, names, titles → Roobert. The split is what makes dense screens scannable.

05 · Motion

Calm, then one heartbeat

Fast color feedback, slow progress fills, and exactly one pulse per view marking "now". Motion never entertains; it locates.

06 · Geometry

Rectangular conviction

2–10px radii, hairline borders, no pills, no stadium shapes. Circles are reserved for avatars, dots, and radios — signals, not chrome.

07 · Color discipline

Accent is a scalpel

Orange marks the primary action and live production state. If two things glow, neither does. Status hues stay tinted and quiet.

08 · Editorial surfaces

Photography carries heroes

Hero areas are full-bleed imagery with borderless glass overlays — luxury-magazine, not dashboard boxes. White cards are for work, not for welcome.

09 · Intent clarity

Design intent ≠ fabrication intent

Reference drawings (what the designer meant) and shop drawings (what the factory will build) are separate objects with separate ceremonies — reference informs, shop drawings get approved. The UI must never blur which one the user is looking at.

10 · AI-first

Legible to humans and machines

Structured registers, tokenized styles, semantic status objects — surfaces are built so agents can read, summarize, and act on them. AI output enters through the same components humans use; provenance stays visible.

17 · Standards

Component Library

The closed inventory. Each component lists its variants, sizes, states, and canonical source. If it isn't here, propose it — don't hand-roll it.

ComponentVariantsSizesStatesSource of truth
Buttonprimary · secondary · quiet(+arrow) · ghost · destructive · dangersm / md / lgdefault, hover, focus, disabled, loadingui/Button.tsx + button.css
StatusChipgreen · neutral · accent · red · amberonestaticbutton.css .achip
Tag (dot)production · transit · review · done · draft · typeonestaticclient-shell.css .tag
Input / Select / Textarea / Datetext, email, search, select, date, textareaonedefault, focus, error, success, disabledui/Input.tsx, ui/Select.tsx
Toggle38×22off, on, focus, disabledui/Toggle.tsx (6px track)
DropZonefull · compact · file-selectedidle, dragover, busy, disabledui/DropZone.tsx (~17 surfaces)
ItemStatusBar5-stage spine (+9/10-stage sets)detail / card / rowanimated fill + pulsing currentitems/ItemStatusBar.module.css
Production registeradmin (full) · client (no cost) · factory (no client identity)row 96pxhover, scrolling after 5 rowsadmin-v3.css .pis-*
KPI cardplain · delta up/down · glass (dark hero)staticoverview cards + .frost
Modaldialog · confirm(danger) · viewer(drawings)480–720pxopen/close, focus-trappedglass rule + drawings viewer
Toastsuccess · error · warning · infomax-w-smenter 200ms, auto-dismiss 4sui/Toast.tsx
Menu / Popoverkebab menu · popovermin 156pxopen, hover, danger row.pis-menu
Tabsunderline (+count chip)oneactive, hover, scroll+fade (mobile)item drawings tabs
Breadcrumbs / Paginationonehover, current, disabledui/Breadcrumbs.tsx
Avataraccent · ink · outline · stack26 / 34 / 46image or initials.pm-av
Empty state / Skeletonicon+title+action · shimmer blocks§08 patterns

Canonical Don'ts (real, from production review)

✕ Pill buttons
Flagged Aug 2026. Rectangular 6px only — no rounded-full anywhere.
✕ Bone backgrounds
Card on #E9E5DC bone
Bone is legacy homepage. Platform surfaces = #FAFAF8 / white.
✕ Mono body copy

Long-form copy set in mono reads like a terminal, not a product.

Mono is labels ≤12px. Body is always Roobert.
✕ Stroked glass
Glass with a border
Glass is borderless — rgba(10,10,8,.30) + blur only.
✕ 6px stage labels
DRAFT   SHOP DWG   APPROVED   PRODUCTION   SHIPPED
Register spine labels were 6px; canon bumped them to 10px (2026-08-04).
✕ Base64 thumbnails
src="data:image/png;base64,iVBORw0KG…"
Item thumbs load via the image-URL endpoint — never inline base64.
18 · Handoff

Getting Started for Engineers

The system lives in the platform repo. Use shared components; never re-implement styles per page. This book ships machine-usable tokens for anything new.

Tokens

ArtifactPathUse
CSS custom propertiesassets/design-tokens.cssImport at :root — all --at-* variables used throughout this book
JSON tokensassets/tokens.jsonDesign-token pipeline / Figma sync / codegen

Canonical sources in atelier-platform

ConcernFile
Global fonts + safe-area + mono rulessrc/app/globals.css
Portal shell vars + shared kitssrc/app/client-shell.css (scoped .atelier-client)
Buttons + chipssrc/components/ui/Button.tsx · button.css — use <Button variant> / buttonClasses() / StatusChip
Uploadssrc/components/ui/DropZone.tsx — visual shell only; callers own upload flow
Status spinesrc/components/items/ItemStatusBar*.{tsx,module.css} — detail/card/row densities
Admin register + overview kitsrc/app/admin/projects/[id]/admin-v3.css (.pis-*, .cticon)
Toasts / inputs / toggles / breadcrumbssrc/components/ui/*
Decision historyATELIER-ARCHITECTURE.md + memory/design-decisions.md

Rules of engagement

#Rule
1New UI uses shared components. A new variant is a PR to the component, not a page-level override.
2No new hex values — pull from tokens. If a color isn't in §03, it doesn't exist.
3No pills, no bone backgrounds, no mono body text, no bordered glass, no sub-10px mono labels.
4One accent-filled primary per view; destructive fills live in confirm modals only.
5Item imagery via the image-URL endpoint. Thumbnails always present in registers.
6Ship at 390px. Verify bottom-nav clearance and safe-area on any fixed element.
7Julien-approved designs are pixel-exact contracts. Codify new approvals in design-decisions.md the same day.
Atelier Design System · v1.0 · August 2026 · Built from production code
app.atelier.inc · © 2026 Atelier Inc.