mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 10:53:59 +00:00
Merge Core main into german/hal-644-ar: Arabic on the Vue UI
Main moved the UI to Vue views and Pinia stores, so the Arabic changes to the old DOM controllers now live in their views: the rail legend range comes from formatScaleRange (keeping units a source supplies as given), the voice timeout options are worded by Intl unit formatting in VoiceControl, and the scene editor's JSON fields stay left to right in SceneDialog. Main's CCTV status line, launch panel and calibration values keep the Arabic isolates and Western-digit formatting. isolate() and keepCodesWithValues() read the locale through getLocale(), which follows the page's vue-i18n instance, and the Intl formatters take intlLocale(getLocale()). A language switch now applies in place, and applyDocumentLanguage sets <html dir> on every switch, so the page mirrors without a reload. The icon rails and their tips are placed with logical properties, so they stay on the outer side of the mirrored stacks; Cyber's new stack offsets, padding and edge lines are logical too, and rtl.css moves Cyber's right stack to its new rail clearance. Main removed the Context mini radio, so its right-to-left rules and test go. The Arabic catalog gains main's new strings and drops the ones main no longer uses; the other catalogs keep main's new keys and the branch's landing labels.
This commit is contained in:
commit
bc5d038afd
630 files changed
+41141
-20956
No files matched your search
@@ -0,0 +1,25 @@
|
||||
/* ── Screen-space annotations (src/annotations/screenAnnotationRenderer.js) ── */
|
||||
.gev-screen-whiteboard { position: fixed; inset: 0; pointer-events: none; z-index: 90; }
|
||||
.gev-screen-whiteboard-svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
|
||||
/* No CSS opacity transition here on purpose: group opacity is driven per-frame in JS
|
||||
(the 260ms fade-in via computeAlpha, and the tracked-entity z-order ease). A CSS
|
||||
transition fought those per-frame writes and made the tracked-fade opacity oscillate
|
||||
(flicker). Fade-OUT keeps its own transition via .gev-anno.gev-out below. */
|
||||
.gev-anno-ring { filter: drop-shadow(0 0 6px currentColor); }
|
||||
.gev-anno-dot { filter: drop-shadow(0 0 5px rgba(255,255,255,0.6)); }
|
||||
.gev-anno-area { filter: drop-shadow(0 0 5px currentColor); }
|
||||
.gev-anno-arrow { filter: drop-shadow(0 0 4px currentColor); stroke-linecap: round; }
|
||||
.gev-anno-leader { stroke-dasharray: 2 3; }
|
||||
.gev-anno-card { fill: rgba(8,18,28,0.78); stroke: rgba(255,255,255,0.14); stroke-width: 1; }
|
||||
.gev-anno-text { fill: #eaf6ff; font: 600 13px "JetBrains Mono", ui-monospace, monospace; letter-spacing: 0.02em; }
|
||||
/* draw-on: outlined shapes reveal their stroke */
|
||||
.gev-draw { stroke-dasharray: 1400; stroke-dashoffset: 1400; }
|
||||
.gev-anno.gev-in .gev-draw { transition: stroke-dashoffset 900ms ease-out; stroke-dashoffset: 0; }
|
||||
/* opacity-only fade-in: a CSS transform here would override the SVG transform
|
||||
attribute used to POSITION the callout and snap it to 0,0. */
|
||||
.gev-anno-callout { opacity: 0; }
|
||||
.gev-anno.gev-in .gev-anno-callout { animation: gev-pop 320ms ease-out both; }
|
||||
.gev-anno.gev-out { opacity: 0 !important; transition: opacity 320ms ease; }
|
||||
.gev-pulse { animation: gev-ring-pulse 1.8s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
|
||||
@keyframes gev-ring-pulse { 0%,100% { opacity: 0.9; stroke-width: 2; } 50% { opacity: 0.35; stroke-width: 3.5; } }
|
||||
@keyframes gev-pop { from { opacity: 0; } to { opacity: 1; } }
|
||||
@@ -106,8 +106,6 @@
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
background: #03080d;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(107, 232, 255, 0.36) transparent;
|
||||
}
|
||||
|
||||
.bhote-embedded-callout.is-youtube {
|
||||
|
||||
@@ -35,8 +35,6 @@
|
||||
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:
|
||||
@@ -45,25 +43,6 @@
|
||||
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;
|
||||
|
||||
+33
-49
@@ -969,23 +969,50 @@ body.cockpit-mode #view-switcher button {
|
||||
.cockpit-context-window[data-state='lost'] {
|
||||
border-top-color: rgba(213, 168, 99, 0.72);
|
||||
}
|
||||
.cockpit-context-header {
|
||||
/* The Cockpit cards' headers (Contact, the briefing) share their frame: a
|
||||
title column over a hairline, a kicker in the accent, and a row of square
|
||||
actions. Each card sets only its spacing and sizes. */
|
||||
.cockpit-card-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 {
|
||||
.cockpit-card-header > div {
|
||||
display: grid;
|
||||
gap: 2px;
|
||||
}
|
||||
.cockpit-context-kicker {
|
||||
.cockpit-card-kicker {
|
||||
color: var(--cockpit-accent);
|
||||
font-size: 8px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.cockpit-card-actions {
|
||||
display: flex;
|
||||
}
|
||||
.cockpit-card-actions button {
|
||||
display: grid;
|
||||
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-card-actions button:hover,
|
||||
.cockpit-card-actions button:focus-visible {
|
||||
border-color: var(--cockpit-accent);
|
||||
color: #fff;
|
||||
outline: none;
|
||||
}
|
||||
.cockpit-context-header {
|
||||
gap: 5px 10px;
|
||||
padding: 0 5px 7px;
|
||||
}
|
||||
.cockpit-context-kicker {
|
||||
font-size: 8px;
|
||||
letter-spacing: 0.2em;
|
||||
}
|
||||
#cockpit-context-subject {
|
||||
@@ -1041,26 +1068,10 @@ body.cockpit-mode #view-switcher button {
|
||||
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);
|
||||
@@ -1500,17 +1511,8 @@ body.cockpit-mode #view-switcher button {
|
||||
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;
|
||||
}
|
||||
html:not([lang='en']) .cockpit-signal-header > div {
|
||||
min-width: 0;
|
||||
@@ -1526,9 +1528,7 @@ html:not([lang='en']) .cockpit-signal-kicker {
|
||||
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 {
|
||||
@@ -1542,7 +1542,6 @@ html:not([lang='en']) .cockpit-signal-kicker {
|
||||
animation: cockpit-live 1.6s ease-in-out infinite;
|
||||
}
|
||||
.cockpit-brief-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
}
|
||||
@@ -1552,22 +1551,7 @@ html:not([lang='en']) .cockpit-brief-actions > * {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.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;
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
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;
|
||||
color: var(--dock-label-color);
|
||||
font-size: var(--dock-label-font-size);
|
||||
font-weight: var(--dock-label-font-weight);
|
||||
letter-spacing: var(--dock-label-letter-spacing);
|
||||
}
|
||||
|
||||
#command-dock .dock-label-icon {
|
||||
@@ -463,17 +463,10 @@ body:not(.ui-clean-view):not(.recording-mode):has(
|
||||
}
|
||||
|
||||
#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 {
|
||||
#intel-hud[data-variant='tactical'] .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);
|
||||
}
|
||||
|
||||
+157
-15
@@ -81,16 +81,104 @@
|
||||
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 {
|
||||
/* Side panel titles read like the command dock's labels: one type for every
|
||||
panel, collapsed or open, and bright enough to read over the globe. The
|
||||
dock's type is in rem, but a collapsed launcher is a fixed 176px, so the
|
||||
rail caps it at its 16px-root size: a larger browser font must not cut
|
||||
Recent Imagery short. */
|
||||
:is(#left-panel-stack, #right-context-rail)
|
||||
:is(.panel-header > .panel-title, .pp-header-label) {
|
||||
font-family: var(--font-mono);
|
||||
font-size: min(var(--dock-label-font-size), 9.28px);
|
||||
font-weight: var(--dock-label-font-weight);
|
||||
letter-spacing: min(var(--dock-label-letter-spacing), 2.08px);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
/* A hovered panel sets --rail-label-hover on itself (see below); its own
|
||||
header picks it up. Radio sits inside Context and keeps its own colour. */
|
||||
:root:not([data-ui-theme='cyber'])
|
||||
:is(#left-panel-stack, #right-context-rail)
|
||||
:is(
|
||||
.panel-header > .panel-title,
|
||||
.pp-header-label,
|
||||
:is(.panel-header, .pp-header-row) > .panel-collapse-btn
|
||||
) {
|
||||
color: var(--rail-label-hover, var(--dock-label-color));
|
||||
}
|
||||
|
||||
#radio-panel {
|
||||
--rail-label-hover: initial;
|
||||
}
|
||||
|
||||
/* A title never pushes its toggle out of the card: one that does not fit
|
||||
ends in an ellipsis. Cyber draws a marker left of the title, which a clip
|
||||
would cut, and keeps its own header layout. */
|
||||
:root:not([data-ui-theme='cyber'])
|
||||
:is(#left-panel-stack, #right-context-rail)
|
||||
:is(.panel-header > .panel-title, .pp-header-label) {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
letter-spacing: 1.5px;
|
||||
}
|
||||
|
||||
/* A collapsed launcher is 176px wide and its divider has no room to draw,
|
||||
so the header drops it and packs closer. English titles such as Recent
|
||||
Imagery then fit whole. Only the rail's own launchers: Radio, nested in
|
||||
Context, keeps its divider. */
|
||||
:root:not([data-ui-theme='cyber'])
|
||||
:is(#left-panel-stack, #right-context-rail)
|
||||
> .panel-collapsible.collapsed
|
||||
> [class$='-panel-inner']
|
||||
> .panel-header,
|
||||
:root:not([data-ui-theme='cyber'])
|
||||
:is(#left-panel-stack, #right-context-rail)
|
||||
> #pp-toggles.collapsed
|
||||
> .pp-header-row {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
:root:not([data-ui-theme='cyber'])
|
||||
:is(#left-panel-stack, #right-context-rail)
|
||||
> .panel-collapsible.collapsed
|
||||
> [class$='-panel-inner']
|
||||
> .panel-header
|
||||
> .panel-divider,
|
||||
:root:not([data-ui-theme='cyber'])
|
||||
:is(#left-panel-stack, #right-context-rail)
|
||||
> #pp-toggles.collapsed
|
||||
> .pp-header-row
|
||||
> .panel-divider {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:root:not([data-ui-theme='cyber'])
|
||||
:is(#left-panel-stack, #right-context-rail)
|
||||
> .panel-collapsible.collapsed
|
||||
> [class$='-panel-inner']
|
||||
> .panel-header
|
||||
> .panel-collapse-btn,
|
||||
:root:not([data-ui-theme='cyber'])
|
||||
:is(#left-panel-stack, #right-context-rail)
|
||||
> #pp-toggles.collapsed
|
||||
> .pp-header-row
|
||||
> .panel-collapse-btn {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
/* Translated titles run longer (Aktuelle Bilddaten), so a collapsed rail
|
||||
launcher sets them in compact type rather than pushing the disclosure
|
||||
button out of the card or cutting the word short. Chinese and Japanese
|
||||
titles fit at full size and stay at or above their 9px floor (cjk.css);
|
||||
Radio, nested in Context, is not a launcher. */
|
||||
html:not([lang='en']):not(:lang(zh)):not(:lang(ja))
|
||||
:is(#left-panel-stack, #right-context-rail)
|
||||
> .panel-collapsible.collapsed
|
||||
> [class$='-panel-inner']
|
||||
> .panel-header
|
||||
> .panel-title {
|
||||
font-size: 8px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.panel-divider {
|
||||
@@ -109,6 +197,8 @@ html:not([lang='en'])
|
||||
font-family: var(--font-mono);
|
||||
font-size: 13px;
|
||||
line-height: 1;
|
||||
/* A long title or a header action must not squeeze the toggle. */
|
||||
flex-shrink: 0;
|
||||
cursor: pointer;
|
||||
transition:
|
||||
background-color var(--transition-fast),
|
||||
@@ -116,17 +206,50 @@ html:not([lang='en'])
|
||||
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);
|
||||
}
|
||||
|
||||
/* A side panel answers the pointer as the command dock's trays do: a
|
||||
brighter edge and an accent title and toggle. Touch screens have no hover,
|
||||
so a tap must not leave a panel lit. */
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
:root:not([data-ui-theme='cyber'])
|
||||
:is(#left-panel-stack, #right-context-rail)
|
||||
:where(
|
||||
.data-panel-inner,
|
||||
.scene-panel-inner,
|
||||
.cctv-panel-inner,
|
||||
.weather-panel-inner,
|
||||
.recent-imagery-panel-inner,
|
||||
.street-level-panel-inner,
|
||||
.global-context-panel-inner,
|
||||
#pp-toggles:not(.collapsed),
|
||||
#pp-toggles.collapsed > .pp-header-row
|
||||
) {
|
||||
transition: border-color var(--transition-fast);
|
||||
}
|
||||
|
||||
:root:not([data-ui-theme='cyber'])
|
||||
:is(#left-panel-stack, #right-context-rail)
|
||||
:where(
|
||||
.data-panel-inner,
|
||||
.scene-panel-inner,
|
||||
.cctv-panel-inner,
|
||||
.weather-panel-inner,
|
||||
.recent-imagery-panel-inner,
|
||||
.street-level-panel-inner,
|
||||
.global-context-panel-inner,
|
||||
#pp-toggles:not(.collapsed),
|
||||
#pp-toggles.collapsed > .pp-header-row
|
||||
):hover {
|
||||
--rail-label-hover: var(--accent);
|
||||
border-color: var(--glass-border-hover);
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Button Grid ──────────────────────────────── */
|
||||
.button-grid {
|
||||
display: flex;
|
||||
@@ -431,12 +554,21 @@ html:not([lang='en']) .panel-collapse-btn {
|
||||
}
|
||||
|
||||
#pp-toggles .pp-header-label {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 8px;
|
||||
letter-spacing: 1.4px;
|
||||
color: var(--text-dim);
|
||||
}
|
||||
|
||||
/* Display's title and toggle sit where the other panels' do: 14px of panel
|
||||
padding plus a 4px header inset. The cyber theme sets its own insets. */
|
||||
:root:not([data-ui-theme='cyber']) #pp-toggles.collapsed > .pp-header-row {
|
||||
padding: 8px 18px;
|
||||
}
|
||||
|
||||
:root:not([data-ui-theme='cyber'])
|
||||
#pp-toggles:not(.collapsed)
|
||||
> .pp-header-row {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
#pp-toggles > .pp-header-row .pp-collapse-btn {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
@@ -445,6 +577,16 @@ html:not([lang='en']) .panel-collapse-btn {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* In the default theme Display's toggle matches the other panels' 22px. */
|
||||
:root:not([data-ui-theme='cyber'])
|
||||
#pp-toggles
|
||||
> .pp-header-row
|
||||
.pp-collapse-btn {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#pp-toggles.collapsed {
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
+53
-19
@@ -41,8 +41,6 @@
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(165, 188, 199, 0.35) transparent;
|
||||
}
|
||||
|
||||
:root[data-ui-theme='cyber'] .cctv-panel-inner > .cyber-panel-body {
|
||||
@@ -68,8 +66,6 @@
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(165, 188, 199, 0.35) transparent;
|
||||
}
|
||||
|
||||
:root[data-ui-theme='cyber'] #pp-toggles > .pp-panel-body > * {
|
||||
@@ -82,6 +78,8 @@
|
||||
|
||||
:root[data-ui-theme='cyber'] {
|
||||
color-scheme: dark;
|
||||
--scroll-thumb: rgba(165, 188, 199, 0.35);
|
||||
--scroll-track: transparent;
|
||||
--cyber-red: #c45454;
|
||||
--cyber-red-bright: #e16666;
|
||||
--cyber-slate: #26343a;
|
||||
@@ -796,6 +794,12 @@
|
||||
accent-color: var(--cyber-red);
|
||||
}
|
||||
|
||||
/* Street Level's range wears Cyber's slider accent like every other range. */
|
||||
:root[data-ui-theme='cyber'] .sl-range {
|
||||
--accent: inherit;
|
||||
--accent-glow: inherit;
|
||||
}
|
||||
|
||||
:root[data-ui-theme='cyber']
|
||||
:where(button, a[href], input, select, textarea):focus-visible {
|
||||
outline-color: var(--cyber-red-bright) !important;
|
||||
@@ -1441,6 +1445,15 @@
|
||||
text-shadow: 0 0 6px var(--cyber-red);
|
||||
}
|
||||
|
||||
/* Cyber frames each mode button itself; the shared segmented track would
|
||||
draw a third, blue frame around them. */
|
||||
:root[data-ui-theme='cyber'] .global-context-modes {
|
||||
gap: 7px;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: none;
|
||||
}
|
||||
|
||||
:root[data-ui-theme='cyber'] .dock-tray-toggle,
|
||||
:root[data-ui-theme='cyber'] .context-mode-button {
|
||||
background-color: rgba(38, 52, 58, 0.95);
|
||||
@@ -1552,10 +1565,6 @@
|
||||
clip-path: polygon(12px 0, 100% 0, calc(100% - 12px) 100%, 0 100%);
|
||||
}
|
||||
|
||||
#intel-hud[data-variant='cyber'] .hud-top-bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Cyber keeps the useful style and locality readouts, not fictional IDs. */
|
||||
#intel-hud[data-variant='cyber'] .hud-top-left .hud-classification,
|
||||
#intel-hud[data-variant='cyber'] .hud-top-left .hud-system {
|
||||
@@ -1645,12 +1654,27 @@
|
||||
}
|
||||
|
||||
:root[data-ui-theme='cyber'] #left-panel-stack {
|
||||
/* The stack holds still, so its rail needs no offset (leftPanelRail.js). */
|
||||
--panel-stack-top-pinned: 1;
|
||||
top: var(--cyber-left-rail-top) !important;
|
||||
bottom: calc(2vh + 13rem);
|
||||
inset-inline-start: 54px;
|
||||
inset-inline-start: calc(54px + var(--panel-rail-clearance));
|
||||
width: 300px;
|
||||
padding-inline-start: 10px;
|
||||
border-inline-start: 1px solid rgba(196, 84, 84, 0.72);
|
||||
border-inline-start: 1px solid transparent;
|
||||
}
|
||||
|
||||
/* An edge line marks each side's open panel, mirrored left and right. */
|
||||
:root[data-ui-theme='cyber']
|
||||
body:not(.cockpit-mode)
|
||||
#left-panel-stack:has(> [data-panel-id]:not(.collapsed, [hidden])) {
|
||||
border-inline-start-color: rgba(196, 84, 84, 0.72);
|
||||
}
|
||||
|
||||
:root[data-ui-theme='cyber']
|
||||
body:not(.cockpit-mode)
|
||||
#right-context-rail:has(> [data-panel-id]:not(.collapsed, [hidden])) {
|
||||
border-inline-end-color: rgba(196, 84, 84, 0.72);
|
||||
}
|
||||
|
||||
:root[data-ui-theme='cyber']
|
||||
@@ -1669,6 +1693,13 @@
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
/* The panel rail lists the collapsed panels. */
|
||||
:root[data-ui-theme='cyber']
|
||||
#left-panel-stack.layout-focus.layout-exclusive
|
||||
> [data-panel-id].collapsed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:root[data-ui-theme='cyber']
|
||||
#left-panel-stack
|
||||
> :is(#data-panel, #scene-panel) {
|
||||
@@ -1722,8 +1753,11 @@
|
||||
:root[data-ui-theme='cyber'] #right-context-rail {
|
||||
--right-display-collapsed-width: var(--cyber-panel-collapsed-width);
|
||||
--right-context-collapsed-width: var(--cyber-panel-collapsed-width);
|
||||
right: 62px;
|
||||
width: 312px;
|
||||
/* The edge line and its gap keep the panels where they were. */
|
||||
right: calc(51px + var(--panel-rail-clearance));
|
||||
width: 323px;
|
||||
padding-inline-end: 10px;
|
||||
border-inline-end: 1px solid transparent;
|
||||
}
|
||||
|
||||
/* The map rails now use one visible expanded width. Keeping the rail itself
|
||||
@@ -1792,8 +1826,11 @@
|
||||
isolation: isolate;
|
||||
min-height: 132px;
|
||||
flex: 1 1 auto;
|
||||
border-style: solid;
|
||||
border-color: rgba(206, 222, 226, 0.14);
|
||||
place-content: center;
|
||||
padding: 12px;
|
||||
border: 1px solid rgba(206, 222, 226, 0.14);
|
||||
border-radius: 7px;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
background:
|
||||
linear-gradient(
|
||||
@@ -1855,7 +1892,6 @@
|
||||
background-size: 78px 78px;
|
||||
}
|
||||
|
||||
#intel-hud[data-variant='cyber'] .hud-top-bar,
|
||||
#intel-hud[data-variant='cyber'] .hud-bottom-bar {
|
||||
display: none;
|
||||
}
|
||||
@@ -2492,15 +2528,13 @@
|
||||
);
|
||||
}
|
||||
|
||||
:root[data-ui-theme='cyber']
|
||||
body.cockpit-mode
|
||||
:is(.cockpit-context-header, .cockpit-signal-header) {
|
||||
:root[data-ui-theme='cyber'] body.cockpit-mode .cockpit-card-header {
|
||||
border-bottom-color: rgba(105, 203, 209, 0.25);
|
||||
}
|
||||
|
||||
:root[data-ui-theme='cyber']
|
||||
body.cockpit-mode
|
||||
:is(.cockpit-context-kicker, .cockpit-signal-kicker, .cockpit-route-kicker) {
|
||||
:is(.cockpit-card-kicker, .cockpit-route-kicker) {
|
||||
color: var(--cockpit-caution);
|
||||
}
|
||||
|
||||
|
||||
@@ -128,20 +128,9 @@ test('cockpit brief controls keep their English sizes', () => {
|
||||
|
||||
test('the count-line class is set only outside English', async () => {
|
||||
const { setLocale } = await import('../../i18n/index.js');
|
||||
const { LayerPanel } = await import('../layerPanel.js');
|
||||
const classes = () => {
|
||||
const toggled = new Map();
|
||||
const node = () => ({
|
||||
textContent: '',
|
||||
classList: { toggle: (name, on) => toggled.set(name, on) },
|
||||
appendChild() {},
|
||||
});
|
||||
LayerPanel.prototype._syncCount.call(LayerPanel.prototype, node(), node(), {
|
||||
countLabel: '693 nearby · 93 on screen',
|
||||
});
|
||||
return toggled.get('data-toggle-row--count-line');
|
||||
};
|
||||
globalThis.document ??= { createElement: () => ({}) };
|
||||
const { presentLayerCount } = await import('../layerPanel.js');
|
||||
const classes = () =>
|
||||
presentLayerCount({ countLabel: '693 nearby · 93 on screen' }).countLine;
|
||||
try {
|
||||
setLocale('en');
|
||||
assert.equal(classes(), false);
|
||||
|
||||
@@ -110,20 +110,11 @@
|
||||
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;
|
||||
/* A visible, non-overlaying affordance that the list continues; the
|
||||
scrollbar itself is the kit's .ui-scroll. */
|
||||
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;
|
||||
|
||||
@@ -10,6 +10,20 @@
|
||||
font-family: var(--font-sans);
|
||||
font-size: 12px;
|
||||
outline: none;
|
||||
/* Native number spinners and the open select list follow the dark skin. */
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
/* A select draws the field's own chevron, not the platform's arrow, so every
|
||||
dropdown in the app reads the same. The open list stays native. */
|
||||
select.gev-field {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
padding-right: 22px;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='rgba(255,255,255,0.62)' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 8px center;
|
||||
background-size: 10px 6px;
|
||||
}
|
||||
|
||||
.gev-field:focus-visible {
|
||||
@@ -30,6 +44,11 @@
|
||||
padding: 2px 6px;
|
||||
}
|
||||
|
||||
select.gev-field--compact {
|
||||
padding-right: 18px;
|
||||
background-position: right 6px center;
|
||||
}
|
||||
|
||||
/* Compact inline editors share density and hide native number spinners.
|
||||
Their containing feature sets width to fit the surrounding readout. */
|
||||
.gev-field--inline {
|
||||
|
||||
Vendored
+13
-2
@@ -9,6 +9,9 @@
|
||||
--glass-border: rgba(255, 255, 255, 0.08);
|
||||
--glass-border-hover: rgba(255, 255, 255, 0.15);
|
||||
--accent: #00d4ff;
|
||||
/* Every scrolling surface's scrollbar (the kit's .ui-scroll). */
|
||||
--scroll-thumb: rgba(0, 212, 255, 0.46);
|
||||
--scroll-track: rgba(255, 255, 255, 0.06);
|
||||
--accent-dim: rgba(0, 212, 255, 0.15);
|
||||
--accent-glow: rgba(0, 212, 255, 0.4);
|
||||
--text-primary: #e8eaed;
|
||||
@@ -21,9 +24,17 @@
|
||||
--panel-radius: 16px;
|
||||
--btn-radius: 10px;
|
||||
--transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
/* Label type shared by the command dock and the side panel titles. */
|
||||
--dock-label-color: rgba(206, 232, 239, 0.72);
|
||||
--dock-label-font-size: 0.58rem;
|
||||
--dock-label-font-weight: 500;
|
||||
--dock-label-letter-spacing: 0.13rem;
|
||||
--transition-smooth: 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
--left-stack-x: 52px;
|
||||
--right-rail-x: 52px;
|
||||
/* The side stacks clear the 52px edge gutter that holds the vertical HUD
|
||||
readout, plus the floating panel rail (42px) and its 6px gap. */
|
||||
--panel-rail-clearance: 48px;
|
||||
--left-stack-x: calc(52px + var(--panel-rail-clearance));
|
||||
--right-rail-x: calc(52px + var(--panel-rail-clearance));
|
||||
--left-stack-top: 26vh;
|
||||
--left-stack-gap: 72px;
|
||||
--left-collapsed-width: 176px;
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/* Generic components in src/ui/kit. The surfaces use this application's
|
||||
glass, accent and type tokens. */
|
||||
|
||||
/* The thin themed scrollbar every scrolling surface wears (.ui-scroll). Without it a surface draws the platform's light scrollbar,
|
||||
because the page declares no dark color-scheme. */
|
||||
/* Cesium builds its credit list and the rail card builder its lines, so
|
||||
those two surfaces are named here instead of carrying the class. */
|
||||
.ui-scroll,
|
||||
.cesium-credit-lightbox > ul,
|
||||
.weather-card [data-line-id='status'] {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--scroll-thumb) var(--scroll-track);
|
||||
}
|
||||
.ui-scroll::-webkit-scrollbar,
|
||||
.cesium-credit-lightbox > ul::-webkit-scrollbar,
|
||||
.weather-card [data-line-id='status']::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
.ui-scroll::-webkit-scrollbar-thumb,
|
||||
.cesium-credit-lightbox > ul::-webkit-scrollbar-thumb,
|
||||
.weather-card [data-line-id='status']::-webkit-scrollbar-thumb {
|
||||
border-radius: 999px;
|
||||
background: var(--scroll-thumb);
|
||||
}
|
||||
.ui-scroll::-webkit-scrollbar-track,
|
||||
.cesium-credit-lightbox > ul::-webkit-scrollbar-track,
|
||||
.weather-card [data-line-id='status']::-webkit-scrollbar-track {
|
||||
background: var(--scroll-track);
|
||||
}
|
||||
|
||||
.ui-icon {
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
font-variation-settings:
|
||||
'FILL' 0,
|
||||
'wght' 400,
|
||||
'GRAD' 0,
|
||||
'opsz' 20;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.ui-tooltip {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
}
|
||||
.ui-tooltip__tip {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
z-index: 1;
|
||||
padding: 4px 8px;
|
||||
border: 1px solid var(--glass-border);
|
||||
border-radius: 6px;
|
||||
background: var(--menu-bg);
|
||||
color: var(--dock-label-color);
|
||||
font: var(--dock-label-font-weight) var(--dock-label-font-size) / 1.4
|
||||
var(--font-sans);
|
||||
letter-spacing: var(--dock-label-letter-spacing);
|
||||
white-space: nowrap;
|
||||
pointer-events: none;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
/* Sides are for left-to-right; a right-to-left page mirrors them with the
|
||||
rails, so a tip still opens toward the middle of the screen. */
|
||||
.ui-tooltip__tip--right {
|
||||
inset-inline-start: calc(100% + 10px);
|
||||
}
|
||||
.ui-tooltip__tip--left {
|
||||
inset-inline-end: calc(100% + 10px);
|
||||
}
|
||||
|
||||
.ui-rail {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
padding: 4px;
|
||||
border: 1px solid var(--glass-border);
|
||||
border-radius: calc(var(--btn-radius) + 4px);
|
||||
background: var(--glass-bg);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
pointer-events: auto;
|
||||
}
|
||||
.ui-rail__sep {
|
||||
height: 1px;
|
||||
margin: 3px 6px;
|
||||
background: var(--glass-border);
|
||||
}
|
||||
.ui-rail__item {
|
||||
position: relative;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: var(--btn-radius);
|
||||
background: transparent;
|
||||
color: var(--text-secondary);
|
||||
cursor: pointer;
|
||||
transition:
|
||||
color var(--transition-fast),
|
||||
background var(--transition-fast),
|
||||
border-color var(--transition-fast);
|
||||
}
|
||||
.ui-rail__item:hover:not(:disabled) {
|
||||
color: var(--text-primary);
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
.ui-rail__item--on,
|
||||
.ui-rail__item--on:hover:not(:disabled) {
|
||||
border-color: var(--accent-dim);
|
||||
background: var(--accent-dim);
|
||||
color: var(--accent);
|
||||
}
|
||||
.ui-rail__item:disabled {
|
||||
opacity: 0.35;
|
||||
cursor: default;
|
||||
}
|
||||
.ui-rail__badge {
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
inset-inline-end: 1px;
|
||||
min-width: 14px;
|
||||
padding: 0 3px;
|
||||
border-radius: 7px;
|
||||
background: var(--accent);
|
||||
color: var(--bg-dark);
|
||||
font: 600 9px/14px var(--font-mono);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Application view hosts (src/ui/views): the view's own elements lay out as
|
||||
children of the page, as the static markup they replace did. */
|
||||
.gev-view {
|
||||
display: contents;
|
||||
}
|
||||
+78
-221
@@ -84,29 +84,9 @@
|
||||
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-layer-group-heading {
|
||||
margin: 8px 10px 2px;
|
||||
padding-top: 12px;
|
||||
@@ -249,7 +229,7 @@
|
||||
box-sizing: border-box;
|
||||
justify-content: center;
|
||||
overflow: visible;
|
||||
padding: 8px 10px 8px 14px;
|
||||
padding: 8px 14px;
|
||||
}
|
||||
#right-context-rail #global-context-panel.collapsed .panel-header {
|
||||
margin: 0;
|
||||
@@ -260,6 +240,39 @@
|
||||
#right-context-rail.layout-exclusive > [data-panel-id].collapsed {
|
||||
display: none;
|
||||
}
|
||||
#left-panel-stack.layout-exclusive > [data-panel-id].collapsed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Panel rails (src/ui/panelNavigation.js). Each rail lives inside its stack,
|
||||
so it shows and hides with the stack, and floats in the screen-edge gutter.
|
||||
The stack's layout offsets it back to its resting top, so it holds still
|
||||
when an opened panel moves the stack. */
|
||||
.gev-panel-rail {
|
||||
position: absolute;
|
||||
top: var(--panel-rail-offset, 0px);
|
||||
z-index: 1;
|
||||
pointer-events: auto;
|
||||
transition: top var(--transition-fast);
|
||||
}
|
||||
.gev-panel-rail--left {
|
||||
inset-inline-end: calc(100% + 6px);
|
||||
}
|
||||
.gev-panel-rail--right {
|
||||
inset-inline-start: calc(100% + 6px);
|
||||
}
|
||||
body.mobile-shell #left-panel-stack > .gev-panel-rail,
|
||||
body.mobile-shell #right-context-rail > .gev-panel-rail,
|
||||
body.cockpit-mode .gev-panel-rail {
|
||||
display: none;
|
||||
}
|
||||
/* Clean view and recording hide the panels one by one, not their stacks. */
|
||||
body.ui-clean-view .gev-panel-rail,
|
||||
body.recording-mode .gev-panel-rail {
|
||||
opacity: 0 !important;
|
||||
visibility: hidden !important;
|
||||
pointer-events: none !important;
|
||||
}
|
||||
#right-context-rail.layout-focus > [data-panel-id].collapsed {
|
||||
display: block;
|
||||
flex: 0 0 auto;
|
||||
@@ -281,8 +294,6 @@
|
||||
#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
|
||||
> #weather-panel:not(.collapsed)
|
||||
@@ -415,8 +426,6 @@
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
padding-right: 3px;
|
||||
scrollbar-color: rgba(34, 230, 230, 0.38) transparent;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
#space-mission-panel-host .space-mission-roster-item {
|
||||
position: relative;
|
||||
@@ -985,17 +994,9 @@
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
/* Context is read for longer than other panels; it carries no halo. */
|
||||
#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;
|
||||
display: none;
|
||||
}
|
||||
.global-context-panel-inner {
|
||||
position: relative;
|
||||
@@ -1012,157 +1013,14 @@
|
||||
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, 0.22);
|
||||
border-radius: 6px;
|
||||
color: rgba(143, 207, 255, 0.58);
|
||||
background: rgba(42, 113, 171, 0.08);
|
||||
cursor: pointer;
|
||||
transition:
|
||||
border-color 0.15s ease,
|
||||
color 0.15s ease,
|
||||
background 0.15s ease,
|
||||
box-shadow 0.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, 0.82);
|
||||
color: #eaffff;
|
||||
background: rgba(0, 212, 255, 0.16);
|
||||
box-shadow:
|
||||
inset 0 0 12px rgba(0, 212, 255, 0.1),
|
||||
0 0 12px rgba(0, 212, 255, 0.2);
|
||||
}
|
||||
.context-radio-toggle:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: wait;
|
||||
}
|
||||
.context-radio-mini {
|
||||
position: absolute;
|
||||
z-index: 5;
|
||||
top: calc(100% + 20px);
|
||||
inset-inline-end: -38px;
|
||||
display: none;
|
||||
width: 244px;
|
||||
box-sizing: border-box;
|
||||
gap: 8px;
|
||||
padding: 10px;
|
||||
border: 1px solid rgba(65, 220, 231, 0.28);
|
||||
border-radius: 8px;
|
||||
background: rgba(2, 15, 20, 0.96);
|
||||
box-shadow:
|
||||
0 12px 32px rgba(0, 0, 0, 0.62),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.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: 0.12em;
|
||||
}
|
||||
.context-radio-mini-heading button {
|
||||
display: grid;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
place-items: center;
|
||||
padding: 0;
|
||||
border: 1px solid rgba(65, 220, 231, 0.28);
|
||||
border-radius: 5px;
|
||||
color: #8feaf2;
|
||||
background: rgba(14, 69, 78, 0.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, 0.28);
|
||||
border-radius: 5px;
|
||||
color: #8feaf2;
|
||||
background: rgba(14, 69, 78, 0.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: 0.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: 0.08em;
|
||||
}
|
||||
.context-radio-mini-volume input {
|
||||
width: 100%;
|
||||
|
||||
/* Data Layers and Context share the 14px side padding of the other default
|
||||
theme panels, so every title and toggle sits 19px from its edge. Cyber
|
||||
keeps its own gutters. */
|
||||
:root:not([data-ui-theme='cyber'])
|
||||
:is(.data-panel-inner, .global-context-panel-inner) {
|
||||
padding-right: 14px;
|
||||
padding-left: 14px;
|
||||
}
|
||||
.global-context-actions {
|
||||
display: grid;
|
||||
@@ -1229,40 +1087,44 @@
|
||||
rather than relying on the chrome alone. */
|
||||
filter: drop-shadow(0 0 5px rgba(150, 210, 255, 0.9));
|
||||
}
|
||||
/* One segmented control: the two modes read as a single choice. */
|
||||
.global-context-modes {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 7px;
|
||||
margin: 0 0 10px;
|
||||
gap: 2px;
|
||||
margin: 0 0 12px;
|
||||
padding: 2px;
|
||||
border: 1px solid rgba(98, 181, 255, 0.22);
|
||||
border-radius: 7px;
|
||||
background: rgba(0, 0, 0, 0.22);
|
||||
}
|
||||
.context-mode-button {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
min-height: 36px;
|
||||
min-height: 34px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
padding: 7px 8px;
|
||||
border: 1px solid rgba(98, 181, 255, 0.28);
|
||||
border-radius: 6px;
|
||||
color: #8fcfff;
|
||||
background: rgba(42, 113, 171, 0.09);
|
||||
font: 8px/1.15 var(--font-mono);
|
||||
letter-spacing: 0.09em;
|
||||
padding: 6px 8px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 5px;
|
||||
color: rgba(214, 236, 255, 0.72);
|
||||
background: transparent;
|
||||
font: 600 10px/1.2 var(--font-mono);
|
||||
letter-spacing: 0.06em;
|
||||
cursor: pointer;
|
||||
transition:
|
||||
border-color 0.15s ease,
|
||||
color 0.15s ease,
|
||||
background 0.15s ease,
|
||||
box-shadow 0.15s ease;
|
||||
background 0.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;
|
||||
background: rgba(98, 181, 255, 0.08);
|
||||
outline: none;
|
||||
}
|
||||
/* Keep focus distinct when the selected tab owns the accent colors. */
|
||||
@@ -1272,12 +1134,9 @@
|
||||
}
|
||||
|
||||
.context-mode-button.active {
|
||||
border-color: rgba(0, 212, 255, 0.75);
|
||||
color: #eaffff;
|
||||
background: rgba(0, 212, 255, 0.14);
|
||||
box-shadow:
|
||||
inset 0 0 16px rgba(0, 212, 255, 0.08),
|
||||
0 0 12px rgba(0, 212, 255, 0.12);
|
||||
border-color: rgba(0, 212, 255, 0.55);
|
||||
color: #fff;
|
||||
background: rgba(0, 212, 255, 0.16);
|
||||
}
|
||||
.context-mode-button:disabled {
|
||||
opacity: 0.55;
|
||||
@@ -1287,23 +1146,20 @@
|
||||
.context-mode-standby[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
/* Plain guidance under the tabs, not a placeholder box. */
|
||||
.context-mode-standby {
|
||||
display: grid;
|
||||
min-height: 72px;
|
||||
place-content: center;
|
||||
gap: 6px;
|
||||
padding: 12px;
|
||||
border: 1px dashed rgba(98, 181, 255, 0.2);
|
||||
border-radius: 7px;
|
||||
color: rgba(190, 230, 230, 0.5);
|
||||
text-align: center;
|
||||
font: 8px/1.45 var(--font-mono);
|
||||
letter-spacing: 0.1em;
|
||||
padding: 2px 2px 4px;
|
||||
color: rgba(214, 236, 255, 0.72);
|
||||
font: 10px/1.6 var(--font-mono);
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
.context-mode-standby strong {
|
||||
color: #8fcfff;
|
||||
font-size: 9px;
|
||||
letter-spacing: 0.16em;
|
||||
color: var(--text-primary);
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
.context-mode-view {
|
||||
min-height: 0;
|
||||
@@ -1344,19 +1200,20 @@
|
||||
}
|
||||
.global-context-actions .panel-layer-toggle {
|
||||
width: 100%;
|
||||
min-height: 30px;
|
||||
min-height: 32px;
|
||||
padding: 6px 8px;
|
||||
font-size: 8px;
|
||||
font-size: 10px;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
#global-context-panel #cockpit-entry {
|
||||
position: static;
|
||||
z-index: auto;
|
||||
width: 100%;
|
||||
min-height: 30px;
|
||||
min-height: 32px;
|
||||
padding: 5px 8px;
|
||||
border-radius: 5px;
|
||||
justify-content: center;
|
||||
font-size: 8px;
|
||||
font-size: 10px;
|
||||
box-shadow: none;
|
||||
}
|
||||
#global-context-panel #cockpit-entry .material-symbols-outlined {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* ============================================================
|
||||
Bottom-right corner row: the POWER UP chip (provider-settings.css)
|
||||
and, in the very corner, the interface language picker
|
||||
(src/ui/localePicker.js). Logical properties throughout, so a
|
||||
(src/ui/views/panels/LocalePicker.vue). Logical properties throughout, so a
|
||||
right-to-left page mirrors the row and the list.
|
||||
============================================================ */
|
||||
|
||||
|
||||
@@ -108,7 +108,6 @@ body.mobile-shell #top-center-actions {
|
||||
/* ── HUD: one compact readout under the top bar ────────────────────────── */
|
||||
body.mobile-shell #intel-hud .hud-edge,
|
||||
body.mobile-shell #intel-hud .hud-corner,
|
||||
body.mobile-shell #intel-hud .hud-top-bar,
|
||||
body.mobile-shell #intel-hud .hud-bottom-bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
+12
-80
@@ -124,7 +124,6 @@
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.hud-top-bar,
|
||||
.hud-bottom-bar {
|
||||
display: none;
|
||||
position: absolute;
|
||||
@@ -141,24 +140,11 @@
|
||||
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;
|
||||
@@ -298,54 +284,15 @@
|
||||
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 {
|
||||
#intel-hud[data-variant='tactical'] .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,
|
||||
@@ -378,11 +325,7 @@
|
||||
}
|
||||
|
||||
:root[data-scope-mask='off']
|
||||
#intel-hud:is(
|
||||
[data-variant='minimal'],
|
||||
[data-variant='operator'],
|
||||
[data-variant='tactical']
|
||||
)
|
||||
#intel-hud:is([data-variant='minimal'], [data-variant='tactical'])
|
||||
.hud-readout,
|
||||
:root[data-scope-mask='off']:not([data-ui-theme='cyber']) .scene-text-holdout {
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
@@ -399,11 +342,7 @@
|
||||
}
|
||||
|
||||
:root[data-scope-mask='off']
|
||||
#intel-hud:is(
|
||||
[data-variant='minimal'],
|
||||
[data-variant='operator'],
|
||||
[data-variant='tactical']
|
||||
)
|
||||
#intel-hud:is([data-variant='minimal'], [data-variant='tactical'])
|
||||
.hud-readout {
|
||||
display: block;
|
||||
width: max-content;
|
||||
@@ -413,11 +352,7 @@
|
||||
}
|
||||
|
||||
:root[data-scope-mask='off']
|
||||
#intel-hud:is(
|
||||
[data-variant='minimal'],
|
||||
[data-variant='operator'],
|
||||
[data-variant='tactical']
|
||||
)
|
||||
#intel-hud:is([data-variant='minimal'], [data-variant='tactical'])
|
||||
:is(.hud-top-right, .hud-bottom-right)
|
||||
.hud-readout,
|
||||
:root[data-scope-mask='off']:not([data-ui-theme='cyber'])
|
||||
@@ -427,38 +362,35 @@
|
||||
}
|
||||
|
||||
/* Preserve glyph opacity without dimming the vertical backplates. */
|
||||
:root[data-scope-mask='off']
|
||||
#intel-hud:is([data-variant='operator'], [data-variant='tactical'])
|
||||
.hud-edge {
|
||||
:root[data-scope-mask='off'] #intel-hud[data-variant='tactical'] .hud-edge {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
:root[data-scope-mask='off']
|
||||
#intel-hud:is([data-variant='operator'], [data-variant='tactical'])
|
||||
#intel-hud[data-variant='tactical']
|
||||
.hud-edge
|
||||
.hud-readout
|
||||
> * {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
:root[data-scope-mask='off'] #intel-hud[data-variant='operator'] .hud-corner,
|
||||
:root[data-scope-mask='off']
|
||||
#intel-hud:is([data-variant='minimal'], [data-variant='operator'])
|
||||
:is(.hud-top-bar, .hud-bottom-bar) {
|
||||
#intel-hud[data-variant='minimal']
|
||||
.hud-bottom-bar {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
:root[data-scope-mask='off']
|
||||
#intel-hud:is([data-variant='minimal'], [data-variant='operator'])
|
||||
:is(.hud-top-bar, .hud-bottom-bar) {
|
||||
#intel-hud[data-variant='minimal']
|
||||
.hud-bottom-bar {
|
||||
width: fit-content;
|
||||
max-width: calc(100vw - 120px);
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
:root[data-scope-mask='off']
|
||||
#intel-hud:is([data-variant='minimal'], [data-variant='operator'])
|
||||
:is(.hud-top-bar, .hud-bottom-bar)
|
||||
#intel-hud[data-variant='minimal']
|
||||
.hud-bottom-bar
|
||||
.hud-readout {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
||||
@@ -152,7 +152,7 @@
|
||||
overflow: auto;
|
||||
overscroll-behavior: contain;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--glass-border-hover) transparent;
|
||||
scrollbar-color: var(--scroll-thumb) var(--scroll-track);
|
||||
/* Keep an inset focus ring inside the intentional scrolling boundary. */
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
@@ -184,19 +184,9 @@
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(54, 220, 255, 0.45) transparent;
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
|
||||
.key-setup-rows::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
.key-setup-rows::-webkit-scrollbar-thumb {
|
||||
background: rgba(54, 220, 255, 0.45);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.key-setup-row {
|
||||
display: grid;
|
||||
gap: 0.35rem;
|
||||
|
||||
+13
-12
@@ -18,8 +18,6 @@
|
||||
border-radius: 8px;
|
||||
background: rgba(2, 15, 20, 0.42);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.035);
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(0, 212, 255, 0.46) rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
#radio-panel .panel-header {
|
||||
margin-bottom: 0;
|
||||
@@ -461,14 +459,16 @@ html:not([lang='en']) .radio-transport button {
|
||||
border-top: 1px solid rgba(98, 181, 255, 0.16);
|
||||
}
|
||||
.military-awareness-standby strong {
|
||||
color: #79c2ff;
|
||||
color: var(--text-primary);
|
||||
font-size: 10px;
|
||||
letter-spacing: 0.1em;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
.military-awareness-standby span {
|
||||
color: #8192a6;
|
||||
font-size: 9px;
|
||||
letter-spacing: 0.05em;
|
||||
color: rgba(214, 236, 255, 0.72);
|
||||
font-size: 10px;
|
||||
line-height: 1.5;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
.military-awareness-standby button {
|
||||
justify-self: start;
|
||||
@@ -695,7 +695,7 @@ html:not([lang='en']) .data-toggle-right {
|
||||
}
|
||||
|
||||
/* Row text pieces that must not break inside: a hyphenated code (ADS-B) and
|
||||
the space before a " · " separator (see setRowText in layerPanel.js). */
|
||||
the space before a " · " separator (see rowTextRuns in layerRowText.js). */
|
||||
html:not([lang='en']) .data-keep {
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -1090,11 +1090,12 @@ html:not([lang='en']) .data-row-list-text {
|
||||
.sdr-radio-card select,
|
||||
.sdr-radio-card input[type='number'] {
|
||||
min-height: 28px;
|
||||
border: 1px solid rgba(255, 183, 82, 0.28);
|
||||
border-radius: 5px;
|
||||
color: #ffd79a;
|
||||
background: rgba(38, 25, 8, 0.52);
|
||||
font: 8px/1 var(--font-mono);
|
||||
/* The shared field paints the surface (and the select's chevron). */
|
||||
--gev-field-border-color: rgba(255, 183, 82, 0.28);
|
||||
--gev-field-color: #ffd79a;
|
||||
--gev-field-background: rgba(38, 25, 8, 0.52);
|
||||
}
|
||||
.sdr-radio-card button {
|
||||
padding: 6px 8px;
|
||||
@@ -1127,7 +1128,7 @@ html:not([lang='en']) .data-row-list-text {
|
||||
.sdr-gain-row select {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding: 5px 7px;
|
||||
padding: 5px 22px 5px 7px;
|
||||
}
|
||||
.sdr-adsb-stats {
|
||||
display: grid;
|
||||
|
||||
@@ -46,8 +46,6 @@
|
||||
max-height: calc(var(--right-stack-max-height, 50svh) - 64px);
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(0, 212, 255, 0.46) transparent;
|
||||
}
|
||||
#recent-imagery-panel.collapsed #recent-imagery-panel-body,
|
||||
#recent-imagery-panel.collapsed #recent-imagery-panel-count,
|
||||
@@ -56,10 +54,6 @@
|
||||
#recent-imagery-split-line[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
#recent-imagery-panel.collapsed .panel-title {
|
||||
font-size: 8px;
|
||||
letter-spacing: 1.8px;
|
||||
}
|
||||
#recent-imagery-panel.collapsed .panel-header {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
@@ -172,7 +166,6 @@
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
scroll-snap-type: x proximity;
|
||||
scrollbar-width: thin;
|
||||
outline: none;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
@@ -98,25 +98,12 @@
|
||||
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;
|
||||
@@ -205,7 +192,7 @@
|
||||
under the expanded panel plus a vertical scrollbar that scrolls nothing
|
||||
but glow. Pin the glow to the panel box here — its blur is ink overflow,
|
||||
which never scrolls — instead of clipping the rail, which would also clip
|
||||
legitimate content such as the Context radio popover. */
|
||||
legitimate content that extends past a panel's edge. */
|
||||
#left-panel-stack .panel-glow,
|
||||
#right-context-rail .panel-glow {
|
||||
inset: 0;
|
||||
@@ -228,10 +215,6 @@
|
||||
#right-context-rail #global-context-panel.collapsed {
|
||||
width: 100%;
|
||||
}
|
||||
.context-radio-mini {
|
||||
inset-inline-end: -38px;
|
||||
width: min(244px, calc(100vw - 32px));
|
||||
}
|
||||
|
||||
#left-panel-stack > #data-panel,
|
||||
#left-panel-stack > #cctv-panel,
|
||||
|
||||
@@ -73,7 +73,7 @@ html:lang(ar) :is(#intel-hud, #cockpit-hud) {
|
||||
@media (min-width: 961px) and (min-height: 650px) {
|
||||
html[dir='rtl'][data-ui-theme='cyber'] #right-context-rail {
|
||||
right: auto;
|
||||
left: 62px;
|
||||
left: calc(51px + var(--panel-rail-clearance));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +150,6 @@ html[dir='rtl']
|
||||
.cockpit-news-list li *,
|
||||
#radio-station-name,
|
||||
#radio-station-tags,
|
||||
#context-radio-mini-station,
|
||||
.cockpit-radio-station
|
||||
) {
|
||||
unicode-bidi: plaintext;
|
||||
@@ -162,12 +161,10 @@ html[dir='rtl'] #bhote-koshi-event-panel [data-role='time'] {
|
||||
unicode-bidi: isolate;
|
||||
}
|
||||
|
||||
/* Physical controls keep their left-to-right sense: the glyph-only media
|
||||
transport (◀◀ ▶ ▶▶), FM seek down/up and the radio dial. The worded
|
||||
PREV / PLAY / NEXT row follows the reading direction like any other
|
||||
button row. */
|
||||
html[dir='rtl']
|
||||
:is(.context-radio-mini-transport, .sdr-seek-row, .radio-tuner) {
|
||||
/* Physical controls keep their left-to-right sense: FM seek down/up and the
|
||||
radio dial. The worded PREV / PLAY / NEXT row follows the reading
|
||||
direction like any other button row. */
|
||||
html[dir='rtl'] :is(.sdr-seek-row, .radio-tuner) {
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
|
||||
+122
-41
@@ -1,6 +1,8 @@
|
||||
/* ── Scene Director Panel ───────────────────── */
|
||||
#scene-panel {
|
||||
--panel-expanded-width: 360px;
|
||||
/* Secondary text in Authoring: dimmer than labels, but legible on the globe. */
|
||||
--scene-quiet: rgba(232, 234, 237, 0.62);
|
||||
position: fixed;
|
||||
top: calc(var(--left-stack-top) + (var(--left-stack-gap) * 2));
|
||||
left: var(--left-stack-x);
|
||||
@@ -150,15 +152,15 @@
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* The scene's name takes its own row; NEW SCENE / DELETE share the next. */
|
||||
#scene-select {
|
||||
flex: 1;
|
||||
flex: 1 1 100%;
|
||||
min-width: 0;
|
||||
min-height: 32px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* A translated scene name needs the width: the select takes its own row,
|
||||
NEW / DEL share the next one. */
|
||||
html:not([lang='en']) #scene-select {
|
||||
flex: 1 1 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
@@ -168,8 +170,7 @@ html:not([lang='en']) #scene-select {
|
||||
}
|
||||
|
||||
/* A translated action longer than its button wraps inside the button instead
|
||||
of running past it. English keeps its one-line buttons ("EXPORT PRESETS"
|
||||
included). */
|
||||
of running past it. English keeps its one-line buttons. */
|
||||
html:not([lang='en']) #scene-panel .scene-controls .scene-btn {
|
||||
white-space: normal;
|
||||
overflow-wrap: break-word;
|
||||
@@ -180,6 +181,70 @@ html:not([lang='en']) #scene-panel .scene-controls .scene-btn {
|
||||
min-width: 72px;
|
||||
}
|
||||
|
||||
#scene-panel .scene-btn {
|
||||
font-size: 10px;
|
||||
padding: 8px 10px;
|
||||
}
|
||||
|
||||
/* Authoring's steps: SCENE, SHOTS, PREVIEW, SAVE & SHARE. */
|
||||
.scene-step-heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin: 10px 0 6px;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 10px;
|
||||
letter-spacing: 1.6px;
|
||||
color: var(--scene-quiet);
|
||||
}
|
||||
|
||||
.scene-step-heading::after {
|
||||
content: '';
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.panel-header + .scene-step-heading {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
/* One primary action per step: CAPTURE SHOT and PLAY. The panel id keeps
|
||||
this above Cyber's shared button surface. */
|
||||
#scene-panel .scene-btn-primary:not(:disabled) {
|
||||
color: var(--accent);
|
||||
border-color: color-mix(in srgb, var(--accent) 55%, transparent);
|
||||
background: color-mix(in srgb, var(--accent) 10%, transparent);
|
||||
}
|
||||
|
||||
/* The file row is housekeeping; it stays quieter than the steps above. */
|
||||
#scene-panel .scene-file-controls .scene-btn {
|
||||
font-size: 9px;
|
||||
/* Room for one long translated word (IMPORTIEREN, ІМПОРТУВАТИ) per line. */
|
||||
padding: 8px 4px;
|
||||
letter-spacing: 0.6px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* Keep the shared hover on the restyled actions. */
|
||||
#scene-panel .scene-btn-primary:hover:not(:disabled),
|
||||
#scene-panel .scene-file-controls .scene-btn:hover:not(:disabled) {
|
||||
color: var(--accent);
|
||||
border-color: var(--accent);
|
||||
background: color-mix(in srgb, var(--accent) 16%, transparent);
|
||||
}
|
||||
|
||||
.scene-shot-hint {
|
||||
margin: 0 0 8px;
|
||||
font-size: 11px;
|
||||
line-height: 1.4;
|
||||
color: var(--scene-quiet);
|
||||
}
|
||||
|
||||
#scene-panel:not(.has-shots) .scene-shot-hint {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#scene-start-btn,
|
||||
#scene-stop-btn,
|
||||
#scene-next-btn {
|
||||
@@ -190,39 +255,34 @@ html:not([lang='en']) #scene-panel .scene-controls .scene-btn {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
max-height: 160px;
|
||||
min-height: 96px;
|
||||
max-height: 260px;
|
||||
/* Two shot rows stay visible; the panel scrolls when space is short. */
|
||||
min-height: 128px;
|
||||
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;
|
||||
margin-bottom: 4px;
|
||||
counter-reset: scene-shot;
|
||||
}
|
||||
|
||||
.scene-shot-empty {
|
||||
border: 1px dashed rgba(255, 255, 255, 0.14);
|
||||
border-radius: 8px;
|
||||
padding: 10px 8px;
|
||||
padding: 16px 12px;
|
||||
text-align: center;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 9px;
|
||||
letter-spacing: 1px;
|
||||
color: var(--text-dim);
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.3px;
|
||||
line-height: 1.5;
|
||||
color: var(--scene-quiet);
|
||||
}
|
||||
|
||||
.scene-shot-row {
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
border-radius: 9px;
|
||||
padding: 7px 8px;
|
||||
padding: 8px 10px;
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
counter-increment: scene-shot;
|
||||
transition:
|
||||
border-color var(--transition-fast),
|
||||
background var(--transition-fast);
|
||||
@@ -243,12 +303,38 @@ html:not([lang='en']) #scene-panel .scene-controls .scene-btn {
|
||||
.scene-shot-label {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 10px;
|
||||
letter-spacing: 1px;
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.4px;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
/* While renaming, the label holds only the editor at full width. */
|
||||
.scene-shot-label:has(.scene-shot-rename) {
|
||||
overflow: visible;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.scene-shot-label:has(.scene-shot-rename)::before {
|
||||
content: none;
|
||||
}
|
||||
|
||||
/* Shots are numbered 01, 02… in playback order. */
|
||||
.scene-shot-label::before {
|
||||
content: counter(scene-shot, decimal-leading-zero);
|
||||
margin-right: 8px;
|
||||
font-size: 10px;
|
||||
color: var(--scene-quiet);
|
||||
}
|
||||
|
||||
.scene-shot-row.active .scene-shot-label::before {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.scene-shot-rename {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
@@ -260,11 +346,11 @@ html:not([lang='en']) #scene-panel .scene-controls .scene-btn {
|
||||
}
|
||||
|
||||
.scene-shot-meta {
|
||||
margin-top: 4px;
|
||||
margin-top: 5px;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 8px;
|
||||
letter-spacing: 0.8px;
|
||||
color: var(--text-dim);
|
||||
font-size: 10px;
|
||||
letter-spacing: 0.4px;
|
||||
color: var(--scene-quiet);
|
||||
}
|
||||
|
||||
.scene-shot-actions {
|
||||
@@ -275,7 +361,7 @@ html:not([lang='en']) #scene-panel .scene-controls .scene-btn {
|
||||
.scene-progress {
|
||||
margin-top: 8px;
|
||||
width: 100%;
|
||||
height: 18px;
|
||||
height: 14px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
@@ -305,9 +391,10 @@ html:not([lang='en']) #scene-panel .scene-controls .scene-btn {
|
||||
#scene-status {
|
||||
margin-top: 8px;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 10px;
|
||||
letter-spacing: 1px;
|
||||
color: var(--text-secondary);
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.4px;
|
||||
line-height: 1.4;
|
||||
color: var(--scene-quiet);
|
||||
}
|
||||
|
||||
#scene-runtime {
|
||||
@@ -357,6 +444,8 @@ html:not([lang='en']) #scene-panel .scene-controls .scene-btn {
|
||||
#cctv-panel.collapsed .cctv-summary-label,
|
||||
#cctv-panel.collapsed #cctv-summary,
|
||||
#scene-panel.collapsed .scene-controls,
|
||||
#scene-panel.collapsed .scene-step-heading,
|
||||
#scene-panel.collapsed .scene-shot-hint,
|
||||
#scene-panel.collapsed .scene-shot-list,
|
||||
#scene-panel.collapsed .scene-progress,
|
||||
#scene-panel.collapsed #scene-status,
|
||||
@@ -378,14 +467,6 @@ html:not([lang='en']) #scene-panel .scene-controls .scene-btn {
|
||||
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,
|
||||
|
||||
@@ -243,20 +243,20 @@ html:not([lang='en']) #global-loading-detail {
|
||||
|
||||
/* ── 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.
|
||||
Planned by src/splitFlap.js and rendered by SplitFlapText.vue, which
|
||||
lays out one cell 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`.
|
||||
a .gev-flap-text span holding one long-lived Text node, plus an
|
||||
aria-hidden .gev-flap-cells sibling, and 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
|
||||
textContent. That is what keeps QA pins honest, and it lets the
|
||||
cells be rebuilt
|
||||
freely while the aria-live region sees only one characterData
|
||||
change per label update.
|
||||
|
||||
|
||||
@@ -39,8 +39,6 @@
|
||||
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;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(0, 212, 255, 0.46) rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
|
||||
/* Class-qualified, not id-qualified, so a theme's header rule still wins. */
|
||||
@@ -236,17 +234,10 @@ html:not([lang='en']) .sl-meta-row .sl-nearest-btn {
|
||||
gap: 4px 10px;
|
||||
}
|
||||
|
||||
/* The shared slider surface, in Street Level's green. */
|
||||
.sl-range {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
accent-color: var(--sl-green);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sl-range:focus-visible {
|
||||
outline: 1px solid var(--accent);
|
||||
outline-offset: 3px;
|
||||
--accent: var(--sl-green);
|
||||
--accent-glow: color-mix(in srgb, var(--sl-green) 55%, transparent);
|
||||
}
|
||||
|
||||
/* The value and its note share a line: ANY DATE (by upload date). */
|
||||
|
||||
@@ -467,7 +467,8 @@ body.recording-mode .gev-pointer-reticle {
|
||||
min-height: 2rem;
|
||||
box-sizing: border-box;
|
||||
color: var(--text-primary);
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
/* background-color, so a .gev-field select keeps its chevron. */
|
||||
background-color: rgba(255, 255, 255, 0.04);
|
||||
border: 1px solid var(--glass-border);
|
||||
border-radius: 0.3rem;
|
||||
font: inherit;
|
||||
@@ -504,7 +505,6 @@ body.recording-mode .gev-pointer-reticle {
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
overscroll-behavior: contain;
|
||||
scrollbar-width: thin;
|
||||
padding: 0.55rem 0.75rem 3px 3px;
|
||||
line-height: 1.45;
|
||||
overflow-wrap: anywhere;
|
||||
@@ -553,7 +553,7 @@ body.recording-mode .gev-pointer-reticle {
|
||||
#gev-voice-timeout-select {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
padding: 0 0.45rem;
|
||||
padding: 0 22px 0 0.45rem;
|
||||
}
|
||||
#gev-voice-timeout-input {
|
||||
flex: 0 0 4.5rem;
|
||||
|
||||
@@ -180,12 +180,11 @@ html:not([lang='en'])
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
min-height: 30px;
|
||||
color: var(--text-primary);
|
||||
background: #09121b;
|
||||
border: 1px solid var(--glass-border);
|
||||
border-radius: 4px;
|
||||
font: inherit;
|
||||
font-size: 0.65rem;
|
||||
--gev-field-background: #09121b;
|
||||
--gev-field-border-color: var(--glass-border);
|
||||
}
|
||||
#gev-voice-control:hover .gev-voice-provider-field,
|
||||
#gev-voice-control:focus-within .gev-voice-provider-field {
|
||||
|
||||
@@ -42,18 +42,12 @@
|
||||
max-height: calc(var(--right-stack-max-height, 50svh) - 64px);
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(0, 212, 255, 0.46) transparent;
|
||||
}
|
||||
#weather-panel.collapsed #weather-panel-body,
|
||||
#weather-panel[hidden],
|
||||
.weather-readout[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
#weather-panel.collapsed .panel-title {
|
||||
font-size: 8px;
|
||||
letter-spacing: 1.8px;
|
||||
}
|
||||
#weather-panel.collapsed .panel-header {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user