* { box-sizing: border-box; } body { margin: 0; font-family: system-ui, sans-serif; background: #1a1a2e; color: #eee; } header { padding: 12px 16px; background: #16213e; display: flex; gap: 12px; align-items: center; flex-wrap: wrap; } header h1 { margin: 0; font-size: 1.2rem; flex: 1; } main { display: grid; grid-template-columns: 1fr 340px; grid-template-rows: 1fr auto; height: calc(100vh - 52px); } @media (max-width: 900px) { main { grid-template-columns: 1fr; grid-template-rows: minmax(200px, 38vh) auto minmax(160px, 1fr); overflow-y: auto; } #mapWrap { grid-row: 1; } #trackTimeline { grid-row: 2; } aside { grid-row: 3; } } #mapWrap { grid-column: 1; grid-row: 1; position: relative; min-height: 0; } #map { width: 100%; height: 100%; } .leaflet-control-layers { background: #16213e; color: #eee; border: 1px solid #444; } .leaflet-control-layers label { color: #eee; } #trackTimeline { display: none; grid-column: 1 / -1; grid-row: 2; background: #16213e; padding: 8px 16px; border-top: 1px solid #333; } #trackTimeline.visible { display: block; min-height: 200px; flex-shrink: 0; } .timeline-bar { display: flex; flex-direction: column; gap: 6px; } .timeline-bar-header { display: flex; justify-content: space-between; align-items: center; gap: 8px; } .timeline-bar-title { font-size: 0.85rem; font-weight: 600; } .timeline-bar .timeline-labels { width: 100%; margin: 0; } .timeline-bar #timeSlider { width: 100%; margin: 0; } #elevationPanel { margin-top: 8px; padding: 8px 10px; background: #0f3460; border: 1px solid #00ff8844; border-radius: 6px; } #elevationPanelTitle { font-size: 0.8rem; color: #00ff88; margin-bottom: 6px; display: flex; justify-content: space-between; align-items: center; font-weight: 600; } #elevationStatus { font-size: 0.7rem; color: #aaa; font-weight: 400; } #elevationCanvas { width: 100%; height: 130px; display: block; background: #0a0a14; border-radius: 4px; } #elevationCanvas.elev-probe { cursor: crosshair; } .elev-legend { font-size: 0.7rem; } #qualityVizPanel { display: none; margin-top: 8px; } #qualityVizPanel.visible { display: block; } .quality-viz-box { background: #0f3460; border: 1px solid #444; border-radius: 6px; padding: 6px; } .quality-viz-title { font-size: 0.7rem; color: #aaa; margin-bottom: 4px; } #qualityDistCanvas { width: 100%; height: 140px; display: block; background: #0a0a14; border-radius: 4px; } #timelineStatsPanel { display: none; margin-top: 10px; padding-top: 10px; border-top: 1px solid #333; } #timelineStatsPanel.visible { display: block; } #timelineStatsPanel.timeline-single #distanceNow { display: none; } #timelineNote { font-size: 0.75rem; color: #aaa; margin: 4px 0 8px; } #timeSlider { width: 100%; margin: 6px 0; } .timeline-labels { display: flex; justify-content: space-between; font-size: 0.75rem; color: #aaa; } #timelineStats { margin-top: 8px; font-size: 0.8rem; } .radio-compare-grid { background: #0a0a14; padding: 8px; border-radius: 4px; } .radio-compare-head { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 6px; font-weight: 600; } .radio-row { display: grid; grid-template-columns: 72px 1fr 1fr; gap: 6px; padding: 2px 0; } .radio-label { color: #aaa; } .radio-tx { color: #e94560; min-width: 0; word-break: break-all; } .radio-rx { color: #4fc3f7; min-width: 0; word-break: break-all; } .radio-row .changed, .changed { background: #e9456033; border-radius: 3px; padding: 0 2px; } .radio-static summary { cursor: pointer; color: #aaa; margin: 4px 0; } #stats .changed { background: #e9456033; border-radius: 3px; } #distanceNow { font-size: 0.9rem; margin-top: 4px; color: #00ff88; } aside { grid-column: 2; grid-row: 1; overflow: auto; padding: 12px; border-left: 1px solid #333; display: flex; flex-direction: column; gap: 12px; } @media (max-width: 900px) { aside { grid-column: 1; grid-row: 2; border-left: none; border-top: 1px solid #333; } } .panel { background: #0f3460; border-radius: 8px; padding: 10px; } .panel h2 { margin: 0 0 8px; font-size: 0.95rem; } #deviceList { list-style: none; padding: 0; margin: 0; max-height: 140px; overflow: auto; } #deviceList li { padding: 6px 8px; cursor: pointer; border-radius: 4px; font-size: 0.85rem; } #deviceList li:hover, #deviceList li.active { background: #e94560; } #stats { font-size: 0.85rem; line-height: 1.5; } #history { font-size: 0.75rem; max-height: 100px; overflow: auto; } #chatLog { height: 140px; overflow: auto; font-size: 0.8rem; background: #0a0a14; padding: 8px; border-radius: 4px; display: flex; flex-direction: column; gap: 4px; } .chat-msg { max-width: 85%; padding: 6px 8px; border-radius: 8px; line-height: 1.35; } .chat-self { align-self: flex-end; background: #16213e; text-align: right; } .chat-other { align-self: flex-start; background: #1a4a6e; } .chat-new { box-shadow: inset 0 0 0 1px #e94560; } .chat-meta { font-size: 0.7rem; color: #aaa; margin-bottom: 2px; } #chatForm { display: flex; gap: 6px; margin-top: 6px; } #chatForm input { flex: 1; padding: 6px; border: none; border-radius: 4px; } #chatForm button { padding: 6px 12px; background: #e94560; color: #fff; border: none; border-radius: 4px; cursor: pointer; } .track-row { margin-bottom: 6px; } .track-row label { font-size: 0.75rem; color: #aaa; display: block; margin-bottom: 2px; } .track-row select { width: 100%; padding: 4px; } .track-actions { display: flex; gap: 6px; margin-top: 4px; } .track-actions button { flex: 1; padding: 6px; border: none; border-radius: 4px; cursor: pointer; font-weight: 600; font-size: 0.8rem; } #btnShowTracks { background: #00ff88; color: #111; } #btnHideTracks { background: #333; color: #eee; } #btnHideTracks:disabled { opacity: 0.4; cursor: not-allowed; } .track-mode { display: flex; gap: 4px; margin-bottom: 8px; } .track-mode button { flex: 1; padding: 4px; font-size: 0.75rem; border: 1px solid #444; background: #0a0a14; color: #ccc; border-radius: 4px; cursor: pointer; } .track-mode button.active { background: #e94560; color: #fff; border-color: #e94560; } #controlPanel input, #controlPanel select { width: 100%; padding: 4px; margin-top: 2px; border-radius: 4px; border: none; font-size: 0.8rem; } #controlPanel .cmd-row { display: flex; gap: 4px; margin-top: 6px; flex-wrap: wrap; } #controlPanel .cmd-row button { padding: 4px 8px; font-size: 0.75rem; border: none; border-radius: 4px; cursor: pointer; background: #16213e; color: #eee; } #macroPresetPanel input, #macroPresetPanel select, #referencePointPanel select { width: 100%; padding: 4px; margin-top: 4px; border-radius: 4px; border: none; font-size: 0.8rem; } #macroPresetPanel .cmd-row { display: flex; gap: 4px; flex-wrap: wrap; } #macroPresetPanel .cmd-row button, #referencePointPanel button { flex: 1; padding: 5px 8px; font-size: 0.75rem; border: none; border-radius: 4px; cursor: pointer; background: #16213e; color: #eee; } #referencePointSummary { margin-top: 6px; line-height: 1.45; } #referencePointChart { width: 100%; height: 140px; display: block; margin-top: 6px; background: #0a0a14; border-radius: 4px; } .metric-card { background: #0a0a14; border-radius: 4px; padding: 6px; margin-top: 6px; } .metric-card b { color: #00ff88; } .metric-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; margin-top: 4px; } .metric-grid span { background: #16213e; border-radius: 3px; padding: 4px; text-align: center; } #pairedStatus { font-size: 0.75rem; color: #aaa; margin-top: 4px; } .muted { color: #aaa; font-size: 0.75rem; } .legend { font-size: 0.75rem; color: #ccc; } .legend-tx { color: #4fc3f7; } .legend-rx { color: #e94560; } #mapModal { display: none; position: fixed; z-index: 2000; min-width: 260px; max-width: 360px; max-height: 70vh; overflow: auto; background: #0f3460; border: 1px solid #444; border-radius: 8px; box-shadow: 0 8px 32px rgba(0,0,0,0.5); } #mapModal.open { display: block; } #mapModalHeader { padding: 8px 10px; background: #16213e; cursor: move; display: flex; justify-content: space-between; align-items: center; user-select: none; border-radius: 8px 8px 0 0; } #mapModalHeader span { font-size: 0.85rem; font-weight: 600; } #mapModalClose { background: none; border: none; color: #eee; font-size: 1.2rem; cursor: pointer; padding: 0 4px; } #mapModalBody { padding: 10px; font-size: 0.85rem; line-height: 1.45; } #mapCenterBar { position: absolute; top: 10px; right: 10px; left: auto; z-index: 1000; display: flex; gap: 4px; flex-wrap: wrap; pointer-events: auto; } #mapWrap .leaflet-top.leaflet-right { top: 46px; right: 10px; margin-top: 0; } #mapWrap .leaflet-control-layers-toggle { width: 30px; height: 30px; line-height: 30px; } #mapCenterBar button { padding: 5px 10px; font-size: 0.75rem; border: 1px solid #444; border-radius: 4px; background: #16213ee6; color: #eee; cursor: pointer; box-shadow: 0 1px 4px rgba(0,0,0,0.35); } #mapCenterBar button:hover { background: #1f3460; } #mapCenterBar button.active { background: #00ff88; color: #111; border-color: #00ff88; } .leaflet-top.leaflet-left { margin-top: 0; margin-left: 0; } #gpsDistance { color: #00ff88; font-size: 0.8rem; } #mapRulerPanel { display: none; position: absolute; left: 8px; right: 8px; bottom: 8px; z-index: 1000; background: #16213ef0; border: 1px solid #00ff8866; border-radius: 8px; padding: 8px 10px; pointer-events: auto; } #mapRulerPanel.open { display: block; } #mapRulerHead { display: flex; justify-content: space-between; align-items: center; font-size: 0.8rem; color: #00ff88; font-weight: 600; margin-bottom: 6px; } #mapRulerStatus { font-size: 0.7rem; color: #aaa; font-weight: 400; } #btnMapRulerClose { background: none; border: none; color: #eee; font-size: 1.1rem; cursor: pointer; padding: 0 4px; line-height: 1; } #mapRulerCanvas { width: 100%; height: 120px; display: block; background: #0a0a14; border-radius: 4px; cursor: crosshair; } #mapRulerTools { display: flex; gap: 4px; margin-bottom: 6px; flex-wrap: wrap; } #mapRulerTools button { padding: 3px 8px; font-size: 0.7rem; border: 1px solid #444; border-radius: 4px; background: #0a0a14; color: #ccc; cursor: pointer; } #mapRulerTools button.active { background: #00ff88; color: #111; border-color: #00ff88; } #mapRulerHint { font-size: 0.7rem; color: #aaa; margin-bottom: 4px; min-height: 1em; } #mapRulerPointsRow { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; flex-wrap: wrap; font-size: 0.7rem; color: #ccc; } #mapRulerPointsRow label { display: flex; align-items: center; gap: 4px; cursor: pointer; white-space: nowrap; } #mapRulerPointsSlider { flex: 1; min-width: 120px; accent-color: #00ff88; } #mapRulerPointsSlider:disabled { opacity: 0.45; } #mapRulerPointsLabel { min-width: 7em; color: #aaa; white-space: nowrap; } #apiDebugPanel { display: none; position: absolute; top: 50px; right: 10px; z-index: 1001; width: min(440px, calc(100% - 20px)); max-height: calc(100% - 70px); overflow: auto; background: #16213ef2; border: 1px solid #4fc3f766; border-radius: 8px; padding: 10px; pointer-events: auto; box-shadow: 0 8px 32px rgba(0,0,0,0.45); } #apiDebugPanel.open { display: block; } #apiDebugHead { display: flex; justify-content: space-between; align-items: center; gap: 8px; color: #4fc3f7; font-size: 0.85rem; font-weight: 600; margin-bottom: 8px; } #btnApiDebugClose { background: none; border: none; color: #eee; font-size: 1.15rem; cursor: pointer; padding: 0 4px; line-height: 1; } #apiDebugPanel label { display: block; color: #aaa; font-size: 0.72rem; margin-top: 6px; } #apiDebugPanel input, #apiDebugPanel select { width: 100%; margin-top: 2px; padding: 5px 6px; border: none; border-radius: 4px; background: #0a0a14; color: #eee; font-size: 0.78rem; } #apiDebugPanel .api-debug-check { display: flex; align-items: center; gap: 6px; margin-top: 22px; color: #ccc; font-size: 0.72rem; cursor: pointer; } #apiDebugPanel .api-debug-check input { width: auto; margin: 0; } .api-debug-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 6px; } .api-debug-actions { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; } .api-debug-actions button { padding: 5px 8px; font-size: 0.72rem; border: 1px solid #444; border-radius: 4px; background: #0a0a14; color: #eee; cursor: pointer; } .api-debug-actions button:hover { background: #1f3460; } .api-debug-actions button.active { background: #4fc3f7; color: #08111b; border-color: #4fc3f7; } .api-debug-section { margin-top: 8px; padding-top: 8px; border-top: 1px solid #333; } .api-debug-section-title { color: #4fc3f7; font-size: 0.75rem; font-weight: 600; margin-bottom: 4px; } .api-debug-help { color: #aaa; font-size: 0.7rem; line-height: 1.35; } #apiDebugStatus { margin-top: 8px; color: #aaa; font-size: 0.72rem; min-height: 1.1em; } #apiDebugOutput { margin: 6px 0 0; padding: 8px; max-height: 260px; overflow: auto; background: #0a0a14; border: 1px solid #333; border-radius: 4px; color: #d7f7ff; font-size: 0.72rem; white-space: pre-wrap; } #apiDebugChart { width: 100%; height: 140px; display: block; margin-top: 8px; background: #0a0a14; border-radius: 4px; } .api-debug-legend { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin-top: 5px; color: #aaa; font-size: 0.7rem; } .api-debug-legend span { display: inline-flex; align-items: center; gap: 4px; } .api-debug-swatch { width: 16px; height: 3px; border-radius: 2px; display: inline-block; } #apiDebugSummary { margin-top: 8px; padding: 8px; background: #0a0a14; border: 1px solid #333; border-radius: 4px; font-size: 0.75rem; line-height: 1.45; } .api-debug-mini { color: #aaa; font-size: 0.7rem; margin-top: 4px; }