@import './rtl-overrides.css'; @import './panels.css'; @import './route-explorer.css'; /* ============================================================ Theme Colors — overridden by [data-theme="light"] below ============================================================ */ :root { /* Backgrounds */ --bg: #0a0a0a; --bg-secondary: #111; --surface: #141414; --surface-hover: #1e1e1e; --surface-active: #1a1a2e; /* Borders */ --border: #2a2a2a; --border-strong: #444; --border-subtle: #1a1a1a; /* Text */ --text: #e8e8e8; --text-secondary: #ccc; --text-dim: #888; --text-muted: #666; --text-faint: #555; --text-ghost: #444; --accent: #fff; /* Overlays & shadows */ --overlay-subtle: rgba(255, 255, 255, 0.03); --overlay-light: rgba(255, 255, 255, 0.05); --overlay-medium: rgba(255, 255, 255, 0.1); --overlay-heavy: rgba(255, 255, 255, 0.2); --shadow-color: rgba(0, 0, 0, 0.5); --darken-light: rgba(0, 0, 0, 0.15); --darken-medium: rgba(0, 0, 0, 0.2); --darken-heavy: rgba(0, 0, 0, 0.3); /* Scrollbar */ --scrollbar-thumb: #333; --scrollbar-thumb-hover: #555; /* Input */ --input-bg: #1a1a1a; /* Panels */ --panel-bg: #141414; --panel-border: #2a2a2a; /* Map */ --map-bg: #020a08; --map-grid: #0a2a20; --map-country: #0a2018; --map-stroke: #0f5040; /* Font stack */ --font-mono: 'SF Mono', 'Monaco', 'Cascadia Code', 'Fira Code', 'DejaVu Sans Mono', 'Liberation Mono', monospace; /* Base body font, controlled by font preference (mono vs system) */ --font-body-base: var(--font-mono); /* Effective body font used throughout the app */ --font-body: var(--font-body-base); } /* System font selection via data-font attribute (avoids inline style specificity issues with RTL) */ [data-font="system"] { --font-body-base: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; } [dir="rtl"] { --font-body: 'Tajawal', 'Geeza Pro', 'SF Arabic', 'Tahoma', var(--font-body-base); } :lang(zh-CN), :lang(zh) { --font-body: 'PingFang SC', 'Microsoft YaHei', 'Noto Sans SC', var(--font-body-base); } /* ============================================================ Semantic Colors — dark-mode defaults, light overrides below ============================================================ */ :root { /* Severity levels */ --semantic-critical: #ff4444; --semantic-high: #ff8800; --semantic-elevated: #ffaa00; --semantic-normal: #44aa44; --semantic-low: #3388ff; --semantic-info: #3b82f6; --semantic-positive: #44ff88; /* Threat levels */ --threat-critical: #ef4444; --threat-high: #f97316; --threat-medium: #eab308; --threat-low: #22c55e; --threat-info: #3b82f6; /* DEFCON levels */ --defcon-1: #ff0040; --defcon-2: #ff4400; --defcon-3: #ffaa00; --defcon-4: #00aaff; --defcon-5: #2d8a6e; /* Status indicators */ --status-live: #44ff88; --status-cached: #ffaa00; --status-unavailable: #ff4444; /* Legacy color aliases (used by existing var() references) */ --red: #ff4444; /* Darker red for white-text "active/live" pills: #fff on --red is only 3.4:1, on --red-strong it clears WCAG AA (≈5:1). Theme-independent (the pill is red in both themes). */ --red-strong: #d62b2b; --green: #44ff88; --yellow: #ffaa00; } /* ============================================================ Light Theme — overrides theme colors AND semantic colors Bright/neon dark-mode colors need darker variants for light backgrounds ============================================================ */ [data-theme="light"] { /* Semantic color overrides — darker variants for light backgrounds */ --semantic-high: #ea580c; /* Tailwind orange-600 (was #ff8800, 2.27:1) */ --semantic-elevated: #d97706; /* Tailwind amber-600 (was #ffaa00, 1.81:1) */ --semantic-normal: #15803d; /* Tailwind green-700 (was #44aa44, 2.81:1) */ --semantic-positive: #16a34a; /* Tailwind green-600 (was #44ff88, too bright for light bg) */ --threat-high: #c2410c; /* Tailwind orange-700 (was #f97316, 2.66:1) */ --threat-medium: #ca8a04; /* Tailwind yellow-600 (was #eab308, 1.82:1) */ --threat-low: #15803d; /* Tailwind green-700 (was #22c55e, 2.16:1) */ --defcon-3: #d97706; /* Tailwind amber-600 (was #ffaa00, 1.81:1) */ --defcon-4: #0284c7; /* Tailwind sky-600 (was #00aaff, 2.43:1) */ --status-live: #16a34a; /* Tailwind green-600 (was #44ff88, 1.25:1) */ --status-cached: #d97706; /* Tailwind amber-600 (was #ffaa00, 1.81:1) */ --status-unavailable: #dc2626; /* Tailwind red-600 (was #ff4444, better contrast on light bg) */ --green: #16a34a; /* Tailwind green-600 (was #44ff88) */ --yellow: #d97706; /* Tailwind amber-600 (was #ffaa00) */ /* Backgrounds */ --bg: #f8f9fa; --bg-secondary: #f0f1f3; --surface: #ffffff; --surface-hover: #f0f0f0; --surface-active: #e8e8f0; /* Borders */ --border: #d4d4d4; --border-strong: #b0b0b0; --border-subtle: #e8e8e8; /* Text */ --text: #1a1a1a; --text-secondary: #333; --text-dim: #6b6b6b; --text-muted: #767676; /* WCAG AA: 4.54:1 vs #f8f9fa */ --text-faint: #aaa; --text-ghost: #bbb; --accent: #111111; /* Overlays & shadows */ --overlay-subtle: rgba(0, 0, 0, 0.02); --overlay-light: rgba(0, 0, 0, 0.04); --overlay-medium: rgba(0, 0, 0, 0.08); --overlay-heavy: rgba(0, 0, 0, 0.12); --shadow-color: rgba(0, 0, 0, 0.1); --darken-light: rgba(0, 0, 0, 0.1); --darken-medium: rgba(0, 0, 0, 0.15); --darken-heavy: rgba(0, 0, 0, 0.2); /* Scrollbar */ --scrollbar-thumb: #c0c0c0; --scrollbar-thumb-hover: #999; /* Input */ --input-bg: #f0f0f0; /* Panels */ --panel-bg: #ffffff; --panel-border: #d4d4d4; /* Map */ --map-bg: #e8f0f8; --map-grid: #b0c8d8; --map-country: #f0e8d8; --map-stroke: #c8b8a8; } * { margin: 0; padding: 0; box-sizing: border-box; } html { height: 100%; width: 100%; overflow: hidden; } body { font-family: var(--font-body); font-size: 12px; line-height: 1.5; background: var(--bg); color: var(--text); overflow: hidden; height: 100%; width: 100%; min-height: 100vh; min-width: 100vw; } /* Pause all animations when tab is hidden or idle */ body.animations-paused *, body.animations-paused *::before, body.animations-paused *::after { animation-play-state: paused !important; transition: none !important; } /* ============================================================ Theme Transition — smooth 200ms animation for theme switches ============================================================ */ *, *::before, *::after { transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease; } /* Suppress transitions during initial page load (FOUC prevention) */ .no-transition *, .no-transition *::before, .no-transition *::after { transition: none !important; } /* Map and canvas elements manage their own rendering */ canvas, .maplibregl-map, .maplibregl-canvas, .deck-canvas { transition: none !important; } #app { height: 100%; width: 100%; min-height: 100vh; min-width: 100vw; display: flex; flex-direction: column; position: absolute; top: 0; left: 0; right: 0; bottom: 0; } /* Keyboard bypass affordance (WCAG 2.4.1). Off-screen until focused, then slides in over the header so a keyboard user can jump straight to
. */ .skip-link { position: fixed; top: 8px; left: 8px; z-index: 100000; padding: 10px 16px; background: var(--surface); color: var(--text); border: 1px solid var(--green); border-radius: 6px; font-size: 13px; font-weight: 600; text-decoration: none; opacity: 0; transform: translateY(-150%); pointer-events: none; transition: transform 0.15s ease, opacity 0.15s ease; } .skip-link:focus, .skip-link:focus-visible { opacity: 1; transform: translateY(0); pointer-events: auto; outline: 2px solid var(--green); outline-offset: 2px; } /* The skip-link moves focus to
(tabindex="-1"). Suppress the full-width focus ring on the container itself; the next Tab lands on a real control with its own visible focus. */ #main.main-content:focus { outline: none; } .header { display: flex; align-items: center; justify-content: space-between; padding: 8px 16px; background: var(--surface); border-bottom: 1px solid var(--border); height: 40px; flex-shrink: 0; /* Lift the header's stacking context above the content grid so its dropdown panels (Intelligence Findings, Pentagon Pizza, etc.) are not occluded by .panels-grid (z-index: 1) or .map-controls (z-index: 500). Kept below .search-overlay (2000) and modals so they still cover the header. */ position: relative; z-index: 600; } /* -- Tauri desktop: separate title bar for traffic lights -- */ .tauri-titlebar { height: 28px; background: var(--bg); flex-shrink: 0; -webkit-app-region: drag; border-bottom: 1px solid var(--border-subtle); } .tauri-titlebar + .header { border-top: none; -webkit-app-region: drag; } .tauri-titlebar + .header button, .tauri-titlebar + .header a, .tauri-titlebar + .header input, .tauri-titlebar + .header select, .tauri-titlebar + .header .search-wrapper { -webkit-app-region: no-drag; } .header-left { display: flex; align-items: center; /* 10px (was 16px): tightens the left cluster so the right-side actions (Search / settings / Sign In) clear the viewport edge on medium-width desktops. Paired with the progressive-disclosure tiers below .github-link. */ gap: 10px; } /* Variant Switcher */ .variant-switcher { display: flex; align-items: center; gap: 2px; background: var(--overlay-subtle); border: 1px solid var(--border); border-radius: 4px; padding: 2px 4px; margin-right: 6px; } .variant-option { display: flex; align-items: center; gap: 4px; padding: 2px 6px; border-radius: 3px; text-decoration: none; color: var(--text-dim); font-size: 9px; font-weight: 600; letter-spacing: 1px; transition: all 0.25s ease; cursor: pointer; } .variant-option .variant-icon { font-size: 11px; filter: grayscale(80%); transition: filter 0.25s ease; } .variant-option .variant-label { max-width: 0; overflow: hidden; opacity: 0; transition: max-width 0.3s ease, opacity 0.2s ease; } .variant-option:hover .variant-label, .variant-option.active .variant-label { max-width: 50px; opacity: 1; } .variant-option:hover { color: var(--text); } .variant-option:hover .variant-icon { filter: grayscale(0%); } .variant-option.active { color: var(--green); background: rgba(68, 255, 136, 0.1); pointer-events: none; } .variant-option.active .variant-icon { filter: grayscale(0%) drop-shadow(0 0 4px var(--green)); } .variant-option[data-variant="tech"].active { color: var(--semantic-info); background: rgba(74, 158, 255, 0.1); } .variant-option[data-variant="tech"].active .variant-icon { filter: grayscale(0%) drop-shadow(0 0 4px var(--semantic-info)); } .variant-divider { width: 1px; height: 12px; background: var(--border); margin: 0 2px; } .variant-switcher:hover .variant-option .variant-label { max-width: 50px; opacity: 1; } .mission-preset-mount { display: inline-flex; align-items: center; } .mission-preset-button { display: inline-flex; align-items: center; gap: 5px; height: 24px; padding: 0 8px; border: 1px solid var(--border); border-radius: 4px; background: var(--overlay-subtle); color: var(--text-dim); font-size: 9px; font-weight: 700; letter-spacing: 0.8px; text-transform: uppercase; cursor: pointer; transition: border-color 0.2s ease, color 0.2s ease, background 0.2s ease; } .mission-preset-button:hover, .mission-preset-button[aria-expanded="true"] { color: var(--text); border-color: var(--accent); background: rgba(68, 255, 136, 0.08); } .mission-preset-button--active { color: var(--green); } .mission-preset-button--suggested { border-color: rgba(68, 255, 136, 0.45); } .mission-preset-button__icon { display: inline-flex; align-items: center; justify-content: center; width: 14px; height: 14px; border-radius: 50%; background: rgba(68, 255, 136, 0.12); color: var(--green); font-size: 9px; } .mission-preset-popover { position: fixed; z-index: 5000; width: min(360px, calc(100vw - 24px)); max-height: min(620px, calc(100vh - 64px)); overflow: auto; padding: 10px; border: 1px solid var(--border); border-radius: 6px; background: var(--surface); box-shadow: 0 18px 44px rgba(0, 0, 0, 0.36); } .mission-preset-popover--mobile { top: 56px; left: 12px; right: 12px; width: auto; } .mission-preset-popover__header { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; padding: 4px 2px 10px; border-bottom: 1px solid var(--border-subtle); } .mission-preset-popover__header span { display: block; color: var(--text-dim); font-size: 9px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase; } .mission-preset-popover__header strong { display: block; margin-top: 2px; color: var(--text); font-size: 13px; font-weight: 700; letter-spacing: 0; } .mission-preset-popover__actions { display: flex; align-items: center; gap: 6px; } .mission-preset-reset, .mission-preset-close { border: 1px solid var(--border); border-radius: 4px; background: var(--overlay-subtle); color: var(--text-dim); cursor: pointer; } .mission-preset-reset { height: 24px; padding: 0 8px; font-size: 10px; font-weight: 700; text-transform: uppercase; } .mission-preset-close { width: 24px; height: 24px; padding: 0; font-size: 16px; line-height: 20px; } .mission-preset-reset:hover, .mission-preset-close:hover { color: var(--text); border-color: var(--accent); } .mission-preset-popover__list { display: grid; gap: 6px; padding-top: 10px; } .mission-preset-card { display: grid; grid-template-columns: 26px 1fr 18px; align-items: center; gap: 8px; width: 100%; min-height: 58px; padding: 8px; border: 1px solid var(--border-subtle); border-radius: 5px; background: transparent; color: var(--text); text-align: left; cursor: pointer; transition: border-color 0.2s ease, background 0.2s ease, transform 0.2s ease; } .mission-preset-card:hover, .mission-preset-card.selected { border-color: var(--accent); background: rgba(68, 255, 136, 0.06); } .mission-preset-card:hover { transform: translateY(-1px); } .mission-preset-card__icon { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; border-radius: 50%; background: rgba(68, 255, 136, 0.12); color: var(--green); font-size: 11px; font-weight: 800; } .mission-preset-card__body { min-width: 0; } .mission-preset-card__body strong, .mission-preset-card__body small { display: block; letter-spacing: 0; } .mission-preset-card__body strong { color: var(--text); font-size: 12px; line-height: 1.25; } .mission-preset-card__body small { margin-top: 2px; color: var(--text-dim); font-size: 10px; line-height: 1.35; } .mission-preset-card__check { color: var(--green); font-size: 14px; font-weight: 800; text-align: center; } .logo { font-weight: bold; font-size: 14px; letter-spacing: 2px; color: var(--accent); } .logo-mobile { display: none; font-weight: bold; font-size: 14px; letter-spacing: 2px; color: var(--accent); } .version { font-size: 9px; color: var(--muted); opacity: 0.5; margin-left: 6px; font-weight: normal; letter-spacing: 0.5px; vertical-align: middle; } /* Update toast notification */ .update-toast { position: fixed; top: 12px; right: 16px; display: flex; align-items: center; gap: 12px; padding: 12px 14px; background: linear-gradient(135deg, #1a2332 0%, #0f1923 100%); border: 1px solid rgba(68, 255, 136, 0.25); border-radius: 10px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(68, 255, 136, 0.08); z-index: 10003; opacity: 0; transform: translateY(-20px); transition: opacity 0.3s ease, transform 0.3s ease; pointer-events: none; max-width: 340px; } .update-toast.visible { opacity: 1; transform: translateY(0); pointer-events: auto; } .update-toast-icon { flex-shrink: 0; display: flex; align-items: center; justify-content: center; width: 36px; height: 36px; border-radius: 8px; background: rgba(68, 255, 136, 0.12); color: var(--green); } .update-toast-body { flex: 1; min-width: 0; } .update-toast-title { font-size: 13px; font-weight: 600; color: #e8e8e8; letter-spacing: 0.2px; } .update-toast-detail { font-size: 11px; color: #888; margin-top: 2px; letter-spacing: 0.3px; } .update-toast-action { flex-shrink: 0; padding: 6px 14px; font-size: 11px; font-weight: 600; letter-spacing: 0.3px; color: #0a0a0a; background: var(--green); border: none; border-radius: 6px; cursor: pointer; transition: filter 0.15s, transform 0.15s; } .update-toast-action:hover { filter: brightness(1.15); transform: scale(1.03); } .update-toast-action:active { transform: scale(0.97); } .update-toast-dismiss { flex-shrink: 0; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; font-size: 16px; color: #666; background: none; border: none; border-radius: 4px; cursor: pointer; transition: color 0.15s, background 0.15s; padding: 0; line-height: 1; } .update-toast-dismiss:hover { color: #ccc; background: rgba(255, 255, 255, 0.08); } .beta-badge { display: inline-flex; align-items: center; margin-left: 6px; padding: 1px 7px; font-size: 9px; font-weight: 600; letter-spacing: 0.5px; color: #0a0a0a; background: #f59e0b; border-radius: 8px; vertical-align: middle; } .credit-link { font-size: 9px; color: var(--muted); opacity: 0.6; font-weight: normal; letter-spacing: 0.5px; text-decoration: none; transition: opacity 0.2s; } .credit-link:hover { opacity: 1; color: var(--accent); } /* Hide X logo on desktop, show text */ .credit-link .x-logo { display: none; } .status-indicator { display: flex; align-items: center; gap: 6px; font-size: 10px; color: var(--text-dim); } .status-indicator--cached { color: var(--status-cached); } .status-indicator--unavailable { color: var(--status-unavailable); } .status-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--green); animation: pulse-dot 2s infinite; } .status-indicator--cached .status-dot { background: var(--status-cached); animation: none; } .status-indicator--unavailable .status-dot { background: var(--status-unavailable); animation: none; } /* Out of flow (fixed, bottom) so inserting/removing the connectivity banner never reflows the #tabs/#main/#panelsGrid column. In-flow it was inserted afterend of .header and toggled during boot on slow connections (cached -> live), shoving the whole column ~83px and generating field CLS (#4580: #panelsGrid/#main top offenders). Bottom-fixed matches the .toast-notification convention; the panel nav is top-sticky so there is no persistent bottom bar to collide with. z-index sits above the bottom search FAB (z 500) / footer but below search overlays (z 2000), so `pointer-events: none` is required: the banner is purely informational (role=status, no interactive children), so it must not trap taps meant for the FAB / open search sheet / footer links it overlaps. */ .cached-mode-banner { position: fixed; left: 0; right: 0; bottom: 0; z-index: 900; pointer-events: none; display: flex; align-items: center; flex-wrap: wrap; gap: 10px; padding: 9px 16px; padding-bottom: calc(9px + env(safe-area-inset-bottom, 0px)); border-top: 1px solid rgba(217, 119, 6, 0.32); background: linear-gradient(0deg, rgba(217, 119, 6, 0.14), rgba(217, 119, 6, 0.08)); color: var(--text); } .cached-mode-banner--unavailable { border-top-color: rgba(239, 68, 68, 0.32); background: linear-gradient(0deg, rgba(239, 68, 68, 0.14), rgba(239, 68, 68, 0.08)); } /* Clear the bottom-right search FAB (56px @ right:16px, mobile only) so the fixed banner's wrapped text never sits under it. */ @media (max-width: 768px) { .cached-mode-banner { padding-right: 84px; } } .cached-mode-banner__badge { display: inline-flex; align-items: center; justify-content: center; min-width: 74px; padding: 2px 8px; border: 1px solid rgba(217, 119, 6, 0.45); border-radius: 999px; font-size: 10px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--status-cached); background: rgba(0, 0, 0, 0.12); } .cached-mode-banner--unavailable .cached-mode-banner__badge { border-color: rgba(239, 68, 68, 0.45); color: var(--status-unavailable); } .cached-mode-banner__text { font-size: 11px; color: var(--text-secondary); } @keyframes pulse-dot { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } /* Region Selector in Header */ .region-selector { display: flex; align-items: center; } .region-select { padding: 4px 24px 4px 10px; background: var(--bg); border: 1px solid var(--border); color: var(--text); font-family: inherit; font-size: 11px; cursor: pointer; appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath fill='%23888' d='M0 0l5 6 5-6z'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 8px center; } .region-select:hover { border-color: var(--green); } .region-select:focus { outline: none; border-color: var(--green); } .header-center { display: flex; gap: 8px; } .focus-label { font-size: 10px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.5px; margin-right: 6px; } .focus-select { padding: 4px 24px 4px 10px; background: var(--bg); border: 1px solid var(--border); color: var(--text); font-family: inherit; font-size: 11px; cursor: pointer; appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath fill='%2388a0a8' d='M0 0l5 6 5-6z'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 8px center; min-width: 100px; } .focus-select:hover { border-color: var(--text-dim); } .focus-select:focus { outline: none; border-color: var(--primary); } .focus-select option { background: var(--panel-bg); color: var(--text); } .header-right { display: flex; align-items: center; gap: 12px; } .fullscreen-btn { padding: 4px 8px; background: transparent; border: 1px solid var(--border); color: var(--text); font-family: inherit; font-size: 14px; cursor: pointer; line-height: 1; } .fullscreen-btn:hover { border-color: var(--text-dim); } .fullscreen-btn.active { background: rgba(59, 130, 246, 0.12); border-color: var(--accent); color: var(--accent); } .mobile-settings-btn { display: none; align-items: center; justify-content: center; background: none; border: 1px solid transparent; border-radius: 4px; color: var(--text-dim); cursor: pointer; padding: 4px; margin-left: 6px; transition: color 0.2s, transform 0.3s; } .mobile-settings-btn:hover { color: var(--accent); transform: rotate(45deg); } .github-link { color: var(--text-dim); margin-left: 8px; display: flex; align-items: center; transition: color 0.2s; } .github-link:hover { color: var(--text); } /* Progressive header disclosure — keep the core right-side actions (Search, settings, and especially the Sign In / Create account cluster) fully on screen as usable width shrinks: small laptops, split-screen, OS scaling (1920px @ 150% = ~1280px CSS), and browsers with a vertical tab strip. The single-row header wants ~1520px; without these tiers it silently overflows and clips the rightmost item (Sign In) anywhere below ~1520px. Items are dropped least-essential first; each is still reachable elsewhere (footer links, the mobile hamburger menu, or the map's own controls). The full mobile hamburger takes over at <=768px. !important mirrors the <=768 block below (needed to beat the #missionPresetMount id rule in header.css). */ @media (max-width: 1530px) { /* redundant with footer/menu: X credit + GitHub icon */ .credit-link, .github-link { display: none !important; } } @media (max-width: 1420px) { .version, .fullscreen-btn { display: none !important; } } @media (max-width: 1330px) { /* Link + Embed share .copy-link-btn */ .copy-link-btn { display: none !important; } } @media (max-width: 1200px) { .pizzint-indicator { display: none !important; } } @media (max-width: 1075px) { .mission-preset-mount { display: none !important; } } @media (max-width: 980px) { .variant-switcher { display: none !important; } } .search-btn { padding: 4px 10px; background: transparent; border: 1px solid var(--border); color: var(--text); font-family: inherit; font-size: 11px; cursor: pointer; display: flex; align-items: center; gap: 6px; margin-right: 8px; } .search-btn:hover { border-color: var(--accent); color: var(--accent); } .copy-link-btn { padding: 4px 10px; background: transparent; border: 1px solid var(--border); color: var(--text); font-family: inherit; font-size: 11px; cursor: pointer; transition: all 0.2s; } .copy-link-btn:hover { border-color: var(--accent); color: var(--accent); } .copy-link-btn.copied { background: var(--text); color: var(--bg); border-color: var(--text); } .embed-modal-overlay { position: fixed; inset: 0; z-index: 10020; display: none; align-items: center; justify-content: center; padding: 24px; background: rgba(0, 0, 0, 0.62); } .embed-modal-overlay.active { display: flex; } .embed-modal { width: min(720px, 100%); max-height: calc(100vh - 48px); display: grid; grid-template-rows: auto minmax(180px, 320px) auto minmax(96px, auto) auto; gap: 14px; overflow: auto; border: 1px solid var(--border); border-radius: 8px; background: var(--panel-bg); box-shadow: 0 24px 80px var(--shadow-color); padding: 18px; } .embed-modal-header { display: flex; align-items: center; justify-content: space-between; gap: 16px; } .embed-modal-header h2 { margin: 0; color: var(--text); font-size: 16px; font-weight: 700; } .embed-modal-close { width: 32px; height: 32px; display: inline-flex; align-items: center; justify-content: center; border: 1px solid var(--border); border-radius: 6px; background: transparent; color: var(--text-dim); cursor: pointer; font-size: 20px; line-height: 1; } .embed-modal-close:hover, .embed-modal-close:focus-visible { color: var(--text); border-color: var(--accent); outline: none; } .embed-preview-frame { width: 100%; height: 100%; min-height: 180px; border: 1px solid var(--border); border-radius: 6px; background: var(--bg); } .embed-snippet-label { color: var(--text-dim); font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; } .embed-snippet-textarea { width: 100%; min-height: 96px; resize: vertical; border: 1px solid var(--border); border-radius: 6px; background: var(--bg); color: var(--text); font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 12px; line-height: 1.45; padding: 10px; } .embed-snippet-textarea:focus { border-color: var(--accent); outline: none; } .embed-modal-actions { display: flex; justify-content: flex-end; } .embed-copy-btn { min-height: 34px; padding: 0 14px; border: 1px solid var(--accent); border-radius: 6px; background: var(--accent); color: var(--bg); cursor: pointer; font-family: inherit; font-size: 12px; font-weight: 700; } .embed-copy-btn:hover, .embed-copy-btn:focus-visible { filter: brightness(1.08); outline: none; } @media (max-width: 720px) { .embed-modal-overlay { padding: 12px; align-items: stretch; } .embed-modal { max-height: calc(100vh - 24px); grid-template-rows: auto minmax(160px, 260px) auto minmax(112px, auto) auto; padding: 14px; } } .download-wrapper { position: relative; } .download-btn { padding: 4px 10px; background: color-mix(in srgb, var(--green) 10%, transparent); border: 1px solid color-mix(in srgb, var(--green) 30%, transparent); color: var(--green); font-family: inherit; font-size: 11px; cursor: pointer; transition: all 0.2s; display: flex; align-items: center; gap: 6px; } .download-btn:hover { background: color-mix(in srgb, var(--green) 18%, transparent); border-color: var(--green); color: var(--green); } .download-dropdown { position: absolute; top: 100%; right: 0; width: 280px; background: var(--border-subtle); border: 1px solid var(--border); border-radius: 6px; box-shadow: 0 8px 24px var(--shadow-color); z-index: 1000; display: none; margin-top: 4px; padding: 10px; } .download-dropdown.open { display: block; } .dl-dd-tagline { font-size: 11px; color: var(--text-dim); margin-bottom: 10px; line-height: 1.4; } .dl-dd-buttons { display: flex; flex-direction: column; gap: 6px; } .dl-dd-btn { display: block; padding: 8px 12px; border-radius: 4px; font-size: 12px; font-weight: 500; text-decoration: none; text-align: center; transition: opacity 0.15s; color: #e0e0e0; } .dl-dd-btn:hover { opacity: 0.85; } .dl-dd-btn.mac { background: #2d5a2d; border: 1px solid #3a7a3a; } .dl-dd-btn.win { background: #2d4a5a; border: 1px solid #3a6a8a; } .dl-dd-btn.linux { background: #5a4a2d; border: 1px solid #8a7a3a; } .dl-dd-btn.primary { font-weight: 600; box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.1); } .dl-dd-toggle { display: block; width: 100%; background: none; border: none; color: var(--accent); font-size: 11px; cursor: pointer; padding: 8px 0 4px; font-family: inherit; text-align: center; } .dl-dd-toggle:hover { text-decoration: underline; } .dl-dd-others { display: none; flex-direction: column; gap: 6px; margin-top: 6px; } .dl-dd-others.show { display: flex; } .search-btn kbd { background: var(--bg-secondary); padding: 2px 5px; border-radius: 3px; font-size: 10px; font-family: inherit; } .main-content { flex: 1 1 0; min-height: 0; display: flex; flex-direction: column; overflow-y: auto; overflow-x: hidden; background: var(--bg); width: 100%; } .map-section { height: 50vh; min-height: 350px; max-height: 90vh; /* Allow resize up to 90% of viewport */ border: 1px solid var(--border); background: var(--surface); display: flex; flex-direction: column; flex-shrink: 0; position: relative; } .map-section.hidden { display: none; } .map-section .panel-header { flex-shrink: 0; gap: 6px; padding: 8px 12px; background: var(--surface); border-bottom: 1px solid var(--border); } .map-section .map-container { flex: 1; position: relative; } .map-resize-handle { position: absolute; bottom: 0; left: 0; right: 0; height: 8px; cursor: ns-resize; background: linear-gradient(to bottom, transparent, var(--border)); z-index: 200; display: flex; align-items: center; justify-content: center; } .map-resize-handle::after { content: ''; width: 40px; height: 3px; background: var(--text-dim); border-radius: 2px; opacity: 0.5; transition: opacity 0.2s; } .map-resize-handle:hover::after { opacity: 1; } .map-section.resizing { user-select: none; overflow: hidden; } .map-section.resizing .map-resize-handle::after { background: var(--green); opacity: 1; } .map-section.pinned { position: sticky; top: 0; z-index: 100; } .map-dimension-toggle { display: flex; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; overflow: hidden; margin-right: 2px; } .map-dim-btn { background: transparent; border: none; color: var(--text-dim); font-size: 11px; font-weight: 600; padding: 3px 8px; cursor: pointer; transition: all 0.2s; letter-spacing: 0.5px; } .map-dim-btn:hover { color: var(--text); background: var(--surface-hover); } .map-dim-btn.active { background: var(--green); color: var(--bg); } .map-header-actions { display: flex; align-items: center; gap: 2px; } .map-pin-btn { background: transparent; border: 1px solid var(--border); color: var(--text-dim); padding: 4px 8px; border-radius: 4px; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all 0.2s; } .map-pin-btn:hover { background: var(--surface-hover); color: var(--text); border-color: var(--text-dim); } .map-pin-btn.active { background: var(--green); border-color: var(--green); color: var(--bg); } .map-pin-btn.active:hover { background: var(--green-dim); } /* Hidden by default — shown only inside 768px media query */ .map-collapse-btn { display: none; } :root { --dashboard-panel-row-min: 200px; --dashboard-panel-row-max: 380px; --dashboard-grid-gap: 4px; --dashboard-first-grid-reservation: calc(var(--dashboard-panel-row-min) + var(--dashboard-panel-row-min) + var(--dashboard-grid-gap)); } .panels-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); grid-auto-flow: row dense; grid-auto-rows: minmax(var(--dashboard-panel-row-min), var(--dashboard-panel-row-max)); gap: var(--dashboard-grid-gap); padding: var(--dashboard-grid-gap); align-content: start; align-items: stretch; min-height: 0; position: relative; z-index: 1; /* This ensures panels scroll UNDER the pinned map (z-index: 100) */ } .panels-grid:empty { min-height: var(--dashboard-first-grid-reservation); } .site-footer { display: flex; align-items: center; justify-content: space-between; padding: 12px 20px; font-size: 11px; color: var(--text-dim); border-top: 1px solid var(--border); flex-shrink: 0; background: var(--surface); } .site-footer-brand { display: flex; align-items: center; gap: 10px; } .site-footer-icon { width: 28px; height: 28px; border-radius: 50%; } .site-footer-brand-text { display: flex; flex-direction: column; } .site-footer-name { font-family: var(--font-mono, monospace); font-size: 12px; font-weight: 600; color: var(--text); letter-spacing: 1px; } .site-footer-sub { font-family: var(--font-mono, monospace); font-size: 9px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 2px; } .site-footer nav { display: flex; gap: 16px; } .site-footer a { color: var(--text-dim); font-family: var(--font-mono, monospace); text-decoration: none; transition: color 0.15s; } .site-footer a:hover { color: var(--accent); } .site-footer-copy { font-family: var(--font-mono, monospace); font-size: 10px; /* No opacity: 0.6 fade — it dropped --text-dim (#888) to an effective #5a5a5a on the #141414 footer (2.67:1). At full strength #888 clears 4.5:1 (≈5.2:1) for WCAG AA, matching the footer nav links. */ color: var(--text-dim); } @media (max-width: 768px) { .site-footer { flex-direction: column; gap: 10px; text-align: center; padding: 12px 16px; } .site-footer nav { flex-wrap: wrap; justify-content: center; gap: 12px; } } .panel { background: var(--surface); border: 1px solid var(--border); display: flex; flex-direction: column; overflow: hidden; height: 100%; min-height: 200px; min-width: 0; cursor: grab; transition: transform 0.15s, box-shadow 0.15s; position: relative; contain: content; } /* .panel.resized: Custom height set - use grid-row span for height */ /* Row span classes for resizable panels */ .panel.span-1 { grid-row: span 1 !important; min-height: var(--dashboard-panel-row-min) !important; } .panel.span-2 { grid-row: span 2 !important; min-height: var(--dashboard-first-grid-reservation) !important; } /* #5332: eager always-full panels grow their grid row when populated content replaces the loading state — rows are minmax(--dashboard-panel-row-min, --dashboard-panel-row-max) sized from the panel's intrinsic content height, so the growth shoves every row below (field: div.panel shift p75 0.244 on 9% of desktop views; the dominant remaining desktop CLS mechanism, #4580). Pin the known always-full panels to the row max so their row lands at its final height from first paint; .panel-content already scrolls. User-set spans (.span-N) keep their own min-height reservation contract and are excluded. Keep this key list in sync with the ranked offenders in #5332. */ #panelsGrid > .panel[data-panel="threat-timeline"]:not(.span-2):not(.span-3):not(.span-4):not(.panel-wide):not(.resized), #panelsGrid > .panel[data-panel="gdelt-intel"]:not(.span-2):not(.span-3):not(.span-4):not(.panel-wide):not(.resized), #panelsGrid > .panel[data-panel="intel"]:not(.span-2):not(.span-3):not(.span-4):not(.panel-wide):not(.resized), #panelsGrid > .panel[data-panel="live-news"]:not(.span-2):not(.span-3):not(.span-4):not(.panel-wide):not(.resized), #panelsGrid > .panel[data-panel="politics"]:not(.span-2):not(.span-3):not(.span-4):not(.panel-wide):not(.resized), #panelsGrid > .panel[data-panel="energy-complex"]:not(.span-2):not(.span-3):not(.span-4):not(.panel-wide):not(.resized), #panelsGrid > .panel[data-panel="global-procurement"]:not(.span-2):not(.span-3):not(.span-4):not(.panel-wide):not(.resized), #panelsGrid > .panel[data-panel="strategic-posture"]:not(.span-2):not(.span-3):not(.span-4):not(.panel-wide):not(.resized), #panelsGrid > .panel[data-panel="cascade"]:not(.span-2):not(.span-3):not(.span-4):not(.panel-wide):not(.resized), #panelsGrid > .panel[data-panel="live-webcams"]:not(.span-2):not(.span-3):not(.span-4):not(.panel-wide):not(.resized) { height: var(--dashboard-panel-row-max); } /* Offenders that are two-row by default — span-2 defaults and the 2x2 .panel-wide pair — get the populated two-row max (2 rows + gap) so their footprint is identical loading vs populated, INCLUDING the deferred-shell phase (the shell carries the same classes, so shell->panel swap is shift-free). The pins apply to NATURAL footprints only: user-resized panels (.resized, PR #5333 review P1) and explicit .span-N overrides keep the resize contract, and the #panelsGrid scope keeps panels dragged into the ultra-wide .map-bottom-grid (height:100%/1fr tracks) on that grid's own sizing contract. */ #panelsGrid > .panel[data-panel="threat-timeline"].span-2:not(.resized), #panelsGrid > .panel[data-panel="gdelt-intel"].span-2:not(.resized), #panelsGrid > .panel[data-panel="energy-complex"].span-2:not(.resized), #panelsGrid > .panel[data-panel="strategic-posture"].span-2:not(.resized), #panelsGrid > .panel[data-panel="global-procurement"].span-2:not(.resized), #panelsGrid > .panel[data-panel="live-news"].panel-wide:not(.resized):not(.span-1):not(.span-2):not(.span-3):not(.span-4), #panelsGrid > .panel[data-panel="live-webcams"].panel-wide:not(.resized):not(.span-1):not(.span-2):not(.span-3):not(.span-4) { height: calc(var(--dashboard-panel-row-max) * 2 + var(--dashboard-grid-gap)); } .panel.span-3 { grid-row: span 3 !important; min-height: 600px !important; } .panel.span-4 { grid-row: span 4 !important; min-height: 800px !important; } .panel.col-span-1 { grid-column: span 1 !important; } .panel.col-span-2 { grid-column: span 2 !important; } .panel.col-span-3 { grid-column: span 3 !important; } .panel-resize-handle { position: absolute; bottom: 0; left: 0; right: 0; height: 20px; cursor: ns-resize; background: linear-gradient(to top, rgba(68, 136, 255, 0.15), transparent); z-index: 100; transition: background 0.2s; touch-action: none; pointer-events: auto !important; user-select: none; } .panel-resize-handle:hover, .panel-resize-handle.active { background: linear-gradient(to top, rgba(68, 136, 255, 0.5), transparent); } .panel-resize-handle::after { content: '⋯'; position: absolute; bottom: 2px; left: 50%; transform: translateX(-50%); font-size: 16px; letter-spacing: 2px; color: var(--text-dim); transition: color 0.2s; } .panel-resize-handle:hover::after { color: var(--accent); } /* Right-edge handle - mirrors the bottom handle exactly */ .panel-col-resize-handle { position: absolute; top: 0; right: 0; bottom: 0; width: 20px; cursor: ew-resize; background: linear-gradient(to left, rgba(68, 136, 255, 0.15), transparent); z-index: 100; transition: background 0.2s; touch-action: none; pointer-events: auto !important; user-select: none; } .panel-col-resize-handle:hover, .panel-col-resize-handle.active { background: linear-gradient(to left, rgba(68, 136, 255, 0.5), transparent); } .panel-col-resize-handle::after { content: '⋮'; position: absolute; right: 3px; top: 50%; transform: translateY(-50%); font-size: 16px; letter-spacing: 2px; color: var(--text-dim); transition: color 0.2s; } .panel-col-resize-handle:hover::after { color: var(--accent); } body.panel-resize-active iframe { pointer-events: none !important; } .panel.resizing { cursor: ns-resize; user-select: none; } /* Horizontal drag cursor */ .panel.col-resizing { cursor: ew-resize; user-select: none; } @media (max-width: 768px) { .panel-col-resize-handle { display: none; } } .panel:active { cursor: grabbing; } .panel.hidden { display: none; } .panel.dragging-source { opacity: 0.4; transform: scale(0.98); transition: opacity 0.2s ease, transform 0.2s ease; pointer-events: none; } .panel-drag-ghost { filter: drop-shadow(0 10px 40px rgba(0, 0, 0, 0.4)); border: 1px solid var(--accent); animation: dragGhostPulse 0.3s ease-out; opacity: 0.8; transform: scale(1.02); /* no rotation */ } @keyframes dragGhostPulse { 0% { opacity: 0.7; transform: scale(0.98); } 100% { opacity: 0.8; transform: scale(1.02); } } .panel-drop-indicator { display: block; position: fixed; pointer-events: none; height: 4px; background: var(--accent); border-radius: 2px; box-shadow: 0 0 8px var(--accent); opacity: 0; transition: opacity 0.15s ease; z-index: 9999; } /* Hover highlight for potential drop target */ .panel-drop-target { outline: 2px dashed var(--accent); outline-offset: -2px; background: color-mix(in srgb, var(--accent) 20%, transparent); transition: background 0.15s ease, outline 0.15s ease; } .panel-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 6px 10px; background: var(--overlay-subtle); border-bottom: 1px solid var(--border); flex-shrink: 0; position: relative; transition: background-color 0.3s ease, border-color 0.3s ease; } .panel-header-error { background: rgba(255, 50, 50, 0.15); border-bottom-color: rgba(255, 80, 80, 0.5); } .panel-header-error .panel-title { color: var(--semantic-critical); } .panel-header-error .panel-count { background: rgba(255, 80, 80, 0.3); color: var(--semantic-critical); } .header-clock { position: absolute; left: 50%; transform: translateX(-50%); font-size: 11px; font-family: var(--font-mono); color: var(--text-secondary); letter-spacing: 0.5px; pointer-events: none; text-transform: uppercase; } .panel-header-left { display: flex; align-items: center; gap: 8px; } .panel-title { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px; color: var(--text); } .panel-severity-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; display: none; } .panel-severity-dot.severity-critical { display: block; background: var(--threat-critical); box-shadow: 0 0 6px var(--threat-critical); animation: severity-pulse 0.6s ease-in-out infinite; } .panel-severity-dot.severity-high { display: block; background: var(--threat-high); box-shadow: 0 0 4px var(--threat-high); animation: severity-pulse 1s ease-in-out infinite; } .panel-severity-dot.severity-medium { display: block; background: var(--threat-medium); animation: severity-pulse 1.8s ease-in-out infinite; } .panel-severity-dot.severity-low { display: block; background: var(--threat-low); animation: severity-pulse 2.5s ease-in-out infinite; } .panel-freshness-badge { display: inline-flex; align-items: center; flex-shrink: 0; max-width: 92px; min-height: 18px; padding: 2px 6px; border: 1px solid var(--border); border-radius: 3px; background: var(--overlay-subtle); color: var(--text-secondary); font-size: 10px; font-weight: 600; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .panel-freshness-fresh { border-color: color-mix(in srgb, var(--semantic-normal) 40%, var(--border)); color: var(--semantic-normal); } .panel-freshness-stale, .panel-freshness-very_stale { border-color: color-mix(in srgb, var(--semantic-elevated) 45%, var(--border)); color: var(--semantic-elevated); } .panel-freshness-no_data, .panel-freshness-disabled { color: var(--text-dim); } .panel-freshness-error { border-color: color-mix(in srgb, var(--semantic-critical) 45%, var(--border)); color: var(--semantic-critical); } @keyframes severity-pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.3; transform: scale(0.7); } } @media (prefers-reduced-motion: reduce) { .panel-severity-dot { animation: none !important; } } /* Push the first element after header-left to the right; subsequent siblings flow via gap */ .panel-header > .panel-header-left + * { margin-left: auto; } .panel-count { font-size: 10px; /* --text-dim (#888) on --border fails WCAG AA (4.04:1 on #2a2a2a / 3.6:1 light); --text-secondary is tuned per-theme and clears 4.5:1 on every theme's --border. */ color: var(--text-secondary); background: var(--border); padding: 2px 6px; border-radius: 2px; transition: color 0.3s ease, background 0.3s ease; position: relative; overflow: hidden; isolation: isolate; z-index: 0; } .panel-count::before { content: ''; position: absolute; inset: 0; background: var(--accent); border-radius: inherit; opacity: 0; pointer-events: none; /* Behind the count digit (bare text node, can't be z-lifted) so the bump tint never washes out the number. Host isolation:isolate scopes this to the badge. */ z-index: -1; } .panel-count.bump { animation: count-bump 0.5s ease-out; } .panel-count.bump::before { animation: count-bump-highlight 0.5s ease-out; } @keyframes count-bump { 0% { transform: scale(1); } 40% { transform: scale(1.3); } 100% { transform: scale(1); } } @keyframes count-bump-highlight { 0%, 100% { opacity: 0; } 40% { opacity: 0.55; } } /* ---- Icon buttons in panel headers ---- */ .panel-header .icon-btn { display: flex; align-items: center; justify-content: center; width: 20px; height: 20px; padding: 0; border: none; border-radius: 3px; background: transparent; color: var(--text-dim); font-size: 13px; line-height: 1; cursor: pointer; transition: background 0.15s ease, color 0.15s ease; flex-shrink: 0; } .panel-header .icon-btn:hover { background: var(--overlay-subtle); color: var(--text); } /* ---- Close (X) button on panels (extends .icon-btn) ---- */ .panel-header .panel-close-btn { font-size: 14px; opacity: 0; transition: opacity 0.15s ease, background 0.15s ease, color 0.15s ease; order: 999; } .panel:hover .panel-close-btn, .panel-close-btn:focus-visible { opacity: 1; } .panel-header .panel-close-btn:hover { background: color-mix(in srgb, var(--semantic-critical) 15%, transparent); color: var(--semantic-critical); } /* On touch devices, always show the close button */ @media (hover: none) { .panel-header .panel-close-btn { opacity: 0.7; } } /* ---- Collapse (▾) button on panels ---- */ .panel-header .panel-collapse-btn { font-size: 12px; opacity: 0; transition: opacity 0.15s ease, background 0.15s ease; order: 998; } .panel:hover .panel-collapse-btn, .panel-collapse-btn:focus-visible { opacity: 1; } .panel.panel-collapsed { align-self: start; height: auto !important; min-height: 0 !important; } .panel-collapsed .panel-collapse-btn { opacity: 0.7; } @media (hover: none) { .panel-header .panel-collapse-btn { opacity: 0.7; } } /* ---- Add Panel (+) block ---- */ .add-panel-block { display: flex; align-items: center; justify-content: center; flex-direction: column; gap: 8px; min-height: 120px; border: 2px dashed var(--border); border-radius: var(--panel-radius, 6px); background: transparent; color: var(--text-dim); cursor: pointer; transition: border-color 0.2s ease, color 0.2s ease, background 0.2s ease; padding: 0; font-family: inherit; } .add-panel-block:hover { border-color: var(--accent); color: var(--accent); background: rgba(0, 255, 136, 0.04); } .add-panel-block-icon { font-size: 28px; line-height: 1; } .add-panel-block-label { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px; } .panel-data-badge { align-items: center; display: inline-flex; font-size: 9px; letter-spacing: 0.4px; padding: 2px 6px; border-radius: 10px; border: 1px solid transparent; color: var(--text); position: relative; transition: none; } .panel-data-badge.live { color: var(--status-live); border-color: rgba(86, 217, 130, 0.45); background: rgba(86, 217, 130, 0.12); padding-left: 16px; } .panel-data-badge.live::before { content: ''; position: absolute; left: 6px; top: 50%; width: 5px; height: 5px; border-radius: 50%; background: currentColor; transform: translateY(-50%); opacity: 1; animation: live-badge-dot-pulse 1.8s ease-in-out infinite; will-change: opacity, transform; } .panel-data-badge.cached { color: var(--semantic-elevated); border-color: rgba(245, 191, 89, 0.45); background: rgba(245, 191, 89, 0.12); } .panel-data-badge.unavailable { color: var(--semantic-critical); border-color: rgba(255, 139, 139, 0.45); background: rgba(255, 139, 139, 0.12); } /* Panel Sort Toggle Button (#107) */ .panel-sort-btn { background: var(--overlay-medium); border: 1px solid var(--overlay-medium); border-radius: 3px; cursor: pointer; font-size: 11px; padding: 2px 6px; margin-right: 2px; opacity: 0.85; transition: opacity 0.15s, transform 0.15s, background 0.15s; display: inline-flex; align-items: center; justify-content: center; color: var(--text-dim); line-height: 1; } .panel-sort-btn:hover { opacity: 1; background: var(--overlay-heavy); transform: scale(1.05); color: var(--text); } .panel-sort-btn svg { display: block; } /* Panel Summarize Button */ .panel-summarize-btn { background: var(--overlay-medium); border: 1px solid var(--overlay-medium); border-radius: 3px; cursor: pointer; font-size: 11px; padding: 2px 6px; opacity: 0.85; transition: opacity 0.15s, transform 0.15s, background 0.15s; } .panel-summarize-btn:hover { opacity: 1; background: var(--overlay-medium); transform: scale(1.05); } .panel-summarize-btn:disabled { cursor: wait; opacity: 0.4; } .panel-summarize-spinner { display: inline-block; width: 10px; height: 10px; border: 1.5px solid var(--border); border-top-color: var(--accent); border-radius: 50%; animation: spin 0.8s linear infinite; } /* Panel Summary Container */ .panel-summary { margin: 8px; padding: 10px; background: linear-gradient(135deg, rgba(68, 136, 255, 0.08), rgba(136, 68, 255, 0.08)); border-radius: 6px; border-left: 3px solid var(--accent); font-size: 11px; line-height: 1.5; max-height: 100px; overflow-y: auto; flex-shrink: 0; } .panel-summary-content { display: flex; align-items: flex-start; gap: 8px; } .panel-summary-text { flex: 1; color: var(--text); } .panel-summary-close { background: transparent; border: none; color: var(--text-dim); cursor: pointer; font-size: 14px; padding: 0 4px; line-height: 1; opacity: 0.6; } .panel-summary-close:hover { opacity: 1; color: var(--text); } .panel-summary-loading { color: var(--text-dim); font-style: italic; } .panel-summary-error { color: var(--accent-red); } .panel-info-wrapper { position: relative; display: inline-flex; } .panel-info-btn { width: 14px; height: 14px; border-radius: 50%; border: 1px solid var(--text-dim); background: transparent; color: var(--text-dim); font-size: 9px; font-weight: 600; cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 0; transition: all 0.15s ease; } .panel-info-btn:hover { border-color: var(--accent); color: var(--accent); background: rgba(0, 200, 255, 0.1); } .panel-info-tooltip { position: absolute; top: calc(100% + 8px); left: 50%; transform: translateX(-50%); background: var(--border-subtle); border: 1px solid var(--border-strong); border-radius: 4px; padding: 10px 12px; font-size: 11px; line-height: 1.5; color: var(--text); min-width: 220px; max-width: 300px; z-index: 1000; box-shadow: 0 4px 16px var(--shadow-color); opacity: 0; visibility: hidden; transition: opacity 0.15s ease, visibility 0.15s ease; } .panel-info-tooltip.visible { opacity: 1; visibility: visible; } .panel-info-tooltip::before { content: ''; position: absolute; top: -6px; left: 50%; transform: translateX(-50%); border: 6px solid transparent; border-bottom-color: var(--border-strong); } .panel-info-tooltip::after { content: ''; position: absolute; top: -4px; left: 50%; transform: translateX(-50%); border: 5px solid transparent; border-bottom-color: var(--border-subtle); } .panel-info-tooltip strong { color: var(--accent); display: block; margin-bottom: 4px; } .panel-info-tooltip ul { margin: 6px 0 0; padding-left: 14px; } .panel-info-tooltip li { margin: 2px 0; color: var(--text-dim); } .panel-content { flex: 1; overflow-y: auto; padding: 8px; min-width: 0; user-select: none; content-visibility: auto; /* #4580: field CLS attribution shows #panelsGrid + deferred panels re-shifting as they scroll in/out of view. `auto ` makes the browser remember each element's last rendered size, so re-entry reserves the real height instead of the fallback and doesn't shift. The plain line stays first as the pre-Chrome-111 fallback. */ contain-intrinsic-size: 260px; contain-intrinsic-size: auto 260px; } .panel-deferred-shell { cursor: default; pointer-events: none; content-visibility: auto; contain-intrinsic-size: var(--dashboard-panel-row-min, 260px); contain-intrinsic-size: auto var(--dashboard-panel-row-min, 260px); } .panel-deferred-shell.panel-wide, .panel-deferred-shell.span-2 { contain-intrinsic-size: var(--dashboard-first-grid-reservation, 400px); contain-intrinsic-size: auto var(--dashboard-first-grid-reservation, 400px); } .panel-deferred-shell.span-3 { contain-intrinsic-size: 600px; contain-intrinsic-size: auto 600px; } .panel-deferred-shell.span-4 { contain-intrinsic-size: 800px; contain-intrinsic-size: auto 800px; } .panel-deferred-shell.panel-collapsed .panel-deferred-content { display: none; } .panel-deferred-content { display: flex; flex-direction: column; justify-content: center; gap: 8px; overflow: hidden; } .panel-deferred-skeleton { display: block; height: 8px; border-radius: 4px; background: linear-gradient(90deg, var(--surface-alt), var(--border), var(--surface-alt)); opacity: 0.65; } .panel-deferred-skeleton:nth-child(2) { width: 72%; } .panel-deferred-skeleton:nth-child(3) { width: 48%; } .panel-content::-webkit-scrollbar { width: 4px; } .panel-content::-webkit-scrollbar-track { background: transparent; } .panel-content::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; } /* Wide panel (spans 2 columns and 2 rows for video content) */ .panel-wide { grid-column: span 2; grid-row: span 2; min-height: var(--dashboard-first-grid-reservation); max-height: none; } /* Live News Panel */ .live-news-toolbar { display: flex; justify-content: space-between; align-items: flex-start; gap: 4px; padding: 6px 8px; background: var(--darken-heavy); border-bottom: 1px solid var(--border); flex-shrink: 0; } .live-news-toolbar .live-news-switcher { flex: 1; min-width: 0; } .live-news-switcher { display: flex; flex-wrap: wrap; gap: 4px; padding: 0; background: transparent; border: none; min-width: 0; } .live-channel-btn { padding: 4px 8px; background: transparent; border: 1px solid var(--border); color: var(--text-dim); font-family: inherit; font-size: 10px; cursor: pointer; transition: all 0.2s; text-transform: uppercase; letter-spacing: 0.5px; white-space: nowrap; } .live-channel-btn:hover { border-color: var(--text-dim); color: var(--text); } .live-channel-btn.active { background: var(--red-strong); border-color: var(--red-strong); color: white; } .live-channel-btn.loading { opacity: 0.6; pointer-events: none; } .live-channel-btn.loading::after { content: '...'; animation: loadingDots 1s infinite; } .live-channel-btn.offline { border-style: dashed; } .live-channel-btn { cursor: grab; } .live-channel-btn.live-channel-dragging { opacity: 0.6; cursor: grabbing; } /* Live News – Channel settings button (same style as webcam view buttons) */ .live-news-settings-btn { padding: 4px 8px; background: transparent; border: 1px solid var(--border); color: var(--text-dim); font-family: inherit; font-size: 10px; cursor: pointer; transition: all 0.2s; display: flex; align-items: center; justify-content: center; flex-shrink: 0; align-self: flex-start; } .live-news-settings-btn:hover { border-color: var(--text-dim); color: var(--text); } /* Channel management list: same layout as LIVE panel channel switcher */ .live-news-manage-list { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; } /* Each row = same style as .live-channel-btn */ .live-news-manage-row { display: inline-flex; align-items: center; gap: 4px; padding: 6px 12px; background: transparent; border: 1px solid var(--border); color: var(--text-dim); font-family: inherit; font-size: 12px; text-transform: uppercase; letter-spacing: 0.75px; white-space: nowrap; cursor: grab; transition: all 0.2s; } .live-news-manage-row:active { cursor: grabbing; } .live-news-manage-row:hover { border-color: var(--text-dim); color: var(--text); } .live-news-manage-row-dragging { opacity: 0.6; cursor: grabbing; } .live-news-manage-remove { padding: 4px 8px; font-size: 10px; min-height: auto; color: var(--red); background: transparent; border: 1px solid var(--border); cursor: pointer; border-radius: 0; text-transform: uppercase; letter-spacing: 0.5px; } .live-news-manage-remove:hover { text-decoration: underline; border-color: var(--red); } .live-news-manage-remove-in-form { font-weight: 600; border-color: var(--red); color: var(--red); } .live-news-manage-remove-in-form:hover { background: rgba(255, 80, 80, 0.15); } .live-news-manage-row-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; } .live-news-manage-row-remove-x { display: none; font-size: 10px; color: var(--text-faint); cursor: pointer; padding: 0 2px; line-height: 1; transition: color 0.15s; } .live-news-manage-row:hover .live-news-manage-row-remove-x { display: inline; } .live-news-manage-row-remove-x:hover { color: var(--red); } .live-news-manage-edit { padding: 4px 8px; font-size: 10px; min-height: auto; color: var(--text-dim); background: transparent; border: 1px solid var(--border); cursor: pointer; border-radius: 0; text-transform: uppercase; letter-spacing: 0.5px; } .live-news-manage-edit:hover { color: var(--text); border-color: var(--text-dim); } .live-news-manage-row-editing { cursor: default; flex-wrap: wrap; gap: 8px; padding: 8px 10px; background: transparent; border: 1px solid var(--border); white-space: normal; } .live-news-manage-row-editing .live-news-manage-edit-handle, .live-news-manage-row-editing .live-news-manage-edit-name { padding: 10px 12px; font-size: 14px; min-width: 160px; min-height: 40px; background: var(--bg); border: 1px solid var(--border); color: var(--text); border-radius: 4px; } .live-news-manage-save, .live-news-manage-cancel { padding: 8px 16px; font-size: 13px; min-height: 40px; border: 1px solid var(--border); cursor: pointer; background: var(--bg); color: var(--text); border-radius: 4px; } .live-news-manage-save:hover { border-color: var(--green); color: var(--green); } .live-news-manage-cancel:hover { border-color: var(--text-dim); } .live-news-manage-add-section { display: flex; flex-direction: column; gap: 10px; } .live-news-manage-add-title { font-size: 14px; font-weight: bold; text-transform: uppercase; letter-spacing: 1px; color: var(--text); } .live-news-manage-add { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end; } .live-news-manage-add-field { display: flex; flex-direction: column; gap: 4px; } .live-news-manage-add-label { font-size: 12px; font-weight: 600; color: var(--text); } .live-news-manage-handle, .live-news-manage-name { padding: 10px 12px; font-size: 14px; min-height: 44px; width: 200px; max-width: 100%; background: var(--bg); border: 1px solid var(--border); color: var(--text); border-radius: 4px; } .live-news-manage-handle.invalid { border-color: #f44; box-shadow: 0 0 0 1px rgba(255, 68, 68, 0.3); } .live-news-manage-add-btn { padding: 10px 18px; font-size: 14px; min-height: 44px; background: var(--border); border: 1px solid var(--border); color: var(--text); cursor: pointer; border-radius: 4px; } .live-news-manage-add-btn:hover { background: var(--text-dim); color: var(--bg); } /* Standalone live channels window (?live-channels=1) */ .live-channels-window-shell { min-height: 100vh; display: flex; flex-direction: column; background: var(--bg); color: var(--text); } .live-channels-window-header { display: flex; justify-content: space-between; align-items: center; padding: 8px 14px; border-bottom: 1px solid var(--border); background: var(--darken-heavy); flex-shrink: 0; } .live-channels-window-shell .modal-close { padding: 10px 14px; font-size: 20px; min-width: 44px; min-height: 44px; border-radius: 4px; } .live-channels-window-toolbar { margin-bottom: 4px; display: flex; flex-wrap: wrap; gap: 8px; align-items: center; } .live-news-manage-restore-defaults { padding: 8px 14px; font-size: 13px; min-height: 40px; color: var(--text-dim); background: transparent; border: 1px solid var(--border); cursor: pointer; border-radius: 4px; } .live-news-manage-restore-defaults:hover { color: var(--text); border-color: var(--text-dim); } .live-channels-window-title { font-size: 14px; font-weight: bold; text-transform: uppercase; letter-spacing: 1px; } .live-channels-window-content { padding: 10px 14px; flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 8px; } .live-channels-window-shell .live-news-manage-list { min-height: 0; overflow-y: auto; align-content: flex-start; } .live-channels-window-shell .live-news-manage-add-section { margin-top: 20px; } /* Channel management modal overlay */ .live-channels-modal-overlay { position: fixed; inset: 0; z-index: 9999; background: rgba(0, 0, 0, 0.6); display: flex; align-items: center; justify-content: center; opacity: 0; transition: opacity 0.15s ease; } .live-channels-modal-overlay.active { opacity: 1; } .live-channels-modal { position: relative; width: 680px; max-width: 95vw; max-height: 85vh; overflow-y: auto; background: var(--bg); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5); } .live-channels-modal .live-channels-window-shell { min-height: auto; } .live-channels-modal-close { position: absolute; top: 8px; right: 8px; z-index: 1; background: transparent; border: none; color: var(--text-dim); font-size: 22px; cursor: pointer; padding: 4px 10px; border-radius: 4px; line-height: 1; } .live-channels-modal-close:hover { color: var(--text); background: var(--darken); } /* Available channels section */ .live-news-manage-available-section { border-top: 1px solid var(--border); padding-top: 8px; margin-top: 4px; } .live-news-manage-available-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; gap: 16px; } .live-news-manage-available-header .live-news-manage-add-title { margin-bottom: 0; } .live-news-manage-search-wrap { position: relative; flex: 1; max-width: 240px; } .live-news-manage-search-icon { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); color: var(--text-dim); pointer-events: none; display: flex; align-items: center; opacity: 0.6; } .live-news-manage-search-input { width: 100%; padding: 6px 12px 6px 32px; background: var(--darken-heavy); border: 1px solid var(--border); border-radius: 4px; color: var(--text); font-size: 13px; outline: none; transition: border-color 0.2s, box-shadow 0.2s; } .live-news-manage-search-input:focus { border-color: var(--text-dim); background: var(--bg); } .live-news-manage-search-input::placeholder { color: var(--text-dim); } .live-news-manage-empty { padding: 30px 10px; text-align: center; color: var(--text-dim); font-size: 14px; background: var(--darken); border: 1px dashed var(--border); border-radius: 6px; margin-top: 4px; } /* live-news-manage-tab: now uses shared .panel-tabs / .panel-tab */ /* Tab content panels */ .live-news-manage-tab-content { display: none; } .live-news-manage-tab-content.active { display: block; } /* 2-column card grid */ .live-news-manage-card-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; } /* Channel card */ .live-news-manage-card { display: flex; align-items: center; gap: 8px; padding: 10px; background: var(--surface); border: 1px solid var(--border); cursor: pointer; transition: all 0.15s; } .live-news-manage-card:hover { border-color: var(--text-faint); background: var(--surface-hover); } .live-news-manage-card.added { border-color: rgba(68, 255, 136, 0.3); background: rgba(68, 255, 136, 0.05); cursor: pointer; } .live-news-manage-card.added:hover { border-color: rgba(255, 80, 80, 0.5); background: rgba(255, 80, 80, 0.08); } .live-news-manage-card:active { transform: scale(0.97); } /* Card icon (initials) */ .live-news-manage-card-icon { width: 28px; height: 28px; border-radius: 4px; background: var(--surface-hover); border: 1px solid var(--border); display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 700; color: var(--text-dim); flex-shrink: 0; text-transform: uppercase; } /* Card text */ .live-news-manage-card-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; } .live-news-manage-card-name { font-size: 11px; color: var(--text-secondary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .live-news-manage-card-handle { font-size: 9px; color: var(--text-faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* Add/check indicator */ .live-news-manage-card-action { font-size: 14px; color: var(--text-faint); flex-shrink: 0; transition: color 0.15s; } .live-news-manage-card:hover .live-news-manage-card-action { color: var(--green); } .live-news-manage-card.added .live-news-manage-card-action { color: var(--green); } .live-news-manage-card:hover .live-news-manage-card-action { color: var(--green); } .live-news-manage-card.added .live-news-manage-card-action { color: var(--green); } .live-news-manage-card.added:hover .live-news-manage-card-action { color: var(--red); } /* Tab count badge */ .live-news-manage-tab-count { font-size: 9px; color: var(--text-faint); margin-left: 4px; } .live-offline { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; min-height: 200px; color: var(--text-dim); text-align: center; gap: 8px; } .live-offline .offline-icon { font-size: 32px; opacity: 0.5; } .live-offline .offline-text { font-size: 12px; } .live-offline .offline-retry { margin-top: 8px; padding: 6px 12px; background: var(--panel-bg); border: 1px solid var(--border); color: var(--text); font-size: 11px; cursor: pointer; border-radius: 4px; } .live-offline .offline-retry:hover { border-color: var(--text-dim); } .live-offline-compact { min-height: 120px; padding: 14px; } .live-offline-compact .offline-icon { font-size: 18px; } .live-media-shell { width: 100%; min-height: 180px; flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; padding: 18px; cursor: pointer; background: radial-gradient(circle at center, rgba(220, 38, 38, 0.12), transparent 42%), var(--bg); } .live-media-shell-status, .webcam-preview-status { display: flex; align-items: center; gap: 7px; color: var(--text-dim); font-size: 10px; font-weight: 700; letter-spacing: 0; text-transform: uppercase; } .live-media-shell-dot { position: relative; width: 7px; height: 7px; border-radius: 50%; background: var(--red); } .live-media-shell-dot::before { content: ''; position: absolute; inset: 0; border-radius: inherit; background: var(--red); opacity: 0; transform: scale(1); pointer-events: none; animation: live-pulse-ring 1.6s ease-out infinite; will-change: opacity, transform; } .live-media-shell-title { color: var(--text); font-size: 14px; font-weight: 700; } .live-media-shell .offline-retry, .webcam-preview-play { appearance: none; margin-top: 2px; min-height: 28px; padding: 6px 12px; background: rgba(220, 38, 38, 0.18); border: 1px solid rgba(248, 113, 113, 0.72); border-radius: 4px; color: #fff; font-family: var(--font-mono); font-size: 10px; font-weight: 700; letter-spacing: 0; line-height: 1; text-transform: uppercase; cursor: pointer; transition: background 0.2s ease, border-color 0.2s ease; } .live-media-shell .offline-retry:hover, .webcam-preview-play:hover { /* White (#fff, from the base rule) on --red is 3.41:1; --red-strong clears AA (≈5:1). axe doesn't audit :hover, but this is the same defect class. */ background: var(--red-strong); border-color: var(--red-strong); } .live-media-shell .offline-retry:focus-visible, .webcam-preview-play:focus-visible { outline: 2px solid rgba(248, 113, 113, 0.72); outline-offset: 2px; } @keyframes live-pulse-ring { 0%, 100% { opacity: 0; transform: scale(1); } 50% { opacity: 0.45; transform: scale(1.9); } } .bot-check-actions { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; margin-top: 4px; } .bot-check-actions .bot-check-signin { background: var(--accent, #4a9eff); border-color: var(--accent, #4a9eff); color: #fff; } @keyframes loadingDots { 0%, 20% { content: '.'; } 40% { content: '..'; } 60%, 100% { content: '...'; } } .live-mute-btn { background: transparent; border: none; color: var(--text-dim); cursor: pointer; padding: 4px; display: flex; align-items: center; justify-content: center; transition: color 0.2s; } .live-mute-btn:hover { color: var(--text); } .live-mute-btn.unmuted { color: var(--green); } .live-news-fullscreen { position: fixed !important; top: 0 !important; left: 0 !important; right: 0 !important; bottom: 0 !important; width: auto !important; height: auto !important; min-height: 0 !important; max-height: none !important; border: 0 !important; z-index: 10000 !important; border-radius: 0 !important; margin: 0 !important; } .live-news-fullscreen .panel-content { height: calc(100vh - 80px) !important; } .live-news-fullscreen .live-news-player, .live-news-fullscreen .live-news-native-video, .live-news-fullscreen .live-news-embed-frame { height: 100% !important; } body.live-news-fullscreen-active { overflow: hidden; } body.live-news-fullscreen-active .time-slider, body.live-news-fullscreen-active .deckgl-layer-toggles, body.live-news-fullscreen-active .map-legend, body.live-news-fullscreen-active .map-controls, body.live-news-fullscreen-active .map-timestamp { visibility: hidden !important; pointer-events: none !important; } body.live-news-fullscreen-active #mapSection.live-news-fullscreen .map-bottom-grid, body.live-news-fullscreen-active #mapSection.live-news-fullscreen .map-resize-handle { display: none !important; } body.live-news-fullscreen-active #mapSection.live-news-fullscreen .map-container { height: auto !important; flex: 1 1 auto !important; min-height: 0 !important; } body.live-news-fullscreen-active .community-widget { display: none; } /* Hide map overlays and sibling panels behind fullscreen panel (#829, #859) */ body.live-news-fullscreen-active .layer-toggles, body.live-news-fullscreen-active .map-legend { display: none !important; } body.live-news-fullscreen-active .panels-grid > *:not(.live-news-fullscreen) { visibility: hidden !important; } .live-indicator-btn { background: transparent; border: none; color: var(--text); cursor: pointer; padding: 4px 8px; display: flex; align-items: center; gap: 4px; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; transition: opacity 0.2s; } .live-indicator-btn:hover { opacity: 0.8; } .live-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--red); animation: live-blink 1.5s ease-in-out infinite; } .live-dot.paused { background: var(--text-dim); animation: none; } .live-indicator-btn.paused { color: var(--text-dim); } @keyframes live-blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } } #live-news .panel-content { padding: 0; flex: 1; display: flex; } .live-news-player { width: 100%; flex: 1; background: var(--bg); aspect-ratio: 16 / 9; } .live-news-player iframe { width: 100%; height: 100%; display: block; } /* Live Webcams Panel */ .panel[data-panel="live-webcams"] .panel-content { padding: 0; flex: 1; display: flex; flex-direction: column; overflow: hidden; } .webcam-content { overflow: hidden !important; } .webcam-toolbar { display: flex; justify-content: space-between; align-items: center; gap: 4px; padding: 6px 8px; background: var(--darken-heavy); border-bottom: 1px solid var(--border); flex-shrink: 0; } .webcam-toolbar-group { display: flex; gap: 4px; } .webcam-region-btn, .webcam-view-btn { padding: 4px 8px; background: transparent; border: 1px solid var(--border); color: var(--text-dim); font-family: inherit; font-size: 10px; cursor: pointer; transition: all 0.2s; text-transform: uppercase; letter-spacing: 0.5px; white-space: nowrap; display: flex; align-items: center; justify-content: center; } .webcam-region-btn:hover, .webcam-view-btn:hover { border-color: var(--text-dim); color: var(--text); } .webcam-region-btn.active { background: var(--red-strong); border-color: var(--red-strong); color: white; } .webcam-view-btn.active { background: var(--red-strong); border-color: var(--red-strong); color: white; } .webcam-grid { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; gap: 2px; flex: 1; min-height: 0; height: 0; background: #000; overflow: hidden; } .webcam-cell { position: relative; overflow: hidden; cursor: pointer; background: #000; min-height: 0; height: 100%; } .webcam-preview-tile { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: flex-start; justify-content: flex-end; gap: 7px; padding: 14px; background: linear-gradient(180deg, rgba(255, 255, 255, 0.05), transparent 38%), linear-gradient(135deg, rgba(220, 38, 38, 0.24), rgba(0, 0, 0, 0.88)); } .webcam-preview-tile:hover .webcam-preview-play { border-color: var(--text); } .webcam-preview-title { color: #fff; font-family: var(--font-mono); font-size: 13px; font-weight: 700; letter-spacing: 0; text-transform: uppercase; text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8); } .webcam-preview-meta { color: rgba(255, 255, 255, 0.72); font-size: 10px; text-transform: uppercase; } .webcam-preview-play { margin-top: 4px; } .webcam-cell:hover .webcam-cell-label { opacity: 1; } .webcam-cell-label { position: absolute; top: 0; left: 0; right: 0; padding: 6px 10px; background: linear-gradient(180deg, rgba(0, 0, 0, 0.8) 0%, transparent 100%); display: flex; align-items: center; gap: 6px; z-index: 2; opacity: 0.85; transition: opacity 0.2s; pointer-events: none; } .webcam-expand-btn { pointer-events: auto; margin-left: auto; background: rgba(0, 0, 0, 0.5); border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 3px; color: #fff; padding: 2px 4px; cursor: pointer; opacity: 0; transition: opacity 0.2s; line-height: 1; } .webcam-cell:hover .webcam-expand-btn { opacity: 0.7; } .webcam-expand-btn:hover { opacity: 1 !important; background: rgba(255, 255, 255, 0.15); } .webcam-city { font-family: var(--font-mono); font-size: 10px; font-weight: 700; color: #fff; letter-spacing: 1px; text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8); } .webcam-live-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--red); animation: live-blink 1.5s ease-in-out infinite; flex-shrink: 0; } .webcam-iframe { width: 100%; height: 100%; border: 0; display: block; pointer-events: auto; } .webcam-single { position: relative; flex: 1; background: #000; aspect-ratio: 16 / 9; } .webcam-embed-fallback { position: absolute; inset: 0; z-index: 3; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; padding: 16px; text-align: center; background: rgba(0, 0, 0, 0.78); backdrop-filter: blur(2px); } .webcam-embed-fallback-text { color: var(--text); font-size: 12px; max-width: 280px; } .webcam-embed-fallback-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; } .webcam-embed-fallback .offline-retry { margin: 0; } .webcam-switcher { display: flex; gap: 4px; padding: 6px 8px; background: var(--darken-heavy); border-top: 1px solid var(--border); flex-shrink: 0; flex-wrap: wrap; } .webcam-feed-btn { padding: 4px 8px; background: transparent; border: 1px solid var(--border); color: var(--text-dim); font-family: inherit; font-size: 10px; cursor: pointer; transition: all 0.2s; text-transform: uppercase; letter-spacing: 0.5px; } .webcam-feed-btn:hover { border-color: var(--text-dim); color: var(--text); } .webcam-feed-btn.active { background: var(--red-strong); border-color: var(--red-strong); color: white; } .webcam-back-btn { display: flex; align-items: center; gap: 4px; border-color: var(--text-dim); margin-inline-end: 4px; } .webcam-placeholder { display: flex; align-items: center; justify-content: center; height: 100%; min-height: 200px; color: var(--text-dim); font-size: 12px; } @media (max-width: 768px) { .webcam-grid { grid-template-columns: 1fr; grid-template-rows: auto; } .webcam-grid .webcam-cell:nth-child(n+3) { display: none; } .webcam-view-btn { display: none; } } /* Mobile: make toolbars swipeable (horizontal scroll) */ @media (max-width: 768px) { /* Live News channels */ .live-news-switcher { flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden; -webkit-overflow-scrolling: touch; scroll-snap-type: x proximity; touch-action: pan-x; padding-bottom: 2px; } .live-news-switcher::-webkit-scrollbar { display: none; } .live-news-switcher { scrollbar-width: none; } .live-channel-btn { scroll-snap-align: start; flex: 0 0 auto; } /* Webcams regions */ .webcam-toolbar { align-items: flex-start; } .webcam-toolbar-group { overflow-x: auto; overflow-y: hidden; -webkit-overflow-scrolling: touch; scroll-snap-type: x proximity; touch-action: pan-x; min-width: 0; flex-wrap: nowrap; } .webcam-toolbar-group::-webkit-scrollbar { display: none; } .webcam-toolbar-group { scrollbar-width: none; } .webcam-region-btn { scroll-snap-align: start; flex: 0 0 auto; } } /* ── Pinned Webcams Panel ── */ .pinned-webcams-grid { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; gap: 4px; aspect-ratio: 16 / 9; width: 100%; } .pinned-webcam-slot { position: relative; background: var(--bg-secondary, #1a1a2e); border-radius: 4px; overflow: hidden; } .pinned-webcam-slot--empty { display: flex; align-items: center; justify-content: center; } .pinned-webcam-iframe { width: 100%; height: 100%; border: none; display: block; } .pinned-webcam-placeholder { color: var(--text-muted, #666); font-size: 0.75rem; text-align: center; padding: 8px; } .pinned-webcam-label { position: absolute; bottom: 0; left: 0; right: 0; display: flex; align-items: center; gap: 4px; padding: 2px 6px; background: rgba(0, 0, 0, 0.7); font-size: 0.65rem; } .pinned-webcam-title { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #eee; } .pinned-webcam-toggle, .pinned-webcam-unpin { background: none; border: none; color: #aaa; cursor: pointer; font-size: 0.7rem; padding: 0 2px; line-height: 1; } .pinned-webcam-toggle:hover, .pinned-webcam-unpin:hover { color: #fff; } /* Pinned list below grid */ .pinned-webcams-list { margin-top: 8px; max-height: 120px; overflow-y: auto; } .pinned-webcams-list-header { font-size: 0.7rem; color: var(--text-muted, #888); padding: 4px 8px; text-transform: uppercase; letter-spacing: 0.5px; } .pinned-webcam-row { display: flex; align-items: center; gap: 6px; padding: 3px 8px; font-size: 0.75rem; } .pinned-webcam-row--active { background: rgba(0, 212, 255, 0.08); } .pinned-webcam-row-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .pinned-webcam-row-country { color: var(--text-muted, #888); font-size: 0.65rem; } .pinned-webcam-row-toggle { background: none; border: 1px solid var(--border-color, #333); color: var(--text-secondary, #aaa); border-radius: 3px; padding: 1px 6px; font-size: 0.65rem; cursor: pointer; } .pinned-webcam-row--active .pinned-webcam-row-toggle { border-color: var(--accent, #00d4ff); color: var(--accent, #00d4ff); } .pinned-webcam-row-remove { background: none; border: none; color: var(--text-muted, #666); cursor: pointer; font-size: 0.7rem; padding: 0 2px; } .pinned-webcam-row-remove:hover { color: var(--error, #ff4444); } /* Pin button in map tooltips */ .webcam-pin-btn { background: none; border: 1px solid var(--border-color, #444); color: var(--text-secondary, #ccc); border-radius: 3px; padding: 2px 8px; font-size: 0.75rem; cursor: pointer; margin-top: 4px; display: inline-flex; align-items: center; gap: 4px; } .webcam-pin-btn:hover { border-color: var(--accent, #00d4ff); color: var(--accent, #00d4ff); } /* Toast notification (localStorage full, etc.) */ .wm-toast { position: fixed; bottom: 16px; left: 50%; transform: translateX(-50%); background: var(--bg-secondary, #1a1a2e); border: 1px solid var(--error, #ff4444); color: var(--text-primary, #eee); padding: 8px 16px; border-radius: 6px; font-size: 0.8rem; z-index: 10000; pointer-events: none; animation: wm-toast-fade 3s ease-in-out; } @keyframes wm-toast-fade { 0%, 80% { opacity: 1; } 100% { opacity: 0; } } .webcam-pin-btn--pinned { opacity: 0.6; cursor: default; border-color: var(--accent, #00d4ff); color: var(--accent, #00d4ff); } /* DeckGL webcam click popup */ .deckgl-webcam-popup { background: var(--bg-secondary, #1a1a2e); border: 1px solid var(--border-color, #333); border-radius: 6px; padding: 8px 12px; min-width: 140px; pointer-events: auto; } .deckgl-webcam-popup-title { font-size: 0.8rem; font-weight: 600; margin-bottom: 2px; } .deckgl-webcam-popup-location { font-size: 0.7rem; color: var(--text-muted, #888); margin-bottom: 6px; } /* News Items */ .item { padding: 8px 0; border-bottom: 1px solid var(--border); } .item:last-child { border-bottom: none; } .item.alert { border-left: 2px solid var(--red); padding-left: 8px; margin-left: -8px; } .item-source { font-size: 9px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 4px; display: flex; align-items: center; gap: 6px; } .alert-tag { background: var(--red); color: var(--bg); padding: 1px 4px; font-size: 8px; font-weight: bold; animation: pulse-alert 1s infinite; } .lang-badge { display: inline-block; padding: 1px 4px; border-radius: 2px; background: var(--surface-light); color: var(--text-dim); font-size: 8px; font-weight: 500; margin-inline-start: 6px; border: 1px solid var(--border); vertical-align: middle; line-height: normal; } .phase-badge { display: inline-block; padding: 1px 4px; border-radius: 2px; font-size: 8px; font-weight: bold; margin-inline-start: 4px; vertical-align: middle; line-height: normal; } .phase-badge.breaking { background: var(--orange, #f97316); color: var(--bg); animation: pulse-alert 1.5s infinite; } .phase-badge.developing { background: var(--yellow, #eab308); color: var(--bg); } .phase-badge.sustained { background: var(--slate, #64748b); color: var(--bg); } @keyframes pulse-alert { 0%, 100% { opacity: 1; } 50% { opacity: 0.7; } } /* CII Share button */ .cii-share-btn { background: none; border: 1px solid var(--border); color: var(--text-muted); font-size: 12px; cursor: pointer; padding: 1px 4px; border-radius: 3px; margin-left: auto; transition: color 0.2s, border-color 0.2s; } .cii-share-btn:hover { color: var(--semantic-info); border-color: var(--semantic-info); } /* Toast */ .toast-notification { position: fixed; bottom: 32px; left: 50%; transform: translateX(-50%) translateY(20px); background: var(--surface-active); color: var(--text-secondary); padding: 10px 20px; border-radius: 8px; border: 1px solid var(--border); font-size: 13px; z-index: 10002; opacity: 0; transition: opacity 0.3s, transform 0.3s; pointer-events: none; } .toast-notification.visible { opacity: 1; transform: translateX(-50%) translateY(0); } /* Story Modal */ .story-modal-overlay { position: fixed; inset: 0; z-index: 10001; background: var(--bg); display: flex; flex-direction: column; align-items: center; justify-content: center; backdrop-filter: blur(8px); } .story-modal { position: relative; display: flex; flex-direction: column; align-items: center; gap: 20px; max-height: 95vh; } .story-close-x { position: absolute; top: -44px; right: -4px; background: var(--overlay-medium); border: none; color: var(--text-dim); width: 36px; height: 36px; border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: background 0.2s, color 0.2s; z-index: 1; } .story-close-x:hover { background: var(--overlay-medium); color: var(--accent); } .story-modal-content { max-height: 75vh; overflow: auto; border-radius: 14px; box-shadow: 0 12px 48px var(--shadow-color), 0 0 0 1px var(--overlay-light); } .story-image { display: block; max-height: 75vh; width: auto; border-radius: 14px; } .story-loading, .story-error { display: flex; flex-direction: column; align-items: center; gap: 12px; padding: 60px 40px; color: var(--text-dim); font-size: 14px; } .story-spinner { width: 32px; height: 32px; border: 3px solid var(--border); border-top-color: var(--semantic-info); border-radius: 50%; animation: spin 0.8s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } .story-error { color: var(--threat-critical); } .story-share-bar { display: flex; gap: 6px; background: var(--overlay-light); padding: 8px 12px; border-radius: 16px; border: 1px solid var(--overlay-light); } .story-share-btn { display: flex; flex-direction: column; align-items: center; gap: 4px; background: none; border: none; color: var(--text-dim); padding: 10px 16px; border-radius: 12px; cursor: pointer; font-size: 11px; font-family: inherit; transition: background 0.2s, color 0.2s; } .story-share-btn:hover { background: var(--overlay-medium); color: var(--accent); } .story-share-btn svg { flex-shrink: 0; } .story-share-btn.story-save:hover { color: var(--semantic-info); } .story-share-btn.story-whatsapp:hover { color: var(--semantic-normal); } .story-share-btn.story-twitter:hover { color: var(--accent); } .story-share-btn.story-linkedin:hover { color: var(--semantic-info); } .story-share-btn.story-copy:hover { color: var(--threat-medium); } .category-tag { color: var(--text); font-size: 8px; padding: 1px 5px; border-radius: 3px; font-weight: 600; border: 1px solid; border-color: var(--category-color); background: var(--category-background); text-transform: uppercase; letter-spacing: 0.3px; } .item-title { color: var(--text); text-decoration: none; font-size: 12px; line-height: 1.4; display: block; } .item-title:hover { color: var(--accent); } .item-time { font-size: 9px; color: var(--text-dim); margin-top: 4px; } /* Clustering */ .source-count { background: var(--accent); color: var(--bg); padding: 1px 5px; font-size: 8px; font-weight: bold; border-radius: 8px; } .cluster-meta { display: flex; align-items: center; justify-content: space-between; margin-top: 4px; gap: 8px; } .top-sources { display: flex; gap: 4px; flex-wrap: wrap; } .top-source { font-size: 8px; padding: 1px 4px; border-radius: 2px; background: var(--panel-border); color: var(--text-dim); } .top-source.tier-1 { background: rgba(0, 255, 136, 0.15); color: var(--green); } .top-source.tier-2 { background: rgba(0, 170, 255, 0.15); color: var(--accent); } .top-source.tier-3 { background: rgba(255, 170, 0, 0.15); color: var(--yellow); } /* Source credibility tier badge */ .tier-badge { font-size: 9px; font-weight: 600; padding: 1px 5px; border-radius: 3px; margin-right: 4px; letter-spacing: 0.3px; } .tier-badge.tier-1 { background: linear-gradient(135deg, rgba(0, 255, 136, 0.25), rgba(0, 200, 100, 0.15)); color: var(--green); border: 1px solid rgba(0, 255, 136, 0.4); } .tier-badge.tier-2 { background: rgba(0, 170, 255, 0.15); color: var(--accent); border: 1px solid rgba(0, 170, 255, 0.3); } /* "Also reported by" label */ .also-reported { font-size: 8px; color: var(--text-dim); margin-right: 4px; font-style: italic; } /* Enhanced tier indicators for top sources */ .top-source.tier-1 { font-weight: 500; border: 1px solid rgba(0, 255, 136, 0.3); } .top-source.tier-2 { border: 1px solid rgba(0, 170, 255, 0.2); } .item.clustered { border-left: 2px solid var(--border); padding-left: 8px; margin-left: -8px; } .item.clustered.alert { border-left: 2px solid var(--red); } .item.clustered:hover { border-left-color: var(--accent); } /* Related assets */ .related-assets { margin-top: 8px; padding: 8px; border-radius: 8px; background: var(--bg); border: 1px solid rgba(0, 255, 170, 0.2); } .related-assets-header { font-size: 9px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.6px; display: flex; gap: 6px; align-items: center; margin-bottom: 6px; } .related-assets-range { color: var(--accent); } .related-assets-list { display: flex; flex-direction: column; gap: 6px; } .related-asset { display: grid; grid-template-columns: auto 1fr auto; gap: 6px; align-items: center; padding: 6px 8px; border-radius: 6px; background: var(--bg); border: 1px solid rgba(0, 255, 170, 0.15); color: var(--text); cursor: pointer; text-align: left; } .related-asset:hover { border-color: rgba(0, 255, 170, 0.5); box-shadow: 0 0 10px rgba(0, 255, 170, 0.2); } .related-asset-type { font-size: 8px; text-transform: uppercase; color: var(--accent); letter-spacing: 0.4px; } .related-asset-name { font-size: 10px; color: var(--text); } .related-asset-distance { font-size: 9px; color: var(--text-dim); } /* Velocity */ .velocity-badge { font-size: 8px; padding: 1px 5px; border-radius: 8px; font-weight: bold; } .velocity-badge.elevated { background: rgba(255, 170, 0, 0.2); color: var(--yellow); } .velocity-badge.spike { background: rgba(var(--semantic-critical), 0.2); color: var(--red); animation: pulse-velocity 1.5s infinite; } @keyframes pulse-velocity { 0%, 100% { opacity: 1; } 50% { opacity: 0.6; } } /* Sentiment */ .sentiment-badge { font-size: 9px; padding: 0 3px; } .sentiment-badge.negative { color: var(--red); } .sentiment-badge.positive { color: var(--green); } /* Deviation indicators */ .deviation-indicator { font-size: 9px; font-weight: bold; margin-left: 8px; padding: 1px 6px; border-radius: 8px; } .deviation-indicator.elevated { background: rgba(255, 170, 0, 0.2); color: var(--yellow); } .deviation-indicator.spike { background: rgba(var(--semantic-critical), 0.2); color: var(--red); animation: pulse-alert 1s infinite; } .deviation-indicator.quiet { background: var(--overlay-heavy); color: var(--text-dim); } /* Signal Modal */ .signal-modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: var(--bg); display: none; justify-content: center; align-items: center; z-index: 9999; } .signal-modal-overlay.active { display: flex; } .signal-modal { background: var(--bg); border: 1px solid var(--accent); border-radius: 4px; width: 90%; max-width: 500px; max-height: 80vh; overflow: hidden; box-shadow: 0 0 30px rgba(0, 170, 255, 0.3); animation: signal-pulse 0.5s ease-out; will-change: transform, opacity; } @keyframes signal-pulse { 0% { transform: scale(0.9); opacity: 0; } 50% { transform: scale(1.02); } 100% { transform: scale(1); opacity: 1; } } .signal-modal-header { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; background: var(--accent); color: var(--bg); } .signal-modal-title { font-weight: bold; font-size: 14px; letter-spacing: 1px; } .signal-modal-close { background: none; border: none; color: var(--bg); font-size: 20px; cursor: pointer; padding: 0 4px; } .signal-modal-content { padding: 16px; max-height: 400px; overflow-y: auto; } .signal-item { padding: 12px; margin-bottom: 12px; background: var(--darken-heavy); border-left: 3px solid var(--accent); border-radius: 2px; } .signal-item:last-child { margin-bottom: 0; } .signal-item.velocity_spike { border-left-color: var(--red); } .signal-item.keyword_spike { border-left-color: var(--semantic-high); } .signal-item.prediction_leads_news { border-left-color: var(--yellow); } .signal-item.silent_divergence { border-left-color: var(--green); } .signal-item.convergence { border-left-color: var(--defcon-4); } .signal-item.triangulation { border-left-color: var(--semantic-high); } .signal-item.flow_drop { border-left-color: var(--semantic-info); } .signal-item.flow_price_divergence { border-left-color: var(--semantic-normal); } .signal-type { font-size: 10px; text-transform: uppercase; color: var(--text-dim); margin-bottom: 4px; } .signal-title { font-weight: bold; font-size: 13px; color: var(--text); margin-bottom: 6px; } .signal-description { font-size: 12px; color: var(--text); line-height: 1.4; margin-bottom: 8px; } .signal-actions { margin-top: 8px; } .suppress-keyword-btn { border: 1px solid rgba(255, 140, 66, 0.5); background: rgba(255, 140, 66, 0.12); color: var(--semantic-high); font-size: 11px; padding: 4px 8px; border-radius: 4px; cursor: pointer; } .suppress-keyword-btn:hover { background: rgba(255, 140, 66, 0.2); } .signal-meta { display: flex; gap: 12px; font-size: 10px; color: var(--text-dim); } .signal-confidence { color: var(--accent); } .signal-topics { display: flex; gap: 4px; flex-wrap: wrap; margin-top: 8px; } .signal-topic { font-size: 9px; padding: 2px 6px; background: rgba(0, 170, 255, 0.15); color: var(--accent); border-radius: 8px; } .signal-modal-footer { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; border-top: 1px solid var(--panel-border); } .signal-audio-toggle { display: flex; align-items: center; gap: 6px; font-size: 11px; color: var(--text-dim); cursor: pointer; } .signal-dismiss-btn { background: var(--accent); border: none; color: var(--bg); padding: 6px 16px; font-size: 11px; cursor: pointer; border-radius: 2px; text-transform: uppercase; letter-spacing: 0.5px; } .signal-dismiss-btn:hover { opacity: 0.9; } /* Header flash for signals */ .header.signal-flash { position: relative; overflow: hidden; isolation: isolate; } .header.signal-flash::after { content: ''; position: absolute; inset: 0; background: rgba(0, 170, 255, 0.3); opacity: 0; pointer-events: none; /* Negative z-index keeps the flash tint behind all header content without promoting every child to its own stacking layer (which could reorder siblings that rely on natural DOM paint order). isolation: isolate on the host bounds this so the overlay can't fall behind the header itself. */ z-index: -1; animation: header-flash 0.5s ease-out 3; } @keyframes header-flash { 0%, 100% { opacity: 0; } 50% { opacity: 1; } } /* Playback Control */ .playback-control { position: relative; } .playback-toggle { background: var(--panel-bg); border: 1px solid var(--panel-border); color: var(--text-dim); padding: 4px 8px; font-size: 12px; cursor: pointer; border-radius: 2px; } .playback-toggle:hover { color: var(--accent); border-color: var(--accent); } .playback-panel { position: absolute; top: 100%; right: 0; margin-top: 8px; background: var(--panel-bg); border: 1px solid var(--accent); border-radius: 4px; width: 280px; z-index: 100; box-shadow: 0 4px 20px var(--shadow-color); } .playback-panel.hidden { display: none; } .playback-header { display: flex; justify-content: space-between; align-items: center; padding: 8px 12px; border-bottom: 1px solid var(--panel-border); font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--accent); } .playback-close { background: none; border: none; color: var(--text-dim); font-size: 16px; cursor: pointer; padding: 0; } .playback-slider-container { padding: 12px; } .playback-slider { width: 100%; height: 4px; -webkit-appearance: none; appearance: none; background: var(--panel-border); border-radius: 2px; outline: none; } .playback-slider::-webkit-slider-thumb { -webkit-appearance: none; width: 12px; height: 12px; background: var(--accent); border-radius: 50%; cursor: pointer; } .playback-time { text-align: center; margin-top: 8px; font-size: 12px; color: var(--green); font-weight: bold; } .playback-time.historical { color: var(--yellow); } .playback-controls { display: flex; justify-content: center; gap: 4px; padding: 8px 12px 12px; } .playback-btn { background: var(--panel-border); border: none; color: var(--text); padding: 6px 10px; font-size: 10px; cursor: pointer; border-radius: 2px; } .playback-btn:hover { background: var(--accent); color: var(--bg); } .playback-btn.playback-live { background: var(--green); color: var(--bg); font-weight: bold; } .playback-btn.playback-live.active { background: var(--green); } /* Playback mode indicator */ body.playback-mode .header { border-bottom: 2px solid var(--yellow); } body.playback-mode .status-dot { background: var(--yellow); animation: none; } /* Map */ .map-container { width: 100%; height: 100%; position: relative; overflow: hidden; background: var(--map-bg); contain: layout paint; /* Let the map library handle all touch gestures (pinch-zoom, pan) instead of the browser intercepting them on mobile/Android */ touch-action: none; } .map-container.map-renderer-shell { contain: layout paint; background: radial-gradient(circle at 52% 48%, color-mix(in srgb, var(--map-stroke, #5ea7d7) 46%, transparent) 0 1px, transparent 2px), linear-gradient(180deg, color-mix(in srgb, var(--map-grid, #6da9cc) 40%, transparent), transparent 46%), var(--map-bg, #06111f); } .map-renderer-shell-surface { position: absolute; inset: 0; overflow: hidden; pointer-events: none; background: radial-gradient(ellipse at 50% 54%, color-mix(in srgb, var(--map-country, #446f8a) 82%, transparent) 0 28%, transparent 29%), linear-gradient(90deg, transparent 0 23%, color-mix(in srgb, var(--map-grid, #6da9cc) 48%, transparent) 24% 24.5%, transparent 25% 49%, color-mix(in srgb, var(--map-grid, #6da9cc) 48%, transparent) 50% 50.5%, transparent 51% 74%, color-mix(in srgb, var(--map-grid, #6da9cc) 48%, transparent) 75% 75.5%, transparent 76%), linear-gradient(0deg, transparent 0 23%, color-mix(in srgb, var(--map-grid, #6da9cc) 48%, transparent) 24% 24.5%, transparent 25% 49%, color-mix(in srgb, var(--map-grid, #6da9cc) 48%, transparent) 50% 50.5%, transparent 51% 74%, color-mix(in srgb, var(--map-grid, #6da9cc) 48%, transparent) 75% 75.5%, transparent 76%); opacity: 0.9; } .map-renderer-shell-surface::before, .map-renderer-shell-surface::after { content: ''; position: absolute; inset: 18% 12%; border: 1px solid color-mix(in srgb, var(--map-stroke, #5ea7d7) 62%, transparent); border-radius: 50%; } .map-renderer-shell-surface::after { inset: 28% 4%; border-color: color-mix(in srgb, var(--map-grid, #6da9cc) 58%, transparent); } .map-wrapper { width: 100%; height: 100%; transition: transform 0.3s ease; position: relative; transform-origin: 0 0; } .map-cluster-canvas { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; } #mapOverlays { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; contain: layout paint; } #mapOverlays>* { pointer-events: auto; } .map-flash { position: absolute; width: 12px; height: 12px; margin: -6px 0 0 -6px; border-radius: 50%; background: rgba(0, 255, 170, 0.85); box-shadow: 0 0 14px rgba(0, 255, 170, 0.9); pointer-events: none; animation: mapFlashPulse var(--flash-duration, 2000ms) ease-out forwards; } .map-flash::after { content: ''; position: absolute; inset: -14px; border-radius: 50%; border: 2px solid rgba(0, 255, 170, 0.7); animation: mapFlashRing var(--flash-duration, 2000ms) ease-out forwards; } @keyframes mapFlashPulse { 0% { transform: scale(0.6); opacity: 1; } 100% { transform: scale(2.6); opacity: 0; } } @keyframes mapFlashRing { 0% { transform: scale(0.4); opacity: 0.9; } 100% { transform: scale(3.6); opacity: 0; } } .map-svg { display: block; width: 100%; height: 100%; } .map-controls { position: absolute; top: 10px; right: 10px; display: flex; flex-direction: column; gap: 4px; z-index: 500; pointer-events: auto; } .map-control-btn { width: 28px; height: 28px; background: var(--bg); border: 1px solid var(--border); color: var(--text); font-size: 14px; cursor: pointer; display: flex; align-items: center; justify-content: center; } .map-control-btn:hover { background: var(--border); } .map-clear-trails-btn { padding: 4px 10px; font-size: 10px; font-weight: 600; color: var(--text); background: color-mix(in srgb, var(--bg) 85%, transparent); border: 1px solid var(--border); border-radius: 4px; cursor: pointer; white-space: nowrap; } .map-clear-trails-btn:hover { background: var(--border); } .time-slider { position: absolute; top: 10px; left: 10px; display: flex; align-items: center; gap: 8px; z-index: 100; background: var(--bg); padding: 6px 10px; border: 1px solid var(--border); border-radius: 4px; } .time-slider-label { font-size: 9px; color: var(--text-dim); letter-spacing: 1px; font-weight: bold; } .time-slider-buttons { display: flex; gap: 2px; } .time-btn { padding: 3px 6px; background: transparent; border: 1px solid var(--border); color: var(--text-dim); font-family: inherit; font-size: 9px; cursor: pointer; transition: all 0.2s ease; } .time-btn:hover { border-color: var(--primary); color: var(--primary); } .time-btn.active { background: var(--primary); border-color: var(--primary); color: var(--bg); font-weight: bold; } .layer-toggles:not(.deckgl-layer-toggles) { position: absolute; bottom: 10px; left: 10px; display: flex; gap: 4px; flex-wrap: wrap; z-index: 100; max-width: 300px; } .layer-toggles:not(.deckgl-layer-toggles) .layer-toggle-row { display: flex; align-items: stretch; gap: 2px; min-width: 0; } .layer-toggles:not(.deckgl-layer-toggles) .layer-toggle { padding: 3px 8px; background: var(--bg); border: 1px solid var(--border); color: var(--text-dim); font-family: inherit; font-size: 9px; cursor: pointer; text-transform: uppercase; position: relative; transition: color 0.2s ease, border-color 0.2s ease, opacity 0.2s ease; } .layer-toggles:not(.deckgl-layer-toggles) .layer-toggle-row .layer-toggle { flex: 1 1 auto; min-width: 0; } .layer-toggles:not(.deckgl-layer-toggles) .layer-toggle.active { color: var(--green); border-color: var(--green); } .layer-toggles:not(.deckgl-layer-toggles) .layer-toggle.auto-hidden { color: var(--text-dim); border-color: var(--overlay-heavy); } .layer-toggles:not(.deckgl-layer-toggles) .layer-toggle.auto-hidden::after { content: 'AUTO'; position: absolute; top: -6px; right: 2px; font-size: 6px; letter-spacing: 0.4px; color: var(--text-dim); opacity: 0.7; } .layer-toggles:not(.deckgl-layer-toggles) .layer-toggle.loading { animation: layer-loading 0.8s ease-in-out infinite; border-color: var(--yellow); color: var(--yellow); } .layer-toggles:not(.deckgl-layer-toggles) .layer-explain-btn { width: 18px; min-width: 18px; padding: 0; background: var(--bg); border: 1px solid var(--border); border-radius: 50%; color: var(--text-dim); font-family: inherit; font-size: 9px; font-weight: 700; cursor: pointer; transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease; } .layer-toggles:not(.deckgl-layer-toggles) .layer-explain-btn.has-layer-explanation { color: var(--accent); border-color: rgba(0, 212, 255, 0.45); } .layer-toggles:not(.deckgl-layer-toggles) .layer-explain-btn:hover, .layer-toggles:not(.deckgl-layer-toggles) .layer-explain-btn:focus-visible, .layer-toggles:not(.deckgl-layer-toggles) .layer-explain-btn.active { color: var(--green); border-color: var(--green); background: var(--overlay-subtle); outline: none; } @keyframes layer-loading { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } } .layer-help-btn { /* WCAG 2.5.8 / issue #3112: 48x48 hit area. margin:-12px 0 keeps the box flush with its toggle-header siblings while ::before (inset:12px) renders the visible 24px circle centred inside the 48px clickable target. */ position: relative; width: 48px; height: 48px; margin: -12px 0; padding: 0; background: transparent; border: 0; border-radius: 50%; color: var(--text-dim); font-family: inherit; font-size: 11px; font-weight: bold; cursor: pointer; transition: all 0.2s ease; display: flex; align-items: center; justify-content: center; } .layer-help-btn::before { content: ''; position: absolute; inset: 12px; background: var(--bg); border: 1px solid var(--border); border-radius: 50%; pointer-events: none; } .layer-help-btn:hover { color: var(--accent); } .layer-help-btn:hover::before { border-color: var(--accent); } .layer-help-popup { position: absolute; bottom: 40px; left: 10px; width: 360px; max-height: 70vh; background: var(--bg); border: 1px solid var(--border); border-radius: 4px; z-index: 200; overflow: hidden; box-shadow: 0 8px 32px var(--shadow-color); } .layer-help-header { display: flex; align-items: center; justify-content: space-between; padding: 10px 12px; background: var(--bg); border-bottom: 1px solid var(--border); font-size: 11px; font-weight: bold; text-transform: uppercase; letter-spacing: 1px; color: var(--accent); } .layer-help-close { width: 20px; height: 20px; padding: 0; background: transparent; border: none; color: var(--text-dim); font-size: 16px; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: color 0.2s; } .layer-help-close:hover { color: var(--accent); } .layer-help-content { padding: 8px; overflow-y: auto; max-height: calc(70vh - 45px); } .layer-help-section { margin-bottom: 12px; } .layer-help-section:last-child { margin-bottom: 4px; } .layer-help-title { font-size: 9px; font-weight: bold; text-transform: uppercase; letter-spacing: 1px; color: var(--green); margin-bottom: 6px; padding-left: 4px; border-left: 2px solid var(--green); } .layer-help-item { display: flex; gap: 8px; font-size: 10px; color: var(--text-dim); padding: 4px 6px; line-height: 1.4; } .layer-help-item span { flex-shrink: 0; min-width: 80px; font-weight: bold; color: var(--accent); font-size: 9px; } .layer-help-item:hover { background: var(--overlay-subtle); } .layer-help-note { font-size: 9px; color: var(--yellow); font-style: italic; padding: 2px 6px; margin-top: 2px; opacity: 0.8; } .hotspot { position: absolute; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; pointer-events: auto; cursor: pointer; z-index: 50; } .hotspot-marker { width: 12px; height: 12px; border-radius: 50%; background: var(--yellow); border: 2px solid var(--bg); box-shadow: 0 0 8px var(--yellow); } .hotspot-marker.high { background: var(--red); box-shadow: 0 0 12px var(--red); animation: pulse-red 1s infinite; } .hotspot-marker.elevated { background: var(--yellow); box-shadow: 0 0 10px var(--yellow); } .hotspot-label { position: absolute; top: 16px; left: 50%; transform: translateX(-50%) scale(calc(var(--label-scale, 1) / var(--marker-scale, 1))); transform-origin: top center; white-space: nowrap; font-size: 8px; color: var(--text); text-shadow: 0 0 4px var(--bg), 0 0 8px var(--bg); text-transform: uppercase; letter-spacing: 1px; } .hotspot-breaking { position: absolute; bottom: 18px; left: 50%; transform: translateX(-50%); white-space: nowrap; font-size: 7px; font-weight: bold; color: var(--bg); background: var(--red); padding: 1px 4px; letter-spacing: 0.5px; animation: pulse-breaking 0.8s ease-in-out infinite; } @keyframes pulse-breaking { 0%, 100% { opacity: 1; } 50% { opacity: 0.6; } } @keyframes pulse-red { 0%, 100% { opacity: 0.8; transform: scale(1); } 50% { opacity: 1; transform: scale(1.1); } } /* Cable paths */ .cable-path { fill: none; stroke: var(--status-live); stroke-width: 1.5; opacity: 0.6; filter: drop-shadow(0 0 3px var(--status-live)); cursor: pointer; pointer-events: stroke; transition: all 0.2s ease; } .cable-path:hover { stroke-width: 3; opacity: 1; filter: drop-shadow(0 0 8px var(--status-live)) drop-shadow(0 0 15px var(--status-live)); animation: cable-pulse 0.6s ease-in-out infinite; } .cable-path.cable-fault { stroke: var(--semantic-critical); filter: drop-shadow(0 0 4px var(--semantic-critical)); } .cable-path.cable-degraded { stroke: var(--semantic-elevated); filter: drop-shadow(0 0 4px var(--semantic-elevated)); } .cable-path.cable-health-fault { stroke: #ff3232; stroke-dasharray: 6 3; opacity: 0.9; filter: drop-shadow(0 0 5px #ff3232); animation: cable-health-fault-pulse 1.4s ease-in-out infinite; } .cable-path.cable-health-degraded { stroke: #ffa500; opacity: 0.8; filter: drop-shadow(0 0 4px #ffa500); } @keyframes cable-health-fault-pulse { 0%, 100% { opacity: 0.9; } 50% { opacity: 0.5; } } @keyframes cable-pulse { 0%, 100% { opacity: 1; stroke-width: 3; } 50% { opacity: 0.5; stroke-width: 4; } } /* Pipeline paths */ .pipeline-path { cursor: pointer; pointer-events: stroke; transition: all 0.2s ease; } .pipeline-path.pipeline-oil { filter: drop-shadow(0 0 3px var(--semantic-high)); } .pipeline-path.pipeline-gas { filter: drop-shadow(0 0 3px var(--defcon-4)); } .pipeline-path.pipeline-products { filter: drop-shadow(0 0 3px var(--semantic-elevated)); } .pipeline-path:hover { stroke-width: 4 !important; opacity: 1 !important; } .pipeline-path.pipeline-oil:hover { filter: drop-shadow(0 0 8px var(--semantic-high)) drop-shadow(0 0 15px var(--semantic-high)); } .pipeline-path.pipeline-gas:hover { filter: drop-shadow(0 0 8px var(--defcon-4)) drop-shadow(0 0 15px var(--defcon-4)); } .pipeline-path.pipeline-products:hover { filter: drop-shadow(0 0 8px var(--semantic-elevated)) drop-shadow(0 0 15px var(--semantic-elevated)); } /* Related asset highlights */ .asset-highlight { animation: asset-pulse 1.2s ease-in-out infinite; } .base-marker.asset-highlight, .datacenter-marker.asset-highlight, .nuclear-marker.asset-highlight { z-index: 30; box-shadow: 0 0 12px rgba(0, 255, 170, 0.6); } .pipeline-path.asset-highlight { stroke-width: 4.5 !important; filter: drop-shadow(0 0 10px var(--accent)); animation: asset-pulse-glow 1.2s ease-in-out infinite; } .cable-path.asset-highlight { stroke-width: 3.5; opacity: 1; filter: drop-shadow(0 0 10px rgba(0, 255, 170, 0.8)); animation: asset-pulse-glow 1.2s ease-in-out infinite; } @keyframes asset-pulse { 0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.05); opacity: 0.7; } } @keyframes asset-pulse-glow { 0%, 100% { opacity: 1; } 50% { opacity: 0.6; } } /* Pipeline popup header colors */ .popup-header.pipeline.oil { border-bottom-color: var(--semantic-high); } .popup-header.pipeline.gas { border-bottom-color: var(--defcon-4); } .popup-header.pipeline.products { border-bottom-color: var(--semantic-elevated); } /* Cable popup header */ .popup-header.cable { border-bottom-color: var(--status-live); } /* Cable advisory & repair ship markers */ .cable-advisory-marker, .repair-ship-marker { position: absolute; display: flex; flex-direction: column; align-items: center; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; cursor: pointer; z-index: 52; } .cable-advisory-marker.fault { --cable-advisory-color: var(--semantic-critical); animation: cable-advisory-pulse 1.4s ease-in-out infinite; } .cable-advisory-marker.degraded { --cable-advisory-color: var(--semantic-elevated); } .cable-advisory-icon { font-size: 14px; filter: drop-shadow(0 0 6px var(--cable-advisory-color, var(--semantic-critical))); } .cable-advisory-label { font-size: 8px; color: var(--cable-advisory-color, var(--semantic-critical)); text-transform: uppercase; letter-spacing: 0.4px; margin-top: 2px; white-space: nowrap; text-shadow: 0 0 4px var(--bg), 0 0 8px var(--bg); } .repair-ship-marker { --repair-ship-color: var(--semantic-low); } .repair-ship-marker.on-station { --repair-ship-color: var(--status-live); } .repair-ship-icon { font-size: 14px; filter: drop-shadow(0 0 6px var(--repair-ship-color, var(--semantic-low))); } .repair-ship-label { font-size: 8px; color: var(--repair-ship-color, var(--semantic-low)); text-transform: uppercase; letter-spacing: 0.4px; margin-top: 2px; white-space: nowrap; text-shadow: 0 0 4px var(--bg), 0 0 8px var(--bg); } @keyframes cable-advisory-pulse { 0%, 100% { opacity: 1; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); } 50% { opacity: 0.7; transform: translate(-50%, -50%) scale(calc(var(--marker-scale, 1) * 1.15)); } } /* Protest / Social Unrest markers */ .protest-marker { position: absolute; display: flex; flex-direction: column; align-items: center; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; cursor: pointer; z-index: 53; --protest-color: var(--semantic-high); } .protest-marker.low { --protest-color: var(--semantic-elevated); } .protest-marker.medium { --protest-color: var(--semantic-high); } .protest-marker.high { --protest-color: var(--semantic-critical); animation: protest-pulse 1.5s ease-in-out infinite; } .protest-marker.riot { --protest-color: var(--semantic-critical); } .protest-marker.validated { filter: drop-shadow(0 0 8px var(--protest-color)); } .protest-icon { font-size: 14px; color: var(--protest-color); filter: drop-shadow(0 0 4px var(--protest-color)); } .protest-label { font-size: 8px; color: var(--protest-color); text-transform: uppercase; letter-spacing: 0.4px; margin-top: 2px; white-space: nowrap; text-shadow: 0 0 4px var(--bg), 0 0 8px var(--bg); max-width: 80px; overflow: hidden; text-overflow: ellipsis; } .protest-marker.cluster .protest-icon { font-size: 16px; } .protest-marker.cluster .cluster-badge { position: absolute; top: -4px; right: -8px; background: var(--protest-color); color: var(--bg); font-size: 9px; font-weight: bold; padding: 1px 4px; border-radius: 8px; min-width: 14px; text-align: center; box-shadow: 0 1px 3px var(--shadow-color); } @keyframes protest-pulse { 0%, 100% { opacity: 1; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); } 50% { opacity: 0.8; transform: translate(-50%, -50%) scale(calc(var(--marker-scale, 1) * 1.2)); } } /* Datacenter cluster markers */ .datacenter-marker { position: absolute; display: flex; flex-direction: column; align-items: center; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; cursor: pointer; z-index: 54; --datacenter-color: var(--semantic-info); } .datacenter-marker.existing { --datacenter-color: var(--semantic-info); } .datacenter-marker.planned { --datacenter-color: var(--semantic-low); } .datacenter-marker:hover { transform: translate(-50%, -50%) scale(calc(var(--marker-scale, 1) * 1.2)); } .datacenter-icon { font-size: 16px; filter: drop-shadow(0 0 6px var(--datacenter-color)); } .datacenter-label { font-size: 8px; color: var(--datacenter-color); text-transform: uppercase; letter-spacing: 0.4px; margin-top: 2px; white-space: nowrap; text-shadow: 0 0 4px var(--bg), 0 0 8px var(--bg); max-width: 80px; overflow: hidden; text-overflow: ellipsis; } .datacenter-marker.cluster .datacenter-icon { font-size: 20px; } .datacenter-marker.cluster .cluster-badge { position: absolute; top: -4px; right: -8px; background: var(--datacenter-color); color: var(--bg); font-size: 9px; font-weight: bold; padding: 1px 4px; border-radius: 8px; min-width: 14px; text-align: center; box-shadow: 0 1px 3px var(--shadow-color); } /* Popup styles for datacenter clusters */ .popup-header.datacenter.cluster { background: rgba(153, 102, 255, 0.08); } /* Popup styles for protests */ .popup-header.protest { background: color-mix(in srgb, var(--protest-color, var(--semantic-high)) 8%, transparent); } .popup-header.protest.high { --protest-color: var(--semantic-critical); } .popup-header.protest.medium { --protest-color: var(--semantic-high); } .popup-header.protest.low { --protest-color: var(--semantic-elevated); } .popup-icon { font-size: 13px; margin-right: 2px; opacity: 0.7; flex-shrink: 0; } .popup-badge.verified { color: var(--semantic-normal); background: none; } .popup-badge.verified::before { background: var(--semantic-normal); } .popup-tags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 8px; } .popup-tag { background: var(--panel-bg); border: 1px solid var(--border); border-radius: 3px; padding: 2px 6px; font-size: 9px; text-transform: uppercase; color: var(--text-muted); } .popup-related { margin-top: 8px; font-size: 10px; color: var(--text-muted); font-style: italic; } .stat-value.alert { color: var(--semantic-critical); font-weight: bold; } /* Internet Outage markers */ .outage-marker { position: absolute; display: flex; flex-direction: column; align-items: center; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; cursor: pointer; z-index: 51; } .outage-marker.partial { --outage-color: var(--semantic-elevated); } .outage-marker.major { --outage-color: var(--semantic-high); } .outage-marker.total { --outage-color: var(--semantic-critical); animation: outage-pulse 1.5s ease-in-out infinite; } .outage-icon { font-size: 14px; filter: drop-shadow(0 0 4px var(--outage-color, var(--semantic-elevated))); } .outage-label { font-size: 8px; color: var(--outage-color, var(--semantic-elevated)); white-space: nowrap; text-transform: uppercase; letter-spacing: 0.5px; margin-top: 2px; text-shadow: 0 0 4px var(--bg), 0 0 8px var(--bg); } @keyframes outage-pulse { 0%, 100% { opacity: 1; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); } 50% { opacity: 0.6; transform: translate(-50%, -50%) scale(calc(var(--marker-scale, 1) * 1.2)); } } /* Outage popup header */ .popup-header.outage.total { border-bottom-color: var(--semantic-critical); } .popup-header.outage.major { border-bottom-color: var(--semantic-high); } .popup-header.outage.partial { border-bottom-color: var(--semantic-elevated); } /* Conflict zones */ .conflict-zone { fill: rgba(var(--semantic-critical), 0.2); stroke: var(--red); stroke-width: 1; stroke-dasharray: 4, 2; animation: pulse-conflict 2s ease-in-out infinite; transition: opacity 0.2s ease; } .conflict-event-marker { position: absolute; width: 9px; height: 9px; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; border-radius: 50%; background: rgba(255, 68, 68, 0.78); border: 1px solid rgba(255, 210, 210, 0.9); box-shadow: 0 0 9px rgba(255, 68, 68, 0.75); pointer-events: auto; z-index: 55; } .conflict-event-marker.fatal { background: rgba(255, 20, 20, 0.9); width: 11px; height: 11px; } .conflict-event-marker.cluster { width: 18px; height: 18px; display: grid; place-items: center; color: #fff; font-size: 9px; font-weight: 700; } .conflict-event-count { transform: scale(calc(1 / var(--marker-scale, 1))); } .conflict-label { fill: var(--red); font-size: 9px; font-weight: bold; text-transform: uppercase; letter-spacing: 1px; text-shadow: 0 0 4px var(--bg), 0 0 8px var(--bg), 0 0 12px var(--bg); pointer-events: none; display: none; /* Replaced by HTML overlay */ } .conflict-label-overlay { position: absolute; transform: translate(-50%, -50%) scale(var(--label-scale, 1)); transform-origin: center; color: var(--red); font-size: 10px; font-weight: bold; text-transform: uppercase; letter-spacing: 1px; text-shadow: 0 0 4px var(--bg), 0 0 8px var(--bg), 0 0 12px var(--bg); cursor: pointer; white-space: nowrap; z-index: 55; transition: opacity 0.2s ease; } .conflict-label-overlay:hover { color: var(--semantic-critical); text-shadow: 0 0 6px var(--bg), 0 0 12px var(--bg), 0 0 18px var(--red); } @keyframes pulse-conflict { 0%, 100% { fill: rgba(255, 68, 68, 0.15); } 50% { fill: rgba(255, 68, 68, 0.3); } } /* Base markers */ .base-marker { position: absolute; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; width: 8px; height: 8px; border-radius: 50%; z-index: 51; cursor: pointer; transition: opacity 0.2s ease, transform 0.2s ease; } .base-marker:hover { transform: translate(-50%, -50%) scale(calc(var(--marker-scale, 1) * 1.3)); } .base-marker.us-nato { background: var(--semantic-low); box-shadow: 0 0 6px var(--semantic-low); } .base-marker.china { background: var(--semantic-high); box-shadow: 0 0 6px var(--semantic-high); } .base-marker.russia { background: var(--semantic-critical); box-shadow: 0 0 6px var(--semantic-critical); } /* UK - Union Jack blue */ .base-marker.uk { background: var(--semantic-low); box-shadow: 0 0 6px var(--semantic-low); } /* France - French blue */ .base-marker.france { background: var(--semantic-info); box-shadow: 0 0 6px var(--semantic-info); } /* India - Saffron orange */ .base-marker.india { background: var(--semantic-high); box-shadow: 0 0 6px var(--semantic-high); } /* Italy - Italian green */ .base-marker.italy { background: #009246; box-shadow: 0 0 6px #009246; } /* UAE - Emirates green */ .base-marker.uae { background: #00732f; box-shadow: 0 0 6px #00732f; } /* Turkey - Turkish red */ .base-marker.turkey { background: #e30a17; box-shadow: 0 0 6px #e30a17; } /* Japan - Rising sun red */ .base-marker.japan { background: #bc002d; box-shadow: 0 0 6px #bc002d; } /* Other nations */ .base-marker.other { background: var(--text-dim); box-shadow: 0 0 6px var(--text-dim); } .base-label { position: absolute; top: 14px; left: 50%; transform: translateX(-50%) scale(calc(var(--label-scale, 1) * var(--marker-scale, 1))); transform-origin: top center; font-size: 8px; font-weight: 600; color: var(--text); text-shadow: 0 0 4px var(--bg), 0 0 8px var(--bg); white-space: nowrap; text-transform: uppercase; pointer-events: none; opacity: 0; transition: opacity 0.2s ease; } .base-marker:hover .base-label, .base-marker.active .base-label { opacity: 1; } .base-marker.us-nato .base-label { color: var(--semantic-low); } .base-marker.china .base-label { color: var(--semantic-high); } .base-marker.russia .base-label { color: var(--semantic-critical); } .base-marker.uk .base-label { color: var(--semantic-low); } .base-marker.france .base-label { color: var(--semantic-info); } .base-marker.india .base-label { color: var(--semantic-high); } .base-marker.italy .base-label { color: #009246; } .base-marker.uae .base-label { color: #00732f; } .base-marker.turkey .base-label { color: #e30a17; } .base-marker.japan .base-label { color: #bc002d; } .base-marker.other .base-label { color: var(--text-dim); } /* Port markers */ .port-marker { position: absolute; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; width: 10px; height: 10px; border-radius: 2px; z-index: 50; cursor: pointer; transition: opacity 0.2s ease, transform 0.2s ease; display: flex; align-items: center; justify-content: center; } .port-marker:hover { transform: translate(-50%, -50%) scale(calc(var(--marker-scale, 1) * 1.3)); } .port-marker.port-container { background: var(--semantic-normal); box-shadow: 0 0 6px var(--semantic-normal); } .port-marker.port-oil { background: #aa4422; box-shadow: 0 0 6px #aa4422; } .port-marker.port-lng { background: var(--semantic-high); box-shadow: 0 0 6px var(--semantic-high); } .port-marker.port-naval { background: var(--semantic-low); box-shadow: 0 0 6px var(--semantic-low); } .port-marker.port-mixed { background: var(--text-dim); box-shadow: 0 0 6px var(--text-dim); } .port-marker.port-bulk { background: var(--text-dim); box-shadow: 0 0 6px var(--text-dim); } .port-icon { display: none; } .port-label { position: absolute; top: 14px; left: 50%; transform: translateX(-50%) scale(calc(var(--label-scale, 1) * var(--marker-scale, 1))); transform-origin: top center; font-size: 7px; font-weight: 600; color: var(--text); text-shadow: 0 0 4px var(--bg), 0 0 8px var(--bg); white-space: nowrap; text-transform: uppercase; pointer-events: none; opacity: 0; transition: opacity 0.2s ease; } .port-marker:hover .port-label { opacity: 1; } .port-marker.port-container .port-label { color: var(--semantic-normal); } .port-marker.port-oil .port-label { color: #aa4422; } .port-marker.port-lng .port-label { color: var(--semantic-high); } .port-marker.port-naval .port-label { color: var(--semantic-low); } .port-marker.port-mixed .port-label { color: var(--text-dim); } .port-marker.port-bulk .port-label { color: var(--text-dim); } /* Iran event markers */ .iran-event-marker { position: absolute; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; border-radius: 50%; border: 1.5px solid rgba(255, 80, 80, 0.9); box-shadow: 0 0 8px rgba(255, 50, 50, 0.6); animation: quake-pulse 2s ease-in-out infinite; cursor: pointer; z-index: 54; transition: opacity 0.2s ease; } .iran-event-marker:hover { box-shadow: 0 0 14px rgba(255, 50, 50, 0.9); transform: translate(-50%, -50%) scale(calc(var(--marker-scale, 1) * 1.3)); } /* Earthquake markers */ .earthquake-marker { position: absolute; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; border-radius: 50%; background: rgba(255, 165, 0, 0.6); border: 2px solid var(--semantic-high); box-shadow: 0 0 10px rgba(255, 165, 0, 0.8); animation: quake-pulse 1.5s ease-in-out infinite; cursor: pointer; z-index: 53; transition: opacity 0.2s ease; } .earthquake-marker:hover { background: rgba(255, 165, 0, 0.9); } .earthquake-label { position: absolute; top: 100%; left: 50%; transform: translateX(-50%) scale(calc(var(--label-scale, 1) / var(--marker-scale, 1))); transform-origin: top center; white-space: nowrap; font-size: 8px; color: var(--semantic-high); text-shadow: 0 0 4px var(--bg), 0 0 8px var(--bg); font-weight: bold; margin-top: 2px; transition: opacity 0.2s ease; } @keyframes quake-pulse { 0%, 100% { opacity: 0.7; } 50% { opacity: 1; } } /* Natural Event markers (NASA EONET) */ .fire-dot { position: absolute; transform: translate(-50%, -50%); border-radius: 50%; opacity: 0.8; z-index: 53; pointer-events: none; box-shadow: 0 0 4px currentColor; } .nat-event-marker { position: absolute; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; display: flex; flex-direction: column; align-items: center; cursor: pointer; z-index: 54; transition: opacity 0.2s ease, transform 0.2s ease; } .nat-event-marker:hover { transform: translate(-50%, -50%) scale(calc(var(--marker-scale, 1) * 1.2)); } .nat-event-icon { font-size: 20px; filter: drop-shadow(0 0 4px var(--shadow-color)); } .nat-event-label { font-size: 8px; color: var(--accent); text-shadow: 0 0 4px var(--bg), 0 0 8px var(--bg); font-weight: bold; white-space: nowrap; margin-top: 2px; max-width: 120px; overflow: hidden; text-overflow: ellipsis; } .nat-event-magnitude { font-size: 7px; color: var(--yellow); text-shadow: 0 0 4px var(--bg); font-weight: bold; } /* Category-specific colors */ .nat-event-marker.severeStorms .nat-event-label { color: var(--semantic-low); } .nat-event-marker.wildfires .nat-event-label { color: var(--semantic-high); } .nat-event-marker.volcanoes .nat-event-label { color: var(--semantic-high); } .nat-event-marker.floods .nat-event-label { color: var(--semantic-info); } .nat-event-marker.landslides .nat-event-label { color: #8b4513; } .nat-event-marker.drought .nat-event-label { color: var(--semantic-elevated); } .nat-event-marker.dustHaze .nat-event-label { color: var(--text-dim); } .nat-event-marker.snow .nat-event-label { color: var(--semantic-low); } .nat-event-marker.tempExtremes .nat-event-label { color: var(--semantic-critical); } .nat-event-marker.seaLakeIce .nat-event-label { color: var(--semantic-low); } .nat-event-marker.waterColor .nat-event-label { color: var(--semantic-normal); } .nat-event-marker.manmade .nat-event-label { color: var(--semantic-info); } /* Popup header for natural events */ .popup-header.nat-event { background: rgba(255, 136, 0, 0.06); } .popup-header.nat-event .popup-title { color: var(--semantic-high); } .popup-header.nat-event.severeStorms { background: rgba(0, 191, 255, 0.06); } .popup-header.nat-event.severeStorms .popup-title { color: var(--semantic-low); } .popup-header.nat-event.wildfires { background: rgba(255, 102, 0, 0.08); } .popup-header.nat-event.wildfires .popup-title { color: var(--semantic-high); } .popup-header.nat-event.volcanoes { background: rgba(255, 51, 0, 0.08); } .popup-header.nat-event.volcanoes .popup-title { color: var(--semantic-high); } .popup-header.nat-event.floods { background: rgba(65, 105, 225, 0.06); } .popup-header.nat-event.floods .popup-title { color: var(--semantic-info); } /* Nuclear markers */ .nuclear-marker { position: absolute; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; width: 10px; height: 10px; border-radius: 2px; z-index: 52; cursor: pointer; transition: opacity 0.2s ease; } .nuclear-marker.active { background: var(--semantic-elevated); box-shadow: 0 0 8px var(--semantic-elevated), 0 0 16px var(--semantic-elevated); animation: nuclear-pulse 1.2s ease-in-out infinite; } .nuclear-marker.contested { background: var(--semantic-critical); box-shadow: 0 0 10px var(--semantic-critical), 0 0 20px var(--semantic-critical); animation: nuclear-alert 0.6s ease-in-out infinite; } .nuclear-marker.inactive { background: var(--text-muted); box-shadow: 0 0 4px var(--text-muted); } .nuclear-marker.decommissioned { background: var(--text-muted); box-shadow: 0 0 4px var(--text-muted); } .nuclear-marker.construction { background: var(--semantic-elevated); box-shadow: 0 0 4px var(--semantic-elevated); opacity: 0.6; } .nuclear-label { position: absolute; top: 14px; left: 50%; transform: translateX(-50%) scale(calc(var(--label-scale, 1) / var(--marker-scale, 1))); transform-origin: top center; white-space: nowrap; font-size: 7px; color: var(--semantic-elevated); text-shadow: 0 0 4px var(--bg), 0 0 8px var(--bg); font-weight: bold; text-transform: uppercase; transition: opacity 0.2s ease; } .nuclear-marker.contested .nuclear-label { color: var(--semantic-critical); } @keyframes nuclear-pulse { 0%, 100% { opacity: 0.8; } 50% { opacity: 1; } } @keyframes nuclear-alert { 0%, 100% { opacity: 0.7; } 50% { opacity: 1; } } /* Gamma Irradiators */ .irradiator-marker { position: absolute; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; width: 8px; height: 8px; border-radius: 50%; background: var(--status-live); box-shadow: 0 0 6px var(--status-live), 0 0 12px #00ffaa40; z-index: 51; cursor: pointer; border: 1px solid var(--semantic-normal); } .irradiator-marker:hover { background: var(--status-live); box-shadow: 0 0 10px var(--status-live), 0 0 20px #00ffaa60; } .irradiator-label { position: absolute; top: 12px; left: 50%; transform: translateX(-50%) scale(calc(var(--label-scale, 1) / var(--marker-scale, 1))); transform-origin: top center; white-space: nowrap; font-size: 6px; color: var(--status-live); text-shadow: 0 0 4px var(--bg), 0 0 8px var(--bg); font-weight: bold; text-transform: uppercase; opacity: 0.8; } .popup-header.irradiator { background: rgba(0, 68, 34, 0.08); } /* AI Data Centers */ .datacenter-marker { position: absolute; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; width: 12px; height: 12px; border-radius: 2px; background: var(--semantic-info); box-shadow: 0 0 8px #8844ff80, 0 0 16px #8844ff40; z-index: 52; cursor: pointer; border: 1px solid var(--semantic-info); display: flex; align-items: center; justify-content: center; } .datacenter-marker.existing { background: var(--semantic-info); border-color: var(--semantic-info); box-shadow: 0 0 8px #8844ff80, 0 0 16px #8844ff40; } .datacenter-marker.planned { background: transparent; border: 1px dashed var(--semantic-info); box-shadow: 0 0 8px #8844ff40; } .datacenter-marker:hover { background: var(--semantic-info); box-shadow: 0 0 12px var(--semantic-info), 0 0 24px #8844ff60; } .datacenter-marker.planned:hover { background: #8844ff40; } .datacenter-icon { font-size: 7px; line-height: 1; } .datacenter-label { position: absolute; top: 14px; left: 50%; transform: translateX(-50%) scale(calc(var(--label-scale, 1) / var(--marker-scale, 1))); transform-origin: top center; white-space: nowrap; font-size: 6px; color: var(--semantic-info); text-shadow: 0 0 4px var(--bg), 0 0 8px var(--bg); font-weight: bold; text-transform: uppercase; opacity: 0.8; max-width: 60px; overflow: hidden; text-overflow: ellipsis; } .popup-header.datacenter { background: rgba(51, 34, 85, 0.08); } .popup-header.datacenter.existing { background: rgba(59, 130, 246, 0.06); } .popup-header.datacenter.planned { background: rgba(234, 179, 8, 0.06); } /* Heatmap */ .heatmap { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; padding: 4px; } .heatmap-cell { padding: 10px 6px; text-align: center; border-radius: 2px; background: var(--border); display: flex; flex-direction: column; align-items: center; gap: 2px; } .heatmap-cell.up-3 { background: var(--map-country); } .heatmap-cell.up-2 { background: var(--map-country); } .heatmap-cell.up-1 { background: var(--map-country); } .heatmap-cell.down-1 { background: var(--surface); } .heatmap-cell.down-2 { background: var(--surface); } .heatmap-cell.down-3 { background: var(--surface); } .sector-ticker { font-size: 10px; font-weight: 700; color: var(--text-dim); letter-spacing: 0.05em; } .sector-name { font-size: 9px; color: var(--text-muted); margin-top: 1px; } .sector-change { font-size: 14px; font-weight: bold; line-height: 1; } .sector-change.up { color: var(--green); } .sector-change.down { color: var(--red); } /* Heatmap bar chart */ .heatmap-bar-chart { padding: 6px 4px 4px; display: flex; flex-direction: column; gap: 2px; } .heatmap-bar-row { display: grid; grid-template-columns: 36px 1fr 46px; align-items: center; gap: 4px; height: 18px; } .heatmap-bar-label { font-size: 10px; font-weight: 600; color: var(--text-dim); text-align: right; white-space: nowrap; } .heatmap-bar-track { height: 8px; background: var(--border); border-radius: 2px; overflow: hidden; } .heatmap-bar-fill { height: 100%; border-radius: 2px; transition: width 0.3s ease; } .heatmap-bar-value { font-size: 10px; font-weight: 600; text-align: right; white-space: nowrap; } .heatmap-bar-value.positive { color: var(--green); } .heatmap-bar-value.negative { color: var(--red); } /* Markets */ .market-item { display: flex; justify-content: space-between; align-items: center; padding: 8px 0; border-bottom: 1px solid var(--border); } .market-item:last-child { border-bottom: none; } .market-item-clickable { cursor: pointer; transition: background 0.12s ease; border-radius: 4px; margin: 0 -6px; padding-left: 6px; padding-right: 6px; } .market-item-clickable:hover, .market-item-clickable:focus-visible { background: var(--surface-active); outline: none; } /* Expandable Bloomberg-terminal-style price chart (market-chart-modal.ts). */ .market-chart-overlay { position: fixed; inset: 0; z-index: 10001; background: var(--overlay-medium); backdrop-filter: blur(8px); display: flex; align-items: center; justify-content: center; padding: 24px; } .market-chart-modal { position: relative; width: 566px; max-width: 100%; background: var(--bg-panel); border: 1px solid var(--border-strong); border-radius: 8px; padding: 20px 22px 16px; box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5); } .market-chart-close { position: absolute; top: 10px; right: 10px; background: transparent; border: none; color: var(--text-dim); cursor: pointer; padding: 4px; line-height: 0; border-radius: 4px; } .market-chart-close:hover { color: var(--text); background: var(--surface-active); } .market-chart-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 24px; margin-bottom: 8px; padding-right: 28px; } .market-chart-name { font-weight: 600; } .market-chart-symbol { color: var(--text-dim); font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; margin-top: 2px; } .market-chart-quote { display: flex; align-items: baseline; gap: 10px; } .market-chart-price { font-variant-numeric: tabular-nums; font-size: 15px; } .market-chart-canvas { width: 100%; line-height: 0; } .market-chart-canvas .terminal-chart { display: block; width: 100%; height: auto; } .market-info { display: flex; flex-direction: column; gap: 2px; } .market-name { font-size: 11px; color: var(--text); } .market-symbol { font-size: 9px; color: var(--text-dim); } .market-data { display: flex; align-items: center; gap: 6px; text-align: right; } .market-data .mini-sparkline { display: block; flex-shrink: 0; opacity: 0.8; } .market-price { font-size: 12px; font-weight: bold; color: var(--text); display: block; } .market-change { font-size: 10px; } .market-change.up { color: var(--green); } .market-change.down { color: var(--red); } .market-change--7d { opacity: 0.7; } .market-data-unavailable { padding: 8px 0; color: var(--text-dim); font-size: 10px; } .market-disclosures { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--border); } .market-disclosure-heading, .market-disclosure-meta, .market-disclosure-footer { display: flex; align-items: center; gap: 6px; } .market-disclosure-heading { justify-content: space-between; margin-bottom: 4px; color: var(--text); font-size: 10px; } .market-disclosure-heading span, .market-disclosure-meta, .market-disclosure-footer { color: var(--text-dim); font-size: 9px; } .market-disclosure-item { padding: 7px 0; border-bottom: 1px solid var(--border); } .market-disclosure-item:last-child { border-bottom: 0; } .market-disclosure-meta, .market-disclosure-footer { flex-wrap: wrap; } .market-disclosure-title { margin: 3px 0; color: var(--text); font-size: 10px; line-height: 1.35; } .market-disclosure-link { margin-left: auto; color: var(--accent); } /* Gulf Economies */ .gulf-section { margin-bottom: 8px; } .gulf-section:last-child { margin-bottom: 0; } .gulf-section-title { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-dim); padding: 6px 0 2px; border-bottom: 1px solid var(--border); margin-bottom: 2px; } /* Commodities */ .commodities-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; } .commodity-item { background: var(--border); padding: 8px; border-radius: 2px; } .commodity-name { font-size: 9px; color: var(--text-dim); text-transform: uppercase; } .commodity-price { font-size: 14px; font-weight: bold; color: var(--text); } .commodity-change { font-size: 10px; } .commodity-change.up { color: var(--green); } .commodity-change.down { color: var(--red); } .liquidity-shifts-panel { padding: 10px 14px; } .liquidity-shifts-panel__section-title { font-size: 11px; font-weight: 700; margin-bottom: 6px; } .liquidity-shifts-panel__section-title--gap { margin-top: 10px; } .liquidity-row { display: flex; justify-content: space-between; gap: 8px; align-items: center; padding: 8px 0; } .liquidity-row__values { text-align: right; } .liquidity-stock-row { display: flex; justify-content: space-between; } .liquidity-report-date { margin-top: 8px; text-align: right; } .commodity-item .mini-sparkline { display: block; margin: 2px 0; opacity: 0.8; } /* 24/7 Positioning Panel */ .pos-panel { padding: 10px 14px; } .pos-section { margin-bottom: 10px; } .pos-section__header { font-size: 10px; font-weight: 600; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 4px; } .pos-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; } .pos-card { background: var(--border); border-radius: 4px; padding: 8px 6px 6px; display: flex; flex-direction: column; align-items: center; text-align: center; transition: box-shadow 0.3s ease, border-color 0.3s ease; border: 1px solid transparent; } .pos-card--elevated { border-color: color-mix(in srgb, var(--pos-glow-color, #2ecc71) 40%, transparent); box-shadow: 0 0 8px color-mix(in srgb, var(--pos-glow-color, #2ecc71) 25%, transparent); } .pos-card--clickable { cursor: pointer; } .pos-card--clickable:hover { border-color: color-mix(in srgb, var(--pos-glow-color, var(--text-dim)) 60%, transparent); } .pos-card__name { font-size: 9px; font-weight: 600; color: var(--text-dim); text-transform: uppercase; margin-bottom: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; } .pos-gauge { display: block; margin: 0 auto; } .pos-card__metrics { display: flex; gap: 6px; font-size: 9px; margin-top: 2px; } .pos-badge { font-size: 8px; vertical-align: super; } .pos-badge--stale { color: #e67e22; } .pos-badge--warmup { color: #888; } .pos-warmup { padding: 6px 8px; background: rgba(230, 126, 34, 0.10); color: #e67e22; border-radius: 4px; font-size: 10px; margin-bottom: 8px; } .pos-footer { margin-top: 6px; font-size: 9px; color: var(--text-dim); text-align: right; } @media (max-width: 600px) { .pos-grid { grid-template-columns: repeat(2, 1fr); } } /* Predictions */ .prediction-item { padding: 14px 16px; border-bottom: 1px solid var(--border); border-left: 2px solid transparent; transition: background 0.15s ease; } .prediction-item:hover { background: rgba(255, 255, 255, 0.02); } .prediction-item:last-child { border-bottom: none; } .prediction-src-kalshi { border-left-color: var(--semantic-info, #3b82f6); } .prediction-src-polymarket { border-left-color: var(--accent, #8b5cf6); } .prediction-head { display: flex; align-items: flex-start; gap: 8px; margin-bottom: 8px; } .prediction-question { font-size: 13px; font-weight: 500; color: var(--text); line-height: 1.35; flex: 1; min-width: 0; } a.prediction-link { text-decoration: none; color: var(--text); font-size: 13px; font-weight: 500; line-height: 1.35; flex: 1; min-width: 0; } a.prediction-link:hover { color: var(--accent, var(--semantic-info)); text-decoration: underline; } .prediction-meta { display: flex; gap: 12px; align-items: center; margin-bottom: 10px; font-size: 11px; color: var(--muted); } .prediction-conviction { font-size: 8px; font-weight: 700; letter-spacing: 0.5px; padding: 2px 5px; border-radius: 3px; text-transform: uppercase; margin-left: auto; } .conviction-neutral { background: rgba(251, 191, 36, 0.12); color: #fbbf24; } .conviction-yes { background: rgba(74, 222, 128, 0.15); color: var(--green, #4ade80); } .conviction-no { background: rgba(248, 113, 113, 0.15); color: var(--red, #f87171); } .prediction-bar { height: 28px; border-radius: 6px; overflow: hidden; display: flex; } .prediction-yes { background: linear-gradient(135deg, rgba(74, 222, 128, 0.75) 0%, rgba(52, 211, 153, 0.6) 100%); display: flex; align-items: center; justify-content: center; min-width: 40px; transition: width 0.5s ease; border-right: 1px solid rgba(0, 0, 0, 0.15); } .prediction-no { background: linear-gradient(135deg, rgba(248, 113, 113, 0.6) 0%, rgba(239, 68, 68, 0.75) 100%); display: flex; align-items: center; justify-content: center; min-width: 40px; flex: 1; transition: width 0.5s ease; } .prediction-bar-strong.prediction-yes { background: linear-gradient(135deg, rgba(74, 222, 128, 0.9) 0%, rgba(52, 211, 153, 0.75) 100%); box-shadow: inset 0 0 12px rgba(74, 222, 128, 0.25); } .prediction-bar-strong.prediction-no { background: linear-gradient(135deg, rgba(248, 113, 113, 0.75) 0%, rgba(239, 68, 68, 0.9) 100%); box-shadow: inset 0 0 12px rgba(248, 113, 113, 0.25); } .prediction-label { font-size: 10px; font-weight: 700; color: var(--bg); text-shadow: 0 0 2px var(--overlay-heavy); white-space: nowrap; padding: 0 6px; } .prediction-source { flex-shrink: 0; font-size: 8px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.6px; padding: 3px 6px; border-radius: 3px; margin-top: 2px; border: 1px solid transparent; background: var(--border); color: var(--muted); } .prediction-source[data-source="kalshi"] { background: rgba(59, 130, 246, 0.12); color: #60a5fa; border-color: rgba(59, 130, 246, 0.25); } .prediction-source[data-source="polymarket"] { background: rgba(139, 92, 246, 0.12); color: #a78bfa; border-color: rgba(139, 92, 246, 0.25); } /* Monitors */ .monitor-input-container { margin-bottom: 12px; padding-bottom: 12px; border-bottom: 1px solid var(--border); } .monitor-input { width: 100%; padding: 8px; background: var(--bg); border: 1px solid var(--border); color: var(--text); font-family: inherit; font-size: 11px; margin-bottom: 8px; } .monitor-input::placeholder { color: var(--text-dim); } .monitor-add-btn { width: 100%; padding: 6px; background: var(--green); border: none; color: var(--bg); font-family: inherit; font-size: 10px; font-weight: bold; cursor: pointer; text-transform: uppercase; } .monitor-add-btn:hover { opacity: 0.9; } .monitor-tag { display: inline-flex; align-items: center; gap: 6px; padding: 4px 8px; background: var(--border); border-radius: 2px; margin: 2px; font-size: 10px; } .monitor-tag-color { width: 8px; height: 8px; border-radius: 50%; } .monitor-tag-remove { cursor: pointer; opacity: 0.6; } .monitor-tag-remove:hover { opacity: 1; } /* Loading */ .loading { display: flex; align-items: center; justify-content: center; height: 100%; color: var(--text-dim); font-size: 11px; } .loading::after { content: ''; width: 12px; height: 12px; border: 2px solid var(--border); border-top-color: var(--text); border-radius: 50%; animation: spin 1s linear infinite; margin-left: 8px; } @keyframes spin { to { transform: rotate(360deg); } } /* Unified Panel Loading - Radar Style */ .panel-loading { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 32px 16px; min-height: 120px; } .panel-loading-radar { width: 64px; height: 64px; margin-bottom: 16px; position: relative; border: 2px solid rgba(68, 255, 136, 0.3); border-radius: 50%; overflow: hidden; } .panel-radar-sweep { position: absolute; top: 50%; left: 50%; width: 50%; height: 2px; background: linear-gradient(90deg, transparent, var(--status-live)); transform-origin: left center; animation: panel-radar-sweep 2s linear infinite; } .panel-radar-dot { position: absolute; top: 50%; left: 50%; width: 6px; height: 6px; margin: -3px; background: var(--status-live); border-radius: 50%; box-shadow: 0 0 10px var(--status-live); } @keyframes panel-radar-sweep { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } .panel-loading-text { font-size: 12px; color: var(--accent); letter-spacing: 0.5px; } .panel-loading-text.retrying { color: var(--yellow, #f0c040); } /* Error */ .error-message { color: var(--text-dim); font-size: 10px; padding: 8px; text-align: center; } .panel-error-state { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; padding: 1.5rem 1rem; min-height: 120px; } .panel-error-radar { transform: scale(0.65); margin-bottom: -8px; opacity: 0.7; } .panel-error-radar .panel-radar-dot.error { background: var(--semantic-warning, #ff8844); box-shadow: 0 0 6px var(--semantic-warning, #ff8844); } .panel-error-countdown { font-size: 10px; color: var(--text-dim); opacity: 0.7; margin-top: 2px; } .panel-error-icon { font-size: 18px; color: var(--text-dim); opacity: 0.5; display: none; } .panel-error-msg { font-size: 11px; color: var(--text-dim); text-align: center; max-width: 180px; line-height: 1.4; } .panel-empty { display: flex; align-items: center; justify-content: center; padding: 24px 12px; min-height: 100px; font-size: 11px; color: var(--text-dim); text-align: center; opacity: 0.6; } .panel-error-retry-btn { margin-top: 4px; padding: 4px 10px; font-size: 10px; font-family: inherit; color: var(--accent); background: var(--overlay-light); border: 1px solid var(--border); border-radius: 4px; cursor: pointer; transition: background 0.15s, opacity 0.15s; } .panel-error-retry-btn:hover { background: var(--overlay-medium, rgba(255,255,255,0.08)); } .panel-error-retry-btn[disabled] { opacity: 0.5; cursor: not-allowed; } .config-error-message { color: var(--semantic-elevated); font-size: 10px; padding: 8px; text-align: center; line-height: 1.6; } .config-error-settings-btn { display: inline-block; margin-top: 6px; padding: 2px 10px; font-size: 9px; color: var(--semantic-elevated); background: rgba(255, 210, 124, 0.1); border: 1px solid rgba(255, 210, 124, 0.3); border-radius: 3px; cursor: pointer; font-family: inherit; } .config-error-settings-btn:hover { background: rgba(255, 210, 124, 0.2); } /* Modal */ .modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: var(--bg); display: none; align-items: center; justify-content: center; z-index: 9999; } .modal-overlay.active { display: flex; } .modal { background: var(--surface); border: 1px solid var(--border); padding: 20px; max-width: 500px; width: 90%; max-height: 80vh; overflow-y: auto; } .modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; } .modal-title { font-size: 14px; font-weight: bold; text-transform: uppercase; letter-spacing: 1px; } .modal-close { background: none; border: none; color: var(--text-dim); font-size: 20px; cursor: pointer; } .confirm-modal-message { margin: 0 0 16px; font-size: 14px; line-height: 1.5; } .confirm-modal-actions { display: flex; justify-content: flex-end; gap: 10px; } /* Pro Activation Interstitial (day-0 onboarding) — a larger, scrollable variant of .modal-overlay/.modal. Themes via the shared CSS variables. */ .pro-activation-overlay { z-index: 10000; /* above the standard 9999 modal layer */ } .pro-activation-modal { max-width: 640px; width: 92%; max-height: 85vh; padding: 0; display: flex; flex-direction: column; overflow: hidden; border-radius: 12px; } .pro-activation-header { flex-shrink: 0; padding: 18px 24px 14px; border-bottom: 1px solid var(--border); background: var(--bg-secondary); } .pro-activation-header-top { display: flex; align-items: center; gap: 12px; } .pro-activation-badge { font-size: 11px; font-weight: 800; letter-spacing: 1.5px; color: var(--bg); background: var(--green); padding: 3px 8px; border-radius: 4px; } .pro-activation-progress { font-size: 12px; letter-spacing: 0.5px; color: var(--text-dim); } .pro-activation-close { margin-left: auto; padding: 2px 4px; background: none; border: none; color: var(--text-dim); font-size: 18px; line-height: 1; cursor: pointer; } .pro-activation-close:hover { color: var(--text); } .pro-activation-account { margin: 8px 0 0; font-size: 12px; color: var(--text-muted); } .pro-activation-body { flex: 1; padding: 24px; overflow-y: auto; } .pro-activation-status { display: inline-block; margin-bottom: 14px; padding: 3px 8px; font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 1px; color: var(--text-dim); border: 1px solid var(--border); border-radius: 999px; } .pro-activation-status.status-verified { color: var(--green); background: color-mix(in srgb, var(--green) 12%, transparent); border-color: color-mix(in srgb, var(--green) 40%, transparent); } .pro-activation-status.status-failed { color: var(--semantic-critical); background: color-mix(in srgb, var(--semantic-critical) 12%, transparent); border-color: color-mix(in srgb, var(--semantic-critical) 40%, transparent); } .pro-activation-status.status-in-flight { color: var(--text-secondary); } .pro-activation-status.status-blocked, .pro-activation-status.status-unavailable { color: var(--semantic-high); border-color: color-mix(in srgb, var(--semantic-high) 40%, transparent); } .pro-activation-heading { margin: 0 0 10px; font-size: 20px; font-weight: 700; line-height: 1.25; color: var(--text); } .pro-activation-step-body { margin: 0 0 16px; font-size: 14px; line-height: 1.55; color: var(--text-secondary); } .pro-activation-note { margin: 0 0 14px; padding: 10px 12px; font-size: 13px; line-height: 1.5; color: var(--text-secondary); background: var(--overlay-light); border-left: 3px solid var(--border-strong); border-radius: 8px; } .pro-activation-note.note-ok { border-left-color: var(--green); } .pro-activation-note.note-warn { border-left-color: var(--semantic-high); } .pro-activation-note.note-error { border-left-color: var(--semantic-critical); } .pro-activation-note.note-muted { color: var(--text-dim); border-left-color: var(--border-strong); } .pro-activation-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 20px; } .pro-activation-summary-sub { margin: 0 0 18px; font-size: 14px; line-height: 1.5; color: var(--text-secondary); } .pro-activation-summary-list { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 12px; } .pro-activation-summary-line { display: flex; align-items: flex-start; gap: 12px; } .pro-activation-summary-icon { flex-shrink: 0; width: 22px; height: 22px; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; color: var(--text-dim); background: var(--overlay-light); border: 1px solid var(--border); border-radius: 999px; } .pro-activation-summary-line.status-verified .pro-activation-summary-icon { color: var(--bg); background: var(--green); border-color: var(--green); } .pro-activation-summary-line.status-failed .pro-activation-summary-icon { color: #fff; background: var(--semantic-critical); border-color: var(--semantic-critical); } .pro-activation-summary-text { display: flex; flex-direction: column; gap: 2px; } .pro-activation-summary-label { font-size: 14px; font-weight: 600; color: var(--text); } .pro-activation-summary-detail { font-size: 13px; line-height: 1.45; color: var(--text-dim); } .pro-activation-extras { margin: 0 0 16px; display: flex; flex-direction: column; gap: 14px; } .pro-activation-brief-preview { display: flex; flex-direction: column; gap: 4px; padding: 12px 14px; font-size: 13px; line-height: 1.5; color: var(--text-secondary); background: var(--overlay-light); border: 1px solid var(--border); border-radius: 8px; } .pro-activation-brief-preview-label { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 1px; color: var(--text-dim); } .pro-activation-brief-preview-text { color: var(--text); } .pro-activation-brief-hour { display: flex; align-items: center; gap: 10px; } .pro-activation-brief-hour-label { font-size: 13px; font-weight: 600; color: var(--text-secondary); } .pro-activation-hour-select { width: auto; } .pro-activation-pointers { display: flex; flex-direction: column; gap: 8px; } .pro-activation-pointer { display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%; padding: 12px 14px; font-size: 14px; font-weight: 600; text-align: left; color: var(--text); background: var(--overlay-light); border: 1px solid var(--border); border-radius: 8px; cursor: pointer; transition: border-color 0.15s ease, background 0.15s ease; } .pro-activation-pointer:hover { border-color: var(--green); background: color-mix(in srgb, var(--green) 8%, transparent); } .pro-activation-pointer:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; } .pro-activation-pointer-label { min-width: 0; } .pro-activation-pointer-shortcut { display: inline-flex; flex-shrink: 0; gap: 4px; } .pro-activation-pointer-shortcut kbd { min-width: 26px; padding: 4px 6px; border: 1px solid var(--border); border-bottom-color: var(--border-strong); border-radius: 4px; background: var(--bg); color: var(--green); font-family: inherit; font-size: 11px; font-weight: 800; line-height: 1; text-align: center; } .pro-activation-pointer-arrow { color: var(--text-dim); } .pro-activation-pointer-note { margin: 12px 0 0; font-size: 13px; line-height: 1.5; color: var(--text-dim); } .pro-activation-pointer-link { padding: 0; background: none; border: none; font-size: inherit; font-weight: 600; color: var(--green); cursor: pointer; } .pro-activation-pointer-link:hover { text-decoration: underline; } @media (max-width: 560px) { .pro-activation-modal { width: 100%; max-height: 100vh; border-radius: 0; } .pro-activation-actions { flex-direction: column-reverse; } .pro-activation-actions .btn { width: 100%; } } /* Standalone settings window (?settings=1) */ .settings-window-shell { min-height: 100vh; display: flex; flex-direction: column; background: var(--bg); color: var(--text); } .settings-window-header { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; border-bottom: 1px solid var(--border); background: var(--darken-heavy); flex-shrink: 0; } .settings-window-header-text { flex: 1; min-width: 0; } .settings-window-title { font-size: 14px; font-weight: bold; text-transform: uppercase; letter-spacing: 1px; display: block; } .settings-window-caption { margin: 4px 0 0; font-size: 12px; font-weight: normal; text-transform: none; letter-spacing: 0; color: var(--text-dim); line-height: 1.3; } .settings-window-shell .panel-toggle-grid { padding: 16px; flex: 1; } .panel-toggle-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; } .panel-toggle-item { display: flex; align-items: center; gap: 8px; padding: 8px; background: var(--bg); border: 1px solid var(--border); cursor: pointer; font: inherit; color: inherit; text-align: inherit; appearance: none; -webkit-appearance: none; border-radius: 0; } .panel-toggle-item:hover { border-color: var(--text-dim); } .panel-toggle-item.active { border-color: var(--green); } .panel-toggle-item.changed { background: rgba(68, 255, 136, 0.06); border-color: rgba(68, 255, 136, 0.35); } .panel-toggle-checkbox { width: 14px; height: 14px; border: 1px solid var(--border); display: flex; align-items: center; justify-content: center; font-size: 10px; } .panel-toggle-item.active .panel-toggle-checkbox { background: var(--green); border-color: var(--green); color: var(--bg); } .panel-toggle-label { font-size: 10px; text-transform: uppercase; } .panel-toggle-item.pro-locked { cursor: pointer; opacity: 0.5; } .panel-toggle-item.pro-locked:hover { opacity: 0.8; border-color: var(--green); } .panel-toggle-item.pro-locked .panel-toggle-checkbox { font-size: 9px; color: var(--text-dim); } .panel-toggle-pro-badge { margin-left: auto; font-size: 8px; font-weight: 700; letter-spacing: 0.05em; padding: 1px 4px; border: 1px solid var(--green); color: var(--green); opacity: 0.7; flex-shrink: 0; } /* Sources Modal */ .sources-modal { max-width: 600px; width: 95%; } .sources-counter { font-size: 11px; color: var(--text-dim); margin-left: auto; margin-right: 12px; } .sources-search, .panels-search { margin-bottom: 12px; } .sources-search input, .panels-search input { width: 100%; padding: 8px 10px; background: var(--bg); border: 1px solid var(--border); color: var(--text); font-family: inherit; font-size: 11px; } .sources-search input:focus, .panels-search input:focus { outline: none; border-color: var(--text-dim); } .sources-toggle-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; max-height: 50vh; overflow-y: auto; margin-bottom: 12px; } .source-toggle-item { display: flex; align-items: center; gap: 6px; padding: 6px 8px; background: var(--bg); border: 1px solid var(--border); cursor: pointer; font: inherit; color: inherit; text-align: inherit; appearance: none; -webkit-appearance: none; border-radius: 0; font-size: 10px; } .source-toggle-item:hover { border-color: var(--text-dim); } .source-toggle-item.active { border-color: var(--green); } .source-toggle-checkbox { width: 12px; height: 12px; border: 1px solid var(--border); display: flex; align-items: center; justify-content: center; font-size: 9px; flex-shrink: 0; } .source-toggle-item.active .source-toggle-checkbox { background: var(--green); border-color: var(--green); color: var(--bg); } .source-toggle-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .panels-footer { display: flex; align-items: center; gap: 8px; padding-top: 8px; } .panels-status { margin-right: auto; min-height: 14px; font-size: 11px; color: var(--green); opacity: 0; transition: opacity 0.15s ease; } .panels-status.visible { opacity: 1; } .panels-save-layout, .panels-reset-layout { padding: 6px 12px; background: var(--bg); border: 1px solid var(--border); color: var(--text); font-family: inherit; font-size: 10px; cursor: pointer; text-transform: uppercase; } .panels-save-layout { color: var(--green); border-color: rgba(68, 255, 136, 0.35); } .panels-save-layout:hover:not(:disabled) { background: rgba(68, 255, 136, 0.08); border-color: var(--green); } .panels-save-layout:disabled { color: var(--text-dim); border-color: var(--border); opacity: 0.6; cursor: default; } .panels-reset-layout:hover { border-color: var(--text-dim); } .sources-footer { display: flex; align-items: center; gap: 8px; } .sources-footer button { flex: 1; padding: 6px 12px; background: var(--bg); border: 1px solid var(--border); color: var(--text); font-family: inherit; font-size: 10px; cursor: pointer; text-transform: uppercase; } .sources-footer button:hover { border-color: var(--text-dim); } @media (max-width: 600px) { .sources-toggle-grid { grid-template-columns: repeat(2, 1fr); } } /* Accessibility Focus Styles */ .panel-toggle-item:focus-visible, .source-toggle-item:focus-visible { outline: 2px solid var(--text); outline-offset: 1px; border-color: var(--text-dim); } /* Map Popups */ .map-popup { position: fixed; width: 360px; max-height: min(560px, 80vh); background: var(--bg); border: 1px solid rgba(255, 255, 255, 0.06); border-radius: 6px; z-index: 1000; overflow-y: auto; box-shadow: 0 12px 40px rgba(0, 0, 0, 0.55), inset 0 1px 20px rgba(255, 255, 255, 0.02), 0 0 0 1px rgba(255, 255, 255, 0.03); } .map-popup.map-popup-sheet { left: 12px !important; right: 12px !important; top: auto !important; bottom: 0; width: auto !important; max-width: none; max-height: min(68vh, calc(100vh - 80px)); border-bottom: none; border-radius: 16px 16px 0 0; box-shadow: 0 -12px 32px rgba(0, 0, 0, 0.35); transform: translate3d(0, 110%, 0); transition: transform 0.22s ease-out; will-change: transform; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; } .map-popup.map-popup-sheet.open { transform: translate3d(0, 0, 0); } .map-popup.map-popup-sheet.dragging { transition: none; } .map-popup-sheet-handle { display: block; width: 56px; height: 24px; margin: 6px auto 2px; padding: 0; border: none; border-radius: 999px; background: transparent; cursor: pointer; position: sticky; top: 0; z-index: 3; } .map-popup-sheet-handle::before { content: ''; display: block; width: 36px; height: 4px; margin: 10px auto 0; border-radius: 999px; background: var(--text-dim); opacity: 0.8; } .popup-header { display: flex; align-items: center; gap: 8px; padding: 10px 14px; border-bottom: 1px solid rgba(255, 255, 255, 0.06); position: sticky; top: 0; z-index: 1; background: var(--bg); } .popup-header.iranEvent { background: rgba(255, 68, 68, 0.06); } .popup-header.iranEvent.high { background: rgba(255, 50, 50, 0.08); } .popup-header.iranEvent.medium { background: rgba(255, 165, 0, 0.08); } .popup-header.iranEvent.low { background: rgba(204, 204, 0, 0.06); } .popup-header.conflict { background: rgba(255, 68, 68, 0.06); } .popup-header.hotspot { background: rgba(68, 255, 136, 0.06); } .popup-header.earthquake { background: rgba(255, 165, 0, 0.06); } .popup-header.ais { background: rgba(0, 209, 255, 0.06); } .popup-title { font-size: 13px; font-weight: 700; color: var(--red); letter-spacing: 0.5px; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .popup-header.hotspot .popup-title { color: var(--green); } .popup-header.earthquake .popup-title { color: var(--semantic-high); } .popup-header.ais .popup-title { color: var(--defcon-4); } .popup-title.magnitude { font-size: 24px; } .popup-badge { display: flex; align-items: center; gap: 4px; padding: 0; font-size: 9px; font-weight: 700; letter-spacing: 0.8px; background: none; border-radius: 0; flex-shrink: 0; } .popup-badge::before { content: ''; width: 5px; height: 5px; border-radius: 50%; flex-shrink: 0; } .popup-badge.high { color: var(--red); background: none; } .popup-badge.high::before { background: var(--red); } .popup-badge.critical { color: var(--semantic-critical); background: none; } .popup-badge.critical::before { background: var(--semantic-critical); } .popup-badge.medium { color: var(--yellow); background: none; } .popup-badge.medium::before { background: var(--yellow); } .popup-badge.elevated { color: var(--yellow); background: none; } .popup-badge.elevated::before { background: var(--yellow); } .popup-badge.low { color: var(--text-muted); background: none; } .popup-badge.low::before { background: var(--text-muted); } .popup-close { background: none; border: none; color: var(--text-muted); font-size: 16px; cursor: pointer; padding: 0; width: 24px; height: 24px; min-width: 24px; min-height: 24px; line-height: 1; touch-action: manipulation; display: flex; align-items: center; justify-content: center; border-radius: 4px; transition: background 0.12s, color 0.12s; flex-shrink: 0; } .popup-close:hover { color: var(--text); background: rgba(255, 255, 255, 0.08); } .popup-body { padding: 12px 14px; } .map-popup.map-popup-sheet .popup-body { padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px)); } .popup-subtitle { font-size: 10px; color: var(--green); margin-bottom: 8px; letter-spacing: 0.4px; } .popup-description { font-size: 11px; line-height: 1.5; color: var(--text-secondary); margin-bottom: 10px; } .popup-location { font-size: 12px; color: var(--text); margin-bottom: 10px; } .popup-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 2px; margin-bottom: 10px; } .popup-stat { display: flex; flex-direction: column; gap: 2px; padding: 6px 8px; } .stat-label { font-size: 8px; color: var(--text-muted); letter-spacing: 0.7px; text-transform: uppercase; } .stat-value { font-size: 11px; color: var(--green); } .popup-section { margin-bottom: 10px; } .section-label { font-size: 8px; color: var(--text-muted); letter-spacing: 0.8px; display: block; margin-bottom: 5px; } .popup-hs2-ring-container { display: flex; flex-direction: row; align-items: center; gap: 12px; padding: 6px 0; } .popup-hs2-ring-canvas { display: block; flex-shrink: 0; } .popup-hs2-ring-legend { flex: 1; min-width: 0; } .popup-hs2-ring-legend-item { display: flex; align-items: center; gap: 6px; padding: 2px 0; font-size: 11px; } .popup-hs2-ring-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; } .popup-hs2-ring-label { flex: 1; color: var(--text-secondary, #cbd5e1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .popup-hs2-ring-pct { color: var(--text-muted, #64748b); font-size: 10px; } .sector-ring-wrap { display: flex; align-items: center; gap: 10px; padding: 4px 0; } .sector-legend { font-size: 11px; color: var(--text-secondary, #cbd5e1); line-height: 1.6; } .sector-legend-item { white-space: nowrap; } .sector-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 4px; vertical-align: middle; } /* Collapsible sections */ .popup-section details { border: none; } .popup-section details summary { font-size: 8px; text-transform: uppercase; letter-spacing: 0.8px; color: var(--text-muted); cursor: pointer; display: flex; align-items: center; gap: 4px; padding: 3px 0; list-style: none; user-select: none; transition: color 0.12s; } .popup-section details summary:hover { color: var(--text-secondary); } .popup-section details summary::-webkit-details-marker { display: none; } .popup-section details summary::before { content: '\25B6'; font-size: 7px; transition: transform 0.2s; } .popup-section details[open] summary::before { transform: rotate(90deg); } .popup-section details .popup-section-content { padding-top: 5px; } /* Popup separator line */ .popup-sep { height: 1px; background: rgba(255, 255, 255, 0.04); margin: 10px 0; } .evidence-list { margin: 4px 0 0; padding-left: 16px; font-size: 11px; color: var(--text-secondary); line-height: 1.5; } .evidence-item { margin-bottom: 4px; } .popup-tags { display: flex; flex-wrap: wrap; gap: 4px; } .popup-tag { padding: 2px 7px; background: rgba(255, 255, 255, 0.05); border: none; color: var(--text); font-size: 9px; font-weight: 600; border-radius: 3px; letter-spacing: 0.3px; } .popup-list { list-style: none; padding: 0; margin: 0; } .popup-list li { position: relative; padding-left: 12px; margin-bottom: 3px; font-size: 11px; color: var(--red); } .popup-list li::before { content: ''; position: absolute; left: 0; top: 7px; width: 4px; height: 4px; border-radius: 50%; background: var(--red); } .popup-news { display: flex; flex-direction: column; gap: 0; } .popup-news-item { display: flex; flex-direction: column; gap: 2px; padding: 5px 0; } .popup-news-item + .popup-news-item { border-top: 1px solid rgba(255, 255, 255, 0.03); } .popup-news-item .news-source { font-size: 9px; color: var(--red); text-transform: uppercase; letter-spacing: 0.5px; } .popup-news-item .news-title { font-size: 11px; color: var(--text); text-decoration: none; line-height: 1.4; } .popup-news-item .news-title:hover { color: var(--accent); } /* Vessel Popup Enhancements */ .popup-title-row { display: flex; align-items: center; gap: 6px; flex: 1; min-width: 0; } .hull-badge { font-size: 9px; font-weight: 600; color: var(--text-dim); background: var(--overlay-subtle); padding: 1px 4px; border-radius: 3px; white-space: nowrap; } .popup-badges { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; } .flag-icon { font-size: 1.25em; margin-right: 6px; vertical-align: middle; } .flag-icon-small { font-size: 1em; vertical-align: middle; } .usni-intel-section { background: rgba(255, 136, 0, 0.05); border: 1px solid rgba(255, 136, 0, 0.2); border-radius: 6px; padding: 10px; margin: 12px 0; } .section-header.usni { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; color: var(--semantic-high); } .section-header.usni .section-label { font-weight: 700; color: inherit; margin-bottom: 0; letter-spacing: 1px; } .usni-intel-content { display: flex; flex-direction: column; gap: 6px; } .usni-field { font-size: 11px; color: var(--text); } .usni-description { font-size: 11px; line-height: 1.5; color: var(--text-secondary); border-left: 2px solid rgba(255, 136, 0, 0.3); padding-left: 8px; margin: 4px 0; } .usni-source-row { margin-top: 4px; font-size: 10px; } .usni-link { color: var(--semantic-high); text-decoration: none; opacity: 0.8; transition: opacity 0.15s; } .usni-link:hover { opacity: 1; text-decoration: underline; } .vessel-history-list { display: flex; flex-direction: column; gap: 4px; } .vessel-history-item { display: flex; justify-content: space-between; align-items: center; padding: 4px 6px; background: rgba(255, 255, 255, 0.03); border-radius: 4px; font-size: 10px; } .history-point { color: var(--text-muted); font-family: monospace; } .history-tag { background: var(--overlay-light); color: var(--accent); padding: 1px 4px; border-radius: 3px; font-size: 9px; font-weight: 600; text-transform: uppercase; } .popup-stat.warning .stat-value { color: var(--semantic-high); font-weight: 600; } .popup-stat.full-width { grid-column: 1 / -1; } .popup-link { display: inline-block; color: var(--green); text-decoration: none; font-size: 11px; margin-top: 8px; } .popup-link:hover { text-decoration: underline; } .popup-source-links { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; } .popup-source-links .popup-link, .cluster-source-link { margin-top: 0; font-size: 10px; } /* Hotspot subtitles on map */ .hotspot-subtext { position: absolute; top: 24px; left: 50%; transform: translateX(-50%) scale(calc(var(--label-scale, 1) / var(--marker-scale, 1))); transform-origin: top center; white-space: nowrap; font-size: 7px; color: var(--yellow); text-shadow: 0 0 4px var(--bg), 0 0 8px var(--bg); font-style: italic; opacity: 0.8; } /* Strategic waterway markers */ .waterway-marker { position: absolute; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; cursor: pointer; z-index: 50; } .waterway-diamond { width: 10px; height: 10px; background: var(--status-live); transform: rotate(45deg); box-shadow: 0 0 6px rgba(0, 255, 170, 0.6); transition: all 0.2s ease; } .waterway-marker:hover .waterway-diamond { background: var(--status-live); box-shadow: 0 0 10px rgba(68, 255, 204, 0.8); transform: rotate(45deg) scale(1.2); } /* AIS disruptions */ .ais-disruption-marker { position: absolute; display: flex; flex-direction: column; align-items: center; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); cursor: pointer; z-index: 53; gap: 2px; } .ais-disruption-marker.high { --ais-color: var(--semantic-elevated); } .ais-disruption-marker.elevated { --ais-color: var(--semantic-elevated); } .ais-disruption-marker.low { --ais-color: var(--defcon-4); } .ais-disruption-icon { font-size: 16px; filter: drop-shadow(0 0 6px var(--ais-color, var(--defcon-4))); } .ais-disruption-label { font-size: 8px; text-transform: uppercase; letter-spacing: 0.6px; color: var(--ais-color, var(--defcon-4)); text-shadow: 0 0 4px var(--bg), 0 0 8px var(--bg); white-space: nowrap; } .ais-density-spot { pointer-events: none; mix-blend-mode: screen; filter: blur(0.2px); } /* APT markers */ .apt-marker { position: absolute; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; white-space: nowrap; cursor: pointer; z-index: 53; opacity: 0.7; } .apt-marker:hover { opacity: 1; } .apt-icon { font-size: 10px; color: var(--semantic-info); text-shadow: 0 0 4px var(--bg), 0 0 8px var(--bg); } .apt-label { font-size: 7px; color: var(--semantic-info); text-shadow: 0 0 4px var(--bg), 0 0 8px var(--bg); letter-spacing: 0.5px; transform: scale(calc(var(--label-scale, 1) / var(--marker-scale, 1))); transform-origin: top center; } /* Breaking tag */ .breaking-tag { position: absolute; white-space: nowrap; font-size: 8px; font-weight: bold; color: var(--bg); background: var(--red); padding: 2px 6px; border: 1px solid var(--red); letter-spacing: 0.5px; animation: pulse-breaking 0.8s ease-in-out infinite; z-index: 55; } /* Map grid lines */ .map-grid-line { stroke: rgba(0, 255, 136, 0.15); stroke-width: 0.5; fill: none; } .map-grid-label { font-size: 8px; fill: var(--text-dim); opacity: 0.5; } /* Map legend bar */ .map-legend { position: absolute; bottom: 8px; left: 50%; transform: translateX(-50%); display: flex; align-items: center; gap: 16px; padding: 6px 16px; background: var(--bg); border: 1px solid var(--border); font-size: 9px; color: var(--text-dim); letter-spacing: 0.5px; z-index: 100; } .map-legend-item { display: flex; align-items: center; gap: 6px; } .map-legend-icon { font-size: 10px; } .map-legend-icon.ship { color: var(--status-live); } .map-legend-icon.nuke { color: var(--semantic-elevated); } .map-legend-icon.base { color: var(--semantic-low); } .map-legend-icon.cable { color: var(--status-live); } .map-legend-icon.conflict { color: var(--semantic-critical); } .map-legend-icon.earthquake { color: var(--semantic-elevated); } .map-legend-icon.apt { color: var(--semantic-high); } .legend-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; } .legend-dot.high { background: var(--semantic-critical); box-shadow: 0 0 6px var(--semantic-critical); } .legend-dot.elevated { background: var(--semantic-elevated); box-shadow: 0 0 4px var(--semantic-elevated); } .legend-dot.low { background: var(--status-live); } .conflict-click-area { position: absolute; z-index: 50; transition: opacity 0.2s ease; } /* Map timestamp */ .map-timestamp { position: absolute; bottom: 8px; right: 10px; font-size: 9px; color: var(--text-dim); z-index: 100; } /* Signal Pulse on Status Dot */ .status-dot.signal-pulse { animation: signal-dot-pulse 0.5s ease-out 6; background: var(--defcon-4); position: relative; overflow: visible; } .status-dot.signal-pulse::after { content: ''; position: absolute; inset: -4px; border-radius: inherit; background: rgba(0, 170, 255, 0.45); opacity: 0; pointer-events: none; animation: signal-dot-pulse-glow 0.5s ease-out 6; } @keyframes signal-dot-pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.8); } } @keyframes signal-dot-pulse-glow { 0%, 100% { opacity: 0; } 50% { opacity: 1; } } /* Status Panel */ /* Status rows (used in settings status tab) */ .status-row { display: flex; align-items: center; gap: 8px; padding: 4px 0; font-size: 11px; } .status-row .status-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; } .status-row .status-dot.ok { background: var(--green); } .status-row .status-dot.warning { background: var(--yellow); } .status-row .status-dot.error { background: var(--red); } .status-row .status-dot.disabled { background: var(--text-faint); } .status-row:has(.status-dot.disabled) { opacity: 0.5; } .status-name { flex: 1; color: var(--text); } .status-detail { color: var(--text-dim); font-size: 10px; } .status-time { color: var(--text-dim); font-size: 10px; } /* Status tab inside Unified Settings */ .us-status-content { padding: 4px 0; max-height: 50vh; overflow-y: auto; } .us-status-section { padding: 8px 12px; } .us-status-section-title { font-size: 9px; color: var(--text-dim); text-transform: uppercase; margin-bottom: 6px; } .us-status-footer { padding: 6px 12px; border-top: 1px solid var(--border); font-size: 9px; color: var(--text-dim); } /* Export Panel */ .export-panel-container { position: relative; } .export-btn { background: transparent; border: 1px solid var(--border); color: var(--text-dim); padding: 4px 8px; font-size: 11px; cursor: pointer; border-radius: 3px; } .export-btn:hover { border-color: var(--accent); color: var(--accent); } .export-menu { position: absolute; top: 100%; right: 0; margin-top: 4px; background: var(--surface); border: 1px solid var(--border); border-radius: 4px; z-index: 1000; box-shadow: 0 4px 12px var(--shadow-color); min-width: 120px; } .export-menu.hidden { display: none; } .export-option { display: block; width: 100%; padding: 8px 12px; background: none; border: none; color: var(--text); font-size: 11px; text-align: left; cursor: pointer; } .export-option[hidden] { display: none; } .export-option:hover { background: var(--border); } .export-option:first-child { border-radius: 3px 3px 0 0; } .export-option:last-child { border-radius: 0 0 3px 3px; } .export-option.is-exporting { color: var(--text-dim); cursor: progress; } /* Locked export menu (plan 2026-07-25-001, U5) — one CTA row replaces the format options. Mirrors .panel-locked-state, sized for a header popover. */ .export-locked-state { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 8px; padding: 12px; max-width: 240px; } /* Shared by both compact locked surfaces (export menu row + tab-cap notice) so the gold treatment can't drift between them. Surface-specific layout stays with each surface's own block. */ .export-locked-icon, .tab-cap-notice-icon { color: #d4a843; filter: drop-shadow(0 0 8px rgba(212, 168, 67, 0.3)); line-height: 0; } .export-locked-desc, .tab-cap-notice-desc { font-size: 11px; line-height: 1.4; color: var(--text-dim, #888); } .export-locked-cta, .tab-cap-notice-cta { padding: 6px 14px; font-size: 11px; font-weight: 600; letter-spacing: 0.05em; color: #111; background: linear-gradient(135deg, #d4a843 0%, #b8902e 100%); border: none; border-radius: 4px; cursor: pointer; transition: filter 0.15s; } .export-locked-cta:hover, .tab-cap-notice-cta:hover { filter: brightness(1.15); } /* Off-screen live region: announces the async export unlock without painting. */ .wm-visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; } /* Weather Markers */ .weather-marker { position: absolute; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; cursor: pointer; display: flex; flex-direction: column; align-items: center; z-index: 60; } .weather-icon { font-size: 16px; color: var(--semantic-elevated); text-shadow: 0 0 4px rgba(255, 170, 0, 0.8); } .weather-marker.extreme .weather-icon { color: var(--semantic-critical); text-shadow: 0 0 6px rgba(255, 0, 0, 0.9); animation: weather-pulse 1s ease-in-out infinite; } .weather-marker.severe .weather-icon { color: var(--semantic-high); text-shadow: 0 0 5px rgba(255, 102, 0, 0.8); } .weather-marker.moderate .weather-icon { color: var(--semantic-elevated); } .weather-marker.minor .weather-icon { color: var(--semantic-elevated); } .weather-label { font-size: 8px; color: var(--text); background: var(--bg); padding: 1px 4px; border-radius: 2px; white-space: nowrap; max-width: 80px; overflow: hidden; text-overflow: ellipsis; transform: scale(calc(var(--label-scale, 1) / var(--marker-scale, 1))); transform-origin: top center; } @keyframes weather-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.6; } } /* Weather popup styles */ .popup-header.weather { background: color-mix(in srgb, var(--semantic-high) 8%, transparent); } .popup-header.weather.extreme { background: color-mix(in srgb, var(--semantic-critical) 10%, transparent); } .popup-header.weather.severe { background: color-mix(in srgb, var(--semantic-high) 8%, transparent); } .popup-header.weather.moderate { background: color-mix(in srgb, var(--semantic-elevated) 8%, transparent); } .popup-header.weather.minor { background: color-mix(in srgb, var(--semantic-elevated) 6%, transparent); } .popup-headline { font-weight: bold; margin-bottom: 8px; color: var(--text); } /* Economic Markers */ .economic-marker { position: absolute; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; cursor: pointer; display: flex; flex-direction: column; align-items: center; z-index: 50; opacity: 0.85; transition: opacity 0.2s ease; } .economic-marker:hover { opacity: 1; z-index: 100; } .economic-icon { font-size: 14px; filter: drop-shadow(0 0 3px var(--shadow-color)); } .economic-marker.exchange .economic-icon { filter: drop-shadow(0 0 4px rgba(76, 175, 80, 0.6)); } .economic-marker.central-bank .economic-icon { filter: drop-shadow(0 0 4px rgba(33, 150, 243, 0.6)); } .economic-marker.financial-hub .economic-icon { filter: drop-shadow(0 0 4px rgba(255, 193, 7, 0.6)); } .economic-label { font-size: 7px; color: var(--text); background: var(--bg); padding: 1px 3px; border-radius: 2px; white-space: nowrap; margin-top: 1px; opacity: 0; transition: opacity 0.2s ease; transform: scale(calc(var(--label-scale, 1) / var(--marker-scale, 1))); transform-origin: top center; } .economic-marker:hover .economic-label { opacity: 1; } .map-wrapper[data-layer-hidden-bases="true"] .base-marker, .map-wrapper[data-layer-hidden-iranAttacks="true"] .iran-event-marker, .map-wrapper[data-layer-hidden-nuclear="true"] .nuclear-marker, .map-wrapper[data-layer-hidden-natural="true"] .earthquake-marker, .map-wrapper[data-layer-hidden-natural="true"] .nat-event-marker, .map-wrapper[data-layer-hidden-economic="true"] .economic-marker, .map-wrapper[data-layer-hidden-conflicts="true"] .conflicts, .map-wrapper[data-layer-hidden-conflicts="true"] .conflict-label-overlay, .map-wrapper[data-layer-hidden-conflicts="true"] .conflict-click-area { opacity: 0; pointer-events: none; } .map-wrapper:not([data-labels-hidden-bases="true"]) .base-label, .map-wrapper:not([data-labels-hidden-economic="true"]) .economic-label { opacity: 1; } .map-wrapper[data-labels-hidden-bases="true"] .base-label, .map-wrapper[data-labels-hidden-nuclear="true"] .nuclear-label, .map-wrapper[data-labels-hidden-natural="true"] .earthquake-label, .map-wrapper[data-labels-hidden-natural="true"] .nat-event-label, .map-wrapper[data-labels-hidden-economic="true"] .economic-label, .map-wrapper[data-labels-hidden-conflicts="true"] .conflict-label-overlay { opacity: 0; } .popup-header.economic { background: color-mix(in srgb, var(--semantic-normal) 8%, transparent); } .popup-header.economic.central-bank { background: color-mix(in srgb, var(--semantic-info) 8%, transparent); } .popup-header.economic.financial-hub { background: color-mix(in srgb, var(--semantic-elevated) 8%, transparent); } /* Spaceport Markers */ .spaceport-marker { position: absolute; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; z-index: 55; cursor: pointer; transition: transform 0.2s ease; } .spaceport-marker:hover { transform: translate(-50%, -50%) scale(calc(var(--marker-scale, 1) * 1.3)); } .spaceport-icon { font-size: 16px; filter: drop-shadow(0 0 4px var(--defcon-4)); } .spaceport-marker.active .spaceport-icon { filter: drop-shadow(0 0 8px var(--status-live)) drop-shadow(0 0 16px var(--status-live)); } .spaceport-marker.planned .spaceport-icon { filter: drop-shadow(0 0 4px var(--semantic-elevated)); opacity: 0.7; } .spaceport-marker.inactive .spaceport-icon { filter: grayscale(1); opacity: 0.5; } .spaceport-label { position: absolute; top: 20px; left: 50%; transform: translateX(-50%) scale(calc(var(--label-scale, 1) / var(--marker-scale, 1))); transform-origin: top center; white-space: nowrap; font-size: 7px; color: var(--defcon-4); text-shadow: 0 0 4px var(--bg), 0 0 8px var(--bg); font-weight: bold; text-transform: uppercase; opacity: 0; transition: opacity 0.2s ease; } .spaceport-marker:hover .spaceport-label { opacity: 1; } .spaceport-marker.active .spaceport-label { color: var(--status-live); } .spaceport-marker.planned .spaceport-label { color: var(--semantic-elevated); } /* Spaceport popup header */ .popup-header.spaceport { background: rgba(0, 36, 68, 0.08); } .popup-header.spaceport.active { background: rgba(68, 255, 136, 0.06); } .popup-header.spaceport.planned { background: rgba(255, 170, 0, 0.06); } /* Critical Minerals Markers */ .mineral-marker { position: absolute; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; z-index: 54; cursor: pointer; transition: transform 0.2s ease; } .mineral-marker:hover { transform: translate(-50%, -50%) scale(calc(var(--marker-scale, 1) * 1.3)); } .mineral-icon { font-size: 14px; filter: drop-shadow(0 0 4px var(--semantic-info)); } .mineral-marker.producing .mineral-icon { filter: drop-shadow(0 0 6px var(--status-live)) drop-shadow(0 0 12px #44ff8860); } .mineral-marker.developing .mineral-icon { filter: drop-shadow(0 0 4px var(--semantic-elevated)); opacity: 0.8; } .mineral-marker.exploration .mineral-icon { filter: drop-shadow(0 0 3px var(--text-dim)); opacity: 0.6; } .mineral-label { position: absolute; top: 18px; left: 50%; transform: translateX(-50%) scale(calc(var(--label-scale, 1) / var(--marker-scale, 1))); transform-origin: top center; white-space: nowrap; font-size: 7px; color: var(--semantic-info); text-shadow: 0 0 4px var(--bg), 0 0 8px var(--bg); font-weight: bold; text-transform: uppercase; opacity: 0; transition: opacity 0.2s ease; } .mineral-marker:hover .mineral-label { opacity: 1; } .mineral-marker.producing .mineral-label { color: var(--status-live); } .mineral-marker.developing .mineral-label { color: var(--semantic-elevated); } /* Mineral popup header */ .popup-header.mineral { background: rgba(51, 26, 68, 0.08); } .popup-header.mineral.producing { background: rgba(68, 255, 136, 0.06); } .popup-header.mineral.developing { background: rgba(255, 170, 0, 0.06); } /* ============================================ TECH VARIANT MARKERS ============================================ */ /* Startup Hub Markers */ .startup-hub-marker { position: absolute; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; z-index: 56; cursor: pointer; transition: transform 0.2s ease; } .startup-hub-marker:hover { transform: translate(-50%, -50%) scale(calc(var(--marker-scale, 1) * 1.3)); } .startup-hub-icon { font-size: 16px; filter: drop-shadow(0 0 4px var(--status-live)); } .startup-hub-marker.mega .startup-hub-icon { font-size: 20px; filter: drop-shadow(0 0 8px var(--semantic-info)) drop-shadow(0 0 16px #ff44ff60); } .startup-hub-marker.major .startup-hub-icon { filter: drop-shadow(0 0 6px var(--defcon-4)) drop-shadow(0 0 12px #00aaff60); } .startup-hub-marker.emerging .startup-hub-icon { filter: drop-shadow(0 0 4px var(--semantic-elevated)); opacity: 0.85; } .startup-hub-label { position: absolute; left: 50%; top: 100%; transform: translateX(-50%); white-space: nowrap; font-size: 8px; padding: 2px 4px; background: var(--bg); border-radius: 2px; text-transform: uppercase; opacity: 0; transition: opacity 0.2s ease; margin-top: 2px; color: var(--status-live); } .startup-hub-marker:hover .startup-hub-label { opacity: 1; } .startup-hub-marker.mega .startup-hub-label { color: var(--semantic-info); opacity: 1; } .startup-hub-marker.major .startup-hub-label { color: var(--defcon-4); } /* Startup Hub popup header */ .popup-header.startup-hub { background: rgba(0, 51, 26, 0.08); } .popup-header.startup-hub.mega { background: rgba(59, 130, 246, 0.06); } .popup-header.startup-hub.major { background: rgba(0, 170, 255, 0.06); } .popup-badge.mega { background: var(--semantic-info); color: var(--bg); } .popup-badge.major { background: var(--defcon-4); color: var(--bg); } .popup-badge.emerging { background: var(--semantic-elevated); color: var(--bg); } /* Cloud Region Markers */ .cloud-region-marker { position: absolute; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; z-index: 54; cursor: pointer; transition: transform 0.2s ease; } .cloud-region-marker:hover { transform: translate(-50%, -50%) scale(calc(var(--marker-scale, 1) * 1.3)); } .cloud-region-icon { font-size: 12px; filter: drop-shadow(0 0 4px var(--accent)); } .cloud-region-marker.aws .cloud-region-icon { filter: drop-shadow(0 0 4px var(--semantic-high)); } .cloud-region-marker.gcp .cloud-region-icon { filter: drop-shadow(0 0 4px var(--semantic-info)); } .cloud-region-marker.azure .cloud-region-icon { filter: drop-shadow(0 0 4px var(--semantic-info)); } .cloud-region-marker.cloudflare .cloud-region-icon { filter: drop-shadow(0 0 4px var(--threat-high)); } .cloud-region-label { position: absolute; left: 50%; top: 100%; transform: translateX(-50%); white-space: nowrap; font-size: 7px; padding: 1px 3px; background: var(--bg); border-radius: 2px; text-transform: uppercase; opacity: 0; transition: opacity 0.2s ease; margin-top: 2px; } .cloud-region-marker:hover .cloud-region-label { opacity: 1; } .cloud-region-marker.aws .cloud-region-label { color: var(--semantic-high); } .cloud-region-marker.gcp .cloud-region-label { color: var(--semantic-info); } .cloud-region-marker.azure .cloud-region-label { color: var(--semantic-info); } .cloud-region-marker.cloudflare .cloud-region-label { color: var(--threat-high); } /* Cloud Region popup header */ .popup-header.cloud-region { background: rgba(0, 34, 26, 0.08); } .popup-header.cloud-region.aws { background: rgba(255, 136, 0, 0.06); } .popup-header.cloud-region.gcp { background: rgba(59, 130, 246, 0.06); } .popup-header.cloud-region.azure { background: rgba(59, 130, 246, 0.06); } .popup-header.cloud-region.cloudflare { background: rgba(249, 115, 22, 0.06); } .popup-badge.aws { background: var(--semantic-high); color: var(--bg); } .popup-badge.gcp { background: var(--semantic-info); color: var(--accent); } .popup-badge.azure { background: var(--semantic-info); color: var(--accent); } .popup-badge.cloudflare { background: var(--threat-high); color: var(--accent); } /* Tech HQ Markers */ .tech-hq-marker { position: absolute; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; z-index: 55; cursor: pointer; transition: transform 0.2s ease; } .tech-hq-marker:hover { transform: translate(-50%, -50%) scale(calc(var(--marker-scale, 1) * 1.3)); } .tech-hq-icon { font-size: 14px; filter: drop-shadow(0 0 4px var(--semantic-info)); } .tech-hq-marker.faang .tech-hq-icon { font-size: 16px; filter: drop-shadow(0 0 6px var(--status-live)) drop-shadow(0 0 12px #00ffaa60); } .tech-hq-marker.unicorn .tech-hq-icon { filter: drop-shadow(0 0 6px var(--semantic-info)) drop-shadow(0 0 12px #ff44ff60); } .tech-hq-marker.public .tech-hq-icon { filter: drop-shadow(0 0 4px var(--defcon-4)); opacity: 0.9; } .tech-hq-label { position: absolute; left: 50%; top: 100%; transform: translateX(-50%); white-space: nowrap; font-size: 8px; padding: 2px 4px; background: var(--bg); border-radius: 2px; text-transform: uppercase; opacity: 0; transition: opacity 0.2s ease; margin-top: 2px; font-weight: bold; } .tech-hq-marker:hover .tech-hq-label { opacity: 1; } .tech-hq-marker.faang .tech-hq-label { color: var(--status-live); opacity: 1; } .tech-hq-marker.unicorn .tech-hq-label { color: var(--semantic-info); } .tech-hq-marker.public .tech-hq-label { color: var(--defcon-4); } /* Tech HQ popup header */ .popup-header.tech-hq { background: rgba(26, 26, 51, 0.08); } .popup-header.tech-hq.faang { background: rgba(68, 255, 136, 0.06); } .popup-header.tech-hq.unicorn { background: rgba(59, 130, 246, 0.06); } .popup-badge.faang { background: var(--status-live); color: var(--bg); } .popup-badge.unicorn { background: var(--semantic-info); color: var(--bg); } .popup-badge.public { background: var(--defcon-4); color: var(--accent); } /* Cluster badges for grouped markers */ .cluster-badge { position: absolute; top: -6px; right: -6px; background: var(--red); color: var(--accent); font-size: 9px; font-weight: bold; min-width: 14px; height: 14px; border-radius: 7px; display: flex; align-items: center; justify-content: center; padding: 0 3px; border: 1px solid var(--bg); z-index: 10; } .tech-hq-marker.cluster { z-index: 60; } .tech-hq-marker.cluster .tech-hq-icon { font-size: 18px; } .tech-event-marker.cluster { width: 18px; height: 18px; z-index: 1001; } .tech-event-marker.cluster .cluster-badge { background: var(--accent); color: var(--border); } /* Cluster popups */ .cluster-popup { max-height: 300px; overflow-y: auto; } .cluster-summary { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0; } .cluster-summary .summary-item { font-size: 10px; padding: 2px 6px; border-radius: 3px; background: var(--overlay-medium); } .cluster-summary .summary-item.faang { color: var(--status-live); } .cluster-summary .summary-item.unicorn { color: var(--semantic-info); } .cluster-summary .summary-item.public { color: var(--defcon-4); } .cluster-summary .summary-item.soon { color: var(--yellow); } .cluster-list { list-style: none; padding: 0; margin: 8px 0 0 0; font-size: 11px; } .cluster-list .cluster-item { padding: 4px 0; border-bottom: 1px solid var(--overlay-medium); } .cluster-list .cluster-item:last-child { border-bottom: none; } .cluster-list .cluster-item.faang { color: var(--status-live); } .cluster-list .cluster-item.unicorn { color: var(--semantic-info); } .cluster-list .cluster-item.public { color: var(--defcon-4); } .cluster-list .cluster-item.urgent { color: var(--red); } .cluster-list .cluster-item.soon { color: var(--yellow); } /* Accelerator Markers */ .accelerator-marker { position: absolute; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; z-index: 53; cursor: pointer; transition: transform 0.2s ease; } .accelerator-marker:hover { transform: translate(-50%, -50%) scale(calc(var(--marker-scale, 1) * 1.3)); } .accelerator-icon { font-size: 14px; filter: drop-shadow(0 0 4px var(--semantic-high)); } .accelerator-marker.accelerator .accelerator-icon { filter: drop-shadow(0 0 6px var(--semantic-high)) drop-shadow(0 0 12px #ff660060); } .accelerator-marker.incubator .accelerator-icon { filter: drop-shadow(0 0 4px var(--status-live)); } .accelerator-marker.studio .accelerator-icon { filter: drop-shadow(0 0 4px var(--semantic-critical)); } .accelerator-label { position: absolute; left: 50%; top: 100%; transform: translateX(-50%); white-space: nowrap; font-size: 7px; padding: 2px 4px; background: var(--bg); border-radius: 2px; text-transform: uppercase; opacity: 0; transition: opacity 0.2s ease; margin-top: 2px; } .accelerator-marker:hover .accelerator-label { opacity: 1; } .accelerator-marker.accelerator .accelerator-label { color: var(--semantic-high); } .accelerator-marker.incubator .accelerator-label { color: var(--status-live); } .accelerator-marker.studio .accelerator-label { color: var(--semantic-critical); } /* Accelerator popup header */ .popup-header.accelerator { background: rgba(51, 26, 16, 0.08); } .popup-header.accelerator.incubator { background: rgba(68, 255, 136, 0.06); } .popup-header.accelerator.studio { background: rgba(239, 68, 68, 0.06); } .popup-badge.accelerator { background: var(--semantic-high); color: var(--accent); } .popup-badge.incubator { background: var(--status-live); color: var(--bg); } .popup-badge.studio { background: var(--semantic-critical); color: var(--accent); } /* Notable alumni list in accelerator popup */ .popup-notable { margin-top: 8px; padding: 6px 8px; background: rgba(255, 102, 0, 0.1); border-radius: 4px; } .notable-label { display: block; font-size: 8px; color: var(--text-dim); text-transform: uppercase; margin-bottom: 4px; } .notable-list { font-size: 10px; color: var(--semantic-high); } /* Economic Panel */ .economic-indicators { display: flex; flex-direction: column; gap: 1px; background: var(--border); } .macro-pressure-card { display: flex; flex-direction: column; gap: 4px; padding: 10px 12px; border: 1px solid var(--border); background: var(--overlay-subtle); } .macro-pressure-stress { border-color: rgba(239, 68, 68, 0.35); background: rgba(239, 68, 68, 0.08); } .macro-pressure-watch { border-color: rgba(245, 158, 11, 0.35); background: rgba(245, 158, 11, 0.08); } .macro-pressure-steady { border-color: rgba(34, 197, 94, 0.35); background: rgba(34, 197, 94, 0.08); } .macro-pressure-label, .energy-section-title { font-size: 9px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-dim); } .macro-pressure-value { font-size: 20px; font-weight: 700; color: var(--accent); } .macro-pressure-detail { font-size: 11px; color: var(--text-secondary); } .macro-summary-grid, .energy-summary-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(116px, 1fr)); gap: 8px; } .macro-summary-card, .energy-summary-card { display: flex; flex-direction: column; gap: 4px; padding: 10px; border: 1px solid var(--border); background: var(--surface); } .macro-summary-head, .energy-summary-head { display: flex; justify-content: space-between; gap: 8px; align-items: baseline; } .macro-summary-value, .energy-summary-value { font-size: 20px; font-weight: 700; color: var(--accent); } .macro-summary-change, .energy-summary-change { font-size: 11px; } .macro-summary-change.positive, .energy-summary-change.positive { color: var(--green); } .macro-summary-change.negative, .energy-summary-change.negative { color: var(--red); } .macro-summary-change.neutral, .energy-summary-change.neutral { color: var(--text-dim); } .energy-unit { font-size: 11px; color: var(--text-dim); } .energy-complex-content { display: flex; flex-direction: column; gap: 10px; padding: 8px; } .energy-tape-section { display: flex; flex-direction: column; gap: 8px; } .economic-indicator { background: var(--surface); padding: 8px 12px; } .indicator-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px; } .indicator-name { font-size: 10px; color: var(--text); font-weight: 500; } .indicator-id { font-size: 9px; color: var(--text-dim); font-family: monospace; } .indicator-value { display: flex; justify-content: space-between; align-items: baseline; } .indicator-value .value { font-size: 14px; font-weight: bold; color: var(--accent); } .indicator-value .change { font-size: 10px; color: var(--text-dim); } .indicator-value .change.positive { color: var(--green); } .indicator-value .change.negative { color: var(--red); } .indicator-date { font-size: 9px; color: var(--text-dim); margin-top: 2px; } .economic-footer { padding: 6px 12px; border-top: 1px solid var(--border); text-align: right; } .sanctions-panel-content { display: flex; flex-direction: column; gap: 10px; } .sanctions-summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(88px, 1fr)); gap: 8px; padding: 0 8px; } .radiation-panel-content { display: flex; flex-direction: column; gap: 8px; } .radiation-summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(92px, 1fr)); gap: 8px; padding: 0 8px; } .sanctions-summary-card { display: flex; flex-direction: column; gap: 2px; padding: 8px; border: 1px solid var(--border); background: var(--overlay-subtle); } .radiation-summary-card { display: flex; flex-direction: column; gap: 2px; padding: 8px; border: 1px solid var(--border); background: var(--overlay-subtle); } .sanctions-summary-card-highlight { border-color: rgba(245, 158, 11, 0.35); background: rgba(245, 158, 11, 0.08); } .radiation-summary-card-spike { border-color: rgba(239, 68, 68, 0.35); background: rgba(239, 68, 68, 0.08); } .radiation-summary-card-confirmed { border-color: rgba(34, 197, 94, 0.35); background: rgba(34, 197, 94, 0.08); } .radiation-summary-card-low-confidence { border-color: rgba(245, 158, 11, 0.35); background: rgba(245, 158, 11, 0.08); } .sanctions-summary-card-muted { border-color: rgba(125, 211, 252, 0.35); background: rgba(125, 211, 252, 0.08); } .radiation-summary-card-conflict { border-color: rgba(125, 211, 252, 0.35); background: rgba(125, 211, 252, 0.08); } .sanctions-summary-label, .sanctions-section-title { font-size: 9px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-dim); } .radiation-summary-label { font-size: 9px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-dim); } .sanctions-summary-value { font-size: 18px; font-weight: 600; color: var(--accent); } .radiation-summary-value { font-size: 18px; font-weight: 600; color: var(--accent); } .sanctions-sections { display: flex; flex-direction: column; gap: 8px; padding: 0 8px; } .sanctions-section { border: 1px solid var(--border); background: var(--surface); } .sanctions-section-title { padding: 8px 10px 0; } .sanctions-list { display: flex; flex-direction: column; } .sanctions-row, .sanctions-entry { padding: 8px 10px; border-top: 1px solid var(--border); } .sanctions-row { display: flex; justify-content: space-between; gap: 12px; align-items: flex-start; } .sanctions-row-main { min-width: 0; } .sanctions-row-title, .sanctions-entry-name { font-size: 12px; font-weight: 600; color: var(--text-secondary); } .radiation-table { width: 100%; border-collapse: collapse; font-size: 11px; } .radiation-table th, .radiation-table td { padding: 6px 8px; border-bottom: 1px solid var(--border); text-align: left; } .radiation-row { cursor: pointer; } .radiation-row:hover { background: rgba(255, 255, 255, 0.03); } .radiation-reading { color: var(--accent); font-weight: 600; white-space: nowrap; } .radiation-location-name { font-weight: 600; color: var(--text-secondary); } .sanctions-row-meta, .sanctions-entry-meta, .sanctions-entry-note { margin-top: 2px; font-size: 10px; color: var(--text-dim); } .radiation-location-meta { margin-top: 2px; font-size: 10px; color: var(--text-dim); } .sanctions-row-flags, .sanctions-entry-top { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; } .sanctions-pill { display: inline-flex; align-items: center; padding: 2px 6px; border-radius: 999px; border: 1px solid var(--border); font-size: 10px; color: var(--text-secondary); background: var(--overlay-subtle); } .sanctions-pill-new { color: var(--semantic-elevated); border-color: rgba(245, 158, 11, 0.35); background: rgba(245, 158, 11, 0.08); } .radiation-location-flags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; } .radiation-delta { white-space: nowrap; color: var(--text-secondary); } .radiation-freshness, .radiation-severity, .radiation-badge { display: inline-flex; padding: 2px 6px; border: 1px solid var(--border); border-radius: 999px; font-size: 10px; } .radiation-confidence-high { color: var(--semantic-normal); border-color: rgba(34, 197, 94, 0.35); background: rgba(34, 197, 94, 0.08); } .radiation-confidence-medium { color: var(--semantic-elevated); border-color: rgba(245, 158, 11, 0.35); background: rgba(245, 158, 11, 0.08); } .sanctions-pill-type { text-transform: uppercase; } .radiation-confidence-low { color: #7dd3fc; border-color: rgba(125, 211, 252, 0.35); background: rgba(125, 211, 252, 0.08); } .radiation-flag-confirmed { color: var(--semantic-normal); } .radiation-flag-conflict { color: #7dd3fc; } .radiation-flag-converted { color: var(--text-dim); } .radiation-severity-normal { color: var(--text-dim); } .radiation-severity-elevated { color: var(--semantic-elevated); border-color: rgba(234, 179, 8, 0.35); background: rgba(234, 179, 8, 0.08); } .radiation-severity-spike { color: var(--semantic-critical); border-color: rgba(239, 68, 68, 0.35); background: rgba(239, 68, 68, 0.08); } .radiation-freshness-live { color: var(--semantic-normal); } .radiation-freshness-recent { color: var(--semantic-elevated); } .radiation-freshness-historical { color: var(--text-dim); } .radiation-footer { padding: 0 8px 8px 8px; color: var(--text-dim); font-size: 10px; text-align: right; } .economic-source { font-size: 9px; color: var(--text-dim); } /* economic-tabs: now uses shared .panel-tabs / .panel-tab */ .panel-content:has(.economic-content) { display: flex; flex-direction: column; } .economic-content { padding: 8px; flex: 1 1 0; min-height: 0; overflow-y: auto; } .economic-content-macro { display: flex; flex-direction: column; gap: 8px; } .panel-content:has(.energy-complex-content) { display: flex; flex-direction: column; } /* regulation-tabs: now uses shared .panel-tabs / .panel-tab */ .economic-empty { padding: 16px; text-align: center; color: var(--text-dim); font-size: 11px; } /* Government Spending */ .spending-summary { padding: 8px; background: rgba(68, 255, 136, 0.05); border-radius: 4px; margin-bottom: 8px; } .spending-total { font-size: 14px; font-weight: 600; color: var(--green); } .spending-period { display: block; font-size: 9px; color: var(--text-dim); font-weight: 400; margin-top: 2px; } .spending-list { display: flex; flex-direction: column; gap: 6px; } .spending-award { padding: 8px; background: var(--overlay-subtle); border-radius: 4px; border-left: 2px solid var(--border); } .spending-award:hover { background: var(--overlay-light); border-left-color: var(--green); } .award-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px; } .award-icon { font-size: 12px; } .award-amount { font-size: 12px; font-weight: 600; color: var(--green); } .award-recipient { font-size: 11px; color: var(--text); font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .award-agency { font-size: 9px; color: var(--text-dim); margin-top: 2px; } .award-desc { font-size: 9px; color: var(--text-dim); margin-top: 4px; line-height: 1.3; } /* Global Procurement */ .global-procurement-controls { display: grid; grid-template-columns: minmax(150px, 2fr) minmax(110px, 1fr) 72px minmax(110px, 1fr) minmax(120px, 1fr) auto auto auto; gap: 6px; padding: 8px; border-bottom: 1px solid var(--border); } .global-procurement-toggle { display: flex; align-items: center; gap: 4px; min-width: 0; color: var(--text-dim); font-size: 10px; white-space: nowrap; cursor: pointer; } .global-procurement-toggle input { margin: 0; accent-color: var(--green); } .global-procurement-input, .global-procurement-select { min-width: 0; padding: 6px 7px; color: var(--text); background: var(--overlay-subtle); border: 1px solid var(--border); border-radius: 4px; font: inherit; font-size: 10px; } .global-procurement-input:focus, .global-procurement-select:focus { outline: 1px solid var(--green); border-color: var(--green); } .global-procurement-apply, .global-procurement-reset { padding: 6px 9px; border: 1px solid var(--border); border-radius: 4px; color: var(--text); background: var(--overlay-light); cursor: pointer; font-size: 10px; } .global-procurement-apply { color: var(--green); border-color: color-mix(in srgb, var(--green) 40%, var(--border)); } .global-procurement-apply:disabled, .global-procurement-reset:disabled { cursor: wait; opacity: 0.55; } .global-procurement-summary { padding: 8px 10px 4px; color: var(--text-dim); font-size: 9px; } .global-procurement-list { padding: 4px 8px 8px; } .global-procurement-card .award-recipient { white-space: normal; } .global-procurement-card a.award-agency { display: inline-block; color: var(--green); } @media (max-width: 900px) { .global-procurement-controls { grid-template-columns: 1fr 1fr; } .global-procurement-input:first-child { grid-column: 1 / -1; } } /* Trade Policy Panel */ .economic-warning { padding: 6px 10px; font-size: 10px; color: var(--semantic-elevated); background: rgba(255, 170, 50, 0.08); border-bottom: 1px solid rgba(255, 170, 50, 0.15); } .trade-restrictions-list, .trade-barriers-list { display: flex; flex-direction: column; gap: 6px; } .trade-restriction-card, .trade-barrier-card { padding: 8px 10px; background: var(--overlay-subtle); border-radius: 4px; border-left: 2px solid var(--border); transition: all 0.15s; } .trade-restriction-card:hover, .trade-barrier-card:hover { background: var(--overlay-light); border-left-color: var(--green); } .trade-restriction-header, .trade-barrier-header { display: flex; align-items: center; gap: 6px; margin-bottom: 4px; } .trade-country { font-size: 11px; font-weight: 600; color: var(--text); } .trade-badge { font-size: 9px; padding: 1px 5px; background: rgba(68, 255, 136, 0.1); color: var(--text-dim); border-radius: 3px; white-space: nowrap; } .trade-status { font-size: 9px; padding: 1px 5px; border-radius: 3px; font-weight: 600; margin-left: auto; white-space: nowrap; } .trade-status.status-active { background: rgba(255, 80, 80, 0.15); color: var(--red); } .trade-status.status-notified { background: rgba(255, 170, 50, 0.15); color: var(--semantic-elevated); } .trade-status.status-terminated { background: rgba(68, 255, 136, 0.1); color: var(--green); } .sc-status-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin: 0 4px; vertical-align: middle; } .sc-dot-red { background: var(--red, #ff5252); } .sc-dot-yellow { background: var(--yellow, #ffd740); } .sc-dot-green { background: var(--green, #69f0ae); } .sc-risk-critical { color: var(--red, #ff5252); font-weight: 600; } .sc-risk-high { color: var(--orange, #ffab40); font-weight: 600; } .sc-risk-moderate { color: var(--yellow, #ffd740); } .sc-risk-low { color: var(--green, #69f0ae); } .trade-restriction-card.expanded { background: var(--overlay-medium); border-left-color: var(--accent-primary, #4fc3f7); border-left-width: 3px; } .trade-revenue-chart { display: flex; align-items: flex-end; gap: 3px; height: 80px; padding: 4px 0 0; margin-bottom: 8px; border-bottom: 1px solid var(--border-color, rgba(255,255,255,0.08)); } .trade-chart-col { flex: 1; display: flex; flex-direction: column; align-items: center; height: 100%; justify-content: flex-end; cursor: default; } .trade-chart-bar { width: 100%; min-height: 2px; background: var(--text-dim, rgba(255,255,255,0.3)); border-radius: 2px 2px 0 0; transition: background 0.2s; } .trade-chart-bar.trade-chart-spike { background: var(--red, #ff5252); } .trade-chart-label { font-size: 8px; color: var(--text-dim, rgba(255,255,255,0.4)); margin-top: 2px; line-height: 1; } .trade-revenue-summary { margin-bottom: 6px; } .trade-revenue-headline { display: flex; justify-content: space-between; align-items: baseline; font-size: 14px; font-weight: 600; } .trade-revenue-value { font-variant-numeric: tabular-nums; } .trade-revenue-compare { font-size: 11px; color: var(--text-dim); } .sc-metric-row { display: flex; flex-wrap: wrap; gap: 8px; font-size: 10px; color: var(--text-dim); margin: 2px 0; } .sc-metric-row span { white-space: nowrap; } .sc-disrupt-red { color: var(--red, #ff5252); } .sc-disrupt-yellow { color: var(--yellow, #ffd740); } .sc-disrupt-green { color: var(--green, #69f0ae); } .sc-routing-advisory { font-size: 10px; padding: 6px 8px; margin-top: 6px; background: rgba(255, 171, 64, 0.08); border-left: 2px solid var(--orange, #ffab40); border-radius: 2px; color: var(--text-secondary); line-height: 1.4; } .sc-disruption-table { width: 100%; font-size: 10px; border-collapse: collapse; margin-bottom: 4px; } .sc-disruption-table th { text-align: left; font-weight: 600; color: var(--text-dim); padding: 4px 6px; border-bottom: 1px solid var(--border-subtle); } .sc-disruption-table td { padding: 4px 6px; border-bottom: 1px solid var(--border-faint); } .sc-disruption-table td:nth-child(n+2) { text-align: right; font-variant-numeric: tabular-nums; } .trade-sector { font-size: 10px; color: var(--text-dim); } .trade-description { font-size: 10px; color: var(--text-dim); margin-top: 2px; line-height: 1.3; } .trade-affected { font-size: 9px; color: var(--text-faint); margin-top: 2px; } .trade-barrier-title { font-size: 10px; color: var(--text-secondary); font-weight: 500; line-height: 1.3; } .trade-restriction-footer, .trade-barrier-footer { display: flex; align-items: center; justify-content: space-between; margin-top: 4px; padding-top: 4px; border-top: 1px solid var(--border); } .trade-date { font-size: 9px; color: var(--text-faint); } .trade-source-link { font-size: 9px; color: var(--accent); text-decoration: none; } .trade-source-link:hover { text-decoration: underline; } .trade-policy-note { margin-bottom: 8px; padding: 8px 10px; background: var(--overlay-subtle); border-left: 2px solid var(--accent); border-radius: 4px; font-size: 10px; line-height: 1.45; color: var(--text-secondary); } .trade-policy-note strong { color: var(--text); } .trade-policy-inline-note { margin-top: 4px; font-size: 9px; line-height: 1.4; color: var(--text-secondary); } .trade-policy-inline-sep { margin: 0 4px; color: var(--text-faint); } .trade-tariff-summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 8px; margin-bottom: 8px; } .trade-tariff-card { padding: 8px 10px; background: var(--overlay-subtle); border: 1px solid var(--border); border-radius: 4px; } .trade-tariff-card-muted { opacity: 0.85; } .trade-tariff-label { font-size: 9px; font-weight: 600; letter-spacing: 0.4px; text-transform: uppercase; color: var(--text-dim); } .trade-tariff-value { margin-top: 4px; font-size: 16px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--text); } .trade-tariff-meta { margin-top: 4px; font-size: 10px; line-height: 1.4; color: var(--text-dim); } .trade-tariff-source { display: inline-block; margin-left: 6px; } .trade-tariff-gap-positive { color: var(--orange, #ffab40); } .trade-tariff-gap-negative { color: var(--green, #69f0ae); } /* Trade Tariffs Table */ .trade-tariffs-table { width: 100%; } .trade-tariffs-table table { width: 100%; border-collapse: collapse; font-size: 11px; } .trade-tariffs-table thead th { text-align: left; font-size: 9px; font-weight: 600; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.5px; padding: 4px 8px 6px; border-bottom: 1px solid var(--border); } .trade-tariffs-table tbody td { padding: 5px 8px; color: var(--text); border-bottom: 1px solid var(--border); } .trade-tariffs-table tbody tr:last-child td { border-bottom: none; } .trade-tariffs-table tbody tr:hover { background: var(--overlay-subtle); } /* Trade Flows */ .trade-flows-list { display: flex; flex-direction: column; gap: 6px; } .trade-flow-card { padding: 8px 10px; background: var(--overlay-subtle); border-radius: 4px; display: flex; align-items: center; gap: 10px; } .trade-flow-card:hover { background: var(--overlay-light); } .trade-flow-year { font-size: 12px; font-weight: 600; color: var(--text-dim); min-width: 36px; } .trade-flow-metrics { flex: 1; display: flex; gap: 12px; } .trade-flow-metric { display: flex; flex-direction: column; gap: 1px; } .trade-flow-label { font-size: 9px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.3px; } .trade-flow-value { font-size: 12px; font-weight: 600; color: var(--text); } .trade-flow-change { font-size: 10px; } .trade-flow-change.change-positive { color: var(--green); } .trade-flow-change.change-negative { color: var(--red); } /* Search Modal (Cmd+K) */ .search-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: var(--bg); display: flex; align-items: flex-start; justify-content: center; padding-top: 15vh; z-index: 2000; backdrop-filter: blur(4px); } .search-modal { width: 560px; max-width: 90vw; background: var(--surface); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 20px 60px var(--shadow-color); overflow: hidden; } .search-header { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--border); background: var(--bg); } .search-icon { font-size: 14px; color: var(--text-dim); background: var(--border); padding: 2px 6px; border-radius: 4px; font-weight: bold; } .search-input { flex: 1; background: transparent; border: none; color: var(--text); font-family: inherit; font-size: 14px; outline: none; } .search-input::placeholder { color: var(--text-dim); } .search-kbd { font-size: 10px; color: var(--text-dim); background: var(--border); padding: 2px 6px; border-radius: 3px; font-family: inherit; } .search-results { max-height: 400px; overflow-y: auto; } .search-section-header { padding: 8px 16px; font-size: 10px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 1px; background: var(--bg); border-bottom: 1px solid var(--border); } .search-result-item { display: flex; align-items: center; gap: 12px; padding: 10px 16px; cursor: pointer; transition: background 0.1s; } .search-result-item:hover, .search-result-item.selected { background: var(--border); } .search-result-item.selected { border-left: 2px solid var(--green); } .search-result-icon { font-size: 16px; width: 24px; text-align: center; } .search-result-content { flex: 1; min-width: 0; } .search-result-title { font-size: 12px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .search-result-title mark { background: rgba(68, 255, 136, 0.3); color: var(--green); padding: 0 2px; border-radius: 2px; } .search-result-item.command-item { border-left: 2px solid var(--semantic-normal, #4488ff); } .search-result-item.command-item .search-result-type { font-size: 9px; text-transform: uppercase; opacity: 0.5; } .search-result-subtitle { font-size: 10px; color: var(--text-dim); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .search-result-type { font-size: 9px; color: var(--text-dim); text-transform: uppercase; background: var(--bg); padding: 2px 6px; border-radius: 3px; } /* "Add" pill for CMD+K results that enable a currently-disabled panel. */ .search-result-item.command-addable .search-result-type-add { color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent); opacity: 1; font-weight: 600; } .search-result-item.command-addable .search-result-icon { opacity: 0.7; } .search-empty { padding: 40px 16px; text-align: center; color: var(--text-dim); } .search-empty-icon { font-size: 32px; margin-bottom: 12px; opacity: 0.5; } .search-empty-hint { font-size: 11px; margin-top: 8px; opacity: 0.7; } .search-empty-examples { font-size: 11px; margin-top: 12px; opacity: 0.5; } .search-empty-examples kbd { background: var(--bg-tertiary, rgba(255, 255, 255, 0.08)); border-radius: 3px; padding: 2px 6px; font-size: 10px; font-family: inherit; margin: 0 2px; } .search-all-commands-wrap { padding: 8px 16px 12px; border-top: 1px solid var(--border); background: var(--bg); } .search-all-commands-link { font-size: 11px; color: var(--text-dim); text-decoration: none; } .search-all-commands-link:hover { color: var(--green); text-decoration: underline; } .search-command-list-back { padding: 8px 16px; } .search-all-commands-back { font-size: 11px; color: var(--text-dim); text-decoration: none; } .search-all-commands-back:hover { color: var(--green); text-decoration: underline; } .search-command-category { border-bottom: 1px solid var(--border); } .search-command-category:last-child { border-bottom: none; } .search-command-category-summary { padding: 8px 16px; font-size: 10px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 1px; background: var(--bg); cursor: pointer; list-style: none; } .search-command-category-summary::-webkit-details-marker { display: none; } .search-command-category-list { max-height: 200px; overflow-y: auto; } .search-command-category-list .command-item { border-left: none; } .search-footer { display: flex; gap: 16px; padding: 8px 16px; border-top: 1px solid var(--border); background: var(--bg); font-size: 10px; color: var(--text-dim); } .search-footer kbd { font-size: 9px; background: var(--border); padding: 1px 4px; border-radius: 2px; margin-right: 4px; } /* Mobile search FAB — always visible floating button */ .search-mobile-fab { display: none; } @media (max-width: 768px) { .search-mobile-fab { display: flex; align-items: center; justify-content: center; position: fixed; bottom: calc(24px + env(safe-area-inset-bottom, 0px)); right: 16px; width: 56px; height: 56px; background: var(--accent, #4488ff); border: none; border-radius: 50%; box-shadow: 0 4px 20px rgba(68, 136, 255, 0.4), 0 2px 8px rgba(0, 0, 0, 0.3); color: #fff; font-size: 22px; cursor: pointer; z-index: 500; -webkit-tap-highlight-color: transparent; } .search-mobile-fab:active { transform: scale(0.9); opacity: 0.85; } } /* Mobile bottom sheet search */ .search-overlay.search-mobile { align-items: flex-end; padding-top: 0; background: rgba(0, 0, 0, 0.5); } .search-overlay.search-mobile .search-sheet { width: 100%; max-height: 50vh; background: var(--surface); border-radius: 16px 16px 0 0; display: flex; flex-direction: column; transform: translateY(100%); transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1); } .search-overlay.search-mobile.open .search-sheet { transform: translateY(0); } .search-sheet-handle { width: 36px; height: 4px; background: var(--text-dim); opacity: 0.4; border-radius: 2px; margin: 8px auto; } .search-sheet-header { display: flex; align-items: center; gap: 8px; padding: 8px 16px 12px; } .search-sheet-icon { font-size: 16px; } .search-sheet-header .search-input { flex: 1; font-size: 15px; background: transparent; border: none; color: var(--text); font-family: inherit; outline: none; } .search-sheet-cancel { background: none; border: none; color: var(--accent, #4488ff); font-size: 20px; font-family: inherit; cursor: pointer; padding: 4px 8px; line-height: 1; } .search-sheet-chips { display: flex; gap: 6px; padding: 0 16px 10px; overflow-x: auto; scrollbar-width: none; -ms-overflow-style: none; } .search-sheet-chips::-webkit-scrollbar { display: none; } .search-chip { flex-shrink: 0; padding: 6px 14px; border-radius: 16px; border: 1px solid var(--border); background: var(--bg); color: var(--text); font-size: 12px; font-family: inherit; cursor: pointer; white-space: nowrap; } .search-chip:active { background: var(--border); } @media (max-width: 768px) { .search-btn { display: none !important; } .search-overlay.search-mobile .search-results { flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; } .search-overlay.search-mobile .search-result-item { min-height: 48px; padding: 12px 16px; } .search-overlay.search-mobile .search-result-title { font-size: 14px; } .search-overlay.search-mobile .search-section-header { font-size: 11px; padding: 10px 16px; } .search-overlay.search-mobile .search-result-subtitle { display: none; } .search-overlay.search-mobile .search-result-type { display: none; } } /* Flight Delay Markers */ .flight-delay-marker { position: absolute; display: flex; flex-direction: column; align-items: center; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; cursor: pointer; z-index: 53; --flight-color: var(--semantic-info); } .flight-delay-marker.normal { --flight-color: var(--status-live); } .flight-delay-marker.minor { --flight-color: var(--semantic-elevated); } .flight-delay-marker.moderate { --flight-color: var(--semantic-high); } .flight-delay-marker.major { --flight-color: var(--semantic-high); animation: flight-pulse 2s ease-in-out infinite; } .flight-delay-marker.severe { --flight-color: var(--semantic-critical); animation: flight-pulse 1s ease-in-out infinite; } /* No-telemetry status (#3707). Render desaturated grey so users don't read the dot as "healthy / green". */ .flight-delay-marker.unknown { --flight-color: var(--text-muted, #9ca3af); opacity: 0.6; } .flight-delay-icon { font-size: 18px; filter: drop-shadow(0 0 6px var(--flight-color)); } .flight-delay-label { font-size: 9px; color: var(--flight-color); text-transform: uppercase; letter-spacing: 0.5px; margin-top: 2px; white-space: nowrap; text-shadow: 0 0 4px var(--bg), 0 0 8px var(--bg); font-weight: bold; } @keyframes flight-pulse { 0%, 100% { opacity: 1; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); } 50% { opacity: 0.7; transform: translate(-50%, -50%) scale(calc(var(--marker-scale, 1) * 1.15)); } } /* Flight Popup Styles */ .popup-header.flight { background: color-mix(in srgb, var(--flight-color, var(--semantic-info)) 8%, transparent); } .popup-header.flight.normal { --flight-color: var(--status-live); } .popup-header.flight.minor { --flight-color: var(--semantic-elevated); } .popup-header.flight.moderate { --flight-color: var(--semantic-high); } .popup-header.flight.major { --flight-color: var(--semantic-high); } .popup-header.flight.severe { --flight-color: var(--semantic-critical); } /* #3707: no telemetry — render the popup header in a neutral grey so users don't read the airport as healthy. */ .popup-header.flight.unknown { --flight-color: var(--text-muted, #9ca3af); } .popup-location { font-size: 10px; color: var(--text-dim); margin-bottom: 8px; } /* ============================================ Military Flight Tracking Markers ============================================ */ .military-flight-marker { position: absolute; display: flex; flex-direction: column; align-items: center; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; cursor: pointer; z-index: 55; --mil-color: var(--status-live); opacity: 0.7; } .military-flight-marker:hover { opacity: 1; } /* US Military - olive */ .military-flight-marker.usaf, .military-flight-marker.usn, .military-flight-marker.usmc, .military-flight-marker.usa { --mil-color: var(--semantic-normal); } /* UK Military - forest green */ .military-flight-marker.raf, .military-flight-marker.rn { --mil-color: var(--semantic-normal); } /* French - teal */ .military-flight-marker.faf { --mil-color: var(--semantic-normal); } /* German - olive */ .military-flight-marker.gaf { --mil-color: #6b8e23; } /* China - red */ .military-flight-marker.plaaf, .military-flight-marker.plan { --mil-color: #dc143c; } /* Russia - orange */ .military-flight-marker.vks { --mil-color: var(--semantic-high); } /* Israel - spring green */ .military-flight-marker.iaf { --mil-color: var(--status-live); } /* NATO - blue */ .military-flight-marker.nato { --mil-color: var(--semantic-info); } .military-flight-marker.interesting { opacity: 0.9; } .military-flight-marker.bomber, .military-flight-marker.reconnaissance { --mil-color: var(--semantic-critical); opacity: 0.9; } .military-flight-icon { width: 20px; height: 20px; position: relative; transition: transform 0.3s ease; } /* Crosshair horizontal line */ .military-flight-icon::before { content: ''; position: absolute; top: 50%; left: 0; right: 0; height: 3px; background: var(--mil-color); transform: translateY(-50%); box-shadow: 0 0 6px var(--mil-color), 0 0 12px var(--mil-color); } /* Crosshair vertical line */ .military-flight-icon::after { content: ''; position: absolute; left: 50%; top: 0; bottom: 0; width: 3px; background: var(--mil-color); transform: translateX(-50%); box-shadow: 0 0 6px var(--mil-color), 0 0 12px var(--mil-color); } /* Special aircraft types get different crosshair styles */ .military-flight-icon.bomber::before, .military-flight-icon.bomber::after { background: var(--semantic-critical); box-shadow: 0 0 4px var(--semantic-critical); } .military-flight-icon.reconnaissance::before, .military-flight-icon.reconnaissance::after, .military-flight-icon.awacs::before, .military-flight-icon.awacs::after { background: var(--status-live); box-shadow: 0 0 4px var(--status-live); } .military-flight-icon.fighter { width: 22px; height: 22px; } .military-flight-icon.fighter::before, .military-flight-icon.fighter::after { box-shadow: 0 0 5px var(--mil-color); } .military-flight-label { font-size: 7px; color: var(--mil-color); text-transform: uppercase; letter-spacing: 0.3px; margin-top: 1px; white-space: nowrap; text-shadow: 0 0 3px var(--shadow-color), 0 0 6px var(--shadow-color); font-weight: bold; font-family: 'Courier New', monospace; opacity: 0.8; } .military-flight-altitude { font-size: 6px; color: var(--text-dim); font-family: 'Courier New', monospace; opacity: 0.6; text-shadow: 0 0 2px var(--shadow-color); } .military-flight-track { stroke: var(--mil-color, var(--defcon-4)); stroke-opacity: 0.5; } .military-flight-track.usaf, .military-flight-track.usn { stroke: var(--semantic-low); } .military-flight-track.plaaf, .military-flight-track.plan { stroke: var(--semantic-critical); } .military-flight-track.vks { stroke: var(--semantic-high); } @keyframes mil-pulse { 0%, 100% { opacity: 1; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); } 50% { opacity: 0.8; transform: translate(-50%, -50%) scale(calc(var(--marker-scale, 1) * 1.1)); } } @keyframes mil-alert { 0%, 100% { opacity: 1; filter: drop-shadow(0 0 6px var(--mil-color)) drop-shadow(0 0 10px var(--mil-color)); } 50% { opacity: 0.9; filter: drop-shadow(0 0 10px var(--mil-color)) drop-shadow(0 0 20px var(--mil-color)); } } /* ============================================ Military Vessel Tracking Markers ============================================ */ .military-vessel-marker { position: absolute; display: flex; flex-direction: column; align-items: center; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); transform-origin: center; cursor: pointer; z-index: 54; --vessel-color: var(--status-live); } .military-vessel-marker.usn { --vessel-color: var(--semantic-low); } .military-vessel-marker.rn { --vessel-color: var(--semantic-critical); } .military-vessel-marker.plan { --vessel-color: var(--semantic-critical); } .military-vessel-marker.vks { --vessel-color: var(--semantic-high); } .military-vessel-marker.carrier { --vessel-color: var(--semantic-elevated); z-index: 56; } .military-vessel-marker.submarine { --vessel-color: var(--semantic-info); } .military-vessel-marker.dark-vessel { --vessel-color: var(--semantic-critical); animation: dark-vessel-alert 0.8s ease-in-out infinite; } .military-vessel-marker.interesting { animation: vessel-pulse 1.5s ease-in-out infinite; } .military-vessel-icon { width: 16px; height: 16px; position: relative; transition: transform 0.3s ease; } /* Diamond shape - rotated square */ .military-vessel-icon::before { content: ''; position: absolute; top: 50%; left: 50%; width: 10px; height: 10px; background: transparent; border: 2px solid var(--vessel-color); transform: translate(-50%, -50%) rotate(45deg); box-shadow: 0 0 4px var(--vessel-color); } /* Center dot */ .military-vessel-icon::after { content: ''; position: absolute; top: 50%; left: 50%; width: 4px; height: 4px; background: var(--vessel-color); border-radius: 50%; transform: translate(-50%, -50%); box-shadow: 0 0 3px var(--vessel-color); } /* Submarine - hollow circle */ .military-vessel-icon.submarine::before { border-radius: 50%; transform: translate(-50%, -50%); } /* Carrier - filled diamond */ .military-vessel-icon.carrier::before { background: var(--vessel-color); opacity: 0.6; } .military-vessel-label { font-size: 8px; color: var(--vessel-color); text-transform: uppercase; letter-spacing: 0.5px; margin-top: 2px; white-space: nowrap; text-shadow: 0 0 4px var(--bg), 0 0 8px var(--bg); font-weight: bold; max-width: 80px; overflow: hidden; text-overflow: ellipsis; } .dark-vessel-indicator { position: absolute; top: -8px; right: -8px; font-size: 12px; animation: blink 0.5s step-end infinite; } .military-vessel-track { stroke: var(--vessel-color, var(--status-live)); stroke-opacity: 0.6; } @keyframes vessel-pulse { 0%, 100% { opacity: 1; transform: translate(-50%, -50%) scale(var(--marker-scale, 1)); } 50% { opacity: 0.85; transform: translate(-50%, -50%) scale(calc(var(--marker-scale, 1) * 1.08)); } } @keyframes dark-vessel-alert { 0%, 100% { opacity: 1; --vessel-color: var(--semantic-critical); } 50% { opacity: 0.7; --vessel-color: var(--semantic-high); } } @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } } /* ============================================ Military Cluster Markers ============================================ */ .military-cluster-marker { position: absolute; display: flex; flex-direction: column; align-items: center; transform: translate(-50%, -50%); cursor: pointer; z-index: 57; --cluster-color: var(--status-live); opacity: 0.65; } .military-cluster-marker:hover { opacity: 1; } .military-cluster-marker.flight-cluster { --cluster-color: var(--status-live); } .military-cluster-marker.vessel-cluster { --cluster-color: var(--status-live); } .military-cluster-marker.exercise { --cluster-color: var(--semantic-high); opacity: 0.8; } .military-cluster-marker.patrol { --cluster-color: var(--semantic-normal); } .military-cluster-marker.deployment, .military-cluster-marker.transport { --cluster-color: #6b8e23; } /* Targeting reticle style for cluster count */ .military-cluster-marker .cluster-count { font-size: 12px; font-weight: bold; color: var(--cluster-color); font-family: 'Courier New', monospace; text-shadow: 0 0 4px var(--shadow-color); position: relative; padding: 4px 8px; } /* Corner brackets for targeting look */ .military-cluster-marker .cluster-count::before { content: ''; position: absolute; top: 0; left: 0; width: 8px; height: 8px; border-left: 2px solid var(--cluster-color); border-top: 2px solid var(--cluster-color); } .military-cluster-marker .cluster-count::after { content: ''; position: absolute; top: 0; right: 0; width: 8px; height: 8px; border-right: 2px solid var(--cluster-color); border-top: 2px solid var(--cluster-color); } .military-cluster-marker .cluster-label { font-size: 7px; color: var(--cluster-color); text-transform: uppercase; letter-spacing: 0.5px; margin-top: 3px; white-space: nowrap; font-weight: bold; font-family: 'Courier New', monospace; text-shadow: 0 0 3px var(--shadow-color); opacity: 0.85; position: relative; } /* Bottom brackets */ .military-cluster-marker .cluster-label::before { content: ''; position: absolute; bottom: -2px; left: -4px; width: 6px; height: 6px; border-left: 1px solid var(--cluster-color); border-bottom: 1px solid var(--cluster-color); } .military-cluster-marker .cluster-label::after { content: ''; position: absolute; bottom: -2px; right: -4px; width: 6px; height: 6px; border-right: 1px solid var(--cluster-color); border-bottom: 1px solid var(--cluster-color); } @keyframes cluster-pulse { 0%, 100% { opacity: 0.6; transform: translate(-50%, -50%) scale(1); } 50% { opacity: 0.85; transform: translate(-50%, -50%) scale(1.02); } } /* Military Popup Styles */ /* Military popup headers - ensure readable text */ .popup-header.militaryFlight, .popup-header.militaryVessel, .popup-header.military-flight, .popup-header.military-vessel { background: rgba(0, 180, 180, 0.08); } .popup-header.militaryFlightCluster, .popup-header.militaryVesselCluster, .popup-header.military-cluster { background: rgba(57, 255, 20, 0.06); } /* US Military - blue tint */ .popup-header.military-flight.usaf, .popup-header.military-flight.usn, .popup-header.military-flight.usmc, .popup-header.military-flight.usa { background: rgba(59, 130, 246, 0.08); } /* NATO/UK - purple tint */ .popup-header.military-flight.nato, .popup-header.military-flight.raf { background: rgba(99, 102, 241, 0.08); } /* Israel - light blue tint */ .popup-header.military-flight.iaf { background: rgba(96, 165, 250, 0.08); } /* China - lighter red tint for contrast */ .popup-header.military-flight.plaaf, .popup-header.military-flight.plan { background: rgba(248, 113, 113, 0.08); } /* Russia - orange tint for better contrast */ .popup-header.military-flight.vks { background: rgba(251, 146, 60, 0.08); } /* Military popup content - ensure readable text */ .popup-header.military-flight .popup-title, .popup-header.military-vessel .popup-title, .popup-header.military-cluster .popup-title, .popup-header.militaryFlight .popup-title, .popup-header.militaryVessel .popup-title, .popup-header.militaryFlightCluster .popup-title, .popup-header.militaryVesselCluster .popup-title { color: var(--accent); } /* Military popup subtitle - always white for contrast */ .popup-body .popup-subtitle { color: var(--accent); } /* Stat values in military popups - green for readability */ .popup-body .stat-value { color: var(--green, var(--status-live)); } /* Attribution text - brighter */ .popup-attribution { color: var(--text-muted); } .cluster-flights, .cluster-vessels { display: flex; flex-direction: column; gap: 4px; margin-top: 8px; font-size: 11px; } .cluster-flight-item, .cluster-vessel-item { padding: 4px 8px; background: var(--overlay-light); border-radius: 4px; color: var(--accent); border-left: 2px solid var(--accent); } .cluster-more { padding: 4px 8px; color: var(--text-muted); font-style: italic; } .popup-description.alert { color: var(--semantic-critical); font-weight: bold; } .popup-attribution { font-size: 10px; color: var(--text-muted); margin-top: 12px; text-align: right; } .flight-photo { position: relative; margin: 8px 0 4px; border-radius: 4px; overflow: hidden; } .flight-photo img { width: 100%; max-height: 160px; object-fit: cover; display: block; border-radius: 4px; } .flight-photo-credit { position: absolute; bottom: 4px; right: 6px; font-size: 10px; color: rgba(255, 255, 255, 0.85); background: rgba(0, 0, 0, 0.45); padding: 1px 5px; border-radius: 3px; pointer-events: none; } /* ============================================ Activity Indicators & New Item Badges ============================================ */ /* Panel "new" badge in header */ .panel-new-badge { display: inline-flex; align-items: center; justify-content: center; background: var(--accent); color: var(--bg); font-size: 9px; font-weight: bold; padding: 2px 6px; border-radius: 10px; margin-left: 8px; letter-spacing: 0.3px; text-transform: uppercase; white-space: nowrap; position: relative; isolation: isolate; z-index: 0; } .panel-live-count { display: inline-flex; align-items: center; gap: 5px; font-size: 10px; font-weight: 600; color: var(--semantic-critical); letter-spacing: 0.5px; text-transform: uppercase; white-space: nowrap; } .panel-live-count::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--semantic-critical); animation: live-dot-pulse 2s ease-in-out infinite; } @keyframes live-dot-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } } .panel-new-badge.pulse { animation: badge-pulse 1.5s ease-in-out infinite; will-change: transform; } .panel-new-badge.pulse::after { content: ''; position: absolute; inset: -3px; border-radius: inherit; box-shadow: 0 0 8px 2px var(--overlay-heavy); opacity: 0; pointer-events: none; animation: badge-pulse-glow 1.5s ease-in-out infinite; will-change: opacity; } @keyframes badge-pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.05); } } @keyframes badge-pulse-glow { 0%, 100% { opacity: 0; } 50% { opacity: 1; } } /* -- Premium locked panel overlay -- */ .panel-locked-state { display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 1.2rem 1rem; gap: 8px; background: radial-gradient(ellipse at center, rgba(180, 130, 40, 0.06) 0%, transparent 70%); } .panel-locked-icon { color: #d4a843; filter: drop-shadow(0 0 8px rgba(212, 168, 67, 0.3)); } .panel-locked-desc { font-size: 11px; color: var(--text-dim, #888); } .panel-locked-features { list-style: none; padding: 0; margin: 4px 0; font-size: 10px; color: var(--text-dim, #888); text-align: center; } .panel-locked-features li::before { content: "— "; color: #d4a843; } .panel-locked-cta { padding: 6px 18px; font-size: 11px; font-weight: 600; letter-spacing: 0.05em; color: #111; background: linear-gradient(135deg, #d4a843 0%, #b8902e 100%); border: none; border-radius: 4px; cursor: pointer; transition: filter 0.15s; } .panel-locked-cta:hover { filter: brightness(1.15); } /* -- PRO badge (panel header) -- */ .panel-pro-badge { display: inline-flex; align-items: center; font-size: 8px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: #d4a843; border: 1px solid rgba(212, 168, 67, 0.4); border-radius: 3px; padding: 1px 4px; margin-left: 6px; vertical-align: middle; line-height: 1; } /* -- PRO badge (layer toggle) -- */ .layer-pro-badge { display: inline; font-size: 7px; font-weight: 700; letter-spacing: 0.05em; color: #d4a843; border: 1px solid rgba(212, 168, 67, 0.35); border-radius: 2px; padding: 0 3px; margin-left: 4px; vertical-align: middle; } /* * "shown/total" for layers the globe's marker budget is trimming (#5368). * Muted and right-aligned: it reports a limit, it is not a call to action. */ .layer-truncation-count { margin-left: auto; font-size: 8px; font-variant-numeric: tabular-nums; /* Theme token, not a hardcoded white: the layer panel is theme-aware and the light theme's --bg is near-white, which would hide a white badge. */ color: var(--text-dim); white-space: nowrap; /* Hoverable on purpose: the full disclosure lives in the element's `title`, and `pointer-events: none` would suppress the tooltip. Safe to hover and click because the badge is a SIBLING of the