Skip to Content
Design DecisionsEditorial Design Language

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:root holds 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-theme hook, 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.css and 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 styles
  • implementation/orbit-webapp/codebase/src/components/orbit/use-document-theme.ts
  • implementation/orbit-webapp/codebase/docs/ — page-pattern docs updated to this language
  • memory/editorial-design-language.md (the contract), memory/aurora-webapp.md (style reuse in Aurora)