Replace remaining hard-coded colors across all CSS files with design
tokens from tokens.css. Remove duplicate inline positioning from
live.html panels (now in layout.css). Add replay session blob fetch
for immediate 3D scene state on seek.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Move inline position:fixed styles from setup.html and expert.css into the
shared layout.css stylesheet. Convert #scene-container and #status-bar from
position:fixed to grid-child layout within .app-shell--live, eliminating
fragile top/height calc chains that broke on every new overlay element.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace `color: white` in #ble-btn .badge with `var(--text-on-accent)`
completing the single design system adoption per plan §8e.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The presence panel positioning was moved to layout.css in a prior commit
but the inline override in live.html was not cleaned up.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace hardcoded spacing (padding, margin, gap), typography (font-size,
line-height), and border-radius values with CSS custom property tokens
from tokens.css across all 26 dashboard CSS files. Colors were already
tokenized; this completes the design system adoption per plan.md §8e.
763 lines changed: 478 from bulk spacing/typography pass, 285 from
directional margin/padding pass. No hex colors remain outside tokens.css.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Extract ID-based panel positioning (#node-panel, #chart-panel,
#presence-panel) from live.html inline styles into shared layout.css
with proper responsive breakpoints for tablet and mobile.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Move inline <style> blocks from simple.html and integrations.html into
external CSS files (wizard.css, integrations.css), replacing all
hard-coded pixel values with design tokens from tokens.css. Remove
inline style attributes in favor of CSS classes. All 5 dashboard pages
now share one design system via Radix dark tokens (§8e).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Wire the replay module's onJumpToTime callback so the full-page timeline
can coordinate with the replay system after a jump-to-time API call. The
callback syncs replay state, shows the control bar, and feeds replay
blobs to the 3D scene.
All CSS (.selected, .now-replaying-chip), DOM elements, sidebar timeline
click handling, Go backend jump-to-time endpoint, and tests were already
in place. This closes the cross-module coordination gap.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace remaining hardcoded font-size, padding, and border-radius values
with design token variables in layout.css, timeline.css, live.html, and
setup.html. Add timeline explain button and selected-event highlight styles.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Continued CSS tokenization pass across ambient, fleet, live, simple,
integrations pages and their component stylesheets. Replaces hardcoded
`white`, `#1a1a2e`, and raw rgba values with semantic tokens from
tokens.css.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Home page (index.html) is now a clean status+cards layout (109 lines):
- Row 1: status headline with ok/warn/alert states
- Row 2: three cards linking to /live#zones, /fleet, /live#timeline
- Row 3: optional briefing, anomaly, security toggle
- Mobile bottom nav for Home/Live/Fleet/Setup
3D viewer lives at /live (live.html), fleet at /fleet, setup at /setup.
All routes served by Go chi router. home-cards.js connects to /ws/dashboard
for snapshot+incremental updates.
Remaining CSS tokenization: live.html buttons and layout.css status bar
now use design tokens instead of hardcoded colors. Added --orange token
for GDOP fair quality. timeline.js gains replay state fields.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace remaining hardcoded border-radius and color values across 22 CSS
files with design system tokens. Add .live-status-bar, .live-scene, and
.live-panel-* classes to layout.css for the grid-based live view shell.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
panels.css: replaced 17 hardcoded rgba values with semantic token
references (--alert, --warn-bg, --ok-bg, --border-strong, etc).
ambient.css: replaced one hardcoded blue rgba with --blue-muted.
Zero hardcoded hex/rgba color values remain outside tokens.css.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
setup.html was the only page not using the .app-shell CSS grid — its
elements were directly on the body with inline position styles. Wraps
content in .app-shell--live (viewport-filling variant), moves header
into .app-header grid area, and nests #scene-container inside .app-main.
Verified: grep for position:absolute across dashboard/css/ returns only
intentional decorative/component uses (pseudo-elements, toggles, tooltips,
dropdowns, canvas overlays) — zero on layout containers.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Cache the full WebSocket snapshot so incremental updates always have
complete state for banner and card rendering. Add fall/security alert
detection in the status banner with --alert level. Add armed security
state styling in home.css.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Convert hardcoded rgba colors across all dashboard CSS files to use
--ok-bg, --warn-bg, --alert-bg tokens from tokens.css per §8e design
system. Home page status banner and card tags now use proper semantic
tokens. Add layout.css import to live.html for shared nav structure.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When timeline event is clicked in expert mode, emit jump_to_time command
with event timestamp. The time-travel player pauses live playback, seeks
CSI recording buffer to timestamp, and begins replay. Selected event
highlights in timeline and "Now replaying" chip appears in header.
Backend: POST /api/replay/jump-to-time creates replay session centered
on timestamp, replaces previous active session. Frontend: handleSeek()
in sidebar-timeline delegates to SpaxelReplay.jumpToTime() which calls
the API, shows replay control bar, and notifies Viz3D.
Tests: 7 Go test cases for jump-to-time endpoint, 8 JS test cases for
tap-to-jump interaction, event highlighting, and now-replaying chip.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The home page (index.html) was restructured into status headline + 3 cards.
The 3D viewer lives at /live (live.html), setup/calibration at /setup (setup.html).
Fleet page remains at /fleet. home-cards.js pulls snapshot from /ws/dashboard.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Per plan.md §8e information architecture:
- index.html (109 lines) is now a home page with status headline,
3 cards (People & Zones, Devices & Fleet Health, Recent Events),
optional extras row, and mobile bottom nav
- live.html serves the full 3D viewer at /live route
- home-cards.js connects to /ws/dashboard for snapshot + incremental updates
- tokens.css provides the Radix dark design system
- layout.css provides the CSS Grid app shell with responsive breakpoints
- home.css provides card grid, status banner, responsive mobile layout
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Delete non-canonical commandpalette.* and blepanel.js in favor of the
hyphenated command-palette.* and ble-panel.* which match the fleet-page.*
naming convention. Rename test file accordingly.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The IIFE had `let _renderer` on line 13 and `let _renderer = null` on
line 30, which throws SyntaxError and kills the entire Viz3D module,
cascading into panel layout failures on the home page.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add server-side types filter (comma-separated) for category-based filtering,
fuzzy text search with FTS5 fallback on Enter, and improved client-side
filtering with character-sequence matching. Category checkboxes now send
types to server for efficient loading. Includes table-driven tests for types
filter, pagination, and combined filter scenarios.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add optional mothership IP override to the provisioning flow so nodes
on networks where mDNS is blocked (enterprise WiFi, mesh, VLANs) can
connect on first boot without manual intervention.
- Add ms_ip field to provisioning Payload and request structs
- Firmware writes ms_ip to both NVS_KEY_MS_IP and NVS_KEY_MS_IP_PROV
- Discovery prefers provisioned IP on first attempt, falls back to
mDNS, then cached IP
- Web Serial wizard adds Mothership IP field in Network Troubleshooting
- Auto-populates IP when browser accesses dashboard by IP address
- Document when/how to use the override in docs/notes/mdns-override.md
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The tokenValidator field and hello-handler validation logic existed but were
never wired from main.go. Now ingestSrv.SetTokenValidator(provSrv.ValidateToken)
connects the provisioning server's HMAC-SHA256(installSecret, mac) derivation
to the ingestion server, so nodes with missing or mismatched tokens are
rejected via sendReject and disconnected. Includes unit tests covering valid
token, missing token, wrong token, no-validator backward compat, and an e2e
test verifying unprovisioned nodes cannot post CSI frames.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
460800 causes the stub to hang mid-write on ESP32-S3 QFN56 boards with XMC
embedded flash. 115200 skips the post-stub baud rate negotiation entirely.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces the hardcoded flash_mb:16 with a runtime query so the mothership
receives the correct physical flash size regardless of the hardware variant.
On the 4MB XMC board this will now report 4; on a 16MB board it reports 16.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The XMC embedded flash on ESP32-S3 (QFN56) has JEDEC ID 164020 which esptool.js
does not recognise — it returns flash size -1 causing 'File doesn't fit in
available flash' before any bytes are written.
firmware/sdkconfig.defaults:
CONFIG_ESPTOOLPY_FLASHSIZE 16MB → 4MB
4MB is the minimum supported flash. The spi_flash check only panics when
physical < header, so 4MB header is safe on 16MB boards as well.
firmware/partitions.csv:
Redesigned to fit within 4MB flash:
factory 0x010000–0x200000 (~1.9MB, fits current 1.7MB binary + 330KB headroom)
ota_0 0x200000–0x3F0000 (~1.9MB, A/B OTA + rollback preserved)
otadata 0x3F0000–0x3F2000 (8KB)
Total flash used: 0x3F2000 (98.6% of 4MB). Drops ota_1 (was at 8MB, unusable
on 4MB devices anyway); rollback still works factory↔ota_0.
dashboard/js/onboard.js:
flashSize: 'detect' → '4MB' (detect returned -1 for this chip's JEDEC ID;
hardcoding '4MB' correctly sets the binary header for all supported boards)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>