fix(dashboard): repair CSS syntax errors and complete token migration

Fix systemic missing-colon bugs in layout.css where property values
like top, left, right, bottom, gap, padding were directly followed by
var() without a colon separator. This broke all fixed-position panels
in the live view. Also add missing --space-half token to tokens.css
and complete design token migration across remaining CSS files.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
jedarden 2026-04-24 16:57:32 -04:00
parent 87d46b391b
commit 5707a89ad5
14 changed files with 103 additions and 182 deletions

View file

@ -65,7 +65,7 @@
letter-spacing: var(--ls-wide);
color: var(--text-muted);
margin: var(--space-3);
padding-bottom: 6px;
padding-bottom: var(--space-150);
border-bottom: 1px solid var(--bg-hover);
}

View file

@ -249,7 +249,7 @@
display: flex;
align-items: center;
gapvar(--space-250);
margin-bottom: 10px;
margin-bottom: var(--space-250);
}
.ble-match-indicator {

View file

@ -233,7 +233,7 @@
align-items: center;
justify-content: center;
transition: all 0.2s;
margin-left: 6px;
margin-left: var(--space-150);
}
.context-help-btn:hover {

View file

@ -124,7 +124,7 @@
display: flex;
flex-direction: column;
align-items: center;
gapvar(--space-half);
gap: var(--space-half);
padding: var(--space-2) 0;
color: var(--text-muted);
text-decoration: none;
@ -269,8 +269,8 @@
.live-panel--left {
position: fixed;
topvar(--space-16);
leftvar(--space-5);
top: var(--space-16);
left: var(--space-5);
width: 280px;
max-height: calc(100vh - 80px);
padding: var(--space-3);
@ -278,16 +278,16 @@
.live-panel--right {
position: fixed;
bottomvar(--space-5);
rightvar(--space-5);
bottom: var(--space-5);
right: var(--space-5);
width: 400px;
padding: var(--space-3);
}
.live-panel--presence {
position: fixed;
topvar(--space-16);
rightvar(--space-5);
top: var(--space-16);
right: var(--space-5);
width: 240px;
max-height: calc(100vh - 80px);
padding: var(--space-3);
@ -296,8 +296,8 @@
/* Legacy ID-based selectors (match live.html panel IDs) */
#node-panel {
position: fixed;
topvar(--space-16);
leftvar(--space-5);
top: var(--space-16);
left: var(--space-5);
width: 280px;
max-height: calc(100vh - 80px);
background: var(--live-node-bg);
@ -309,8 +309,8 @@
#chart-panel {
position: fixed;
bottomvar(--space-5);
rightvar(--space-5);
bottom: var(--space-5);
right: var(--space-5);
width: 400px;
height: 260px;
background: var(--live-chart-bg);
@ -321,8 +321,8 @@
#presence-panel {
position: fixed;
topvar(--space-16);
rightvar(--space-5);
top: var(--space-16);
right: var(--space-5);
width: 300px;
background: var(--live-panel-bg);
border-radius: var(--radius-card);
@ -342,8 +342,8 @@
#chart-panel {
width: calc(100% - 16px);
rightvar(--space-2);
leftvar(--space-2);
right: var(--space-2);
left: var(--space-2);
bottom: calc(8px + env(safe-area-inset-bottom));
}
}
@ -352,9 +352,9 @@
@media (max-width: 639px) {
#chart-panel {
width: calc(100% - 16px);
rightvar(--space-2);
leftvar(--space-2);
bottomvar(--space-2);
right: var(--space-2);
left: var(--space-2);
bottom: var(--space-2);
height: 200px;
}
}
@ -392,13 +392,13 @@ dialog.app-dialog::backdrop {
/* ── Setup toolbar (floats over 3D canvas in setup page) ── */
.setup-toolbar {
position: fixed;
bottomvar(--space-5);
bottom: var(--space-5);
left: 50%;
transform: translateX(-50%);
display: flex;
gapvar(--space-2);
gap: var(--space-2);
background: var(--overlay-strong);
paddingvar(--space-2) var(--space-4);
padding: var(--space-2) var(--space-4);
border-radius: var(--radius-card);
z-index: 100;
}
@ -407,7 +407,7 @@ dialog.app-dialog::backdrop {
background: var(--slate-5);
border: 1px solid var(--border-default);
color: var(--text-primary);
paddingvar(--space-2) var(--space-4);
padding: var(--space-2) var(--space-4);
border-radius: var(--radius-control);
cursor: pointer;
font-size: var(--text-sm);
@ -428,8 +428,8 @@ dialog.app-dialog::backdrop {
@media (max-width: 639px) {
.setup-toolbar {
bottom: calc(8px + env(safe-area-inset-bottom));
leftvar(--space-2);
rightvar(--space-2);
left: var(--space-2);
right: var(--space-2);
transform: none;
width: auto;
overflow-x: auto;
@ -438,7 +438,7 @@ dialog.app-dialog::backdrop {
.setup-toolbar button {
flex-shrink: 0;
paddingvar(--space-2) var(--space-3);
padding: var(--space-2) var(--space-3);
font-size: var(--text-xs);
}
}
@ -446,7 +446,7 @@ dialog.app-dialog::backdrop {
/* ── Mobile body padding for bottom nav ── */
@media (max-width: 639px) {
.has-mobile-nav {
padding-bottom: calc(60px + env(safe-area-inset-bottom));
padding-bottom: calc(var(--space-16) + env(safe-area-inset-bottom));
}
}
@ -473,8 +473,8 @@ dialog.app-dialog::backdrop {
#diurnal-banner {
top: auto;
bottom: calc(60px + env(safe-area-inset-bottom));
leftvar(--space-2);
rightvar(--space-2);
left: var(--space-2);
right: var(--space-2);
transform: none;
}
}
@ -492,8 +492,8 @@ dialog.app-dialog::backdrop {
#anomaly-learning-banner {
top: auto;
bottom: calc(60px + env(safe-area-inset-bottom));
leftvar(--space-2);
rightvar(--space-2);
left: var(--space-2);
right: var(--space-2);
transform: none;
}
}
@ -502,7 +502,7 @@ dialog.app-dialog::backdrop {
#security-mode-indicator {
position: fixed;
top: 45px;
rightvar(--space-5);
right: var(--space-5);
z-index: 150;
}
@ -510,21 +510,21 @@ dialog.app-dialog::backdrop {
#security-mode-indicator {
top: auto;
bottom: calc(60px + env(safe-area-inset-bottom));
rightvar(--space-2);
right: var(--space-2);
}
}
/* ── Link health panel (floats over canvas) ── */
.link-health-panel {
position: fixed;
topvar(--space-16);
rightvar(--space-5);
top: var(--space-16);
right: var(--space-5);
z-index: 100;
}
@media (max-width: 1023px) {
.link-health-panel {
rightvar(--space-2);
right: var(--space-2);
}
}
@ -532,8 +532,8 @@ dialog.app-dialog::backdrop {
.link-health-panel {
top: auto;
bottom: calc(60px + env(safe-area-inset-bottom));
leftvar(--space-2);
rightvar(--space-2);
left: var(--space-2);
right: var(--space-2);
max-height: 40vh;
overflow-y: auto;
}
@ -542,7 +542,7 @@ dialog.app-dialog::backdrop {
/* ── Replay control bar (shown during replay) ── */
.replay-control-bar {
position: fixed;
bottomvar(--space-5);
bottom: var(--space-5);
left: 50%;
transform: translateX(-50%);
z-index: 150;
@ -550,8 +550,8 @@ dialog.app-dialog::backdrop {
@media (max-width: 639px) {
.replay-control-bar {
leftvar(--space-2);
rightvar(--space-2);
left: var(--space-2);
right: var(--space-2);
transform: none;
bottom: calc(60px + env(safe-area-inset-bottom));
}
@ -560,7 +560,7 @@ dialog.app-dialog::backdrop {
/* ── Replay tuning panel (floats over canvas) ── */
.replay-tuning-panel {
position: fixed;
topvar(--space-16);
top: var(--space-16);
right: 340px;
width: 280px;
z-index: 100;
@ -569,8 +569,8 @@ dialog.app-dialog::backdrop {
@media (max-width: 1023px) {
.replay-tuning-panel {
rightvar(--space-2);
leftvar(--space-2);
right: var(--space-2);
left: var(--space-2);
width: auto;
max-width: 340px;
}
@ -578,8 +578,8 @@ dialog.app-dialog::backdrop {
@media (max-width: 639px) {
.replay-tuning-panel {
rightvar(--space-2);
leftvar(--space-2);
right: var(--space-2);
left: var(--space-2);
width: auto;
top: auto;
bottom: calc(60px + env(safe-area-inset-bottom));
@ -599,7 +599,7 @@ dialog.app-dialog::backdrop {
/* ── Portal editor panel (floats over canvas) ── */
#portal-editor-panel {
position: fixed;
topvar(--space-16);
top: var(--space-16);
left: 320px;
width: 240px;
z-index: 100;
@ -608,8 +608,8 @@ dialog.app-dialog::backdrop {
@media (max-width: 1023px) {
#portal-editor-panel {
leftvar(--space-2);
rightvar(--space-2);
left: var(--space-2);
right: var(--space-2);
width: auto;
max-width: 300px;
}
@ -617,8 +617,8 @@ dialog.app-dialog::backdrop {
@media (max-width: 639px) {
#portal-editor-panel {
leftvar(--space-2);
rightvar(--space-2);
left: var(--space-2);
right: var(--space-2);
width: auto;
top: auto;
bottom: calc(60px + env(safe-area-inset-bottom));
@ -630,7 +630,7 @@ dialog.app-dialog::backdrop {
/* ── Room editor panel (floats over canvas) ── */
#room-editor-panel {
position: fixed;
topvar(--space-16);
top: var(--space-16);
left: 320px;
width: 240px;
z-index: 100;
@ -639,8 +639,8 @@ dialog.app-dialog::backdrop {
@media (max-width: 1023px) {
#room-editor-panel {
leftvar(--space-2);
rightvar(--space-2);
left: var(--space-2);
right: var(--space-2);
width: auto;
max-width: 300px;
}
@ -648,8 +648,8 @@ dialog.app-dialog::backdrop {
@media (max-width: 639px) {
#room-editor-panel {
leftvar(--space-2);
rightvar(--space-2);
left: var(--space-2);
right: var(--space-2);
width: auto;
top: auto;
bottom: calc(60px + env(safe-area-inset-bottom));
@ -661,7 +661,7 @@ dialog.app-dialog::backdrop {
/* ── GDOP legend (floats over canvas) ── */
#gdop-legend {
position: fixed;
bottomvar(--space-5);
bottom: var(--space-5);
left: 320px;
z-index: 100;
display: none;
@ -669,14 +669,14 @@ dialog.app-dialog::backdrop {
@media (max-width: 1023px) {
#gdop-legend {
leftvar(--space-2);
left: var(--space-2);
bottom: calc(280px + env(safe-area-inset-bottom));
}
}
@media (max-width: 639px) {
#gdop-legend {
leftvar(--space-2);
left: var(--space-2);
bottom: calc(220px + env(safe-area-inset-bottom));
}
}

View file

@ -20,7 +20,7 @@
.settings-section h3 {
margin-top: 0;
margin-bottom: 10px;
margin-bottom: var(--space-250);
color: var(--blue-10);
}
@ -48,7 +48,7 @@
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
margin-bottom: var(--space-250);
}
.channel-type {
@ -397,7 +397,7 @@
display: block;
color: var(--text-secondary);
font-size: 0.9em;
margin-bottom: 10px;
margin-bottom: var(--space-250);
}
#modal-event-types {
@ -576,7 +576,7 @@
display: flex;
flex-wrap: wrap;
gapvar(--space-250);
margin-top: 10px;
margin-top: var(--space-250);
}
.panel-day-checkbox {
@ -666,7 +666,7 @@
.panel-form-hint {
color: var(--text-muted);
font-size: 0.85em;
margin-top: -8px;
margin-top: -var(--space-2);
margin-bottom: var(--space-3);
}

View file

@ -444,7 +444,7 @@
display: block;
font-size: var(--text-sm);
color: var(--text-secondary);
margin-bottom: 6px;
margin-bottom: var(--space-150);
font-weight: 500;
}
@ -530,7 +530,7 @@
color: var(--blue-10);
font-weight: 500;
text-align: right;
margin-top: -8px;
margin-top: -var(--space-2);
margin-bottom: var(--space-2);
}
@ -568,7 +568,7 @@
letter-spacing: var(--ls-wide);
color: var(--text-muted);
margin-bottom: var(--space-3);
padding-bottom: 6px;
padding-bottom: var(--space-150);
border-bottom: 1px solid var(--bg-hover);
}
@ -1186,7 +1186,7 @@
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 6px;
margin-bottom: var(--space-150);
}
.anomaly-item-type {
@ -1212,7 +1212,7 @@
border-radius: var(--radius-card);
font-size: var(--text-3xs);
font-weight: 600;
margin-top: 6px;
margin-top: var(--space-150);
}
.anomaly-item-status.active {
@ -2095,7 +2095,7 @@
border: 1px solid var(--border-subtle);
border-radius: var(--radius-control);
font-size: var(--text-xs);
margin-bottom: 6px;
margin-bottom: var(--space-150);
}
.action-item .action-type {
@ -2145,7 +2145,7 @@
}
.form-group {
margin-bottom: 10px;
margin-bottom: var(--space-250);
}
.form-group label {
@ -2605,7 +2605,7 @@
padding: var(--space-2) var(--space-3);
background: var(--border-subtle);
border-radius: var(--radius-control);
margin-bottom: 6px;
margin-bottom: var(--space-150);
}
.sim-item-name {
@ -2678,7 +2678,7 @@
display: block;
font-size: var(--text-xs);
color: var(--text-muted);
margin-bottom: 6px;
margin-bottom: var(--space-150);
}
.sim-progress-bar {
@ -3233,7 +3233,7 @@
============================================ */
.sim-gdop-legend {
margin-top: 15px;
margin-top: var(--space-375);
padding: var(--space-3);
background: var(--shadow);
border-radius: var(--radius-control);
@ -3255,7 +3255,7 @@
width: 16px;
height: 16px;
border-radius: var(--radius-control);
margin-right: 10px;
margin-right: var(--space-250);
flex-shrink: 0;
border: 1px solid var(--border-strong);
}

View file

@ -165,7 +165,7 @@
flex-shrink: 0;
width: 24px;
text-align: center;
padding-top: 2px;
padding-top: var(--space-half);
}
.item-content {
@ -177,7 +177,7 @@
font-size: var(--text-sm);
font-weight: 500;
color: var(--context-text, var(--slate-12));
margin-bottom: 2px;
margin-bottom: var(--space-half);
}
.item-description {

View file

@ -348,7 +348,7 @@
.tuning-actions {
display: flex;
gap: var(--space-3);
margin-top: 28px;
margin-top: var(--space-7);
}
.tuning-btn {

View file

@ -143,7 +143,7 @@ body.simple-mode {
.simple-alert-banner .alert-title {
font-weight: 600;
font-size: var(--text-base);
margin-bottom: 2px;
margin-bottom: var(--space-half);
}
.simple-alert-banner .alert-message {
@ -529,7 +529,7 @@ body.simple-mode {
font-size: var(--text-sm);
font-weight: 500;
color: var(--simple-text-primary);
margin-bottom: 2px;
margin-bottom: var(--space-half);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@ -579,7 +579,7 @@ body.simple-mode {
-webkit-backdrop-filter: blur(20px);
border-top: 1px solid var(--simple-border);
padding: var(--space-3) var(--space-4);
padding-bottom: max(12px, env(safe-area-inset-bottom));
padding-bottom: max(var(--space-3), env(safe-area-inset-bottom));
z-index: 100;
}
@ -696,7 +696,7 @@ body.simple-mode {
.simple-sleep-summary .metric-unit {
font-size: var(--text-sm);
opacity: 0.8;
margin-left: 2px;
margin-left: var(--space-half);
}
.simple-sleep-summary .sleep-quality {

View file

@ -303,7 +303,7 @@
.gdop-legend-item {
display: flex;
align-items: center;
margin-bottom: 6px;
margin-bottom: var(--space-150);
}
.gdop-legend-item:last-child {

View file

@ -298,7 +298,7 @@
display: flex;
align-items: flex-start;
gapvar(--space-250);
margin-bottom: 6px;
margin-bottom: var(--space-150);
}
.timeline-event-icon {
@ -363,7 +363,7 @@
.timeline-event-details {
font-size: var(--text-sm);
color: var(--text-secondary, var(--text-secondary));
margin-top: 6px;
margin-top: var(--space-150);
line-height: 1.4;
}
@ -1032,7 +1032,7 @@
font-weight: 500;
color: var(--text-primary, var(--slate-11));
line-height: 1.3;
margin-bottom: 2px;
margin-bottom: var(--space-half);
word-wrap: break-word;
}

View file

@ -90,6 +90,7 @@
--text-lg: 20px;
--text-xl: 18px;
--text-2xl: 28px;
--text-22: 22px;
--text-3xl: 24px;
--text-4xl: 32px;
--text-5xl: 48px;
@ -101,6 +102,7 @@
--fw-heading: 600;
/* ── Spacing (4 px grid) ── */
--space-half: 2px;
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;

View file

@ -117,8 +117,8 @@ describe('SpaxelReplay', function() {
});
}
// Stop session
if (url === '/api/replay/stop') {
// Stop session (match by method+url since body isn't in URL)
if (options && options.method === 'POST' && url === '/api/replay/stop') {
return Promise.resolve({
ok: true,
json: function() {

View file

@ -2149,12 +2149,9 @@
50% { box-shadow: 0 0 16px var(--alert-border); }
}
/* ===== Anomaly Learning Banner ===== */
/* ===== Anomaly Learning Banner =====
Positioning in layout.css — only cosmetic styles here */
#anomaly-learning-banner {
position: fixed;
top: 45px;
left: 50%;
transform: translateX(-50%);
background: linear-gradient(135deg, var(--blue-9), var(--blue-10));
color: var(--text-on-accent);
padding: 8px 16px;
@ -2163,7 +2160,6 @@
display: none;
align-items: center;
gap: 10px;
z-index: 150;
box-shadow: 0 4px 12px var(--blue-border);
}
@ -2579,29 +2575,17 @@
margin-left: 8px;
}
/* ===== Mobile Responsive Styles ===== */
@media (max-width: 1024px) {
/* ===== Mobile Responsive Styles =====
Panel positioning and responsive overrides live in layout.css (§8e).
Only page-specific cosmetic adjustments remain here. */
@media (max-width: 1023px) {
/* Show hamburger menu button */
#mobile-menu-btn {
display: block;
}
/* Hide side panels on mobile - use hamburger menu instead */
#node-panel,
#presence-panel {
display: none;
}
/* Chart panel - adjust position */
#chart-panel {
width: calc(100% - 16px);
right: 8px;
left: 8px;
bottom: calc(8px + env(safe-area-inset-bottom));
}
}
@media (max-width: 768px) {
@media (max-width: 639px) {
/* Show mobile menu button */
#mobile-menu-btn {
display: block;
@ -2627,37 +2611,6 @@
display: none;
}
/* Node panel - collapsible on mobile */
#node-panel {
top: auto;
bottom: 0;
left: 0;
right: 0;
width: auto;
max-height: 50vh;
border-radius: 12px 12px 0 0;
transform: translateY(calc(100% - 40px));
transition: transform 0.3s ease;
}
#node-panel.expanded {
transform: translateY(0);
}
/* Chart panel - smaller on mobile */
#chart-panel {
width: calc(100% - 16px);
right: 8px;
left: 8px;
bottom: 8px;
height: 200px;
}
/* Presence panel - hide on mobile (use timeline instead) */
#presence-panel {
display: none;
}
/* Buttons - smaller on mobile */
.view-btn, #gdop-toggle-btn, #fresnel-toggle-btn, #room-editor-btn,
#floorplan-btn, #simulator-btn, #pause-live-btn, #ble-btn,
@ -2684,29 +2637,7 @@
display: none;
}
/* Room editor panel - full width on mobile */
#room-editor-panel {
top: auto;
bottom: 0;
left: 0;
right: 0;
width: auto;
border-radius: 12px 12px 0 0;
transform: translateY(calc(100% - 40px));
transition: transform 0.3s ease;
}
#room-editor-panel.expanded {
transform: translateY(0);
}
/* GDOP legend - smaller on mobile */
#gdop-legend {
left: 8px;
bottom: 220px;
padding: 8px;
}
/* GDOP gradient - smaller on mobile */
#gdop-gradient {
width: 100px;
}
@ -2882,19 +2813,14 @@
background: var(--warn-muted);
}
/* Replay control bar (shown during replay mode) */
/* Replay control bar — positioning in layout.css */
.replay-control-bar {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background: var(--overlay-panel);
border-radius: 12px;
padding: 12px 20px;
display: flex;
align-items: center;
gap: 16px;
z-index: 150;
box-shadow: 0 4px 20px var(--overlay);
border: 1px solid var(--bg-hover);
}
@ -3015,16 +2941,11 @@
background: var(--blue-interact-bg);
}
/* Replay tuning panel */
/* Replay tuning panel — positioning in layout.css */
.replay-tuning-panel {
position: fixed;
top: 60px;
right: 340px;
width: 280px;
background: var(--overlay-panel);
border-radius: 8px;
padding: 16px;
z-index: 100;
display: none;
box-shadow: 0 4px 20px var(--overlay);
border: 1px solid var(--bg-hover);
@ -3144,9 +3065,8 @@
background: var(--border-strong);
}
/* Fresnel zone debug tooltip */
/* Fresnel zone debug tooltip — positioning in layout.css */
.fresnel-tooltip {
position: fixed;
display: none;
background: var(--overlay-panel);
border: 1px solid var(--blue-interact-border);
@ -3155,7 +3075,6 @@
font-size: var(--text-xs);
color: var(--text-primary);
pointer-events: none;
z-index: 1000;
max-width: 280px;
box-shadow: 0 4px 12px var(--overlay);
}