The editorial broadsheet design language
Status: Accepted · Date: 2026-06-09/10 · Area: UI
Context
The orbit-webapp originally shipped a dark glassmorphism look with rainbow-gradient branding. As the product matured into a reading-heavy analysis surface — long prose, dense tables, severity and status annotation — that idiom worked against it, and ad-hoc per-component styling made the two themes drift apart. A restyle established a written contract so new UI does not reintroduce the old idioms.
Decision
The webapp follows an editorial broadsheet language:
- Light-first: warm cream “paper” is the default theme; dark is a warm
graphite companion. Theming is token-only —
:rootholds the paper tokens and:root[data-theme="dark"]is a token override block. There must be zero per-component theme rules (single recorded exception: the header theme-toggle icon swap). If a component looks wrong in one theme, fix token values, never fork rules. - One accent: a single Prussian ink-blue (
--accent) does all interactive work — links, active nav bars, focus rings, tab underlines, code refs. The brand rainbow stops survive only in the logo image and the agent-strip pulse. - A tint formula, not hardcoded washes: badges/pills/chips use
color-mix(in srgb, var(--TOKEN) 12%, transparent)backgrounds with 24% borders and full-token text; raw white/black rgba values are banned. - A shape code: severity badges are square print stamps; status pills stay round. Square = severity, round = state — deliberate.
- Banned idioms: no glass (
backdrop-filter), no glow shadows, no gradient text, no hover translate/scale/brightness lifts. Elevation is hairlines plus paper shadows. - Editorial typography: serif display for detail titles and KPI numerals, masthead double rules, dash-slug eyebrows; the semantic palette is print-annotation (brick/sienna/ochre for severity, moss/steel/wine for status), defined per-theme in the token blocks only.
- A related maintainer preference is part of the contract: keep-context-while-scrolling is structure, not overlays — pin a pane title as a fixed region with an inner scroller, never a scroll-triggered overlay bar.
Consequences
- New UI has a decidable style contract; both themes stay consistent because divergence can only happen in token values, which live in exactly two blocks.
- Third-party surfaces must follow the document theme: Mermaid and Monaco are
wired through a shared
use-document-themehook, and the graph JS palettes reference the same CSS variables. - A FOUC guard (inline pre-hydration script reading
localStorage) and the default-theme constant must be kept in sync by hand. - Recorded leftover: the rail logo asset is a black-background raster of the rainbow mark, awkward on the cream rail — needs a new asset; CSS cannot fix a JPG.
- Aurora’s webapp reuses the same
globals.cssand shell, so the contract extends to the control plane, not just the reader.
Evidence
implementation/orbit-webapp/codebase/src/app/globals.css— the two token blocks and the component stylesimplementation/orbit-webapp/codebase/src/components/orbit/use-document-theme.tsimplementation/orbit-webapp/codebase/docs/— page-pattern docs updated to this languagememory/editorial-design-language.md(the contract),memory/aurora-webapp.md(style reuse in Aurora)