/* ═══════════════════════════════════════════════════════════════
   Satellite Viewer — satellite_styles.css
   Lightweight plan-view satellite imagery page styles.
   Embedded as a tab within the Real-Time Monitor page.
   ═══════════════════════════════════════════════════════════════ */

/* ── Shared chrome geometry ─────────────────────────────────── */

/* Topbar + secondary bar heights — INCLUDING their 1px bottom
   borders — so consumers (sat-main, sub-main, seasonal-main) can
   stack their `top:` cleanly via calc(). Override per breakpoint. */
:root {
    --topbar-h: 53px;          /* .topbar-inner 52px + 1px border */
    --secondary-bar-h: 32px;
}
@media (max-width: 768px) {
    :root {
        --topbar-h: 47px;      /* .topbar-inner 46px + 1px border */
        --secondary-bar-h: 36px;
    }
}

/* ── Secondary Bar (view tabs + storm counts) ───────────────── */

.ir-secondary-bar {
    position: fixed;
    top: var(--topbar-h);
    left: 0;
    right: 0;
    height: var(--secondary-bar-h);
    background: #12141c;
    border-bottom: 1px solid #2a2d38;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 16px;
    z-index: 100;
    /* Include the 1px bottom border in the bar height so flex children
       center inside the visible bar, not the content box. The 1px
       top padding compensates for the bottom border. */
    box-sizing: border-box;
    padding-top: 1px;
}

.ir-view-tabs {
    /* Flat-with-underline submenu — matches the Global Archive's
       .ga-tabs treatment for a consistent navigation feel across
       pages. No background container; tabs sit directly on the
       .ir-secondary-bar's dark surface. */
    display: flex;
    gap: 2px;
    background: transparent;
    border-radius: 0;
    padding: 0;
    border: none;
    /* Align tabs to the bottom edge of the bar so the active
       underline meets the bar's bottom border seamlessly. */
    align-self: stretch;
    align-items: flex-end;
}

.ir-view-tab {
    background: transparent;
    color: #8b8fa4;
    border: none;
    border-radius: 0;
    /* Match .ga-tab proportions: taller padding, slightly larger
       font, and a 2 px transparent bottom-border slot that turns
       solid on active so the layout doesn't shift when tabs flip. */
    padding: 8px 18px;
    font-size: 13px;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    transition: color 0.15s, border-color 0.15s, background 0.15s;
    line-height: 1.3;
    letter-spacing: 0.01em;
    border-bottom: 2px solid transparent;
}

.ir-view-tab:hover {
    color: #e0e0e0;
    background: rgba(255, 255, 255, 0.03);
}

.ir-view-tab.active {
    color: #fb923c;
    border-bottom-color: #fb923c;
    background: transparent;
    box-shadow: none;
}

/* Mobile tweaks — vars in :root already widen the bar to 36px. */
@media (max-width: 768px) {
    .ir-secondary-bar {
        justify-content: center;
        padding: 0 8px;
    }
    .ir-view-tab {
        font-size: 13px;
        padding: 7px 14px;
    }
    .ir-storm-counts {
        display: none !important;
    }
}

/* Tab label swap — long labels wrap to 2 lines on narrow viewports
   ("Global / Map", "Storm / Satellite"). Shorter forms kick in at
   ≤640px while still leaving room on small tablets. */
.ir-view-tab .tab-short { display: none; }
@media (max-width: 640px) {
    .ir-view-tab .tab-full  { display: none; }
    .ir-view-tab .tab-short { display: inline; }
    /* Even the SHORT labels still wrapped at 375px: the five tabs' natural
       widths (~374px incl. gaps) exceed the bar, so flex shrank each one
       below its text width and "Storm Sat" broke onto two lines. That grew
       the button to 50px inside a 35px bar, and .ir-view-tabs'
       align-items:flex-end pins buttons to the bar's BOTTOM — so the extra
       height pushed the first line up under the header, where it was
       clipped mid-glyph.

       Keep every label on one line, stop tabs shrinking below their text,
       and let the row scroll horizontally when the set is wider than the
       viewport (scrollbar hidden — it's a touch surface). */
    .ir-view-tab {
        padding: 7px 10px;
        white-space: nowrap;
        flex: 0 0 auto;
    }
    .ir-view-tabs {
        overflow-x: auto;
        overflow-y: hidden;
        scrollbar-width: none;
        -webkit-overflow-scrolling: touch;
    }
    .ir-view-tabs::-webkit-scrollbar { display: none; }
}

.ir-storm-counts {
    display: flex;
    gap: 14px;
    align-items: center;
}

.ir-count {
    font-size: 11px;
    color: #8b8fa4;
}

.ir-count-val {
    color: #e2e4ea;
    font-weight: 600;
    margin-right: 2px;
}

/* ── Layout ─────────────────────────────────────────────────── */

.sat-main {
    position: fixed;
    top: calc(var(--topbar-h) + var(--secondary-bar-h));
    left: 0;
    right: 0;
    bottom: 0;
    flex-direction: row;
    background: var(--surface);
    overflow: hidden;
}

/* ── Sidebar ────────────────────────────────────────────────── */

.sat-sidebar {
    width: 220px;
    min-width: 220px;
    background: var(--surface-raised);
    border-right: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    z-index: 10;
    overflow: hidden;
}

.sat-sidebar-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 14px 8px;
    border-bottom: 1px solid #2a2d38;
}

.sat-sidebar-header h3 {
    margin: 0;
    font-size: 13px;
    font-weight: 600;
    color: #e2e4ea;
    letter-spacing: 0.02em;
}

.sat-sidebar-close {
    display: none;
    background: none;
    border: none;
    color: #8b8fa4;
    font-size: 18px;
    cursor: pointer;
    padding: 0 4px;
    line-height: 1;
}

.sat-storm-list {
    flex: 1;
    overflow-y: auto;
    padding: 6px 0;
}

.sat-loading-msg {
    color: #8b8fa4;
    font-size: 12px;
    padding: 16px 14px;
    text-align: center;
}

.sat-storm-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    cursor: pointer;
    transition: background 0.15s;
    border-left: 3px solid transparent;
}

.sat-storm-item:hover {
    background: #1e2130;
}

.sat-storm-item.active {
    background: #1e2130;
    border-left-color: var(--storm-color, #60a5fa);
}

.sat-storm-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex-shrink: 0;
}

.sat-storm-info {
    flex: 1;
    min-width: 0;
}

.sat-storm-name {
    font-size: 13px;
    font-weight: 500;
    color: #e2e4ea;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sat-storm-meta {
    font-size: 11px;
    color: #8b8fa4;
    margin-top: 1px;
}

.sat-sidebar-section {
    padding: 10px 14px;
    border-top: 1px solid #2a2d38;
}

.sat-sidebar-section label {
    display: block;
    font-size: 11px;
    font-weight: 500;
    color: #8b8fa4;
    margin-bottom: 4px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.sat-sidebar-section select {
    width: 100%;
    background: #12141c;
    color: #e2e4ea;
    border: 1px solid #2a2d38;
    border-radius: 4px;
    padding: 5px 8px;
    font-size: 12px;
    font-family: inherit;
    cursor: pointer;
    outline: none;
}

.sat-sidebar-section select:focus {
    border-color: #4a8cff;
}

.sat-product-toggle {
    display: flex;
    gap: 2px;
    background: #0a0c12;
    border-radius: 5px;
    padding: 2px;
    border: 1px solid #2a2d38;
}

.sat-product-btn {
    flex: 1;
    background: transparent;
    color: #8b8fa4;
    border: none;
    border-radius: 3px;
    padding: 5px 8px;
    font-size: 11px;
    font-family: inherit;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}

.sat-product-btn:hover {
    color: #c8cad2;
}

.sat-product-btn.active {
    background: #2a2d38;
    color: #e2e4ea;
}

/* ── Crosshair Toggle ──────────────────────────────────────── */

.sat-checkbox-label {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 11px;
    color: #8b8fa4;
    cursor: pointer;
}

.sat-checkbox-label input[type="checkbox"] {
    accent-color: #4a8cff;
    width: 14px;
    height: 14px;
    cursor: pointer;
}

/* ── Mode Toggle (Diagnostics / WV / Vis) ──────────────────── */

.sat-mode-toggle {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 2px;
    background: #0a0c12;
    border-radius: 5px;
    padding: 2px;
    border: 1px solid #2a2d38;
}

.sat-mode-btn {
    background: transparent;
    color: #8b8fa4;
    border: none;
    border-radius: 3px;
    padding: 6px 4px;
    font-size: 10px;
    font-family: inherit;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
    white-space: nowrap;
}

.sat-mode-btn:hover {
    color: #c8cad2;
}

.sat-mode-btn.active {
    background: #2a2d38;
    color: #e2e4ea;
}

/* ── Diagnostics Panel ─────────────────────────────────────── */

.sat-diag-panel {
    display: flex;
    flex-direction: column;
    flex: 1;
    overflow-y: auto;
    padding: 6px 8px 8px;
    gap: 6px;
    background: var(--surface);
    min-height: 0;
    width: 100%;
}

.sat-diag-header {
    flex-shrink: 0;
    display: flex;
    justify-content: center;
    padding: 2px 0;
}

.sat-diag-toggle {
    display: flex;
    gap: 2px;
    background: #0a0c12;
    border-radius: 5px;
    padding: 2px;
    border: 1px solid #2a2d38;
}

.sat-diag-tab {
    background: transparent;
    color: #8b8fa4;
    border: none;
    border-radius: 3px;
    padding: 4px 14px;
    font-size: 11px;
    font-family: inherit;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}

.sat-diag-tab:hover {
    color: #c8cad2;
}

.sat-diag-tab.active {
    background: #2a2d38;
    color: #e2e4ea;
}

.sat-diag-view {
    display: flex;
    flex-direction: column;
    gap: 6px;
    flex: 1;
    min-height: 0;
}

.sat-hov-lookback-bar {
    display: flex;
    justify-content: center;
    gap: 2px;
    padding: 2px 0 0;
    flex-shrink: 0;
}
.sat-hov-lookback-btn {
    background: transparent;
    color: #8b8fa4;
    border: 1px solid #2a2d38;
    border-radius: 3px;
    padding: 2px 10px;
    font-size: 10px;
    font-family: inherit;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}
.sat-hov-lookback-btn:hover { color: #c8cad2; }
.sat-hov-lookback-btn.active { background: #2a2d38; color: #e2e4ea; }

.sat-diag-chart {
    min-height: 170px;
    width: 100%;
    flex-shrink: 0;
}

.sat-diag-hovmoller-chart {
    min-height: 400px;
    flex: 1;
}

.sat-diag-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 1;
    color: #5c6070;
    font-size: 12px;
    text-align: center;
    padding: 40px 20px;
    line-height: 1.6;
}

.sat-compare-panel {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    flex: 1;
    min-height: 0;
    width: 100%;
    overflow: hidden;
}

/* Layout ratio: 60/40 in diagnostics mode, 50/50 in compare mode */
#sat-panel-ir {
    flex: 3;
}

#sat-panel-right[data-mode="diagnostics"] {
    flex: 2;
}

#sat-panel-right[data-mode="compare-wv"],
#sat-panel-right[data-mode="compare-vis"],
#sat-panel-right[data-mode="track-map"],
#sat-panel-right[data-mode="asymmetry"],
#sat-panel-right[data-mode="microwave"] {
    flex: 3;
}

/* ── Track Map Panel ───────────────────────────────────────── */

.sat-track-panel {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    flex: 1;
    min-height: 0;
    width: 100%;
    overflow: hidden;
}

/* ── Environment Panel ─────────────────────────────────────── */
/* Default right-pane view for sub-hurricane systems. Intensity
   history, shear, model spread, motion — useful for any storm
   without requiring a detected eye. */

.sat-env-panel {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    width: 100%;
    overflow: hidden;
}
.sat-env-body {
    flex: 1;
    overflow-y: auto;
    padding: 8px 12px 12px;
    font-family: "DM Sans", "Helvetica Neue", sans-serif;
    color: #e2e8f0;
    font-size: 13px;
    line-height: 1.4;
}
.sat-env-section {
    margin-bottom: 14px;
    padding-bottom: 12px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.sat-env-section:last-child {
    border-bottom: none;
}
.sat-env-label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: #94a3b8;
    margin-bottom: 6px;
}
.sat-env-row {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    align-items: baseline;
    margin-bottom: 4px;
}
.sat-env-headline {
    margin-bottom: 8px;
}
.sat-env-cat-chip {
    padding: 2px 8px;
    border-radius: 4px;
    background: #2e7dff;
    color: #fff;
    font-size: 12px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}
.sat-env-name {
    font-size: 17px;
    font-weight: 600;
    color: #f1f5f9;
}
.sat-env-vitals {
    font-variant-numeric: tabular-nums;
    color: #cbd5e1;
}
.sat-env-vitals b {
    color: #f1f5f9;
    font-weight: 600;
}
.sat-env-motion {
    color: #94a3b8;
    font-size: 12px;
}
.sat-env-shear {
    font-variant-numeric: tabular-nums;
    color: #f1f5f9;
    font-size: 15px;
}
.sat-env-shear-dir {
    color: #94a3b8;
    font-size: 12px;
}
.sat-env-chart {
    width: 100%;
    height: 140px;
}
.sat-env-meta {
    color: #94a3b8;
    font-size: 11px;
    margin-top: 4px;
}
.sat-env-recon {
    color: #cbd5e1;
}
.sat-env-recon.active {
    color: #34d399;
    font-weight: 500;
}

/* ── Asymmetry Panel ───────────────────────────────────────── */

.sat-asym-panel {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    flex: 1;
    min-height: 0;
    width: 100%;
    overflow: hidden;
}

.sat-sidebar-footer {
    padding: 8px 14px;
    border-top: 1px solid #2a2d38;
}

.sat-sidebar-hint {
    font-size: 10px;
    color: #5c6070;
    line-height: 1.4;
}

/* Sidebar toggle button (visible when sidebar is hidden on mobile) */
.sat-sidebar-toggle {
    display: none;
    position: absolute;
    top: 10px;
    left: 10px;
    z-index: 25;
    background: #181b24ee;
    color: #e2e4ea;
    border: 1px solid #3a3d48;
    border-radius: 6px;
    padding: 8px 14px;
    font-size: 13px;
    font-weight: 500;
    font-family: inherit;
    cursor: pointer;
    box-shadow: 0 2px 8px rgba(0,0,0,0.12);
}

/* ── Canvas Area ────────────────────────────────────────────── */

.sat-canvas-wrap {
    flex: 1;
    position: relative;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: #0a0c12;
}

.sat-canvas-area {
    flex: 1;
    position: relative;
    display: flex;
    align-items: stretch;
    justify-content: center;
    overflow: hidden;
    min-height: 0;
}

/* ── Split Panels ───────────────────────────────────────────── */

.sat-split-panels {
    display: flex;
    flex: 1;
    gap: 2px;
    min-height: 0;
    padding: 0;
}

.sat-panel {
    flex: 1;
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    min-width: 0;
}

.sat-panel-label {
    position: absolute;
    top: 6px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 6;
    background: #181b24cc;
    color: var(--text-dim);
    font-size: 11px;
    font-weight: 500;
    padding: 2px 10px;
    border-radius: 3px;
    pointer-events: none;
    white-space: nowrap;
}

.sat-panel-canvas-wrap {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 1;
    min-height: 0;
    width: 100%;
}

.sat-panel canvas {
    display: block;
    max-width: 100%;
    max-height: 100%;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    cursor: crosshair;
}

.sat-overlay-canvas {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    pointer-events: none;
    image-rendering: auto;
}

/* ── Panel Colorbars (horizontal, below image) ──────────────── */

.sat-colorbar-horiz {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 3px 8px;
    flex-shrink: 0;
}

.sat-colorbar-horiz canvas {
    flex: 1;
    height: 8px;
    border-radius: 2px;
    border: 1px solid #2a2d38;
    image-rendering: auto;
}

.sat-cb-label-left,
.sat-cb-label-right {
    font-size: 9px;
    font-variant-numeric: tabular-nums;
    color: #8b8fa4;
    white-space: nowrap;
}

/* ── Lat/Lon Axes ───────────────────────────────────────────── */

.sat-axes-y {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 32px;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    pointer-events: none;
    padding: 4px 0;
}

.sat-axes-y-left { left: 2px; }
.sat-axes-y-right { right: 2px; text-align: right; }

.sat-axes-x {
    position: absolute;
    bottom: 2px;
    left: 32px;
    right: 32px;
    display: flex;
    justify-content: space-between;
    pointer-events: none;
}

.sat-axis-label {
    font-variant-numeric: tabular-nums;
    font-size: 10px;
    color: var(--text-dim);
    text-shadow: 0 0 4px #0a0c12, 0 0 8px #0a0c12, 0 0 12px #0a0c12;
}

/* ── Storm Satellite Quick View ────────────────────────────────
   The default "casual viewer" layout: a pre-rendered animated WebP
   + minimal context. Loads in ~200-400 ms from GCS direct, matching
   the simplicity of cyclonicwx / Tropical Tidbits. The full
   interactive viewer (sat-main) is one button-click away. */

.sat-quick-view {
    /* Same positioning approach as .sat-main: fixed below the topbar
       + secondary-bar so the storm picker isn't covered by the nav,
       and the meta bar at the bottom always reaches the viewport edge. */
    position: fixed;
    top: calc(var(--topbar-h) + var(--secondary-bar-h));
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    flex-direction: column;
    min-height: 0;
    background: #0a0c12;
    color: #e2e8f0;
    font-family: "DM Sans", "Helvetica Neue", sans-serif;
    z-index: 1;
}

.qv-storm-bar {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 12px 18px;
    border-bottom: 1px solid #1d2030;
    background: #11141d;
    flex-wrap: wrap;
}
.qv-storm-picker-wrap {
    flex: 0 0 auto;
}
.qv-storm-select {
    background: #1a1e2a;
    color: #e2e8f0;
    border: 1px solid #2a2d38;
    border-radius: 4px;
    padding: 6px 10px;
    font-size: 13px;
    font-family: inherit;
    min-width: 180px;
}
.qv-storm-info {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}
.qv-cat-chip {
    padding: 3px 10px;
    border-radius: 4px;
    background: #2e7dff;
    color: #fff;
    font-size: 13px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}
.qv-name {
    font-size: 20px;
    font-weight: 600;
    color: #f1f5f9;
}
.qv-vitals {
    color: #cbd5e1;
    font-variant-numeric: tabular-nums;
    font-size: 14px;
}
.qv-detailed-btn {
    background: #2e7dff;
    color: #fff;
    border: none;
    border-radius: 4px;
    padding: 8px 14px;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    font-family: inherit;
}
.qv-detailed-btn:hover { background: #1e6fff; }
.qv-detailed-btn:active { background: #1858d8; }

.qv-stage {
    flex: 1;
    min-height: 0;
    position: relative;
    background: #0a0c12;
    overflow: hidden;
}
/* Leaflet map container — fills the stage. Each storm frame is an
   L.imageOverlay placed at its TRUE geographic bounds, so the storm
   moves across the displayed area while coastlines + lat/lon grid
   from the basemap layer stay stable.  */
.qv-leaflet-map {
    width: 100%;
    height: 100%;
    background: #0a0c12;
}
/* Hide the default Leaflet attribution that appears bottom-right —
   we attribute in the sidebar of the detailed viewer; quick view
   should be clean. */
.qv-leaflet-map .leaflet-control-attribution { display: none; }
/* Overlay states — centered on top of the Leaflet map */
.qv-loader, .qv-empty, .qv-error {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 500;
    pointer-events: none;
}
.qv-loader {
    color: #e2e8f0;
    font-size: 14px;
    padding: 12px 18px;
    background: rgba(15, 22, 36, 0.85);
    border-radius: 6px;
    backdrop-filter: blur(6px);
    border: 1px solid rgba(255, 255, 255, 0.08);
}
.qv-empty {
    text-align: center;
    color: #e2e8f0;
    max-width: 420px;
    padding: 32px 24px;
    background: rgba(15, 22, 36, 0.92);
    border-radius: 8px;
}
.qv-error {
    color: #f87171;
    text-align: center;
    padding: 18px;
    max-width: 480px;
    line-height: 1.5;
    background: rgba(15, 22, 36, 0.92);
    border-radius: 8px;
    border: 1px solid rgba(248, 113, 113, 0.25);
}

.qv-meta-bar {
    display: flex;
    gap: 24px;
    padding: 12px 18px;
    border-top: 1px solid #1d2030;
    background: #11141d;
    flex-wrap: wrap;
    font-size: 13px;
}
.qv-meta-item {
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.qv-meta-label {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: #94a3b8;
}
.qv-meta-item b {
    color: #f1f5f9;
    font-variant-numeric: tabular-nums;
    font-weight: 500;
}

/* ── Storm Satellite: active-storm gallery ─────────────────────
   Default landing for the Storm Satellite tab — every active storm
   as an IR-snapshot card. Clicking a card opens that storm's full
   detail card (#ir-detail). Standalone fixed-position sibling of
   #ir-detail / #sat-main / #sat-quick-view. */
#sat-gallery {
    position: fixed;
    top: calc(var(--topbar-h) + var(--secondary-bar-h));
    left: 0;
    right: 0;
    bottom: 0;
    overflow-y: auto;
    padding: 20px 22px 28px;
    background: var(--surface);
    color: var(--text);
    font-family: "DM Sans", "Helvetica Neue", sans-serif;
    z-index: 1;
}
.qv-gallery-head { margin-bottom: 16px; }
.qv-gallery-title {
    margin: 0;
    font-size: 20px;
    font-weight: 600;
    color: var(--text);
    display: flex;
    align-items: baseline;
    gap: 8px;
}
.qv-gallery-count {
    font-size: 14px;
    font-weight: 500;
    color: var(--text-dim);
    font-variant-numeric: tabular-nums;
}
.qv-gallery-sub {
    margin-top: 4px;
    font-size: 13px;
    color: var(--text-dim);
}
.qv-gallery-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    gap: 16px;
}
.qv-card {
    display: flex;
    flex-direction: column;
    text-align: left;
    padding: 0;
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: 10px;
    overflow: hidden;
    cursor: pointer;
    font-family: inherit;
    color: inherit;
    transition: border-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}
.qv-card:hover {
    border-color: var(--blue);
    transform: translateY(-2px);
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.18);
}
.qv-card:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
}
.qv-card-thumb {
    position: relative;
    width: 100%;
    aspect-ratio: 4 / 3;
    background: var(--surface);
    display: flex;
    align-items: center;
    justify-content: center;
}
.qv-card-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
/* Spinner is absolutely positioned (not a flex item) so it stays
   centered over the thumbnail regardless of the sibling <img>. Centred
   with negative margins rather than translate(-50%) so the qv-spin
   keyframe's `transform: rotate()` doesn't clobber the centering. */
.qv-card-thumb.is-loading::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 22px;
    height: 22px;
    margin: -11px 0 0 -11px;
    border: 2px solid var(--border-light);
    border-top-color: var(--text-dim);
    border-radius: 50%;
    animation: qv-spin 0.8s linear infinite;
}
.qv-card-thumb.is-error::after {
    content: "No recent imagery";
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-faint);
    font-size: 12px;
}
@keyframes qv-spin { to { transform: rotate(360deg); } }
/* Chips sit OVER the (always-dark) IR image, so they keep a dark scrim
   + light text in both themes. */
.qv-card-basin-chip {
    position: absolute;
    top: 8px;
    left: 8px;
    padding: 2px 7px;
    border-radius: 4px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.04em;
    color: #e2e8f0;
    background: rgba(10, 12, 18, 0.78);
    backdrop-filter: blur(4px);
    z-index: 2;
}
.qv-card-recon {
    position: absolute;
    top: 8px;
    right: 8px;
    padding: 2px 7px;
    border-radius: 4px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.05em;
    color: #0a0c12;
    background: #fbbf24;
    z-index: 2;
}
/* Locator: a small themed basemap with the storm's recent track +
   current position, giving the "where on Earth" context the zoomed IR
   thumbnail lacks. */
.qv-card-locator {
    width: 100%;
    height: 96px;
    position: relative;
    border-top: 1px solid var(--border);
    background: var(--surface);
}
.qv-card-locator .leaflet-container { background: var(--surface); font: inherit; }
.qv-card-locator .leaflet-control-container,
.qv-card-locator .leaflet-control-attribution { display: none; }
.qv-card-body {
    padding: 10px 12px 12px;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.qv-card-row {
    display: flex;
    align-items: center;
    gap: 8px;
}
.qv-card-chip {
    padding: 2px 8px;
    border-radius: 4px;
    background: var(--blue);
    color: #fff;
    font-size: 12px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    flex: 0 0 auto;
}
.qv-card-name {
    font-size: 16px;
    font-weight: 600;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.qv-card-vitals {
    font-size: 13px;
    color: var(--text);
    font-variant-numeric: tabular-nums;
}
.qv-card-pos {
    font-size: 12px;
    color: var(--text-dim);
    font-variant-numeric: tabular-nums;
}
.qv-card-formation {
    margin-top: 1px;
    font-size: 12px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    text-decoration: none;        /* color set inline by 7-day risk */
    cursor: pointer;
    width: fit-content;
}
.qv-card-formation:hover { text-decoration: underline; }
.qv-card-stats {
    margin-top: 2px;
    font-size: 11px;
    color: var(--text-faint);
    font-variant-numeric: tabular-nums;
}
.qv-gallery-empty {
    text-align: center;
    color: var(--text);
    max-width: 420px;
    margin: 48px auto 0;
    padding: 24px;
}
@media (max-width: 640px) {
    /* Mobile: stack bar items, shrink chip sizes. The animation
       still gets the central space.  */
    .qv-storm-bar { padding: 10px 12px; gap: 10px; }
    .qv-name { font-size: 17px; }
    .qv-vitals { font-size: 12px; }
    .qv-detailed-btn { padding: 7px 11px; font-size: 12px; }
    .qv-meta-bar { gap: 12px; padding: 10px 12px; font-size: 12px; }
    .qv-meta-label { font-size: 9px; }
    /* Gallery: tighter padding + smaller card floor so two columns
       still fit on a phone. */
    #sat-gallery { padding: 14px 12px 20px; }
    .qv-gallery-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; }
    .qv-gallery-title { font-size: 17px; }
    .qv-card-name { font-size: 15px; }
}

/* ── Hover Tooltip ──────────────────────────────────────────── */

.sat-tooltip {
    position: absolute;
    /* z-index 1500: must clear the in-page UI that lives over the map
       (anim bar at 20, badges/labels at 25, loader at 30, mobile
       sidebar at 40, topbar at 100) plus Leaflet's controls (~1000).
       JS overrides position to `fixed` at runtime so the tooltip
       tracks viewport coords directly. Without this bump, the cursor
       readout was rendering BEHIND the anim bar / badges, looking
       like the hover was broken on the microwave pane. */
    z-index: 1500;
    pointer-events: none;
    background: #181b24ee;
    color: #e2e4ea;
    border: 1px solid #2a2d38;
    border-radius: 4px;
    padding: 4px 8px;
    font-size: 12px;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    display: none;
    box-shadow: 0 2px 8px rgba(0,0,0,0.12);
}

.sat-tb-val {
    color: #7dd3fc;
    font-weight: 500;
}

.sat-tb-sep {
    color: #5c6070;
}

.sat-tb-coord {
    color: var(--text-dim);
}

/* ── Loading Overlay ────────────────────────────────────────── */

.sat-loader {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: #0a0c12ee;
    z-index: 30;
    transition: opacity 0.3s;
}

.sat-loader.hidden {
    opacity: 0;
    pointer-events: none;
}

.sat-spinner {
    width: 36px;
    height: 36px;
    /* Hard-coded dark-slate track was fine on dark navy but invisible
       on the new light-theme surfaces. Neutral alpha works on both. */
    border: 3px solid rgba(148, 163, 184, 0.4);
    border-top-color: #4a8cff;
    border-radius: 50%;
    animation: sat-spin 0.8s linear infinite;
}

@keyframes sat-spin {
    to { transform: rotate(360deg); }
}

.sat-loader-msg {
    margin-top: 12px;
    color: #8b8fa4;
    font-size: 13px;
}

/* ── No-Storms Message ──────────────────────────────────────── */

.sat-no-storms {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    z-index: 25;
    text-align: center;
    padding: 32px;
}

.sat-no-storms h2 {
    color: #e2e4ea;
    font-size: 20px;
    font-weight: 600;
    margin: 0 0 8px;
}

.sat-no-storms p {
    color: #8b8fa4;
    font-size: 14px;
    margin: 0;
}

/* ── Animation Bar ──────────────────────────────────────────── */

.sat-anim-bar {
    flex-shrink: 0;
    background: #181b24;
    border-top: 1px solid #2a2d38;
    padding: 6px 14px;
    z-index: 20;
}

.sat-anim-controls {
    display: flex;
    align-items: center;
    gap: 6px;
}

.sat-anim-btn {
    background: #12141c;
    color: #e2e4ea;
    border: 1px solid #2a2d38;
    border-radius: 4px;
    padding: 4px 10px;
    font-size: 12px;
    cursor: pointer;
    line-height: 1;
    transition: background 0.15s;
    font-family: inherit;
}

.sat-anim-btn:hover {
    background: #1e2130;
}

.sat-play-btn {
    min-width: 36px;
    text-align: center;
}

.sat-speed-btn {
    font-variant-numeric: tabular-nums;
    font-size: 11px;
    min-width: 32px;
    text-align: center;
}

/* Adjust-Speed control: [−] [label] [+] — replaces the old single
   "cycle through fixed speeds" button. Step buttons reuse .sat-anim-btn
   styling so they sit naturally with play/next/save. */
.sat-speed-control {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    margin: 0 4px;
}
.sat-speed-step-btn {
    min-width: 22px;
    padding: 2px 6px;
    font-size: 14px;
    font-weight: 600;
    line-height: 1;
}
.sat-speed-step-btn:disabled {
    opacity: 0.3;
    cursor: not-allowed;
}
.sat-speed-label {
    display: inline-block;
    min-width: 32px;
    text-align: center;
    font-variant-numeric: tabular-nums;
    font-size: 11px;
    color: #cbd5e1;
    user-select: none;
}

input[type="range"].sat-slider {
    flex: 1;
    min-width: 80px;
    max-width: 300px;
    height: 4px;
    -webkit-appearance: none;
    appearance: none;
    background: #2a2d38;
    border-radius: 2px;
    outline: none;
    cursor: pointer;
    /* Override tc_radar_styles.css global input[type="range"] */
    position: static;
    width: auto;
    top: auto;
    transform: none;
    pointer-events: auto;
}

.sat-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 14px;
    height: 14px;
    background: #4a8cff;
    border-radius: 50%;
    cursor: pointer;
}

.sat-slider::-moz-range-thumb {
    width: 14px;
    height: 14px;
    background: #4a8cff;
    border-radius: 50%;
    border: none;
    cursor: pointer;
}

.sat-frame-counter {
    font-variant-numeric: tabular-nums;
    font-size: 11px;
    color: #8b8fa4;
    min-width: 42px;
    text-align: center;
}

.sat-anim-info {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 3px;
}

.sat-timestamp {
    font-variant-numeric: tabular-nums;
    font-size: 11px;
    color: var(--text-dim);
}

.sat-satellite {
    font-size: 11px;
    color: #5c6070;
}

.sat-storm-label {
    font-size: 11px;
    font-weight: 500;
    color: #7dd3fc;
    margin-left: auto;
}

/* ── Loading Status ─────────────────────────────────────────── */

.sat-load-status {
    font-variant-numeric: tabular-nums;
    font-size: 10px;
    color: #4a8cff;
    margin-left: 4px;
    white-space: nowrap;
}

.sat-load-status:empty {
    display: none;
}

/* ── Zoom Buttons ───────────────────────────────────────────── */

.sat-zoom-group {
    display: flex;
    gap: 1px;
    background: #2a2d38;
    border-radius: 4px;
    overflow: hidden;
    border: 1px solid #2a2d38;
}

/* Hide the canvas-era 10°/5°/2° zoom presets when Leaflet IR is the
   active display — Leaflet's native scroll-wheel + pinch zoom
   subsumes them. Toggled from satellite.js via body.sat-leaflet-active. */
body.sat-leaflet-active .sat-zoom-group { display: none; }

.sat-zoom-btn {
    background: #12141c;
    color: #8b8fa4;
    border: none;
    padding: 4px 8px;
    font-size: 11px;
    font-variant-numeric: tabular-nums;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}

.sat-zoom-btn:hover {
    background: #1e2130;
    color: #e2e4ea;
}

.sat-zoom-btn.active {
    background: #2a2d38;
    color: #7dd3fc;
}

/* ── Responsive ─────────────────────────────────────────────── */

@media (max-width: 640px) {
    /* ═══════════════════════════════════════════════════════════
       Phone-only layout overhaul (single-pane by default, MW stacks).
       Breakpoint = 640px (was 768px) — keeps phones in single-pane
       but lets tablets (iPad portrait = 768px) get the full
       dual-pane WV/Vis compare UX. The original OOM concern is
       moot post-bundle: WV adds only ~1.5 MB now, not 13 separate
       fetches. Phones (≤5-6") still get single-pane purely for
       readability — side-by-side at <320 px per pane is unusable.

       Rationale (original): side-by-side dual-pane is unreadable at
       <360 px per pane on phones, and pre-loading 13 IR + 13 WV
       frames routinely OOM'd iOS Safari. We collapse to a single IR
       pane and reserve the second pane exclusively for MW (where
       the comparison is two static frames — light + valuable).
       ═══════════════════════════════════════════════════════════ */

    /* .sat-main top is already correct via var(--topbar-h) +
       var(--secondary-bar-h) — no override needed. */

    .sat-sidebar {
        position: absolute;
        top: 0;
        left: 0;
        bottom: 0;
        z-index: 40;
        transform: translateX(-100%);
        transition: transform 0.25s ease;
        overflow-y: auto;
        /* Slightly wider drawer + bigger interior padding so the
           mode-toggle buttons stop getting fat-finger'd. */
        width: 260px;
        min-width: 260px;
    }

    .sat-sidebar.open {
        transform: translateX(0);
        box-shadow: 4px 0 14px rgba(0,0,0,0.45);
    }

    .sat-sidebar-close {
        display: block;
        font-size: 22px;
        padding: 4px 8px;
        min-width: 36px;
        min-height: 36px;
    }

    .sat-sidebar-toggle {
        display: block;
        /* Larger tap target — the previous 8×14 padding gave a
           ~32 px hit area, below Apple's 44 px guideline. */
        padding: 10px 16px;
        font-size: 14px;
        min-height: 44px;
    }

    /* Backdrop dim while drawer is open — clicking the dimmed area
       closes the sidebar (wired in JS). Without this, the mode
       buttons sometimes register as "outside the sidebar" taps and
       do nothing while the drawer is up. */
    .sat-sidebar-backdrop {
        display: none;
        position: absolute;
        inset: 0;
        background: rgba(0,0,0,0.4);
        z-index: 35;
    }
    .sat-sidebar.open ~ .sat-sidebar-backdrop {
        display: block;
    }

    /* Stack panels vertically when both are visible (MW mode). */
    .sat-split-panels {
        flex-direction: column;
    }

    /* Right pane stacks below IR. We split available panel height
       55/45 (IR/right) via flex ratios — this auto-adjusts to the
       actual usable height after the topbar/secondary-bar/anim-bar
       are subtracted, unlike a fixed `vh` slice which can over- or
       under-allocate.

       Heavy comparison modes (WV / Vis) get force-hidden because
       they pre-load a second 13-frame image stack and tip iOS
       Safari into its tab-kill memory zone. Their mode buttons
       are hidden too (rule below) and JS redirects them to
       Diagnostics defensively. MW is fine because it's a single
       static frame plus a re-used IR layer — light. */
    #sat-panel-ir {
        flex: 55 1 0;
        min-height: 0;
    }
    #sat-panel-right {
        flex: 45 1 0;
        min-height: 0;
    }
    #sat-panel-right[data-mode="compare-wv"],
    #sat-panel-right[data-mode="compare-vis"] {
        display: none;
    }
    /* When the right pane is hidden (WV/Vis on mobile), IR claims
       the full viewport height — its flex weight stays the only
       contributor to the parent's main-axis distribution. */

    /* Hide WV / Vis mode buttons on mobile — those modes are
       designed around side-by-side comparison and offer no value
       in single-pane. Keeps the mode row uncluttered too. */
    #sat-mode-wv,
    #sat-mode-vis {
        display: none;
    }

    /* The remaining 4 buttons (Diag, Track, Asym, MW) get a wider
       2-row grid: 2 cols × 2 rows instead of 3×2. Bigger tap
       targets, less crammed text. */
    .sat-mode-toggle {
        grid-template-columns: repeat(2, 1fr);
        gap: 4px;
    }
    .sat-mode-btn {
        padding: 12px 6px;
        font-size: 13px;
        min-height: 44px;
    }

    /* Pin the floating sat-sidebar-toggle so it doesn't get
       buried under the secondary bar / animation controls on
       very tall pages. */
    .sat-sidebar-toggle {
        position: fixed;
        top: calc(var(--topbar-h) + var(--secondary-bar-h) + 8px);
        left: 8px;
    }

    /* MW controls row reflow: chips wrap, dropdown gets full width
       on its own row so it's tappable. */
    .sat-mw-controls-row {
        flex-wrap: wrap;
        gap: 6px 4px;
    }
    .sat-mw-pass-select {
        flex: 1 1 100%;
        min-width: 0;
    }

    /* Hide the canvas-era preset zoom buttons on mobile. Leaflet
       pinch-zoom is the natural gesture; the buttons crowd the
       transport bar. */
    .sat-zoom-group {
        display: none !important;
    }
}

@media (max-width: 480px) {
    /* Two-row animation bar: slider on its own row (full width) so it
       stays draggable; transport buttons + speed + counter wrap below.
       Single-row layout cramps everything past ~80 px of slider on
       375 px screens. */
    .sat-anim-controls {
        flex-wrap: wrap;
        gap: 4px 6px;
    }
    input[type="range"].sat-slider {
        order: -1;
        flex: 1 1 100%;
        min-width: 0;
        max-width: none;
    }

    .sat-anim-info {
        flex-wrap: wrap;
        gap: 4px 10px;
    }

    .sat-anim-btn {
        padding: 6px 10px;
        font-size: 12px;
        min-height: 36px;
    }

    .sat-zoom-btn {
        padding: 4px 8px;
        font-size: 11px;
    }

    .sat-frame-counter {
        font-size: 11px;
        min-width: 40px;
    }
}
