9211 lines
244 KiB
CSS
9211 lines
244 KiB
CSS
/* ═══════════════════════════════════════════════
|
||
GOD'S EYE VIEW — Dark Sci-Fi UI
|
||
Apple meets Blade Runner
|
||
═══════════════════════════════════════════════ */
|
||
|
||
:root {
|
||
--bg-dark: #0a0a0f;
|
||
--glass-bg: rgba(12, 12, 20, 0.72);
|
||
--glass-border: rgba(255, 255, 255, 0.08);
|
||
--glass-border-hover: rgba(255, 255, 255, 0.15);
|
||
--accent: #00d4ff;
|
||
--accent-dim: rgba(0, 212, 255, 0.15);
|
||
--accent-glow: rgba(0, 212, 255, 0.4);
|
||
--text-primary: #e8eaed;
|
||
--text-secondary: rgba(232, 234, 237, 0.5);
|
||
--text-dim: rgba(232, 234, 237, 0.3);
|
||
--font-mono: 'JetBrains Mono', 'SF Mono', 'Fira Code', monospace;
|
||
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
||
--panel-radius: 16px;
|
||
--btn-radius: 10px;
|
||
--transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
||
--transition-smooth: 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
||
--left-stack-x: 52px;
|
||
--right-rail-x: 52px;
|
||
--left-stack-top: 26vh;
|
||
--left-stack-gap: 72px;
|
||
--left-collapsed-width: 176px;
|
||
--display-panel-expanded-width: 272px;
|
||
--cockpit-radio-collapsed-width: 148px;
|
||
--cockpit-radio-expanded-width: 232px;
|
||
}
|
||
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
html, body {
|
||
width: 100%;
|
||
height: 100%;
|
||
overflow: hidden;
|
||
background: var(--bg-dark);
|
||
font-family: var(--font-sans);
|
||
color: var(--text-primary);
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
|
||
/* ── Cesium Container ─────────────────────────── */
|
||
#cesiumContainer {
|
||
width: 100%;
|
||
height: 100%;
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
}
|
||
|
||
/* Unified world-overlay host: detection uses one host-owned blend surface
|
||
beneath the shared text/card canvas; both share one frame path. The root
|
||
holds ONLY the card canvas — it is a stacking context (z-index below), and
|
||
a canvas that blends against the scene cannot live inside one. */
|
||
#world-overlay-root {
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: 6;
|
||
overflow: hidden;
|
||
pointer-events: none;
|
||
}
|
||
|
||
#world-overlay-detection-surface,
|
||
#world-overlay-canvas {
|
||
position: absolute;
|
||
inset: 0;
|
||
display: block;
|
||
width: 100%;
|
||
height: 100%;
|
||
pointer-events: none;
|
||
}
|
||
|
||
/* Scope mask — the explicit circular viewport treatment (see
|
||
src/scopeMask.js for the emergent-artifact history). z2 keeps it above
|
||
the WebGL scene but under the z5 detection surface, preserving the old
|
||
compositing order where detection's blend rode the masked scene. */
|
||
#scope-mask {
|
||
position: absolute;
|
||
inset: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
/* z1 like the celestial ring; the ring is appended LATER so DOM order
|
||
keeps it ABOVE the mask — matching the old stacking, where the DOM
|
||
ring rode above the in-scene scope artifact. Detection (z5) and the
|
||
overlay root (z6) stay above both. */
|
||
z-index: 1;
|
||
pointer-events: none;
|
||
}
|
||
|
||
/* The detection surface is host-owned but parented into #cesiumContainer
|
||
(position:absolute, z-index:auto — NOT a stacking context) so its
|
||
`mix-blend-mode: screen` composites against the WebGL scene. z5 keeps it
|
||
under the z6 root that carries the shared card canvas; do not move this
|
||
surface inside #world-overlay-root, which would isolate the blend. */
|
||
#world-overlay-detection-surface {
|
||
z-index: 5;
|
||
}
|
||
|
||
/* Canvas cards retain their spatial renderer; this parallel focusable list
|
||
exposes only the currently painted actionable targets to assistive tech. */
|
||
.world-overlay-accessibility {
|
||
position: fixed;
|
||
width: 1px;
|
||
height: 1px;
|
||
padding: 0;
|
||
margin: -1px;
|
||
overflow: hidden;
|
||
clip: rect(0, 0, 0, 0);
|
||
white-space: nowrap;
|
||
border: 0;
|
||
}
|
||
|
||
/* ── Source-backed cockpit weather ─────────────
|
||
Low-resolution GPU cloud pass composited only inside the cockpit keyhole. */
|
||
#cockpit-cloud-effects {
|
||
position: fixed;
|
||
inset: 0;
|
||
z-index: 7;
|
||
display: none;
|
||
width: 100vw;
|
||
height: 100vh;
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
clip-path: circle(min(40vw, 52vh) at 50% 50%);
|
||
filter: blur(0.7px) saturate(0.72) contrast(1.08);
|
||
transform: translateZ(0);
|
||
transition: opacity 900ms ease;
|
||
}
|
||
|
||
body.cockpit-mode #cockpit-cloud-effects.active {
|
||
display: block;
|
||
opacity: 0.86;
|
||
}
|
||
|
||
/* ── Full-globe celestial keyhole ring ─────── */
|
||
.celestial-ring-overlay {
|
||
position: absolute;
|
||
inset: 0;
|
||
/* Above the z1 scope mask regardless of DOM order (the ring is built by
|
||
StyleManager before the scope installs) — the ring always rode above
|
||
the scope treatment. Detection (z5) and the overlay root (z6) stay on
|
||
top of both. */
|
||
z-index: 2;
|
||
overflow: hidden;
|
||
pointer-events: none;
|
||
opacity: 0;
|
||
visibility: hidden;
|
||
transition: opacity 300ms ease, visibility 300ms ease;
|
||
}
|
||
|
||
.celestial-ring-overlay.visible {
|
||
opacity: 1;
|
||
visibility: visible;
|
||
}
|
||
|
||
.celestial-ring-overlay.disabled {
|
||
display: none;
|
||
}
|
||
|
||
.celestial-ring-canvas {
|
||
position: absolute;
|
||
inset: 0;
|
||
display: block;
|
||
transform-origin: 50% 50%;
|
||
will-change: transform, opacity;
|
||
}
|
||
|
||
.celestial-ring-outline {
|
||
position: absolute;
|
||
box-sizing: border-box;
|
||
border: 0.8px solid rgba(151, 218, 232, 0.095);
|
||
border-radius: 50%;
|
||
will-change: width, height;
|
||
}
|
||
|
||
.celestial-marker {
|
||
position: absolute;
|
||
z-index: 2;
|
||
transform: translate(-50%, -50%);
|
||
font-family: 'Material Symbols Outlined';
|
||
font-size: 20px;
|
||
font-weight: 400;
|
||
font-style: normal;
|
||
line-height: 1;
|
||
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 20;
|
||
transition: opacity 120ms linear;
|
||
user-select: none;
|
||
}
|
||
|
||
.celestial-sun {
|
||
color: rgba(231, 194, 72, 0.92);
|
||
text-shadow: 0 0 7px rgba(231, 194, 72, 0.72), 0 0 18px rgba(231, 194, 72, 0.3);
|
||
}
|
||
|
||
.celestial-moon {
|
||
color: rgba(55, 211, 239, 0.84);
|
||
text-shadow: 0 0 7px rgba(55, 211, 239, 0.65), 0 0 17px rgba(55, 211, 239, 0.25);
|
||
}
|
||
|
||
#celestial-toggle:disabled {
|
||
cursor: not-allowed;
|
||
opacity: 0.42;
|
||
}
|
||
|
||
/* Hide Cesium default UI elements */
|
||
.cesium-viewer-toolbar,
|
||
.cesium-viewer-animationContainer,
|
||
.cesium-viewer-timelineContainer,
|
||
.cesium-viewer-bottom,
|
||
.cesium-viewer-fullscreenContainer,
|
||
.cesium-viewer-vrContainer,
|
||
.cesium-viewer-geocoderContainer,
|
||
.cesium-viewer-selectionIndicatorContainer,
|
||
.cesium-viewer-infoBoxContainer {
|
||
display: none !important;
|
||
}
|
||
|
||
/* Data-source attribution (Google Maps / 3D Tiles, etc.).
|
||
Required by the Google Maps Platform Terms of Service — keep it visible.
|
||
Styled to be unobtrusive but legible against the dark UI. */
|
||
#cesium-credits {
|
||
position: fixed;
|
||
/* Bottom-LEFT corner, mirrored from the GEV mic pill (right:36/bottom:36) so the two bottom
|
||
corners are symmetric; sits below the coordinate HUD (.hud-bottom-left, bottom:180). Was
|
||
dead-center at the bottom, tucked under the LOCATIONS/STYLE panels. Must stay visible (Google
|
||
/Cesium attribution ToS). */
|
||
bottom: 36px;
|
||
left: 36px;
|
||
z-index: 90;
|
||
max-width: 90vw;
|
||
/* Keep the Google logo + "Data attribution" link on ONE line — they were wrapping to a second
|
||
row (looked like it was falling over). nowrap + a roomy max-width holds them inline. */
|
||
white-space: nowrap;
|
||
pointer-events: auto;
|
||
font-family: var(--font-mono);
|
||
font-size: 10px;
|
||
color: rgba(232, 234, 237, 0.55);
|
||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.9);
|
||
}
|
||
#cesium-credits .cesium-credit-logoContainer,
|
||
#cesium-credits .cesium-credit-textContainer,
|
||
#cesium-credits .cesium-credit-expand-link {
|
||
display: inline-block;
|
||
vertical-align: middle;
|
||
}
|
||
#cesium-credits a,
|
||
#cesium-credits .cesium-credit-expand-link {
|
||
color: rgba(232, 234, 237, 0.7);
|
||
}
|
||
|
||
/* Cesium's stock attribution lightbox grows with every registered data source.
|
||
Keep the title and close affordance fixed while the complete, unabridged
|
||
credit list wraps and scrolls inside a compact panel. */
|
||
.cesium-credit-lightbox-overlay {
|
||
z-index: 200 !important;
|
||
}
|
||
|
||
.cesium-credit-lightbox {
|
||
display: flex;
|
||
flex-direction: column;
|
||
width: 470px;
|
||
max-width: calc(100vw - 2rem);
|
||
max-height: min(70dvh, 36rem);
|
||
overflow: hidden;
|
||
}
|
||
|
||
.cesium-credit-lightbox > ul {
|
||
flex: 1;
|
||
min-height: 0;
|
||
margin: 0;
|
||
padding: 8px 20px 14px 40px;
|
||
overflow-x: hidden;
|
||
overflow-y: auto;
|
||
overscroll-behavior: contain;
|
||
scrollbar-gutter: stable;
|
||
font-size: 12px !important;
|
||
line-height: 1.35;
|
||
white-space: normal;
|
||
}
|
||
|
||
.cesium-credit-lightbox > ul > li {
|
||
padding-bottom: 5px;
|
||
overflow-wrap: anywhere;
|
||
}
|
||
|
||
@media (max-width: 575px) {
|
||
.cesium-credit-lightbox {
|
||
width: 100% !important;
|
||
max-width: none !important;
|
||
height: 100% !important;
|
||
max-height: 100dvh !important;
|
||
margin: 0 !important;
|
||
}
|
||
}
|
||
/* Clean-view / recording: the Google + Cesium attribution MUST stay visible.
|
||
Google Maps Platform ToS and Cesium's terms require the credit whenever the
|
||
content is displayed — and these are exactly the modes used to record demos
|
||
and launch videos, so hiding #cesium-credits here (as it was before) shipped
|
||
non-compliant footage. The full credit line — Cesium/Ion logo, "Google Maps",
|
||
and the "Data attribution" link that opens the per-layer license popover —
|
||
stays on screen; it's already styled small and unobtrusive above. The GEV
|
||
chrome (panels/HUD) still fades via its own rules; only the required notice
|
||
is exempt. (Note: Cesium re-applies inline styles on the credit elements each
|
||
frame, so the on-screen credit content is owned by Cesium's update loop, not
|
||
CSS overrides — we deliberately don't fight it here.) */
|
||
|
||
#gev-voice-control {
|
||
position: fixed;
|
||
right: 36px;
|
||
bottom: 36px;
|
||
/* Z ladder: panels 100-139, voice pill 150, toast 200, clean-view-exit 300 */
|
||
z-index: 150;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
min-width: 214px;
|
||
padding: 9px 14px;
|
||
color: var(--text-primary);
|
||
background: var(--glass-bg);
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: 999px;
|
||
box-shadow:
|
||
0 8px 32px rgba(0, 0, 0, 0.5),
|
||
0 0 0 1px rgba(255, 255, 255, 0.03) inset,
|
||
0 1px 0 rgba(255, 255, 255, 0.06) inset,
|
||
0 0 20px rgba(0, 212, 255, 0.08);
|
||
backdrop-filter: blur(24px) saturate(1.4);
|
||
-webkit-backdrop-filter: blur(24px) saturate(1.4);
|
||
font-family: var(--font-mono);
|
||
pointer-events: auto;
|
||
}
|
||
|
||
#gev-voice-button {
|
||
width: 72px;
|
||
height: 34px;
|
||
flex: 0 0 auto;
|
||
color: var(--accent);
|
||
background: rgba(0, 212, 255, 0.06);
|
||
border: 1px solid rgba(0, 212, 255, 0.28);
|
||
border-radius: var(--btn-radius);
|
||
font-family: var(--font-mono);
|
||
font-size: 10px;
|
||
letter-spacing: 0;
|
||
cursor: pointer;
|
||
}
|
||
|
||
#gev-voice-button:hover {
|
||
color: #ffffff;
|
||
border-color: var(--accent);
|
||
box-shadow: 0 0 12px rgba(0, 212, 255, 0.22);
|
||
}
|
||
|
||
.gev-voice-readout {
|
||
min-width: 0;
|
||
line-height: 1.2;
|
||
text-align: right;
|
||
}
|
||
|
||
#gev-voice-status {
|
||
font-size: 10px;
|
||
color: var(--accent);
|
||
}
|
||
|
||
#gev-voice-detail {
|
||
max-width: 132px;
|
||
margin-top: 2px;
|
||
overflow: hidden;
|
||
color: var(--text-secondary);
|
||
font-size: 9px;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
#gev-voice-control[data-status='listening'] {
|
||
border-color: rgba(92, 255, 198, 0.45);
|
||
}
|
||
|
||
#gev-voice-control[data-status='listening'] #gev-voice-status {
|
||
color: #5cffc6;
|
||
}
|
||
|
||
#gev-voice-control[data-status='executing'] {
|
||
border-color: rgba(255, 220, 120, 0.55);
|
||
}
|
||
|
||
#gev-voice-control[data-status='executing'] #gev-voice-status {
|
||
color: #ffdc78;
|
||
}
|
||
|
||
#gev-voice-control[data-status='error'] {
|
||
align-items: flex-start;
|
||
width: min(440px, calc(100vw - 72px));
|
||
border-color: rgba(255, 92, 110, 0.6);
|
||
/* Multi-line error block reads as a panel, not a capsule */
|
||
border-radius: var(--panel-radius);
|
||
}
|
||
|
||
#gev-voice-control[data-status='error'] #gev-voice-status {
|
||
color: #ff5c6e;
|
||
}
|
||
|
||
#gev-voice-control[data-status='error'] .gev-voice-readout {
|
||
flex: 1;
|
||
text-align: left;
|
||
}
|
||
|
||
#gev-voice-control[data-status='error'] #gev-voice-detail {
|
||
max-width: none;
|
||
overflow: visible;
|
||
color: #ffb4bd;
|
||
line-height: 1.45;
|
||
text-overflow: clip;
|
||
white-space: pre-wrap;
|
||
overflow-wrap: anywhere;
|
||
user-select: text;
|
||
}
|
||
|
||
/* ── Title Bar ────────────────────────────────── */
|
||
#title-bar {
|
||
position: fixed;
|
||
top: 32px;
|
||
left: 36px;
|
||
z-index: 100;
|
||
pointer-events: none;
|
||
user-select: none;
|
||
}
|
||
|
||
#title-bar .title-glow {
|
||
position: absolute;
|
||
top: -20px;
|
||
left: -20px;
|
||
width: 200px;
|
||
height: 80px;
|
||
background: radial-gradient(ellipse, var(--accent-dim) 0%, transparent 70%);
|
||
filter: blur(20px);
|
||
opacity: 0.6;
|
||
}
|
||
|
||
#title-bar h1 {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
font-family: var(--font-mono);
|
||
font-size: 26px;
|
||
font-weight: 600;
|
||
letter-spacing: 8px;
|
||
color: var(--text-primary);
|
||
text-shadow: 0 0 30px var(--accent-glow);
|
||
position: relative;
|
||
}
|
||
|
||
#title-bar .title-logo {
|
||
position: relative;
|
||
display: block;
|
||
width: 52px;
|
||
height: auto;
|
||
filter: drop-shadow(0 0 12px rgba(0, 246, 255, 0.5));
|
||
}
|
||
|
||
#title-bar .title-logo::before,
|
||
#title-bar .title-logo::after {
|
||
--radio-broadcast-opacity: .28;
|
||
content: '';
|
||
position: absolute;
|
||
z-index: 1;
|
||
left: 50%;
|
||
top: -9px;
|
||
width: 13px;
|
||
height: 7px;
|
||
border: 1px solid var(--accent);
|
||
border-bottom: 0;
|
||
border-radius: 999px 999px 0 0;
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
transform: translateX(-50%);
|
||
transform-origin: 50% 100%;
|
||
}
|
||
|
||
#title-bar .title-logo::after {
|
||
--radio-broadcast-opacity: .17;
|
||
top: -15px;
|
||
width: 27px;
|
||
height: 13px;
|
||
}
|
||
|
||
#title-bar.radio-broadcasting .title-logo::before,
|
||
#title-bar.radio-broadcasting .title-logo::after {
|
||
opacity: var(--radio-broadcast-opacity);
|
||
animation: title-radio-broadcast 1.8s ease-in-out infinite;
|
||
}
|
||
|
||
#title-bar.radio-broadcasting .title-logo::after { animation-delay: .28s; }
|
||
|
||
@keyframes title-radio-broadcast {
|
||
0%, 100% {
|
||
opacity: calc(var(--radio-broadcast-opacity) * .55);
|
||
transform: translateX(-50%) scale(.94);
|
||
}
|
||
50% {
|
||
opacity: var(--radio-broadcast-opacity);
|
||
transform: translateX(-50%) scale(1);
|
||
}
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
#title-bar.radio-broadcasting .title-logo::before,
|
||
#title-bar.radio-broadcasting .title-logo::after {
|
||
animation: none;
|
||
}
|
||
}
|
||
|
||
.brand-logo {
|
||
aspect-ratio: 775 / 520;
|
||
overflow: visible;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.brand-logo > img,
|
||
.brand-logo > svg {
|
||
display: block;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
#title-bar .title-accent,
|
||
.loader-content .title-accent {
|
||
color: var(--accent);
|
||
font-weight: 300;
|
||
}
|
||
|
||
#title-bar .subtitle {
|
||
font-family: var(--font-mono);
|
||
font-size: 11px;
|
||
letter-spacing: 5px;
|
||
color: var(--text-dim);
|
||
margin-top: 8px;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
/* ── Style Indicator ──────────────────────────── */
|
||
#style-indicator {
|
||
position: fixed;
|
||
top: 32px;
|
||
right: 36px;
|
||
z-index: 100;
|
||
pointer-events: none;
|
||
user-select: none;
|
||
text-align: right;
|
||
}
|
||
|
||
#style-indicator .indicator-label {
|
||
display: block;
|
||
font-family: var(--font-mono);
|
||
font-size: 10px;
|
||
letter-spacing: 3px;
|
||
color: var(--text-dim);
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
#style-indicator .indicator-value {
|
||
display: block;
|
||
font-family: var(--font-mono);
|
||
font-size: 16px;
|
||
font-weight: 500;
|
||
letter-spacing: 5px;
|
||
color: var(--accent);
|
||
margin-top: 4px;
|
||
text-shadow: 0 0 20px var(--accent-glow);
|
||
transition: var(--transition-smooth);
|
||
}
|
||
|
||
/* ── Control Panel ────────────────────────────── */
|
||
#control-panel {
|
||
position: fixed;
|
||
bottom: 36px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
z-index: 100;
|
||
width: auto;
|
||
max-width: 680px;
|
||
}
|
||
|
||
#control-panel .panel-glow {
|
||
position: absolute;
|
||
inset: -30px;
|
||
background: radial-gradient(ellipse at center bottom, var(--accent-dim) 0%, transparent 60%);
|
||
filter: blur(30px);
|
||
opacity: 0.4;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.panel-inner {
|
||
position: relative;
|
||
background: var(--glass-bg);
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: var(--panel-radius);
|
||
padding: 16px 20px 18px;
|
||
backdrop-filter: blur(24px) saturate(1.4);
|
||
-webkit-backdrop-filter: blur(24px) saturate(1.4);
|
||
box-shadow:
|
||
0 8px 32px rgba(0, 0, 0, 0.5),
|
||
0 0 0 1px rgba(255, 255, 255, 0.03) inset,
|
||
0 1px 0 rgba(255, 255, 255, 0.06) inset;
|
||
}
|
||
|
||
.panel-header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
margin-bottom: 14px;
|
||
padding: 0 4px;
|
||
}
|
||
|
||
.panel-mini-status {
|
||
display: none;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding: 0 6px 2px;
|
||
}
|
||
|
||
#control-panel.collapsed .panel-mini-status {
|
||
display: flex;
|
||
}
|
||
|
||
.panel-mini-label {
|
||
font-family: var(--font-mono);
|
||
font-size: 8px;
|
||
letter-spacing: 1.4px;
|
||
color: var(--text-dim);
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.panel-mini-value {
|
||
font-family: var(--font-mono);
|
||
font-size: 9px;
|
||
letter-spacing: 1.8px;
|
||
color: var(--accent);
|
||
text-transform: uppercase;
|
||
text-shadow: 0 0 8px rgba(0, 212, 255, 0.3);
|
||
}
|
||
|
||
.panel-drag-handle {
|
||
cursor: grab;
|
||
user-select: none;
|
||
}
|
||
|
||
.panel-drag-handle:active {
|
||
cursor: grabbing;
|
||
}
|
||
|
||
.panel-drag-handle.compact {
|
||
margin-left: auto;
|
||
margin-bottom: 2px;
|
||
padding: 2px 8px;
|
||
border-radius: 999px;
|
||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||
background: rgba(255, 255, 255, 0.04);
|
||
font-family: var(--font-mono);
|
||
font-size: 8px;
|
||
letter-spacing: 1.4px;
|
||
color: var(--text-dim);
|
||
}
|
||
|
||
.panel-drag-handle.compact:hover {
|
||
color: var(--text-primary);
|
||
border-color: var(--glass-border-hover);
|
||
}
|
||
|
||
.panel-dragging {
|
||
opacity: 0.96;
|
||
}
|
||
|
||
.panel-title {
|
||
font-family: var(--font-mono);
|
||
font-size: 9px;
|
||
letter-spacing: 3px;
|
||
color: var(--text-dim);
|
||
text-transform: uppercase;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.panel-divider {
|
||
flex: 1;
|
||
height: 1px;
|
||
background: linear-gradient(to right, var(--glass-border), transparent);
|
||
}
|
||
|
||
.panel-collapse-btn {
|
||
width: 22px;
|
||
height: 22px;
|
||
border-radius: 6px;
|
||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||
background: rgba(255, 255, 255, 0.03);
|
||
color: var(--text-dim);
|
||
font-family: var(--font-mono);
|
||
font-size: 13px;
|
||
line-height: 1;
|
||
cursor: pointer;
|
||
transition: all var(--transition-fast);
|
||
}
|
||
|
||
.panel-collapse-btn:hover {
|
||
border-color: var(--glass-border-hover);
|
||
color: var(--text-primary);
|
||
background: rgba(255, 255, 255, 0.07);
|
||
}
|
||
|
||
/* ── Button Grid ──────────────────────────────── */
|
||
.button-grid {
|
||
display: flex;
|
||
gap: 8px;
|
||
overflow-x: auto;
|
||
scroll-behavior: smooth;
|
||
scrollbar-width: none;
|
||
-ms-overflow-style: none;
|
||
}
|
||
|
||
.button-grid::-webkit-scrollbar {
|
||
display: none;
|
||
}
|
||
|
||
.style-btn {
|
||
position: relative;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 14px 16px 10px;
|
||
min-width: 78px;
|
||
flex-shrink: 0;
|
||
background: rgba(255, 255, 255, 0.03);
|
||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||
border-radius: var(--btn-radius);
|
||
cursor: pointer;
|
||
transition: all var(--transition-fast);
|
||
overflow: hidden;
|
||
outline: none;
|
||
}
|
||
|
||
.style-btn::before {
|
||
content: '';
|
||
position: absolute;
|
||
inset: 0;
|
||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.04) 0%, transparent 100%);
|
||
opacity: 0;
|
||
transition: opacity var(--transition-fast);
|
||
}
|
||
|
||
.style-btn:hover {
|
||
border-color: var(--glass-border-hover);
|
||
background: rgba(255, 255, 255, 0.06);
|
||
transform: translateY(-1px);
|
||
}
|
||
|
||
.style-btn:hover::before {
|
||
opacity: 1;
|
||
}
|
||
|
||
.style-btn:active {
|
||
transform: translateY(0);
|
||
}
|
||
|
||
.style-btn.active {
|
||
border-color: var(--accent);
|
||
background: var(--accent-dim);
|
||
box-shadow:
|
||
0 0 20px rgba(0, 212, 255, 0.15),
|
||
0 0 0 1px rgba(0, 212, 255, 0.1) inset;
|
||
}
|
||
|
||
.style-btn.active .btn-icon {
|
||
color: var(--accent);
|
||
text-shadow: 0 0 12px var(--accent-glow);
|
||
}
|
||
|
||
.style-btn.active .btn-label {
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.btn-icon {
|
||
font-size: 20px;
|
||
line-height: 1;
|
||
color: var(--text-secondary);
|
||
transition: all var(--transition-fast);
|
||
}
|
||
|
||
.btn-label {
|
||
font-family: var(--font-sans);
|
||
font-size: 11px;
|
||
font-weight: 500;
|
||
color: var(--text-secondary);
|
||
letter-spacing: 0.3px;
|
||
transition: color var(--transition-fast);
|
||
}
|
||
|
||
.btn-key {
|
||
position: absolute;
|
||
top: 6px;
|
||
right: 6px;
|
||
font-family: var(--font-mono);
|
||
font-size: 8px;
|
||
color: var(--text-dim);
|
||
opacity: 0;
|
||
transition: opacity var(--transition-fast);
|
||
}
|
||
|
||
.style-btn:hover .btn-key,
|
||
.style-btn.active .btn-key {
|
||
opacity: 1;
|
||
}
|
||
|
||
/* ── Loading Screen ───────────────────────────── */
|
||
#loading-screen {
|
||
position: fixed;
|
||
inset: 0;
|
||
z-index: 1000;
|
||
background: var(--bg-dark);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: opacity 0.8s ease, visibility 0.8s ease;
|
||
}
|
||
|
||
#loading-screen.hidden {
|
||
opacity: 0;
|
||
visibility: hidden;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.loader-content {
|
||
text-align: center;
|
||
}
|
||
|
||
.loader-logo {
|
||
display: block;
|
||
width: 128px;
|
||
height: auto;
|
||
margin: 0 auto 24px;
|
||
filter: drop-shadow(0 0 24px rgba(0, 246, 255, 0.42));
|
||
animation: logo-pulse 2s ease-in-out infinite;
|
||
}
|
||
|
||
@keyframes logo-pulse {
|
||
0%, 100% { opacity: 0.72; transform: scale(0.98); }
|
||
50% { opacity: 1; transform: scale(1.02); }
|
||
}
|
||
|
||
.loader-content h2 {
|
||
font-family: var(--font-mono);
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
letter-spacing: 6px;
|
||
color: var(--text-primary);
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.loader-status {
|
||
font-family: var(--font-mono);
|
||
font-size: 11px;
|
||
letter-spacing: 2px;
|
||
color: var(--text-dim);
|
||
animation: pulse 2s ease-in-out infinite;
|
||
}
|
||
|
||
@keyframes pulse {
|
||
0%, 100% { opacity: 0.4; }
|
||
50% { opacity: 1; }
|
||
}
|
||
|
||
/* ── Post-Processing Toggles ─────────────────── */
|
||
#pp-toggles {
|
||
--pp-expanded-width: var(--display-panel-expanded-width);
|
||
position: relative;
|
||
z-index: 110;
|
||
width: var(--pp-expanded-width);
|
||
max-width: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-end;
|
||
gap: 7px;
|
||
}
|
||
|
||
#pp-toggles:not(.collapsed) {
|
||
box-sizing: border-box;
|
||
padding: 8px;
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: var(--panel-radius);
|
||
background: var(--glass-bg);
|
||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.42), inset 0 1px 0 rgba(255, 255, 255, 0.04);
|
||
backdrop-filter: blur(24px) saturate(1.4);
|
||
-webkit-backdrop-filter: blur(24px) saturate(1.4);
|
||
}
|
||
|
||
#pp-toggles:not(.collapsed) > .pp-header-row,
|
||
#pp-toggles:not(.collapsed) > .pp-toggle-group,
|
||
#pp-toggles:not(.collapsed) > #clean-view-toggle {
|
||
width: 100%;
|
||
}
|
||
|
||
.pp-toggle-btn {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 5px;
|
||
padding: 7px 12px;
|
||
background: var(--glass-bg);
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: 8px;
|
||
backdrop-filter: blur(16px);
|
||
-webkit-backdrop-filter: blur(16px);
|
||
cursor: pointer;
|
||
transition: all var(--transition-fast);
|
||
outline: none;
|
||
}
|
||
|
||
.pp-toggle-group {
|
||
width: var(--pp-expanded-width);
|
||
max-width: 100%;
|
||
}
|
||
|
||
#pp-toggles .pp-toggle-btn {
|
||
width: 100%;
|
||
min-height: 38px;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
#pp-toggles .pp-header-row {
|
||
width: var(--pp-expanded-width);
|
||
max-width: 100%;
|
||
min-height: 42px;
|
||
box-sizing: border-box;
|
||
margin-left: auto;
|
||
margin-bottom: 0;
|
||
padding: 8px 10px 8px 14px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 8px;
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: var(--panel-radius);
|
||
background: var(--glass-bg);
|
||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.42), inset 0 1px 0 rgba(255, 255, 255, 0.04);
|
||
backdrop-filter: blur(24px) saturate(1.4);
|
||
-webkit-backdrop-filter: blur(24px) saturate(1.4);
|
||
cursor: default;
|
||
}
|
||
|
||
/* Expanded Display already owns the glass shell. Keep its header visually
|
||
* integrated with that container, matching the other expanded panel headers;
|
||
* the collapsed launcher retains the standalone card treatment above. */
|
||
#pp-toggles:not(.collapsed) > .pp-header-row {
|
||
min-height: 32px;
|
||
padding: 0 4px;
|
||
border: 0;
|
||
border-radius: 0;
|
||
background: transparent;
|
||
box-shadow: none;
|
||
backdrop-filter: none;
|
||
-webkit-backdrop-filter: none;
|
||
}
|
||
|
||
#pp-toggles .pp-header-label {
|
||
font-family: var(--font-mono);
|
||
font-size: 8px;
|
||
letter-spacing: 1.4px;
|
||
color: var(--text-dim);
|
||
}
|
||
|
||
#pp-toggles > .pp-header-row .pp-collapse-btn {
|
||
width: 20px;
|
||
height: 20px;
|
||
border-radius: 6px;
|
||
font-size: 12px;
|
||
padding: 0;
|
||
}
|
||
|
||
#pp-toggles.collapsed {
|
||
gap: 0;
|
||
}
|
||
|
||
#pp-toggles.collapsed .pp-header-row {
|
||
width: var(--right-collapsed-width, 132px);
|
||
}
|
||
|
||
#pp-toggles.collapsed .pp-toggle-group,
|
||
#pp-toggles.collapsed #clean-view-toggle,
|
||
#pp-toggles.collapsed #param-slider-panel {
|
||
display: none;
|
||
}
|
||
|
||
.pp-toggle-btn:hover {
|
||
border-color: var(--glass-border-hover);
|
||
background: rgba(255, 255, 255, 0.06);
|
||
}
|
||
|
||
.pp-toggle-btn.active {
|
||
border-color: var(--accent);
|
||
background: var(--accent-dim);
|
||
box-shadow: 0 0 12px rgba(0, 212, 255, 0.15);
|
||
}
|
||
|
||
.pp-icon {
|
||
font-size: 14px;
|
||
line-height: 1;
|
||
}
|
||
|
||
.pp-icon.material-symbols-outlined {
|
||
width: 14px;
|
||
overflow: hidden;
|
||
font-family: 'Material Symbols Outlined';
|
||
font-size: 14px;
|
||
font-weight: 400;
|
||
font-style: normal;
|
||
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 20;
|
||
}
|
||
|
||
.pp-label {
|
||
font-family: var(--font-mono);
|
||
font-size: 9px;
|
||
letter-spacing: 1.5px;
|
||
color: var(--text-secondary);
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.pp-toggle-btn.active .pp-label {
|
||
color: var(--accent);
|
||
}
|
||
|
||
/* ── Bloom Slider (inline with toggle) ───────── */
|
||
.pp-toggle-group {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0;
|
||
}
|
||
|
||
.pp-slider-row {
|
||
display: none;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 5px 10px 6px;
|
||
background: var(--glass-bg);
|
||
border: 1px solid var(--glass-border);
|
||
border-top: none;
|
||
border-radius: 0 0 8px 8px;
|
||
backdrop-filter: blur(16px);
|
||
-webkit-backdrop-filter: blur(16px);
|
||
}
|
||
|
||
.pp-slider-row.visible {
|
||
display: flex;
|
||
}
|
||
|
||
.pp-toggle-group .pp-toggle-btn {
|
||
transition: all var(--transition-fast), border-radius var(--transition-fast);
|
||
}
|
||
|
||
.pp-toggle-group .pp-slider-row.visible ~ .pp-toggle-btn,
|
||
.pp-toggle-group:has(.pp-slider-row.visible) .pp-toggle-btn {
|
||
border-radius: 8px 8px 0 0;
|
||
}
|
||
|
||
.pp-slider {
|
||
flex: 1;
|
||
-webkit-appearance: none;
|
||
appearance: none;
|
||
height: 3px;
|
||
background: rgba(255, 255, 255, 0.08);
|
||
border-radius: 2px;
|
||
outline: none;
|
||
cursor: pointer;
|
||
min-width: 60px;
|
||
}
|
||
|
||
.pp-slider::-webkit-slider-thumb {
|
||
-webkit-appearance: none;
|
||
appearance: none;
|
||
width: 10px;
|
||
height: 10px;
|
||
border-radius: 50%;
|
||
background: var(--accent);
|
||
box-shadow: 0 0 6px var(--accent-glow);
|
||
cursor: pointer;
|
||
}
|
||
|
||
.pp-slider::-moz-range-thumb {
|
||
width: 10px;
|
||
height: 10px;
|
||
border-radius: 50%;
|
||
background: var(--accent);
|
||
border: none;
|
||
box-shadow: 0 0 6px var(--accent-glow);
|
||
cursor: pointer;
|
||
}
|
||
|
||
.pp-slider-value {
|
||
font-family: var(--font-mono);
|
||
font-size: 9px;
|
||
letter-spacing: 0.5px;
|
||
color: var(--accent);
|
||
min-width: 28px;
|
||
text-align: right;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
/* Quantitative companion sliders share Display / Sharpen's visible rail,
|
||
* circular thumb, glow, and value treatment while retaining a taller hit area. */
|
||
.gev-quantitative-slider {
|
||
width: 100%;
|
||
min-width: 0;
|
||
height: 18px;
|
||
margin: 0;
|
||
-webkit-appearance: none;
|
||
appearance: none;
|
||
background: transparent;
|
||
outline: none;
|
||
cursor: pointer;
|
||
}
|
||
.gev-quantitative-slider::-webkit-slider-runnable-track {
|
||
height: 3px;
|
||
border-radius: 2px;
|
||
background: rgba(255, 255, 255, 0.08);
|
||
}
|
||
.gev-quantitative-slider::-webkit-slider-thumb {
|
||
width: 10px;
|
||
height: 10px;
|
||
margin-top: -3.5px;
|
||
border: 0;
|
||
border-radius: 50%;
|
||
-webkit-appearance: none;
|
||
appearance: none;
|
||
background: var(--accent);
|
||
box-shadow: 0 0 6px var(--accent-glow);
|
||
cursor: pointer;
|
||
}
|
||
.gev-quantitative-slider::-moz-range-track,
|
||
.gev-quantitative-slider::-moz-range-progress {
|
||
height: 3px;
|
||
border: 0;
|
||
border-radius: 2px;
|
||
background: rgba(255, 255, 255, 0.08);
|
||
}
|
||
.gev-quantitative-slider::-moz-range-thumb {
|
||
width: 10px;
|
||
height: 10px;
|
||
border: 0;
|
||
border-radius: 50%;
|
||
background: var(--accent);
|
||
box-shadow: 0 0 6px var(--accent-glow);
|
||
cursor: pointer;
|
||
}
|
||
.gev-quantitative-slider:focus-visible {
|
||
border-radius: 4px;
|
||
outline: 1px solid color-mix(in srgb, var(--accent) 80%, transparent);
|
||
outline-offset: 2px;
|
||
}
|
||
.gev-quantitative-slider:disabled {
|
||
opacity: .42;
|
||
cursor: not-allowed;
|
||
}
|
||
.gev-slider-value {
|
||
min-width: 28px;
|
||
color: var(--accent);
|
||
font-family: var(--font-mono);
|
||
font-size: 9px;
|
||
letter-spacing: .5px;
|
||
text-align: right;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.pp-slider-mini-label {
|
||
font-family: var(--font-mono);
|
||
font-size: 8px;
|
||
letter-spacing: 1px;
|
||
color: var(--text-dim);
|
||
text-transform: uppercase;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.detection-slider-row {
|
||
min-width: 170px;
|
||
padding: 5px 8px 6px;
|
||
}
|
||
|
||
#detection-slider-row.visible,
|
||
#detection-allocation-row.visible,
|
||
#detection-fade-row.visible {
|
||
border-radius: 0;
|
||
}
|
||
|
||
.detection-allocation-row {
|
||
min-width: 170px;
|
||
padding: 5px 8px 6px;
|
||
}
|
||
|
||
.detection-fade-row,
|
||
.detection-opacity-row {
|
||
min-width: 170px;
|
||
padding: 5px 8px 6px;
|
||
}
|
||
|
||
.detection-allocation-seg .pp-mode-btn {
|
||
font-size: 8px;
|
||
letter-spacing: 0.35px;
|
||
}
|
||
|
||
#hud-layout-row {
|
||
min-width: 200px;
|
||
}
|
||
|
||
/* Map Source tiles live with Visual Presets in the bottom command tray. */
|
||
.map-source-section {
|
||
display: grid;
|
||
gap: 6px;
|
||
margin-top: 8px;
|
||
padding-top: 8px;
|
||
border-top: 1px solid rgba(123, 189, 211, 0.18);
|
||
}
|
||
|
||
.map-source-heading {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
color: rgba(190, 221, 230, 0.62);
|
||
font-family: var(--font-mono);
|
||
font-size: 8px;
|
||
letter-spacing: 1.35px;
|
||
}
|
||
|
||
.map-stack-chip-row {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||
gap: 4px;
|
||
}
|
||
|
||
.map-stack-chip {
|
||
display: inline-flex;
|
||
align-items: baseline;
|
||
justify-content: center;
|
||
gap: 4px;
|
||
padding: 4px 7px;
|
||
font-family: var(--font-mono);
|
||
font-size: 9px;
|
||
letter-spacing: 0.6px;
|
||
text-transform: uppercase;
|
||
white-space: nowrap;
|
||
color: var(--text-dim);
|
||
background: rgba(255, 255, 255, 0.04);
|
||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
/* Explicit property list, NOT `transition: all`: `all` animates
|
||
`outline-width` off the `outline: none` base, and Chrome leaves that
|
||
transition parked at 0px for chips on a wrapped line — the keyboard ring
|
||
silently never appeared on rows 2 and 3. A focus indicator should be
|
||
instant anyway. */
|
||
transition:
|
||
color var(--transition-fast),
|
||
background-color var(--transition-fast),
|
||
border-color var(--transition-fast),
|
||
box-shadow var(--transition-fast);
|
||
outline: none;
|
||
}
|
||
|
||
#command-dock #control-panel.collapsed .map-source-section {
|
||
display: none;
|
||
}
|
||
|
||
@media (max-width: 620px) {
|
||
.map-stack-chip-row {
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
}
|
||
}
|
||
|
||
/* Order matters, and matches `.data-toggle-btn`: hover/focus, then active, then
|
||
disabled — all at the same specificity, so the later rule wins. Hovering the
|
||
active chip must not wash the cyan out, and a disabled chip must not light up
|
||
under the cursor. Do not add `:not(...)` here: it would raise specificity and
|
||
let hover beat `.active` again. */
|
||
.map-stack-chip:hover,
|
||
.map-stack-chip:focus-visible {
|
||
border-color: var(--glass-border-hover);
|
||
background: rgba(255, 255, 255, 0.06);
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
/* The keyboard ring is an `outline`, a property NO other chip-state rule sets,
|
||
so it survives on the active chip — whose `.active` rule legitimately wins
|
||
the color/border/background/box-shadow it shares with the rule above. Without
|
||
this, tabbing onto the active chip produced no visible change at all. */
|
||
.map-stack-chip:focus-visible {
|
||
outline: 1px solid color-mix(in srgb, var(--accent) 80%, transparent);
|
||
outline-offset: 2px;
|
||
}
|
||
|
||
.map-stack-chip.active {
|
||
color: var(--accent);
|
||
border-color: var(--accent);
|
||
background: var(--accent-dim);
|
||
box-shadow: 0 0 10px rgba(0, 212, 255, 0.15);
|
||
}
|
||
|
||
.map-stack-chip.unavailable,
|
||
.map-stack-chip[aria-disabled='true'] {
|
||
color: rgba(232, 234, 237, 0.28);
|
||
border-color: rgba(255, 255, 255, 0.08);
|
||
background: rgba(255, 255, 255, 0.02);
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
.map-stack-chip-req {
|
||
font-size: 7px;
|
||
letter-spacing: 0.3px;
|
||
color: rgba(232, 234, 237, 0.28);
|
||
}
|
||
|
||
.pp-stack-status {
|
||
min-width: 42px;
|
||
max-width: 54px;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
font-family: var(--font-mono);
|
||
font-size: 9px;
|
||
letter-spacing: 0.8px;
|
||
color: var(--accent);
|
||
text-align: center;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.pp-stack-status.warn {
|
||
color: #ffb84d;
|
||
}
|
||
|
||
.pp-select {
|
||
flex: 1;
|
||
min-width: 0;
|
||
height: 24px;
|
||
background: rgba(255, 255, 255, 0.06);
|
||
border: 1px solid rgba(255, 255, 255, 0.14);
|
||
border-radius: 6px;
|
||
color: var(--text-primary);
|
||
font-family: var(--font-mono);
|
||
font-size: 10px;
|
||
letter-spacing: 0.6px;
|
||
padding: 2px 6px;
|
||
outline: none;
|
||
}
|
||
|
||
/* Proximity / All segmented control under the 3D toggle */
|
||
#models3d-mode-row { min-width: 184px; }
|
||
.pp-mode-seg {
|
||
display: flex;
|
||
flex: 1;
|
||
border: 1px solid rgba(255, 255, 255, 0.14);
|
||
border-radius: 6px;
|
||
overflow: hidden;
|
||
}
|
||
.pp-mode-btn {
|
||
flex: 1;
|
||
height: 22px;
|
||
background: rgba(255, 255, 255, 0.04);
|
||
border: none;
|
||
color: var(--text-dim);
|
||
font-family: var(--font-mono);
|
||
font-size: 9px;
|
||
letter-spacing: 0.6px;
|
||
text-transform: uppercase;
|
||
cursor: pointer;
|
||
transition: all var(--transition-fast);
|
||
}
|
||
.pp-mode-btn + .pp-mode-btn { border-left: 1px solid rgba(255, 255, 255, 0.14); }
|
||
.pp-mode-btn:hover { background: rgba(255, 255, 255, 0.08); color: var(--text-primary); }
|
||
.pp-mode-btn.active { background: var(--accent); color: #000; }
|
||
|
||
#clean-view-toggle {
|
||
width: var(--pp-expanded-width);
|
||
}
|
||
|
||
#clean-view-exit {
|
||
position: fixed;
|
||
top: 18px;
|
||
right: 50%;
|
||
transform: translateX(50%);
|
||
z-index: 300;
|
||
border-radius: 999px;
|
||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||
background: rgba(8, 10, 14, 0.88);
|
||
color: #d9f7ff;
|
||
font-family: var(--font-mono);
|
||
font-size: 10px;
|
||
letter-spacing: 1.8px;
|
||
padding: 8px 14px;
|
||
cursor: pointer;
|
||
display: none;
|
||
}
|
||
|
||
body.ui-clean-view #clean-view-exit {
|
||
display: inline-flex;
|
||
}
|
||
|
||
body.ui-clean-view #title-bar,
|
||
body.ui-clean-view #style-indicator,
|
||
body.ui-clean-view #top-center-actions,
|
||
body.ui-clean-view #global-loading-status,
|
||
body.ui-clean-view #traffic-sync-chip,
|
||
body.ui-clean-view #cctv-sync-chip,
|
||
body.ui-clean-view #pp-toggles,
|
||
body.ui-clean-view #param-slider-panel,
|
||
body.ui-clean-view #control-panel,
|
||
body.ui-clean-view #location-bar,
|
||
body.ui-clean-view #data-panel,
|
||
body.ui-clean-view #cctv-panel,
|
||
body.ui-clean-view #radio-panel,
|
||
body.ui-clean-view #global-context-panel,
|
||
body.ui-clean-view #scene-panel {
|
||
opacity: 0 !important;
|
||
visibility: hidden !important;
|
||
pointer-events: none !important;
|
||
}
|
||
|
||
body.ui-clean-view #scene-runtime.active {
|
||
opacity: 1;
|
||
visibility: visible;
|
||
}
|
||
|
||
/* ── Detection Toggle States ─────────────────── */
|
||
#detection-toggle.active {
|
||
border-color: rgba(0, 255, 80, 0.6);
|
||
background: rgba(0, 255, 80, 0.1);
|
||
box-shadow: 0 0 12px rgba(0, 255, 80, 0.15);
|
||
}
|
||
|
||
#detection-toggle.active .pp-label {
|
||
color: rgba(0, 255, 80, 0.9);
|
||
}
|
||
|
||
#detection-toggle.active .pp-icon {
|
||
color: rgba(0, 255, 80, 0.9);
|
||
text-shadow: 0 0 6px rgba(0, 255, 80, 0.5);
|
||
}
|
||
|
||
#detection-toggle.panoptic,
|
||
#detection-toggle.god {
|
||
border-color: rgba(0, 255, 80, 0.8);
|
||
background: rgba(0, 255, 80, 0.18);
|
||
box-shadow: 0 0 16px rgba(0, 255, 80, 0.25);
|
||
animation: detection-pulse 2s ease-in-out infinite;
|
||
}
|
||
|
||
@keyframes detection-pulse {
|
||
0%, 100% { box-shadow: 0 0 12px rgba(0, 255, 80, 0.15); }
|
||
50% { box-shadow: 0 0 22px rgba(0, 255, 80, 0.35); }
|
||
}
|
||
|
||
/* ── Parameter Slider Panel ──────────────────── */
|
||
#param-slider-panel {
|
||
display: none;
|
||
position: relative;
|
||
top: auto;
|
||
right: auto;
|
||
left: auto;
|
||
bottom: auto;
|
||
z-index: 95;
|
||
width: 100%;
|
||
max-height: min(38vh, 360px);
|
||
box-sizing: border-box;
|
||
overflow-y: auto;
|
||
scrollbar-width: none;
|
||
-ms-overflow-style: none;
|
||
background: var(--glass-bg);
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: 12px;
|
||
padding: 14px 16px;
|
||
backdrop-filter: blur(24px) saturate(1.4);
|
||
-webkit-backdrop-filter: blur(24px) saturate(1.4);
|
||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
|
||
opacity: 0;
|
||
visibility: hidden;
|
||
transform: translateY(6px);
|
||
transition: opacity var(--transition-smooth), visibility var(--transition-smooth), transform var(--transition-smooth);
|
||
}
|
||
|
||
#param-slider-panel::-webkit-scrollbar {
|
||
display: none;
|
||
}
|
||
|
||
#param-slider-panel.active {
|
||
display: block;
|
||
opacity: 1;
|
||
visibility: visible;
|
||
transform: translateY(0);
|
||
}
|
||
|
||
/* Display owns the constrained desktop scroll surface. Keeping Parameters as
|
||
* a second scroll container traps wheel/touch input at its boundary and lets
|
||
* the flex column compress newly added preset rows below the visible panel. */
|
||
#pp-toggles:not(.collapsed) > #param-slider-panel.active {
|
||
flex: 0 0 auto;
|
||
max-height: none;
|
||
overflow-y: visible;
|
||
}
|
||
|
||
.param-panel-header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.param-panel-title {
|
||
font-family: var(--font-mono);
|
||
font-size: 8px;
|
||
letter-spacing: 2.5px;
|
||
color: var(--text-dim);
|
||
text-transform: uppercase;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.param-panel-divider {
|
||
flex: 1;
|
||
height: 1px;
|
||
background: linear-gradient(to right, var(--glass-border), transparent);
|
||
}
|
||
|
||
#param-slider-panel:not(.collapsed) .param-panel-divider {
|
||
background: linear-gradient(90deg, rgb(0 212 255 / 28%), rgba(0, 212, 255, 0.18) 58%, transparent);
|
||
}
|
||
|
||
.param-slider-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.param-slider-row:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.param-label {
|
||
font-family: var(--font-mono);
|
||
font-size: 9px;
|
||
letter-spacing: 1px;
|
||
color: var(--text-secondary);
|
||
min-width: 72px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.param-slider {
|
||
flex: 1;
|
||
min-width: 0;
|
||
-webkit-appearance: none;
|
||
appearance: none;
|
||
height: 3px;
|
||
background: rgba(255, 255, 255, 0.08);
|
||
border-radius: 2px;
|
||
outline: none;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.param-slider::-webkit-slider-thumb {
|
||
-webkit-appearance: none;
|
||
appearance: none;
|
||
width: 12px;
|
||
height: 12px;
|
||
border-radius: 50%;
|
||
background: var(--accent);
|
||
box-shadow: 0 0 6px var(--accent-glow);
|
||
cursor: pointer;
|
||
transition: box-shadow var(--transition-fast);
|
||
}
|
||
|
||
.param-slider::-webkit-slider-thumb:hover {
|
||
box-shadow: 0 0 12px var(--accent-glow);
|
||
}
|
||
|
||
.param-slider::-moz-range-thumb {
|
||
width: 12px;
|
||
height: 12px;
|
||
border-radius: 50%;
|
||
background: var(--accent);
|
||
border: none;
|
||
box-shadow: 0 0 6px var(--accent-glow);
|
||
cursor: pointer;
|
||
}
|
||
|
||
.param-value {
|
||
font-family: var(--font-mono);
|
||
font-size: 10px;
|
||
letter-spacing: 0.5px;
|
||
color: var(--accent);
|
||
min-width: 32px;
|
||
text-align: right;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
/* ── Location Bar ────────────────────────────── */
|
||
#location-bar {
|
||
position: fixed;
|
||
bottom: 130px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
z-index: 100;
|
||
width: auto;
|
||
max-width: 720px;
|
||
}
|
||
|
||
#location-bar .panel-glow {
|
||
position: absolute;
|
||
inset: -20px;
|
||
background: radial-gradient(ellipse at center, var(--accent-dim) 0%, transparent 60%);
|
||
filter: blur(20px);
|
||
opacity: 0.25;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.location-inner {
|
||
position: relative;
|
||
display: flex;
|
||
flex-direction: column;
|
||
background: var(--glass-bg);
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: 12px;
|
||
padding: 8px 12px;
|
||
backdrop-filter: blur(24px) saturate(1.4);
|
||
-webkit-backdrop-filter: blur(24px) saturate(1.4);
|
||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
|
||
}
|
||
|
||
.location-toolbar {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 6px;
|
||
padding: 0 4px;
|
||
}
|
||
|
||
.location-toolbar-label {
|
||
font-family: var(--font-mono);
|
||
font-size: 8px;
|
||
letter-spacing: 2px;
|
||
color: var(--text-dim);
|
||
}
|
||
|
||
.location-mini-status {
|
||
display: none;
|
||
gap: 2px;
|
||
padding: 0 4px 4px;
|
||
}
|
||
|
||
#location-bar.collapsed .location-mini-status {
|
||
display: grid;
|
||
}
|
||
|
||
.location-mini-city {
|
||
font-family: var(--font-mono);
|
||
font-size: 9px;
|
||
letter-spacing: 0.8px;
|
||
color: #bdefff;
|
||
}
|
||
|
||
.location-mini-poi {
|
||
font-family: var(--font-mono);
|
||
font-size: 8px;
|
||
letter-spacing: 1px;
|
||
color: var(--text-secondary);
|
||
max-width: 190px;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.location-pills {
|
||
display: flex;
|
||
gap: 6px;
|
||
overflow-x: auto;
|
||
scroll-behavior: smooth;
|
||
scrollbar-width: none;
|
||
-ms-overflow-style: none;
|
||
}
|
||
|
||
.location-pills::-webkit-scrollbar {
|
||
display: none;
|
||
}
|
||
|
||
.location-pill {
|
||
padding: 6px 14px;
|
||
background: rgba(255, 255, 255, 0.04);
|
||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||
border-radius: 20px;
|
||
cursor: pointer;
|
||
transition: all var(--transition-fast);
|
||
outline: none;
|
||
white-space: nowrap;
|
||
font-family: var(--font-sans);
|
||
font-size: 11px;
|
||
font-weight: 500;
|
||
color: var(--text-secondary);
|
||
letter-spacing: 0.3px;
|
||
}
|
||
|
||
.location-pill:hover {
|
||
background: rgba(255, 255, 255, 0.08);
|
||
border-color: var(--glass-border-hover);
|
||
transform: translateY(-1px);
|
||
}
|
||
|
||
.location-pill.active {
|
||
background: var(--accent-dim);
|
||
border-color: var(--accent);
|
||
color: var(--accent);
|
||
box-shadow: 0 0 12px rgba(0, 212, 255, 0.15);
|
||
}
|
||
|
||
/* ── Expandable POI Row ──────────────────────── */
|
||
.poi-row-container {
|
||
display: flex;
|
||
gap: 6px;
|
||
justify-content: center;
|
||
max-height: 0;
|
||
overflow: hidden;
|
||
opacity: 0;
|
||
transition: max-height 250ms cubic-bezier(0.4, 0, 0.2, 1),
|
||
opacity 200ms ease,
|
||
padding 250ms cubic-bezier(0.4, 0, 0.2, 1);
|
||
padding: 0 4px;
|
||
}
|
||
|
||
.poi-row-container.expanded {
|
||
max-height: 50px;
|
||
opacity: 1;
|
||
padding: 4px 4px 0;
|
||
}
|
||
|
||
.location-bar-divider {
|
||
height: 0;
|
||
border: none;
|
||
border-top: 1px solid var(--glass-border);
|
||
margin: 0 4px;
|
||
opacity: 0;
|
||
transition: opacity 200ms ease, margin 250ms ease;
|
||
}
|
||
|
||
.location-bar-divider.visible {
|
||
opacity: 1;
|
||
margin: 6px 4px;
|
||
}
|
||
|
||
.location-city-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.poi-pill {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 5px 12px;
|
||
background: rgba(255, 255, 255, 0.04);
|
||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||
border-radius: 20px;
|
||
cursor: pointer;
|
||
transition: all var(--transition-fast);
|
||
outline: none;
|
||
white-space: nowrap;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.poi-pill:hover {
|
||
background: rgba(255, 255, 255, 0.08);
|
||
border-color: var(--glass-border-hover);
|
||
transform: translateY(-1px);
|
||
}
|
||
|
||
.poi-pill.active {
|
||
background: var(--accent-dim);
|
||
border-color: var(--accent);
|
||
box-shadow: 0 0 12px rgba(0, 212, 255, 0.15);
|
||
}
|
||
|
||
.poi-pill-name {
|
||
font-family: var(--font-sans);
|
||
font-size: 10px;
|
||
font-weight: 500;
|
||
color: var(--text-secondary);
|
||
letter-spacing: 0.3px;
|
||
}
|
||
|
||
.poi-pill.active .poi-pill-name {
|
||
color: var(--accent);
|
||
}
|
||
|
||
.poi-pill-key {
|
||
font-family: var(--font-mono);
|
||
font-size: 8px;
|
||
letter-spacing: 1px;
|
||
color: var(--text-dim);
|
||
background: rgba(255, 255, 255, 0.06);
|
||
padding: 2px 5px;
|
||
border-radius: 3px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.poi-pill.active .poi-pill-key {
|
||
color: var(--accent);
|
||
background: rgba(0, 212, 255, 0.12);
|
||
}
|
||
|
||
/* ── Location Search ─────────────────────────── */
|
||
.location-search-wrap {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.search-toggle-btn {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 32px;
|
||
height: 32px;
|
||
background: rgba(255, 255, 255, 0.04);
|
||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||
border-radius: 50%;
|
||
cursor: pointer;
|
||
transition: all var(--transition-fast);
|
||
outline: none;
|
||
font-size: 14px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.search-toggle-btn:hover {
|
||
background: rgba(255, 255, 255, 0.08);
|
||
border-color: var(--glass-border-hover);
|
||
}
|
||
|
||
#location-search {
|
||
width: 0;
|
||
padding: 0;
|
||
border: none;
|
||
background: none;
|
||
outline: none;
|
||
color: var(--text-primary);
|
||
font-family: var(--font-sans);
|
||
font-size: 13px;
|
||
letter-spacing: 0.3px;
|
||
transition: width var(--transition-smooth), padding var(--transition-smooth);
|
||
caret-color: var(--accent);
|
||
}
|
||
|
||
#location-search.expanded {
|
||
width: 180px;
|
||
padding: 6px 10px;
|
||
}
|
||
|
||
#location-search::placeholder {
|
||
color: var(--text-dim);
|
||
font-style: italic;
|
||
}
|
||
|
||
#location-search.searching {
|
||
opacity: 0.5;
|
||
}
|
||
|
||
/* ── Top-center Globe Actions ────────────────── */
|
||
#top-center-actions {
|
||
position: fixed;
|
||
top: 32px;
|
||
left: 50%;
|
||
z-index: 100;
|
||
display: flex;
|
||
gap: 8px;
|
||
transform: translateX(-50%);
|
||
}
|
||
|
||
#top-center-actions button {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 36px;
|
||
height: 36px;
|
||
padding: 0;
|
||
background: var(--glass-bg);
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: 50%;
|
||
color: var(--text-secondary);
|
||
backdrop-filter: blur(16px);
|
||
-webkit-backdrop-filter: blur(16px);
|
||
cursor: pointer;
|
||
transition: all var(--transition-fast);
|
||
outline: none;
|
||
}
|
||
|
||
#top-center-actions button:hover,
|
||
#top-center-actions button:focus-visible {
|
||
border-color: var(--glass-border-hover);
|
||
background: rgba(255, 255, 255, 0.06);
|
||
transform: scale(1.1);
|
||
}
|
||
|
||
#top-center-actions button:active {
|
||
transform: scale(0.95);
|
||
}
|
||
|
||
#top-center-actions button:disabled {
|
||
cursor: wait;
|
||
opacity: 0.55;
|
||
transform: none;
|
||
}
|
||
|
||
#top-center-actions .material-symbols-outlined {
|
||
font-size: 18px;
|
||
}
|
||
|
||
#global-loading-status {
|
||
position: fixed;
|
||
top: 74px;
|
||
left: 50%;
|
||
z-index: 102;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
max-width: calc(100vw - 32px);
|
||
padding: 6px 10px;
|
||
border-radius: 7px;
|
||
border: 1px solid rgba(0, 212, 255, 0.24);
|
||
background: rgba(3, 10, 18, 0.78);
|
||
backdrop-filter: blur(14px);
|
||
-webkit-backdrop-filter: blur(14px);
|
||
color: rgba(170, 252, 255, 0.92);
|
||
font-family: var(--font-mono);
|
||
font-size: 8px;
|
||
letter-spacing: 1.35px;
|
||
text-transform: uppercase;
|
||
transform: translateX(-50%);
|
||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.34), 0 0 14px rgba(0, 212, 255, 0.08);
|
||
pointer-events: none;
|
||
}
|
||
#global-loading-status[hidden] { display: none; }
|
||
#global-loading-label {
|
||
color: rgba(184, 244, 255, 0.92);
|
||
}
|
||
#global-loading-detail {
|
||
min-width: 34px;
|
||
max-width: min(220px, 38vw);
|
||
overflow: hidden;
|
||
color: #00e1ff;
|
||
font-weight: 600;
|
||
letter-spacing: 1.6px;
|
||
text-align: right;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
#global-loading-status:is([data-state='complete'], [data-state='cancelled'], [data-state='error']) {
|
||
justify-content: center;
|
||
text-align: center;
|
||
}
|
||
#global-loading-status:is([data-state='complete'], [data-state='cancelled'], [data-state='error']) #global-loading-detail {
|
||
display: none;
|
||
}
|
||
#global-loading-status[data-state='error'] { border-color: rgba(255, 98, 82, 0.55); color: #ff9b8e; }
|
||
#global-loading-status[data-state='error'] #global-loading-label,
|
||
#global-loading-status[data-state='error'] #global-loading-detail { color: #ff9b8e; }
|
||
#global-loading-status[data-state='cancelled'] { color: #ffd488; }
|
||
#global-loading-status[data-state='cancelled'] #global-loading-label,
|
||
#global-loading-status[data-state='cancelled'] #global-loading-detail { color: #ffd488; }
|
||
#global-loading-status[data-state='acquiring'] {
|
||
border-color: rgba(0, 212, 255, 0.42);
|
||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.34), 0 0 18px rgba(0, 212, 255, 0.12);
|
||
}
|
||
|
||
.share-icon {
|
||
font-size: 16px;
|
||
line-height: 1;
|
||
}
|
||
|
||
#traffic-sync-chip,
|
||
#cctv-sync-chip {
|
||
position: fixed;
|
||
top: 112px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
z-index: 101;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
padding: 6px 10px;
|
||
border-radius: 7px;
|
||
border: 1px solid rgba(0, 212, 255, 0.24);
|
||
background: rgba(3, 10, 18, 0.78);
|
||
backdrop-filter: blur(14px);
|
||
-webkit-backdrop-filter: blur(14px);
|
||
color: rgba(170, 252, 255, 0.92);
|
||
font-family: var(--font-mono);
|
||
font-size: 8px;
|
||
letter-spacing: 1.35px;
|
||
text-transform: uppercase;
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
transition: opacity 0.22s ease, transform 0.22s ease;
|
||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.34), 0 0 14px rgba(0, 212, 255, 0.08);
|
||
}
|
||
|
||
/* Stacked below the traffic chip so both can show at once */
|
||
#cctv-sync-chip {
|
||
top: 146px;
|
||
}
|
||
|
||
#traffic-sync-chip.visible,
|
||
#cctv-sync-chip.visible {
|
||
opacity: 1;
|
||
transform: translateX(-50%) translateY(0);
|
||
}
|
||
|
||
#traffic-sync-label,
|
||
#cctv-sync-label {
|
||
color: rgba(184, 244, 255, 0.92);
|
||
}
|
||
|
||
#traffic-sync-progress,
|
||
#cctv-sync-progress {
|
||
color: #00e1ff;
|
||
font-weight: 600;
|
||
letter-spacing: 1.6px;
|
||
min-width: 34px;
|
||
text-align: right;
|
||
}
|
||
|
||
/* The settled traffic chip carries no progress number — the label's coverage
|
||
figure is the honest one. Collapse the empty slot so the chip closes up
|
||
instead of trailing a 34px stub and its flex gap. */
|
||
#traffic-sync-progress:empty {
|
||
display: none;
|
||
}
|
||
|
||
/* ── Split-flap chip text ─────────────────────────────────────────
|
||
Per-character departure-board flip when a chip label changes.
|
||
Driven entirely by src/splitFlap.js, which rebuilds the label as
|
||
one span per character on the change and strips them again once
|
||
the cascade lands.
|
||
|
||
The DOM text is the truth and its node never moves. A chip label is
|
||
upgraded once into a permanent shell — a .gev-flap-text span holding
|
||
one long-lived Text node, plus an aria-hidden .gev-flap-cells
|
||
sibling — and from then on a label change is only `node.data = next`.
|
||
During a cascade the host takes .gev-flap-active, which clips the
|
||
real text out of view and lets the cells stand in for it. The cells
|
||
carry no text at all: both glyphs are generated content (::before =
|
||
outgoing, ::after = incoming), and generated content never reaches
|
||
textContent. That is what keeps QA pins and the traffic chip's own
|
||
`textContent !==` guard honest, and it lets the cells be rebuilt
|
||
freely while the aria-live region sees only one characterData
|
||
change per label update.
|
||
|
||
Motion matches the cockpit odometer roll (.cockpit-roll-token):
|
||
same cubic-bezier, same reduced-motion treatment. Only the
|
||
left-to-right stagger is new — that cascade is what makes it read
|
||
as a Solari board rather than a counter.
|
||
------------------------------------------------------------------ */
|
||
/* While the flaps play, the real text is clipped out of view but stays in
|
||
the DOM and in the accessibility tree — same clipped-but-present treatment
|
||
as .world-overlay-accessibility. It is never removed or reparented. */
|
||
.gev-flap-host.gev-flap-active > .gev-flap-text {
|
||
position: absolute;
|
||
width: 1px;
|
||
height: 1px;
|
||
padding: 0;
|
||
margin: -1px;
|
||
overflow: hidden;
|
||
clip: rect(0, 0, 0, 0);
|
||
white-space: nowrap;
|
||
border: 0;
|
||
}
|
||
/* Permanent sibling: empty (and so zero-width) whenever no cascade is running. */
|
||
.gev-flap-cells {
|
||
white-space: pre;
|
||
}
|
||
.gev-flap-cell {
|
||
display: inline-block;
|
||
/* Chip labels carry real spaces; a collapsed space would drop a column. */
|
||
white-space: pre;
|
||
}
|
||
/* The incoming glyph is in flow, so it — not any text node — is what gives
|
||
the column its natural width. EVERY column has one, including a column the
|
||
new string does not reach: that one carries a blank, so it holds its width
|
||
and its index for the whole cascade instead of collapsing. Collapsing would
|
||
stack the absolutely-positioned outgoing glyphs on one x and would let a
|
||
later glyph slide into an earlier column. */
|
||
.gev-flap-cell::after {
|
||
content: attr(data-flap-next);
|
||
display: inline-block;
|
||
white-space: pre;
|
||
}
|
||
.gev-flap-cell.is-flapping {
|
||
position: relative;
|
||
/* Relative to the chip's own font size, so the foreshortening reads the
|
||
same on the 8px status chips as it would anywhere else. */
|
||
perspective: 4em;
|
||
}
|
||
.gev-flap-cell.is-flapping::before,
|
||
.gev-flap-cell.is-flapping::after {
|
||
transform-origin: 50% 50%;
|
||
backface-visibility: hidden;
|
||
}
|
||
.gev-flap-cell.is-flapping::after {
|
||
animation: gev-flap-in var(--gev-flap-dur, 190ms)
|
||
cubic-bezier(0.2, 0.75, 0.25, 1) var(--gev-flap-delay, 0ms) both;
|
||
}
|
||
/* Out of flow, so the outgoing glyph overlays its own column without
|
||
affecting layout — one per column, each anchored to its own cell box. */
|
||
.gev-flap-cell.is-flapping::before {
|
||
content: attr(data-flap-prev);
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
white-space: pre;
|
||
animation: gev-flap-out var(--gev-flap-dur, 190ms)
|
||
cubic-bezier(0.2, 0.75, 0.25, 1) var(--gev-flap-delay, 0ms) both;
|
||
}
|
||
/* Length changes are eased, never snapped. A GROWING label reserves its new
|
||
columns the moment the cells go in, so splitFlap.js eases from the previous
|
||
on-screen width to the cascade width at the start. A SHRINKING one holds
|
||
every column for the whole cascade, so its ease runs at SETTLEMENT instead,
|
||
from the cascade width down to the natural width — one smooth transition
|
||
after the flaps have landed, rather than columns collapsing underneath
|
||
them. */
|
||
.gev-flap-sizing {
|
||
display: inline-block;
|
||
transition: width var(--gev-flap-total, 500ms) cubic-bezier(0.2, 0.75, 0.25, 1);
|
||
}
|
||
/* The old leaf hinges down and away on the cell's midline. */
|
||
@keyframes gev-flap-out {
|
||
0% { transform: rotateX(0deg); opacity: 1; }
|
||
48% { transform: rotateX(-88deg); opacity: 0.5; }
|
||
100% { transform: rotateX(-90deg); opacity: 0; }
|
||
}
|
||
/* The new leaf waits for the old one to clear, then drops in and settles
|
||
with a single small overshoot — the mechanical clack. */
|
||
@keyframes gev-flap-in {
|
||
0% { transform: rotateX(90deg); opacity: 0; }
|
||
46% { transform: rotateX(90deg); opacity: 0; }
|
||
78% { transform: rotateX(-7deg); opacity: 1; }
|
||
100% { transform: rotateX(0deg); opacity: 1; }
|
||
}
|
||
/* Matches the .cockpit-roll-track treatment: collapse the duration rather
|
||
than dropping the animation, so the final frame still lands the glyph.
|
||
src/splitFlap.js also checks the query and takes the instant path, so
|
||
this is the belt to that braces. */
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.gev-flap-cell.is-flapping::before,
|
||
.gev-flap-cell.is-flapping::after {
|
||
animation-duration: 1ms;
|
||
animation-delay: 0ms;
|
||
}
|
||
.gev-flap-sizing {
|
||
transition-duration: 1ms;
|
||
}
|
||
}
|
||
|
||
/* ── Toast Notification ──────────────────────── */
|
||
#toast {
|
||
position: fixed;
|
||
bottom: 100px;
|
||
left: 50%;
|
||
transform: translateX(-50%) translateY(20px);
|
||
z-index: 200;
|
||
padding: 10px 24px;
|
||
background: var(--glass-bg);
|
||
border: 1px solid var(--accent);
|
||
border-radius: 8px;
|
||
backdrop-filter: blur(16px);
|
||
-webkit-backdrop-filter: blur(16px);
|
||
font-family: var(--font-mono);
|
||
font-size: 11px;
|
||
letter-spacing: 2px;
|
||
color: var(--accent);
|
||
text-transform: uppercase;
|
||
opacity: 0;
|
||
visibility: hidden;
|
||
pointer-events: none;
|
||
transition: opacity 0.3s ease, visibility 0.3s ease, transform 0.3s ease;
|
||
box-shadow: 0 0 20px rgba(0, 212, 255, 0.15);
|
||
}
|
||
|
||
#toast.visible {
|
||
opacity: 1;
|
||
visibility: visible;
|
||
transform: translateX(-50%) translateY(0);
|
||
}
|
||
|
||
/* ── Aircraft Cockpit View ─────────────────── */
|
||
#cockpit-entry {
|
||
position: fixed;
|
||
left: calc(50% + 270px);
|
||
bottom: 34px;
|
||
z-index: 151;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
min-height: 38px;
|
||
padding: 0 12px;
|
||
border: 1px solid rgba(0, 220, 255, 0.5);
|
||
border-radius: 8px;
|
||
background: rgba(2, 12, 18, 0.9);
|
||
color: #dceeff;
|
||
font: 600 10px/1 var(--font-mono);
|
||
letter-spacing: 0.14em;
|
||
box-shadow: 0 0 18px rgba(0, 220, 255, 0.14);
|
||
cursor: pointer;
|
||
}
|
||
|
||
#cockpit-entry[hidden], #cockpit-hud[hidden] { display: none; }
|
||
#cockpit-entry:hover, #cockpit-entry:focus-visible {
|
||
border-color: #00dcff;
|
||
color: #fff;
|
||
outline: none;
|
||
}
|
||
#cockpit-entry .material-symbols-outlined { color: #00dcff; font-size: 18px; }
|
||
#cockpit-entry kbd {
|
||
padding: 3px 5px;
|
||
border: 1px solid rgba(220, 238, 255, 0.25);
|
||
border-radius: 4px;
|
||
color: rgba(220, 238, 255, 0.6);
|
||
font: inherit;
|
||
}
|
||
|
||
#cockpit-hud {
|
||
--cockpit-accent: #00dcff;
|
||
--cockpit-side-panel-width: min(340px, 28vw);
|
||
/* HUD bottom offset + tallest scaled telemetry block + 20px clear border. */
|
||
--cockpit-bottom-rail-safe: calc(clamp(84px, 11vh, 118px) + 100px);
|
||
position: fixed;
|
||
inset: 0;
|
||
z-index: 145;
|
||
overflow: hidden;
|
||
pointer-events: none;
|
||
color: #f4fbff;
|
||
font-family: var(--font-mono);
|
||
text-shadow: 0 0 10px color-mix(in srgb, var(--cockpit-accent) 60%, transparent), 0 1px 2px #000;
|
||
perspective: 920px;
|
||
}
|
||
#cockpit-hud[data-layer="military"] { --cockpit-accent: #ffb800; }
|
||
.cockpit-visor-shell {
|
||
position: absolute;
|
||
inset: clamp(62px, 9vh, 90px) clamp(18px, 3vw, 48px) clamp(38px, 5vh, 56px);
|
||
transform-style: preserve-3d;
|
||
perspective: 880px;
|
||
}
|
||
.cockpit-roll-arc {
|
||
position: absolute;
|
||
top: 2px;
|
||
left: 50%;
|
||
width: min(620px, 56vw);
|
||
height: 96px;
|
||
transform: translateX(-50%) rotateX(-8deg);
|
||
transform-style: preserve-3d;
|
||
}
|
||
.cockpit-roll-arc::after {
|
||
content: '';
|
||
position: absolute;
|
||
inset: 18px 6% 0;
|
||
border-top: 1px solid color-mix(in srgb, var(--cockpit-accent) 62%, transparent);
|
||
border-radius: 50%;
|
||
opacity: 0.72;
|
||
}
|
||
.cockpit-roll-arc span {
|
||
position: absolute;
|
||
left: 50%;
|
||
top: 0;
|
||
color: rgba(244, 251, 255, 0.46);
|
||
font-size: 8px;
|
||
letter-spacing: 0.1em;
|
||
transform:
|
||
translateX(calc(-50% + (var(--slot) * 74px)))
|
||
translateY(calc(var(--depth) * 9px))
|
||
rotateZ(calc(var(--slot) * 4deg))
|
||
rotateY(calc(var(--slot) * -5deg));
|
||
}
|
||
.cockpit-roll-arc span::after {
|
||
content: '';
|
||
display: block;
|
||
width: 1px;
|
||
height: calc(11px + (3 - var(--depth)) * 2px);
|
||
margin: 5px auto 0;
|
||
background: color-mix(in srgb, var(--cockpit-accent) 62%, transparent);
|
||
}
|
||
.cockpit-roll-arc span.active { color: #fff; font-size: 10px; }
|
||
.cockpit-pitch-rail {
|
||
position: absolute;
|
||
top: 25%;
|
||
bottom: 21%;
|
||
display: grid;
|
||
grid-template-rows: repeat(5, 1fr);
|
||
align-items: center;
|
||
color: rgba(244, 251, 255, 0.38);
|
||
font-size: 8px;
|
||
letter-spacing: 0.08em;
|
||
transform-style: preserve-3d;
|
||
}
|
||
.cockpit-pitch-rail-left {
|
||
left: clamp(190px, 22vw, 330px);
|
||
text-align: right;
|
||
transform: rotateY(24deg) translateZ(-18px);
|
||
}
|
||
.cockpit-pitch-rail-right {
|
||
right: clamp(190px, 22vw, 330px);
|
||
text-align: left;
|
||
transform: rotateY(-24deg) translateZ(-18px);
|
||
}
|
||
body.cockpit-mode:has(#left-panel-stack > .panel-collapsible:not(.collapsed)) .cockpit-pitch-rail-left {
|
||
opacity: 0;
|
||
transition: opacity 0.25s;
|
||
}
|
||
.cockpit-pitch-rail span {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 7px;
|
||
}
|
||
.cockpit-pitch-rail-left span { justify-content: flex-end; }
|
||
.cockpit-pitch-rail span::after {
|
||
content: '';
|
||
width: 24px;
|
||
border-top: 1px solid color-mix(in srgb, var(--cockpit-accent) 46%, transparent);
|
||
}
|
||
.cockpit-pitch-rail-right span::after { order: -1; }
|
||
.cockpit-pitch-rail span.active { color: var(--cockpit-accent); }
|
||
.cockpit-pitch-rail span.active::after { width: 42px; border-color: var(--cockpit-accent); }
|
||
.cockpit-horizon-guide {
|
||
position: absolute;
|
||
top: 46%;
|
||
left: 50%;
|
||
display: grid;
|
||
grid-template-columns: minmax(74px, 190px) auto minmax(74px, 190px);
|
||
align-items: center;
|
||
gap: 16px;
|
||
width: min(470px, 42vw);
|
||
transform: translate(-50%, -50%) translateZ(22px);
|
||
color: color-mix(in srgb, var(--cockpit-accent) 72%, white);
|
||
}
|
||
.cockpit-horizon-guide span { border-top: 1px solid currentColor; }
|
||
.cockpit-horizon-guide span:first-child { transform: rotateZ(2deg); transform-origin: right; }
|
||
.cockpit-horizon-guide span:last-child { transform: rotateZ(-2deg); transform-origin: left; }
|
||
.cockpit-horizon-guide small { font-size: 7px; letter-spacing: 0.16em; }
|
||
.cockpit-route-direction {
|
||
--route-angle: 0deg;
|
||
position: absolute;
|
||
z-index: 3;
|
||
/* Keep the cue in one predictable center slot. Its rotation communicates
|
||
relative destination bearing; lateral movement made it look like a random
|
||
scene arrow and allowed it to collide with the speed/heading readouts. */
|
||
top: 62%;
|
||
left: 50%;
|
||
display: grid;
|
||
justify-items: center;
|
||
gap: 5px;
|
||
color: color-mix(in srgb, var(--cockpit-accent) 24%, #79b8ff);
|
||
opacity: 0.84;
|
||
transform: translate(-50%, -50%) translateZ(24px);
|
||
transition: opacity 180ms ease;
|
||
filter: drop-shadow(0 0 8px color-mix(in srgb, var(--cockpit-accent) 34%, transparent));
|
||
}
|
||
.cockpit-route-direction[hidden] { display: none; }
|
||
.cockpit-route-direction .cockpit-route-chevron {
|
||
display: block;
|
||
width: clamp(56px, 6vw, 78px);
|
||
height: clamp(56px, 6vw, 78px);
|
||
overflow: visible;
|
||
color: color-mix(in srgb, var(--cockpit-accent) 28%, #79b8ff);
|
||
fill: currentColor;
|
||
stroke: color-mix(in srgb, var(--cockpit-accent) 58%, #d8f3ff);
|
||
stroke-width: 0.7px;
|
||
stroke-linejoin: round;
|
||
filter:
|
||
drop-shadow(0 0 4px rgba(213, 242, 255, 0.68))
|
||
drop-shadow(0 5px 6px rgba(0, 53, 102, 0.5));
|
||
/* Present the direction cue on the apparent ground plane while its parent
|
||
remains locked to the same fixed HUD position. */
|
||
transform: perspective(220px) rotateX(62deg) rotateZ(var(--route-angle)) scaleY(1.35);
|
||
transform-origin: center;
|
||
transition: transform 180ms ease;
|
||
}
|
||
.cockpit-route-direction small {
|
||
padding: 2px 5px;
|
||
border: 1px solid color-mix(in srgb, var(--cockpit-accent) 20%, transparent);
|
||
border-radius: 3px;
|
||
background: rgba(0, 7, 12, 0.24);
|
||
font-size: 7px;
|
||
text-align: center;
|
||
letter-spacing: 0.14em;
|
||
white-space: nowrap;
|
||
}
|
||
.cockpit-altitude-rim {
|
||
--cockpit-keyhole-radius: min(40vw, 52vh);
|
||
position: absolute;
|
||
z-index: 2;
|
||
top: calc(50vh - var(--cockpit-keyhole-radius) + 20px);
|
||
right: calc(50vw - var(--cockpit-keyhole-radius) + 20px);
|
||
bottom: auto;
|
||
width: 230px;
|
||
height: calc((var(--cockpit-keyhole-radius) - 20px) * 2);
|
||
overflow: hidden;
|
||
color: var(--cockpit-accent);
|
||
opacity: 0.9;
|
||
}
|
||
.cockpit-altitude-rim-label {
|
||
position: absolute;
|
||
top: 20%;
|
||
right: calc(12px + (0.2 * (var(--cockpit-keyhole-radius) - 20px)));
|
||
color: color-mix(in srgb, var(--cockpit-accent) 82%, white);
|
||
font-size: 7px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.18em;
|
||
white-space: nowrap;
|
||
}
|
||
.cockpit-altitude-rim-rail {
|
||
position: absolute;
|
||
inset: 0;
|
||
overflow: hidden;
|
||
-webkit-mask-image: linear-gradient(
|
||
to bottom,
|
||
transparent 0%,
|
||
rgba(0, 0, 0, 0.04) 10%,
|
||
rgba(0, 0, 0, 0.28) 24%,
|
||
#000 42%,
|
||
#000 58%,
|
||
rgba(0, 0, 0, 0.28) 76%,
|
||
rgba(0, 0, 0, 0.04) 90%,
|
||
transparent 100%
|
||
);
|
||
mask-image: linear-gradient(
|
||
to bottom,
|
||
transparent 0%,
|
||
rgba(0, 0, 0, 0.04) 10%,
|
||
rgba(0, 0, 0, 0.28) 24%,
|
||
#000 42%,
|
||
#000 58%,
|
||
rgba(0, 0, 0, 0.28) 76%,
|
||
rgba(0, 0, 0, 0.04) 90%,
|
||
transparent 100%
|
||
);
|
||
}
|
||
.cockpit-altitude-rim-rail::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: 0;
|
||
right: 0;
|
||
box-sizing: border-box;
|
||
width: calc((var(--cockpit-keyhole-radius) - 20px) * 2);
|
||
height: calc((var(--cockpit-keyhole-radius) - 20px) * 2);
|
||
border: 2px solid color-mix(in srgb, var(--cockpit-accent) 72%, transparent);
|
||
border-radius: 50%;
|
||
box-shadow: 5px 0 18px color-mix(in srgb, var(--cockpit-accent) 18%, transparent);
|
||
}
|
||
.cockpit-altitude-rim-scale {
|
||
position: absolute;
|
||
inset: 0;
|
||
overflow: hidden;
|
||
-webkit-mask-image: linear-gradient(
|
||
to bottom,
|
||
transparent 0%,
|
||
rgba(0, 0, 0, 0.03) 9%,
|
||
rgba(0, 0, 0, 0.22) 23%,
|
||
#000 41%,
|
||
#000 59%,
|
||
rgba(0, 0, 0, 0.22) 77%,
|
||
rgba(0, 0, 0, 0.03) 91%,
|
||
transparent 100%
|
||
);
|
||
mask-image: linear-gradient(
|
||
to bottom,
|
||
transparent 0%,
|
||
rgba(0, 0, 0, 0.03) 9%,
|
||
rgba(0, 0, 0, 0.22) 23%,
|
||
#000 41%,
|
||
#000 59%,
|
||
rgba(0, 0, 0, 0.22) 77%,
|
||
rgba(0, 0, 0, 0.03) 91%,
|
||
transparent 100%
|
||
);
|
||
}
|
||
.cockpit-altitude-rim-scale > span {
|
||
position: absolute;
|
||
top: calc(50% + (var(--slot) * 8%));
|
||
right: calc(7px + (var(--curve) * (var(--cockpit-keyhole-radius) - 20px)));
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
color: rgba(244, 251, 255, 0.68);
|
||
transform: translateY(-50%) rotateZ(calc(var(--slot) * -1.7deg));
|
||
transform-origin: right center;
|
||
transition: top 120ms linear, right 120ms linear, transform 120ms linear;
|
||
}
|
||
.cockpit-altitude-rim-scale > span i {
|
||
order: 2;
|
||
display: block;
|
||
width: 20px;
|
||
border-top: 1px solid color-mix(in srgb, var(--cockpit-accent) 58%, transparent);
|
||
}
|
||
.cockpit-altitude-rim-scale > span b {
|
||
min-width: 46px;
|
||
padding: 1px 3px;
|
||
border-radius: 2px;
|
||
background: rgba(0, 7, 12, 0.28);
|
||
font-size: 8px;
|
||
font-weight: 500;
|
||
letter-spacing: 0.08em;
|
||
text-align: right;
|
||
}
|
||
.cockpit-altitude-rim-scale > span.major { color: rgba(244, 251, 255, 0.9); }
|
||
.cockpit-altitude-rim-scale > span.major i {
|
||
width: 32px;
|
||
border-color: color-mix(in srgb, var(--cockpit-accent) 86%, transparent);
|
||
}
|
||
.cockpit-altitude-rim-pointer {
|
||
position: absolute;
|
||
top: 50%;
|
||
right: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
color: #fff;
|
||
transform: translateY(-50%);
|
||
text-shadow: 0 0 12px var(--cockpit-accent);
|
||
}
|
||
.cockpit-altitude-rim-pointer strong {
|
||
min-width: 48px;
|
||
font-size: 10px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.06em;
|
||
text-align: right;
|
||
}
|
||
.cockpit-altitude-rim-pointer .material-symbols-outlined {
|
||
margin-left: 4px;
|
||
color: var(--cockpit-accent);
|
||
font-size: 24px;
|
||
font-variation-settings: 'FILL' 1, 'wght' 600;
|
||
animation: cockpit-altitude-pointer 1.8s ease-in-out infinite;
|
||
}
|
||
@keyframes cockpit-altitude-pointer {
|
||
50% { transform: translateX(-3px); filter: brightness(1.35); }
|
||
}
|
||
.cockpit-altitude-rim.unavailable { opacity: 0.24; }
|
||
.cockpit-speed-rim {
|
||
--speed-tape-inset: clamp(112px, 9vw, 148px);
|
||
right: auto;
|
||
left: calc(50vw - var(--cockpit-keyhole-radius) + 20px);
|
||
width: 300px;
|
||
}
|
||
.cockpit-speed-rim .cockpit-altitude-rim-label {
|
||
right: auto;
|
||
left: var(--speed-tape-inset);
|
||
}
|
||
.cockpit-speed-rim .cockpit-altitude-rim-rail::before {
|
||
right: auto;
|
||
left: 0;
|
||
box-shadow: -5px 0 18px color-mix(in srgb, var(--cockpit-accent) 18%, transparent);
|
||
}
|
||
.cockpit-speed-rim .cockpit-altitude-rim-scale > span {
|
||
right: auto;
|
||
left: calc(1px + (var(--curve) * (var(--cockpit-keyhole-radius) - 20px)));
|
||
flex-direction: row-reverse;
|
||
/* Speed rises toward the top of the tape; altitude intentionally runs the
|
||
opposite way on the mirrored right-hand ruler. */
|
||
top: calc(50% - (var(--slot) * 8%));
|
||
transform: translateY(-50%) rotateZ(calc(var(--slot) * 1.7deg));
|
||
transform-origin: left center;
|
||
}
|
||
.cockpit-speed-rim .cockpit-altitude-rim-scale > span b { text-align: left; }
|
||
.cockpit-speed-rim .cockpit-altitude-rim-pointer {
|
||
right: auto;
|
||
left: 0;
|
||
}
|
||
.cockpit-speed-rim .cockpit-altitude-rim-pointer strong { text-align: left; }
|
||
.cockpit-speed-rim .cockpit-altitude-rim-pointer .material-symbols-outlined {
|
||
margin-right: 4px;
|
||
margin-left: 0;
|
||
animation-name: cockpit-speed-pointer;
|
||
}
|
||
@keyframes cockpit-speed-pointer {
|
||
50% { transform: translateX(3px); filter: brightness(1.35); }
|
||
}
|
||
.cockpit-visor-status {
|
||
position: absolute;
|
||
bottom: 3px;
|
||
color: color-mix(in srgb, var(--cockpit-accent) 54%, transparent);
|
||
font-size: 7px;
|
||
letter-spacing: 0.22em;
|
||
}
|
||
.cockpit-visor-status-left { left: clamp(110px, 15vw, 220px); transform: rotateY(22deg); }
|
||
.cockpit-visor-status-right { right: clamp(110px, 15vw, 220px); transform: rotateY(-22deg); }
|
||
.cockpit-topline {
|
||
position: absolute;
|
||
z-index: 5;
|
||
top: clamp(18px, 3vh, 34px);
|
||
left: clamp(22px, 4vw, 58px);
|
||
right: clamp(22px, 4vw, 58px);
|
||
display: grid;
|
||
grid-template-columns: 1fr auto 1fr;
|
||
align-items: start;
|
||
gap: 24px;
|
||
}
|
||
.cockpit-topline > div:first-child { display: flex; flex-direction: column; gap: 4px; }
|
||
.cockpit-kicker, .cockpit-readout-label {
|
||
color: var(--cockpit-accent);
|
||
font-size: 9px;
|
||
font-weight: 600;
|
||
letter-spacing: 0.22em;
|
||
}
|
||
#cockpit-callsign { font-size: 18px; letter-spacing: 0.12em; }
|
||
.cockpit-aircraft-meta {
|
||
color: rgba(244, 251, 255, 0.48);
|
||
font-size: 7px;
|
||
letter-spacing: 0.16em;
|
||
}
|
||
.cockpit-mode-chip {
|
||
margin-top: 2px;
|
||
padding: 7px 11px;
|
||
border: 1px solid color-mix(in srgb, var(--cockpit-accent) 45%, transparent);
|
||
border-radius: 20px;
|
||
background: rgba(0, 7, 12, 0.62);
|
||
color: var(--cockpit-accent);
|
||
font-size: 9px;
|
||
font-weight: 600;
|
||
letter-spacing: 0.16em;
|
||
}
|
||
.cockpit-live-dot {
|
||
display: inline-block;
|
||
width: 5px;
|
||
height: 5px;
|
||
margin-right: 6px;
|
||
border-radius: 50%;
|
||
background: var(--cockpit-accent);
|
||
box-shadow: 0 0 8px var(--cockpit-accent);
|
||
animation: cockpit-live 1.6s ease-in-out infinite;
|
||
}
|
||
@keyframes cockpit-live { 50% { opacity: 0.35; } }
|
||
.cockpit-readout {
|
||
position: relative;
|
||
display: grid;
|
||
min-width: 118px;
|
||
padding: 6px 10px 7px;
|
||
border-top: 1px solid color-mix(in srgb, var(--cockpit-accent) 50%, transparent);
|
||
border-bottom: 1px solid color-mix(in srgb, var(--cockpit-accent) 18%, transparent);
|
||
background: linear-gradient(90deg, transparent, rgba(0, 7, 12, 0.34), transparent);
|
||
transform-style: preserve-3d;
|
||
}
|
||
.cockpit-speed {
|
||
justify-self: end;
|
||
text-align: right;
|
||
transform: perspective(760px) rotateY(10deg) translateZ(-5px);
|
||
transform-origin: right center;
|
||
}
|
||
.cockpit-altitude {
|
||
justify-self: start;
|
||
text-align: left;
|
||
transform: perspective(760px) rotateY(-10deg) translateZ(-5px);
|
||
transform-origin: left center;
|
||
}
|
||
.cockpit-readout strong {
|
||
margin-top: 1px;
|
||
font-size: clamp(30px, 3.6vw, 48px);
|
||
font-weight: 500;
|
||
line-height: 0.98;
|
||
letter-spacing: -0.06em;
|
||
white-space: nowrap;
|
||
}
|
||
.cockpit-roll-token {
|
||
position: relative;
|
||
display: inline-block;
|
||
min-width: 0.56em;
|
||
height: 1em;
|
||
overflow: hidden;
|
||
line-height: 1;
|
||
text-align: center;
|
||
vertical-align: -0.08em;
|
||
}
|
||
.cockpit-roll-token.is-rolling {
|
||
color: color-mix(in srgb, currentColor 92%, var(--cockpit-accent));
|
||
text-shadow: 0 0 10px color-mix(in srgb, var(--cockpit-accent) 35%, transparent);
|
||
}
|
||
.cockpit-roll-track {
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 2em;
|
||
will-change: transform;
|
||
}
|
||
.cockpit-roll-track > span {
|
||
display: block;
|
||
flex: 0 0 1em;
|
||
height: 1em;
|
||
line-height: 1;
|
||
}
|
||
.cockpit-roll-token.roll-up .cockpit-roll-track {
|
||
animation: cockpit-number-roll-up 200ms cubic-bezier(0.2, 0.75, 0.25, 1) both;
|
||
}
|
||
.cockpit-roll-token.roll-down .cockpit-roll-track {
|
||
animation: cockpit-number-roll-down 200ms cubic-bezier(0.2, 0.75, 0.25, 1) both;
|
||
}
|
||
@keyframes cockpit-number-roll-up {
|
||
from { transform: translateY(0); }
|
||
to { transform: translateY(-1em); }
|
||
}
|
||
@keyframes cockpit-number-roll-down {
|
||
from { transform: translateY(-1em); }
|
||
to { transform: translateY(0); }
|
||
}
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.cockpit-roll-token .cockpit-roll-track { animation-duration: 1ms; }
|
||
}
|
||
.cockpit-readout-unit {
|
||
margin-top: 2px;
|
||
color: rgba(244, 251, 255, 0.7);
|
||
font-size: 11px;
|
||
font-weight: 600;
|
||
letter-spacing: 0.2em;
|
||
}
|
||
.cockpit-reticle {
|
||
position: absolute;
|
||
top: 46%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%) translateZ(34px);
|
||
color: var(--cockpit-accent);
|
||
font-size: clamp(30px, 3vw, 44px);
|
||
font-variation-settings: 'wght' 200;
|
||
opacity: 0.8;
|
||
}
|
||
.cockpit-compass {
|
||
position: absolute;
|
||
left: 50%;
|
||
bottom: clamp(44px, 7vh, 72px);
|
||
width: min(760px, 72vw);
|
||
transform: translateX(-50%) rotateX(7deg) translateZ(18px);
|
||
transform-style: preserve-3d;
|
||
perspective: 760px;
|
||
text-align: center;
|
||
}
|
||
.cockpit-instrument-row {
|
||
display: grid;
|
||
grid-template-columns: minmax(118px, 1fr) auto minmax(118px, 1fr);
|
||
align-items: center;
|
||
gap: clamp(18px, 3vw, 42px);
|
||
}
|
||
.cockpit-heading-value {
|
||
min-width: 74px;
|
||
font-size: 34px;
|
||
font-weight: 600;
|
||
line-height: 1;
|
||
white-space: nowrap;
|
||
}
|
||
.cockpit-heading-value small { color: var(--cockpit-accent); font-size: 12px; }
|
||
.cockpit-heading-caret {
|
||
display: block;
|
||
height: 20px;
|
||
color: var(--cockpit-accent);
|
||
font-size: 28px;
|
||
line-height: 20px;
|
||
}
|
||
.cockpit-compass-tape {
|
||
position: relative;
|
||
height: 74px;
|
||
margin-top: -2px;
|
||
transform-style: preserve-3d;
|
||
}
|
||
.cockpit-compass-tape::before {
|
||
content: '';
|
||
position: absolute;
|
||
inset: 10px 2% 0;
|
||
border-top: 1px solid color-mix(in srgb, var(--cockpit-accent) 78%, transparent);
|
||
border-radius: 50%;
|
||
background: rgba(0, 7, 12, 0.16);
|
||
}
|
||
.cockpit-compass-tape span {
|
||
position: absolute;
|
||
top: 8px;
|
||
left: 50%;
|
||
color: rgba(244, 251, 255, 0.52);
|
||
font-size: 12px;
|
||
letter-spacing: 0.12em;
|
||
transform:
|
||
translateX(calc(-50% + (var(--slot) * 86px)))
|
||
translateY(calc(var(--depth) * 8px))
|
||
rotateZ(calc(var(--slot) * 3.6deg))
|
||
rotateY(calc(var(--slot) * -9deg));
|
||
}
|
||
.cockpit-compass-tape span::before {
|
||
content: '';
|
||
display: block;
|
||
width: 1px;
|
||
height: calc(17px - (var(--depth) * 2px));
|
||
margin: 0 auto 7px;
|
||
background: color-mix(in srgb, var(--cockpit-accent) 70%, transparent);
|
||
}
|
||
.cockpit-compass-tape span.active {
|
||
color: #fff;
|
||
font-size: 18px;
|
||
font-weight: 700;
|
||
text-shadow: 0 0 14px var(--cockpit-accent);
|
||
}
|
||
.cockpit-position-readout {
|
||
position: absolute;
|
||
right: clamp(24px, 4vw, 58px);
|
||
bottom: clamp(22px, 4vh, 42px);
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-end;
|
||
gap: 4px;
|
||
color: rgba(244, 251, 255, 0.72);
|
||
font-size: 10px;
|
||
letter-spacing: 0.1em;
|
||
}
|
||
.cockpit-vision-controls {
|
||
display: grid;
|
||
grid-template-columns: 48px 58px 48px;
|
||
align-items: stretch;
|
||
gap: 2px;
|
||
margin-top: 2px;
|
||
padding: 2px;
|
||
border: 1px solid color-mix(in srgb, var(--cockpit-accent) 22%, transparent);
|
||
border-radius: 7px;
|
||
background: rgba(0, 7, 12, 0.46);
|
||
box-shadow: inset 0 0 14px rgba(0, 0, 0, 0.28);
|
||
pointer-events: auto;
|
||
}
|
||
.cockpit-vision-controls button {
|
||
display: flex;
|
||
min-width: 0;
|
||
min-height: 31px;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 1px;
|
||
padding: 4px 5px;
|
||
border: 1px solid transparent;
|
||
border-radius: 5px;
|
||
background: rgba(0, 7, 12, 0.38);
|
||
color: rgba(244, 251, 255, 0.64);
|
||
font: 700 7px/1 var(--font-mono);
|
||
letter-spacing: 0.08em;
|
||
cursor: pointer;
|
||
}
|
||
.cockpit-vision-controls button:hover,
|
||
.cockpit-vision-controls button:focus-visible {
|
||
border-color: color-mix(in srgb, var(--cockpit-accent) 62%, transparent);
|
||
color: #fff;
|
||
outline: none;
|
||
}
|
||
.cockpit-vision-controls .material-symbols-outlined {
|
||
font-size: 14px;
|
||
}
|
||
.cockpit-vision-controls small {
|
||
font: 700 6px/1 var(--font-mono);
|
||
letter-spacing: 0.1em;
|
||
}
|
||
.cockpit-vision-current {
|
||
flex-direction: column;
|
||
}
|
||
.cockpit-vision-current small {
|
||
color: color-mix(in srgb, var(--cockpit-accent) 70%, #fff);
|
||
}
|
||
.cockpit-vision-current strong {
|
||
color: #fff;
|
||
font: 700 9px/1 var(--font-mono);
|
||
letter-spacing: 0.12em;
|
||
}
|
||
.cockpit-vision-controls .cockpit-vision-current {
|
||
border-color: var(--cockpit-accent);
|
||
background: color-mix(in srgb, var(--cockpit-accent) 10%, rgba(0, 7, 12, 0.72));
|
||
box-shadow: 0 0 10px color-mix(in srgb, var(--cockpit-accent) 30%, transparent);
|
||
}
|
||
.cockpit-route-card {
|
||
display: grid;
|
||
gap: 8px;
|
||
min-width: 0;
|
||
padding: 2px 6px 10px 8px;
|
||
border-bottom: 1px solid color-mix(in srgb, var(--cockpit-accent) 22%, transparent);
|
||
color: rgba(224, 247, 255, 0.9);
|
||
font: 7px/1.25 var(--font-mono);
|
||
letter-spacing: 0.09em;
|
||
}
|
||
.cockpit-route-card[hidden] { display: none; }
|
||
.cockpit-route-heading {
|
||
display: flex;
|
||
min-width: 0;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 8px;
|
||
}
|
||
.cockpit-route-kicker {
|
||
flex: 0 0 auto;
|
||
color: var(--cockpit-accent);
|
||
font-size: 7px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.16em;
|
||
}
|
||
.cockpit-route-heading small {
|
||
overflow: hidden;
|
||
color: color-mix(in srgb, var(--cockpit-accent) 68%, rgba(244, 251, 255, 0.46));
|
||
font-size: 5px;
|
||
letter-spacing: 0.08em;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
.cockpit-route-endpoints {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) 18px minmax(0, 1fr);
|
||
align-items: center;
|
||
gap: 7px;
|
||
}
|
||
.cockpit-route-airport {
|
||
display: grid;
|
||
min-width: 0;
|
||
gap: 3px;
|
||
padding: 6px 7px;
|
||
border-left: 1px solid color-mix(in srgb, var(--cockpit-accent) 52%, transparent);
|
||
background: rgba(0, 7, 12, 0.3);
|
||
}
|
||
.cockpit-route-airport > span {
|
||
color: color-mix(in srgb, var(--cockpit-accent) 76%, white);
|
||
font-size: 6px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.14em;
|
||
}
|
||
.cockpit-route-airport strong {
|
||
overflow: hidden;
|
||
color: #fff;
|
||
font-size: 8px;
|
||
letter-spacing: 0.06em;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
.cockpit-route-arrow {
|
||
color: var(--cockpit-accent);
|
||
font-size: 15px;
|
||
text-align: center;
|
||
}
|
||
#view-switcher {
|
||
position: fixed;
|
||
z-index: 146;
|
||
right: 36px;
|
||
bottom: calc(2vh + 4.5rem);
|
||
display: grid;
|
||
gap: 6px;
|
||
}
|
||
#view-switcher button {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 6px;
|
||
min-height: 32px;
|
||
padding: 7px 10px;
|
||
border: 1px solid rgba(116, 219, 255, 0.38);
|
||
border-radius: 6px;
|
||
background: rgba(2, 12, 20, 0.82);
|
||
color: #bceeff;
|
||
font: 700 8px/1 var(--font-mono);
|
||
letter-spacing: 0.12em;
|
||
cursor: pointer;
|
||
box-shadow: 0 0 18px rgba(0, 0, 0, 0.24);
|
||
}
|
||
#view-switcher button[hidden] { display: none; }
|
||
#view-switcher button:hover, #view-switcher button:focus-visible { border-color: #fff; color: #fff; outline: none; }
|
||
#view-switcher .material-symbols-outlined { font-size: 16px; }
|
||
body.cockpit-mode #view-switcher {
|
||
right: auto;
|
||
bottom: max(clamp(128px, 15vh, 150px), env(safe-area-inset-bottom));
|
||
display: flex;
|
||
max-width: calc(100vw - 24px);
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-bottom: -95px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
}
|
||
body.cockpit-mode #view-switcher button {
|
||
flex: 0 1 auto;
|
||
min-width: 0;
|
||
min-height: 28px;
|
||
padding: 6px 11px;
|
||
border-radius: 999px;
|
||
background: rgba(0, 7, 12, 0.74);
|
||
white-space: nowrap;
|
||
}
|
||
.cockpit-context-window {
|
||
position: absolute;
|
||
z-index: 4;
|
||
top: auto;
|
||
left: var(--cockpit-context-left, clamp(24px, 4vw, 58px));
|
||
bottom: var(--cockpit-bottom-rail-safe);
|
||
display: grid;
|
||
gap: 7px;
|
||
width: var(--cockpit-side-panel-width);
|
||
max-height: min(42vh, 410px);
|
||
overflow-x: hidden;
|
||
overflow-y: auto;
|
||
box-sizing: border-box;
|
||
padding: 11px 12px 10px;
|
||
border: 1px solid color-mix(in srgb, var(--cockpit-accent) 30%, transparent);
|
||
border-top-color: color-mix(in srgb, var(--cockpit-accent) 64%, transparent);
|
||
border-radius: 8px 24px 24px 8px;
|
||
background: rgba(0, 7, 12, 0.68);
|
||
box-shadow: inset 0 1px 0 rgba(255,255,255,0.04), 0 0 28px rgba(0,0,0,0.26);
|
||
transform: perspective(900px) rotateY(4deg) translateZ(18px);
|
||
transform-origin: left center;
|
||
transform-style: preserve-3d;
|
||
pointer-events: auto;
|
||
text-shadow: 0 0 8px color-mix(in srgb, var(--cockpit-accent) 45%, transparent);
|
||
scrollbar-color: color-mix(in srgb, var(--cockpit-accent) 45%, transparent) transparent;
|
||
scrollbar-width: thin;
|
||
transition: width 180ms ease, background-color 180ms ease, border-radius 180ms ease;
|
||
}
|
||
#cockpit-context[hidden] { display: none; }
|
||
.cockpit-context-window[data-state="uncertain"] { border-top-color: rgba(116, 219, 255, 0.72); }
|
||
/* CONTACT LOST reuses the amber the app already spends on unknown/stale inputs
|
||
(.cockpit-context-cohorts > div.unknown, .cockpit-brief-status[data-state="unavailable"]),
|
||
so a held last-known readout never reads as a live one. */
|
||
.cockpit-context-window[data-state="lost"] { border-top-color: rgba(213, 168, 99, 0.72); }
|
||
.cockpit-context-header {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) auto;
|
||
align-items: center;
|
||
gap: 5px 10px;
|
||
padding: 0 5px 7px;
|
||
border-bottom: 1px solid color-mix(in srgb, var(--cockpit-accent) 22%, transparent);
|
||
}
|
||
.cockpit-context-header > div { display: grid; gap: 2px; }
|
||
.cockpit-context-kicker {
|
||
color: var(--cockpit-accent);
|
||
font-size: 8px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.2em;
|
||
}
|
||
#cockpit-context-subject {
|
||
color: #fff;
|
||
font-size: 10px;
|
||
font-weight: 600;
|
||
letter-spacing: 0.12em;
|
||
}
|
||
.cockpit-context-qualifier {
|
||
grid-column: 1 / -1;
|
||
justify-self: start;
|
||
color: rgba(116, 219, 255, 0.82);
|
||
font-size: 7px;
|
||
letter-spacing: 0.16em;
|
||
white-space: nowrap;
|
||
}
|
||
.cockpit-context-weather {
|
||
display: inline-flex;
|
||
min-width: 48px;
|
||
height: 20px;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 5px;
|
||
padding: 0 7px;
|
||
border: 1px solid color-mix(in srgb, var(--cockpit-accent) 46%, transparent);
|
||
border-radius: 999px;
|
||
background: color-mix(in srgb, var(--cockpit-accent) 8%, rgba(0, 7, 12, 0.78));
|
||
color: color-mix(in srgb, var(--cockpit-accent) 82%, white);
|
||
font: 700 6px/1 var(--font-mono);
|
||
letter-spacing: 0.1em;
|
||
cursor: pointer;
|
||
}
|
||
.cockpit-context-weather strong {
|
||
color: #fff;
|
||
font: inherit;
|
||
}
|
||
.cockpit-context-weather[aria-pressed="false"] {
|
||
border-color: rgba(244, 251, 255, 0.15);
|
||
background: rgba(0, 7, 12, 0.54);
|
||
color: rgba(244, 251, 255, 0.42);
|
||
}
|
||
.cockpit-context-weather[aria-pressed="false"] strong { color: rgba(244, 251, 255, 0.5); }
|
||
.cockpit-context-weather:hover, .cockpit-context-weather:focus-visible {
|
||
border-color: var(--cockpit-accent);
|
||
color: #fff;
|
||
outline: none;
|
||
}
|
||
.cockpit-context-actions { display: flex; gap: 4px; }
|
||
.cockpit-context-actions button {
|
||
display: grid;
|
||
width: 28px;
|
||
height: 24px;
|
||
place-items: center;
|
||
padding: 0;
|
||
border: 1px solid color-mix(in srgb, var(--cockpit-accent) 30%, transparent);
|
||
border-radius: 5px;
|
||
background: rgba(0, 7, 12, 0.72);
|
||
color: color-mix(in srgb, var(--cockpit-accent) 82%, white);
|
||
cursor: pointer;
|
||
}
|
||
.cockpit-context-actions button:hover, .cockpit-context-actions button:focus-visible {
|
||
border-color: var(--cockpit-accent);
|
||
color: #fff;
|
||
outline: none;
|
||
}
|
||
.cockpit-context-actions button:disabled {
|
||
border-color: rgba(244, 251, 255, 0.1);
|
||
color: rgba(244, 251, 255, 0.2);
|
||
cursor: default;
|
||
}
|
||
.cockpit-context-actions .material-symbols-outlined { font-size: 15px; }
|
||
.cockpit-context-cohorts {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 6px;
|
||
}
|
||
.cockpit-context-cohorts > div {
|
||
display: grid;
|
||
grid-template-columns: auto 1fr;
|
||
align-items: baseline;
|
||
gap: 3px 8px;
|
||
min-width: 0;
|
||
padding: 6px 9px;
|
||
border-left: 1px solid color-mix(in srgb, var(--cockpit-accent) 40%, transparent);
|
||
background: rgba(0, 7, 12, 0.34);
|
||
}
|
||
.cockpit-context-cohorts span {
|
||
color: var(--cockpit-accent);
|
||
font-size: 8px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.14em;
|
||
}
|
||
.cockpit-context-cohorts strong {
|
||
justify-self: end;
|
||
color: #fff;
|
||
font-size: 17px;
|
||
font-weight: 600;
|
||
}
|
||
.cockpit-context-cohorts small {
|
||
grid-column: 1 / -1;
|
||
overflow: hidden;
|
||
color: rgba(244, 251, 255, 0.4);
|
||
font-size: 6px;
|
||
letter-spacing: 0.05em;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
.cockpit-context-cohorts > div.unknown { border-left-color: rgba(213, 168, 99, 0.58); }
|
||
.cockpit-context-cohorts > div.unknown strong { color: #d5a863; }
|
||
.cockpit-context-nearest {
|
||
display: grid;
|
||
grid-template-columns: 22px minmax(0, 1fr) auto;
|
||
grid-template-rows: auto auto;
|
||
align-items: center;
|
||
gap: 2px 8px;
|
||
padding: 3px 5px 2px;
|
||
}
|
||
#cockpit-context-direction {
|
||
grid-row: 1 / 3;
|
||
color: var(--cockpit-accent);
|
||
font-size: 22px;
|
||
transform-origin: 50% 50%;
|
||
transition: transform 180ms ease-out;
|
||
}
|
||
#cockpit-context-direction.unknown { opacity: 0.3; }
|
||
.cockpit-context-nearest > div { grid-column: 2; grid-row: 1; display: grid; gap: 2px; min-width: 0; }
|
||
.cockpit-context-nearest small {
|
||
color: rgba(244, 251, 255, 0.42);
|
||
font-size: 6px;
|
||
letter-spacing: 0.12em;
|
||
}
|
||
#cockpit-context-nearest-label {
|
||
overflow: hidden;
|
||
color: #fff;
|
||
font-size: 9px;
|
||
letter-spacing: 0.1em;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
#cockpit-context-bearing, #cockpit-context-distance {
|
||
color: var(--cockpit-accent);
|
||
font-size: 10px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.08em;
|
||
white-space: nowrap;
|
||
}
|
||
#cockpit-context-bearing { grid-column: 2; grid-row: 2; justify-self: start; }
|
||
#cockpit-context-distance { grid-column: 3; grid-row: 1 / 3; }
|
||
#cockpit-context-distance { color: #fff; }
|
||
.cockpit-context-footer {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) auto auto;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding: 6px 8px 0;
|
||
border-top: 1px solid rgba(244, 251, 255, 0.08);
|
||
color: rgba(244, 251, 255, 0.4);
|
||
font-size: 6px;
|
||
letter-spacing: 0.11em;
|
||
}
|
||
.cockpit-context-window[data-state="uncertain"] #cockpit-context-uncertainty { color: #74dbff; }
|
||
.cockpit-context-window[data-state="lost"] #cockpit-context-uncertainty {
|
||
color: #d5a863;
|
||
font-weight: 600;
|
||
}
|
||
/* The held values are last-known, not current — dim them to match the cue. */
|
||
.cockpit-context-window[data-state="lost"] :is(
|
||
.cockpit-context-cohorts,
|
||
.cockpit-context-nearest
|
||
) { opacity: 0.55; }
|
||
#cockpit-hud.context-active .cockpit-pitch-rail-left {
|
||
opacity: 0.16;
|
||
transition: opacity 180ms ease;
|
||
}
|
||
.cockpit-context-window[data-layout-mode="rail-left-constrained"] {
|
||
gap: 5px;
|
||
padding-top: 8px;
|
||
padding-bottom: 8px;
|
||
}
|
||
.cockpit-context-window[data-collapsed="true"] {
|
||
width: min(248px, 22vw);
|
||
max-height: none;
|
||
gap: 0;
|
||
padding: 9px 10px;
|
||
border-radius: 7px 18px 18px 7px;
|
||
background: rgba(0, 7, 12, 0.54);
|
||
}
|
||
.cockpit-context-window[data-collapsed="true"] .cockpit-context-header {
|
||
gap: 8px;
|
||
padding: 0;
|
||
border-bottom: 0;
|
||
}
|
||
.cockpit-context-window[data-collapsed="true"] :is(
|
||
.cockpit-context-qualifier,
|
||
.cockpit-context-cohorts,
|
||
.cockpit-context-nearest,
|
||
.cockpit-context-footer,
|
||
.cockpit-context-actions button:not(#cockpit-context-toggle)
|
||
) { display: none; }
|
||
.cockpit-context-window[data-collapsed="true"] #cockpit-context-subject {
|
||
font-size: 8px;
|
||
letter-spacing: 0.08em;
|
||
}
|
||
#cockpit-hud.signals-active .cockpit-pitch-rail-right {
|
||
opacity: 0.16;
|
||
transition: opacity 180ms ease;
|
||
}
|
||
.cockpit-signal-window {
|
||
position: absolute;
|
||
z-index: 3;
|
||
top: auto;
|
||
right: var(--cockpit-signal-right, clamp(24px, 4vw, 58px));
|
||
bottom: var(--cockpit-bottom-rail-safe);
|
||
display: grid;
|
||
gap: 7px;
|
||
width: var(--cockpit-side-panel-width);
|
||
max-height: min(42vh, 410px);
|
||
overflow-x: hidden;
|
||
overflow-y: auto;
|
||
box-sizing: border-box;
|
||
padding: 11px 12px 9px;
|
||
border: 1px solid color-mix(in srgb, var(--cockpit-accent) 30%, transparent);
|
||
border-top-color: color-mix(in srgb, var(--cockpit-accent) 64%, transparent);
|
||
border-radius: 24px 8px 8px 24px;
|
||
background: rgba(0, 7, 12, 0.68);
|
||
box-shadow: inset 0 1px 0 rgba(255,255,255,0.04), 0 0 28px rgba(0,0,0,0.26);
|
||
transform: perspective(900px) rotateY(-4deg) translateZ(18px);
|
||
transform-origin: right center;
|
||
pointer-events: auto;
|
||
text-shadow: 0 0 8px color-mix(in srgb, var(--cockpit-accent) 45%, transparent);
|
||
scrollbar-color: color-mix(in srgb, var(--cockpit-accent) 45%, transparent) transparent;
|
||
scrollbar-width: thin;
|
||
transition: width 180ms ease, background-color 180ms ease, border-radius 180ms ease;
|
||
}
|
||
#cockpit-signal-stream[hidden] { display: none; }
|
||
.cockpit-utility-controls {
|
||
position: absolute;
|
||
z-index: 5;
|
||
top: var(--cockpit-utility-top, var(--left-stack-safe-top, var(--left-stack-top)));
|
||
right: clamp(24px, 4vw, 58px);
|
||
bottom: auto;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-end;
|
||
justify-content: flex-end;
|
||
gap: 7px;
|
||
pointer-events: auto;
|
||
}
|
||
.cockpit-utility-control { position: relative; }
|
||
.cockpit-utility-control.is-expanded {
|
||
width: 272px;
|
||
box-sizing: border-box;
|
||
padding: 8px;
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: var(--panel-radius);
|
||
background: var(--glass-bg);
|
||
box-shadow: 0 8px 32px rgba(0, 0, 0, .5), inset 0 1px 0 rgba(255, 255, 255, .05);
|
||
backdrop-filter: blur(24px) saturate(1.4);
|
||
-webkit-backdrop-filter: blur(24px) saturate(1.4);
|
||
max-height: var(
|
||
--cockpit-utility-expanded-max-height,
|
||
var(--cockpit-utility-max-height, min(44vh, 430px))
|
||
);
|
||
overflow-y: auto;
|
||
}
|
||
.cockpit-utility-control.is-expanded:has([data-cockpit-launcher="display"]) {
|
||
width: var(--display-panel-expanded-width);
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-end;
|
||
gap: 7px;
|
||
box-shadow: 0 8px 32px rgba(0, 0, 0, .42), inset 0 1px 0 rgba(255, 255, 255, .04);
|
||
}
|
||
.cockpit-utility-control.is-expanded:has([data-cockpit-launcher="radio"]) {
|
||
width: var(--cockpit-radio-expanded-width, 232px);
|
||
}
|
||
.cockpit-utility-controls.layout-primary-only
|
||
> .cockpit-utility-control:not(.is-expanded) { display: none; }
|
||
.cockpit-utility-launcher {
|
||
display: grid;
|
||
grid-template-columns: auto minmax(0, 1fr) auto;
|
||
align-items: center;
|
||
gap: 7px;
|
||
width: var(--left-collapsed-width, 176px);
|
||
min-height: 50px;
|
||
padding: 8px 10px 8px 14px;
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: var(--panel-radius);
|
||
background: var(--glass-bg);
|
||
box-shadow: 0 8px 32px rgba(0, 0, 0, .42), inset 0 1px 0 rgba(255, 255, 255, .04);
|
||
backdrop-filter: blur(24px) saturate(1.4);
|
||
-webkit-backdrop-filter: blur(24px) saturate(1.4);
|
||
color: var(--text-dim);
|
||
font: 8px/1.1 var(--font-mono);
|
||
letter-spacing: 1.4px;
|
||
text-align: left;
|
||
}
|
||
[data-cockpit-launcher="display"] {
|
||
width: var(--left-collapsed-width, 176px);
|
||
}
|
||
[data-cockpit-launcher="radio"] {
|
||
width: var(--cockpit-radio-collapsed-width, 148px);
|
||
}
|
||
.cockpit-utility-control.is-expanded .cockpit-utility-launcher {
|
||
width: 100%;
|
||
min-height: 42px;
|
||
padding: 6px 2px 8px 6px;
|
||
border: 0;
|
||
border-radius: 0;
|
||
background: transparent;
|
||
box-shadow: none;
|
||
backdrop-filter: none;
|
||
-webkit-backdrop-filter: none;
|
||
}
|
||
.cockpit-utility-control.is-expanded .cockpit-utility-launcher {
|
||
width: 100%;
|
||
}
|
||
.cockpit-utility-control.is-expanded:has([data-cockpit-launcher="display"])
|
||
.cockpit-utility-launcher {
|
||
min-height: 42px;
|
||
box-sizing: border-box;
|
||
margin-left: auto;
|
||
margin-bottom: 0;
|
||
padding: 6px 2px 8px 6px;
|
||
gap: 8px;
|
||
}
|
||
.cockpit-utility-divider {
|
||
height: 1px;
|
||
background: linear-gradient(to right, var(--glass-border), transparent);
|
||
box-shadow: none;
|
||
}
|
||
.cockpit-utility-control.is-expanded .cockpit-utility-divider {
|
||
background: linear-gradient(90deg, rgb(0 212 255 / 28%), rgba(0, 212, 255, 0.18) 58%, transparent);
|
||
box-shadow: 0 0 7px rgba(0, 212, 255, .22);
|
||
}
|
||
.cockpit-utility-glyph {
|
||
display: grid;
|
||
width: 20px;
|
||
height: 20px;
|
||
padding: 0;
|
||
place-items: center;
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: 6px;
|
||
background: rgba(255, 255, 255, .03);
|
||
color: var(--text-secondary);
|
||
font-family: var(--font-mono);
|
||
font-size: 12px;
|
||
line-height: 1;
|
||
cursor: pointer;
|
||
}
|
||
.cockpit-utility-glyph:focus-visible {
|
||
border-color: var(--glass-border-hover);
|
||
color: var(--text-primary);
|
||
outline: none;
|
||
}
|
||
.cockpit-utility-popover {
|
||
position: static;
|
||
display: grid;
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
gap: 7px;
|
||
padding: 9px;
|
||
border: 0;
|
||
border-top: 1px solid var(--glass-border);
|
||
border-radius: 0;
|
||
background: transparent;
|
||
box-shadow: none;
|
||
}
|
||
.cockpit-utility-popover[hidden] { display: none !important; }
|
||
.cockpit-display-slot {
|
||
display: block;
|
||
min-width: 0;
|
||
}
|
||
#cockpit-display-panel {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 7px;
|
||
padding: 0;
|
||
border-top: 0;
|
||
max-height: min(52vh, 470px);
|
||
overflow-y: auto;
|
||
}
|
||
#cockpit-display-panel .pp-toggle-group {
|
||
width: 100%;
|
||
min-width: 0;
|
||
}
|
||
#cockpit-display-panel [data-cockpit-display-slot="parameters"] #param-slider-panel.active {
|
||
width: 100%;
|
||
max-height: none;
|
||
overflow-y: visible;
|
||
}
|
||
#cockpit-display-panel .pp-toggle-btn {
|
||
width: 100%;
|
||
min-height: 38px;
|
||
box-sizing: border-box;
|
||
}
|
||
.cockpit-radio-compact { width: 100%; }
|
||
.cockpit-radio-station {
|
||
overflow: hidden;
|
||
color: #fff;
|
||
font: 500 8px/1.2 var(--font-mono);
|
||
letter-spacing: .08em;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
.cockpit-radio-transport {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 6px;
|
||
}
|
||
.cockpit-radio-transport button {
|
||
min-height: 32px;
|
||
border: 1px solid rgba(65, 220, 231, .24);
|
||
border-radius: 6px;
|
||
background: rgba(65, 220, 231, .05);
|
||
color: #9ceaf1;
|
||
cursor: pointer;
|
||
}
|
||
.cockpit-radio-transport button:disabled { opacity: .38; cursor: not-allowed; }
|
||
.cockpit-radio-transport button.active { border-color: var(--cockpit-accent); color: #fff; }
|
||
.cockpit-radio-volume {
|
||
display: grid;
|
||
grid-template-columns: auto 1fr auto;
|
||
align-items: center;
|
||
gap: 8px;
|
||
color: rgba(244, 251, 255, .58);
|
||
font: 7px/1 var(--font-mono);
|
||
letter-spacing: .1em;
|
||
}
|
||
.cockpit-radio-volume input { width: 100%; }
|
||
.cockpit-signal-header {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) auto;
|
||
align-items: center;
|
||
gap: 10px;
|
||
padding: 0 4px 7px 8px;
|
||
border-bottom: 1px solid color-mix(in srgb, var(--cockpit-accent) 22%, transparent);
|
||
}
|
||
.cockpit-signal-header > div { display: grid; gap: 2px; }
|
||
.cockpit-signal-header strong {
|
||
color: #fff;
|
||
font-size: 8px;
|
||
letter-spacing: 0.1em;
|
||
}
|
||
.cockpit-signal-kicker {
|
||
color: var(--cockpit-accent);
|
||
font-size: 8px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.18em;
|
||
}
|
||
.cockpit-signal-kicker i {
|
||
display: inline-block;
|
||
width: 5px;
|
||
height: 5px;
|
||
margin-right: 5px;
|
||
border-radius: 50%;
|
||
background: var(--cockpit-accent);
|
||
box-shadow: 0 0 7px var(--cockpit-accent);
|
||
animation: cockpit-live 1.6s ease-in-out infinite;
|
||
}
|
||
.cockpit-brief-actions {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 3px;
|
||
}
|
||
.cockpit-brief-actions button {
|
||
display: grid;
|
||
width: 23px;
|
||
height: 24px;
|
||
place-items: center;
|
||
padding: 0;
|
||
border: 1px solid color-mix(in srgb, var(--cockpit-accent) 30%, transparent);
|
||
border-radius: 5px;
|
||
background: rgba(0, 7, 12, 0.72);
|
||
color: color-mix(in srgb, var(--cockpit-accent) 82%, white);
|
||
cursor: pointer;
|
||
}
|
||
.cockpit-brief-actions button:hover, .cockpit-brief-actions button:focus-visible {
|
||
border-color: var(--cockpit-accent);
|
||
color: #fff;
|
||
outline: none;
|
||
}
|
||
.cockpit-brief-actions .material-symbols-outlined { font-size: 14px; }
|
||
#cockpit-brief-auto {
|
||
width: 50px;
|
||
color: rgba(244, 251, 255, 0.42);
|
||
font: 700 6px/1 var(--font-mono);
|
||
letter-spacing: 0.05em;
|
||
}
|
||
#cockpit-brief-auto[aria-pressed="true"] {
|
||
border-color: var(--cockpit-accent);
|
||
background: color-mix(in srgb, var(--cockpit-accent) 14%, rgba(0, 7, 12, 0.72));
|
||
color: #fff;
|
||
box-shadow: 0 0 10px color-mix(in srgb, var(--cockpit-accent) 24%, transparent);
|
||
}
|
||
#cockpit-signal-toggle { width: 28px; margin-left: 2px; }
|
||
#cockpit-brief-position {
|
||
min-width: 25px;
|
||
color: rgba(244, 251, 255, 0.48);
|
||
font-size: 6px;
|
||
letter-spacing: 0.08em;
|
||
text-align: center;
|
||
}
|
||
.cockpit-brief-stage {
|
||
min-height: 178px;
|
||
overflow: hidden;
|
||
}
|
||
[data-cockpit-brief-page] {
|
||
animation: cockpit-brief-enter 220ms ease-out both;
|
||
}
|
||
[data-cockpit-brief-page][hidden] { display: none; }
|
||
.cockpit-signal-list {
|
||
display: grid;
|
||
gap: 3px;
|
||
margin: 0;
|
||
padding: 0;
|
||
list-style: none;
|
||
}
|
||
.cockpit-signal-list li {
|
||
display: grid;
|
||
grid-template-columns: 54px minmax(0, 1fr);
|
||
gap: 8px;
|
||
padding: 7px 7px 7px 9px;
|
||
border-left: 1px solid rgba(244, 251, 255, 0.2);
|
||
background: rgba(0, 7, 12, 0.3);
|
||
}
|
||
.cockpit-signal-list li.actionable {
|
||
transition: border-color 160ms ease, background 160ms ease;
|
||
}
|
||
.cockpit-signal-list li.actionable:hover,
|
||
.cockpit-signal-list li.actionable:focus-within {
|
||
border-left-color: var(--cockpit-accent);
|
||
background: color-mix(in srgb, var(--cockpit-accent) 10%, rgba(0, 7, 12, 0.4));
|
||
}
|
||
.cockpit-signal-list li.track, .cockpit-signal-list li.current { border-left-color: var(--cockpit-accent); }
|
||
.cockpit-signal-list li.nearby { border-left-color: #fff; }
|
||
.cockpit-signal-list li.military { border-left-color: #d5a863; }
|
||
.cockpit-signal-list li.warning { border-left-color: #d5a863; }
|
||
.cockpit-signal-list time {
|
||
color: rgba(244, 251, 255, 0.38);
|
||
font-size: 6px;
|
||
letter-spacing: 0.06em;
|
||
}
|
||
.cockpit-signal-list li > div { display: grid; gap: 2px; min-width: 0; }
|
||
.cockpit-signal-list strong {
|
||
color: color-mix(in srgb, var(--cockpit-accent) 78%, white);
|
||
font-size: 10px;
|
||
letter-spacing: 0.11em;
|
||
}
|
||
.cockpit-signal-target {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, auto) minmax(14px, 1fr) 12px;
|
||
align-items: center;
|
||
gap: 7px;
|
||
width: 100%;
|
||
padding: 0;
|
||
border: 0;
|
||
background: transparent;
|
||
color: color-mix(in srgb, var(--cockpit-accent) 78%, white);
|
||
font: inherit;
|
||
font-size: 11px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.11em;
|
||
text-align: left;
|
||
cursor: pointer;
|
||
}
|
||
.cockpit-signal-list li.military .cockpit-signal-target { color: #f0c968; }
|
||
.cockpit-signal-target-label {
|
||
overflow: hidden;
|
||
color: currentColor !important;
|
||
font: inherit;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
.cockpit-signal-target-rule {
|
||
height: 1px;
|
||
overflow: visible !important;
|
||
background: linear-gradient(90deg, currentColor, transparent);
|
||
opacity: 0.42;
|
||
transition: opacity 160ms ease, transform 160ms ease;
|
||
transform-origin: left center;
|
||
}
|
||
.cockpit-signal-target-chevron {
|
||
overflow: visible !important;
|
||
color: currentColor !important;
|
||
font-size: 12px !important;
|
||
line-height: 1;
|
||
transition: transform 160ms ease;
|
||
}
|
||
.cockpit-signal-target:hover,
|
||
.cockpit-signal-target:focus-visible {
|
||
color: #fff;
|
||
outline: none;
|
||
text-shadow: 0 0 8px color-mix(in srgb, var(--cockpit-accent) 72%, transparent);
|
||
}
|
||
.cockpit-signal-target:hover .cockpit-signal-target-rule,
|
||
.cockpit-signal-target:focus-visible .cockpit-signal-target-rule {
|
||
opacity: 0.82;
|
||
transform: scaleX(1.04);
|
||
}
|
||
.cockpit-signal-target:hover .cockpit-signal-target-chevron,
|
||
.cockpit-signal-target:focus-visible .cockpit-signal-target-chevron {
|
||
transform: translateX(2px);
|
||
}
|
||
.cockpit-signal-list li.warning strong { color: #d5a863; }
|
||
.cockpit-signal-list span {
|
||
overflow: hidden;
|
||
color: rgba(244, 251, 255, 0.66);
|
||
font-size: 8px;
|
||
letter-spacing: 0.06em;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
.cockpit-news-list {
|
||
display: grid;
|
||
gap: 4px;
|
||
margin: 0;
|
||
padding: 0;
|
||
list-style: none;
|
||
}
|
||
.cockpit-news-list:empty { display: none; }
|
||
.cockpit-news-list li {
|
||
border-left: 1px solid color-mix(in srgb, var(--cockpit-accent) 62%, transparent);
|
||
background: rgba(0, 7, 12, 0.3);
|
||
}
|
||
.cockpit-news-list a {
|
||
display: grid;
|
||
gap: 4px;
|
||
padding: 7px 9px;
|
||
color: inherit;
|
||
text-decoration: none;
|
||
}
|
||
.cockpit-news-list a:hover, .cockpit-news-list a:focus-visible {
|
||
background: color-mix(in srgb, var(--cockpit-accent) 8%, transparent);
|
||
outline: 1px solid color-mix(in srgb, var(--cockpit-accent) 46%, transparent);
|
||
}
|
||
.cockpit-news-list strong {
|
||
display: -webkit-box;
|
||
overflow: hidden;
|
||
color: rgba(244, 251, 255, 0.88);
|
||
font-size: 8px;
|
||
font-weight: 600;
|
||
line-height: 1.35;
|
||
letter-spacing: 0.045em;
|
||
-webkit-box-orient: vertical;
|
||
-webkit-line-clamp: 2;
|
||
}
|
||
.cockpit-news-list span {
|
||
color: color-mix(in srgb, var(--cockpit-accent) 65%, rgba(244, 251, 255, 0.42));
|
||
font-size: 6px;
|
||
letter-spacing: 0.08em;
|
||
text-transform: uppercase;
|
||
}
|
||
.cockpit-brief-status {
|
||
display: grid;
|
||
min-height: 0;
|
||
place-items: center;
|
||
padding: 18px 10px;
|
||
border: 0;
|
||
color: rgba(244, 251, 255, 0.45);
|
||
font-size: 7px;
|
||
letter-spacing: 0.13em;
|
||
text-align: center;
|
||
}
|
||
.cockpit-brief-status[data-state="unavailable"] { color: #d5a863; }
|
||
.cockpit-local-place {
|
||
display: grid;
|
||
gap: 3px;
|
||
padding: 5px 8px 8px;
|
||
border-bottom: 1px solid rgba(244, 251, 255, 0.08);
|
||
}
|
||
.cockpit-local-place strong {
|
||
overflow: hidden;
|
||
color: #fff;
|
||
font-size: 9px;
|
||
letter-spacing: 0.1em;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
.cockpit-local-place small {
|
||
color: rgba(244, 251, 255, 0.44);
|
||
font-size: 6px;
|
||
letter-spacing: 0.09em;
|
||
}
|
||
.cockpit-local-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 1px;
|
||
margin-top: 5px;
|
||
background: rgba(244, 251, 255, 0.07);
|
||
}
|
||
.cockpit-local-grid > div {
|
||
display: grid;
|
||
min-height: 60px;
|
||
align-content: center;
|
||
gap: 3px;
|
||
padding: 7px 9px;
|
||
background: rgba(0, 7, 12, 0.76);
|
||
}
|
||
.cockpit-local-grid span {
|
||
color: var(--cockpit-accent);
|
||
font-size: 7px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.13em;
|
||
}
|
||
.cockpit-local-grid strong {
|
||
overflow: hidden;
|
||
color: #fff;
|
||
font-size: 13px;
|
||
font-weight: 500;
|
||
letter-spacing: 0.06em;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
#cockpit-local-condition {
|
||
font-size: 10px;
|
||
line-height: 1.15;
|
||
letter-spacing: 0.03em;
|
||
text-overflow: clip;
|
||
white-space: normal;
|
||
}
|
||
.cockpit-local-grid small {
|
||
color: rgba(244, 251, 255, 0.35);
|
||
font-size: 6px;
|
||
letter-spacing: 0.07em;
|
||
}
|
||
|
||
.cockpit-weather-credit {
|
||
display: inline-block;
|
||
margin-top: 7px;
|
||
color: rgba(182, 226, 241, 0.72);
|
||
font: 600 7px/1.2 var(--font-mono);
|
||
letter-spacing: 0.08em;
|
||
text-transform: uppercase;
|
||
}
|
||
.cockpit-signal-footer {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 8px;
|
||
padding: 5px 8px 0;
|
||
border-top: 1px solid rgba(244, 251, 255, 0.08);
|
||
color: rgba(244, 251, 255, 0.34);
|
||
font-size: 6px;
|
||
letter-spacing: 0.1em;
|
||
}
|
||
.cockpit-signal-footer > span {
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
.cockpit-brief-tabs { display: flex; gap: 3px; }
|
||
.cockpit-brief-tabs button {
|
||
padding: 2px 4px;
|
||
border: 0;
|
||
border-bottom: 1px solid rgba(244, 251, 255, 0.16);
|
||
background: transparent;
|
||
color: rgba(244, 251, 255, 0.34);
|
||
font: inherit;
|
||
letter-spacing: 0.08em;
|
||
cursor: pointer;
|
||
}
|
||
.cockpit-brief-tabs button[aria-current="true"] {
|
||
border-bottom-color: var(--cockpit-accent);
|
||
color: color-mix(in srgb, var(--cockpit-accent) 80%, white);
|
||
}
|
||
.cockpit-brief-tabs button:hover, .cockpit-brief-tabs button:focus-visible {
|
||
color: #fff;
|
||
outline: none;
|
||
}
|
||
.cockpit-signal-window[data-layout-mode="rail-right-constrained"] { gap: 5px; }
|
||
.cockpit-signal-window[data-collapsed="true"] {
|
||
width: min(248px, 22vw);
|
||
max-height: none;
|
||
gap: 0;
|
||
padding: 9px 10px;
|
||
border-radius: 18px 7px 7px 18px;
|
||
background: rgba(0, 7, 12, 0.54);
|
||
}
|
||
.cockpit-signal-window[data-collapsed="true"] .cockpit-signal-header {
|
||
padding: 0;
|
||
border-bottom: 0;
|
||
}
|
||
.cockpit-signal-window[data-collapsed="true"] .cockpit-route-card { display: none; }
|
||
.cockpit-signal-window[data-collapsed="true"] :is(.cockpit-brief-stage, .cockpit-signal-footer) {
|
||
display: none;
|
||
}
|
||
.cockpit-signal-window[data-collapsed="true"] .cockpit-brief-actions > :not(#cockpit-signal-toggle) {
|
||
display: none;
|
||
}
|
||
@keyframes cockpit-brief-enter {
|
||
from { opacity: 0; transform: translateY(8px); }
|
||
to { opacity: 1; transform: translateY(0); }
|
||
}
|
||
.cockpit-help {
|
||
position: absolute;
|
||
left: clamp(24px, 4vw, 58px);
|
||
bottom: clamp(22px, 4vh, 42px);
|
||
color: rgba(244, 251, 255, 0.55);
|
||
font-size: 9px;
|
||
letter-spacing: 0.14em;
|
||
}
|
||
.cockpit-help span { color: var(--cockpit-accent); }
|
||
body.cockpit-mode :is(
|
||
#title-bar, #style-indicator, #top-center-actions, #traffic-sync-chip, #cctv-sync-chip,
|
||
#command-dock,
|
||
#military-awareness-panel, #military-awareness-direction-overlay,
|
||
#cockpit-entry
|
||
) { display: none !important; }
|
||
body.cockpit-mode :is(#clear-selected-layers, #share-btn, #reset-globe-view) {
|
||
display: none !important;
|
||
}
|
||
body.cockpit-mode #left-panel-stack {
|
||
z-index: 147;
|
||
display: flex;
|
||
top: var(--left-stack-safe-top, var(--left-stack-top));
|
||
bottom: var(--left-stack-safe-bottom, 24px);
|
||
height: auto;
|
||
max-height: none;
|
||
transition: none;
|
||
}
|
||
body.cockpit-mode #left-panel-stack > #scene-panel { display: none !important; }
|
||
body.cockpit-mode #right-context-rail {
|
||
display: none !important;
|
||
}
|
||
|
||
/* Keep the user's intelligence HUD text available in first person. It stays
|
||
subordinate to the visor instruments and occupies the four peripheral
|
||
corridors, leaving the optical center, context rails, and heading tape free. */
|
||
body.cockpit-mode #intel-hud.active {
|
||
z-index: 146;
|
||
opacity: 0.72;
|
||
visibility: visible;
|
||
}
|
||
body.cockpit-mode #intel-hud .hud-top-left,
|
||
body.cockpit-mode #intel-hud .hud-bottom-left {
|
||
left: clamp(18px, 3vw, 44px);
|
||
transform: scale(0.78);
|
||
transform-origin: left center;
|
||
}
|
||
body.cockpit-mode #intel-hud .hud-top-right,
|
||
body.cockpit-mode #intel-hud .hud-bottom-right {
|
||
right: clamp(18px, 3vw, 44px);
|
||
transform: scale(0.78);
|
||
transform-origin: right center;
|
||
}
|
||
body.cockpit-mode #intel-hud .hud-top-left,
|
||
body.cockpit-mode #intel-hud .hud-top-right {
|
||
top: clamp(104px, 13vh, 138px);
|
||
}
|
||
body.cockpit-mode #intel-hud .hud-bottom-left,
|
||
body.cockpit-mode #intel-hud .hud-bottom-right {
|
||
bottom: clamp(84px, 11vh, 118px);
|
||
}
|
||
body.cockpit-mode #intel-hud .hud-summary-wrap { max-width: min(34vw, 380px); }
|
||
body.cockpit-mode #intel-hud .hud-summary { font-size: 9px; }
|
||
body.cockpit-mode #intel-hud .hud-left-edge { left: 22px; }
|
||
body.cockpit-mode #intel-hud .hud-right-edge { right: 22px; }
|
||
|
||
@media (max-width: 760px) {
|
||
#view-switcher { right: 16px; bottom: 16px; }
|
||
body.cockpit-mode #view-switcher {
|
||
right: auto;
|
||
bottom: max(76px, env(safe-area-inset-bottom));
|
||
width: max-content;
|
||
max-width: calc(100vw - 20px);
|
||
margin-bottom: 0;
|
||
}
|
||
body.cockpit-mode #view-switcher button {
|
||
padding-inline: 9px;
|
||
font-size: 7px;
|
||
}
|
||
#cockpit-entry { left: auto; right: 16px; bottom: 88px; }
|
||
body.cockpit-mode #left-panel-stack,
|
||
body.cockpit-mode #intel-hud,
|
||
body.cockpit-mode .cockpit-context-window,
|
||
body.cockpit-mode .cockpit-signal-window {
|
||
display: none !important;
|
||
}
|
||
body.cockpit-mode #right-context-rail {
|
||
display: none !important;
|
||
}
|
||
body.cockpit-mode .cockpit-utility-controls {
|
||
top: auto;
|
||
right: 12px;
|
||
bottom: 152px;
|
||
max-width: calc(100vw - 24px);
|
||
}
|
||
body.cockpit-mode .cockpit-utility-controls {
|
||
flex-direction: row;
|
||
}
|
||
body.cockpit-mode .cockpit-utility-launcher {
|
||
width: min(150px, calc((100vw - 31px) / 2));
|
||
min-height: 42px;
|
||
}
|
||
body.cockpit-mode .cockpit-utility-control.is-expanded {
|
||
position: fixed;
|
||
top: 96px;
|
||
right: 12px;
|
||
width: min(272px, calc(100vw - 24px));
|
||
max-height: calc(100vh - 260px);
|
||
}
|
||
body.cockpit-mode .cockpit-utility-controls:has(.cockpit-utility-control.is-expanded)
|
||
> .cockpit-utility-control:not(.is-expanded) { display: none; }
|
||
body.cockpit-mode .cockpit-utility-popover {
|
||
position: static;
|
||
width: 100%;
|
||
}
|
||
.cockpit-topline { grid-template-columns: 1fr auto; }
|
||
.cockpit-mode-chip { display: none; }
|
||
.cockpit-readout { min-width: 76px; padding: 4px 6px 5px; }
|
||
.cockpit-readout strong { font-size: clamp(24px, 8vw, 34px); }
|
||
.cockpit-readout-label { font-size: 7px; letter-spacing: 0.12em; }
|
||
.cockpit-readout-unit { font-size: 8px; }
|
||
.cockpit-speed { transform: perspective(600px) rotateY(7deg); }
|
||
.cockpit-altitude { transform: perspective(600px) rotateY(-7deg); }
|
||
.cockpit-compass { width: 92vw; }
|
||
.cockpit-instrument-row {
|
||
grid-template-columns: minmax(76px, 1fr) auto minmax(76px, 1fr);
|
||
gap: 8px;
|
||
}
|
||
.cockpit-context-window {
|
||
top: auto;
|
||
left: 12px;
|
||
right: 12px;
|
||
bottom: 180px;
|
||
width: auto;
|
||
max-height: min(38vh, 280px);
|
||
padding: 10px 12px 8px;
|
||
border-radius: 20px 20px 10px 10px;
|
||
transform: translateZ(22px);
|
||
}
|
||
.cockpit-context-window[data-collapsed="true"] {
|
||
right: auto;
|
||
width: min(248px, calc(100vw - 24px));
|
||
max-height: none;
|
||
}
|
||
.cockpit-signal-window {
|
||
top: 112px;
|
||
right: 12px;
|
||
width: calc(100vw - 24px);
|
||
max-height: min(28vh, 220px);
|
||
padding: 10px 12px 8px;
|
||
border-radius: 20px 10px 10px 20px;
|
||
transform: translateZ(22px);
|
||
}
|
||
.cockpit-signal-window[data-collapsed="true"] {
|
||
left: auto;
|
||
width: min(248px, calc(100vw - 24px));
|
||
max-height: none;
|
||
}
|
||
.cockpit-context-header { grid-template-columns: 1fr auto; }
|
||
.cockpit-context-qualifier { display: none; }
|
||
.cockpit-context-cohorts small { display: none; }
|
||
.cockpit-context-cohorts { grid-template-columns: repeat(4, minmax(0, 1fr)); }
|
||
.cockpit-context-cohorts > div { padding: 4px 6px; }
|
||
.cockpit-context-nearest { grid-template-columns: 20px minmax(0, 1fr) auto; gap: 6px; }
|
||
#cockpit-context-bearing { display: none; }
|
||
.cockpit-context-footer { font-size: 5px; }
|
||
.cockpit-compass-tape span {
|
||
transform:
|
||
translateX(calc(-50% + (var(--slot) * 52px)))
|
||
translateY(calc(var(--depth) * 7px))
|
||
rotateZ(calc(var(--slot) * 3deg));
|
||
}
|
||
.cockpit-pitch-rail { display: none; }
|
||
.cockpit-altitude-rim { display: none; }
|
||
.cockpit-visor-status { display: none; }
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.cockpit-altitude-rim-pointer .material-symbols-outlined { animation: none; }
|
||
.cockpit-altitude-rim-scale > span { transition: none; }
|
||
[data-cockpit-brief-page] { animation: none; }
|
||
}
|
||
|
||
/* ── Safe Frame Overlay ─────────────────────── */
|
||
#safe-frame-overlay {
|
||
position: fixed;
|
||
inset: 0;
|
||
z-index: 95;
|
||
pointer-events: none;
|
||
display: none;
|
||
}
|
||
|
||
#safe-frame-overlay.active {
|
||
display: block;
|
||
}
|
||
|
||
#safe-frame-box {
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
width: min(90vw, calc(90vh * (16 / 9)));
|
||
aspect-ratio: 16 / 9;
|
||
border: 1px solid rgba(255, 255, 255, 0.28);
|
||
box-shadow:
|
||
0 0 0 1px rgba(0, 0, 0, 0.35),
|
||
inset 0 0 0 1px rgba(255, 255, 255, 0.06);
|
||
}
|
||
|
||
#safe-frame-overlay.ratio-9-16 #safe-frame-box {
|
||
width: min(58vh, 76vw);
|
||
aspect-ratio: 9 / 16;
|
||
}
|
||
|
||
/* Rule-of-thirds guides */
|
||
#safe-frame-box::before,
|
||
#safe-frame-box::after {
|
||
content: '';
|
||
position: absolute;
|
||
inset: 0;
|
||
pointer-events: none;
|
||
}
|
||
|
||
#safe-frame-box::before {
|
||
background:
|
||
linear-gradient(to right,
|
||
transparent 33.333%,
|
||
rgba(255, 255, 255, 0.2) 33.333%,
|
||
rgba(255, 255, 255, 0.2) 33.7%,
|
||
transparent 33.7%,
|
||
transparent 66.333%,
|
||
rgba(255, 255, 255, 0.2) 66.333%,
|
||
rgba(255, 255, 255, 0.2) 66.7%,
|
||
transparent 66.7%
|
||
),
|
||
linear-gradient(to bottom,
|
||
transparent 33.333%,
|
||
rgba(255, 255, 255, 0.2) 33.333%,
|
||
rgba(255, 255, 255, 0.2) 33.7%,
|
||
transparent 33.7%,
|
||
transparent 66.333%,
|
||
rgba(255, 255, 255, 0.2) 66.333%,
|
||
rgba(255, 255, 255, 0.2) 66.7%,
|
||
transparent 66.7%
|
||
);
|
||
}
|
||
|
||
/* ── Orbit Indicator ─────────────────────────── */
|
||
#orbit-indicator {
|
||
position: fixed;
|
||
top: 70px;
|
||
right: 36px;
|
||
z-index: 100;
|
||
font-family: var(--font-mono);
|
||
font-size: 10px;
|
||
letter-spacing: 2px;
|
||
color: var(--accent);
|
||
text-shadow: 0 0 12px var(--accent-glow);
|
||
pointer-events: none;
|
||
user-select: none;
|
||
opacity: 0;
|
||
visibility: hidden;
|
||
transition: opacity var(--transition-smooth), visibility var(--transition-smooth);
|
||
}
|
||
|
||
#orbit-indicator.active {
|
||
opacity: 1;
|
||
visibility: visible;
|
||
}
|
||
|
||
.orbit-icon {
|
||
font-size: 13px;
|
||
vertical-align: middle;
|
||
margin-right: 2px;
|
||
}
|
||
|
||
/* ── Intelligence HUD Overlay ────────────────── */
|
||
#intel-hud {
|
||
position: fixed;
|
||
inset: 0;
|
||
z-index: 2;
|
||
pointer-events: none;
|
||
opacity: 0;
|
||
visibility: hidden;
|
||
transition: opacity 0.4s ease, visibility 0.4s ease;
|
||
--hud-color: rgba(0, 255, 255, 0.6);
|
||
--hud-glow: rgba(0, 255, 255, 0.4);
|
||
--hud-border: rgba(0, 255, 255, 0.15);
|
||
}
|
||
|
||
#intel-hud.active {
|
||
opacity: 1;
|
||
visibility: visible;
|
||
}
|
||
|
||
#intel-hud * {
|
||
font-family: var(--font-mono);
|
||
color: var(--hud-color);
|
||
text-shadow: 0 0 4px var(--hud-glow);
|
||
text-transform: uppercase;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.hud-top-bar,
|
||
.hud-bottom-bar {
|
||
display: none;
|
||
position: absolute;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: min(980px, calc(100vw - 120px));
|
||
border: 1px solid var(--hud-border);
|
||
background: rgba(0, 0, 0, 0.34);
|
||
padding: 4px 10px;
|
||
font-size: 10px;
|
||
letter-spacing: 1.4px;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.hud-top-bar {
|
||
top: 70px;
|
||
}
|
||
|
||
.hud-bottom-bar {
|
||
bottom: 110px;
|
||
justify-content: center;
|
||
}
|
||
|
||
.hud-top-bar-center {
|
||
opacity: 0.84;
|
||
}
|
||
|
||
.hud-top-bar-left,
|
||
.hud-top-bar-right {
|
||
opacity: 0.6;
|
||
}
|
||
|
||
/* Corner blocks */
|
||
.hud-corner {
|
||
position: absolute;
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: 6px;
|
||
padding: 4px;
|
||
}
|
||
|
||
.hud-top-left {
|
||
top: 120px;
|
||
left: 36px;
|
||
}
|
||
|
||
.hud-top-right {
|
||
top: 120px;
|
||
right: 36px;
|
||
}
|
||
|
||
.hud-bottom-left {
|
||
bottom: 180px;
|
||
left: 36px;
|
||
}
|
||
|
||
.hud-bottom-right {
|
||
bottom: 180px;
|
||
right: 36px;
|
||
}
|
||
|
||
.hud-bracket {
|
||
font-size: 22px;
|
||
line-height: 1;
|
||
opacity: 0.6;
|
||
}
|
||
|
||
.hud-content {
|
||
font-size: 13px;
|
||
letter-spacing: 2px;
|
||
}
|
||
|
||
.hud-ais-vessel {
|
||
margin-top: 6px;
|
||
max-width: 340px;
|
||
white-space: pre-line;
|
||
line-height: 1.35;
|
||
opacity: 0.64;
|
||
}
|
||
|
||
.hud-ais-vessel.active {
|
||
opacity: 0.95;
|
||
}
|
||
|
||
.hud-classification {
|
||
font-size: 12px;
|
||
letter-spacing: 2.5px;
|
||
font-weight: 600;
|
||
margin-bottom: 3px;
|
||
}
|
||
|
||
.hud-system {
|
||
font-size: 13px;
|
||
opacity: 0.8;
|
||
}
|
||
|
||
.hud-mode {
|
||
font-size: 16px;
|
||
font-weight: 700;
|
||
letter-spacing: 4px;
|
||
margin-top: 3px;
|
||
}
|
||
|
||
.hud-summary-wrap {
|
||
margin-top: 6px;
|
||
max-width: 420px;
|
||
}
|
||
|
||
.hud-summary-label {
|
||
font-size: 9px;
|
||
letter-spacing: 1.8px;
|
||
opacity: 0.55;
|
||
}
|
||
|
||
.hud-summary {
|
||
margin-top: 2px;
|
||
min-height: 16px;
|
||
font-size: 11px;
|
||
letter-spacing: 1.2px;
|
||
opacity: 0.88;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.hud-rec {
|
||
font-size: 13px;
|
||
letter-spacing: 2px;
|
||
}
|
||
|
||
#hud-rec-dot {
|
||
color: #ff3333;
|
||
text-shadow: 0 0 6px rgba(255, 51, 51, 0.8);
|
||
font-size: 14px;
|
||
vertical-align: middle;
|
||
}
|
||
|
||
.hud-orbital {
|
||
font-size: 12px;
|
||
opacity: 0.7;
|
||
letter-spacing: 1.5px;
|
||
}
|
||
|
||
/* Edge annotations (vertical text) */
|
||
.hud-edge {
|
||
position: absolute;
|
||
font-size: 10px;
|
||
letter-spacing: 1.5px;
|
||
opacity: 0.5;
|
||
}
|
||
|
||
.hud-left-edge {
|
||
left: 36px;
|
||
top: 50%;
|
||
transform: translateY(-50%) rotate(-90deg);
|
||
transform-origin: left center;
|
||
white-space: nowrap;
|
||
display: flex;
|
||
gap: 20px;
|
||
}
|
||
|
||
.hud-right-edge {
|
||
right: 36px;
|
||
top: 50%;
|
||
transform: translateY(-50%) rotate(90deg);
|
||
transform-origin: right center;
|
||
white-space: nowrap;
|
||
display: flex;
|
||
gap: 20px;
|
||
}
|
||
|
||
#intel-hud[data-variant='tactical'] .hud-top-bar,
|
||
#intel-hud[data-variant='tactical'] .hud-bottom-bar {
|
||
display: none;
|
||
}
|
||
|
||
#intel-hud[data-variant='operator'] .hud-top-bar,
|
||
#intel-hud[data-variant='operator'] .hud-bottom-bar {
|
||
display: flex;
|
||
}
|
||
|
||
#intel-hud[data-variant='operator'] .hud-top-bar {
|
||
top: max(10vh, 90px);
|
||
left: 50%;
|
||
right: auto;
|
||
width: min(52vw, 720px);
|
||
transform: translateX(-50%);
|
||
border-color: rgba(255, 255, 255, 0.24);
|
||
background: linear-gradient(90deg, rgba(0, 0, 0, 0.56), rgba(8, 26, 34, 0.5));
|
||
box-shadow: 0 0 24px rgba(0, 255, 255, 0.08);
|
||
}
|
||
|
||
#intel-hud[data-variant='tactical'] .hud-top-left,
|
||
#intel-hud[data-variant='tactical'] .hud-top-right,
|
||
#intel-hud[data-variant='operator'] .hud-top-left,
|
||
#intel-hud[data-variant='operator'] .hud-top-right {
|
||
top: max(14vh, 136px);
|
||
}
|
||
|
||
#intel-hud[data-variant='operator'] .hud-bottom-bar {
|
||
border-color: rgba(255, 255, 255, 0.2);
|
||
background: linear-gradient(90deg, rgba(0, 0, 0, 0.52), rgba(8, 22, 18, 0.52));
|
||
}
|
||
|
||
#intel-hud[data-variant='operator'] .hud-corner {
|
||
padding: 8px 10px;
|
||
border: 1px solid rgba(255, 255, 255, 0.16);
|
||
border-radius: 8px;
|
||
background: rgba(0, 0, 0, 0.36);
|
||
}
|
||
|
||
#intel-hud[data-variant='operator'] .hud-bracket {
|
||
display: none;
|
||
}
|
||
|
||
#intel-hud[data-variant='minimal'] .hud-top-right,
|
||
#intel-hud[data-variant='minimal'] .hud-bottom-right,
|
||
#intel-hud[data-variant='minimal'] .hud-left-edge,
|
||
#intel-hud[data-variant='minimal'] .hud-right-edge,
|
||
#intel-hud[data-variant='minimal'] .hud-classification,
|
||
#intel-hud[data-variant='minimal'] .hud-system {
|
||
display: none;
|
||
}
|
||
|
||
#intel-hud[data-variant='minimal'] .hud-top-left {
|
||
top: 88px;
|
||
}
|
||
|
||
#intel-hud[data-variant='minimal'] .hud-bottom-left {
|
||
bottom: 12vh;
|
||
}
|
||
|
||
#intel-hud[data-variant='minimal'] .hud-bottom-bar {
|
||
display: flex;
|
||
bottom: calc(12vh + 4rem);
|
||
}
|
||
|
||
#intel-hud[data-variant='minimal'] .hud-summary-wrap {
|
||
max-width: 280px;
|
||
}
|
||
|
||
/* ── Data Layer Toggle Panel ─────────────────── */
|
||
#left-panel-stack {
|
||
position: fixed;
|
||
top: var(--left-stack-safe-top, var(--left-stack-top));
|
||
bottom: var(--left-stack-safe-bottom, 4vh);
|
||
left: var(--left-stack-x);
|
||
z-index: 100;
|
||
width: 360px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
gap: 8px;
|
||
pointer-events: none;
|
||
transition: top var(--transition-fast), bottom var(--transition-fast);
|
||
}
|
||
|
||
#data-panel {
|
||
--panel-expanded-width: 280px;
|
||
position: fixed;
|
||
top: calc(var(--left-stack-top) + var(--left-stack-gap));
|
||
left: var(--left-stack-x);
|
||
right: auto;
|
||
bottom: auto;
|
||
z-index: 100;
|
||
width: var(--panel-expanded-width);
|
||
opacity: 0;
|
||
visibility: hidden;
|
||
transform: translateY(8px);
|
||
transition: opacity var(--transition-smooth), visibility var(--transition-smooth), transform var(--transition-smooth);
|
||
}
|
||
|
||
#data-panel.active {
|
||
opacity: 1;
|
||
visibility: visible;
|
||
transform: translateY(0);
|
||
}
|
||
|
||
#data-panel .panel-glow {
|
||
position: absolute;
|
||
inset: -20px;
|
||
background: radial-gradient(ellipse at center, var(--accent-dim) 0%, transparent 60%);
|
||
filter: blur(20px);
|
||
opacity: 0.25;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.data-panel-inner {
|
||
position: relative;
|
||
background: var(--glass-bg);
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: var(--panel-radius);
|
||
padding: 14px 16px 12px;
|
||
backdrop-filter: blur(24px) saturate(1.4);
|
||
-webkit-backdrop-filter: blur(24px) saturate(1.4);
|
||
box-shadow:
|
||
0 8px 32px rgba(0, 0, 0, 0.5),
|
||
0 0 0 1px rgba(255, 255, 255, 0.03) inset,
|
||
0 1px 0 rgba(255, 255, 255, 0.06) inset;
|
||
max-height: min(620px, calc(100vh - var(--left-stack-top) - var(--left-stack-gap) - 36px));
|
||
display: flex;
|
||
flex-direction: column;
|
||
min-height: 0;
|
||
}
|
||
|
||
.data-toggle-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 2px;
|
||
flex: 1 1 auto;
|
||
min-height: 0;
|
||
max-height: 100%;
|
||
overflow-y: auto;
|
||
overscroll-behavior: contain;
|
||
padding-right: 4px;
|
||
scrollbar-width: thin;
|
||
scrollbar-color: rgba(0, 212, 255, 0.5) rgba(255, 255, 255, 0.04);
|
||
scrollbar-gutter: stable;
|
||
}
|
||
|
||
.data-toggle-list::-webkit-scrollbar {
|
||
width: 6px;
|
||
}
|
||
|
||
.data-toggle-list::-webkit-scrollbar-track {
|
||
background: rgba(255, 255, 255, 0.04);
|
||
border-radius: 999px;
|
||
}
|
||
|
||
.data-toggle-list::-webkit-scrollbar-thumb {
|
||
background: linear-gradient(180deg, rgba(0, 212, 255, 0.65), rgba(0, 212, 255, 0.2));
|
||
border-radius: 999px;
|
||
}
|
||
|
||
.data-toggle-row {
|
||
padding: 8px 10px 6px;
|
||
border-radius: 8px;
|
||
transition: background var(--transition-fast);
|
||
}
|
||
|
||
.data-toggle-row:hover {
|
||
background: rgba(255, 255, 255, 0.03);
|
||
}
|
||
|
||
/* Selected-only, provenance-first proximity results. This is intentionally a
|
||
contextual panel, not a radar/engagement display. */
|
||
#global-context-panel {
|
||
--panel-expanded-width: 330px;
|
||
width: var(--panel-expanded-width);
|
||
max-width: 100%;
|
||
min-height: 0;
|
||
}
|
||
#right-context-rail {
|
||
--right-display-collapsed-width: var(--left-collapsed-width);
|
||
--right-context-collapsed-width: var(--left-collapsed-width);
|
||
position: fixed;
|
||
z-index: 110;
|
||
top: var(--right-stack-safe-top, 26vh);
|
||
right: var(--right-rail-x);
|
||
width: 330px;
|
||
max-height: var(--right-stack-max-height, 70vh);
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-end;
|
||
gap: 8px;
|
||
pointer-events: none;
|
||
transition: top var(--transition-fast), max-height var(--transition-fast);
|
||
}
|
||
#right-context-rail > #pp-toggles,
|
||
#right-context-rail > #cctv-panel,
|
||
#right-context-rail > #global-context-panel {
|
||
position: relative;
|
||
inset: auto;
|
||
flex: 0 0 auto;
|
||
pointer-events: auto;
|
||
}
|
||
#right-context-rail #global-context-panel {
|
||
width: 100%;
|
||
max-height: 100%;
|
||
pointer-events: auto;
|
||
}
|
||
#right-context-rail #cctv-panel {
|
||
width: 100%;
|
||
max-height: 100%;
|
||
pointer-events: auto;
|
||
}
|
||
#right-context-rail #cctv-panel.collapsed {
|
||
width: var(--right-display-collapsed-width);
|
||
margin-left: auto;
|
||
}
|
||
#right-context-rail > #pp-toggles.collapsed {
|
||
width: var(--right-display-collapsed-width);
|
||
margin-left: auto;
|
||
}
|
||
#right-context-rail > #pp-toggles.collapsed .pp-header-row {
|
||
width: 100%;
|
||
}
|
||
#right-context-rail > #pp-toggles.collapsed .pp-header-row,
|
||
#right-context-rail #cctv-panel.collapsed .cctv-panel-inner,
|
||
#right-context-rail #global-context-panel.collapsed .global-context-panel-inner {
|
||
height: 50px;
|
||
min-height: 50px;
|
||
box-sizing: border-box;
|
||
}
|
||
#right-context-rail #cctv-panel:not(.collapsed) .cctv-panel-inner {
|
||
max-height: 100%;
|
||
overflow-y: auto;
|
||
scrollbar-gutter: stable;
|
||
}
|
||
#right-context-rail .global-context-panel-inner { max-height: 100%; }
|
||
#right-context-rail #global-context-panel:not(.collapsed) .global-context-panel-inner {
|
||
max-height: 100%;
|
||
overflow-y: auto;
|
||
scrollbar-gutter: stable;
|
||
}
|
||
#right-context-rail #global-context-panel.collapsed {
|
||
width: var(--right-context-collapsed-width);
|
||
/* Keep the compact Context tab on the rail edge rather than leaving it
|
||
stranded at the rail's expanded-width origin. */
|
||
margin-left: auto;
|
||
}
|
||
#right-context-rail #global-context-panel.collapsed .global-context-panel-inner {
|
||
min-height: 42px;
|
||
box-sizing: border-box;
|
||
justify-content: center;
|
||
overflow: visible;
|
||
padding: 8px 10px 8px 14px;
|
||
}
|
||
#right-context-rail #global-context-panel.collapsed .panel-header {
|
||
margin: 0;
|
||
}
|
||
#right-context-rail.layout-focus {
|
||
height: var(--right-stack-max-height);
|
||
}
|
||
#right-context-rail.layout-exclusive > [data-panel-id].collapsed {
|
||
display: none;
|
||
}
|
||
#right-context-rail.layout-focus > [data-panel-id].collapsed {
|
||
display: block;
|
||
flex: 0 0 auto;
|
||
}
|
||
#right-context-rail.layout-focus.layout-exclusive > [data-panel-id].collapsed {
|
||
display: none;
|
||
}
|
||
#right-context-rail.layout-focus > #pp-toggles:not(.collapsed),
|
||
#right-context-rail.layout-focus > #cctv-panel:not(.collapsed),
|
||
#right-context-rail.layout-focus > #global-context-panel:not(.collapsed) {
|
||
flex: 0 1 var(--right-panel-allocated-height);
|
||
height: var(--right-panel-allocated-height);
|
||
min-height: 0;
|
||
max-height: var(--right-panel-allocated-height);
|
||
}
|
||
#right-context-rail.layout-focus > #pp-toggles:not(.collapsed) {
|
||
overflow-y: auto;
|
||
overscroll-behavior: contain;
|
||
scrollbar-width: thin;
|
||
scrollbar-color: rgba(0, 212, 255, 0.4) transparent;
|
||
}
|
||
#right-context-rail.layout-focus > #cctv-panel:not(.collapsed) .cctv-panel-inner,
|
||
#right-context-rail.layout-focus > #global-context-panel:not(.collapsed) .global-context-panel-inner {
|
||
height: 100%;
|
||
box-sizing: border-box;
|
||
}
|
||
#right-context-rail #context-missions-view:not([hidden]),
|
||
#right-context-rail #space-mission-panel-host,
|
||
#right-context-rail .space-mission-roster {
|
||
min-height: 0;
|
||
}
|
||
#right-context-rail.layout-focus #context-missions-view:not([hidden]),
|
||
#right-context-rail.layout-focus #space-mission-panel-host,
|
||
#right-context-rail.layout-focus .space-mission-roster {
|
||
display: flex;
|
||
flex: 1 1 auto;
|
||
flex-direction: column;
|
||
}
|
||
#right-context-rail.layout-focus .space-mission-roster-list {
|
||
flex: 1 1 auto;
|
||
max-height: none;
|
||
}
|
||
#space-mission-panel {
|
||
width: 100%;
|
||
margin-top: 8px;
|
||
pointer-events: auto;
|
||
}
|
||
#space-mission-panel-host:has(#space-mission-panel:not([hidden])) > .context-mode-standby,
|
||
#space-mission-panel-host:has(#space-mission-panel:not([hidden])) > .space-mission-roster {
|
||
display: none;
|
||
}
|
||
#space-mission-panel-host .space-mission-roster {
|
||
display: grid;
|
||
min-height: 0;
|
||
gap: 8px;
|
||
padding: 9px;
|
||
border: 1px solid rgba(98, 181, 255, .2);
|
||
border-radius: 7px;
|
||
background: rgba(4, 17, 31, .28);
|
||
}
|
||
#space-mission-panel-host .space-mission-roster-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 10px;
|
||
padding: 1px 3px 7px;
|
||
border-bottom: 1px solid rgba(34, 230, 230, .14);
|
||
font-family: 'JetBrains Mono', monospace;
|
||
}
|
||
#space-mission-panel-host .space-mission-roster-header > div {
|
||
display: grid;
|
||
min-width: 0;
|
||
gap: 3px;
|
||
}
|
||
#space-mission-panel-host .space-mission-roster-header strong {
|
||
color: #8fcfff;
|
||
font-size: 9px;
|
||
letter-spacing: .16em;
|
||
}
|
||
#space-mission-panel-host .space-mission-roster-header span {
|
||
color: rgba(190, 230, 230, .46);
|
||
font-size: 7px;
|
||
letter-spacing: .1em;
|
||
}
|
||
#space-mission-panel-host .space-mission-roster-header output {
|
||
flex: 0 0 auto;
|
||
color: #22e6e6;
|
||
font-size: 9px;
|
||
letter-spacing: .08em;
|
||
}
|
||
#space-mission-panel-host .space-mission-roster-list {
|
||
display: grid;
|
||
max-height: min(43vh, 420px);
|
||
gap: 4px;
|
||
overflow-x: hidden;
|
||
overflow-y: auto;
|
||
padding-right: 3px;
|
||
scrollbar-color: rgba(34, 230, 230, .38) transparent;
|
||
scrollbar-width: thin;
|
||
}
|
||
#space-mission-panel-host .space-mission-roster-item {
|
||
position: relative;
|
||
display: grid;
|
||
grid-template-columns: 10px minmax(0, 1fr) 12px;
|
||
align-items: center;
|
||
gap: 7px;
|
||
width: 100%;
|
||
min-height: 42px;
|
||
padding: 7px 7px;
|
||
border: 1px solid rgba(98, 181, 255, .13);
|
||
border-radius: 4px;
|
||
color: #d8ffff;
|
||
background: rgba(42, 113, 171, .045);
|
||
font-family: 'JetBrains Mono', monospace;
|
||
text-align: left;
|
||
cursor: pointer;
|
||
transition: border-color .15s ease, background .15s ease, transform .15s ease;
|
||
}
|
||
#space-mission-panel-host .space-mission-roster-item::before {
|
||
content: '';
|
||
position: absolute;
|
||
inset: 3px;
|
||
z-index: 1;
|
||
opacity: 0;
|
||
background:
|
||
linear-gradient(#22e6e6, #22e6e6) left top / 9px 1px no-repeat,
|
||
linear-gradient(#22e6e6, #22e6e6) left top / 1px 9px no-repeat,
|
||
linear-gradient(#22e6e6, #22e6e6) right top / 9px 1px no-repeat,
|
||
linear-gradient(#22e6e6, #22e6e6) right top / 1px 9px no-repeat,
|
||
linear-gradient(#22e6e6, #22e6e6) left bottom / 9px 1px no-repeat,
|
||
linear-gradient(#22e6e6, #22e6e6) left bottom / 1px 9px no-repeat,
|
||
linear-gradient(#22e6e6, #22e6e6) right bottom / 9px 1px no-repeat,
|
||
linear-gradient(#22e6e6, #22e6e6) right bottom / 1px 9px no-repeat;
|
||
filter: drop-shadow(0 0 4px rgba(34, 230, 230, .45));
|
||
pointer-events: none;
|
||
transition: opacity .12s ease;
|
||
}
|
||
#space-mission-panel-host .space-mission-roster-item:hover,
|
||
#space-mission-panel-host .space-mission-roster-item:focus-visible {
|
||
border-color: rgba(34, 230, 230, .58);
|
||
outline: none;
|
||
background: rgba(34, 230, 230, .09);
|
||
transform: translateX(2px);
|
||
}
|
||
#space-mission-panel-host .space-mission-roster-item:hover::before,
|
||
#space-mission-panel-host .space-mission-roster-item:focus-visible::before {
|
||
opacity: 1;
|
||
}
|
||
#space-mission-panel-host .space-mission-roster-item > * {
|
||
position: relative;
|
||
z-index: 2;
|
||
}
|
||
#space-mission-panel-host .space-mission-roster-marker {
|
||
width: 5px;
|
||
height: 5px;
|
||
justify-self: center;
|
||
border-radius: 50%;
|
||
background: var(--mission-roster-color, #22e6e6);
|
||
box-shadow: 0 0 7px color-mix(in srgb, var(--mission-roster-color, #22e6e6) 70%, transparent);
|
||
}
|
||
#space-mission-panel-host .space-mission-roster-copy {
|
||
display: grid;
|
||
min-width: 0;
|
||
gap: 3px;
|
||
}
|
||
#space-mission-panel-host .space-mission-roster-copy strong,
|
||
#space-mission-panel-host .space-mission-roster-copy small {
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
#space-mission-panel-host .space-mission-roster-copy strong {
|
||
color: #d8ffff;
|
||
font-size: 9px;
|
||
font-weight: 500;
|
||
letter-spacing: .07em;
|
||
}
|
||
#space-mission-panel-host .space-mission-roster-copy small {
|
||
color: rgba(190, 230, 230, .48);
|
||
font-size: 7px;
|
||
letter-spacing: .035em;
|
||
}
|
||
#space-mission-panel-host .space-mission-roster-chevron {
|
||
color: rgba(34, 230, 230, .54);
|
||
font-size: 16px;
|
||
line-height: 1;
|
||
}
|
||
#space-mission-panel-host .space-mission-roster-empty {
|
||
padding: 18px 10px;
|
||
color: rgba(190, 230, 230, .48);
|
||
font: 8px/1.5 'JetBrains Mono', monospace;
|
||
letter-spacing: .09em;
|
||
text-align: center;
|
||
}
|
||
#space-mission-panel .space-mission-view-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 8px 0 2px;
|
||
border-top: 1px solid rgba(34, 230, 230, .18);
|
||
color: rgba(190, 230, 230, .58);
|
||
font: 8px 'JetBrains Mono', monospace;
|
||
letter-spacing: .18em;
|
||
}
|
||
#space-mission-panel .space-mission-view-header button {
|
||
width: 24px;
|
||
height: 24px;
|
||
border: 1px solid rgba(98, 181, 255, .24);
|
||
border-radius: 5px;
|
||
color: rgba(190, 230, 230, .7);
|
||
background: rgba(42, 113, 171, .08);
|
||
cursor: pointer;
|
||
}
|
||
#space-mission-panel .space-mission-view-header button:hover {
|
||
border-color: #22e6e6;
|
||
color: #fff;
|
||
}
|
||
#space-mission-panel .space-mission-detail {
|
||
display: grid;
|
||
gap: 8px;
|
||
padding: 12px 0;
|
||
color: var(--hud-cyan, #22e6e6);
|
||
font: 11px 'JetBrains Mono', monospace;
|
||
letter-spacing: .08em;
|
||
}
|
||
#space-mission-panel .space-mission-detail strong { font-size: 14px; }
|
||
#space-mission-panel .space-mission-detail span { color: rgba(190, 230, 230, .7); }
|
||
#space-mission-panel .space-mission-detail b { color: #d8ffff; font-weight: 400; }
|
||
#space-mission-panel .mission-data-section {
|
||
margin: 0 0 11px;
|
||
border-top: 1px solid rgba(34, 230, 230, .18);
|
||
padding-top: 9px;
|
||
}
|
||
#space-mission-panel .mission-data-section h4 {
|
||
margin: 0 0 6px;
|
||
color: #22e6e6;
|
||
font: 10px 'JetBrains Mono', monospace;
|
||
letter-spacing: .17em;
|
||
}
|
||
#space-mission-panel .mission-table-scroll { overflow-x: auto; }
|
||
#space-mission-panel .mission-data-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
table-layout: fixed;
|
||
color: #d8ffff;
|
||
font: 9px 'JetBrains Mono', monospace;
|
||
letter-spacing: .025em;
|
||
}
|
||
#space-mission-panel .mission-data-table th {
|
||
padding: 4px 5px;
|
||
border-bottom: 1px solid rgba(34, 230, 230, .22);
|
||
color: rgba(190, 230, 230, .58);
|
||
font-weight: 400;
|
||
text-align: left;
|
||
}
|
||
#space-mission-panel .mission-data-table td {
|
||
overflow-wrap: anywhere;
|
||
padding: 6px 5px;
|
||
border-bottom: 1px solid rgba(34, 230, 230, .1);
|
||
vertical-align: top;
|
||
}
|
||
#space-mission-panel .mission-data-table th:nth-child(1),
|
||
#space-mission-panel .mission-data-table td:nth-child(1) { width: 34%; }
|
||
#space-mission-panel .mission-data-table th:nth-child(2),
|
||
#space-mission-panel .mission-data-table td:nth-child(2) { width: 25%; }
|
||
#space-mission-panel .mission-data-table small {
|
||
display: block;
|
||
margin-top: 3px;
|
||
color: rgba(190, 230, 230, .56);
|
||
font-size: 8px;
|
||
line-height: 1.35;
|
||
}
|
||
#space-mission-panel .mission-table-empty {
|
||
color: rgba(190, 230, 230, .56);
|
||
text-align: center;
|
||
}
|
||
#space-mission-panel .mission-replay-speed-control {
|
||
display: grid;
|
||
gap: 5px;
|
||
margin: 1px 0 10px;
|
||
padding: 8px 10px 6px;
|
||
border: 1px solid rgba(34, 230, 230, .2);
|
||
border-radius: 5px;
|
||
background: rgba(3, 21, 31, .36);
|
||
}
|
||
#space-mission-panel .mission-replay-speed-control[hidden] { display: none; }
|
||
#space-mission-panel .mission-replay-speed-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
color: rgba(190, 230, 230, .68);
|
||
font: 8px 'JetBrains Mono', monospace;
|
||
letter-spacing: .16em;
|
||
}
|
||
#space-mission-panel .mission-replay-speed-header output {
|
||
min-width: 42px;
|
||
text-align: right;
|
||
}
|
||
#space-mission-panel [data-mission-replay-speed] {
|
||
width: 100%;
|
||
}
|
||
#space-mission-panel .mission-replay-speed-scale {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
color: rgba(190, 230, 230, .42);
|
||
font: 7px 'JetBrains Mono', monospace;
|
||
letter-spacing: .08em;
|
||
}
|
||
|
||
#space-mission-panel .mission-action-row {
|
||
display: flex;
|
||
gap: 8px;
|
||
margin: 1px 0 10px;
|
||
}
|
||
#space-mission-panel .mission-replay-button,
|
||
#space-mission-panel .mission-focus-button {
|
||
flex: 1;
|
||
min-width: 0;
|
||
padding: 9px 12px;
|
||
border: 1px solid rgba(255, 159, 67, .62);
|
||
border-radius: 5px;
|
||
color: #ffc078;
|
||
background: linear-gradient(90deg, rgba(255, 159, 67, .08), rgba(34, 230, 230, .08));
|
||
font: 9px 'JetBrains Mono', monospace;
|
||
letter-spacing: .16em;
|
||
cursor: pointer;
|
||
transition: border-color .15s ease, color .15s ease, background .15s ease, box-shadow .15s ease;
|
||
}
|
||
#space-mission-panel .mission-focus-button {
|
||
border-color: rgba(34, 230, 230, .58);
|
||
color: #22e6e6;
|
||
background: rgba(34, 230, 230, .07);
|
||
}
|
||
#space-mission-panel .mission-replay-button:hover,
|
||
#space-mission-panel .mission-replay-button:focus-visible,
|
||
#space-mission-panel .mission-focus-button:hover,
|
||
#space-mission-panel .mission-focus-button:focus-visible {
|
||
border-color: #ffb45f;
|
||
color: #fff;
|
||
outline: none;
|
||
box-shadow: 0 0 14px rgba(255, 159, 67, .14);
|
||
}
|
||
#space-mission-panel .mission-focus-button:hover,
|
||
#space-mission-panel .mission-focus-button:focus-visible {
|
||
border-color: #22e6e6;
|
||
box-shadow: 0 0 14px rgba(34, 230, 230, .14);
|
||
}
|
||
#space-mission-panel .mission-replay-button.active {
|
||
border-color: #22e6e6;
|
||
color: #d8ffff;
|
||
background: rgba(34, 230, 230, .13);
|
||
box-shadow: inset 0 0 16px rgba(34, 230, 230, .08);
|
||
}
|
||
#space-mission-panel .mission-replay-transport {
|
||
flex: 1;
|
||
min-width: 0;
|
||
display: grid;
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
gap: 5px;
|
||
}
|
||
#space-mission-panel .mission-replay-transport[hidden] { display: none; }
|
||
#space-mission-panel .mission-replay-transport button {
|
||
min-width: 0;
|
||
min-height: 34px;
|
||
padding: 0;
|
||
border: 1px solid rgba(34, 230, 230, .5);
|
||
border-radius: 4px;
|
||
color: #22e6e6;
|
||
background: rgba(34, 230, 230, .08);
|
||
font: 15px/1 'JetBrains Mono', monospace;
|
||
cursor: pointer;
|
||
transition: border-color .15s ease, color .15s ease, background .15s ease, box-shadow .15s ease, opacity .15s ease;
|
||
}
|
||
#space-mission-panel .mission-replay-transport button:hover:not(:disabled),
|
||
#space-mission-panel .mission-replay-transport button:focus-visible {
|
||
border-color: #d8ffff;
|
||
color: #fff;
|
||
outline: none;
|
||
background: rgba(34, 230, 230, .16);
|
||
box-shadow: 0 0 12px rgba(34, 230, 230, .14);
|
||
}
|
||
#space-mission-panel .mission-replay-transport button:disabled {
|
||
opacity: .28;
|
||
cursor: default;
|
||
}
|
||
#space-mission-panel .mission-replay-transport button.cancel {
|
||
border-color: rgba(255, 159, 67, .58);
|
||
color: #ffb15c;
|
||
background: rgba(255, 159, 67, .08);
|
||
}
|
||
#space-mission-panel .mission-replay-transport.is-paused [data-mission-replay-play] {
|
||
border-color: #22e6e6;
|
||
color: #d8ffff;
|
||
background: rgba(34, 230, 230, .18);
|
||
box-shadow: inset 0 0 12px rgba(34, 230, 230, .1);
|
||
}
|
||
#space-mission-panel .space-mission-nav { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
|
||
#space-mission-panel .mission-nav-button {
|
||
min-width: 94px;
|
||
padding: 7px 10px;
|
||
border: 1px solid rgba(34, 230, 230, .55);
|
||
background: rgba(8, 34, 42, .72);
|
||
color: #22e6e6;
|
||
font: 11px 'JetBrains Mono', monospace;
|
||
letter-spacing: .12em;
|
||
cursor: pointer;
|
||
transition: background .15s ease, border-color .15s ease, opacity .15s ease;
|
||
}
|
||
#space-mission-panel .mission-nav-button:hover:not(:disabled) { background: rgba(34, 230, 230, .18); border-color: #22e6e6; }
|
||
#space-mission-panel .mission-nav-button:disabled { cursor: not-allowed; opacity: .28; }
|
||
#space-mission-panel .mission-nav-button span { font-size: 18px; line-height: 0; vertical-align: -2px; }
|
||
#space-mission-panel .mission-nav-index { min-width: 58px; text-align: center; color: #d8ffff; font: 11px 'JetBrains Mono', monospace; letter-spacing: .1em; }
|
||
#space-mission-panel button { cursor: pointer; }
|
||
|
||
.mission-replay-vehicle-overlay {
|
||
--mission-replay-vehicle-scale: .50;
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
z-index: 86;
|
||
width: 92px;
|
||
height: 138px;
|
||
pointer-events: none;
|
||
will-change: transform;
|
||
}
|
||
|
||
.mission-replay-flight-symbol {
|
||
position: absolute;
|
||
inset: 0;
|
||
transform: rotate(var(--mission-replay-rotation, 0deg)) scale(var(--mission-replay-vehicle-scale));
|
||
transform-origin: 46px 69px;
|
||
will-change: transform;
|
||
}
|
||
|
||
.mission-replay-orbit-dot {
|
||
display: none;
|
||
position: absolute;
|
||
top: 65px;
|
||
left: 42px;
|
||
width: 8px;
|
||
height: 8px;
|
||
border-radius: 50%;
|
||
background: #22e6e6;
|
||
box-shadow: 0 0 7px rgba(34, 230, 230, .78);
|
||
}
|
||
|
||
.mission-replay-vehicle-overlay[data-mode='orbit'] .mission-replay-flight-symbol {
|
||
display: none;
|
||
}
|
||
|
||
.mission-replay-vehicle-overlay[data-mode='orbit'] .mission-replay-orbit-dot {
|
||
display: block;
|
||
}
|
||
|
||
.mission-replay-rocket {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 22px;
|
||
width: 48px;
|
||
height: 72px;
|
||
overflow: visible;
|
||
filter: drop-shadow(0 0 6px rgba(34, 230, 230, .66));
|
||
}
|
||
|
||
.mission-replay-rocket-body {
|
||
fill: #22e6e6;
|
||
stroke: #22e6e6;
|
||
stroke-width: 2;
|
||
stroke-linejoin: round;
|
||
}
|
||
|
||
.mission-replay-rocket-port {
|
||
fill: #22e6e6;
|
||
stroke: none;
|
||
}
|
||
|
||
.mission-replay-rocket-flame {
|
||
display: none;
|
||
}
|
||
|
||
.mission-replay-thrust {
|
||
display: none;
|
||
position: absolute;
|
||
top: 57px;
|
||
left: 10px;
|
||
width: 72px;
|
||
height: 72px;
|
||
overflow: visible;
|
||
filter: drop-shadow(0 0 4px rgba(34, 230, 230, .9));
|
||
}
|
||
|
||
.mission-replay-vehicle-overlay.is-thrusting .mission-replay-thrust {
|
||
display: block;
|
||
}
|
||
|
||
.mission-replay-thrust ellipse {
|
||
fill: none;
|
||
stroke: rgba(34, 230, 230, .98);
|
||
stroke-width: 2;
|
||
opacity: 0;
|
||
vector-effect: non-scaling-stroke;
|
||
animation: mission-thrust-wave .9s ease-in-out infinite;
|
||
animation-delay: calc(var(--thrust-index) * .15s);
|
||
}
|
||
|
||
.mission-replay-thrust ellipse:nth-child(2n) {
|
||
stroke: rgba(216, 255, 255, .78);
|
||
}
|
||
|
||
.mission-replay-vehicle-overlay.is-paused .mission-replay-thrust ellipse {
|
||
animation-play-state: paused;
|
||
}
|
||
|
||
.mission-replay-overlay-callout {
|
||
position: absolute;
|
||
top: 18px;
|
||
left: 70px;
|
||
min-width: 188px;
|
||
color: #fff;
|
||
font: 9px/1.38 'JetBrains Mono', monospace;
|
||
letter-spacing: .075em;
|
||
text-shadow: 0 1px 2px #001018, 0 0 6px #001018;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.mission-replay-overlay-callout strong,
|
||
.mission-replay-overlay-callout span {
|
||
display: block;
|
||
}
|
||
|
||
.mission-replay-overlay-callout strong {
|
||
color: #22e6e6;
|
||
font-size: 10px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.mission-replay-overlay-callout span {
|
||
color: rgba(255, 255, 255, .92);
|
||
white-space: pre-line;
|
||
}
|
||
|
||
.mission-replay-vehicle-overlay[data-mode='orbit'] .mission-replay-overlay-callout {
|
||
top: 55px;
|
||
left: 58px;
|
||
}
|
||
|
||
@keyframes mission-thrust-wave {
|
||
0%, 18% { opacity: 0; }
|
||
24% { opacity: 1; }
|
||
32%, 100% { opacity: 0; }
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.mission-replay-thrust ellipse {
|
||
animation: none;
|
||
}
|
||
}
|
||
#global-context-panel .panel-glow {
|
||
position: absolute;
|
||
inset: -20px;
|
||
background: radial-gradient(ellipse at center, rgba(98, 181, 255, 0.2) 0%, transparent 62%);
|
||
filter: blur(20px);
|
||
opacity: 0.24;
|
||
pointer-events: none;
|
||
}
|
||
.global-context-panel-inner {
|
||
position: relative;
|
||
display: flex;
|
||
min-height: 0;
|
||
flex-direction: column;
|
||
padding: 14px 16px 12px;
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: var(--panel-radius);
|
||
background: var(--glass-bg);
|
||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.05);
|
||
backdrop-filter: blur(24px) saturate(1.4);
|
||
-webkit-backdrop-filter: blur(24px) saturate(1.4);
|
||
}
|
||
.context-radio-dock {
|
||
position: relative;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.context-radio-toggle {
|
||
display: grid;
|
||
width: 28px;
|
||
height: 28px;
|
||
place-items: center;
|
||
padding: 0;
|
||
border: 1px solid rgba(98, 181, 255, .22);
|
||
border-radius: 6px;
|
||
color: rgba(143, 207, 255, .58);
|
||
background: rgba(42, 113, 171, .08);
|
||
cursor: pointer;
|
||
transition: border-color .15s ease, color .15s ease, background .15s ease, box-shadow .15s ease;
|
||
}
|
||
.context-radio-toggle .material-symbols-outlined { font-size: 17px; }
|
||
.context-radio-toggle:hover,
|
||
.context-radio-toggle:focus-visible {
|
||
border-color: #79c2ff;
|
||
color: #fff;
|
||
outline: none;
|
||
}
|
||
.context-radio-toggle.active {
|
||
border-color: rgba(101, 247, 255, .82);
|
||
color: #eaffff;
|
||
background: rgba(0, 212, 255, .16);
|
||
box-shadow: inset 0 0 12px rgba(0, 212, 255, .1), 0 0 12px rgba(0, 212, 255, .2);
|
||
}
|
||
.context-radio-toggle:disabled { opacity: .5; cursor: wait; }
|
||
.context-radio-mini {
|
||
position: absolute;
|
||
z-index: 5;
|
||
top: calc(100% + 20px);
|
||
right: -38px;
|
||
display: none;
|
||
width: 244px;
|
||
box-sizing: border-box;
|
||
gap: 8px;
|
||
padding: 10px;
|
||
border: 1px solid rgba(65, 220, 231, .28);
|
||
border-radius: 8px;
|
||
background: rgba(2, 15, 20, .96);
|
||
box-shadow: 0 12px 32px rgba(0, 0, 0, .62), inset 0 1px 0 rgba(255, 255, 255, .04);
|
||
backdrop-filter: blur(22px) saturate(1.35);
|
||
-webkit-backdrop-filter: blur(22px) saturate(1.35);
|
||
}
|
||
.context-radio-mini[hidden] { display: none !important; }
|
||
.context-radio-dock.disclosure-open .context-radio-mini {
|
||
display: grid;
|
||
}
|
||
.context-radio-mini-heading {
|
||
display: grid;
|
||
grid-template-columns: auto minmax(0, 1fr) auto;
|
||
gap: 8px;
|
||
align-items: center;
|
||
color: #65f7ff;
|
||
font: 7px/1.2 var(--font-mono);
|
||
letter-spacing: .12em;
|
||
}
|
||
.context-radio-mini-heading button {
|
||
display: grid;
|
||
width: 26px;
|
||
height: 26px;
|
||
place-items: center;
|
||
padding: 0;
|
||
border: 1px solid rgba(65, 220, 231, .28);
|
||
border-radius: 5px;
|
||
color: #8feaf2;
|
||
background: rgba(14, 69, 78, .16);
|
||
cursor: pointer;
|
||
}
|
||
.context-radio-mini-heading button:hover,
|
||
.context-radio-mini-heading button:focus-visible {
|
||
border-color: #65f7ff;
|
||
color: #fff;
|
||
outline: none;
|
||
}
|
||
.context-radio-mini-actions {
|
||
display: flex;
|
||
gap: 5px;
|
||
}
|
||
.context-radio-mini-heading .material-symbols-outlined { font-size: 16px; }
|
||
.context-radio-mini > .panel-layer-toggle { width: 100%; }
|
||
.context-radio-mini-heading strong {
|
||
overflow: hidden;
|
||
color: #e8feff;
|
||
font-size: 8px;
|
||
font-weight: 500;
|
||
text-align: right;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
.context-radio-mini-transport {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
gap: 5px;
|
||
}
|
||
.context-radio-mini-transport button {
|
||
min-height: 28px;
|
||
padding: 5px;
|
||
border: 1px solid rgba(65, 220, 231, .28);
|
||
border-radius: 5px;
|
||
color: #8feaf2;
|
||
background: rgba(14, 69, 78, .16);
|
||
font: 8px/1 var(--font-mono);
|
||
cursor: pointer;
|
||
}
|
||
.context-radio-mini-transport button:hover:not(:disabled),
|
||
.context-radio-mini-transport button:focus-visible:not(:disabled),
|
||
.context-radio-mini-transport button.active {
|
||
border-color: #65f7ff;
|
||
color: #fff;
|
||
outline: none;
|
||
}
|
||
.context-radio-mini-transport button:disabled { opacity: .38; cursor: not-allowed; }
|
||
.context-radio-mini-volume {
|
||
display: grid;
|
||
grid-template-columns: auto minmax(0, 1fr) 30px;
|
||
gap: 7px;
|
||
align-items: center;
|
||
color: var(--text-dim);
|
||
font: 7px/1 var(--font-mono);
|
||
letter-spacing: .08em;
|
||
}
|
||
.context-radio-mini-volume input { width: 100%; }
|
||
.global-context-actions {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||
gap: 6px;
|
||
margin: 0 0 8px;
|
||
}
|
||
.global-context-actions:has(#installations-search-btn) { grid-template-columns: minmax(0, 1fr); }
|
||
.global-context-actions:has(#cockpit-entry:not([hidden])) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||
.global-context-actions:has(#cockpit-entry[hidden]) { grid-template-columns: 1fr; }
|
||
/* TR-3B reclassify toggle rides an `auto` trailing column so the chip never
|
||
resizes the COCKPIT / SEARCH buttons beside it. */
|
||
.global-context-actions:has(#tr3b-toggle:not([hidden])) { grid-template-columns: repeat(2, minmax(0, 1fr)) auto; }
|
||
.global-context-actions:has(#cockpit-entry[hidden]):has(#tr3b-toggle:not([hidden])) { grid-template-columns: minmax(0, 1fr) auto; }
|
||
.tr3b-toggle {
|
||
width: 26px;
|
||
min-height: 30px;
|
||
padding: 0;
|
||
border: 1px solid rgba(98, 181, 255, 0.22);
|
||
border-radius: 5px;
|
||
background: rgba(42, 113, 171, 0.08);
|
||
/* The saucer is a COLOR-font glyph: `color` and `text-shadow` cannot touch
|
||
it, so the dim/lit states are carried by `filter` alongside the border and
|
||
fill. 14px sits inside the 26px chip with breathing room. */
|
||
font: 14px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
|
||
filter: grayscale(0.6) opacity(0.62);
|
||
cursor: pointer;
|
||
transition: filter 160ms ease, border-color 160ms ease, background 160ms ease;
|
||
}
|
||
.tr3b-toggle[hidden] { display: none; }
|
||
.tr3b-toggle:hover, .tr3b-toggle:focus-visible {
|
||
border-color: rgba(127, 200, 255, 0.6);
|
||
background: rgba(66, 148, 211, 0.18);
|
||
filter: grayscale(0.15) opacity(0.95);
|
||
outline: none;
|
||
}
|
||
.tr3b-toggle[aria-pressed="true"] {
|
||
border-color: rgba(190, 220, 255, 0.75);
|
||
background: rgba(20, 23, 28, 0.9);
|
||
/* Active: full-colour saucer with a soft halo. drop-shadow works on an emoji
|
||
where text-shadow does not, so the glyph itself telegraphs the state
|
||
rather than relying on the chrome alone. */
|
||
filter: drop-shadow(0 0 5px rgba(150, 210, 255, 0.9));
|
||
}
|
||
.global-context-modes {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 7px;
|
||
margin: 0 0 10px;
|
||
}
|
||
.context-mode-button {
|
||
display: flex;
|
||
min-width: 0;
|
||
min-height: 36px;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 6px;
|
||
padding: 7px 8px;
|
||
border: 1px solid rgba(98, 181, 255, .28);
|
||
border-radius: 6px;
|
||
color: #8fcfff;
|
||
background: rgba(42, 113, 171, .09);
|
||
font: 8px/1.15 var(--font-mono);
|
||
letter-spacing: .09em;
|
||
cursor: pointer;
|
||
transition: border-color .15s ease, color .15s ease, background .15s ease, box-shadow .15s ease;
|
||
}
|
||
.context-mode-button .material-symbols-outlined { font-size: 16px; }
|
||
.context-mode-button:hover,
|
||
.context-mode-button:focus-visible {
|
||
border-color: #79c2ff;
|
||
color: #fff;
|
||
outline: none;
|
||
}
|
||
.context-mode-button.active {
|
||
border-color: rgba(0, 212, 255, .75);
|
||
color: #eaffff;
|
||
background: rgba(0, 212, 255, .14);
|
||
box-shadow: inset 0 0 16px rgba(0, 212, 255, .08), 0 0 12px rgba(0, 212, 255, .12);
|
||
}
|
||
.context-mode-button:disabled { opacity: .55; cursor: wait; }
|
||
.context-mode-view[hidden],
|
||
.context-mode-standby[hidden] { display: none !important; }
|
||
.context-mode-standby {
|
||
display: grid;
|
||
min-height: 72px;
|
||
place-content: center;
|
||
gap: 6px;
|
||
padding: 12px;
|
||
border: 1px dashed rgba(98, 181, 255, .2);
|
||
border-radius: 7px;
|
||
color: rgba(190, 230, 230, .5);
|
||
text-align: center;
|
||
font: 8px/1.45 var(--font-mono);
|
||
letter-spacing: .1em;
|
||
}
|
||
.context-mode-standby strong {
|
||
color: #8fcfff;
|
||
font-size: 9px;
|
||
letter-spacing: .16em;
|
||
}
|
||
.context-mode-view { min-height: 0; }
|
||
#right-context-rail #global-context-panel:not(.collapsed) .context-mode-view,
|
||
#right-context-rail #global-context-panel:not(.collapsed) #radio-panel {
|
||
/* These sections share the Context panel's existing scroller. Keep their
|
||
natural heights so flexbox cannot compress one section and let its
|
||
contents paint through the next section. */
|
||
flex: 0 0 auto;
|
||
}
|
||
.panel-layer-toggle {
|
||
min-width: 54px;
|
||
padding: 4px 7px;
|
||
border: 1px solid rgba(98, 181, 255, 0.3);
|
||
border-radius: 5px;
|
||
color: #8fcfff;
|
||
background: rgba(42, 113, 171, 0.12);
|
||
font: 7px/1.1 var(--font-mono);
|
||
letter-spacing: 0.1em;
|
||
cursor: pointer;
|
||
}
|
||
.panel-layer-toggle:hover, .panel-layer-toggle:focus-visible {
|
||
border-color: #79c2ff;
|
||
color: #fff;
|
||
outline: none;
|
||
}
|
||
.panel-layer-toggle.active {
|
||
border-color: rgba(0, 212, 255, 0.7);
|
||
color: #fff;
|
||
background: rgba(0, 212, 255, 0.14);
|
||
box-shadow: 0 0 12px rgba(0, 212, 255, 0.14);
|
||
}
|
||
.panel-layer-toggle:disabled { opacity: 0.45; cursor: wait; }
|
||
.global-context-actions .panel-layer-toggle {
|
||
width: 100%;
|
||
min-height: 30px;
|
||
padding: 6px 8px;
|
||
font-size: 8px;
|
||
}
|
||
#global-context-panel #cockpit-entry {
|
||
position: static;
|
||
z-index: auto;
|
||
width: 100%;
|
||
min-height: 30px;
|
||
padding: 5px 8px;
|
||
border-radius: 5px;
|
||
justify-content: center;
|
||
font-size: 8px;
|
||
box-shadow: none;
|
||
}
|
||
#global-context-panel #cockpit-entry .material-symbols-outlined { font-size: 15px; }
|
||
#global-context-panel #cockpit-entry kbd { padding: 2px 4px; }
|
||
|
||
/* ── Radio companion section inside Context ── */
|
||
#radio-panel {
|
||
position: relative;
|
||
width: 100%;
|
||
min-height: 0;
|
||
margin-top: 10px;
|
||
padding-top: 10px;
|
||
border-top: 1px solid rgba(65, 220, 231, .16);
|
||
}
|
||
.radio-panel-inner {
|
||
position: relative;
|
||
display: flex;
|
||
min-height: 0;
|
||
flex-direction: column;
|
||
gap: 9px;
|
||
padding: 10px;
|
||
border: 1px solid rgba(65, 220, 231, .18);
|
||
border-radius: 8px;
|
||
background: rgba(2, 15, 20, .42);
|
||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .035);
|
||
scrollbar-width: thin;
|
||
scrollbar-color: rgba(0, 212, 255, .46) rgba(255, 255, 255, .06);
|
||
}
|
||
#radio-panel .panel-header { margin-bottom: 0; }
|
||
.radio-layer-state {
|
||
color: var(--text-dim);
|
||
font: 8px/1 var(--font-mono);
|
||
letter-spacing: .12em;
|
||
}
|
||
.radio-layer-state.active { color: #65f7ff; }
|
||
.radio-directory-row {
|
||
display: grid;
|
||
grid-template-columns: auto minmax(0, 1fr);
|
||
gap: 6px 8px;
|
||
align-items: end;
|
||
}
|
||
.radio-filter-label {
|
||
grid-column: 2;
|
||
color: var(--text-dim);
|
||
font: 7px/1 var(--font-mono);
|
||
letter-spacing: .12em;
|
||
}
|
||
#radio-enable-btn { grid-row: 1 / span 2; min-height: 36px; }
|
||
#radio-filter {
|
||
min-width: 0;
|
||
padding: 7px 24px 7px 8px;
|
||
border: 1px solid rgba(65, 220, 231, .28);
|
||
border-radius: 5px;
|
||
color: #c5faff;
|
||
background: rgba(5, 24, 31, .88);
|
||
font: 9px/1.2 var(--font-mono);
|
||
}
|
||
.radio-station-card {
|
||
display: grid;
|
||
gap: 4px;
|
||
padding: 10px;
|
||
border: 1px solid rgba(65, 220, 231, .18);
|
||
border-radius: 7px;
|
||
background: rgba(2, 15, 20, .48);
|
||
overflow-wrap: anywhere;
|
||
}
|
||
.radio-station-card strong {
|
||
color: #e8feff;
|
||
font: 11px/1.25 var(--font-mono);
|
||
letter-spacing: .05em;
|
||
}
|
||
.radio-station-card span {
|
||
color: var(--text-dim);
|
||
font: 8px/1.35 var(--font-mono);
|
||
}
|
||
#radio-station-tags { color: #72dce6; }
|
||
.radio-tuner {
|
||
display: grid;
|
||
width: 100%;
|
||
min-width: 0;
|
||
max-width: 100%;
|
||
gap: 5px;
|
||
padding: 8px;
|
||
overflow: hidden;
|
||
border: 1px solid rgba(65, 220, 231, .22);
|
||
border-radius: 7px;
|
||
background: linear-gradient(180deg, rgba(1, 9, 13, .92), rgba(4, 24, 30, .72));
|
||
box-shadow: inset 0 0 18px rgba(0, 212, 255, .045);
|
||
}
|
||
.radio-tuner[hidden] { display: none; }
|
||
.radio-tuner-header,
|
||
.radio-tuner-readout {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
gap: 8px;
|
||
color: #6daeb5;
|
||
font: 7px/1.2 var(--font-mono);
|
||
letter-spacing: .1em;
|
||
}
|
||
#radio-tuner-value {
|
||
min-width: 0;
|
||
color: #a8f7ff;
|
||
overflow: hidden;
|
||
text-align: right;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
.radio-tuner-dial {
|
||
position: relative;
|
||
width: 100%;
|
||
min-width: 0;
|
||
max-width: 100%;
|
||
height: 51px;
|
||
overflow: hidden;
|
||
contain: paint;
|
||
border-block: 1px solid rgba(72, 225, 237, .3);
|
||
background:
|
||
linear-gradient(180deg, transparent 23px, rgba(65, 220, 231, .8) 24px, transparent 25px, transparent 28px, rgba(65, 220, 231, .6) 29px, transparent 30px),
|
||
radial-gradient(ellipse at center, rgba(39, 177, 191, .12), transparent 70%);
|
||
}
|
||
.radio-tuner-scale {
|
||
position: absolute;
|
||
inset: 0;
|
||
overflow: hidden;
|
||
color: #58cbd6;
|
||
font: 9px/1 var(--font-mono);
|
||
text-shadow: 0 0 7px rgba(65, 220, 231, .5);
|
||
pointer-events: none;
|
||
}
|
||
.radio-tuner-tick {
|
||
position: absolute;
|
||
top: 6px;
|
||
bottom: 0;
|
||
min-width: 1px;
|
||
border-left: 1px solid rgba(85, 224, 235, .38);
|
||
color: #58cbd6;
|
||
padding-left: 3px;
|
||
white-space: nowrap;
|
||
transform: translateX(-50%);
|
||
transition: left 80ms linear;
|
||
}
|
||
.radio-tuner-tick.is-current {
|
||
border-left-color: rgba(168, 247, 255, .9);
|
||
color: #a8f7ff;
|
||
}
|
||
.radio-tuner-needle {
|
||
position: absolute;
|
||
z-index: 1;
|
||
top: 2px;
|
||
bottom: 2px;
|
||
left: calc(7px + (100% - 14px) * var(--radio-tuner-ratio, 0));
|
||
width: 3px;
|
||
border-radius: 1px;
|
||
background: #ff6f4f;
|
||
box-shadow: 0 0 4px #ff6f4f, 0 0 10px rgba(255, 77, 50, .65);
|
||
pointer-events: none;
|
||
transform: translateX(-50%);
|
||
transition: left .18s ease-out;
|
||
}
|
||
.radio-tuner.is-dragging .radio-tuner-needle,
|
||
.radio-tuner.is-dragging .radio-tuner-tick { transition: none; }
|
||
#radio-tuner-slider {
|
||
position: absolute;
|
||
z-index: 2;
|
||
inset: 0;
|
||
width: 100%;
|
||
min-width: 0;
|
||
max-width: 100%;
|
||
height: 100%;
|
||
margin: 0;
|
||
appearance: none;
|
||
-webkit-appearance: none;
|
||
cursor: ew-resize;
|
||
touch-action: none;
|
||
background: transparent;
|
||
}
|
||
#radio-tuner-slider::-webkit-slider-runnable-track {
|
||
height: 100%;
|
||
background: transparent;
|
||
}
|
||
#radio-tuner-slider::-webkit-slider-thumb {
|
||
width: 14px;
|
||
height: 47px;
|
||
margin-top: 2px;
|
||
border: 0;
|
||
border-radius: 1px;
|
||
appearance: none;
|
||
-webkit-appearance: none;
|
||
background: transparent;
|
||
box-shadow: none;
|
||
}
|
||
#radio-tuner-slider::-moz-range-track { height: 100%; background: transparent; }
|
||
#radio-tuner-slider::-moz-range-thumb {
|
||
width: 14px;
|
||
height: 47px;
|
||
border: 0;
|
||
border-radius: 1px;
|
||
background: transparent;
|
||
box-shadow: none;
|
||
}
|
||
.radio-tuner.is-static .radio-tuner-dial {
|
||
box-shadow: inset 0 0 14px rgba(255, 111, 79, .1);
|
||
}
|
||
.radio-tuner.is-static #radio-tuner-station { color: #ff9b7e; }
|
||
.radio-tuner-readout span:first-child {
|
||
min-width: 0;
|
||
color: #7fe6ef;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
.radio-tuner-readout span:last-child {
|
||
flex: 0 0 auto;
|
||
color: #517f84;
|
||
}
|
||
.radio-transport {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||
gap: 5px;
|
||
}
|
||
.radio-transport button {
|
||
min-height: 30px;
|
||
padding: 6px 3px;
|
||
border: 1px solid rgba(65, 220, 231, .28);
|
||
border-radius: 5px;
|
||
color: #8feaf2;
|
||
background: rgba(14, 69, 78, .14);
|
||
font: 8px/1 var(--font-mono);
|
||
letter-spacing: .06em;
|
||
cursor: pointer;
|
||
}
|
||
.radio-transport button:hover:not(:disabled),
|
||
.radio-transport button:focus-visible:not(:disabled) {
|
||
border-color: #65f7ff;
|
||
color: #fff;
|
||
outline: none;
|
||
}
|
||
.radio-transport button:disabled,
|
||
#radio-filter:disabled { opacity: .42; cursor: not-allowed; }
|
||
#radio-play-btn.active {
|
||
color: #fff;
|
||
border-color: rgba(101, 247, 255, .8);
|
||
background: rgba(65, 220, 231, .18);
|
||
box-shadow: 0 0 12px rgba(65, 220, 231, .12);
|
||
}
|
||
.radio-volume-row {
|
||
display: grid;
|
||
grid-template-columns: auto minmax(0, 1fr) 32px;
|
||
gap: 8px;
|
||
align-items: center;
|
||
color: var(--text-dim);
|
||
font: 7px/1 var(--font-mono);
|
||
letter-spacing: .1em;
|
||
}
|
||
.radio-volume-row input { width: 100%; }
|
||
.radio-playback-state {
|
||
min-height: 12px;
|
||
color: #79d7df;
|
||
font: 8px/1.35 var(--font-mono);
|
||
}
|
||
.radio-playback-state.error { color: #ff9d8f; }
|
||
.radio-links {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
justify-content: space-between;
|
||
gap: 5px 10px;
|
||
}
|
||
.radio-links a {
|
||
color: #64cbd5;
|
||
font: 7px/1.3 var(--font-mono);
|
||
letter-spacing: .06em;
|
||
text-decoration: none;
|
||
}
|
||
.radio-links a:hover, .radio-links a:focus-visible { color: #fff; }
|
||
.radio-privacy {
|
||
margin: 0;
|
||
color: rgba(190, 230, 230, .48);
|
||
font: 7px/1.4 var(--font-mono);
|
||
}
|
||
#military-awareness-panel {
|
||
width: 100%;
|
||
min-height: 0;
|
||
overflow: auto;
|
||
box-sizing: border-box;
|
||
padding: 2px 1px 0;
|
||
color: #dceeff;
|
||
background: transparent;
|
||
border: 0;
|
||
font: 11px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace;
|
||
}
|
||
|
||
#military-awareness-panel[hidden] { display: none; }
|
||
.military-awareness-subject { margin: 0 0 7px; color: #fff; }
|
||
.military-awareness-controls { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 5px; margin: 0 0 8px; }
|
||
.military-awareness-controls button { border: 1px solid rgba(98,181,255,0.34); border-radius: 4px; padding: 4px 3px; color: #a9d9ff; background: rgba(42,113,171,0.12); font: 9px/1.2 ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: 0.07em; cursor: pointer; }
|
||
.military-awareness-controls button:hover, .military-awareness-controls button:focus-visible { color: #fff; border-color: rgba(127,200,255,0.85); background: rgba(66,148,211,0.24); outline: none; }
|
||
.military-awareness-controls button:disabled { color: #627181; border-color: rgba(98,181,255,0.12); background: transparent; cursor: default; }
|
||
.military-awareness-row { border-top: 1px solid rgba(255,255,255,0.1); padding: 7px 0; }
|
||
.military-awareness-row > div { display: flex; justify-content: space-between; }
|
||
.military-awareness-row b { color: #7fc8ff; }
|
||
.military-awareness-row.unknown b { color: #8fcfff; }
|
||
.military-awareness-row small, .military-awareness-note { color: #a9b7c7; }
|
||
.military-awareness-row ul { margin: 4px 0 0; padding: 0; list-style: none; }
|
||
.military-awareness-row li { display: block; }
|
||
.military-awareness-target { display: flex; justify-content: space-between; gap: 10px; width: 100%; border: 0; padding: 1px 0; color: #dceeff; background: transparent; font: inherit; text-align: left; cursor: pointer; }
|
||
.military-awareness-target.unavailable { color: var(--text-dim); cursor: default; }
|
||
.military-awareness-target:hover, .military-awareness-target:focus-visible { color: #fff; outline: none; text-shadow: 0 0 8px rgba(114, 202, 255, 0.85); }
|
||
.military-awareness-target:focus-visible { box-shadow: inset 0 -1px 0 #7fc8ff; }
|
||
.military-awareness-target span { color: #7fc8ff; white-space: nowrap; }
|
||
.military-awareness-note { margin: 8px 0 0; font-size: 10px; }
|
||
.military-awareness-standby {
|
||
display: grid;
|
||
gap: 7px;
|
||
padding: 12px 4px 4px;
|
||
border-top: 1px solid rgba(98, 181, 255, 0.16);
|
||
}
|
||
.military-awareness-standby strong { color: #79c2ff; font-size: 10px; letter-spacing: 0.1em; }
|
||
.military-awareness-standby span { color: #8192a6; font-size: 9px; letter-spacing: 0.05em; }
|
||
.military-awareness-standby button {
|
||
justify-self: start;
|
||
padding: 4px 12px;
|
||
border: 1px solid rgba(98, 181, 255, 0.34);
|
||
border-radius: 4px;
|
||
color: #a9d9ff;
|
||
background: rgba(42, 113, 171, 0.12);
|
||
font: 9px/1.2 ui-monospace, SFMono-Regular, Menlo, monospace;
|
||
letter-spacing: 0.08em;
|
||
cursor: pointer;
|
||
}
|
||
|
||
#military-awareness-direction-overlay { position: absolute; inset: 0; z-index: 4; overflow: hidden; pointer-events: none; }
|
||
#military-awareness-direction-overlay[hidden] { display: none; }
|
||
.military-awareness-compass-ring {
|
||
--compass-rotation: 0deg;
|
||
position: absolute;
|
||
box-sizing: border-box;
|
||
border: 1px solid rgba(111,196,255,0.2);
|
||
outline: 1px dashed rgba(111,196,255,0.28);
|
||
outline-offset: -5px;
|
||
border-radius: 50%;
|
||
box-shadow:
|
||
inset 0 0 0 5px rgba(34,128,196,0.018),
|
||
inset 0 0 24px rgba(34,128,196,0.035),
|
||
0 0 14px rgba(34,128,196,0.05);
|
||
}
|
||
.military-awareness-compass-ring::before { content: ''; position: absolute; left: 50%; top: -7px; width: 0; height: 0; border-left: 5px solid transparent; border-right: 5px solid transparent; border-bottom: 8px solid rgba(127,200,255,0.88); transform: translateX(-50%); filter: drop-shadow(0 0 5px rgba(87,184,255,0.7)); }
|
||
.military-awareness-compass-ring::after {
|
||
content: '';
|
||
position: absolute;
|
||
inset: -5px;
|
||
border-radius: 50%;
|
||
background: repeating-conic-gradient(
|
||
from 0deg,
|
||
rgba(125, 205, 255, 0.38) 0deg 0.7deg,
|
||
transparent 0.7deg 15deg
|
||
);
|
||
-webkit-mask: radial-gradient(circle, transparent calc(100% - 8px), #000 calc(100% - 8px) calc(100% - 4px), transparent calc(100% - 4px));
|
||
mask: radial-gradient(circle, transparent calc(100% - 8px), #000 calc(100% - 8px) calc(100% - 4px), transparent calc(100% - 4px));
|
||
transform: rotate(var(--compass-rotation));
|
||
transition: transform 80ms linear;
|
||
}
|
||
.military-awareness-compass-label, .military-awareness-compass-heading { position: absolute; transform: translate(-50%, -50%); color: rgba(156,213,255,0.7); font: 9px/1 ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: 0.08em; text-shadow: 0 0 7px rgba(53,161,235,0.55); }
|
||
.military-awareness-compass-label.cardinal-n { color: rgba(255,188,87,0.92); }
|
||
.military-awareness-compass-heading { color: rgba(190,225,249,0.76); font-size: 8px; }
|
||
.military-awareness-direction-marker { position: absolute; width: 1px; height: 1px; transform: translate(-50%, -50%); transition: opacity 100ms linear; }
|
||
.military-awareness-direction-marker[hidden] { display: none; }
|
||
.military-awareness-direction-arrow { position: absolute; left: 50%; top: 50%; color: #74dbff; font: 23px/1 sans-serif; transform-origin: 50% 50%; text-shadow: 0 0 5px rgba(87,223,255,0.9), 0 0 13px rgba(87,223,255,0.35); }
|
||
.military-awareness-direction-label { position: absolute; left: 50%; top: 50%; padding: 3px 6px; border: 1px solid rgba(116,219,255,0.24); border-radius: 3px; color: #bceeff; background: rgba(5,12,20,0.68); font: 8px/1.3 ui-monospace, SFMono-Regular, Menlo, monospace; text-align: center; white-space: pre; text-shadow: 0 0 5px rgba(116,219,255,0.38); }
|
||
|
||
.data-toggle-row.gev-voice-focus {
|
||
background: rgba(92, 255, 198, 0.1);
|
||
box-shadow: inset 0 0 0 1px rgba(92, 255, 198, 0.72), 0 0 18px rgba(92, 255, 198, 0.18);
|
||
}
|
||
|
||
.data-toggle-top {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 8px;
|
||
}
|
||
|
||
.data-toggle-left {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.data-icon {
|
||
font-size: 16px;
|
||
line-height: 1;
|
||
}
|
||
|
||
.data-name {
|
||
font-family: var(--font-sans);
|
||
font-size: 13px;
|
||
font-weight: 500;
|
||
color: var(--text-primary);
|
||
letter-spacing: 0.3px;
|
||
}
|
||
|
||
.data-toggle-right {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
|
||
.data-count {
|
||
font-family: var(--font-mono);
|
||
font-size: 11px;
|
||
letter-spacing: 0.5px;
|
||
color: var(--text-secondary);
|
||
min-width: 30px;
|
||
text-align: right;
|
||
}
|
||
|
||
.data-toggle-btn {
|
||
padding: 3px 10px;
|
||
font-family: var(--font-mono);
|
||
font-size: 9px;
|
||
letter-spacing: 1.5px;
|
||
color: var(--text-dim);
|
||
background: rgba(255, 255, 255, 0.04);
|
||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
transition: all var(--transition-fast);
|
||
outline: none;
|
||
min-width: 38px;
|
||
text-align: center;
|
||
}
|
||
|
||
.data-toggle-btn.feed-loading,
|
||
.data-toggle-btn.feed-degraded,
|
||
.data-toggle-btn.feed-stale,
|
||
.data-toggle-btn.feed-fallback,
|
||
.data-toggle-btn.feed-unavailable {
|
||
min-width: 82px;
|
||
letter-spacing: 0.8px;
|
||
}
|
||
|
||
.data-toggle-btn:hover {
|
||
border-color: var(--glass-border-hover);
|
||
background: rgba(255, 255, 255, 0.06);
|
||
}
|
||
|
||
.data-toggle-btn.active {
|
||
color: var(--accent);
|
||
border-color: var(--accent);
|
||
background: var(--accent-dim);
|
||
box-shadow: 0 0 10px rgba(0, 212, 255, 0.15);
|
||
}
|
||
|
||
.data-toggle-btn.active.feed-stale,
|
||
.data-toggle-btn.active.feed-fallback {
|
||
color: #ffd27a;
|
||
border-color: rgba(255, 190, 82, 0.75);
|
||
background: rgba(255, 174, 51, 0.1);
|
||
box-shadow: 0 0 10px rgba(255, 174, 51, 0.12);
|
||
}
|
||
|
||
.data-toggle-btn.active.feed-degraded {
|
||
color: #ffad72;
|
||
border-color: rgba(255, 137, 72, 0.78);
|
||
background: rgba(255, 112, 48, 0.1);
|
||
box-shadow: 0 0 10px rgba(255, 112, 48, 0.12);
|
||
}
|
||
|
||
.data-toggle-btn.active.feed-unavailable {
|
||
color: #ff8585;
|
||
border-color: rgba(255, 92, 92, 0.78);
|
||
background: rgba(255, 60, 60, 0.1);
|
||
box-shadow: 0 0 10px rgba(255, 60, 60, 0.12);
|
||
}
|
||
|
||
.data-toggle-meta {
|
||
font-family: var(--font-mono);
|
||
font-size: 9px;
|
||
letter-spacing: 0.5px;
|
||
color: var(--text-dim);
|
||
padding-left: 26px;
|
||
margin-top: 2px;
|
||
}
|
||
|
||
/* Optional per-layer sub-controls: mode chips plus a color legend. Aligned
|
||
under the layer name like .data-toggle-meta, and wrapping so a legend can
|
||
grow without widening the rail. */
|
||
.data-toggle-controls {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
align-items: center;
|
||
gap: 4px 8px;
|
||
padding-left: 26px;
|
||
margin-top: 5px;
|
||
}
|
||
|
||
.data-toggle-controls[hidden] {
|
||
display: none;
|
||
}
|
||
|
||
.data-toggle-chip {
|
||
padding: 2px 7px;
|
||
font-family: var(--font-mono);
|
||
font-size: 8px;
|
||
letter-spacing: 1.2px;
|
||
color: var(--text-dim);
|
||
background: rgba(255, 255, 255, 0.04);
|
||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||
border-radius: 3px;
|
||
cursor: pointer;
|
||
transition: all var(--transition-fast);
|
||
outline: none;
|
||
}
|
||
|
||
.data-toggle-chip:hover,
|
||
.data-toggle-chip:focus-visible {
|
||
border-color: var(--glass-border-hover);
|
||
background: rgba(255, 255, 255, 0.06);
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
.data-toggle-chip.active {
|
||
color: var(--accent);
|
||
border-color: var(--accent);
|
||
background: var(--accent-dim);
|
||
}
|
||
|
||
/* Async sub-controls: a chip must never read ACTIVE before the data it turns
|
||
on actually exists, so loading and failure are their own visible states. */
|
||
.data-toggle-chip:disabled {
|
||
cursor: wait;
|
||
opacity: 0.7;
|
||
}
|
||
|
||
.data-toggle-chip.chip-loading {
|
||
color: var(--text-secondary);
|
||
border-color: rgba(255, 255, 255, 0.18);
|
||
}
|
||
|
||
.data-toggle-chip.chip-error {
|
||
color: #ff8585;
|
||
border-color: rgba(255, 92, 92, 0.6);
|
||
background: rgba(255, 60, 60, 0.08);
|
||
}
|
||
|
||
.data-toggle-legend-item {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
font-family: var(--font-mono);
|
||
font-size: 8px;
|
||
letter-spacing: 0.5px;
|
||
color: var(--text-dim);
|
||
cursor: default;
|
||
}
|
||
|
||
.data-toggle-legend-swatch {
|
||
width: 6px;
|
||
height: 6px;
|
||
border-radius: 50%;
|
||
/* The swatch IS the datum — keep it exactly the point color, with only a
|
||
hairline ring so a near-black class still reads on the panel glass. */
|
||
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.18);
|
||
flex: none;
|
||
}
|
||
|
||
/* ── CCTV Panel ─────────────────────────────── */
|
||
#cctv-panel {
|
||
--panel-expanded-width: 360px;
|
||
position: fixed;
|
||
top: var(--left-stack-top);
|
||
left: var(--left-stack-x);
|
||
right: auto;
|
||
bottom: auto;
|
||
z-index: 100;
|
||
width: var(--panel-expanded-width);
|
||
max-height: calc(100vh - 24px);
|
||
}
|
||
|
||
#cctv-panel .panel-glow {
|
||
position: absolute;
|
||
inset: -18px;
|
||
background: radial-gradient(ellipse at center, rgba(0, 212, 255, 0.16) 0%, transparent 65%);
|
||
filter: blur(16px);
|
||
opacity: 0.25;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.cctv-panel-inner {
|
||
position: relative;
|
||
background: var(--glass-bg);
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: var(--panel-radius);
|
||
padding: 14px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
max-height: calc(100vh - 24px);
|
||
overflow-y: auto;
|
||
scrollbar-width: thin;
|
||
scrollbar-color: rgba(0, 212, 255, 0.46) rgba(255, 255, 255, 0.06);
|
||
backdrop-filter: blur(24px) saturate(1.4);
|
||
-webkit-backdrop-filter: blur(24px) saturate(1.4);
|
||
box-shadow:
|
||
0 8px 32px rgba(0, 0, 0, 0.5),
|
||
0 0 0 1px rgba(255, 255, 255, 0.03) inset,
|
||
0 1px 0 rgba(255, 255, 255, 0.06) inset;
|
||
}
|
||
|
||
.cctv-panel-inner::-webkit-scrollbar {
|
||
width: 8px;
|
||
}
|
||
|
||
.cctv-panel-inner::-webkit-scrollbar-track {
|
||
background: rgba(255, 255, 255, 0.04);
|
||
border-radius: 999px;
|
||
}
|
||
|
||
.cctv-panel-inner::-webkit-scrollbar-thumb {
|
||
background: linear-gradient(180deg, rgba(0, 212, 255, 0.6), rgba(0, 212, 255, 0.28));
|
||
border: 1px solid rgba(0, 212, 255, 0.4);
|
||
border-radius: 999px;
|
||
}
|
||
|
||
.cctv-controls {
|
||
display: flex;
|
||
gap: 8px;
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.cctv-calibration-block {
|
||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||
border-radius: 9px;
|
||
padding: 8px 9px;
|
||
background: rgba(255, 255, 255, 0.02);
|
||
}
|
||
|
||
.cctv-calibration-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 8px;
|
||
margin-bottom: 7px;
|
||
}
|
||
|
||
.cctv-calibration-header .cctv-summary-label {
|
||
margin: 0;
|
||
}
|
||
|
||
/* Click-to-edit effective-pose readout (viewshed/gizmo design §3d): compact
|
||
value chips replace the seven offset sliders. */
|
||
.cctv-cal-readout {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 5px;
|
||
}
|
||
|
||
.cctv-cal-value {
|
||
font-family: var(--font-mono);
|
||
font-size: 9px;
|
||
letter-spacing: 0.7px;
|
||
color: #91edff;
|
||
background: rgba(255, 255, 255, 0.04);
|
||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||
border-radius: 7px;
|
||
padding: 4px 7px;
|
||
cursor: text;
|
||
transition: border-color 0.15s ease, background 0.15s ease;
|
||
}
|
||
|
||
.cctv-cal-value:hover:not(:disabled) {
|
||
border-color: rgba(0, 212, 255, 0.45);
|
||
background: rgba(0, 212, 255, 0.08);
|
||
}
|
||
|
||
.cctv-cal-input {
|
||
width: 58px;
|
||
font-family: var(--font-mono);
|
||
font-size: 9px;
|
||
letter-spacing: 0.7px;
|
||
color: var(--text-primary);
|
||
background: rgba(0, 212, 255, 0.1);
|
||
border: 1px solid rgba(0, 212, 255, 0.5);
|
||
border-radius: 4px;
|
||
padding: 1px 3px;
|
||
outline: none;
|
||
-moz-appearance: textfield;
|
||
}
|
||
|
||
.cctv-cal-input::-webkit-outer-spin-button,
|
||
.cctv-cal-input::-webkit-inner-spin-button {
|
||
-webkit-appearance: none;
|
||
margin: 0;
|
||
}
|
||
|
||
.cctv-calibration-actions {
|
||
margin-top: 8px;
|
||
}
|
||
|
||
#cctv-panel input:disabled,
|
||
#cctv-panel button:disabled,
|
||
#cctv-panel select:disabled {
|
||
opacity: 0.45;
|
||
}
|
||
|
||
#cctv-camera-select {
|
||
flex: 1;
|
||
min-width: 0;
|
||
background: rgba(255, 255, 255, 0.06);
|
||
border: 1px solid rgba(255, 255, 255, 0.14);
|
||
border-radius: 7px;
|
||
color: var(--text-primary);
|
||
padding: 6px 8px;
|
||
font-family: var(--font-sans);
|
||
font-size: 12px;
|
||
outline: none;
|
||
}
|
||
|
||
#cctv-camera-select:disabled {
|
||
opacity: 0.45;
|
||
}
|
||
|
||
#cctv-enable-btn.active,
|
||
#cctv-coverage-btn.active,
|
||
#cctv-auto-hop-btn.active,
|
||
#cctv-projection-btn.active {
|
||
color: var(--accent);
|
||
border-color: var(--accent);
|
||
background: rgba(0, 212, 255, 0.14);
|
||
}
|
||
|
||
#cctv-quality-chip {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
min-width: 90px;
|
||
padding: 6px 8px;
|
||
border: 1px solid rgba(0, 212, 255, 0.2);
|
||
border-radius: 8px;
|
||
font-family: var(--font-mono);
|
||
font-size: 9px;
|
||
letter-spacing: 1px;
|
||
color: #8fe7ff;
|
||
background: rgba(0, 212, 255, 0.08);
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
/* CAL badge states (cctv-v2 §3b, amended by LOCKED §9.2 — panel-only, no
|
||
in-world tint). Three visually distinct states: calibrated / curated /
|
||
raw-prior. */
|
||
#cctv-quality-chip[data-cal-badge='calibrated'] {
|
||
color: #adffbf;
|
||
border-color: rgba(141, 255, 135, 0.42);
|
||
background: rgba(141, 255, 135, 0.12);
|
||
}
|
||
|
||
#cctv-quality-chip[data-cal-badge='curated'] {
|
||
color: #ffe6a2;
|
||
border-color: rgba(255, 217, 122, 0.35);
|
||
background: rgba(255, 217, 122, 0.1);
|
||
}
|
||
|
||
/* Unsaved live edits (save-gated persistence, viewshed design §3e). */
|
||
#cctv-quality-chip[data-cal-badge='edited'] {
|
||
color: #ffd08a;
|
||
border-color: rgba(255, 176, 82, 0.5);
|
||
background: rgba(255, 176, 82, 0.14);
|
||
}
|
||
|
||
.cctv-frame-wrap {
|
||
position: relative;
|
||
border-radius: 10px;
|
||
overflow: hidden;
|
||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||
background:
|
||
radial-gradient(circle at 20% 20%, rgba(0, 244, 255, 0.09), transparent 44%),
|
||
linear-gradient(180deg, rgba(8, 14, 19, 0.88), rgba(4, 7, 11, 0.96));
|
||
min-height: 150px;
|
||
/* .cctv-panel-inner is a scrolling column flex container, so the default
|
||
flex-shrink:1 squeezed this wrap down to its 150px floor while the 16:9
|
||
image inside is taller — and the wrap is overflow:hidden, which clipped
|
||
the bottom of the frame right back off. Never shrink the preview. */
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
/* Lightweight loading shimmer while the active frame is fetching */
|
||
.cctv-frame-wrap::after {
|
||
content: '';
|
||
position: absolute;
|
||
inset: 0;
|
||
background: linear-gradient(
|
||
100deg,
|
||
transparent 24%,
|
||
rgba(0, 212, 255, 0.08) 44%,
|
||
rgba(170, 244, 255, 0.14) 50%,
|
||
rgba(0, 212, 255, 0.08) 56%,
|
||
transparent 76%
|
||
);
|
||
transform: translateX(-100%);
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
transition: opacity 0.2s ease;
|
||
}
|
||
|
||
.cctv-frame-wrap.loading::after {
|
||
opacity: 1;
|
||
animation: cctv-frame-shimmer 1.4s linear infinite;
|
||
}
|
||
|
||
/* "Acquiring" caption only when no previous frame is showing underneath */
|
||
.cctv-frame-wrap.loading:not(.has-frame)::before {
|
||
content: 'ACQUIRING FRAME';
|
||
position: absolute;
|
||
inset: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-family: var(--font-mono);
|
||
font-size: 8px;
|
||
letter-spacing: 2.2px;
|
||
color: rgba(145, 237, 255, 0.62);
|
||
pointer-events: none;
|
||
}
|
||
|
||
@keyframes cctv-frame-shimmer {
|
||
to {
|
||
transform: translateX(100%);
|
||
}
|
||
}
|
||
|
||
#cctv-frame {
|
||
width: 100%;
|
||
/* A fixed 16:9 box with the frame CONTAINED inside it. Providers burn their
|
||
timestamp into a corner (TfL top-left, Austin bottom-left) and the old
|
||
150px-tall box was ~2.2:1, so object-fit: cover ate ~18px off the top and
|
||
bottom — exactly where those stamps live (field test 2026-07-31).
|
||
Sources are not all 16:9 either (a TfL frame measures 352x288), so
|
||
`contain` is what actually guarantees nothing is cut; the ratio just keeps
|
||
the panel height stable as you switch cameras. */
|
||
aspect-ratio: 16 / 9;
|
||
height: auto;
|
||
object-fit: contain;
|
||
display: block;
|
||
opacity: 0;
|
||
transition: opacity 180ms ease;
|
||
}
|
||
|
||
#cctv-frame.active {
|
||
opacity: 1;
|
||
}
|
||
|
||
#cctv-meta {
|
||
font-family: var(--font-mono);
|
||
font-size: 9px;
|
||
letter-spacing: 1px;
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
#cctv-source-badge {
|
||
align-self: flex-start;
|
||
border: 1px solid rgba(0, 212, 255, 0.32);
|
||
border-radius: 999px;
|
||
background: rgba(0, 212, 255, 0.09);
|
||
color: #9defff;
|
||
font-family: var(--font-mono);
|
||
font-size: 8px;
|
||
letter-spacing: 1.3px;
|
||
padding: 4px 8px;
|
||
}
|
||
|
||
#cctv-source-badge[data-frame-state='loading'] {
|
||
color: #ffe59b;
|
||
border-color: rgba(255, 205, 92, 0.45);
|
||
background: rgba(255, 205, 92, 0.1);
|
||
}
|
||
|
||
#cctv-source-badge[data-frame-state='error'] {
|
||
color: #ffb0b0;
|
||
border-color: rgba(255, 102, 102, 0.5);
|
||
background: rgba(255, 72, 72, 0.11);
|
||
}
|
||
|
||
.cctv-summary-label {
|
||
font-family: var(--font-mono);
|
||
font-size: 8px;
|
||
letter-spacing: 1.7px;
|
||
color: var(--text-dim);
|
||
}
|
||
|
||
#cctv-summary {
|
||
min-height: 38px;
|
||
font-family: var(--font-mono);
|
||
font-size: 10px;
|
||
letter-spacing: 0.8px;
|
||
line-height: 1.45;
|
||
color: #a8f7ff;
|
||
text-shadow: 0 0 10px rgba(0, 212, 255, 0.18);
|
||
}
|
||
|
||
/* ── Scene Director Panel ───────────────────── */
|
||
#scene-panel {
|
||
--panel-expanded-width: 360px;
|
||
position: fixed;
|
||
top: calc(var(--left-stack-top) + (var(--left-stack-gap) * 2));
|
||
left: var(--left-stack-x);
|
||
right: auto;
|
||
bottom: auto;
|
||
z-index: 100;
|
||
width: var(--panel-expanded-width);
|
||
max-height: calc(100vh - 24px);
|
||
}
|
||
|
||
#left-panel-stack > #data-panel,
|
||
#left-panel-stack > #cctv-panel,
|
||
#left-panel-stack > #global-context-panel,
|
||
#left-panel-stack > #scene-panel {
|
||
position: relative;
|
||
top: auto;
|
||
right: auto;
|
||
bottom: auto;
|
||
left: auto;
|
||
z-index: auto;
|
||
max-height: none;
|
||
flex: 0 0 auto;
|
||
min-height: 0;
|
||
pointer-events: auto;
|
||
}
|
||
|
||
#left-panel-stack > #data-panel {
|
||
order: 1;
|
||
}
|
||
|
||
#left-panel-stack > #cctv-panel {
|
||
order: 2;
|
||
}
|
||
|
||
#left-panel-stack > #scene-panel { order: 4; }
|
||
|
||
/*
|
||
* Runtime focus mode: the layout engine applies this only when the expanded
|
||
* panel's measured natural height plus sibling labels cannot fit inside the
|
||
* live HUD/attribution-safe corridor.
|
||
*/
|
||
#left-panel-stack.layout-focus > [data-panel-id].collapsed {
|
||
display: none;
|
||
}
|
||
|
||
#left-panel-stack > #data-panel:not(.collapsed),
|
||
#left-panel-stack > #cctv-panel:not(.collapsed),
|
||
#left-panel-stack > #scene-panel:not(.collapsed) {
|
||
box-sizing: border-box;
|
||
flex: 0 1 var(--left-panel-allocated-height, auto);
|
||
height: var(--left-panel-allocated-height, auto);
|
||
max-height: var(--left-panel-allocated-height, 100%);
|
||
}
|
||
|
||
/*
|
||
* When an expanded panel and its collapsed siblings fit together, preserve
|
||
* the canonical control order and center their combined stack at 50vh.
|
||
*/
|
||
#left-panel-stack.layout-tail > :is(#data-panel, #cctv-panel, #scene-panel):not(.collapsed) {
|
||
box-sizing: border-box;
|
||
flex: 0 0 var(--left-panel-allocated-height);
|
||
height: var(--left-panel-allocated-height);
|
||
max-height: var(--left-panel-allocated-height);
|
||
}
|
||
|
||
#left-panel-stack > #data-panel:not(.collapsed) .data-panel-inner,
|
||
#left-panel-stack > #cctv-panel:not(.collapsed) .cctv-panel-inner,
|
||
#left-panel-stack > #scene-panel:not(.collapsed) .scene-panel-inner {
|
||
height: 100%;
|
||
max-height: 100%;
|
||
}
|
||
|
||
#left-panel-stack > #data-panel:not(.collapsed) .data-panel-inner {
|
||
overflow: hidden;
|
||
}
|
||
|
||
#left-panel-stack > #cctv-panel:not(.collapsed) .cctv-panel-inner,
|
||
#left-panel-stack > #scene-panel:not(.collapsed) .scene-panel-inner {
|
||
overflow-y: auto;
|
||
scrollbar-gutter: stable;
|
||
}
|
||
|
||
#left-panel-stack > [data-panel-id]:not(.collapsed) .panel-header {
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 2;
|
||
background: transparent;
|
||
}
|
||
|
||
#left-panel-stack > [data-panel-id]:not(.collapsed) .panel-divider {
|
||
background: linear-gradient(90deg, rgb(0 212 255 / 28%), rgba(0, 212, 255, 0.18) 58%, transparent);
|
||
box-shadow: 0 0 7px rgba(0, 212, 255, 0.22);
|
||
}
|
||
|
||
#right-context-rail [data-panel-id]:not(.collapsed) .panel-divider {
|
||
background: linear-gradient(90deg, rgb(0 212 255 / 28%), rgba(0, 212, 255, 0.18) 58%, transparent);
|
||
box-shadow: 0 0 7px rgba(0, 212, 255, 0.22);
|
||
}
|
||
|
||
#scene-panel .panel-glow {
|
||
position: absolute;
|
||
inset: -18px;
|
||
background: radial-gradient(ellipse at center, rgba(0, 212, 255, 0.16) 0%, transparent 65%);
|
||
filter: blur(16px);
|
||
opacity: 0.25;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.scene-panel-inner {
|
||
position: relative;
|
||
background: var(--glass-bg);
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: var(--panel-radius);
|
||
padding: 14px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
max-height: calc(100vh - 24px);
|
||
backdrop-filter: blur(24px) saturate(1.4);
|
||
-webkit-backdrop-filter: blur(24px) saturate(1.4);
|
||
box-shadow:
|
||
0 8px 32px rgba(0, 0, 0, 0.5),
|
||
0 0 0 1px rgba(255, 255, 255, 0.03) inset,
|
||
0 1px 0 rgba(255, 255, 255, 0.06) inset;
|
||
}
|
||
|
||
.scene-controls {
|
||
display: flex;
|
||
gap: 8px;
|
||
margin-bottom: 8px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
#scene-select {
|
||
flex: 1;
|
||
min-width: 0;
|
||
background: rgba(255, 255, 255, 0.06);
|
||
border: 1px solid rgba(255, 255, 255, 0.14);
|
||
border-radius: 7px;
|
||
color: var(--text-primary);
|
||
padding: 6px 8px;
|
||
font-family: var(--font-sans);
|
||
font-size: 12px;
|
||
outline: none;
|
||
}
|
||
|
||
.scene-btn {
|
||
background: rgba(255, 255, 255, 0.05);
|
||
border: 1px solid rgba(255, 255, 255, 0.14);
|
||
border-radius: 7px;
|
||
color: var(--text-secondary);
|
||
font-family: var(--font-mono);
|
||
font-size: 9px;
|
||
letter-spacing: 1.2px;
|
||
padding: 6px 9px;
|
||
cursor: pointer;
|
||
transition: all var(--transition-fast);
|
||
white-space: nowrap;
|
||
flex: 1;
|
||
min-width: 72px;
|
||
}
|
||
|
||
#scene-start-btn,
|
||
#scene-stop-btn,
|
||
#scene-next-btn {
|
||
flex: 1 1 0;
|
||
}
|
||
|
||
.scene-shot-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 6px;
|
||
max-height: 160px;
|
||
min-height: 96px;
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
padding: 4px 2px 6px;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.scene-shot-list::-webkit-scrollbar {
|
||
width: 6px;
|
||
}
|
||
|
||
.scene-shot-list::-webkit-scrollbar-thumb {
|
||
background: rgba(255, 255, 255, 0.16);
|
||
border-radius: 999px;
|
||
}
|
||
|
||
.scene-shot-empty {
|
||
border: 1px dashed rgba(255, 255, 255, 0.14);
|
||
border-radius: 8px;
|
||
padding: 10px 8px;
|
||
text-align: center;
|
||
font-family: var(--font-mono);
|
||
font-size: 9px;
|
||
letter-spacing: 1px;
|
||
color: var(--text-dim);
|
||
}
|
||
|
||
.scene-shot-row {
|
||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||
border-radius: 9px;
|
||
padding: 7px 8px;
|
||
background: rgba(255, 255, 255, 0.03);
|
||
transition: border-color var(--transition-fast), background var(--transition-fast);
|
||
}
|
||
|
||
.scene-shot-row.active {
|
||
border-color: var(--accent);
|
||
background: rgba(0, 212, 255, 0.08);
|
||
}
|
||
|
||
.scene-shot-top {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 8px;
|
||
}
|
||
|
||
.scene-shot-label {
|
||
font-family: var(--font-mono);
|
||
font-size: 10px;
|
||
letter-spacing: 1px;
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.scene-shot-meta {
|
||
margin-top: 4px;
|
||
font-family: var(--font-mono);
|
||
font-size: 8px;
|
||
letter-spacing: 0.8px;
|
||
color: var(--text-dim);
|
||
}
|
||
|
||
.scene-shot-actions {
|
||
display: flex;
|
||
gap: 6px;
|
||
}
|
||
|
||
.scene-shot-btn {
|
||
border: 1px solid rgba(255, 255, 255, 0.14);
|
||
border-radius: 6px;
|
||
background: rgba(255, 255, 255, 0.05);
|
||
color: var(--text-secondary);
|
||
font-family: var(--font-mono);
|
||
font-size: 8px;
|
||
letter-spacing: 0.8px;
|
||
padding: 4px 6px;
|
||
cursor: pointer;
|
||
transition: all var(--transition-fast);
|
||
}
|
||
|
||
.scene-shot-btn:hover {
|
||
color: var(--text-primary);
|
||
border-color: var(--glass-border-hover);
|
||
}
|
||
|
||
.scene-shot-btn.scene-shot-danger:hover {
|
||
color: #ff7e7e;
|
||
border-color: #ff7e7e;
|
||
}
|
||
|
||
.scene-btn:hover:not(:disabled) {
|
||
color: var(--accent);
|
||
border-color: var(--accent);
|
||
background: rgba(0, 212, 255, 0.14);
|
||
}
|
||
|
||
.scene-btn:disabled {
|
||
opacity: 0.45;
|
||
cursor: default;
|
||
}
|
||
|
||
.scene-btn-danger:hover:not(:disabled) {
|
||
color: #ff7272;
|
||
border-color: #ff7272;
|
||
background: rgba(255, 88, 88, 0.15);
|
||
}
|
||
|
||
.scene-progress {
|
||
margin-top: 8px;
|
||
width: 100%;
|
||
height: 18px;
|
||
border-radius: 999px;
|
||
background: rgba(255, 255, 255, 0.06);
|
||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||
overflow: hidden;
|
||
}
|
||
|
||
#scene-progress-fill {
|
||
width: 0%;
|
||
height: 100%;
|
||
background: linear-gradient(90deg, rgba(0, 212, 255, 0.2), rgba(0, 212, 255, 0.75));
|
||
color: #d5f7ff;
|
||
font-family: var(--font-mono);
|
||
font-size: 8px;
|
||
letter-spacing: 1px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
padding-right: 6px;
|
||
transition: width 100ms linear;
|
||
text-shadow: 0 0 6px rgba(0, 212, 255, 0.6);
|
||
}
|
||
|
||
#scene-status {
|
||
margin-top: 8px;
|
||
font-family: var(--font-mono);
|
||
font-size: 10px;
|
||
letter-spacing: 1px;
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
#scene-runtime {
|
||
position: fixed;
|
||
top: 34px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
z-index: 105;
|
||
opacity: 0;
|
||
visibility: hidden;
|
||
transition: opacity 180ms ease, visibility 180ms ease;
|
||
font-family: var(--font-mono);
|
||
font-size: 11px;
|
||
letter-spacing: 2px;
|
||
color: #bff4ff;
|
||
background: rgba(0, 0, 0, 0.45);
|
||
border: 1px solid rgba(0, 212, 255, 0.36);
|
||
border-radius: 999px;
|
||
padding: 6px 14px;
|
||
text-shadow: 0 0 8px rgba(0, 212, 255, 0.55);
|
||
pointer-events: none;
|
||
}
|
||
|
||
#scene-runtime.active {
|
||
opacity: 1;
|
||
visibility: visible;
|
||
}
|
||
|
||
#control-panel.collapsed .button-grid,
|
||
#data-panel.collapsed .data-toggle-list,
|
||
#global-context-panel.collapsed #radio-panel,
|
||
#global-context-panel.collapsed #military-awareness-panel,
|
||
#global-context-panel.collapsed .global-context-actions,
|
||
#global-context-panel.collapsed .global-context-modes,
|
||
#global-context-panel.collapsed .context-mode-view,
|
||
#global-context-panel.collapsed > .global-context-panel-inner > .context-mode-standby,
|
||
#radio-panel.collapsed .radio-panel-inner > :not(.panel-header),
|
||
#cctv-panel.collapsed .cctv-controls,
|
||
#cctv-panel.collapsed .cctv-calibration-block,
|
||
#cctv-panel.collapsed .cctv-frame-wrap,
|
||
#cctv-panel.collapsed #cctv-source-badge,
|
||
#cctv-panel.collapsed #cctv-meta,
|
||
#cctv-panel.collapsed .cctv-summary-label,
|
||
#cctv-panel.collapsed #cctv-summary,
|
||
#scene-panel.collapsed .scene-controls,
|
||
#scene-panel.collapsed .scene-shot-list,
|
||
#scene-panel.collapsed .scene-progress,
|
||
#scene-panel.collapsed #scene-status,
|
||
#param-slider-panel.collapsed #param-sliders,
|
||
#location-bar.collapsed .poi-row-container,
|
||
#location-bar.collapsed .location-bar-divider,
|
||
#location-bar.collapsed .location-city-row {
|
||
display: none !important;
|
||
}
|
||
|
||
#data-panel.collapsed,
|
||
#cctv-panel.collapsed,
|
||
#scene-panel.collapsed {
|
||
width: var(--left-collapsed-width);
|
||
}
|
||
|
||
#global-context-panel #radio-panel.collapsed { width: 100%; }
|
||
|
||
#data-panel.collapsed .panel-title,
|
||
#cctv-panel.collapsed .panel-title,
|
||
#radio-panel.collapsed .panel-title,
|
||
#scene-panel.collapsed .panel-title {
|
||
font-size: 8px;
|
||
letter-spacing: 1.8px;
|
||
}
|
||
|
||
#control-panel.collapsed .panel-inner,
|
||
#data-panel.collapsed .data-panel-inner,
|
||
#cctv-panel.collapsed .cctv-panel-inner,
|
||
#radio-panel.collapsed .radio-panel-inner,
|
||
#scene-panel.collapsed .scene-panel-inner,
|
||
#param-slider-panel.collapsed,
|
||
#location-bar.collapsed .location-inner {
|
||
padding-bottom: 10px;
|
||
}
|
||
|
||
#control-panel.collapsed .panel-header,
|
||
#data-panel.collapsed .panel-header,
|
||
#cctv-panel.collapsed .panel-header,
|
||
#radio-panel.collapsed .panel-header,
|
||
#global-context-panel.collapsed .panel-header,
|
||
#scene-panel.collapsed .panel-header,
|
||
#param-slider-panel.collapsed .param-panel-header {
|
||
margin-bottom: 2px;
|
||
}
|
||
|
||
/* ── Recording Mode ─────────────────────────── */
|
||
body.recording-mode #title-bar,
|
||
body.recording-mode #style-indicator,
|
||
body.recording-mode #top-center-actions,
|
||
body.recording-mode #global-loading-status,
|
||
body.recording-mode #traffic-sync-chip,
|
||
body.recording-mode #cctv-sync-chip,
|
||
body.recording-mode #pp-toggles,
|
||
body.recording-mode #clean-view-exit,
|
||
body.recording-mode #param-slider-panel,
|
||
body.recording-mode #control-panel,
|
||
body.recording-mode #location-bar,
|
||
body.recording-mode #data-panel,
|
||
body.recording-mode #cctv-panel,
|
||
body.recording-mode #radio-panel,
|
||
body.recording-mode #global-context-panel,
|
||
body.recording-mode #gev-voice-control,
|
||
body.recording-mode #scene-panel {
|
||
opacity: 0 !important;
|
||
visibility: hidden !important;
|
||
pointer-events: none !important;
|
||
}
|
||
|
||
body.recording-mode #scene-runtime.active {
|
||
opacity: 1;
|
||
visibility: visible;
|
||
}
|
||
|
||
/* Scene playback owns layer and camera sequencing until Stop or completion. */
|
||
body.scene-playback-mode :is(#clear-selected-layers, #reset-globe-view) {
|
||
display: none !important;
|
||
}
|
||
|
||
/* ── Responsive ───────────────────────────────── */
|
||
@media (max-width: 720px) {
|
||
#pp-toggles {
|
||
--pp-expanded-width: 176px;
|
||
position: relative;
|
||
inset: auto;
|
||
gap: 6px;
|
||
}
|
||
|
||
.pp-toggle-group,
|
||
#clean-view-toggle {
|
||
width: 176px;
|
||
}
|
||
|
||
.button-grid {
|
||
flex-wrap: nowrap;
|
||
}
|
||
|
||
#control-panel {
|
||
left: 16px;
|
||
right: 16px;
|
||
transform: none;
|
||
max-width: none;
|
||
}
|
||
|
||
#title-bar {
|
||
top: 20px;
|
||
left: 20px;
|
||
}
|
||
|
||
#title-bar h1 {
|
||
font-size: 16px;
|
||
letter-spacing: 4px;
|
||
}
|
||
|
||
#title-bar h1 {
|
||
gap: 8px;
|
||
}
|
||
|
||
#title-bar .title-logo {
|
||
width: 36px;
|
||
}
|
||
|
||
#location-bar {
|
||
left: 16px;
|
||
right: 16px;
|
||
transform: none;
|
||
max-width: none;
|
||
bottom: 120px;
|
||
}
|
||
|
||
#gev-voice-control {
|
||
right: 16px;
|
||
bottom: 16px;
|
||
min-width: 196px;
|
||
}
|
||
|
||
#gev-voice-detail {
|
||
max-width: 112px;
|
||
}
|
||
|
||
.hud-top-left,
|
||
.hud-bottom-left {
|
||
left: 16px;
|
||
}
|
||
|
||
.hud-top-right,
|
||
.hud-bottom-right {
|
||
right: 16px;
|
||
}
|
||
|
||
.hud-left-edge,
|
||
.hud-right-edge {
|
||
display: none;
|
||
}
|
||
|
||
.hud-top-bar,
|
||
.hud-bottom-bar {
|
||
width: calc(100vw - 24px);
|
||
left: 12px;
|
||
transform: none;
|
||
}
|
||
|
||
.hud-top-bar {
|
||
top: 54px;
|
||
font-size: 9px;
|
||
}
|
||
|
||
#intel-hud[data-variant='operator'] .hud-top-bar {
|
||
left: 12px;
|
||
right: auto;
|
||
width: calc(100vw - 24px);
|
||
transform: none;
|
||
}
|
||
|
||
.hud-bottom-bar {
|
||
bottom: 90px;
|
||
font-size: 9px;
|
||
}
|
||
|
||
#data-panel {
|
||
top: auto;
|
||
left: 16px;
|
||
bottom: 200px;
|
||
width: 260px;
|
||
}
|
||
|
||
#data-panel.collapsed {
|
||
width: 260px;
|
||
}
|
||
|
||
#cctv-panel {
|
||
top: auto;
|
||
left: 16px;
|
||
right: 16px;
|
||
width: auto;
|
||
bottom: 308px;
|
||
}
|
||
|
||
#cctv-panel.collapsed {
|
||
width: auto;
|
||
}
|
||
|
||
/* Narrow viewports: cap the preview height to keep the panel compact. Cap
|
||
the IMAGE, not the wrap — the wrap is overflow:hidden, so capping it would
|
||
re-crop the very timestamp this is protecting. object-fit: contain then
|
||
letterboxes inside the shorter box. */
|
||
#cctv-frame {
|
||
aspect-ratio: auto;
|
||
height: 120px;
|
||
}
|
||
|
||
.cctv-frame-wrap {
|
||
min-height: 0;
|
||
}
|
||
|
||
#scene-panel {
|
||
top: auto;
|
||
right: 16px;
|
||
left: 16px;
|
||
width: auto;
|
||
bottom: 12px;
|
||
}
|
||
|
||
#scene-panel.collapsed {
|
||
width: auto;
|
||
}
|
||
|
||
#left-panel-stack {
|
||
top: 70px;
|
||
right: 16px;
|
||
bottom: calc(50vh + 8px);
|
||
left: 16px;
|
||
width: auto;
|
||
max-height: none;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
#right-context-rail {
|
||
top: calc(50vh + 8px);
|
||
right: 16px;
|
||
/* The rail goes edge-to-edge at this width, so its floor is what decides
|
||
whether the required Google/Cesium credit line survives. The credit's
|
||
top edge sits at calc(2vh + 5rem) plus its own 28px, so a flat 100px
|
||
floor cut into it at EVERY viewport height — the DISPLAY toggles were
|
||
drawn straight over the notice. Track the credit's own anchor instead
|
||
and the 12px of clear air holds regardless of height; the rail already
|
||
scrolls (overflow-y below), so it loses reach, not content. */
|
||
bottom: calc(2vh + 7.5rem);
|
||
left: 16px;
|
||
width: auto;
|
||
max-height: none;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
#right-context-rail > #pp-toggles {
|
||
width: 100%;
|
||
}
|
||
|
||
#right-context-rail #pp-toggles.collapsed .pp-header-row,
|
||
#right-context-rail #cctv-panel,
|
||
#right-context-rail #cctv-panel.collapsed,
|
||
#right-context-rail #radio-panel,
|
||
#right-context-rail #radio-panel.collapsed,
|
||
#right-context-rail #global-context-panel,
|
||
#right-context-rail #global-context-panel.collapsed {
|
||
width: 100%;
|
||
}
|
||
.context-radio-mini {
|
||
right: -38px;
|
||
width: min(244px, calc(100vw - 32px));
|
||
}
|
||
|
||
#left-panel-stack > #data-panel,
|
||
#left-panel-stack > #cctv-panel,
|
||
#left-panel-stack > #global-context-panel,
|
||
#left-panel-stack > #scene-panel,
|
||
#left-panel-stack > #data-panel.collapsed,
|
||
#left-panel-stack > #cctv-panel.collapsed,
|
||
#left-panel-stack > #global-context-panel.collapsed,
|
||
#left-panel-stack > #scene-panel.collapsed {
|
||
position: relative;
|
||
top: auto;
|
||
right: auto;
|
||
bottom: auto;
|
||
left: auto;
|
||
width: 100%;
|
||
}
|
||
|
||
#scene-runtime {
|
||
top: 16px;
|
||
max-width: calc(100vw - 24px);
|
||
text-align: center;
|
||
}
|
||
}
|
||
|
||
/* ── Unified Command Dock ────────────────────── */
|
||
#command-dock {
|
||
position: fixed;
|
||
right: auto;
|
||
bottom: 2vh;
|
||
left: 50%;
|
||
z-index: 145;
|
||
display: grid;
|
||
grid-template-areas: 'locations voice presets';
|
||
grid-template-columns: minmax(300px, 1fr) minmax(230px, 270px) minmax(390px, 1.15fr);
|
||
align-items: stretch;
|
||
width: min(94vw, 1240px);
|
||
padding: 6px;
|
||
overflow: visible;
|
||
background: rgba(9, 18, 27, 0.84);
|
||
border: 1px solid rgba(123, 189, 211, 0.28);
|
||
border-radius: 12px;
|
||
box-shadow:
|
||
0 12px 36px rgba(0, 0, 0, 0.58),
|
||
0 0 0 1px rgba(255, 255, 255, 0.03) inset,
|
||
0 0 28px rgba(0, 212, 255, 0.06);
|
||
backdrop-filter: blur(28px) saturate(1.35);
|
||
-webkit-backdrop-filter: blur(28px) saturate(1.35);
|
||
transform: translateX(-50%);
|
||
transition: opacity var(--transition-smooth), visibility var(--transition-smooth);
|
||
}
|
||
|
||
#command-dock > #location-bar,
|
||
#command-dock > #control-panel,
|
||
#command-dock > #gev-voice-control {
|
||
position: relative;
|
||
inset: auto;
|
||
width: auto;
|
||
max-width: none;
|
||
transform: none;
|
||
}
|
||
|
||
#command-dock > #location-bar {
|
||
grid-area: locations;
|
||
min-width: 0;
|
||
border-right: 1px solid rgba(123, 189, 211, 0.16);
|
||
}
|
||
|
||
#command-dock > #control-panel {
|
||
grid-area: presets;
|
||
min-width: 0;
|
||
border-left: 1px solid rgba(123, 189, 211, 0.16);
|
||
}
|
||
|
||
#command-dock > #gev-voice-control {
|
||
grid-area: voice;
|
||
z-index: 2;
|
||
align-self: stretch;
|
||
justify-content: center;
|
||
min-width: 0;
|
||
margin: -14px 0;
|
||
padding: 19px 14px 12px;
|
||
border-color: rgba(0, 212, 255, 0.36);
|
||
border-radius: 12px;
|
||
background: rgba(8, 31, 42, 0.94);
|
||
box-shadow:
|
||
0 12px 30px rgba(0, 0, 0, 0.56),
|
||
0 0 26px rgba(0, 212, 255, 0.12),
|
||
0 0 0 1px rgba(0, 212, 255, 0.08) inset;
|
||
}
|
||
|
||
#command-dock .gev-voice-kicker {
|
||
position: absolute;
|
||
top: 6px;
|
||
right: 14px;
|
||
left: 14px;
|
||
overflow: hidden;
|
||
color: rgba(190, 221, 230, 0.52);
|
||
font-family: var(--font-mono);
|
||
font-size: 7px;
|
||
letter-spacing: 1.5px;
|
||
text-align: center;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
#command-dock #gev-voice-button {
|
||
width: 78px;
|
||
height: 42px;
|
||
}
|
||
|
||
#command-dock .gev-voice-readout {
|
||
flex: 1;
|
||
text-align: left;
|
||
}
|
||
|
||
#command-dock #gev-voice-detail {
|
||
max-width: 110px;
|
||
}
|
||
|
||
#command-dock .panel-glow {
|
||
display: none;
|
||
}
|
||
|
||
#command-dock .panel-inner,
|
||
#command-dock .location-inner,
|
||
#command-dock #control-panel.collapsed .panel-inner,
|
||
#command-dock #location-bar.collapsed .location-inner {
|
||
height: 100%;
|
||
padding: 8px 14px;
|
||
background: transparent;
|
||
border: 0;
|
||
border-radius: 0;
|
||
box-shadow: none;
|
||
backdrop-filter: none;
|
||
-webkit-backdrop-filter: none;
|
||
}
|
||
|
||
#command-dock .panel-header,
|
||
#command-dock .location-toolbar,
|
||
#command-dock #control-panel.collapsed .panel-header {
|
||
min-height: 18px;
|
||
margin: 0 0 6px;
|
||
padding: 0;
|
||
}
|
||
|
||
#command-dock .panel-title,
|
||
#command-dock .location-toolbar-label {
|
||
font-size: 8px;
|
||
letter-spacing: 1.6px;
|
||
color: rgba(190, 221, 230, 0.58);
|
||
}
|
||
|
||
#command-dock .panel-collapse-btn,
|
||
#command-dock .panel-mini-status,
|
||
#command-dock .location-mini-status {
|
||
display: none !important;
|
||
}
|
||
|
||
#command-dock #control-panel.collapsed .button-grid,
|
||
#command-dock #location-bar.collapsed .location-city-row {
|
||
display: flex !important;
|
||
}
|
||
|
||
#command-dock .button-grid {
|
||
gap: 6px;
|
||
}
|
||
|
||
#command-dock .style-btn {
|
||
min-width: 52px;
|
||
gap: 4px;
|
||
padding: 9px 8px 7px;
|
||
border-radius: 7px;
|
||
}
|
||
|
||
#command-dock .btn-icon {
|
||
font-size: 16px;
|
||
}
|
||
|
||
#command-dock .btn-label {
|
||
font-family: var(--font-mono);
|
||
font-size: 8px;
|
||
letter-spacing: 0.4px;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
#command-dock .btn-key {
|
||
top: 3px;
|
||
right: 4px;
|
||
font-size: 7px;
|
||
}
|
||
|
||
#command-dock .location-city-row {
|
||
min-width: 0;
|
||
gap: 8px;
|
||
}
|
||
|
||
#command-dock .location-search-wrap {
|
||
order: -1;
|
||
flex: 0 1 190px;
|
||
min-width: 132px;
|
||
padding-right: 8px;
|
||
border-right: 1px solid rgba(123, 189, 211, 0.14);
|
||
}
|
||
|
||
#command-dock .search-toggle-btn {
|
||
width: 30px;
|
||
height: 30px;
|
||
border-radius: 6px;
|
||
}
|
||
|
||
#command-dock #location-search,
|
||
#command-dock #location-search.expanded {
|
||
width: 100%;
|
||
min-width: 0;
|
||
padding: 6px 8px;
|
||
font-size: 11px;
|
||
}
|
||
|
||
#command-dock .location-pills {
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
|
||
#command-dock .location-pill {
|
||
padding: 7px 10px;
|
||
border-radius: 6px;
|
||
font-family: var(--font-mono);
|
||
font-size: 9px;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
#command-dock .poi-row-container.expanded {
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
/* Keep required map attribution clear of the full-width command surface. */
|
||
body:not(.ui-clean-view):not(.recording-mode) #cesium-credits {
|
||
bottom: calc(2vh + 7rem);
|
||
}
|
||
|
||
body:not(.ui-clean-view):not(.recording-mode):has(#intel-hud[data-variant='minimal'].active) #cesium-credits {
|
||
right: 36px;
|
||
left: auto;
|
||
width: min(340px, calc(100vw - 72px)) !important;
|
||
text-align: right;
|
||
}
|
||
|
||
body.ui-clean-view #command-dock,
|
||
body.recording-mode #command-dock {
|
||
opacity: 0 !important;
|
||
visibility: hidden !important;
|
||
pointer-events: none !important;
|
||
}
|
||
|
||
body.ui-clean-view #cesium-credits,
|
||
body.recording-mode #cesium-credits {
|
||
right: auto;
|
||
bottom: 36px;
|
||
left: 36px;
|
||
}
|
||
|
||
#intel-hud[data-variant='minimal'] .hud-bottom-left {
|
||
bottom: calc(2vh + 7.5rem);
|
||
}
|
||
|
||
#intel-hud[data-variant='minimal'] .hud-bottom-bar {
|
||
bottom: calc(2vh + 11.5rem);
|
||
}
|
||
|
||
@media (max-width: 980px) {
|
||
#command-dock {
|
||
grid-template-areas:
|
||
'locations voice'
|
||
'presets presets';
|
||
grid-template-columns: minmax(0, 1fr) minmax(170px, 210px);
|
||
width: calc(100vw - 24px);
|
||
}
|
||
|
||
#command-dock > #location-bar {
|
||
border-right: 1px solid rgba(123, 189, 211, 0.16);
|
||
border-bottom: 1px solid rgba(123, 189, 211, 0.16);
|
||
}
|
||
|
||
#command-dock > #control-panel {
|
||
border-top: 1px solid rgba(123, 189, 211, 0.16);
|
||
border-left: 0;
|
||
}
|
||
|
||
#command-dock > #gev-voice-control {
|
||
margin: -10px 0 0;
|
||
}
|
||
|
||
body:not(.ui-clean-view):not(.recording-mode) #cesium-credits {
|
||
bottom: calc(2vh + 9.5rem);
|
||
}
|
||
|
||
#intel-hud[data-variant='minimal'] .hud-bottom-left {
|
||
bottom: calc(2vh + 12rem);
|
||
}
|
||
|
||
#intel-hud[data-variant='minimal'] .hud-bottom-bar {
|
||
bottom: calc(2vh + 16rem);
|
||
}
|
||
}
|
||
|
||
@media (max-width: 720px) {
|
||
#command-dock {
|
||
bottom: 8px;
|
||
}
|
||
|
||
#command-dock .location-search-wrap {
|
||
flex-basis: 150px;
|
||
}
|
||
|
||
#command-dock .panel-inner,
|
||
#command-dock .location-inner,
|
||
#command-dock #control-panel.collapsed .panel-inner,
|
||
#command-dock #location-bar.collapsed .location-inner {
|
||
padding: 7px 9px;
|
||
}
|
||
|
||
#left-panel-stack {
|
||
bottom: calc(50vh + 8px);
|
||
}
|
||
}
|
||
/* ── Compact accordion command dock ──────────── */
|
||
#command-dock {
|
||
--dock-side-compact: clamp(9.5rem, 12vw, 10.5rem);
|
||
--dock-location-open: clamp(28rem, 40vw, 33rem);
|
||
--dock-presets-open: clamp(25rem, 36vw, 29rem);
|
||
--dock-voice-width: clamp(13.5rem, 17vw, 15rem);
|
||
display: flex;
|
||
grid-template-areas: none;
|
||
grid-template-columns: none;
|
||
align-items: center;
|
||
width: fit-content;
|
||
max-width: calc(100vw - 4vw);
|
||
min-height: 3.75rem;
|
||
padding: 0.2rem;
|
||
border-radius: 0.4rem;
|
||
transform: translateX(-50%);
|
||
transition:
|
||
transform 280ms cubic-bezier(0.2, 0.8, 0.2, 1),
|
||
opacity var(--transition-smooth),
|
||
visibility var(--transition-smooth);
|
||
}
|
||
|
||
#command-dock:has(#location-bar:not(.collapsed)) {
|
||
transform: translateX(calc(-50% + (var(--dock-location-open) - var(--dock-side-compact)) / 2));
|
||
}
|
||
|
||
#command-dock:has(#control-panel:not(.collapsed)) {
|
||
transform: translateX(calc(-50% - (var(--dock-presets-open) - var(--dock-side-compact)) / 2));
|
||
}
|
||
|
||
#command-dock > #location-bar,
|
||
#command-dock > #control-panel {
|
||
flex: 0 0 var(--dock-side-compact);
|
||
align-self: stretch;
|
||
min-width: 0;
|
||
height: auto;
|
||
overflow: hidden;
|
||
border: 0;
|
||
transition: flex-basis 280ms cubic-bezier(0.2, 0.8, 0.2, 1);
|
||
}
|
||
|
||
#command-dock > #location-bar:not(.collapsed) {
|
||
flex-basis: var(--dock-location-open);
|
||
}
|
||
|
||
#command-dock > #control-panel:not(.collapsed) {
|
||
flex-basis: var(--dock-presets-open);
|
||
}
|
||
|
||
#command-dock > #location-bar {
|
||
border-right: 1px solid rgba(123, 189, 211, 0.18);
|
||
}
|
||
|
||
#command-dock > #control-panel {
|
||
border-left: 1px solid rgba(123, 189, 211, 0.18);
|
||
}
|
||
|
||
#command-dock .panel-inner,
|
||
#command-dock .location-inner,
|
||
#command-dock #control-panel.collapsed .panel-inner,
|
||
#command-dock #location-bar.collapsed .location-inner {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
min-height: 3.75rem;
|
||
padding: 0.45rem 0.75rem;
|
||
}
|
||
|
||
#command-dock .panel-header,
|
||
#command-dock .location-toolbar,
|
||
#command-dock #control-panel.collapsed .panel-header {
|
||
flex: 0 0 auto;
|
||
min-width: calc(var(--dock-side-compact) - 1.5rem);
|
||
min-height: 1rem;
|
||
margin: 0;
|
||
}
|
||
|
||
#command-dock .panel-title,
|
||
#command-dock .location-toolbar-label {
|
||
width: max-content;
|
||
font-size: 0.45rem;
|
||
letter-spacing: 0.12rem;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
#command-dock .panel-title::after,
|
||
#command-dock .location-toolbar-label::after {
|
||
content: '›';
|
||
margin-left: 0.45rem;
|
||
color: rgba(54, 220, 255, 0.68);
|
||
font-size: 0.7rem;
|
||
}
|
||
|
||
#command-dock #control-panel .panel-title::after {
|
||
content: '‹';
|
||
margin-right: 0.45rem;
|
||
margin-left: 0;
|
||
float: left;
|
||
}
|
||
|
||
#command-dock #location-bar.collapsed .location-city-row,
|
||
#command-dock #location-bar.collapsed .poi-row-container,
|
||
#command-dock #location-bar.collapsed .location-bar-divider,
|
||
#command-dock #control-panel.collapsed .button-grid {
|
||
display: none !important;
|
||
}
|
||
|
||
#command-dock #location-bar:not(.collapsed) .location-toolbar,
|
||
#command-dock #control-panel:not(.collapsed) .panel-header {
|
||
margin-bottom: 0.35rem;
|
||
}
|
||
|
||
#command-dock #location-bar:not(.collapsed) .location-city-row,
|
||
#command-dock #control-panel:not(.collapsed) .button-grid {
|
||
display: flex !important;
|
||
animation: command-dock-reveal 220ms ease-out both;
|
||
}
|
||
|
||
#command-dock .location-city-row {
|
||
flex-wrap: nowrap;
|
||
gap: 0.35rem;
|
||
overflow: hidden;
|
||
}
|
||
|
||
#command-dock .location-search-wrap {
|
||
flex: 0 0 10.5rem;
|
||
min-width: 0;
|
||
padding-right: 0.4rem;
|
||
}
|
||
|
||
#command-dock .search-toggle-btn {
|
||
width: 1.75rem;
|
||
height: 1.75rem;
|
||
}
|
||
|
||
#command-dock #location-search,
|
||
#command-dock #location-search.expanded {
|
||
height: 1.75rem;
|
||
padding: 0.3rem 0.45rem;
|
||
font-size: 0.62rem;
|
||
}
|
||
|
||
#command-dock .location-pills {
|
||
display: flex;
|
||
gap: 0.3rem;
|
||
overflow-x: auto;
|
||
scrollbar-width: none;
|
||
}
|
||
|
||
#command-dock .location-pills::-webkit-scrollbar {
|
||
display: none;
|
||
}
|
||
|
||
#command-dock .location-pill,
|
||
#command-dock .poi-pill {
|
||
flex: 0 0 auto;
|
||
min-height: 1.75rem;
|
||
padding: 0.3rem 0.55rem;
|
||
border-radius: 0.2rem;
|
||
font-size: 0.52rem;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
#command-dock .poi-row-container.expanded {
|
||
display: flex;
|
||
justify-content: flex-start;
|
||
gap: 0.3rem;
|
||
max-height: 2.1rem;
|
||
margin: 0 0 0.35rem;
|
||
overflow-x: auto;
|
||
overflow-y: hidden;
|
||
animation: command-dock-reveal 180ms ease-out both;
|
||
scrollbar-width: none;
|
||
}
|
||
|
||
#command-dock .poi-row-container.expanded::-webkit-scrollbar {
|
||
display: none;
|
||
}
|
||
|
||
#command-dock .location-bar-divider.visible {
|
||
display: none;
|
||
}
|
||
|
||
#command-dock .button-grid {
|
||
flex-wrap: nowrap;
|
||
gap: 0.3rem;
|
||
overflow-x: auto;
|
||
scrollbar-width: none;
|
||
}
|
||
|
||
#command-dock .button-grid::-webkit-scrollbar {
|
||
display: none;
|
||
}
|
||
|
||
#command-dock .style-btn {
|
||
flex: 0 0 3.2rem;
|
||
min-width: 3.2rem;
|
||
min-height: 2.45rem;
|
||
gap: 0.1rem;
|
||
padding: 0.3rem 0.25rem;
|
||
border-radius: 0.2rem;
|
||
}
|
||
|
||
#command-dock .btn-icon {
|
||
font-size: 0.78rem;
|
||
}
|
||
|
||
#command-dock .btn-label {
|
||
font-size: 0.43rem;
|
||
letter-spacing: 0.02rem;
|
||
}
|
||
|
||
#command-dock .btn-key {
|
||
display: none;
|
||
}
|
||
|
||
#command-dock > #gev-voice-control {
|
||
position: relative;
|
||
inset: auto;
|
||
z-index: 3;
|
||
display: grid;
|
||
grid-template-columns: 3.2rem 1fr 3.6rem;
|
||
grid-template-rows: 0.8rem 2.55rem 0.8rem;
|
||
flex: 0 0 var(--dock-voice-width);
|
||
width: var(--dock-voice-width);
|
||
min-width: 0;
|
||
height: 4.9rem;
|
||
margin: -0.65rem 0;
|
||
padding: 0.3rem 0.65rem;
|
||
gap: 0 0.35rem;
|
||
overflow: hidden;
|
||
border-radius: var(--panel-radius);
|
||
transform: none;
|
||
}
|
||
|
||
#command-dock .gev-voice-kicker {
|
||
position: static;
|
||
grid-column: 2 / 4;
|
||
grid-row: 1;
|
||
align-self: center;
|
||
color: rgba(190, 221, 230, 0.58);
|
||
font-size: 0.39rem;
|
||
letter-spacing: 0.07rem;
|
||
text-align: center;
|
||
}
|
||
|
||
#command-dock #gev-voice-button {
|
||
grid-column: 1;
|
||
grid-row: 1 / 4;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 3rem;
|
||
height: 3rem;
|
||
align-self: center;
|
||
gap: 0.15rem;
|
||
padding: 0;
|
||
border-radius: 50%;
|
||
box-shadow:
|
||
0 0 0 0.2rem rgba(0, 212, 255, 0.06),
|
||
0 0 1rem rgba(0, 212, 255, 0.12);
|
||
}
|
||
|
||
#command-dock .gev-mic-orbit {
|
||
display: grid;
|
||
place-items: center;
|
||
width: 1.7rem;
|
||
height: 1.7rem;
|
||
}
|
||
|
||
#command-dock .gev-mic-orbit img {
|
||
width: 1.55rem;
|
||
height: 1.55rem;
|
||
}
|
||
|
||
#command-dock .gev-mic-label {
|
||
font-size: 0.35rem;
|
||
color: rgba(190, 221, 230, 0.72);
|
||
letter-spacing: 0.02rem;
|
||
}
|
||
|
||
#command-dock .gev-voice-visualizer {
|
||
grid-column: 2;
|
||
grid-row: 2;
|
||
display: flex;
|
||
align-items: end;
|
||
justify-content: center;
|
||
gap: 0.12rem;
|
||
height: 2.2rem;
|
||
padding: 0.2rem 0.1rem;
|
||
border-bottom: 1px solid rgba(54, 220, 255, 0.34);
|
||
}
|
||
|
||
#command-dock .gev-voice-visualizer span {
|
||
width: 0.18rem;
|
||
height: 0.55rem;
|
||
background: linear-gradient(to top, #28b9db, #71eaff);
|
||
box-shadow: 0 0 0.35rem rgba(54, 220, 255, 0.28);
|
||
transform-origin: bottom;
|
||
}
|
||
|
||
#command-dock .gev-voice-visualizer span:nth-child(3n) { height: 1.35rem; }
|
||
#command-dock .gev-voice-visualizer span:nth-child(4n) { height: 0.95rem; }
|
||
#command-dock .gev-voice-visualizer span:nth-child(5n) { height: 1.7rem; }
|
||
#command-dock .gev-voice-visualizer span:nth-child(7n) { height: 0.75rem; }
|
||
|
||
#command-dock #gev-voice-control[data-status='listening'] .gev-voice-visualizer span,
|
||
#command-dock #gev-voice-control[data-status='executing'] .gev-voice-visualizer span {
|
||
animation: gev-voice-bar 680ms ease-in-out infinite alternate;
|
||
animation-delay: calc(var(--bar) * -45ms);
|
||
}
|
||
|
||
#command-dock .gev-voice-readout {
|
||
display: contents;
|
||
}
|
||
|
||
#command-dock #gev-voice-status {
|
||
grid-column: 3;
|
||
grid-row: 2;
|
||
align-self: start;
|
||
padding-top: 0.2rem;
|
||
font-size: 0.45rem;
|
||
text-align: right;
|
||
}
|
||
|
||
#command-dock #gev-voice-detail {
|
||
grid-column: 2 / 4;
|
||
grid-row: 3;
|
||
align-self: center;
|
||
max-width: none;
|
||
margin: 0;
|
||
font-size: 0.39rem;
|
||
letter-spacing: 0.08rem;
|
||
text-align: center;
|
||
}
|
||
|
||
@keyframes command-dock-reveal {
|
||
from { opacity: 0; transform: translateY(0.2rem); }
|
||
to { opacity: 1; transform: translateY(0); }
|
||
}
|
||
|
||
@keyframes gev-voice-bar {
|
||
from { transform: scaleY(0.35); opacity: 0.5; }
|
||
to { transform: scaleY(1); opacity: 1; }
|
||
}
|
||
|
||
/* Compact dock clearance keeps the reference-like low profile. */
|
||
body:not(.ui-clean-view):not(.recording-mode) #cesium-credits {
|
||
bottom: calc(2vh + 4.7rem);
|
||
}
|
||
|
||
#intel-hud[data-variant='minimal'] .hud-bottom-left {
|
||
bottom: calc(2vh + 5.4rem);
|
||
}
|
||
|
||
#intel-hud[data-variant='minimal'] .hud-bottom-bar {
|
||
bottom: calc(2vh + 8.9rem);
|
||
}
|
||
|
||
@media (max-width: 900px) {
|
||
#command-dock {
|
||
--dock-popover-mobile-width: calc(100vw - 1.5rem);
|
||
}
|
||
|
||
#command-dock {
|
||
--dock-side-compact: 4.25rem;
|
||
--dock-location-open: calc(100vw - 7rem);
|
||
--dock-presets-open: calc(100vw - 7rem);
|
||
--dock-voice-width: 11.5rem;
|
||
max-width: calc(100vw - 1rem);
|
||
}
|
||
|
||
#command-dock:has(#location-bar:not(.collapsed)),
|
||
#command-dock:has(#control-panel:not(.collapsed)) {
|
||
transform: translateX(-50%);
|
||
}
|
||
|
||
#command-dock:has(#location-bar:not(.collapsed)) > #control-panel,
|
||
#command-dock:has(#control-panel:not(.collapsed)) > #location-bar {
|
||
flex-basis: 0;
|
||
border: 0;
|
||
}
|
||
|
||
#command-dock:has(#location-bar:not(.collapsed)) > #gev-voice-control,
|
||
#command-dock:has(#control-panel:not(.collapsed)) > #gev-voice-control {
|
||
flex-basis: 4.75rem;
|
||
width: 4.75rem;
|
||
}
|
||
|
||
#command-dock:has(#location-bar:not(.collapsed)) .gev-voice-visualizer,
|
||
#command-dock:has(#location-bar:not(.collapsed)) .gev-voice-kicker,
|
||
#command-dock:has(#location-bar:not(.collapsed)) .gev-voice-readout,
|
||
#command-dock:has(#control-panel:not(.collapsed)) .gev-voice-visualizer,
|
||
#command-dock:has(#control-panel:not(.collapsed)) .gev-voice-kicker,
|
||
#command-dock:has(#control-panel:not(.collapsed)) .gev-voice-readout {
|
||
visibility: hidden;
|
||
}
|
||
|
||
#command-dock .location-search-wrap {
|
||
flex-basis: 8.5rem;
|
||
}
|
||
}
|
||
|
||
/* ── Command dock refinement: stacked trays + voice states ── */
|
||
#command-dock {
|
||
--dock-voice-width: 8.75rem;
|
||
--dock-location-pinned-height: 0px;
|
||
--dock-presets-pinned-height: 0px;
|
||
--dock-pinned-stack-height: 0px;
|
||
--dock-lower-pinned-height: 0px;
|
||
--dock-unified-width: calc(var(--dock-side-compact) * 2 + var(--dock-voice-width));
|
||
--dock-location-open: max(34rem, calc(var(--dock-unified-width) + 0.75rem));
|
||
--dock-presets-open: max(34rem, calc(var(--dock-unified-width) + 0.75rem));
|
||
}
|
||
|
||
#command-dock .panel-title,
|
||
#command-dock .location-toolbar-label {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.42rem;
|
||
color: rgba(206, 232, 239, 0.72);
|
||
font-size: 0.58rem;
|
||
font-weight: 500;
|
||
letter-spacing: 0.13rem;
|
||
}
|
||
|
||
#command-dock .dock-label-icon {
|
||
display: inline-block;
|
||
flex: 0 0 1rem;
|
||
width: 1rem;
|
||
height: 1rem;
|
||
background: rgba(232, 234, 237, 0.3);
|
||
mask-position: center;
|
||
mask-repeat: no-repeat;
|
||
mask-size: contain;
|
||
-webkit-mask-position: center;
|
||
-webkit-mask-repeat: no-repeat;
|
||
-webkit-mask-size: contain;
|
||
transition: background-color 160ms ease, filter 160ms ease;
|
||
}
|
||
|
||
#command-dock .dock-label-icon-location {
|
||
mask-image: url('/location.svg');
|
||
-webkit-mask-image: url('/location.svg');
|
||
}
|
||
|
||
#command-dock .dock-label-icon-presets {
|
||
mask-image: url('/visual-presets.svg');
|
||
-webkit-mask-image: url('/visual-presets.svg');
|
||
}
|
||
|
||
#command-dock :is(#location-bar, #control-panel):hover .dock-label-icon,
|
||
#command-dock :is(#location-bar, #control-panel).dock-pinned .dock-label-icon {
|
||
background: var(--accent);
|
||
filter: drop-shadow(0 0 0.35rem rgba(0, 212, 255, 0.28));
|
||
}
|
||
|
||
#command-dock :is(#location-bar, #control-panel):hover .location-toolbar-label,
|
||
#command-dock :is(#location-bar, #control-panel):hover .panel-title{
|
||
color: var(--accent);
|
||
}
|
||
|
||
|
||
|
||
#command-dock #control-panel .panel-header {
|
||
justify-content: center;
|
||
}
|
||
|
||
#command-dock #control-panel .dock-tray-toggle {
|
||
box-sizing: border-box;
|
||
width: 100%;
|
||
color: inherit;
|
||
background: transparent;
|
||
border: 0;
|
||
font: inherit;
|
||
cursor: pointer;
|
||
outline: none;
|
||
}
|
||
|
||
#command-dock #control-panel .dock-tray-toggle:focus-visible {
|
||
outline: 1px solid color-mix(in srgb, var(--accent) 80%, transparent);
|
||
outline-offset: 3px;
|
||
border-radius: 3px;
|
||
}
|
||
|
||
#command-dock #control-panel .panel-title {
|
||
justify-content: center;
|
||
width: 100%;
|
||
text-align: center;
|
||
}
|
||
|
||
#command-dock #control-panel .panel-divider {
|
||
display: none;
|
||
}
|
||
|
||
#command-dock .location-toolbar-label,
|
||
#command-dock #control-panel .panel-title {
|
||
position: relative;
|
||
padding-bottom: 0.4rem;
|
||
}
|
||
|
||
#command-dock .location-toolbar-label::after,
|
||
#command-dock #control-panel .panel-title::after {
|
||
content: '';
|
||
position: absolute;
|
||
right: 0;
|
||
bottom: 0;
|
||
left: 0;
|
||
display: block;
|
||
height: 1px;
|
||
}
|
||
|
||
#command-dock .location-toolbar-label::after {
|
||
background: linear-gradient(to right, rgba(232, 234, 237, 0.3), transparent);
|
||
}
|
||
|
||
#command-dock #control-panel .panel-title::after {
|
||
background: linear-gradient(to left, rgba(232, 234, 237, 0.3), transparent);
|
||
}
|
||
|
||
#command-dock .panel-title::after,
|
||
#command-dock .location-toolbar-label::after,
|
||
#command-dock #control-panel .panel-title::after {
|
||
content: none;
|
||
display: none;
|
||
}
|
||
|
||
#command-dock .dock-popover-content {
|
||
padding: 0.7rem;
|
||
}
|
||
|
||
#command-dock .dock-pin-btn {
|
||
position: relative;
|
||
top: auto;
|
||
right: auto;
|
||
align-self: flex-end;
|
||
display: none;
|
||
place-items: center;
|
||
width: 1.65rem;
|
||
min-width: 1.65rem;
|
||
height: 1.65rem;
|
||
margin: -1.48rem -0.22rem 0.25rem 0;
|
||
padding: 0;
|
||
border-radius: 50%;
|
||
background: rgba(8, 24, 34, 0.96);
|
||
box-shadow: 0 0.35rem 0.9rem rgba(0, 0, 0, 0.5);
|
||
transform: translateY(-0.12rem);
|
||
}
|
||
|
||
#command-dock #location-bar:not(.collapsed) .dock-pin-btn,
|
||
#command-dock #control-panel:not(.collapsed) .dock-pin-btn {
|
||
display: grid;
|
||
}
|
||
|
||
#command-dock .dock-pin-btn img {
|
||
width: 0.9rem;
|
||
height: 0.9rem;
|
||
opacity: 0.58;
|
||
transition: opacity 160ms ease, transform 160ms ease;
|
||
}
|
||
|
||
#command-dock #location-bar .dock-pin-btn {
|
||
align-self: flex-start;
|
||
margin-right: 0;
|
||
margin-left: -0.22rem;
|
||
}
|
||
|
||
#command-dock .dock-pin-btn:hover img,
|
||
#command-dock .dock-pin-btn[aria-pressed='true'] img {
|
||
opacity: 1;
|
||
transform: rotate(-12deg) scale(1.08);
|
||
}
|
||
|
||
#command-dock.dock-has-pinned-tray #location-bar:not(.collapsed):not(.dock-pinned) .dock-popover-content,
|
||
#command-dock.dock-has-pinned-tray #control-panel:not(.collapsed):not(.dock-pinned) .dock-popover-content {
|
||
bottom: calc(100% + 1.2rem + var(--dock-pinned-stack-height));
|
||
}
|
||
|
||
#command-dock.dock-has-two-pinned-trays .dock-pinned-top.dock-pinned:not(.collapsed) .dock-popover-content {
|
||
bottom: calc(100% + 1.2rem + var(--dock-lower-pinned-height));
|
||
}
|
||
|
||
#command-dock.dock-has-pinned-tray .gev-voice-error-tray {
|
||
bottom: calc(100% + 1.7rem + var(--dock-pinned-stack-height));
|
||
}
|
||
|
||
#command-dock .location-pill,
|
||
#command-dock .poi-pill,
|
||
#command-dock .btn-label {
|
||
font-size: 0.56rem;
|
||
}
|
||
|
||
#command-dock #location-search,
|
||
#command-dock #location-search.expanded {
|
||
font-size: 0.68rem;
|
||
}
|
||
|
||
#command-dock > #gev-voice-control {
|
||
grid-template-columns: 3rem minmax(0, 1fr);
|
||
grid-template-rows: 0.8rem 2.25rem 0.85rem;
|
||
gap: 0.12rem 0.28rem;
|
||
width: var(--dock-voice-width);
|
||
flex-basis: var(--dock-voice-width);
|
||
height: 5.35rem;
|
||
margin-top: -0.97rem;
|
||
margin-bottom: -0.97rem;
|
||
padding: 0.32rem 0.38rem 0.3rem;
|
||
overflow: visible;
|
||
}
|
||
|
||
#command-dock .gev-voice-heading {
|
||
grid-column: 2;
|
||
grid-row: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-start;
|
||
gap: 0.35rem;
|
||
min-width: 0;
|
||
}
|
||
|
||
#command-dock .gev-voice-kicker {
|
||
position: static;
|
||
padding-right: 0;
|
||
font-size: 0.46rem;
|
||
font-weight: 500;
|
||
letter-spacing: 0.08rem;
|
||
}
|
||
|
||
#command-dock #gev-voice-button {
|
||
grid-column: 1;
|
||
grid-row: 1 / 4;
|
||
align-self: center;
|
||
width: 2.65rem;
|
||
height: 4.15rem;
|
||
background: transparent;
|
||
border: 0;
|
||
border-radius: 0;
|
||
box-shadow: none;
|
||
}
|
||
|
||
#command-dock .gev-mic-orbit {
|
||
flex: 0 0 2.45rem;
|
||
width: 2.45rem;
|
||
height: 2.45rem;
|
||
aspect-ratio: 1;
|
||
box-sizing: border-box;
|
||
background: rgba(0, 212, 255, 0.06);
|
||
border: 1px solid rgba(0, 212, 255, 0.48);
|
||
border-radius: 50%;
|
||
box-shadow: 0 0 0 0.18rem rgba(0, 212, 255, 0.06), 0 0 0.9rem rgba(0, 212, 255, 0.12);
|
||
}
|
||
|
||
#command-dock .gev-mic-label {
|
||
display: block;
|
||
margin-top: 0.18rem;
|
||
font-size: 0.42rem;
|
||
letter-spacing: 0.035rem;
|
||
}
|
||
|
||
#command-dock .gev-voice-visualizer {
|
||
grid-column: 2;
|
||
grid-row: 2;
|
||
align-self: stretch;
|
||
box-sizing: border-box;
|
||
height: 2.25rem;
|
||
padding: 0.3rem 0.05rem 0.12rem;
|
||
overflow: hidden;
|
||
visibility: visible;
|
||
opacity: 0.54;
|
||
transform: none;
|
||
transition: opacity 180ms ease;
|
||
}
|
||
|
||
#command-dock #gev-voice-control[data-status='connecting'] .gev-voice-visualizer,
|
||
#command-dock #gev-voice-control[data-status='listening'] .gev-voice-visualizer,
|
||
#command-dock #gev-voice-control[data-status='executing'] .gev-voice-visualizer {
|
||
visibility: visible;
|
||
opacity: 1;
|
||
transform: none;
|
||
}
|
||
|
||
#command-dock #gev-voice-status {
|
||
position: static;
|
||
width: auto;
|
||
padding-top: 0;
|
||
color: var(--accent);
|
||
font-size: 0.43rem;
|
||
text-align: left;
|
||
}
|
||
|
||
#command-dock #gev-voice-detail {
|
||
grid-column: 2;
|
||
grid-row: 3;
|
||
align-self: start;
|
||
padding-top: 0.12rem;
|
||
max-width: 100%;
|
||
overflow: hidden;
|
||
font-size: 0.39rem;
|
||
font-weight: 500;
|
||
letter-spacing: 0.035rem;
|
||
text-align: left;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
#command-dock #gev-voice-control[data-status='connecting'] #gev-voice-detail,
|
||
#command-dock #gev-voice-control[data-status='listening'] #gev-voice-detail,
|
||
#command-dock #gev-voice-control[data-status='executing'] #gev-voice-detail {
|
||
grid-row: 3;
|
||
font-size: 0.43rem;
|
||
}
|
||
|
||
#command-dock #gev-voice-control[data-status='error'] {
|
||
display: grid;
|
||
align-items: initial;
|
||
width: var(--dock-voice-width);
|
||
border-color: rgba(255, 92, 110, 0.58);
|
||
border-radius: 0.4rem;
|
||
}
|
||
|
||
#command-dock #gev-voice-control[data-status='error'] .gev-voice-readout {
|
||
display: contents;
|
||
}
|
||
|
||
#command-dock #gev-voice-control[data-status='error'] #gev-voice-detail {
|
||
max-width: none;
|
||
overflow: hidden;
|
||
color: #ffb4bd;
|
||
line-height: 1.2;
|
||
text-align: center;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
#command-dock .gev-voice-error-tray {
|
||
position: absolute;
|
||
bottom: calc(100% + 0.7rem);
|
||
left: 50%;
|
||
z-index: 8;
|
||
width: clamp(19rem, 29vw, 24rem);
|
||
padding: 0.85rem 0.9rem;
|
||
visibility: hidden;
|
||
opacity: 0;
|
||
color: rgba(255, 220, 224, 0.92);
|
||
background: rgba(34, 10, 16, 0.96);
|
||
border: 1px solid rgba(255, 92, 110, 0.5);
|
||
border-radius: 0.42rem;
|
||
box-shadow: 0 0.9rem 2.2rem rgba(0, 0, 0, 0.62), 0 0 1.4rem rgba(255, 92, 110, 0.08);
|
||
backdrop-filter: blur(28px) saturate(1.25);
|
||
-webkit-backdrop-filter: blur(28px) saturate(1.25);
|
||
pointer-events: none;
|
||
transform: translate(-50%, 0.55rem) scale(0.985);
|
||
transform-origin: bottom center;
|
||
transition: opacity 180ms ease, visibility 180ms ease, transform 220ms cubic-bezier(0.2, 0.8, 0.2, 1);
|
||
}
|
||
|
||
#command-dock #gev-voice-control[data-status='error']:not(.error-dismissed) .gev-voice-error-tray {
|
||
visibility: visible;
|
||
opacity: 1;
|
||
pointer-events: auto;
|
||
transform: translate(-50%, 0) scale(1);
|
||
}
|
||
|
||
#command-dock .gev-voice-error-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 0.75rem;
|
||
color: #ff8f9d;
|
||
font-family: var(--font-mono);
|
||
font-size: 0.62rem;
|
||
font-weight: 600;
|
||
letter-spacing: 0.1rem;
|
||
}
|
||
|
||
#command-dock .gev-voice-error-dismiss {
|
||
padding: 0.25rem 0.42rem;
|
||
color: rgba(255, 220, 224, 0.72);
|
||
background: rgba(255, 255, 255, 0.04);
|
||
border: 1px solid rgba(255, 143, 157, 0.32);
|
||
border-radius: 0.2rem;
|
||
font-family: var(--font-mono);
|
||
font-size: 0.43rem;
|
||
letter-spacing: 0.06rem;
|
||
cursor: pointer;
|
||
}
|
||
|
||
#command-dock #gev-voice-error-detail {
|
||
margin-top: 0.65rem;
|
||
color: rgba(255, 232, 235, 0.92);
|
||
font-family: var(--font-sans);
|
||
font-size: 0.78rem;
|
||
line-height: 1.45;
|
||
}
|
||
|
||
#command-dock .gev-voice-error-hint {
|
||
margin-top: 0.5rem;
|
||
color: rgba(255, 196, 203, 0.58);
|
||
font-family: var(--font-mono);
|
||
font-size: 0.52rem;
|
||
line-height: 1.45;
|
||
letter-spacing: 0.035rem;
|
||
}
|
||
|
||
/* The compact dock leaves both lower corners free for required attribution and telemetry. */
|
||
body:not(.ui-clean-view):not(.recording-mode) #cesium-credits,
|
||
body:not(.ui-clean-view):not(.recording-mode):has(#intel-hud[data-variant='minimal'].active) #cesium-credits {
|
||
right: auto;
|
||
bottom: 0.75rem;
|
||
left: 1.5rem;
|
||
width: auto !important;
|
||
max-width: calc(50vw - 15rem);
|
||
text-align: left;
|
||
}
|
||
|
||
#intel-hud[data-variant='tactical'] .hud-bottom-left,
|
||
#intel-hud[data-variant='tactical'] .hud-bottom-right,
|
||
#intel-hud[data-variant='operator'] .hud-bottom-left,
|
||
#intel-hud[data-variant='operator'] .hud-bottom-right {
|
||
bottom: calc(2vh + 6.5rem);
|
||
}
|
||
|
||
#intel-hud[data-variant='operator'] .hud-bottom-bar {
|
||
bottom: calc(2vh + 9.8rem);
|
||
width: min(48vw, 680px);
|
||
}
|
||
|
||
#intel-hud[data-variant='minimal'] .hud-bottom-left {
|
||
bottom: calc(2vh + 5.4rem);
|
||
}
|
||
|
||
#intel-hud[data-variant='minimal'] .hud-bottom-bar {
|
||
bottom: calc(2vh + 9rem);
|
||
}
|
||
|
||
@media (max-width: 900px) {
|
||
body:not(.ui-clean-view):not(.recording-mode) #cesium-credits,
|
||
body:not(.ui-clean-view):not(.recording-mode):has(#intel-hud[data-variant='minimal'].active) #cesium-credits {
|
||
bottom: calc(2vh + 5rem);
|
||
left: 0.75rem;
|
||
max-width: calc(100vw - 1.5rem);
|
||
}
|
||
|
||
#command-dock .gev-voice-error-tray {
|
||
width: min(24rem, calc(100vw - 1.5rem));
|
||
}
|
||
}
|
||
|
||
@media (max-width: 620px) {
|
||
#command-dock {
|
||
--dock-side-compact: 3.25rem;
|
||
--dock-voice-width: 8.75rem;
|
||
}
|
||
|
||
#command-dock .panel-title,
|
||
#command-dock .location-toolbar-label {
|
||
max-width: 2.3rem;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
#left-panel-stack {
|
||
bottom: calc(50vh + 8px);
|
||
}
|
||
}
|
||
|
||
/* ── Slide-up command trays ──────────────────── */
|
||
#command-dock,
|
||
#command-dock:has(#location-bar:not(.collapsed)),
|
||
#command-dock:has(#control-panel:not(.collapsed)) {
|
||
transform: translateX(-50%);
|
||
}
|
||
|
||
#command-dock > #location-bar,
|
||
#command-dock > #location-bar:not(.collapsed),
|
||
#command-dock > #control-panel,
|
||
#command-dock > #control-panel:not(.collapsed) {
|
||
position: relative;
|
||
flex-basis: var(--dock-side-compact);
|
||
width: var(--dock-side-compact);
|
||
overflow: visible;
|
||
}
|
||
|
||
#command-dock .location-inner,
|
||
#command-dock .panel-inner,
|
||
#command-dock #location-bar.collapsed .location-inner,
|
||
#command-dock #control-panel.collapsed .panel-inner {
|
||
position: relative;
|
||
overflow: visible;
|
||
}
|
||
|
||
#command-dock .dock-popover-content {
|
||
position: absolute;
|
||
bottom: calc(100% + 0.65rem);
|
||
z-index: 5;
|
||
display: flex;
|
||
flex-direction: column;
|
||
width: var(--dock-location-open);
|
||
padding: 1.55rem 0.6rem 0.6rem;
|
||
visibility: hidden;
|
||
opacity: 0;
|
||
background: rgba(8, 20, 30, 0.94);
|
||
border: 1px solid rgba(123, 189, 211, 0.32);
|
||
border-radius: 0.42rem;
|
||
box-shadow:
|
||
0 0.9rem 2.4rem rgba(0, 0, 0, 0.58),
|
||
0 0 1.5rem rgba(0, 212, 255, 0.08),
|
||
0 0 0 1px rgba(255, 255, 255, 0.025) inset;
|
||
backdrop-filter: blur(28px) saturate(1.3);
|
||
-webkit-backdrop-filter: blur(28px) saturate(1.3);
|
||
pointer-events: none;
|
||
transform: translateY(0.55rem) scale(0.985);
|
||
transform-origin: bottom left;
|
||
transition:
|
||
opacity 180ms ease,
|
||
visibility 180ms ease,
|
||
transform 220ms cubic-bezier(0.2, 0.8, 0.2, 1);
|
||
}
|
||
|
||
#command-dock #location-bar .dock-popover-content {
|
||
left: -0.75rem;
|
||
}
|
||
|
||
#command-dock #control-panel .dock-popover-content {
|
||
right: -0.75rem;
|
||
left: auto;
|
||
width: var(--dock-presets-open);
|
||
transform-origin: bottom right;
|
||
}
|
||
|
||
#command-dock #location-bar:not(.collapsed) .dock-popover-content,
|
||
#command-dock #control-panel:not(.collapsed) .dock-popover-content {
|
||
visibility: visible;
|
||
opacity: 1;
|
||
pointer-events: auto;
|
||
transform: translateY(0) scale(1);
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
#command-dock #location-bar.collapsed .dock-popover-content,
|
||
#command-dock #control-panel.collapsed .dock-popover-content {
|
||
display: flex !important;
|
||
}
|
||
|
||
#command-dock .dock-popover-content::after {
|
||
/* content: ''; */
|
||
position: absolute;
|
||
bottom: -0.34rem;
|
||
left: 1.65rem;
|
||
width: 0.6rem;
|
||
height: 0.6rem;
|
||
background: rgba(8, 20, 30, 0.96);
|
||
border-right: 1px solid rgba(123, 189, 211, 0.28);
|
||
border-bottom: 1px solid rgba(123, 189, 211, 0.28);
|
||
transform: rotate(45deg);
|
||
}
|
||
|
||
#command-dock #control-panel .dock-popover-content::after {
|
||
right: 1.65rem;
|
||
left: auto;
|
||
}
|
||
|
||
#command-dock .dock-popover-content .location-city-row,
|
||
#command-dock .dock-popover-content .button-grid {
|
||
display: flex !important;
|
||
}
|
||
|
||
#command-dock .dock-popover-content .poi-row-container:not(.expanded) {
|
||
display: none !important;
|
||
}
|
||
|
||
#command-dock .dock-pin-btn {
|
||
position: absolute;
|
||
top: 0.4rem;
|
||
right: 0.5rem;
|
||
z-index: 2;
|
||
display: none;
|
||
flex: 0 0 auto;
|
||
min-width: 1.65rem;
|
||
height: 1rem;
|
||
padding: 0 0.28rem;
|
||
color: rgba(190, 221, 230, 0.5);
|
||
background: rgba(255, 255, 255, 0.025);
|
||
border: 1px solid rgba(123, 189, 211, 0.2);
|
||
border-radius: 0.2rem;
|
||
font-family: var(--font-mono);
|
||
font-size: 0.35rem;
|
||
letter-spacing: 0.04rem;
|
||
cursor: pointer;
|
||
}
|
||
|
||
#command-dock #location-bar:not(.collapsed) .dock-pin-btn,
|
||
#command-dock #control-panel:not(.collapsed) .dock-pin-btn {
|
||
display: block;
|
||
}
|
||
|
||
#command-dock .dock-pin-btn:hover,
|
||
#command-dock .dock-pin-btn[aria-pressed='true'] {
|
||
color: var(--accent);
|
||
border-color: rgba(0, 212, 255, 0.62);
|
||
background: rgba(0, 212, 255, 0.1);
|
||
box-shadow: 0 0 0.55rem rgba(0, 212, 255, 0.12);
|
||
}
|
||
|
||
#command-dock .panel-divider {
|
||
min-width: 0.25rem;
|
||
}
|
||
|
||
@media (max-width: 900px) {
|
||
#command-dock:has(#location-bar:not(.collapsed)) > #control-panel,
|
||
#command-dock:has(#control-panel:not(.collapsed)) > #location-bar {
|
||
flex-basis: var(--dock-side-compact);
|
||
border: inherit;
|
||
}
|
||
|
||
#command-dock:has(#location-bar:not(.collapsed)) > #gev-voice-control,
|
||
#command-dock:has(#control-panel:not(.collapsed)) > #gev-voice-control {
|
||
flex-basis: var(--dock-voice-width);
|
||
width: var(--dock-voice-width);
|
||
}
|
||
|
||
#command-dock:has(#location-bar:not(.collapsed)) .gev-voice-visualizer,
|
||
#command-dock:has(#location-bar:not(.collapsed)) .gev-voice-kicker,
|
||
#command-dock:has(#location-bar:not(.collapsed)) .gev-voice-readout,
|
||
#command-dock:has(#control-panel:not(.collapsed)) .gev-voice-visualizer,
|
||
#command-dock:has(#control-panel:not(.collapsed)) .gev-voice-kicker,
|
||
#command-dock:has(#control-panel:not(.collapsed)) .gev-voice-readout {
|
||
visibility: visible;
|
||
}
|
||
|
||
#command-dock .dock-popover-content {
|
||
width: var(--dock-popover-mobile-width);
|
||
}
|
||
|
||
#command-dock #location-bar .dock-popover-content {
|
||
left: calc((var(--dock-side-compact) + var(--dock-side-compact) + var(--dock-voice-width) - var(--dock-popover-mobile-width)) / 2);
|
||
}
|
||
|
||
#command-dock #control-panel .dock-popover-content {
|
||
/* NOT a duplicate of the `#command-dock .dock-popover-content` width above:
|
||
that selector is (1 id, 1 class) and loses to the unconditional
|
||
`#command-dock #control-panel .dock-popover-content { width:
|
||
var(--dock-presets-open) }`, which is 34rem here. Without this override
|
||
the tray renders 544 px wide inside a 480 px viewport and hangs off the
|
||
left edge — pinned by the 480 px bounds assert in
|
||
`scripts/qa-map-source-tray.mjs`. */
|
||
width: var(--dock-popover-mobile-width);
|
||
right: calc((var(--dock-side-compact) + var(--dock-side-compact) + var(--dock-voice-width) - var(--dock-popover-mobile-width)) / 2);
|
||
}
|
||
|
||
/* ── Required-attribution clearance ─────────────────────────────────
|
||
At this width the tray widens to nearly the whole viewport (the rule
|
||
above), and at its stock 0.65rem offset it lands squarely on the
|
||
Google/Cesium credit line in the bottom-left corner — a notice the
|
||
Maps Platform and Cesium terms require to stay visible in EVERY state.
|
||
|
||
The transient popover yields, not the permanent notice: the credit
|
||
keeps the position every other state gives it.
|
||
|
||
The tray hangs off the dock, so its clearance is
|
||
dock bottom + dock height 62px + offset − (credit bottom + 28px).
|
||
Across 721–900px the dock is anchored at 2vh and the credit at
|
||
calc(2vh + 5rem), so those terms cancel and 3rem + the tray's own 10px
|
||
margin leaves a flat 12px. That cancellation is NOT universal: at 720px
|
||
and below the dock re-anchors to a flat 8px while the credit keeps its
|
||
2vh base, which is what the max-width:720px override further down
|
||
repairs. Nothing here may be reasoned about "at every viewport height"
|
||
without checking the dock anchor that actually applies.
|
||
|
||
Keep these in step with the base offsets (0.65rem, and 1.2rem for the
|
||
pinned variants); src/creditAttribution.test.mjs walks the real cascade
|
||
over a viewport grid and fails if any of them re-enters the credit
|
||
band. */
|
||
#command-dock #location-bar .dock-popover-content,
|
||
#command-dock #control-panel .dock-popover-content {
|
||
bottom: calc(100% + 3rem);
|
||
}
|
||
|
||
#command-dock.dock-has-pinned-tray #location-bar:not(.collapsed):not(.dock-pinned) .dock-popover-content,
|
||
#command-dock.dock-has-pinned-tray #control-panel:not(.collapsed):not(.dock-pinned) .dock-popover-content {
|
||
bottom: calc(100% + 3rem + var(--dock-pinned-stack-height));
|
||
}
|
||
|
||
/* Written with the panel IDs on purpose. The stock two-pinned selector
|
||
carries one ID (#command-dock) against five classes, and the ordinary
|
||
narrow rule above carries two IDs — so the stock form LOSES here and the
|
||
top tray drops var(--dock-lower-pinned-height), landing on top of its
|
||
pinned sibling. Naming the panel makes it (2,5,0), ahead of both the
|
||
ordinary (2,1,0) and single-pinned (2,4,0) rules. */
|
||
#command-dock.dock-has-two-pinned-trays #location-bar.dock-pinned-top.dock-pinned:not(.collapsed) .dock-popover-content,
|
||
#command-dock.dock-has-two-pinned-trays #control-panel.dock-pinned-top.dock-pinned:not(.collapsed) .dock-popover-content {
|
||
bottom: calc(100% + 3rem + var(--dock-lower-pinned-height));
|
||
}
|
||
}
|
||
|
||
/* The dock re-anchors from 2vh to a flat 8px at this width (see the
|
||
max-width:720px block above), while the credit keeps its 2vh base — so the
|
||
clearance above stops being height-independent and goes negative on tall
|
||
narrow viewports (0 at 1000px high, −4px at 1200px). Carrying the 2vh back
|
||
into the tray's own offset restores the same flat 12px the wider band gets.
|
||
This block must stay AFTER the max-width:900px rules to win the cascade. */
|
||
@media (max-width: 720px) {
|
||
#command-dock #location-bar .dock-popover-content,
|
||
#command-dock #control-panel .dock-popover-content {
|
||
bottom: calc(100% + 2vh + 2.5rem);
|
||
}
|
||
|
||
#command-dock.dock-has-pinned-tray #location-bar:not(.collapsed):not(.dock-pinned) .dock-popover-content,
|
||
#command-dock.dock-has-pinned-tray #control-panel:not(.collapsed):not(.dock-pinned) .dock-popover-content {
|
||
bottom: calc(100% + 2vh + 2.5rem + var(--dock-pinned-stack-height));
|
||
}
|
||
|
||
/* Panel IDs for the same specificity reason as the max-width:900px block. */
|
||
#command-dock.dock-has-two-pinned-trays #location-bar.dock-pinned-top.dock-pinned:not(.collapsed) .dock-popover-content,
|
||
#command-dock.dock-has-two-pinned-trays #control-panel.dock-pinned-top.dock-pinned:not(.collapsed) .dock-popover-content {
|
||
bottom: calc(100% + 2vh + 2.5rem + var(--dock-lower-pinned-height));
|
||
}
|
||
}
|
||
|
||
/* Final top-right positioning for the floating SVG tray pins. */
|
||
#command-dock .dock-popover-content {
|
||
padding: 0.7rem;
|
||
}
|
||
|
||
#command-dock .dock-popover-content .button-grid {
|
||
align-items: stretch;
|
||
min-height: 3.7rem;
|
||
}
|
||
|
||
#command-dock .dock-popover-content .style-btn {
|
||
flex: 1 1 0;
|
||
min-width: 3.6rem;
|
||
min-height: 3.7rem;
|
||
height: 100%;
|
||
padding: 0.45rem 0.3rem;
|
||
}
|
||
|
||
#command-dock .dock-popover-content .btn-icon {
|
||
font-size: 1.15rem;
|
||
line-height: 1;
|
||
}
|
||
|
||
#command-dock .btn-label {
|
||
padding-top: 10px;
|
||
}
|
||
|
||
#command-dock .dock-pin-btn {
|
||
position: absolute;
|
||
top: -1rem;
|
||
right: -1rem;
|
||
z-index: 2;
|
||
place-items: center;
|
||
width: 2.05rem;
|
||
min-width: 2.05rem;
|
||
height: 2.05rem;
|
||
margin: 0;
|
||
padding: 0;
|
||
border-radius: 50%;
|
||
background: rgba(8, 24, 34, 0.96);
|
||
box-shadow: 0 0.35rem 0.9rem rgba(0, 0, 0, 0.5);
|
||
transform: none;
|
||
}
|
||
|
||
#command-dock #location-bar .dock-pin-btn {
|
||
top: -1rem;
|
||
right: -1rem;
|
||
}
|
||
|
||
#command-dock #control-panel .dock-pin-btn {
|
||
top: -1rem;
|
||
right: -1rem;
|
||
}
|
||
|
||
#command-dock #location-bar:not(.collapsed) .dock-pin-btn,
|
||
#command-dock #control-panel:not(.collapsed) .dock-pin-btn {
|
||
display: grid;
|
||
}
|
||
|
||
#command-dock .dock-pin-btn img {
|
||
width: 1.15rem;
|
||
height: 1.15rem;
|
||
}
|
||
|
||
/* Five-pixel standby baseline; live microphone analysis sets --audio-level. */
|
||
#command-dock .gev-voice-visualizer span,
|
||
#command-dock .gev-voice-visualizer span:nth-child(3n),
|
||
#command-dock .gev-voice-visualizer span:nth-child(4n),
|
||
#command-dock .gev-voice-visualizer span:nth-child(5n),
|
||
#command-dock .gev-voice-visualizer span:nth-child(7n) {
|
||
height: var(--audio-level, 5px);
|
||
opacity: var(--audio-opacity, 0.56);
|
||
animation: none;
|
||
transition: height 70ms linear, opacity 90ms linear;
|
||
}
|
||
|
||
#command-dock #gev-voice-control[data-status='listening'] .gev-voice-visualizer span,
|
||
#command-dock #gev-voice-control[data-status='executing'] .gev-voice-visualizer span {
|
||
animation: none;
|
||
}
|
||
|
||
#command-dock #gev-voice-control[data-speaker='user'] :is(#gev-voice-status, #gev-voice-detail) {
|
||
color: #ffbf69;
|
||
}
|
||
|
||
#command-dock #gev-voice-control[data-speaker='user'] .gev-voice-visualizer span {
|
||
background: linear-gradient(to top, #d98a35, #ffcf8a);
|
||
box-shadow: 0 0 0.35rem rgba(255, 191, 105, 0.32);
|
||
}
|
||
|
||
#command-dock #gev-voice-control[data-speaker='ai'] :is(#gev-voice-status, #gev-voice-detail) {
|
||
color: var(--accent);
|
||
}
|
||
|
||
#command-dock #gev-voice-control[data-speaker='ai'] .gev-voice-visualizer span {
|
||
background: linear-gradient(to top, #28b9db, #71eaff);
|
||
box-shadow: 0 0 0.35rem rgba(54, 220, 255, 0.28);
|
||
}
|
||
|
||
/* Center every slide-up tray on the complete unified dock, not its side wing. */
|
||
#command-dock #location-bar .dock-popover-content {
|
||
left: calc((var(--dock-unified-width) - var(--dock-location-open)) / 2);
|
||
}
|
||
|
||
#command-dock #control-panel .dock-popover-content {
|
||
right: calc((var(--dock-unified-width) - var(--dock-presets-open)) / 2);
|
||
}
|
||
|
||
@media (max-width: 900px) {
|
||
#command-dock #location-bar .dock-popover-content {
|
||
left: calc((var(--dock-unified-width) - var(--dock-popover-mobile-width)) / 2);
|
||
}
|
||
|
||
#command-dock #control-panel .dock-popover-content {
|
||
right: calc((var(--dock-unified-width) - var(--dock-popover-mobile-width)) / 2);
|
||
}
|
||
}
|
||
|
||
/* Final joined-dock geometry: only the three controls own visible surfaces. */
|
||
#command-dock {
|
||
padding: 0;
|
||
background: none;
|
||
border: none;
|
||
box-shadow: none;
|
||
backdrop-filter: none;
|
||
-webkit-backdrop-filter: none;
|
||
}
|
||
|
||
#command-dock > #location-bar {
|
||
border-top-right-radius: 0;
|
||
border-bottom-right-radius: 0;
|
||
}
|
||
|
||
#command-dock > #location-bar > .location-inner {
|
||
border-top-right-radius: 0;
|
||
border-bottom-right-radius: 0;
|
||
}
|
||
|
||
#command-dock > #control-panel {
|
||
border-top-left-radius: 0;
|
||
border-bottom-left-radius: 0;
|
||
}
|
||
|
||
#command-dock > #control-panel > .panel-inner {
|
||
border-top-left-radius: 0;
|
||
border-bottom-left-radius: 0;
|
||
}
|
||
|
||
#command-dock .dock-popover-content .style-btn:hover {
|
||
transform: none;
|
||
}
|
||
|
||
#command-dock .dock-popover-content :is(.location-pill, .poi-pill):hover {
|
||
transform: none;
|
||
}
|
||
|
||
/* Keep the microphone neutral at rest; cyan signals hover and live states. */
|
||
#command-dock .gev-mic-orbit {
|
||
background: rgba(232, 234, 237, 0.04);
|
||
border-color: rgba(232, 234, 237, 0.36);
|
||
box-shadow:
|
||
0 0 0 0.18rem rgba(232, 234, 237, 0.04),
|
||
0 0 0.75rem rgba(232, 234, 237, 0.08);
|
||
transition: background var(--transition-fast), border-color var(--transition-fast), box-shadow var(--transition-fast);
|
||
}
|
||
|
||
#command-dock .gev-mic-orbit img {
|
||
filter: grayscale(1) saturate(0) brightness(1.65);
|
||
opacity: 0.68;
|
||
transition: filter var(--transition-fast), opacity var(--transition-fast);
|
||
}
|
||
|
||
#command-dock #gev-voice-button:hover .gev-mic-orbit,
|
||
#command-dock #gev-voice-control:is(
|
||
[data-status='connecting'],
|
||
[data-status='listening']:not([data-microphone='muted']),
|
||
[data-status='executing']
|
||
) .gev-mic-orbit {
|
||
background: rgba(0, 212, 255, 0.06);
|
||
border-color: rgba(0, 212, 255, 0.48);
|
||
box-shadow: 0 0 0 0.18rem rgba(0, 212, 255, 0.06), 0 0 0.9rem rgba(0, 212, 255, 0.12);
|
||
}
|
||
|
||
#command-dock #gev-voice-button:hover .gev-mic-orbit img,
|
||
#command-dock #gev-voice-control:is(
|
||
[data-status='connecting'],
|
||
[data-status='listening']:not([data-microphone='muted']),
|
||
[data-status='executing']
|
||
) .gev-mic-orbit img {
|
||
filter: none;
|
||
opacity: 1;
|
||
}
|
||
|
||
/* Match compact dock wings to the glass treatment used by left-panel buttons. */
|
||
#command-dock > #location-bar,
|
||
#command-dock > #control-panel {
|
||
box-sizing: border-box;
|
||
background: var(--glass-bg);
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: var(--panel-radius);
|
||
box-shadow:
|
||
0 8px 32px rgba(0, 0, 0, 0.5),
|
||
0 0 0 1px rgba(255, 255, 255, 0.03) inset,
|
||
0 1px 0 rgba(255, 255, 255, 0.06) inset;
|
||
backdrop-filter: blur(24px) saturate(1.4);
|
||
-webkit-backdrop-filter: blur(24px) saturate(1.4);
|
||
transition:
|
||
border-color 160ms ease,
|
||
background-color 160ms ease,
|
||
box-shadow 160ms ease;
|
||
}
|
||
|
||
#command-dock > :is(#location-bar, #control-panel):hover {
|
||
background: var(--glass-bg);
|
||
border-color: var(--glass-border-hover);
|
||
color: var(--accent);
|
||
|
||
}
|
||
|
||
#command-dock > :is(#location-bar, #control-panel).dock-pinned {
|
||
border-color: rgba(0, 212, 255, 0.55);
|
||
box-shadow:
|
||
0 8px 32px rgba(0, 0, 0, 0.5),
|
||
0 0 0 1px rgba(0, 212, 255, 0.08) inset,
|
||
0 0 1rem rgba(0, 212, 255, 0.12);
|
||
}
|
||
|
||
#command-dock #location-bar .location-toolbar {
|
||
justify-content: flex-start;
|
||
width: 100%;
|
||
}
|
||
|
||
#command-dock #location-bar .location-toolbar-label {
|
||
justify-content: flex-start;
|
||
width: 100%;
|
||
text-align: left;
|
||
}
|
||
|
||
#command-dock #location-bar .location-toolbar-label::after {
|
||
content: none;
|
||
}
|
||
|
||
#command-dock #control-panel .panel-header {
|
||
justify-content: flex-end;
|
||
width: 100%;
|
||
}
|
||
|
||
#command-dock #control-panel .panel-title {
|
||
justify-content: flex-end;
|
||
width: 100%;
|
||
text-align: right;
|
||
}
|
||
|
||
/* These must follow the shared wing skin so the visible borders stay joined. */
|
||
#command-dock > #location-bar {
|
||
border-top-right-radius: 0;
|
||
border-bottom-right-radius: 0;
|
||
}
|
||
|
||
#command-dock > #control-panel {
|
||
border-top-left-radius: 0;
|
||
border-bottom-left-radius: 0;
|
||
}
|
||
|
||
#command-dock #location-bar .location-toolbar,
|
||
#command-dock #control-panel .panel-header {
|
||
position: relative;
|
||
}
|
||
|
||
#command-dock #control-panel .panel-header {
|
||
flex-direction: row;
|
||
gap: 0;
|
||
}
|
||
|
||
#command-dock #control-panel .panel-title {
|
||
flex: 0 0 auto;
|
||
width: auto;
|
||
}
|
||
|
||
#command-dock #control-panel .panel-title::before {
|
||
content: none;
|
||
}
|
||
|
||
#command-dock #control-panel .panel-divider {
|
||
display: none;
|
||
}
|
||
|
||
#gev-voice-control .gev-voice-help-tray {
|
||
position: absolute;
|
||
bottom: calc(100% + 0.7rem);
|
||
left: 50%;
|
||
z-index: 7;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
gap: 0.22rem;
|
||
box-sizing: border-box;
|
||
width: max-content;
|
||
max-width: min(22rem, calc(100vw - 2rem));
|
||
padding: 0.62rem 0.72rem;
|
||
visibility: hidden;
|
||
opacity: 0;
|
||
color: rgba(223, 245, 250, 0.92);
|
||
background: rgba(7, 22, 31, 0.96);
|
||
border: 1px solid rgba(54, 220, 255, 0.34);
|
||
border-radius: 0.38rem;
|
||
box-shadow:
|
||
0 0.85rem 2rem rgba(0, 0, 0, 0.58),
|
||
0 0 1.2rem rgba(0, 212, 255, 0.08);
|
||
backdrop-filter: blur(24px) saturate(1.3);
|
||
-webkit-backdrop-filter: blur(24px) saturate(1.3);
|
||
pointer-events: none;
|
||
transform: translate(-50%, 0.65rem) scale(0.985);
|
||
transform-origin: bottom center;
|
||
transition:
|
||
opacity 160ms ease,
|
||
visibility 160ms ease,
|
||
transform 210ms cubic-bezier(0.2, 0.8, 0.2, 1);
|
||
}
|
||
|
||
#gev-voice-control .gev-voice-help-kicker {
|
||
color: rgba(54, 220, 255, 0.72);
|
||
font-family: var(--font-mono);
|
||
font-size: 0.46rem;
|
||
font-weight: 600;
|
||
letter-spacing: 0.1rem;
|
||
}
|
||
|
||
#gev-voice-control .gev-voice-help-detail {
|
||
font-family: var(--font-sans);
|
||
font-size: 0.7rem;
|
||
line-height: 1.35;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
#gev-voice-control:not([data-status='error']):hover .gev-voice-help-tray,
|
||
#gev-voice-control:not([data-status='error']) #gev-voice-button:focus-visible ~ .gev-voice-help-tray {
|
||
visibility: visible;
|
||
opacity: 1;
|
||
transform: translate(-50%, 0) scale(1);
|
||
}
|
||
|
||
#command-dock.dock-has-pinned-tray .gev-voice-help-tray {
|
||
bottom: calc(100% + 1.7rem + var(--dock-pinned-stack-height));
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
#gev-voice-control .gev-voice-help-tray {
|
||
transition: none;
|
||
}
|
||
.radio-tuner-needle,
|
||
.radio-tuner-tick {
|
||
transition: none;
|
||
}
|
||
}
|
||
|
||
#command-dock #location-bar .location-toolbar::after,
|
||
#command-dock #control-panel .panel-header::after {
|
||
content: '';
|
||
position: absolute;
|
||
right: 0.45rem;
|
||
bottom: 0.12rem;
|
||
left: 0.45rem;
|
||
height: 1px;
|
||
pointer-events: none;
|
||
}
|
||
|
||
#command-dock #location-bar .location-toolbar::after {
|
||
background: linear-gradient(90deg, rgba(232, 234, 237, 0.24), rgba(232, 234, 237, 0));
|
||
}
|
||
|
||
#command-dock #control-panel .panel-header::after {
|
||
background: linear-gradient(90deg, rgba(232, 234, 237, 0), rgba(232, 234, 237, 0.24));
|
||
}
|
||
|
||
/* ------------------------------------------------------------------ *
|
||
* Voice cost control — model-tier toggle + running session estimate.
|
||
* Appended (not woven into the dock passes above) so the three existing
|
||
* #gev-voice-control cascades stay untouched; these rules only add the
|
||
* new .gev-voice-cost cluster inside the existing .gev-voice-heading row.
|
||
* ------------------------------------------------------------------ */
|
||
.gev-voice-cost {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.22rem;
|
||
margin-left: auto; /* pin right; kicker + status keep their left cluster */
|
||
flex: 0 0 auto;
|
||
}
|
||
|
||
.gev-voice-tier-btn {
|
||
padding: 0 0.24rem;
|
||
height: 0.72rem;
|
||
min-width: 1.55rem;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: rgba(0, 212, 255, 0.06);
|
||
border: 1px solid rgba(0, 212, 255, 0.34);
|
||
border-radius: 0.18rem;
|
||
color: var(--text-secondary);
|
||
font-family: var(--font-mono);
|
||
font-size: 0.4rem;
|
||
letter-spacing: 0.045rem;
|
||
line-height: 1;
|
||
cursor: pointer;
|
||
transition: color var(--transition-fast), border-color var(--transition-fast),
|
||
background var(--transition-fast);
|
||
}
|
||
|
||
.gev-voice-tier-btn:hover {
|
||
color: var(--text-primary);
|
||
border-color: rgba(0, 212, 255, 0.6);
|
||
background: rgba(0, 212, 255, 0.12);
|
||
}
|
||
|
||
/* MINI engaged — amber, distinct from the cyan default so the cheaper tier
|
||
is legible at a glance without reading the label. */
|
||
.gev-voice-tier-btn[aria-pressed='true'] {
|
||
color: #ffc46b;
|
||
border-color: rgba(255, 196, 107, 0.55);
|
||
background: rgba(255, 196, 107, 0.12);
|
||
}
|
||
|
||
.gev-voice-cost-value {
|
||
color: var(--text-dim);
|
||
font-family: var(--font-mono);
|
||
font-size: 0.4rem;
|
||
letter-spacing: 0.02rem;
|
||
line-height: 1;
|
||
font-variant-numeric: tabular-nums;
|
||
transition: color var(--transition-fast);
|
||
}
|
||
|
||
.gev-voice-cost-value[data-level='warn'] {
|
||
color: #ffc46b;
|
||
}
|
||
|
||
.gev-voice-cost-value[data-level='cap'] {
|
||
color: #ff6b6b;
|
||
font-weight: 600;
|
||
}
|
||
|
||
/* The dock heading row is 0.8rem tall; keep the cluster inside it. */
|
||
#command-dock .gev-voice-cost {
|
||
max-height: 0.8rem;
|
||
}
|
||
|
||
/* The dock collapses the kicker/readout when a tray is open — the cost
|
||
cluster follows the same rule so the row never overflows. */
|
||
#command-dock.tray-open .gev-voice-cost {
|
||
display: none;
|
||
}
|
||
|
||
/* ── First-run mission launcher ───────────────────────────────────
|
||
Compact and non-modal: it gives a new visitor a meaningful starting
|
||
choice without blocking manual map interaction or spending API quota. */
|
||
#first-run-launcher {
|
||
position: fixed;
|
||
z-index: 175;
|
||
top: 50%;
|
||
left: 50%;
|
||
width: min(34rem, calc(100vw - 2rem));
|
||
/* Five tiles do not fit a short landscape phone (667 x 390), where the card
|
||
would otherwise render past BOTH ends of the viewport. Cap it to the
|
||
viewport and let the mission list scroll inside — the heading, the checkbox
|
||
and the status line must stay reachable at every height. */
|
||
max-height: calc(100vh - 1.5rem);
|
||
max-height: calc(100dvh - 1.5rem);
|
||
display: flex;
|
||
flex-direction: column;
|
||
padding: 1.15rem;
|
||
overflow: hidden;
|
||
color: var(--text-primary);
|
||
background:
|
||
linear-gradient(145deg, rgba(10, 27, 37, 0.97), rgba(7, 13, 22, 0.95)),
|
||
rgba(7, 17, 25, 0.96);
|
||
border: 1px solid rgba(54, 220, 255, 0.42);
|
||
border-radius: 0.65rem;
|
||
box-shadow:
|
||
0 1.4rem 4.5rem rgba(0, 0, 0, 0.72),
|
||
0 0 2.5rem rgba(0, 212, 255, 0.09),
|
||
inset 0 0 0 1px rgba(255, 255, 255, 0.025);
|
||
backdrop-filter: blur(28px) saturate(1.25);
|
||
-webkit-backdrop-filter: blur(28px) saturate(1.25);
|
||
opacity: 0;
|
||
transform: translate(-50%, calc(-50% + 0.8rem)) scale(0.985);
|
||
transition: opacity 220ms ease, transform 280ms cubic-bezier(0.2, 0.8, 0.2, 1);
|
||
/* Inert until revealed AND again while fading out, so a click during the
|
||
dismiss animation cannot launch a second mission behind the fade. */
|
||
pointer-events: none;
|
||
}
|
||
|
||
/* An AUTHOR `display` on this id beats the UA's `[hidden] { display: none }` in
|
||
the cascade, so the flex above would otherwise leave the card in the
|
||
accessibility tree from page parse until it is revealed — or, on a share
|
||
link, until it is removed. Restore the attribute's meaning explicitly. */
|
||
#first-run-launcher[hidden] {
|
||
display: none;
|
||
}
|
||
|
||
#first-run-launcher.visible {
|
||
opacity: 1;
|
||
transform: translate(-50%, -50%) scale(1);
|
||
pointer-events: auto;
|
||
}
|
||
|
||
.first-run-scanline {
|
||
position: absolute;
|
||
inset: 0 0 auto;
|
||
height: 2px;
|
||
background: linear-gradient(90deg, transparent, rgba(54, 220, 255, 0.8), transparent);
|
||
box-shadow: 0 0 1rem rgba(54, 220, 255, 0.45);
|
||
pointer-events: none;
|
||
}
|
||
|
||
.first-run-header,
|
||
.first-run-footer {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 1rem;
|
||
color: rgba(171, 210, 220, 0.6);
|
||
font-family: var(--font-mono);
|
||
font-size: 0.58rem;
|
||
letter-spacing: 0.1rem;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.first-run-kicker { color: rgba(54, 220, 255, 0.86); }
|
||
|
||
#first-run-launcher h2 {
|
||
margin-top: 0.6rem;
|
||
font-family: var(--font-mono);
|
||
font-size: clamp(1.25rem, 2.4vw, 1.75rem);
|
||
font-weight: 500;
|
||
letter-spacing: -0.045rem;
|
||
}
|
||
|
||
#first-run-description {
|
||
max-width: 29rem;
|
||
margin-top: 0.3rem;
|
||
color: rgba(215, 231, 235, 0.66);
|
||
font-size: 0.78rem;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.first-run-choices {
|
||
display: grid;
|
||
gap: 0.42rem;
|
||
margin-top: 1rem;
|
||
/* The one part of the card allowed to scroll when the viewport is too short.
|
||
min-height:0 is what actually lets this flex child shrink below its content. */
|
||
min-height: 0;
|
||
overflow-y: auto;
|
||
overscroll-behavior: contain;
|
||
scroll-behavior: smooth;
|
||
/* A visible, non-overlaying affordance that the list continues. */
|
||
scrollbar-width: thin;
|
||
scrollbar-color: rgba(54, 220, 255, 0.45) transparent;
|
||
scrollbar-gutter: stable;
|
||
}
|
||
|
||
.first-run-choices::-webkit-scrollbar { width: 6px; }
|
||
.first-run-choices::-webkit-scrollbar-thumb {
|
||
background: rgba(54, 220, 255, 0.45);
|
||
border-radius: 3px;
|
||
}
|
||
|
||
.first-run-choices button {
|
||
display: grid;
|
||
grid-template-columns: 1.7rem 1fr 1.3rem;
|
||
align-items: center;
|
||
gap: 0.7rem;
|
||
width: 100%;
|
||
min-height: 3.55rem;
|
||
padding: 0.6rem 0.7rem;
|
||
color: rgba(225, 244, 248, 0.92);
|
||
text-align: left;
|
||
background: rgba(29, 69, 81, 0.18);
|
||
border: 1px solid rgba(100, 200, 220, 0.18);
|
||
border-radius: 0.42rem;
|
||
cursor: pointer;
|
||
transition: background var(--transition-fast), border-color var(--transition-fast), transform var(--transition-fast);
|
||
}
|
||
|
||
.first-run-choices button:hover,
|
||
.first-run-choices button:focus-visible {
|
||
background: rgba(25, 151, 178, 0.16);
|
||
border-color: rgba(54, 220, 255, 0.62);
|
||
outline: none;
|
||
transform: translateX(2px);
|
||
}
|
||
|
||
/* aria-disabled, not :disabled — the JS keeps the buttons focusable while a
|
||
mission runs so the keyboard is never dumped out of the launcher mid-flight. */
|
||
.first-run-choices button[aria-disabled='true'] {
|
||
cursor: wait;
|
||
opacity: 0.48;
|
||
transform: none;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.first-run-choices button > .material-symbols-outlined:first-child {
|
||
color: #55dff5;
|
||
font-size: 1.35rem;
|
||
}
|
||
|
||
.first-run-choices button > span:nth-child(2) {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.15rem;
|
||
}
|
||
|
||
.first-run-choices strong {
|
||
font-family: var(--font-mono);
|
||
font-size: 0.72rem;
|
||
font-weight: 600;
|
||
letter-spacing: 0.08rem;
|
||
}
|
||
|
||
.first-run-choices small {
|
||
color: rgba(198, 220, 226, 0.55);
|
||
font-size: 0.66rem;
|
||
}
|
||
|
||
.first-run-arrow {
|
||
color: rgba(54, 220, 255, 0.4);
|
||
font-size: 1rem;
|
||
transition: transform var(--transition-fast), color var(--transition-fast);
|
||
}
|
||
|
||
.first-run-choices button:hover .first-run-arrow,
|
||
.first-run-choices button:focus-visible .first-run-arrow {
|
||
color: rgba(54, 220, 255, 0.9);
|
||
transform: translateX(2px);
|
||
}
|
||
|
||
/* Ordered after the shared button rule rather than shouting !important at it. */
|
||
.first-run-choices button.first-run-explore {
|
||
background: rgba(255, 255, 255, 0.025);
|
||
}
|
||
|
||
.first-run-footer {
|
||
margin-top: 0.85rem;
|
||
font-size: 0.48rem;
|
||
letter-spacing: 0.055rem;
|
||
}
|
||
|
||
.first-run-suppress {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.4rem;
|
||
color: rgba(199, 225, 231, 0.66);
|
||
text-transform: none;
|
||
font-size: 0.62rem;
|
||
letter-spacing: 0.02rem;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.first-run-suppress input {
|
||
width: 0.82rem;
|
||
height: 0.82rem;
|
||
margin: 0;
|
||
accent-color: #36dcff;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.first-run-suppress:hover { color: rgba(225, 244, 248, 0.92); }
|
||
|
||
/* The live region carries mission progress and failures, so it owns a full row
|
||
and reserves its height — otherwise the card resizes as it speaks. */
|
||
.first-run-note {
|
||
min-height: 1.1rem;
|
||
margin-top: 0.5rem;
|
||
color: rgba(199, 225, 231, 0.62);
|
||
font-family: var(--font-mono);
|
||
font-size: 0.62rem;
|
||
line-height: 1.35;
|
||
}
|
||
|
||
#first-run-launcher[data-state='loading'] .first-run-note {
|
||
color: rgba(54, 220, 255, 0.85);
|
||
}
|
||
|
||
/* Every surface that claims the screen hides the launcher. This list is the CSS
|
||
half of the ESC arbitration: src/firstRunExperience.js watches these same
|
||
classes and makes the launcher step aside, so a hidden card is never left
|
||
holding a keyboard handler. Keep the two lists in step —
|
||
EXCLUSIVE_SURFACE_CLASSES pins them together. */
|
||
body.ui-clean-view #first-run-launcher,
|
||
body.recording-mode #first-run-launcher,
|
||
body.cockpit-mode #first-run-launcher,
|
||
body.scene-playback-mode #first-run-launcher {
|
||
display: none;
|
||
}
|
||
|
||
@media (max-width: 620px) {
|
||
#first-run-launcher {
|
||
top: auto;
|
||
bottom: 5.8rem;
|
||
padding: 0.9rem;
|
||
transform: translate(-50%, 0.8rem) scale(0.985);
|
||
}
|
||
|
||
#first-run-launcher.visible { transform: translate(-50%, 0) scale(1); }
|
||
/* Five tiles have to clear the dock on a 375 x 812 phone, so the rows tighten
|
||
and the redundant "ESC to dismiss" hint (no ESC key on a phone) drops. */
|
||
#first-run-launcher h2 { margin-top: 0.45rem; }
|
||
#first-run-description { margin-top: 0.25rem; font-size: 0.72rem; }
|
||
.first-run-choices { margin-top: 0.75rem; }
|
||
.first-run-choices button { min-height: 3rem; padding: 0.45rem 0.6rem; }
|
||
.first-run-choices small { font-size: 0.62rem; }
|
||
.first-run-footer > span:last-child { display: none; }
|
||
}
|
||
|
||
/* Short viewports — landscape phones, small laptop windows. The chrome tightens
|
||
so the mission list keeps a usable share of the height. The intro line STAYS:
|
||
it is the only copy that says what this thing is, and with four tiles it
|
||
fits. (It was dropped here while there were five; the tile that went is
|
||
exactly why it can come back.) */
|
||
@media (max-height: 620px) {
|
||
#first-run-launcher { padding: 0.75rem 0.85rem; }
|
||
#first-run-launcher h2 { margin-top: 0.3rem; font-size: 1.1rem; }
|
||
#first-run-description { margin-top: 0.2rem; font-size: 0.7rem; line-height: 1.4; }
|
||
.first-run-choices { margin-top: 0.55rem; }
|
||
.first-run-choices button { min-height: 2.7rem; padding: 0.36rem 0.6rem; }
|
||
.first-run-choices strong { font-size: 0.68rem; }
|
||
.first-run-choices small { font-size: 0.6rem; }
|
||
.first-run-footer { margin-top: 0.5rem; }
|
||
.first-run-note { margin-top: 0.3rem; min-height: 0; }
|
||
}
|
||
|
||
/* A soft edge on the list, so a tile cut by the fold reads as "more below"
|
||
rather than as a rendering seam. Gated on `data-scrollable`, which the JS sets
|
||
only when the list ACTUALLY overflows — a fade on a list that fits would
|
||
promise content that is not there, which is the opposite of the affordance
|
||
it is meant to be. Decorative only: the list scrolls under it. */
|
||
.first-run-choices[data-scrollable='true'] {
|
||
-webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 1.4rem), transparent 100%);
|
||
mask-image: linear-gradient(to bottom, #000 calc(100% - 1.4rem), transparent 100%);
|
||
}
|
||
|
||
/* Scrolled to the end, there is nothing left to promise, so the fade lifts.
|
||
Browsers without scroll-driven animations keep the static fade, which is
|
||
still honest — there IS more list, it is just above rather than below. */
|
||
@supports (animation-timeline: scroll(self block)) {
|
||
.first-run-choices[data-scrollable='true'] {
|
||
animation: first-run-scroll-fade linear both;
|
||
animation-timeline: scroll(self block);
|
||
animation-range: contain 80% contain 100%;
|
||
}
|
||
}
|
||
|
||
@keyframes first-run-scroll-fade {
|
||
to {
|
||
-webkit-mask-image: linear-gradient(to bottom, #000 100%, transparent 100%);
|
||
mask-image: linear-gradient(to bottom, #000 100%, transparent 100%);
|
||
}
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
#first-run-launcher,
|
||
.first-run-choices button,
|
||
.first-run-arrow { transition: none; }
|
||
/* Scrolling a tile into view must not animate either. */
|
||
.first-run-choices { scroll-behavior: auto; }
|
||
}
|
||
/* Source health is on demand; no extra polling or panel work while closed. */
|
||
#source-status-dialog {
|
||
margin: auto;
|
||
box-sizing: border-box;
|
||
width: min(680px, calc(100vw - 40px));
|
||
max-height: 80vh;
|
||
overflow: auto;
|
||
color: #d8f4f3;
|
||
background: #0b171f;
|
||
border: 1px solid #46777d;
|
||
border-radius: 14px;
|
||
padding: 24px;
|
||
font: 14px/1.5 system-ui, sans-serif;
|
||
}
|
||
#source-status-dialog::backdrop { background: #000b; }
|
||
#source-status-dialog h2 { font-size: 22px; margin: 0 0 12px; }
|
||
#source-status-dialog section { padding: 10px 0; border-bottom: 1px solid #29414b; }
|
||
#source-status-dialog p { margin: 6px 0 14px; color: #b5ced3; }
|
||
#source-status-dialog section p { margin: 4px 0 0; font-size: 12px; }
|
||
#source-status-dialog a { color: #86e5e8; }
|
||
#source-status-dialog button { padding: 8px 14px; margin: 0 8px 10px 0; border: 1px solid #568d97; border-radius: 6px; color: #e1ffff; background: #163b46; cursor: pointer; }
|
||
#source-status-dialog button:disabled { opacity: .55; cursor: wait; }
|
||
#camera-browser-dialog h2 { margin: 0 0 12px; font-size: 24px; }
|
||
#camera-browser-dialog p { margin: 12px 0; line-height: 1.5; }
|
||
#camera-browser-dialog button, #camera-browser-dialog select {
|
||
font: inherit; color: #e1edf2; background: #19323e;
|
||
border: 1px solid #547783; border-radius: 6px; padding: 8px 12px;
|
||
margin: 4px 8px 4px 0;
|
||
}
|
||
#camera-browser-dialog button { cursor: pointer; }
|
||
#camera-browser-dialog button:disabled { opacity: .5; cursor: default; }
|
||
#camera-browser-dialog::backdrop { background: rgba(0,0,0,.55); }
|
||
#live-views-panel { position:fixed;z-index:10000;right:16px;top:85px;width:min(390px,90vw);max-height:78vh;overflow:auto;padding:20px;background:#0b1922;color:#e1edf2;border:1px solid #547783;border-radius:12px;font:14px/1.5 sans-serif; }
|
||
#live-views-panel h2 { font-size:22px;margin:0 0 12px; }
|
||
#live-views-panel button,#live-views-panel select,#live-views-panel input { color:#e1edf2;background:#19323e;border:1px solid #547783;border-radius:6px;padding:8px;margin:4px;max-width:100%;font:inherit; }
|
||
#live-views-panel button { cursor:pointer; }
|
||
#live-views-panel section { border-top:1px solid #34505c;padding:8px 0; }
|
||
#live-views-panel p { margin:8px 0; }
|
||
|
||
#live-views-panel fieldset { border:1px solid #39526e; border-radius:10px; margin:12px 0; padding:12px; background:#101c30; }
|
||
#live-views-panel fieldset legend { color:#8fd9ff; font-weight:600; }
|
||
#live-views-panel fieldset label { display:flex; align-items:center; gap:8px; }
|
||
#live-views-panel fieldset input[type=checkbox] { width:auto; }
|
||
#live-views-panel fieldset input[type=range] { width:100%; }
|
||
#live-views-panel a { color:#8fd9ff; }
|
||
#live-views-panel > div > section { border:1px solid #2e4158; border-radius:9px; padding:10px; margin:8px 0; background:#101a28; }
|
||
#live-views-panel [hidden] { display:none!important; }
|