* { margin: 0; padding: 0; box-sizing: border-box; } :root { --primary-color: #4CAF50; --primary-hover: #5cb860; --primary-contrast: #ffffff; --danger-color: #f44336; --warning-color: #ff9800; --info-color: #2196F3; --font-mono: 'Cascadia Code', 'Fira Code', 'JetBrains Mono', 'SF Mono', 'Consolas', 'Liberation Mono', monospace; /* Spacing scale */ --space-xs: 4px; --space-sm: 8px; --space-md: 12px; --space-lg: 20px; --space-xl: 40px; /* Border radius */ --radius: 8px; --radius-sm: 4px; --radius-md: 8px; --radius-lg: 12px; --radius-pill: 100px; /* Animation timing */ --duration-fast: 0.15s; --duration-normal: 0.25s; --duration-slow: 0.4s; --ease-out: cubic-bezier(0.16, 1, 0.3, 1); --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); /* Font weights */ --weight-normal: 400; --weight-medium: 500; --weight-semibold: 600; --weight-bold: 700; /* Z-index layers */ --z-card-elevated: 10; --z-sticky: 100; --z-dropdown: 200; --z-bulk-toolbar: 1000; --z-modal: 2000; --z-log-overlay: 2100; --z-confirm: 2500; --z-command-palette: 3000; --z-toast: 3500; --z-overlay-spinner: 9999; --z-lightbox: 10000; --z-connection: 10000; } /* ── SVG icon base ── */ .icon { display: inline-block; width: 1em; height: 1em; vertical-align: -0.125em; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; flex-shrink: 0; } /* Dark theme (default) */ [data-theme="dark"] { --bg-color: #1a1a1a; --bg-secondary: #242424; --card-bg: #2d2d2d; --text-color: #e0e0e0; --text-primary: #e0e0e0; --text-secondary: #999; --text-muted: #777; --border-color: #404040; --display-badge-bg: rgba(0, 0, 0, 0.4); --primary-text-color: #66bb6a; --success-color: #28a745; --shadow-color: rgba(0, 0, 0, 0.3); --hover-bg: rgba(255, 255, 255, 0.05); --input-bg: #1a1a2e; color-scheme: dark; } /* Light theme */ [data-theme="light"] { --bg-color: #f5f5f5; --bg-secondary: #eee; --card-bg: #ffffff; --text-color: #333333; --text-primary: #333333; --text-secondary: #595959; --text-muted: #767676; --border-color: #e0e0e0; --display-badge-bg: rgba(255, 255, 255, 0.85); --primary-text-color: #3d8b40; --success-color: #2e7d32; --shadow-color: rgba(0, 0, 0, 0.12); --hover-bg: rgba(0, 0, 0, 0.05); --input-bg: #f0f0f0; color-scheme: light; } /* Default to dark theme */ body { background: var(--bg-color); color: var(--text-color); } html { background: var(--bg-color); overflow-x: hidden; overflow-y: scroll; scroll-behavior: smooth; scrollbar-gutter: stable; } body { font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; background: var(--bg-color); color: var(--text-color); line-height: 1.6; } html.modal-open { overflow: hidden; /* scrollbar-gutter: stable keeps the gutter reserved */ } /* ── Ambient animated background ── */ #bg-anim-canvas, #bg-effect-canvas { display: none; position: fixed; inset: 0; z-index: -1; width: 100%; height: 100%; pointer-events: none; } [data-bg-anim="on"] #bg-anim-canvas { display: block; } [data-bg-anim="on"] body { background: transparent; } /* When bg-anim is active, make entity cards slightly translucent so the shader bleeds through. Only target cards — NOT modals, pickers, tab bars, headers, or other chrome. */ [data-bg-anim="on"][data-theme="dark"] .card, [data-bg-anim="on"][data-theme="dark"] .template-card, [data-bg-anim="on"][data-theme="dark"] .add-device-card, [data-bg-anim="on"][data-theme="dark"] .dashboard-target { background: rgba(45, 45, 45, 0.88); } [data-bg-anim="on"][data-theme="light"] .card, [data-bg-anim="on"][data-theme="light"] .template-card, [data-bg-anim="on"][data-theme="light"] .add-device-card, [data-bg-anim="on"][data-theme="light"] .dashboard-target { background: rgba(255, 255, 255, 0.85); } /* Blur behind header via pseudo-element — applying backdrop-filter directly to header would create a containing block and break position:fixed on the .tab-bar nested inside it (mobile bottom nav). */ [data-bg-anim="on"] header { background: transparent; } [data-bg-anim="on"] header::after { content: ''; position: absolute; inset: 0; z-index: -1; backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); background: color-mix(in srgb, var(--bg-color) 60%, transparent); } /* ── Tab indicator (background watermark) ── */ #tab-indicator { position: fixed; right: -10vw; top: 50%; transform: translateY(-50%); width: 55vw; height: 55vw; max-width: 600px; max-height: 600px; pointer-events: none; z-index: -1; opacity: 0; filter: blur(6px); color: var(--primary-color); transition: opacity 0.5s ease; } #tab-indicator svg { width: 100%; height: 100%; opacity: 0.04; } #tab-indicator.tab-indicator-visible { opacity: 1; } [data-theme="light"] #tab-indicator svg { opacity: 0.07; } .container { padding: 20px; } /* ── Smooth theme transitions ── */ body, .card, .template-card, .modal-content, .dashboard-target, .perf-chart-card, header { transition: background-color var(--duration-normal) ease, color var(--duration-normal) ease, border-color var(--duration-normal) ease; } /* ── Respect reduced motion preference ── */ @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; } html { scroll-behavior: auto; } } @media print { [data-theme] { --bg-color: #fff; --card-bg: #fff; --text-color: #000; --text-secondary: #333; --border-color: #ccc; } .tab-bar, .app-header, .scroll-to-top, .toast-container { display: none; } }