Modularize index.html with CSS and HTML partials

- Extract inline CSS to static/css/modes/ (acars, aprs, tscm)
- Create HTML partials for all 9 modes in templates/partials/modes/
- Reduce index.html from 11,862 to 10,281 lines (~15% reduction)
- Use Jinja2 includes for cleaner template organization

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Smittix
2026-01-14 20:07:38 +00:00
parent 7eba7dbaaa
commit f326be77cd
13 changed files with 11869 additions and 11862 deletions

View File

@@ -0,0 +1,91 @@
/* ACARS Sidebar Styles */
@keyframes pulse {
0%, 100% { opacity: 0.3; transform: scale(0.8); }
50% { opacity: 1; transform: scale(1); }
}
/* Main ACARS Sidebar (Collapsible) */
.main-acars-sidebar {
display: flex;
flex-direction: row;
background: var(--bg-panel);
border-left: 1px solid var(--border-color);
}
.main-acars-collapse-btn {
width: 24px;
min-width: 24px;
background: rgba(0,0,0,0.4);
border: none;
border-right: 1px solid var(--border-color);
color: var(--accent-cyan);
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 5px;
padding: 6px 0;
transition: background 0.2s;
}
.main-acars-collapse-btn:hover {
background: rgba(74, 158, 255, 0.15);
}
.main-acars-collapse-label {
writing-mode: vertical-rl;
text-orientation: mixed;
font-size: 8px;
font-weight: 600;
letter-spacing: 1px;
}
.main-acars-sidebar.collapsed .main-acars-collapse-label { display: block; }
.main-acars-sidebar:not(.collapsed) .main-acars-collapse-label { display: none; }
#mainAcarsCollapseIcon {
font-size: 10px;
transition: transform 0.3s;
}
.main-acars-sidebar.collapsed #mainAcarsCollapseIcon {
transform: rotate(180deg);
}
.main-acars-content {
width: 196px;
display: flex;
flex-direction: column;
overflow: hidden;
transition: width 0.3s ease, opacity 0.2s ease;
}
.main-acars-sidebar.collapsed .main-acars-content {
width: 0;
opacity: 0;
pointer-events: none;
}
.main-acars-messages {
max-height: 350px;
}
.main-acars-msg {
padding: 6px 8px;
border-bottom: 1px solid var(--border-color);
animation: fadeInMsg 0.3s ease;
}
.main-acars-msg:hover {
background: rgba(74, 158, 255, 0.05);
}
@keyframes fadeInMsg {
from { opacity: 0; transform: translateY(-3px); }
to { opacity: 1; transform: translateY(0); }
}
/* ACARS Status Indicator */
.acars-status-dot.listening {
background: var(--accent-cyan) !important;
animation: acars-pulse 1.5s ease-in-out infinite;
}
.acars-status-dot.receiving {
background: var(--accent-green) !important;
}
.acars-status-dot.error {
background: var(--accent-red) !important;
}
@keyframes acars-pulse {
0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(74, 158, 255, 0.7); }
50% { opacity: 0.6; box-shadow: 0 0 6px 3px rgba(74, 158, 255, 0.3); }
}

48
static/css/modes/aprs.css Normal file
View File

@@ -0,0 +1,48 @@
/* APRS Status Bar Styles */
.aprs-status-bar {
margin-top: 12px;
padding: 10px;
background: rgba(0,0,0,0.3);
border: 1px solid var(--border-color);
border-radius: 4px;
}
.aprs-status-indicator {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 8px;
}
.aprs-status-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: var(--text-muted);
}
.aprs-status-dot.standby { background: var(--text-muted); }
.aprs-status-dot.listening {
background: var(--accent-cyan);
animation: aprs-pulse 1.5s ease-in-out infinite;
}
.aprs-status-dot.tracking { background: var(--accent-green); }
.aprs-status-dot.error { background: var(--accent-red); }
@keyframes aprs-pulse {
0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(74, 158, 255, 0.7); }
50% { opacity: 0.6; box-shadow: 0 0 8px 4px rgba(74, 158, 255, 0.3); }
}
.aprs-status-text {
font-size: 10px;
font-weight: bold;
letter-spacing: 1px;
}
.aprs-status-stats {
display: flex;
flex-wrap: wrap;
gap: 8px;
font-size: 9px;
}
.aprs-stat {
color: var(--text-secondary);
}
.aprs-stat-label {
color: var(--text-muted);
}

725
static/css/modes/tscm.css Normal file
View File

@@ -0,0 +1,725 @@
/* TSCM Styles */
/* TSCM Threat Cards */
.threat-card {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 8px;
border-radius: 6px;
background: rgba(0,0,0,0.3);
border: 1px solid var(--border-color);
}
.threat-card .count {
font-size: 18px;
font-weight: bold;
line-height: 1;
}
.threat-card .label {
font-size: 9px;
text-transform: uppercase;
opacity: 0.7;
margin-top: 2px;
}
.threat-card.critical { border-color: #ff3366; color: #ff3366; }
.threat-card.critical.active { background: rgba(255,51,102,0.2); }
.threat-card.high { border-color: #ff9933; color: #ff9933; }
.threat-card.high.active { background: rgba(255,153,51,0.2); }
.threat-card.medium { border-color: #ffcc00; color: #ffcc00; }
.threat-card.medium.active { background: rgba(255,204,0,0.2); }
.threat-card.low { border-color: #00ff88; color: #00ff88; }
.threat-card.low.active { background: rgba(0,255,136,0.2); }
/* TSCM Dashboard */
.tscm-dashboard {
display: flex;
flex-direction: column;
gap: 16px;
height: 100%;
}
.tscm-threat-banner {
display: flex;
gap: 12px;
padding: 12px;
background: rgba(0,0,0,0.3);
border-radius: 8px;
}
.tscm-threat-banner .threat-card {
flex: 1;
padding: 12px;
}
.tscm-threat-banner .threat-card .count {
font-size: 24px;
}
.tscm-main-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
flex: 1;
min-height: 0;
}
.tscm-panel {
background: rgba(0,0,0,0.3);
border: 1px solid var(--border-color);
border-radius: 8px;
display: flex;
flex-direction: column;
overflow: hidden;
}
.tscm-panel-header {
padding: 10px 12px;
background: rgba(0,0,0,0.3);
border-bottom: 1px solid var(--border-color);
font-weight: 600;
font-size: 12px;
display: flex;
justify-content: space-between;
align-items: center;
}
.tscm-panel-header .badge {
background: var(--primary-color);
color: #fff;
padding: 2px 8px;
border-radius: 10px;
font-size: 10px;
font-weight: normal;
}
.tscm-panel-content {
flex: 1;
overflow-y: auto;
padding: 8px;
}
.tscm-device-item {
padding: 8px 10px;
border-radius: 4px;
margin-bottom: 6px;
background: rgba(0,0,0,0.2);
border-left: 3px solid var(--border-color);
cursor: pointer;
transition: background 0.2s;
}
.tscm-device-item:hover {
background: rgba(74,158,255,0.1);
}
.tscm-device-item.new {
border-left-color: #ff9933;
animation: pulse-glow 2s infinite;
}
.tscm-device-item.threat {
border-left-color: #ff3366;
}
.tscm-device-item.baseline {
border-left-color: #00ff88;
}
/* Classification colors */
.tscm-device-item.classification-green {
border-left-color: #00cc00;
background: rgba(0, 204, 0, 0.1);
}
.tscm-device-item.classification-yellow {
border-left-color: #ffcc00;
background: rgba(255, 204, 0, 0.1);
}
.tscm-device-item.classification-red {
border-left-color: #ff3333;
background: rgba(255, 51, 51, 0.15);
animation: pulse-glow 2s infinite;
}
.classification-indicator {
margin-right: 6px;
}
.tscm-status-message {
padding: 12px;
background: rgba(255, 153, 51, 0.15);
border: 1px solid rgba(255, 153, 51, 0.3);
border-radius: 6px;
color: var(--text-primary);
font-size: 12px;
display: flex;
align-items: center;
gap: 8px;
}
.tscm-status-message .status-icon {
font-size: 16px;
}
.tscm-privilege-warning {
padding: 10px 12px;
background: rgba(255, 51, 51, 0.15);
border: 1px solid rgba(255, 51, 51, 0.4);
border-radius: 6px;
color: var(--text-primary);
font-size: 11px;
display: flex;
align-items: flex-start;
gap: 10px;
margin-bottom: 12px;
}
.tscm-privilege-warning .warning-icon {
font-size: 18px;
flex-shrink: 0;
}
.tscm-privilege-warning .warning-action {
margin-top: 4px;
font-family: 'JetBrains Mono', monospace;
font-size: 10px;
color: var(--accent-cyan);
background: rgba(0, 0, 0, 0.3);
padding: 4px 8px;
border-radius: 3px;
}
.tscm-action-btn {
padding: 10px 16px;
background: var(--accent-green);
border: none;
border-radius: 4px;
color: #000;
font-size: 12px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
}
.tscm-action-btn:hover {
background: #2ecc71;
transform: translateY(-1px);
}
.tscm-device-reasons {
font-size: 10px;
color: var(--text-secondary);
margin-top: 4px;
font-style: italic;
line-height: 1.4;
}
.audio-badge {
margin-left: 6px;
font-size: 10px;
}
.tscm-device-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 4px;
}
.tscm-device-name {
font-weight: 600;
font-size: 12px;
}
.tscm-device-meta {
font-size: 10px;
color: var(--text-muted);
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.tscm-device-indicators {
margin-top: 6px;
display: flex;
flex-wrap: wrap;
gap: 4px;
}
.indicator-tag {
font-size: 9px;
padding: 2px 6px;
border-radius: 3px;
background: rgba(255, 255, 255, 0.1);
color: var(--text-secondary);
white-space: nowrap;
}
.score-badge {
font-size: 10px;
padding: 2px 8px;
border-radius: 10px;
font-weight: 600;
}
.score-badge.score-low {
background: rgba(0, 204, 0, 0.2);
color: #00cc00;
}
.score-badge.score-medium {
background: rgba(255, 204, 0, 0.2);
color: #ffcc00;
}
.score-badge.score-high {
background: rgba(255, 51, 51, 0.2);
color: #ff3333;
}
.tscm-action {
margin-top: 4px;
font-size: 10px;
color: #ff9933;
font-weight: 600;
text-transform: uppercase;
}
.tscm-correlations {
margin-top: 16px;
padding: 12px;
background: rgba(255, 153, 51, 0.1);
border-radius: 6px;
border: 1px solid #ff9933;
}
.tscm-correlations h4 {
margin: 0 0 8px 0;
font-size: 12px;
color: #ff9933;
}
.correlation-item {
padding: 8px;
margin-bottom: 6px;
background: rgba(0, 0, 0, 0.2);
border-radius: 4px;
font-size: 11px;
}
.correlation-devices {
font-size: 10px;
color: var(--text-muted);
margin-top: 4px;
}
.tscm-summary-box {
display: flex;
gap: 12px;
margin-bottom: 16px;
flex-wrap: wrap;
}
.summary-stat {
flex: 1;
min-width: 100px;
padding: 12px;
background: rgba(0, 0, 0, 0.3);
border-radius: 6px;
text-align: center;
}
.summary-stat .count {
font-size: 24px;
font-weight: 700;
}
.summary-stat .label {
font-size: 10px;
color: var(--text-muted);
text-transform: uppercase;
}
.summary-stat.high-interest .count { color: #ff3333; }
.summary-stat.needs-review .count { color: #ffcc00; }
.summary-stat.informational .count { color: #00cc00; }
.tscm-assessment {
padding: 10px 14px;
margin: 12px 0;
border-radius: 6px;
font-size: 13px;
}
.tscm-assessment.high-interest {
background: rgba(255, 51, 51, 0.15);
border: 1px solid #ff3333;
color: #ff3333;
}
.tscm-assessment.needs-review {
background: rgba(255, 204, 0, 0.15);
border: 1px solid #ffcc00;
color: #ffcc00;
}
.tscm-assessment.informational {
background: rgba(0, 204, 0, 0.15);
border: 1px solid #00cc00;
color: #00cc00;
}
.tscm-disclaimer {
font-size: 10px;
color: var(--text-muted);
font-style: italic;
padding: 8px 12px;
background: rgba(0, 0, 0, 0.2);
border-radius: 4px;
margin-top: 8px;
}
/* TSCM Device Details Modal */
.tscm-modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.8);
display: flex;
align-items: center;
justify-content: center;
z-index: 10000;
}
.tscm-modal {
background: var(--bg-card);
border: 1px solid var(--border-light);
border-radius: 8px;
max-width: 500px;
width: 90%;
max-height: 80vh;
overflow-y: auto;
position: relative;
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
}
.tscm-modal-close {
position: absolute;
top: 12px;
right: 12px;
background: var(--bg-tertiary);
border: 1px solid var(--border-light);
border-radius: 50%;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
color: var(--text-secondary);
font-size: 20px;
cursor: pointer;
z-index: 10;
transition: all 0.2s;
}
.tscm-modal-close:hover {
background: var(--accent-red);
border-color: var(--accent-red);
color: #fff;
}
.device-detail-header {
padding: 16px;
padding-right: 52px; /* Reserve space for close button */
border-bottom: 1px solid var(--border-color);
display: flex;
justify-content: space-between;
align-items: center;
}
.device-detail-header h3 {
margin: 0;
font-size: 16px;
}
.device-detail-header.classification-red { background: rgba(255, 51, 51, 0.15); }
.device-detail-header.classification-yellow { background: rgba(255, 204, 0, 0.15); }
.device-detail-header.classification-green { background: rgba(0, 204, 0, 0.15); }
.device-detail-protocol {
font-size: 10px;
padding: 3px 8px;
background: rgba(255, 255, 255, 0.1);
border-radius: 3px;
text-transform: uppercase;
}
.device-detail-score {
display: flex;
align-items: center;
padding: 16px;
gap: 16px;
border-bottom: 1px solid var(--border-color);
}
.score-circle {
width: 70px;
height: 70px;
border-radius: 50%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border: 3px solid;
}
.score-circle.high { border-color: #ff3333; background: rgba(255, 51, 51, 0.1); }
.score-circle.medium { border-color: #ffcc00; background: rgba(255, 204, 0, 0.1); }
.score-circle.low { border-color: #00cc00; background: rgba(0, 204, 0, 0.1); }
.score-circle .score-value {
font-size: 24px;
font-weight: 700;
}
.score-circle.high .score-value { color: #ff3333; }
.score-circle.medium .score-value { color: #ffcc00; }
.score-circle.low .score-value { color: #00cc00; }
.score-circle .score-label {
font-size: 8px;
color: var(--text-muted);
text-transform: uppercase;
}
.score-breakdown {
flex: 1;
font-size: 12px;
line-height: 1.6;
}
.device-detail-section {
padding: 16px;
border-bottom: 1px solid var(--border-color);
}
.device-detail-section h4 {
margin: 0 0 12px 0;
font-size: 12px;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.device-detail-table {
width: 100%;
font-size: 12px;
}
.device-detail-table td {
padding: 4px 0;
}
.device-detail-table td:first-child {
color: var(--text-dim);
width: 40%;
}
.indicator-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.indicator-item {
display: flex;
gap: 10px;
padding: 8px;
background: rgba(0, 0, 0, 0.2);
border-radius: 4px;
font-size: 11px;
}
.indicator-type {
background: rgba(255, 153, 51, 0.2);
color: #ff9933;
padding: 2px 6px;
border-radius: 3px;
font-size: 10px;
white-space: nowrap;
}
.indicator-desc {
color: var(--text-color);
}
.device-reasons-list {
margin: 0;
padding-left: 20px;
font-size: 12px;
color: var(--text-primary);
}
.device-reasons-list li {
margin-bottom: 4px;
color: var(--text-secondary);
}
.device-detail-disclaimer {
padding: 12px 16px;
font-size: 10px;
color: var(--text-secondary);
background: rgba(74, 158, 255, 0.1);
border-top: 1px solid rgba(74, 158, 255, 0.3);
}
.tscm-threat-action {
margin-top: 6px;
font-size: 10px;
color: #ff9933;
text-transform: uppercase;
font-weight: 600;
}
.tscm-device-item {
cursor: pointer;
}
.tscm-device-item:hover {
background: rgba(255, 255, 255, 0.05);
}
.threat-card.clickable {
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
}
.threat-card.clickable:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
.category-device-list {
max-height: 400px;
overflow-y: auto;
}
.category-device-item {
padding: 12px 16px;
border-bottom: 1px solid var(--border-color);
cursor: pointer;
transition: background 0.2s;
}
.category-device-item:hover {
background: rgba(255, 255, 255, 0.05);
}
.category-device-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.category-device-name {
font-weight: 600;
font-size: 13px;
}
.category-device-score {
background: rgba(255, 255, 255, 0.1);
padding: 2px 8px;
border-radius: 10px;
font-size: 11px;
font-weight: 600;
}
.category-device-meta {
display: flex;
gap: 6px;
margin-top: 6px;
}
.protocol-badge {
font-size: 9px;
padding: 2px 6px;
background: rgba(74, 158, 255, 0.2);
color: #4a9eff;
border-radius: 3px;
text-transform: uppercase;
}
.indicator-mini {
font-size: 9px;
padding: 2px 6px;
background: rgba(255, 153, 51, 0.2);
color: #ff9933;
border-radius: 3px;
}
.correlation-detail-item {
padding: 12px;
background: rgba(0, 0, 0, 0.2);
border-radius: 6px;
margin-bottom: 8px;
}
.tscm-threat-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.tscm-threat-item {
padding: 10px 12px;
border-radius: 6px;
background: rgba(0,0,0,0.2);
border: 1px solid;
}
.tscm-threat-item.critical { border-color: #ff3366; background: rgba(255,51,102,0.1); }
.tscm-threat-item.high { border-color: #ff9933; background: rgba(255,153,51,0.1); }
.tscm-threat-item.medium { border-color: #ffcc00; background: rgba(255,204,0,0.1); }
.tscm-threat-item.low { border-color: #00ff88; background: rgba(0,255,136,0.1); }
.tscm-threat-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 4px;
}
.tscm-threat-type {
font-weight: 600;
font-size: 12px;
}
.tscm-threat-severity {
font-size: 10px;
padding: 2px 6px;
border-radius: 3px;
text-transform: uppercase;
}
.tscm-threat-item.critical .tscm-threat-severity { background: #ff3366; color: #fff; }
.tscm-threat-item.high .tscm-threat-severity { background: #ff9933; color: #000; }
.tscm-threat-item.medium .tscm-threat-severity { background: #ffcc00; color: #000; }
.tscm-threat-item.low .tscm-threat-severity { background: #00ff88; color: #000; }
.tscm-threat-details {
font-size: 11px;
color: var(--text-muted);
}
@keyframes pulse-glow {
0%, 100% { box-shadow: 0 0 5px rgba(255,153,51,0.3); }
50% { box-shadow: 0 0 15px rgba(255,153,51,0.6); }
}
.tscm-empty {
text-align: center;
padding: 30px;
color: var(--text-muted);
font-size: 12px;
}
/* Futuristic Scanner Progress */
.tscm-scanner-progress {
display: flex;
align-items: center;
gap: 12px;
padding: 12px;
margin-top: 10px;
background: rgba(0,0,0,0.4);
border: 1px solid var(--border-color);
border-radius: 8px;
}
.scanner-ring {
position: relative;
width: 70px;
height: 70px;
flex-shrink: 0;
}
.scanner-ring svg {
width: 100%;
height: 100%;
transform: rotate(-90deg);
}
.scanner-track {
fill: none;
stroke: rgba(74,158,255,0.1);
stroke-width: 4;
}
.scanner-progress {
fill: none;
stroke: var(--accent-cyan);
stroke-width: 4;
stroke-linecap: round;
stroke-dasharray: 283;
stroke-dashoffset: 283;
transition: stroke-dashoffset 0.3s ease;
filter: drop-shadow(0 0 6px var(--accent-cyan));
}
.scanner-sweep {
stroke: var(--accent-cyan);
stroke-width: 2;
opacity: 0.8;
transform-origin: 50px 50px;
animation: sweep-rotate 2s linear infinite;
filter: drop-shadow(0 0 4px var(--accent-cyan));
}
@keyframes sweep-rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.scanner-center {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
}
.scanner-percent {
font-size: 14px;
font-weight: bold;
color: var(--accent-cyan);
text-shadow: 0 0 10px var(--accent-cyan);
}
.scanner-info {
flex: 1;
min-width: 0;
}
.scanner-status {
font-size: 10px;
font-weight: 600;
letter-spacing: 2px;
color: var(--accent-cyan);
margin-bottom: 6px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.scanner-devices {
display: flex;
gap: 8px;
}
.device-indicator {
font-size: 14px;
opacity: 0.3;
transition: opacity 0.3s, transform 0.3s;
}
.device-indicator.active {
opacity: 1;
animation: device-pulse 1.5s ease-in-out infinite;
}
.device-indicator.inactive {
opacity: 0.2;
filter: grayscale(1);
}
@keyframes device-pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.1); }
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,121 @@
<!-- AIRCRAFT MODE (ADS-B) -->
<div id="aircraftMode" class="mode-content">
<div class="section">
<h3>ADS-B Receiver</h3>
<div class="form-group">
<label>Frequency</label>
<input type="text" id="adsbFrequency" value="1090" readonly style="opacity: 0.7;">
<div class="info-text">Fixed at 1090 MHz</div>
</div>
<div class="form-group">
<label>Gain (dB)</label>
<input type="text" id="adsbGain" value="40" placeholder="40">
</div>
<div class="checkbox-group">
<label>
<input type="checkbox" id="adsbEnableMap" checked onchange="toggleAircraftRadar()">
Show Radar Display
</label>
</div>
</div>
<div class="section">
<h3>Display Settings</h3>
<div class="form-group">
<label>Range (nm)</label>
<select id="adsbRange">
<option value="50">50 nm</option>
<option value="100" selected>100 nm</option>
<option value="200">200 nm</option>
<option value="500">500 nm</option>
</select>
</div>
<div class="checkbox-group">
<label>
<input type="checkbox" id="adsbShowLabels" checked>
Show Callsigns
</label>
<label>
<input type="checkbox" id="adsbShowAltitude" checked>
Show Altitude
</label>
<label>
<input type="checkbox" id="adsbShowTrails">
Show Flight Trails
</label>
<label>
<input type="checkbox" id="adsbEnableClustering" onchange="toggleAircraftClustering()">
Cluster Markers
</label>
<label>
<input type="checkbox" id="adsbShowRangeRings" checked onchange="drawRangeRings()">
Show Range Rings
</label>
</div>
<div class="form-group" style="margin-top: 10px;">
<label style="display: flex; align-items: center; gap: 8px;">
Observer Location
<span id="adsbGpsIndicator" class="gps-indicator" style="display: none;" title="GPS connected via gpsd">
<span class="gps-dot"></span> GPS
</span>
</label>
<div style="display: flex; gap: 5px;">
<input type="text" id="adsbObsLat" value="51.5074" placeholder="Latitude" style="flex: 1;" onchange="updateObserverLocation()">
<input type="text" id="adsbObsLon" value="-0.1278" placeholder="Longitude" style="flex: 1;" onchange="updateObserverLocation()">
</div>
<button class="preset-btn" id="adsbGeolocateBtn" onclick="getAdsbGeolocation()" style="width: 100%; margin-top: 5px;">
📍 Use Browser Location
</button>
</div>
<div class="form-group" style="margin-top: 10px;">
<label>Aircraft Filter</label>
<select id="adsbAircraftFilter" onchange="applyAircraftFilter()">
<option value="all">All Aircraft</option>
<option value="military">Military Only</option>
<option value="civil">Civil Only</option>
<option value="emergency">Emergency Only</option>
</select>
</div>
<div class="form-group" style="margin-top: 10px;">
<label style="display: flex; align-items: center; gap: 8px; cursor: pointer;">
<input type="checkbox" id="adsbAlertToggle" checked onchange="adsbAlertsEnabled = this.checked">
🔔 Audio Alerts (Military/Emergency)
</label>
</div>
</div>
<div class="section">
<h3>Reception Statistics</h3>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 8px; font-size: 11px;">
<div style="background: rgba(0,212,255,0.1); padding: 8px; border-radius: 4px; text-align: center;">
<div style="color: var(--text-secondary); font-size: 9px; text-transform: uppercase;">Max Range</div>
<div id="adsbMaxRange" style="color: var(--accent-cyan); font-size: 14px; font-weight: bold;">0.0 nm</div>
</div>
<div style="background: rgba(0,212,255,0.1); padding: 8px; border-radius: 4px; text-align: center;">
<div style="color: var(--text-secondary); font-size: 9px; text-transform: uppercase;">Total Seen</div>
<div id="adsbTotalSeen" style="color: var(--accent-cyan); font-size: 14px; font-weight: bold;">0</div>
</div>
<div style="background: rgba(0,212,255,0.1); padding: 8px; border-radius: 4px; text-align: center;">
<div style="color: var(--text-secondary); font-size: 9px; text-transform: uppercase;">Msg Rate</div>
<div id="adsbMsgRate" style="color: var(--accent-cyan); font-size: 14px; font-weight: bold;">0.0/s</div>
</div>
<div style="background: rgba(0,212,255,0.1); padding: 8px; border-radius: 4px; text-align: center;">
<div style="color: var(--text-secondary); font-size: 9px; text-transform: uppercase;">Busiest Hour</div>
<div id="adsbBusiestHour" style="color: var(--accent-cyan); font-size: 14px; font-weight: bold;">--</div>
</div>
</div>
</div>
<div class="info-text" style="margin-top: 8px; display: grid; grid-template-columns: auto auto; gap: 4px 8px; align-items: center;" id="adsbToolStatus">
<span>dump1090:</span><span class="tool-status" id="dump1090Status">Checking...</span>
<span>rtl_adsb:</span><span class="tool-status" id="rtlAdsbStatus">Checking...</span>
</div>
<button class="run-btn" id="startAdsbBtn" onclick="startAdsbScan()">
Start Tracking
</button>
<button class="stop-btn" id="stopAdsbBtn" onclick="stopAdsbScan()" style="display: none;">
Stop Tracking
</button>
</div>

View File

@@ -0,0 +1,57 @@
<!-- APRS MODE -->
<div id="aprsMode" class="mode-content">
<div class="section">
<h3>APRS Tracking</h3>
<p style="color: var(--text-secondary); font-size: 11px; line-height: 1.5; margin-bottom: 15px;">
Decode APRS (Automatic Packet Reporting System) amateur radio position reports on VHF.
</p>
<div style="background: rgba(255,193,7,0.1); border: 1px solid var(--accent-yellow); border-radius: 4px; padding: 8px; margin-bottom: 10px; font-size: 10px;">
<strong style="color: var(--accent-yellow);">Amateur Radio</strong><br>
<span style="color: var(--text-secondary);">APRS operates on 144.390 MHz (N. America) or 144.800 MHz (Europe). Decodes position, weather, and messages from ham radio operators.</span>
</div>
</div>
<div class="section">
<h3>Configuration</h3>
<div class="form-group">
<label>Region</label>
<select id="aprsRegion">
<option value="north_america">North America (144.390)</option>
<option value="europe">Europe (144.800)</option>
<option value="australia">Australia (145.175)</option>
<option value="japan">Japan (144.640)</option>
</select>
</div>
<div class="form-group">
<label>SDR Device</label>
<select id="aprsDevice">
<option value="">Loading devices...</option>
</select>
</div>
<div class="form-group">
<label>Gain (dB)</label>
<input type="text" id="aprsGain" value="40" placeholder="40">
</div>
<div class="info-text" style="margin-top: 8px; display: grid; grid-template-columns: auto auto; gap: 4px 8px; align-items: center;">
<span>direwolf:</span><span class="tool-status" id="direwolfStatus">Checking...</span>
<span>multimon-ng:</span><span class="tool-status" id="aprsMultimonStatus">Checking...</span>
</div>
</div>
<button class="run-btn" id="startAprsBtn" onclick="startAprs()">
Start APRS
</button>
<button class="stop-btn" id="stopAprsBtn" onclick="stopAprs()" style="display: none;">
Stop APRS
</button>
<!-- APRS Status Bar -->
<div id="aprsStatusBar" class="aprs-status-bar" style="display: none;">
<div class="aprs-status-indicator">
<span class="aprs-status-dot" id="aprsStatusDot"></span>
<span class="aprs-status-text" id="aprsStatusText">STANDBY</span>
</div>
<div class="aprs-status-stats">
<span class="aprs-stat"><span class="aprs-stat-label">FREQ:</span> <span id="aprsStatusFreq">--</span></span>
<span class="aprs-stat"><span class="aprs-stat-label">STATIONS:</span> <span id="aprsStatusStations">0</span></span>
<span class="aprs-stat"><span class="aprs-stat-label">PACKETS:</span> <span id="aprsStatusPackets">0</span></span>
</div>
</div>
</div>

View File

@@ -0,0 +1,70 @@
<!-- BLUETOOTH MODE -->
<div id="bluetoothMode" class="mode-content">
<div class="section">
<h3>Bluetooth Interface</h3>
<div class="form-group">
<select id="btInterfaceSelect">
<option value="">Detecting interfaces...</option>
</select>
</div>
<button class="preset-btn" onclick="refreshBtInterfaces()" style="width: 100%;">
Refresh Interfaces
</button>
<div class="info-text" style="margin-top: 8px; display: grid; grid-template-columns: auto auto; gap: 4px 8px; align-items: center;" id="btToolStatus">
<span>hcitool:</span><span class="tool-status missing">Checking...</span>
<span>bluetoothctl:</span><span class="tool-status missing">Checking...</span>
</div>
</div>
<div class="section">
<h3>Scan Mode</h3>
<div class="checkbox-group" style="margin-bottom: 10px;">
<label><input type="radio" name="btScanMode" value="bluetoothctl" checked> bluetoothctl (Recommended)</label>
<label><input type="radio" name="btScanMode" value="hcitool"> hcitool (Legacy)</label>
</div>
<div class="form-group">
<label>Scan Duration (sec)</label>
<input type="text" id="btScanDuration" value="30" placeholder="30">
</div>
<div class="checkbox-group">
<label>
<input type="checkbox" id="btScanBLE" checked>
Scan BLE Devices
</label>
<label>
<input type="checkbox" id="btScanClassic" checked>
Scan Classic BT
</label>
<label>
<input type="checkbox" id="btDetectBeacons" checked>
Detect Trackers (AirTag/Tile)
</label>
</div>
</div>
<div class="section">
<h3>Device Actions</h3>
<div class="form-group">
<label>Target MAC</label>
<input type="text" id="btTargetMac" placeholder="AA:BB:CC:DD:EE:FF">
</div>
<button class="preset-btn" onclick="btEnumServices()" style="width: 100%;">
Enumerate Services
</button>
</div>
<!-- Tracker Following Alert -->
<div id="trackerFollowingAlert" class="tracker-following-alert" style="display: none;">
<!-- Populated by JavaScript -->
</div>
<button class="run-btn" id="startBtBtn" onclick="startBtScan()">
Start Scanning
</button>
<button class="stop-btn" id="stopBtBtn" onclick="stopBtScan()" style="display: none;">
Stop Scanning
</button>
<button class="preset-btn" onclick="resetBtAdapter()" style="margin-top: 5px; width: 100%;">
Reset Adapter
</button>
</div>

View File

@@ -0,0 +1,49 @@
<!-- LISTENING POST MODE -->
<div id="listeningPostMode" class="mode-content">
<div class="section">
<h3>Status</h3>
<!-- Dependency Warning -->
<div id="scannerToolsWarning" style="display: none; background: rgba(255, 100, 100, 0.1); border: 1px solid var(--accent-red); border-radius: 4px; padding: 10px; margin-bottom: 10px;">
<p style="color: var(--accent-red); margin: 0; font-size: 0.85em;">
<strong>Missing:</strong><br>
<span id="scannerToolsWarningText"></span>
</p>
</div>
<!-- Quick Status -->
<div style="background: rgba(0,0,0,0.3); border-radius: 6px; padding: 12px;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
<span style="font-size: 10px; color: var(--text-muted); text-transform: uppercase;">Status</span>
<span id="lpQuickStatus" style="font-size: 11px; color: var(--accent-cyan);">IDLE</span>
</div>
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
<span style="font-size: 10px; color: var(--text-muted); text-transform: uppercase;">Frequency</span>
<span id="lpQuickFreq" style="font-size: 14px; font-family: 'JetBrains Mono', monospace; color: var(--text-primary);">---.--- MHz</span>
</div>
<div style="display: flex; justify-content: space-between; align-items: center;">
<span style="font-size: 10px; color: var(--text-muted); text-transform: uppercase;">Signals</span>
<span id="lpQuickSignals" style="font-size: 14px; font-weight: bold; color: var(--accent-green);">0</span>
</div>
</div>
</div>
<div class="section">
<h3>Bookmarks</h3>
<div style="display: flex; gap: 4px; margin-bottom: 8px;">
<input type="text" id="bookmarkFreqInput" placeholder="Freq (MHz)" style="flex: 1; padding: 6px; background: var(--bg-secondary); border: 1px solid var(--border-color); color: var(--text-primary); border-radius: 4px; font-size: 11px;">
<button class="preset-btn" onclick="addFrequencyBookmark()" style="background: var(--accent-green); color: #000; padding: 6px 10px;">+</button>
</div>
<div id="bookmarksList" style="max-height: 150px; overflow-y: auto; font-size: 11px;">
<div style="color: var(--text-muted); text-align: center; padding: 10px;">No bookmarks saved</div>
</div>
</div>
<div class="section">
<h3>Recent Signals</h3>
<div id="sidebarRecentSignals" style="max-height: 150px; overflow-y: auto; font-size: 11px;">
<div style="color: var(--text-muted); text-align: center; padding: 10px;">No signals yet</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,84 @@
<!-- PAGER MODE -->
<div id="pagerMode" class="mode-content active">
<div class="section">
<h3>Frequency</h3>
<div class="form-group">
<label>Frequency (MHz)</label>
<input type="text" id="frequency" value="153.350" placeholder="e.g., 153.350">
</div>
<div class="preset-buttons" id="presetButtons">
<!-- Populated by JavaScript -->
</div>
<div style="margin-top: 8px; display: flex; gap: 5px;">
<input type="text" id="newPresetFreq" placeholder="New freq (MHz)" style="flex: 1; padding: 6px; background: #0f3460; border: 1px solid #1a1a2e; color: #fff; border-radius: 4px; font-size: 12px;">
<button class="preset-btn" onclick="addPreset()" style="background: #2ecc71;">Add</button>
</div>
<div style="margin-top: 5px;">
<button class="preset-btn" onclick="resetPresets()" style="font-size: 11px;">Reset to Defaults</button>
</div>
</div>
<div class="section">
<h3>Protocols</h3>
<div class="checkbox-group">
<label><input type="checkbox" id="proto_pocsag512" checked> POCSAG-512</label>
<label><input type="checkbox" id="proto_pocsag1200" checked> POCSAG-1200</label>
<label><input type="checkbox" id="proto_pocsag2400" checked> POCSAG-2400</label>
<label><input type="checkbox" id="proto_flex" checked> FLEX</label>
</div>
</div>
<div class="section">
<h3>Settings</h3>
<div class="form-group">
<label>Gain (dB, 0 = auto)</label>
<input type="text" id="gain" value="0" placeholder="0-49 or 0 for auto">
</div>
<div class="form-group">
<label>Squelch Level</label>
<input type="text" id="squelch" value="0" placeholder="0 = off">
</div>
<div class="form-group">
<label>PPM Correction</label>
<input type="text" id="ppm" value="0" placeholder="Frequency correction">
</div>
</div>
<div class="section">
<h3>Logging</h3>
<div class="checkbox-group" style="margin-bottom: 15px;">
<label>
<input type="checkbox" id="loggingEnabled" onchange="toggleLogging()">
Enable Logging
</label>
</div>
<div class="form-group">
<label>Log file path</label>
<input type="text" id="logFilePath" value="pager_messages.log" placeholder="pager_messages.log">
</div>
</div>
<div class="section">
<h3>Message Filters</h3>
<div class="checkbox-group" style="margin-bottom: 10px;">
<label>
<input type="checkbox" id="filterToneOnly" checked onchange="savePagerFilters()">
Hide "Tone Only" messages
</label>
</div>
<div class="form-group">
<label>Hide messages containing (comma-separated)</label>
<input type="text" id="filterKeywords" placeholder="e.g. test, spam, alert" onchange="savePagerFilters()">
</div>
<div class="info-text" style="font-size: 10px; color: #666; margin-top: 5px;">
Messages matching these keywords will be hidden from display but still logged.
</div>
</div>
<button class="run-btn" id="startBtn" onclick="startDecoding()">
Start Decoding
</button>
<button class="stop-btn" id="stopBtn" onclick="stopDecoding()" style="display: none;">
Stop Decoding
</button>
</div>

View File

@@ -0,0 +1,50 @@
<!-- SATELLITE MODE -->
<div id="satelliteMode" class="mode-content">
<div class="section">
<h3>Satellite Command</h3>
<p style="color: var(--text-secondary); font-size: 11px; line-height: 1.5; margin-bottom: 15px;">
Full satellite tracking dashboard with polar plot, ground track map, pass predictions, and live telemetry.
</p>
<a href="/satellite/dashboard" target="_blank" class="preset-btn" style="display: block; text-align: center; text-decoration: none; width: 100%; margin-bottom: 10px;">
Open in New Window
</a>
</div>
<div class="section">
<h3>Satellite Database</h3>
<p style="color: var(--text-secondary); font-size: 11px; margin-bottom: 10px;">
Add satellites via TLE data or fetch from Celestrak.
</p>
<div style="display: flex; flex-direction: column; gap: 8px;">
<button class="preset-btn" onclick="showAddSatelliteModal()" style="width: 100%;">
Add Satellite (TLE)
</button>
<button class="preset-btn" onclick="fetchCelestrak()" style="width: 100%;">
Update from Celestrak
</button>
</div>
<div style="margin-top: 10px; padding: 8px; background: rgba(0,0,0,0.2); border-radius: 4px;">
<div style="font-size: 10px; color: var(--text-muted); margin-bottom: 6px;">TRACKED SATELLITES</div>
<div id="satTrackingList" style="font-size: 11px; color: var(--text-secondary); max-height: 120px; overflow-y: auto;">
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 4px;">
<span>ISS (ZARYA)</span>
<span>NOAA 15</span>
<span>NOAA 18</span>
<span>NOAA 19</span>
<span>NOAA 20</span>
<span>METEOR-M2</span>
<span>METEOR-M2-3</span>
</div>
</div>
</div>
</div>
<div class="section">
<h3>Quick Info</h3>
<div style="font-size: 11px; color: var(--text-secondary); line-height: 1.6;">
<p><strong>Polar Plot:</strong> Shows satellite path across the sky. Center = overhead, edge = horizon.</p>
<p style="margin-top: 8px;"><strong>Ground Track:</strong> Real-time satellite position and orbital path on world map.</p>
<p style="margin-top: 8px;"><strong>Pass Quality:</strong> Excellent (60°+), Good (30°+), Fair (below 30°).</p>
</div>
</div>
</div>

View File

@@ -0,0 +1,48 @@
<!-- 433MHz SENSOR MODE -->
<div id="sensorMode" class="mode-content">
<div class="section">
<h3>Frequency</h3>
<div class="form-group">
<label>Frequency (MHz)</label>
<input type="text" id="sensorFrequency" value="433.92" placeholder="e.g., 433.92">
</div>
<div class="preset-buttons">
<button class="preset-btn" onclick="setSensorFreq('433.92')">433.92</button>
<button class="preset-btn" onclick="setSensorFreq('315.00')">315.00</button>
<button class="preset-btn" onclick="setSensorFreq('868.00')">868.00</button>
<button class="preset-btn" onclick="setSensorFreq('915.00')">915.00</button>
</div>
</div>
<div class="section">
<h3>Settings</h3>
<div class="form-group">
<label>Gain (dB, 0 = auto)</label>
<input type="text" id="sensorGain" value="0" placeholder="0-49 or 0 for auto">
</div>
<div class="form-group">
<label>PPM Correction</label>
<input type="text" id="sensorPpm" value="0" placeholder="Frequency correction">
</div>
</div>
<div class="section">
<h3>Protocols</h3>
<div class="info-text" style="margin-bottom: 10px;">
rtl_433 auto-detects 200+ device protocols including weather stations, TPMS, doorbells, and more.
</div>
<div class="checkbox-group">
<label>
<input type="checkbox" id="sensorLogging" onchange="toggleSensorLogging()">
Enable Logging
</label>
</div>
</div>
<button class="run-btn" id="startSensorBtn" onclick="startSensorDecoding()">
Start Listening
</button>
<button class="stop-btn" id="stopSensorBtn" onclick="stopSensorDecoding()" style="display: none;">
Stop Listening
</button>
</div>

View File

@@ -0,0 +1,103 @@
<!-- TSCM MODE (Counter-Surveillance) -->
<div id="tscmMode" class="mode-content">
<div class="section">
<h3 style="display: flex; align-items: center; gap: 8px;">TSCM Sweep <span style="font-size: 9px; font-weight: normal; background: var(--accent-orange); color: #000; padding: 2px 6px; border-radius: 3px; text-transform: uppercase; letter-spacing: 0.5px;">Alpha</span></h3>
<div class="form-group">
<label>Sweep Type</label>
<select id="tscmSweepType">
<option value="quick">Quick Scan (2 min)</option>
<option value="standard" selected>Standard (5 min)</option>
<option value="full">Full Sweep (15 min)</option>
<option value="wireless_cameras">Wireless Cameras</option>
<option value="body_worn">Body-Worn Devices</option>
<option value="gps_trackers">GPS Trackers</option>
</select>
</div>
<div class="form-group">
<label>Compare Against</label>
<select id="tscmBaselineSelect">
<option value="">No Baseline</option>
</select>
</div>
</div>
<div class="section">
<h3>Scan Sources</h3>
<div class="form-group" style="margin-bottom: 8px;">
<div style="display: flex; align-items: center; gap: 8px;">
<input type="checkbox" id="tscmWifiEnabled" checked style="margin: 0;">
<label for="tscmWifiEnabled" style="flex: 1; margin: 0;">WiFi Networks</label>
</div>
<select id="tscmWifiInterface" style="width: 100%; margin-top: 4px; font-size: 11px;">
<option value="">Select WiFi interface...</option>
</select>
</div>
<div class="form-group" style="margin-bottom: 8px;">
<div style="display: flex; align-items: center; gap: 8px;">
<input type="checkbox" id="tscmBtEnabled" checked style="margin: 0;">
<label for="tscmBtEnabled" style="flex: 1; margin: 0;">Bluetooth Devices</label>
</div>
<select id="tscmBtInterface" style="width: 100%; margin-top: 4px; font-size: 11px;">
<option value="">Select Bluetooth adapter...</option>
</select>
</div>
<div class="form-group" style="margin-bottom: 8px;">
<div style="display: flex; align-items: center; gap: 8px;">
<input type="checkbox" id="tscmRfEnabled" style="margin: 0;">
<label for="tscmRfEnabled" style="flex: 1; margin: 0;">RF Signals</label>
</div>
<select id="tscmSdrDevice" style="width: 100%; margin-top: 4px; font-size: 11px;">
<option value="">Select SDR device...</option>
</select>
</div>
<button class="preset-btn" onclick="refreshTscmDevices()" style="width: 100%; margin-top: 8px; font-size: 10px;">
🔄 Refresh Devices
</button>
</div>
<div class="section">
<h3>Baseline Management</h3>
<div class="form-group">
<input type="text" id="tscmBaselineName" placeholder="Baseline name...">
</div>
<button class="run-btn" id="tscmRecordBaselineBtn" onclick="tscmRecordBaseline()" style="width: 100%; padding: 8px;">
Record New Baseline
</button>
<button class="stop-btn" id="tscmStopBaselineBtn" onclick="tscmStopBaseline()" style="width: 100%; padding: 8px; display: none;">
Stop Recording
</button>
<div id="tscmBaselineStatus" style="margin-top: 8px; font-size: 11px; color: var(--text-muted);"></div>
</div>
<button class="run-btn" id="startTscmBtn" onclick="startTscmSweep()">
Start Sweep
</button>
<button class="stop-btn" id="stopTscmBtn" onclick="stopTscmSweep()" style="display: none;">
Stop Sweep
</button>
<!-- Futuristic Scanner Progress -->
<div id="tscmProgress" class="tscm-scanner-progress" style="display: none;">
<div class="scanner-ring">
<svg viewBox="0 0 100 100">
<circle class="scanner-track" cx="50" cy="50" r="45" />
<circle class="scanner-progress" id="tscmScannerCircle" cx="50" cy="50" r="45" />
<line class="scanner-sweep" x1="50" y1="50" x2="50" y2="8" />
</svg>
<div class="scanner-center">
<span class="scanner-percent" id="tscmProgressPercent">0%</span>
</div>
</div>
<div class="scanner-info">
<div class="scanner-status" id="tscmProgressLabel">INITIALIZING</div>
<div class="scanner-devices">
<span class="device-indicator" id="tscmWifiIndicator" title="WiFi">📶</span>
<span class="device-indicator" id="tscmBtIndicator" title="Bluetooth">🔵</span>
<span class="device-indicator" id="tscmRfIndicator" title="RF/SDR">📡</span>
</div>
</div>
</div>
<!-- Device Warnings -->
<div id="tscmDeviceWarnings" style="display: none; margin-top: 8px; padding: 8px; background: rgba(255,153,51,0.1); border: 1px solid rgba(255,153,51,0.3); border-radius: 4px;"></div>
</div>

View File

@@ -0,0 +1,142 @@
<!-- WiFi MODE -->
<div id="wifiMode" class="mode-content">
<div class="section">
<h3>WiFi Adapter</h3>
<div class="form-group">
<label>Select Device</label>
<select id="wifiInterfaceSelect" style="font-size: 12px;">
<option value="">Detecting interfaces...</option>
</select>
</div>
<button class="preset-btn" onclick="refreshWifiInterfaces()" style="width: 100%;">
🔄 Refresh Devices
</button>
<div class="info-text" style="margin-top: 8px; display: grid; grid-template-columns: auto auto; gap: 4px 8px; align-items: center;" id="wifiToolStatus">
<span>airmon-ng:</span><span class="tool-status missing">Checking...</span>
<span>airodump-ng:</span><span class="tool-status missing">Checking...</span>
</div>
</div>
<div class="section">
<h3>Monitor Mode</h3>
<div style="display: flex; gap: 8px;">
<button class="preset-btn" id="monitorStartBtn" onclick="enableMonitorMode()" style="flex: 1; background: var(--accent-green); color: #000;">
Enable Monitor
</button>
<button class="preset-btn" id="monitorStopBtn" onclick="disableMonitorMode()" style="flex: 1; display: none;">
Disable Monitor
</button>
</div>
<div class="checkbox-group" style="margin-top: 8px;">
<label style="font-size: 10px;">
<input type="checkbox" id="killProcesses">
Kill interfering processes (may drop other connections)
</label>
</div>
<div id="monitorStatus" class="info-text" style="margin-top: 8px;">
Monitor mode: <span style="color: var(--accent-red);">Inactive</span>
</div>
</div>
<div class="section">
<h3>Scan Settings</h3>
<div class="form-group">
<label>Band</label>
<select id="wifiBand">
<option value="abg">All (2.4 + 5 GHz)</option>
<option value="bg">2.4 GHz only</option>
<option value="a">5 GHz only</option>
</select>
</div>
<div class="form-group">
<label>Channel (empty = hop)</label>
<input type="text" id="wifiChannel" placeholder="e.g., 6 or 36">
</div>
</div>
<div class="section">
<h3>Proximity Alerts</h3>
<div class="info-text" style="margin-bottom: 8px;">
Alert when specific MAC addresses appear
</div>
<div class="form-group">
<input type="text" id="watchMacInput" placeholder="AA:BB:CC:DD:EE:FF">
</div>
<button class="preset-btn" onclick="addWatchMac()" style="width: 100%; margin-bottom: 8px;">
Add to Watch List
</button>
<div id="watchList" style="max-height: 80px; overflow-y: auto; font-size: 10px; color: var(--text-dim);"></div>
</div>
<div class="section">
<h3>Attack Options</h3>
<div class="info-text" style="color: var(--accent-red); margin-bottom: 10px;">
⚠ Only use on authorized networks
</div>
<div class="form-group">
<label>Target BSSID</label>
<input type="text" id="targetBssid" placeholder="AA:BB:CC:DD:EE:FF">
</div>
<div class="form-group">
<label>Target Client (optional)</label>
<input type="text" id="targetClient" placeholder="FF:FF:FF:FF:FF:FF (broadcast)">
</div>
<div class="form-group">
<label>Deauth Count</label>
<input type="text" id="deauthCount" value="5" placeholder="5">
</div>
<button class="preset-btn" onclick="sendDeauth()" style="width: 100%; border-color: var(--accent-red); color: var(--accent-red);">
Send Deauth
</button>
</div>
<!-- Handshake Capture Status Panel -->
<div class="section" id="captureStatusPanel" style="display: none; border: 1px solid var(--accent-orange); border-radius: 4px; padding: 10px; background: rgba(255, 165, 0, 0.1);">
<h3 style="color: var(--accent-orange); margin: 0 0 8px 0;">🎯 Handshake Capture</h3>
<div style="font-size: 11px;">
<div style="margin-bottom: 4px;">
<span style="color: var(--text-dim);">Target:</span>
<span id="captureTargetBssid" style="font-family: monospace;">--</span>
</div>
<div style="margin-bottom: 4px;">
<span style="color: var(--text-dim);">Channel:</span>
<span id="captureTargetChannel">--</span>
</div>
<div style="margin-bottom: 4px;">
<span style="color: var(--text-dim);">File:</span>
<span id="captureFilePath" style="font-size: 9px; word-break: break-all;">--</span>
</div>
<div style="margin-bottom: 8px;">
<span style="color: var(--text-dim);">Status:</span>
<span id="captureStatus" style="font-weight: bold;">--</span>
</div>
<div style="display: flex; gap: 8px;">
<button class="preset-btn" onclick="checkCaptureStatus()" style="flex: 1; font-size: 10px; padding: 4px;">
Check Status
</button>
<button class="preset-btn" onclick="stopHandshakeCapture()" style="flex: 1; font-size: 10px; padding: 4px; background: var(--accent-red); border: none; color: #fff;">
Stop Capture
</button>
</div>
</div>
</div>
<!-- Beacon Flood Alert Panel -->
<div id="beaconFloodAlert" class="beacon-flood-alert" style="display: none;">
<h4 style="color: #ff4444; margin: 0 0 8px 0;">⚠️ BEACON FLOOD DETECTED</h4>
<div style="font-size: 11px;">
<div id="beaconFloodDetails">Multiple beacon frames detected from same channel</div>
<div style="margin-top: 8px;">
<span style="color: var(--text-dim);">Networks/sec:</span>
<span id="beaconFloodRate" style="font-weight: bold; color: #ff4444;">--</span>
</div>
</div>
</div>
<button class="run-btn" id="startWifiBtn" onclick="startWifiScan()">
Start Scanning
</button>
<button class="stop-btn" id="stopWifiBtn" onclick="stopWifiScan()" style="display: none;">
Stop Scanning
</button>
</div>