fix: resolve two-window hang and sweep UI/theming updates

Fix app becoming unresponsive when two browser windows are open: the
root cause was HTTP/1.1 connection pool exhaustion (6-connection limit
per origin). VoiceAlerts was opening 3 SSE streams per window by
default, so two windows produced 8 connections and permanently starved
all regular HTTP requests.

- voice-alerts.js: default all streams to false (opt-in) to stay within
  the browser connection limit; existing user preferences in localStorage
  are preserved
- routes/alerts.py: replace direct AlertManager.stream_events() with
  sse_stream_fanout so both windows receive every alert instead of
  competing for the same queue
- routes/bluetooth_v2.py: same fanout fix via subscribe_fanout_queue,
  preserving named SSE events (device_update, scan_started, etc.)

Also includes accumulated UI/theming changes: accent-cyan CSS variable
sweep across mode CSS/JS files, standalone dashboard pages, template
updates, satellite TLE data refresh, and tile provider default rename.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
James Smith
2026-05-20 22:01:10 +01:00
parent 5100f55586
commit a3f2fa7b88
48 changed files with 1524 additions and 943 deletions
+68 -9
View File
@@ -266,7 +266,7 @@
}
.toggle-switch input:focus + .toggle-slider {
box-shadow: 0 0 0 2px rgba(0, 212, 255, 0.3);
box-shadow: 0 0 0 2px rgba(var(--accent-cyan-rgb), 0.3);
}
/* Select Dropdown */
@@ -461,8 +461,8 @@
/* Info Callout */
.settings-info {
background: rgba(0, 212, 255, 0.1);
border: 1px solid rgba(0, 212, 255, 0.2);
background: rgba(var(--accent-cyan-rgb), 0.1);
border: 1px solid rgba(var(--accent-cyan-rgb), 0.2);
border-radius: 6px;
padding: 12px;
margin-top: 16px;
@@ -474,25 +474,32 @@
color: var(--accent-cyan, #00d4ff);
}
/* Map tile variants */
.tile-layer-cyan {
/* Map tile variants — teal tint, skipped in lean mode */
html:not([data-ui-tier="lean"]) .tile-layer-cyan {
filter: sepia(0.35) hue-rotate(185deg) saturate(1.75) brightness(1.06) contrast(1.05);
}
/* Global Leaflet map theme: cyber overlay */
/* Lean mode: suppress every map filter unconditionally */
html[data-ui-tier="lean"] .leaflet-tile-pane,
html[data-ui-tier="lean"] .leaflet-tile,
html[data-ui-tier="lean"] .tile-layer-cyan {
filter: none !important;
}
/* Global Leaflet map theme: cyber overlay — default and enhanced only, not lean */
.leaflet-container.map-theme-cyber {
position: relative;
background: #020813;
isolation: isolate;
}
.leaflet-container.map-theme-cyber .leaflet-tile-pane {
html:not([data-ui-tier="lean"]) .leaflet-container.map-theme-cyber .leaflet-tile-pane {
filter: sepia(0.74) hue-rotate(176deg) saturate(1.72) brightness(1.05) contrast(1.08);
opacity: 1;
}
/* Hard global fallback: enforce cyber tint on all Leaflet tile images */
html.map-cyber-enabled .leaflet-container .leaflet-tile {
/* Hard global fallback: enforce cyber tint on all Leaflet tile images — not lean */
html:not([data-ui-tier="lean"]).map-cyber-enabled .leaflet-container .leaflet-tile {
filter: sepia(0.74) hue-rotate(176deg) saturate(1.72) brightness(1.05) contrast(1.08) !important;
}
@@ -527,6 +534,58 @@ html.map-cyber-enabled .leaflet-container::after {
background-size: 52px 52px, 52px 52px;
}
/* Lean tier: no overlays, no filters — original tile colors */
html[data-ui-tier="lean"] .leaflet-container::before,
html[data-ui-tier="lean"] .leaflet-container::after {
background: none !important;
background-image: none !important;
}
/* Enhanced tier: signals teal map tint overrides — global (all Leaflet maps) */
html[data-ui-tier="enhanced"] .leaflet-container {
background: #000000;
}
html[data-ui-tier="enhanced"] .leaflet-container::before {
background: none !important;
}
html[data-ui-tier="enhanced"] .leaflet-tile-pane {
filter: sepia(0.85) hue-rotate(150deg) saturate(1.35) brightness(0.78) contrast(1.08);
}
/* Narrower overrides for cyber-specific classes (same filter, kept for !important precedence) */
html[data-ui-tier="enhanced"] .leaflet-container.map-theme-cyber {
background: #000000;
}
html[data-ui-tier="enhanced"] .tile-layer-cyan {
filter: sepia(0.85) hue-rotate(150deg) saturate(1.35) brightness(0.78) contrast(1.08);
}
html[data-ui-tier="enhanced"] .leaflet-container.map-theme-cyber .leaflet-tile-pane {
filter: sepia(0.85) hue-rotate(150deg) saturate(1.35) brightness(0.78) contrast(1.08);
}
html[data-ui-tier="enhanced"].map-cyber-enabled .leaflet-container {
background: #000000;
}
html[data-ui-tier="enhanced"].map-cyber-enabled .leaflet-container .leaflet-tile {
filter: sepia(0.85) hue-rotate(150deg) saturate(1.35) brightness(0.78) contrast(1.08) !important;
}
html[data-ui-tier="enhanced"].map-cyber-enabled .leaflet-container::before {
background: none;
}
html[data-ui-tier="enhanced"].map-cyber-enabled .leaflet-container::after {
background-image:
linear-gradient(rgba(46, 125, 138, 0.1) 1px, transparent 1px),
linear-gradient(90deg, rgba(46, 125, 138, 0.1) 1px, transparent 1px);
background-size: 52px 52px, 52px 52px;
}
/* Responsive */
@media (max-width: 1023px) {
.settings-tabs {