Files
gods-eye-view/src/ui/styles/controls.css
T
Said Turksever 8543b7be43 Keep Directions reachable and tested in the Utilities panel
Voice show_data_layers_menu opens the panel that holds the row, so asking
for Directions opens UTILITIES and reports that panel, not a hidden row
under Data Layers. In Cockpit the panel stays with Directions alone, as
Data Layers does; only Draw and Import step aside there.

Draw's options sit flat under its name instead of keeping the card that
hung under a DISPLAY button, and its Shape label no longer takes DISPLAY's
label column in other languages. Cyber marks Draw on with its red edge.

LayerPanel routing, the voice panel choice, and the panel's order, mode
and phone-sheet CSS gain tests that fail on the earlier code. The form-field
and segmented-control gates open Utilities for Draw's controls, measuring
Scenes and Utilities in turn since the left rail fits one tall panel.
README, CONTRIBUTING, the PR template, CURRENT-STATE and comments now say
UTILITIES for Draw and Import and list the Audio group, and two files
outside the format scope lose an unrelated reflow.
2026-10-29 11:53:15 +00:00

1131 lines
25 KiB
CSS

/* ── 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-title {
font-family: var(--font-mono);
font-size: 9px;
letter-spacing: 3px;
color: var(--text-dim);
text-transform: uppercase;
white-space: nowrap;
}
/* A longer translated title in a collapsed rail launcher tightens its
tracking rather than pushing the disclosure button out of the card. */
html:not([lang='en'])
#right-context-rail
.panel-collapsible.collapsed
.panel-title {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
letter-spacing: 1.5px;
}
.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:
background-color var(--transition-fast),
border-color var(--transition-fast),
color var(--transition-fast);
}
/* A long translated title must not squeeze the toggle into a sliver. */
html:not([lang='en']) .panel-collapse-btn {
flex-shrink: 0;
}
.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;
/* Keep the keyboard focus outline immediate. */
transition:
background-color var(--transition-fast),
border-color var(--transition-fast),
box-shadow var(--transition-fast),
color var(--transition-fast),
transform var(--transition-fast);
overflow: hidden;
outline: none;
}
/* Keep keyboard focus visible inside the scrolling preset row. */
.style-btn:focus-visible {
outline: 2px solid var(--text-primary);
outline-offset: -3px;
}
.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:
color var(--transition-fast),
text-shadow 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-panel-body > .pp-toggle-group,
#pp-toggles:not(.collapsed) > .pp-panel-body > #clean-view-toggle {
width: 100%;
}
.pp-panel-body,
.cyber-panel-body {
display: contents;
}
.panel-collapsible.collapsed > .global-context-panel-inner > .cyber-panel-body {
display: none;
}
.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:
background-color var(--transition-fast),
border-color var(--transition-fast),
box-shadow var(--transition-fast),
color var(--transition-fast),
border-radius 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);
}
.pp-scope-toggle input {
width: 14px;
height: 14px;
margin: 0 0 0 auto;
accent-color: var(--accent);
cursor: pointer;
}
.pp-scope-toggle:has(input:checked) .pp-label {
color: var(--accent);
}
.pp-scope-toggle:has(input:focus-visible) {
outline: 1px solid var(--accent);
outline-offset: 2px;
}
#scope-slider-row:has(input:disabled) {
opacity: 0.45;
}
/* ── 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-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;
min-width: 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;
}
/* One label column across the Display rows: --pp-label-chars is the longest
label of the active language (set in applicationShell.js); the labels are
monospace. 0.125em is the 1px letter-spacing at 8px. */
html:not([lang='en']) .pp-slider-row > .pp-slider-mini-label {
flex: 0 0 auto;
min-width: calc(var(--pp-label-chars, 0) * (1ch + 0.125em));
}
.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;
}
#hud-layout-row {
min-width: 200px;
}
.cyber-sonar-control {
display: none;
}
:root[data-ui-theme='cyber'] .cyber-sonar-control {
display: flex;
}
.cyber-sonar-toggle-row,
.cyber-sonar-setting {
min-width: 200px;
}
.cyber-sonar-toggle-row .pp-mode-btn:not(.gev-segment) {
margin-left: auto;
min-width: 48px;
}
:root[data-cyber-sonar='off'] .cyber-sonar-setting {
display: none;
}
/* 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(5, 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(3, 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;
}
/* UTILITIES ▸ Draw: shape segment, label field, colour, and the one-line hint */
#draw-mode-row {
min-width: 184px;
}
#draw-label-row {
flex-wrap: wrap;
row-gap: 6px;
}
.pp-text-input {
flex: 1 1 110px;
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;
}
.pp-text-input:focus {
border-color: var(--accent);
}
.draw-color-select {
flex: 0 0 74px;
}
/* Sized to its longest colour name so a translated one is never clipped. */
html:not([lang='en']) .draw-color-select {
flex: 0 0 auto;
min-width: 74px;
}
.draw-clear-btn {
flex: 0 0 auto;
padding: 0 8px;
border: 1px solid rgba(255, 255, 255, 0.14);
border-radius: 6px;
}
.draw-hint {
flex-basis: 100%;
font-family: var(--font-mono);
font-size: 8px;
letter-spacing: 0.6px;
color: var(--text-dim);
line-height: 1.4;
}
body.gev-drawing #cesiumContainer canvas {
cursor: crosshair;
}
/* UTILITIES ▸ Import: one row per imported file, and the drop-target outline */
.geo-import-list {
display: none;
flex-direction: column;
gap: 4px;
margin: 6px 0 0;
padding: 0;
list-style: none;
}
.geo-import-list.visible {
display: flex;
}
.geo-import-row {
display: flex;
align-items: center;
gap: 6px;
min-width: 0;
}
.geo-import-swatch {
flex: 0 0 8px;
height: 8px;
border-radius: 2px;
}
/* KML/KMZ draw with the styles written in the file, so the swatch shows a
hatch instead of a color the globe does not use. */
.geo-import-swatch.own-styles {
background: repeating-linear-gradient(
45deg,
var(--text-dim) 0 1px,
transparent 1px 3px
);
box-shadow: inset 0 0 0 1px var(--text-dim);
}
.geo-import-name {
flex: 1 1 auto;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-family: var(--font-mono);
font-size: 10px;
letter-spacing: 0.6px;
color: var(--text-primary);
}
.geo-import-action {
flex: 0 0 auto;
display: inline-flex;
align-items: center;
justify-content: center;
width: 22px;
height: 22px;
padding: 0;
background: transparent;
border: 1px solid rgba(255, 255, 255, 0.14);
border-radius: 6px;
color: var(--text-dim);
cursor: pointer;
}
.geo-import-action:hover,
.geo-import-action:focus-visible {
color: var(--text-primary);
border-color: var(--accent);
}
.geo-import-action .material-symbols-outlined {
font-size: 14px;
}
.geo-import-hint:empty {
display: none;
}
body.gev-geo-import-drag #cesiumContainer {
outline: 2px dashed var(--accent);
outline-offset: -6px;
}
/* Proximity / All segmented control under the 3D toggle */
#models3d-mode-row {
min-width: 184px;
}
.pp-mode-seg {
display: flex;
flex: 1;
}
.pp-mode-btn:not(.gev-segment) {
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:
background-color var(--transition-fast),
color var(--transition-fast);
}
.pp-mode-btn:not(.gev-segment):hover {
background: rgba(255, 255, 255, 0.08);
color: var(--text-primary);
}
.pp-mode-btn:not(.gev-segment).active {
background: var(--accent);
color: #000;
}
/* These controls also move into Cockpit Display; keep focus on the control
itself and inside clipped button groups, independent of selection color. */
.pp-toggle-btn:focus-visible,
.pp-select:focus-visible,
.pp-mode-btn:focus-visible {
outline: 2px solid var(--text-primary);
outline-offset: -3px;
}
.pp-mode-btn:focus-visible {
box-shadow: inset 0 0 0 4px #061014;
}
#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 #utilities-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) > .pp-panel-body > #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;
}
/* One label column for every parameter, as wide as the longest translated
label, so all slider tracks start and end at the same x. */
html:not([lang='en']) #param-sliders {
display: grid;
grid-template-columns: max-content minmax(0, 1fr) max-content;
align-items: center;
gap: 10px;
}
html:not([lang='en']) .param-slider-row {
display: grid;
grid-column: 1 / -1;
grid-template-columns: subgrid;
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;
}