This commit is contained in:
2026-08-27 18:24:22 +02:00
parent 3d47f479e6
commit 10cd37eea7
26 changed files with 4905 additions and 860 deletions
+126 -19
View File
@@ -118,7 +118,7 @@ body.maximized .app-shell {
transition: transform 0.15s, background 0.15s, border-color 0.15s;
}
.button:hover, .icon-button:hover {
transform: translateY(-1px);
transform: none;
border-color: rgba(255, 255, 255, 0.18);
background: #293237;
}
@@ -500,15 +500,15 @@ body[data-app-state="connecting"] .status-line .status-dot {
}
body[data-app-state="connected_disarmed"] .status-line .status-dot {
background: var(--cyan);
box-shadow: 0 0 6px rgba(114, 216, 232, 0.6);
box-shadow: none;
}
body[data-app-state="armed"] .status-line .status-dot {
background: var(--acid);
box-shadow: 0 0 6px rgba(201, 242, 119, 0.65);
box-shadow: none;
}
body[data-app-state="link_degraded"] .status-line .status-dot {
background: var(--red);
box-shadow: 0 0 6px rgba(240, 149, 139, 0.65);
box-shadow: none;
}
.status-line p {
margin: 0;
@@ -603,10 +603,11 @@ body[data-app-state="link_degraded"] .status-line .status-dot {
/* ── Engage / Disarm Slot Above Joysticks ── */
.engage-header-zone {
display: flex;
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
justify-content: space-between;
min-height: 42px;
min-height: 76px;
margin-bottom: 10px;
}
.zone-label {
@@ -617,13 +618,13 @@ body[data-app-state="link_degraded"] .status-line .status-dot {
}
@property --engage-progress {
syntax: "<percentage>";
inherits: false;
inherits: true;
initial-value: 0%;
}
.engage-button {
--engage-progress: 0%;
min-width: 166px;
height: 38px;
height: 44px;
padding: 0 24px;
border-radius: 10px;
position: relative;
@@ -653,15 +654,26 @@ body[data-app-state="link_degraded"] .status-line .status-dot {
background-clip: text;
-webkit-background-clip: text;
}
.arm:not(.charging):not(.state-transition) .engage-label { animation: engage-shimmer 2.8s linear infinite; }
.arm:not(:disabled):not(.charging):not(.canceling):not(.state-transition) .engage-label { animation: engage-shimmer 4.8s linear infinite; }
.engage-progress-label {
color: #a9ed72;
clip-path: inset(0 calc(100% - var(--engage-progress)) 0 0);
transition: clip-path .06s linear, opacity .18s ease;
transition: opacity .18s ease;
}
.state-transition .engage-face { opacity: .2; transform: translateY(-2px); }
.engage-face { transition: opacity .14s ease, transform .14s ease; }
@keyframes engage-shimmer { from{background-position:160% 0} to{background-position:-90% 0} }
.state-transition .engage-face { animation: state-label .24s ease-out; }
@keyframes state-label { from {opacity:.35} to {opacity:1} }
@keyframes engage-shimmer { 0%,35%{background-position:160% 0} 80%,100%{background-position:-90% 0} }
.engage-button:hover { transform:none; }
.engage-button.pending { background:#405346; border-color:#516e56; }
.engage-button.pending .engage-label { color:#f4f6f3; background:none; }
.engage-button.pending .engage-progress-label { opacity:0; }
.control-status { grid-column:1/-1; min-height:28px; margin:6px 0 0; font-size:12px; line-height:1.4; color:#64716a; transition:color .18s ease; }
.control-status.is-error { color:#a23931; }
.controls-grid { transition:opacity .18s ease; }
.heave-track[data-commanded="true"] .heave-center { background:#3d5145; }
.heave-track .heave-center, .heave-fill { transition:background-color .12s linear; }
body[data-telemetry-stale="true"] #battery-fill { opacity:.35; }
#battery-fill { transition:width .25s linear, opacity .18s ease; }
.subtle { background: #e2e6e1; color: #28302c; border: 1px solid rgba(0, 0, 0, 0.08); }
.subtle:hover { background: #d7dcd5; }
@@ -832,7 +844,7 @@ body[data-app-state="link_degraded"] .status-line .status-dot {
transform: translate(-50%, -50%);
}
.heave-knob:active, .heave-knob.pressed {
scale: 0.93;
filter: brightness(.83);
}
.control-card footer {
@@ -978,7 +990,7 @@ body[data-app-state="link_degraded"] .status-line .status-dot {
/* ══════════════════════════════════════════════════════════════════
APP-STATE CONDITIONAL GATING
══════════════════════════════════════════════════════════════════ */
body:not([data-app-state="armed"]) .controls-grid {
body:not([data-controls-enabled="true"]) .controls-grid {
opacity: 0.45;
pointer-events: none;
user-select: none;
@@ -991,10 +1003,6 @@ button:disabled {
}
button:disabled::after { display: none !important; }
body[data-app-state="disconnected"] #engage,
body[data-app-state="connecting"] #engage,
body[data-app-state="link_degraded"] #engage,
body[data-app-state="connecting"] #connect,
body[data-app-state="disconnected"] button[data-open="motors-modal"],
body[data-app-state="connecting"] button[data-open="motors-modal"],
body[data-app-state="link_degraded"] button[data-open="motors-modal"] {
@@ -1003,8 +1011,107 @@ body[data-app-state="link_degraded"] button[data-open="motors-modal"] {
cursor: not-allowed;
}
/* A pending or unknown armed state must stay legible, even without a link. */
#engage.danger:disabled, #engage.pending:disabled { opacity:1 !important; }
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { animation:none !important; transition:none !important; }
}
@media (max-width: 950px) {
.app-shell { grid-template-columns: 210px minmax(0, 1fr); }
.controls-grid { grid-template-columns: minmax(230px, 1fr) 150px; }
.controls-workspace { padding: 8px 12px; }
}
/* Compact control surface: interactive content is never a native drag region. */
.app-shell { grid-template-columns:260px minmax(0,1fr); }
.sidebar-deck { position:relative; padding:20px; gap:18px; background:linear-gradient(160deg,#333,#242424); }
.sidebar-drag-surface { position:absolute; inset:0; cursor:grab; }
.sidebar-deck > :not(.sidebar-drag-surface) { position:relative; pointer-events:none; }
.sidebar-deck :is(button,select,input,a,.rov-stage,.activity-history) { pointer-events:auto; }
.deck-connection { gap:12px; padding-bottom:16px; }
.port-row select { height:36px; font-size:12px; border-radius:999px; background:#3a3a3a; }
.icon-button { width:34px; height:34px; background:#3a3a3a; }
body #connect, body #connect:hover, body #connect.is-connected, body #connect.is-connecting {
width:100%; min-width:0; height:62px; padding:0 14px; align-self:stretch;
background:#fff !important; color:#303030 !important; border:0 !important;
border-radius:999px; box-shadow:none !important; font-size:30px; font-weight:300; letter-spacing:-.025em;
}
body #connect .btn-label { animation:none; }
.telemetry-zone { gap:20px; }
.rov-stage { height:clamp(180px,32vh,250px); min-height:180px; touch-action:none; }
.model-card { justify-content:flex-start; }
.rov-stage::before { display:none; }
.model-tools button { font-size:12px; padding:7px 11px; }
.battery-card small { font-size:12px; }
.battery-card strong { font-size:23px; }
.battery-card i { font-size:12px; }
.activity-heading { display:flex; align-items:center; justify-content:space-between; font-size:14px; font-weight:650; color:#eee; margin:8px 0 0; }
.activity-heading .logs-link { font-size:14px; font-weight:650; color:#eee; }
.activity-history { list-style:none; padding:0; margin:0; display:grid; gap:4px; }
.activity-history li { font-size:12px; font-weight:300; line-height:1.25; color:#999; overflow-wrap:anywhere; }
.activity-history #status-text { color:#fff; font-size:12px; font-weight:300; }
.activity-history li[hidden] { display:none; }
.controls-workspace { padding:8px 20px 16px; background:#f6f6f6; }
.primary-control-zone { grid-template-rows:120px minmax(0,1fr) 52px; }
.engage-header-zone { display:block; position:relative; height:120px; min-height:0; margin:0; padding:0; }
body #engage { width:calc(100% + 40px); margin-left:-20px; height:104px; padding:0 20px; border:0; border-radius:0; background:transparent; box-shadow:none; }
body #engage:hover, body #engage.pending, body #engage.danger { background:transparent; border:0; }
#engage::before, #engage::after { display:none; }
body #engage { align-items:flex-end; padding-bottom:12px; }
.engage-face > span { font-family:"Segoe UI Variable Display","Segoe UI",Arial,sans-serif; font-size:clamp(64px,7.3vw,90px); font-weight:200; letter-spacing:.015em; line-height:1; padding-bottom:.22em; margin-bottom:-.22em; }
#engage .engage-label { color:#777; background:none; animation:none; }
.engage-sheen-label { color:#fff; pointer-events:none; opacity:0; mask-image:linear-gradient(105deg,transparent 40%,#000 49%,#000 51%,transparent 60%); mask-size:300% 100%; mask-repeat:no-repeat; -webkit-mask-image:linear-gradient(105deg,transparent 40%,#000 49%,#000 51%,transparent 60%); -webkit-mask-size:300% 100%; -webkit-mask-repeat:no-repeat; }
#engage:is(.arm,.danger):not(:disabled):not(.charging):not(.canceling):not(.state-transition) .engage-sheen-label { opacity:1; animation:engage-sweep 2.2s linear infinite; }
@keyframes engage-sweep { from {mask-position:100% 0;-webkit-mask-position:100% 0} to {mask-position:0% 0;-webkit-mask-position:0% 0} }
.engage-progress-label { color:#4cce73; clip-path:none; filter:drop-shadow(0 0 2px rgba(76,206,115,.3)); mask-image:linear-gradient(to right,#000 calc(var(--engage-progress) - 8%),transparent var(--engage-progress)); -webkit-mask-image:linear-gradient(to right,#000 calc(var(--engage-progress) - 8%),transparent var(--engage-progress)); }
#engage.charged .engage-progress-label { mask-image:none; -webkit-mask-image:none; }
#engage.pending .engage-label { color:#5a8753; background:none; }
#engage.danger .engage-label { color:#171717; }
#engage:focus-visible { outline:2px solid #8d9991; outline-offset:-6px; }
.control-status { position:absolute; z-index:2; top:100%; left:0; right:0; margin:0; min-height:0; text-align:center; font-size:12px; max-height:48px; overflow:auto; background:#f6f6f6; }
.control-status[hidden] { display:none; }
@media (prefers-reduced-motion: reduce) {
.engage-sheen-label { display:none; }
}
.controls-grid {
--joy-size:min(54vh,calc(100vw - 480px),460px);
--joy-circle-d:calc(var(--joy-size) * .86);
grid-template-columns:var(--joy-size) 112px; gap:24px;
justify-content:center; align-content:center;
}
.control-card { border:0; border-radius:0; box-shadow:none; background:transparent; padding:0; }
.control-card header { align-items:center; min-height:20px; }
.control-card small, .key-hint { font-size:12px; }
.key-hint { background:transparent; }
.control-card footer { height:22px; font-size:13px; margin:0; }
.vertical-card footer { justify-content:center; text-align:center; }
.vertical-card footer b { display:inline-block; width:4ch; text-align:right; font-variant-numeric:tabular-nums; }
.joystick-pad,.heave-pad { padding:0; flex:none; }
.vertical-control { font-size:11px; gap:4px; }
.heave-track { width:58px; border-radius:999px; background:#eaeaea; border-color:#d6d6d6; }
.heave-knob { width:76px; height:40px; border-radius:999px; background:linear-gradient(145deg,#737373,#454545); }
.heave-fill { left:22px; right:22px; background:#999; }
.control-toolbar { display:flex; justify-content:center; align-items:center; gap:16px; padding-top:12px; }
.control-toolbar .output-limit { width:auto; flex-direction:row; align-items:center; font-size:13px; gap:12px; color:#777; }
.control-toolbar .output-limit span { flex:0 0 128px; width:128px; gap:8px; align-items:baseline; justify-content:space-between; }
.control-toolbar .output-limit b { display:inline-block; flex:0 0 4ch; width:4ch; text-align:right; color:#333; font-variant-numeric:tabular-nums; }
.control-toolbar .range-pill { width:175px; grid-template-columns:28px 1fr 28px; height:40px; background:#e7e7e7; border:0; }
.control-toolbar .range-pill button { width:28px; height:40px; color:#666; font-size:22px; }
.control-toolbar .range-pill input[type="range"] { background:#c4c4c4; height:20px; background-clip:content-box; padding:8px 0; }
.control-toolbar .range-pill input[type="range"]::-webkit-slider-thumb { width:18px; height:18px; background:#858585; }
.control-toolbar .config-btn { width:auto; height:40px; padding:0 18px; font-size:13px; background:#e7e7e7; color:#444; border:0; border-radius:999px; }
.workspace-topbar { height:40px; min-height:40px; }
.window-actions { gap:5px; }
.window-actions button { width:42px; height:38px; border-radius:999px; }
.window-actions button svg { width:20px; height:20px; }
body:not([data-controls-enabled="true"]) .controls-grid { opacity:.65; }
@media (max-height:610px) {
.primary-control-zone { grid-template-rows:100px minmax(0,1fr) 52px; }
.engage-header-zone { height:100px; }
body #engage { height:84px; }
.controls-grid { --joy-size:min(49vh,calc(100vw - 480px),420px); }
.sidebar-deck { gap:12px; padding-top:14px; padding-bottom:14px; }
.telemetry-zone { gap:12px; }
.activity-history { gap:4px; }
}