mirror of
https://github.com/smittix/intercept.git
synced 2026-06-08 14:11:54 -07:00
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:
@@ -209,7 +209,7 @@ def inject_offline_settings():
|
||||
"enabled": get_setting("offline.enabled", False),
|
||||
"assets_source": assets_source,
|
||||
"fonts_source": fonts_source,
|
||||
"tile_provider": get_setting("offline.tile_provider", "cartodb_dark_cyan"),
|
||||
"tile_provider": get_setting("offline.tile_provider", "cartodb_dark_nolabels"),
|
||||
"tile_server_url": get_setting("offline.tile_server_url", ""),
|
||||
}
|
||||
}
|
||||
@@ -440,8 +440,8 @@ def get_sdr_device_status() -> dict[str, str]:
|
||||
@app.before_request
|
||||
def require_login():
|
||||
# Skip auth entirely when INTERCEPT_DISABLE_AUTH is set
|
||||
if os.environ.get('INTERCEPT_DISABLE_AUTH', '').lower() in ('1', 'true', 'yes'):
|
||||
session['logged_in'] = True
|
||||
if os.environ.get("INTERCEPT_DISABLE_AUTH", "").lower() in ("1", "true", "yes"):
|
||||
session["logged_in"] = True
|
||||
return None
|
||||
|
||||
# Routes that don't require login (to avoid infinite redirect loop)
|
||||
|
||||
+50
-32
@@ -1,32 +1,50 @@
|
||||
# TLE data for satellite tracking (updated periodically)
|
||||
# To update: click "Update TLE" in satellite dashboard or SSTV mode
|
||||
# Data source: CelesTrak (celestrak.org)
|
||||
TLE_SATELLITES = {
|
||||
'ISS': ('ISS (ZARYA)',
|
||||
'1 25544U 98067A 25029.51432176 .00020818 00000+0 36919-3 0 9991',
|
||||
'2 25544 51.6400 157.5640 0002671 123.5041 236.6291 15.49988902492099'),
|
||||
'NOAA-15': ('NOAA 15',
|
||||
'1 25338U 98030A 25028.84157420 .00000535 00000+0 26168-3 0 9999',
|
||||
'2 25338 98.5676 356.1853 0009968 282.2567 77.7505 14.26225252390049'),
|
||||
'NOAA-18': ('NOAA 18',
|
||||
'1 28654U 05018A 25028.87364583 .00000454 00000+0 25082-3 0 9996',
|
||||
'2 28654 98.8801 59.1618 0013609 281.7181 78.2479 14.13003043 24668'),
|
||||
'NOAA-19': ('NOAA 19',
|
||||
'1 33591U 09005A 25028.82370718 .00000425 00000+0 24556-3 0 9998',
|
||||
'2 33591 99.0905 25.2347 0013428 265.3457 94.6190 14.13019285827447'),
|
||||
'NOAA-20': ('NOAA 20 (JPSS-1)',
|
||||
'1 43013U 17073A 25028.83917428 .00000284 00000+0 15698-3 0 9995',
|
||||
'2 43013 98.7104 59.9558 0001165 102.5891 257.5432 14.19571458378899'),
|
||||
'NOAA-21': ('NOAA 21 (JPSS-2)',
|
||||
'1 54234U 22150A 25028.86292604 .00000268 00000+0 14911-3 0 9995',
|
||||
'2 54234 98.7064 59.6648 0001271 88.4689 271.6646 14.19545810114699'),
|
||||
'METEOR-M2': ('METEOR-M 2',
|
||||
'1 40069U 14037A 25028.47802083 .00000099 00000+0 69422-4 0 9990',
|
||||
'2 40069 98.4752 356.8632 0003942 251.7291 108.3489 14.20719440555299'),
|
||||
'METEOR-M2-3': ('METEOR-M2 3',
|
||||
'1 57166U 23091A 25028.81539352 .00000157 00000+0 94432-4 0 9993',
|
||||
'2 57166 98.7690 91.9652 0001790 107.4859 252.6519 14.23646028 77844'),
|
||||
'METEOR-M2-4': ('METEOR-M2 4',
|
||||
'1 59051U 24039A 26061.19281216 .00000032 00000+0 34037-4 0 9998',
|
||||
'2 59051 98.6892 21.9068 0008025 115.2158 244.9852 14.22415711104050'),
|
||||
}
|
||||
# TLE data for satellite tracking (updated periodically)
|
||||
# To update: click "Update TLE" in satellite dashboard or SSTV mode
|
||||
# Data source: CelesTrak (celestrak.org)
|
||||
TLE_SATELLITES = {
|
||||
"ISS": (
|
||||
"ISS (ZARYA)",
|
||||
"1 25544U 98067A 26140.52007258 .00005164 00000+0 10084-3 0 9993",
|
||||
"2 25544 51.6328 77.0641 0007497 79.3410 280.8422 15.49283153567468",
|
||||
),
|
||||
"NOAA-15": (
|
||||
"NOAA 15",
|
||||
"1 25338U 98030A 25028.84157420 .00000535 00000+0 26168-3 0 9999",
|
||||
"2 25338 98.5676 356.1853 0009968 282.2567 77.7505 14.26225252390049",
|
||||
),
|
||||
"NOAA-18": (
|
||||
"NOAA 18",
|
||||
"1 28654U 05018A 25028.87364583 .00000454 00000+0 25082-3 0 9996",
|
||||
"2 28654 98.8801 59.1618 0013609 281.7181 78.2479 14.13003043 24668",
|
||||
),
|
||||
"NOAA-19": (
|
||||
"NOAA 19",
|
||||
"1 33591U 09005A 25028.82370718 .00000425 00000+0 24556-3 0 9998",
|
||||
"2 33591 99.0905 25.2347 0013428 265.3457 94.6190 14.13019285827447",
|
||||
),
|
||||
"NOAA-20": (
|
||||
"NOAA 20 (JPSS-1)",
|
||||
"1 43013U 17073A 26140.44110773 .00000055 00000+0 46930-4 0 9994",
|
||||
"2 43013 98.7764 80.1520 0001265 43.4537 316.6738 14.19505991440534",
|
||||
),
|
||||
"NOAA-21": (
|
||||
"NOAA 21 (JPSS-2)",
|
||||
"1 54234U 22150A 26140.47502274 .00000020 00000+0 29984-4 0 9999",
|
||||
"2 54234 98.7052 79.7311 0000538 296.4939 63.6182 14.19559760182618",
|
||||
),
|
||||
"METEOR-M2": (
|
||||
"METEOR-M 2",
|
||||
"1 40069U 14037A 26140.48222780 .00000329 00000+0 16961-3 0 9999",
|
||||
"2 40069 98.5104 117.2052 0006833 111.5029 248.6878 14.21453950615385",
|
||||
),
|
||||
"METEOR-M2-3": (
|
||||
"METEOR-M2 3",
|
||||
"1 57166U 23091A 26140.55562749 -.00000013 00000+0 13331-4 0 9995",
|
||||
"2 57166 98.6097 196.0965 0002883 242.0522 118.0365 14.24044155150583",
|
||||
),
|
||||
"METEOR-M2-4": (
|
||||
"METEOR-M2 4",
|
||||
"1 59051U 24039A 26140.53898488 .00000003 00000+0 20858-4 0 9993",
|
||||
"2 59051 98.6996 100.1874 0005955 247.0139 113.0410 14.22426327115336",
|
||||
),
|
||||
}
|
||||
|
||||
+31
-30
@@ -2,74 +2,75 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Generator
|
||||
|
||||
from flask import Blueprint, Response, request
|
||||
|
||||
from utils.alerts import get_alert_manager
|
||||
from utils.responses import api_error, api_success
|
||||
from utils.sse import format_sse
|
||||
from utils.sse import sse_stream_fanout
|
||||
|
||||
alerts_bp = Blueprint('alerts', __name__, url_prefix='/alerts')
|
||||
alerts_bp = Blueprint("alerts", __name__, url_prefix="/alerts")
|
||||
|
||||
|
||||
@alerts_bp.route('/rules', methods=['GET'])
|
||||
@alerts_bp.route("/rules", methods=["GET"])
|
||||
def list_rules():
|
||||
manager = get_alert_manager()
|
||||
include_disabled = request.args.get('all') in ('1', 'true', 'yes')
|
||||
return api_success(data={'rules': manager.list_rules(include_disabled=include_disabled)})
|
||||
include_disabled = request.args.get("all") in ("1", "true", "yes")
|
||||
return api_success(data={"rules": manager.list_rules(include_disabled=include_disabled)})
|
||||
|
||||
|
||||
@alerts_bp.route('/rules', methods=['POST'])
|
||||
@alerts_bp.route("/rules", methods=["POST"])
|
||||
def create_rule():
|
||||
data = request.get_json() or {}
|
||||
if not isinstance(data.get('match', {}), dict):
|
||||
return api_error('match must be a JSON object', 400)
|
||||
if not isinstance(data.get("match", {}), dict):
|
||||
return api_error("match must be a JSON object", 400)
|
||||
|
||||
manager = get_alert_manager()
|
||||
rule_id = manager.add_rule(data)
|
||||
return api_success(data={'rule_id': rule_id})
|
||||
return api_success(data={"rule_id": rule_id})
|
||||
|
||||
|
||||
@alerts_bp.route('/rules/<int:rule_id>', methods=['PUT', 'PATCH'])
|
||||
@alerts_bp.route("/rules/<int:rule_id>", methods=["PUT", "PATCH"])
|
||||
def update_rule(rule_id: int):
|
||||
data = request.get_json() or {}
|
||||
manager = get_alert_manager()
|
||||
ok = manager.update_rule(rule_id, data)
|
||||
if not ok:
|
||||
return api_error('Rule not found or no changes', 404)
|
||||
return api_error("Rule not found or no changes", 404)
|
||||
return api_success()
|
||||
|
||||
|
||||
@alerts_bp.route('/rules/<int:rule_id>', methods=['DELETE'])
|
||||
@alerts_bp.route("/rules/<int:rule_id>", methods=["DELETE"])
|
||||
def delete_rule(rule_id: int):
|
||||
manager = get_alert_manager()
|
||||
ok = manager.delete_rule(rule_id)
|
||||
if not ok:
|
||||
return api_error('Rule not found', 404)
|
||||
return api_error("Rule not found", 404)
|
||||
return api_success()
|
||||
|
||||
|
||||
@alerts_bp.route('/events', methods=['GET'])
|
||||
@alerts_bp.route("/events", methods=["GET"])
|
||||
def list_events():
|
||||
manager = get_alert_manager()
|
||||
limit = request.args.get('limit', default=100, type=int)
|
||||
mode = request.args.get('mode')
|
||||
severity = request.args.get('severity')
|
||||
limit = request.args.get("limit", default=100, type=int)
|
||||
mode = request.args.get("mode")
|
||||
severity = request.args.get("severity")
|
||||
events = manager.list_events(limit=limit, mode=mode, severity=severity)
|
||||
return api_success(data={'events': events})
|
||||
return api_success(data={"events": events})
|
||||
|
||||
|
||||
@alerts_bp.route('/stream', methods=['GET'])
|
||||
@alerts_bp.route("/stream", methods=["GET"])
|
||||
def stream_alerts() -> Response:
|
||||
manager = get_alert_manager()
|
||||
|
||||
def generate() -> Generator[str, None, None]:
|
||||
for event in manager.stream_events(timeout=1.0):
|
||||
yield format_sse(event)
|
||||
|
||||
response = Response(generate(), mimetype='text/event-stream')
|
||||
response.headers['Cache-Control'] = 'no-cache'
|
||||
response.headers['X-Accel-Buffering'] = 'no'
|
||||
response.headers['Connection'] = 'keep-alive'
|
||||
response = Response(
|
||||
sse_stream_fanout(
|
||||
source_queue=manager._queue,
|
||||
channel_key="alerts",
|
||||
timeout=1.0,
|
||||
keepalive_interval=30.0,
|
||||
),
|
||||
mimetype="text/event-stream",
|
||||
)
|
||||
response.headers["Cache-Control"] = "no-cache"
|
||||
response.headers["X-Accel-Buffering"] = "no"
|
||||
response.headers["Connection"] = "keep-alive"
|
||||
return response
|
||||
|
||||
+542
-523
File diff suppressed because it is too large
Load Diff
@@ -1031,7 +1031,7 @@ body {
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 6px;
|
||||
border: 1px solid rgba(0, 212, 255, 0.3);
|
||||
border: 1px solid rgba(var(--accent-cyan-rgb), 0.3);
|
||||
}
|
||||
|
||||
.selected-callsign {
|
||||
@@ -2227,6 +2227,10 @@ body {
|
||||
color: var(--text-inverse);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .strip-btn.primary {
|
||||
background: linear-gradient(135deg, rgba(46, 125, 138, 0.85) 0%, rgba(20, 88, 100, 0.80) 100%);
|
||||
}
|
||||
|
||||
.strip-btn.primary:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(var(--accent-cyan-rgb), 0.3);
|
||||
@@ -2462,19 +2466,18 @@ body {
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
ENHANCED TIER — amber military console
|
||||
ENHANCED TIER — signals teal console
|
||||
============================================ */
|
||||
html[data-ui-tier="enhanced"] {
|
||||
--bg-dark: #080600;
|
||||
--bg-panel: #0c0a04;
|
||||
--bg-card: #0e0b05;
|
||||
--radar-bg: #0c0a04;
|
||||
--radar-cyan: #c89628;
|
||||
--border-glow: rgba(200, 150, 40, 0.25);
|
||||
--border-color: rgba(200, 150, 40, 0.2);
|
||||
--grid-line: rgba(200, 150, 40, 0.07);
|
||||
--accent-cyan: #c89628;
|
||||
--accent-green: #c89628;
|
||||
--bg-dark: #000000;
|
||||
--bg-panel: #020404;
|
||||
--bg-card: #020404;
|
||||
--radar-bg: #020404;
|
||||
--radar-cyan: #2e7d8a;
|
||||
--border-glow: rgba(46, 125, 138, 0.20);
|
||||
--border-color: rgba(46, 125, 138, 0.18);
|
||||
--grid-line: rgba(46, 125, 138, 0.07);
|
||||
--accent-cyan: #2e7d8a;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
|
||||
@@ -721,3 +721,28 @@ body {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] {
|
||||
--accent-cyan: #2e7d8a;
|
||||
--accent-cyan-rgb: 46, 125, 138;
|
||||
--border-color: rgba(46, 125, 138, 0.18);
|
||||
--border-glow: rgba(46, 125, 138, 0.20);
|
||||
--grid-line: rgba(46, 125, 138, 0.07);
|
||||
--bg-dark: #000000;
|
||||
--bg-panel: #020404;
|
||||
--bg-card: #020404;
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] body {
|
||||
background: #000000;
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .session-strip {
|
||||
background: linear-gradient(120deg, rgba(4, 8, 8, 0.95), rgba(6, 10, 10, 0.95));
|
||||
}
|
||||
|
||||
html[data-ui-tier="lean"] {
|
||||
--border-color: #2a2a2a;
|
||||
--border-glow: transparent;
|
||||
--grid-line: transparent;
|
||||
}
|
||||
|
||||
@@ -10,15 +10,15 @@
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 6px 12px;
|
||||
background: rgba(0, 212, 255, 0.1);
|
||||
border: 1px solid rgba(0, 212, 255, 0.3);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.1);
|
||||
border: 1px solid rgba(var(--accent-cyan-rgb), 0.3);
|
||||
border-radius: 20px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.agent-indicator:hover {
|
||||
background: rgba(0, 212, 255, 0.2);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.2);
|
||||
border-color: var(--accent-cyan);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
.agent-indicator-count {
|
||||
font-size: 10px;
|
||||
padding: 2px 6px;
|
||||
background: rgba(0, 212, 255, 0.2);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.2);
|
||||
border-radius: 10px;
|
||||
color: var(--accent-cyan);
|
||||
}
|
||||
@@ -123,11 +123,11 @@
|
||||
}
|
||||
|
||||
.agent-selector-item:hover {
|
||||
background: rgba(0, 212, 255, 0.1);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.1);
|
||||
}
|
||||
|
||||
.agent-selector-item.selected {
|
||||
background: rgba(0, 212, 255, 0.15);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.15);
|
||||
border-left: 3px solid var(--accent-cyan);
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@
|
||||
gap: 4px;
|
||||
padding: 2px 8px;
|
||||
font-size: 10px;
|
||||
background: rgba(0, 212, 255, 0.1);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.1);
|
||||
color: var(--accent-cyan);
|
||||
border-radius: 10px;
|
||||
font-family: var(--font-mono);
|
||||
@@ -201,7 +201,7 @@
|
||||
}
|
||||
|
||||
.agent-badge.agent-remote {
|
||||
background: rgba(0, 212, 255, 0.1);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.1);
|
||||
color: var(--accent-cyan);
|
||||
}
|
||||
|
||||
|
||||
@@ -1375,19 +1375,18 @@ body {
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
ENHANCED TIER — amber military console
|
||||
ENHANCED TIER — signals teal console
|
||||
============================================ */
|
||||
html[data-ui-tier="enhanced"] {
|
||||
--bg-dark: #080600;
|
||||
--bg-panel: #0c0a04;
|
||||
--bg-card: #0e0b05;
|
||||
--radar-bg: #0c0a04;
|
||||
--radar-cyan: #c89628;
|
||||
--border-glow: rgba(200, 150, 40, 0.25);
|
||||
--border-color: rgba(200, 150, 40, 0.2);
|
||||
--grid-line: rgba(200, 150, 40, 0.07);
|
||||
--accent-cyan: #c89628;
|
||||
--accent-green: #c89628;
|
||||
--bg-dark: #000000;
|
||||
--bg-panel: #020404;
|
||||
--bg-card: #020404;
|
||||
--radar-bg: #020404;
|
||||
--radar-cyan: #2e7d8a;
|
||||
--border-glow: rgba(46, 125, 138, 0.20);
|
||||
--border-color: rgba(46, 125, 138, 0.18);
|
||||
--grid-line: rgba(46, 125, 138, 0.07);
|
||||
--accent-cyan: #2e7d8a;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
.device-card:hover {
|
||||
border-color: var(--accent-cyan, #00d4ff);
|
||||
box-shadow: 0 0 0 1px rgba(0, 212, 255, 0.2);
|
||||
box-shadow: 0 0 0 1px rgba(var(--accent-cyan-rgb), 0.2);
|
||||
}
|
||||
|
||||
.device-card:active {
|
||||
|
||||
@@ -162,8 +162,8 @@
|
||||
}
|
||||
|
||||
.heatmap-row.selected {
|
||||
background: rgba(0, 212, 255, 0.1);
|
||||
outline: 1px solid rgba(0, 212, 255, 0.3);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.1);
|
||||
outline: 1px solid rgba(var(--accent-cyan-rgb), 0.3);
|
||||
}
|
||||
|
||||
.heatmap-header {
|
||||
|
||||
@@ -1645,7 +1645,7 @@
|
||||
|
||||
.signal-card.signal-card-clickable:hover {
|
||||
border-color: var(--accent-cyan, #00d4ff);
|
||||
box-shadow: 0 0 0 1px rgba(0, 212, 255, 0.2);
|
||||
box-shadow: 0 0 0 1px rgba(var(--accent-cyan-rgb), 0.2);
|
||||
}
|
||||
|
||||
.signal-card.signal-card-clickable:active {
|
||||
|
||||
@@ -406,6 +406,42 @@
|
||||
color: var(--text-primary, #e6edf5);
|
||||
}
|
||||
|
||||
/* ---- Enhanced tier overrides ---- */
|
||||
html[data-ui-tier="enhanced"] .run-state-strip {
|
||||
background: linear-gradient(180deg, rgba(4, 8, 8, 0.96), rgba(2, 4, 4, 0.97));
|
||||
border-color: rgba(46, 125, 138, 0.28);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .run-state-chip {
|
||||
background: linear-gradient(180deg, rgba(4, 8, 8, 0.82), rgba(2, 4, 4, 0.84));
|
||||
border-color: rgba(46, 125, 138, 0.22);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .run-state-chip.active {
|
||||
border-color: rgba(46, 125, 138, 0.60);
|
||||
box-shadow: inset 0 0 0 1px rgba(46, 125, 138, 0.16);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .run-state-chip .dot {
|
||||
background: rgba(46, 125, 138, 0.40);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .run-state-chip.running .dot {
|
||||
background: var(--accent-green, #38c180);
|
||||
box-shadow: 0 0 0 4px rgba(56, 193, 128, 0.16), 0 0 12px rgba(56, 193, 128, 0.35);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .run-state-btn {
|
||||
background: linear-gradient(180deg, rgba(4, 8, 8, 0.9), rgba(2, 4, 4, 0.92));
|
||||
border-color: rgba(46, 125, 138, 0.40);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .run-state-btn:hover {
|
||||
background: rgba(46, 125, 138, 0.12);
|
||||
border-color: rgba(46, 125, 138, 0.65);
|
||||
}
|
||||
|
||||
/* ---- Light theme overrides ---- */
|
||||
[data-theme="light"] .run-state-chip {
|
||||
background: linear-gradient(180deg, rgba(233, 238, 245, 0.9), rgba(225, 232, 242, 0.92));
|
||||
|
||||
@@ -1206,12 +1206,12 @@ textarea:focus {
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
ENHANCED TIER — amber left-border card accents
|
||||
ENHANCED TIER — signals teal card accents
|
||||
============================================ */
|
||||
[data-ui-tier="enhanced"] .stat-card,
|
||||
[data-ui-tier="enhanced"] .data-card {
|
||||
border-left: 2px solid var(--accent-cyan);
|
||||
background: rgba(200, 150, 40, 0.03);
|
||||
background: rgba(46, 125, 138, 0.03);
|
||||
}
|
||||
|
||||
[data-ui-tier="enhanced"] .stat-value,
|
||||
@@ -1226,5 +1226,10 @@ textarea:focus {
|
||||
letter-spacing: 2px;
|
||||
text-transform: uppercase;
|
||||
font-size: var(--text-xs);
|
||||
color: rgba(200, 150, 40, 0.5);
|
||||
color: rgba(46, 125, 138, 0.55);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .card-header,
|
||||
html[data-ui-tier="enhanced"] .panel-header {
|
||||
background: linear-gradient(180deg, rgba(4, 8, 8, 0.88) 0%, rgba(2, 4, 4, 0.9) 100%);
|
||||
}
|
||||
|
||||
+12
-12
@@ -1188,10 +1188,10 @@ a.nav-dashboard-btn:hover {
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
ENHANCED TIER — amber console nav framing
|
||||
ENHANCED TIER — signals teal console nav framing
|
||||
============================================ */
|
||||
[data-ui-tier="enhanced"] .mode-nav {
|
||||
background: linear-gradient(180deg, rgba(14, 11, 3, 0.95), rgba(8, 6, 0, 0.92));
|
||||
background: linear-gradient(180deg, rgba(4, 8, 8, 0.95), rgba(2, 4, 4, 0.92));
|
||||
}
|
||||
|
||||
[data-ui-tier="enhanced"] .mode-nav::after,
|
||||
@@ -1201,16 +1201,16 @@ a.nav-dashboard-btn:hover {
|
||||
}
|
||||
|
||||
[data-ui-tier="enhanced"] .mode-nav-btn.active {
|
||||
background: rgba(200, 150, 40, 0.08);
|
||||
background: rgba(46, 125, 138, 0.08);
|
||||
color: var(--accent-cyan);
|
||||
border-left: 2px solid var(--accent-cyan);
|
||||
box-shadow: -2px 0 8px rgba(200, 150, 40, 0.15);
|
||||
box-shadow: -2px 0 8px rgba(46, 125, 138, 0.15);
|
||||
padding-left: 12px;
|
||||
}
|
||||
|
||||
[data-ui-tier="enhanced"] .nav-clock .utc-time {
|
||||
color: var(--accent-cyan);
|
||||
text-shadow: 0 0 8px rgba(200, 150, 40, 0.3);
|
||||
text-shadow: 0 0 8px rgba(46, 125, 138, 0.28);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
@@ -1236,14 +1236,14 @@ a.nav-dashboard-btn:hover {
|
||||
|
||||
/* Enhanced tier toggle button styling */
|
||||
[data-ui-tier="enhanced"] .nav-tier-btn {
|
||||
background: rgba(200, 150, 40, 0.10);
|
||||
border-color: rgba(200, 150, 40, 0.4);
|
||||
color: #c89628;
|
||||
box-shadow: 0 0 8px rgba(200, 150, 40, 0.08);
|
||||
text-shadow: 0 0 6px rgba(200, 150, 40, 0.3);
|
||||
background: rgba(46, 125, 138, 0.10);
|
||||
border-color: rgba(46, 125, 138, 0.38);
|
||||
color: #2e7d8a;
|
||||
box-shadow: 0 0 8px rgba(46, 125, 138, 0.07);
|
||||
text-shadow: 0 0 6px rgba(46, 125, 138, 0.25);
|
||||
}
|
||||
|
||||
[data-ui-tier="enhanced"] .nav-tier-btn:hover {
|
||||
background: rgba(200, 150, 40, 0.16);
|
||||
border-color: rgba(200, 150, 40, 0.6);
|
||||
background: rgba(46, 125, 138, 0.16);
|
||||
border-color: rgba(46, 125, 138, 0.55);
|
||||
}
|
||||
|
||||
+156
-108
@@ -29,6 +29,7 @@
|
||||
/* Accent colors */
|
||||
--accent-cyan: #4aa3ff;
|
||||
--accent-cyan-rgb: 74, 163, 255;
|
||||
--primary-color: var(--accent-cyan);
|
||||
--accent-cyan-dim: rgba(var(--accent-cyan-rgb), 0.16);
|
||||
--accent-cyan-hover: #6bb3ff;
|
||||
--accent-cyan-glow: rgba(var(--accent-cyan-rgb), 0.12);
|
||||
@@ -108,7 +109,7 @@
|
||||
/* ============================================
|
||||
TYPOGRAPHY
|
||||
============================================ */
|
||||
--font-sans: 'Roboto Condensed', 'Arial Narrow', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
--font-sans: 'Inter', 'Roboto Condensed', 'Helvetica Neue', Arial, sans-serif;
|
||||
--font-mono: 'JetBrains Mono', 'Fira Code', 'Source Code Pro', Consolas, monospace;
|
||||
|
||||
/* Font sizes */
|
||||
@@ -178,85 +179,6 @@
|
||||
--content-max-width: 1400px;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
LIGHT THEME OVERRIDES
|
||||
============================================ */
|
||||
[data-theme="light"] {
|
||||
--bg-primary: #f4f7fb;
|
||||
--bg-secondary: #e9eef5;
|
||||
--bg-tertiary: #dde5f0;
|
||||
--bg-card: #ffffff;
|
||||
--bg-elevated: #f1f4f9;
|
||||
--bg-overlay: rgba(244, 247, 251, 0.92);
|
||||
--surface-glass: rgba(255, 255, 255, 0.84);
|
||||
--surface-panel-gradient: linear-gradient(160deg, rgba(255, 255, 255, 0.96) 0%, rgba(241, 245, 251, 0.97) 100%);
|
||||
--ambient-top-left: rgba(31, 95, 168, 0.1);
|
||||
--ambient-top-right: rgba(31, 138, 87, 0.06);
|
||||
--ambient-bottom: rgba(181, 134, 58, 0.05);
|
||||
|
||||
/* Background aliases for components */
|
||||
--bg-dark: var(--bg-primary);
|
||||
--bg-panel: var(--bg-secondary);
|
||||
|
||||
--accent-cyan: #1f5fa8;
|
||||
--accent-cyan-rgb: 31, 95, 168;
|
||||
--accent-cyan-dim: rgba(31, 95, 168, 0.12);
|
||||
--accent-cyan-hover: #2c73bf;
|
||||
--accent-green: #1f8a57;
|
||||
--accent-green-hover: #167a4a;
|
||||
--accent-green-dim: rgba(31, 138, 87, 0.12);
|
||||
--accent-red: #c74444;
|
||||
--accent-red-hover: #b33a3a;
|
||||
--accent-red-dim: rgba(199, 68, 68, 0.12);
|
||||
--accent-orange: #b5863a;
|
||||
--accent-orange-dim: rgba(181, 134, 58, 0.12);
|
||||
--accent-amber: #b5863a;
|
||||
--accent-amber-dim: rgba(181, 134, 58, 0.12);
|
||||
--accent-yellow: #9a8420;
|
||||
--accent-purple: #6b5ba8;
|
||||
|
||||
/* Status colors - light theme */
|
||||
--status-online: #1f8a57;
|
||||
--status-warning: #b5863a;
|
||||
--status-error: #c74444;
|
||||
--status-offline: #6b7c93;
|
||||
--status-info: #1f5fa8;
|
||||
|
||||
/* Severity colors */
|
||||
--severity-critical: #c74444;
|
||||
--severity-high: #b5863a;
|
||||
--severity-medium: #9a8420;
|
||||
--severity-low: #1f8a57;
|
||||
|
||||
/* Data visualization neon replacements */
|
||||
--neon-green: #1a8a50;
|
||||
--neon-yellow: #9a8420;
|
||||
--neon-orange: #b5863a;
|
||||
--neon-red: #c74444;
|
||||
|
||||
--text-primary: #122034;
|
||||
--text-secondary: #3a4a5f;
|
||||
--text-dim: #566a7f;
|
||||
--text-muted: #7a8a9e;
|
||||
--text-inverse: #f4f7fb;
|
||||
|
||||
--border-color: #d1d9e6;
|
||||
--border-light: #c1ccdb;
|
||||
--border-glow: rgba(31, 95, 168, 0.12);
|
||||
|
||||
--grid-line: rgba(31, 95, 168, 0.14);
|
||||
--grid-dot: rgba(12, 18, 24, 0.06);
|
||||
--noise-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='40'%20height='40'%20viewBox='0%200%2040%2040'%3E%3Cg%20fill='%23000000'%20fill-opacity='0.05'%3E%3Ccircle%20cx='3'%20cy='5'%20r='1'/%3E%3Ccircle%20cx='11'%20cy='9'%20r='1'/%3E%3Ccircle%20cx='18'%20cy='3'%20r='1'/%3E%3Ccircle%20cx='26'%20cy='12'%20r='1'/%3E%3Ccircle%20cx='34'%20cy='6'%20r='1'/%3E%3Ccircle%20cx='7'%20cy='19'%20r='1'/%3E%3Ccircle%20cx='15'%20cy='24'%20r='1'/%3E%3Ccircle%20cx='28'%20cy='22'%20r='1'/%3E%3Ccircle%20cx='36'%20cy='18'%20r='1'/%3E%3Ccircle%20cx='5'%20cy='33'%20r='1'/%3E%3Ccircle%20cx='19'%20cy='32'%20r='1'/%3E%3Ccircle%20cx='31'%20cy='34'%20r='1'/%3E%3C/g%3E%3C/svg%3E");
|
||||
|
||||
--accent-cyan-glow: rgba(31, 95, 168, 0.08);
|
||||
--scanline: none;
|
||||
|
||||
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.15);
|
||||
--shadow-glow: 0 0 18px rgba(31, 95, 168, 0.1);
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
REDUCED MOTION
|
||||
============================================ */
|
||||
@@ -304,40 +226,166 @@ html[data-ui-tier="lean"] {
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
ENHANCED TIER — amber military console
|
||||
ENHANCED TIER — signals teal console
|
||||
============================================ */
|
||||
html[data-ui-tier="enhanced"] {
|
||||
--bg-primary: #080600;
|
||||
--bg-secondary: #0c0a04;
|
||||
--bg-tertiary: #100d06;
|
||||
--bg-card: #0e0b05;
|
||||
--bg-elevated: #141008;
|
||||
--bg-overlay: rgba(8, 6, 0, 0.82);
|
||||
--surface-glass: rgba(14, 11, 5, 0.82);
|
||||
--surface-panel-gradient: linear-gradient(160deg, rgba(20, 16, 8, 0.94) 0%, rgba(12, 10, 4, 0.96) 100%);
|
||||
--bg-primary: #000000;
|
||||
--bg-secondary: #020404;
|
||||
--bg-tertiary: #040808;
|
||||
--bg-card: #020404;
|
||||
--bg-elevated: #060a0a;
|
||||
--bg-overlay: rgba(0, 0, 0, 0.88);
|
||||
--surface-glass: rgba(2, 4, 4, 0.90);
|
||||
--surface-panel-gradient: linear-gradient(160deg, rgba(6, 10, 10, 0.96) 0%, rgba(2, 4, 4, 0.98) 100%);
|
||||
|
||||
--accent-cyan: #c89628;
|
||||
--accent-cyan-rgb: 200, 150, 40;
|
||||
--accent-cyan-dim: rgba(200, 150, 40, 0.14);
|
||||
--accent-cyan-hover: #e0aa30;
|
||||
--accent-cyan-glow: rgba(200, 150, 40, 0.10);
|
||||
--accent-cyan: #2e7d8a;
|
||||
--accent-cyan-rgb: 46, 125, 138;
|
||||
--accent-cyan-dim: rgba(46, 125, 138, 0.14);
|
||||
--accent-cyan-hover: #3a9aaa;
|
||||
--accent-cyan-glow: rgba(46, 125, 138, 0.09);
|
||||
|
||||
--accent-green: #c89628;
|
||||
--accent-green-hover: #e0aa30;
|
||||
--accent-green-dim: rgba(200, 150, 40, 0.14);
|
||||
/* red/green intentionally unchanged — semantic status only */
|
||||
|
||||
/* red is intentionally unchanged — critical alerts only */
|
||||
--ambient-top-left: rgba(46, 125, 138, 0.07);
|
||||
--ambient-top-right: rgba(46, 125, 138, 0.04);
|
||||
--ambient-bottom: rgba(46, 125, 138, 0.03);
|
||||
|
||||
--ambient-top-left: rgba(200, 150, 40, 0.08);
|
||||
--ambient-top-right: rgba(200, 150, 40, 0.05);
|
||||
--ambient-bottom: rgba(200, 150, 40, 0.04);
|
||||
--grid-line: rgba(46, 125, 138, 0.07);
|
||||
--border-color: rgba(46, 125, 138, 0.18);
|
||||
--border-light: rgba(46, 125, 138, 0.28);
|
||||
--border-glow: rgba(46, 125, 138, 0.20);
|
||||
--border-focus: #2e7d8a;
|
||||
|
||||
--grid-line: rgba(200, 150, 40, 0.07);
|
||||
--border-color: rgba(200, 150, 40, 0.2);
|
||||
--border-light: rgba(200, 150, 40, 0.3);
|
||||
--border-glow: rgba(200, 150, 40, 0.25);
|
||||
--border-focus: #c89628;
|
||||
--status-info: #2e7d8a;
|
||||
|
||||
--status-online: #c89628;
|
||||
--status-info: #c89628;
|
||||
--font-sans: 'Inter', 'Roboto Condensed', 'Helvetica Neue', Arial, sans-serif;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
LIGHT THEME OVERRIDES
|
||||
Placed after tier blocks so html[data-theme="light"]
|
||||
(specificity 0,1,1) beats both tier selectors when active.
|
||||
============================================ */
|
||||
html[data-theme="light"] {
|
||||
--bg-primary: #f4f7fb;
|
||||
--bg-secondary: #e9eef5;
|
||||
--bg-tertiary: #dde5f0;
|
||||
--bg-card: #ffffff;
|
||||
--bg-elevated: #f1f4f9;
|
||||
--bg-overlay: rgba(244, 247, 251, 0.92);
|
||||
--surface-glass: rgba(255, 255, 255, 0.84);
|
||||
--surface-panel-gradient: linear-gradient(160deg, rgba(255, 255, 255, 0.96) 0%, rgba(241, 245, 251, 0.97) 100%);
|
||||
--ambient-top-left: rgba(31, 95, 168, 0.1);
|
||||
--ambient-top-right: rgba(31, 138, 87, 0.06);
|
||||
--ambient-bottom: rgba(181, 134, 58, 0.05);
|
||||
|
||||
--bg-dark: var(--bg-primary);
|
||||
--bg-panel: var(--bg-secondary);
|
||||
|
||||
--accent-cyan: #1f5fa8;
|
||||
--accent-cyan-rgb: 31, 95, 168;
|
||||
--accent-cyan-dim: rgba(31, 95, 168, 0.12);
|
||||
--accent-cyan-hover: #2c73bf;
|
||||
--accent-green: #1f8a57;
|
||||
--accent-green-hover: #167a4a;
|
||||
--accent-green-dim: rgba(31, 138, 87, 0.12);
|
||||
--accent-red: #c74444;
|
||||
--accent-red-hover: #b33a3a;
|
||||
--accent-red-dim: rgba(199, 68, 68, 0.12);
|
||||
--accent-orange: #b5863a;
|
||||
--accent-orange-dim: rgba(181, 134, 58, 0.12);
|
||||
--accent-amber: #b5863a;
|
||||
--accent-amber-dim: rgba(181, 134, 58, 0.12);
|
||||
--accent-yellow: #9a8420;
|
||||
--accent-purple: #6b5ba8;
|
||||
|
||||
--status-online: #1f8a57;
|
||||
--status-warning: #b5863a;
|
||||
--status-error: #c74444;
|
||||
--status-offline: #6b7c93;
|
||||
--status-info: #1f5fa8;
|
||||
|
||||
--severity-critical: #c74444;
|
||||
--severity-high: #b5863a;
|
||||
--severity-medium: #9a8420;
|
||||
--severity-low: #1f8a57;
|
||||
|
||||
--neon-green: #1a8a50;
|
||||
--neon-yellow: #9a8420;
|
||||
--neon-orange: #b5863a;
|
||||
--neon-red: #c74444;
|
||||
|
||||
--text-primary: #122034;
|
||||
--text-secondary: #3a4a5f;
|
||||
--text-dim: #566a7f;
|
||||
--text-muted: #7a8a9e;
|
||||
--text-inverse: #f4f7fb;
|
||||
|
||||
--border-color: #d1d9e6;
|
||||
--border-light: #c1ccdb;
|
||||
--border-glow: rgba(31, 95, 168, 0.12);
|
||||
|
||||
--grid-line: rgba(31, 95, 168, 0.14);
|
||||
--grid-dot: rgba(12, 18, 24, 0.06);
|
||||
--noise-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='40'%20height='40'%20viewBox='0%200%2040%2040'%3E%3Cg%20fill='%23000000'%20fill-opacity='0.05'%3E%3Ccircle%20cx='3'%20cy='5'%20r='1'/%3E%3Ccircle%20cx='11'%20cy='9'%20r='1'/%3E%3Ccircle%20cx='18'%20cy='3'%20r='1'/%3E%3Ccircle%20cx='26'%20cy='12'%20r='1'/%3E%3Ccircle%20cx='34'%20cy='6'%20r='1'/%3E%3Ccircle%20cx='7'%20cy='19'%20r='1'/%3E%3Ccircle%20cx='15'%20cy='24'%20r='1'/%3E%3Ccircle%20cx='28'%20cy='22'%20r='1'/%3E%3Ccircle%20cx='36'%20cy='18'%20r='1'/%3E%3Ccircle%20cx='5'%20cy='33'%20r='1'/%3E%3Ccircle%20cx='19'%20cy='32'%20r='1'/%3E%3Ccircle%20cx='31'%20cy='34'%20r='1'/%3E%3C/g%3E%3C/svg%3E");
|
||||
|
||||
--accent-cyan-glow: rgba(31, 95, 168, 0.08);
|
||||
--scanline: none;
|
||||
|
||||
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.15);
|
||||
--shadow-glow: 0 0 18px rgba(31, 95, 168, 0.1);
|
||||
}
|
||||
|
||||
/* Lean tier + light: specificity (0,2,1) beats lean-only (0,1,1) */
|
||||
html[data-ui-tier="lean"][data-theme="light"] {
|
||||
--bg-primary: #f4f7fb;
|
||||
--bg-secondary: #e9eef5;
|
||||
--bg-tertiary: #dde5f0;
|
||||
--bg-card: #ffffff;
|
||||
--bg-elevated: #f1f4f9;
|
||||
--bg-dark: #f4f7fb;
|
||||
--bg-panel: #e9eef5;
|
||||
--bg-overlay: rgba(244, 247, 251, 0.92);
|
||||
--surface-glass: rgba(255, 255, 255, 0.84);
|
||||
--surface-panel-gradient: linear-gradient(160deg, rgba(255, 255, 255, 0.96) 0%, rgba(241, 245, 251, 0.97) 100%);
|
||||
--accent-cyan: #1f5fa8;
|
||||
--accent-cyan-rgb: 31, 95, 168;
|
||||
--accent-cyan-dim: rgba(31, 95, 168, 0.12);
|
||||
--accent-green: #1f8a57;
|
||||
--text-primary: #122034;
|
||||
--text-secondary: #3a4a5f;
|
||||
--text-dim: #566a7f;
|
||||
--text-muted: #7a8a9e;
|
||||
--border-color: #d1d9e6;
|
||||
--border-light: #c1ccdb;
|
||||
--border-glow: rgba(31, 95, 168, 0.12);
|
||||
--grid-line: rgba(31, 95, 168, 0.14);
|
||||
--ambient-top-left: rgba(31, 95, 168, 0.1);
|
||||
--ambient-top-right: rgba(31, 138, 87, 0.06);
|
||||
--ambient-bottom: rgba(181, 134, 58, 0.05);
|
||||
}
|
||||
|
||||
/* Enhanced tier + light: cool whites with signals teal accents */
|
||||
html[data-ui-tier="enhanced"][data-theme="light"] {
|
||||
--bg-primary: #f4f7fb;
|
||||
--bg-secondary: #e9eef5;
|
||||
--bg-tertiary: #dde5f0;
|
||||
--bg-card: #ffffff;
|
||||
--bg-elevated: #f1f4f9;
|
||||
--bg-dark: #f4f7fb;
|
||||
--bg-panel: #e9eef5;
|
||||
--bg-overlay: rgba(244, 247, 251, 0.92);
|
||||
--surface-glass: rgba(255, 255, 255, 0.84);
|
||||
--text-primary: #0a1a1e;
|
||||
--text-secondary: #1c3a42;
|
||||
--text-dim: #3a5a62;
|
||||
--border-color: rgba(30, 100, 112, 0.28);
|
||||
--grid-line: rgba(30, 100, 112, 0.12);
|
||||
--accent-cyan: #1e6470;
|
||||
--accent-cyan-rgb: 30, 100, 112;
|
||||
--accent-cyan-dim: rgba(30, 100, 112, 0.12);
|
||||
--accent-cyan-hover: #25808e;
|
||||
--accent-cyan-glow: rgba(30, 100, 112, 0.08);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Local font declarations for offline mode */
|
||||
/* Roboto Condensed - variable font, one file covers all weights */
|
||||
|
||||
/* Roboto Condensed - variable font, one file covers all weights */
|
||||
@font-face {
|
||||
font-family: 'Roboto Condensed';
|
||||
font-style: normal;
|
||||
@@ -18,3 +18,69 @@
|
||||
src: url('/static/vendor/fonts/RobotoCondensed-LatinExt.woff2') format('woff2');
|
||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* Inter - used by enhanced tier */
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url('/static/vendor/fonts/Inter-Regular.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url('/static/vendor/fonts/Inter-Medium.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url('/static/vendor/fonts/Inter-SemiBold.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url('/static/vendor/fonts/Inter-Bold.woff2') format('woff2');
|
||||
}
|
||||
|
||||
/* JetBrains Mono - used by enhanced tier and all --font-mono elements */
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url('/static/vendor/fonts/JetBrainsMono-Regular.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url('/static/vendor/fonts/JetBrainsMono-Medium.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url('/static/vendor/fonts/JetBrainsMono-SemiBold.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url('/static/vendor/fonts/JetBrainsMono-Bold.woff2') format('woff2');
|
||||
}
|
||||
|
||||
+89
-18
@@ -262,10 +262,10 @@ body {
|
||||
|
||||
@keyframes logoPulse {
|
||||
0%, 100% {
|
||||
filter: drop-shadow(0 0 15px rgba(0, 212, 255, 0.3));
|
||||
filter: drop-shadow(0 0 15px rgba(var(--accent-cyan-rgb), 0.3));
|
||||
}
|
||||
50% {
|
||||
filter: drop-shadow(0 0 30px rgba(0, 212, 255, 0.6));
|
||||
filter: drop-shadow(0 0 30px rgba(var(--accent-cyan-rgb), 0.6));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,7 +304,7 @@ body {
|
||||
color: var(--text-primary);
|
||||
letter-spacing: 0.2em;
|
||||
margin: 0;
|
||||
text-shadow: 0 0 20px rgba(0, 212, 255, 0.3);
|
||||
text-shadow: 0 0 20px rgba(var(--accent-cyan-rgb), 0.3);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@@ -453,7 +453,7 @@ body {
|
||||
background: var(--bg-elevated);
|
||||
border-color: var(--accent-cyan);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 20px rgba(0, 212, 255, 0.15);
|
||||
box-shadow: 0 4px 20px rgba(var(--accent-cyan-rgb), 0.15);
|
||||
}
|
||||
|
||||
.mode-card:hover .mode-icon {
|
||||
@@ -2529,7 +2529,7 @@ header h1 .tagline {
|
||||
border: 1px solid var(--accent-cyan);
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 0 20px rgba(0, 212, 255, 0.2);
|
||||
box-shadow: 0 0 20px rgba(var(--accent-cyan-rgb), 0.2);
|
||||
}
|
||||
|
||||
#aircraftMap {
|
||||
@@ -2863,7 +2863,7 @@ header h1 .tagline {
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
margin-bottom: 15px;
|
||||
box-shadow: 0 0 20px rgba(0, 212, 255, 0.1);
|
||||
box-shadow: 0 0 20px rgba(var(--accent-cyan-rgb), 0.1);
|
||||
}
|
||||
|
||||
.countdown-satellite-name {
|
||||
@@ -5879,7 +5879,7 @@ body::before {
|
||||
max-width: 550px;
|
||||
padding: 30px;
|
||||
text-align: center;
|
||||
box-shadow: 0 0 50px rgba(0, 212, 255, 0.3);
|
||||
box-shadow: 0 0 50px rgba(var(--accent-cyan-rgb), 0.3);
|
||||
pointer-events: auto;
|
||||
position: relative;
|
||||
z-index: 100000;
|
||||
@@ -5939,7 +5939,7 @@ body::before {
|
||||
|
||||
.disclaimer-modal .accept-btn:hover {
|
||||
background: #fff;
|
||||
box-shadow: 0 0 20px rgba(0, 212, 255, 0.5);
|
||||
box-shadow: 0 0 20px rgba(var(--accent-cyan-rgb), 0.5);
|
||||
}
|
||||
|
||||
.disclaimer-hidden {
|
||||
@@ -6190,7 +6190,7 @@ body::before {
|
||||
|
||||
/* Map Clustering */
|
||||
.marker-cluster {
|
||||
background: rgba(0, 212, 255, 0.6);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.6);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -7045,7 +7045,7 @@ body::before {
|
||||
.radio-module-box.scanner-main {
|
||||
background: linear-gradient(180deg, var(--bg-secondary) 0%, rgba(0,20,30,0.95) 100%);
|
||||
border: 1px solid var(--accent-cyan-dim);
|
||||
box-shadow: 0 0 20px rgba(0, 212, 255, 0.1), inset 0 0 40px rgba(0, 0, 0, 0.3);
|
||||
box-shadow: 0 0 20px rgba(var(--accent-cyan-rgb), 0.1), inset 0 0 40px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.radio-module-box.scanner-main::before {
|
||||
@@ -7224,7 +7224,7 @@ body::before {
|
||||
}
|
||||
|
||||
.radio-module-box table tbody tr:hover {
|
||||
background: rgba(0, 212, 255, 0.05);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.05);
|
||||
}
|
||||
|
||||
/* Log Content Compact */
|
||||
@@ -7257,14 +7257,14 @@ body::before {
|
||||
.radio-mode-btn:hover {
|
||||
border-color: var(--accent-cyan);
|
||||
color: var(--accent-cyan);
|
||||
background: rgba(0, 212, 255, 0.05);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.05);
|
||||
}
|
||||
|
||||
.radio-mode-btn.active {
|
||||
background: linear-gradient(135deg, rgba(0, 212, 255, 0.2), rgba(0, 255, 136, 0.1));
|
||||
background: linear-gradient(135deg, rgba(var(--accent-cyan-rgb), 0.2), rgba(0, 255, 136, 0.1));
|
||||
border-color: var(--accent-cyan);
|
||||
color: var(--accent-cyan);
|
||||
box-shadow: 0 0 20px rgba(0, 212, 255, 0.2), inset 0 0 20px rgba(0, 212, 255, 0.05);
|
||||
box-shadow: 0 0 20px rgba(var(--accent-cyan-rgb), 0.2), inset 0 0 20px rgba(var(--accent-cyan-rgb), 0.05);
|
||||
}
|
||||
|
||||
/* Listening Mode Panels */
|
||||
@@ -7292,7 +7292,7 @@ body::before {
|
||||
.preset-freq-btn:hover {
|
||||
border-color: var(--accent-cyan);
|
||||
color: var(--accent-cyan);
|
||||
background: rgba(0, 212, 255, 0.1);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.1);
|
||||
}
|
||||
|
||||
.preset-freq-btn:active {
|
||||
@@ -7652,6 +7652,11 @@ body[data-mode="tscm"] {
|
||||
background-size: unset;
|
||||
}
|
||||
|
||||
html[data-ui-tier="lean"][data-theme="light"] body {
|
||||
background-color: var(--bg-primary);
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
[data-ui-tier="lean"] *,
|
||||
[data-ui-tier="lean"] *::before,
|
||||
[data-ui-tier="lean"] *::after {
|
||||
@@ -7677,9 +7682,75 @@ body[data-mode="tscm"] {
|
||||
|
||||
|
||||
/* ============================================
|
||||
ENHANCED TIER — visual edge/glow overrides
|
||||
ENHANCED TIER — panel surface overrides
|
||||
Replaces hardcoded cool-dark navy gradients
|
||||
with warm near-black amber equivalents.
|
||||
============================================ */
|
||||
html[data-ui-tier="enhanced"] {
|
||||
--visual-edge-cyan: rgba(200, 150, 40, 0.34);
|
||||
--visual-glow-cyan: 0 0 24px rgba(200, 150, 40, 0.16);
|
||||
--visual-edge-cyan: rgba(46, 125, 138, 0.30);
|
||||
--visual-glow-cyan: 0 0 24px rgba(46, 125, 138, 0.12);
|
||||
--visual-surface-soft: linear-gradient(180deg, rgba(6, 10, 10, 0.9) 0%, rgba(3, 5, 5, 0.95) 100%);
|
||||
--visual-surface-panel: linear-gradient(160deg, rgba(6, 10, 10, 0.95) 0%, rgba(2, 4, 4, 0.96) 100%);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .mode-nav {
|
||||
background: linear-gradient(180deg, rgba(4, 8, 8, 0.96) 0%, rgba(2, 4, 4, 0.98) 100%);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .mode-nav-dropdown-menu {
|
||||
background: linear-gradient(180deg, rgba(4, 8, 8, 0.98) 0%, rgba(2, 4, 4, 0.99) 100%);
|
||||
border-color: rgba(46, 125, 138, 0.20);
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(46, 125, 138, 0.09);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .run-state-strip {
|
||||
background: linear-gradient(180deg, rgba(4, 8, 8, 0.96) 0%, rgba(2, 4, 4, 0.97) 100%);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .section h3 {
|
||||
background: linear-gradient(180deg, rgba(6, 10, 10, 1) 0%, rgba(4, 8, 8, 1) 100%);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .section h3::after {
|
||||
background: rgba(2, 4, 4, 0.9);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .form-group input,
|
||||
html[data-ui-tier="enhanced"] .form-group select {
|
||||
background: rgba(2, 4, 4, 0.72);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .preset-btn,
|
||||
html[data-ui-tier="enhanced"] .control-btn,
|
||||
html[data-ui-tier="enhanced"] .clear-btn {
|
||||
background: linear-gradient(180deg, rgba(4, 8, 8, 0.88) 0%, rgba(2, 4, 4, 0.9) 100%);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .output-panel {
|
||||
background: linear-gradient(180deg, rgba(2, 4, 4, 0.98) 0%, rgba(1, 2, 2, 0.99) 100%);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .output-header {
|
||||
background: linear-gradient(180deg, rgba(4, 8, 8, 0.95) 0%, rgba(2, 4, 4, 0.98) 100%);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .output-content {
|
||||
background: linear-gradient(180deg, rgba(2, 4, 4, 0.6) 0%, rgba(2, 4, 4, 0.9) 100%);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .stats > div {
|
||||
background: linear-gradient(180deg, rgba(4, 8, 8, 0.8) 0%, rgba(2, 4, 4, 0.82) 100%);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .message {
|
||||
background: linear-gradient(180deg, rgba(4, 8, 8, 0.8) 0%, rgba(2, 4, 4, 0.82) 100%);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .status-bar {
|
||||
background: linear-gradient(180deg, rgba(3, 6, 6, 0.96) 0%, rgba(2, 4, 4, 0.97) 100%);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .status-indicator,
|
||||
html[data-ui-tier="enhanced"] .control-group {
|
||||
background: linear-gradient(180deg, rgba(3, 6, 6, 0.78) 0%, rgba(2, 4, 4, 0.8) 100%);
|
||||
}
|
||||
|
||||
@@ -284,7 +284,7 @@
|
||||
#btLocateMap {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: #1a1a2e;
|
||||
background: var(--bg-primary, #07090e);
|
||||
}
|
||||
|
||||
.btl-map-overlay-controls {
|
||||
@@ -442,8 +442,8 @@
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
color: var(--accent-cyan, #00d4ff);
|
||||
background: rgba(0, 212, 255, 0.1);
|
||||
border: 1px solid rgba(0, 212, 255, 0.3);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.1);
|
||||
border: 1px solid rgba(var(--accent-cyan-rgb), 0.3);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
@@ -452,7 +452,7 @@
|
||||
}
|
||||
|
||||
.btl-detect-irk-btn:hover {
|
||||
background: rgba(0, 212, 255, 0.2);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.2);
|
||||
border-color: var(--accent-cyan, #00d4ff);
|
||||
}
|
||||
|
||||
|
||||
@@ -471,3 +471,26 @@
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .meteor-visuals-container {
|
||||
--ms-border: rgba(46, 125, 138, 0.22);
|
||||
--ms-surface: linear-gradient(180deg, rgba(2, 6, 6, 0.97) 0%, rgba(1, 3, 3, 0.98) 100%);
|
||||
--ms-accent: #2e7d8a;
|
||||
--ms-accent-dim: rgba(46, 125, 138, 0.12);
|
||||
background: radial-gradient(circle at 14% -18%, rgba(46, 125, 138, 0.10) 0%, rgba(46, 125, 138, 0) 38%),
|
||||
radial-gradient(circle at 86% -26%, rgba(46, 125, 138, 0.07) 0%, rgba(46, 125, 138, 0) 36%),
|
||||
#000202;
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .ms-headline,
|
||||
html[data-ui-tier="enhanced"] .ms-events-panel {
|
||||
background: rgba(2, 6, 6, 0.9);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .ms-events-table th {
|
||||
background: rgba(2, 6, 6, 0.95);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .ms-events-table tr:hover td {
|
||||
background: rgba(46, 125, 138, 0.04);
|
||||
}
|
||||
|
||||
@@ -199,3 +199,17 @@
|
||||
align-items: stretch;
|
||||
}
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .morse-raw-panel {
|
||||
border-color: rgba(46, 125, 138, 0.18);
|
||||
background: rgba(1, 4, 4, 0.9);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .morse-raw-text {
|
||||
color: rgba(70, 180, 200, 0.90);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .morse-metrics-panel span {
|
||||
border-color: rgba(46, 125, 138, 0.18);
|
||||
background: rgba(1, 4, 4, 0.88);
|
||||
}
|
||||
|
||||
@@ -160,14 +160,14 @@
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 4px 10px;
|
||||
background: rgba(0, 229, 255, 0.05);
|
||||
border: 1px solid rgba(0, 229, 255, 0.15);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.05);
|
||||
border: 1px solid rgba(var(--accent-cyan-rgb), 0.15);
|
||||
border-radius: 4px;
|
||||
min-width: 55px;
|
||||
}
|
||||
.radiosonde-strip .strip-stat:hover {
|
||||
background: rgba(0, 229, 255, 0.1);
|
||||
border-color: rgba(0, 229, 255, 0.3);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.1);
|
||||
border-color: rgba(var(--accent-cyan-rgb), 0.3);
|
||||
}
|
||||
.radiosonde-strip .strip-value {
|
||||
font-family: var(--font-mono);
|
||||
|
||||
@@ -342,7 +342,7 @@
|
||||
.sstv-general-image-card:hover {
|
||||
border-color: var(--accent-cyan);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 212, 255, 0.2);
|
||||
box-shadow: 0 4px 12px rgba(var(--accent-cyan-rgb), 0.2);
|
||||
}
|
||||
|
||||
.sstv-general-image-card-inner {
|
||||
|
||||
@@ -401,7 +401,7 @@
|
||||
.sstv-image-card:hover {
|
||||
border-color: var(--accent-cyan);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 212, 255, 0.2);
|
||||
box-shadow: 0 4px 12px rgba(var(--accent-cyan-rgb), 0.2);
|
||||
}
|
||||
|
||||
.sstv-image-card-inner {
|
||||
@@ -688,7 +688,7 @@
|
||||
font-weight: 700;
|
||||
color: var(--accent-cyan);
|
||||
letter-spacing: 2px;
|
||||
text-shadow: 0 0 20px rgba(0, 212, 255, 0.3);
|
||||
text-shadow: 0 0 20px rgba(var(--accent-cyan-rgb), 0.3);
|
||||
}
|
||||
|
||||
.sstv-countdown-value.imminent {
|
||||
|
||||
+29
-29
@@ -300,7 +300,7 @@
|
||||
}
|
||||
|
||||
.subghz-btn.active {
|
||||
background: rgba(0, 212, 255, 0.1);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.1);
|
||||
border-color: var(--accent-cyan, var(--accent-cyan));
|
||||
color: var(--accent-cyan, var(--accent-cyan));
|
||||
}
|
||||
@@ -384,9 +384,9 @@
|
||||
}
|
||||
|
||||
.subghz-capture-card.selected {
|
||||
border-color: rgba(0, 212, 255, 0.85);
|
||||
box-shadow: 0 0 0 1px rgba(0, 212, 255, 0.3);
|
||||
background: rgba(0, 212, 255, 0.06);
|
||||
border-color: rgba(var(--accent-cyan-rgb), 0.85);
|
||||
box-shadow: 0 0 0 1px rgba(var(--accent-cyan-rgb), 0.3);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.06);
|
||||
}
|
||||
|
||||
.subghz-capture-header {
|
||||
@@ -455,9 +455,9 @@
|
||||
}
|
||||
|
||||
.subghz-capture-tag.auto {
|
||||
border-color: rgba(0, 212, 255, 0.55);
|
||||
border-color: rgba(var(--accent-cyan-rgb), 0.55);
|
||||
color: var(--accent-cyan);
|
||||
background: rgba(0, 212, 255, 0.12);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.12);
|
||||
}
|
||||
|
||||
.subghz-capture-tag.hint {
|
||||
@@ -536,13 +536,13 @@
|
||||
}
|
||||
|
||||
.subghz-capture-actions button.select-btn {
|
||||
border-color: rgba(0, 212, 255, 0.5);
|
||||
border-color: rgba(var(--accent-cyan-rgb), 0.5);
|
||||
color: var(--accent-cyan);
|
||||
}
|
||||
|
||||
.subghz-capture-actions button.select-btn.selected {
|
||||
border-color: rgba(0, 212, 255, 0.9);
|
||||
background: rgba(0, 212, 255, 0.18);
|
||||
border-color: rgba(var(--accent-cyan-rgb), 0.9);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.18);
|
||||
color: #7beeff;
|
||||
}
|
||||
|
||||
@@ -781,14 +781,14 @@
|
||||
height: 26px;
|
||||
border: 1px solid var(--border-color, #2a3040);
|
||||
border-radius: 4px;
|
||||
background: linear-gradient(90deg, rgba(0, 212, 255, 0.07), rgba(255, 170, 0, 0.07));
|
||||
background: linear-gradient(90deg, rgba(var(--accent-cyan-rgb), 0.07), rgba(255, 170, 0, 0.07));
|
||||
margin-bottom: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.subghz-tx-burst-timeline.dragging {
|
||||
border-color: rgba(0, 212, 255, 0.65);
|
||||
box-shadow: 0 0 0 1px rgba(0, 212, 255, 0.25) inset;
|
||||
border-color: rgba(var(--accent-cyan-rgb), 0.65);
|
||||
box-shadow: 0 0 0 1px rgba(var(--accent-cyan-rgb), 0.25) inset;
|
||||
}
|
||||
|
||||
.subghz-tx-burst-selection {
|
||||
@@ -796,8 +796,8 @@
|
||||
top: 3px;
|
||||
bottom: 3px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid rgba(0, 212, 255, 0.95);
|
||||
background: rgba(0, 212, 255, 0.22);
|
||||
border: 1px solid rgba(var(--accent-cyan-rgb), 0.95);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.22);
|
||||
pointer-events: none;
|
||||
display: none;
|
||||
z-index: 2;
|
||||
@@ -823,8 +823,8 @@
|
||||
}
|
||||
|
||||
.subghz-tx-burst-marker:hover {
|
||||
background: rgba(0, 212, 255, 0.85);
|
||||
border-color: rgba(0, 212, 255, 1);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.85);
|
||||
border-color: rgba(var(--accent-cyan-rgb), 1);
|
||||
}
|
||||
|
||||
.subghz-tx-burst-list {
|
||||
@@ -861,7 +861,7 @@
|
||||
|
||||
.subghz-tx-burst-item button {
|
||||
padding: 2px 8px;
|
||||
border: 1px solid rgba(0, 212, 255, 0.5);
|
||||
border: 1px solid rgba(var(--accent-cyan-rgb), 0.5);
|
||||
border-radius: 3px;
|
||||
background: transparent;
|
||||
color: var(--accent-cyan);
|
||||
@@ -871,7 +871,7 @@
|
||||
}
|
||||
|
||||
.subghz-tx-burst-item button:hover {
|
||||
background: rgba(0, 212, 255, 0.12);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.12);
|
||||
}
|
||||
|
||||
.subghz-tx-modal-actions {
|
||||
@@ -901,13 +901,13 @@
|
||||
}
|
||||
|
||||
.subghz-tx-trim-btn {
|
||||
background: rgba(0, 212, 255, 0.14);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.14);
|
||||
color: var(--accent-cyan);
|
||||
border-color: rgba(0, 212, 255, 0.55) !important;
|
||||
border-color: rgba(var(--accent-cyan-rgb), 0.55) !important;
|
||||
}
|
||||
|
||||
.subghz-tx-trim-btn:hover {
|
||||
background: rgba(0, 212, 255, 0.26);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.26);
|
||||
}
|
||||
|
||||
.subghz-tx-cancel-btn {
|
||||
@@ -1043,7 +1043,7 @@
|
||||
}
|
||||
|
||||
.subghz-action-btn.decode:hover {
|
||||
background: rgba(0, 212, 255, 0.12);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.12);
|
||||
border-color: var(--accent-cyan, var(--accent-cyan));
|
||||
color: var(--accent-cyan, var(--accent-cyan));
|
||||
}
|
||||
@@ -1275,7 +1275,7 @@
|
||||
|
||||
.subghz-phase-step.active {
|
||||
color: var(--accent-cyan, var(--accent-cyan));
|
||||
text-shadow: 0 0 6px rgba(0, 212, 255, 0.3);
|
||||
text-shadow: 0 0 6px rgba(var(--accent-cyan-rgb), 0.3);
|
||||
}
|
||||
|
||||
.subghz-phase-step.completed {
|
||||
@@ -1328,9 +1328,9 @@
|
||||
}
|
||||
|
||||
.subghz-burst-indicator.recent {
|
||||
border-color: rgba(0, 212, 255, 0.45);
|
||||
border-color: rgba(var(--accent-cyan-rgb), 0.45);
|
||||
color: var(--accent-cyan);
|
||||
background: rgba(0, 212, 255, 0.1);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.1);
|
||||
}
|
||||
|
||||
.subghz-burst-indicator.recent .subghz-burst-dot {
|
||||
@@ -1445,8 +1445,8 @@
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.subghz-hub-card--cyan { border-color: rgba(0, 212, 255, 0.2); }
|
||||
.subghz-hub-card--cyan:hover { border-color: var(--accent-cyan, var(--accent-cyan)); background: rgba(0, 212, 255, 0.05); }
|
||||
.subghz-hub-card--cyan { border-color: rgba(var(--accent-cyan-rgb), 0.2); }
|
||||
.subghz-hub-card--cyan:hover { border-color: var(--accent-cyan, var(--accent-cyan)); background: rgba(var(--accent-cyan-rgb), 0.05); }
|
||||
.subghz-hub-card--cyan .subghz-hub-icon { color: var(--accent-cyan, var(--accent-cyan)); }
|
||||
|
||||
.subghz-hub-card--green { border-color: rgba(0, 255, 136, 0.2); }
|
||||
@@ -1736,8 +1736,8 @@
|
||||
|
||||
.subghz-rx-burst-pill.recent {
|
||||
color: var(--accent-cyan);
|
||||
border-color: rgba(0, 212, 255, 0.65);
|
||||
background: rgba(0, 212, 255, 0.12);
|
||||
border-color: rgba(var(--accent-cyan-rgb), 0.65);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.12);
|
||||
}
|
||||
|
||||
.subghz-rx-level-label {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.12em;
|
||||
color: var(--accent-cyan, #00d4ff);
|
||||
border-bottom: 1px solid rgba(0, 212, 255, 0.2);
|
||||
border-bottom: 1px solid rgba(var(--accent-cyan-rgb), 0.2);
|
||||
padding-bottom: 6px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
@@ -221,7 +221,7 @@
|
||||
fill: none;
|
||||
stroke: var(--accent-cyan, #00d4ff);
|
||||
stroke-width: 1.5;
|
||||
filter: drop-shadow(0 0 2px rgba(0, 212, 255, 0.4));
|
||||
filter: drop-shadow(0 0 2px rgba(var(--accent-cyan-rgb), 0.4));
|
||||
}
|
||||
|
||||
.sys-sparkline-area {
|
||||
|
||||
@@ -1180,3 +1180,139 @@
|
||||
font-family: var(--font-mono, monospace);
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
/* ---- Enhanced tier: replace blue palette with signals teal ---- */
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-container {
|
||||
--wf-border: rgba(46, 125, 138, 0.22);
|
||||
--wf-surface: linear-gradient(180deg, rgba(2, 6, 6, 0.97) 0%, rgba(1, 3, 3, 0.98) 100%);
|
||||
background: radial-gradient(circle at 14% -18%, rgba(46, 125, 138, 0.08) 0%, rgba(46, 125, 138, 0) 38%),
|
||||
radial-gradient(circle at 86% -26%, rgba(46, 125, 138, 0.05) 0%, rgba(46, 125, 138, 0) 36%),
|
||||
#000202;
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-headline {
|
||||
background: rgba(2, 6, 6, 0.86);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-headline-tag {
|
||||
color: rgba(70, 185, 200, 0.90);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-rx-vfo {
|
||||
border-color: rgba(46, 125, 138, 0.25);
|
||||
background: linear-gradient(180deg, rgba(3, 8, 8, 0.92) 0%, rgba(1, 4, 4, 0.95) 100%);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-rx-vfo-status {
|
||||
color: rgba(65, 175, 192, 0.88);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-rx-vfo-readout {
|
||||
color: rgba(80, 190, 205, 0.92);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] #wfRxFreqReadout {
|
||||
text-shadow: 0 0 16px rgba(46, 125, 138, 0.25);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-rx-modebank {
|
||||
border-color: rgba(46, 125, 138, 0.22);
|
||||
background: rgba(1, 4, 4, 0.86);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-mode-btn {
|
||||
border-color: rgba(46, 125, 138, 0.24);
|
||||
background: linear-gradient(180deg, rgba(4, 8, 8, 0.95) 0%, rgba(2, 5, 5, 0.95) 100%);
|
||||
color: rgba(65, 175, 192, 0.90);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-mode-btn:hover {
|
||||
border-color: rgba(46, 125, 138, 0.48);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-mode-btn.is-active,
|
||||
html[data-ui-tier="enhanced"] .wf-mode-btn.active {
|
||||
border-color: rgba(46, 125, 138, 0.62);
|
||||
background: linear-gradient(180deg, rgba(6, 16, 18, 0.92) 0%, rgba(4, 12, 14, 0.95) 100%);
|
||||
color: rgba(100, 210, 222, 0.96);
|
||||
box-shadow: 0 0 14px rgba(46, 125, 138, 0.22);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-rx-levels,
|
||||
html[data-ui-tier="enhanced"] .wf-rx-meter-wrap,
|
||||
html[data-ui-tier="enhanced"] .wf-rx-actions {
|
||||
border-color: rgba(46, 125, 138, 0.20);
|
||||
background: rgba(1, 4, 4, 0.85);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-monitor-select {
|
||||
border-color: rgba(46, 125, 138, 0.25);
|
||||
background: rgba(1, 3, 3, 0.8);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-rx-smeter-fill {
|
||||
box-shadow: 0 0 10px rgba(46, 125, 138, 0.22);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-monitor-btn-secondary {
|
||||
border-color: rgba(46, 125, 138, 0.45);
|
||||
background: linear-gradient(180deg, rgba(4, 12, 14, 0.95) 0%, rgba(2, 8, 10, 0.95) 100%);
|
||||
color: rgba(80, 190, 205, 0.90);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-freq-bar {
|
||||
background: rgba(2, 6, 6, 0.78);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-spectrum-canvas-wrap {
|
||||
background: radial-gradient(circle at 50% -120%, rgba(46, 125, 138, 0.06) 0%, rgba(46, 125, 138, 0) 65%);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-band-strip {
|
||||
background: linear-gradient(180deg, rgba(2, 6, 6, 0.96) 0%, rgba(1, 3, 3, 0.98) 100%);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-band-block {
|
||||
border-color: rgba(46, 125, 138, 0.42);
|
||||
color: rgba(80, 190, 205, 0.92);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-band-edge {
|
||||
color: rgba(65, 175, 192, 0.88);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-band-marker::before {
|
||||
background: rgba(46, 125, 138, 0.58);
|
||||
box-shadow: 0 0 5px rgba(46, 125, 138, 0.30);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-band-marker-label {
|
||||
border-color: rgba(46, 125, 138, 0.48);
|
||||
background: rgba(2, 5, 5, 0.95);
|
||||
color: rgba(80, 190, 205, 0.90);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-tune-line {
|
||||
background: rgba(46, 125, 138, 0.72);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-freq-axis {
|
||||
background: rgba(2, 6, 6, 0.86);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-side .section.wf-side-hero {
|
||||
background: linear-gradient(180deg, rgba(3, 8, 8, 0.95) 0%, rgba(1, 4, 4, 0.97) 100%);
|
||||
border-color: rgba(46, 125, 138, 0.30);
|
||||
box-shadow: 0 8px 24px rgba(0, 8, 10, 0.30), inset 0 0 0 1px rgba(255, 255, 255, 0.03);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-side-chip {
|
||||
color: rgba(65, 175, 192, 0.88);
|
||||
border-color: rgba(46, 125, 138, 0.32);
|
||||
background: rgba(6, 16, 18, 0.30);
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] .wf-side-stat {
|
||||
border-color: rgba(46, 125, 138, 0.20);
|
||||
}
|
||||
|
||||
@@ -308,7 +308,7 @@
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.wxsat-timeline-pass.apt { background: rgba(0, 212, 255, 0.6); }
|
||||
.wxsat-timeline-pass.apt { background: rgba(var(--accent-cyan-rgb), 0.6); }
|
||||
.wxsat-timeline-pass.lrpt { background: rgba(0, 255, 136, 0.6); }
|
||||
.wxsat-timeline-pass.scheduled { border: 1px solid var(--accent-yellow); }
|
||||
|
||||
@@ -585,7 +585,7 @@
|
||||
}
|
||||
|
||||
.wxsat-pass-mode.apt {
|
||||
background: rgba(0, 212, 255, 0.15);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.15);
|
||||
color: var(--accent-cyan);
|
||||
}
|
||||
|
||||
@@ -626,7 +626,7 @@
|
||||
}
|
||||
|
||||
.wxsat-pass-quality.good {
|
||||
background: rgba(0, 212, 255, 0.15);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.15);
|
||||
color: var(--accent-cyan);
|
||||
}
|
||||
|
||||
@@ -759,16 +759,16 @@
|
||||
|
||||
.wxsat-map-tooltip {
|
||||
background: rgba(5, 15, 32, 0.92);
|
||||
border: 1px solid rgba(102, 229, 255, 0.65);
|
||||
border: 1px solid rgba(var(--accent-cyan-rgb), 0.65);
|
||||
border-radius: 4px;
|
||||
color: #8fe8ff;
|
||||
color: var(--accent-cyan);
|
||||
box-shadow: 0 0 12px rgba(0, 210, 255, 0.24);
|
||||
font-size: 10px;
|
||||
letter-spacing: 0.25px;
|
||||
}
|
||||
|
||||
.wxsat-map-tooltip.leaflet-tooltip-top:before {
|
||||
border-top-color: rgba(102, 229, 255, 0.65);
|
||||
border-top-color: rgba(var(--accent-cyan-rgb), 0.65);
|
||||
}
|
||||
|
||||
/* ===== Image Gallery Panel ===== */
|
||||
@@ -1221,8 +1221,8 @@
|
||||
|
||||
.wxsat-phase-step.completed {
|
||||
color: var(--accent-cyan, #00d4ff);
|
||||
border-color: rgba(0, 212, 255, 0.3);
|
||||
background: rgba(0, 212, 255, 0.05);
|
||||
border-color: rgba(var(--accent-cyan-rgb), 0.3);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.05);
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
@@ -1267,7 +1267,7 @@
|
||||
.wxsat-console-filter.active {
|
||||
border-color: var(--accent-cyan, #00d4ff);
|
||||
color: var(--accent-cyan, #00d4ff);
|
||||
background: rgba(0, 212, 255, 0.08);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.08);
|
||||
}
|
||||
|
||||
.wxsat-console-actions {
|
||||
|
||||
@@ -157,7 +157,7 @@ body {
|
||||
|
||||
.stat-badge {
|
||||
background: var(--bg-card);
|
||||
border: 1px solid rgba(0, 212, 255, 0.3);
|
||||
border: 1px solid rgba(var(--accent-cyan-rgb), 0.3);
|
||||
border-radius: 4px;
|
||||
padding: 4px 10px;
|
||||
font-family: var(--font-mono);
|
||||
@@ -309,7 +309,7 @@ body {
|
||||
/* Panels */
|
||||
.panel {
|
||||
background: var(--bg-panel);
|
||||
border: 1px solid rgba(0, 212, 255, 0.2);
|
||||
border: 1px solid rgba(var(--accent-cyan-rgb), 0.2);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
@@ -326,8 +326,8 @@ body {
|
||||
|
||||
.panel-header {
|
||||
padding: 10px 15px;
|
||||
background: rgba(0, 212, 255, 0.05);
|
||||
border-bottom: 1px solid rgba(0, 212, 255, 0.1);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.05);
|
||||
border-bottom: 1px solid rgba(var(--accent-cyan-rgb), 0.1);
|
||||
font-family: 'Orbitron', monospace;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
@@ -955,7 +955,7 @@ body {
|
||||
|
||||
.packet-entry {
|
||||
padding: 7px 10px;
|
||||
border-bottom: 1px solid rgba(0, 212, 255, 0.08);
|
||||
border-bottom: 1px solid rgba(var(--accent-cyan-rgb), 0.08);
|
||||
font-size: 10px;
|
||||
font-family: var(--font-mono);
|
||||
word-break: break-word;
|
||||
@@ -1010,7 +1010,7 @@ body {
|
||||
.packet-modal {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 2000;
|
||||
z-index: 5000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -1140,7 +1140,7 @@ body {
|
||||
gap: 10px;
|
||||
padding: 10px;
|
||||
background: var(--bg-panel);
|
||||
border-bottom: 1px solid rgba(0, 212, 255, 0.2);
|
||||
border-bottom: 1px solid rgba(var(--accent-cyan-rgb), 0.2);
|
||||
}
|
||||
|
||||
.satellite-selector label {
|
||||
@@ -1153,7 +1153,7 @@ body {
|
||||
|
||||
.satellite-selector select {
|
||||
flex: 1;
|
||||
background: rgba(0, 212, 255, 0.1);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.1);
|
||||
border: 1px solid var(--accent-cyan);
|
||||
border-radius: 4px;
|
||||
padding: 8px 12px;
|
||||
@@ -1166,12 +1166,12 @@ body {
|
||||
|
||||
.satellite-selector select:focus {
|
||||
outline: none;
|
||||
box-shadow: 0 0 15px rgba(0, 212, 255, 0.3);
|
||||
box-shadow: 0 0 15px rgba(var(--accent-cyan-rgb), 0.3);
|
||||
}
|
||||
|
||||
#satRefreshBtn {
|
||||
background: transparent;
|
||||
border: 1px solid rgba(0, 212, 255, 0.4);
|
||||
border: 1px solid rgba(var(--accent-cyan-rgb), 0.4);
|
||||
border-radius: 4px;
|
||||
color: var(--text-secondary);
|
||||
cursor: pointer;
|
||||
@@ -1199,7 +1199,7 @@ body {
|
||||
/* Countdown panel */
|
||||
.countdown-panel {
|
||||
flex-shrink: 0;
|
||||
background: linear-gradient(135deg, rgba(0, 212, 255, 0.1) 0%, rgba(0, 255, 136, 0.05) 100%);
|
||||
background: linear-gradient(135deg, rgba(var(--accent-cyan-rgb), 0.1) 0%, rgba(0, 255, 136, 0.05) 100%);
|
||||
}
|
||||
|
||||
.countdown-display {
|
||||
@@ -1232,7 +1232,7 @@ body {
|
||||
|
||||
.countdown-block {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
border: 1px solid rgba(0, 212, 255, 0.2);
|
||||
border: 1px solid rgba(var(--accent-cyan-rgb), 0.2);
|
||||
border-radius: 4px;
|
||||
padding: 8px 4px;
|
||||
text-align: center;
|
||||
@@ -1359,7 +1359,7 @@ body {
|
||||
|
||||
.pass-item {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
border: 1px solid rgba(0, 212, 255, 0.15);
|
||||
border: 1px solid rgba(var(--accent-cyan-rgb), 0.15);
|
||||
border-radius: 4px;
|
||||
padding: 8px 10px;
|
||||
margin-bottom: 6px;
|
||||
@@ -1369,13 +1369,13 @@ body {
|
||||
|
||||
.pass-item:hover {
|
||||
border-color: var(--accent-cyan);
|
||||
background: rgba(0, 212, 255, 0.05);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.05);
|
||||
}
|
||||
|
||||
.pass-item.active {
|
||||
border-color: var(--accent-cyan);
|
||||
box-shadow: 0 0 15px rgba(0, 212, 255, 0.2);
|
||||
background: rgba(0, 212, 255, 0.1);
|
||||
box-shadow: 0 0 15px rgba(var(--accent-cyan-rgb), 0.2);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.1);
|
||||
}
|
||||
|
||||
.pass-item-header {
|
||||
@@ -1407,7 +1407,7 @@ body {
|
||||
}
|
||||
|
||||
.pass-quality.good {
|
||||
background: rgba(0, 212, 255, 0.2);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.2);
|
||||
color: var(--accent-cyan);
|
||||
}
|
||||
|
||||
@@ -1434,7 +1434,7 @@ body {
|
||||
gap: 20px;
|
||||
padding: 10px 20px;
|
||||
background: var(--bg-panel);
|
||||
border-top: 1px solid rgba(0, 212, 255, 0.3);
|
||||
border-top: 1px solid rgba(var(--accent-cyan-rgb), 0.3);
|
||||
}
|
||||
|
||||
.control-group {
|
||||
@@ -1455,7 +1455,7 @@ body {
|
||||
width: 90px;
|
||||
padding: 6px 8px;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
border: 1px solid rgba(0, 212, 255, 0.3);
|
||||
border: 1px solid rgba(var(--accent-cyan-rgb), 0.3);
|
||||
border-radius: 4px;
|
||||
color: var(--accent-cyan);
|
||||
font-family: var(--font-mono);
|
||||
@@ -1465,13 +1465,13 @@ body {
|
||||
.control-group input:focus {
|
||||
outline: none;
|
||||
border-color: var(--accent-cyan);
|
||||
box-shadow: 0 0 10px rgba(0, 212, 255, 0.2);
|
||||
box-shadow: 0 0 10px rgba(var(--accent-cyan-rgb), 0.2);
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 8px 16px;
|
||||
border: 1px solid var(--accent-cyan);
|
||||
background: rgba(0, 212, 255, 0.1);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.1);
|
||||
color: var(--accent-cyan);
|
||||
font-family: 'Orbitron', monospace;
|
||||
font-size: 11px;
|
||||
@@ -1486,7 +1486,7 @@ body {
|
||||
.btn:hover {
|
||||
background: var(--accent-cyan);
|
||||
color: var(--bg-dark);
|
||||
box-shadow: 0 0 20px rgba(0, 212, 255, 0.3);
|
||||
box-shadow: 0 0 20px rgba(var(--accent-cyan-rgb), 0.3);
|
||||
}
|
||||
|
||||
.btn.primary {
|
||||
@@ -1780,17 +1780,16 @@ body.embedded .controls-bar {
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
ENHANCED TIER — amber military console
|
||||
ENHANCED TIER — signals teal console
|
||||
============================================ */
|
||||
html[data-ui-tier="enhanced"] {
|
||||
--bg-dark: #080600;
|
||||
--bg-panel: #0c0a04;
|
||||
--bg-card: #0e0b05;
|
||||
--border-glow: rgba(200, 150, 40, 0.25);
|
||||
--border-color: rgba(200, 150, 40, 0.2);
|
||||
--grid-line: rgba(200, 150, 40, 0.07);
|
||||
--accent-cyan: #c89628;
|
||||
--accent-green: #c89628;
|
||||
--bg-dark: #000000;
|
||||
--bg-panel: #020404;
|
||||
--bg-card: #020404;
|
||||
--border-glow: rgba(46, 125, 138, 0.20);
|
||||
--border-color: rgba(46, 125, 138, 0.18);
|
||||
--grid-line: rgba(46, 125, 138, 0.07);
|
||||
--accent-cyan: #2e7d8a;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
|
||||
+68
-9
@@ -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 {
|
||||
|
||||
@@ -216,9 +216,9 @@ const FirstRunSetup = (function() {
|
||||
el.innerHTML = '<div style="display:flex;justify-content:space-between;font-size:7px;color:#aaa;font-family:monospace;"><span>INTERCEPT</span><span style="color:#4a4;">● LIVE</span></div><div style="font-size:7px;color:#888;font-family:monospace;margin-top:2px;">ADS-B ........... 247<br>TSCM ............ 3 ⚠</div>';
|
||||
});
|
||||
|
||||
const enhancedBtn = makeTierBtn('enhanced', 'Enhanced', 'Amber military console — for desktop or laptop.', (el) => {
|
||||
el.style.cssText += 'background:#080600;border:1px solid rgba(200,150,40,0.3);display:flex;flex-direction:column;justify-content:center;padding:6px;gap:3px;';
|
||||
el.innerHTML = '<div style="display:flex;justify-content:space-between;font-size:7px;color:#c89628;font-family:monospace;letter-spacing:2px;"><span>INTERCEPT</span><span style="opacity:0.6;">14:27Z</span></div><div style="border-left:2px solid #c89628;padding-left:4px;margin-top:4px;font-size:8px;color:#c89628;font-family:monospace;font-weight:700;">247 ADS-B</div>';
|
||||
const enhancedBtn = makeTierBtn('enhanced', 'Enhanced', 'Signals teal console — for desktop or laptop.', (el) => {
|
||||
el.style.cssText += 'background:#000202;border:1px solid rgba(46,125,138,0.3);display:flex;flex-direction:column;justify-content:center;padding:6px;gap:3px;';
|
||||
el.innerHTML = '<div style="display:flex;justify-content:space-between;font-size:7px;color:#2e7d8a;font-family:monospace;letter-spacing:2px;"><span>INTERCEPT</span><span style="opacity:0.6;">14:27Z</span></div><div style="border-left:2px solid #2e7d8a;padding-left:4px;margin-top:4px;font-size:8px;color:#2e7d8a;font-family:monospace;font-weight:700;">247 ADS-B</div>';
|
||||
});
|
||||
|
||||
btnWrap.appendChild(leanBtn);
|
||||
|
||||
@@ -16,17 +16,18 @@ const VoiceAlerts = (function () {
|
||||
const PITCH_MIN = 0.5;
|
||||
const PITCH_MAX = 2.0;
|
||||
|
||||
// Default config
|
||||
// Default config — streams are opt-in to avoid saturating the browser's
|
||||
// HTTP/1.1 per-origin connection limit (6) when multiple tabs are open.
|
||||
let _config = {
|
||||
rate: 1.1,
|
||||
pitch: 0.9,
|
||||
voiceName: '',
|
||||
streams: {
|
||||
pager: true,
|
||||
tscm: true,
|
||||
bluetooth: true,
|
||||
adsb_military: true,
|
||||
squawks: true,
|
||||
pager: false,
|
||||
tscm: false,
|
||||
bluetooth: false,
|
||||
adsb_military: false,
|
||||
squawks: false,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -197,30 +197,11 @@ const BtLocate = (function() {
|
||||
|
||||
// Init map
|
||||
const mapEl = document.getElementById('btLocateMap');
|
||||
if (mapEl && typeof L !== 'undefined') {
|
||||
map = L.map('btLocateMap', {
|
||||
if (mapEl && typeof L !== 'undefined' && typeof MapUtils !== 'undefined') {
|
||||
map = MapUtils.init('btLocateMap', {
|
||||
center: [0, 0],
|
||||
zoom: 2,
|
||||
zoomControl: true,
|
||||
});
|
||||
let tileLayer = null;
|
||||
// Use tile provider from user settings
|
||||
if (typeof Settings !== 'undefined' && Settings.createTileLayer) {
|
||||
tileLayer = Settings.createTileLayer();
|
||||
tileLayer.addTo(map);
|
||||
Settings.registerMap(map);
|
||||
} else {
|
||||
tileLayer = L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
|
||||
maxZoom: 19,
|
||||
attribution: '© OSM © CARTO'
|
||||
});
|
||||
tileLayer.addTo(map);
|
||||
}
|
||||
if (tileLayer && typeof tileLayer.on === 'function') {
|
||||
tileLayer.on('load', () => {
|
||||
scheduleMapStabilization(8);
|
||||
});
|
||||
}
|
||||
ensureHeatLayer();
|
||||
syncMovementLayer();
|
||||
syncHeatLayer();
|
||||
|
||||
@@ -43,6 +43,9 @@ var OokMode = (function () {
|
||||
}
|
||||
|
||||
function destroy() {
|
||||
if (state.running) {
|
||||
stop();
|
||||
}
|
||||
disconnectSSE();
|
||||
}
|
||||
|
||||
|
||||
@@ -874,7 +874,11 @@ const SSTVGeneral = (function() {
|
||||
* Destroy — close SSE stream and stop scope animation for clean mode switching.
|
||||
*/
|
||||
function destroy() {
|
||||
stopStream();
|
||||
if (isRunning) {
|
||||
stop().catch(() => {});
|
||||
} else {
|
||||
stopStream();
|
||||
}
|
||||
}
|
||||
|
||||
// Public API
|
||||
|
||||
@@ -1428,9 +1428,13 @@ const SSTV = (function() {
|
||||
* Destroy — close SSE stream and clear ISS tracking/countdown timers for clean mode switching.
|
||||
*/
|
||||
function destroy() {
|
||||
if (eventSource) {
|
||||
eventSource.close();
|
||||
eventSource = null;
|
||||
if (isRunning) {
|
||||
stop().catch(() => {});
|
||||
} else {
|
||||
if (eventSource) {
|
||||
eventSource.close();
|
||||
eventSource = null;
|
||||
}
|
||||
}
|
||||
stopIssTracking();
|
||||
stopCountdown();
|
||||
|
||||
@@ -3014,10 +3014,14 @@ const Waterfall = (function () {
|
||||
}
|
||||
|
||||
// Backend stop is fire-and-forget; UI is already updated above.
|
||||
const _audioStopCtrl = new AbortController();
|
||||
const _audioStopTid = setTimeout(() => _audioStopCtrl.abort(), 3000);
|
||||
try {
|
||||
await fetch('/receiver/audio/stop', { method: 'POST' });
|
||||
await fetch('/receiver/audio/stop', { method: 'POST', signal: _audioStopCtrl.signal });
|
||||
} catch (_) {
|
||||
// Ignore backend stop errors
|
||||
} finally {
|
||||
clearTimeout(_audioStopTid);
|
||||
}
|
||||
|
||||
if (resumeWaterfall && _active) {
|
||||
@@ -3222,10 +3226,14 @@ const Waterfall = (function () {
|
||||
|
||||
if (_es) {
|
||||
_closeSseStream();
|
||||
const _wfStopCtrl = new AbortController();
|
||||
const _wfStopTid = setTimeout(() => _wfStopCtrl.abort(), 3000);
|
||||
try {
|
||||
await fetch('/receiver/waterfall/stop', { method: 'POST' });
|
||||
await fetch('/receiver/waterfall/stop', { method: 'POST', signal: _wfStopCtrl.signal });
|
||||
} catch (_) {
|
||||
// Ignore fallback stop errors.
|
||||
} finally {
|
||||
clearTimeout(_wfStopTid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2344,7 +2344,11 @@ const WeatherSat = (function() {
|
||||
clearInterval(countdownInterval);
|
||||
countdownInterval = null;
|
||||
}
|
||||
stopStream();
|
||||
if (isRunning) {
|
||||
stop().catch(() => {});
|
||||
} else {
|
||||
stopStream();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -260,7 +260,10 @@ function initWebsdrGlobe(mapEl) {
|
||||
if (typeof window.Globe !== 'function' || !isWebglSupported()) return false;
|
||||
|
||||
mapEl.innerHTML = '';
|
||||
mapEl.style.background = 'radial-gradient(circle at 30% 20%, rgba(14, 42, 68, 0.9), rgba(4, 9, 16, 0.95) 58%, rgba(2, 4, 9, 0.98) 100%)';
|
||||
const _wsdrTier = document.documentElement.getAttribute('data-ui-tier') || 'enhanced';
|
||||
mapEl.style.background = _wsdrTier === 'enhanced'
|
||||
? 'radial-gradient(circle at 30% 20%, rgba(4, 18, 22, 0.92), rgba(2, 8, 10, 0.96) 58%, rgba(0, 2, 2, 0.99) 100%)'
|
||||
: 'radial-gradient(circle at 30% 20%, rgba(14, 42, 68, 0.9), rgba(4, 9, 16, 0.95) 58%, rgba(2, 4, 9, 0.98) 100%)';
|
||||
mapEl.style.cursor = 'grab';
|
||||
|
||||
const _wsdrAccent = getComputedStyle(document.documentElement).getPropertyValue('--accent-cyan').trim() || '#3bb9ff';
|
||||
@@ -296,6 +299,8 @@ function initWebsdrGlobe(mapEl) {
|
||||
|
||||
ensureWebsdrGlobePopup(mapEl);
|
||||
resizeWebsdrGlobe();
|
||||
// Grid layout may not have settled on the first rAF; re-sync after one frame.
|
||||
requestAnimationFrame(() => resizeWebsdrGlobe());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -475,8 +480,10 @@ function ensureWebsdrGlobePopup(mapEl) {
|
||||
websdrGlobePopup.style.maxWidth = '260px';
|
||||
websdrGlobePopup.style.padding = '10px';
|
||||
websdrGlobePopup.style.borderRadius = '8px';
|
||||
websdrGlobePopup.style.border = '1px solid rgba(0, 212, 255, 0.35)';
|
||||
websdrGlobePopup.style.background = 'rgba(5, 13, 20, 0.92)';
|
||||
const _wsdrPopupRgb = getComputedStyle(document.documentElement).getPropertyValue('--accent-cyan-rgb').trim() || '0, 212, 255';
|
||||
const _wsdrPopupTier = document.documentElement.getAttribute('data-ui-tier') || 'enhanced';
|
||||
websdrGlobePopup.style.border = `1px solid rgba(${_wsdrPopupRgb}, 0.35)`;
|
||||
websdrGlobePopup.style.background = _wsdrPopupTier === 'enhanced' ? 'rgba(2, 8, 10, 0.94)' : 'rgba(5, 13, 20, 0.92)';
|
||||
websdrGlobePopup.style.backdropFilter = 'blur(4px)';
|
||||
websdrGlobePopup.style.boxShadow = '0 8px 24px rgba(0, 0, 0, 0.4)';
|
||||
websdrGlobePopup.style.color = 'var(--text-primary)';
|
||||
@@ -574,8 +581,9 @@ function renderReceiverList(receivers) {
|
||||
|
||||
container.innerHTML = receivers.slice(0, 50).map((rx, idx) => {
|
||||
const selected = idx === websdrSelectedReceiverIndex;
|
||||
const baseBg = selected ? 'rgba(0,212,255,0.14)' : 'transparent';
|
||||
const hoverBg = selected ? 'rgba(0,212,255,0.18)' : 'rgba(0,212,255,0.05)';
|
||||
const _wsdrRxRgb = getComputedStyle(document.documentElement).getPropertyValue('--accent-cyan-rgb').trim() || '0, 212, 255';
|
||||
const baseBg = selected ? `rgba(${_wsdrRxRgb},0.14)` : 'transparent';
|
||||
const hoverBg = selected ? `rgba(${_wsdrRxRgb},0.18)` : `rgba(${_wsdrRxRgb},0.05)`;
|
||||
return `
|
||||
<div style="padding: 8px 8px 8px 10px; border-bottom: 1px solid rgba(255,255,255,0.05); cursor: pointer; transition: background 0.2s; border-left: 2px solid ${selected ? 'var(--accent-cyan)' : 'transparent'}; background: ${baseBg};"
|
||||
onmouseover="this.style.background='${hoverBg}'" onmouseout="this.style.background='${baseBg}'"
|
||||
@@ -951,13 +959,14 @@ function loadSpyStationPresets() {
|
||||
return;
|
||||
}
|
||||
|
||||
const _wsdrSpyRgb = getComputedStyle(document.documentElement).getPropertyValue('--accent-cyan-rgb').trim() || '0, 212, 255';
|
||||
container.innerHTML = stations.slice(0, 30).map(s => {
|
||||
const primaryFreq = s.frequencies?.find(f => f.primary) || s.frequencies?.[0];
|
||||
const freqKhz = primaryFreq?.freq_khz || 0;
|
||||
return `
|
||||
<div style="padding: 6px 4px; border-bottom: 1px solid rgba(255,255,255,0.05); cursor: pointer; display: flex; justify-content: space-between; align-items: center;"
|
||||
onclick="tuneToSpyStation('${escapeHtmlWebsdr(s.id)}', ${freqKhz})"
|
||||
onmouseover="this.style.background='rgba(0,212,255,0.05)'" onmouseout="this.style.background='transparent'">
|
||||
onmouseover="this.style.background='rgba(${_wsdrSpyRgb},0.05)'" onmouseout="this.style.background='transparent'">
|
||||
<div>
|
||||
<span style="color: var(--accent-cyan); font-weight: bold;">${escapeHtmlWebsdr(s.name)}</span>
|
||||
<span style="color: var(--text-muted); font-size: 9px; margin-left: 4px;">${escapeHtmlWebsdr(s.nickname || '')}</span>
|
||||
|
||||
@@ -58,6 +58,9 @@ var WeFax = (function () {
|
||||
|
||||
function destroy() {
|
||||
closeImage();
|
||||
if (state.running) {
|
||||
stop();
|
||||
}
|
||||
disconnectSSE();
|
||||
stopScope();
|
||||
stopCountdownTimer();
|
||||
|
||||
+10
-13
@@ -155,25 +155,22 @@ const WiFiMode = (function() {
|
||||
// ==========================================================================
|
||||
|
||||
function init() {
|
||||
console.log('[WiFiMode] Initializing...');
|
||||
// Capabilities and one-time component setup only on first call.
|
||||
// Subsequent visits refresh scan state and re-render without redundant fetches.
|
||||
const firstInit = capabilities === null;
|
||||
|
||||
// Cache DOM elements
|
||||
cacheDOM();
|
||||
|
||||
// Check capabilities
|
||||
checkCapabilities();
|
||||
if (firstInit) {
|
||||
checkCapabilities();
|
||||
initScanModeTabs();
|
||||
initNetworkFilters();
|
||||
initSortControls();
|
||||
initHeatmap();
|
||||
}
|
||||
|
||||
// Initialize components
|
||||
initScanModeTabs();
|
||||
initNetworkFilters();
|
||||
initSortControls();
|
||||
initHeatmap();
|
||||
scheduleRender({ table: true, stats: true, radar: true });
|
||||
|
||||
// Check if already scanning
|
||||
checkScanStatus();
|
||||
|
||||
console.log('[WiFiMode] Initialized');
|
||||
}
|
||||
|
||||
// DOM element cache
|
||||
|
||||
@@ -2094,13 +2094,25 @@ ACARS: ${r.statistics.acarsMessages} messages`;
|
||||
const existing = document.getElementById('aircraftDbBanner');
|
||||
if (existing) existing.remove();
|
||||
|
||||
const _dbTier = document.documentElement.getAttribute('data-ui-tier') || 'enhanced';
|
||||
const _dbBg = _dbTier === 'enhanced'
|
||||
? (type === 'not_installed' ? 'rgba(4, 22, 26, 0.97)' : 'rgba(4, 22, 26, 0.97)')
|
||||
: (type === 'not_installed' ? 'rgba(59, 130, 246, 0.95)' : 'rgba(34, 197, 94, 0.95)');
|
||||
const _dbBorder = _dbTier === 'enhanced'
|
||||
? (type === 'not_installed' ? '1px solid rgba(46, 125, 138, 0.45)' : '1px solid rgba(46, 125, 138, 0.45)')
|
||||
: 'none';
|
||||
const _dbBtnColor = _dbTier === 'enhanced'
|
||||
? (type === 'not_installed' ? '#2e7d8a' : '#38c180')
|
||||
: (type === 'not_installed' ? '#3b82f6' : '#22c55e');
|
||||
|
||||
const banner = document.createElement('div');
|
||||
banner.id = 'aircraftDbBanner';
|
||||
banner.style.cssText = `
|
||||
position: fixed;
|
||||
top: 70px;
|
||||
right: 20px;
|
||||
background: ${type === 'not_installed' ? 'rgba(59, 130, 246, 0.95)' : 'rgba(34, 197, 94, 0.95)'};
|
||||
background: ${_dbBg};
|
||||
border: ${_dbBorder};
|
||||
color: white;
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px;
|
||||
@@ -2115,14 +2127,14 @@ ACARS: ${r.statistics.acarsMessages} messages`;
|
||||
banner.innerHTML = `
|
||||
<div style="font-weight: bold; margin-bottom: 6px;">Aircraft Database Not Installed</div>
|
||||
<div style="margin-bottom: 10px; font-size: 11px; opacity: 0.9;">Download to see aircraft types, registrations, and model info.</div>
|
||||
<button onclick="downloadAircraftDb()" style="background: white; color: #3b82f6; border: none; padding: 6px 12px; border-radius: 4px; cursor: pointer; font-weight: 500; font-size: 11px;">Download Database</button>
|
||||
<button onclick="downloadAircraftDb()" style="background: rgba(0,0,0,0.35); color: ${_dbBtnColor}; border: 1px solid ${_dbBtnColor}; padding: 6px 12px; border-radius: 4px; cursor: pointer; font-weight: 500; font-size: 11px;">Download Database</button>
|
||||
<button onclick="this.parentElement.remove()" style="position: absolute; top: 6px; right: 8px; background: none; border: none; color: white; cursor: pointer; font-size: 14px;">×</button>
|
||||
`;
|
||||
} else {
|
||||
banner.innerHTML = `
|
||||
<div style="font-weight: bold; margin-bottom: 6px;">Database Update Available</div>
|
||||
<div style="margin-bottom: 10px; font-size: 11px; opacity: 0.9;">New version: ${version || 'latest'}</div>
|
||||
<button onclick="downloadAircraftDb()" style="background: white; color: #22c55e; border: none; padding: 6px 12px; border-radius: 4px; cursor: pointer; font-weight: 500; font-size: 11px;">Update Now</button>
|
||||
<button onclick="downloadAircraftDb()" style="background: rgba(0,0,0,0.35); color: ${_dbBtnColor}; border: 1px solid ${_dbBtnColor}; padding: 6px 12px; border-radius: 4px; cursor: pointer; font-weight: 500; font-size: 11px;">Update Now</button>
|
||||
<button onclick="this.parentElement.remove()" style="position: absolute; top: 6px; right: 8px; background: none; border: none; color: white; cursor: pointer; font-size: 14px;">×</button>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="{% if offline_settings.tile_provider in ['cartodb_dark', 'cartodb_dark_cyan'] %}map-cyber-enabled{% endif %}">
|
||||
<head>
|
||||
<script>(function(){var t=localStorage.getItem('intercept-ui-tier')||'enhanced';document.documentElement.setAttribute('data-ui-tier',t);})();</script>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>ADS-B History // INTERCEPT</title>
|
||||
{% if offline_settings.fonts_source == 'local' %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/fonts-local.css') }}">
|
||||
{% else %}
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Roboto+Condensed:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
{% endif %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/core/variables.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/responsive.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/core/layout.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/settings.css') }}?v={{ version }}&r=maptheme17">
|
||||
|
||||
@@ -5,7 +5,10 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>iNTERCEPT // Remote Agents</title>
|
||||
<script>(function(){var t=localStorage.getItem('intercept-ui-tier')||'enhanced';document.documentElement.setAttribute('data-ui-tier',t);})();</script>
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/fonts-local.css') }}">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Roboto+Condensed:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/core/variables.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/core/base.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/responsive.css') }}">
|
||||
|
||||
+14
-9
@@ -42,7 +42,7 @@
|
||||
{% if offline_settings.fonts_source == 'local' %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/fonts-local.css') }}">
|
||||
{% else %}
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Roboto+Condensed:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
{% endif %}
|
||||
<!-- Leaflet CSS -->
|
||||
{% if offline_settings.assets_source == 'local' %}
|
||||
@@ -1478,7 +1478,7 @@
|
||||
<div id="tscmVisuals" class="tscm-dashboard" style="display: none; padding: 16px;">
|
||||
<!-- Legal Disclaimer Banner -->
|
||||
<div class="tscm-legal-banner"
|
||||
style="margin-bottom: 12px; padding: 8px 12px; background: rgba(74, 158, 255, 0.1); border: 1px solid rgba(74, 158, 255, 0.3); border-radius: 4px; font-size: 10px; color: #ffffff;">
|
||||
style="margin-bottom: 12px; padding: 8px 12px; background: rgba(var(--accent-cyan-rgb), 0.1); border: 1px solid rgba(var(--accent-cyan-rgb), 0.3); border-radius: 4px; font-size: 10px; color: #ffffff;">
|
||||
<strong>TSCM Screening Tool:</strong> This system identifies wireless and RF anomalies.
|
||||
Findings are indicators, NOT confirmed surveillance devices.
|
||||
No content is intercepted or decoded. Professional verification required.
|
||||
@@ -2172,7 +2172,7 @@
|
||||
<div style="display: grid; grid-template-columns: 3fr 1fr; gap: 12px; flex: 1; min-height: 0; overflow: hidden;">
|
||||
<!-- Map -->
|
||||
<div class="radio-module-box" style="padding: 0; overflow: hidden; position: relative; min-height: 0;">
|
||||
<div id="websdrMap" style="position: absolute; top: 0; left: 0; right: 0; bottom: 0;"></div>
|
||||
<div id="websdrMap" style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; display: flex; align-items: center; justify-content: center; overflow: hidden;"></div>
|
||||
</div>
|
||||
<!-- Receiver List -->
|
||||
<div style="display: flex; flex-direction: column; gap: 12px; min-width: 0; min-height: 0; overflow: hidden;">
|
||||
@@ -4639,15 +4639,17 @@
|
||||
return;
|
||||
}
|
||||
if (!validModes.has(mode)) mode = 'pager';
|
||||
const _modeAssetTimeout = (p) =>
|
||||
Promise.race([p, new Promise((r) => setTimeout(r, 5000))]);
|
||||
const styleReadyPromise = (typeof window.ensureModeStyles === 'function')
|
||||
? Promise.resolve(window.ensureModeStyles(mode)).catch((err) => {
|
||||
? _modeAssetTimeout(Promise.resolve(window.ensureModeStyles(mode)).catch((err) => {
|
||||
console.warn(`[ModeSwitch] style load failed for ${mode}: ${err?.message || err}`);
|
||||
})
|
||||
}))
|
||||
: Promise.resolve();
|
||||
const scriptReadyPromise = (typeof window.ensureModeScript === 'function')
|
||||
? Promise.resolve(window.ensureModeScript(mode)).catch((err) => {
|
||||
? _modeAssetTimeout(Promise.resolve(window.ensureModeScript(mode)).catch((err) => {
|
||||
console.warn(`[ModeSwitch] script load failed for ${mode}: ${err?.message || err}`);
|
||||
})
|
||||
}))
|
||||
: Promise.resolve();
|
||||
// Only stop local scans if in local mode (not agent mode)
|
||||
const isAgentMode = typeof currentAgent !== 'undefined' && currentAgent !== 'local';
|
||||
@@ -4697,6 +4699,9 @@
|
||||
if (isDroneRunning) {
|
||||
stopTasks.push(awaitStopAction('drone', () => fetch('/drone/stop', { method: 'POST' }), LOCAL_STOP_TIMEOUT_MS));
|
||||
}
|
||||
if (isRtlamrRunning) {
|
||||
stopTasks.push(awaitStopAction('rtlamr', () => stopRtlamrDecoding(), LOCAL_STOP_TIMEOUT_MS));
|
||||
}
|
||||
|
||||
if (stopTasks.length) {
|
||||
await Promise.allSettled(stopTasks);
|
||||
@@ -16616,7 +16621,7 @@
|
||||
|
||||
<!-- Cheat Sheet Modal -->
|
||||
<div id="cheatSheetModal" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.7); z-index:10000; align-items:center; justify-content:center; padding:20px;" onclick="if(event.target===this)CheatSheets.hide()">
|
||||
<div style="background:var(--bg-card, #1a1f2e); border:1px solid rgba(255,255,255,0.15); border-radius:12px; max-width:480px; width:100%; max-height:80vh; overflow-y:auto; padding:20px; position:relative;">
|
||||
<div style="background:var(--bg-card, #1a1f2e); border:1px solid var(--border-color); border-radius:12px; max-width:480px; width:100%; max-height:80vh; overflow-y:auto; padding:20px; position:relative;">
|
||||
<button onclick="CheatSheets.hide()" style="position:absolute; top:12px; right:12px; background:none; border:none; color:var(--text-dim); cursor:pointer; font-size:18px; line-height:1;">✕</button>
|
||||
<div id="cheatSheetContent"></div>
|
||||
</div>
|
||||
@@ -16624,7 +16629,7 @@
|
||||
|
||||
<!-- Keyboard Shortcuts Modal -->
|
||||
<div id="kbShortcutsModal" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.7); z-index:10000; align-items:center; justify-content:center; padding:20px;" onclick="if(event.target===this)KeyboardShortcuts.hideHelp()">
|
||||
<div style="background:var(--bg-card, #1a1f2e); border:1px solid rgba(255,255,255,0.15); border-radius:12px; max-width:520px; width:100%; max-height:80vh; overflow-y:auto; padding:20px; position:relative;">
|
||||
<div style="background:var(--bg-card, #1a1f2e); border:1px solid var(--border-color); border-radius:12px; max-width:520px; width:100%; max-height:80vh; overflow-y:auto; padding:20px; position:relative;">
|
||||
<button onclick="KeyboardShortcuts.hideHelp()" style="position:absolute; top:12px; right:12px; background:none; border:none; color:var(--text-dim); cursor:pointer; font-size:18px; line-height:1;">✕</button>
|
||||
<h2 style="margin:0 0 16px; font-size:16px; color:var(--accent-cyan, #4aa3ff); font-family:var(--font-mono);">Keyboard Shortcuts</h2>
|
||||
<table style="width:100%; border-collapse:collapse; font-family:var(--font-mono); font-size:12px;">
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
{% if offline_settings and offline_settings.fonts_source == 'local' %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/fonts-local.css') }}">
|
||||
{% else %}
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Roboto+Condensed:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
{% endif %}
|
||||
|
||||
{# Core CSS (Design System) #}
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>iNTERCEPT // Restricted Access</title>
|
||||
<script src="{{ url_for('static', filename='js/core/login.js') }}"></script>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/fonts-local.css') }}" />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Roboto+Condensed:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/index.css') }}" />
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/login.css') }}" />
|
||||
</head>
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="{% if offline_settings.tile_provider in ['cartodb_dark', 'cartodb_dark_cyan'] %}map-cyber-enabled{% endif %}">
|
||||
<head>
|
||||
<script>(function(){var t=localStorage.getItem('intercept-ui-tier')||'enhanced';document.documentElement.setAttribute('data-ui-tier',t);})();</script>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Network Monitor // INTERCEPT</title>
|
||||
{% if offline_settings.fonts_source == 'local' %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/fonts-local.css') }}">
|
||||
{% else %}
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Roboto+Condensed:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
{% endif %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/core/variables.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/responsive.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/agents.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/core/layout.css') }}">
|
||||
@@ -18,8 +20,8 @@
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
:root {
|
||||
--font-sans: 'Roboto Condensed', 'Arial Narrow', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
--font-mono: 'Roboto Condensed', 'Arial Narrow', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
--font-sans: 'Inter', 'Roboto Condensed', 'Helvetica Neue', Arial, sans-serif;
|
||||
--font-mono: 'JetBrains Mono', 'Fira Code', 'Source Code Pro', Consolas, monospace;
|
||||
--bg-primary: #0a0c10;
|
||||
--bg-secondary: #0f1218;
|
||||
--bg-tertiary: #151a23;
|
||||
@@ -28,12 +30,29 @@
|
||||
--text-dim: #4b5563;
|
||||
--border-color: #1f2937;
|
||||
--accent-cyan: #4a9eff;
|
||||
--accent-cyan-rgb: 74, 158, 255;
|
||||
--accent-green: #22c55e;
|
||||
--accent-red: #ef4444;
|
||||
--accent-orange: #f59e0b;
|
||||
--accent-purple: #a855f7;
|
||||
}
|
||||
|
||||
html[data-ui-tier="enhanced"] {
|
||||
--bg-primary: #000000;
|
||||
--bg-secondary: #020404;
|
||||
--bg-tertiary: #040808;
|
||||
--border-color: rgba(46, 125, 138, 0.18);
|
||||
--accent-cyan: #2e7d8a;
|
||||
--accent-cyan-rgb: 46, 125, 138;
|
||||
}
|
||||
|
||||
html[data-ui-tier="lean"] {
|
||||
--bg-primary: #111111;
|
||||
--bg-secondary: #181818;
|
||||
--bg-tertiary: #1f1f1f;
|
||||
--border-color: #2a2a2a;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: var(--font-sans);
|
||||
background: var(--bg-primary);
|
||||
@@ -161,7 +180,7 @@
|
||||
.panel-count {
|
||||
font-size: 10px;
|
||||
padding: 2px 8px;
|
||||
background: rgba(74, 158, 255, 0.2);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.2);
|
||||
color: var(--accent-cyan);
|
||||
border-radius: 10px;
|
||||
font-family: var(--font-mono);
|
||||
@@ -192,7 +211,7 @@
|
||||
}
|
||||
|
||||
.panel-tab.active {
|
||||
background: rgba(74, 158, 255, 0.1);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.1);
|
||||
color: var(--accent-cyan);
|
||||
border-color: var(--accent-cyan);
|
||||
}
|
||||
@@ -230,7 +249,7 @@
|
||||
}
|
||||
|
||||
.data-table tr:hover {
|
||||
background: rgba(74, 158, 255, 0.05);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.05);
|
||||
}
|
||||
|
||||
.mono {
|
||||
@@ -249,7 +268,7 @@
|
||||
gap: 4px;
|
||||
padding: 2px 6px;
|
||||
font-size: 9px;
|
||||
background: rgba(74, 158, 255, 0.15);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.15);
|
||||
color: var(--accent-cyan);
|
||||
border-radius: 8px;
|
||||
font-family: var(--font-mono);
|
||||
@@ -439,7 +458,7 @@
|
||||
gap: 6px;
|
||||
margin-top: 4px;
|
||||
padding: 3px 8px;
|
||||
background: rgba(74, 158, 255, 0.1);
|
||||
background: rgba(var(--accent-cyan-rgb), 0.1);
|
||||
border-radius: 4px;
|
||||
font-size: 10px;
|
||||
}
|
||||
@@ -497,7 +516,7 @@
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.type-badge.type-wifi { background: rgba(74, 158, 255, 0.2); color: var(--accent-cyan); }
|
||||
.type-badge.type-wifi { background: rgba(var(--accent-cyan-rgb), 0.2); color: var(--accent-cyan); }
|
||||
.type-badge.type-bluetooth { background: rgba(168, 85, 247, 0.2); color: var(--accent-purple); }
|
||||
.type-badge.type-adsb { background: rgba(34, 197, 94, 0.2); color: var(--accent-green); }
|
||||
.type-badge.type-ais { background: rgba(245, 158, 11, 0.2); color: var(--accent-orange); }
|
||||
|
||||
@@ -563,7 +563,7 @@
|
||||
}
|
||||
.location-select:focus {
|
||||
outline: none;
|
||||
border-color: #00d4ff;
|
||||
border-color: var(--accent-cyan);
|
||||
}
|
||||
.location-status-dot {
|
||||
width: 8px;
|
||||
@@ -823,14 +823,16 @@
|
||||
]
|
||||
};
|
||||
|
||||
const _satAccent = getComputedStyle(document.documentElement).getPropertyValue('--accent-cyan').trim() || '#00ffff';
|
||||
|
||||
let satellites = {
|
||||
25544: { name: 'ISS (ZARYA)', color: '#00ffff' },
|
||||
25544: { name: 'ISS (ZARYA)', color: _satAccent },
|
||||
40069: { name: 'METEOR-M2', color: '#9370DB' },
|
||||
57166: { name: 'METEOR-M2-3', color: '#ff00ff' },
|
||||
59051: { name: 'METEOR-M2-4', color: '#00ff88' }
|
||||
};
|
||||
|
||||
const satColors = ['#00ffff', '#9370DB', '#ff00ff', '#00ff00', '#ff6600', '#ffff00', '#ff69b4', '#7b68ee'];
|
||||
const satColors = [_satAccent, '#9370DB', '#ff00ff', '#00ff00', '#ff6600', '#ffff00', '#ff69b4', '#7b68ee'];
|
||||
|
||||
async function fetchJsonWithTimeout(url, options = {}, timeoutMs = SAT_DRAWER_FETCH_TIMEOUT_MS) {
|
||||
const controller = new AbortController();
|
||||
@@ -1102,7 +1104,7 @@
|
||||
drawPolarPlotWithPosition(
|
||||
normalized.azimuth ?? normalized.az,
|
||||
normalized.elevation ?? normalized.el,
|
||||
satellites[selectedSatellite]?.color || '#00d4ff'
|
||||
satellites[selectedSatellite]?.color || _satAccent
|
||||
);
|
||||
}
|
||||
renderMapTrackOverlays({ refreshPass: false, refreshLive: true });
|
||||
@@ -1547,7 +1549,7 @@
|
||||
const track = Array.isArray(pass?.groundTrack) ? pass.groundTrack : [];
|
||||
if (!track.length) return null;
|
||||
|
||||
const color = pass.color || satellites[selectedSatellite]?.color || '#00d4ff';
|
||||
const color = pass.color || satellites[selectedSatellite]?.color || _satAccent;
|
||||
const layer = L.layerGroup();
|
||||
const segments = splitAtAntimeridian(track);
|
||||
const bounds = [];
|
||||
@@ -1687,7 +1689,7 @@
|
||||
bounds.push(...liveTrack.map(p => [p.lat, p.lon]));
|
||||
}
|
||||
|
||||
const satColor = satellites[selectedSatellite]?.color || '#00d4ff';
|
||||
const satColor = satellites[selectedSatellite]?.color || _satAccent;
|
||||
const currentPos = latestLivePosition?.lat != null && latestLivePosition?.lon != null
|
||||
? { lat: latestLivePosition.lat, lon: latestLivePosition.lon }
|
||||
: (pass?.currentPos?.lat != null && pass?.currentPos?.lon != null
|
||||
@@ -2328,7 +2330,7 @@
|
||||
|
||||
// Pass trajectory
|
||||
if (pass && pass.trajectory) {
|
||||
ctx.strokeStyle = pass.color || '#00d4ff';
|
||||
ctx.strokeStyle = pass.color || _satAccent;
|
||||
ctx.lineWidth = 3;
|
||||
ctx.setLineDash([8, 4]);
|
||||
ctx.beginPath();
|
||||
@@ -2356,7 +2358,7 @@
|
||||
if (maxElPoint) {
|
||||
ctx.beginPath();
|
||||
ctx.arc(maxElPoint.x, maxElPoint.y, 8, 0, Math.PI * 2);
|
||||
ctx.fillStyle = pass.color || '#00d4ff';
|
||||
ctx.fillStyle = pass.color || _satAccent;
|
||||
ctx.fill();
|
||||
ctx.strokeStyle = '#fff';
|
||||
ctx.lineWidth = 2;
|
||||
|
||||
Reference in New Issue
Block a user