The component kit.
One sheet, and cross-surface consistency stops being a discipline and becomes a lookup. Every part the sphere, the world OS, and the arrival share is rendered live here in both registers, the day paper and the night Forge, each with the exact CSS beside it. The registers are a token flip of one composition: set data-register="forge" and the same classes carry the night set, no component re-decided. The law is the Mainstar binder, verbatim. Zero-radius, one act per view, Plex Mono for all chrome, elevation an engraved hairline. Build from this and the surfaces cannot drift.
§ 01Type and tone, three voices, no fourth
Fraunces is the human voice (claims, world names, window titles). Space Grotesk is the working voice (labels, body, controls). Plex Mono is the machine voice and it holds all chrome, kickers, statuses, data rows, timestamps, always uppercase, tracked .12 to .18em. A surface that reaches for a fourth family is off-law.
TYPE ROLES · CSS▸
:root {
--serif: "Fraunces", Georgia, serif; /* claims, names, titles */
--ui: "Space Grotesk", ui-sans-serif; /* labels, body, controls */
--mono: "IBM Plex Mono", ui-monospace; /* ALL chrome, uppercase */
}
.claim { font: 600 clamp(34px,4.4vw,50px)/1.04 var(--serif); letter-spacing:-.018em; }
.wtitle { font: 500 italic 21px var(--serif); }
.body { font: 500 15px/1.6 var(--ui); color: var(--text-soft); }
.chrome { font: 600 12px var(--mono); letter-spacing:.16em; text-transform:uppercase; }§ 02The one act, orange is a promise
Cadmium by day, ember by night, appears in exactly two places: the one primary action per view, and attention waiting on you. Nothing else. Teal is quiet positive status, stamp red is destructive only, the craft tones live in charts and agent marks, never on a control. Grounds stay on the paper family by day and the Forge set by night. Never pure black, never pure white.
THE REGISTER FLIP · CSS▸
/* day = default */
:root {
--surface: var(--paper); --text: var(--ink); --border: var(--line);
--act: var(--cad); --act-on: var(--cad-on);
--positive: var(--teal); --working: var(--warn); --destructive: var(--stamp);
}
/* the flip — same names, night set. Put it on html/body or any subtree. */
[data-register="forge"] {
--surface: var(--night); --text: var(--night-ink); --border: var(--night-line);
--act: var(--ember); --act-on: var(--night);
--positive: var(--night-teal); --working: var(--night-warn); --destructive: var(--night-stamp);
}§ 03Kicker
The mono uppercase label that names a region or a record. It is the quietest thing on any surface and it never carries the act, unless it is naming attention, in which case it takes the promise color.
.kicker · CSS▸
.kicker { font: 600 10px var(--mono); letter-spacing:.16em; text-transform:uppercase; color: var(--text-faint); }
.kicker.act { color: var(--act); } /* only when naming attention; flips to ember in forge */§ 04Door family, the buttons
.door is the outlined mono button, the quiet peer. .door.quiet is quieter still, a hairline ghost. .door-fill is the one filled act, and a surface carries at most one. Every button ships all four live states below: default, hover, focus-visible (a 2px ring), and disabled. Disabled goes dashed, keeps its label legible, and states its reason beside it in both registers.
.door / .door-fill / .door.quiet · CSS▸
.door, .door-fill {
font: 600 12px var(--mono); letter-spacing:.12em; text-transform:uppercase;
transition: transform var(--mo-snap) var(--ease-tap), background var(--mo-settle) var(--ease-settle);
}
.door { color: var(--text); background: transparent; border: 1px solid var(--border-strong); padding: 11px 18px; }
.door:hover { transform: translateY(-1px); background: var(--btn-hover-bg); }
.door:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.door.quiet { border-color: var(--border); color: var(--text-soft); } /* the ghost peer */
.door-fill { /* the one act — flips cad→ember */
color: var(--act-on); background: var(--act); border: 1px solid var(--act-deep); padding: 12px 20px;
box-shadow: var(--act-glow); /* none by day, one filament by night */
}
/* disabled = dashed structural signal, reason sits beside it */
.door[disabled], .door-fill[disabled] {
cursor: not-allowed; border-style: dashed; background: transparent;
color: var(--text-soft); border-color: var(--border);
}§ 05State vocabulary, the canon five
The only words a world state may wear: WORKING (breathing dot), IDLE (still, faint), NEEDS YOU (the promise, diamond dot), ALL CLEAR (the designed calm, teal), and at the artifact level DRAFT READY. No synonyms, no moods. ALL CLEAR is not the absence of a state, it is a state we designed. The rail visibly stills.
.vchip · CSS▸
.vchip { display: inline-flex; align-items: center; gap: 7px; padding: 6px 11px;
font: 600 9.5px var(--mono); letter-spacing:.16em; text-transform:uppercase; border: 1px solid currentColor; }
.vchip .dot { width: 7px; height: 7px; background: currentColor; }
.vchip.working { color: var(--working-ink); } .vchip.working .dot { animation: vc-breathe 2.1s var(--ease-settle) infinite; }
.vchip.idle { color: var(--text-faint); }
.vchip.needs-you { color: var(--act); } .vchip.needs-you .dot { transform: rotate(45deg); }
.vchip.all-clear { color: var(--positive); }
.vchip.draft-ready{ color: var(--text-soft); } /* quiet tier in BOTH registers */§ 06Journal line
The world's memory, one row at a time. A 2px left rule carries the record's meaning in color: neutral for ordinary work, teal for something finished well, cadmium for a decision waiting on you, stamp for something removed. A fresh entry lands with the Cold Press Settle, then goes quiet.
.journal-line · CSS▸
.journal-line { display: grid; grid-template-columns: auto 1fr auto; gap: 12px; align-items: baseline;
border-left: 2px solid var(--border); background: var(--surface); padding: 9px 14px 9px 13px;
font: 500 13.5px/1.45 var(--serif); color: var(--text-soft); }
.journal-line .jw { font: 600 9.5px var(--mono); letter-spacing:.12em; text-transform:uppercase; color: var(--text-faint); }
.journal-line .jt em { color: var(--text); font-style: normal; }
.journal-line.success { border-left-color: var(--positive); }
.journal-line.needs-you { border-left-color: var(--act); background: var(--wash-needs); }
.journal-line.destructive { border-left-color: var(--destructive); }
.journal-line.fresh { animation: st-settle var(--mo-settle) var(--ease-settle); } /* lands, then quiets */§ 07World tile
One client, one sealed world, one pane on the sphere. A sharp rectangle showing three abstract window bars, the documents open inside, with its state told by the temperature of the light: parchment when idle, warm amber when the crew is working, cadmium-bracketed when it needs you. The name rides a two-row mono flag beneath, so the longest client name never wraps into the state.
Rendered from the shared demo data (4-world cast), so the same names and states appear on every surface.
.world-tile · CSS▸
.world-tile { width: 150px; border: 1px solid var(--border); background: var(--surface-3); position: relative; }
.world-tile .screen { height: 92px; padding: 11px 11px 0; background: var(--screen); border-bottom: 1px solid var(--border); }
.world-tile .bar { height: 6px; background: var(--border); margin-bottom: 6px; }
/* two-row flag — name never wraps into state */
.world-tile .flag { padding: 7px 10px 8px; display: flex; flex-direction: column; gap: 3px; }
.world-tile .flag .nm { font: 600 9.5px var(--mono); text-transform:uppercase; white-space:nowrap; }
.world-tile .flag .st { font: 400 9px var(--mono); text-transform:uppercase; white-space:nowrap; }
/* state by light temperature */
.world-tile.working { border-color: var(--working); }
.world-tile.working .screen { background: var(--screen-work); }
.world-tile.working .cursor { position:absolute; bottom:16px; left:11px; width:16px; height:5px;
background: var(--act); animation: wt-write 1.9s var(--ease-settle) infinite; }
.world-tile.needs-you { border-color: var(--act); box-shadow: var(--act-ring-glow); }
.world-tile.needs-you .beacon { position:absolute; top:-7px; right:-7px; width:11px; height:11px;
background: var(--act); transform: rotate(45deg); }§ 08Instrument bar
The reading across the top of a surface: local time, the counts, and the one number that matters, how many worlds need you. When that number is zero the segment does not vanish, it turns teal and says ALL CLEAR, so the calm is a stated reading. A stale variant covers the moment before live data lands. On a phone the bar scrolls rather than pushing the page sideways.
.instrument-bar · CSS▸
/* wrap so the bar SCROLLS on a phone, never pushes the page sideways */
.instrument-wrap { max-width: 100%; overflow-x: auto; }
.instrument-bar { display: flex; border: 1px solid var(--border-strong); background: var(--surface);
font: 500 11px var(--mono); letter-spacing:.08em; text-transform:uppercase; color: var(--text-soft); width: max-content; min-width: 100%; }
.instrument-bar .seg.attn { margin-left: auto; background: var(--act); color: var(--act-on); }
/* ALL CLEAR is a stated reading, not an empty slot */
.instrument-bar .seg.attn.clear { background: var(--surface-2); color: var(--positive); }
.instrument-bar.stale { color: var(--text-faint); } /* awaiting live data */§ 09Frame
The general container: an engraved hairline plus the faint warm cast of --elev, closed by a mono caption bar. This is elevation without a drop-shadow idiom. The sheet sits on the desk, it does not float above it. In the Forge the cast drops away and the hairline alone carries the frame.
.frame · CSS▸
/* elevation = engraved hairline + faint warm cast; --elev flips to none in forge */
--lift: 0 1px 0 var(--line), 0 14px 34px -20px rgba(44,33,24,.35);
.frame { border: 1px solid var(--border); background: var(--surface-2); box-shadow: var(--elev); }
.frame .fbody { padding: 20px 22px; font: 500 14px/1.6 var(--ui); color: var(--text-soft); }
.frame .caption { font: 500 10px var(--mono); letter-spacing:.14em; text-transform:uppercase;
color: var(--text-faint); padding: 8px 14px; border-top: 1px solid var(--border); display: flex; justify-content: space-between; }§ 10Reg window
The app window, the sphere's signature chrome: a sheet with a registration cross printed at each corner, the way a plate is trued on a press. The crosses are a 1px ink stroke by default and turn to the act color only when the window is focused. By day it is a filled paper sheet, in the Forge it is drawn in line on the hull.
.reg-window + .reg · CSS▸
.reg-window { position: relative; border: 1px solid var(--border-strong); background: var(--surface); box-shadow: var(--elev); }
/* the cross: 1px stroke, 9px, centered on the corner, ink by default */
.reg { position: absolute; width: 9px; height: 9px; }
.reg::before, .reg::after { content:""; position: absolute; background: var(--text); }
.reg::before { width: 9px; height: 1px; top: 4px; } /* horizontal arm */
.reg::after { width: 1px; height: 9px; left: 4px; } /* vertical arm */
.reg.tl{ top:-4.5px; left:-4.5px } /* .tr .bl .br mirror it */
/* act ONLY under focus/attention — never a resting accent */
.focused .reg::before, .attn .reg::before { background: var(--act); }§ 11Form controls
Where the owner names a world or tells the crew what to make. Label above in mono, field on ground with a hairline that darkens on focus plus the 2px ring. The full set ships: default, focus, filled, valid, disabled, error, a select, a checkbox and radio, and a textarea with a live character counter. An error is a record, not a scolding: it states when, what, and what to do next.
Name is free. Ready to seal the world.
14:12 · That name is already on the sphere. Pick another, or open the existing world.
Name is free. Ready to seal the world.
14:12 · That name is already on the sphere. Pick another, or open the existing world.
form controls · CSS▸
.field { width: 100%; font: 500 16px var(--ui); color: var(--text); background: var(--surface);
border: 1px solid var(--border); padding: 11px 13px; transition: border-color var(--mo-settle) var(--ease-settle); }
.field:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; border-color: var(--border-strong); }
.field.filled { border-color: var(--text-soft); }
.field.ok { border-color: var(--positive); } /* valid */
.field.err { border-color: var(--destructive); } /* error, with when/what/next line */
.field:disabled { border-style: dashed; color: var(--text-faint); background: var(--surface-2); }
.select select.field { appearance: none; padding-right: 34px; } /* mono caret drawn in ::after */
.check input:checked + .box { border-color: var(--act); }
.check input:checked + .box::after { content:""; position:absolute; inset:3px; background: var(--act); }§ 12Motion tempos
Three tempos, transform and opacity only, each with one job. Snap answers a press. Settle is the signature Cold Press Settle, a record landing and quieting. Arrive is a window dealing onto the desk, registration crosses first. Press a tile to replay. Under reduced-motion all three resolve to their final state instantly.
MOTION TOKENS · CSS▸
--mo-snap: 120ms; --mo-settle: 240ms; --mo-arrive: 480ms;
--ease-settle: cubic-bezier(0.22,0.61,0.36,1); /* Cold Press Settle, the signature */
--ease-arrive: cubic-bezier(0.16,1,0.3,1);
--ease-tap: cubic-bezier(0.4,0,0.2,1);
@keyframes st-settle { from { transform: translateY(5px); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes st-arrive { from { transform: translateY(-22px) scale(.94); opacity: 0; } to { transform: none; opacity: 1; } }
@media (prefers-reduced-motion: reduce) { * { animation: none !important; transition: none !important; } }§ 13Decision card
The one place the owner is asked to choose. It states who raised it, what it blocks, and the evidence, then offers a clear act. On approve, the outcome types itself into being and the journal beside it settles from NEEDS YOU to ALL CLEAR, and the card cools: its header and corner crosses drop the act once nothing is pending. This is the split-truth in one part, the choice and its result made visible. Approve, decline, or hold, then replay.
§ 14Agent mark
The crew, named and marked. A mono monogram in a hairline square, with the who beside it. When an agent is working the mark takes the warn edge, when it raised something for you it takes the act. The crew is Vela, Corvin, Sable, and only these three.
.agent-mark · CSS▸
.agent-mark .mono-badge { width: 26px; height: 26px; display:flex; align-items:center; justify-content:center;
border: 1px solid var(--border-strong); background: var(--surface-2); font: 600 11px var(--mono); color: var(--text); }
.agent-mark.working .mono-badge { border-color: var(--working); color: var(--working-ink); }
.agent-mark.needs-you .mono-badge { border-color: var(--act); color: var(--act); }§ 16Table and pager
Rows of record. A mono header, hairline rules, serif nowhere but the numbers stay legible. The pager is a mono strip, the current page filled with the act.
| World | State | Last action |
|---|
| World | State | Last action |
|---|
.dtable / .pager · CSS▸
.dtable th { font: 600 9px var(--mono); letter-spacing:.14em; text-transform:uppercase; color: var(--text-faint);
padding: 9px 14px; border-bottom: 1px solid var(--border); background: var(--surface-2); }
.dtable td { font: 500 13px var(--ui); color: var(--text-soft); padding: 10px 14px; border-bottom: 1px solid var(--border-soft); }
.pager button.on { color: var(--act-on); background: var(--act); } /* current page */
.pager button:disabled { color: var(--text-faint); border-style: dashed; }§ 17Toast, tooltip, empty state
Small feedback, same law. A toast is a framed note with a 2px semantic rule, teal for done, cadmium for needs-you, stamp for removed. A tooltip is a mono bubble. An empty state is a designed room, not a blank, with a mark, a line, and a way out.
.toast / .tip / .empty · CSS▸
.toast { display: flex; gap: 12px; border: 1px solid var(--border); border-left: 2px solid var(--positive);
background: var(--surface-2); box-shadow: var(--elev); padding: 12px 15px; }
.toast.needs-you { border-left-color: var(--act); }
.tip .tip-bubble { position: absolute; bottom: calc(100% + 8px); color: var(--act-on); background: var(--text);
opacity: 0; transition: opacity var(--mo-snap) var(--ease-tap); }
.tip:hover .tip-bubble { opacity: 1; }
.empty { border: 1px dashed var(--border); background: var(--surface); padding: 34px 26px; text-align: center; }§ 18Modal and skeleton
The overlay and the wait. A modal is a reg-window pulled to the middle over a faint warm scrim, its close always reachable at the top. A skeleton is the shape of coming content, pulsing in opacity only, never a shimmer sweep.
.modal / .scrim / .skel · CSS▸
.scrim { position: fixed; inset: 0; background: var(--wash-needs); display: flex; align-items: center; justify-content: center; z-index: 60; }
.modal { width: 100%; max-width: 420px; background: var(--surface); border: 1px solid var(--border-strong); box-shadow: var(--lift); }
.modal .m-close { margin-left: auto; } /* the way out is always at the top */
.skel { background: var(--surface-2); border: 1px solid var(--border); animation: skel-pulse 1.4s var(--ease-settle) infinite; }
@keyframes skel-pulse { 0%,100%{ opacity:1 } 50%{ opacity:.45 } } /* opacity only, no shimmer sweep */