{% extends "base.html" %} {% block title %}SDR — SignalOps{% endblock %} {% block extra_style %} #sdr-map{width:100%;height:100%;background:#000} .layer-row{display:flex;align-items:center;justify-content:space-between;padding:8px 10px;border-radius:6px;background:var(--e);margin-bottom:6px;cursor:pointer;user-select:none;border:1px solid transparent;transition:border-color 0.15s} .layer-row:hover{border-color:rgba(138, 122, 184,0.25)} .layer-row.active{border-color:rgba(138, 122, 184,0.4);background:rgba(138, 122, 184,0.06)} .layer-row span.name{font-family:'Rajdhani',sans-serif;font-weight:600;font-size:12px;letter-spacing:1px;color:var(--t)} .layer-row span.cnt{font-size:10px;color:var(--tm);font-family:monospace} .node-row{background:var(--s);border:1px solid var(--b);border-radius:6px;padding:9px 11px;cursor:pointer;transition:border-color 0.15s} .node-row:hover{border-color:rgba(138, 122, 184,0.35)} #tuner-panel{position:fixed;right:20px;bottom:20px;width:560px;height:480px;background:var(--s);border:1px solid rgba(138, 122, 184,0.3);border-radius:10px;box-shadow:0 12px 40px rgba(0,0,0,0.6);z-index:2000;display:none;overflow:hidden;flex-direction:column} #tuner-panel.open{display:flex} #tuner-hdr{padding:10px 14px;background:rgba(138, 122, 184,0.08);border-bottom:1px solid rgba(138, 122, 184,0.2);display:flex;align-items:center;justify-content:space-between} #tuner-hdr .ttl{font-family:'Rajdhani',sans-serif;font-size:13px;font-weight:700;letter-spacing:2px;color:var(--pl)} #tuner-hdr .x{background:none;border:none;color:var(--td);cursor:pointer;font-size:18px;padding:0 4px} #tuner-freqbar{padding:10px 12px;background:rgba(0,0,0,0.25);border-bottom:1px solid rgba(138, 122, 184,0.15)} #tuner-freq{font-family:'JetBrains Mono',monospace;font-size:14px;color:#B4A8D6;text-align:center;letter-spacing:2px;margin-bottom:8px;font-weight:600} #tuner-presets{display:flex;gap:4px;flex-wrap:wrap;margin-bottom:6px} #tuner-presets button{flex:1;min-width:54px;padding:4px 6px;background:rgba(138, 122, 184,0.1);color:#B4A8D6;border:1px solid rgba(138, 122, 184,0.3);border-radius:3px;cursor:pointer;font-family:'JetBrains Mono',monospace;font-size:10px;font-weight:600} #tuner-presets button:hover{background:rgba(138, 122, 184,0.25);border-color:rgba(138, 122, 184,0.6)} #tuner-custom{display:flex;gap:4px} #tuner-custom input{flex:1;padding:4px 8px;background:rgba(0,0,0,0.3);color:var(--t);border:1px solid rgba(138, 122, 184,0.25);border-radius:3px;font-family:'JetBrains Mono',monospace;font-size:11px} #tuner-custom select{padding:4px 6px;background:rgba(0,0,0,0.3);color:var(--t);border:1px solid rgba(138, 122, 184,0.25);border-radius:3px;font-family:'JetBrains Mono',monospace;font-size:11px} #tuner-custom button{padding:4px 12px;background:rgba(138, 122, 184,0.2);color:#B4A8D6;border:1px solid rgba(138, 122, 184,0.4);border-radius:3px;cursor:pointer;font-family:'Rajdhani',sans-serif;font-size:11px;font-weight:700;letter-spacing:1px} #tuner-iframe-wrap{flex:1;position:relative;background:#000;display:flex} #tuner-iframe{flex:1;border:0;background:#000;width:100%;height:100%} #tuner-overlay{position:absolute;inset:0;display:none;align-items:center;justify-content:center;background:rgba(11, 11, 15,0.92);flex-direction:column;padding:24px;text-align:center;pointer-events:none} #tuner-overlay.show{display:flex;pointer-events:auto} #tuner-overlay .ic{font-size:36px;margin-bottom:12px} #tuner-overlay .msg{font-family:'Rajdhani',sans-serif;font-size:14px;color:var(--t);font-weight:600;letter-spacing:1px;margin-bottom:6px} #tuner-overlay .sub{font-family:monospace;font-size:11px;color:var(--tm);max-width:400px;line-height:1.5} #tuner-overlay .spinner{width:30px;height:30px;border:3px solid rgba(138, 122, 184,0.2);border-top-color:#B4A8D6;border-radius:50%;animation:spin 0.8s linear infinite;margin-bottom:12px} @keyframes spin{to{transform:rotate(360deg)}} #tuner-hint{position:absolute;top:10px;right:10px;width:260px;background:linear-gradient(135deg,rgba(138, 122, 184,0.96),rgba(76,29,149,0.96));border:1px solid rgba(180, 168, 214,0.6);border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,0.5);padding:0;display:none;flex-direction:column;z-index:10;opacity:0;transform:translateX(8px);transition:opacity 0.3s ease, transform 0.3s ease;backdrop-filter:blur(6px)} #tuner-hint.show{display:flex;opacity:1;transform:translateX(0)} #tuner-hint .h-hdr{display:flex;justify-content:space-between;align-items:center;padding:8px 10px;border-bottom:1px solid rgba(255,255,255,0.15)} #tuner-hint .h-title{font-family:'Rajdhani',sans-serif;font-size:11px;font-weight:700;color:#fff;letter-spacing:2px} #tuner-hint .h-x{background:none;border:none;color:rgba(255,255,255,0.7);cursor:pointer;font-size:14px;padding:0 4px;line-height:1} #tuner-hint .h-x:hover{color:#fff} #tuner-hint .h-body{padding:10px;font-size:11px;color:#fff;line-height:1.5;font-family:'JetBrains Mono',monospace} #tuner-hint .h-kbd{display:inline-block;background:rgba(255,255,255,0.2);border:1px solid rgba(255,255,255,0.35);border-radius:3px;padding:1px 6px;margin:0 2px;font-weight:700;color:#fff} #tuner-hint .h-ok{margin:0 10px 10px;background:rgba(0,0,0,0.3);color:#fff;border:1px solid rgba(255,255,255,0.3);border-radius:4px;padding:6px 8px;cursor:pointer;font-family:'Rajdhani',sans-serif;font-size:10px;font-weight:700;letter-spacing:1.2px} #tuner-hint .h-ok:hover{background:rgba(0,0,0,0.5);border-color:rgba(255,255,255,0.5)} #aprs-panel{position:fixed;left:20px;bottom:20px;width:420px;max-height:75vh;background:var(--s);border:1px solid rgba(201, 161, 90,0.35);border-radius:10px;box-shadow:0 12px 40px rgba(0,0,0,0.6);z-index:2000;display:none;overflow:hidden;flex-direction:column} #aprs-panel.open{display:flex} #aprs-hdr{padding:10px 14px;background:rgba(201, 161, 90,0.08);border-bottom:1px solid rgba(201, 161, 90,0.2);display:flex;align-items:center;justify-content:space-between} #aprs-hdr .ttl{font-family:'Rajdhani',sans-serif;font-size:13px;font-weight:700;letter-spacing:2px;color:#C9A15A} #aprs-hdr .x{background:none;border:none;color:var(--td);cursor:pointer;font-size:18px;padding:0 4px} #aprs-body{padding:12px 14px;overflow-y:auto;font-size:11px;color:var(--td);line-height:1.5} #aprs-body .sec{display:flex;align-items:center;font-family:'Rajdhani',sans-serif;font-size:10px;font-weight:700;color:#C9A15A;letter-spacing:2px;text-transform:uppercase;margin-top:10px;margin-bottom:4px;padding-bottom:3px;border-bottom:1px solid rgba(201, 161, 90,0.2)} #aprs-body .sec:first-child{margin-top:0} #aprs-body .row{display:flex;padding:4px 0;gap:10px} #aprs-body .lbl{color:var(--tm);min-width:95px;font-size:10px;letter-spacing:0.5px;text-transform:uppercase} #aprs-body .val{color:var(--t);flex:1;word-break:break-all;font-family:'JetBrains Mono',monospace} #aprs-body .pkts{max-height:220px;overflow-y:auto;margin-top:4px;padding-right:4px} #aprs-body .pkt{background:rgba(0,0,0,0.25);border-left:2px solid rgba(201, 161, 90,0.3);padding:5px 8px;margin-bottom:4px;border-radius:0 3px 3px 0;font-family:'JetBrains Mono',monospace;font-size:10px} #aprs-body .pkt-ts{color:#C9A15A;margin-right:6px} #aprs-body .pkt-cmt{color:var(--t);margin-top:3px;word-break:break-word} #aprs-body .pkt-data{color:var(--tm);margin-top:2px;font-size:9px} /* ═══ MAP STYLE TOGGLE (base + overlay) ═══ */ #map-style-toggle{ position:absolute; bottom:14px;left:14px; background:rgba(11, 11, 15,0.92); backdrop-filter:blur(14px) saturate(1.2); -webkit-backdrop-filter:blur(14px) saturate(1.2); border:1px solid rgba(138, 122, 184,0.28); border-radius:10px; padding:4px; z-index:500; display:flex;flex-direction:column;gap:2px; box-shadow:0 10px 30px rgba(0,0,0,0.55), inset 0 1px 0 rgba(255,255,255,0.04); font-family:'Rajdhani',sans-serif; } #map-style-toggle .mst-row{display:flex;gap:1px;padding:2px} #map-style-toggle .mst-sep{ height:1px;margin:1px 8px; background:linear-gradient(to right, transparent, rgba(138, 122, 184,0.25), transparent); } #map-style-toggle button{ background:transparent;border:none; color:var(--td); font-family:'Rajdhani',sans-serif;font-size:10px;font-weight:700; letter-spacing:1.2px; padding:6px 10px;border-radius:6px; cursor:pointer;transition:all 0.18s ease; display:inline-flex;align-items:center;gap:5px; position:relative; } #map-style-toggle button svg{ width:13px;height:13px;flex-shrink:0; stroke:currentColor;fill:none; stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round; opacity:0.85;transition:opacity 0.15s, transform 0.2s; } #map-style-toggle button:hover{color:var(--t);background:rgba(138, 122, 184,0.08)} #map-style-toggle button:hover svg{opacity:1;transform:scale(1.08)} #map-style-toggle .mst-base button.active{ color:#C3B8E2; background:linear-gradient(180deg, rgba(138, 122, 184,0.25), rgba(138, 122, 184,0.12)); box-shadow:inset 0 0 0 1px rgba(180, 168, 214,0.4), 0 0 12px rgba(138, 122, 184,0.2); } #map-style-toggle .mst-base button.active svg{opacity:1} #map-style-toggle .mst-overlay button.active{ color:#FCD34D; background:linear-gradient(180deg, rgba(201, 161, 90,0.2), rgba(201, 161, 90,0.08)); box-shadow:inset 0 0 0 1px rgba(201, 161, 90,0.45), 0 0 10px rgba(201, 161, 90,0.18); } #map-style-toggle .mst-overlay button.active svg{opacity:1} /* Attribution control styling */ .leaflet-control-attribution{ background:rgba(8,11,9,0.7) !important; color:var(--tm) !important; font-size:9px !important; padding:2px 6px !important; border-radius:4px 0 0 0 !important; } .leaflet-control-attribution a{color:var(--td) !important} /* ═══ MAP HUD OVERLAY (live map-derived values) ═══ */ #drone-hud{ position:absolute;inset:0;pointer-events:none;z-index:450; display:none; font-family:'JetBrains Mono',monospace;color:#4ADE80; text-shadow:0 0 4px rgba(74,222,128,0.6); } #drone-hud.active{display:block} #drone-hud::before{ content:'';position:absolute;inset:0; background: radial-gradient(ellipse at center, transparent 35%, rgba(0,0,0,0.35) 100%), linear-gradient(rgba(74,222,128,0.04) 1px, transparent 1px), linear-gradient(90deg, rgba(74,222,128,0.04) 1px, transparent 1px); background-size:100% 100%, 40px 40px, 40px 40px; pointer-events:none; } #drone-hud .dh-cross{ position:absolute;top:50%;left:50%; width:80px;height:80px; transform:translate(-50%,-50%); } #drone-hud .dh-cross::before, #drone-hud .dh-cross::after{ content:'';position:absolute;background:#4ADE80; box-shadow:0 0 6px rgba(74,222,128,0.8); } #drone-hud .dh-cross::before{left:50%;top:0;bottom:0;width:1px;transform:translateX(-0.5px)} #drone-hud .dh-cross::after{top:50%;left:0;right:0;height:1px;transform:translateY(-0.5px)} #drone-hud .dh-cross .dh-dot{ position:absolute;top:50%;left:50%;width:8px;height:8px; border:1px solid #4ADE80;border-radius:50%; transform:translate(-50%,-50%); } #drone-hud .dh-corner{ position:absolute;width:28px;height:28px; border-color:#4ADE80;border-style:solid; } #drone-hud .dh-tl{top:16px;left:16px;border-width:2px 0 0 2px} #drone-hud .dh-tr{top:16px;right:16px;border-width:2px 2px 0 0} #drone-hud .dh-bl{bottom:16px;left:16px;border-width:0 0 2px 2px} #drone-hud .dh-br{bottom:16px;right:16px;border-width:0 2px 2px 0} #drone-hud .dh-telemetry{ position:absolute;top:20px;left:56px; font-size:10px;letter-spacing:1.5px;line-height:1.7; } #drone-hud .dh-telemetry .k{color:rgba(74,222,128,0.5);margin-right:6px} #drone-hud .dh-telemetry .v{color:#4ADE80;font-weight:700} #drone-hud .dh-status{ position:absolute;top:20px;right:56px;text-align:right; font-size:10px;letter-spacing:2px; } #drone-hud .dh-status .rec{ display:inline-block;width:8px;height:8px;border-radius:50%; background:#F87171;margin-right:6px; animation:dh-blink 1s infinite; box-shadow:0 0 8px rgba(248,113,113,0.8); } @keyframes dh-blink{0%,50%{opacity:1}51%,100%{opacity:0.2}} #drone-hud .dh-altbar{ position:absolute;right:24px;top:50%;transform:translateY(-50%); width:4px;height:180px;background:rgba(74,222,128,0.15);border-radius:2px; } #drone-hud .dh-altbar::before{ content:'';position:absolute;left:-1px;right:-1px;bottom:0; height:var(--dh-zoom-pct,60%);background:linear-gradient(to top, #4ADE80, rgba(74,222,128,0.3)); border-radius:2px;box-shadow:0 0 6px rgba(74,222,128,0.6); } #drone-hud .dh-footer{ position:absolute;bottom:20px;left:56px;right:56px; display:flex;justify-content:space-between;font-size:9px; letter-spacing:2px;color:rgba(74,222,128,0.7); } /* ═══ MGRS GRID LABEL ═══ */ .mgrs-lbl{ background:rgba(11, 11, 15,0.85); color:#C9A15A; font-family:'JetBrains Mono',monospace; font-size:9px;font-weight:700; padding:1px 4px;border:1px solid rgba(201, 161, 90,0.3); border-radius:2px;letter-spacing:0.5px; white-space:nowrap;pointer-events:none; } /* Drone-mode subtle map desaturation for immersion */ .sdr-map-drone{filter:contrast(1.15) saturate(0.75) brightness(0.9)} /* ═══ RESPONSIVE — map toolbar + HUD (desktop >900px unchanged) ═══ */ @media (max-width:900px){ #map-style-toggle{left:8px;bottom:8px;max-width:calc(100% - 16px)} #map-style-toggle .mst-row{flex-wrap:wrap} #map-style-toggle button{min-height:36px;padding:6px 9px} #drone-hud .dh-corner{width:20px;height:20px} #drone-hud .dh-tl{top:10px;left:10px} #drone-hud .dh-tr{top:10px;right:10px} #drone-hud .dh-bl{bottom:10px;left:10px} #drone-hud .dh-br{bottom:10px;right:10px} #drone-hud .dh-telemetry{top:14px;left:54px;font-size:9px;letter-spacing:0.5px;line-height:1.6} #drone-hud .dh-status{top:14px;right:38px;font-size:9px;letter-spacing:0.5px} #drone-hud .dh-altbar{right:14px;height:110px} #drone-hud .dh-footer{top:96px;bottom:auto;left:54px;right:38px;font-size:8px;letter-spacing:0.5px;gap:8px;flex-wrap:wrap} .leaflet-popup-content{max-width:calc(100vw - 80px)} } @media (max-width:600px){ /* icon-only map toolbar on phones (labels stay in title tooltips) */ #map-style-toggle button{font-size:0;gap:0;min-width:36px;justify-content:center;padding:6px} #map-style-toggle button svg{width:16px;height:16px} } /* ═══ RESPONSIVE — page layout ═══ */ @media (max-width:900px){ .sdr-grid{grid-template-columns:minmax(0,1fr) !important;height:auto !important;gap:12px !important} .sdr-side{display:contents} .sdr-side > .card{order:2;margin-bottom:0 !important} .sdr-side > .card:first-child{order:0} .sdr-map-card{order:1;height:60vh;min-height:360px;margin-bottom:0} .sdr-side .btn{min-height:40px} .layer-row{min-height:40px} .layer-row span.cnt{max-width:55%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:right} .node-row{overflow-wrap:anywhere} #tuner-panel{left:8px;right:8px;bottom:8px;width:auto;height:min(480px,calc(100vh - var(--so-nav-h,62px) - 16px))} #tuner-presets button{min-height:34px} #tuner-custom input,#tuner-custom select,#tuner-custom button{min-height:36px} #tuner-custom input{min-width:90px} #tuner-custom select{flex:0 0 auto;width:auto} #tuner-hint{width:auto;left:10px} #aprs-panel{left:8px;right:8px;bottom:8px;width:auto;max-height:70vh} #aprs-body .lbl{min-width:80px} } @media (max-width:600px){ .sdr-side > .card{padding:14px} } {% endblock %} {% block content %}