dragonflight/DESIGN.md
Zac Gaetano 5882c68217 feat(schedule): EPG stylesheet + impeccable context (PRODUCT/DESIGN.md)
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>
2026-05-23 16:19:25 -04:00

6 KiB
Raw Blame History

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.060.08em letterspacing Column heads, section labels
1111.5px Metadata, secondary rows
1212.5px Body in lists/tables
13px, 500600 Row labels, button text
14px Default body
15px, 600 Modal titles, panel heads
2228px, 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: 80120ms 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 — 910px 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 (~68px) 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.