The EPG JSX components in screens-ingest.jsx ship with the YouTube branch but the matching stylesheet got lost during the parallel-branch shuffle. This adds the missing .epg-* block to styles-rest.css and replaces the dead .cal-* (month-calendar) rules left over from the previous design. What the styles cover: - .epg-page / .epg-toolbar — top-level flex layout + date nav row - .epg-status — sticky "on air" strip with pulse halo on the live dot - .epg / .epg-corner / .epg-gutter / .epg-canvas-head / .epg-canvas — the 2x2 sticky grid (top ruler + left gutter both sticky) - .epg-ruler / .epg-ruler-tick — hour ticks - .epg-row + .epg-block + .epg-block.live/.failed/.past — event blocks with project-color 4px inner bar (no side-stripes; impeccable ban) - .epg-now / .epg-now-pip — vertical hot-red now-line with broadcast glow - .epg-week + .epg-week-day — stacked 7-day sections for week view - .epg-empty — recorder-less / loading empty state Also adds PRODUCT.md and DESIGN.md so future design passes have the context files the impeccable skill requires. Both drafted from the existing codebase (tokens, screen patterns) rather than synthesised from a prompt. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
143 lines
6 KiB
Markdown
143 lines
6 KiB
Markdown
# 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.
|
||
|
||
## 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.
|