# Design system Documented from the live tokens in `services/web-ui/public/styles.css` and the patterns used across `screens-*.jsx`. Treat this as the source of truth for shared primitives; pages may override locally but should not invent new color or type scales. ## Color Dark theme only. Tokens live in `:root` in `styles.css`. Tinted neutrals — no `#000`, no `#fff`. ### Surfaces | Token | Hex | Use | |---|---|---| | `--bg-0` | `#0B0D11` | Page background, deepest surface | | `--bg-1` | `#14171E` | Panels, sidebars, primary chrome | | `--bg-2` | `#1B1F27` | Panel headers, hover state | | `--bg-3` | `#232833` | Inputs, raised buttons, badges | | `--bg-4` | `#2D3340` | Strongly raised elements (rare) | ### Borders + overlays | Token | Use | |---|---| | `--border` (rgba white 6%) | Default 1px separator | | `--border-strong` (rgba white 10%) | Emphasized separator | | `--border-stronger` (rgba white 14%) | Hover/active border | | `--hover` (rgba white 4%) | Subtle hover fill | | `--hover-strong` (rgba white 7%) | Stronger hover fill | ### Text | Token | Hex | Use | |---|---|---| | `--text-1` | `#F2F3F6` | Primary content | | `--text-2` | `#A8AEBC` | Secondary content | | `--text-3` | `#6B7280` | Labels, metadata | | `--text-4` | `#4B5260` | Section labels, off-month, disabled | ### Accent `--accent: #5B7CFA` (Frame.io-ish blue). Soft variants `--accent-soft` (14%) and `--accent-soft-2` (22%) for fills. `--accent-text: #B4C3FF` for high-contrast accent text. **Restrained strategy.** Accent is the only saturated color in chrome. Status colors below appear only where they reflect actual state. Project colors appear only on project chips. ### Status | Token | Hex | Use | |---|---|---| | `--success` | `#2DD4A8` | Done, healthy, ready | | `--warning` | `#F5A623` | Processing, attention-needed | | `--danger` | `#FF5B5B` | Failed, error | | `--live` | `#FF3B30` | Currently recording (broadcast red, intentionally hotter than `--danger`) | | `--purple` | `#B57CFA` | Editor / dev tags | Each has a `*-soft` variant at ~14% for background fills. ### Project palette Six fixed colors cycled by index in `data.jsx` (`PROJECT_COLORS`): `#5B7CFA · #2DD4A8 · #FF5B5B · #F5A623 · #B57CFA · #6B7280` Used only on the project chip / rail dot. Do not reuse for status meaning. ## Typography - **Sans:** Geist (with `cv11`, `ss01` features enabled). All UI text by default. - **Mono:** Geist Mono. URLs, IDs, timestamps, durations, technical metadata. Body scale runs small for density: | Size | Use | |---|---| | 10.5px, 600, uppercase, 0.06–0.08em letterspacing | Column heads, section labels | | 11–11.5px | Metadata, secondary rows | | 12–12.5px | Body in lists/tables | | 13px, 500–600 | Row labels, button text | | 14px | Default body | | 15px, 600 | Modal titles, panel heads | | 22–28px, 600+ | Page H1 (`.page-header h1`) | Never use `gradient text` (impeccable absolute ban). Emphasis via weight and size only. ## Layout - Sidebar: 232px fixed (`--sidebar-w`). - Topbar: 56px (`--topbar-h`). - Row height: 44px default, 36px compact (`--row-h`, `data-density="compact"`). - Gap unit: 16px default, 12px compact (`--gap`). - Border radius scale: 4 / 6 / 8 / 12 / 16 px (`--r-xs` → `--r-xl`). - Panels (`.panel`): `--bg-1` + 1px `--border` + `--r-lg`. Use for grouped lists, not for every section. - Do NOT nest panels. ### Page header Standard screens use `.page > .page-header > h1`. Three screens are documented exceptions because they need full-bleed layouts and their own top-chrome: - **Home** uses `.launcher` (lobby pattern: hero logo + tile grid + status pip). - **Library** uses `.library-layout` (dual-pane rail + main). The h1 sits inside `.library-toolbar` as `.toolbar-title`. - **Editor** uses `.editor-shell` (NLE with timeline + monitors). The beta banner doubles as its top chrome. All other screens should render `

` for consistent IA and screen-reader hierarchy. ## Shadow Two tokens, used sparingly: - `--shadow-card`: subtle inset highlight + soft outer. Default for raised inputs. - `--shadow-pop`: modal / popover / context menu. No drop shadows on flat surfaces. No glow effects (except: the EPG now-line uses a tight `box-shadow` for the broadcast-red glow, and live status dots have a pulse halo; these are state cues, not decoration). ## Motion - Default transition: 80–120ms on background/border (`transition: background 80ms, border 80ms`). - Heavier reveals: 200ms. - Easing: prefer ease-out (no bounce, no elastic). - Don't animate layout (width/height/top); animate transforms and opacity. ## Patterns ### Status badges (`.badge`) Variants: `live` (red, animated dot), `success`, `danger`, `warning`, `accent`, `neutral`, `outline`. Tiny — 9–10px font, ~2px vertical padding. Reserved for state, not labels. ### Row tables (`.user-row`, `.token-row`, `.job-row`, `.schedule-row`, etc.) CSS-grid with explicit columns. Header row uses `.head` (uppercase 10.5px). No card stacking — these are dense data lists. ### Schedule EPG (`.epg-*`) Broadcast timeline pattern. Recorder rows × time-of-day axis. Single scrolling container with sticky left gutter (220px) and sticky top ruler (32px). Hour rhythm via `repeating-linear-gradient`. Now-line is a 1px hot-red vertical bar with `--live` glow, animated by re-rendering the line component every second (transform-only positioning, no layout thrash). Event blocks are absolute-positioned within each row, colored via `--epg-block-color` set per recorder's project color. Live events get a red gradient + pulse; failures get a glyph + full red border; past events fade to 0.55 opacity. ### Inputs `.field-input` — `--bg-3` fill, 1px `--border`, `--r-sm`, 12.5px font. Focus: `--border-strong`. ### Status dot (`.signal-dot`, `.rec-dot`, etc.) Small (~6–8px) circle, used inline with text. Recording dots pulse with a keyframe animation. ## Impeccable absolute bans (apply project-wide) - No `border-left` / `border-right` greater than 1px as a colored accent (rewrite with full borders, leading icons, or background tint). - No `background-clip: text` gradient text. - No glassmorphism (blur + translucent) decoratively. - No hero-metric template (big number, small label, gradient accent, supporting stats). - No identical card grids. - Modal as last resort — exhaust inline alternatives first. - No em dashes in code or copy. Use commas, colons, parentheses, periods. ## To extend When a new design need arises, prefer adding a variant to an existing primitive over inventing a new token. New tokens land in `styles.css`. New components land in the relevant `screens-*.jsx` only if reused; otherwise keep them local.