Files
echo-core/dashboard/static/tokens.css
Marius Mutu 5e930ade02 feat(dashboard): unified workspace hub — cookie auth, 9-state projects, planning chat
Merges workspace.html + ralph.html into a single unified project hub with:
- Cookie-based auth (DASHBOARD_TOKEN, HttpOnly, SameSite=Strict)
- 9-state project badge system (running-ralph/manual, planning, approved,
  pending, blocked, failed, complete, idle) with BUTTONS_FOR_STATE matrix
- SSE realtime + polling fallback, version-based optimistic concurrency (If-Match)
- Planning chat modal (phase stepper, markdown bubbles, 50s+ wait state, auto-resume)
- Propose modal (Variant B: inline Plan-with-Echo checkbox)
- 5-type toast taxonomy (success/info/warning/busy/error, 3px colored left-bar)
- Inter font self-hosted + shared tokens.css design system + DESIGN.md
- src/jsonlock.py (flock helper, sidecar .lock for stable inode)
- src/approved_tasks_cli.py (shell-safe wrapper for cron/ralph.sh)
- 55 new tests (T#1–T#30) + real jsonlock bug fix caught by T#16/T#28
- No emoji anywhere (enforced by test_dashboard_no_emoji.py)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 07:26:19 +00:00

160 lines
5.0 KiB
CSS

/*
* Echo Dashboard — Design Tokens
* Single source of truth for all CSS variables, fonts, and shared
* mobile-modal behavior. Loaded via /echo/static/tokens.css on every
* dashboard page (in addition to common.css for now).
*
* Token coverage:
* - Colors (dark default + light theme override)
* - Status palette (running, blocked, failed, complete, idle,
* planning, pending, approved)
* - Typography (Inter sans + JetBrains Mono mono, size scale)
* - Spacing (8px grid)
* - Radius scale
* - Shadows / transitions
*/
/* ==========================================================
@font-face — Inter (self-hosted, woff2 only)
========================================================== */
@font-face {
font-family: 'Inter';
src: url('/echo/static/fonts/inter-400.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Inter';
src: url('/echo/static/fonts/inter-500.woff2') format('woff2');
font-weight: 500;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Inter';
src: url('/echo/static/fonts/inter-600.woff2') format('woff2');
font-weight: 600;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Inter';
src: url('/echo/static/fonts/inter-700.woff2') format('woff2');
font-weight: 700;
font-style: normal;
font-display: swap;
}
/* ==========================================================
Tokens — dark theme (default)
========================================================== */
:root {
/* Colors — dark surface */
--bg-base: #13131a;
--bg-surface: rgba(255, 255, 255, 0.12);
--bg-surface-hover: rgba(255, 255, 255, 0.16);
--bg-surface-active: rgba(255, 255, 255, 0.20);
--bg-elevated: rgba(255, 255, 255, 0.14);
--text-primary: #ffffff;
--text-secondary: #f5f5f5;
--text-muted: #e5e5e5;
--accent: #3b82f6;
--accent-hover: #2563eb;
--accent-subtle: rgba(59, 130, 246, 0.2);
--border: rgba(255, 255, 255, 0.3);
--border-focus: rgba(59, 130, 246, 0.7);
--header-bg: rgba(19, 19, 26, 0.95);
--success: #22c55e;
--warning: #eab308;
--error: #ef4444;
/* Status palette — used by .status-pill[data-status] */
--status-running: rgb(34, 197, 94); /* green — running-ralph / running-manual */
--status-blocked: rgb(245, 158, 11); /* amber */
--status-failed: rgb(239, 68, 68); /* red */
--status-complete: rgb(156, 163, 175); /* slate (done = neutral) */
--status-idle: var(--text-muted);
/* Status palette — extended (workflow states) */
--status-planning: rgb(167, 139, 250); /* violet — Echo is planning */
--status-pending: rgb(96, 165, 250); /* sky — awaiting approval */
--status-approved: rgb(234, 179, 8); /* gold — approved tonight */
/* Spacing — 8px grid */
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--space-5: 20px;
--space-6: 24px;
--space-8: 32px;
--space-10: 40px;
/* Typography */
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--font-mono: 'JetBrains Mono', 'Fira Code', ui-monospace, monospace;
--text-xs: 0.75rem;
--text-sm: 0.875rem;
--text-base: 1rem;
--text-lg: 1.125rem;
--text-xl: 1.25rem;
/* Radius */
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
--radius-full: 9999px;
/* Shadows */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4);
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.5);
/* Motion */
--transition-fast: 0.15s ease;
--transition-base: 0.2s ease;
}
/* ==========================================================
Light theme override
========================================================== */
[data-theme="light"] {
--bg-base: #f8f9fa;
--bg-surface: rgba(0, 0, 0, 0.04);
--bg-surface-hover: rgba(0, 0, 0, 0.08);
--bg-surface-active: rgba(0, 0, 0, 0.12);
--bg-elevated: rgba(0, 0, 0, 0.06);
--text-primary: #1a1a1a;
--text-secondary: #444444;
--text-muted: #666666;
--border: rgba(0, 0, 0, 0.12);
--border-focus: rgba(59, 130, 246, 0.5);
--accent-subtle: rgba(59, 130, 246, 0.12);
--header-bg: rgba(255, 255, 255, 0.95);
}
/* ==========================================================
Mobile modal — shared across all pages with .modal-overlay
========================================================== */
@media (max-width: 640px) {
.modal-overlay { padding: 0; align-items: stretch; }
.modal { max-width: 100vw !important; max-height: 100vh !important; border-radius: 0; height: 100vh; }
.modal-header { position: sticky; top: 0; background: var(--bg-base); }
.modal-footer { position: sticky; bottom: 0; padding-bottom: max(var(--space-4), env(safe-area-inset-bottom)); }
.phase-stepper .phase-step:not(.active) span:not(.step-num) { display: none; }
}