@import "tailwindcss";
@import "@nuxt/ui";
html,
body,
#cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
position: fixed;
overflow: hidden;
font-family: sans-serif;
color: #edffff;
background-color: black;
}
body {
-webkit-touch-callout: none;
user-select: none;
}
/* Hides #app until Vue mounts. The `dark` class index.html sets alongside it forces
Nuxt UI onto its dark palette, since Vue mode has no color-mode switch and
defaults to light while this app is a dark globe ui throughout. */
[v-cloak] {
display: none;
}
/* The safe area, named once. `viewport-fit=cover` in index.html is what makes these
report anything: without it iOS keeps them 0 even where the page already reaches
under the home indicator. The top is 0 on every iOS layout, and is carried for an
Android install, which is edge to edge. */
:root {
--safe-top: env(safe-area-inset-top, 0px);
--safe-right: env(safe-area-inset-right, 0px);
--safe-bottom: env(safe-area-inset-bottom, 0px);
--safe-left: env(safe-area-inset-left, 0px);
/* Cesium's credit line in the bottom-left corner: the inset lifts it off the home
indicator, and the screen's rounded corner then cuts into the left. The same inset
scales how much of 12px that costs, so a square screen keeps Cesium's own 5/3. */
--credit-corner-bottom: calc(3px + var(--safe-bottom));
--credit-corner-left: calc(5px + var(--safe-left) + min(12px, var(--safe-bottom)));
/* With no deck to clear, the corner. `body.clock-deck` moves the line up. */
--credit-bottom: var(--credit-corner-bottom);
--credit-left: var(--credit-corner-left);
}
/* Above the sky view's HUD (z-4) and the entity info panel (z-5), so the control
that leaves the sky view stays reachable while it is up. Sideways the notch is
beside these rows, and without the inset they slide under it. */
#toolbarLeft {
position: absolute;
top: calc(5px + var(--safe-top));
left: calc(2px + var(--safe-left));
z-index: 6;
}
#toolbarRight {
position: absolute;
top: calc(5px + var(--safe-top));
right: calc(2px + var(--safe-right));
z-index: 6;
}
/* Cesium styles these buttons for a mouse, and on iOS a tap leaves `:hover` and
`:focus` behind on whatever it touched last. The lit state is bound to `menu` in
Satvis.vue instead; these put the pointer states back to base. */
#toolbarLeft .cesium-button:not(.toolbarButton--open):focus,
#toolbarRight .cesium-button:not(.toolbarButton--open):focus {
border-color: #444;
}
/* Only where a pointer can actually rest on a button. Elsewhere :hover is whatever
was tapped last. */
@media (hover: none) {
#toolbarLeft .cesium-button:not(.toolbarButton--open):hover,
#toolbarRight .cesium-button:not(.toolbarButton--open):hover {
background: #303336;
border-color: #444;
color: #edffff;
fill: #edffff;
box-shadow: none;
}
}
/* The propagation panel deliberately reuses Satvis's compact toolbar language
instead of creating a competing application shell. */
.propagation-panel {
width: min(330px, calc(100vw - 20px));
max-height: min(76vh, 760px);
overflow: auto;
padding-bottom: 10px;
}
.propagation-panel__intro,
.propagation-panel__note,
.propagation-panel__status {
margin: 7px 12px 10px;
color: #bfd0d8;
font-size: 12px;
line-height: 1.35;
}
.propagation-panel__note {
color: #9eacb4;
font-size: 11px;
}
.propagation-panel__status {
min-height: 32px;
color: #82e6f4;
}
.propagation-panel__status--error {
color: #ffac99;
}
.propagation-panel__grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
padding: 0 12px 12px;
}
.propagation-panel__grid label {
display: grid;
gap: 4px;
color: #d8e4e9;
font-size: 11px;
}
.propagation-panel__grid span {
display: flex;
align-items: center;
gap: 4px;
color: #92acb9;
}
.propagation-panel__grid input {
box-sizing: border-box;
width: 100%;
min-width: 0;
border: 1px solid #58676f;
border-radius: 3px;
background: #1d2428;
color: #e7fbff;
font: inherit;
padding: 5px 6px;
}
.propagation-panel__details {
margin: 8px 12px 12px;
color: #d8e4e9;
font-size: 12px;
}
.propagation-panel__details summary {
cursor: pointer;
margin-bottom: 10px;
}
.propagation-panel__details .propagation-panel__grid {
padding: 0;
}
.propagation-panel__run {
display: block;
width: calc(100% - 24px);
margin: 12px;
border: 1px solid #5cd8ec;
border-radius: 4px;
background: #176274;
color: #f2ffff;
cursor: pointer;
font-size: 13px;
font-weight: 600;
padding: 9px 10px;
}
.propagation-panel__run:hover,
.propagation-panel__run:focus-visible {
background: #23899e;
}
/* Cesium's `outline: none` leaves keyboard focus with nothing to show for it. */
#toolbarLeft .cesium-button:focus-visible,
#toolbarRight .cesium-button:focus-visible {
outline: 2px solid #7fd2ea;
outline-offset: 2px;
}
/* The button whose panel is open. The shadow is cleared so it looks the same whether
or not a pointer also happens to be resting on it. */
#toolbarLeft .toolbarButton--open,
#toolbarRight .toolbarButton--open {
background: #3d4348;
border-color: #7fd2ea;
color: #7fd2ea;
fill: #7fd2ea;
box-shadow: none;
}
.toolbarSwitches {
display: flex;
flex-direction: column;
margin: 2px 3px;
/* Carries the group titles, which have no surface of their own — the rows do,
so the panel is what has to hold them legible against a bright globe. */
background-color: #303336d9;
border-radius: 8px;
}
/* The satellite catalog panel is a dense text list; a more opaque surface
keeps globe labels from bleeding through the rows. */
.toolbarSwitches--catalog {
background-color: #303336e6;
}
.toolbarTitle {
text-align: center;
height: 24px;
line-height: 24px;
margin-top: 5px;
}
.toolbarContent {
margin: 5px;
}
/* A control whose selection a surface model has taken over, so it is no longer
describing what is on screen. Dimming says only that; whether the row is still
the user's to change is a separate question the markup answers per group (a
hidden globe leaves the choice theirs, an imposed terrain does not).
Opacity only, deliberately. A `grayscale` filter here read as a broken panel
rather than an inert one: the red/green dot is the only state a row carries,
and draining its colour left a column of switches saying nothing at all. */
.toolbarSwitch--inert {
opacity: 0.3;
}
.toolbarTitle--inert {
opacity: 0.5;
}
/* Why nothing happened, for a surface model that cannot apply in this view mode.
Zero width with a full-width minimum so the sentence wraps inside the panel
instead of widening it: these panels are sized by their content, and the
longest row is what should set that width. */
.toolbarNote {
width: 0;
min-width: 100%;
box-sizing: border-box;
padding: 2px 8px 3px 8px;
font-size: 11px;
line-height: 14px;
opacity: 0.6;
}
.toolbarSwitch {
/* Lighter than the panel it sits on, not the same colour. These were both
#303336, which was invisible while the panel was translucent enough to show
the globe through the gaps — and once the panel was made opaque, the rows and
their surface merged into one flat slab with no edges at all. */
background-color: #464b50;
border-radius: 8px;
cursor: pointer;
display: inline-block;
height: 24px;
line-height: 24px;
margin: 1px 0px 1px 0px;
opacity: 0.85;
padding-left: 50px;
position: relative;
}
.toolbarSwitch input {
display: none;
}
/* Waiting on the device — a location fix, or the orientation sensor answering a
probe. Not clickable, so a second tap cannot queue a second request while the
first is still out. */
.toolbarSwitch:has(input:disabled) {
cursor: default;
}
/* Sits exactly where the slider's dot does, and is positioned rather than inline
so that showing it costs no width: these panels are sized by their content, so
anything that grows a row reflows the whole menu. That is why the wait is not
said in the label. */
.toolbarSpinner {
position: absolute;
left: 4px;
bottom: 4px;
box-sizing: border-box;
height: 16px;
width: 16px;
border: 2px solid #ffffff40;
border-top-color: #ffffff;
border-radius: 50%;
animation: toolbarSpin 0.8s linear infinite;
}
@keyframes toolbarSpin {
to {
transform: rotate(1turn);
}
}
/* Still a ring rather than a dot, so it reads as busy without moving. */
@media (prefers-reduced-motion: reduce) {
.toolbarSpinner {
animation: none;
}
}
.slider::before {
position: absolute;
content: "";
height: 16px;
width: 16px;
left: 4px;
bottom: 4px;
border-radius: 50%;
background-color: red;
transition: 0.4s;
}
input:checked + .slider::before {
background-color: green;
transform: translateX(20px);
}
.cesium-toolbar-button {
font-size: 22px;
color: #ffffff;
}
/* Center the Nuxt UI