// ============================================================================ // OpenClaw Control Center — M3 Tactical Dark Theme // ============================================================================ // Main global stylesheet. Imports the design system token modules and // applies the M3 dark theme. All tokens are defined once in // styles/_tokens.scss — SCSS variables and mixins // styles/_css-properties.scss — CSS custom property output // styles/_utilities.scss — utility mixins for components // // Components should @use these modules rather than hardcoding values. // ============================================================================ @use 'styles/tokens' as tokens; @use 'styles/css-properties' as css-props; @use 'styles/utilities' as utils; @use '@angular/material' as mat; // --------------------------------------------------------------------------- // M3 Theme Definition // --------------------------------------------------------------------------- // Using mat.define-theme() with custom color tokens to match the tactical // dark palette. Angular Material 19+ uses the new theming API. // --------------------------------------------------------------------------- $dark-theme: mat.define-theme(( color: ( theme-type: dark, primary: mat.$cyan-palette, tertiary: mat.$violet-palette, ), typography: ( brand-family: tokens.$font-family-brand, plain-family: tokens.$font-family-body, bold-weight: tokens.$font-weight-bold, medium-weight: tokens.$font-weight-medium, regular-weight: tokens.$font-weight-regular, ), density: ( scale: 0, ), )); // --------------------------------------------------------------------------- // Apply theme to :root // --------------------------------------------------------------------------- html { height: 100%; @include mat.theme($dark-theme); color-scheme: dark; } // --------------------------------------------------------------------------- // Emit Design System CSS Custom Properties // --------------------------------------------------------------------------- @include css-props.emit-custom-properties; // --------------------------------------------------------------------------- // Per spec Section 5.1 "Status Colors (Semantic — outside M3 tonal system)" // These are NOT part of the M3 tonal palette; they are semantic overrides. // --------------------------------------------------------------------------- :root { // --- Tactical Dark Mode color palette (CUB-47) --- --color-surface: #0F172A; --color-surface-light: #1E293B; --color-primary: #38BDF8; --color-secondary: #2DD4BF; --color-accent: #A78BFA; --color-danger: #F87171; --color-text-primary: #FFFFFF; --color-text-secondary: #94A3B8; --color-border: #334155; // --- Status colors --- --status-active: #38BDF8; --status-idle: #2DD4BF; --status-thinking: #A78BFA; --status-error: #F87171; --status-offline: #64748B; // --- Status background tints (12% opacity) --- --status-active-bg: rgba(56, 189, 248, 0.12); --status-idle-bg: rgba(45, 212, 191, 0.12); --status-thinking-bg: rgba(167, 139, 250, 0.12); --status-error-bg: rgba(248, 113, 113, 0.12); // --- Surface overrides (tactical dark palette) --- --cc-background: #0D0F12; --cc-surface: #13161A; --cc-surface-container: #1C2027; --cc-surface-container-high: #252B33; --cc-on-surface: #E2E8F0; --cc-on-surface-variant: #8A9BB0; --cc-outline: #2D3748; // --- Mono font stack --- --cc-font-mono: 'Roboto Mono', 'Cascadia Code', 'Fira Code', monospace; // --- Layout constants --- --cc-nav-rail-collapsed-width: 72px; --cc-nav-rail-expanded-width: 256px; --cc-header-height: 64px; --cc-header-height-compact: 56px; --cc-bottom-nav-height: 80px; --cc-card-border-radius: 16px; --cc-card-min-width: 280px; --cc-card-gap: 16px; --cc-card-padding: 20px; --cc-section-padding: 24px; --cc-section-padding-compact: 16px; --cc-spacing-unit: 8px; // --- Responsive breakpoints (CUB-27) --- --cc-breakpoint-compact: 599px; // 0-599px: phone / compact --cc-breakpoint-medium: 600px; // 600-1023px: tablet / medium --cc-breakpoint-expanded: 1024px; // ≥1024px: desktop/kiosk / expanded } // --------------------------------------------------------------------------- // Global Body Styles // --------------------------------------------------------------------------- body { background-color: var(--cc-surface-darkest); color: var(--cc-on-surface); font-family: var(--cc-font-body); margin: 0; height: 100%; min-height: 100vh; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } // --------------------------------------------------------------------------- // Typography Helpers // --------------------------------------------------------------------------- .text-mono { font-family: var(--cc-font-mono); font-size: tokens.$font-size-body-medium; font-weight: tokens.$font-weight-regular; letter-spacing: tokens.$letter-spacing-mono; } .text-display-large { font-size: tokens.$font-size-display-large; font-weight: tokens.$font-weight-heavy; line-height: tokens.$line-height-tight; letter-spacing: tokens.$letter-spacing-tight; } .text-headline-medium { font-size: tokens.$font-size-headline-medium; font-weight: tokens.$font-weight-bold; line-height: tokens.$line-height-tight; } .text-title-large { font-size: tokens.$font-size-title-large; font-weight: tokens.$font-weight-bold; } .text-title-medium { font-size: tokens.$font-size-title-medium; font-weight: tokens.$font-weight-medium; } .text-body-large { font-size: tokens.$font-size-body-large; font-weight: tokens.$font-weight-regular; line-height: tokens.$line-height-normal; } .text-body-medium { font-size: tokens.$font-size-body-medium; font-weight: tokens.$font-weight-regular; line-height: tokens.$line-height-normal; } .text-label-medium { font-size: tokens.$font-size-label-medium; font-weight: tokens.$font-weight-medium; letter-spacing: tokens.$letter-spacing-wide; } // --------------------------------------------------------------------------- // Status Dot Pulse Animations // --------------------------------------------------------------------------- @keyframes pulse-active { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.7; transform: scale(1.15); } } @keyframes pulse-error { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } } @keyframes pulse-thinking { 0%, 100% { opacity: 0.8; } 50% { opacity: 0.4; } } // --------------------------------------------------------------------------- // Status Dot Utility Classes // --------------------------------------------------------------------------- .status-dot { width: tokens.$status-dot-size; height: tokens.$status-dot-size; border-radius: tokens.$radius-full; display: inline-block; &--active { background-color: var(--cc-status-active); animation: pulse-active tokens.$duration-standard tokens.$easing-standard infinite; } &--idle { background-color: var(--cc-status-idle); } &--thinking { background-color: var(--cc-status-thinking); animation: pulse-thinking 3s tokens.$easing-standard infinite; } &--error { background-color: var(--cc-status-error); animation: pulse-error tokens.$duration-fast tokens.$easing-standard infinite; } &--offline { background-color: var(--cc-status-offline); } } // --------------------------------------------------------------------------- // Accessibility: Reduced Motion // --------------------------------------------------------------------------- @media (prefers-reduced-motion: reduce) { .status-dot--active, .status-dot--error, .status-dot--thinking { animation: none; } } // --------------------------------------------------------------------------- // Screen-reader-only utility // --------------------------------------------------------------------------- .sr-only { @include tokens.sr-only; } // --------------------------------------------------------------------------- // Truncate utility // --------------------------------------------------------------------------- .truncate { @include tokens.truncate; } // --------------------------------------------------------------------------- // Focus ring utility // --------------------------------------------------------------------------- .focus-ring { @include tokens.focus-ring; } // --------------------------------------------------------------------------- // Scrollbar Styling (Tactical Dark) // --------------------------------------------------------------------------- ::-webkit-scrollbar { width: 6px; height: 6px; } ::-webkit-scrollbar-track { background: var(--cc-surface-dark); } ::-webkit-scrollbar-thumb { background: var(--cc-surface-lighter); border-radius: 3px; &:hover { background: var(--cc-on-surface-variant); } }