<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>iNTERCEPT // See the Invisible</title>
    <link rel="icon" type="image/svg+xml" href="/favicon.svg">
    <!-- Leaflet.js for APRS map -->
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" crossorigin=""/>
    <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" crossorigin=""></script>
    <!-- Chart.js for signal strength graphs -->
    <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
    <link rel="stylesheet" href="{{ url_for('static', filename='css/responsive.css') }}">
    <link rel="stylesheet" href="{{ url_for('static', filename='css/index.css') }}">
    <link rel="stylesheet" href="{{ url_for('static', filename='css/modes/acars.css') }}">
    <link rel="stylesheet" href="{{ url_for('static', filename='css/modes/aprs.css') }}">
    <link rel="stylesheet" href="{{ url_for('static', filename='css/modes/tscm.css') }}">
</head>
<body>
    <!-- Welcome Page -->
    <div class="welcome-overlay" id="welcomePage">
        <div class="welcome-container">
            <!-- Header Section -->
            <div class="welcome-header">
                <div class="welcome-logo">
                    <svg width="80" height="80" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
                        <path d="M15 30 Q5 50, 15 70" stroke="#00d4ff" stroke-width="3" fill="none" stroke-linecap="round" opacity="0.5" class="signal-wave signal-wave-1"/>
                        <path d="M22 35 Q14 50, 22 65" stroke="#00d4ff" stroke-width="2.5" fill="none" stroke-linecap="round" opacity="0.7" class="signal-wave signal-wave-2"/>
                        <path d="M29 40 Q23 50, 29 60" stroke="#00d4ff" stroke-width="2" fill="none" stroke-linecap="round" class="signal-wave signal-wave-3"/>
                        <path d="M85 30 Q95 50, 85 70" stroke="#00d4ff" stroke-width="3" fill="none" stroke-linecap="round" opacity="0.5" class="signal-wave signal-wave-1"/>
                        <path d="M78 35 Q86 50, 78 65" stroke="#00d4ff" stroke-width="2.5" fill="none" stroke-linecap="round" opacity="0.7" class="signal-wave signal-wave-2"/>
                        <path d="M71 40 Q77 50, 71 60" stroke="#00d4ff" stroke-width="2" fill="none" stroke-linecap="round" class="signal-wave signal-wave-3"/>
                        <circle cx="50" cy="22" r="6" fill="#00ff88" class="logo-dot"/>
                        <rect x="44" y="35" width="12" height="45" rx="2" fill="#00d4ff"/>
                        <rect x="38" y="35" width="24" height="4" rx="1" fill="#00d4ff"/>
                        <rect x="38" y="76" width="24" height="4" rx="1" fill="#00d4ff"/>
                    </svg>
                </div>
                <div class="welcome-title-block">
                    <h1 class="welcome-title">iNTERCEPT</h1>
                    <p class="welcome-tagline">// See the Invisible</p>
                    <span class="welcome-version">v{{ version }}</span>
                </div>
            </div>

            <!-- Main Content Grid -->
            <div class="welcome-content">
                <!-- Left: Changelog -->
                <div class="welcome-changelog">
                    <h2>What's New</h2>
                    {% for release in changelog[:2] %}
                    <div class="changelog-release">
                        <div class="changelog-version-header">
                            <span class="changelog-version">v{{ release.version }}</span>
                            <span class="changelog-date">{{ release.date }}</span>
                        </div>
                        <ul class="changelog-list">
                            {% for item in release.highlights %}
                            <li>{{ item }}</li>
                            {% endfor %}
                        </ul>
                    </div>
                    {% endfor %}
                </div>

                <!-- Right: Mode Selection -->
                <div class="welcome-modes">
                    <h2>Select Mode</h2>
                    <div class="mode-grid">
                        <button class="mode-card" onclick="selectMode('pager')">
                            <span class="mode-icon">📟</span>
                            <span class="mode-name">Pager</span>
                            <span class="mode-desc">POCSAG/FLEX decoding</span>
                        </button>
                        <button class="mode-card" onclick="selectMode('sensor')">
                            <span class="mode-icon">📡</span>
                            <span class="mode-name">433MHz</span>
                            <span class="mode-desc">IoT sensor monitoring</span>
                        </button>
                        <a href="/adsb/dashboard" class="mode-card" style="text-decoration: none;">
                            <span class="mode-icon">✈️</span>
                            <span class="mode-name">Aircraft</span>
                            <span class="mode-desc">ADS-B tracking</span>
                        </a>
                        <button class="mode-card" onclick="selectMode('wifi')">
                            <span class="mode-icon">📶</span>
                            <span class="mode-name">WiFi</span>
                            <span class="mode-desc">Network reconnaissance</span>
                        </button>
                        <button class="mode-card" onclick="selectMode('bluetooth')">
                            <span class="mode-icon">🔵</span>
                            <span class="mode-name">Bluetooth</span>
                            <span class="mode-desc">Device discovery</span>
                        </button>
                        <button class="mode-card" onclick="selectMode('tscm')">
                            <span class="mode-icon">🔍</span>
                            <span class="mode-name">TSCM</span>
                            <span class="mode-desc">Counter-surveillance</span>
                        </button>
                        <button class="mode-card" onclick="selectMode('satellite')">
                            <span class="mode-icon">🛰️</span>
                            <span class="mode-name">Satellite</span>
                            <span class="mode-desc">Pass prediction</span>
                        </button>
                        <button class="mode-card" onclick="selectMode('listening')">
                            <span class="mode-icon">📻</span>
                            <span class="mode-name">Scanner</span>
                            <span class="mode-desc">Frequency scanning</span>
                        </button>
                        <button class="mode-card" onclick="selectMode('aprs')">
                            <span class="mode-icon">📍</span>
                            <span class="mode-name">APRS</span>
                            <span class="mode-desc">Amateur radio</span>
                        </button>
                    </div>
                </div>
            </div>

            <!-- Footer -->
            <div class="welcome-footer">
                <p>Signal Intelligence & Counter Surveillance Platform</p>
            </div>
        </div>
        <div class="welcome-scanline"></div>
    </div>

    <!-- Disclaimer Modal -->
    <div class="disclaimer-overlay" id="disclaimerModal" style="display: none;">
        <div class="disclaimer-modal">
            <div class="warning-icon">⚠️</div>
            <h2>DISCLAIMER</h2>
            <p>
                <strong>iNTERCEPT</strong> is a signal intelligence tool designed for <strong>educational purposes only</strong>.
            </p>
            <p>By using this software, you acknowledge and agree that:</p>
            <ul>
                <li>This tool is intended for use by <strong>cyber security professionals</strong> and researchers only</li>
                <li>You will only use this software in a <strong>controlled environment</strong> with proper authorization</li>
                <li>Intercepting communications without consent may be <strong>illegal</strong> in your jurisdiction</li>
                <li>You are solely responsible for ensuring compliance with all applicable laws and regulations</li>
                <li>The developers assume no liability for misuse of this software</li>
            </ul>
            <p style="color: var(--accent-red); font-weight: bold;">
                Only proceed if you understand and accept these terms.
            </p>
            <div style="display: flex; gap: 15px; justify-content: center; margin-top: 20px;">
                <button class="accept-btn" onclick="acceptDisclaimer()">I UNDERSTAND & ACCEPT</button>
                <button class="accept-btn" onclick="declineDisclaimer()" style="background: transparent; border: 1px solid var(--accent-red); color: var(--accent-red);">DECLINE</button>
            </div>
        </div>
    </div>

    <!-- TSCM Device Details Modal -->
    <div class="tscm-modal-overlay" id="tscmDeviceModal" style="display: none;" onclick="if(event.target === this) closeTscmDeviceModal()">
        <div class="tscm-modal">
            <button class="tscm-modal-close" onclick="closeTscmDeviceModal()">&times;</button>
            <div id="tscmDeviceModalContent"></div>
        </div>
    </div>

    <!-- Rejection Page -->
    <div class="disclaimer-overlay disclaimer-hidden" id="rejectionPage">
        <div class="disclaimer-modal" style="max-width: 600px;">
            <pre style="color: var(--accent-red); font-size: 9px; line-height: 1.1; margin-bottom: 20px; text-align: center;">
 █████╗  ██████╗ ██████╗███████╗███████╗███████╗
██╔══██╗██╔════╝██╔════╝██╔════╝██╔════╝██╔════╝
███████║██║     ██║     █████╗  ███████╗███████╗
██╔══██║██║     ██║     ██╔══╝  ╚════██║╚════██║
██║  ██║╚██████╗╚██████╗███████╗███████║███████║
╚═╝  ╚═╝ ╚═════╝ ╚═════╝╚══════╝╚══════╝╚══════╝
██████╗ ███████╗███╗   ██╗██╗███████╗██████╗
██╔══██╗██╔════╝████╗  ██║██║██╔════╝██╔══██╗
██║  ██║█████╗  ██╔██╗ ██║██║█████╗  ██║  ██║
██║  ██║██╔══╝  ██║╚██╗██║██║██╔══╝  ██║  ██║
██████╔╝███████╗██║ ╚████║██║███████╗██████╔╝
╚═════╝ ╚══════╝╚═╝  ╚═══╝╚═╝╚══════╝╚═════╝</pre>
            <div style="margin: 25px 0; padding: 15px; background: #0a0a0a; border-left: 3px solid var(--accent-red);">
                <p style="font-family: 'JetBrains Mono', monospace; font-size: 11px; color: #888; text-align: left; margin: 0;">
                    <span style="color: var(--accent-red);">root@intercepted:</span><span style="color: var(--accent-cyan);">~#</span> sudo access --grant-permission<br>
                    <span style="color: #666;">[sudo] password for user: ********</span><br>
                    <span style="color: var(--accent-red);">Error:</span> User is not in the sudoers file.<br>
                    <span style="color: var(--accent-orange);">This incident will be reported.</span>
                </p>
            </div>
            <p style="color: #666; font-size: 11px; text-align: center;">
                "In a world of locked doors, the man with the key is king.<br>
                And you, my friend, just threw away the key."
            </p>
            <button class="accept-btn" onclick="location.reload()" style="margin-top: 20px; background: transparent; border: 1px solid var(--accent-cyan); color: var(--accent-cyan);">
                TRY AGAIN
            </button>
        </div>
    </div>
    <header>
        <!-- Hamburger Menu Button (Mobile) -->
        <button class="hamburger-btn" id="hamburgerBtn" aria-label="Toggle navigation menu">
            <span></span>
            <span></span>
            <span></span>
        </button>
        <!-- UTC Clock -->
        <div class="header-clock hide-mobile">
            <span class="utc-label">UTC</span>
            <span class="utc-time" id="headerUtcTime">--:--:--</span>
        </div>
        <button class="theme-toggle" onclick="toggleTheme()" title="Toggle Light/Dark Theme">
            <span class="icon-moon">🌙</span>
            <span class="icon-sun">☀️</span>
        </button>
        <button class="help-btn" onclick="showDependencies()" title="Check Tool Dependencies" id="depsBtn" style="margin-right: 5px;">🔧</button>
        <button class="help-btn" onclick="showHelp()" title="Help & Documentation">?</button>
        <div class="logo">
            <svg width="50" height="50" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
                <!-- Signal brackets - left side -->
                <path d="M15 30 Q5 50, 15 70" stroke="#00d4ff" stroke-width="3" fill="none" stroke-linecap="round" opacity="0.5"/>
                <path d="M22 35 Q14 50, 22 65" stroke="#00d4ff" stroke-width="2.5" fill="none" stroke-linecap="round" opacity="0.7"/>
                <path d="M29 40 Q23 50, 29 60" stroke="#00d4ff" stroke-width="2" fill="none" stroke-linecap="round"/>
                <!-- Signal brackets - right side -->
                <path d="M85 30 Q95 50, 85 70" stroke="#00d4ff" stroke-width="3" fill="none" stroke-linecap="round" opacity="0.5"/>
                <path d="M78 35 Q86 50, 78 65" stroke="#00d4ff" stroke-width="2.5" fill="none" stroke-linecap="round" opacity="0.7"/>
                <path d="M71 40 Q77 50, 71 60" stroke="#00d4ff" stroke-width="2" fill="none" stroke-linecap="round"/>
                <!-- The 'i' letter -->
                <!-- dot of i -->
                <circle cx="50" cy="22" r="6" fill="#00ff88"/>
                <!-- stem of i with styled terminals -->
                <rect x="44" y="35" width="12" height="45" rx="2" fill="#00d4ff"/>
                <!-- top terminal bar -->
                <rect x="38" y="35" width="24" height="4" rx="1" fill="#00d4ff"/>
                <!-- bottom terminal bar -->
                <rect x="38" y="76" width="24" height="4" rx="1" fill="#00d4ff"/>
            </svg>
        </div>
        <h1>iNTERCEPT <span class="tagline">// See the Invisible</span> <span class="version-badge">v{{ version }}</span></h1>
        <p class="subtitle">Signal Intelligence & Counter Surveillance Platform <span class="active-mode-indicator" id="activeModeIndicator"><span class="pulse-dot"></span>PAGER</span></p>

        <!-- Header Stats (mode-specific) -->
        <div class="header-stats">
            <!-- Pager Stats -->
            <div class="header-stats-group active" id="headerPagerStats">
                <div class="stat-badge">
                    <span class="badge-icon">📨</span>
                    <div>
                        <span class="badge-value" id="headerMsgCount">0</span>
                        <span class="badge-label">messages</span>
                    </div>
                </div>
                <div class="stat-badge">
                    <span class="badge-icon">📟</span>
                    <div>
                        <span class="badge-value" id="headerPocsagCount">0</span>
                        <span class="badge-label">POCSAG</span>
                    </div>
                </div>
                <div class="stat-badge">
                    <span class="badge-icon">📠</span>
                    <div>
                        <span class="badge-value" id="headerFlexCount">0</span>
                        <span class="badge-label">FLEX</span>
                    </div>
                </div>
            </div>

            <!-- 433MHz Sensor Stats -->
            <div class="header-stats-group" id="headerSensorStats">
                <div class="stat-badge">
                    <span class="badge-icon">🌡️</span>
                    <div>
                        <span class="badge-value" id="headerSensorCount">0</span>
                        <span class="badge-label">sensors</span>
                    </div>
                </div>
                <div class="stat-badge">
                    <span class="badge-icon">📊</span>
                    <div>
                        <span class="badge-value" id="headerDeviceTypeCount">0</span>
                        <span class="badge-label">types</span>
                    </div>
                </div>
            </div>

            <!-- WiFi Stats -->
            <div class="header-stats-group" id="headerWifiStats">
                <div class="stat-badge">
                    <span class="badge-icon">📡</span>
                    <div>
                        <span class="badge-value" id="headerApCount">0</span>
                        <span class="badge-label">networks</span>
                    </div>
                </div>
                <div class="stat-badge">
                    <span class="badge-icon">👤</span>
                    <div>
                        <span class="badge-value" id="headerClientCount">0</span>
                        <span class="badge-label">clients</span>
                    </div>
                </div>
                <div class="stat-badge">
                    <span class="badge-icon">🤝</span>
                    <div>
                        <span class="badge-value highlight" id="headerHandshakeCount">0</span>
                        <span class="badge-label">handshakes</span>
                    </div>
                </div>
                <div class="stat-badge">
                    <span class="badge-icon">🚁</span>
                    <div>
                        <span class="badge-value warning" id="headerDroneCount">0</span>
                        <span class="badge-label">drones</span>
                    </div>
                </div>
            </div>

            <!-- Bluetooth Stats -->
            <div class="header-stats-group" id="headerBtStats">
                <div class="stat-badge">
                    <span class="badge-icon">🔵</span>
                    <div>
                        <span class="badge-value" id="headerBtDeviceCount">0</span>
                        <span class="badge-label">devices</span>
                    </div>
                </div>
                <div class="stat-badge">
                    <span class="badge-icon">📍</span>
                    <div>
                        <span class="badge-value" id="headerBtBeaconCount">0</span>
                        <span class="badge-label">beacons</span>
                    </div>
                </div>
            </div>

            <!-- Satellite Stats -->
            <div class="header-stats-group" id="headerSatelliteStats">
                <div class="stat-badge">
                    <span class="badge-icon">🛰️</span>
                    <div>
                        <span class="badge-value" id="headerPassCount">0</span>
                        <span class="badge-label">passes</span>
                    </div>
                </div>
                <div class="stat-badge">
                    <span class="badge-icon">📡</span>
                    <div>
                        <span class="badge-value" id="headerBurstCount">0</span>
                        <span class="badge-label">bursts</span>
                    </div>
                </div>
            </div>

        </div>
    </header>

    <!-- Mode Navigation Bar -->
    <nav class="mode-nav">
        <div class="mode-nav-dropdown" data-group="sdr">
            <button class="mode-nav-dropdown-btn" onclick="toggleNavDropdown('sdr')">
                <span class="nav-icon">📡</span>
                <span class="nav-label">SDR / RF</span>
                <span class="dropdown-arrow">▼</span>
            </button>
            <div class="mode-nav-dropdown-menu">
                <button class="mode-nav-btn active" onclick="switchMode('pager')"><span class="nav-icon">📟</span><span class="nav-label">Pager</span></button>
                <button class="mode-nav-btn" onclick="switchMode('sensor')"><span class="nav-icon">📡</span><span class="nav-label">433MHz</span></button>
                <a href="/adsb/dashboard" class="mode-nav-btn" style="text-decoration: none;"><span class="nav-icon">✈️</span><span class="nav-label">Aircraft</span></a>
                <button class="mode-nav-btn" onclick="switchMode('aprs')"><span class="nav-icon">📍</span><span class="nav-label">APRS</span></button>
                <button class="mode-nav-btn" onclick="switchMode('satellite')"><span class="nav-icon">🛰️</span><span class="nav-label">Satellite</span></button>
                <button class="mode-nav-btn" onclick="switchMode('listening')"><span class="nav-icon">📻</span><span class="nav-label">Listening Post</span></button>
            </div>
        </div>
        <div class="mode-nav-dropdown" data-group="wireless">
            <button class="mode-nav-dropdown-btn" onclick="toggleNavDropdown('wireless')">
                <span class="nav-icon">📶</span>
                <span class="nav-label">Wireless</span>
                <span class="dropdown-arrow">▼</span>
            </button>
            <div class="mode-nav-dropdown-menu">
                <button class="mode-nav-btn" onclick="switchMode('wifi')"><span class="nav-icon">📶</span><span class="nav-label">WiFi</span></button>
                <button class="mode-nav-btn" onclick="switchMode('bluetooth')"><span class="nav-icon">🔵</span><span class="nav-label">Bluetooth</span></button>
            </div>
        </div>
        <div class="mode-nav-dropdown" data-group="security">
            <button class="mode-nav-dropdown-btn" onclick="toggleNavDropdown('security')">
                <span class="nav-icon">🔍</span>
                <span class="nav-label">Security</span>
                <span class="dropdown-arrow">▼</span>
            </button>
            <div class="mode-nav-dropdown-menu">
                <button class="mode-nav-btn" onclick="switchMode('tscm')"><span class="nav-icon">🔍</span><span class="nav-label">TSCM</span></button>
            </div>
        </div>
        <div class="mode-nav-actions">
            <a href="/satellite/dashboard" target="_blank" class="nav-action-btn" id="satelliteDashboardBtn" style="display: none;">
                <span class="nav-icon">🖥️</span><span class="nav-label">Full Dashboard</span>
            </a>
        </div>
    </nav>

    <!-- Mobile Navigation Bar (simplified mode switching) -->
    <nav class="mobile-nav-bar" id="mobileNavBar">
        <button class="mobile-nav-btn active" data-mode="pager" onclick="switchMode('pager')">📟 Pager</button>
        <button class="mobile-nav-btn" data-mode="sensor" onclick="switchMode('sensor')">📡 433MHz</button>
        <a href="/adsb/dashboard" class="mobile-nav-btn" style="text-decoration: none;">✈️ Aircraft</a>
        <button class="mobile-nav-btn" data-mode="aprs" onclick="switchMode('aprs')">📍 APRS</button>
        <button class="mobile-nav-btn" data-mode="wifi" onclick="switchMode('wifi')">📶 WiFi</button>
        <button class="mobile-nav-btn" data-mode="bluetooth" onclick="switchMode('bluetooth')">🔵 BT</button>
        <button class="mobile-nav-btn" data-mode="tscm" onclick="switchMode('tscm')">🔍 TSCM</button>
        <button class="mobile-nav-btn" data-mode="satellite" onclick="switchMode('satellite')">🛰️ Sat</button>
        <button class="mobile-nav-btn" data-mode="listening" onclick="switchMode('listening')">📻 Scanner</button>
    </nav>

    <!-- Mobile Drawer Overlay -->
    <div class="drawer-overlay" id="drawerOverlay"></div>

    <div class="container">
        <div class="main-content">
            <div class="sidebar mobile-drawer" id="mainSidebar">
                <div class="section" id="rtlDeviceSection">
                    <h3>SDR Device</h3>
                    <div class="form-group">
                        <label style="font-size: 11px; color: #888; margin-bottom: 4px;">Hardware Type</label>
                        <select id="sdrTypeSelect" onchange="onSDRTypeChanged()">
                            <option value="rtlsdr">RTL-SDR</option>
                            <option value="limesdr">LimeSDR</option>
                            <option value="hackrf">HackRF</option>
                            <option value="airspy">Airspy</option>
                        </select>
                    </div>
                    <div class="form-group">
                        <label style="font-size: 11px; color: #888; margin-bottom: 4px;">Device</label>
                        <select id="deviceSelect">
                            {% if devices %}
                                {% for device in devices %}
                                <option value="{{ device.index }}" data-sdr-type="{{ device.sdr_type | default('rtlsdr') }}">{{ device.index }}: {{ device.name }}</option>
                                {% endfor %}
                            {% else %}
                                <option value="0">No devices found</option>
                            {% endif %}
                        </select>
                    </div>
                    <div id="deviceCapabilities" class="info-text" style="font-size: 11px; margin-bottom: 8px; padding: 6px; background: #0a0a1a; border-radius: 4px;">
                        <div style="display: grid; grid-template-columns: auto 1fr; gap: 2px 8px;">
                            <span style="color: #888;">Freq:</span><span id="capFreqRange">24-1766 MHz</span>
                            <span style="color: #888;">Gain:</span><span id="capGainRange">0-50 dB</span>
                        </div>
                    </div>
                    <!-- Bias-T Power Toggle - Prominent Location -->
                    <div style="display: flex; align-items: center; gap: 10px; padding: 8px; margin-bottom: 8px; background: linear-gradient(90deg, rgba(255,100,0,0.2), rgba(255,100,0,0.05)); border: 1px solid var(--accent-orange); border-radius: 4px;">
                        <input type="checkbox" id="biasT" onchange="saveBiasTSetting()" style="width: 18px; height: 18px; accent-color: var(--accent-orange);">
                        <div>
                            <div style="color: var(--accent-orange); font-weight: bold; font-size: 12px;">⚡ Bias-T Power</div>
                            <div style="color: #888; font-size: 9px;">Powers external LNA/preamp</div>
                        </div>
                    </div>
                    <button class="preset-btn" onclick="refreshDevices()" style="width: 100%;">
                        Refresh Devices
                    </button>

                    <!-- Remote SDR (rtl_tcp) -->
                    <div class="form-group" style="margin-top: 10px;">
                        <label class="inline-checkbox">
                            <input type="checkbox" id="useRemoteSDR" onchange="toggleRemoteSDR()">
                            Use Remote SDR (rtl_tcp)
                        </label>
                    </div>
                    <div id="remoteSDRConfig" style="display: none; margin-bottom: 10px;">
                        <div class="form-group">
                            <label style="font-size: 11px; color: #888;">Host</label>
                            <input type="text" id="rtlTcpHost" placeholder="192.168.1.100" style="width: 100%;">
                        </div>
                        <div class="form-group">
                            <label style="font-size: 11px; color: #888;">Port</label>
                            <input type="number" id="rtlTcpPort" value="1234" min="1" max="65535" style="width: 100%;">
                        </div>
                        <div class="info-text" style="font-size: 10px; color: #666; margin-top: 4px;">
                            Connect to rtl_tcp server on remote machine.<br>
                            Start server with: <code style="color: #00d4ff;">rtl_tcp -a 0.0.0.0</code>
                        </div>
                    </div>

                    <div id="toolStatusPager" class="info-text tool-status-section" style="display: grid; grid-template-columns: auto auto; gap: 4px 8px; align-items: center;">
                        <span>rtl_fm:</span><span class="tool-status {{ 'ok' if tools.rtl_fm else 'missing' }}">{{ 'OK' if tools.rtl_fm else 'Missing' }}</span>
                        <span>multimon-ng:</span><span class="tool-status {{ 'ok' if tools.multimon else 'missing' }}">{{ 'OK' if tools.multimon else 'Missing' }}</span>
                    </div>
                    <div id="toolStatusSensor" class="info-text tool-status-section" style="display: none; grid-template-columns: auto auto; gap: 4px 8px; align-items: center;">
                        <span>rtl_433:</span><span class="tool-status {{ 'ok' if tools.rtl_433 else 'missing' }}">{{ 'OK' if tools.rtl_433 else 'Missing' }}</span>
                    </div>
                </div>

                {% include 'partials/modes/pager.html' %}

                {% include 'partials/modes/sensor.html' %}

                {% include 'partials/modes/wifi.html' %}

                {% include 'partials/modes/bluetooth.html' %}

                {% include 'partials/modes/aprs.html' %}

                {% include 'partials/modes/satellite.html' %}

                {% include 'partials/modes/listening-post.html' %}

                {% include 'partials/modes/tscm.html' %}

                <button class="preset-btn" onclick="killAll()" style="width: 100%; margin-top: 10px; border-color: #ff3366; color: #ff3366;">
                    Kill All Processes
                </button>
            </div>

            <div class="output-panel">
                <div class="output-header">
                    <h3 id="outputTitle">Pager Decoder</h3>
                    <div class="header-controls">
                        <div class="stats" id="pagerStats">
                            <div title="Total Messages">📨 <span id="msgCount">0</span></div>
                            <div title="POCSAG Messages">📟 <span id="pocsagCount">0</span></div>
                            <div title="FLEX Messages">📠 <span id="flexCount">0</span></div>
                        </div>
                        <div class="stats" id="sensorStats" style="display: none;">
                            <div title="Unique Sensors">🌡️ <span id="sensorCount">0</span></div>
                            <div title="Device Types">📊 <span id="deviceCount">0</span></div>
                        </div>
                        <div class="stats" id="wifiStats" style="display: none;">
                            <div title="Access Points">📡 <span id="apCount">0</span></div>
                            <div title="Connected Clients">👤 <span id="clientCount">0</span></div>
                            <div title="Captured Handshakes" style="color: var(--accent-green);">🤝 <span id="handshakeCount">0</span></div>
                            <div style="color: var(--accent-orange); cursor: pointer;" onclick="showDroneDetails()" title="Click: Drone details">🚁 <span id="droneCount">0</span></div>
                            <div style="color: var(--accent-red); cursor: pointer;" onclick="showRogueApDetails()" title="Click: Rogue AP details">⚠️ <span id="rogueApCount">0</span></div>
                        </div>
                        <div class="stats" id="btStats" style="display: none;">
                            <div title="Bluetooth Devices">🔵 <span id="btDeviceCount">0</span></div>
                            <div title="BLE Beacons">📍 <span id="btBeaconCount">0</span></div>
                        </div>
                        <div class="stats" id="satelliteStats" style="display: none;">
                            <div title="Upcoming Passes">🛰️ <span id="passCount">0</span></div>
                        </div>
                    </div>
                </div>

                <!-- WiFi Layout Container (visualizations left, device cards right) -->
                <div class="wifi-layout-container" id="wifiLayoutContainer" style="display: none;">
                    <!-- Left: WiFi Visualizations -->
                    <div class="wifi-visuals" id="wifiVisuals">
                        <!-- Selected WiFi Device Info - at top for visibility -->
                        <div class="wifi-visual-panel" style="grid-column: span 2;">
                            <h5>📋 Selected Device</h5>
                            <div id="wifiSelectedDevice" style="font-size: 11px; min-height: 100px;">
                                <div style="color: var(--text-dim); padding: 20px; text-align: center;">Click a network or client to view details</div>
                            </div>
                        </div>
                    <!-- Row 1: Network Radar + Security Overview -->
                    <div class="wifi-visual-panel">
                        <h5>Network Radar</h5>
                        <div class="radar-container">
                            <canvas id="radarCanvas" width="150" height="150"></canvas>
                        </div>
                    </div>
                    <div class="wifi-visual-panel">
                        <h5>Security Overview</h5>
                        <div class="security-container">
                            <div class="security-donut">
                                <canvas id="securityCanvas" width="80" height="80"></canvas>
                            </div>
                            <div class="security-legend">
                                <div class="security-legend-item"><div class="security-legend-dot wpa3"></div>WPA3: <span id="wpa3Count">0</span></div>
                                <div class="security-legend-item"><div class="security-legend-dot wpa2"></div>WPA2: <span id="wpa2Count">0</span></div>
                                <div class="security-legend-item"><div class="security-legend-dot wep"></div>WEP: <span id="wepCount">0</span></div>
                                <div class="security-legend-item"><div class="security-legend-dot open"></div>Open: <span id="openCount">0</span></div>
                            </div>
                        </div>
                    </div>
                    <!-- Row 2: Channel Utilization (2.4 GHz + 5 GHz side by side) -->
                    <div class="wifi-visual-panel">
                        <h5>Channel Utilization (2.4 GHz)</h5>
                        <div class="channel-graph" id="channelGraph">
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">1</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">2</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">3</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">4</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">5</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">6</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">7</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">8</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">9</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">10</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">11</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">12</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">13</span></div>
                        </div>
                    </div>
                    <div class="wifi-visual-panel">
                        <h5>Channel Utilization (5 GHz)</h5>
                        <div class="channel-graph" id="channelGraph5g" style="font-size: 7px;">
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">36</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">40</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">44</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">48</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">52</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">56</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">60</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">64</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">100</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">149</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">153</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">157</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">161</span></div>
                            <div class="channel-bar-wrapper"><div class="channel-bar" style="height: 2px;"></div><span class="channel-label">165</span></div>
                        </div>
                    </div>
                    <!-- Row 3: Channel Recommendation -->
                    <div class="wifi-visual-panel channel-recommendation" id="channelRecommendation">
                        <h4>💡 Channel Recommendation</h4>
                        <div class="rec-text">
                            <strong>2.4 GHz:</strong> Use channel <span class="rec-channel" id="rec24Channel">--</span>
                            <span id="rec24Reason" style="font-size: 10px; color: var(--text-dim);"></span>
                        </div>
                        <div class="rec-text" style="margin-top: 5px;">
                            <strong>5 GHz:</strong> Use channel <span class="rec-channel" id="rec5Channel">--</span>
                            <span id="rec5Reason" style="font-size: 10px; color: var(--text-dim);"></span>
                        </div>
                    </div>
                    <!-- Device Correlation -->
                    <div class="wifi-visual-panel" id="correlationPanel">
                        <h5>🔗 Device Correlation</h5>
                        <div id="correlationList" style="font-size: 11px; max-height: 100px; overflow-y: auto;">
                            <div style="color: var(--text-dim);">Analyzing WiFi/BT device patterns...</div>
                        </div>
                    </div>
                    <!-- Hidden SSID Revealer -->
                    <div class="wifi-visual-panel" id="hiddenSsidPanel">
                        <h5>👁️ Hidden SSIDs Revealed</h5>
                        <div id="hiddenSsidList" style="font-size: 11px; max-height: 100px; overflow-y: auto;">
                            <div style="color: var(--text-dim);">Monitoring probe requests...</div>
                        </div>
                    </div>
                    <!-- Client Probe Analysis -->
                    <div class="wifi-visual-panel" id="probeAnalysisPanel" style="grid-column: span 2;">
                        <h5>📡 Client Probe Analysis</h5>
                        <div style="display: flex; gap: 10px; margin-bottom: 8px; font-size: 10px;">
                            <span>Clients: <strong id="probeClientCount">0</strong></span>
                            <span>Unique SSIDs: <strong id="probeSSIDCount">0</strong></span>
                            <span>Privacy Leaks: <strong id="probePrivacyCount" style="color: var(--accent-orange);">0</strong></span>
                        </div>
                        <div id="probeAnalysisList" style="font-size: 11px; max-height: 200px; overflow-y: auto;">
                            <div style="color: var(--text-dim);">Waiting for client probe requests...</div>
                        </div>
                    </div>
                    </div>
                    <!-- Right: WiFi Device Cards -->
                    <div class="wifi-device-list" id="wifiDeviceList">
                        <div class="wifi-device-list-header">
                            <h5>📡 Discovered Networks</h5>
                            <span class="device-count">(<span id="wifiDeviceListCount">0</span>)</span>
                        </div>
                        <div class="wifi-device-list-content" id="wifiDeviceListContent">
                            <div style="color: var(--text-dim); text-align: center; padding: 30px;">
                                Start scanning to discover WiFi networks
                            </div>
                        </div>
                    </div>
                </div>

                <!-- Bluetooth Layout Container (visualizations left, device cards right) -->
                <div class="bt-layout-container" id="btLayoutContainer" style="display: none;">
                    <!-- Left: Bluetooth Visualizations -->
                    <div class="wifi-visuals" id="btVisuals">
                        <!-- Selected Bluetooth Device Info - at top for visibility -->
                        <div class="wifi-visual-panel" style="grid-column: span 2;">
                            <h5>📋 Selected Device</h5>
                            <div id="btSelectedDevice" style="font-size: 11px; min-height: 100px;">
                                <div style="color: var(--text-dim); padding: 20px; text-align: center;">Click a device to view details</div>
                            </div>
                        </div>
                        <!-- Row 1: Bluetooth Radar + Device Types -->
                        <div class="wifi-visual-panel">
                            <h5>Proximity Radar</h5>
                            <div class="radar-container">
                                <canvas id="btRadarCanvas" width="150" height="150"></canvas>
                            </div>
                        </div>
                        <div class="wifi-visual-panel">
                            <h5>Device Types</h5>
                            <div class="bt-type-overview" id="btTypeOverview">
                                <div class="bt-type-item"><span class="bt-type-icon">📱</span> Phones: <strong id="btPhoneCount">0</strong></div>
                                <div class="bt-type-item"><span class="bt-type-icon">💻</span> Computers: <strong id="btComputerCount">0</strong></div>
                                <div class="bt-type-item"><span class="bt-type-icon">🎧</span> Audio: <strong id="btAudioCount">0</strong></div>
                                <div class="bt-type-item"><span class="bt-type-icon">⌚</span> Wearables: <strong id="btWearableCount">0</strong></div>
                                <div class="bt-type-item"><span class="bt-type-icon">🔵</span> Other: <strong id="btOtherCount">0</strong></div>
                            </div>
                        </div>
                        <!-- Row 2: Tracker Detection + Signal Analysis -->
                        <div class="wifi-visual-panel">
                            <h5>📍 Tracker Detection</h5>
                            <div id="btTrackerList" style="max-height: 120px; overflow-y: auto; font-size: 11px;">
                                <div style="color: var(--text-dim); padding: 10px; text-align: center;">Monitoring for AirTags, Tiles...</div>
                            </div>
                        </div>
                        <div class="wifi-visual-panel">
                            <h5>📶 Signal Distribution</h5>
                            <div class="bt-signal-dist" id="btSignalDist">
                                <div class="signal-range"><span>Strong (-50+)</span><div class="signal-bar-bg"><div class="signal-bar strong" id="btSignalStrong" style="width: 0%;"></div></div><span id="btSignalStrongCount">0</span></div>
                                <div class="signal-range"><span>Medium (-70)</span><div class="signal-bar-bg"><div class="signal-bar medium" id="btSignalMedium" style="width: 0%;"></div></div><span id="btSignalMediumCount">0</span></div>
                                <div class="signal-range"><span>Weak (-90)</span><div class="signal-bar-bg"><div class="signal-bar weak" id="btSignalWeak" style="width: 0%;"></div></div><span id="btSignalWeakCount">0</span></div>
                            </div>
                        </div>
                        <!-- Row 3: FindMy Detection -->
                        <div class="wifi-visual-panel" style="grid-column: span 2;">
                            <h5>🍎 Apple FindMy Network</h5>
                            <div id="btFindMyList" style="max-height: 100px; overflow-y: auto; font-size: 11px;">
                                <div style="color: var(--text-dim); padding: 10px; text-align: center;">Scanning for FindMy-compatible devices...</div>
                            </div>
                        </div>
                    </div>
                    <!-- Right: Bluetooth Device Cards -->
                    <div class="wifi-device-list bt-device-list" id="btDeviceListPanel">
                        <div class="wifi-device-list-header">
                            <h5>🔵 Bluetooth Devices</h5>
                            <span class="device-count">(<span id="btDeviceListCount">0</span>)</span>
                        </div>
                        <div class="wifi-device-list-content" id="btDeviceListContent">
                            <div style="color: var(--text-dim); text-align: center; padding: 30px;">
                                Start scanning to discover Bluetooth devices
                            </div>
                        </div>
                    </div>
                </div>

                <!-- APRS Visualizations -->
                <div id="aprsVisuals" style="display: none; flex-direction: column; gap: 10px; flex: 1; padding: 10px;">
                    <!-- APRS Function Bar -->
                    <div class="aprs-strip">
                        <div class="aprs-strip-inner">
                            <!-- Stats -->
                            <div class="strip-stat">
                                <span class="strip-value" id="aprsStripFreq">--</span>
                                <span class="strip-label">MHz</span>
                            </div>
                            <div class="strip-stat">
                                <span class="strip-value" id="aprsStripStations">0</span>
                                <span class="strip-label">STATIONS</span>
                            </div>
                            <div class="strip-stat">
                                <span class="strip-value" id="aprsStripPackets">0</span>
                                <span class="strip-label">PACKETS</span>
                            </div>
                            <div class="strip-stat signal-stat" id="aprsStripSignalStat">
                                <span class="strip-value" id="aprsStripSignal">--</span>
                                <span class="strip-label">SIGNAL</span>
                            </div>
                            <div class="strip-divider"></div>
                            <!-- Controls -->
                            <div class="strip-control">
                                <select id="aprsStripRegion" class="strip-select">
                                    <option value="north_america">N. America (144.390)</option>
                                    <option value="europe">Europe (144.800)</option>
                                    <option value="uk">UK (144.800)</option>
                                    <option value="australia">Australia (145.175)</option>
                                    <option value="japan">Japan (144.640)</option>
                                </select>
                            </div>
                            <div class="strip-control">
                                <span class="strip-input-label">GAIN</span>
                                <input type="number" id="aprsStripGain" class="strip-input" value="40" min="0" max="50">
                            </div>
                            <div class="strip-divider"></div>
                            <!-- Tool Status Indicators -->
                            <div class="strip-tools">
                                <span class="strip-tool" id="aprsStripDirewolf" title="direwolf">DW</span>
                                <span class="strip-tool" id="aprsStripMultimon" title="multimon-ng">MM</span>
                            </div>
                            <div class="strip-divider"></div>
                            <!-- Actions -->
                            <button type="button" class="strip-btn primary" id="aprsStripStartBtn" onclick="startAprs()">
                                ▶ START
                            </button>
                            <button type="button" class="strip-btn stop" id="aprsStripStopBtn" onclick="stopAprs()" style="display: none;">
                                ◼ STOP
                            </button>
                            <!-- Status -->
                            <div class="strip-status">
                                <div class="status-dot inactive" id="aprsStripDot"></div>
                                <span id="aprsStripStatus">STANDBY</span>
                            </div>
                            <div class="strip-time" id="aprsStripTime">--:--:-- UTC</div>
                        </div>
                    </div>
                    <!-- Top row: Map and Station List side by side -->
                    <div style="display: flex; gap: 10px; flex: 1; min-height: 0;">
                        <!-- Map Panel (larger) -->
                        <div class="wifi-visual-panel" style="flex: 2; display: flex; flex-direction: column; min-width: 0;">
                            <h5 style="color: var(--accent-cyan); text-shadow: 0 0 10px var(--accent-cyan); padding: 0 10px; margin-bottom: 8px;">APRS STATION MAP</h5>
                            <div class="aircraft-map-container" style="flex: 1; display: flex; flex-direction: column;">
                                <div class="map-header">
                                    <span id="aprsMapTime">--:--:--</span>
                                    <span id="aprsMapStatus">STANDBY</span>
                                </div>
                                <div id="aprsMap" style="flex: 1; min-height: 350px;"></div>
                                <div class="map-footer">
                                    <span>STATIONS: <span id="aprsStationCount">0</span></span>
                                    <span>PACKETS: <span id="aprsPacketCount">0</span></span>
                                </div>
                            </div>
                        </div>

                        <!-- Station List Panel -->
                        <div class="wifi-visual-panel" style="flex: 1; min-width: 280px; max-width: 350px; display: flex; flex-direction: column;">
                            <h5 style="color: var(--accent-green); text-shadow: 0 0 10px var(--accent-green); margin-bottom: 8px;">STATION LIST</h5>
                            <div id="aprsStationList" style="flex: 1; overflow-y: auto; font-size: 11px;">
                                <div style="padding: 20px; text-align: center; color: var(--text-muted);">
                                    No stations received yet
                                </div>
                            </div>
                        </div>
                    </div>

                    <!-- Bottom row: Packet Log -->
                    <div class="wifi-visual-panel" style="display: flex; flex-direction: column; max-height: 200px;">
                        <h5 style="color: var(--accent-orange); text-shadow: 0 0 10px var(--accent-orange); margin-bottom: 8px;">PACKET LOG</h5>
                        <div id="aprsPacketLog" style="flex: 1; overflow-y: auto; font-family: 'JetBrains Mono', monospace; font-size: 10px; background: rgba(0,0,0,0.3); padding: 8px; border-radius: 4px;">
                            <div style="color: var(--text-muted);">Waiting for packets...</div>
                        </div>
                    </div>
                </div>

                <!-- Listening Post Visualizations - Professional Ham Radio Scanner -->
                <div class="wifi-visuals" id="listeningPostVisuals" style="display: none;">

                    <!-- TOP: FREQUENCY DISPLAY PANEL -->
                    <div class="radio-module-box scanner-main" style="grid-column: span 4; padding: 12px;">
                        <div style="display: flex; gap: 15px; align-items: stretch;">
                            <!-- Main Frequency Display -->
                            <div style="flex: 1; text-align: center; padding: 15px 20px; background: rgba(0,0,0,0.6); border-radius: 6px; border: 1px solid var(--border-color);">
                                <div class="freq-status" id="mainScannerModeLabel" style="font-size: 10px; color: var(--text-muted); margin-bottom: 4px; letter-spacing: 3px;">STOPPED</div>
                                <div style="display: flex; justify-content: center; align-items: baseline; gap: 8px;">
                                    <div class="freq-digits" id="mainScannerFreq" style="font-size: 52px; font-weight: bold; color: var(--accent-cyan); text-shadow: 0 0 30px var(--accent-cyan); font-family: 'JetBrains Mono', monospace; letter-spacing: 3px;">118.000</div>
                                    <span class="freq-unit" style="font-size: 20px; color: var(--text-secondary); font-weight: 500;">MHz</span>
                                </div>
                                <div style="display: flex; justify-content: center; align-items: center; margin-top: 6px;">
                                    <span class="freq-mode-badge" id="mainScannerMod" style="background: var(--accent-cyan); color: #000; padding: 3px 12px; border-radius: 4px; font-size: 12px; font-weight: bold;">AM</span>
                                </div>
                                <!-- Progress bar -->
                                <div id="mainScannerProgress" style="display: none; margin-top: 12px;">
                                    <div style="display: flex; justify-content: space-between; font-size: 9px; color: var(--text-muted); margin-bottom: 3px;">
                                        <span id="mainRangeStart">--</span>
                                        <span id="mainRangeEnd">--</span>
                                    </div>
                                    <div style="height: 6px; background: rgba(0,0,0,0.5); border-radius: 3px; overflow: hidden;">
                                        <div class="scan-bar" id="mainProgressBar" style="height: 100%; background: linear-gradient(90deg, var(--accent-cyan), var(--accent-green)); width: 0%; transition: width 0.1s;"></div>
                                    </div>
                                </div>
                            </div>

                            <!-- Synthesizer + Audio Output Panel -->
                            <div style="width: 320px; display: flex; flex-direction: column; gap: 8px;">
                                <!-- Synthesizer Display -->
                                <div style="flex: 1; padding: 10px; background: rgba(0,0,0,0.6); border-radius: 6px; border: 1px solid var(--border-color);">
                                    <div style="font-size: 8px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 1px; margin-bottom: 6px;">Synthesizer</div>
                                    <canvas id="synthesizerCanvas" style="width: 100%; height: 60px; background: rgba(0,0,0,0.4); border-radius: 4px;"></canvas>
                                </div>
                                <!-- Audio Output -->
                                <div style="padding: 10px; background: rgba(0,0,0,0.4); border-radius: 6px; border: 1px solid var(--border-color);">
                                    <div style="display: flex; align-items: center; gap: 10px; margin-bottom: 8px;">
                                        <div style="font-size: 8px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 1px;">Audio Output</div>
                                    </div>
                                    <audio id="scannerAudioPlayer" style="width: 100%; height: 28px;" controls></audio>
                                    <div style="display: flex; align-items: center; gap: 8px; margin-top: 8px;">
                                        <span style="font-size: 7px; color: var(--text-muted);">LEVEL</span>
                                        <div style="flex: 1; height: 8px; background: rgba(0,0,0,0.5); border-radius: 4px; overflow: hidden;">
                                            <div id="audioSignalBar" style="height: 100%; background: linear-gradient(90deg, var(--accent-green), var(--accent-cyan), var(--accent-orange), var(--accent-red)); width: 0%; transition: width 0.1s;"></div>
                                        </div>
                                        <span id="audioSignalDb" style="font-size: 8px; color: var(--text-muted); min-width: 40px; text-align: right;">-- dB</span>
                                    </div>
                                    <!-- Signal Alert inline -->
                                    <div id="mainSignalAlert" style="display: none; background: rgba(0, 255, 100, 0.2); border: 1px solid var(--accent-green); border-radius: 4px; padding: 5px; text-align: center; margin-top: 8px;">
                                        <span style="font-size: 9px; color: var(--accent-green); font-weight: bold;">● SIGNAL</span>
                                        <button class="tune-btn" onclick="skipSignal()" style="margin-left: 8px; padding: 2px 8px; font-size: 8px;">Skip</button>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>

                    <!-- CONTROL PANEL: Tuning Section | Mode/Band | Action Buttons -->
                    <div class="radio-module-box" style="grid-column: span 4; padding: 12px;">
                        <div style="display: flex; gap: 15px; align-items: stretch;">

                            <!-- LEFT: Tuning Section -->
                            <div style="flex: 1; display: flex; align-items: center; justify-content: center; gap: 20px; padding: 10px 15px; background: rgba(0,0,0,0.3); border-radius: 8px; border: 1px solid var(--border-color);">

                                <!-- Fine Tune Buttons (Left of dial) -->
                                <div style="display: flex; flex-direction: column; gap: 4px;">
                                    <button class="tune-btn" onclick="tuneFreq(-1)" style="padding: 8px 12px; font-size: 11px;">-1</button>
                                    <button class="tune-btn" onclick="tuneFreq(-0.1)" style="padding: 8px 12px; font-size: 11px;">-.1</button>
                                </div>

                                <!-- Main Tuning Dial -->
                                <div style="display: flex; flex-direction: column; align-items: center;">
                                    <div class="tuning-dial" id="mainTuningDial" data-value="118" data-min="24" data-max="1800" data-step="0.1" style="width: 100px; height: 100px;"></div>
                                    <div style="font-size: 9px; color: var(--text-muted); margin-top: 6px; text-transform: uppercase; letter-spacing: 1px;">Tune</div>
                                </div>

                                <!-- Fine Tune Buttons (Right of dial) -->
                                <div style="display: flex; flex-direction: column; gap: 4px;">
                                    <button class="tune-btn" onclick="tuneFreq(0.1)" style="padding: 8px 12px; font-size: 11px;">+.1</button>
                                    <button class="tune-btn" onclick="tuneFreq(1)" style="padding: 8px 12px; font-size: 11px;">+1</button>
                                </div>

                                <!-- Divider -->
                                <div style="width: 1px; height: 80px; background: var(--border-color);"></div>

                                <!-- Settings: Step & Dwell -->
                                <div style="display: flex; flex-direction: column; gap: 8px; min-width: 90px;">
                                    <div style="display: flex; justify-content: space-between; align-items: center; font-size: 10px;">
                                        <span style="color: var(--text-muted);">Step</span>
                                        <select id="radioScanStep" style="background: var(--bg-secondary); border: 1px solid var(--border-color); color: var(--text-primary); padding: 3px 5px; border-radius: 3px; font-size: 9px;">
                                            <option value="8.33">8.33k</option>
                                            <option value="12.5">12.5k</option>
                                            <option value="25" selected>25k</option>
                                            <option value="50">50k</option>
                                            <option value="100">100k</option>
                                        </select>
                                    </div>
                                    <div style="display: flex; justify-content: space-between; align-items: center; font-size: 10px;">
                                        <span style="color: var(--text-muted);">Dwell</span>
                                        <select id="radioScanDwell" style="background: var(--bg-secondary); border: 1px solid var(--border-color); color: var(--text-primary); padding: 3px 5px; border-radius: 3px; font-size: 9px;">
                                            <option value="2">2s</option>
                                            <option value="5">5s</option>
                                            <option value="10" selected>10s</option>
                                            <option value="30">30s</option>
                                        </select>
                                    </div>
                                </div>

                                <!-- Divider -->
                                <div style="width: 1px; height: 80px; background: var(--border-color);"></div>

                                <!-- SQL, Gain, Vol Knobs -->
                                <div style="display: flex; gap: 15px;">
                                    <div class="knob-container">
                                        <div class="radio-knob" id="radioSquelchKnob" data-value="30" data-min="0" data-max="100" data-step="1"></div>
                                        <div class="knob-label">SQL</div>
                                        <div class="knob-value" id="radioSquelchValue">30</div>
                                    </div>
                                    <div class="knob-container">
                                        <div class="radio-knob" id="radioGainKnob" data-value="40" data-min="0" data-max="50" data-step="1"></div>
                                        <div class="knob-label">GAIN</div>
                                        <div class="knob-value" id="radioGainValue">40</div>
                                    </div>
                                    <div class="knob-container">
                                        <div class="radio-knob" id="radioVolumeKnob" data-value="80" data-min="0" data-max="100" data-step="1"></div>
                                        <div class="knob-label">VOL</div>
                                        <div class="knob-value" id="radioVolumeValue">80</div>
                                    </div>
                                </div>
                            </div>

                            <!-- CENTER: Mode & Band (Stacked) -->
                            <div style="width: 130px; display: flex; flex-direction: column; gap: 10px; justify-content: center;">
                                <div>
                                    <div style="font-size: 8px; color: var(--text-muted); margin-bottom: 4px; text-transform: uppercase; letter-spacing: 1px;">Modulation</div>
                                    <div class="radio-button-bank compact" id="modBtnBank" style="flex-wrap: wrap; gap: 2px;">
                                        <button class="radio-btn active" data-mod="am" onclick="setModulation('am')" style="padding: 6px 10px; font-size: 10px;">AM</button>
                                        <button class="radio-btn" data-mod="fm" onclick="setModulation('fm')" style="padding: 6px 10px; font-size: 10px;">NFM</button>
                                        <button class="radio-btn" data-mod="wfm" onclick="setModulation('wfm')" style="padding: 6px 10px; font-size: 10px;">WFM</button>
                                        <button class="radio-btn" data-mod="usb" onclick="setModulation('usb')" style="padding: 6px 10px; font-size: 10px;">USB</button>
                                        <button class="radio-btn" data-mod="lsb" onclick="setModulation('lsb')" style="padding: 6px 10px; font-size: 10px;">LSB</button>
                                    </div>
                                </div>
                                <div>
                                    <div style="font-size: 8px; color: var(--text-muted); margin-bottom: 4px; text-transform: uppercase; letter-spacing: 1px;">Band</div>
                                    <div class="radio-button-bank compact" id="bandBtnBank" style="flex-wrap: wrap; gap: 2px;">
                                        <button class="radio-btn" data-band="fm" onclick="setBand('fm')" style="padding: 6px 10px; font-size: 10px;">FM</button>
                                        <button class="radio-btn active" data-band="air" onclick="setBand('air')" style="padding: 6px 10px; font-size: 10px;">AIR</button>
                                        <button class="radio-btn" data-band="marine" onclick="setBand('marine')" style="padding: 6px 10px; font-size: 10px;">MAR</button>
                                        <button class="radio-btn" data-band="amateur2m" onclick="setBand('amateur2m')" style="padding: 6px 10px; font-size: 10px;">2M</button>
                                        <button class="radio-btn" data-band="amateur70cm" onclick="setBand('amateur70cm')" style="padding: 6px 10px; font-size: 10px;">70CM</button>
                                    </div>
                                </div>
                            </div>

                            <!-- RIGHT: Scan Range + Action Buttons -->
                            <div style="width: 175px; display: flex; flex-direction: column; gap: 8px;">
                                <!-- Frequency Range - Prominent -->
                                <div style="background: rgba(0,0,0,0.4); border: 1px solid var(--border-color); border-radius: 6px; padding: 10px;">
                                    <div style="font-size: 8px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 1px; margin-bottom: 8px; text-align: center;">Scan Range (MHz)</div>
                                    <div style="display: flex; align-items: center; gap: 6px;">
                                        <div style="flex: 1;">
                                            <div style="font-size: 7px; color: var(--text-muted); margin-bottom: 2px;">START</div>
                                            <input type="number" id="radioScanStart" value="118" step="0.1" class="radio-input" style="width: 100%; font-size: 16px; padding: 8px 6px; text-align: center; font-family: 'JetBrains Mono', monospace; font-weight: bold; color: var(--accent-cyan);">
                                        </div>
                                        <span style="color: var(--text-muted); font-size: 16px; padding-top: 12px;">→</span>
                                        <div style="flex: 1;">
                                            <div style="font-size: 7px; color: var(--text-muted); margin-bottom: 2px;">END</div>
                                            <input type="number" id="radioScanEnd" value="137" step="0.1" class="radio-input" style="width: 100%; font-size: 16px; padding: 8px 6px; text-align: center; font-family: 'JetBrains Mono', monospace; font-weight: bold; color: var(--accent-cyan);">
                                        </div>
                                    </div>
                                </div>
                                <!-- Action Buttons -->
                                <button class="radio-action-btn scan" id="radioScanBtn" onclick="toggleScanner()" style="padding: 12px; font-size: 13px; width: 100%; font-weight: bold;">📡 SCAN</button>
                                <button class="radio-action-btn" id="radioListenBtn" onclick="toggleDirectListen()" style="padding: 10px; font-size: 12px; width: 100%; background: var(--accent-green); border: none; color: #fff;">🎧 LISTEN</button>
                            </div>
                        </div>
                    </div>

                    <!-- QUICK TUNE BAR -->
                    <div class="radio-module-box" style="grid-column: span 4; padding: 8px 12px;">
                        <div style="display: flex; align-items: center; gap: 10px;">
                            <span style="font-size: 9px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 1px;">Quick Tune:</span>
                            <button class="preset-freq-btn" onclick="quickTune(121.5, 'am')">121.5 GUARD</button>
                            <button class="preset-freq-btn" onclick="quickTune(156.8, 'fm')">156.8 CH16</button>
                            <button class="preset-freq-btn" onclick="quickTune(145.5, 'fm')">145.5 2M</button>
                            <button class="preset-freq-btn" onclick="quickTune(98.1, 'wfm')">98.1 FM</button>
                            <button class="preset-freq-btn" onclick="quickTune(462.5625, 'fm')">462.56 FRS</button>
                            <button class="preset-freq-btn" onclick="quickTune(446.0, 'fm')">446.0 PMR</button>
                        </div>
                    </div>

                    <!-- SIGNAL HITS -->
                    <div class="radio-module-box" style="grid-column: span 2; padding: 10px;">
                        <div class="module-header" style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; font-size: 10px;">
                            <span>SIGNAL HITS</span>
                            <span style="font-size: 10px; color: var(--accent-cyan); background: rgba(0,212,255,0.1); padding: 2px 8px; border-radius: 3px;" id="scannerHitCount">0 signals</span>
                        </div>
                        <div id="scannerHitsList" style="overflow-y: auto; max-height: 100px;">
                            <table style="width: 100%; font-size: 10px; border-collapse: collapse;">
                                <thead>
                                    <tr style="color: var(--text-muted); border-bottom: 1px solid var(--border-color);">
                                        <th style="text-align: left; padding: 4px;">Time</th>
                                        <th style="text-align: left; padding: 4px;">Frequency</th>
                                        <th style="text-align: left; padding: 4px;">Mod</th>
                                        <th style="text-align: center; padding: 4px; width: 60px;">Action</th>
                                    </tr>
                                </thead>
                                <tbody id="scannerHitsBody">
                                    <tr style="color: var(--text-muted);">
                                        <td colspan="4" style="padding: 15px; text-align: center; font-size: 10px;">No signals detected</td>
                                    </tr>
                                </tbody>
                            </table>
                        </div>
                    </div>

                    <!-- STATS PANEL -->
                    <div class="radio-module-box" style="grid-column: span 1; padding: 10px;">
                        <div class="module-header" style="margin-bottom: 8px; font-size: 10px;">
                            <span>STATS</span>
                        </div>
                        <div style="display: flex; flex-direction: column; gap: 8px;">
                            <div style="display: flex; align-items: center; justify-content: space-between;">
                                <span style="font-size: 9px; color: var(--text-muted);">SIGNALS</span>
                                <span style="color: var(--accent-green); font-size: 18px; font-weight: bold; font-family: 'JetBrains Mono', monospace;" id="mainSignalCount">0</span>
                            </div>
                            <div style="display: flex; align-items: center; justify-content: space-between;">
                                <span style="font-size: 9px; color: var(--text-muted);">SCANNED</span>
                                <span style="color: var(--accent-cyan); font-size: 18px; font-weight: bold; font-family: 'JetBrains Mono', monospace;" id="mainFreqsScanned">0</span>
                            </div>
                            <div style="display: flex; align-items: center; justify-content: space-between;">
                                <span style="font-size: 9px; color: var(--text-muted);">CYCLES</span>
                                <span style="color: var(--accent-orange); font-size: 18px; font-weight: bold; font-family: 'JetBrains Mono', monospace;" id="mainScanCycles">0</span>
                            </div>
                        </div>
                    </div>

                    <!-- ACTIVITY LOG -->
                    <div class="radio-module-box" style="grid-column: span 1; padding: 10px;">
                        <div class="module-header" style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; font-size: 10px;">
                            <span>LOG</span>
                            <div style="display: flex; gap: 4px;">
                                <button class="tune-btn" onclick="exportScannerLog()" style="padding: 2px 6px; font-size: 8px;">Export</button>
                                <button class="tune-btn" onclick="clearScannerLog()" style="padding: 2px 6px; font-size: 8px;">Clear</button>
                            </div>
                        </div>
                        <div class="log-content" id="scannerActivityLog" style="max-height: 100px; overflow-y: auto; font-size: 9px; background: rgba(0,0,0,0.2); border-radius: 3px; padding: 6px;">
                            <div class="scanner-log-entry" style="color: var(--text-muted);">Ready</div>
                        </div>
                    </div>
                </div>

                <!-- Satellite Dashboard (Embedded) -->
                <div id="satelliteVisuals" class="satellite-dashboard-embed" style="display: none;">
                    <iframe
                        id="satelliteDashboardFrame"
                        src="/satellite/dashboard?embedded=true"
                        frameborder="0"
                        style="width: 100%; height: 100%; min-height: 700px; border: none; border-radius: 8px;"
                        allowfullscreen>
                    </iframe>
                </div>

                <!-- TSCM Dashboard -->
                <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: var(--text-muted);">
                        <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.
                    </div>

                    <!-- Risk Summary Banner (new scoring model) - clickable cards -->
                    <div class="tscm-threat-banner">
                        <div class="threat-card critical clickable" id="tscmHighInterestCard" onclick="showDevicesByCategory('high_interest')" title="Click to view high interest devices">
                            <span class="count" id="tscmHighInterestCount">0</span>
                            <span class="label">High Interest</span>
                        </div>
                        <div class="threat-card high clickable" id="tscmNeedsReviewCard" onclick="showDevicesByCategory('review')" title="Click to view devices needing review">
                            <span class="count" id="tscmNeedsReviewCount">0</span>
                            <span class="label">Needs Review</span>
                        </div>
                        <div class="threat-card low clickable" id="tscmInformationalCard" onclick="showDevicesByCategory('informational')" title="Click to view informational devices">
                            <span class="count" id="tscmInformationalCount">0</span>
                            <span class="label">Informational</span>
                        </div>
                        <div class="threat-card medium clickable" id="tscmCorrelationsCard" onclick="showDevicesByCategory('correlations')" title="Click to view correlations">
                            <span class="count" id="tscmCorrelationsCount">0</span>
                            <span class="label">Correlations</span>
                        </div>
                    </div>

                    <!-- Sweep Summary (shown after sweep completes) -->
                    <div id="tscmSweepSummary" style="display: none; margin-bottom: 16px;"></div>

                    <!-- Cross-Protocol Correlations (shown when correlations found) -->
                    <div id="tscmCorrelationsContainer" style="display: none;"></div>

                    <!-- Main Content Grid -->
                    <div class="tscm-main-grid">
                        <!-- WiFi Panel -->
                        <div class="tscm-panel">
                            <div class="tscm-panel-header">
                                WiFi Networks
                                <span class="badge" id="tscmWifiCount">0</span>
                            </div>
                            <div class="tscm-panel-content" id="tscmWifiList">
                                <div class="tscm-empty">Start a sweep to scan for WiFi networks</div>
                            </div>
                        </div>

                        <!-- Bluetooth Panel -->
                        <div class="tscm-panel">
                            <div class="tscm-panel-header">
                                Bluetooth Devices
                                <span class="badge" id="tscmBtCount">0</span>
                            </div>
                            <div class="tscm-panel-content" id="tscmBtList">
                                <div class="tscm-empty">Start a sweep to scan for Bluetooth devices</div>
                            </div>
                        </div>

                        <!-- RF Signals Panel -->
                        <div class="tscm-panel">
                            <div class="tscm-panel-header">
                                RF Signals
                                <span class="badge" id="tscmRfCount">0</span>
                            </div>
                            <div class="tscm-panel-content" id="tscmRfList">
                                <div class="tscm-empty">Enable RF scanning with an SDR device</div>
                            </div>
                        </div>

                        <!-- Threats Panel -->
                        <div class="tscm-panel" style="grid-column: span 2;">
                            <div class="tscm-panel-header">
                                Detected Threats
                                <span class="badge" id="tscmThreatCount">0</span>
                            </div>
                            <div class="tscm-panel-content" id="tscmThreatList">
                                <div class="tscm-empty">No threats detected</div>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- Device Intelligence Dashboard (above waterfall for prominence) -->
                <div class="recon-panel collapsed" id="reconPanel">
                    <div class="recon-header" onclick="toggleReconCollapse()" style="cursor: pointer;">
                        <h4><span id="reconCollapseIcon">▶</span> Device Intelligence</h4>
                        <div class="recon-stats">
                            <div>TRACKED: <span id="trackedCount">0</span></div>
                            <div>NEW: <span id="newDeviceCount">0</span></div>
                            <div>ANOMALIES: <span id="anomalyCount">0</span></div>
                        </div>
                    </div>
                    <div class="recon-content" id="reconContent">
                        <div style="color: #444; text-align: center; padding: 20px; font-size: 11px;">
                            Device intelligence data will appear here as signals are intercepted.
                        </div>
                    </div>
                </div>

                <div class="output-content" id="output">
                    <div class="placeholder" style="color: #888; text-align: center; padding: 50px;">
                        Configure settings and click "Start Decoding" to begin.
                    </div>
                </div>

                <!-- Pager Waterfall (pager mode only, at bottom, collapsible) -->
                <div class="sensor-waterfall-panel collapsed" id="pagerWaterfallPanel" style="display: none;">
                    <div class="sensor-waterfall-header" onclick="togglePagerWaterfall()" style="cursor: pointer;">
                        <span id="pagerWaterfallIcon">▶</span> Signal Waterfall
                    </div>
                    <div class="sensor-waterfall-content" id="pagerWaterfallContent">
                        <canvas id="waterfallCanvas" width="800" height="30"></canvas>
                    </div>
                </div>

                <!-- Sensor Waterfall (433MHz mode only, at bottom, collapsible) -->
                <div class="sensor-waterfall-panel collapsed" id="sensorWaterfallPanel" style="display: none;">
                    <div class="sensor-waterfall-header" onclick="toggleSensorWaterfall()" style="cursor: pointer;">
                        <span id="sensorWaterfallIcon">▶</span> Signal Waterfall
                    </div>
                    <div class="sensor-waterfall-content" id="sensorWaterfallContent">
                        <canvas id="sensorWaterfallCanvas" width="800" height="30"></canvas>
                    </div>
                </div>

                <div class="status-bar">
                    <div class="status-indicator">
                        <div class="status-dot" id="statusDot"></div>
                        <span id="statusText">Idle</span>
                    </div>
                    <div class="status-controls">
                        <div class="control-group">
                            <span class="control-group-label">Mode</span>
                            <button id="reconBtn" class="recon-toggle" onclick="toggleRecon()">RECON</button>
                            <button id="muteBtn" class="control-btn" onclick="toggleMute()">🔊</button>
                            <button id="autoScrollBtn" class="control-btn active" onclick="toggleAutoScroll()">⬇ AUTO</button>
                        </div>
                        <div class="control-group">
                            <span class="control-group-label">Export</span>
                            <button class="control-btn" onclick="exportCSV()">CSV</button>
                            <button class="control-btn" onclick="exportJSON()">JSON</button>
                            <button class="control-btn" onclick="exportDeviceDB()" title="Export Device Intelligence">INTEL</button>
                        </div>
                        <button class="clear-btn" onclick="clearMessages()">Clear</button>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Intercept JS Modules -->
    <script src="{{ url_for('static', filename='js/core/utils.js') }}"></script>
    <script src="{{ url_for('static', filename='js/core/audio.js') }}"></script>
    <script src="{{ url_for('static', filename='js/components/radio-knob.js') }}"></script>
    <script src="{{ url_for('static', filename='js/modes/listening-post.js') }}"></script>

    <script>
        // Selected mode from welcome screen
        let selectedStartMode = 'pager';

        // Mode selection from welcome page
        function selectMode(mode) {
            selectedStartMode = mode;
            const welcome = document.getElementById('welcomePage');
            welcome.classList.add('fade-out');

            // After fade out, hide welcome and show disclaimer if needed
            setTimeout(() => {
                welcome.style.display = 'none';
                checkDisclaimer();
            }, 400);
        }

        // Disclaimer handling
        function checkDisclaimer() {
            const accepted = localStorage.getItem('disclaimerAccepted');
            if (accepted === 'true') {
                document.getElementById('disclaimerModal').style.display = 'none';
                // Switch to the selected mode
                switchMode(selectedStartMode);
            } else {
                document.getElementById('disclaimerModal').style.display = 'flex';
            }
        }

        function acceptDisclaimer() {
            localStorage.setItem('disclaimerAccepted', 'true');
            document.getElementById('disclaimerModal').classList.add('disclaimer-hidden');
            // Switch to the selected mode after accepting
            setTimeout(() => {
                switchMode(selectedStartMode);
            }, 300);
        }

        function declineDisclaimer() {
            document.getElementById('disclaimerModal').classList.add('disclaimer-hidden');
            document.getElementById('rejectionPage').classList.remove('disclaimer-hidden');
        }

        // Don't auto-check disclaimer - wait for welcome page mode selection

        let eventSource = null;
        let isRunning = false;
        let isSensorRunning = false;
        let isWifiRunning = false;
        let isBtRunning = false;
        let currentMode = 'pager';
        let msgCount = 0;
        let pocsagCount = 0;
        let flexCount = 0;
        let sensorCount = 0;
        let filteredCount = 0;  // Count of filtered messages
        let deviceList = {{ devices | tojson | safe }};

        // Pager message filter settings
        let pagerFilters = {
            hideToneOnly: true,
            keywords: []
        };

        // UTC Clock Update
        function updateHeaderClock() {
            const now = new Date();
            const utc = now.toISOString().substring(11, 19);
            document.getElementById('headerUtcTime').textContent = utc;
        }
        // Update clock every second
        setInterval(updateHeaderClock, 1000);
        updateHeaderClock();  // Initial call

        // Pager message filter functions
        function loadPagerFilters() {
            const saved = localStorage.getItem('pagerFilters');
            if (saved) {
                try {
                    pagerFilters = JSON.parse(saved);
                } catch (e) {
                    console.warn('Failed to load pager filters:', e);
                }
            }
            // Update UI
            document.getElementById('filterToneOnly').checked = pagerFilters.hideToneOnly;
            document.getElementById('filterKeywords').value = pagerFilters.keywords.join(', ');
        }

        function savePagerFilters() {
            pagerFilters.hideToneOnly = document.getElementById('filterToneOnly').checked;
            const keywordsInput = document.getElementById('filterKeywords').value;
            pagerFilters.keywords = keywordsInput
                .split(',')
                .map(k => k.trim().toLowerCase())
                .filter(k => k.length > 0);
            localStorage.setItem('pagerFilters', JSON.stringify(pagerFilters));
        }

        function shouldFilterMessage(msg) {
            // Check for Tone Only filter
            if (pagerFilters.hideToneOnly) {
                if (msg.message === '[Tone Only]' || msg.msg_type === 'Tone') {
                    return true;
                }
            }
            // Check keyword filters
            if (pagerFilters.keywords.length > 0) {
                const msgLower = (msg.message || '').toLowerCase();
                for (const keyword of pagerFilters.keywords) {
                    if (msgLower.includes(keyword)) {
                        return true;
                    }
                }
            }
            return false;
        }

        // Sync header stats with output panel stats
        function syncHeaderStats() {
            // Pager stats
            document.getElementById('headerMsgCount').textContent = msgCount;
            document.getElementById('headerPocsagCount').textContent = pocsagCount;
            document.getElementById('headerFlexCount').textContent = flexCount;

            // Sensor stats
            document.getElementById('headerSensorCount').textContent = document.getElementById('sensorCount')?.textContent || '0';
            document.getElementById('headerDeviceTypeCount').textContent = document.getElementById('deviceCount')?.textContent || '0';

            // WiFi stats
            document.getElementById('headerApCount').textContent = document.getElementById('apCount')?.textContent || '0';
            document.getElementById('headerClientCount').textContent = document.getElementById('clientCount')?.textContent || '0';
            document.getElementById('headerHandshakeCount').textContent = document.getElementById('handshakeCount')?.textContent || '0';
            document.getElementById('headerDroneCount').textContent = document.getElementById('droneCount')?.textContent || '0';

            // Bluetooth stats
            document.getElementById('headerBtDeviceCount').textContent = document.getElementById('btDeviceCount')?.textContent || '0';
            document.getElementById('headerBtBeaconCount').textContent = document.getElementById('btBeaconCount')?.textContent || '0';

            // Satellite stats
            document.getElementById('headerPassCount').textContent = document.getElementById('passCount')?.textContent || '0';
        }
        // Sync stats periodically
        setInterval(syncHeaderStats, 500);

        // Observer location for distance calculations (load from localStorage or default to London)
        let observerLocation = (function() {
            const saved = localStorage.getItem('observerLocation');
            if (saved) {
                try {
                    const parsed = JSON.parse(saved);
                    if (parsed.lat && parsed.lon) return parsed;
                } catch (e) {}
            }
            return { lat: 51.5074, lon: -0.1278 };
        })();

        // GPS Dongle state
        let gpsConnected = false;
        let gpsEventSource = null;
        let gpsLastPosition = null;

        // Satellite state
        let satellitePasses = [];
        let selectedPass = null;
        let selectedPassIndex = 0;
        let countdownInterval = null;

        // Start satellite countdown timer
        function startCountdownTimer() {
            if (countdownInterval) clearInterval(countdownInterval);
            countdownInterval = setInterval(updateSatelliteCountdown, 1000);
        }

        // Update satellite countdown display
        function updateSatelliteCountdown() {
            // Update both main and popout countdowns
            updateCountdownDisplay('');
            updateCountdownDisplay('Popout');
        }

        // Helper to update countdown elements by suffix
        function updateCountdownDisplay(suffix) {
            const container = document.getElementById('satelliteCountdown' + suffix);
            if (!container) return;

            // Use the globally selected pass
            if (!selectedPass || satellitePasses.length === 0) {
                container.style.display = 'none';
                return;
            }

            const now = new Date();
            const startTime = parsePassTime(selectedPass.startTime);
            const endTime = new Date(startTime.getTime() + selectedPass.duration * 60000);

            container.style.display = 'block';
            document.getElementById('countdownSatName' + suffix).textContent = selectedPass.satellite;

            if (now >= startTime && now <= endTime) {
                // Currently visible
                const remaining = Math.max(0, Math.floor((endTime - now) / 1000));
                const mins = Math.floor(remaining / 60);
                const secs = remaining % 60;

                document.getElementById('countdownToPass' + suffix).textContent = 'VISIBLE';
                document.getElementById('countdownToPass' + suffix).classList.add('active');
                document.getElementById('countdownPassTime' + suffix).textContent = 'Now overhead';

                document.getElementById('countdownVisibility' + suffix).textContent = `${mins}:${secs.toString().padStart(2, '0')}`;
                document.getElementById('countdownVisLabel' + suffix).textContent = 'Remaining';

                document.getElementById('countdownMaxEl' + suffix).textContent = selectedPass.maxEl + '°';
                document.getElementById('countdownDirection' + suffix).textContent = selectedPass.direction || 'Pass';

                document.getElementById('countdownStatus' + suffix).textContent = '🟢 SATELLITE CURRENTLY VISIBLE';
                document.getElementById('countdownStatus' + suffix).className = 'countdown-status visible';

            } else if (startTime > now) {
                // Upcoming pass
                const secsToPass = Math.max(0, Math.floor((startTime - now) / 1000));
                const hours = Math.floor(secsToPass / 3600);
                const mins = Math.floor((secsToPass % 3600) / 60);
                const secs = secsToPass % 60;

                let countdownStr;
                if (hours > 0) {
                    countdownStr = `${hours}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
                } else {
                    countdownStr = `${mins}:${secs.toString().padStart(2, '0')}`;
                }

                document.getElementById('countdownToPass' + suffix).textContent = countdownStr;
                document.getElementById('countdownToPass' + suffix).classList.remove('active');
                document.getElementById('countdownPassTime' + suffix).textContent = selectedPass.startTime;

                document.getElementById('countdownVisibility' + suffix).textContent = selectedPass.duration + 'm';
                document.getElementById('countdownVisLabel' + suffix).textContent = 'Duration';

                document.getElementById('countdownMaxEl' + suffix).textContent = selectedPass.maxEl + '°';
                document.getElementById('countdownDirection' + suffix).textContent = selectedPass.direction || 'Pass';

                if (secsToPass < 300) {
                    document.getElementById('countdownStatus' + suffix).textContent = '🟡 PASS STARTING SOON';
                    document.getElementById('countdownStatus' + suffix).className = 'countdown-status upcoming';
                } else {
                    document.getElementById('countdownStatus' + suffix).textContent = 'Selected pass';
                    document.getElementById('countdownStatus' + suffix).className = 'countdown-status';
                }

            } else {
                // Pass already happened
                document.getElementById('countdownToPass' + suffix).textContent = 'PASSED';
                document.getElementById('countdownToPass' + suffix).classList.remove('active');
                document.getElementById('countdownPassTime' + suffix).textContent = selectedPass.startTime;

                document.getElementById('countdownVisibility' + suffix).textContent = selectedPass.duration + 'm';
                document.getElementById('countdownVisLabel' + suffix).textContent = 'Duration';

                document.getElementById('countdownMaxEl' + suffix).textContent = selectedPass.maxEl + '°';
                document.getElementById('countdownDirection' + suffix).textContent = selectedPass.direction || 'Pass';

                document.getElementById('countdownStatus' + suffix).textContent = 'Pass has ended';
                document.getElementById('countdownStatus' + suffix).className = 'countdown-status';
            }
        }

        // Parse pass time string to Date object
        function parsePassTime(timeStr) {
            // Expected format: "2025-12-21 14:32 UTC"
            // Remove "UTC" suffix and parse as ISO-like format
            const cleanTime = timeStr.replace(' UTC', '').replace(' ', 'T') + ':00Z';
            const parsed = new Date(cleanTime);

            // Fallback if that doesn't work
            if (isNaN(parsed.getTime())) {
                // Try parsing as-is
                return new Date(timeStr.replace(' UTC', ''));
            }
            return parsed;
        }

        // Make sections collapsible
        document.addEventListener('DOMContentLoaded', function() {
            document.querySelectorAll('.section h3').forEach(h3 => {
                h3.addEventListener('click', function() {
                    this.parentElement.classList.toggle('collapsed');
                });
            });

            // Collapse all sections by default (except SDR Device which is first)
            document.querySelectorAll('.section').forEach((section, index) => {
                // Keep first section expanded, collapse rest
                if (index > 0) {
                    section.classList.add('collapsed');
                }
            });

            // Load bias-T setting from localStorage
            loadBiasTSetting();

            // Initialize observer location input fields from saved location
            const obsLatInput = document.getElementById('obsLat');
            const obsLonInput = document.getElementById('obsLon');
            if (obsLatInput) obsLatInput.value = observerLocation.lat.toFixed(4);
            if (obsLonInput) obsLonInput.value = observerLocation.lon.toFixed(4);

            // Auto-connect to gpsd if available
            autoConnectGps();

            // Load pager message filters
            loadPagerFilters();

            // Initialize dropdown nav active state
            updateDropdownActiveState();
        });

        // Toggle section collapse
        function toggleSection(el) {
            el.closest('.section').classList.toggle('collapsed');
        }

        // Dropdown navigation
        function toggleNavDropdown(group) {
            const dropdown = document.querySelector(`.mode-nav-dropdown[data-group="${group}"]`);
            const isOpen = dropdown.classList.contains('open');

            // Close all dropdowns first
            document.querySelectorAll('.mode-nav-dropdown').forEach(d => d.classList.remove('open'));

            // Open this one if it was closed
            if (!isOpen) {
                dropdown.classList.add('open');
            }
        }

        function closeAllDropdowns() {
            document.querySelectorAll('.mode-nav-dropdown').forEach(d => d.classList.remove('open'));
        }

        function updateDropdownActiveState() {
            // Map modes to their dropdown groups
            const modeGroups = {
                'pager': 'sdr', 'sensor': 'sdr',
                'aprs': 'sdr', 'satellite': 'sdr', 'listening': 'sdr',
                'wifi': 'wireless', 'bluetooth': 'wireless',
                'tscm': 'security'
            };

            // Remove has-active from all dropdowns
            document.querySelectorAll('.mode-nav-dropdown').forEach(d => d.classList.remove('has-active'));

            // Add has-active to the dropdown containing the current mode
            const activeGroup = modeGroups[currentMode];
            if (activeGroup) {
                const dropdown = document.querySelector(`.mode-nav-dropdown[data-group="${activeGroup}"]`);
                if (dropdown) dropdown.classList.add('has-active');
            }
        }

        // Close dropdowns when clicking outside
        document.addEventListener('click', function(e) {
            if (!e.target.closest('.mode-nav-dropdown')) {
                closeAllDropdowns();
            }
        });

        // Mode switching
        function switchMode(mode) {
            // Stop any running scans when switching modes
            if (isRunning) stopDecoding();
            if (isSensorRunning) stopSensorDecoding();
            if (isWifiRunning) stopWifiScan();
            if (isBtRunning) stopBtScan();
            if (isAprsRunning) stopAprs();
            if (isTscmRunning) stopTscmSweep();

            currentMode = mode;

            // Close dropdowns and update active state
            closeAllDropdowns();
            updateDropdownActiveState();

            // Remove active from all nav buttons, then add to the correct one
            document.querySelectorAll('.mode-nav-btn').forEach(btn => btn.classList.remove('active'));
            const modeMap = {
                'pager': 'pager', 'sensor': '433',
                'satellite': 'satellite', 'wifi': 'wifi', 'bluetooth': 'bluetooth',
                'listening': 'listening', 'aprs': 'aprs', 'tscm': 'tscm'
            };
            document.querySelectorAll('.mode-nav-btn').forEach(btn => {
                const label = btn.querySelector('.nav-label');
                if (label && label.textContent.toLowerCase().includes(modeMap[mode])) {
                    btn.classList.add('active');
                }
            });
            document.getElementById('pagerMode').classList.toggle('active', mode === 'pager');
            document.getElementById('sensorMode').classList.toggle('active', mode === 'sensor');
            document.getElementById('satelliteMode').classList.toggle('active', mode === 'satellite');
            document.getElementById('wifiMode').classList.toggle('active', mode === 'wifi');
            document.getElementById('bluetoothMode').classList.toggle('active', mode === 'bluetooth');
            document.getElementById('listeningPostMode').classList.toggle('active', mode === 'listening');
            document.getElementById('aprsMode').classList.toggle('active', mode === 'aprs');
            document.getElementById('tscmMode').classList.toggle('active', mode === 'tscm');
            document.getElementById('pagerStats').style.display = mode === 'pager' ? 'flex' : 'none';
            document.getElementById('sensorStats').style.display = mode === 'sensor' ? 'flex' : 'none';
            document.getElementById('satelliteStats').style.display = mode === 'satellite' ? 'flex' : 'none';
            document.getElementById('wifiStats').style.display = mode === 'wifi' ? 'flex' : 'none';
            document.getElementById('btStats').style.display = mode === 'bluetooth' ? 'flex' : 'none';

            // Update header stats groups
            document.getElementById('headerPagerStats').classList.toggle('active', mode === 'pager');
            document.getElementById('headerSensorStats').classList.toggle('active', mode === 'sensor');
            document.getElementById('headerSatelliteStats').classList.toggle('active', mode === 'satellite');
            document.getElementById('headerWifiStats').classList.toggle('active', mode === 'wifi');
            document.getElementById('headerBtStats').classList.toggle('active', mode === 'bluetooth');

            // Show/hide dashboard buttons in nav bar
            document.getElementById('satelliteDashboardBtn').style.display = mode === 'satellite' ? 'inline-flex' : 'none';

            // Update active mode indicator
            const modeNames = {
                'pager': 'PAGER',
                'sensor': '433MHZ',
                'satellite': 'SATELLITE',
                'wifi': 'WIFI',
                'bluetooth': 'BLUETOOTH',
                'listening': 'LISTENING POST',
                'aprs': 'APRS',
                'tscm': 'TSCM'
            };
            document.getElementById('activeModeIndicator').innerHTML = '<span class="pulse-dot"></span>' + modeNames[mode];
            document.getElementById('wifiLayoutContainer').style.display = mode === 'wifi' ? 'flex' : 'none';
            document.getElementById('btLayoutContainer').style.display = mode === 'bluetooth' ? 'flex' : 'none';
            document.getElementById('satelliteVisuals').style.display = mode === 'satellite' ? 'block' : 'none';
            document.getElementById('listeningPostVisuals').style.display = mode === 'listening' ? 'grid' : 'none';
            document.getElementById('aprsVisuals').style.display = mode === 'aprs' ? 'flex' : 'none';
            document.getElementById('tscmVisuals').style.display = mode === 'tscm' ? 'flex' : 'none';

            // Update output panel title based on mode
            const titles = {
                'pager': 'Pager Decoder',
                'sensor': '433MHz Sensor Monitor',
                'satellite': 'Satellite Monitor',
                'wifi': 'WiFi Scanner',
                'bluetooth': 'Bluetooth Scanner',
                'listening': 'Listening Post',
                'aprs': 'APRS Tracker',
                'tscm': 'TSCM Counter-Surveillance'
            };
            document.getElementById('outputTitle').textContent = titles[mode] || 'Signal Monitor';

            // Initialize TSCM mode when selected
            if (mode === 'tscm') {
                loadTscmBaselines();
                refreshTscmDevices();
            }

            // Show/hide Device Intelligence for modes that use it (not for satellite/aircraft/tscm)
            const reconBtn = document.getElementById('reconBtn');
            const intelBtn = document.querySelector('[onclick="exportDeviceDB()"]');
            if (mode === 'satellite' || mode === 'listening' || mode === 'aprs' || mode === 'tscm') {
                document.getElementById('reconPanel').style.display = 'none';
                if (reconBtn) reconBtn.style.display = 'none';
                if (intelBtn) intelBtn.style.display = 'none';
            } else {
                if (reconBtn) reconBtn.style.display = 'inline-block';
                if (intelBtn) intelBtn.style.display = 'inline-block';
                // Restore panel visibility based on reconEnabled state
                if (reconEnabled) {
                    document.getElementById('reconPanel').style.display = 'block';
                }
            }

            // Show RTL-SDR device section for modes that use it
            document.getElementById('rtlDeviceSection').style.display = (mode === 'pager' || mode === 'sensor' || mode === 'listening' || mode === 'aprs') ? 'block' : 'none';

            // Toggle mode-specific tool status displays
            document.getElementById('toolStatusPager').style.display = (mode === 'pager') ? 'grid' : 'none';
            document.getElementById('toolStatusSensor').style.display = (mode === 'sensor') ? 'grid' : 'none';

            // Hide waterfall and output console for modes with their own visualizations
            // Pager waterfall: show only for pager mode
            document.getElementById('pagerWaterfallPanel').style.display = (mode === 'pager') ? 'block' : 'none';
            // Sensor waterfall: show only for sensor (433MHz) mode
            document.getElementById('sensorWaterfallPanel').style.display = (mode === 'sensor') ? 'block' : 'none';
            document.getElementById('output').style.display = (mode === 'satellite' || mode === 'aprs' || mode === 'wifi' || mode === 'bluetooth' || mode === 'listening' || mode === 'tscm') ? 'none' : 'block';
            document.querySelector('.status-bar').style.display = (mode === 'satellite') ? 'none' : 'flex';

            // Load interfaces and initialize visualizations when switching modes
            if (mode === 'wifi') {
                refreshWifiInterfaces();
                initRadar();
                initWatchList();
            } else if (mode === 'bluetooth') {
                refreshBtInterfaces();
                initBtRadar();
            } else if (mode === 'aprs') {
                checkAprsTools();
                initAprsMap();
                // Fix map sizing on mobile after container becomes visible
                setTimeout(() => {
                    if (aprsMap) aprsMap.invalidateSize();
                }, 100);
            } else if (mode === 'satellite') {
                initPolarPlot();
                initSatelliteList();
            }
        }

        // Handle window resize for maps (especially important on mobile orientation change)
        window.addEventListener('resize', function() {
            if (aprsMap) aprsMap.invalidateSize();
        });

        // Also handle orientation changes explicitly for mobile
        window.addEventListener('orientationchange', function() {
            setTimeout(() => {
                if (aprsMap) aprsMap.invalidateSize();
            }, 200);
        });

        // Track unique sensor devices
        let uniqueDevices = new Set();

        // Sensor frequency
        function setSensorFreq(freq) {
            document.getElementById('sensorFrequency').value = freq;
            if (isSensorRunning) {
                fetch('/stop_sensor', {method: 'POST'})
                    .then(() => setTimeout(() => startSensorDecoding(), 500));
            }
        }

        // Start sensor decoding
        function startSensorDecoding() {
            const freq = document.getElementById('sensorFrequency').value;
            const gain = document.getElementById('sensorGain').value;
            const ppm = document.getElementById('sensorPpm').value;
            const device = getSelectedDevice();

            // Check if device is available
            if (!checkDeviceAvailability('sensor')) {
                return;
            }

            // Check for remote SDR
            const remoteConfig = getRemoteSDRConfig();
            if (remoteConfig === false) return; // Validation failed

            const config = {
                frequency: freq,
                gain: gain,
                ppm: ppm,
                device: device,
                sdr_type: getSelectedSDRType(),
                bias_t: getBiasTEnabled()
            };

            // Add rtl_tcp params if using remote SDR
            if (remoteConfig) {
                config.rtl_tcp_host = remoteConfig.host;
                config.rtl_tcp_port = remoteConfig.port;
            }

            fetch('/start_sensor', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify(config)
            }).then(r => r.json())
              .then(data => {
                  if (data.status === 'started') {
                      reserveDevice(parseInt(device), 'sensor');
                      setSensorRunning(true);
                      startSensorStream();
                  } else {
                      alert('Error: ' + data.message);
                  }
              });
        }

        // Stop sensor decoding
        function stopSensorDecoding() {
            fetch('/stop_sensor', {method: 'POST'})
                .then(r => r.json())
                .then(data => {
                    releaseDevice('sensor');
                    setSensorRunning(false);
                    if (eventSource) {
                        eventSource.close();
                        eventSource = null;
                    }
                });
        }

        function setSensorRunning(running) {
            isSensorRunning = running;
            document.getElementById('statusDot').classList.toggle('running', running);
            document.getElementById('statusText').textContent = running ? 'Listening...' : 'Idle';
            document.getElementById('startSensorBtn').style.display = running ? 'none' : 'block';
            document.getElementById('stopSensorBtn').style.display = running ? 'block' : 'none';
        }

        function startSensorStream() {
            if (eventSource) {
                eventSource.close();
            }

            eventSource = new EventSource('/stream_sensor');

            eventSource.onopen = function() {
                showInfo('Sensor stream connected...');
            };

            eventSource.onmessage = function(e) {
                const data = JSON.parse(e.data);
                if (data.type === 'sensor') {
                    addSensorReading(data);
                } else if (data.type === 'status') {
                    if (data.text === 'stopped') {
                        setSensorRunning(false);
                    }
                } else if (data.type === 'info' || data.type === 'raw') {
                    showInfo(data.text);
                }
            };

            eventSource.onerror = function(e) {
                console.error('Sensor stream error');
            };
        }

        function addSensorReading(data) {
            const output = document.getElementById('output');
            const placeholder = output.querySelector('.placeholder');
            if (placeholder) placeholder.remove();

            // Store for export
            allMessages.push(data);
            playAlert();
            pulseSignal();
            addWaterfallPoint(Date.now(), 0.8);

            sensorCount++;
            document.getElementById('sensorCount').textContent = sensorCount;

            // Track unique devices by model + id
            const deviceKey = (data.model || 'Unknown') + '_' + (data.id || data.channel || '0');
            if (!uniqueDevices.has(deviceKey)) {
                uniqueDevices.add(deviceKey);
                document.getElementById('deviceCount').textContent = uniqueDevices.size;
            }

            const card = document.createElement('div');
            card.className = 'sensor-card';

            let dataItems = '';
            const skipKeys = ['type', 'time', 'model', 'raw'];
            for (const [key, value] of Object.entries(data)) {
                if (!skipKeys.includes(key) && value !== null && value !== undefined) {
                    const label = key.replace(/_/g, ' ');
                    let displayValue = value;
                    if (key === 'temperature_C') displayValue = value + ' °C';
                    else if (key === 'temperature_F') displayValue = value + ' °F';
                    else if (key === 'humidity') displayValue = value + ' %';
                    else if (key === 'pressure_hPa') displayValue = value + ' hPa';
                    else if (key === 'wind_avg_km_h') displayValue = value + ' km/h';
                    else if (key === 'rain_mm') displayValue = value + ' mm';
                    else if (key === 'battery_ok') displayValue = value ? 'OK' : 'Low';

                    dataItems += '<div class="data-item"><div class="data-label">' + label + '</div><div class="data-value">' + displayValue + '</div></div>';
                }
            }

            const relTime = data.time ? getRelativeTime(data.time.split(' ')[1] || data.time) : 'now';

            card.innerHTML =
                '<div class="header" style="display: flex; justify-content: space-between; margin-bottom: 8px;">' +
                    '<span class="device-name">' + (data.model || 'Unknown Device') + '</span>' +
                    '<span class="msg-time" data-timestamp="' + (data.time || '') + '" style="color: #444; font-size: 10px;">' + relTime + '</span>' +
                '</div>' +
                '<div class="sensor-data">' + dataItems + '</div>';

            output.insertBefore(card, output.firstChild);

            if (autoScroll) output.scrollTop = 0;
            while (output.children.length > 100) {
                output.removeChild(output.lastChild);
            }
        }

        function toggleSensorLogging() {
            const enabled = document.getElementById('sensorLogging').checked;
            fetch('/logging', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify({enabled: enabled, log_file: 'sensor_data.log'})
            });
        }

        // NOTE: Audio alert settings moved to static/js/core/audio.js

        // Message storage for export
        let allMessages = [];

        function exportCSV() {
            if (allMessages.length === 0) {
                alert('No messages to export');
                return;
            }
            const headers = ['Timestamp', 'Protocol', 'Address', 'Function', 'Type', 'Message'];
            const csv = [headers.join(',')];
            allMessages.forEach(msg => {
                const row = [
                    msg.timestamp || '',
                    msg.protocol || '',
                    msg.address || '',
                    msg.function || '',
                    msg.msg_type || '',
                    '"' + (msg.message || '').replace(/"/g, '""') + '"'
                ];
                csv.push(row.join(','));
            });
            downloadFile(csv.join('\n'), 'intercept_messages.csv', 'text/csv');
        }

        function exportJSON() {
            if (allMessages.length === 0) {
                alert('No messages to export');
                return;
            }
            downloadFile(JSON.stringify(allMessages, null, 2), 'intercept_messages.json', 'application/json');
        }

        function downloadFile(content, filename, type) {
            const blob = new Blob([content], { type });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = filename;
            a.click();
            URL.revokeObjectURL(url);
        }

        // Auto-scroll setting
        let autoScroll = localStorage.getItem('autoScroll') !== 'false';

        function toggleAutoScroll() {
            autoScroll = !autoScroll;
            localStorage.setItem('autoScroll', autoScroll);
            updateAutoScrollButton();
        }

        function updateAutoScrollButton() {
            const btn = document.getElementById('autoScrollBtn');
            if (btn) {
                btn.innerHTML = autoScroll ? '⬇ AUTO-SCROLL ON' : '⬇ AUTO-SCROLL OFF';
                btn.classList.toggle('active', autoScroll);
            }
        }

        // Signal activity meter
        let signalActivity = 0;
        let lastMessageTime = 0;

        function updateSignalMeter() {
            const now = Date.now();
            const timeSinceLastMsg = now - lastMessageTime;

            // Decay signal activity over time
            if (timeSinceLastMsg > 1000) {
                signalActivity = Math.max(0, signalActivity - 0.05);
            }

            const meter = document.getElementById('signalMeter');
            const bars = meter?.querySelectorAll('.signal-bar');
            if (bars) {
                const activeBars = Math.ceil(signalActivity * bars.length);
                bars.forEach((bar, i) => {
                    bar.classList.toggle('active', i < activeBars);
                });
            }
        }

        function pulseSignal() {
            signalActivity = Math.min(1, signalActivity + 0.4);
            lastMessageTime = Date.now();

            // Flash waterfall canvas (use appropriate canvas based on mode)
            const canvasId = (currentMode === 'sensor') ? 'sensorWaterfallCanvas' : 'waterfallCanvas';
            const canvas = document.getElementById(canvasId);
            if (canvas) {
                canvas.classList.add('active');
                setTimeout(() => canvas.classList.remove('active'), 500);
            }
        }

        // Waterfall display
        const waterfallData = [];
        const maxWaterfallRows = 50;

        function addWaterfallPoint(timestamp, intensity) {
            waterfallData.push({ time: timestamp, intensity });
            if (waterfallData.length > maxWaterfallRows * 100) {
                waterfallData.shift();
            }
            renderWaterfall();
        }

        function renderWaterfall() {
            // Render to the appropriate canvas based on current mode
            const canvasId = (currentMode === 'sensor') ? 'sensorWaterfallCanvas' : 'waterfallCanvas';
            const canvas = document.getElementById(canvasId);
            if (!canvas) return;
            const ctx = canvas.getContext('2d', { willReadFrequently: true });
            const width = canvas.width;
            const height = canvas.height;

            // Shift existing image down
            const imageData = ctx.getImageData(0, 0, width, height - 2);
            ctx.putImageData(imageData, 0, 2);

            // Draw new row at top
            ctx.fillStyle = '#000';
            ctx.fillRect(0, 0, width, 2);

            // Add activity markers
            const now = Date.now();
            const recentData = waterfallData.filter(d => now - d.time < 100);
            recentData.forEach(d => {
                const x = Math.random() * width;
                const hue = 180 + (d.intensity * 60); // cyan to green
                ctx.fillStyle = `hsla(${hue}, 100%, 50%, ${d.intensity})`;
                ctx.fillRect(x - 2, 0, 4, 2);
            });
        }

        // Relative timestamps
        function getRelativeTime(timestamp) {
            if (!timestamp) return '';
            const now = new Date();
            const parts = timestamp.split(':');
            const msgTime = new Date();
            msgTime.setHours(parseInt(parts[0]), parseInt(parts[1]), parseInt(parts[2]));

            const diff = Math.floor((now - msgTime) / 1000);
            if (diff < 5) return 'just now';
            if (diff < 60) return diff + 's ago';
            if (diff < 3600) return Math.floor(diff / 60) + 'm ago';
            return timestamp;
        }

        function updateRelativeTimes() {
            document.querySelectorAll('.msg-time').forEach(el => {
                const ts = el.dataset.timestamp;
                if (ts) el.textContent = getRelativeTime(ts);
            });
        }

        // Update timers
        setInterval(updateSignalMeter, 100);
        setInterval(updateRelativeTimes, 10000);

        // Default presets (UK frequencies)
        const defaultPresets = ['153.350', '153.025'];

        // Load presets from localStorage or use defaults
        function loadPresets() {
            const saved = localStorage.getItem('pagerPresets');
            return saved ? JSON.parse(saved) : [...defaultPresets];
        }

        function savePresets(presets) {
            localStorage.setItem('pagerPresets', JSON.stringify(presets));
        }

        function renderPresets() {
            const presets = loadPresets();
            const container = document.getElementById('presetButtons');
            container.innerHTML = presets.map(freq =>
                `<button class="preset-btn" onclick="setFreq('${freq}')" oncontextmenu="removePreset('${freq}'); return false;" title="Right-click to remove">${freq}</button>`
            ).join('');
        }

        function addPreset() {
            const input = document.getElementById('newPresetFreq');
            const freq = input.value.trim();
            if (!freq || isNaN(parseFloat(freq))) {
                alert('Please enter a valid frequency');
                return;
            }
            const presets = loadPresets();
            if (!presets.includes(freq)) {
                presets.push(freq);
                savePresets(presets);
                renderPresets();
            }
            input.value = '';
        }

        function removePreset(freq) {
            if (confirm('Remove preset ' + freq + ' MHz?')) {
                let presets = loadPresets();
                presets = presets.filter(p => p !== freq);
                savePresets(presets);
                renderPresets();
            }
        }

        function resetPresets() {
            if (confirm('Reset to default presets?')) {
                savePresets([...defaultPresets]);
                renderPresets();
            }
        }

        // Initialize presets on load
        renderPresets();

        // Initialize button states on load
        updateMuteButton();
        updateAutoScrollButton();

        // NOTE: Audio context initialization moved to static/js/core/audio.js

        function setFreq(freq) {
            document.getElementById('frequency').value = freq;
            // Auto-restart decoder with new frequency if currently running
            if (isRunning) {
                fetch('/stop', {method: 'POST'})
                    .then(() => {
                        setTimeout(() => startDecoding(), 500);
                    });
            }
        }

        // SDR hardware capabilities
        const sdrCapabilities = {
            'rtlsdr': { name: 'RTL-SDR', freq_min: 24, freq_max: 1766, gain_min: 0, gain_max: 50 },
            'limesdr': { name: 'LimeSDR', freq_min: 0.1, freq_max: 3800, gain_min: 0, gain_max: 73 },
            'hackrf': { name: 'HackRF', freq_min: 1, freq_max: 6000, gain_min: 0, gain_max: 62 }
        };

        // Current device list with SDR type info
        let currentDeviceList = [];

        // SDR Device Usage Tracking
        // Tracks which mode is using which device index
        const sdrDeviceUsage = {
            // deviceIndex: 'modeName' (e.g., 0: 'pager', 1: 'scanner')
        };

        function getDeviceInUseBy(deviceIndex) {
            return sdrDeviceUsage[deviceIndex] || null;
        }

        function isDeviceInUse(deviceIndex) {
            return sdrDeviceUsage[deviceIndex] !== undefined;
        }

        function reserveDevice(deviceIndex, modeName) {
            sdrDeviceUsage[deviceIndex] = modeName;
            updateDeviceSelectStatus();
        }

        function releaseDevice(modeName) {
            for (const [idx, mode] of Object.entries(sdrDeviceUsage)) {
                if (mode === modeName) {
                    delete sdrDeviceUsage[idx];
                }
            }
            updateDeviceSelectStatus();
        }

        function getAvailableDevice() {
            // Find first device not in use
            for (const device of currentDeviceList) {
                if (!isDeviceInUse(device.index)) {
                    return device.index;
                }
            }
            return null;
        }

        function updateDeviceSelectStatus() {
            // Update device dropdown to show which devices are in use
            const select = document.getElementById('deviceSelect');
            if (!select) return;

            const options = select.querySelectorAll('option');
            options.forEach(opt => {
                const idx = parseInt(opt.value);
                const usedBy = getDeviceInUseBy(idx);
                const baseName = opt.textContent.replace(/ \[.*\]$/, ''); // Remove existing status
                if (usedBy) {
                    opt.textContent = `${baseName} [${usedBy.toUpperCase()}]`;
                    opt.style.color = 'var(--accent-orange)';
                } else {
                    opt.textContent = baseName;
                    opt.style.color = '';
                }
            });
        }

        function checkDeviceAvailability(modeName) {
            const selectedDevice = parseInt(getSelectedDevice());
            const usedBy = getDeviceInUseBy(selectedDevice);

            if (usedBy && usedBy !== modeName) {
                // Device is in use by another mode
                const availableDevice = getAvailableDevice();

                if (availableDevice !== null) {
                    // Another device is available - offer to switch
                    const switchDevice = confirm(
                        `Device ${selectedDevice} is in use by ${usedBy.toUpperCase()}.\n\n` +
                        `Device ${availableDevice} is available. Switch to it?`
                    );
                    if (switchDevice) {
                        document.getElementById('deviceSelect').value = availableDevice;
                        return true; // Can proceed with new device
                    }
                    return false; // User declined to switch
                } else {
                    // No other devices available
                    showNotification('SDR In Use',
                        `Device ${selectedDevice} is in use by ${usedBy.toUpperCase()}. ` +
                        `No other SDR devices available. Stop ${usedBy} first or connect another SDR.`
                    );
                    return false;
                }
            }
            return true; // Device is available
        }

        function onSDRTypeChanged() {
            const sdrType = document.getElementById('sdrTypeSelect').value;
            const select = document.getElementById('deviceSelect');

            // Filter devices by selected SDR type
            const filteredDevices = currentDeviceList.filter(d =>
                (d.sdr_type || 'rtlsdr') === sdrType
            );

            if (filteredDevices.length === 0) {
                select.innerHTML = `<option value="0">No ${sdrCapabilities[sdrType]?.name || sdrType} devices found</option>`;
            } else {
                select.innerHTML = filteredDevices.map(d =>
                    `<option value="${d.index}" data-sdr-type="${d.sdr_type || 'rtlsdr'}">${d.index}: ${d.name}</option>`
                ).join('');
            }

            // Update capabilities display
            updateCapabilitiesDisplay(sdrType);
        }

        function updateCapabilitiesDisplay(sdrType) {
            const caps = sdrCapabilities[sdrType];
            if (caps) {
                document.getElementById('capFreqRange').textContent = `${caps.freq_min}-${caps.freq_max} MHz`;
                document.getElementById('capGainRange').textContent = `${caps.gain_min}-${caps.gain_max} dB`;
            }
        }

        function refreshDevices() {
            fetch('/devices')
                .then(r => r.json())
                .then(devices => {
                    // Store full device list with SDR type info
                    currentDeviceList = devices;
                    deviceList = devices;

                    // Auto-select SDR type if devices found
                    if (devices.length > 0) {
                        const firstType = devices[0].sdr_type || 'rtlsdr';
                        document.getElementById('sdrTypeSelect').value = firstType;
                    }

                    // Trigger filter update
                    onSDRTypeChanged();
                })
                .catch(err => {
                    console.error('Failed to refresh devices:', err);
                    const select = document.getElementById('deviceSelect');
                    select.innerHTML = '<option value="0">Error loading devices</option>';
                });
        }

        function getSelectedDevice() {
            return document.getElementById('deviceSelect').value;
        }

        function getSelectedSDRType() {
            return document.getElementById('sdrTypeSelect').value;
        }

        // Bias-T power setting
        function saveBiasTSetting() {
            const enabled = document.getElementById('biasT')?.checked || false;
            localStorage.setItem('biasTEnabled', enabled);
        }

        function getBiasTEnabled() {
            return document.getElementById('biasT')?.checked || false;
        }

        function loadBiasTSetting() {
            const saved = localStorage.getItem('biasTEnabled');
            if (saved === 'true') {
                const checkbox = document.getElementById('biasT');
                if (checkbox) checkbox.checked = true;
            }
        }

        function toggleRemoteSDR() {
            const useRemote = document.getElementById('useRemoteSDR').checked;
            const configDiv = document.getElementById('remoteSDRConfig');
            const localControls = document.querySelectorAll('#sdrTypeSelect, #deviceSelect');

            configDiv.style.display = useRemote ? 'block' : 'none';

            // Dim local device controls when using remote
            localControls.forEach(el => {
                el.style.opacity = useRemote ? '0.5' : '1';
                el.disabled = useRemote;
            });
        }

        function getRemoteSDRConfig() {
            const useRemote = document.getElementById('useRemoteSDR').checked;
            if (!useRemote) return null;

            const host = document.getElementById('rtlTcpHost').value.trim();
            const port = parseInt(document.getElementById('rtlTcpPort').value) || 1234;

            if (!host) {
                alert('Please enter rtl_tcp host address');
                return false;
            }

            return { host, port };
        }

        function getSelectedProtocols() {
            const protocols = [];
            if (document.getElementById('proto_pocsag512').checked) protocols.push('POCSAG512');
            if (document.getElementById('proto_pocsag1200').checked) protocols.push('POCSAG1200');
            if (document.getElementById('proto_pocsag2400').checked) protocols.push('POCSAG2400');
            if (document.getElementById('proto_flex').checked) protocols.push('FLEX');
            return protocols;
        }

        function startDecoding() {
            const freq = document.getElementById('frequency').value;
            const gain = document.getElementById('gain').value;
            const squelch = document.getElementById('squelch').value;
            const ppm = document.getElementById('ppm').value;
            const device = getSelectedDevice();
            const protocols = getSelectedProtocols();

            if (protocols.length === 0) {
                alert('Please select at least one protocol');
                return;
            }

            // Check if device is available
            if (!checkDeviceAvailability('pager')) {
                return;
            }

            // Check for remote SDR
            const remoteConfig = getRemoteSDRConfig();
            if (remoteConfig === false) return; // Validation failed

            const config = {
                frequency: freq,
                gain: gain,
                squelch: squelch,
                ppm: ppm,
                device: device,
                sdr_type: getSelectedSDRType(),
                protocols: protocols,
                bias_t: getBiasTEnabled()
            };

            // Add rtl_tcp params if using remote SDR
            if (remoteConfig) {
                config.rtl_tcp_host = remoteConfig.host;
                config.rtl_tcp_port = remoteConfig.port;
            }

            fetch('/start', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify(config)
            }).then(r => r.json())
              .then(data => {
                  if (data.status === 'started') {
                      reserveDevice(parseInt(device), 'pager');
                      setRunning(true);
                      startStream();
                  } else {
                      alert('Error: ' + data.message);
                  }
              })
              .catch(err => {
                  console.error('Start error:', err);
              });
        }

        function stopDecoding() {
            fetch('/stop', {method: 'POST'})
                .then(r => r.json())
                .then(data => {
                    releaseDevice('pager');
                    setRunning(false);
                    if (eventSource) {
                        eventSource.close();
                        eventSource = null;
                    }
                });
        }

        function killAll() {
            fetch('/killall', {method: 'POST'})
                .then(r => r.json())
                .then(data => {
                    // Release all devices
                    Object.keys(sdrDeviceUsage).forEach(idx => delete sdrDeviceUsage[idx]);
                    updateDeviceSelectStatus();

                    setRunning(false);
                    setSensorRunning(false);
                    isScannerRunning = false;
                    isAudioPlaying = false;

                    if (eventSource) {
                        eventSource.close();
                        eventSource = null;
                    }
                    showInfo('Killed all processes: ' + (data.processes.length ? data.processes.join(', ') : 'none running'));
                });
        }

        function checkStatus() {
            fetch('/status')
                .then(r => r.json())
                .then(data => {
                    if (data.running !== isRunning) {
                        setRunning(data.running);
                        if (data.running && !eventSource) {
                            startStream();
                        }
                    }
                })
                .catch(() => {
                    // Silently ignore - server may be restarting or network issue
                });
        }

        // Periodic status check every 5 seconds
        setInterval(checkStatus, 5000);

        function toggleLogging() {
            const enabled = document.getElementById('loggingEnabled').checked;
            const logFile = document.getElementById('logFilePath').value;
            fetch('/logging', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify({enabled: enabled, log_file: logFile})
            }).then(r => r.json())
              .then(data => {
                  showInfo(data.logging ? 'Logging enabled: ' + data.log_file : 'Logging disabled');
              });
        }

        function setRunning(running) {
            isRunning = running;
            document.getElementById('statusDot').classList.toggle('running', running);
            document.getElementById('statusText').textContent = running ? 'Decoding...' : 'Idle';
            document.getElementById('startBtn').style.display = running ? 'none' : 'block';
            document.getElementById('stopBtn').style.display = running ? 'block' : 'none';
        }

        function startStream() {
            if (eventSource) {
                eventSource.close();
            }

            eventSource = new EventSource('/stream');

            eventSource.onopen = function() {
                showInfo('Stream connected...');
            };

            eventSource.onmessage = function(e) {
                const data = JSON.parse(e.data);

                if (data.type === 'message') {
                    addMessage(data);
                } else if (data.type === 'status') {
                    if (data.text === 'stopped') {
                        setRunning(false);
                    } else if (data.text === 'started') {
                        showInfo('Decoder started, waiting for signals...');
                    }
                } else if (data.type === 'info') {
                    showInfo(data.text);
                } else if (data.type === 'raw') {
                    showInfo(data.text);
                }
            };

            eventSource.onerror = function(e) {
                checkStatus();
            };
        }

        function addMessage(msg) {
            const output = document.getElementById('output');

            // Remove placeholder if present
            const placeholder = output.querySelector('.placeholder');
            if (placeholder) {
                placeholder.remove();
            }

            // Store message for export (always, even if filtered)
            allMessages.push(msg);

            // Check if message should be filtered from display
            const isFiltered = shouldFilterMessage(msg);

            // Update counts (always, even if filtered)
            msgCount++;
            document.getElementById('msgCount').textContent = msgCount;

            let protoClass = '';
            if (msg.protocol.includes('POCSAG')) {
                pocsagCount++;
                protoClass = 'pocsag';
                document.getElementById('pocsagCount').textContent = pocsagCount;
            } else if (msg.protocol.includes('FLEX')) {
                flexCount++;
                protoClass = 'flex';
                document.getElementById('flexCount').textContent = flexCount;
            }

            // If filtered, skip display but update filtered count
            if (isFiltered) {
                filteredCount++;
                return;
            }

            // Play audio alert (only for non-filtered messages)
            playAlert();

            // Update signal meter
            pulseSignal();

            // Add to waterfall
            addWaterfallPoint(Date.now(), 0.8);

            const isNumeric = /^[0-9\s\-\*\#U]+$/.test(msg.message);
            const relativeTime = getRelativeTime(msg.timestamp);

            const msgEl = document.createElement('div');
            msgEl.className = 'message ' + protoClass;
            msgEl.innerHTML = `
                <div class="header">
                    <span class="protocol">${escapeHtml(msg.protocol)}</span>
                    <span class="msg-time" data-timestamp="${escapeAttr(msg.timestamp)}" title="${escapeAttr(msg.timestamp)}">${escapeHtml(relativeTime)}</span>
                </div>
                <div class="address">Address: ${escapeHtml(msg.address)}${msg.function ? ' | Func: ' + escapeHtml(msg.function) : ''}</div>
                <div class="content ${isNumeric ? 'numeric' : ''}">${escapeHtml(msg.message)}</div>
            `;

            output.insertBefore(msgEl, output.firstChild);

            // Auto-scroll to top (newest messages)
            if (autoScroll) {
                output.scrollTop = 0;
            }

            // Limit messages displayed
            while (output.children.length > 100) {
                output.removeChild(output.lastChild);
            }
        }

        function escapeHtml(text) {
            const div = document.createElement('div');
            div.textContent = text;
            return div.innerHTML;
        }

        function escapeAttr(text) {
            // Escape for use in HTML attributes (especially onclick handlers)
            if (text === null || text === undefined) return '';
            var s = String(text);
            s = s.replace(/&/g, '&amp;');
            s = s.replace(/'/g, '&#39;');
            s = s.replace(/"/g, '&quot;');
            s = s.replace(/</g, '&lt;');
            s = s.replace(/>/g, '&gt;');
            return s;
        }

        function isValidMac(mac) {
            // Validate MAC address format (XX:XX:XX:XX:XX:XX)
            return /^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$/.test(mac);
        }

        function isValidChannel(ch) {
            // Validate WiFi channel (1-200 covers all bands)
            const num = parseInt(ch, 10);
            return !isNaN(num) && num >= 1 && num <= 200;
        }

        function showInfo(text) {
            const output = document.getElementById('output');

            // Clear placeholder only (has the 'placeholder' class)
            const placeholder = output.querySelector('.placeholder');
            if (placeholder) {
                placeholder.remove();
            }

            const infoEl = document.createElement('div');
            infoEl.className = 'info-msg';
            infoEl.style.cssText = 'padding: 12px 15px; margin-bottom: 8px; background: #0a0a0a; border: 1px solid #1a1a1a; border-left: 2px solid #00d4ff; font-family: "JetBrains Mono", monospace; font-size: 11px; color: #888; word-break: break-all;';
            infoEl.textContent = text;
            output.insertBefore(infoEl, output.firstChild);
        }

        function showError(text) {
            const output = document.getElementById('output');

            // Clear placeholder only (has the 'placeholder' class)
            const placeholder = output.querySelector('.placeholder');
            if (placeholder) {
                placeholder.remove();
            }

            const errorEl = document.createElement('div');
            errorEl.className = 'error-msg';
            errorEl.style.cssText = 'padding: 12px 15px; margin-bottom: 8px; background: #1a0a0a; border: 1px solid #2a1a1a; border-left: 2px solid #ff3366; font-family: "JetBrains Mono", monospace; font-size: 11px; color: #ff6688; word-break: break-all;';
            errorEl.textContent = '⚠ ' + text;
            output.insertBefore(errorEl, output.firstChild);
        }

        function clearMessages() {
            document.getElementById('output').innerHTML = `
                <div class="placeholder" style="color: #888; text-align: center; padding: 50px;">
                    Messages cleared. ${isRunning || isSensorRunning ? 'Waiting for new messages...' : 'Start decoding to receive messages.'}
                </div>
            `;
            msgCount = 0;
            pocsagCount = 0;
            flexCount = 0;
            sensorCount = 0;
            filteredCount = 0;
            allMessages = [];
            uniqueDevices.clear();
            document.getElementById('msgCount').textContent = '0';
            document.getElementById('pocsagCount').textContent = '0';
            document.getElementById('flexCount').textContent = '0';
            document.getElementById('sensorCount').textContent = '0';
            document.getElementById('deviceCount').textContent = '0';

            // Reset recon data
            deviceDatabase.clear();
            newDeviceAlerts = 0;
            anomalyAlerts = 0;
            document.getElementById('trackedCount').textContent = '0';
            document.getElementById('newDeviceCount').textContent = '0';
            document.getElementById('anomalyCount').textContent = '0';
            document.getElementById('reconContent').innerHTML = '<div style="color: #444; text-align: center; padding: 30px; font-size: 11px;">Device intelligence data will appear here as signals are intercepted.</div>';
        }

        // ============== DEVICE INTELLIGENCE & RECONNAISSANCE ==============

        // Device tracking database
        const deviceDatabase = new Map(); // key: deviceId, value: device profile
        // Default to true if not set, so device intelligence works by default
        let reconEnabled = localStorage.getItem('reconEnabled') !== 'false';
        let newDeviceAlerts = 0;
        let anomalyAlerts = 0;

        // Device profile structure
        function createDeviceProfile(deviceId, protocol, firstSeen) {
            return {
                id: deviceId,
                protocol: protocol,
                firstSeen: firstSeen,
                lastSeen: firstSeen,
                transmissionCount: 1,
                transmissions: [firstSeen], // timestamps of recent transmissions
                avgInterval: null, // average time between transmissions
                addresses: new Set(),
                models: new Set(),
                messages: [],
                isNew: true,
                anomalies: [],
                signalStrength: [],
                encrypted: null // null = unknown, true/false
            };
        }

        // Analyze transmission patterns for anomalies
        function analyzeTransmissions(profile) {
            const anomalies = [];
            const now = Date.now();

            // Need at least 3 transmissions to analyze patterns
            if (profile.transmissions.length < 3) {
                return anomalies;
            }

            // Calculate intervals between transmissions
            const intervals = [];
            for (let i = 1; i < profile.transmissions.length; i++) {
                intervals.push(profile.transmissions[i] - profile.transmissions[i-1]);
            }

            // Calculate average and standard deviation
            const avg = intervals.reduce((a, b) => a + b, 0) / intervals.length;
            profile.avgInterval = avg;

            const variance = intervals.reduce((a, b) => a + Math.pow(b - avg, 2), 0) / intervals.length;
            const stdDev = Math.sqrt(variance);

            // Check for burst transmission (sudden increase in frequency)
            const lastInterval = intervals[intervals.length - 1];
            if (avg > 0 && lastInterval < avg * 0.2) {
                anomalies.push({
                    type: 'burst',
                    severity: 'medium',
                    message: 'Burst transmission detected - interval ' + Math.round(lastInterval/1000) + 's vs avg ' + Math.round(avg/1000) + 's'
                });
            }

            // Check for silence break (device was quiet, now transmitting again)
            if (avg > 0 && lastInterval > avg * 5) {
                anomalies.push({
                    type: 'silence_break',
                    severity: 'low',
                    message: 'Device resumed after ' + Math.round(lastInterval/60000) + ' min silence'
                });
            }

            return anomalies;
        }

        // Check for encryption indicators
        function detectEncryption(message) {
            if (!message || message === '[No Message]' || message === '[Tone Only]') {
                return null; // Can't determine
            }

            // Check for high entropy (random-looking data)
            const printableRatio = (message.match(/[a-zA-Z0-9\s.,!?-]/g) || []).length / message.length;

            // Check for common encrypted patterns (hex strings, base64-like)
            const hexPattern = /^[0-9A-Fa-f\s]+$/;
            const hasNonPrintable = /[^\x20-\x7E]/.test(message);

            if (printableRatio > 0.8 && !hasNonPrintable) {
                return false; // Likely plaintext
            } else if (hexPattern.test(message.replace(/\s/g, '')) || hasNonPrintable) {
                return true; // Likely encrypted or encoded
            }

            return null; // Unknown
        }

        // Generate device fingerprint
        function generateDeviceId(data) {
            if (data.protocol && data.protocol.includes('POCSAG')) {
                return 'PAGER_' + (data.address || 'UNK');
            } else if (data.protocol === 'FLEX') {
                return 'FLEX_' + (data.address || 'UNK');
            } else if (data.protocol === 'WiFi-AP') {
                return 'WIFI_AP_' + (data.address || 'UNK').replace(/:/g, '');
            } else if (data.protocol === 'WiFi-Client') {
                return 'WIFI_CLIENT_' + (data.address || 'UNK').replace(/:/g, '');
            } else if (data.protocol === 'Bluetooth' || data.protocol === 'BLE') {
                return 'BT_' + (data.address || 'UNK').replace(/:/g, '');
            } else if (data.model) {
                // 433MHz sensor
                const id = data.id || data.channel || data.unit || '0';
                return 'SENSOR_' + data.model.replace(/\s+/g, '_') + '_' + id;
            }
            return 'UNKNOWN_' + Date.now();
        }

        // Track a device transmission
        function trackDevice(data) {
            const now = Date.now();
            const deviceId = generateDeviceId(data);
            const protocol = data.protocol || data.model || 'Unknown';

            let profile = deviceDatabase.get(deviceId);
            let isNewDevice = false;

            if (!profile) {
                // New device discovered
                profile = createDeviceProfile(deviceId, protocol, now);
                isNewDevice = true;
                newDeviceAlerts++;
                document.getElementById('newDeviceCount').textContent = newDeviceAlerts;
            } else {
                // Update existing profile
                profile.lastSeen = now;
                profile.transmissionCount++;
                profile.transmissions.push(now);
                profile.isNew = false;

                // Keep only last 100 transmissions for analysis
                if (profile.transmissions.length > 100) {
                    profile.transmissions = profile.transmissions.slice(-100);
                }
            }

            // Track addresses
            if (data.address) profile.addresses.add(data.address);
            if (data.model) profile.models.add(data.model);

            // Store recent messages (keep last 10)
            if (data.message) {
                profile.messages.unshift({
                    text: data.message,
                    time: now
                });
                if (profile.messages.length > 10) profile.messages.pop();

                // Detect encryption
                const encrypted = detectEncryption(data.message);
                if (encrypted !== null) profile.encrypted = encrypted;
            }

            // Analyze for anomalies
            const newAnomalies = analyzeTransmissions(profile);
            if (newAnomalies.length > 0) {
                profile.anomalies = profile.anomalies.concat(newAnomalies);
                anomalyAlerts += newAnomalies.length;
                document.getElementById('anomalyCount').textContent = anomalyAlerts;
            }

            deviceDatabase.set(deviceId, profile);
            document.getElementById('trackedCount').textContent = deviceDatabase.size;

            // Update recon display
            if (reconEnabled) {
                updateReconDisplay(deviceId, profile, isNewDevice, newAnomalies);
            }

            return { deviceId, profile, isNewDevice, anomalies: newAnomalies };
        }

        // Update reconnaissance display
        function updateReconDisplay(deviceId, profile, isNewDevice, anomalies) {
            const content = document.getElementById('reconContent');

            // Remove placeholder if present
            const placeholder = content.querySelector('div[style*="text-align: center"]');
            if (placeholder) placeholder.remove();

            // Check if device row already exists
            let row = document.getElementById('device_' + deviceId.replace(/[^a-zA-Z0-9]/g, '_'));

            if (!row) {
                // Create new row
                row = document.createElement('div');
                row.id = 'device_' + deviceId.replace(/[^a-zA-Z0-9]/g, '_');
                row.className = 'device-row' + (isNewDevice ? ' new-device' : '');
                content.insertBefore(row, content.firstChild);
            }

            // Determine protocol badge class
            let badgeClass = 'proto-unknown';
            if (profile.protocol.includes('POCSAG')) badgeClass = 'proto-pocsag';
            else if (profile.protocol === 'FLEX') badgeClass = 'proto-flex';
            else if (profile.protocol.includes('SENSOR') || profile.models.size > 0) badgeClass = 'proto-433';

            // Calculate transmission rate bar width
            const maxRate = 100; // Max expected transmissions
            const rateWidth = Math.min(100, (profile.transmissionCount / maxRate) * 100);

            // Determine timeline status
            const timeSinceLast = Date.now() - profile.lastSeen;
            let timelineDot = 'recent';
            if (timeSinceLast > 300000) timelineDot = 'old'; // > 5 min
            else if (timeSinceLast > 60000) timelineDot = 'stale'; // > 1 min

            // Build encryption indicator
            let encStatus = 'Unknown';
            let encClass = '';
            if (profile.encrypted === true) { encStatus = 'Encrypted'; encClass = 'encrypted'; }
            else if (profile.encrypted === false) { encStatus = 'Plaintext'; encClass = 'plaintext'; }

            // Format time
            const lastSeenStr = getRelativeTime(new Date(profile.lastSeen).toTimeString().split(' ')[0]);
            const firstSeenStr = new Date(profile.firstSeen).toLocaleTimeString();

            // Update row content
            row.className = 'device-row' + (isNewDevice ? ' new-device' : '') + (anomalies.length > 0 ? ' anomaly' : '');
            row.innerHTML = `
                <div class="device-info">
                    <div class="device-name-row">
                        <span class="timeline-dot ${timelineDot}"></span>
                        <span class="badge ${badgeClass}">${profile.protocol.substring(0, 10)}</span>
                        ${deviceId.substring(0, 30)}
                    </div>
                    <div class="device-id">
                        First: ${firstSeenStr} | Last: ${lastSeenStr} | TX: ${profile.transmissionCount}
                        ${profile.avgInterval ? ' | Interval: ' + Math.round(profile.avgInterval/1000) + 's' : ''}
                    </div>
                </div>
                <div class="device-meta ${encClass}">${encStatus}</div>
                <div>
                    <div class="transmission-bar">
                        <div class="transmission-bar-fill" style="width: ${rateWidth}%"></div>
                    </div>
                </div>
                <div class="device-meta">${Array.from(profile.addresses).slice(0, 2).join(', ')}</div>
            `;

            // Show anomaly alerts
            if (anomalies.length > 0) {
                anomalies.forEach(a => {
                    const alertEl = document.createElement('div');
                    alertEl.style.cssText = 'padding: 5px 15px; background: rgba(255,51,102,0.1); border-left: 2px solid var(--accent-red); font-size: 10px; color: var(--accent-red);';
                    alertEl.textContent = '⚠ ' + a.message;
                    row.appendChild(alertEl);
                });
            }

            // Limit displayed devices
            while (content.children.length > 50) {
                content.removeChild(content.lastChild);
            }
        }

        // Toggle recon panel visibility
        function toggleRecon() {
            reconEnabled = !reconEnabled;
            localStorage.setItem('reconEnabled', reconEnabled);
            document.getElementById('reconPanel').style.display = reconEnabled ? 'block' : 'none';
            document.getElementById('reconBtn').classList.toggle('active', reconEnabled);

            // Populate recon display if enabled and we have data
            if (reconEnabled && deviceDatabase.size > 0) {
                deviceDatabase.forEach((profile, deviceId) => {
                    updateReconDisplay(deviceId, profile, false, []);
                });
            }
        }

        // Initialize recon state
        if (reconEnabled) {
            document.getElementById('reconPanel').style.display = 'block';
            document.getElementById('reconBtn').classList.add('active');
        } else {
            document.getElementById('reconPanel').style.display = 'none';
        }

        // Hook into existing message handlers to track devices
        const originalAddMessage = addMessage;
        addMessage = function(msg) {
            originalAddMessage(msg);
            trackDevice(msg);
        };

        const originalAddSensorReading = addSensorReading;
        addSensorReading = function(data) {
            originalAddSensorReading(data);
            trackDevice(data);
        };

        // Export device database
        function exportDeviceDB() {
            const data = [];
            deviceDatabase.forEach((profile, id) => {
                data.push({
                    id: id,
                    protocol: profile.protocol,
                    firstSeen: new Date(profile.firstSeen).toISOString(),
                    lastSeen: new Date(profile.lastSeen).toISOString(),
                    transmissionCount: profile.transmissionCount,
                    avgIntervalSeconds: profile.avgInterval ? Math.round(profile.avgInterval / 1000) : null,
                    addresses: Array.from(profile.addresses),
                    models: Array.from(profile.models),
                    encrypted: profile.encrypted,
                    anomalyCount: profile.anomalies.length,
                    recentMessages: profile.messages.slice(0, 5).map(m => m.text)
                });
            });
            downloadFile(JSON.stringify(data, null, 2), 'intercept_device_intelligence.json', 'application/json');
        }

        // Toggle recon panel collapse
        function toggleReconCollapse() {
            const panel = document.getElementById('reconPanel');
            const icon = document.getElementById('reconCollapseIcon');
            panel.classList.toggle('collapsed');
            icon.textContent = panel.classList.contains('collapsed') ? '▶' : '▼';
        }

        function toggleSensorWaterfall() {
            const panel = document.getElementById('sensorWaterfallPanel');
            const icon = document.getElementById('sensorWaterfallIcon');
            panel.classList.toggle('collapsed');
            icon.textContent = panel.classList.contains('collapsed') ? '▶' : '▼';
        }

        function togglePagerWaterfall() {
            const panel = document.getElementById('pagerWaterfallPanel');
            const icon = document.getElementById('pagerWaterfallIcon');
            panel.classList.toggle('collapsed');
            icon.textContent = panel.classList.contains('collapsed') ? '▶' : '▼';
        }

        // ============== WIFI RECONNAISSANCE ==============

        let wifiEventSource = null;
        let monitorInterface = null;
        let wifiNetworks = {};
        let wifiClients = {};
        let apCount = 0;
        let clientCount = 0;
        let handshakeCount = 0;
        let rogueApCount = 0;
        let droneCount = 0;
        let detectedDrones = {};  // Track detected drones by BSSID
        let ssidToBssids = {};  // Track SSIDs to their BSSIDs for rogue AP detection
        let rogueApDetails = {};  // Store details about rogue APs: {ssid: [{bssid, signal, channel, firstSeen}]}
        let rogueBssids = new Set();  // Track all BSSIDs that are suspected rogues
        let activeCapture = null;  // {bssid, channel, file, startTime, pollInterval}
        let watchMacs = JSON.parse(localStorage.getItem('watchMacs') || '[]');
        let alertedMacs = new Set();  // Prevent duplicate alerts per session
        let selectedWifiDevice = null;  // Selected network or client for details view
        let selectedWifiType = null;  // 'network' or 'client'

        // 5GHz channel mapping for the graph
        const channels5g = ['36', '40', '44', '48', '52', '56', '60', '64', '100', '149', '153', '157', '161', '165'];

        // Drone SSID patterns for detection
        const dronePatterns = [
            /^DJI[-_]/i, /Mavic/i, /Phantom/i, /^Spark[-_]/i, /^Mini[-_]/i, /^Air[-_]/i,
            /Inspire/i, /Matrice/i, /Avata/i, /^FPV[-_]/i, /Osmo/i, /RoboMaster/i, /Tello/i,
            /Parrot/i, /Bebop/i, /Anafi/i, /^Disco[-_]/i, /Mambo/i, /Swing/i,
            /Autel/i, /^EVO[-_]/i, /Dragonfish/i, /Skydio/i,
            /Holy.?Stone/i, /Potensic/i, /SYMA/i, /Hubsan/i, /Eachine/i, /FIMI/i,
            /Yuneec/i, /Typhoon/i, /PowerVision/i, /PowerEgg/i,
            /Drone/i, /^UAV[-_]/i, /Quadcopter/i, /^RC[-_]Drone/i
        ];

        // Drone OUI prefixes
        const droneOuiPrefixes = {
            '60:60:1F': 'DJI', '48:1C:B9': 'DJI', '34:D2:62': 'DJI', 'E0:DB:55': 'DJI',
            'C8:6C:87': 'DJI', 'A0:14:3D': 'DJI', '70:D7:11': 'DJI', '98:3A:56': 'DJI',
            '90:03:B7': 'Parrot', '00:12:1C': 'Parrot', '00:26:7E': 'Parrot',
            '8C:F5:A3': 'Autel', 'D8:E0:E1': 'Autel', 'F8:0F:6F': 'Skydio'
        };

        // Check if network is a drone
        function isDrone(ssid, bssid) {
            // Check SSID patterns
            if (ssid) {
                for (const pattern of dronePatterns) {
                    if (pattern.test(ssid)) {
                        return { isDrone: true, method: 'SSID', brand: ssid.split(/[-_\s]/)[0] };
                    }
                }
            }
            // Check OUI prefix
            if (bssid) {
                const prefix = bssid.substring(0, 8).toUpperCase();
                if (droneOuiPrefixes[prefix]) {
                    return { isDrone: true, method: 'OUI', brand: droneOuiPrefixes[prefix] };
                }
            }
            return { isDrone: false };
        }

        // Handle drone detection
        function handleDroneDetection(net, droneInfo) {
            if (detectedDrones[net.bssid]) return; // Already detected

            detectedDrones[net.bssid] = {
                ssid: net.essid,
                bssid: net.bssid,
                brand: droneInfo.brand,
                method: droneInfo.method,
                signal: net.power,
                channel: net.channel,
                firstSeen: new Date().toISOString()
            };

            droneCount++;
            document.getElementById('droneCount').textContent = droneCount;

            // Calculate approximate distance from signal strength
            const rssi = parseInt(net.power) || -70;
            const distance = estimateDroneDistance(rssi);

            // Triple alert for drones
            playAlert();
            setTimeout(playAlert, 200);
            setTimeout(playAlert, 400);

            // Show drone alert
            showDroneAlert(net.essid, net.bssid, droneInfo.brand, distance, rssi);
        }

        // Estimate distance from RSSI (rough approximation)
        function estimateDroneDistance(rssi) {
            // Using free-space path loss model (very approximate)
            // Reference: -30 dBm at 1 meter
            const txPower = -30;
            const n = 2.5; // Path loss exponent (2-4, higher for obstacles)
            const distance = Math.pow(10, (txPower - rssi) / (10 * n));
            return Math.round(distance);
        }

        // Show drone alert popup
        function showDroneAlert(ssid, bssid, brand, distance, rssi) {
            const alertDiv = document.createElement('div');
            alertDiv.className = 'drone-alert';
            alertDiv.innerHTML = `
                <div style="font-weight: bold; color: var(--accent-orange); font-size: 16px;">🚁 DRONE DETECTED</div>
                <div style="margin: 10px 0;">
                    <div><strong>SSID:</strong> ${escapeHtml(ssid || 'Unknown')}</div>
                    <div><strong>BSSID:</strong> ${bssid}</div>
                    <div><strong>Brand:</strong> ${brand || 'Unknown'}</div>
                    <div><strong>Signal:</strong> ${rssi} dBm</div>
                    <div><strong>Est. Distance:</strong> ~${distance}m</div>
                </div>
                <button onclick="this.parentElement.remove()" style="padding: 6px 16px; cursor: pointer; background: var(--accent-orange); border: none; color: #000; border-radius: 4px;">Dismiss</button>
            `;
            alertDiv.style.cssText = 'position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: #1a1a2e; border: 2px solid var(--accent-orange); padding: 20px; border-radius: 8px; z-index: 10000; text-align: center; box-shadow: 0 0 30px rgba(255,165,0,0.5); min-width: 280px;';
            document.body.appendChild(alertDiv);
            setTimeout(() => { if (alertDiv.parentElement) alertDiv.remove(); }, 15000);
        }

        // Initialize watch list display
        function initWatchList() {
            updateWatchListDisplay();
        }

        // Add MAC to watch list
        function addWatchMac() {
            const input = document.getElementById('watchMacInput');
            const mac = input.value.trim().toUpperCase();
            if (!mac || !/^([0-9A-F]{2}:){5}[0-9A-F]{2}$/.test(mac)) {
                alert('Please enter a valid MAC address (AA:BB:CC:DD:EE:FF)');
                return;
            }
            if (!watchMacs.includes(mac)) {
                watchMacs.push(mac);
                localStorage.setItem('watchMacs', JSON.stringify(watchMacs));
                updateWatchListDisplay();
            }
            input.value = '';
        }

        // Remove MAC from watch list
        function removeWatchMac(mac) {
            watchMacs = watchMacs.filter(m => m !== mac);
            localStorage.setItem('watchMacs', JSON.stringify(watchMacs));
            alertedMacs.delete(mac);
            updateWatchListDisplay();
        }

        // Update watch list display
        function updateWatchListDisplay() {
            const container = document.getElementById('watchList');
            if (!container) return;
            if (watchMacs.length === 0) {
                container.innerHTML = '<div style="color: #555;">No MACs in watch list</div>';
            } else {
                container.innerHTML = watchMacs.map(mac =>
                    `<div style="display: flex; justify-content: space-between; align-items: center; padding: 2px 0;">
                        <span>${mac}</span>
                        <button onclick="removeWatchMac('${mac}')" style="background: none; border: none; color: var(--accent-red); cursor: pointer; font-size: 10px;">✕</button>
                    </div>`
                ).join('');
            }
        }

        // Check if MAC is in watch list and alert
        function checkWatchList(mac, type) {
            const upperMac = mac.toUpperCase();
            if (watchMacs.includes(upperMac) && !alertedMacs.has(upperMac)) {
                alertedMacs.add(upperMac);
                // Play alert sound multiple times for urgency
                playAlert();
                setTimeout(playAlert, 300);
                setTimeout(playAlert, 600);
                // Show prominent alert
                showProximityAlert(mac, type);
            }
        }

        // Show proximity alert popup
        function showProximityAlert(mac, type) {
            const alertDiv = document.createElement('div');
            alertDiv.className = 'proximity-alert';
            alertDiv.innerHTML = `
                <div style="font-weight: bold; color: var(--accent-red);">⚠ PROXIMITY ALERT</div>
                <div>Watched ${type} detected:</div>
                <div style="font-family: monospace; font-size: 14px;">${mac}</div>
                <button onclick="this.parentElement.remove()" style="margin-top: 8px; padding: 4px 12px; cursor: pointer;">Dismiss</button>
            `;
            alertDiv.style.cssText = 'position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: #1a1a2e; border: 2px solid var(--accent-red); padding: 20px; border-radius: 8px; z-index: 10000; text-align: center; box-shadow: 0 0 30px rgba(255,0,0,0.5);';
            document.body.appendChild(alertDiv);
            // Auto-dismiss after 10 seconds
            setTimeout(() => alertDiv.remove(), 10000);
        }

        // Check for rogue APs (same SSID, different BSSID)
        // Extract OUI (manufacturer ID) from MAC address
        function getOui(mac) {
            if (!mac) return '';
            return mac.toUpperCase().substring(0, 8);  // First 3 octets: "AA:BB:CC"
        }

        function checkRogueAP(ssid, bssid, channel, signal) {
            if (!ssid || ssid === 'Hidden' || ssid === '[Hidden]') return false;

            if (!ssidToBssids[ssid]) {
                ssidToBssids[ssid] = new Set();
            }

            // Store details for this BSSID
            if (!rogueApDetails[ssid]) {
                rogueApDetails[ssid] = [];
            }

            // Check if we already have this BSSID stored
            const existingEntry = rogueApDetails[ssid].find(e => e.bssid === bssid);
            if (!existingEntry) {
                rogueApDetails[ssid].push({
                    bssid: bssid,
                    channel: channel || '?',
                    signal: signal || '?',
                    oui: getOui(bssid),
                    firstSeen: new Date().toLocaleTimeString()
                });
            }

            const isNewBssid = !ssidToBssids[ssid].has(bssid);
            ssidToBssids[ssid].add(bssid);

            // Only flag as rogue if multiple BSSIDs AND different manufacturers (OUIs)
            // This prevents false positives from mesh WiFi systems and enterprise networks
            if (ssidToBssids[ssid].size > 1 && isNewBssid) {
                // Check if all BSSIDs have the same OUI (manufacturer)
                const ouis = new Set(rogueApDetails[ssid].map(e => e.oui));

                // If all BSSIDs have the same OUI, it's likely a mesh system - not rogue
                if (ouis.size === 1) {
                    // Same manufacturer - probably mesh system, not rogue
                    return false;
                }

                // Different manufacturers detected - this is suspicious!
                rogueApCount++;
                document.getElementById('rogueApCount').textContent = rogueApCount;
                playAlert();

                // Mark ALL BSSIDs with this SSID as suspected rogues
                ssidToBssids[ssid].forEach(b => rogueBssids.add(b));

                // Get the BSSIDs to show in alert
                const bssidList = rogueApDetails[ssid].map(e => e.bssid).join(', ');
                showInfo(`⚠ Rogue AP: "${ssid}" has ${ouis.size} different vendors: ${bssidList}`);
                showNotification('⚠️ Rogue AP Detected!', `"${ssid}" has different vendor BSSIDs`);

                // Update all network cards with this SSID to show rogue indicator
                ssidToBssids[ssid].forEach(rogueBssid => {
                    const net = wifiNetworks[rogueBssid];
                    if (net) addWifiNetworkCard(net, false);
                });

                return true;
            }
            return false;
        }

        // Show rogue AP details popup
        function showRogueApDetails() {
            const rogueSSIDs = Object.keys(rogueApDetails).filter(ssid =>
                rogueApDetails[ssid].length > 1
            );

            if (rogueSSIDs.length === 0) {
                showInfo('No rogue APs detected. Rogue AP = same SSID on multiple BSSIDs.');
                return;
            }

            // Remove existing popup if any
            const existing = document.getElementById('rogueApPopup');
            if (existing) existing.remove();

            // Build details HTML
            let html = '<div style="max-height: 300px; overflow-y: auto;">';
            rogueSSIDs.forEach(ssid => {
                const aps = rogueApDetails[ssid];
                html += `<div style="margin-bottom: 12px;">
                    <div style="color: var(--accent-red); font-weight: bold; margin-bottom: 4px;">
                        📡 "${ssid}" (${aps.length} BSSIDs)
                    </div>
                    <table style="width: 100%; font-size: 10px; border-collapse: collapse;">
                        <tr style="color: var(--text-dim);">
                            <th style="text-align: left; padding: 2px 8px;">BSSID</th>
                            <th style="text-align: left; padding: 2px 8px;">CH</th>
                            <th style="text-align: left; padding: 2px 8px;">Signal</th>
                            <th style="text-align: left; padding: 2px 8px;">First Seen</th>
                        </tr>`;
                aps.forEach((ap, idx) => {
                    const bgColor = idx % 2 === 0 ? 'rgba(255,255,255,0.05)' : 'transparent';
                    html += `<tr style="background: ${bgColor};">
                        <td style="padding: 2px 8px; font-family: monospace;">${ap.bssid}</td>
                        <td style="padding: 2px 8px;">${ap.channel}</td>
                        <td style="padding: 2px 8px;">${ap.signal} dBm</td>
                        <td style="padding: 2px 8px;">${ap.firstSeen}</td>
                    </tr>`;
                });
                html += '</table></div>';
            });
            html += '</div>';
            html += '<div style="margin-top: 8px; font-size: 9px; color: var(--text-dim);">⚠ Multiple BSSIDs for same SSID may indicate rogue AP or legitimate multi-AP setup</div>';

            // Create popup
            const popup = document.createElement('div');
            popup.id = 'rogueApPopup';
            popup.style.cssText = `
                position: fixed;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                background: var(--bg-primary);
                border: 1px solid var(--accent-red);
                border-radius: 8px;
                padding: 16px;
                z-index: 10000;
                min-width: 400px;
                max-width: 600px;
                box-shadow: 0 4px 20px rgba(0,0,0,0.5);
            `;
            popup.innerHTML = `
                <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;">
                    <span style="font-weight: bold; color: var(--accent-red);">🚨 Rogue AP Details</span>
                    <button onclick="this.parentElement.parentElement.remove()"
                            style="background: none; border: none; color: var(--text-dim); cursor: pointer; font-size: 16px;">✕</button>
                </div>
                ${html}
            `;

            document.body.appendChild(popup);
        }

        // Show drone details popup
        function showDroneDetails() {
            const drones = Object.values(detectedDrones);

            if (drones.length === 0) {
                showInfo('No drones detected. Drones are identified by SSID patterns and manufacturer OUI.');
                return;
            }

            // Remove existing popup if any
            const existing = document.getElementById('droneDetailsPopup');
            if (existing) existing.remove();

            // Build details HTML
            let html = '<div style="max-height: 300px; overflow-y: auto;">';
            html += `<table style="width: 100%; font-size: 10px; border-collapse: collapse;">
                <tr style="color: var(--text-dim);">
                    <th style="text-align: left; padding: 4px 8px;">Brand</th>
                    <th style="text-align: left; padding: 4px 8px;">SSID</th>
                    <th style="text-align: left; padding: 4px 8px;">BSSID</th>
                    <th style="text-align: left; padding: 4px 8px;">CH</th>
                    <th style="text-align: left; padding: 4px 8px;">Signal</th>
                    <th style="text-align: left; padding: 4px 8px;">Distance</th>
                    <th style="text-align: left; padding: 4px 8px;">Detected</th>
                </tr>`;

            drones.forEach((drone, idx) => {
                const bgColor = idx % 2 === 0 ? 'rgba(255,165,0,0.1)' : 'transparent';
                const rssi = parseInt(drone.signal) || -70;
                const distance = estimateDroneDistance(rssi);
                const timeStr = new Date(drone.firstSeen).toLocaleTimeString();
                html += `<tr style="background: ${bgColor};">
                    <td style="padding: 4px 8px; font-weight: bold; color: var(--accent-orange);">${drone.brand || 'Unknown'}</td>
                    <td style="padding: 4px 8px;">${drone.ssid || '[Hidden]'}</td>
                    <td style="padding: 4px 8px; font-family: monospace; font-size: 9px;">${drone.bssid}</td>
                    <td style="padding: 4px 8px;">${drone.channel || '?'}</td>
                    <td style="padding: 4px 8px;">${drone.signal || '?'} dBm</td>
                    <td style="padding: 4px 8px;">~${distance}m</td>
                    <td style="padding: 4px 8px;">${timeStr}</td>
                </tr>`;
            });
            html += '</table></div>';
            html += '<div style="margin-top: 8px; font-size: 9px; color: var(--text-dim);">Detection via: SSID pattern matching and manufacturer OUI lookup</div>';

            // Create popup
            const popup = document.createElement('div');
            popup.id = 'droneDetailsPopup';
            popup.style.cssText = `
                position: fixed;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                background: var(--bg-primary);
                border: 1px solid var(--accent-orange);
                border-radius: 8px;
                padding: 16px;
                z-index: 10000;
                min-width: 500px;
                max-width: 700px;
                box-shadow: 0 4px 20px rgba(0,0,0,0.5);
            `;
            popup.innerHTML = `
                <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;">
                    <span style="font-weight: bold; color: var(--accent-orange);">🚁 Detected Drones (${drones.length})</span>
                    <button onclick="this.parentElement.parentElement.remove()"
                            style="background: none; border: none; color: var(--text-dim); cursor: pointer; font-size: 16px;">✕</button>
                </div>
                ${html}
            `;

            document.body.appendChild(popup);
        }

        // Update 5GHz channel graph
        function updateChannel5gGraph() {
            const bars = document.querySelectorAll('#channelGraph5g .channel-bar');
            const labels = document.querySelectorAll('#channelGraph5g .channel-label');

            // Count networks per 5GHz channel
            const channelCounts = {};
            channels5g.forEach(ch => channelCounts[ch] = 0);

            Object.values(wifiNetworks).forEach(net => {
                const ch = net.channel?.toString().trim();
                if (channels5g.includes(ch)) {
                    channelCounts[ch]++;
                }
            });

            const maxCount = Math.max(1, ...Object.values(channelCounts));

            bars.forEach((bar, i) => {
                const ch = channels5g[i];
                const count = channelCounts[ch] || 0;
                const height = Math.max(2, (count / maxCount) * 50);
                bar.style.height = height + 'px';
                bar.className = 'channel-bar' + (count > 0 ? ' active' : '') + (count > 3 ? ' congested' : '') + (count > 5 ? ' very-congested' : '');
            });
        }

        // ============== NEW FEATURES ==============

        // Network Topology Graph
        function drawNetworkGraph() {
            const canvas = document.getElementById('networkGraph');
            if (!canvas) return;
            const ctx = canvas.getContext('2d');
            const width = canvas.offsetWidth;
            const height = canvas.offsetHeight;
            canvas.width = width;
            canvas.height = height;

            // Clear
            ctx.fillStyle = '#000';
            ctx.fillRect(0, 0, width, height);

            const networks = Object.values(wifiNetworks);
            const clients = Object.values(wifiClients);

            if (networks.length === 0) {
                ctx.fillStyle = '#444';
                ctx.font = '12px sans-serif';
                ctx.fillText('Start scanning to see network topology', width/2 - 100, height/2);
                return;
            }

            // Calculate positions for APs (top row)
            const apPositions = {};
            const apSpacing = width / (networks.length + 1);
            networks.forEach((net, i) => {
                apPositions[net.bssid] = {
                    x: apSpacing * (i + 1),
                    y: 40,
                    ssid: net.essid,
                    isDrone: isDrone(net.essid, net.bssid).isDrone
                };
            });

            // Draw connections from clients to APs
            ctx.strokeStyle = '#1a1a1a';
            ctx.lineWidth = 1;
            clients.forEach(client => {
                if (client.ap && apPositions[client.ap]) {
                    const ap = apPositions[client.ap];
                    const clientY = 120 + (Math.random() * 60);
                    const clientX = ap.x + (Math.random() - 0.5) * 80;

                    ctx.beginPath();
                    ctx.moveTo(ap.x, ap.y + 15);
                    ctx.lineTo(clientX, clientY - 10);
                    ctx.stroke();

                    // Draw client node
                    ctx.beginPath();
                    ctx.arc(clientX, clientY, 6, 0, Math.PI * 2);
                    ctx.fillStyle = '#00ff88';
                    ctx.fill();
                }
            });

            // Draw AP nodes
            Object.entries(apPositions).forEach(([bssid, pos]) => {
                ctx.beginPath();
                ctx.arc(pos.x, pos.y, 12, 0, Math.PI * 2);
                ctx.fillStyle = pos.isDrone ? '#ff8800' : '#00d4ff';
                ctx.fill();

                // Draw label
                ctx.fillStyle = '#888';
                ctx.font = '9px sans-serif';
                ctx.textAlign = 'center';
                const label = (pos.ssid || 'Hidden').substring(0, 12);
                ctx.fillText(label, pos.x, pos.y + 25);
            });

            ctx.textAlign = 'left';
        }

        // Channel Recommendation
        function updateChannelRecommendation() {
            const channelCounts24 = {};
            const channelCounts5 = {};

            // Initialize
            for (let i = 1; i <= 13; i++) channelCounts24[i] = 0;
            channels5g.forEach(ch => channelCounts5[ch] = 0);

            // Count networks per channel
            Object.values(wifiNetworks).forEach(net => {
                const ch = parseInt(net.channel);
                if (ch >= 1 && ch <= 13) {
                    // 2.4 GHz channels overlap, so count neighbors too
                    for (let i = Math.max(1, ch - 2); i <= Math.min(13, ch + 2); i++) {
                        channelCounts24[i] = (channelCounts24[i] || 0) + (i === ch ? 1 : 0.5);
                    }
                } else if (channels5g.includes(ch.toString())) {
                    channelCounts5[ch.toString()]++;
                }
            });

            // Count total networks for context
            const totalNetworks = Object.keys(wifiNetworks).length;

            // Find best 2.4 GHz channel (1, 6, or 11 preferred - non-overlapping)
            const preferred24 = [1, 6, 11];
            let best24 = 1;
            let minCount24 = Infinity;
            let channelUsage24 = [];
            preferred24.forEach(ch => {
                channelUsage24.push({ channel: ch, count: channelCounts24[ch] || 0 });
                if ((channelCounts24[ch] || 0) < minCount24) {
                    minCount24 = channelCounts24[ch] || 0;
                    best24 = ch;
                }
            });

            // Find best 5 GHz channel
            let best5 = '36';
            let minCount5 = Infinity;
            let used5g = 0;
            channels5g.forEach(ch => {
                const count = channelCounts5[ch] || 0;
                if (count > 0) used5g++;
                if (count < minCount5) {
                    minCount5 = count;
                    best5 = ch;
                }
            });

            // Update UI with more context
            document.getElementById('rec24Channel').textContent = best24;
            if (totalNetworks === 0) {
                document.getElementById('rec24Reason').textContent = '(no networks detected)';
            } else {
                const usage = channelUsage24.map(c => `CH${c.channel}:${Math.round(c.count)}`).join(', ');
                document.getElementById('rec24Reason').textContent =
                    minCount24 === 0 ? '(clear)' : `(${Math.round(minCount24)} interference) [${usage}]`;
            }

            document.getElementById('rec5Channel').textContent = best5;
            if (totalNetworks === 0) {
                document.getElementById('rec5Reason').textContent = '(no networks detected)';
            } else {
                document.getElementById('rec5Reason').textContent =
                    minCount5 === 0 ? `(clear, ${channels5g.length - used5g} unused)` : `(${minCount5} networks)`;
            }
        }

        // Device Correlation (WiFi <-> Bluetooth)
        let deviceCorrelations = [];
        let correlationFetchPending = false;

        function correlateDevices() {
            // Use server-side correlation API for better analysis
            if (correlationFetchPending) return;
            correlationFetchPending = true;

            fetch('/correlation?min_confidence=0.4')
                .then(r => r.json())
                .then(data => {
                    if (data.status === 'success') {
                        deviceCorrelations = data.correlations || [];
                        updateCorrelationDisplay();
                    }
                })
                .catch(err => {
                    console.warn('Correlation fetch failed:', err);
                    // Fallback to local OUI matching
                    correlateDevicesLocal();
                })
                .finally(() => {
                    correlationFetchPending = false;
                });
        }

        function correlateDevicesLocal() {
            // Fallback: simple OUI-based correlation
            deviceCorrelations = [];
            const wifiMacs = Object.keys(wifiNetworks).concat(Object.keys(wifiClients));
            const btMacs = Object.keys(btDevices || {});

            wifiMacs.forEach(wifiMac => {
                const wifiOui = wifiMac.substring(0, 8).toUpperCase();
                btMacs.forEach(btMac => {
                    const btOui = btMac.substring(0, 8).toUpperCase();
                    if (wifiOui === btOui) {
                        const wifiDev = wifiNetworks[wifiMac] || wifiClients[wifiMac];
                        const btDev = btDevices[btMac];
                        deviceCorrelations.push({
                            wifi_mac: wifiMac,
                            bt_mac: btMac,
                            wifi_name: wifiDev?.essid || wifiDev?.mac || wifiMac,
                            bt_name: btDev?.name || btMac,
                            confidence: 0.5,
                            reason: 'same OUI'
                        });
                    }
                });
            });
            updateCorrelationDisplay();
        }

        function updateCorrelationDisplay() {
            const list = document.getElementById('correlationList');
            if (!list) return;

            if (deviceCorrelations.length === 0) {
                list.innerHTML = '<div style="color: var(--text-dim);">No correlated devices found yet</div>';
                return;
            }

            list.innerHTML = deviceCorrelations.slice(0, 10).map(c => {
                const confidence = Math.round((c.confidence || 0.5) * 100);
                const confidenceColor = confidence >= 70 ? 'var(--accent-green)' :
                                       confidence >= 50 ? 'var(--accent-orange)' : 'var(--text-dim)';
                return `
                    <div style="padding: 4px 0; border-bottom: 1px solid var(--border-color);">
                        <div style="display: flex; justify-content: space-between; align-items: center;">
                            <span style="color: var(--accent-cyan);">📶 ${c.wifi_name || c.wifi_mac}</span>
                            <span class="correlation-badge" style="background: ${confidenceColor};">${confidence}%</span>
                        </div>
                        <div style="display: flex; justify-content: space-between; align-items: center;">
                            <span style="color: #6495ED;">🔵 ${c.bt_name || c.bt_mac}</span>
                            <span style="font-size: 9px; color: var(--text-dim);">${c.reason || ''}</span>
                        </div>
                    </div>
                `;
            }).join('');
        }

        // Hidden SSID Revealer
        let revealedSsids = {};  // {bssid: ssid}

        function revealHiddenSsid(bssid, ssid) {
            if (ssid && ssid !== '' && ssid !== 'Hidden' && ssid !== '[Hidden]') {
                if (!revealedSsids[bssid]) {
                    revealedSsids[bssid] = ssid;
                    updateHiddenSsidDisplay();
                    showNotification('Hidden SSID Revealed', `"${ssid}" on ${bssid}`);
                }
            }
        }

        function updateHiddenSsidDisplay() {
            const list = document.getElementById('hiddenSsidList');
            if (!list) return;

            const entries = Object.entries(revealedSsids);
            const hiddenCount = Object.keys(hiddenNetworks).length;

            if (entries.length === 0) {
                if (hiddenCount > 0) {
                    list.innerHTML = `<div style="color: var(--text-dim);">Monitoring ${hiddenCount} hidden network${hiddenCount > 1 ? 's' : ''}...</div>`;
                } else {
                    list.innerHTML = '<div style="color: var(--text-dim);">No hidden networks detected</div>';
                }
                return;
            }

            let html = entries.map(([bssid, ssid]) => `
                <div style="padding: 4px 0; border-bottom: 1px solid var(--border-color);">
                    <span style="color: var(--accent-green);">✓ "${escapeHtml(ssid)}"</span>
                    <span style="color: var(--text-dim); font-size: 9px;"> (${bssid})</span>
                </div>
            `).join('');

            if (hiddenCount > 0) {
                html += `<div style="color: var(--text-dim); margin-top: 4px; font-size: 10px;">+ ${hiddenCount} hidden still monitoring</div>`;
            }

            list.innerHTML = html;
        }

        // NOTE: Browser Notifications code moved to static/js/core/audio.js

        // Update visualizations periodically
        setInterval(() => {
            if (currentMode === 'wifi') {
                updateChannelRecommendation();
                correlateDevices();
                updateHiddenSsidDisplay();
                updateProbeAnalysis();
            }
        }, 2000);

        // Refresh WiFi interfaces
        function refreshWifiInterfaces() {
            const select = document.getElementById('wifiInterfaceSelect');
            select.innerHTML = '<option value="">Loading interfaces...</option>';

            fetch('/wifi/interfaces')
                .then(r => {
                    if (!r.ok) throw new Error('Failed to fetch interfaces');
                    return r.json();
                })
                .then(data => {
                    if (!data.interfaces || data.interfaces.length === 0) {
                        select.innerHTML = '<option value="">No WiFi interfaces found</option>';
                        showNotification('WiFi', 'No WiFi interfaces detected. Make sure you have a WiFi adapter connected.');
                    } else {
                        select.innerHTML = data.interfaces.map(i => {
                            // Build descriptive label with available info
                            let label = i.name;
                            let details = [];
                            if (i.chipset) details.push(i.chipset);
                            else if (i.driver) details.push(i.driver);
                            if (i.mac) details.push(i.mac.substring(0, 8) + '...');
                            if (details.length > 0) label += ' - ' + details.join(' | ');
                            label += ` (${i.type})`;
                            if (i.monitor_capable) label += ' [Monitor OK]';
                            return `<option value="${i.name}">${label}</option>`;
                        }).join('');
                        showNotification('WiFi', `Found ${data.interfaces.length} interface(s)`);
                    }

                    // Update tool status
                    const statusDiv = document.getElementById('wifiToolStatus');
                    if (statusDiv) {
                        statusDiv.innerHTML = `
                            <span>airmon-ng:</span><span class="tool-status ${data.tools?.airmon ? 'ok' : 'missing'}">${data.tools?.airmon ? 'OK' : 'Missing'}</span>
                            <span>airodump-ng:</span><span class="tool-status ${data.tools?.airodump ? 'ok' : 'missing'}">${data.tools?.airodump ? 'OK' : 'Missing'}</span>
                        `;
                    }

                    // Update monitor status
                    if (data.monitor_interface) {
                        monitorInterface = data.monitor_interface;
                        updateMonitorStatus(true);
                    }
                })
                .catch(err => {
                    console.error('Error fetching WiFi interfaces:', err);
                    select.innerHTML = '<option value="">Error loading interfaces</option>';
                    showNotification('WiFi Error', 'Could not detect WiFi interfaces: ' + err.message);
                });
        }

        // Enable monitor mode
        function enableMonitorMode() {
            const iface = document.getElementById('wifiInterfaceSelect').value;
            if (!iface) {
                alert('Please select an interface');
                return;
            }

            const killProcesses = document.getElementById('killProcesses').checked;

            // Show loading state
            const btn = document.getElementById('monitorStartBtn');
            const originalText = btn.textContent;
            btn.textContent = 'Enabling...';
            btn.disabled = true;

            fetch('/wifi/monitor', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify({interface: iface, action: 'start', kill_processes: killProcesses})
            }).then(r => r.json())
              .then(data => {
                  btn.textContent = originalText;
                  btn.disabled = false;

                  if (data.status === 'success') {
                      monitorInterface = data.monitor_interface;
                      updateMonitorStatus(true);
                      showInfo('Monitor mode enabled on ' + monitorInterface + ' - Ready to scan!');

                      // Refresh interface list and auto-select the monitor interface
                      fetch('/wifi/interfaces')
                          .then(r => r.json())
                          .then(ifaceData => {
                              const select = document.getElementById('wifiInterfaceSelect');
                              if (ifaceData.interfaces.length > 0) {
                                  select.innerHTML = ifaceData.interfaces.map(i => {
                                      let label = i.name;
                                      let details = [];
                                      if (i.chipset) details.push(i.chipset);
                                      else if (i.driver) details.push(i.driver);
                                      if (i.mac) details.push(i.mac.substring(0, 8) + '...');
                                      if (details.length > 0) label += ' - ' + details.join(' | ');
                                      label += ` (${i.type})`;
                                      if (i.monitor_capable) label += ' [Monitor OK]';
                                      return `<option value="${i.name}" ${i.name === monitorInterface ? 'selected' : ''}>${label}</option>`;
                                  }).join('');
                              }
                          });
                  } else {
                      alert('Error: ' + data.message);
                  }
              })
              .catch(err => {
                  btn.textContent = originalText;
                  btn.disabled = false;
                  alert('Error: ' + err.message);
              });
        }

        // Disable monitor mode
        function disableMonitorMode() {
            const iface = monitorInterface || document.getElementById('wifiInterfaceSelect').value;

            fetch('/wifi/monitor', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify({interface: iface, action: 'stop'})
            }).then(r => r.json())
              .then(data => {
                  if (data.status === 'success') {
                      monitorInterface = null;
                      updateMonitorStatus(false);
                      showInfo('Monitor mode disabled');
                  } else {
                      alert('Error: ' + data.message);
                  }
              });
        }

        function updateMonitorStatus(enabled) {
            document.getElementById('monitorStartBtn').style.display = enabled ? 'none' : 'block';
            document.getElementById('monitorStopBtn').style.display = enabled ? 'block' : 'none';
            document.getElementById('monitorStatus').innerHTML = enabled
                ? 'Monitor mode: <span style="color: var(--accent-green);">Active (' + monitorInterface + ')</span>'
                : 'Monitor mode: <span style="color: var(--accent-red);">Inactive</span>';
        }

        // Start WiFi scan - auto-enables monitor mode if needed
        async function startWifiScan() {
            console.log('startWifiScan called');
            const band = document.getElementById('wifiBand').value;
            const channel = document.getElementById('wifiChannel').value;

            // Auto-enable monitor mode if not already enabled
            if (!monitorInterface) {
                const iface = document.getElementById('wifiInterfaceSelect').value;
                console.log('Selected interface:', iface);

                if (!iface) {
                    showNotification('WiFi Error', 'No WiFi interface selected. Please select an adapter from the dropdown.');
                    alert('No WiFi interface selected. Please select an adapter from the dropdown above.');
                    return;
                }

                // Show status
                document.getElementById('statusText').textContent = 'Enabling monitor mode...';
                document.getElementById('statusDot').classList.add('running');
                showNotification('WiFi', 'Enabling monitor mode on ' + iface + '...');

                try {
                    const killProcesses = document.getElementById('killProcesses').checked;
                    console.log('Enabling monitor mode, kill processes:', killProcesses);

                    const monitorResp = await fetch('/wifi/monitor', {
                        method: 'POST',
                        headers: {'Content-Type': 'application/json'},
                        body: JSON.stringify({interface: iface, action: 'start', kill_processes: killProcesses})
                    });
                    const monitorData = await monitorResp.json();
                    console.log('Monitor response:', monitorData);

                    if (monitorData.status === 'success') {
                        monitorInterface = monitorData.monitor_interface;
                        updateMonitorStatus(true);
                        showNotification('Monitor Mode', 'Enabled on ' + monitorInterface);
                    } else {
                        document.getElementById('statusText').textContent = 'Idle';
                        document.getElementById('statusDot').classList.remove('running');
                        showNotification('Monitor Error', monitorData.message || 'Failed to enable monitor mode');
                        alert('Monitor mode failed: ' + (monitorData.message || 'Unknown error'));
                        return;
                    }
                } catch (err) {
                    console.error('Monitor mode error:', err);
                    document.getElementById('statusText').textContent = 'Idle';
                    document.getElementById('statusDot').classList.remove('running');
                    showNotification('Monitor Error', err.message);
                    alert('Monitor mode error: ' + err.message);
                    return;
                }
            }

            // Now start the scan
            document.getElementById('statusText').textContent = 'Starting scan...';
            console.log('Starting scan on', monitorInterface);

            try {
                const scanResp = await fetch('/wifi/scan/start', {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({
                        interface: monitorInterface,
                        band: band,
                        channel: channel || null
                    })
                });
                const scanData = await scanResp.json();
                console.log('Scan response:', scanData);

                if (scanData.status === 'started') {
                    setWifiRunning(true);
                    startWifiStream();
                    showNotification('WiFi Scanner', 'Scanning started on ' + monitorInterface);
                } else {
                    document.getElementById('statusText').textContent = 'Idle';
                    document.getElementById('statusDot').classList.remove('running');
                    showNotification('Scan Error', scanData.message || 'Failed to start scan');
                    alert('Scan failed: ' + (scanData.message || 'Unknown error'));
                }
            } catch (err) {
                console.error('Scan error:', err);
                document.getElementById('statusText').textContent = 'Idle';
                document.getElementById('statusDot').classList.remove('running');
                showNotification('Scan Error', err.message);
                alert('Scan error: ' + err.message);
            }
        }

        // Stop WiFi scan
        function stopWifiScan() {
            fetch('/wifi/scan/stop', {method: 'POST'})
                .then(r => r.json())
                .then(data => {
                    setWifiRunning(false);
                    if (wifiEventSource) {
                        wifiEventSource.close();
                        wifiEventSource = null;
                    }
                });
        }

        function setWifiRunning(running) {
            isWifiRunning = running;
            document.getElementById('statusDot').classList.toggle('running', running);
            document.getElementById('statusText').textContent = running ? 'Scanning...' : 'Idle';
            document.getElementById('startWifiBtn').style.display = running ? 'none' : 'block';
            document.getElementById('stopWifiBtn').style.display = running ? 'block' : 'none';
        }

        // Batching state for WiFi updates
        let pendingWifiUpdate = false;
        let pendingWifiNetworks = [];
        let pendingWifiClients = [];

        function scheduleWifiUIUpdate() {
            if (pendingWifiUpdate) return;
            pendingWifiUpdate = true;
            requestAnimationFrame(() => {
                // Process networks
                pendingWifiNetworks.forEach(data => handleWifiNetworkImmediate(data));
                pendingWifiNetworks = [];

                // Process clients (limit to last 5 per frame)
                const clientsToProcess = pendingWifiClients.slice(-5);
                pendingWifiClients = [];
                clientsToProcess.forEach(data => handleWifiClientImmediate(data));

                // Update graphs once per frame instead of per-network
                updateChannelGraph();
                updateChannel5gGraph();

                // Update selected device panel
                updateWifiSelectedDevice();

                // Update probe analysis (throttled)
                if (clientsToProcess.length > 0) {
                    scheduleProbeAnalysisUpdate();
                }

                pendingWifiUpdate = false;
            });
        }

        // Start WiFi event stream
        function startWifiStream() {
            if (wifiEventSource) {
                wifiEventSource.close();
            }

            wifiEventSource = new EventSource('/wifi/stream');

            wifiEventSource.onmessage = function(e) {
                const data = JSON.parse(e.data);

                if (data.type === 'network') {
                    pendingWifiNetworks.push(data);
                    scheduleWifiUIUpdate();
                } else if (data.type === 'client') {
                    pendingWifiClients.push(data);
                    scheduleWifiUIUpdate();
                } else if (data.type === 'info' || data.type === 'raw') {
                    showInfo(data.text);
                } else if (data.type === 'error') {
                    showError(data.text);
                } else if (data.type === 'status') {
                    if (data.text === 'stopped') {
                        setWifiRunning(false);
                    }
                }
            };

            wifiEventSource.onerror = function() {
                console.error('WiFi stream error');
            };
        }

        // Track networks that were originally hidden
        let hiddenNetworks = {};  // {bssid: true} for networks first seen with hidden ESSID

        // Handle discovered WiFi network (called from batched update)
        function handleWifiNetworkImmediate(net) {
            const isNew = !wifiNetworks[net.bssid];
            const previousNet = wifiNetworks[net.bssid];
            wifiNetworks[net.bssid] = net;

            // Track if this network was originally hidden
            if (isNew) {
                const isHidden = !net.essid || net.essid === '' || net.essid === 'Hidden' || net.essid === '[Hidden]';
                if (isHidden) {
                    hiddenNetworks[net.bssid] = true;
                }
            }

            // Check if a previously hidden network now has a revealed SSID
            if (hiddenNetworks[net.bssid] && net.essid && net.essid !== '' && net.essid !== 'Hidden' && net.essid !== '[Hidden]') {
                revealHiddenSsid(net.bssid, net.essid);
                delete hiddenNetworks[net.bssid];  // No longer hidden
            }

            if (isNew) {
                apCount++;
                document.getElementById('apCount').textContent = apCount;
                playAlert();
                pulseSignal();

                // Check for rogue AP (same SSID, different BSSID)
                checkRogueAP(net.essid, net.bssid, net.channel, net.power);

                // Check proximity watch list
                checkWatchList(net.bssid, 'AP');

                // Check for drone
                const droneCheck = isDrone(net.essid, net.bssid);
                if (droneCheck.isDrone) {
                    handleDroneDetection(net, droneCheck);
                    showNotification('🚁 Drone Detected!', `${droneCheck.brand}: ${net.essid}`);
                }
            }

            // Update recon display
            const droneInfo = isDrone(net.essid, net.bssid);
            trackDevice({
                protocol: droneInfo.isDrone ? 'DRONE' : 'WiFi-AP',
                address: net.bssid,
                message: net.essid || '[Hidden SSID]',
                model: net.essid,
                channel: net.channel,
                privacy: net.privacy,
                isDrone: droneInfo.isDrone,
                droneBrand: droneInfo.brand
            });

            // Add to output
            addWifiNetworkCard(net, isNew);
            // Note: Channel graphs are updated in the batched scheduleWifiUIUpdate
        }

        // Handle discovered WiFi client (called from batched update)
        function handleWifiClientImmediate(client) {
            const isNew = !wifiClients[client.mac];
            wifiClients[client.mac] = client;

            if (isNew) {
                clientCount++;
                document.getElementById('clientCount').textContent = clientCount;

                // Check proximity watch list
                checkWatchList(client.mac, 'Client');
            }

            // If client is connected to a hidden network and has probes, try to reveal the SSID
            if (client.bssid && hiddenNetworks[client.bssid] && client.probes) {
                const probes = client.probes.split(',').map(p => p.trim()).filter(p => p);
                if (probes.length > 0) {
                    // Use the first probe as the likely SSID for this hidden network
                    revealHiddenSsid(client.bssid, probes[0]);
                    delete hiddenNetworks[client.bssid];
                }
            }

            // Track in device intelligence with vendor info
            const vendorInfo = client.vendor && client.vendor !== 'Unknown' ? ` [${client.vendor}]` : '';
            trackDevice({
                protocol: 'WiFi-Client',
                address: client.mac,
                message: (client.probes || '[No probes]') + vendorInfo,
                bssid: client.bssid,
                vendor: client.vendor
            });

            // Update probe analysis when we get client data with probes
            if (client.probes && client.probes.trim()) {
                scheduleProbeAnalysisUpdate();
            }

            // Add client card to device list
            addWifiClientCard(client, isNew);
        }

        // Throttled probe analysis (called less frequently)
        let lastProbeAnalysisUpdate = 0;
        function scheduleProbeAnalysisUpdate() {
            const now = Date.now();
            if (now - lastProbeAnalysisUpdate > 2000) {
                lastProbeAnalysisUpdate = now;
                updateProbeAnalysis();
            }
        }

        // Update client probe analysis panel
        function updateProbeAnalysis() {
            const list = document.getElementById('probeAnalysisList');
            if (!list) return;

            const clientsWithProbes = Object.values(wifiClients).filter(c => c.probes && c.probes.trim());
            const allProbes = new Set();
            let privacyLeaks = 0;

            // Count unique probes and privacy leaks
            clientsWithProbes.forEach(client => {
                const probes = client.probes.split(',').map(p => p.trim()).filter(p => p);
                probes.forEach(p => allProbes.add(p));

                // Check for sensitive network names (home networks, corporate, etc.)
                probes.forEach(probe => {
                    const lowerProbe = probe.toLowerCase();
                    if (lowerProbe.includes('home') || lowerProbe.includes('office') ||
                        lowerProbe.includes('corp') || lowerProbe.includes('work') ||
                        lowerProbe.includes('private') || lowerProbe.includes('hotel') ||
                        lowerProbe.includes('airport') || lowerProbe.match(/^[a-z]+-[a-z]+$/i)) {
                        privacyLeaks++;
                    }
                });
            });

            // Update counters
            document.getElementById('probeClientCount').textContent = clientsWithProbes.length;
            document.getElementById('probeSSIDCount').textContent = allProbes.size;
            document.getElementById('probePrivacyCount').textContent = privacyLeaks;

            if (clientsWithProbes.length === 0) {
                list.innerHTML = '<div style="color: var(--text-dim);">Waiting for client probe requests...</div>';
                return;
            }

            // Sort by number of probes (most revealing first)
            clientsWithProbes.sort((a, b) => {
                const aCount = (a.probes || '').split(',').length;
                const bCount = (b.probes || '').split(',').length;
                return bCount - aCount;
            });

            let html = '<div style="display: flex; flex-direction: column; gap: 8px;">';

            clientsWithProbes.forEach(client => {
                const probes = client.probes.split(',').map(p => p.trim()).filter(p => p);
                const vendorBadge = client.vendor && client.vendor !== 'Unknown'
                    ? `<span style="background: var(--bg-tertiary); padding: 1px 4px; border-radius: 2px; font-size: 9px; margin-left: 5px;">${escapeHtml(client.vendor)}</span>`
                    : '';

                // Check for privacy-revealing probes
                const probeHtml = probes.map(probe => {
                    const lowerProbe = probe.toLowerCase();
                    const isSensitive = lowerProbe.includes('home') || lowerProbe.includes('office') ||
                        lowerProbe.includes('corp') || lowerProbe.includes('work') ||
                        lowerProbe.includes('private') || lowerProbe.includes('hotel') ||
                        lowerProbe.includes('airport') || lowerProbe.match(/^[a-z]+-[a-z]+$/i);

                    const style = isSensitive
                        ? 'background: var(--accent-orange); color: #000; padding: 1px 4px; border-radius: 2px; margin: 1px;'
                        : 'background: var(--bg-tertiary); padding: 1px 4px; border-radius: 2px; margin: 1px;';

                    return `<span style="${style}" title="${isSensitive ? 'Potentially sensitive - reveals user location history' : ''}">${escapeHtml(probe)}</span>`;
                }).join(' ');

                html += `
                    <div style="border-left: 2px solid var(--accent-cyan); padding-left: 8px; cursor: pointer;" onclick="selectWifiDevice('${escapeAttr(client.mac)}', 'client')" title="Click for details">
                        <div style="display: flex; align-items: center; gap: 5px; margin-bottom: 3px;">
                            <span style="color: var(--accent-cyan); font-family: monospace; font-size: 10px;">${escapeHtml(client.mac)}</span>
                            ${vendorBadge}
                            <span style="color: var(--text-dim); font-size: 9px;">(${probes.length} probe${probes.length !== 1 ? 's' : ''})</span>
                        </div>
                        <div style="display: flex; flex-wrap: wrap; gap: 2px; font-size: 10px;">
                            ${probeHtml}
                        </div>
                    </div>
                `;
            });

            html += '</div>';
            list.innerHTML = html;
        }

        // Select a WiFi network or client for detailed view
        function selectWifiDevice(id, type) {
            selectedWifiDevice = id;
            selectedWifiType = type;
            updateWifiSelectedDevice();
        }

        // Update the selected WiFi device panel
        function updateWifiSelectedDevice() {
            const panel = document.getElementById('wifiSelectedDevice');
            if (!panel) return;

            if (!selectedWifiDevice) {
                panel.innerHTML = '<div style="color: var(--text-dim); padding: 20px; text-align: center;">Click a network or client to view details</div>';
                return;
            }

            if (selectedWifiType === 'network') {
                const net = wifiNetworks[selectedWifiDevice];
                if (!net) {
                    panel.innerHTML = '<div style="color: var(--text-dim); padding: 20px; text-align: center;">Network no longer visible</div>';
                    return;
                }

                const power = parseInt(net.power) || -100;
                const signalPercent = Math.max(0, Math.min(100, (power + 100) * 2));
                const signalColor = power >= -50 ? 'var(--accent-green)' : power >= -70 ? 'var(--accent-orange)' : 'var(--accent-red)';
                const isRogue = rogueBssids.has(net.bssid);

                panel.innerHTML = `
                    ${isRogue ? '<div class="rogue-indicator" style="margin: -10px -10px 10px -10px; padding: 8px;">⚠️ SUSPECTED ROGUE ACCESS POINT</div>' : ''}
                    <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;">
                        <div style="grid-column: span 2; text-align: center; padding-bottom: 10px; border-bottom: 1px solid var(--border-color);">
                            <div style="font-size: 18px; color: ${isRogue ? 'var(--accent-red)' : 'var(--accent-cyan)'}; font-weight: bold;">${escapeHtml(net.essid || '[Hidden]')}</div>
                            <div style="font-size: 10px; color: var(--text-muted);">${escapeHtml(net.bssid)}</div>
                        </div>
                        <div style="background: rgba(0,0,0,0.3); padding: 8px; border-radius: 4px;">
                            <div style="color: var(--text-dim); font-size: 9px;">SIGNAL</div>
                            <div style="color: ${signalColor}; font-size: 16px; font-weight: bold;">${power} dBm</div>
                            <div style="background: var(--bg-tertiary); height: 4px; border-radius: 2px; margin-top: 4px;">
                                <div style="background: ${signalColor}; height: 100%; width: ${signalPercent}%; border-radius: 2px;"></div>
                            </div>
                        </div>
                        <div style="background: rgba(0,0,0,0.3); padding: 8px; border-radius: 4px;">
                            <div style="color: var(--text-dim); font-size: 9px;">CHANNEL</div>
                            <div style="color: var(--accent-cyan); font-size: 16px; font-weight: bold;">${net.channel}</div>
                        </div>
                        <div style="background: rgba(0,0,0,0.3); padding: 8px; border-radius: 4px;">
                            <div style="color: var(--text-dim); font-size: 9px;">SECURITY</div>
                            <div style="color: ${(net.privacy || '').includes('WPA3') ? 'var(--accent-green)' : (net.privacy || '').includes('WPA') ? 'var(--accent-orange)' : 'var(--accent-red)'};">${escapeHtml(net.privacy || 'Unknown')}</div>
                        </div>
                        <div style="background: rgba(0,0,0,0.3); padding: 8px; border-radius: 4px;">
                            <div style="color: var(--text-dim); font-size: 9px;">BEACONS</div>
                            <div style="color: var(--text-secondary);">${net.beacons || 0}</div>
                        </div>
                        <div style="grid-column: span 2; display: flex; gap: 8px; margin-top: 8px;">
                            <button class="preset-btn" onclick="targetNetwork('${escapeAttr(net.bssid)}', '${escapeAttr(net.channel)}')" style="flex: 1;">Target</button>
                            <button class="preset-btn" onclick="captureHandshake('${escapeAttr(net.bssid)}', '${escapeAttr(net.channel)}')" style="flex: 1; border-color: var(--accent-orange); color: var(--accent-orange);">Handshake</button>
                        </div>
                    </div>
                `;
            } else if (selectedWifiType === 'client') {
                const client = wifiClients[selectedWifiDevice];
                if (!client) {
                    panel.innerHTML = '<div style="color: var(--text-dim); padding: 20px; text-align: center;">Client no longer visible</div>';
                    return;
                }

                const power = parseInt(client.power) || -100;
                const signalPercent = Math.max(0, Math.min(100, (power + 100) * 2));
                const signalColor = power >= -50 ? 'var(--accent-green)' : power >= -70 ? 'var(--accent-orange)' : 'var(--accent-red)';
                const probes = (client.probes || '').split(',').map(p => p.trim()).filter(p => p);
                const associatedNet = client.bssid && wifiNetworks[client.bssid];

                panel.innerHTML = `
                    <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;">
                        <div style="grid-column: span 2; text-align: center; padding-bottom: 10px; border-bottom: 1px solid var(--border-color);">
                            <div style="font-size: 14px; color: var(--accent-orange); font-weight: bold;">CLIENT DEVICE</div>
                            <div style="font-size: 12px; color: var(--text-secondary);">${escapeHtml(client.mac)}</div>
                            ${client.vendor ? `<div style="font-size: 10px; color: var(--text-muted);">${escapeHtml(client.vendor)}</div>` : ''}
                        </div>
                        <div style="background: rgba(0,0,0,0.3); padding: 8px; border-radius: 4px;">
                            <div style="color: var(--text-dim); font-size: 9px;">SIGNAL</div>
                            <div style="color: ${signalColor}; font-size: 16px; font-weight: bold;">${power} dBm</div>
                            <div style="background: var(--bg-tertiary); height: 4px; border-radius: 2px; margin-top: 4px;">
                                <div style="background: ${signalColor}; height: 100%; width: ${signalPercent}%; border-radius: 2px;"></div>
                            </div>
                        </div>
                        <div style="background: rgba(0,0,0,0.3); padding: 8px; border-radius: 4px;">
                            <div style="color: var(--text-dim); font-size: 9px;">PACKETS</div>
                            <div style="color: var(--text-secondary);">${client.packets || 0}</div>
                        </div>
                        ${associatedNet ? `
                        <div style="grid-column: span 2; background: rgba(0,0,0,0.3); padding: 8px; border-radius: 4px;">
                            <div style="color: var(--text-dim); font-size: 9px;">CONNECTED TO</div>
                            <div style="color: var(--accent-cyan);">${escapeHtml(associatedNet.essid || associatedNet.bssid)}</div>
                        </div>
                        ` : ''}
                        ${probes.length > 0 ? `
                        <div style="grid-column: span 2; background: rgba(0,0,0,0.3); padding: 8px; border-radius: 4px;">
                            <div style="color: var(--text-dim); font-size: 9px;">PROBING FOR</div>
                            <div style="display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px;">
                                ${probes.slice(0, 5).map(p => `<span style="background: var(--accent-orange); color: #000; padding: 2px 6px; border-radius: 3px; font-size: 10px;">${escapeHtml(p)}</span>`).join('')}
                                ${probes.length > 5 ? `<span style="color: var(--text-muted);">+${probes.length - 5} more</span>` : ''}
                            </div>
                        </div>
                        ` : ''}
                    </div>
                `;
            }
        }

        // Add WiFi network card to device list
        function addWifiNetworkCard(net, isNew) {
            // Use the WiFi device list panel instead of the generic output
            const deviceList = document.getElementById('wifiDeviceListContent');
            if (!deviceList) return;

            // Remove placeholder if present
            const placeholder = deviceList.querySelector('div[style*="text-align: center"]');
            if (placeholder && placeholder.textContent.includes('Start scanning')) {
                placeholder.remove();
            }

            // Check if card already exists
            let card = document.getElementById('wifi_' + net.bssid.replace(/:/g, ''));

            if (!card) {
                card = document.createElement('div');
                card.id = 'wifi_' + net.bssid.replace(/:/g, '');
                card.className = 'sensor-card wifi-network-card';
                card.style.borderLeftColor = net.privacy.includes('WPA') ? 'var(--accent-orange)' :
                                             net.privacy.includes('WEP') ? 'var(--accent-red)' :
                                             'var(--accent-green)';
                card.style.cursor = 'pointer';
                card.onclick = () => selectWifiDevice(net.bssid, 'network');
                deviceList.insertBefore(card, deviceList.firstChild);

                // Update device count
                const countEl = document.getElementById('wifiDeviceListCount');
                if (countEl) countEl.textContent = Object.keys(wifiNetworks).length;
            }

            // Handle signal strength - airodump returns -1 when not measured
            let signalStrength = parseInt(net.power);
            if (isNaN(signalStrength) || signalStrength === -1) {
                signalStrength = null;  // No reading available
            }
            const signalBars = signalStrength !== null ? Math.max(0, Math.min(5, Math.floor((signalStrength + 100) / 15))) : 0;
            const signalDisplay = signalStrength !== null ? `${signalStrength} dBm` : 'N/A';

            const wpsEnabled = net.wps === '1' || net.wps === 'Yes' || (net.privacy || '').includes('WPS');
            const wpsHtml = wpsEnabled ? '<span class="wps-enabled">WPS</span>' : '';
            const isRogue = rogueBssids.has(net.bssid);
            const rogueHtml = isRogue ? '<div class="rogue-indicator">⚠️ SUSPECTED ROGUE AP</div>' : '';

            // Update card border for rogue APs
            if (isRogue) {
                card.style.borderLeftColor = 'var(--accent-red)';
                card.style.borderLeftWidth = '4px';
                card.style.background = 'rgba(255, 0, 0, 0.1)';
            }

            card.innerHTML = `
                ${rogueHtml}
                <div class="header" style="display: flex; justify-content: space-between; margin-bottom: 8px;">
                    <span class="device-name">${escapeHtml(net.essid || '[Hidden]')}${wpsHtml}</span>
                    <span style="color: #444; font-size: 10px;">CH ${net.channel}</span>
                </div>
                <div class="sensor-data">
                    <div class="data-item">
                        <div class="data-label">BSSID</div>
                        <div class="data-value" style="font-size: 11px;">${escapeHtml(net.bssid)}</div>
                    </div>
                    <div class="data-item">
                        <div class="data-label">Security</div>
                        <div class="data-value" style="color: ${(net.privacy || '').includes('WPA') ? 'var(--accent-orange)' : net.privacy === 'OPN' ? 'var(--accent-green)' : 'var(--accent-red)'}">${escapeHtml(net.privacy || '')}</div>
                    </div>
                    <div class="data-item">
                        <div class="data-label">Signal</div>
                        <div class="data-value">${signalDisplay} ${'█'.repeat(signalBars)}${'░'.repeat(5-signalBars)}</div>
                    </div>
                    <div class="data-item">
                        <div class="data-label">Beacons</div>
                        <div class="data-value">${net.beacons}</div>
                    </div>
                </div>
                <div style="margin-top: 8px; display: flex; gap: 5px; flex-wrap: wrap;">
                    <button class="preset-btn" onclick="targetNetwork('${escapeAttr(net.bssid)}', '${escapeAttr(net.channel)}')" style="font-size: 10px; padding: 4px 8px;">Target</button>
                    <button class="preset-btn" onclick="captureHandshake('${escapeAttr(net.bssid)}', '${escapeAttr(net.channel)}')" style="font-size: 10px; padding: 4px 8px; border-color: var(--accent-orange); color: var(--accent-orange);">Handshake</button>
                </div>
            `;

            if (autoScroll) output.scrollTop = 0;
        }

        // Add WiFi client card to device list
        function addWifiClientCard(client, isNew) {
            const deviceList = document.getElementById('wifiDeviceListContent');
            if (!deviceList) return;

            // Remove placeholder if present
            const placeholder = deviceList.querySelector('div[style*="text-align: center"]');
            if (placeholder && placeholder.textContent.includes('Start scanning')) {
                placeholder.remove();
            }

            // Check if card already exists
            let card = document.getElementById('client_' + client.mac.replace(/:/g, ''));

            if (!card) {
                card = document.createElement('div');
                card.id = 'client_' + client.mac.replace(/:/g, '');
                card.className = 'sensor-card wifi-client-card';
                card.style.borderLeftColor = 'var(--accent-purple)';
                card.style.cursor = 'pointer';
                card.onclick = () => selectWifiDevice(client.mac, 'client');
                deviceList.appendChild(card);  // Clients go after networks

                // Update device count
                const countEl = document.getElementById('wifiDeviceListCount');
                if (countEl) countEl.textContent = Object.keys(wifiNetworks).length + Object.keys(wifiClients).length;
            }

            // Handle signal strength
            let signalStrength = parseInt(client.power);
            if (isNaN(signalStrength) || signalStrength === -1) {
                signalStrength = null;
            }
            const signalBars = signalStrength !== null ? Math.max(0, Math.min(5, Math.floor((signalStrength + 100) / 15))) : 0;
            const signalDisplay = signalStrength !== null ? `${signalStrength} dBm` : 'N/A';

            // Get connected AP info
            const connectedAP = client.bssid && wifiNetworks[client.bssid];
            const apName = connectedAP ? (connectedAP.essid || '[Hidden]') : (client.bssid || 'Not Associated');

            // Format probes
            const probes = client.probes ? client.probes.split(',').map(p => p.trim()).filter(p => p) : [];
            const probesDisplay = probes.length > 0 ? probes.slice(0, 3).join(', ') + (probes.length > 3 ? ` +${probes.length - 3}` : '') : 'None';

            card.innerHTML = `
                <div class="header" style="display: flex; justify-content: space-between; margin-bottom: 8px;">
                    <span class="device-name" style="color: var(--accent-purple);">📱 ${escapeHtml(client.vendor || 'Client')}</span>
                    <span style="font-size: 10px; color: var(--text-dim);">CLIENT</span>
                </div>
                <div class="sensor-data">
                    <div class="data-item">
                        <div class="data-label">MAC</div>
                        <div class="data-value" style="font-size: 11px;">${escapeHtml(client.mac)}</div>
                    </div>
                    <div class="data-item">
                        <div class="data-label">Connected To</div>
                        <div class="data-value" style="color: var(--accent-cyan);">${escapeHtml(apName)}</div>
                    </div>
                    <div class="data-item">
                        <div class="data-label">Signal</div>
                        <div class="data-value">${signalDisplay} ${'█'.repeat(signalBars)}${'░'.repeat(5-signalBars)}</div>
                    </div>
                    <div class="data-item">
                        <div class="data-label">Probes</div>
                        <div class="data-value" style="font-size: 10px;">${escapeHtml(probesDisplay)}</div>
                    </div>
                </div>
            `;
        }

        // Target a network for attack
        function targetNetwork(bssid, channel) {
            document.getElementById('targetBssid').value = bssid;
            document.getElementById('wifiChannel').value = channel;
            showInfo('Targeted: ' + bssid + ' on channel ' + channel);
        }

        // Start handshake capture
        async function captureHandshake(bssid, channel) {
            if (!confirm('Start handshake capture for ' + bssid + '? This will stop the current scan.')) {
                return;
            }

            const iface = monitorInterface || document.getElementById('wifiInterfaceSelect').value;
            if (!iface) {
                showError('No monitor interface available. Enable monitor mode first.');
                return;
            }

            // Stop any existing scan first
            if (isWifiRunning) {
                showInfo('Stopping current scan...');
                try {
                    await fetch('/wifi/scan/stop', {method: 'POST'});
                    if (wifiEventSource) {
                        wifiEventSource.close();
                        wifiEventSource = null;
                    }
                    setWifiRunning(false);
                    // Brief delay to ensure process stops
                    await new Promise(resolve => setTimeout(resolve, 500));
                } catch (e) {
                    console.error('Error stopping scan:', e);
                }
            }

            try {
                const response = await fetch('/wifi/handshake/capture', {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({bssid: bssid, channel: channel, interface: iface})
                });
                const data = await response.json();

                if (data.status === 'started') {
                    showInfo('🎯 Capturing handshakes for ' + bssid);
                    setWifiRunning(true);

                    // Update handshake indicator to show active capture
                    const hsSpan = document.getElementById('handshakeCount');
                    hsSpan.style.animation = 'pulse 1s infinite';
                    hsSpan.title = 'Capturing: ' + bssid;

                    // Show capture status panel
                    const panel = document.getElementById('captureStatusPanel');
                    panel.style.display = 'block';
                    document.getElementById('captureTargetBssid').textContent = bssid;
                    document.getElementById('captureTargetChannel').textContent = channel;
                    document.getElementById('captureFilePath').textContent = data.capture_file;
                    document.getElementById('captureStatus').textContent = 'Waiting for handshake...';
                    document.getElementById('captureStatus').style.color = 'var(--accent-orange)';

                    // Store active capture info and start polling
                    activeCapture = {
                        bssid: bssid,
                        channel: channel,
                        file: data.capture_file,
                        startTime: Date.now(),
                        pollInterval: setInterval(checkCaptureStatus, 5000)  // Check every 5 seconds
                    };
                } else {
                    showError('Handshake capture failed: ' + (data.message || 'Unknown error'));
                }
            } catch (err) {
                showError('Handshake capture error: ' + err.message);
                console.error('Handshake capture error:', err);
            }
        }

        // Check handshake capture status
        function checkCaptureStatus() {
            if (!activeCapture) {
                showInfo('No active handshake capture');
                return;
            }

            fetch('/wifi/handshake/status', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify({file: activeCapture.file, bssid: activeCapture.bssid})
            }).then(r => r.json())
              .then(data => {
                  const statusSpan = document.getElementById('captureStatus');
                  const elapsed = Math.round((Date.now() - activeCapture.startTime) / 1000);
                  const elapsedStr = elapsed < 60 ? elapsed + 's' : Math.floor(elapsed/60) + 'm ' + (elapsed%60) + 's';

                  if (data.handshake_found) {
                      // Handshake captured!
                      statusSpan.textContent = '✓ HANDSHAKE CAPTURED!';
                      statusSpan.style.color = 'var(--accent-green)';
                      handshakeCount++;
                      document.getElementById('handshakeCount').textContent = handshakeCount;
                      playAlert();
                      showInfo('🎉 Handshake captured for ' + activeCapture.bssid + '! File: ' + data.file);
                      showNotification('🤝 Handshake Captured!', `Target: ${activeCapture.bssid}`);

                      // Stop polling
                      if (activeCapture.pollInterval) {
                          clearInterval(activeCapture.pollInterval);
                      }
                      document.getElementById('handshakeCount').style.animation = '';

                      // Show crack button in the capture panel
                      const panel = document.getElementById('captureStatusPanel');
                      const existingCrackBtn = panel.querySelector('.crack-btn');
                      if (!existingCrackBtn) {
                          const crackDiv = document.createElement('div');
                          crackDiv.style.marginTop = '10px';
                          crackDiv.innerHTML = `
                              <button class="preset-btn crack-btn" onclick="crackHandshake('${data.file}', '${activeCapture.bssid}')" style="width: 100%; background: var(--accent-green); border-color: var(--accent-green); color: #000; font-weight: bold;">
                                  🔓 Crack with Aircrack-ng
                              </button>
                          `;
                          panel.querySelector('.section') ? panel.querySelector('.section').appendChild(crackDiv) : panel.appendChild(crackDiv);
                      }

                      // Store the captured file for later use
                      activeCapture.captured = true;
                      activeCapture.capturedFile = data.file;
                  } else if (data.file_exists) {
                      const sizeKB = (data.file_size / 1024).toFixed(1);
                      statusSpan.textContent = 'Capturing... (' + sizeKB + ' KB, ' + elapsedStr + ')';
                      statusSpan.style.color = 'var(--accent-orange)';
                  } else if (data.status === 'stopped') {
                      statusSpan.textContent = 'Capture stopped';
                      statusSpan.style.color = 'var(--text-dim)';
                      if (activeCapture.pollInterval) {
                          clearInterval(activeCapture.pollInterval);
                      }
                  } else {
                      statusSpan.textContent = 'Waiting for data... (' + elapsedStr + ')';
                      statusSpan.style.color = 'var(--accent-orange)';
                  }
              })
              .catch(err => {
                  console.error('Capture status check failed:', err);
              });
        }

        // Stop handshake capture
        function stopHandshakeCapture() {
            if (activeCapture && activeCapture.pollInterval) {
                clearInterval(activeCapture.pollInterval);
            }

            // Stop the WiFi scan (which stops airodump-ng)
            stopWifiScan();

            document.getElementById('captureStatus').textContent = 'Stopped';
            document.getElementById('captureStatus').style.color = 'var(--text-dim)';
            document.getElementById('handshakeCount').style.animation = '';

            // Keep the panel visible so user can see the file path
            showInfo('Handshake capture stopped. Check ' + (activeCapture ? activeCapture.file : 'capture file'));

            activeCapture = null;
        }

        // Crack handshake with aircrack-ng
        function crackHandshake(captureFile, bssid) {
            const wordlist = prompt('Enter path to wordlist file:\n\nCommon locations:\n- /usr/share/wordlists/rockyou.txt\n- /usr/share/john/password.lst', '/usr/share/wordlists/rockyou.txt');

            if (!wordlist) {
                showInfo('Cracking cancelled');
                return;
            }

            showInfo('Starting aircrack-ng... This may take a while.');

            fetch('/wifi/handshake/crack', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    capture_file: captureFile,
                    bssid: bssid,
                    wordlist: wordlist
                })
            })
            .then(r => r.json())
            .then(data => {
                if (data.status === 'success' && data.password) {
                    showInfo('🎉 PASSWORD FOUND: ' + data.password);
                    showNotification('🔓 Password Cracked!', data.password);
                    alert('Password found!\n\n' + data.password + '\n\nThis has been logged.');
                } else if (data.status === 'not_found') {
                    showInfo('Password not found in wordlist. Try a different wordlist.');
                    alert('Password not found in wordlist.\n\nTry using a larger or different wordlist.');
                } else if (data.status === 'running') {
                    showInfo('Aircrack-ng is running in background. Check terminal for progress.');
                } else {
                    showError('Crack failed: ' + (data.message || 'Unknown error'));
                }
            })
            .catch(err => {
                showError('Crack error: ' + err.message);
                console.error('Crack error:', err);
            });
        }

        // Beacon Flood Detection
        let beaconHistory = [];
        let lastBeaconCheck = Date.now();

        function checkBeaconFlood(networks) {
            const now = Date.now();
            const windowMs = 5000; // 5 second window

            // Add current networks to history
            beaconHistory.push({ time: now, count: Object.keys(networks).length });

            // Remove old entries
            beaconHistory = beaconHistory.filter(h => now - h.time < windowMs);

            // Calculate rate of new networks
            if (beaconHistory.length >= 2) {
                const oldest = beaconHistory[0];
                const newest = beaconHistory[beaconHistory.length - 1];
                const timeDiff = (newest.time - oldest.time) / 1000;
                const countDiff = newest.count - oldest.count;

                if (timeDiff > 0) {
                    const rate = countDiff / timeDiff;

                    // Alert if more than 10 new networks per second
                    if (rate > 10) {
                        document.getElementById('beaconFloodAlert').style.display = 'block';
                        document.getElementById('beaconFloodRate').textContent = rate.toFixed(1);
                        if (!muted) playAlertSound();
                    } else if (rate < 2) {
                        document.getElementById('beaconFloodAlert').style.display = 'none';
                    }
                }
            }
        }

        // Send deauth
        function sendDeauth() {
            const bssid = document.getElementById('targetBssid').value;
            const client = document.getElementById('targetClient').value || 'FF:FF:FF:FF:FF:FF';
            const count = document.getElementById('deauthCount').value || '5';

            if (!bssid) {
                alert('Enter target BSSID');
                return;
            }

            if (!confirm('Send ' + count + ' deauth packets to ' + bssid + '?\\n\\n⚠ Only use on networks you own or have authorization to test!')) {
                return;
            }

            fetch('/wifi/deauth', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify({bssid: bssid, client: client, count: parseInt(count)})
            }).then(r => r.json())
              .then(data => {
                  if (data.status === 'success') {
                      showInfo(data.message);
                  } else {
                      alert('Error: ' + data.message);
                  }
              });
        }

        // ============== WIFI VISUALIZATIONS ==============

        let radarCtx = null;
        let radarAngle = 0;
        let radarAnimFrame = null;
        let radarNetworks = [];  // {x, y, strength, ssid, bssid}
        let targetBssidForSignal = null;

        // Initialize radar canvas
        function initRadar() {
            const canvas = document.getElementById('radarCanvas');
            if (!canvas) return;

            radarCtx = canvas.getContext('2d');
            canvas.width = 150;
            canvas.height = 150;

            // Start animation
            if (!radarAnimFrame) {
                animateRadar();
            }
        }

        // Animate radar sweep
        function animateRadar() {
            if (!radarCtx) {
                radarAnimFrame = null;
                return;
            }

            const canvas = radarCtx.canvas;
            const cx = canvas.width / 2;
            const cy = canvas.height / 2;
            const radius = Math.min(cx, cy) - 5;

            // Clear canvas
            radarCtx.fillStyle = 'rgba(0, 10, 10, 0.1)';
            radarCtx.fillRect(0, 0, canvas.width, canvas.height);

            // Draw grid circles
            radarCtx.strokeStyle = 'rgba(0, 212, 255, 0.2)';
            radarCtx.lineWidth = 1;
            for (let r = radius / 4; r <= radius; r += radius / 4) {
                radarCtx.beginPath();
                radarCtx.arc(cx, cy, r, 0, Math.PI * 2);
                radarCtx.stroke();
            }

            // Draw crosshairs
            radarCtx.beginPath();
            radarCtx.moveTo(cx, cy - radius);
            radarCtx.lineTo(cx, cy + radius);
            radarCtx.moveTo(cx - radius, cy);
            radarCtx.lineTo(cx + radius, cy);
            radarCtx.stroke();

            // Draw sweep line
            radarCtx.strokeStyle = 'rgba(0, 255, 136, 0.8)';
            radarCtx.lineWidth = 2;
            radarCtx.beginPath();
            radarCtx.moveTo(cx, cy);
            radarCtx.lineTo(
                cx + Math.cos(radarAngle) * radius,
                cy + Math.sin(radarAngle) * radius
            );
            radarCtx.stroke();

            // Draw sweep gradient
            const gradient = radarCtx.createConicalGradient ?
                null : // Not supported in all browsers
                radarCtx.createRadialGradient(cx, cy, 0, cx, cy, radius);

            radarCtx.fillStyle = 'rgba(0, 255, 136, 0.05)';
            radarCtx.beginPath();
            radarCtx.moveTo(cx, cy);
            radarCtx.arc(cx, cy, radius, radarAngle - 0.5, radarAngle);
            radarCtx.closePath();
            radarCtx.fill();

            // Draw network blips
            radarNetworks.forEach(net => {
                const age = Date.now() - net.timestamp;
                const alpha = Math.max(0.1, 1 - age / 10000);

                radarCtx.fillStyle = `rgba(0, 255, 136, ${alpha})`;
                radarCtx.beginPath();
                radarCtx.arc(net.x, net.y, 4 + (1 - alpha) * 3, 0, Math.PI * 2);
                radarCtx.fill();

                // Glow effect
                radarCtx.fillStyle = `rgba(0, 255, 136, ${alpha * 0.3})`;
                radarCtx.beginPath();
                radarCtx.arc(net.x, net.y, 8 + (1 - alpha) * 5, 0, Math.PI * 2);
                radarCtx.fill();
            });

            // Update angle
            radarAngle += 0.03;
            if (radarAngle > Math.PI * 2) radarAngle = 0;

            radarAnimFrame = requestAnimationFrame(animateRadar);
        }

        // Add network to radar
        function addNetworkToRadar(net) {
            const canvas = document.getElementById('radarCanvas');
            if (!canvas) return;

            const cx = canvas.width / 2;
            const cy = canvas.height / 2;
            const radius = Math.min(cx, cy) - 10;

            // Convert signal strength to distance (stronger = closer)
            const power = parseInt(net.power) || -80;
            const distance = Math.max(0.1, Math.min(1, (power + 100) / 60));
            const r = radius * (1 - distance);

            // Random angle based on BSSID hash
            let angle = 0;
            for (let i = 0; i < net.bssid.length; i++) {
                angle += net.bssid.charCodeAt(i);
            }
            angle = (angle % 360) * Math.PI / 180;

            const x = cx + Math.cos(angle) * r;
            const y = cy + Math.sin(angle) * r;

            // Update or add
            const existing = radarNetworks.find(n => n.bssid === net.bssid);
            if (existing) {
                existing.x = x;
                existing.y = y;
                existing.timestamp = Date.now();
            } else {
                radarNetworks.push({
                    x, y,
                    bssid: net.bssid,
                    ssid: net.essid,
                    timestamp: Date.now()
                });
            }

            // Limit to 50 networks
            if (radarNetworks.length > 50) {
                radarNetworks.shift();
            }
        }

        // Update channel graph
        function updateChannelGraph() {
            const channels = {};
            for (let i = 1; i <= 13; i++) channels[i] = 0;

            // Count networks per channel
            Object.values(wifiNetworks).forEach(net => {
                const ch = parseInt(net.channel);
                if (ch >= 1 && ch <= 13) {
                    channels[ch]++;
                }
            });

            // Find max for scaling
            const maxCount = Math.max(1, ...Object.values(channels));

            // Update bars
            const bars = document.querySelectorAll('#channelGraph .channel-bar');
            bars.forEach((bar, i) => {
                const ch = i + 1;
                const count = channels[ch] || 0;
                const height = Math.max(2, (count / maxCount) * 55);
                bar.style.height = height + 'px';

                bar.classList.remove('active', 'congested', 'very-congested');
                if (count > 0) bar.classList.add('active');
                if (count >= 3) bar.classList.add('congested');
                if (count >= 5) bar.classList.add('very-congested');
            });
        }

        // Update security donut chart
        function updateSecurityDonut() {
            const canvas = document.getElementById('securityCanvas');
            if (!canvas) return;

            const ctx = canvas.getContext('2d');
            const cx = canvas.width / 2;
            const cy = canvas.height / 2;
            const radius = Math.min(cx, cy) - 2;
            const innerRadius = radius * 0.6;

            // Count security types
            let wpa3 = 0, wpa2 = 0, wep = 0, open = 0;
            Object.values(wifiNetworks).forEach(net => {
                const priv = (net.privacy || '').toUpperCase();
                if (priv.includes('WPA3')) wpa3++;
                else if (priv.includes('WPA')) wpa2++;
                else if (priv.includes('WEP')) wep++;
                else if (priv === 'OPN' || priv === '' || priv === 'OPEN') open++;
                else wpa2++; // Default to WPA2
            });

            const total = wpa3 + wpa2 + wep + open;

            // Update legend
            document.getElementById('wpa3Count').textContent = wpa3;
            document.getElementById('wpa2Count').textContent = wpa2;
            document.getElementById('wepCount').textContent = wep;
            document.getElementById('openCount').textContent = open;

            // Clear canvas
            ctx.clearRect(0, 0, canvas.width, canvas.height);

            if (total === 0) {
                // Draw empty circle
                ctx.strokeStyle = '#1a1a1a';
                ctx.lineWidth = radius - innerRadius;
                ctx.beginPath();
                ctx.arc(cx, cy, (radius + innerRadius) / 2, 0, Math.PI * 2);
                ctx.stroke();
                return;
            }

            // Draw segments
            const colors = {
                wpa3: '#00ff88',
                wpa2: '#ff8800',
                wep: '#ff3366',
                open: '#00d4ff'
            };

            const data = [
                { value: wpa3, color: colors.wpa3 },
                { value: wpa2, color: colors.wpa2 },
                { value: wep, color: colors.wep },
                { value: open, color: colors.open }
            ];

            let startAngle = -Math.PI / 2;

            data.forEach(segment => {
                if (segment.value === 0) return;

                const sliceAngle = (segment.value / total) * Math.PI * 2;

                ctx.fillStyle = segment.color;
                ctx.beginPath();
                ctx.moveTo(cx, cy);
                ctx.arc(cx, cy, radius, startAngle, startAngle + sliceAngle);
                ctx.closePath();
                ctx.fill();

                startAngle += sliceAngle;
            });

            // Draw inner circle (donut hole)
            ctx.fillStyle = '#000';
            ctx.beginPath();
            ctx.arc(cx, cy, innerRadius, 0, Math.PI * 2);
            ctx.fill();

            // Draw total in center
            ctx.fillStyle = '#fff';
            ctx.font = 'bold 16px JetBrains Mono';
            ctx.textAlign = 'center';
            ctx.textBaseline = 'middle';
            ctx.fillText(total, cx, cy);
        }

        // Update signal strength meter for targeted network
        function updateSignalMeter(net) {
            if (!net) return;

            targetBssidForSignal = net.bssid;

            const ssidEl = document.getElementById('targetSsid');
            const valueEl = document.getElementById('signalValue');
            const barsEl = document.querySelectorAll('.signal-bar-large');

            ssidEl.textContent = net.essid || net.bssid;

            const power = parseInt(net.power) || -100;
            valueEl.textContent = power + ' dBm';

            // Determine signal quality
            let quality = 'weak';
            let activeBars = 1;

            if (power >= -50) { quality = 'strong'; activeBars = 5; }
            else if (power >= -60) { quality = 'strong'; activeBars = 4; }
            else if (power >= -70) { quality = 'medium'; activeBars = 3; }
            else if (power >= -80) { quality = 'medium'; activeBars = 2; }
            else { quality = 'weak'; activeBars = 1; }

            valueEl.className = 'signal-value ' + quality;

            barsEl.forEach((bar, i) => {
                bar.className = 'signal-bar-large';
                if (i < activeBars) {
                    bar.classList.add('active', quality);
                }
            });
        }

        // Hook into handleWifiNetworkImmediate to update visualizations
        const originalHandleWifiNetworkImmediate = handleWifiNetworkImmediate;
        handleWifiNetworkImmediate = function(net) {
            originalHandleWifiNetworkImmediate(net);

            // Update radar
            addNetworkToRadar(net);

            // Update security donut
            updateSecurityDonut();

            // Update signal meter if this is the targeted network
            if (targetBssidForSignal === net.bssid) {
                updateSignalMeter(net);
            }
            // Note: Channel graphs are updated in the batched scheduleWifiUIUpdate
        };

        // Update targetNetwork to also set signal meter
        const originalTargetNetwork = targetNetwork;
        targetNetwork = function(bssid, channel) {
            originalTargetNetwork(bssid, channel);

            const net = wifiNetworks[bssid];
            if (net) {
                updateSignalMeter(net);
            }
        };

        // ============== BLUETOOTH RECONNAISSANCE ==============

        let btEventSource = null;
        let btDevices = {};
        let btDeviceCount = 0;
        let btBeaconCount = 0;
        let btRadarCtx = null;
        let btRadarAngle = 0;
        let btRadarAnimFrame = null;
        let btRadarDevices = [];

        // Refresh Bluetooth interfaces
        function refreshBtInterfaces() {
            fetch('/bt/interfaces')
                .then(r => r.json())
                .then(data => {
                    const select = document.getElementById('btInterfaceSelect');
                    if (data.interfaces.length === 0) {
                        select.innerHTML = '<option value="">No BT interfaces found</option>';
                    } else {
                        select.innerHTML = data.interfaces.map(i =>
                            `<option value="${i.name}">${i.name} (${i.type}) [${i.status}]</option>`
                        ).join('');
                    }

                    // Update tool status
                    const statusDiv = document.getElementById('btToolStatus');
                    statusDiv.innerHTML = `
                        <span>hcitool:</span><span class="tool-status ${data.tools.hcitool ? 'ok' : 'missing'}">${data.tools.hcitool ? 'OK' : 'Missing'}</span>
                        <span>bluetoothctl:</span><span class="tool-status ${data.tools.bluetoothctl ? 'ok' : 'missing'}">${data.tools.bluetoothctl ? 'OK' : 'Missing'}</span>
                    `;
                });
        }

        // Start Bluetooth scan
        function startBtScan() {
            const scanMode = document.querySelector('input[name="btScanMode"]:checked').value;
            const iface = document.getElementById('btInterfaceSelect').value;
            const duration = document.getElementById('btScanDuration').value;
            const scanBLE = document.getElementById('btScanBLE').checked;
            const scanClassic = document.getElementById('btScanClassic').checked;

            fetch('/bt/scan/start', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify({
                    mode: scanMode,
                    interface: iface,
                    duration: parseInt(duration),
                    scan_ble: scanBLE,
                    scan_classic: scanClassic
                })
            }).then(r => r.json())
              .then(data => {
                  if (data.status === 'started') {
                      setBtRunning(true);
                      startBtStream();
                  } else {
                      alert('Error: ' + data.message);
                  }
              });
        }

        // Stop Bluetooth scan
        function stopBtScan() {
            fetch('/bt/scan/stop', {method: 'POST'})
                .then(r => r.json())
                .then(data => {
                    setBtRunning(false);
                    if (btEventSource) {
                        btEventSource.close();
                        btEventSource = null;
                    }
                });
        }

        function resetBtAdapter() {
            const iface = document.getElementById('btInterfaceSelect')?.value || 'hci0';
            fetch('/bt/reset', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify({interface: iface})
            }).then(r => r.json())
              .then(data => {
                  setBtRunning(false);
                  if (btEventSource) {
                      btEventSource.close();
                      btEventSource = null;
                  }
                  if (data.status === 'success') {
                      showInfo('Bluetooth adapter reset. Status: ' + (data.is_up ? 'UP' : 'DOWN'));
                      // Refresh interface list
                      if (typeof refreshBtInterfaces === 'function') refreshBtInterfaces();
                  } else {
                      showError('Reset failed: ' + data.message);
                  }
              });
        }

        function setBtRunning(running) {
            isBtRunning = running;
            document.getElementById('statusDot').classList.toggle('running', running);
            document.getElementById('statusText').textContent = running ? 'Scanning...' : 'Idle';
            document.getElementById('startBtBtn').style.display = running ? 'none' : 'block';
            document.getElementById('stopBtBtn').style.display = running ? 'block' : 'none';
        }

        // Batching state for Bluetooth updates
        let pendingBtUpdate = false;
        let pendingBtDevices = [];

        function scheduleBtUIUpdate() {
            if (pendingBtUpdate) return;
            pendingBtUpdate = true;
            requestAnimationFrame(() => {
                // Process devices (limit to 10 per frame)
                const devicesToProcess = pendingBtDevices.slice(0, 10);
                pendingBtDevices = pendingBtDevices.slice(10);

                devicesToProcess.forEach(data => handleBtDeviceImmediate(data));

                // If more pending, schedule another frame
                if (pendingBtDevices.length > 0) {
                    pendingBtUpdate = false;
                    scheduleBtUIUpdate();
                    return;
                }

                pendingBtUpdate = false;
            });
        }

        // Start Bluetooth event stream
        function startBtStream() {
            if (btEventSource) btEventSource.close();

            btEventSource = new EventSource('/bt/stream');

            btEventSource.onmessage = function(e) {
                const data = JSON.parse(e.data);

                if (data.type === 'device') {
                    pendingBtDevices.push(data);
                    scheduleBtUIUpdate();
                } else if (data.type === 'info' || data.type === 'raw') {
                    showInfo(data.text);
                } else if (data.type === 'error') {
                    showError(data.text);
                } else if (data.type === 'status') {
                    if (data.text === 'stopped') {
                        setBtRunning(false);
                    }
                }
            };

            btEventSource.onerror = function() {
                console.error('BT stream error');
            };
        }

        // Tracker following detection
        let trackerHistory = {};  // MAC -> { firstSeen, lastSeen, seenCount, locations: [] }
        const FOLLOWING_THRESHOLD_MINUTES = 30;
        const FOLLOWING_MIN_DETECTIONS = 5;

        // Find My network detection patterns
        const FINDMY_PATTERNS = {
            // Apple Find My / AirTag
            apple: {
                prefixes: ['4C:00'],
                mfgData: [0x004C],  // Apple company ID
                names: ['AirTag', 'Find My']
            },
            // Samsung SmartTag
            samsung: {
                prefixes: ['58:4D', 'A0:75', 'DC:0C', 'E4:5F'],
                mfgData: [0x0075],  // Samsung company ID
                names: ['SmartTag', 'Galaxy SmartTag']
            },
            // Tile
            tile: {
                prefixes: ['C4:E7', 'DC:54', 'E4:B0', 'F8:8A', 'D0:03'],
                names: ['Tile', 'Tile Pro', 'Tile Mate', 'Tile Slim']
            },
            // Chipolo
            chipolo: {
                prefixes: ['00:0D'],
                names: ['Chipolo', 'CHIPOLO']
            }
        };

        function detectFindMyDevice(device) {
            const mac = device.mac.toUpperCase();
            const macPrefix = mac.substring(0, 5);
            const name = (device.name || '').toLowerCase();

            for (const [network, patterns] of Object.entries(FINDMY_PATTERNS)) {
                // Check MAC prefix
                if (patterns.prefixes && patterns.prefixes.some(p => mac.startsWith(p))) {
                    return { network: network, type: 'Find My Network', icon: '📍' };
                }
                // Check name patterns
                if (patterns.names && patterns.names.some(n => name.includes(n.toLowerCase()))) {
                    return { network: network, type: 'Find My Network', icon: '📍' };
                }
            }

            // Check manufacturer data for Apple continuity
            if (device.manufacturer_data) {
                const mfgData = device.manufacturer_data;
                if (mfgData.includes('4c00') || mfgData.includes('004c')) {
                    // Check for Find My payload (manufacturer specific data type 0x12)
                    if (mfgData.includes('12') || mfgData.length > 40) {
                        return { network: 'apple', type: 'Apple Find My', icon: '🍎' };
                    }
                }
            }

            return null;
        }

        function checkTrackerFollowing(device) {
            if (!device.tracker && !detectFindMyDevice(device)) return;

            const mac = device.mac;
            const now = Date.now();

            if (!trackerHistory[mac]) {
                trackerHistory[mac] = {
                    firstSeen: now,
                    lastSeen: now,
                    seenCount: 1,
                    name: device.name || device.mac
                };
            } else {
                trackerHistory[mac].lastSeen = now;
                trackerHistory[mac].seenCount++;
            }

            const tracker = trackerHistory[mac];
            const durationMinutes = (now - tracker.firstSeen) / 60000;

            // Alert if tracker has been following for a while
            if (durationMinutes >= FOLLOWING_THRESHOLD_MINUTES && tracker.seenCount >= FOLLOWING_MIN_DETECTIONS) {
                showTrackerFollowingAlert(mac, tracker);
            }
        }

        function showTrackerFollowingAlert(mac, tracker) {
            const alertDiv = document.getElementById('trackerFollowingAlert');
            if (!alertDiv) return;

            const durationMinutes = Math.floor((Date.now() - tracker.firstSeen) / 60000);

            alertDiv.style.display = 'block';
            alertDiv.innerHTML = `
                <h4>⚠️ POSSIBLE TRACKING DETECTED</h4>
                <div style="font-size: 12px;">
                    <div><strong>Device:</strong> ${escapeHtml(tracker.name)}</div>
                    <div><strong>MAC:</strong> ${escapeHtml(mac)}</div>
                    <div><strong>Duration:</strong> ${durationMinutes} minutes</div>
                    <div><strong>Detections:</strong> ${tracker.seenCount}</div>
                    <div style="margin-top: 10px; color: #ff6666;">
                        This tracker has been detected near you for an extended period.
                        If you don't recognize this device, consider your safety.
                    </div>
                    <button onclick="dismissTrackerAlert('${mac}')" class="preset-btn" style="margin-top: 10px; border-color: #ff4444; color: #ff4444;">
                        Dismiss
                    </button>
                </div>
            `;

            if (!muted) {
                // Play warning sound
                for (let i = 0; i < 3; i++) {
                    setTimeout(() => playAlertSound(), i * 300);
                }
            }

            showNotification('⚠️ Tracking Alert', `${tracker.name} detected for ${durationMinutes} min`);
        }

        function dismissTrackerAlert(mac) {
            document.getElementById('trackerFollowingAlert').style.display = 'none';
            // Reset the tracker history for this device
            if (trackerHistory[mac]) {
                trackerHistory[mac].firstSeen = Date.now();
                trackerHistory[mac].seenCount = 0;
            }
        }

        // Handle discovered Bluetooth device (called from batched update)
        function handleBtDeviceImmediate(device) {
            const isNew = !btDevices[device.mac];

            // Check for Find My network
            const findMyInfo = detectFindMyDevice(device);
            if (findMyInfo) {
                device.findmy = findMyInfo;
                device.tracker = device.tracker || { name: findMyInfo.type };
            }

            // Merge with existing device data to preserve RSSI if not in update
            if (btDevices[device.mac] && !device.rssi && btDevices[device.mac].rssi) {
                device.rssi = btDevices[device.mac].rssi;
            }
            btDevices[device.mac] = device;


            if (isNew) {
                btDeviceCount++;
                document.getElementById('btDeviceCount').textContent = btDeviceCount;
                playAlert();
                pulseSignal();
            }

            // Update selected device panel if this device is selected
            if (selectedBtDevice === device.mac) {
                updateBtSelectedDevice(device);
            }

            // Check for tracker following
            checkTrackerFollowing(device);

            // Track in device intelligence
            trackDevice({
                protocol: 'Bluetooth',
                address: device.mac,
                message: device.name,
                model: device.manufacturer,
                device_type: device.device_type || device.type || 'other'
            });

            // Update visualizations
            addBtDeviceToRadar(device);

            // Add device card
            addBtDeviceCard(device, isNew);

            // Update device list panel
            updateBtDeviceList();

            // Check for trackers and update tracker list
            if (device.tracker || device.findmy) {
                updateBtTrackerList();
            }
        }

        // Currently selected BT device for signal tracking
        let selectedBtDevice = null;

        // Update the Bluetooth device list panel
        function updateBtDeviceList() {
            const listEl = document.getElementById('btDeviceList');
            const countEl = document.getElementById('btListCount');
            if (!listEl) return;

            const devices = Object.values(btDevices);
            countEl.textContent = devices.length;

            if (devices.length === 0) {
                listEl.innerHTML = '<div style="color: var(--text-dim); padding: 10px; text-align: center;">Start scanning to discover devices...</div>';
                return;
            }

            // Sort by RSSI (strongest first)
            devices.sort((a, b) => (b.rssi || -100) - (a.rssi || -100));

            listEl.innerHTML = devices.map(d => {
                const typeIcon = {
                    'phone': '📱', 'audio': '🎧', 'wearable': '⌚', 'tracker': '📍',
                    'computer': '💻', 'input': '⌨️', 'other': '📶'
                }[d.device_type || d.type] || '📶';

                const rssiColor = d.rssi > -50 ? 'var(--accent-green)' :
                                  d.rssi > -70 ? 'var(--accent-cyan)' :
                                  d.rssi > -85 ? 'var(--accent-orange)' : 'var(--accent-red)';

                const isSelected = selectedBtDevice === d.mac;
                const trackerBadge = d.findmy ? `<span style="color:#007aff;font-size:9px;">FindMy</span>` :
                                     d.tracker ? `<span style="color:var(--accent-red);font-size:9px;">Tracker</span>` : '';

                return `
                    <div onclick="selectBtDevice('${d.mac}')" style="
                        padding: 8px;
                        border-bottom: 1px solid rgba(255,255,255,0.05);
                        cursor: pointer;
                        background: ${isSelected ? 'rgba(0,212,255,0.1)' : 'transparent'};
                        border-left: 2px solid ${isSelected ? 'var(--accent-cyan)' : 'transparent'};
                    " onmouseover="this.style.background='rgba(255,255,255,0.05)'" onmouseout="this.style.background='${isSelected ? 'rgba(0,212,255,0.1)' : 'transparent'}'">
                        <div style="display:flex;justify-content:space-between;align-items:center;">
                            <span>${typeIcon} ${escapeHtml(d.name || 'Unknown')}</span>
                            <span style="color:${rssiColor};font-weight:bold;">${d.rssi || '--'} dBm</span>
                        </div>
                        <div style="display:flex;justify-content:space-between;color:var(--text-dim);font-size:10px;margin-top:2px;">
                            <span>${escapeHtml(d.mac)}</span>
                            ${trackerBadge}
                        </div>
                    </div>
                `;
            }).join('');
        }

        // Select a BT device for details
        function selectBtDevice(mac) {
            selectedBtDevice = mac;
            const device = btDevices[mac];
            if (device) {
                document.getElementById('btTargetMac').value = mac;
                updateBtSelectedDevice(device);
            }
            updateBtDeviceList(); // Refresh to show selection
        }

        // Update the selected device details panel
        function updateBtSelectedDevice(device) {
            const panel = document.getElementById('btSelectedDevice');
            if (!panel || !device) return;

            const typeIcon = {
                'phone': '📱', 'audio': '🎧', 'wearable': '⌚', 'tracker': '📍',
                'computer': '💻', 'input': '⌨️', 'other': '📶'
            }[device.device_type || device.type] || '📶';

            const rssiColor = device.rssi > -50 ? 'var(--accent-green)' :
                              device.rssi > -70 ? 'var(--accent-cyan)' :
                              device.rssi > -85 ? 'var(--accent-orange)' : 'var(--accent-red)';

            const signalBars = Math.max(1, Math.min(5, Math.floor((device.rssi + 100) / 10)));
            const barsHtml = Array(5).fill(0).map((_, i) =>
                `<div style="width:4px;height:${8 + i * 4}px;background:${i < signalBars ? rssiColor : 'rgba(255,255,255,0.1)'};border-radius:1px;"></div>`
            ).join('');

            let trackerInfo = '';
            if (device.findmy) {
                trackerInfo = `
                    <div style="background:rgba(0,122,255,0.15);border:1px solid #007aff;border-radius:6px;padding:8px;margin-top:8px;">
                        <div style="color:#007aff;font-weight:bold;">🍎 ${escapeHtml(device.findmy.type)}</div>
                        <div style="color:var(--text-dim);font-size:10px;margin-top:2px;">${escapeHtml(device.findmy.network)} Network Device</div>
                    </div>`;
            } else if (device.tracker) {
                trackerInfo = `
                    <div style="background:rgba(255,100,100,0.15);border:1px solid var(--accent-red);border-radius:6px;padding:8px;margin-top:8px;">
                        <div style="color:var(--accent-red);font-weight:bold;">📍 ${escapeHtml(device.tracker.name)}</div>
                        <div style="color:var(--text-dim);font-size:10px;margin-top:2px;">Tracking Device Detected</div>
                    </div>`;
            }

            panel.innerHTML = `
                <div style="display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:10px;">
                    <div>
                        <div style="font-size:16px;font-weight:bold;color:var(--accent-cyan);">${typeIcon} ${escapeHtml(device.name || 'Unknown Device')}</div>
                        <div style="color:var(--text-dim);font-size:10px;margin-top:2px;">${escapeHtml((device.device_type || device.type || 'unknown').toUpperCase())}</div>
                    </div>
                    <div style="text-align:right;">
                        <div style="font-size:18px;font-weight:bold;color:${rssiColor};">${device.rssi || '--'} dBm</div>
                        <div style="display:flex;gap:2px;justify-content:flex-end;align-items:flex-end;height:24px;margin-top:4px;">${barsHtml}</div>
                    </div>
                </div>
                <div style="display:grid;grid-template-columns:1fr 1fr;gap:6px;">
                    <div style="background:rgba(0,0,0,0.3);padding:6px;border-radius:4px;">
                        <div style="color:var(--text-dim);font-size:9px;">MAC ADDRESS</div>
                        <div style="font-family:monospace;font-size:11px;">${escapeHtml(device.mac)}</div>
                    </div>
                    <div style="background:rgba(0,0,0,0.3);padding:6px;border-radius:4px;">
                        <div style="color:var(--text-dim);font-size:9px;">MANUFACTURER</div>
                        <div style="font-size:11px;">${escapeHtml(device.manufacturer || 'Unknown')}</div>
                    </div>
                    <div style="background:rgba(0,0,0,0.3);padding:6px;border-radius:4px;">
                        <div style="color:var(--text-dim);font-size:9px;">ADDRESS TYPE</div>
                        <div style="font-size:11px;">${escapeHtml(device.address_type || 'Unknown')}</div>
                    </div>
                    <div style="background:rgba(0,0,0,0.3);padding:6px;border-radius:4px;">
                        <div style="color:var(--text-dim);font-size:9px;">LAST SEEN</div>
                        <div style="font-size:11px;">${device.last_seen ? new Date(device.last_seen * 1000).toLocaleTimeString() : 'Now'}</div>
                    </div>
                </div>
                ${trackerInfo}
                <div style="display:flex;gap:6px;margin-top:10px;">
                    <button class="preset-btn" onclick="btEnumServicesFor('${escapeAttr(device.mac)}')" style="flex:1;font-size:10px;padding:6px;">Enumerate Services</button>
                    <button class="preset-btn" onclick="copyToClipboard('${escapeAttr(device.mac)}')" style="flex:1;font-size:10px;padding:6px;">Copy MAC</button>
                </div>
            `;
        }

        // Copy text to clipboard helper
        function copyToClipboard(text) {
            navigator.clipboard.writeText(text).then(() => {
                showNotification('Copied', text);
            }).catch(() => {
                showInfo('Failed to copy to clipboard');
            });
        }

        // Update tracker list panel
        function updateBtTrackerList() {
            const listEl = document.getElementById('btTrackerList');
            if (!listEl) return;

            const trackers = Object.values(btDevices).filter(d => d.tracker || d.findmy);

            if (trackers.length === 0) {
                listEl.innerHTML = '<div style="color: var(--text-dim); padding: 10px; text-align: center;">Monitoring for AirTags, Tiles, and other trackers...</div>';
                return;
            }

            listEl.innerHTML = trackers.map(d => {
                const icon = d.findmy ? '🍎' : '📍';
                const type = d.findmy ? d.findmy.type : (d.tracker ? d.tracker.name : 'Unknown');
                const color = d.findmy ? '#007aff' : 'var(--accent-red)';

                return `
                    <div style="padding: 6px; border-bottom: 1px solid rgba(255,255,255,0.05);">
                        <div style="display:flex;justify-content:space-between;">
                            <span style="color:${color};">${icon} ${escapeHtml(type)}</span>
                            <span style="color:var(--text-dim);">${d.rssi || '--'} dBm</span>
                        </div>
                        <div style="color:var(--text-dim);font-size:10px;">${escapeHtml(d.mac)}</div>
                    </div>
                `;
            }).join('');
        }

        // Add Bluetooth device card to device list panel
        function addBtDeviceCard(device, isNew) {
            // Add to new device list panel
            const deviceList = document.getElementById('btDeviceListContent');
            if (deviceList) {
                // Remove placeholder if present
                const placeholder = deviceList.querySelector('div[style*="text-align: center"]');
                if (placeholder && placeholder.textContent.includes('Start scanning')) {
                    placeholder.remove();
                }

                let card = document.getElementById('btcard_' + device.mac.replace(/:/g, ''));
                const devType = device.device_type || device.type || 'other';

                if (!card) {
                    card = document.createElement('div');
                    card.id = 'btcard_' + device.mac.replace(/:/g, '');
                    card.className = 'sensor-card bt-device-card' +
                                     (device.findmy ? ' findmy' : '') +
                                     (device.tracker && !device.findmy ? ' tracker' : '');
                    card.style.cursor = 'pointer';
                    card.onclick = () => selectBtDevice(device.mac);
                    deviceList.insertBefore(card, deviceList.firstChild);

                    // Update device count
                    const countEl = document.getElementById('btDeviceListCount');
                    if (countEl) countEl.textContent = Object.keys(btDevices).length;
                }

                const typeIcon = {
                    'phone': '📱', 'audio': '🎧', 'wearable': '⌚', 'tracker': '📍',
                    'computer': '💻', 'input': '⌨️', 'other': '📶'
                }[devType] || '📶';

                // Handle signal strength
                const rssi = device.rssi || -100;
                const signalBars = Math.max(0, Math.min(5, Math.floor((rssi + 100) / 15)));
                const signalDisplay = rssi > -100 ? `${rssi} dBm` : 'N/A';

                const findMyBadge = device.findmy
                    ? `<span style="background: #007aff; color: #fff; padding: 2px 6px; border-radius: 3px; font-size: 9px; margin-left: 5px;">${device.findmy.network.toUpperCase()}</span>`
                    : '';

                const trackerBadge = device.tracker && !device.findmy
                    ? `<span style="background: var(--accent-orange); color: #000; padding: 2px 6px; border-radius: 3px; font-size: 9px; margin-left: 5px;">TRACKER</span>`
                    : '';

                card.innerHTML = `
                    <div class="header" style="display: flex; justify-content: space-between; margin-bottom: 8px;">
                        <span class="device-name" style="color: var(--accent-purple);">${typeIcon} ${escapeHtml(device.name || 'Unknown')}${findMyBadge}${trackerBadge}</span>
                        <span style="font-size: 10px; color: var(--text-dim);">${escapeHtml(devType.toUpperCase())}</span>
                    </div>
                    <div class="sensor-data">
                        <div class="data-item">
                            <div class="data-label">MAC</div>
                            <div class="data-value" style="font-size: 11px;">${escapeHtml(device.mac)}</div>
                        </div>
                        <div class="data-item">
                            <div class="data-label">Manufacturer</div>
                            <div class="data-value">${escapeHtml(device.manufacturer || 'Unknown')}</div>
                        </div>
                        <div class="data-item">
                            <div class="data-label">Signal</div>
                            <div class="data-value">${signalDisplay} ${'█'.repeat(signalBars)}${'░'.repeat(5-signalBars)}</div>
                        </div>
                    </div>
                    <div style="margin-top: 8px; display: flex; gap: 5px;">
                        <button class="preset-btn" onclick="event.stopPropagation(); btTargetDevice('${escapeAttr(device.mac)}')" style="font-size: 10px; padding: 4px 8px;">Target</button>
                        <button class="preset-btn" onclick="event.stopPropagation(); btEnumServicesFor('${escapeAttr(device.mac)}')" style="font-size: 10px; padding: 4px 8px;">Services</button>
                    </div>
                `;
            }

            // Update statistics panels
            updateBtStatsPanels();
        }

        // Select a Bluetooth device
        function selectBtDevice(mac) {
            selectedBtDevice = mac;
            const device = btDevices[mac];
            if (device) {
                updateBtSelectedDevice(device);
            }
        }

        // Update Bluetooth statistics panels
        function updateBtStatsPanels() {
            const devices = Object.values(btDevices);

            // Device type counts
            let phones = 0, computers = 0, audio = 0, wearables = 0, other = 0;
            let strong = 0, medium = 0, weak = 0;

            devices.forEach(d => {
                const devType = d.device_type || d.type || 'other';
                if (devType === 'phone') phones++;
                else if (devType === 'computer') computers++;
                else if (devType === 'audio') audio++;
                else if (devType === 'wearable') wearables++;
                else other++;

                const rssi = d.rssi || -100;
                if (rssi >= -50) strong++;
                else if (rssi >= -70) medium++;
                else weak++;
            });

            // Update type counts
            const phoneEl = document.getElementById('btPhoneCount');
            const compEl = document.getElementById('btComputerCount');
            const audioEl = document.getElementById('btAudioCount');
            const wearEl = document.getElementById('btWearableCount');
            const otherEl = document.getElementById('btOtherCount');
            if (phoneEl) phoneEl.textContent = phones;
            if (compEl) compEl.textContent = computers;
            if (audioEl) audioEl.textContent = audio;
            if (wearEl) wearEl.textContent = wearables;
            if (otherEl) otherEl.textContent = other;

            // Update signal distribution
            const total = devices.length || 1;
            const strongBar = document.getElementById('btSignalStrong');
            const mediumBar = document.getElementById('btSignalMedium');
            const weakBar = document.getElementById('btSignalWeak');
            const strongCount = document.getElementById('btSignalStrongCount');
            const mediumCount = document.getElementById('btSignalMediumCount');
            const weakCount = document.getElementById('btSignalWeakCount');

            if (strongBar) strongBar.style.width = (strong / total * 100) + '%';
            if (mediumBar) mediumBar.style.width = (medium / total * 100) + '%';
            if (weakBar) weakBar.style.width = (weak / total * 100) + '%';
            if (strongCount) strongCount.textContent = strong;
            if (mediumCount) mediumCount.textContent = medium;
            if (weakCount) weakCount.textContent = weak;

            // Update FindMy list
            updateBtFindMyList();
        }

        // Update FindMy device list
        function updateBtFindMyList() {
            const listEl = document.getElementById('btFindMyList');
            if (!listEl) return;

            const findMyDevices = Object.values(btDevices).filter(d => d.findmy);

            if (findMyDevices.length === 0) {
                listEl.innerHTML = '<div style="color: var(--text-dim); padding: 10px; text-align: center;">Scanning for FindMy-compatible devices...</div>';
                return;
            }

            listEl.innerHTML = findMyDevices.map(d => `
                <div style="display: flex; justify-content: space-between; padding: 5px 8px; background: rgba(0,122,255,0.1); border-radius: 3px; margin-bottom: 4px; cursor: pointer;" onclick="selectBtDevice('${escapeAttr(d.mac)}')">
                    <span>${d.findmy.icon || '📍'} ${escapeHtml(d.name || d.findmy.type)}</span>
                    <span style="color: #007aff;">${d.rssi || '--'} dBm</span>
                </div>
            `).join('');
        }

        // Target a Bluetooth device
        function btTargetDevice(mac) {
            document.getElementById('btTargetMac').value = mac;
            showInfo('Targeted: ' + mac);
        }

        // Enumerate services for a device
        function btEnumServicesFor(mac) {
            document.getElementById('btTargetMac').value = mac;
            btEnumServices();
        }

        // Enumerate services
        function btEnumServices() {
            const mac = document.getElementById('btTargetMac').value;
            if (!mac) { alert('Enter target MAC'); return; }

            showInfo('Enumerating services for ' + mac + '...');

            fetch('/bt/enum', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify({mac: mac})
            }).then(r => r.json())
              .then(data => {
                  if (data.status === 'success') {
                      let msg = 'Services for ' + mac + ': ';
                      if (data.services.length === 0) {
                          msg += 'None found';
                      } else {
                          msg += data.services.map(s => s.name).join(', ');
                      }
                      showInfo(msg);
                  } else {
                      showInfo('Error: ' + data.message);
                  }
              });
        }

        // Initialize Bluetooth radar
        function initBtRadar() {
            const canvas = document.getElementById('btRadarCanvas');
            if (!canvas) return;

            btRadarCtx = canvas.getContext('2d');
            canvas.width = 150;
            canvas.height = 150;

            if (!btRadarAnimFrame) {
                animateBtRadar();
            }
        }

        // Animate Bluetooth radar
        function animateBtRadar() {
            if (!btRadarCtx) { btRadarAnimFrame = null; return; }

            const canvas = btRadarCtx.canvas;
            const cx = canvas.width / 2;
            const cy = canvas.height / 2;
            const radius = Math.min(cx, cy) - 5;

            btRadarCtx.fillStyle = 'rgba(0, 10, 20, 0.1)';
            btRadarCtx.fillRect(0, 0, canvas.width, canvas.height);

            // Grid circles
            btRadarCtx.strokeStyle = 'rgba(138, 43, 226, 0.2)';
            btRadarCtx.lineWidth = 1;
            for (let r = radius / 4; r <= radius; r += radius / 4) {
                btRadarCtx.beginPath();
                btRadarCtx.arc(cx, cy, r, 0, Math.PI * 2);
                btRadarCtx.stroke();
            }

            // Sweep line (purple for BT)
            btRadarCtx.strokeStyle = 'rgba(138, 43, 226, 0.8)';
            btRadarCtx.lineWidth = 2;
            btRadarCtx.beginPath();
            btRadarCtx.moveTo(cx, cy);
            btRadarCtx.lineTo(cx + Math.cos(btRadarAngle) * radius, cy + Math.sin(btRadarAngle) * radius);
            btRadarCtx.stroke();

            // Device blips
            btRadarDevices.forEach(dev => {
                const age = Date.now() - dev.timestamp;
                const alpha = Math.max(0.1, 1 - age / 15000);
                const color = dev.isTracker ? '255, 51, 102' : '138, 43, 226';

                btRadarCtx.fillStyle = `rgba(${color}, ${alpha})`;
                btRadarCtx.beginPath();
                btRadarCtx.arc(dev.x, dev.y, dev.isTracker ? 6 : 4, 0, Math.PI * 2);
                btRadarCtx.fill();
            });

            btRadarAngle += 0.025;
            if (btRadarAngle > Math.PI * 2) btRadarAngle = 0;

            btRadarAnimFrame = requestAnimationFrame(animateBtRadar);
        }

        // Add device to BT radar
        function addBtDeviceToRadar(device) {
            const canvas = document.getElementById('btRadarCanvas');
            if (!canvas) return;

            const cx = canvas.width / 2;
            const cy = canvas.height / 2;
            const radius = Math.min(cx, cy) - 10;

            // Random position based on MAC hash
            let angle = 0;
            for (let i = 0; i < device.mac.length; i++) {
                angle += device.mac.charCodeAt(i);
            }
            angle = (angle % 360) * Math.PI / 180;
            const r = radius * (0.3 + Math.random() * 0.6);

            const x = cx + Math.cos(angle) * r;
            const y = cy + Math.sin(angle) * r;

            const existing = btRadarDevices.find(d => d.mac === device.mac);
            if (existing) {
                existing.timestamp = Date.now();
            } else {
                btRadarDevices.push({
                    x, y,
                    mac: device.mac,
                    isTracker: !!device.tracker,
                    timestamp: Date.now()
                });
            }

            if (btRadarDevices.length > 50) btRadarDevices.shift();
        }

        // ============================================
        // APRS Functions
        // ============================================
        let aprsMap = null;
        let aprsMarkers = {};
        let aprsEventSource = null;
        let isAprsRunning = false;
        let aprsPacketCount = 0;
        let aprsStationCount = 0;
        let aprsMeterLastUpdate = 0;
        let aprsMeterCheckInterval = null;
        const APRS_METER_TIMEOUT = 5000; // 5 seconds for "no signal" state

        function checkAprsTools() {
            fetch('/aprs/tools')
                .then(r => r.json())
                .then(data => {
                    // Update function bar tool indicators
                    const direwolfEl = document.getElementById('aprsStripDirewolf');
                    const multimonEl = document.getElementById('aprsStripMultimon');

                    if (direwolfEl) {
                        direwolfEl.className = 'strip-tool' + (data.direwolf ? ' ok' : '');
                        direwolfEl.title = 'direwolf: ' + (data.direwolf ? 'OK' : 'Missing');
                    }
                    if (multimonEl) {
                        multimonEl.className = 'strip-tool' + (data.multimon_ng ? ' ok' : '');
                        multimonEl.title = 'multimon-ng: ' + (data.multimon_ng ? 'OK' : 'Missing');
                    }
                })
                .catch(() => {
                    const direwolfEl = document.getElementById('aprsStripDirewolf');
                    const multimonEl = document.getElementById('aprsStripMultimon');
                    if (direwolfEl) {
                        direwolfEl.className = 'strip-tool';
                        direwolfEl.title = 'direwolf: Error';
                    }
                    if (multimonEl) {
                        multimonEl.className = 'strip-tool';
                        multimonEl.title = 'multimon-ng: Error';
                    }
                });
        }

        function initAprsMap() {
            if (aprsMap) return;

            const mapContainer = document.getElementById('aprsMap');
            if (!mapContainer) return;

            aprsMap = L.map('aprsMap').setView([39.8283, -98.5795], 4);

            L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
                attribution: '&copy; OpenStreetMap contributors &copy; CARTO',
                maxZoom: 19
            }).addTo(aprsMap);

            // Update time display (both map header and function bar)
            setInterval(() => {
                const now = new Date();
                const timeStr = now.toLocaleTimeString('en-US', {hour12: false});
                const utcStr = now.toUTCString().slice(17, 25) + ' UTC';

                const timeEl = document.getElementById('aprsMapTime');
                if (timeEl) timeEl.textContent = timeStr;

                const stripTimeEl = document.getElementById('aprsStripTime');
                if (stripTimeEl) stripTimeEl.textContent = utcStr;
            }, 1000);
        }

        function updateAprsStatus(state, freq) {
            // Update function bar status
            const stripDot = document.getElementById('aprsStripDot');
            const stripStatus = document.getElementById('aprsStripStatus');
            const stripFreq = document.getElementById('aprsStripFreq');

            if (stripDot) {
                stripDot.className = 'status-dot ' + state;
            }
            if (stripStatus) {
                stripStatus.textContent = state.toUpperCase();
                if (state === 'listening') {
                    stripStatus.style.color = 'var(--accent-cyan)';
                } else if (state === 'tracking') {
                    stripStatus.style.color = 'var(--accent-green)';
                } else if (state === 'error') {
                    stripStatus.style.color = 'var(--accent-red)';
                } else {
                    stripStatus.style.color = '';
                }
            }
            if (freq && stripFreq) {
                stripFreq.textContent = freq;
            }
        }

        function startAprs() {
            // Get values from function bar controls
            const region = document.getElementById('aprsStripRegion').value;
            const device = getSelectedDevice();
            const gain = document.getElementById('aprsStripGain').value;

            fetch('/aprs/start', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ region, device: parseInt(device), gain: parseInt(gain) })
            })
            .then(r => r.json())
            .then(data => {
                if (data.status === 'started') {
                    isAprsRunning = true;
                    aprsPacketCount = 0;
                    aprsStationCount = 0;
                    // Update function bar buttons
                    document.getElementById('aprsStripStartBtn').style.display = 'none';
                    document.getElementById('aprsStripStopBtn').style.display = 'inline-block';
                    // Update map status
                    document.getElementById('aprsMapStatus').textContent = 'TRACKING';
                    document.getElementById('aprsMapStatus').style.color = 'var(--accent-green)';
                    // Update function bar status
                    updateAprsStatus('listening', data.frequency);
                    // Reset function bar stats
                    document.getElementById('aprsStripStations').textContent = '0';
                    document.getElementById('aprsStripPackets').textContent = '0';
                    document.getElementById('aprsStripSignal').textContent = '--';
                    // Disable controls while running
                    document.getElementById('aprsStripRegion').disabled = true;
                    document.getElementById('aprsStripGain').disabled = true;
                    startAprsMeterCheck();
                    startAprsStream();
                } else {
                    alert('APRS Error: ' + data.message);
                    updateAprsStatus('error');
                }
            })
            .catch(err => {
                alert('APRS Error: ' + err);
                updateAprsStatus('error');
            });
        }

        function stopAprs() {
            fetch('/aprs/stop', { method: 'POST' })
                .then(r => r.json())
                .then(data => {
                    isAprsRunning = false;
                    // Update function bar buttons
                    document.getElementById('aprsStripStartBtn').style.display = 'inline-block';
                    document.getElementById('aprsStripStopBtn').style.display = 'none';
                    // Update map status
                    document.getElementById('aprsMapStatus').textContent = 'STANDBY';
                    document.getElementById('aprsMapStatus').style.color = '';
                    // Reset function bar status
                    updateAprsStatus('standby');
                    document.getElementById('aprsStripFreq').textContent = '--';
                    document.getElementById('aprsStripSignal').textContent = '--';
                    // Re-enable controls
                    document.getElementById('aprsStripRegion').disabled = false;
                    document.getElementById('aprsStripGain').disabled = false;
                    // Remove signal quality class
                    const signalStat = document.getElementById('aprsStripSignalStat');
                    if (signalStat) {
                        signalStat.classList.remove('good', 'warning', 'poor');
                    }
                    // Stop meter check interval
                    stopAprsMeterCheck();
                    if (aprsEventSource) {
                        aprsEventSource.close();
                        aprsEventSource = null;
                    }
                });
        }

        function startAprsStream() {
            if (aprsEventSource) aprsEventSource.close();
            aprsEventSource = new EventSource('/aprs/stream');

            aprsEventSource.onmessage = function(e) {
                const data = JSON.parse(e.data);
                if (data.type === 'aprs') {
                    aprsPacketCount++;
                    // Update map footer and function bar
                    document.getElementById('aprsPacketCount').textContent = aprsPacketCount;
                    document.getElementById('aprsStripPackets').textContent = aprsPacketCount;
                    // Switch to tracking state on first packet
                    const dot = document.getElementById('aprsStripDot');
                    if (dot && !dot.classList.contains('tracking')) {
                        updateAprsStatus('tracking');
                    }
                    processAprsPacket(data);
                } else if (data.type === 'meter') {
                    // Update signal indicator in function bar
                    updateAprsMeter(data.level);
                }
            };

            aprsEventSource.onerror = function() {
                console.error('APRS stream error');
                updateAprsStatus('error');
            };
        }

        // Signal Meter Functions
        function resetAprsMeter() {
            aprsMeterLastUpdate = 0;
            // Reset function bar signal indicator
            const signalEl = document.getElementById('aprsStripSignal');
            const signalStat = document.getElementById('aprsStripSignalStat');
            if (signalEl) signalEl.textContent = '--';
            if (signalStat) signalStat.classList.remove('good', 'warning', 'poor');
        }

        function updateAprsMeter(level) {
            aprsMeterLastUpdate = Date.now();

            // Update function bar signal indicator
            const signalEl = document.getElementById('aprsStripSignal');
            const signalStat = document.getElementById('aprsStripSignalStat');

            if (signalEl) {
                // Show signal level as bars
                if (level >= 60) {
                    signalEl.textContent = '●●●';
                } else if (level >= 30) {
                    signalEl.textContent = '●●○';
                } else if (level >= 10) {
                    signalEl.textContent = '●○○';
                } else {
                    signalEl.textContent = '○○○';
                }
            }

            if (signalStat) {
                signalStat.classList.remove('good', 'warning', 'poor');
                if (level >= 60) {
                    signalStat.classList.add('good');
                } else if (level >= 30) {
                    signalStat.classList.add('warning');
                } else {
                    signalStat.classList.add('poor');
                }
            }
        }

        function startAprsMeterCheck() {
            // Check for no-signal state every second
            aprsMeterCheckInterval = setInterval(function() {
                if (aprsMeterLastUpdate > 0 && (Date.now() - aprsMeterLastUpdate) > APRS_METER_TIMEOUT) {
                    // No meter updates for 5 seconds - show no-signal state
                    const signalEl = document.getElementById('aprsStripSignal');
                    const signalStat = document.getElementById('aprsStripSignalStat');
                    if (signalEl) signalEl.textContent = '○○○';
                    if (signalStat) {
                        signalStat.classList.remove('good', 'warning');
                        signalStat.classList.add('poor');
                    }
                }
            }, 1000);
        }

        function stopAprsMeterCheck() {
            if (aprsMeterCheckInterval) {
                clearInterval(aprsMeterCheckInterval);
                aprsMeterCheckInterval = null;
            }
        }

        function processAprsPacket(packet) {
            // Update packet log
            const logEl = document.getElementById('aprsPacketLog');
            const logEntry = document.createElement('div');
            logEntry.style.cssText = 'padding: 3px 0; border-bottom: 1px solid var(--border-color);';

            const time = new Date().toLocaleTimeString('en-US', {hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit'});
            const callsign = packet.callsign || 'UNKNOWN';
            const packetType = packet.packet_type || 'unknown';

            logEntry.innerHTML = `<span style="color: var(--text-muted);">${time}</span> <span style="color: var(--accent-cyan); font-weight: bold;">${callsign}</span> <span style="color: var(--accent-green);">[${packetType}]</span>`;

            // Remove placeholder if present
            const placeholder = logEl.querySelector('div[style*="color: var(--text-muted)"]');
            if (placeholder && placeholder.textContent.includes('Waiting')) {
                placeholder.remove();
            }

            logEl.insertBefore(logEntry, logEl.firstChild);

            // Keep log manageable
            while (logEl.children.length > 100) {
                logEl.removeChild(logEl.lastChild);
            }

            // Update map if position data
            if (packet.lat && packet.lon && aprsMap) {
                updateAprsMarker(packet);
            }

            // Update station list
            updateAprsStationList(packet);
        }

        function updateAprsMarker(packet) {
            const callsign = packet.callsign;

            if (aprsMarkers[callsign]) {
                // Update existing marker
                aprsMarkers[callsign].setLatLng([packet.lat, packet.lon]);
            } else {
                // Create new marker
                aprsStationCount++;
                // Update map footer and function bar
                document.getElementById('aprsStationCount').textContent = aprsStationCount;
                document.getElementById('aprsStripStations').textContent = aprsStationCount;

                const icon = L.divIcon({
                    className: 'aprs-marker',
                    html: `<div style="background: var(--accent-cyan); color: #000; padding: 2px 6px; border-radius: 3px; font-size: 10px; font-weight: bold; white-space: nowrap;">${callsign}</div>`,
                    iconSize: [80, 20],
                    iconAnchor: [40, 10]
                });

                const marker = L.marker([packet.lat, packet.lon], { icon: icon }).addTo(aprsMap);

                marker.bindPopup(`
                    <div style="font-family: monospace;">
                        <strong>${callsign}</strong><br>
                        Position: ${packet.lat.toFixed(4)}, ${packet.lon.toFixed(4)}<br>
                        ${packet.altitude ? `Altitude: ${packet.altitude} ft<br>` : ''}
                        ${packet.speed ? `Speed: ${packet.speed} kts<br>` : ''}
                        ${packet.course ? `Course: ${packet.course}°<br>` : ''}
                    </div>
                `);

                aprsMarkers[callsign] = marker;
            }
        }

        function updateAprsStationList(packet) {
            const listEl = document.getElementById('aprsStationList');
            const callsign = packet.callsign;

            // Remove placeholder if present
            const placeholder = listEl.querySelector('div[style*="text-align: center"]');
            if (placeholder && placeholder.textContent.includes('No stations')) {
                placeholder.remove();
            }

            // Check if station already exists
            let stationEl = listEl.querySelector(`[data-callsign="${callsign}"]`);

            if (!stationEl) {
                stationEl = document.createElement('div');
                stationEl.dataset.callsign = callsign;
                stationEl.style.cssText = 'padding: 6px 8px; border-bottom: 1px solid var(--border-color); cursor: pointer;';
                stationEl.onclick = () => {
                    if (aprsMarkers[callsign] && aprsMap) {
                        aprsMap.setView(aprsMarkers[callsign].getLatLng(), 10);
                        aprsMarkers[callsign].openPopup();
                    }
                };
                listEl.insertBefore(stationEl, listEl.firstChild);
            }

            const time = new Date().toLocaleTimeString('en-US', {hour12: false, hour: '2-digit', minute: '2-digit'});
            const hasPos = packet.lat && packet.lon;

            stationEl.innerHTML = `
                <div style="display: flex; justify-content: space-between; align-items: center;">
                    <span style="color: var(--accent-cyan); font-weight: bold;">${callsign}</span>
                    <span style="font-size: 9px; color: var(--text-muted);">${time}</span>
                </div>
                <div style="font-size: 9px; color: var(--text-secondary); margin-top: 2px;">
                    ${packet.packet_type || 'unknown'} ${hasPos ? `| ${packet.lat.toFixed(2)}, ${packet.lon.toFixed(2)}` : ''}
                </div>
            `;

            // Keep list manageable
            while (listEl.children.length > 50) {
                listEl.removeChild(listEl.lastChild);
            }
        }


        // ============================================
        // SATELLITE MODE FUNCTIONS
        // ============================================

        function getLocation() {
            if (navigator.geolocation) {
                navigator.geolocation.getCurrentPosition(
                    position => {
                        document.getElementById('obsLat').value = position.coords.latitude.toFixed(4);
                        document.getElementById('obsLon').value = position.coords.longitude.toFixed(4);
                        showInfo('Location updated!');
                    },
                    error => {
                        alert('Could not get location: ' + error.message);
                    }
                );
            } else {
                alert('Geolocation not supported by browser');
            }
        }

        // ============================================
        // GPS FUNCTIONS (gpsd auto-connect)
        // ============================================

        async function autoConnectGps() {
            // Automatically try to connect to gpsd on page load
            try {
                const response = await fetch('/gps/auto-connect', { method: 'POST' });
                const data = await response.json();

                if (data.status === 'connected') {
                    gpsConnected = true;
                    startGpsStream();
                    showGpsIndicator(true);
                    console.log('GPS: Auto-connected to gpsd');
                    if (data.position) {
                        updateLocationFromGps(data.position);
                    }
                } else {
                    console.log('GPS: gpsd not available -', data.message);
                }
            } catch (e) {
                console.log('GPS: Auto-connect failed -', e.message);
            }
        }

        let gpsReconnectTimeout = null;

        function startGpsStream() {
            if (gpsEventSource) {
                gpsEventSource.close();
            }
            if (gpsReconnectTimeout) {
                clearTimeout(gpsReconnectTimeout);
                gpsReconnectTimeout = null;
            }

            gpsEventSource = new EventSource('/gps/stream');
            gpsEventSource.onmessage = (event) => {
                try {
                    const data = JSON.parse(event.data);
                    if (data.type === 'position') {
                        gpsLastPosition = data;
                        updateLocationFromGps(data);
                    }
                } catch (e) {
                    console.error('GPS parse error:', e);
                }
            };
            gpsEventSource.onerror = (e) => {
                // Don't log every error - connection suspends are normal
                if (gpsEventSource) {
                    gpsEventSource.close();
                    gpsEventSource = null;
                }
                // Auto-reconnect after 5 seconds if still connected
                if (gpsConnected && !gpsReconnectTimeout) {
                    gpsReconnectTimeout = setTimeout(() => {
                        gpsReconnectTimeout = null;
                        if (gpsConnected) {
                            startGpsStream();
                        }
                    }, 5000);
                }
            };
        }

        // Reconnect GPS stream when tab becomes visible
        document.addEventListener('visibilitychange', () => {
            if (!document.hidden && gpsConnected && !gpsEventSource) {
                startGpsStream();
            }
        });

        function updateLocationFromGps(position) {
            if (!position || !position.latitude || !position.longitude) {
                return;
            }

            // Update satellite observer location
            const satLatInput = document.getElementById('obsLat');
            const satLonInput = document.getElementById('obsLon');
            if (satLatInput) satLatInput.value = position.latitude.toFixed(4);
            if (satLonInput) satLonInput.value = position.longitude.toFixed(4);

            // Update observerLocation
            observerLocation.lat = position.latitude;
            observerLocation.lon = position.longitude;
        }

        function showGpsIndicator(show) {
            // Show/hide all GPS indicators (by class and by ID)
            document.querySelectorAll('.gps-indicator').forEach(el => {
                el.style.display = show ? 'inline-flex' : 'none';
            });
            // Also target specific IDs in case class selector doesn't work
            ['satGpsIndicator'].forEach(id => {
                const el = document.getElementById(id);
                if (el) el.style.display = show ? 'inline-flex' : 'none';
            });
        }

        function initPolarPlot() {
            const canvas = document.getElementById('polarPlotCanvas');
            if (!canvas) return;
            const container = canvas.parentElement;
            const size = Math.min(container.offsetWidth, 400);
            canvas.width = size;
            canvas.height = size;
            drawPolarPlot();
        }

        function drawPolarPlot(pass = null) {
            const canvas = document.getElementById('polarPlotCanvas');
            if (!canvas) return;
            const ctx = canvas.getContext('2d');
            const size = canvas.width;
            const cx = size / 2;
            const cy = size / 2;
            const radius = size / 2 - 30;

            // Clear
            ctx.fillStyle = '#0a0a0a';
            ctx.fillRect(0, 0, size, size);

            // Draw elevation rings
            ctx.strokeStyle = 'rgba(0, 255, 255, 0.2)';
            ctx.lineWidth = 1;
            for (let el = 0; el <= 90; el += 30) {
                const r = radius * (90 - el) / 90;
                ctx.beginPath();
                ctx.arc(cx, cy, r, 0, Math.PI * 2);
                ctx.stroke();

                // Label
                if (el > 0) {
                    ctx.fillStyle = '#444';
                    ctx.font = '10px JetBrains Mono';
                    ctx.textAlign = 'center';
                    ctx.fillText(el + '°', cx, cy - r + 12);
                }
            }

            // Draw azimuth lines
            for (let az = 0; az < 360; az += 45) {
                const rad = az * Math.PI / 180;
                ctx.beginPath();
                ctx.moveTo(cx, cy);
                ctx.lineTo(cx + Math.sin(rad) * radius, cy - Math.cos(rad) * radius);
                ctx.stroke();
            }

            // Draw cardinal directions
            ctx.fillStyle = '#00ffff';
            ctx.font = 'bold 14px Rajdhani';
            ctx.textAlign = 'center';
            ctx.fillText('N', cx, cy - radius - 8);
            ctx.fillStyle = '#888';
            ctx.fillText('S', cx, cy + radius + 16);
            ctx.fillText('E', cx + radius + 12, cy + 4);
            ctx.fillText('W', cx - radius - 12, cy + 4);

            // Draw zenith
            ctx.fillStyle = '#00ffff';
            ctx.beginPath();
            ctx.arc(cx, cy, 3, 0, Math.PI * 2);
            ctx.fill();

            // Draw selected pass trajectory
            if (pass && pass.trajectory) {
                ctx.strokeStyle = pass.color || '#00ff00';
                ctx.lineWidth = 2;
                ctx.setLineDash([5, 3]);
                ctx.beginPath();

                pass.trajectory.forEach((point, i) => {
                    // Backend returns 'el' and 'az' properties
                    const el = point.el !== undefined ? point.el : point.elevation;
                    const az = point.az !== undefined ? point.az : point.azimuth;
                    const r = radius * (90 - el) / 90;
                    const rad = az * Math.PI / 180;
                    const x = cx + Math.sin(rad) * r;
                    const y = cy - Math.cos(rad) * r;

                    if (i === 0) ctx.moveTo(x, y);
                    else ctx.lineTo(x, y);
                });
                ctx.stroke();
                ctx.setLineDash([]);

                // Draw max elevation point
                const maxPoint = pass.trajectory.reduce((max, p) => {
                    const pEl = p.el !== undefined ? p.el : p.elevation;
                    const maxEl = max.el !== undefined ? max.el : max.elevation;
                    return pEl > maxEl ? p : max;
                }, { el: 0, elevation: 0 });
                const maxEl = maxPoint.el !== undefined ? maxPoint.el : maxPoint.elevation;
                const maxAz = maxPoint.az !== undefined ? maxPoint.az : maxPoint.azimuth;
                const maxR = radius * (90 - maxEl) / 90;
                const maxRad = maxAz * Math.PI / 180;
                const maxX = cx + Math.sin(maxRad) * maxR;
                const maxY = cy - Math.cos(maxRad) * maxR;

                ctx.fillStyle = pass.color || '#00ff00';
                ctx.beginPath();
                ctx.arc(maxX, maxY, 6, 0, Math.PI * 2);
                ctx.fill();

                // Label
                ctx.fillStyle = '#fff';
                ctx.font = '11px JetBrains Mono';
                ctx.fillText(pass.satellite, maxX + 10, maxY - 5);
            }
        }

        function calculatePasses() {
            const lat = parseFloat(document.getElementById('obsLat').value);
            const lon = parseFloat(document.getElementById('obsLon').value);
            const hours = parseInt(document.getElementById('predictionHours').value);
            const minEl = parseInt(document.getElementById('minElevation').value);

            const satellites = getSelectedSatellites();

            if (satellites.length === 0) {
                alert('Please select at least one satellite to track');
                return;
            }

            fetch('/satellite/predict', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ lat, lon, hours, minEl, satellites })
            })
            .then(r => r.json())
            .then(data => {
                if (data.status === 'success') {
                    satellitePasses = data.passes;
                    renderPassList();
                    document.getElementById('passCount').textContent = data.passes.length;
                    if (data.passes.length > 0) {
                        selectPass(0);
                        document.getElementById('satelliteCountdown').style.display = 'block';
                        updateSatelliteCountdown();
                        startCountdownTimer();
                    } else {
                        document.getElementById('satelliteCountdown').style.display = 'none';
                    }
                } else {
                    alert('Error: ' + data.message);
                }
            });
        }

        function renderPassList() {
            const container = document.getElementById('passList');
            container.innerHTML = '';

            if (satellitePasses.length === 0) {
                container.innerHTML = '<div style="color: #666; text-align: center; padding: 30px;">No passes found for selected criteria.</div>';
                return;
            }

            document.getElementById('passListCount').textContent = satellitePasses.length + ' passes';

            satellitePasses.forEach((pass, index) => {
                const card = document.createElement('div');
                card.className = 'pass-card' + (index === 0 ? ' active' : '');
                card.onclick = () => selectPass(index);

                const quality = pass.maxEl >= 60 ? 'excellent' : pass.maxEl >= 30 ? 'good' : 'fair';

                card.innerHTML = `
                    <div class="pass-satellite">${pass.satellite}</div>
                    <div class="pass-time">${pass.startTime}</div>
                    <div class="pass-details">
                        <div>Max El: <span>${pass.maxEl}°</span></div>
                        <div>Duration: <span>${pass.duration}m</span></div>
                        <div class="pass-quality ${quality}">${quality.toUpperCase()}</div>
                    </div>
                `;
                container.appendChild(card);
            });
        }

        function selectPass(index) {
            selectedPass = satellitePasses[index];
            selectedPassIndex = index;
            document.querySelectorAll('.pass-card').forEach((card, i) => {
                card.classList.toggle('active', i === index);
            });
            drawPolarPlot(selectedPass);
            updateGroundTrack(selectedPass);
            // Update countdown to show selected pass
            updateSatelliteCountdown();
            // Start real-time position updates for full orbit track
            startSatellitePositionUpdates();
            // Fetch position immediately
            updateRealTimePosition();
        }

        // Ground Track Map
        let groundTrackMap = null;
        let groundTrackLine = null;
        let satMarker = null;
        let observerMarker = null;
        let satPositionInterval = null;

        function initGroundTrackMap() {
            const mapContainer = document.getElementById('groundTrackMap');
            if (!mapContainer || groundTrackMap) return;

            groundTrackMap = L.map('groundTrackMap', {
                center: [20, 0],
                zoom: 1,
                zoomControl: true,
                attributionControl: false
            });

            L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
                maxZoom: 19,
                attribution: '© OpenStreetMap contributors'
            }).addTo(groundTrackMap);

            // Add observer marker
            const lat = parseFloat(document.getElementById('obsLat').value) || 51.5;
            const lon = parseFloat(document.getElementById('obsLon').value) || -0.1;
            observerMarker = L.circleMarker([lat, lon], {
                radius: 8,
                fillColor: '#ff6600',
                color: '#fff',
                weight: 2,
                fillOpacity: 1
            }).addTo(groundTrackMap).bindPopup('Observer Location');
        }

        function updateGroundTrack(pass) {
            if (!groundTrackMap) initGroundTrackMap();
            if (!pass || !pass.groundTrack) return;

            // Remove old track and marker
            if (groundTrackLine) {
                groundTrackMap.removeLayer(groundTrackLine);
                groundTrackLine = null;
            }
            if (satMarker) {
                groundTrackMap.removeLayer(satMarker);
                satMarker = null;
            }
            if (orbitTrackLine) {
                groundTrackMap.removeLayer(orbitTrackLine);
                orbitTrackLine = null;
            }
            if (pastOrbitLine) {
                groundTrackMap.removeLayer(pastOrbitLine);
                pastOrbitLine = null;
            }

            // Split ground track only at true antimeridian crossings (±180° line)
            const segments = [];
            let currentSegment = [];
            for (let i = 0; i < pass.groundTrack.length; i++) {
                const p = pass.groundTrack[i];
                if (currentSegment.length > 0) {
                    const prevLon = currentSegment[currentSegment.length - 1][1];
                    // Only split when crossing the antimeridian (one side > 90, other < -90)
                    const crossesAntimeridian = (prevLon > 90 && p.lon < -90) || (prevLon < -90 && p.lon > 90);
                    if (crossesAntimeridian) {
                        if (currentSegment.length >= 1) segments.push(currentSegment);
                        currentSegment = [];
                    }
                }
                currentSegment.push([p.lat, p.lon]);
            }
            if (currentSegment.length >= 1) segments.push(currentSegment);

            // Draw ground track segments
            groundTrackLine = L.layerGroup();
            const allCoords = [];
            segments.forEach(seg => {
                L.polyline(seg, {
                    color: pass.color || '#00ff00',
                    weight: 2,
                    opacity: 0.8,
                    dashArray: '5, 5'
                }).addTo(groundTrackLine);
                allCoords.push(...seg);
            });
            groundTrackLine.addTo(groundTrackMap);

            // Add current position marker
            if (pass.currentPosition) {
                satMarker = L.marker([pass.currentPosition.lat, pass.currentPosition.lon], {
                    icon: L.divIcon({
                        className: 'sat-marker',
                        html: '<div style="background:#ffff00;width:12px;height:12px;border-radius:50%;border:2px solid #000;box-shadow:0 0 10px #ffff00;"></div>',
                        iconSize: [12, 12],
                        iconAnchor: [6, 6]
                    })
                }).addTo(groundTrackMap).bindPopup(pass.satellite);
            }

            // Update observer marker position
            const lat = parseFloat(document.getElementById('obsLat').value) || 51.5;
            const lon = parseFloat(document.getElementById('obsLon').value) || -0.1;
            if (observerMarker) {
                observerMarker.setLatLng([lat, lon]);
            }

            // Fit bounds to show track
            if (allCoords.length > 0) {
                groundTrackMap.fitBounds(L.latLngBounds(allCoords), { padding: [20, 20] });
            }
        }

        function toggleGroundTrack() {
            const show = document.getElementById('showGroundTrack').checked;
            document.getElementById('groundTrackMap').style.display = show ? 'block' : 'none';
            if (show && groundTrackMap) {
                groundTrackMap.invalidateSize();
            }
        }

        function startSatellitePositionUpdates() {
            if (satPositionInterval) clearInterval(satPositionInterval);
            satPositionInterval = setInterval(() => {
                if (selectedPass) {
                    updateRealTimePosition();
                }
            }, 5000);
        }

        function updateRealTimePosition() {
            let satellites = getSelectedSatellites();

            // Ensure selected pass's satellite is included in the request
            if (selectedPass && selectedPass.satellite) {
                if (!satellites.includes(selectedPass.satellite)) {
                    satellites = [selectedPass.satellite, ...satellites];
                }
            }

            if (satellites.length === 0) return;

            const lat = parseFloat(document.getElementById('obsLat').value);
            const lon = parseFloat(document.getElementById('obsLon').value);

            fetch('/satellite/position', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ lat, lon, satellites, includeTrack: true })
            })
            .then(r => r.json())
            .then(data => {
                if (data.status === 'success' && data.positions) {
                    updateRealTimeIndicators(data.positions);
                }
            });
        }

        let orbitTrackLine = null;
        let pastOrbitLine = null;

        function updateRealTimeIndicators(positions) {
            // Update ground track map markers
            positions.forEach(pos => {
                if (selectedPass && pos.satellite === selectedPass.satellite) {
                    // Update satellite marker position
                    if (satMarker) {
                        satMarker.setLatLng([pos.lat, pos.lon]);
                        satMarker.setPopupContent(pos.satellite + '<br>Alt: ' + pos.altitude.toFixed(0) + ' km<br>El: ' + pos.elevation.toFixed(1) + '°');
                    } else if (groundTrackMap) {
                        satMarker = L.marker([pos.lat, pos.lon], {
                            icon: L.divIcon({
                                className: 'sat-marker',
                                html: '<div style="background:#ffff00;width:14px;height:14px;border-radius:50%;border:2px solid #000;box-shadow:0 0 15px #ffff00;animation:pulse-sat 1s infinite;"></div>',
                                iconSize: [14, 14],
                                iconAnchor: [7, 7]
                            })
                        }).addTo(groundTrackMap).bindPopup(pos.satellite + '<br>Alt: ' + pos.altitude.toFixed(0) + ' km');
                    }

                    // Draw full orbit track from position endpoint
                    // Backend returns 'track' property
                    const orbitData = pos.track || pos.orbitTrack;
                    if (orbitData && orbitData.length > 0 && groundTrackMap) {
                        // Split into past and future, handling antimeridian crossings
                        const pastPoints = orbitData.filter(p => p.past);
                        const futurePoints = orbitData.filter(p => !p.past);

                        // Helper to split coords only at true antimeridian crossings (±180° line)
                        function splitAtAntimeridian(points) {
                            const segments = [];
                            let currentSegment = [];
                            for (let i = 0; i < points.length; i++) {
                                const p = points[i];
                                if (currentSegment.length > 0) {
                                    const prevLon = currentSegment[currentSegment.length - 1][1];
                                    // Only split when crossing the antimeridian (one side > 90, other < -90)
                                    const crossesAntimeridian = (prevLon > 90 && p.lon < -90) || (prevLon < -90 && p.lon > 90);
                                    if (crossesAntimeridian) {
                                        if (currentSegment.length >= 1) segments.push(currentSegment);
                                        currentSegment = [];
                                    }
                                }
                                currentSegment.push([p.lat, p.lon]);
                            }
                            if (currentSegment.length >= 1) segments.push(currentSegment);
                            return segments;
                        }

                        // Remove old lines
                        if (orbitTrackLine) groundTrackMap.removeLayer(orbitTrackLine);
                        if (pastOrbitLine) groundTrackMap.removeLayer(pastOrbitLine);

                        // Draw past track segments (dimmer)
                        const pastSegments = splitAtAntimeridian(pastPoints);
                        if (pastSegments.length > 0) {
                            pastOrbitLine = L.layerGroup();
                            pastSegments.forEach(seg => {
                                L.polyline(seg, {
                                    color: '#666666',
                                    weight: 2,
                                    opacity: 0.5,
                                    dashArray: '3, 6'
                                }).addTo(pastOrbitLine);
                            });
                            pastOrbitLine.addTo(groundTrackMap);
                        }

                        // Draw future track segments (brighter)
                        const futureSegments = splitAtAntimeridian(futurePoints);
                        if (futureSegments.length > 0) {
                            orbitTrackLine = L.layerGroup();
                            futureSegments.forEach(seg => {
                                L.polyline(seg, {
                                    color: selectedPass.color || '#00ff00',
                                    weight: 3,
                                    opacity: 0.8
                                }).addTo(orbitTrackLine);
                            });
                            orbitTrackLine.addTo(groundTrackMap);
                        }
                    }

                    // Update polar plot with pass trajectory and real-time position
                    if (selectedPass) {
                        drawPolarPlot(selectedPass);
                        // Draw current position on top if satellite is visible
                        if (pos.elevation > 0) {
                            drawRealTimePositionOnPolar(pos);
                        }
                    }
                }
            });
        }

        function drawRealTimePositionOnPolar(pos) {
            const canvas = document.getElementById('polarPlotCanvas');
            if (!canvas) return;
            const ctx = canvas.getContext('2d');
            const size = canvas.width;
            const cx = size / 2;
            const cy = size / 2;
            const radius = size / 2 - 30;

            // Draw pulsing indicator for current position
            const r = radius * (90 - pos.elevation) / 90;
            const rad = pos.azimuth * Math.PI / 180;
            const x = cx + Math.sin(rad) * r;
            const y = cy - Math.cos(rad) * r;

            ctx.fillStyle = '#ffff00';
            ctx.beginPath();
            ctx.arc(x, y, 8, 0, Math.PI * 2);
            ctx.fill();

            ctx.strokeStyle = '#ffff00';
            ctx.lineWidth = 2;
            ctx.beginPath();
            ctx.arc(x, y, 12, 0, Math.PI * 2);
            ctx.stroke();
        }

        function updateTLE() {
            fetch('/satellite/update-tle', { method: 'POST' })
                .then(r => r.json())
                .then(data => {
                    if (data.status === 'success') {
                        showInfo('TLE data updated!');
                    } else {
                        alert('Error updating TLE: ' + data.message);
                    }
                });
        }

        // Satellite management
        let trackedSatellites = [
            { id: 'ISS', name: 'ISS (ZARYA)', norad: '25544', builtin: true, checked: true },
            { id: 'NOAA-15', name: 'NOAA 15', norad: '25338', builtin: true, checked: true },
            { id: 'NOAA-18', name: 'NOAA 18', norad: '28654', builtin: true, checked: true },
            { id: 'NOAA-19', name: 'NOAA 19', norad: '33591', builtin: true, checked: true },
            { id: 'METEOR-M2', name: 'Meteor-M 2', norad: '40069', builtin: true, checked: true }
        ];

        function renderSatelliteList() {
            const list = document.getElementById('satelliteList');
            if (!list) return;

            list.innerHTML = trackedSatellites.map((sat, idx) => `
                <div class="sat-item ${sat.builtin ? 'builtin' : ''}">
                    <label>
                        <input type="checkbox" ${sat.checked ? 'checked' : ''} onchange="toggleSatellite(${idx})">
                        <span class="sat-name">${sat.name}</span>
                        <span class="sat-norad">#${sat.norad}</span>
                    </label>
                    <button class="sat-remove" onclick="removeSatellite(${idx})" title="Remove">✕</button>
                </div>
            `).join('');
        }

        function toggleSatellite(idx) {
            trackedSatellites[idx].checked = !trackedSatellites[idx].checked;
        }

        function removeSatellite(idx) {
            if (!trackedSatellites[idx].builtin) {
                trackedSatellites.splice(idx, 1);
                renderSatelliteList();
            }
        }

        function getSelectedSatellites() {
            return trackedSatellites.filter(s => s.checked).map(s => s.id);
        }

        function showAddSatelliteModal() {
            document.getElementById('satModal').classList.add('active');
        }

        function closeSatModal() {
            document.getElementById('satModal').classList.remove('active');
        }

        function switchSatModalTab(tab) {
            document.querySelectorAll('.sat-modal-tab').forEach(t => t.classList.remove('active'));
            document.querySelectorAll('.sat-modal-section').forEach(s => s.classList.remove('active'));

            if (tab === 'tle') {
                document.querySelector('.sat-modal-tab:first-child').classList.add('active');
                document.getElementById('tleSection').classList.add('active');
            } else {
                document.querySelector('.sat-modal-tab:last-child').classList.add('active');
                document.getElementById('celestrakSection').classList.add('active');
            }
        }

        function addFromTLE() {
            const tleText = document.getElementById('tleInput').value.trim();
            if (!tleText) {
                alert('Please paste TLE data');
                return;
            }

            const lines = tleText.split('\\n').map(l => l.trim()).filter(l => l);
            let added = 0;

            for (let i = 0; i < lines.length; i += 3) {
                if (i + 2 < lines.length) {
                    const name = lines[i];
                    const line1 = lines[i + 1];
                    const line2 = lines[i + 2];

                    if (line1.startsWith('1 ') && line2.startsWith('2 ')) {
                        const norad = line1.substring(2, 7).trim();
                        const id = name.replace(/[^a-zA-Z0-9]/g, '-').toUpperCase();

                        // Check if already exists
                        if (!trackedSatellites.find(s => s.norad === norad)) {
                            trackedSatellites.push({
                                id: id,
                                name: name,
                                norad: norad,
                                builtin: false,
                                checked: true,
                                tle: [name, line1, line2]
                            });
                            added++;
                        }
                    }
                }
            }

            if (added > 0) {
                renderSatelliteList();
                document.getElementById('tleInput').value = '';
                closeSatModal();
                showInfo(`Added ${added} satellite(s)`);
            } else {
                alert('No valid TLE data found. Format: Name, Line 1, Line 2 (3 lines per satellite)');
            }
        }

        function fetchCelestrak() {
            showAddSatelliteModal();
            switchSatModalTab('celestrak');
        }

        function fetchCelestrakCategory(category) {
            const status = document.getElementById('celestrakStatus');
            status.innerHTML = '<span style="color: var(--accent-cyan);">Fetching ' + category + '...</span>';

            fetch('/satellite/celestrak/' + category)
                .then(r => r.json())
                .then(data => {
                    if (data.status === 'success' && data.satellites) {
                        let added = 0;
                        data.satellites.forEach(sat => {
                            if (!trackedSatellites.find(s => s.norad === sat.norad)) {
                                trackedSatellites.push({
                                    id: sat.id,
                                    name: sat.name,
                                    norad: sat.norad,
                                    builtin: false,
                                    checked: false, // Don't auto-select
                                    tle: sat.tle
                                });
                                added++;
                            }
                        });
                        renderSatelliteList();
                        status.innerHTML = `<span style="color: var(--accent-green);">Added ${added} satellites (${data.satellites.length} total in category)</span>`;
                    } else {
                        status.innerHTML = `<span style="color: var(--accent-red);">Error: ${data.message || 'Failed to fetch'}</span>`;
                    }
                })
                .catch(err => {
                    status.innerHTML = `<span style="color: var(--accent-red);">Network error</span>`;
                });
        }

        // Initialize satellite list when satellite mode is loaded
        function initSatelliteList() {
            renderSatelliteList();
        }

        // Utility function
        function showInfo(message) {
            // Simple notification - could be enhanced
            const existing = document.querySelector('.info-toast');
            if (existing) existing.remove();

            const toast = document.createElement('div');
            toast.className = 'info-toast';
            toast.textContent = message;
            toast.style.cssText = 'position: fixed; bottom: 20px; right: 20px; background: var(--accent-cyan); color: #000; padding: 10px 20px; border-radius: 4px; z-index: 10001; font-size: 12px;';
            document.body.appendChild(toast);
            setTimeout(() => toast.remove(), 3000);
        }

        // Theme toggle functions
        function toggleTheme() {
            const html = document.documentElement;
            const currentTheme = html.getAttribute('data-theme');
            const newTheme = currentTheme === 'light' ? 'dark' : 'light';

            if (newTheme === 'dark') {
                html.removeAttribute('data-theme');
            } else {
                html.setAttribute('data-theme', newTheme);
            }

            // Save to localStorage for instant load on next visit
            localStorage.setItem('intercept-theme', newTheme);

            // Persist to server for cross-device sync
            fetch('/settings', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ theme: newTheme })
            }).catch(err => console.warn('Failed to save theme to server:', err));
        }

        // Load saved theme on page load
        (function() {
            // First apply localStorage theme for instant load (no flash)
            const localTheme = localStorage.getItem('intercept-theme');
            if (localTheme === 'light') {
                document.documentElement.setAttribute('data-theme', 'light');
            }

            // Then fetch from server to sync (in case changed on another device)
            fetch('/settings/theme')
                .then(r => r.json())
                .then(data => {
                    if (data.status === 'success' && data.value) {
                        const serverTheme = data.value;
                        if (serverTheme !== localTheme) {
                            // Server has different theme, apply it
                            if (serverTheme === 'light') {
                                document.documentElement.setAttribute('data-theme', 'light');
                            } else {
                                document.documentElement.removeAttribute('data-theme');
                            }
                            localStorage.setItem('intercept-theme', serverTheme);
                        }
                    }
                })
                .catch(() => {}); // Ignore errors, localStorage is fallback
        })();

        // Help modal functions
        function showHelp() {
            document.getElementById('helpModal').classList.add('active');
            document.body.style.overflow = 'hidden';
        }

        function hideHelp() {
            document.getElementById('helpModal').classList.remove('active');
            document.body.style.overflow = '';
        }

        function switchHelpTab(tab) {
            document.querySelectorAll('.help-tab').forEach(t => t.classList.remove('active'));
            document.querySelectorAll('.help-section').forEach(s => s.classList.remove('active'));
            document.querySelector(`.help-tab[data-tab="${tab}"]`).classList.add('active');
            document.getElementById(`help-${tab}`).classList.add('active');
        }

        // Keyboard shortcuts for help
        document.addEventListener('keydown', function(e) {
            if (e.key === 'Escape') hideHelp();
            // Open help with F1 or ? key (when not typing in an input)
            if ((e.key === 'F1' || (e.key === '?' && !e.target.matches('input, textarea, select'))) && !document.getElementById('helpModal').classList.contains('active')) {
                e.preventDefault();
                showHelp();
            }
        });

        // NOTE: Scanner and Audio Receiver code moved to static/js/modes/listening-post.js

        // ============================================
        // TSCM (Counter-Surveillance) Functions
        // ============================================
        let isTscmRunning = false;
        let tscmEventSource = null;
        let tscmThreats = [];
        let tscmWifiDevices = [];
        let tscmBtDevices = [];
        let isRecordingBaseline = false;
        let tscmSweepStartTime = null;
        let tscmSweepEndTime = null;

        async function refreshTscmDevices() {
            // Fetch available interfaces for TSCM scanning
            try {
                const response = await fetch('/tscm/devices');
                const data = await response.json();
                const devices = data.devices || {};

                // Populate WiFi interfaces
                const wifiSelect = document.getElementById('tscmWifiInterface');
                wifiSelect.innerHTML = '<option value="">Select WiFi interface...</option>';
                if (devices.wifi_interfaces && devices.wifi_interfaces.length > 0) {
                    devices.wifi_interfaces.forEach(iface => {
                        const opt = document.createElement('option');
                        opt.value = iface.name;
                        opt.textContent = iface.display_name || iface.name;
                        wifiSelect.appendChild(opt);
                    });
                    // Auto-select first interface
                    if (devices.wifi_interfaces.length > 0) {
                        wifiSelect.value = devices.wifi_interfaces[0].name;
                    }
                } else {
                    wifiSelect.innerHTML = '<option value="">No WiFi interfaces found</option>';
                }

                // Populate Bluetooth adapters
                const btSelect = document.getElementById('tscmBtInterface');
                btSelect.innerHTML = '<option value="">Select Bluetooth adapter...</option>';
                if (devices.bt_adapters && devices.bt_adapters.length > 0) {
                    devices.bt_adapters.forEach(adapter => {
                        const opt = document.createElement('option');
                        opt.value = adapter.name;
                        opt.textContent = adapter.display_name || adapter.name;
                        btSelect.appendChild(opt);
                    });
                    // Auto-select first adapter
                    if (devices.bt_adapters.length > 0) {
                        btSelect.value = devices.bt_adapters[0].name;
                    }
                } else {
                    btSelect.innerHTML = '<option value="">No Bluetooth adapters found</option>';
                }

                // Populate SDR devices
                const sdrSelect = document.getElementById('tscmSdrDevice');
                sdrSelect.innerHTML = '<option value="">Select SDR device...</option>';
                if (devices.sdr_devices && devices.sdr_devices.length > 0) {
                    devices.sdr_devices.forEach(dev => {
                        const opt = document.createElement('option');
                        opt.value = dev.index;
                        opt.textContent = dev.display_name || dev.name || 'SDR Device';
                        sdrSelect.appendChild(opt);
                    });
                    // Auto-select first SDR if available
                    if (devices.sdr_devices.length > 0) {
                        sdrSelect.value = devices.sdr_devices[0].index;
                    }
                } else {
                    sdrSelect.innerHTML = '<option value="">No SDR devices found</option>';
                }

                // Show warnings (e.g., not running as root)
                const warningsDiv = document.getElementById('tscmDeviceWarnings');
                if (data.warnings && data.warnings.length > 0) {
                    warningsDiv.innerHTML = data.warnings.map(w =>
                        `<div class="tscm-privilege-warning">
                            <span class="warning-icon">⚠️</span>
                            <div>
                                <strong>${escapeHtml(w.message)}</strong>
                                ${w.action ? `<div class="warning-action">${escapeHtml(w.action)}</div>` : ''}
                            </div>
                        </div>`
                    ).join('');
                    warningsDiv.style.display = 'block';
                } else {
                    warningsDiv.style.display = 'none';
                }

            } catch (e) {
                console.error('Failed to refresh TSCM devices:', e);
            }
        }

        async function loadTscmBaselines() {
            try {
                const response = await fetch('/tscm/baselines');
                const data = await response.json();
                const select = document.getElementById('tscmBaselineSelect');
                select.innerHTML = '<option value="">No Baseline</option>';
                if (data.baselines) {
                    data.baselines.forEach(b => {
                        const opt = document.createElement('option');
                        opt.value = b.id;
                        opt.textContent = b.name + (b.is_active ? ' (Active)' : '');
                        select.appendChild(opt);
                    });
                }
            } catch (e) {
                console.error('Failed to load baselines:', e);
            }
        }

        async function startTscmSweep() {
            const sweepType = document.getElementById('tscmSweepType').value;
            const baselineId = document.getElementById('tscmBaselineSelect').value || null;
            const wifiEnabled = document.getElementById('tscmWifiEnabled').checked;
            const btEnabled = document.getElementById('tscmBtEnabled').checked;
            const rfEnabled = document.getElementById('tscmRfEnabled').checked;
            const wifiInterface = document.getElementById('tscmWifiInterface').value;
            const btInterface = document.getElementById('tscmBtInterface').value;
            const sdrDevice = document.getElementById('tscmSdrDevice').value;

            // Clear any previous warnings
            document.getElementById('tscmDeviceWarnings').style.display = 'none';
            document.getElementById('tscmDeviceWarnings').innerHTML = '';

            try {
                const response = await fetch('/tscm/sweep/start', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({
                        sweep_type: sweepType,
                        baseline_id: baselineId ? parseInt(baselineId) : null,
                        wifi: wifiEnabled,
                        bluetooth: btEnabled,
                        rf: rfEnabled,
                        wifi_interface: wifiInterface,
                        bt_interface: btInterface,
                        sdr_device: sdrDevice ? parseInt(sdrDevice) : null
                    })
                });

                const data = await response.json();
                if (data.status === 'success') {
                    isTscmRunning = true;
                    tscmSweepStartTime = new Date();
                    tscmSweepEndTime = null;
                    document.getElementById('startTscmBtn').style.display = 'none';
                    document.getElementById('stopTscmBtn').style.display = 'block';
                    document.getElementById('tscmProgress').style.display = 'flex';
                    document.getElementById('tscmReportBtn').style.display = 'none';

                    // Show warnings if any devices unavailable
                    if (data.warnings && data.warnings.length > 0) {
                        const warningsDiv = document.getElementById('tscmDeviceWarnings');
                        warningsDiv.innerHTML = data.warnings.map(w =>
                            `<div style="color: #ff9933; font-size: 10px; margin-bottom: 2px;">⚠ ${w}</div>`
                        ).join('');
                        warningsDiv.style.display = 'block';
                    }

                    // Update device indicators
                    updateTscmDeviceIndicators(data.devices);

                    // Reset displays
                    tscmThreats = [];
                    tscmWifiDevices = [];
                    tscmBtDevices = [];
                    tscmRfSignals = [];
                    tscmRfStatusMessage = null;
                    updateTscmDisplays();

                    // Start SSE stream
                    startTscmStream();
                } else {
                    // Show error with details
                    let errorMsg = data.message || 'Failed to start sweep';
                    if (data.details && data.details.length > 0) {
                        errorMsg += '\n\n' + data.details.join('\n');
                    }
                    alert(errorMsg);
                }
            } catch (e) {
                console.error('Failed to start TSCM sweep:', e);
                alert('Failed to start sweep: Network error');
            }
        }

        function updateTscmDeviceIndicators(devices) {
            const wifiIndicator = document.getElementById('tscmWifiIndicator');
            const btIndicator = document.getElementById('tscmBtIndicator');
            const rfIndicator = document.getElementById('tscmRfIndicator');

            if (wifiIndicator) {
                wifiIndicator.classList.toggle('active', devices.wifi);
                wifiIndicator.classList.toggle('inactive', !devices.wifi);
            }
            if (btIndicator) {
                btIndicator.classList.toggle('active', devices.bluetooth);
                btIndicator.classList.toggle('inactive', !devices.bluetooth);
            }
            if (rfIndicator) {
                rfIndicator.classList.toggle('active', devices.rf);
                rfIndicator.classList.toggle('inactive', !devices.rf);
            }
        }

        async function stopTscmSweep() {
            try {
                await fetch('/tscm/sweep/stop', { method: 'POST' });
            } catch (e) {
                console.error('Error stopping sweep:', e);
            }

            isTscmRunning = false;
            tscmSweepEndTime = new Date();
            if (tscmEventSource) {
                tscmEventSource.close();
                tscmEventSource = null;
            }

            document.getElementById('startTscmBtn').style.display = 'block';
            document.getElementById('stopTscmBtn').style.display = 'none';
            document.getElementById('tscmProgress').style.display = 'none';

            // Show report button if we have any data
            const hasData = tscmWifiDevices.length > 0 || tscmBtDevices.length > 0 || tscmRfSignals.length > 0;
            document.getElementById('tscmReportBtn').style.display = hasData ? 'block' : 'none';
        }

        function generateTscmReport() {
            // Calculate sweep duration
            const startTime = tscmSweepStartTime || new Date();
            const endTime = tscmSweepEndTime || new Date();
            const durationMs = endTime - startTime;
            const durationMin = Math.floor(durationMs / 60000);
            const durationSec = Math.floor((durationMs % 60000) / 1000);

            // Categorize devices by classification
            const allDevices = [
                ...tscmWifiDevices.map(d => ({...d, protocol: 'WiFi'})),
                ...tscmBtDevices.map(d => ({...d, protocol: 'Bluetooth'})),
                ...tscmRfSignals.map(d => ({...d, protocol: 'RF'}))
            ];

            const highInterest = allDevices.filter(d => d.classification === 'high_interest' || d.score >= 6);
            const needsReview = allDevices.filter(d => d.classification === 'review' || (d.score >= 3 && d.score < 6));
            const informational = allDevices.filter(d => d.classification === 'informational' || d.score < 3);

            // Determine overall assessment
            let assessment = 'LOW CONCERN';
            let assessmentClass = 'informational';
            if (highInterest.length > 0) {
                assessment = `ELEVATED CONCERN: ${highInterest.length} high-interest item(s) detected requiring immediate attention`;
                assessmentClass = 'high-interest';
            } else if (needsReview.length > 0) {
                assessment = `MODERATE CONCERN: ${needsReview.length} item(s) requiring further review`;
                assessmentClass = 'needs-review';
            } else {
                assessment = 'LOW CONCERN: No significant threats detected. Environment appears normal.';
            }

            // Helper function to render device row
            const renderDevice = (device) => {
                const scoreClass = device.score >= 6 ? 'high' : (device.score >= 3 ? 'medium' : 'low');
                const indicators = (device.indicators || []).map(i =>
                    `<span class="indicator">${i.type}: ${i.desc}</span>`
                ).join('');
                const reasons = (device.reasons || []).map(r => `<li>${r}</li>`).join('');

                let identifier = device.bssid || device.mac || (device.frequency ? `${device.frequency} MHz` : 'Unknown');
                let name = device.essid || device.name || device.band || 'Unknown';

                return `
                    <tr class="device-row ${device.classification || ''}">
                        <td><span class="protocol-badge ${device.protocol.toLowerCase()}">${device.protocol}</span></td>
                        <td><strong>${name}</strong><br><small class="identifier">${identifier}</small></td>
                        <td><span class="score-badge ${scoreClass}">${device.score || 0}</span></td>
                        <td>${device.classification || 'unknown'}</td>
                        <td>${device.signal || device.rssi || device.power || 'N/A'} dBm</td>
                        <td>
                            ${indicators ? `<div class="indicators">${indicators}</div>` : ''}
                            ${reasons ? `<ul class="reasons">${reasons}</ul>` : ''}
                        </td>
                        <td>${device.recommended_action || 'monitor'}</td>
                    </tr>
                `;
            };

            // Generate HTML report
            const reportHtml = `
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>TSCM Sweep Report - ${startTime.toLocaleDateString()}</title>
    <style>
        * { box-sizing: border-box; margin: 0; padding: 0; }
        body {
            font-family: 'Segoe UI', -apple-system, BlinkMacSystemFont, sans-serif;
            background: #1a1a2e;
            color: #e8eaed;
            padding: 40px;
            line-height: 1.6;
        }
        .report-container {
            max-width: 1200px;
            margin: 0 auto;
            background: #0f1218;
            border-radius: 12px;
            overflow: hidden;
            box-shadow: 0 20px 60px rgba(0,0,0,0.5);
        }
        .report-header {
            background: linear-gradient(135deg, #1a1a2e 0%, #0f1218 100%);
            padding: 40px;
            border-bottom: 1px solid #2a2a4a;
        }
        .report-title {
            font-size: 28px;
            font-weight: 700;
            color: #4a9eff;
            margin-bottom: 8px;
        }
        .report-subtitle {
            font-size: 14px;
            color: #9ca3af;
            letter-spacing: 1px;
            text-transform: uppercase;
        }
        .report-meta {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 20px;
            margin-top: 30px;
            padding: 20px;
            background: rgba(0,0,0,0.3);
            border-radius: 8px;
        }
        .meta-item {
            text-align: center;
        }
        .meta-value {
            font-size: 24px;
            font-weight: 700;
            color: #fff;
        }
        .meta-label {
            font-size: 11px;
            color: #6b7280;
            text-transform: uppercase;
            letter-spacing: 1px;
        }
        .section {
            padding: 30px 40px;
            border-bottom: 1px solid #2a2a4a;
        }
        .section:last-child {
            border-bottom: none;
        }
        .section-title {
            font-size: 18px;
            font-weight: 600;
            color: #4a9eff;
            margin-bottom: 20px;
            display: flex;
            align-items: center;
            gap: 10px;
        }
        .assessment {
            padding: 20px;
            border-radius: 8px;
            font-size: 14px;
            font-weight: 500;
        }
        .assessment.high-interest {
            background: rgba(255, 51, 51, 0.15);
            border: 1px solid #ff3333;
            color: #ff6666;
        }
        .assessment.needs-review {
            background: rgba(255, 204, 0, 0.15);
            border: 1px solid #ffcc00;
            color: #ffdd44;
        }
        .assessment.informational {
            background: rgba(0, 204, 0, 0.15);
            border: 1px solid #00cc00;
            color: #44dd44;
        }
        .summary-grid {
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            gap: 16px;
            margin-bottom: 20px;
        }
        .summary-card {
            background: rgba(0,0,0,0.3);
            padding: 20px;
            border-radius: 8px;
            text-align: center;
            border: 1px solid #2a2a4a;
        }
        .summary-card.high-interest { border-color: #ff3333; }
        .summary-card.needs-review { border-color: #ffcc00; }
        .summary-card.informational { border-color: #00cc00; }
        .summary-card .count {
            font-size: 32px;
            font-weight: 700;
        }
        .summary-card.high-interest .count { color: #ff3333; }
        .summary-card.needs-review .count { color: #ffcc00; }
        .summary-card.informational .count { color: #00cc00; }
        .summary-card .label {
            font-size: 11px;
            color: #6b7280;
            text-transform: uppercase;
            margin-top: 4px;
        }
        table {
            width: 100%;
            border-collapse: collapse;
            font-size: 13px;
        }
        th {
            text-align: left;
            padding: 12px;
            background: rgba(0,0,0,0.4);
            color: #9ca3af;
            font-weight: 600;
            font-size: 11px;
            text-transform: uppercase;
            letter-spacing: 0.5px;
            border-bottom: 1px solid #2a2a4a;
        }
        td {
            padding: 12px;
            border-bottom: 1px solid #2a2a4a;
            vertical-align: top;
        }
        .device-row.high_interest { background: rgba(255, 51, 51, 0.08); }
        .device-row.review { background: rgba(255, 204, 0, 0.08); }
        .protocol-badge {
            display: inline-block;
            padding: 3px 8px;
            border-radius: 4px;
            font-size: 10px;
            font-weight: 600;
            text-transform: uppercase;
        }
        .protocol-badge.wifi { background: #4a9eff; color: #000; }
        .protocol-badge.bluetooth { background: #8b5cf6; color: #fff; }
        .protocol-badge.rf { background: #f59e0b; color: #000; }
        .score-badge {
            display: inline-block;
            padding: 4px 10px;
            border-radius: 12px;
            font-weight: 600;
            font-size: 12px;
        }
        .score-badge.high { background: rgba(255,51,51,0.2); color: #ff3333; }
        .score-badge.medium { background: rgba(255,204,0,0.2); color: #ffcc00; }
        .score-badge.low { background: rgba(0,204,0,0.2); color: #00cc00; }
        .identifier {
            color: #6b7280;
            font-family: monospace;
            font-size: 11px;
        }
        .indicators {
            display: flex;
            flex-wrap: wrap;
            gap: 4px;
            margin-bottom: 6px;
        }
        .indicator {
            display: inline-block;
            padding: 2px 6px;
            background: rgba(255,153,51,0.2);
            color: #ff9933;
            border-radius: 3px;
            font-size: 10px;
        }
        .reasons {
            margin: 0;
            padding-left: 16px;
            font-size: 11px;
            color: #9ca3af;
        }
        .reasons li {
            margin-bottom: 2px;
        }
        .category-section {
            margin-bottom: 30px;
        }
        .category-title {
            font-size: 14px;
            font-weight: 600;
            margin-bottom: 12px;
            padding: 8px 12px;
            border-radius: 6px;
        }
        .category-title.high-interest { background: rgba(255,51,51,0.15); color: #ff6666; }
        .category-title.needs-review { background: rgba(255,204,0,0.15); color: #ffdd44; }
        .category-title.informational { background: rgba(0,204,0,0.15); color: #44dd44; }
        .empty-state {
            text-align: center;
            padding: 40px;
            color: #6b7280;
        }
        .disclaimer {
            padding: 20px;
            background: rgba(74, 158, 255, 0.1);
            border-radius: 8px;
            font-size: 12px;
            color: #9ca3af;
        }
        .disclaimer h4 {
            color: #4a9eff;
            margin-bottom: 10px;
            font-size: 13px;
        }
        .recommendations {
            margin-top: 20px;
        }
        .recommendations ul {
            padding-left: 20px;
        }
        .recommendations li {
            margin-bottom: 8px;
        }
        .report-actions {
            position: fixed;
            top: 20px;
            right: 20px;
            display: flex;
            gap: 10px;
            z-index: 1000;
        }
        .report-btn {
            padding: 12px 24px;
            background: #4a9eff;
            color: #000;
            border: none;
            border-radius: 6px;
            font-weight: 600;
            cursor: pointer;
            font-size: 14px;
        }
        .report-btn:hover {
            background: #6bb3ff;
        }
        .report-btn.save {
            background: #22c55e;
        }
        .report-btn.save:hover {
            background: #2ecc71;
        }
        @media print {
            body { background: #fff; color: #000; padding: 20px; }
            .report-container { box-shadow: none; }
            .report-header { background: #f8f9fa; }
            .report-title { color: #1a1a2e; }
            .section { border-color: #ddd; }
            .section-title { color: #1a1a2e; }
            th { background: #f0f0f0; color: #333; }
            td { border-color: #ddd; }
            .report-actions { display: none; }
            .device-row.high_interest { background: rgba(255, 51, 51, 0.1); }
            .device-row.review { background: rgba(255, 204, 0, 0.1); }
        }
    </style>
</head>
<body>
    <div class="report-actions">
        <button class="report-btn save" onclick="saveReport()">💾 Save Report</button>
        <button class="report-btn" onclick="window.print()">🖨️ Print Report</button>
    </div>

    <div class="report-container">
        <div class="report-header">
            <div class="report-title">TSCM Sweep Report</div>
            <div class="report-subtitle">Technical Surveillance Counter-Measures Analysis</div>

            <div class="report-meta">
                <div class="meta-item">
                    <div class="meta-value">${startTime.toLocaleDateString()}</div>
                    <div class="meta-label">Date</div>
                </div>
                <div class="meta-item">
                    <div class="meta-value">${startTime.toLocaleTimeString()} - ${endTime.toLocaleTimeString()}</div>
                    <div class="meta-label">Time Range</div>
                </div>
                <div class="meta-item">
                    <div class="meta-value">${durationMin}m ${durationSec}s</div>
                    <div class="meta-label">Duration</div>
                </div>
                <div class="meta-item">
                    <div class="meta-value">${allDevices.length}</div>
                    <div class="meta-label">Total Devices</div>
                </div>
            </div>
        </div>

        <div class="section">
            <div class="section-title">📊 Executive Summary</div>
            <div class="summary-grid">
                <div class="summary-card high-interest">
                    <div class="count">${highInterest.length}</div>
                    <div class="label">High Interest</div>
                </div>
                <div class="summary-card needs-review">
                    <div class="count">${needsReview.length}</div>
                    <div class="label">Needs Review</div>
                </div>
                <div class="summary-card informational">
                    <div class="count">${informational.length}</div>
                    <div class="label">Informational</div>
                </div>
                <div class="summary-card">
                    <div class="count" style="color: #4a9eff;">${tscmWifiDevices.length}/${tscmBtDevices.length}/${tscmRfSignals.length}</div>
                    <div class="label">WiFi/BT/RF</div>
                </div>
            </div>
            <div class="assessment ${assessmentClass}">
                <strong>Assessment:</strong> ${assessment}
            </div>
        </div>

        ${highInterest.length > 0 ? `
        <div class="section">
            <div class="section-title">🔴 High Interest Items</div>
            <div class="category-section">
                <table>
                    <thead>
                        <tr>
                            <th>Type</th>
                            <th>Device</th>
                            <th>Score</th>
                            <th>Class</th>
                            <th>Signal</th>
                            <th>Indicators / Reasons</th>
                            <th>Action</th>
                        </tr>
                    </thead>
                    <tbody>
                        ${highInterest.map(renderDevice).join('')}
                    </tbody>
                </table>
            </div>
        </div>
        ` : ''}

        ${needsReview.length > 0 ? `
        <div class="section">
            <div class="section-title">🟡 Items Requiring Review</div>
            <div class="category-section">
                <table>
                    <thead>
                        <tr>
                            <th>Type</th>
                            <th>Device</th>
                            <th>Score</th>
                            <th>Class</th>
                            <th>Signal</th>
                            <th>Indicators / Reasons</th>
                            <th>Action</th>
                        </tr>
                    </thead>
                    <tbody>
                        ${needsReview.map(renderDevice).join('')}
                    </tbody>
                </table>
            </div>
        </div>
        ` : ''}

        ${informational.length > 0 ? `
        <div class="section">
            <div class="section-title">🟢 Informational Items</div>
            <div class="category-section">
                <table>
                    <thead>
                        <tr>
                            <th>Type</th>
                            <th>Device</th>
                            <th>Score</th>
                            <th>Class</th>
                            <th>Signal</th>
                            <th>Indicators / Reasons</th>
                            <th>Action</th>
                        </tr>
                    </thead>
                    <tbody>
                        ${informational.map(renderDevice).join('')}
                    </tbody>
                </table>
            </div>
        </div>
        ` : ''}

        ${allDevices.length === 0 ? `
        <div class="section">
            <div class="empty-state">
                <p>No devices were detected during this sweep.</p>
            </div>
        </div>
        ` : ''}

        <div class="section">
            <div class="section-title">📋 Recommendations</div>
            <div class="recommendations">
                <ul>
                    ${highInterest.length > 0 ? `
                    <li><strong>Immediate Action Required:</strong> ${highInterest.length} high-interest item(s) detected. These devices exhibit characteristics commonly associated with surveillance equipment and should be physically located and investigated.</li>
                    ` : ''}
                    ${needsReview.length > 0 ? `
                    <li><strong>Further Investigation Recommended:</strong> ${needsReview.length} item(s) require additional review to determine their purpose and legitimacy.</li>
                    ` : ''}
                    ${allDevices.filter(d => d.is_new).length > 0 ? `
                    <li><strong>New Devices Detected:</strong> ${allDevices.filter(d => d.is_new).length} device(s) were not present in the baseline. Verify these are authorized.</li>
                    ` : ''}
                    <li><strong>Regular Monitoring:</strong> Consider establishing a baseline of normal wireless activity and conducting periodic sweeps to detect changes.</li>
                    <li><strong>Physical Inspection:</strong> For any high-interest items, conduct a thorough physical inspection of the area to locate potential surveillance devices.</li>
                </ul>
            </div>
        </div>

        <div class="section">
            <div class="section-title">⚠️ Disclaimer</div>
            <div class="disclaimer">
                <h4>Important Notice</h4>
                <p>This report is generated by automated wireless spectrum analysis software. The findings presented are <strong>indicators only</strong> and do not constitute confirmation of surveillance activity. Many legitimate devices may trigger alerts due to their wireless characteristics.</p>
                <p style="margin-top: 10px;">Professional TSCM services involve specialized equipment and expertise beyond wireless spectrum analysis, including: non-linear junction detection, thermal imaging, physical inspection, and RF spectrum analysis with calibrated equipment.</p>
                <p style="margin-top: 10px;"><strong>No content was intercepted or decoded during this analysis.</strong> This tool only detects the presence and characteristics of wireless transmissions.</p>
            </div>
        </div>
    </div>

    <scr` + `ipt>
        function saveReport() {
            const html = document.documentElement.outerHTML;
            const blob = new Blob([html], { type: 'text/html' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = 'TSCM_Report_${startTime.toISOString().split('T')[0]}.html';
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
        }
    </scr` + `ipt>
</body>
</html>
            `;

            // Open report in new window
            const reportWindow = window.open('', '_blank');
            reportWindow.document.write(reportHtml);
            reportWindow.document.close();
        }

        function startTscmStream() {
            if (tscmEventSource) {
                tscmEventSource.close();
            }

            tscmEventSource = new EventSource('/tscm/sweep/stream');

            tscmEventSource.onmessage = function(event) {
                try {
                    const data = JSON.parse(event.data);
                    handleTscmEvent(data);
                } catch (e) {
                    console.error('TSCM SSE parse error:', e);
                }
            };

            tscmEventSource.onerror = function() {
                console.warn('TSCM SSE connection error');
            };
        }

        let tscmCorrelations = [];

        function handleTscmEvent(data) {
            switch (data.type) {
                case 'sweep_progress':
                    updateTscmProgress(data);
                    break;
                case 'wifi_device':
                    addTscmWifiDevice(data);
                    break;
                case 'bt_device':
                    addTscmBtDevice(data);
                    break;
                case 'rf_signal':
                    addTscmRfSignal(data);
                    break;
                case 'rf_status':
                    handleRfStatus(data);
                    break;
                case 'threat_detected':
                    addTscmThreat(data);
                    break;
                case 'correlation_findings':
                    handleCorrelationFindings(data);
                    break;
                case 'sweep_completed':
                    completeTscmSweep(data);
                    break;
                case 'sweep_stopped':
                case 'sweep_error':
                    stopTscmSweep();
                    break;
            }
        }

        function handleCorrelationFindings(data) {
            tscmCorrelations = data.correlations || [];
            updateCorrelationsDisplay();
        }

        function addTscmWifiDevice(device) {
            // Check if already exists
            const exists = tscmWifiDevices.some(d => d.bssid === device.bssid);
            if (!exists) {
                tscmWifiDevices.push(device);
                updateTscmDisplays();
                updateTscmThreatCounts();
                // Add to findings panel if score >= 3 (review level or higher)
                if (device.score >= 3) {
                    addHighInterestDevice(device, 'wifi');
                }
                // Feed to baseline recorder if recording
                if (isRecordingBaseline) {
                    fetch('/tscm/feed/wifi', {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify(device)
                    }).catch(e => console.error('Baseline feed error:', e));
                }
            }
        }

        function addTscmBtDevice(device) {
            // Check if already exists
            const exists = tscmBtDevices.some(d => d.mac === device.mac);
            if (!exists) {
                tscmBtDevices.push(device);
                updateTscmDisplays();
                updateTscmThreatCounts();
                // Add to threats panel if score >= 3 (review level or higher)
                if (device.score >= 3) {
                    addHighInterestDevice(device, 'bluetooth');
                }
                // Feed to baseline recorder if recording
                if (isRecordingBaseline) {
                    fetch('/tscm/feed/bluetooth', {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify(device)
                    }).catch(e => console.error('Baseline feed error:', e));
                }
            }
        }

        let tscmRfSignals = [];
        let tscmRfStatusMessage = null;

        function addTscmRfSignal(signal) {
            // Clear any error message since we're receiving signals
            tscmRfStatusMessage = null;
            // Check if already exists (within 0.1 MHz)
            const exists = tscmRfSignals.some(s => Math.abs(s.frequency - signal.frequency) < 0.1);
            if (!exists) {
                tscmRfSignals.push(signal);
                updateTscmDisplays();
                updateTscmThreatCounts();
                // Add to findings panel if score >= 3 (review level or higher)
                if (signal.score >= 3) {
                    addHighInterestDevice(signal, 'rf');
                }
                // Feed to baseline recorder if recording
                if (isRecordingBaseline) {
                    fetch('/tscm/feed/rf', {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify(signal)
                    }).catch(e => console.error('Baseline feed error:', e));
                }
            }
        }

        function handleRfStatus(data) {
            // Store status message to display in RF panel
            tscmRfStatusMessage = data.message;
            updateRfDisplay();
        }

        function updateRfDisplay() {
            const rfList = document.getElementById('tscmRfList');
            if (!rfList) return;

            if (tscmRfSignals.length === 0) {
                if (tscmRfStatusMessage) {
                    rfList.innerHTML = `<div class="tscm-status-message"><span class="status-icon">⚠️</span> ${escapeHtml(tscmRfStatusMessage)}</div>`;
                } else {
                    rfList.innerHTML = '<div class="tscm-empty">No RF signals detected</div>';
                }
            }
            // If there are signals, updateTscmDisplays() will handle the display
        }

        // Track high-interest devices for the threats panel
        let tscmHighInterestDevices = [];
        function addHighInterestDevice(device, protocol) {
            const id = device.mac || device.bssid || device.frequency;
            const exists = tscmHighInterestDevices.some(d => d.id === id);
            if (!exists) {
                tscmHighInterestDevices.push({
                    id: id,
                    protocol: protocol,
                    name: device.name || device.ssid || `${device.frequency} MHz`,
                    score: device.score,
                    classification: device.classification,
                    indicators: device.indicators || [],
                    recommended_action: device.recommended_action,
                    device: device
                });
                updateHighInterestPanel();
            }
        }

        function updateHighInterestPanel() {
            const panel = document.getElementById('tscmThreatList');
            if (tscmHighInterestDevices.length === 0) {
                panel.innerHTML = '<div class="tscm-empty">No flagged findings yet</div>';
            } else {
                // Sort by score (highest first)
                const sorted = [...tscmHighInterestDevices].sort((a, b) => b.score - a.score);
                panel.innerHTML = '<div class="tscm-threat-list">' + sorted.map(d => {
                    const severityClass = d.score >= 6 ? 'critical' : d.score >= 4 ? 'high' : 'medium';
                    return `
                    <div class="tscm-threat-item ${severityClass}" onclick="showDeviceDetails('${d.id}', '${d.protocol}')">
                        <div class="tscm-threat-header">
                            <span class="tscm-threat-type">${d.protocol.toUpperCase()}</span>
                            <span class="tscm-threat-severity">Score: ${d.score}</span>
                        </div>
                        <div class="tscm-threat-details">
                            <strong>${escapeHtml(d.name)}</strong><br>
                            <span style="font-size: 10px; color: var(--text-muted);">
                            ${d.indicators && d.indicators.length > 0 ? d.indicators.slice(0, 2).map(i => i.desc || i.type).join(' | ') : 'Review recommended'}
                            </span>
                        </div>
                        <div class="tscm-threat-action">${d.recommended_action || 'review'}</div>
                    </div>
                    `;
                }).join('') + '</div>';
            }
        }

        function updateTscmProgress(data) {
            // Update percentage text
            document.getElementById('tscmProgressPercent').textContent = data.progress + '%';

            // Update SVG circle progress (circumference = 2 * PI * 45 = ~283)
            const circumference = 283;
            const offset = circumference - (data.progress / 100) * circumference;
            const circle = document.getElementById('tscmScannerCircle');
            if (circle) {
                circle.style.strokeDashoffset = offset;
            }

            // Update status text
            let statusText = 'SCANNING...';
            if (data.threats_found > 0) {
                statusText = `THREATS: ${data.threats_found}`;
            } else if (data.status) {
                statusText = data.status;
            } else {
                const parts = [];
                if (data.wifi_count > 0) parts.push(`${data.wifi_count} WiFi`);
                if (data.bt_count > 0) parts.push(`${data.bt_count} BT`);
                if (data.rf_count > 0) parts.push(`${data.rf_count} RF`);
                statusText = parts.length > 0 ? parts.join(' | ') : 'SCANNING...';
            }
            document.getElementById('tscmProgressLabel').textContent = statusText;
        }

        function addTscmThreat(threat) {
            tscmThreats.unshift(threat);

            // Update dashboard counts
            updateTscmThreatCounts();
            updateTscmDisplays();
        }

        function updateTscmThreatCounts() {
            // Count devices by new scoring model classification
            const counts = { high_interest: 0, review: 0, informational: 0 };

            // Count from all device lists
            [...tscmWifiDevices, ...tscmBtDevices, ...tscmRfSignals].forEach(d => {
                const classification = d.classification || 'review';
                if (classification === 'high_interest') counts.high_interest++;
                else if (classification === 'review') counts.review++;
                else counts.informational++;
            });

            document.getElementById('tscmHighInterestCount').textContent = counts.high_interest;
            document.getElementById('tscmNeedsReviewCount').textContent = counts.review;
            document.getElementById('tscmInformationalCount').textContent = counts.informational;
            document.getElementById('tscmCorrelationsCount').textContent = tscmCorrelations.length;

            document.getElementById('tscmHighInterestCard').classList.toggle('active', counts.high_interest > 0);
            document.getElementById('tscmNeedsReviewCard').classList.toggle('active', counts.review > 0);
            document.getElementById('tscmInformationalCard').classList.toggle('active', counts.informational > 0);
            document.getElementById('tscmCorrelationsCard').classList.toggle('active', tscmCorrelations.length > 0);

            // Update threat panel count (now shows high interest items)
            document.getElementById('tscmThreatCount').textContent = counts.high_interest;
        }

        function getClassificationClass(classification) {
            // Map classification to CSS class
            switch (classification) {
                case 'high_interest': return 'classification-red';
                case 'review': return 'classification-yellow';
                case 'informational': return 'classification-green';
                default: return 'classification-yellow';
            }
        }

        function getClassificationIcon(classification) {
            switch (classification) {
                case 'high_interest': return '🔴';
                case 'review': return '🟡';
                case 'informational': return '🟢';
                default: return '🟡';
            }
        }

        function formatIndicators(indicators) {
            if (!indicators || indicators.length === 0) return '';
            return indicators.map(i => `<span class="indicator-tag">${escapeHtml(i.desc || i.type)}</span>`).join(' ');
        }

        function getScoreBadge(score) {
            if (score === undefined || score === null) return '';
            let scoreClass = 'score-low';
            if (score >= 6) scoreClass = 'score-high';
            else if (score >= 3) scoreClass = 'score-medium';
            return `<span class="score-badge ${scoreClass}">Score: ${score}</span>`;
        }

        // Store all devices for lookup
        function getAllTscmDevices() {
            const devices = {};
            tscmWifiDevices.forEach(d => { devices[`wifi:${d.bssid}`] = {...d, protocol: 'wifi'}; });
            tscmBtDevices.forEach(d => { devices[`bluetooth:${d.mac}`] = {...d, protocol: 'bluetooth'}; });
            tscmRfSignals.forEach(d => { devices[`rf:${d.frequency}`] = {...d, protocol: 'rf'}; });
            return devices;
        }

        function showDeviceDetails(id, protocol) {
            const devices = getAllTscmDevices();
            const key = `${protocol}:${id}`;
            const device = devices[key];

            if (!device) {
                console.warn('Device not found:', key);
                return;
            }

            const modal = document.getElementById('tscmDeviceModal');
            const content = document.getElementById('tscmDeviceModalContent');

            // Build detailed view
            let html = `
                <div class="device-detail-header ${getClassificationClass(device.classification)}">
                    <h3>${getClassificationIcon(device.classification)} ${escapeHtml(device.name || device.ssid || device.mac || device.bssid || device.frequency + ' MHz')}</h3>
                    <span class="device-detail-protocol">${protocol.toUpperCase()}</span>
                </div>

                <div class="device-detail-score">
                    <div class="score-circle ${device.score >= 6 ? 'high' : device.score >= 3 ? 'medium' : 'low'}">
                        <span class="score-value">${device.score || 0}</span>
                        <span class="score-label">SCORE</span>
                    </div>
                    <div class="score-breakdown">
                        <strong>Risk Level:</strong> ${device.classification === 'high_interest' ? 'HIGH INTEREST' : device.classification === 'review' ? 'NEEDS REVIEW' : 'INFORMATIONAL'}<br>
                        <strong>Recommended Action:</strong> ${device.recommended_action || 'Monitor'}
                    </div>
                </div>

                <div class="device-detail-section">
                    <h4>Device Information</h4>
                    <table class="device-detail-table">
            `;

            // Add device-specific fields
            if (protocol === 'wifi') {
                html += `
                    <tr><td>BSSID</td><td>${device.bssid || 'Unknown'}</td></tr>
                    <tr><td>SSID</td><td>${escapeHtml(device.ssid || '[Hidden]')}</td></tr>
                    <tr><td>Channel</td><td>${device.channel || 'Unknown'}</td></tr>
                    <tr><td>Signal</td><td>${device.signal || '--'} dBm</td></tr>
                    <tr><td>Security</td><td>${device.security || 'Unknown'}</td></tr>
                `;
            } else if (protocol === 'bluetooth') {
                html += `
                    <tr><td>MAC Address</td><td>${device.mac || 'Unknown'}</td></tr>
                    <tr><td>Name</td><td>${escapeHtml(device.name || 'Unknown')}</td></tr>
                    <tr><td>Type</td><td>${device.device_type || 'Unknown'}</td></tr>
                    <tr><td>RSSI</td><td>${device.rssi || '--'} dBm</td></tr>
                    <tr><td>Audio Capable</td><td>${device.is_audio_capable ? 'Yes' : 'No'}</td></tr>
                `;
            } else if (protocol === 'rf') {
                html += `
                    <tr><td>Frequency</td><td>${device.frequency?.toFixed(3) || 'Unknown'} MHz</td></tr>
                    <tr><td>Band</td><td>${device.band || 'Unknown'}</td></tr>
                    <tr><td>Power</td><td>${device.power?.toFixed(1) || '--'} dBm</td></tr>
                    <tr><td>Signal Strength</td><td>+${(device.signal_strength || 0).toFixed(1)} dB above noise</td></tr>
                `;
            }
            html += `</table></div>`;

            // Add "Listen" button for RF signals
            if (protocol === 'rf' && device.frequency) {
                const freq = device.frequency;
                html += `
                    <div class="device-detail-section" style="border-bottom: none;">
                        <h4>Actions</h4>
                        <div style="display: flex; gap: 8px; flex-wrap: wrap;">
                            <button class="tscm-action-btn" onclick="listenToRfSignal(${freq}, 'fm')">
                                🎧 Listen (FM)
                            </button>
                            <button class="tscm-action-btn" onclick="listenToRfSignal(${freq}, 'am')">
                                🎧 Listen (AM)
                            </button>
                        </div>
                        <div style="font-size: 10px; color: var(--text-secondary); margin-top: 8px;">
                            Opens Listening Post and tunes to this frequency
                        </div>
                    </div>
                `;
            }

            // Add indicators section
            if (device.indicators && device.indicators.length > 0) {
                html += `
                    <div class="device-detail-section">
                        <h4>Risk Indicators (Why This Score)</h4>
                        <div class="indicator-list">
                            ${device.indicators.map(i => `
                                <div class="indicator-item">
                                    <span class="indicator-type">${i.type}</span>
                                    <span class="indicator-desc">${escapeHtml(i.desc || '')}</span>
                                </div>
                            `).join('')}
                        </div>
                    </div>
                `;
            }

            // Add reasons section
            if (device.reasons && device.reasons.length > 0) {
                html += `
                    <div class="device-detail-section">
                        <h4>Detection Notes</h4>
                        <ul class="device-reasons-list">
                            ${device.reasons.map(r => `<li>${escapeHtml(r)}</li>`).join('')}
                        </ul>
                    </div>
                `;
            }

            // Add disclaimer
            html += `
                <div class="device-detail-disclaimer">
                    <strong>Disclaimer:</strong> This analysis identifies indicators and anomalies.
                    It does NOT confirm surveillance activity. Professional verification required.
                </div>
            `;

            content.innerHTML = html;
            modal.style.display = 'flex';
        }

        function closeTscmDeviceModal() {
            document.getElementById('tscmDeviceModal').style.display = 'none';
        }

        function listenToRfSignal(frequency, modulation) {
            // Close the modal
            closeTscmDeviceModal();

            // Switch to listening post mode
            switchMode('listening');

            // Wait a moment for the mode to switch, then tune to the frequency
            setTimeout(() => {
                if (typeof tuneToFrequency === 'function') {
                    tuneToFrequency(frequency, modulation);
                } else {
                    // Fallback: manually update the frequency input
                    const freqInput = document.getElementById('radioScanStart');
                    if (freqInput) {
                        freqInput.value = frequency.toFixed(1);
                    }
                    alert(`Tune to ${frequency.toFixed(3)} MHz (${modulation.toUpperCase()}) to listen`);
                }
            }, 300);
        }

        function showDevicesByCategory(category) {
            const modal = document.getElementById('tscmDeviceModal');
            const content = document.getElementById('tscmDeviceModalContent');

            let devices = [];
            let title = '';
            let titleClass = '';

            if (category === 'correlations') {
                // Show correlations
                title = 'Cross-Protocol Correlations';
                titleClass = 'classification-yellow';

                if (tscmCorrelations.length === 0) {
                    content.innerHTML = `
                        <div class="device-detail-header ${titleClass}">
                            <h3>${title}</h3>
                        </div>
                        <div class="device-detail-section">
                            <p style="text-align: center; color: var(--text-muted);">No correlations detected yet.</p>
                        </div>
                    `;
                } else {
                    content.innerHTML = `
                        <div class="device-detail-header ${titleClass}">
                            <h3>${title} (${tscmCorrelations.length})</h3>
                        </div>
                        <div class="device-detail-section">
                            ${tscmCorrelations.map(c => `
                                <div class="correlation-detail-item">
                                    <strong>${escapeHtml(c.description || 'Cross-protocol match')}</strong>
                                    <div style="font-size: 11px; color: var(--text-muted); margin-top: 4px;">
                                        Protocols: ${(c.protocols || []).join(', ')}<br>
                                        Devices: ${(c.devices || []).join(', ')}
                                    </div>
                                </div>
                            `).join('')}
                        </div>
                    `;
                }
                modal.style.display = 'flex';
                return;
            }

            // Filter devices by classification
            const allDevices = [
                ...tscmWifiDevices.map(d => ({...d, protocol: 'wifi', id: d.bssid})),
                ...tscmBtDevices.map(d => ({...d, protocol: 'bluetooth', id: d.mac})),
                ...tscmRfSignals.map(d => ({...d, protocol: 'rf', id: d.frequency}))
            ];

            if (category === 'high_interest') {
                devices = allDevices.filter(d => d.classification === 'high_interest');
                title = 'High Interest Devices';
                titleClass = 'classification-red';
            } else if (category === 'review') {
                devices = allDevices.filter(d => d.classification === 'review');
                title = 'Devices Needing Review';
                titleClass = 'classification-yellow';
            } else if (category === 'informational') {
                devices = allDevices.filter(d => d.classification === 'informational');
                title = 'Informational Devices';
                titleClass = 'classification-green';
            }

            // Sort by score descending
            devices.sort((a, b) => (b.score || 0) - (a.score || 0));

            if (devices.length === 0) {
                content.innerHTML = `
                    <div class="device-detail-header ${titleClass}">
                        <h3>${title}</h3>
                    </div>
                    <div class="device-detail-section">
                        <p style="text-align: center; color: var(--text-muted);">No devices in this category.</p>
                    </div>
                `;
            } else {
                content.innerHTML = `
                    <div class="device-detail-header ${titleClass}">
                        <h3>${title} (${devices.length})</h3>
                    </div>
                    <div class="category-device-list">
                        ${devices.map(d => `
                            <div class="category-device-item" onclick="event.stopPropagation(); showDeviceDetails('${d.id}', '${d.protocol}')">
                                <div class="category-device-header">
                                    <span class="category-device-name">
                                        ${getClassificationIcon(d.classification)}
                                        ${escapeHtml(d.name || d.ssid || d.mac || d.bssid || d.frequency + ' MHz')}
                                    </span>
                                    <span class="category-device-score">${d.score || 0}</span>
                                </div>
                                <div class="category-device-meta">
                                    <span class="protocol-badge">${d.protocol}</span>
                                    ${d.indicators ? d.indicators.slice(0, 2).map(i => `<span class="indicator-mini">${i.type}</span>`).join('') : ''}
                                </div>
                            </div>
                        `).join('')}
                    </div>
                `;
            }
            modal.style.display = 'flex';
        }

        function updateTscmDisplays() {
            // Update WiFi list
            const wifiList = document.getElementById('tscmWifiList');
            if (tscmWifiDevices.length === 0) {
                wifiList.innerHTML = '<div class="tscm-empty">No WiFi networks detected</div>';
            } else {
                // Sort by score (highest first)
                const sorted = [...tscmWifiDevices].sort((a, b) => (b.score || 0) - (a.score || 0));
                wifiList.innerHTML = sorted.map(d => `
                    <div class="tscm-device-item ${getClassificationClass(d.classification)}" onclick="showDeviceDetails('${d.bssid}', 'wifi')">
                        <div class="tscm-device-header">
                            <div class="tscm-device-name">
                                <span class="classification-indicator">${getClassificationIcon(d.classification)}</span>
                                ${escapeHtml(d.ssid || d.bssid || 'Hidden')}
                            </div>
                            ${getScoreBadge(d.score)}
                        </div>
                        <div class="tscm-device-meta">
                            <span>${d.bssid}</span>
                            <span>${d.signal || '--'} dBm</span>
                            <span>${d.security || 'Open'}</span>
                        </div>
                        ${d.indicators && d.indicators.length > 0 ? `<div class="tscm-device-indicators">${formatIndicators(d.indicators)}</div>` : ''}
                        ${d.recommended_action && d.recommended_action !== 'monitor' ? `<div class="tscm-action">Action: ${d.recommended_action}</div>` : ''}
                    </div>
                `).join('');
            }
            document.getElementById('tscmWifiCount').textContent = tscmWifiDevices.length;

            // Update BT list
            const btList = document.getElementById('tscmBtList');
            if (tscmBtDevices.length === 0) {
                btList.innerHTML = '<div class="tscm-empty">No Bluetooth devices detected</div>';
            } else {
                // Sort by score (highest first)
                const sorted = [...tscmBtDevices].sort((a, b) => (b.score || 0) - (a.score || 0));
                btList.innerHTML = sorted.map(d => `
                    <div class="tscm-device-item ${getClassificationClass(d.classification)}" onclick="showDeviceDetails('${d.mac}', 'bluetooth')">
                        <div class="tscm-device-header">
                            <div class="tscm-device-name">
                                <span class="classification-indicator">${getClassificationIcon(d.classification)}</span>
                                ${escapeHtml(d.name || 'Unknown')}
                                ${d.is_audio_capable ? '<span class="audio-badge" title="Audio-capable device">🎤</span>' : ''}
                            </div>
                            ${getScoreBadge(d.score)}
                        </div>
                        <div class="tscm-device-meta">
                            <span>${d.mac}</span>
                            <span>${d.rssi || '--'} dBm</span>
                            <span>${d.device_type || 'Unknown'}</span>
                        </div>
                        ${d.indicators && d.indicators.length > 0 ? `<div class="tscm-device-indicators">${formatIndicators(d.indicators)}</div>` : ''}
                        ${d.recommended_action && d.recommended_action !== 'monitor' ? `<div class="tscm-action">Action: ${d.recommended_action}</div>` : ''}
                    </div>
                `).join('');
            }
            document.getElementById('tscmBtCount').textContent = tscmBtDevices.length;

            // Update RF list
            const rfList = document.getElementById('tscmRfList');
            if (tscmRfSignals.length === 0) {
                if (tscmRfStatusMessage) {
                    rfList.innerHTML = `<div class="tscm-status-message"><span class="status-icon">⚠️</span> ${escapeHtml(tscmRfStatusMessage)}</div>`;
                } else {
                    rfList.innerHTML = '<div class="tscm-empty">No RF signals detected</div>';
                }
            } else {
                // Sort by score (highest first)
                const sorted = [...tscmRfSignals].sort((a, b) => (b.score || 0) - (a.score || 0));
                rfList.innerHTML = sorted.map(s => `
                    <div class="tscm-device-item ${getClassificationClass(s.classification)}" onclick="showDeviceDetails('${s.frequency}', 'rf')">
                        <div class="tscm-device-header">
                            <div class="tscm-device-name">
                                <span class="classification-indicator">${getClassificationIcon(s.classification)}</span>
                                ${s.frequency.toFixed(3)} MHz
                            </div>
                            ${getScoreBadge(s.score)}
                        </div>
                        <div class="tscm-device-meta">
                            <span>${s.band}</span>
                            <span>${s.power.toFixed(1)} dBm</span>
                            <span>+${(s.signal_strength || 0).toFixed(1)} dB above noise</span>
                        </div>
                        ${s.indicators && s.indicators.length > 0 ? `<div class="tscm-device-indicators">${formatIndicators(s.indicators)}</div>` : ''}
                        ${s.recommended_action && s.recommended_action !== 'monitor' ? `<div class="tscm-action">Action: ${s.recommended_action}</div>` : ''}
                    </div>
                `).join('');
            }
            document.getElementById('tscmRfCount').textContent = tscmRfSignals.length;

            // Update threats list
            const threatList = document.getElementById('tscmThreatList');
            if (tscmThreats.length === 0) {
                threatList.innerHTML = '<div class="tscm-empty">No threats detected</div>';
            } else {
                threatList.innerHTML = '<div class="tscm-threat-list">' + tscmThreats.map(t => `
                    <div class="tscm-threat-item ${t.severity}">
                        <div class="tscm-threat-header">
                            <span class="tscm-threat-type">${escapeHtml(t.threat_type || 'Unknown')}</span>
                            <span class="tscm-threat-severity">${t.severity}</span>
                        </div>
                        <div class="tscm-threat-details">
                            <strong>${escapeHtml(t.name || t.identifier)}</strong><br>
                            Source: ${t.source} | Signal: ${t.signal_strength || '--'} dBm
                        </div>
                    </div>
                `).join('') + '</div>';
            }
        }

        function updateCorrelationsDisplay() {
            const container = document.getElementById('tscmCorrelationsContainer');
            if (!container) return;

            if (tscmCorrelations.length === 0) {
                container.innerHTML = '';
                container.style.display = 'none';
                return;
            }

            container.style.display = 'block';
            container.innerHTML = `
                <div class="tscm-correlations">
                    <h4>Cross-Protocol Correlations (${tscmCorrelations.length})</h4>
                    ${tscmCorrelations.map(c => `
                        <div class="correlation-item">
                            <strong>${escapeHtml(c.description)}</strong>
                            <div class="correlation-devices">
                                Devices: ${c.devices.join(', ')} | Protocols: ${c.protocols.join(', ')}
                            </div>
                        </div>
                    `).join('')}
                </div>
            `;
        }

        function completeTscmSweep(data) {
            isTscmRunning = false;
            if (tscmEventSource) {
                tscmEventSource.close();
                tscmEventSource = null;
            }

            document.getElementById('startTscmBtn').style.display = 'block';
            document.getElementById('stopTscmBtn').style.display = 'none';
            document.getElementById('tscmProgress').style.display = 'none';
            document.getElementById('tscmProgressLabel').textContent = 'Sweep Complete';
            document.getElementById('tscmProgressPercent').textContent = '100%';
            document.getElementById('tscmProgressBar').style.width = '100%';

            // Final update of counts
            updateTscmThreatCounts();

            // Display sweep summary with correlation results
            const summaryContainer = document.getElementById('tscmSweepSummary');
            if (summaryContainer && data) {
                const highInterest = data.high_interest_devices || 0;
                const needsReview = data.needs_review_devices || 0;
                const correlations = data.correlations_found || 0;

                let assessment = 'BASELINE ENVIRONMENT';
                let assessmentClass = 'informational';
                if (highInterest > 0 || correlations > 0) {
                    assessment = 'ELEVATED CONCERN';
                    assessmentClass = 'high-interest';
                } else if (needsReview > 3) {
                    assessment = 'MODERATE CONCERN';
                    assessmentClass = 'needs-review';
                } else if (needsReview > 0) {
                    assessment = 'LOW CONCERN';
                    assessmentClass = 'needs-review';
                }

                summaryContainer.innerHTML = `
                    <div class="tscm-summary-box">
                        <div class="summary-stat high-interest">
                            <div class="count">${highInterest}</div>
                            <div class="label">High Interest</div>
                        </div>
                        <div class="summary-stat needs-review">
                            <div class="count">${needsReview}</div>
                            <div class="label">Needs Review</div>
                        </div>
                        <div class="summary-stat">
                            <div class="count">${correlations}</div>
                            <div class="label">Correlations</div>
                        </div>
                    </div>
                    <div class="tscm-assessment ${assessmentClass}">
                        <strong>Assessment:</strong> ${assessment}
                    </div>
                    <div class="tscm-disclaimer">
                        This screening identifies wireless/RF anomalies, NOT confirmed surveillance devices.
                        Findings require professional verification.
                    </div>
                `;
                summaryContainer.style.display = 'block';
            }

            // Update correlations display
            updateCorrelationsDisplay();
        }

        async function tscmRecordBaseline() {
            const name = document.getElementById('tscmBaselineName').value ||
                         `Baseline ${new Date().toLocaleString()}`;

            try {
                const response = await fetch('/tscm/baseline/record', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ name: name })
                });

                const data = await response.json();
                if (data.status === 'success') {
                    isRecordingBaseline = true;
                    document.getElementById('tscmRecordBaselineBtn').style.display = 'none';
                    document.getElementById('tscmStopBaselineBtn').style.display = 'block';
                    document.getElementById('tscmBaselineStatus').textContent = 'Recording baseline...';
                    document.getElementById('tscmBaselineStatus').style.color = '#ff9933';
                } else {
                    alert(data.message || 'Failed to start baseline recording');
                }
            } catch (e) {
                console.error('Failed to start baseline:', e);
                alert('Failed to start baseline recording');
            }
        }

        async function tscmStopBaseline() {
            try {
                const response = await fetch('/tscm/baseline/stop', { method: 'POST' });
                const data = await response.json();

                isRecordingBaseline = false;
                document.getElementById('tscmRecordBaselineBtn').style.display = 'block';
                document.getElementById('tscmStopBaselineBtn').style.display = 'none';

                if (data.status === 'success') {
                    document.getElementById('tscmBaselineStatus').textContent =
                        `Baseline saved: ${data.wifi_count} WiFi, ${data.bt_count} BT, ${data.rf_count} RF`;
                    document.getElementById('tscmBaselineStatus').style.color = '#00ff88';
                    loadTscmBaselines();
                } else {
                    document.getElementById('tscmBaselineStatus').textContent = data.message || 'Recording stopped';
                    document.getElementById('tscmBaselineStatus').style.color = 'var(--text-muted)';
                }
            } catch (e) {
                console.error('Failed to stop baseline:', e);
                document.getElementById('tscmBaselineStatus').textContent = 'Error stopping baseline';
            }
        }

        function escapeHtml(str) {
            if (!str) return '';
            const div = document.createElement('div');
            div.textContent = str;
            return div.innerHTML;
        }
    </script>

    <!-- Scanner/Audio code moved to static/js/modes/listening-post.js -->

    <!-- Help Modal -->
    <div id="helpModal" class="help-modal" onclick="if(event.target === this) hideHelp()">
        <div class="help-content">
            <button class="help-close" onclick="hideHelp()">×</button>
            <h2>📡 iNTERCEPT Help</h2>

            <div class="help-tabs">
                <button class="help-tab active" data-tab="icons" onclick="switchHelpTab('icons')">Icons</button>
                <button class="help-tab" data-tab="modes" onclick="switchHelpTab('modes')">Modes</button>
                <button class="help-tab" data-tab="wifi" onclick="switchHelpTab('wifi')">WiFi</button>
                <button class="help-tab" data-tab="tips" onclick="switchHelpTab('tips')">Tips</button>
            </div>

            <!-- Icons Section -->
            <div id="help-icons" class="help-section active">
                <h3>Stats Bar Icons</h3>
                <div class="icon-grid">
                    <div class="icon-item"><span class="icon">📟</span><span class="desc">POCSAG messages decoded</span></div>
                    <div class="icon-item"><span class="icon">📠</span><span class="desc">FLEX messages decoded</span></div>
                    <div class="icon-item"><span class="icon">📨</span><span class="desc">Total messages received</span></div>
                    <div class="icon-item"><span class="icon">🌡️</span><span class="desc">Unique sensors detected</span></div>
                    <div class="icon-item"><span class="icon">📊</span><span class="desc">Device types found</span></div>
                    <div class="icon-item"><span class="icon">🛰️</span><span class="desc">Satellites monitored</span></div>
                    <div class="icon-item"><span class="icon">📡</span><span class="desc">WiFi Access Points</span></div>
                    <div class="icon-item"><span class="icon">👤</span><span class="desc">Connected WiFi clients</span></div>
                    <div class="icon-item"><span class="icon">🤝</span><span class="desc">Captured handshakes</span></div>
                    <div class="icon-item"><span class="icon">🚁</span><span class="desc">Detected drones (click for details)</span></div>
                    <div class="icon-item"><span class="icon">⚠️</span><span class="desc">Rogue APs (click for details)</span></div>
                    <div class="icon-item"><span class="icon">🔵</span><span class="desc">Bluetooth devices</span></div>
                    <div class="icon-item"><span class="icon">📍</span><span class="desc">BLE beacons / APRS stations</span></div>
                </div>

                <h3>Mode Tab Icons</h3>
                <div class="icon-grid">
                    <div class="icon-item"><span class="icon">📟</span><span class="desc">Pager - POCSAG/FLEX decoder</span></div>
                    <div class="icon-item"><span class="icon">📡</span><span class="desc">433MHz - Sensor decoder</span></div>
                    <div class="icon-item"><span class="icon">✈️</span><span class="desc">Aircraft - Opens ADS-B Dashboard</span></div>
                    <div class="icon-item"><span class="icon">📍</span><span class="desc">APRS - Amateur radio tracking</span></div>
                    <div class="icon-item"><span class="icon">🛰️</span><span class="desc">Satellite - Pass prediction</span></div>
                    <div class="icon-item"><span class="icon">📶</span><span class="desc">WiFi - Network scanner</span></div>
                    <div class="icon-item"><span class="icon">🔵</span><span class="desc">Bluetooth - BT/BLE scanner</span></div>
                    <div class="icon-item"><span class="icon">📻</span><span class="desc">Listening Post - SDR scanner</span></div>
                    <div class="icon-item"><span class="icon">🔍</span><span class="desc">TSCM - Counter-surveillance</span></div>
                </div>
            </div>

            <!-- Modes Section -->
            <div id="help-modes" class="help-section">
                <h3>📟 Pager Mode</h3>
                <ul class="tip-list">
                    <li>Decodes POCSAG and FLEX pager signals using RTL-SDR</li>
                    <li>Set frequency to local pager frequencies (common: 152-158 MHz)</li>
                    <li>Messages are displayed in real-time as they're decoded</li>
                    <li>Use presets for common pager frequencies</li>
                </ul>

                <h3>📡 433MHz Sensor Mode</h3>
                <ul class="tip-list">
                    <li>Decodes wireless sensors on 433.92 MHz ISM band</li>
                    <li>Detects temperature, humidity, weather stations, tire pressure monitors</li>
                    <li>Supports many common protocols (Acurite, LaCrosse, Oregon Scientific, etc.)</li>
                    <li>Device intelligence builds profiles of recurring devices</li>
                </ul>

                <h3>✈️ Aircraft (Dashboard)</h3>
                <ul class="tip-list">
                    <li>Opens the dedicated ADS-B Dashboard for aircraft tracking</li>
                    <li>Features radar scope, map view, airband audio, and ACARS decoding</li>
                </ul>

                <h3>📍 APRS Mode</h3>
                <ul class="tip-list">
                    <li>Decodes APRS (Automatic Packet Reporting System) on VHF</li>
                    <li>Tracks amateur radio operators transmitting position data</li>
                    <li>Regional frequencies: 144.390 MHz (N. America), 144.800 MHz (Europe)</li>
                    <li>Uses Direwolf or multimon-ng for packet decoding</li>
                    <li>Interactive map shows station positions in real-time</li>
                </ul>

                <h3>🛰️ Satellite Mode</h3>
                <ul class="tip-list">
                    <li>Track satellites using TLE (Two-Line Element) data</li>
                    <li>Add satellites manually or fetch from Celestrak by category</li>
                    <li>Categories: Amateur, Weather, ISS, Starlink, GPS, and more</li>
                    <li>View next pass predictions with elevation and duration</li>
                </ul>

                <h3>📶 WiFi Mode</h3>
                <ul class="tip-list">
                    <li>Requires a WiFi adapter capable of monitor mode</li>
                    <li>Click "Enable Monitor" to put adapter in monitor mode</li>
                    <li>Scans all channels or lock to a specific channel</li>
                    <li>Detects drones by SSID patterns and manufacturer OUI</li>
                    <li>Rogue AP detection flags same SSID on multiple BSSIDs</li>
                    <li>Click network rows to target for deauth or handshake capture</li>
                </ul>

                <h3>🔵 Bluetooth Mode</h3>
                <ul class="tip-list">
                    <li>Scans for classic Bluetooth and BLE devices</li>
                    <li>Shows device names, addresses, and signal strength</li>
                    <li>Manufacturer lookup from MAC address OUI</li>
                    <li>Radar visualization shows device proximity</li>
                </ul>

                <h3>📻 Listening Post Mode</h3>
                <ul class="tip-list">
                    <li>Wideband SDR scanner with spectrum visualization</li>
                    <li>Tune to any frequency supported by your SDR hardware</li>
                    <li>AM/FM/USB/LSB demodulation modes</li>
                    <li>Bookmark frequencies for quick recall</li>
                    <li>Quick tune presets for emergency and marine channels</li>
                </ul>

                <h3>🔍 TSCM Mode</h3>
                <ul class="tip-list">
                    <li>Technical Surveillance Countermeasures sweep</li>
                    <li>Scans for unknown RF transmitters, WiFi devices, Bluetooth</li>
                    <li>Baseline comparison to detect new/anomalous devices</li>
                    <li>Threat classification: Critical, High, Medium, Low</li>
                    <li>Useful for security audits and bug sweeps</li>
                    <li><em style="color: var(--text-muted);">Note: This feature is in early development</em></li>
                </ul>
            </div>

            <!-- WiFi Section -->
            <div id="help-wifi" class="help-section">
                <h3>Monitor Mode</h3>
                <ul class="tip-list">
                    <li><strong>Enable Monitor:</strong> Puts WiFi adapter in monitor mode for passive scanning</li>
                    <li><strong>Kill Processes:</strong> Optional - stops NetworkManager/wpa_supplicant (may drop other connections)</li>
                    <li>Some adapters rename when entering monitor mode (e.g., wlan0 → wlan0mon)</li>
                </ul>

                <h3>Handshake Capture</h3>
                <ul class="tip-list">
                    <li>Click "Capture" on a network to start targeted handshake capture</li>
                    <li>Status panel shows capture progress and file location</li>
                    <li>Use deauth to force clients to reconnect (only on authorized networks!)</li>
                    <li>Handshake files saved to /tmp/intercept_handshake_*.cap</li>
                </ul>

                <h3>Drone Detection</h3>
                <ul class="tip-list">
                    <li>Drones detected by SSID patterns (DJI, Parrot, Autel, etc.)</li>
                    <li>Also detected by manufacturer OUI in MAC address</li>
                    <li>Distance estimated from signal strength (approximate)</li>
                    <li>Click drone count in stats bar to see all detected drones</li>
                </ul>

                <h3>Rogue AP Detection</h3>
                <ul class="tip-list">
                    <li>Flags networks where same SSID appears on multiple BSSIDs</li>
                    <li>Could indicate evil twin attack or legitimate multi-AP setup</li>
                    <li>Click rogue count to see which SSIDs are flagged</li>
                </ul>

                <h3>Proximity Alerts</h3>
                <ul class="tip-list">
                    <li>Add MAC addresses to watch list for alerts when detected</li>
                    <li>Watch list persists in browser localStorage</li>
                    <li>Useful for tracking specific devices</li>
                </ul>

                <h3>Client Probe Analysis</h3>
                <ul class="tip-list">
                    <li>Shows what networks client devices are looking for</li>
                    <li>Orange highlights indicate sensitive/private network names</li>
                    <li>Reveals user location history (home, work, hotels, airports)</li>
                    <li>Useful for security awareness and pen test reports</li>
                </ul>
            </div>

            <!-- Tips Section -->
            <div id="help-tips" class="help-section">
                <h3>General Tips</h3>
                <ul class="tip-list">
                    <li><strong>Collapsible sections:</strong> Click any section header (▼) to collapse/expand</li>
                    <li><strong>Sound alerts:</strong> Toggle sound on/off in settings for each mode</li>
                    <li><strong>Export data:</strong> Use export buttons to save captured data as JSON</li>
                    <li><strong>Device Intelligence:</strong> Tracks device patterns over time</li>
                    <li><strong>Theme toggle:</strong> Click 🌙/☀️ button in header to switch dark/light mode</li>
                </ul>

                <h3>Keyboard Shortcuts</h3>
                <ul class="tip-list">
                    <li><strong>F1</strong> - Open this help page</li>
                    <li><strong>?</strong> - Open help (when not typing in a field)</li>
                    <li><strong>Escape</strong> - Close help and modal dialogs</li>
                </ul>

                <h3>Requirements</h3>
                <ul class="tip-list">
                    <li><strong>Pager:</strong> RTL-SDR, rtl_fm, multimon-ng</li>
                    <li><strong>433MHz Sensors:</strong> RTL-SDR, rtl_433</li>
                    <li><strong>Aircraft (ADS-B):</strong> RTL-SDR, dump1090 or rtl_adsb</li>
                    <li><strong>Aircraft (ACARS):</strong> Second RTL-SDR, acarsdec</li>
                    <li><strong>APRS:</strong> RTL-SDR, direwolf or multimon-ng</li>
                    <li><strong>Satellite:</strong> Internet for Celestrak (optional), skyfield</li>
                    <li><strong>WiFi:</strong> Monitor-mode adapter, aircrack-ng suite</li>
                    <li><strong>Bluetooth:</strong> Bluetooth adapter, bluez (hcitool/bluetoothctl)</li>
                    <li><strong>Listening Post:</strong> RTL-SDR or SoapySDR-compatible hardware</li>
                    <li><strong>TSCM:</strong> WiFi adapter, Bluetooth adapter, RTL-SDR (all optional)</li>
                    <li>Run as root/sudo for full hardware access</li>
                </ul>

                <h3>Legal Notice</h3>
                <ul class="tip-list">
                    <li>Only use on networks and devices you own or have authorization to test</li>
                    <li>Passive monitoring may be legal; active attacks require authorization</li>
                    <li>Check local laws regarding radio frequency monitoring</li>
                </ul>
            </div>
        </div>
    </div>

    <!-- Dependencies Modal -->
    <div id="depsModal" class="help-modal" onclick="if(event.target === this) hideDependencies()">
        <div class="help-content" style="max-width: 800px;">
            <button class="help-close" onclick="hideDependencies()">×</button>
            <h2>🔧 Tool Dependencies</h2>
            <p style="color: var(--text-dim); margin-bottom: 15px;">Check which tools are installed for each mode. <span style="color: var(--accent-green);">●</span> = Installed, <span style="color: var(--accent-red);">●</span> = Missing</p>
            <div id="depsContent" style="max-height: 60vh; overflow-y: auto;">
                <div style="text-align: center; padding: 40px; color: var(--text-dim);">
                    Loading dependencies...
                </div>
            </div>
            <div style="margin-top: 20px; padding-top: 15px; border-top: 1px solid var(--border-color);">
                <h3 style="margin-bottom: 10px;">Quick Install (Debian/Ubuntu)</h3>
                <div style="background: var(--bg-tertiary); padding: 10px; border-radius: 4px; font-family: monospace; font-size: 11px; overflow-x: auto;">
                    <div>sudo apt install rtl-sdr multimon-ng rtl-433 aircrack-ng bluez dump1090-mutability hcxdumptool hcxtools</div>
                    <div style="margin-top: 5px;">pip install skyfield flask</div>
                </div>
                <div style="margin-top: 10px; font-size: 11px; color: var(--text-dim);">
                    <strong>Note:</strong> ACARS decoding requires <code>acarsdec</code> which must be built from source.
                    See <a href="https://github.com/TLeconte/acarsdec" target="_blank" style="color: var(--accent-cyan);">github.com/TLeconte/acarsdec</a> or run <code>./setup.sh</code> for automated installation.
                </div>
            </div>
        </div>
    </div>

    <!-- Satellite Add Modal -->
    <div id="satModal" class="help-modal" onclick="if(event.target === this) closeSatModal()">
        <div class="help-content" style="max-width: 600px;">
            <button class="help-close" onclick="closeSatModal()">×</button>
            <h2>Add Satellites</h2>

            <!-- Tabs -->
            <div style="display: flex; gap: 10px; margin-bottom: 15px; border-bottom: 1px solid var(--border-color); padding-bottom: 10px;">
                <button class="sat-modal-tab preset-btn active" onclick="switchSatModalTab('tle')" style="flex: 1;">Manual TLE</button>
                <button class="sat-modal-tab preset-btn" onclick="switchSatModalTab('celestrak')" style="flex: 1;">Celestrak</button>
            </div>

            <!-- TLE Section -->
            <div id="tleSection" class="sat-modal-section active">
                <p style="color: var(--text-secondary); font-size: 11px; margin-bottom: 10px;">
                    Paste TLE (Two-Line Element) data. Format: Name on first line, followed by TLE lines 1 and 2.
                </p>
                <textarea id="tleInput" placeholder="ISS (ZARYA)
1 25544U 98067A   24001.50000000  .00016717  00000-0  10270-3 0  9002
2 25544  51.6400 208.9163 0006703 296.5855  63.4606 15.49995465478450"
                    style="width: 100%; height: 150px; background: var(--bg-tertiary); color: var(--text-primary); border: 1px solid var(--border-color); border-radius: 4px; padding: 10px; font-family: 'JetBrains Mono', monospace; font-size: 11px; resize: vertical;"></textarea>
                <button class="preset-btn" onclick="addFromTLE()" style="margin-top: 10px; width: 100%;">Add Satellite</button>
            </div>

            <!-- Celestrak Section -->
            <div id="celestrakSection" class="sat-modal-section">
                <p style="color: var(--text-secondary); font-size: 11px; margin-bottom: 10px;">
                    Fetch satellite TLE data from CelesTrak by category.
                </p>
                <div id="celestrakStatus" style="margin-bottom: 10px; font-size: 11px; min-height: 20px;"></div>

                <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; max-height: 300px; overflow-y: auto;">
                    <button class="preset-btn" onclick="fetchCelestrakCategory('stations')">Space Stations</button>
                    <button class="preset-btn" onclick="fetchCelestrakCategory('weather')">Weather</button>
                    <button class="preset-btn" onclick="fetchCelestrakCategory('noaa')">NOAA</button>
                    <button class="preset-btn" onclick="fetchCelestrakCategory('goes')">GOES</button>
                    <button class="preset-btn" onclick="fetchCelestrakCategory('amateur')">Amateur</button>
                    <button class="preset-btn" onclick="fetchCelestrakCategory('cubesat')">CubeSats</button>
                    <button class="preset-btn" onclick="fetchCelestrakCategory('starlink')">Starlink</button>
                    <button class="preset-btn" onclick="fetchCelestrakCategory('oneweb')">OneWeb</button>
                    <button class="preset-btn" onclick="fetchCelestrakCategory('iridium-NEXT')">Iridium NEXT</button>
                    <button class="preset-btn" onclick="fetchCelestrakCategory('visual')">Bright/Visual</button>
                    <button class="preset-btn" onclick="fetchCelestrakCategory('geo')">Geostationary</button>
                    <button class="preset-btn" onclick="fetchCelestrakCategory('resource')">Earth Resources</button>
                </div>

                <p style="color: var(--text-muted); font-size: 10px; margin-top: 10px;">
                    Data from <a href="https://celestrak.org" target="_blank" style="color: var(--accent-cyan);">celestrak.org</a>.
                    Note: Some categories (Starlink, OneWeb) contain many satellites.
                </p>
            </div>
        </div>
    </div>

    <script>
        function showDependencies() {
            document.getElementById('depsModal').classList.add('active');
            loadDependencies();
        }

        function hideDependencies() {
            document.getElementById('depsModal').classList.remove('active');
        }

        function loadDependencies() {
            const content = document.getElementById('depsContent');
            content.innerHTML = '<div style="text-align: center; padding: 40px; color: var(--text-dim);">Loading dependencies...</div>';

            fetch('/dependencies')
                .then(r => r.json())
                .then(data => {
                    if (data.status !== 'success') {
                        content.innerHTML = '<div style="color: var(--accent-red);">Error loading dependencies</div>';
                        return;
                    }

                    let html = '';
                    let totalMissing = 0;

                    for (const [modeKey, mode] of Object.entries(data.modes)) {
                        const statusColor = mode.ready ? 'var(--accent-green)' : 'var(--accent-red)';
                        const statusIcon = mode.ready ? '✓' : '✗';

                        html += `
                            <div style="background: var(--bg-tertiary); border-radius: 8px; padding: 15px; margin-bottom: 15px; border-left: 3px solid ${statusColor};">
                                <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
                                    <h3 style="margin: 0; color: var(--accent-cyan);">${mode.name}</h3>
                                    <span style="color: ${statusColor}; font-weight: bold;">${statusIcon} ${mode.ready ? 'Ready' : 'Missing Required'}</span>
                                </div>
                                <div style="display: grid; gap: 8px;">
                        `;

                        for (const [toolName, tool] of Object.entries(mode.tools)) {
                            const installed = tool.installed;
                            const dotColor = installed ? 'var(--accent-green)' : 'var(--accent-red)';
                            const requiredBadge = tool.required ? '<span style="background: var(--accent-orange); color: #000; padding: 1px 5px; border-radius: 3px; font-size: 9px; margin-left: 5px;">REQUIRED</span>' : '';

                            if (!installed) totalMissing++;

                            // Get install command for current OS
                            let installCmd = '';
                            if (tool.install) {
                                if (tool.install.pip) {
                                    installCmd = tool.install.pip;
                                } else if (data.pkg_manager && tool.install[data.pkg_manager]) {
                                    installCmd = tool.install[data.pkg_manager];
                                } else if (tool.install.manual) {
                                    installCmd = tool.install.manual;
                                }
                            }

                            html += `
                                <div style="display: flex; align-items: center; gap: 10px; padding: 8px; background: var(--bg-secondary); border-radius: 4px;">
                                    <span style="color: ${dotColor}; font-size: 16px;">●</span>
                                    <div style="flex: 1;">
                                        <div style="font-weight: bold;">${toolName}${requiredBadge}</div>
                                        <div style="font-size: 11px; color: var(--text-dim);">${tool.description}</div>
                                    </div>
                                    ${!installed && installCmd ? `
                                        <code style="font-size: 10px; background: var(--bg-tertiary); padding: 4px 8px; border-radius: 3px; max-width: 250px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;" title="${installCmd}">${installCmd}</code>
                                    ` : ''}
                                    <span style="font-size: 11px; color: ${dotColor}; font-weight: bold;">${installed ? 'OK' : 'MISSING'}</span>
                                </div>
                            `;
                        }

                        html += '</div></div>';
                    }

                    // Summary at top
                    const summaryHtml = `
                        <div style="background: ${totalMissing > 0 ? 'rgba(255, 100, 0, 0.1)' : 'rgba(0, 255, 100, 0.1)'}; border: 1px solid ${totalMissing > 0 ? 'var(--accent-orange)' : 'var(--accent-green)'}; border-radius: 8px; padding: 15px; margin-bottom: 20px;">
                            <div style="font-size: 16px; font-weight: bold; color: ${totalMissing > 0 ? 'var(--accent-orange)' : 'var(--accent-green)'};">
                                ${totalMissing > 0 ? '⚠️ ' + totalMissing + ' tool(s) not found' : '✓ All tools installed'}
                            </div>
                            <div style="font-size: 12px; color: var(--text-dim); margin-top: 5px;">
                                OS: ${data.os} | Package Manager: ${data.pkg_manager}
                            </div>
                        </div>
                    `;

                    content.innerHTML = summaryHtml + html;

                    // Update button indicator
                    const btn = document.getElementById('depsBtn');
                    if (btn) {
                        btn.style.color = totalMissing > 0 ? 'var(--accent-orange)' : 'var(--accent-green)';
                    }
                })
                .catch(err => {
                    content.innerHTML = '<div style="color: var(--accent-red);">Error loading dependencies: ' + err.message + '</div>';
                });
        }

        // Check dependencies on page load
        document.addEventListener('DOMContentLoaded', function() {
            // Check if user dismissed the startup check
            const dismissed = localStorage.getItem('depsCheckDismissed');

            // Quick check for missing dependencies
            fetch('/dependencies')
                .then(r => r.json())
                .then(data => {
                    if (data.status === 'success') {
                        let missingModes = 0;
                        let missingTools = [];

                        for (const [modeKey, mode] of Object.entries(data.modes)) {
                            if (!mode.ready) {
                                missingModes++;
                                mode.missing_required.forEach(tool => {
                                    if (!missingTools.includes(tool)) {
                                        missingTools.push(tool);
                                    }
                                });
                            }
                        }

                        const btn = document.getElementById('depsBtn');
                        if (btn && missingModes > 0) {
                            btn.style.color = 'var(--accent-orange)';
                            btn.title = missingModes + ' mode(s) have missing tools - click to see details';
                        }

                        // Show startup prompt if tools are missing and not dismissed
                        // Only show if disclaimer has been accepted
                        const disclaimerAccepted = localStorage.getItem('disclaimerAccepted') === 'true';
                        if (missingModes > 0 && !dismissed && disclaimerAccepted) {
                            showStartupDepsPrompt(missingModes, missingTools.length);
                        }
                    }
                });
        });

        function showStartupDepsPrompt(modeCount, toolCount) {
            const notice = document.createElement('div');
            notice.id = 'startupDepsModal';
            notice.style.cssText = `
                position: fixed;
                top: 20px;
                left: 20px;
                z-index: 10000;
                background: var(--bg-secondary);
                border: 1px solid var(--accent-orange);
                border-radius: 8px;
                box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5), 0 0 15px rgba(255, 165, 0, 0.2);
                max-width: 380px;
                animation: slideIn 0.3s ease-out;
            `;
            notice.innerHTML = `
                <style>
                    @keyframes slideIn {
                        from { transform: translateX(-100%); opacity: 0; }
                        to { transform: translateX(0); opacity: 1; }
                    }
                </style>
                <div style="padding: 15px;">
                    <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;">
                        <h3 style="margin: 0; color: var(--accent-orange); font-size: 14px; display: flex; align-items: center; gap: 8px;">
                            <span>🔧</span> Missing Dependencies
                        </h3>
                        <button onclick="closeStartupDeps()" style="background: none; border: none; color: var(--text-dim); cursor: pointer; font-size: 18px; padding: 0; line-height: 1;">&times;</button>
                    </div>
                    <p style="color: var(--text-secondary); margin: 0 0 15px 0; font-size: 13px; line-height: 1.4;">
                        <strong style="color: var(--accent-orange);">${modeCount} mode(s)</strong> require tools that aren't installed.
                    </p>
                    <div style="display: flex; flex-direction: column; gap: 8px;">
                        <button class="action-btn" onclick="closeStartupDeps(); showDependencies();" style="padding: 10px 16px; font-size: 12px;">
                            View Details & Install
                        </button>
                        <label style="display: flex; align-items: center; gap: 8px; font-size: 11px; color: var(--text-dim); cursor: pointer;">
                            <input type="checkbox" id="dontShowAgain" style="cursor: pointer;">
                            Don't show again
                        </label>
                    </div>
                </div>
            `;
            document.body.appendChild(notice);
        }

        function closeStartupDeps() {
            const modal = document.getElementById('startupDepsModal');
            if (modal) {
                if (document.getElementById('dontShowAgain')?.checked) {
                    localStorage.setItem('depsCheckDismissed', 'true');
                }
                modal.remove();
            }
        }
    </script>
</body>
</html>
