# HUD Panel Component Plan ## Goal Unify Earth HUD panels into a reusable component layer so new panels can share: - a consistent shell - a consistent header - a consistent action-button system - a consistent body and collapse pattern ## Scope Target panels: - `tv-panel` - `news-panel` - `legend` - `layer-panel` - `earth-stats` - `info-card` - settings modal header/actions ## Component Model ### Base shell - `.hud-panel` - `.hud-panel--compact` - `.hud-panel--media` - `.hud-panel--collapsed` - `.hud-panel-hidden` - `.hud-panel.is-dragging` - `.hud-panel.is-layout-animating` ### Header - `.hud-panel__header` - `.hud-panel__title-group` - `.hud-panel__title` - `.hud-panel__subtitle` - `.hud-panel__chip` - `.hud-panel__actions` Header baseline rule: - Header title styling is fixed by the component layer and should not drift per panel - Title font size, font weight, letter spacing, line height, text color, and vertical alignment come from the shared header tokens and structure - Header divider, border treatment, inner spacing, and title-to-actions alignment are part of the same shared baseline - Panel-specific header differences should be limited to explicit variants such as `compact` or `media`, or token overrides with documented intent - “Looks close enough” local header overrides should be treated as temporary compatibility code and removed during migration ### Actions - `.hud-panel__action` - `.hud-panel__action--icon` - `.hud-panel__action--collapse` - `.hud-panel__action--close` - `.hud-panel__action--refresh` - `.hud-panel__action--external` Action-button baseline rule: - Header action buttons must have one fixed default style baseline across all HUD panels - Default width behavior, padding, icon size, radius, alignment, hover, and active feedback all come from `.hud-panel__action` - Panel-specific differences must be expressed through explicit variants or token overrides, not ad-hoc local button rewrites - `close` buttons are part of the same default action system and must not silently fall back to a separate legacy box model ### Body - `.hud-panel__body` - `.hud-panel__body--scroll` - `.hud-panel__body--collapsible` ### Collapse behavior - `.hud-panel--collapsed` - `.hud-panel--expand-up` - `.hud-panel--expand-down` Adaptive collapse / expand rule: - HUD panels support two expansion directions: - top-to-bottom expansion - bottom-to-top expansion - Expansion direction should be decided at runtime from available viewport space rather than hardcoded per panel - Use: - `d` = available distance from the header anchor to the viewport bottom edge - `h` = expected expanded panel height - buffer = `20px` - Collapsed-state direction rule: - if `d > h + 20px`, the next action direction is `expand-up` - if `d <= h + 20px`, the next action direction is `expand-down` - To avoid jitter around the threshold, the shared controller should keep a small hysteresis band: - if the current direction is already `up`, keep it until `d <= h` - if the current direction is already `down`, keep it until `d > h + 20px` - The opposite edge is still a safety guard: - if the chosen side cannot fit at all, fall back to the other side if it can fit - if neither side fully fits, choose the side with more space and let the body scroll - If neither direction fully fits, choose the direction with more available space and let the body scroll - Collapse icon direction must match the active expansion direction so the icon always describes the real open/close motion - The collapse icon describes the next action, not the current state - This mapping is fixed component behavior and must not drift per panel: - collapsed + expand-down => `expand_more` - expanded + expand-down => `expand_less` - collapsed + expand-up => `expand_less` - expanded + expand-up => `expand_more` - Panels must not combine icon-name swapping with extra CSS rotation for the same collapse control - Expansion direction and icon direction must come from one shared source of truth in the component controller - The direction decision should be recomputed when opening, resizing the viewport, or restoring a dragged panel near another edge ## Tokens Promote panel differences into CSS variables instead of duplicating selectors: - `--hud-panel-padding` - `--hud-header-padding` - `--hud-header-gap` - `--hud-action-padding` - `--hud-action-gap` - `--hud-action-icon-size` - `--hud-body-gap` - `--hud-body-max-height` - `--hud-chip-radius` - `--hud-title-font-size` - `--hud-title-font-weight` - `--hud-title-letter-spacing` - `--hud-title-line-height` - `--hud-title-color` - `--hud-header-border-color` - `--hud-header-divider-opacity` - `--hud-expand-direction` ## Migration Order 1. Build the shared component layer in `frontend/public/earth/css/hud.css` 2. Migrate `tv-panel` and `news-panel` first as the reference implementation 3. Migrate `legend` and `layer-panel` into a compact variant 4. Migrate `earth-stats` and `info-card` 5. Align settings modal header/actions with the same action system 6. Remove legacy one-off button selectors after verification ## Guardrails - Do not change panel behavior and data flow during the first pass - Keep old class names temporarily as compatibility hooks - Prefer variable overrides over per-panel reimplementation - Treat header action-button default styling as fixed component API, not per-panel design space - Treat header title typography, border, and divider styling as fixed component API, not per-panel design space - Treat collapse direction as a component behavior contract, not a one-off panel trick - Treat collapse icon semantics as a component behavior contract, not a per-panel visual preference - Verify header alignment and drag/collapse behavior after each migration batch ## First Implementation Batch Batch 1 should only do: - shared header structure - shared action-button system - shared title typography and header border/divider baseline - shared collapsible body pattern - adaptive collapse direction logic and direction-aware collapse icons - migration of `tv-panel` and `news-panel` That keeps risk low while giving the rest of the HUD a stable target to migrate toward.