/* ═══════════════════════════════════════════════════════════════
   Real-Time Monitor — Page-Specific Styles
   Shared base styles (topbar, fonts, CSS vars) from tc_radar_styles.css
   ═══════════════════════════════════════════════════════════════ */

/* The universal reset in tc_radar_styles.css doesn't always beat the
   browser's default body { margin: 8px }. Without this the sticky
   topbar gets pushed 8px down and the position:fixed secondary bar
   overlaps the bottom of the topbar — clipping "Global Map / Storm
   Satellite" tabs and the storm-counts strip. */
html, body { margin: 0; padding: 0; }

/* ── Version badge override ──────────────────────────────────── */
.ir-version {
    background: linear-gradient(135deg, #ef4444 0%, #f59e0b 100%) !important;
    -webkit-background-clip: text !important;
    -webkit-text-fill-color: transparent !important;
    background-clip: text !important;
}

/* ── Map ─────────────────────────────────────────────────────── */
.ir-map {
    position: absolute;
    top: 85px;    /* below topbar + secondary bar */
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1;
}

/* ── Status bar ──────────────────────────────────────────────── */
.ir-status-bar {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    height: 28px;
    background: rgba(255, 255, 255, 0.92);
    backdrop-filter: blur(8px);
    border-top: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 16px;
    font-size: 0.72rem;
    color: #8993a4;
    z-index: 800;
    font-variant-numeric: tabular-nums;
}
.ir-last-update {
    color: #64748b;
}

/* ── Loading overlay ─────────────────────────────────────────── */
.ir-loader {
    position: absolute;
    bottom: 28px;
    left: 50%;
    transform: translateX(-50%);
    background: rgba(255, 255, 255, 0.88);
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 10px;
    z-index: 600;
    padding: 8px 18px;
    border-radius: 20px;
    border: 1px solid rgba(74, 155, 110, 0.25);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
.ir-loader-spinner {
    width: 16px;
    height: 16px;
    /* Neutral track — green-on-green-alpha was nearly invisible on
       the dark navy surface where this spinner is overlaid. */
    border: 2px solid rgba(148, 163, 184, 0.4);
    border-top-color: #4a9b6e;
    border-radius: 50%;
    animation: ir-spin 0.8s linear infinite;
    flex-shrink: 0;
}
@keyframes ir-spin {
    to { transform: rotate(360deg); }
}
.ir-loader-text {
    color: #8993a4;
    font-size: 0.78rem;
    font-family: 'DM Sans', sans-serif;
    white-space: nowrap;
}

/* ── No storms message ───────────────────────────────────────── */
.ir-no-storms {
    position: absolute;
    bottom: 70px;
    left: 50%;
    transform: translateX(-50%);
    text-align: center;
    z-index: 500;
    padding: 10px 24px;
    background: rgba(255, 255, 255, 0.85);
    backdrop-filter: blur(8px);
    border: 1px solid rgba(15, 22, 35,0.1);
    border-radius: 10px;
    display: flex;
    align-items: center;
    gap: 12px;
    pointer-events: auto;
}
.ir-no-storms-icon {
    font-size: 1.4rem;
    flex-shrink: 0;
}
.ir-no-storms-title {
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--text);
    white-space: nowrap;
}
.ir-no-storms-desc {
    display: none;
}
.ir-no-storms-close {
    background: none;
    border: none;
    color: #64748b;
    font-size: 1rem;
    cursor: pointer;
    padding: 0 0 0 4px;
    line-height: 1;
}
.ir-no-storms-close:hover {
    color: var(--text);
}

/* The map section needs explicit viewport dimensions so the
   absolutely-positioned .ir-map child has a real height. Previously
   #ir-main was position:relative with no height — since all its
   children are position:fixed/absolute, #ir-main collapsed to 0,
   which made the map invisible. Pin it to the viewport so .ir-map's
   top/bottom resolve correctly. */
#ir-main {
    position: fixed;
    inset: 0;
}

/* ── Env Profile toggle button (Storm Info panel) ───────────── */
.rt-env-toggle-btn {
    font-size: 0.7rem;
    padding: 4px 10px;
    border-radius: 4px;
    border: 1px solid var(--border-light);
    background: var(--surface);
    color: var(--text);
    cursor: pointer;
    font-family: inherit;
    transition: background 0.15s, border-color 0.15s;
}
.rt-env-toggle-btn:hover {
    background: var(--surface-raised);
    border-color: var(--um-green);
}
.rt-env-toggle-btn.active {
    background: rgba(74, 155, 110, 0.15);
    border-color: var(--um-green);
    color: var(--um-green);
}

/* ── GIBS feed staleness banner ─────────────────────────────── */
/* Pin to viewport so it stays visible regardless of #ir-main's layout.
   88 px = sticky topbar (~53 px) + fixed secondary bar (32 px) + 3 px
   margin. Matches the visual offset .ir-map uses (top: 85 px). */
.ir-feed-banner {
    position: fixed;
    top: 88px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 500;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 14px 8px 12px;
    background: rgba(254, 243, 199, 0.92);
    border: 1px solid rgba(251, 146, 60, 0.45);
    border-radius: 8px;
    color: #a16207;
    font-size: 0.78rem;
    font-weight: 500;
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.1);
    pointer-events: auto;
    max-width: min(720px, 90vw);
}
.ir-feed-banner-icon {
    color: #fb923c;
    font-size: 1rem;
    flex-shrink: 0;
}
.ir-feed-banner-link {
    color: #1d4ed8;
    text-decoration: underline;
    text-underline-offset: 2px;
    font-weight: 500;
    white-space: nowrap;
}
.ir-feed-banner-link:hover { color: #bfdbfe; }
.ir-feed-banner-close {
    background: none;
    border: none;
    color: var(--text-dim);
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
    padding: 0 0 0 4px;
}
.ir-feed-banner-close:hover { color: var(--text); }

/* In-app-webview nudge — reuses the feed-banner shell but reads as an
   info prompt (blue) rather than a staleness warning (amber). */
.ir-inapp-banner {
    background: rgba(219, 234, 254, 0.94);
    border-color: rgba(59, 130, 246, 0.5);
    color: #1e40af;
}
.ir-inapp-banner .ir-feed-banner-icon { color: #3b82f6; }
.ir-inapp-banner-action {
    flex-shrink: 0;
    background: #2563eb;
    color: #fff;
    border: none;
    border-radius: 6px;
    padding: 4px 10px;
    font-size: 0.74rem;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
}
.ir-inapp-banner-action:hover { background: #1d4ed8; }

/* ── Legend ───────────────────────────────────────────────────── */
/* Theme-aware glass card — uses tokens so background, header text, and
   row text all flip cleanly between light and dark. */
.ir-legend {
    position: fixed;
    bottom: 40px;
    right: 12px;
    background: var(--surface-raised);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid var(--border-light);
    border-radius: 8px;
    padding: 10px 14px;
    z-index: 700;
    font-family: 'DM Sans', sans-serif;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.12);
    color: var(--text);
}
.ir-legend h4 {
    font-size: 0.7rem;
    font-weight: 700;
    color: var(--text);
    margin-bottom: 6px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.ir-legend-row {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.74rem;
    color: var(--text);
    padding: 2px 0;
}
.ir-legend-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex-shrink: 0;
}

/* ── Storm marker popups ─────────────────────────────────────── */
.ir-popup {
    font-family: 'DM Sans', sans-serif;
}
.ir-popup-name {
    font-size: 0.95rem;
    font-weight: 700;
    color: var(--text);
    margin-bottom: 4px;
}
.ir-popup-meta {
    font-size: 0.78rem;
    color: #8993a4;
    line-height: 1.5;
}
.ir-popup-meta strong {
    color: var(--text);
}
.ir-popup-btn {
    display: inline-block;
    margin-top: 8px;
    background: var(--um-green);
    color: #ffffff;
    border: none;
    border-radius: 4px;
    padding: 5px 16px;
    font-size: 0.75rem;
    font-weight: 600;
    cursor: pointer;
    font-family: 'DM Sans', sans-serif;
    transition: background 0.2s;
}
.ir-popup-btn:hover {
    background: var(--um-green-deep);
}
/* DeepMind-ensemble action — distinct cyan so it reads as the model
   (genesis) action vs the green IR-detail action. */
.ir-popup-btn-dm {
    background: #0891b2;
    margin-left: 6px;
}
.ir-popup-btn-dm:hover {
    background: #0e7490;
}

/* ── Custom storm markers ────────────────────────────────────── */
.ir-storm-marker {
    border-radius: 50%;
    border: 2px solid rgba(15, 22, 35, 0.6);
    box-shadow: 0 0 8px rgba(0, 0, 0, 0.15);
    transition: transform 0.2s;
}
.ir-storm-marker:hover {
    transform: scale(1.25);
    z-index: 1000 !important;
}

/* ── Pulsing marker animation for active storms ──────────────── */
.ir-storm-marker::after {
    content: '';
    position: absolute;
    top: -4px;
    left: -4px;
    right: -4px;
    bottom: -4px;
    border-radius: 50%;
    border: 2px solid currentColor;
    opacity: 0;
    animation: ir-pulse 2s ease-out infinite;
}
@keyframes ir-pulse {
    0%   { transform: scale(1);   opacity: 0.6; }
    100% { transform: scale(1.8); opacity: 0; }
}

/* ═══════════════════════════════════════════════════════════════
   Storm Detail View
   ═══════════════════════════════════════════════════════════════ */

.ir-detail {
    position: absolute;
    top: 52px;
    left: 0;
    right: 0;
    bottom: 0;
    background: var(--navy, #0d1318);
    z-index: 500;
    overflow: hidden;
    /* Column flex so the body fills exactly the space left by the header,
       whatever height the header wraps to. (Previously the body hardcoded
       calc(100% - 48px); when the header wrapped past 48px the body
       overflowed the clipped bottom and cut off the animation controls.) */
    display: flex;
    flex-direction: column;
}

/* ── Detail header ───────────────────────────────────────────── */
.ir-detail-header {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 10px 20px;
    border-bottom: 1px solid var(--border);
    background: var(--surface-raised);
    flex-shrink: 0;   /* keep natural height; never compress into the body */
}
.ir-back-btn {
    background: var(--border);
    border: 1px solid rgba(15, 22, 35, 0.1);
    color: #8993a4;
    font-size: 0.8rem;
    font-weight: 500;
    padding: 6px 14px;
    border-radius: 6px;
    cursor: pointer;
    font-family: 'DM Sans', sans-serif;
    transition: all 0.2s;
    white-space: nowrap;
}
.ir-back-btn:hover {
    color: var(--text);
    background: rgba(15, 22, 35, 0.1);
}
.ir-detail-title {
    display: flex;
    align-items: center;
    gap: 10px;
}
.ir-detail-storm-select {
    background: var(--surface-raised);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 5px 10px;
    font-size: 0.78rem;
    font-family: 'DM Sans', sans-serif;
    font-variant-numeric: tabular-nums;
    max-width: 280px;
    cursor: pointer;
}
.ir-detail-storm-select:hover { border-color: rgba(255, 255, 255, 0.2); }
.ir-detail-name {
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--text);
}
.ir-detail-id {
    font-variant-numeric: tabular-nums;
    font-size: 0.78rem;
    color: #64748b;
}
.ir-detail-cat {
    font-variant-numeric: tabular-nums;
    font-size: 0.8rem;
    font-weight: 700;
    padding: 2px 10px;
    border-radius: 4px;
    color: var(--text);
    white-space: nowrap;
}

/* Active-recon badge — shown on the map popup and the storm-detail
   header when a vortex data message was issued in the last ~18h. Uses
   the UM-orange "live / attention" accent (brand-true in both themes,
   matching the version pill and active view-tab). */
.ir-recon-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 0.66rem;
    font-weight: 800;
    letter-spacing: 0.04em;
    padding: 2px 8px;
    border-radius: 4px;
    white-space: nowrap;
    color: #ffffff;
    background: var(--um-orange);
    box-shadow: 0 0 0 1px var(--um-orange-deep, rgba(214, 95, 18, 0.6));
    vertical-align: middle;
}
.ir-popup-name .ir-recon-badge {
    margin-left: 6px;
}
/* The storm-detail header badge is a button (opens Live Flight for the storm);
   the popup badge is display-only, so scope the affordance to the header one. */
#ir-detail-recon {
    cursor: pointer;
    transition: filter 0.12s ease, box-shadow 0.12s ease;
}
#ir-detail-recon:hover,
#ir-detail-recon:focus-visible {
    filter: brightness(1.08);
    box-shadow: 0 0 0 1px var(--um-orange-deep, rgba(214, 95, 18, 0.6)), 0 2px 8px rgba(214, 95, 18, 0.45);
    outline: none;
}

/* Storm-detail header pills — KML / Satellite / Microwave.
   Tinted with the site's UM brand palette: green for primary
   data export + in-page nav (KML, Microwave), orange for the
   loud "open external viewer" accent (Satellite). */
.ir-kml-btn {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 0.75rem;
    padding: 3px 9px;
    border-radius: 4px;
    border: 1px solid rgba(0, 80, 48, 0.4);
    background: rgba(0, 80, 48, 0.10);
    color: var(--um-green);
    cursor: pointer;
    margin-left: 8px;
    transition: background 0.2s, border-color 0.2s, color 0.2s;
}
.ir-kml-btn svg {
    flex-shrink: 0;
    width: 13px;
    height: 13px;
    stroke: currentColor;
    fill: none;
    stroke-width: 1.75;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.ir-kml-btn:hover {
    background: rgba(0, 80, 48, 0.20);
    border-color: rgba(0, 80, 48, 0.55);
}
[data-theme="dark"] .ir-kml-btn {
    color: var(--um-green);
    border-color: rgba(74, 155, 110, 0.5);
    background: rgba(74, 155, 110, 0.14);
}
[data-theme="dark"] .ir-kml-btn:hover {
    background: rgba(74, 155, 110, 0.26);
    border-color: rgba(74, 155, 110, 0.65);
}
/* Grid + Obs toggles dim when inactive so users can see at a glance
   whether the overlay is on. Active state inherits the green tint. */
.ir-detail-grid-toggle-btn:not(.active),
.ir-detail-obs-toggle-btn:not(.active),
.ir-detail-track-toggle-btn:not(.active) {
    opacity: 0.55;
}
.ir-detail-grid-toggle-btn:not(.active):hover,
.ir-detail-obs-toggle-btn:not(.active):hover,
.ir-detail-track-toggle-btn:not(.active):hover {
    opacity: 0.85;
}
/* Lite/Detailed toggle: disabled (Detailed-only) for storms outside mosaic
   coverage or on the non-GL build. Active state uses .ir-sat-viewer-btn.active. */
.ir-detail-mode-toggle-btn:disabled {
    opacity: 0.4;
    cursor: default;
    pointer-events: none;
}

/* Surface-obs station plots — SVG injected into a divIcon. */
.ir-stn-plot-icon {
    background: transparent;
    border: none;
    pointer-events: auto;
}
.ir-stn-plot-tooltip {
    font: 600 11px/1.35 'DM Sans', sans-serif;
    background: rgba(15, 22, 35, 0.92);
    color: #e2e8f0;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 4px;
    padding: 6px 8px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
}
.ir-stn-plot-tooltip::before { display: none; }

/* Download dropdown — wraps the .ir-kml-btn-styled button and a
   floating menu of three options (PNG/GIF/KML). */
.ir-download-wrap {
    position: relative;
    display: inline-block;
}
.ir-download-menu {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    z-index: 1100;
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: 6px;
    min-width: 180px;
    box-shadow: 0 6px 24px rgba(15, 22, 36, 0.18);
    padding: 4px;
    font-family: 'DM Sans', sans-serif;
}
[data-theme="dark"] .ir-download-menu {
    background: rgba(20, 26, 38, 0.98);
    border-color: rgba(255, 255, 255, 0.12);
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.5);
}
.ir-download-item {
    display: flex;
    flex-direction: column;
    width: 100%;
    padding: 7px 10px;
    background: transparent;
    border: none;
    border-radius: 4px;
    text-align: left;
    cursor: pointer;
    color: var(--text);
    transition: background 0.12s;
}
.ir-download-item:hover {
    background: rgba(74, 155, 110, 0.12);
}
[data-theme="dark"] .ir-download-item:hover {
    background: rgba(74, 155, 110, 0.20);
}
.ir-download-item-title {
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--um-green);
    line-height: 1.2;
}
.ir-download-item-desc {
    font-size: 0.68rem;
    color: #64748b;
    margin-top: 2px;
}
[data-theme="dark"] .ir-download-item-desc {
    color: #94a3b8;
}
.ir-download-opt {
    display: flex;
    align-items: center;
    gap: 7px;
    width: 100%;
    padding: 7px 10px;
    margin-top: 4px;
    border-top: 1px solid rgba(100, 116, 139, 0.18);
    font-size: 0.74rem;
    color: var(--text);
    cursor: pointer;
    user-select: none;
}
.ir-download-opt input {
    margin: 0;
    cursor: pointer;
    accent-color: var(--um-green);
}

/* ── Options dropdown ─────────────────────────────────────────────
   Consolidates the former header toggle/action buttons into one menu.
   Toggle items keep their original IDs + .active class; the .ir-opt-dot
   reflects on/off state so the existing state-sync JS needs no changes. */
.ir-options-wrap {
    position: relative;
    display: inline-block;
}
.ir-options-menu {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    z-index: 1100;
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: 8px;
    min-width: 244px;
    max-height: 70vh;
    overflow-y: auto;
    box-shadow: 0 6px 24px rgba(15, 22, 36, 0.18);
    padding: 5px;
    font-family: 'DM Sans', sans-serif;
}
[data-theme="dark"] .ir-options-menu {
    background: rgba(20, 26, 38, 0.98);
    border-color: rgba(255, 255, 255, 0.12);
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.5);
}
.ir-opt-group-label {
    font-size: 0.62rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: #94a3b8;
    padding: 6px 10px 3px;
}
.ir-opt-sep {
    height: 1px;
    margin: 4px 6px;
    background: rgba(100, 116, 139, 0.18);
}
.ir-opt-item {
    display: flex;
    align-items: center;
    gap: 9px;
    width: 100%;
    padding: 7px 10px;
    background: transparent;
    border: none;
    border-radius: 5px;
    text-align: left;
    cursor: pointer;
    color: var(--text);
    opacity: 1;           /* override the legacy :not(.active) dimming */
    transition: background 0.12s;
}
.ir-opt-item:hover {
    background: rgba(74, 155, 110, 0.12);
}
[data-theme="dark"] .ir-opt-item:hover {
    background: rgba(74, 155, 110, 0.20);
}
.ir-opt-item:disabled {
    opacity: 0.4;
    cursor: default;
}
.ir-opt-item:disabled:hover { background: transparent; }
.ir-opt-item.active {
    background: rgba(74, 155, 110, 0.10);
}
/* State dot: hollow when off, filled green when on. */
.ir-opt-dot {
    flex: 0 0 auto;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    border: 1.5px solid #94a3b8;
    background: transparent;
    transition: background 0.12s, border-color 0.12s;
}
.ir-opt-item.active .ir-opt-dot {
    background: var(--um-green);
    border-color: var(--um-green);
    box-shadow: 0 0 5px rgba(74, 155, 110, 0.6);
}
.ir-opt-dot-blank {          /* action items — keep alignment, no state */
    border-color: transparent;
}
.ir-opt-ic {
    flex: 0 0 auto;
    display: inline-flex;
    color: var(--um-green);
}
.ir-opt-ic svg {
    width: 15px;
    height: 15px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.75;
    stroke-linecap: round;
    stroke-linejoin: round;
}
/* Loop-only glyph is a filled play triangle. */
.ir-opt-ic svg polygon { fill: currentColor; stroke: none; }
.ir-opt-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}
.ir-opt-title {
    font-size: 0.82rem;
    font-weight: 600;
    line-height: 1.2;
}
.ir-opt-desc {
    font-size: 0.68rem;
    color: #64748b;
    margin-top: 1px;
}
[data-theme="dark"] .ir-opt-desc { color: #94a3b8; }
.ir-chart-save-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 3px;
    background: transparent;
    border: 1px solid rgba(100, 116, 139, 0.35);
    border-radius: 4px;
    color: #64748b;
    cursor: pointer;
    transition: color 0.12s, border-color 0.12s, background 0.12s;
}
.ir-chart-save-btn:hover {
    color: var(--um-green);
    border-color: var(--um-green);
    background: rgba(74, 155, 110, 0.10);
}
.ir-chart-save-btn svg {
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.ir-shear-arrow {
    display: inline-block;
    vertical-align: -2px;
    margin: 0 1px;
    fill: none;
    stroke: currentColor;
    stroke-width: 2.4;
    stroke-linecap: round;
    stroke-linejoin: round;
    transform-origin: 50% 50%;
}
/* Small circled-"i" info affordance next to a label; native title tooltip. */
.ir-info-help {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 13px;
    height: 13px;
    margin-left: 5px;
    padding: 0;
    border: 1px solid currentColor;
    border-radius: 50%;
    background: transparent;
    color: var(--text-dim, #64748b);
    font: italic 700 9px/1 Georgia, "Times New Roman", serif;
    cursor: help;
    opacity: 0.65;
    vertical-align: middle;
    transition: opacity 0.12s, color 0.12s;
}
.ir-info-help:hover,
.ir-info-help:focus-visible {
    opacity: 1;
    color: var(--um-green, #4a9b6e);
    outline: none;
}
/* The Diagnostics button is a toggle (it no longer launches a separate page):
   neutral + dimmed when OFF (like the Track/Grid/Obs toggles beside it), and
   UM-orange only when ACTIVE — orange now signals "diagnostics engaged" rather
   than being the button's permanent identity. */
.ir-sat-viewer-btn.active {
    color: var(--um-orange);
    border-color: rgba(244, 115, 33, 0.45);
    background: rgba(244, 115, 33, 0.12);
}
.ir-sat-viewer-btn.active:hover {
    background: rgba(244, 115, 33, 0.24);
    border-color: rgba(244, 115, 33, 0.65);
}
[data-theme="dark"] .ir-sat-viewer-btn.active {
    color: #fdba74;
    border-color: rgba(244, 115, 33, 0.55);
    background: rgba(244, 115, 33, 0.16);
}
[data-theme="dark"] .ir-sat-viewer-btn.active:hover {
    background: rgba(244, 115, 33, 0.30);
    border-color: rgba(244, 115, 33, 0.75);
}

/* ── Section divider (Observations) ──────────────────────────── */
.ir-section-divider {
    font-size: 0.6rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: rgba(148, 163, 184, 0.5);
    border-top: 1px solid var(--border);
    padding-top: 12px;
    margin: 16px 0 8px;
}

/* ── Detail body: two-panel layout ───────────────────────────── */
.ir-detail-body {
    display: flex;
    flex: 1;
    min-height: 0;   /* allow children to shrink/scroll within the flex row */
    overflow: hidden;
}
.ir-detail-left {
    flex: 3;
    display: flex;
    flex-direction: column;
    border-right: 1px solid var(--border);
    min-width: 0;
    overflow: hidden;  /* clip Leaflet markers from bleeding into sidebar */
}
.ir-detail-right {
    flex: 2;
    overflow-y: auto;
    padding: 16px 20px;
    position: relative;
    z-index: 500;  /* above Leaflet panes (400-450) to prevent map bleed */
    min-width: 280px;
}

/* ── IR image container ──────────────────────────────────────── */
.ir-image-container {
    flex: 1;
    position: relative;
    background: #080e1a;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 0;
    overflow: hidden;
}
.ir-canvas {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}
.ir-overlay-info {
    position: absolute;
    top: 10px;
    left: 48px;
    display: flex;
    gap: 14px;
    align-items: center;
    font-variant-numeric: tabular-nums;
    font-size: 0.82rem;
    color: #f1f5f9;
    background: rgba(10, 14, 22, 0.62);
    border: 1px solid rgba(255, 255, 255, 0.12);
    padding: 6px 14px;
    border-radius: 6px;
    z-index: 500;
    pointer-events: none;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    transition: opacity 0.2s;
}
.ir-overlay-info .ir-frame-time-label {
    font-weight: 600;
    letter-spacing: 0.03em;
}
.ir-overlay-info .ir-sat-label {
    font-size: 0.72rem;
    color: rgba(241, 245, 249, 0.78);
}

/* ── Product toggle (IR / GeoColor) ────────────────────────── */
.ir-product-toggle {
    position: absolute;
    top: 10px;
    right: 10px;
    z-index: 500;
    display: flex;
    gap: 0;
    border-radius: 5px;
    overflow: hidden;
    border: 1px solid var(--border-light);
}
.ir-product-btn {
    padding: 5px 12px;
    font-family: 'DM Sans', sans-serif;
    font-size: 0.7rem;
    font-weight: 500;
    color: #8993a4;
    background: rgba(255, 255, 255, 0.85);
    border: none;
    cursor: pointer;
    transition: background 0.2s, color 0.2s;
    white-space: nowrap;
}
.ir-product-btn:hover {
    background: rgba(30, 60, 110, 0.9);
    color: #c0d0ea;
}
.ir-product-btn.ir-product-active {
    /* Solid, not 25%-transparent — a see-through "selected" button vanished over
       bright imagery (WV/Vis especially). Opaque green + white text reads on any
       background and clearly marks the active channel. */
    background: #4a9b6e;
    color: #ffffff;
}
.ir-product-btn.ir-loading {
    color: #fbbf24;
}

/* ── Storm-detail env Layers control ─────────────────────────────
   Sits top-right under the product toggle; opens a compact grouped
   menu of GFS/OISST analyses to drape over the zoomed storm view. */
.ir-detail-layers {
    position: absolute;
    top: 46px;
    right: 10px;
    z-index: 500;
}
.ir-detail-layers-btn {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 5px 10px;
    font-family: 'DM Sans', sans-serif;
    font-size: 0.7rem;
    font-weight: 500;
    color: #8993a4;
    background: rgba(255, 255, 255, 0.85);
    border: 1px solid var(--border-light);
    border-radius: 5px;
    cursor: pointer;
    transition: background 0.2s, color 0.2s;
}
.ir-detail-layers-btn svg {
    width: 13px; height: 13px; fill: none; stroke: currentColor;
    stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round;
}
.ir-detail-layers-btn svg polygon { fill: currentColor; stroke: none; }
.ir-detail-layers-btn:hover { background: rgba(30, 60, 110, 0.9); color: #c0d0ea; }
.ir-detail-layers-btn.active { background: rgba(74, 155, 110, 0.25); color: #60a5fa; }
.ir-detail-layers-count {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 15px; height: 15px; padding: 0 4px;
    font-size: 0.6rem; font-weight: 700; line-height: 1;
    color: #fff; background: var(--um-green); border-radius: 999px;
}
.ir-detail-layers-menu {
    position: absolute;
    top: calc(100% + 5px);
    right: 0;
    width: 236px;
    max-height: 62vh;
    overflow-y: auto;
    background: rgba(20, 26, 38, 0.98);
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 8px;
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.5);
    padding: 8px;
    font-family: 'DM Sans', sans-serif;
    color: #e2e8f0;
}
.ir-dl-head {
    display: flex; justify-content: space-between; align-items: baseline;
    font-size: 0.74rem; font-weight: 700; color: #cbd5e1;
    padding-bottom: 6px; margin-bottom: 4px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}
.ir-dl-valid { font-size: 0.6rem; font-weight: 600; color: #7c8aa0; }
.ir-dl-group {
    font-size: 0.6rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: 0.07em; color: #7c8aa0; margin: 8px 0 3px;
}
.ir-dl-row {
    display: flex; align-items: center; gap: 8px;
    padding: 4px 4px; border-radius: 5px; cursor: pointer;
    font-size: 0.76rem; color: #e2e8f0;
}
.ir-dl-row:hover { background: rgba(74, 155, 110, 0.18); }
.ir-dl-row input { margin: 0; cursor: pointer; accent-color: var(--um-green); flex: 0 0 auto; }
.ir-dl-empty { font-size: 0.72rem; color: #94a3b8; padding: 6px 4px; }
.ir-dl-opacity {
    display: flex; align-items: center; gap: 8px;
    margin-top: 8px; padding-top: 8px;
    border-top: 1px solid rgba(255, 255, 255, 0.12);
}
.ir-dl-opacity label { font-size: 0.7rem; color: #94a3b8; }
.ir-dl-opacity input { flex: 1; accent-color: var(--um-green); }
.ir-dl-note {
    font-size: 0.62rem; color: #7c8aa0; line-height: 1.4; margin-top: 6px;
}
/* Persistent GFS run/valid caption under the Layers button when a layer
   is draped (so the valid time is visible with the menu closed). */
.ir-detail-layers-caption {
    position: absolute;
    top: calc(100% + 5px);
    right: 0;
    white-space: nowrap;
    padding: 3px 8px;
    font-family: 'DM Sans', sans-serif;
    font-size: 0.64rem;
    font-weight: 600;
    color: #e2e8f0;
    background: rgba(20, 26, 38, 0.9);
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 5px;
    pointer-events: none;
}
/* Active analysis-layer colorbars, stacked bottom-right of the imagery. */
.ir-detail-env-cbars {
    position: absolute;
    right: 10px;
    bottom: 10px;
    z-index: 500;
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-width: 200px;
    max-height: 55%;
    overflow-y: auto;
    padding: 8px 10px;
    background: rgba(15, 22, 35, 0.82);
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 6px;
    backdrop-filter: blur(4px);
}
.ir-detail-cbar-item { font-family: 'DM Sans', sans-serif; color: #c7d2e0; }
.ir-detail-cbar-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 6px;
    font-size: 0.62rem;
    margin-bottom: 3px;
}
.ir-detail-cbar-units {
    display: flex;
    align-items: center;
    gap: 5px;
    color: #94a3b8;
}
.ir-detail-cbar-grad {
    width: 100%;
    height: 8px;
    border-radius: 2px;
}
.ir-detail-cbar-ticks {
    display: flex;
    justify-content: space-between;
    font-size: 0.52rem;
    color: #94a3b8;
    margin-top: 1px;
}
@media (max-width: 768px) {
    .ir-detail-env-cbars { max-width: 150px; padding: 6px 7px; }
}
/* US Radar overlay toggle — a sibling pill of the ⛰3D / Microwave toggles in
   the global-map control bar. Mirrors .ir-3d-mode-btn; green (reflectivity)
   active state so it reads as an overlay, not a base product. */
.ir-layers-wrap .ir-radar-mode-btn { order: 2; }
.ir-radar-mode-btn {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    border-radius: 5px;
    border: 1px solid rgba(255, 255, 255, 0.14);
    background: rgba(22, 27, 36, 0.92);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    padding: 4px 10px;
    font-family: 'DM Sans', sans-serif;
    font-size: 0.7rem;
    font-weight: 600;
    color: #cbd5e1;
    cursor: pointer;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.ir-radar-mode-btn .ir-radar-mode-glyph { font-size: 0.85rem; line-height: 1; opacity: 0.9; }
.ir-radar-mode-btn:hover {
    background: rgba(34, 197, 94, 0.16);
    border-color: rgba(34, 197, 94, 0.40);
    color: #ffffff;
}
.ir-radar-mode-btn.active {
    background: rgba(34, 197, 94, 0.22);
    border-color: rgba(34, 197, 94, 0.55);
    color: #86efac;
}
/* Radar dBZ legend (created in JS, appended to the map). Desktop: bottom-right,
   clear of the genesis/anim dock (which is bottom-left). */
.ir-radar-global-legend {
    position: absolute;
    right: 12px;
    bottom: 14px;
    z-index: 600;
    pointer-events: none;
    background: rgba(15, 23, 42, 0.82);
    color: #e2e8f0;
    font: 11px/1.3 'DM Sans', sans-serif;
    padding: 7px 9px;
    border-radius: 7px;
}
/* Mobile: the anim/genesis dock spans the FULL width at the bottom, so anchor
   the legend up under the (wrapped) control bar instead. */
@media (max-width: 768px) {
    /* Colorbar just above the bottom anim/genesis dock (#ir-global-anim-panel
       sits ~119px tall, bottom-anchored above the status bar). */
    .ir-radar-global-legend {
        right: auto;
        top: auto;
        left: 8px;
        bottom: 128px;
    }
    /* Compact the control bar — tighter inter-pill gap + slimmer toggle
       padding — so the wrapped rows take less width and clear the top-left
       Display button without a reserved-space gap. */
    .ir-layers-wrap { gap: 2px; }
    .ir-layers-wrap .ir-3d-mode-btn,
    .ir-layers-wrap .ir-radar-mode-btn,
    .ir-layers-wrap .ir-mw-toggle-btn { padding: 4px 6px; }
    .ir-mode-segment .ir-mode-btn { padding: 4px 6px; }
}

/* IR Brightness Temperature legend overlay */
.ir-tb-legend {
    position: absolute;
    bottom: 10px;
    left: 10px;
    z-index: 500;
    background: rgba(10, 14, 22, 0.62);
    border: 1px solid rgba(255, 255, 255, 0.12);
    padding: 6px 10px;
    border-radius: 4px;
    font-variant-numeric: tabular-nums;
    font-size: 0.65rem;
    color: #e2e8f0;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}
.ir-tb-legend-bar {
    width: 160px;
    height: 10px;
    border-radius: 2px;
    margin: 4px 0 2px;
    /* Claude IR LUT (matches satellite_ir.py _IR_STOPS, server-side
       pre-rendered into the WebP bundles): left = warm (+57°C / 330K),
       right = cold (-113°C / 160K). Sequence: near-black grey →
       grey-blue → light grey → pale blue → teal → green → gold →
       orange → crimson → magenta → violet → indigo. */
    background: linear-gradient(to right,
        rgb(12, 12, 22)     0.0%,
        rgb(70, 70, 82)    14.2%,
        rgb(120, 120, 132) 22.5%,
        rgb(180, 180, 192) 30.8%,
        rgb(216, 218, 228) 39.2%,
        rgb(140, 210, 220) 47.5%,
        rgb(68, 180, 196)  51.7%,
        rgb(32, 148, 166)  55.8%,
        rgb(40, 178, 116)  60.0%,
        rgb(96, 208, 68)   64.2%,
        rgb(192, 220, 40)  68.3%,
        rgb(238, 196, 48)  72.5%,
        rgb(228, 132, 48)  76.7%,
        rgb(214, 78, 56)   80.8%,
        rgb(180, 36, 68)   85.0%,
        rgb(196, 48, 156)  89.2%,
        rgb(168, 64, 200)  93.3%,
        rgb(120, 48, 180)  97.5%,
        rgb(64, 24, 140)  100.0%
    );
}
/* GIBS Band-8 WV is rendered with NASA's stock WV colormap: dry/warm
   pixels are sepia/brown, moist/cold pixels run through gray into
   blue → green → white. Mirror that ordering so 270 K → 200 K reads
   left → right. */
.ir-wv-legend-bar {
    background: linear-gradient(to right,
        rgb(102, 60, 30),
        rgb(170, 130, 90),
        rgb(220, 220, 220),
        rgb(80, 140, 200),
        rgb(40, 200, 180),
        rgb(255, 255, 255)
    );
}
.ir-tb-legend-labels {
    display: flex;
    justify-content: space-between;
    font-size: 0.6rem;
}

/* ── Animation controls ──────────────────────────────────────── */
.ir-anim-controls {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px;
    background: var(--surface-raised);
    border-top: 1px solid var(--border);
}
.ir-anim-btn {
    width: 32px;
    height: 32px;
    border: 1px solid rgba(15, 22, 35, 0.1);
    background: rgba(15, 22, 35, 0.04);
    color: #8993a4;
    border-radius: 4px;
    cursor: pointer;
    font-size: 0.75rem;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.2s;
}
.ir-anim-btn:hover {
    color: var(--text);
    background: var(--border);
}
.ir-anim-play {
    background: rgba(74, 155, 110, 0.15);
    border-color: rgba(74, 155, 110, 0.3);
    color: #4a9b6e;
}
.ir-anim-slider {
    flex: 1;
    min-width: 80px;
    height: 4px;
    -webkit-appearance: none;
    appearance: none;
    background: rgba(15, 22, 35, 0.1);
    border-radius: 2px;
    outline: none;
}
.ir-anim-speed {
    display: flex;
    align-items: center;
    gap: 4px;
    flex: 0 0 auto;
}
.ir-anim-speed-btn {
    width: 24px;
    height: 24px;
    font-weight: 700;
    line-height: 1;
}
.ir-anim-speed-btn:disabled {
    opacity: 0.35;
    cursor: not-allowed;
}
.ir-anim-speed-label {
    font-variant-numeric: tabular-nums;
    font-size: 0.72rem;
    color: #64748b;
    min-width: 32px;
    text-align: center;
    user-select: none;
}
.ir-anim-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--um-green);
    cursor: pointer;
    border: 2px solid var(--border-light);
}

/* Dark-mode overrides — the original ir-detail-header / ir-anim-* were
   calibrated for the light theme (low-alpha navy borders/backgrounds),
   which become invisible on the dark surface. Flip the alpha base from
   navy → white in dark mode for the back/kml/animation buttons + slider
   track + frame counter. */
[data-theme="dark"] .ir-back-btn,
[data-theme="dark"] .ir-kml-btn,
[data-theme="dark"] .ir-anim-btn {
    border-color: rgba(255, 255, 255, 0.18);
    background: rgba(255, 255, 255, 0.04);
}
[data-theme="dark"] .ir-back-btn:hover,
[data-theme="dark"] .ir-kml-btn:hover,
[data-theme="dark"] .ir-anim-btn:hover {
    background: rgba(255, 255, 255, 0.10);
    color: var(--text);
}
[data-theme="dark"] .ir-anim-slider {
    background: rgba(255, 255, 255, 0.14);
}

/* Frame-trim dropdown ("Frames ▾") — mirrors the download dropdown. */
.ir-frames-wrap { position: relative; display: inline-block; }
.ir-frames-btn.active {
    background: rgba(74, 155, 110, 0.30);
    border-color: rgba(74, 155, 110, 0.6);
}
.ir-frames-menu {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    z-index: 1100;
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: 6px;
    min-width: 200px;
    box-shadow: 0 6px 24px rgba(15, 22, 36, 0.18);
    padding: 4px;
    font-family: 'DM Sans', sans-serif;
}
[data-theme="dark"] .ir-frames-menu {
    background: rgba(20, 26, 38, 0.98);
    border-color: rgba(255, 255, 255, 0.12);
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.5);
}
.ir-frames-item {
    display: flex;
    flex-direction: column;
    width: 100%;
    padding: 7px 10px;
    background: transparent;
    border: none;
    border-radius: 4px;
    text-align: left;
    cursor: pointer;
    color: var(--text);
    transition: background 0.12s;
}
.ir-frames-item:hover { background: rgba(74, 155, 110, 0.12); }
[data-theme="dark"] .ir-frames-item:hover { background: rgba(74, 155, 110, 0.20); }
.ir-frames-item-title { font-size: 0.82rem; font-weight: 600; color: var(--um-green); line-height: 1.2; }
.ir-frames-item-desc { font-size: 0.68rem; color: #64748b; margin-top: 2px; }
[data-theme="dark"] .ir-frames-item-desc { color: #94a3b8; }

/* Scrubber wrapper + trim-range overlay (start/end handles + dimmed masks).
   The overlay is pointer-transparent except the handles, so the native
   slider thumb (playhead) still drags freely between them. */
.ir-anim-slider-wrap { position: relative; flex: 1; min-width: 80px; display: flex; align-items: center; }
.ir-anim-slider-wrap .ir-anim-slider { flex: 1; width: 100%; }
.ir-trim-overlay {
    position: absolute;
    left: 0; right: 0; top: 50%;
    transform: translateY(-50%);
    height: 18px;
    pointer-events: none;
}
.ir-trim-mask {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    height: 4px;
    background: repeating-linear-gradient(45deg,
        rgba(15, 22, 35, 0.30) 0, rgba(15, 22, 35, 0.30) 3px,
        rgba(15, 22, 35, 0.12) 3px, rgba(15, 22, 35, 0.12) 6px);
    border-radius: 2px;
}
.ir-trim-mask-left { left: 0; width: 0; }
.ir-trim-mask-right { right: 0; width: 0; }
[data-theme="dark"] .ir-trim-mask {
    background: repeating-linear-gradient(45deg,
        rgba(0, 0, 0, 0.50) 0, rgba(0, 0, 0, 0.50) 3px,
        rgba(0, 0, 0, 0.22) 3px, rgba(0, 0, 0, 0.22) 6px);
}
.ir-trim-handle {
    position: absolute;
    top: 50%;
    width: 9px;
    height: 18px;
    margin-left: -4.5px;
    transform: translateY(-50%);
    background: var(--um-green);
    border: 2px solid var(--border-light);
    border-radius: 3px;
    cursor: ew-resize;
    pointer-events: auto;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
    touch-action: none;
}
.ir-trim-handle:hover { filter: brightness(1.12); }
.ir-anim-counter {
    font-variant-numeric: tabular-nums;
    font-size: 0.72rem;
    color: #64748b;
    min-width: 50px;
    text-align: right;
}

/* ── Info sections (right panel) ─────────────────────────────── */
/* Skeleton pulse animation for loading placeholders */
@keyframes skeleton-pulse {
    0%   { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}
.skeleton-pulse {
    background: linear-gradient(90deg, transparent 25%, rgba(15, 22, 35,0.04) 50%, transparent 75%);
    background-size: 200% 100%;
    animation: skeleton-pulse 1.8s ease-in-out infinite;
    border-radius: 4px;
}
.skeleton-chart {
    height: 180px;
    background-color: rgba(15, 22, 35,0.03);
}
.skeleton-text {
    height: 14px;
    width: 120px;
    background-color: rgba(15, 22, 35,0.05);
    display: inline-block;
}

.ir-info-section {
    margin-bottom: 20px;
}
.ir-info-heading {
    font-size: 0.72rem;
    font-weight: 600;
    color: #64748b;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-bottom: 10px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--border);
}

/* ── IR Diagnostics in-panel section (#rt-diag-section) ─────────────── */
/* The Diagnostics toolbar button is a toggle: dim when off, full orange
   (the existing .ir-sat-viewer-btn style) when active. */
.ir-detail-diag-toggle-btn:not(.active) { opacity: 0.55; }
.ir-detail-diag-toggle-btn:not(.active):hover { opacity: 0.85; }

.rt-diag-readout {
    font-size: 0.72rem;
    line-height: 1.5;
    color: var(--text, #0f172a);
    background: rgba(46, 125, 255, 0.06);
    border: 1px solid var(--border, rgba(0, 0, 0, 0.12));
    border-radius: 6px;
    padding: 6px 9px;
    margin-bottom: 8px;
}
.rt-diag-readout .rt-diag-readout-gated { color: #b45309; }
[data-theme="dark"] .rt-diag-readout { color: var(--text, #e2e8f0); }
[data-theme="dark"] .rt-diag-readout .rt-diag-readout-gated { color: #fbbf24; }

.rt-diag-tabs,
.rt-diag-lookback {
    display: flex;
    gap: 4px;
    margin-bottom: 8px;
}
.rt-diag-lookback { justify-content: flex-start; margin-top: 2px; }

.rt-diag-tab,
.rt-diag-lookback-btn {
    padding: 3px 12px;
    font-size: 10px;
    font-weight: 600;
    color: var(--text, #0f172a);
    background: transparent;
    border: 1px solid var(--border, rgba(0, 0, 0, 0.12));
    border-radius: 999px;
    cursor: pointer;
    font-family: inherit;
    transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.rt-diag-tab:hover,
.rt-diag-lookback-btn:hover {
    background: rgba(46, 125, 255, 0.08);
    border-color: rgba(46, 125, 255, 0.45);
}
.rt-diag-tab.active,
.rt-diag-lookback-btn.active {
    background: rgba(46, 125, 255, 0.18);
    border-color: rgba(46, 125, 255, 0.65);
    color: #2e7dff;
}
[data-theme="dark"] .rt-diag-tab,
[data-theme="dark"] .rt-diag-lookback-btn {
    color: var(--text, #e2e8f0);
    border-color: rgba(148, 163, 184, 0.3);
}
[data-theme="dark"] .rt-diag-tab.active,
[data-theme="dark"] .rt-diag-lookback-btn.active {
    background: rgba(46, 125, 255, 0.28);
    border-color: rgba(46, 125, 255, 0.7);
    color: #93c5fd;
}

.rt-diag-view { display: flex; flex-direction: column; gap: 8px; }
.rt-diag-chart { width: 100%; min-height: 190px; }
.rt-diag-hovmoller-chart { min-height: 420px; }

.rt-diag-empty {
    color: #64748b;
    font-size: 0.78rem;
    text-align: center;
    padding: 24px 16px;
    line-height: 1.6;
}
.ir-info-grid {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.ir-info-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
}
.ir-info-label {
    font-size: 0.78rem;
    color: #8993a4;
}
.ir-info-value {
    font-variant-numeric: tabular-nums;
    font-size: 0.8rem;
    font-weight: 500;
    color: var(--text);
}

/* ── Environmental favorability dashboard ─────────────────────────
   Thin meter bars under Storm Info. Fill LENGTH = favorability (0→1),
   fill COLOR = favorable / marginal / hostile (set inline by JS). */
.ir-fav-dash {
    margin-top: 12px;
    padding-top: 10px;
    border-top: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    gap: 9px;
}
.ir-fav-heading {
    font-size: 0.62rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: #94a3b8;
}
.ir-fav-meter { display: flex; flex-direction: column; gap: 4px; }
.ir-fav-top {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
}
.ir-fav-label {
    font-size: 0.76rem;
    color: #8993a4;
    display: inline-flex;
    align-items: center;
    gap: 2px;
}
.ir-fav-sub {
    font-size: 0.66rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    margin-left: 5px;
    padding: 1px 5px;
    border-radius: 999px;
    background: rgba(148, 163, 184, 0.16);
    color: #94a3b8;
}
.ir-fav-sub.warm { background: rgba(226, 96, 63, 0.16); color: #e2603f; }
.ir-fav-sub.cool { background: rgba(56, 132, 214, 0.16); color: #4c86d6; }
.ir-fav-val {
    font-size: 0.82rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}
.ir-fav-bar {
    position: relative;
    height: 6px;
    border-radius: 999px;
    background: rgba(148, 163, 184, 0.20);
    overflow: hidden;
}
.ir-fav-fill {
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 0%;
    border-radius: 999px;
    background: #94a3b8;      /* neutral until data loads; JS recolors */
    transition: width 0.5s cubic-bezier(0.22, 0.61, 0.36, 1), background 0.35s;
}
.ir-fav-meter.is-empty .ir-fav-fill { width: 100%; opacity: 0.18; }
.ir-fav-note {
    font-size: 0.64rem;
    color: #64748b;
    line-height: 1.4;
}
[data-theme="dark"] .ir-fav-note { color: #7c8aa0; }
/* Composite ventilation-index meter — set apart from the 3 ingredient
   meters above it with a divider + slightly bolder label. */
.ir-fav-composite {
    margin-top: 4px;
    padding-top: 9px;
    border-top: 1px dashed rgba(100, 116, 139, 0.30);
}
.ir-fav-composite .ir-fav-label { font-weight: 600; color: var(--text); }
.ir-fav-vi-sub {
    font-size: 0.62rem;
    color: #64748b;
    font-variant-numeric: tabular-nums;
    margin-top: 2px;
}
[data-theme="dark"] .ir-fav-vi-sub { color: #7c8aa0; }

/* Vmax|MSLP segmented toggle in the intensity-chart heading. */
.ir-intensity-metric {
    display: inline-flex;
    border: 1px solid var(--border-light);
    border-radius: 5px;
    overflow: hidden;
}
.ir-intensity-metric-btn {
    padding: 2px 8px;
    font-family: 'DM Sans', sans-serif;
    font-size: 0.62rem;
    font-weight: 600;
    color: #8993a4;
    background: transparent;
    border: none;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}
.ir-intensity-metric-btn:hover { color: var(--text); }
.ir-intensity-metric-btn.active {
    background: rgba(0, 229, 255, 0.18);
    color: #00e5ff;
}

/* ── Intensity chart ─────────────────────────────────────────── */
.ir-intensity-chart {
    width: 100%;
    height: 200px;
    /* Was a hardcoded rgba(0,0,0,0.1) — a gray fill that ignored the
       theme. Use a transparent surface with a themed border so the
       Plotly transparent paper shows the card background through and
       the panel reads correctly in both light and dark layouts. */
    background: transparent;
    border: 1px solid var(--border);
    border-radius: 6px;
    overflow: hidden;
}

/* ── Recon cross-reference ───────────────────────────────────── */
.ir-recon-info {
    font-size: 0.82rem;
    color: #8993a4;
    line-height: 1.6;
}
.ir-recon-info a {
    color: #F47321;
    text-decoration: none;
}
.ir-recon-info a:hover {
    text-decoration: underline;
}

/* ── Official forecast link ─────────────────────────────────── */
.ir-official-link {
    display: inline-block;
    padding: 8px 16px;
    background: rgba(74, 155, 110, 0.12);
    border: 1px solid rgba(74, 155, 110, 0.3);
    border-radius: 6px;
    color: #60a5fa;
    text-decoration: none;
    font-size: 0.82rem;
    font-weight: 500;
    transition: all 0.2s;
}
.ir-official-link:hover {
    background: rgba(74, 155, 110, 0.2);
    border-color: rgba(74, 155, 110, 0.5);
    color: #93bbfc;
}
.ir-official-note {
    margin-top: 6px;
    font-size: 0.72rem;
    color: #64748b;
    line-height: 1.4;
}

/* ═══════════════════════════════════════════════════════════════
   Responsive
   ═══════════════════════════════════════════════════════════════ */

@media (max-width: 900px) {
    /* Stack the map over the info column and make the BODY the single
       scroll container (the desktop layout scrolls only inside
       .ir-detail-right, which on a phone buries everything below the
       Intensity chart — Model Forecasts, ASCAT, Recon — in a cramped,
       non-obvious nested scroll region the user can't find). Here the
       map gets a fixed height and the info column flows below it at its
       natural height, so normal page-scroll reaches every section. */
    .ir-detail-body {
        flex-direction: column;
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
    }
    .ir-detail-left {
        flex: none;
        height: 56vh;
        min-height: 280px;
        border-right: none;
        border-bottom: 1px solid var(--border);
    }
    .ir-detail-right {
        flex: none;          /* natural content height — flows below map */
        min-width: 0;
        overflow: visible;   /* defer scrolling to .ir-detail-body */
    }
}

@media (max-width: 600px) {
    .ir-legend {
        bottom: 36px;
        right: 8px;
        padding: 8px 10px;
    }
    .ir-legend h4 {
        font-size: 0.65rem;
    }
    .ir-legend-row {
        font-size: 0.65rem;
    }
}

/* ── Leaflet popup override for dark theme ───────────────────── */
.leaflet-popup-content-wrapper {
    background: rgba(255, 255, 255, 0.96) !important;
    border: 1px solid rgba(15, 22, 35, 0.1) !important;
    border-radius: 8px !important;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12) !important;
}
.leaflet-popup-tip {
    background: rgba(255, 255, 255, 0.96) !important;
}
.leaflet-popup-content {
    margin: 10px 14px !important;
}
.leaflet-popup-close-button {
    color: #8993a4 !important;
}
.leaflet-popup-close-button:hover {
    color: var(--text) !important;
}

/* Per-member genesis inspect popup — theme-aware override of the
   default Leaflet popup chrome so it matches dark mode and reads
   correctly over both light and dark basemaps. */
.leaflet-popup.rt-gen-member-leaflet-popup .leaflet-popup-content-wrapper {
    background: var(--surface-raised) !important;
    color: var(--text) !important;
    border: 1px solid rgba(148, 163, 184, 0.25) !important;
    box-shadow: 0 10px 28px rgba(0, 0, 0, 0.25) !important;
}
.leaflet-popup.rt-gen-member-leaflet-popup .leaflet-popup-tip {
    background: var(--surface-raised) !important;
}
.leaflet-popup.rt-gen-member-leaflet-popup .leaflet-popup-content {
    color: var(--text) !important;
}
.rt-gen-member-popup {
    color: var(--text);
}

/* Recon overlay popups (flight-level ob / dropsonde / VDM) — dark chrome
   to match the IR viewer, legible over satellite imagery. */
.leaflet-popup.rt-recon-popup .leaflet-popup-content-wrapper {
    background: var(--surface-raised) !important;
    color: var(--text) !important;
    border: 1px solid rgba(148, 163, 184, 0.25) !important;
    box-shadow: 0 10px 28px rgba(0, 0, 0, 0.3) !important;
}
.leaflet-popup.rt-recon-popup .leaflet-popup-tip {
    background: var(--surface-raised) !important;
}
.leaflet-popup.rt-recon-popup .leaflet-popup-content,
.leaflet-popup.rt-recon-popup .ir-popup {
    color: var(--text) !important;
}
.rt-recon-sonde-icon, .rt-recon-vdm-icon { background: transparent; border: none; }

/* ── Mobile touch-target and layout fixes ──────────────────── */
@media (max-width: 768px) {
    /* The GIBS feed banner is a centered shrink-to-fit flex row on
       desktop. On a narrow phone that intrinsic width collapses to a
       ~210px column, turning a one-line notice into a ~450px-tall wall
       of text covering half the map. Pin it full-width so the text
       flows into a couple of short lines instead. */
    .ir-feed-banner {
        left: 8px;
        right: 8px;
        transform: none;
        max-width: none;
        width: auto;
        top: 84px;
        font-size: 0.72rem;
        padding: 7px 10px;
    }
    /* Storm-card header: the action pills (Download / Obs / Grid /
       Loop Only / Diagnostics / Microwave) used to run off the right
       edge with no wrap and no scroll, so the last few were
       unreachable on a phone. Let the header + title row wrap so
       every control is tappable; compact the pills so the wrap stays
       to ~2 rows. */
    .ir-detail-header {
        flex-wrap: wrap;
        align-items: flex-start;   /* back button sits at top, not
                                       vertically centered against the
                                       taller wrapped title block */
        gap: 8px;
        padding: 8px 10px;
    }
    .ir-detail-title {
        flex-wrap: wrap;
        align-items: center;
        gap: 6px;
        row-gap: 6px;
        flex: 1 1 100%;            /* title (name + action pills) takes
                                       its own row(s) below the back
                                       button so the pills wrap cleanly */
    }
    .ir-kml-btn {
        margin-left: 0;
        padding: 6px 9px;
        font-size: 0.72rem;
        min-height: 34px;       /* comfortable touch target */
    }
    .ir-back-btn {
        padding: 6px 11px;
    }
    .ir-detail-storm-select {
        max-width: 150px;
    }
    /* Download dropdown anchors to its button; keep it from being
       clipped by the wrapped header. */
    .ir-download-menu,
    .ir-options-menu {
        z-index: 1200;
    }
    .ir-options-menu {
        max-height: 60vh;
    }

    .ir-product-toggle button {
        padding: 6px 9px;
        font-size: 11px;
        min-height: 34px;
    }
    /* The Models / DeepMind toggles default to a ~22px-tall pill — too
       small to tap reliably. Bring them up to the same 34px touch target
       as the other mobile controls. */
    .rt-model-toggle-btn,
    .rt-model-filter-btn {
        min-height: 34px;
        padding: 6px 12px;
    }
    .modebar-container,
    .modebar {
        display: none !important;
    }
    /* Stack the frame time and product toggle to avoid overlap. Hide
       the satellite name (redundant with the Storm Info panel) so the
       time readout stays narrow and doesn't collide with the toggle. */
    .ir-overlay-info {
        /* 48px (not 8px) so the timestamp clears the top-left zoom control —
           at 8px it sat on top of the +/− buttons. The pill is already
           narrowed below (sat-label hidden, max-width 44%) so it still clears
           the top-right product toggle. */
        left: 48px !important;
        top: 8px !important;
        font-size: 0.7rem;
        gap: 6px;
        max-width: 44%;
    }
    .ir-overlay-info .ir-sat-label {
        display: none;
    }
    .ir-product-toggle {
        top: 8px !important;
        right: 8px !important;
    }
    .ir-product-btn {
        font-size: 0.6rem;
        padding: 5px 7px;
    }
    /* Colorbar legend: the 160px bar covered a big chunk of the
       half-height mobile map. Shrink it to a compact strip. */
    .ir-tb-legend {
        bottom: 8px;
        left: 8px;
        padding: 4px 7px;
        font-size: 0.56rem;
    }
    .ir-tb-legend-bar {
        width: 92px;
        height: 7px;
    }
    .ir-tb-legend-labels {
        font-size: 0.5rem;
    }
    /* Fix map top offset to match compact topbar + secondary bar */
    .ir-map {
        top: 82px !important;
    }
    /* Hide intensity legend on mobile — saves ~180px of screen space */
    .ir-legend {
        display: none !important;
    }
    /* Move basins button below Leaflet zoom controls */
    .basin-sidebar-toggle {
        top: 180px !important;
    }
}

/* ═══════════════════════════════════════════════════════════════
   BASIN ACTIVITY SIDEBAR
   ═══════════════════════════════════════════════════════════════ */

.basin-sidebar {
    position: fixed;
    top: 52px;
    left: 0;
    bottom: 28px;
    width: 270px;
    background: rgba(255, 255, 255, 0.96);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border-right: 1px solid var(--border);
    z-index: 500;
    display: flex;
    flex-direction: column;
    transform: translateX(-100%);
    transition: transform 0.3s ease;
    overflow: hidden;
}
.basin-sidebar.open {
    transform: translateX(0);
}

/* When sidebar is open, shift the map */
.ir-map.sidebar-open {
    left: 270px !important;
}

.basin-sidebar-header {
    padding: 14px 16px 10px;
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: baseline;
    justify-content: space-between;
}
.basin-sidebar-header h3 {
    margin: 0;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text);
    letter-spacing: 0.02em;
}
.basin-sidebar-year {
    font-size: 0.72rem;
    color: #64748b;
    font-variant-numeric: tabular-nums;
}

.basin-sidebar-content {
    flex: 1;
    overflow-y: auto;
    padding: 8px 12px;
}

.basin-sidebar-footer {
    padding: 8px 16px;
    border-top: 1px solid var(--border);
    font-size: 0.65rem;
    color: #475569;
}
.basin-sidebar-climo-label {
    font-variant-numeric: tabular-nums;
}

.basin-sidebar-loading {
    text-align: center;
    color: #64748b;
    font-size: 0.78rem;
    padding: 20px 0;
}

/* ── Basin Card ──────────────────────────────────────────────── */
.basin-card {
    background: rgba(15, 22, 35, 0.03);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 10px 12px;
    margin-bottom: 8px;
    border-left: 3px solid var(--basin-color, #64748b);
}
.basin-card-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 6px;
}
.basin-card-name {
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--text);
}
.basin-card-active {
    font-size: 0.68rem;
    font-weight: 600;
    padding: 2px 8px;
    border-radius: 10px;
    background: rgba(239, 68, 68, 0.15);
    color: #f87171;
}
.basin-card-active.none {
    background: rgba(100, 116, 139, 0.1);
    color: #475569;
}

.basin-card-stats {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    gap: 4px;
    margin-bottom: 8px;
}
.basin-stat {
    text-align: center;
}
.basin-stat-val {
    font-size: 0.82rem;
    font-weight: 700;
    color: var(--text);
    font-variant-numeric: tabular-nums;
}
.basin-stat-label {
    font-size: 0.6rem;
    color: #64748b;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* ACE progress bar */
.basin-ace-row {
    display: flex;
    align-items: center;
    gap: 8px;
}
.basin-ace-label {
    font-size: 0.65rem;
    color: #8993a4;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
    min-width: 60px;
}
.basin-ace-bar {
    flex: 1;
    height: 6px;
    background: var(--border);
    border-radius: 3px;
    overflow: hidden;
    position: relative;
}
.basin-ace-fill {
    height: 100%;
    border-radius: 3px;
    transition: width 0.5s ease;
}
.basin-ace-pct {
    font-size: 0.62rem;
    color: #64748b;
    font-variant-numeric: tabular-nums;
    min-width: 32px;
    text-align: right;
}

/* ── Intensity legend toggle pill ────────────────────────────── */
/* Mirrors the basin-sidebar-toggle styling but doesn't shift left when
   active (that's a basin-sidebar-only behavior). Sits below the basin
   toggle on the map's top-left. */
.ir-legend-toggle {
    position: fixed;
    top: 208px;  /* below the Basins toggle (170-198) which itself sits below Leaflet zoom (95-155) */
    left: 10px;
    /* Uniform width + left-aligned text so Basins/Legend/Labels/Grid/Obs
       form a clean aligned column instead of ragged content-width pills. */
    width: 104px;
    box-sizing: border-box;
    text-align: left;
    z-index: 600;
    background: rgba(255, 255, 255, 0.88);
    color: #8993a4;
    border: 1px solid rgba(15, 22, 35, 0.1);
    border-radius: 6px;
    padding: 6px 12px;
    font-size: 0.72rem;
    font-family: 'DM Sans', sans-serif;
    font-weight: 500;
    cursor: pointer;
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    transition: background 0.15s, border-color 0.15s, color 0.15s;
    /* Skip iOS's 300 ms double-tap delay on these single-press toggles. */
    touch-action: manipulation;
}
.ir-legend-toggle:hover {
    background: rgba(255, 255, 255, 0.95);
    color: var(--text);
    border-color: rgba(74, 155, 110, 0.3);
}
.ir-legend-toggle.active {
    background: rgba(74, 155, 110, 0.18);
    color: #60a5fa;
    border-color: rgba(74, 155, 110, 0.4);
}

/* ── Global IR animation bar (bottom-left of RT map) ─────────── */
/* Style mirrors the .ir-bar pattern on the Global Archive storm
   detail page so the RT monitor's global-IR scrubber feels like
   the rest of the site — step buttons + play + draggable slider
   + monospace timestamp + speed pill — instead of the bespoke
   inline-styled bar that came before. */
.rt-anim-bar {
    background: rgba(22, 27, 36, 0.92);
    border: 1px solid rgba(255, 255, 255, 0.10);
    border-radius: 6px;
    padding: 5px 10px;
    font-family: 'DM Sans', sans-serif;
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
    /* Clear the 28px fixed status bar with a comfortable gap. !important
       because Leaflet's `.leaflet-bottom .leaflet-control` margin rule has
       higher specificity and otherwise pins the dock ~1px above the bar
       (so it reads as covered). */
    margin-bottom: 44px !important;
    min-width: 360px;
    max-width: min(90vw, 540px);
}
.rt-anim-row {
    display: flex;
    align-items: center;
    gap: 6px;
}
.rt-anim-btn {
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid rgba(255, 255, 255, 0.10);
    color: #c0d0ea;
    cursor: pointer;
    font-family: inherit;
    font-size: 0.74rem;
    line-height: 1;
    padding: 3px 8px;
    border-radius: 4px;
    min-width: 24px;
    height: 22px;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
}
/* Playback-control SVG icons (Play/Pause/Prev/Next/Stop) — vertical-center the
   glyph in the button and spin the loading icon. Shared across the Global Map,
   storm IR, storm-satellite and genesis-tau scrubbers for a consistent set. */
/* Flex-center the glyph in the button box — vertical-align:middle only centers
   against the line box (line-height), which left the SVGs sitting off-center. */
.rt-anim-btn, .ir-anim-btn, .sat-anim-btn, .rt-genesis-tau-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.rt-anim-btn svg, .ir-anim-btn svg, .sat-anim-btn svg, .rt-genesis-tau-btn svg {
    display: block;
}
.rt-anim-spin { animation: rt-anim-spin 0.8s linear infinite; transform-origin: 50% 50%; }
@keyframes rt-anim-spin { to { transform: rotate(360deg); } }
.rt-anim-btn:hover {
    background: rgba(74, 155, 110, 0.18);
    border-color: rgba(74, 155, 110, 0.45);
    color: #6cb78a;
}
.rt-anim-play.active {
    background: rgba(74, 155, 110, 0.22);
    border-color: rgba(74, 155, 110, 0.55);
    color: #6cb78a;
}
.rt-anim-btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}
.rt-anim-slider {
    flex: 1;
    min-width: 110px;
    -webkit-appearance: none;
    appearance: none;
    height: 4px;
    background: rgba(255, 255, 255, 0.10);
    border-radius: 2px;
    outline: none;
    cursor: pointer;
    margin: 0 4px;
}
.rt-anim-slider:disabled { opacity: 0.4; cursor: not-allowed; }
.rt-anim-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: #4a9b6e;
    cursor: pointer;
    border: 2px solid #161b24;
    margin-top: 0;
    transition: transform 0.12s;
}
.rt-anim-slider::-webkit-slider-thumb:hover { transform: scale(1.15); }
.rt-anim-slider::-moz-range-thumb {
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: #4a9b6e;
    cursor: pointer;
    border: 2px solid #161b24;
}
.rt-anim-dt {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.66rem;
    color: #e2e8f0;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.02em;
    min-width: 102px;
    text-align: right;
    white-space: nowrap;
}
.rt-anim-speed {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.62rem;
    font-weight: 600;
    min-width: 32px;
    padding: 3px 6px;
}
.rt-anim-status {
    font-size: 0.62rem;
    color: #94a3b8;
    margin-left: 4px;
}

/* ── Narrow-viewport animation dock ──────────────────────────────
   On a 375px phone the dock ran off the right edge and took two of its
   controls with it. Two compounding causes:

   1. .rt-anim-bar sets min-width:360px AND max-width:min(90vw,540px).
      min-width always wins over max-width, so at 375px the dock resolved
      to 360 + 20 padding + 2 border = 382px inside a 375px viewport.
   2. .rt-anim-row is a nowrap flex row whose children need ~460px
      (4x24 buttons + 110 slider + 102 timestamp + 32 speed + 58 colorbar
      + gaps), so they overflowed the dock's own box on top of that.

   Net effect: the speed button sat 30px past the viewport and the Tb
   colorbar 106px past it, and because documentElement.scrollWidth stayed
   at 375 there was no horizontal scroll to reach them — they were simply
   unreachable, not merely off-screen.

   Fix: let the dock shrink to the viewport, and let the row wrap so the
   overflowing controls fall to a second line. The scrubber may shrink;
   the timestamp keeps its 102px so "07/25 01:20 UTC" can't clip. */
@media (max-width: 560px) {
    .rt-anim-bar {
        /* border-box so the 10px padding + 1px border are INSIDE max-width —
           with the default content-box the dock still measured 377px wide and,
           sitting at the Leaflet control's 10px left margin, spilled 12px past
           a 375px viewport. */
        box-sizing: border-box;
        min-width: 0;
        max-width: calc(100vw - 20px);
    }
    .rt-anim-row {
        flex-wrap: wrap;
        justify-content: center;
        row-gap: 6px;
    }
    .rt-anim-slider { min-width: 0; flex: 1 1 90px; }
}

/* ── Contour value labels (env GeoJSON layers) ───────────────── */
/* L.divIcon HTML labels placed at each contour line's midpoint. They
   inherit DM Sans, stay crisp at any zoom (browser re-renders text),
   and have a high-contrast pill background so they read over the
   satellite IR basemap. */
.env-contour-label {
    font-family: 'DM Sans', sans-serif;
    font-size: 10px;
    font-weight: 600;
    color: #0f1a2e;
    background: rgba(255, 255, 255, 0.82);
    border-radius: 3px;
    padding: 0 4px;
    pointer-events: none;
    white-space: nowrap;
    box-shadow: 0 0 0 1px rgba(15, 22, 35, 0.15);
    line-height: 1.4;
}

/* ── Toggle button ───────────────────────────────────────────── */
.basin-sidebar-toggle {
    position: fixed;
    top: 170px;  /* sits below the Leaflet zoom controls (~95-155 px) so it doesn't cover them */
    left: 10px;
    /* Match the Legend/Labels/Grid/Obs pills for a clean aligned column. */
    width: 104px;
    box-sizing: border-box;
    text-align: left;
    z-index: 600;
    background: rgba(255, 255, 255, 0.88);
    color: #8993a4;
    border: 1px solid rgba(15, 22, 35, 0.1);
    border-radius: 6px;
    padding: 6px 12px;
    font-size: 0.72rem;
    font-family: 'DM Sans', sans-serif;
    font-weight: 500;
    cursor: pointer;
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    transition: all 0.2s;
    /* Skip iOS's 300 ms double-tap delay on this single-press toggle. */
    touch-action: manipulation;
}
.basin-sidebar-toggle:hover {
    background: rgba(255, 255, 255, 0.95);
    color: var(--text);
    border-color: rgba(74, 155, 110, 0.3);
}
.basin-sidebar-toggle.active {
    background: rgba(74, 155, 110, 0.15);
    color: #60a5fa;
    border-color: rgba(74, 155, 110, 0.4);
}

/* When sidebar is open, shift the toggle button */
.basin-sidebar-toggle.active {
    left: 280px;
}

/* ── Display Options dropdown ───────────────────────────────────────────────
   Folds Basins/Legend/Labels/Grid/Obs under one "Display" button. The original
   toggles are moved into #ir-display-menu and forced to flow (override their
   per-pill fixed positioning). The wrap shifts clear when the basin sidebar opens. */
#ir-display-wrap {
    position: fixed;
    /* Top-left corner of the map (below the header+tab strip), taking the spot
       the now-hidden zoom control used to occupy. */
    top: 92px;
    left: 10px;
    z-index: 600;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
}
body:has(.basin-sidebar.open) #ir-display-wrap { left: 280px; }
/* On mobile the IR/Vis/WV + 3D + Microwave + Layers controls are right-aligned
   and fill the top row, leaving only the top-LEFT corner free. Pin the Display
   button into that corner (top:92px, aligned with the control row) and collapse
   it to the ☰ icon so it clears the IR pill (which starts ~56px in) instead of
   overlapping it or floating orphaned lower-left. */
@media (max-width: 768px) {
    #ir-display-wrap { top: 92px; }
    .ir-display-toggle .ir-display-label { display: none; }
    /* Shrink to the ☰ glyph — the base .basin-sidebar-toggle pins width:104px,
       which would overlap the IR pill (~56px in). */
    .ir-display-toggle { width: auto !important; padding: 6px 10px; text-align: center; }
}
.ir-display-toggle {
    position: static !important;
    top: auto !important;
    left: auto !important;
}
#ir-display-menu {
    display: flex;
    flex-direction: column;
    gap: 6px;
    animation: irDisplayMenuIn 0.14s ease;
}
@keyframes irDisplayMenuIn {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: none; }
}
#ir-display-menu .ir-display-item {
    position: static !important;
    top: auto !important;
    left: auto !important;
    margin: 0 !important;
}
/* IR colormap picker inside the Display menu */
#ir-display-menu .ir-cmap-row { display: flex; width: 104px; box-sizing: border-box; }
#ir-display-menu .ir-cmap-select {
    width: 100%;
    font: 500 0.72rem 'DM Sans', sans-serif;
    color: #8993a4;
    background: rgba(255, 255, 255, 0.88);
    border: 1px solid rgba(15, 22, 35, 0.1);
    border-radius: 6px;
    padding: 6px 8px;
    cursor: pointer;
}

/* Drop the +/- zoom buttons on the global map (all viewports) — continuous
   scroll / pinch zoom is natural on GL, and removing them frees the top-left
   corner for the Display button. */
#ir-map .maplibregl-ctrl-top-left .maplibregl-ctrl-group { display: none; }

/* The Legend/Labels/Grid pills sit at z-index 600 (above the 270-px
   sidebar at z-index 500), so without this they render on top of the
   basin cards when the panel opens. Shift them right alongside the
   toggle so they stay reachable and stop covering the cards. */
body:has(.basin-sidebar.open) #ir-legend-toggle,
body:has(.basin-sidebar.open) #ir-labels-toggle,
body:has(.basin-sidebar.open) #ir-grid-toggle,
body:has(.basin-sidebar.open) #ir-obs-toggle,
body:has(.basin-sidebar.open) #ir-obs-hint {
    left: 280px;
}

/* ── Mobile: hide sidebar, show as overlay ───────────────────── */
@media (max-width: 768px) {
    .basin-sidebar {
        width: 100%;
        bottom: auto;
        max-height: 60vh;
        border-right: none;
        border-bottom: 1px solid var(--border);
        border-radius: 0 0 12px 12px;
        /* Fade-mask the bottom edge so users see that the season-data
           list scrolls inside the 60vh cap (otherwise the truncation
           looks like a missing list). The mask only renders when
           inner content actually overflows. */
        -webkit-mask-image: linear-gradient(to bottom, #000 0, #000 calc(100% - 24px), transparent 100%);
                mask-image: linear-gradient(to bottom, #000 0, #000 calc(100% - 24px), transparent 100%);
    }
    .basin-sidebar-content {
        scroll-padding-bottom: 28px;
    }
    .ir-map.sidebar-open {
        left: 0 !important;
    }
    .basin-sidebar-toggle.active {
        left: 10px;
    }
    /* Full-width overlay on mobile — the 280-px desktop shift would push
       these off-screen, so hide the map-control pills while the basin
       panel is open instead. */
    body:has(.basin-sidebar.open) #ir-legend-toggle,
    body:has(.basin-sidebar.open) #ir-labels-toggle,
    body:has(.basin-sidebar.open) #ir-grid-toggle,
    body:has(.basin-sidebar.open) #ir-obs-toggle,
    body:has(.basin-sidebar.open) #ir-obs-hint {
        display: none;
    }
}

/* ═══════════════════════════════════════════════════════════════
   Model Forecast Overlay
   ═══════════════════════════════════════════════════════════════ */

.rt-model-toggle-btn {
    font-size: 0.7rem;
    padding: 3px 10px;
    border: 1px solid rgba(116, 185, 255, 0.4);
    background: rgba(116, 185, 255, 0.15);
    color: #1d4ed8;
    border-radius: 4px;
    cursor: pointer;
    font-family: 'DM Sans', sans-serif;
    transition: all 0.2s;
}
.rt-model-toggle-btn:hover {
    background: rgba(116, 185, 255, 0.25);
}

.rt-model-controls-inner {
    background: var(--surface-raised, #ffffff);
    border: 1px solid var(--border-light);
    border-radius: 6px;
    padding: 8px 10px;
}

.rt-model-cycle-select {
    flex: 1;
    min-width: 120px;
    font-size: 10px;
    padding: 3px 6px;
    border: 1px solid var(--border-light);
    border-radius: 4px;
    background: var(--surface-raised);
    color: var(--text);
    font-variant-numeric: tabular-nums;
}

.rt-model-filter-btn {
    font-size: 9px;
    padding: 2px 6px;
    border: 1px solid var(--border-light);
    background: transparent;
    color: #1d4ed8;
    border-radius: 3px;
    cursor: pointer;
    font-family: 'DM Sans', sans-serif;
    transition: all 0.15s;
}
.rt-model-filter-btn:hover {
    border-color: rgba(116, 185, 255, 0.3);
}
.rt-model-filter-btn.active {
    background: rgba(116, 185, 255, 0.15);
    border-color: rgba(116, 185, 255, 0.4);
}

.rt-model-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 2px 8px;
    padding: 2px 0;
}
.rt-model-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    font-size: 0.7rem;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    line-height: 1.4;
}
.rt-model-legend-swatch {
    display: inline-block;
    width: 10px;
    height: 3px;
    border-radius: 1px;
    flex-shrink: 0;
}

/* ── Raw Tb Image Overlay ─────────────────────────────────────── */
/* At 2km resolution the image is ~1000px — browser default smooth
   interpolation looks best when displayed at screen resolution. */

/* ── ASCAT Wind Barb Overlay ─────────────────────────────────── */
.ascat-barb-icon {
    background: none !important;
    border: none !important;
}
.ascat-barb-icon svg {
    overflow: visible;
}
.ascat-tooltip {
    font-variant-numeric: tabular-nums;
    font-size: 11px;
    padding: 3px 6px;
    background: rgba(255, 255, 255, 0.9);
    border: 1px solid rgba(116, 185, 255, 0.3);
    color: var(--text);
    border-radius: 3px;
}

/* ── DeepMind Ensemble Distribution Sliders ──────────────────── */

.rt-dm-slider {
    flex: 1;
    -webkit-appearance: none;
    appearance: none;
    height: 4px;
    background: rgba(15, 22, 35, 0.1);
    border-radius: 2px;
    outline: none;
    cursor: pointer;
}
.rt-dm-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: var(--um-orange, #F47321);
    border: 2px solid #0f172a;
    cursor: pointer;
    margin-top: -4px;  /* center on 4px track */
}
.rt-dm-slider::-moz-range-thumb {
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: var(--um-orange, #F47321);
    border: 2px solid #0f172a;
    cursor: pointer;
}

/* GDMI chart export button */
.rt-dm-export-btn {
    background: none;
    border: 1px solid rgba(0, 229, 255, 0.25);
    color: #00e5ff;
    font-size: 13px;
    width: 28px;
    height: 28px;
    min-width: 28px;
    min-height: 28px;
    border-radius: 4px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    opacity: 0.6;
    transition: opacity 0.15s, background 0.15s;
    position: relative;
}
.rt-dm-export-btn:hover {
    opacity: 1;
    background: rgba(0, 229, 255, 0.12);
}

/* Export theme popup */
.rt-dm-export-popup {
    position: absolute;
    right: 0;
    top: 100%;
    margin-top: 0;
    background: rgba(255, 255, 255, 0.95);
    border: 1px solid rgba(0, 229, 255, 0.2);
    border-radius: 6px;
    padding: 4px;
    display: flex;
    gap: 4px;
    z-index: 100;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.rt-dm-export-popup button {
    font-size: 11px;
    padding: 5px 14px;
    border-radius: 4px;
    border: 1px solid rgba(15, 22, 35, 0.15);
    cursor: pointer;
    font-variant-numeric: tabular-nums;
    transition: background 0.15s;
}
.rt-dm-export-popup .export-dark {
    background: #1e293b;
    color: var(--text);
}
.rt-dm-export-popup .export-dark:hover {
    background: #334155;
}
.rt-dm-export-popup .export-light {
    background: #f1f5f9;
    color: #1e293b;
}
.rt-dm-export-popup .export-light:hover {
    background: #e6e8eb;
}

/* ═══════════════════════════════════════════════════════════════
   GLOBAL MAP TOGGLE PILLS  (top-right floating menus)
   Switch to GeoColor / DeepMind 10-day / Genesis Forecasts /
   Winds / Environmental Analysis — all share a dark glass-pill
   base with UM-green hover + active. Genesis uses .active-orange
   so "potential genesis" stays visually separated from active
   storms (UM orange = the live/attention accent in the palette).
   ═══════════════════════════════════════════════════════════════ */

.ir-global-toggle-btn {
    padding: 6px 14px;
    font-family: 'DM Sans', sans-serif;
    font-size: 0.72rem;
    font-weight: 500;
    color: #cbd5e1;
    background: rgba(22, 27, 36, 0.92);
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 5px;
    cursor: pointer;
    white-space: nowrap;
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.ir-global-toggle-btn:hover {
    background: rgba(74, 155, 110, 0.22);
    color: #ffffff;
    border-color: rgba(74, 155, 110, 0.45);
}
.ir-global-toggle-btn.active {
    background: rgba(74, 155, 110, 0.28);
    color: #ffffff;
    border-color: rgba(74, 155, 110, 0.65);
}
.ir-global-toggle-btn.active:hover {
    background: rgba(74, 155, 110, 0.34);
    border-color: rgba(74, 155, 110, 0.75);
}
.ir-global-toggle-btn.active-orange {
    background: rgba(244, 115, 33, 0.22);
    color: #ffd2a8;
    border-color: rgba(244, 115, 33, 0.55);
}
.ir-global-toggle-btn.active-orange:hover {
    background: rgba(244, 115, 33, 0.30);
    color: #ffe2c2;
    border-color: rgba(244, 115, 33, 0.70);
}

/* Status pill that sits under the DeepMind 10-day toggle */
.ir-global-wl-status {
    font-family: 'DM Sans', sans-serif;
    font-size: 0.62rem;
    color: #cbd5e1;
    background: rgba(22, 27, 36, 0.75);
    padding: 2px 6px;
    border-radius: 3px;
}

/* ── Dropdown menus (Genesis / Winds / Env Analysis) ────────── */
.ir-global-menu {
    background: rgba(22, 27, 36, 0.95);
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: 6px;
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.30);
    overflow: hidden;
}
.ir-global-menu-valid {
    padding: 6px 10px;
    font-size: 0.6rem;
    color: #94a3b8;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.ir-global-menu-valid b {
    color: #e2e8f0;
    font-weight: 600;
}
.ir-global-menu-section {
    padding: 6px 10px 2px;
    font-size: 0.6rem;
    color: #cbd5e1;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-weight: 600;
}
.ir-global-menu-section.with-divider {
    border-top: 1px solid rgba(255, 255, 255, 0.08);
    margin-top: 4px;
    padding-top: 6px;
}
.ir-global-menu-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 10px;
    cursor: pointer;
    font-size: 0.72rem;
    color: #e2e8f0;
    line-height: 1.25;
    transition: background 0.12s;
}
.ir-global-menu-row:hover {
    background: rgba(74, 155, 110, 0.10);
}
.ir-global-menu-row input[type="checkbox"] {
    cursor: pointer;
    accent-color: #4a9b6e;  /* UM green (dark-theme value reads on dark surface) */
}
.ir-global-menu-row .label {
    flex: 1;
}
.ir-global-menu-row .units {
    font-size: 0.6rem;
    color: #94a3b8;
}
.ir-global-menu-row .substatus {
    font-size: 0.62rem;
    color: #94a3b8;
    display: block;
    margin-top: 1px;
}
/* Small "ⓘ" hint that surfaces the row's full description via the
   native title-attribute tooltip on hover. Used for subseasonal-forcing
   layers whose abbreviated name (e.g. "MRG / TD-type") needs unpacking. */
.ir-global-menu-row .ir-row-info {
    font-size: 0.72rem;
    color: #94a3b8;
    opacity: 0.55;
    margin-left: 4px;
    flex: 0 0 auto;
    transition: opacity 0.12s;
}
.ir-global-menu-row:hover .ir-row-info {
    opacity: 1;
    color: var(--blue, #2e7dff);
}
.ir-global-menu-empty {
    padding: 8px 10px;
    font-size: 0.7rem;
    color: #94a3b8;
}
.ir-global-menu-help {
    padding: 6px 10px 8px;
    font-size: 0.55rem;
    color: #94a3b8;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
    margin-top: 6px;
    line-height: 1.4;
}
.ir-global-menu-opacity-wrap {
    padding: 6px 10px 8px;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
    margin-top: 4px;
}
.ir-global-menu-opacity {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.65rem;
    color: #cbd5e1;
}
.ir-global-menu-opacity input[type="range"] {
    flex: 1;
    height: 14px;
    accent-color: #4a9b6e;  /* UM green slider thumb/fill */
}
.ir-global-menu-opacity .pct {
    width: 30px;
    text-align: right;
    color: #e2e8f0;
    font-variant-numeric: tabular-nums;
}

/* Sub-headers inside the unified Layers panel — for the Wind Shear /
   Vorticity / Heights / Moisture & SST physical-category groups
   sitting INSIDE the larger ANALYSIS section. Tighter, dimmer than
   the top-level .ir-global-menu-section so the hierarchy reads
   "section → subhead → row" without competing weights. */
.ir-global-menu-subhead {
    padding: 4px 10px 1px;
    font-size: 0.58rem;
    color: #94a3b8;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-weight: 600;
}

/* ═══════════════════════════════════════════════════════════════
   UNIFIED LAYERS PANEL  (right-rail UI shell)
   One primary "Layers ▾" trigger replaces the old stack of DeepMind
   / Genesis / Winds / Env Analysis pills. The redesign collapses six
   visually-identical buttons into one labeled control + small utility
   chips, with a count badge so users see how many overlays are on
   without opening anything.
   ═══════════════════════════════════════════════════════════════ */

/* Top control strip: lay the controls in ONE horizontal row instead of a
   3-deep vertical stack, so the top-right footprint is shallow and the map gets
   more vertical room (esp. mobile). Order (left→right): IR/Vis/WV · Microwave ·
   Layers. CSS `order` does the reordering without touching the DOM build order. */
.ir-layers-wrap {
    display: flex;
    flex-direction: row;
    align-items: center;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 6px;
    position: relative;   /* anchor the export PNG/GIF menu */
}

/* Download chooser (PNG / animated GIF) under the export icon. */
.ir-export-menu {
    position: absolute;
    top: 100%;
    right: 0;
    margin-top: 6px;
    z-index: 1200;
    min-width: 180px;
    padding: 4px;
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: 7px;
    background: rgba(22, 27, 36, 0.96);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    box-shadow: 0 6px 22px rgba(0, 0, 0, 0.45);
}
.ir-export-menu-item {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 7px 10px;
    background: transparent;
    border: none;
    border-radius: 5px;
    font-family: 'DM Sans', sans-serif;
    font-size: 0.74rem;
    font-weight: 500;
    color: #e2e8f0;
    text-align: left;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}
.ir-export-menu-item:hover {
    background: rgba(74, 155, 110, 0.22);
    color: #ffffff;
}
.ir-export-menu-glyph {
    width: 14px;
    text-align: center;
    opacity: 0.85;
}
.ir-layers-wrap .ir-mode-segment { order: 1; }
.ir-layers-wrap .ir-mw-toggle-group { order: 2; margin-top: 0; }
.ir-layers-wrap .ir-layers-row { order: 3; }

.ir-layers-row {
    display: flex;
    align-items: center;
    gap: 6px;
}

/* Primary "Layers" trigger button — slightly more emphatic than the
   utility chips beside it (slight bg lift, label has more weight). */
.ir-layers-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-weight: 600;
}
.ir-layers-toggle .ir-layers-label {
    letter-spacing: 0.02em;
}
.ir-layers-toggle .ir-layers-caret {
    font-size: 0.65rem;
    opacity: 0.7;
    transition: transform 0.18s;
}
.ir-layers-toggle.active .ir-layers-caret {
    transform: rotate(180deg);
}
.ir-layers-toggle .ir-layers-count {
    display: none;            /* hidden until JS sets has-active */
    min-width: 16px;
    padding: 0 5px;
    height: 16px;
    line-height: 16px;
    text-align: center;
    border-radius: 8px;
    background: var(--um-orange, #F47321);
    color: #ffffff;
    font-size: 0.62rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    margin-left: 2px;
}
.ir-layers-toggle.has-active .ir-layers-count {
    display: inline-block;
}

/* Icon-only utility chip (PNG export) — square footprint, same dark
   pill base as .ir-global-toggle-btn but compact so it doesn't compete
   with the labeled trigger. */
.ir-layers-icon-btn {
    width: 32px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 28px;
}

/* IR/GeoColor segmented mode switch — replaces the wide "Switch to
   GeoColor" pill. Binary mode picker reads more clearly as two pills
   side by side with one always lit. */
.ir-mode-segment {
    display: inline-flex;
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: 5px;
    overflow: hidden;
    background: rgba(22, 27, 36, 0.92);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}
.ir-mode-btn {
    background: transparent;
    border: none;
    padding: 4px 12px;
    font-family: 'DM Sans', sans-serif;
    font-size: 0.7rem;
    font-weight: 500;
    color: #cbd5e1;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
    border-right: 1px solid rgba(255, 255, 255, 0.10);
}
.ir-mode-btn:last-child { border-right: none; }
.ir-mode-btn:hover {
    background: rgba(74, 155, 110, 0.18);
    color: #ffffff;
}
.ir-mode-btn.ir-mode-active {
    background: rgba(74, 155, 110, 0.32);
    color: #ffffff;
}

/* Microwave one-click pill — sits below the IR/GeoColor segment.
   MW is an additive overlay (not a basemap replacement), so it gets
   its own pill with a dot indicator rather than living inside the
   IR/GeoColor radio segment. Active state matches the segment's
   green-tint so the controls feel like a single group visually.
   Split-button: main pill toggles, chevron opens Layers panel. */
.ir-mw-toggle-group {
    display: inline-flex;
    align-items: stretch;
    margin-top: 4px;
    border-radius: 5px;
    overflow: hidden;
    border: 1px solid rgba(255, 255, 255, 0.14);
    background: rgba(22, 27, 36, 0.92);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    transition: border-color 0.15s;
}
.ir-mw-toggle-group:has(.ir-mw-toggle-btn.active) {
    border-color: rgba(74, 155, 110, 0.55);
}
.ir-mw-toggle-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: transparent;
    border: none;
    padding: 4px 10px;
    font-family: 'DM Sans', sans-serif;
    font-size: 0.7rem;
    font-weight: 500;
    color: #cbd5e1;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}
.ir-mw-toggle-btn:hover {
    background: rgba(74, 155, 110, 0.18);
    color: #ffffff;
}
.ir-mw-toggle-btn.active {
    background: rgba(74, 155, 110, 0.32);
    color: #ffffff;
}
.ir-mw-toggle-dot {
    width: 7px; height: 7px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.25);
    transition: background 0.15s;
}
.ir-mw-toggle-btn.active .ir-mw-toggle-dot {
    background: #4ade80;
    box-shadow: 0 0 6px rgba(74, 222, 128, 0.7);
}

/* 3D Convection top-level pill — sibling of IR/Vis/WV (sits right after the
   segment). Muted when off; UM-orange when the 3D terrain is engaged, matching
   the Tilt/Height control accents + the active toolbar buttons. */
.ir-layers-wrap .ir-3d-mode-btn { order: 1; }
.ir-3d-mode-btn {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    border-radius: 5px;
    border: 1px solid rgba(255, 255, 255, 0.14);
    background: rgba(22, 27, 36, 0.92);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    padding: 4px 10px;
    font-family: 'DM Sans', sans-serif;
    font-size: 0.7rem;
    font-weight: 600;
    color: #cbd5e1;
    cursor: pointer;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.ir-3d-mode-btn .ir-3d-mode-glyph { font-size: 0.85rem; line-height: 1; opacity: 0.9; }
.ir-3d-mode-btn:hover {
    background: rgba(244, 115, 33, 0.16);
    border-color: rgba(244, 115, 33, 0.40);
    color: #ffffff;
}
.ir-3d-mode-btn.active {
    background: rgba(244, 115, 33, 0.22);
    border-color: rgba(244, 115, 33, 0.55);
    color: #fdba74;
}
.ir-mw-expand-btn {
    background: transparent;
    border: none;
    border-left: 1px solid rgba(255, 255, 255, 0.10);
    padding: 4px 7px;
    font-family: 'DM Sans', sans-serif;
    font-size: 0.65rem;
    color: #94a3b8;
    cursor: pointer;
    transition: background 0.15s, color 0.15s, transform 0.15s;
}
.ir-mw-expand-btn:hover {
    background: rgba(74, 155, 110, 0.18);
    color: #ffffff;
}
.ir-mw-expand-btn.open {
    background: rgba(74, 155, 110, 0.24);
    color: #ffffff;
}
.ir-mw-expand-btn.open span {
    display: inline-block;
    transform: rotate(180deg);
}

/* MW options popover — anchored to the wrap (Leaflet control) so it
   floats out under the pill group without colliding with the Layers
   panel. Width sized for the controls (product + sensors + sliders +
   legend + scrubber + opacity). Right-aligned because the pill is in
   the top-right of the map. */
.ir-mw-popover {
    position: absolute;
    right: 0;
    top: 100%;
    margin-top: 6px;
    min-width: 280px;
    max-width: 320px;
    background: rgba(15, 22, 36, 0.96);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border: 1px solid rgba(255, 255, 255, 0.16);
    border-radius: 8px;
    padding: 10px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
    z-index: 1000;
}
/* Popover hosts the same .tc-mw-ui block as the (former) Layers
   panel slot used to. Tighten the wrap so it fits the popover. */
.ir-mw-popover .tc-mw-ui {
    width: 100%;
}

/* Labels toggle position — sits in the top-left stack underneath the
   Legend toggle (Basins 170px → Legend 208px → Labels 246px). Reuses
   the .ir-legend-toggle pill styling for visual consistency across
   the three buttons. */
.ir-labels-toggle-pos {
    top: 246px !important;
}
/* Grid toggle — fourth in the stack, beneath Labels. */
.ir-grid-toggle-pos {
    top: 284px !important;
}
/* Surface Obs toggle — fifth in the stack, beneath Grid. */
.ir-obs-toggle-pos {
    top: 322px !important;
}
/* Surface Obs status hint — sits just below the Obs toggle, shows
   "Zoom in…" gating prompt or the station count for the viewport. */
.ir-obs-hint-pos {
    position: fixed;
    top: 358px;
    left: 10px;
    z-index: 600;
    max-width: 180px;
    padding: 3px 8px;
    border-radius: 5px;
    background: rgba(15, 22, 35, 0.72);
    color: rgba(226, 232, 240, 0.92);
    font-family: 'DM Sans', sans-serif;
    font-size: 0.66rem;
    font-weight: 500;
    pointer-events: none;
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}
/* Graticule labels — divIcon markers placed at gridline crossings on
   the RT global map. Mono font, light text with a dark halo so they
   read on both bright land and dark ocean basemap tiles. */
.rt-graticule-label {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 10px;
    font-weight: 600;
    color: #f1f5f9;
    text-shadow:
        0 0 4px rgba(15, 22, 36, 0.95),
        0 0 2px rgba(15, 22, 36, 0.95),
        0 0 1px rgba(15, 22, 36, 0.95);
    pointer-events: none;
    white-space: nowrap;
    line-height: 14px;
    background: transparent;
    border: none;
}

/* ═══════════════════════════════════════════════════════════════
   MOBILE: Layers panel as a bottom sheet
   Phones can't host a 300-px-wide dropdown without it clobbering
   the bottom-left colorbar stack and most of the visible map.
   Below 768 px the panel slides up from the bottom as a sheet,
   the env-colorbar stack lifts above its top edge, and a tap-to-
   dismiss backdrop appears so users don't have to hunt for the
   "Layers" pill again to close.
   ═══════════════════════════════════════════════════════════════ */
.ir-layers-backdrop {
    display: none;  /* mobile media query enables */
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.35);
    z-index: 1099;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease-out;
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
}

/* Sheet header (drag handle + X close) is hidden on desktop — the
   panel is a flow-positioned dropdown there, not a dismissable sheet.
   The mobile media query overrides display: block. */
.ir-layers-sheet-header {
    display: none;
}

@media (max-width: 768px) {
    .ir-layers-backdrop {
        display: block;
    }
    .ir-layers-backdrop.is-active {
        opacity: 1;
        pointer-events: auto;
    }
    /* Override desktop top-right dropdown positioning. The wrap
       around the panel stays at top-right (so the trigger button
       stays there) but the panel itself flies off to the bottom
       of the viewport. */
    .ir-layers-panel {
        position: fixed !important;
        bottom: 0 !important;
        left: 0 !important;
        right: 0 !important;
        top: auto !important;
        width: 100% !important;
        min-width: 0 !important;
        max-width: 100% !important;
        max-height: 65vh !important;
        border-radius: 14px 14px 0 0 !important;
        border: 1px solid rgba(255, 255, 255, 0.10);
        border-bottom: none;
        box-shadow: 0 -10px 28px rgba(0, 0, 0, 0.55);
        transform: translateY(100%);
        transition: transform 0.25s cubic-bezier(0.2, 0.7, 0.2, 1);
        z-index: 1100;
        padding-top: 22px;   /* room for the drag handle */
        overflow-y: auto;
        /* The shared .ir-global-menu base is rgba(22,27,36,0.95) + an
           8 px backdrop blur — on a phone that reads as a low-contrast
           frosted card with the satellite imagery showing through.
           Override to a fully opaque dark surface so text is sharp and
           the rows pop. */
        background: #11161f !important;
        backdrop-filter: none !important;
        -webkit-backdrop-filter: none !important;
    }
    /* Bump font + row padding inside the sheet so labels are
       comfortable to read AND tap. Desktop's 0.72 rem ≈ 11.5 px is
       too small for touch input. */
    .ir-layers-panel .ir-global-menu-row {
        font-size: 0.9rem;
        padding: 10px 14px;
    }
    .ir-layers-panel .ir-global-menu-row .label {
        font-size: 0.88rem;
    }
    .ir-layers-panel .ir-global-menu-row .units {
        font-size: 0.78rem;
    }
    .ir-layers-panel .ir-global-menu-section {
        font-size: 0.82rem;
        padding-left: 14px;
        padding-right: 14px;
        padding-top: 10px;
    }
    .ir-layers-panel .ir-global-menu-subhead {
        font-size: 0.62rem;
        padding-left: 14px;
        padding-right: 14px;
    }
    .ir-layers-panel .ir-global-menu-valid,
    .ir-layers-panel .ir-global-menu-help,
    .ir-layers-panel .ir-global-menu-opacity-wrap {
        padding-left: 14px;
        padding-right: 14px;
    }
    .ir-layers-panel.is-open-mobile {
        transform: translateY(0);
    }
    /* Sheet header — visible only on mobile. Contains the drag-handle
       pill (tappable to dismiss) and the X close button. Sits at the
       top of the sheet inside its own row so the content below scrolls
       independently. */
    .ir-layers-sheet-header {
        display: block;
        position: relative;
        height: 28px;
        flex-shrink: 0;
        border-bottom: 1px solid rgba(255, 255, 255, 0.06);
    }
    /* Tappable drag-handle pill — centered visually. Click it to
       dismiss (drag-to-dismiss would need pointer math; not done). */
    .ir-layers-handle {
        position: absolute;
        top: 8px;
        left: 50%;
        transform: translateX(-50%);
        width: 56px;            /* fat tap target — visual pill is 40px */
        height: 14px;
        padding: 0;
        background: transparent;
        border: none;
        cursor: pointer;
    }
    .ir-layers-handle::before {
        content: '';
        position: absolute;
        top: 5px;
        left: 50%;
        transform: translateX(-50%);
        width: 40px;
        height: 4px;
        background: rgba(255, 255, 255, 0.30);
        border-radius: 2px;
        transition: background 0.15s;
    }
    .ir-layers-handle:active::before {
        background: rgba(255, 255, 255, 0.55);
    }
    /* X close button — top-right corner of the sheet header. The
       most universally-understood "dismiss" affordance for users
       who don't know about backdrop-tap or drag handles. */
    .ir-layers-sheet-close {
        position: absolute;
        top: 0;
        right: 0;
        width: 44px;
        height: 44px;            /* Apple HIG min tap target */
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 0;
        background: transparent;
        border: none;
        color: rgba(255, 255, 255, 0.55);
        font-size: 1.6rem;
        line-height: 1;
        cursor: pointer;
        transition: color 0.15s, background 0.15s;
    }
    .ir-layers-sheet-close:active {
        color: #ffffff;
        background: rgba(255, 255, 255, 0.06);
    }
    /* Reset the desktop-only padding-top that used to make room for
       the pseudo-element drag handle. The real .ir-layers-sheet-header
       provides its own height now. */
    .ir-layers-panel {
        padding-top: 0 !important;
    }
    .ir-layers-content {
        overflow-y: auto;
    }
    /* When the sheet is open, lift the env-colorbar stack above its
       top edge so users can read the legend they're configuring. */
    body.rt-layers-sheet-open #ir-global-env-cbars {
        bottom: calc(65vh + 8px) !important;
        max-height: 25vh !important;
        left: 50% !important;
        transform: translateX(-50%);
        right: auto !important;
        max-width: min(92vw, 360px) !important;
    }
}

/* The unified Layers dropdown — wider than the old single-purpose
   menus so it can hold the FORECAST / ANALYSIS / WIND BARBS sections
   side-by-side at the same panel level. Capped on tall screens so the
   panel doesn't bleed off the bottom of the map. */
.ir-layers-panel {
    /* Desktop top-right dropdown: pop the panel OUT of the .ir-layers-wrap
       flex row (position:absolute) so its height never grows the row. As a
       static flex child it was sized into an `align-items:center` line, which
       vertically re-centered the IR/Vis/WV + Layers buttons downward when the
       (tall) menu opened. Anchored to the wrap (position:absolute), it drops
       just below the trigger, right-aligned. The mobile sheet overrides this
       with position:fixed !important. */
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    min-width: 280px;
    max-width: 320px;
    max-height: calc(100vh - 220px);
    overflow-y: auto;
}

/* Map-only floating controls — appended to <body> by realtime_ir.js
   after the Leaflet map initializes, so they don't inherit
   `#ir-main { display: none }`. We hide them on any non-map view via
   the data-view attribute set by switchIRView. */
html:not([data-view="map"]) #ir-legend-toggle,
html:not([data-view="map"]) #ir-labels-toggle,
/* The "▦ Grid" pill toggles the GLOBAL MAP's graticule. Without
   this gate it floats at top:284px over every other RT tab — most
   visibly inside the Storm Satellite sidebar — and clicking it
   silently toggles a graticule on the hidden global map. Treat it
   the same as Legend / Labels / Basins. */
html:not([data-view="map"]) #ir-grid-toggle,
/* The "◎ Obs" pill toggles the GLOBAL MAP's viewport surface-obs
   overlay — same treatment as Grid so it doesn't float over other
   RT tabs. */
html:not([data-view="map"]) #ir-obs-toggle,
html:not([data-view="map"]) #ir-obs-hint,
html:not([data-view="map"]) #ir-legend,
html:not([data-view="map"]) #basin-sidebar-toggle,
html:not([data-view="map"]) #basin-sidebar,
/* Env-overlay colorbar stack: also position:fixed on <body>, so hiding
   #ir-main isn't enough. Toggling on a Global Map overlay and switching
   to Subseasonal/Seasonal would otherwise leave the colorbar floating
   over the new view. */
html:not([data-view="map"]) #ir-global-env-cbars,
/* The 3D-convection Tilt slider is position:fixed on <body> too. */
html:not([data-view="map"]) #ir-3d-tilt-ctl,
/* The "Display" dropdown wrap is position:fixed on <body> and HOLDS the
   moved-in toggles, so hiding the individual toggles above isn't enough — the
   wrap + its "Display" button still float over Subseasonal/Seasonal/Recon. */
html:not([data-view="map"]) #ir-display-wrap {
    display: none !important;
}
/* Mobile: the 3D Tilt/Height/Orbit control (inline-positioned at bottom:44px)
   overlaps the DeepMind animation deck, whose top sits ~119px off the bottom.
   Lift it clear of the deck. !important overrides the inline style. */
@media (max-width: 768px) {
    #ir-3d-tilt-ctl { bottom: 128px !important; }
}

/* …and the SAME controls bleed over the storm-detail pane. Opening a
   storm hides #ir-main and shows #ir-detail (z-index 500) but leaves
   data-view="map", so the rule above never fires and these pills
   (position:fixed, z-index 600) float on top of the detail view —
   reading as stray "leftover" buttons, most obviously on a phone. The
   detail pane carries an inline display while open — `block` on desktop but
   `flex` on mobile — so match EITHER (:has takes a selector list) to hide the
   global-map controls whenever a detail is showing, regardless of viewport.
   Keying on `block` alone missed the mobile (flex) case → the pills leaked
   onto the phone card. (:has is universally supported in current browsers.) */
body:has(#ir-detail[style*="block"], #ir-detail[style*="flex"]) #ir-legend-toggle,
body:has(#ir-detail[style*="block"], #ir-detail[style*="flex"]) #ir-labels-toggle,
body:has(#ir-detail[style*="block"], #ir-detail[style*="flex"]) #ir-grid-toggle,
body:has(#ir-detail[style*="block"], #ir-detail[style*="flex"]) #ir-obs-toggle,
body:has(#ir-detail[style*="block"], #ir-detail[style*="flex"]) #ir-obs-hint,
body:has(#ir-detail[style*="block"], #ir-detail[style*="flex"]) #ir-legend,
body:has(#ir-detail[style*="block"], #ir-detail[style*="flex"]) #basin-sidebar-toggle,
body:has(#ir-detail[style*="block"], #ir-detail[style*="flex"]) #basin-sidebar,
body:has(#ir-detail[style*="block"], #ir-detail[style*="flex"]) #ir-global-env-cbars,
body:has(#ir-detail[style*="block"], #ir-detail[style*="flex"]) #ir-display-wrap {
    display: none !important;
}

/* × button on each env colorbar — one-click removal of that overlay. */
.env-cbar-x {
    background: none;
    border: none;
    color: #8b97a8;
    cursor: pointer;
    font-size: 0.95rem;
    line-height: 1;
    padding: 0 2px;
    border-radius: 3px;
    transition: color 0.15s, background 0.15s;
}
.env-cbar-x:hover {
    color: #fff;
    background: rgba(244, 115, 33, 0.85);
}

/* ════════════════════════════════════════════════════════════════
   Subseasonal tab — phase clocks (left) + Hovmöllers (right)
   ════════════════════════════════════════════════════════════════ */
.sub-main {
    position: fixed;
    top: calc(var(--topbar-h, 53px) + var(--secondary-bar-h, 32px));
    left: 0;
    right: 0;
    bottom: 0;
    flex-direction: column;
    background: var(--surface);
    overflow: auto;
    padding: 14px 18px 24px;
    font-family: 'DM Sans', system-ui, sans-serif;
    color: var(--text);
}

.sub-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 24px;
    flex-wrap: wrap;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 12px;
}
.sub-title-block { flex: 1 1 480px; min-width: 280px; }
.sub-title {
    margin: 0 0 4px 0;
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: 0.2px;
}
.sub-sub {
    margin: 0;
    font-size: 0.78rem;
    color: var(--text-dim, #64748b);
    line-height: 1.45;
    max-width: 720px;
}

.sub-controls {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    font-size: 0.78rem;
}
.sub-control-label {
    color: var(--text-dim, #64748b);
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    font-weight: 600;
}
.sub-latband-toggle { display: inline-flex; gap: 0; }
.sub-latband-btn {
    padding: 4px 10px;
    border: 1px solid var(--border);
    background: var(--surface-raised, #ffffff);
    color: var(--text);
    font-family: inherit;
    font-size: 0.72rem;
    cursor: pointer;
    border-right: none;
}
.sub-latband-btn:first-child { border-top-left-radius: 4px; border-bottom-left-radius: 4px; }
.sub-latband-btn:last-child  { border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-right: 1px solid var(--border); }
.sub-latband-btn.active {
    background: rgba(46, 125, 255, 0.18);
    color: var(--text);
    font-weight: 600;
}

/* View-mode toggle (Stacked | Combined) — same styling as latband. */
.sub-view-toggle { display: inline-flex; gap: 0; }
.sub-view-btn {
    padding: 4px 10px;
    border: 1px solid var(--border);
    background: var(--surface-raised, #ffffff);
    color: var(--text);
    font-family: inherit;
    font-size: 0.72rem;
    cursor: pointer;
    border-right: none;
}
.sub-view-btn:first-child { border-top-left-radius: 4px; border-bottom-left-radius: 4px; }
.sub-view-btn:last-child  { border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-right: 1px solid var(--border); }
.sub-view-btn.active {
    background: rgba(46, 125, 255, 0.18);
    color: var(--text);
    font-weight: 600;
}

/* Combined Hovmöller panel — single tall figure that replaces the
   stacked panels when the user picks "Combined". */
.sub-hov-combined {
    position: relative;
    width: 100%;
    height: 620px;
    margin-bottom: 6px;
}

/* Small affordance hint shown only in combined view, telling the user
   the legend entries are clickable. DOM sibling of the Plotly panel
   (not a Plotly annotation) so it stays out of exported PNGs. */
.sub-hov-combined-tip {
    font-size: 0.72rem;
    color: var(--text-muted, #64748b);
    font-style: italic;
    padding: 2px 4px 8px 60px;  /* 60px left aligns with Hovmöller plot area */
}

/* OLR-base smoothing toggle is only meaningful in combined view. We
   keep it in the DOM and reserve its space at all times — switching
   `display` would shuffle the rest of the controls bar around — and
   visually dim it + block interaction in stacked view instead. */
.sub-smooth-control[hidden-by-mode] {
    opacity: 0.32;
    pointer-events: none;
}

.sub-save-png-btn {
    padding: 4px 12px;
    border: 1px solid var(--border);
    background: rgba(46, 125, 255, 0.12);
    color: var(--text);
    font-family: inherit;
    font-size: 0.72rem;
    font-weight: 600;
    border-radius: 4px;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
}
.sub-save-png-btn:hover {
    background: rgba(46, 125, 255, 0.28);
    border-color: rgba(46, 125, 255, 0.55);
}
.sub-save-png-btn:disabled {
    opacity: 0.55;
    cursor: wait;
}

.sub-body {
    display: grid;
    grid-template-columns: minmax(320px, 380px) 1fr;
    gap: 18px;
    align-items: start;
}

.sub-section-heading {
    margin: 0 0 8px 0;
    font-size: 0.85rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--text-dim, #64748b);
}

.sub-clocks { display: flex; flex-direction: column; gap: 6px; }
.sub-clock-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
}
.sub-clock-card {
    position: relative;
    background: var(--surface-raised, #ffffff);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 8px 10px 10px;
    display: flex;
    flex-direction: column;
    align-items: center;
    cursor: pointer;
    transition: border-color 0.15s, box-shadow 0.15s;
}
/* Per-clock save button: tap target sits over the card's top-right
   corner. Always visible (no hover-only) so it's reachable on touch
   devices. Click handler stops propagation so it doesn't open the
   evolution modal. */
.sub-clock-save-btn {
    position: absolute;
    top: 4px;
    right: 4px;
    z-index: 3;
    width: 26px;
    height: 26px;
    padding: 0;
    line-height: 1;
    font-size: 0.85rem;
    color: var(--text-dim, #64748b);
    background: rgba(255,255,255,0.78);
    border: 1px solid var(--border);
    border-radius: 4px;
    cursor: pointer;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.sub-clock-save-btn:hover,
.sub-clock-save-btn:focus-visible {
    background: rgba(46,125,255,0.18);
    color: var(--text);
    border-color: rgba(46,125,255,0.55);
    outline: none;
}
[data-theme="dark"] .sub-clock-save-btn { background: rgba(22,27,36,0.78); }
.sub-clock-card:hover {
    border-color: rgba(46, 125, 255, 0.55);
    box-shadow: 0 1px 4px rgba(46, 125, 255, 0.12);
}
.sub-clock-mode {
    font-size: 0.72rem;
    font-weight: 700;
    color: var(--text-dim, #64748b);
    text-transform: uppercase;
    letter-spacing: 0.4px;
    margin-bottom: 2px;
}
.sub-clock-svg {
    width: 140px;
    height: 140px;
    display: block;
}
.sub-clock-readout {
    display: flex;
    gap: 10px;
    margin-top: 4px;
    font-size: 0.7rem;
    font-variant-numeric: tabular-nums;
}
.sub-clock-key {
    color: var(--text-dim, #64748b);
    margin-right: 3px;
}
.sub-clock-val {
    font-weight: 600;
}
.sub-clock-status {
    margin-top: 3px;
    font-size: 0.65rem;
    color: var(--text-dim, #64748b);
    text-align: center;
    min-height: 14px;
    line-height: 1.3;
}

/* Per-mode genesis enhancement readout: "ATL 1.6× · EP 0.9× · WP 1.0×".
   Color-coded per basin (green = enhanced, red = suppressed, gray = near
   climatology). Quiescent days show "phase amp < 1 · no modulation". */
.sub-clock-genesis {
    margin-top: 4px;
    font-size: 0.62rem;
    color: var(--text-dim, #64748b);
    text-align: center;
    min-height: 14px;
    line-height: 1.3;
    font-variant-numeric: tabular-nums;
}
.sub-clock-genesis .sub-gen-basin {
    white-space: nowrap;
    margin: 0 2px;
}
/* Active modulation ≥ 1.0 → red (warm/enhanced); < 1.0 → blue
   (cool/suppressed). Threshold is the uniform-phase expectation
   so every basin reads cleanly as enhanced or suppressed. */
.sub-clock-genesis .sub-gen-up   { color: #dc2626; font-weight: 600; }
.sub-clock-genesis .sub-gen-down { color: #2563eb; font-weight: 600; }
[data-theme="dark"] .sub-clock-genesis .sub-gen-up   { color: #f87171; }
[data-theme="dark"] .sub-clock-genesis .sub-gen-down { color: #60a5fa; }
.sub-clock-footnote {
    margin: 6px 4px 0;
    font-size: 0.65rem;
    color: var(--text-dim, #64748b);
    line-height: 1.4;
}

.sub-hovs { min-width: 0; }
.sub-hov-stack {
    display: flex;
    flex-direction: column;
    gap: 4px;
    background: var(--surface-raised, #ffffff);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 8px;
}
.sub-hov-loading {
    padding: 40px 16px;
    text-align: center;
    color: var(--text-dim, #64748b);
    font-size: 0.85rem;
}
.sub-hov-panel {
    position: relative;
    height: 145px;       /* tall enough to fit the per-panel longitude axis */
    min-height: 130px;
    transition: height 0.18s ease-out;
}
.sub-hov-panel.expanded {
    /* Triples vertical space so individual wave packets in the time
       dimension become easier to inspect. User per-band toggle — no
       cap on how many can be expanded simultaneously, so two panels
       can be put in expanded mode for side-by-side comparison.
       !important is required because Plotly mutates the panel's
       sizing context after newPlot in a way that pins the legacy
       145px height against simple specificity overrides. */
    height: 380px !important;
}
.sub-hov-expand-btn,
.sub-hov-save-btn {
    position: absolute;
    top: 4px;
    z-index: 3;
    width: 22px;
    height: 22px;
    padding: 0;
    line-height: 1;
    font-size: 0.78rem;
    color: var(--text-dim, #64748b);
    background: rgba(255,255,255,0.7);
    border: 1px solid var(--border);
    border-radius: 3px;
    cursor: pointer;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.sub-hov-expand-btn { right: 8px; }
.sub-hov-save-btn   { right: 34px; }
.sub-hov-expand-btn:hover,
.sub-hov-save-btn:hover {
    background: rgba(46,125,255,0.18);
    color: var(--text);
    border-color: rgba(46,125,255,0.45);
}
[data-theme="dark"] .sub-hov-expand-btn,
[data-theme="dark"] .sub-hov-save-btn { background: rgba(22,27,36,0.72); }
.sub-hov-basin-strip {
    position: relative;
    height: 60px;
    margin-top: 4px;
}
.sub-hov-panel-title {
    position: absolute;
    top: 4px;
    left: 8px;
    z-index: 2;
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--text);
    background: rgba(255,255,255,0.82);
    padding: 1px 6px;
    border-radius: 3px;
    pointer-events: none;
}
[data-theme="dark"] .sub-hov-panel-title {
    background: rgba(22,27,36,0.82);
}

.sub-active-tc-list {
    margin-top: 10px;
    padding: 8px 10px;
    background: var(--surface-raised, #ffffff);
    border: 1px solid var(--border);
    border-radius: 6px;
    font-size: 0.74rem;
}
.sub-active-tc-list:empty { display: none; }
.sub-active-tc-row {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding: 3px 0;
    border-bottom: 1px dotted var(--border);
}
.sub-active-tc-row:last-child { border-bottom: none; }
.sub-active-tc-name {
    font-weight: 600;
    min-width: 130px;
}
.sub-active-tc-coord {
    color: var(--text-dim, #64748b);
    font-variant-numeric: tabular-nums;
}
.sub-active-tc-note { color: var(--text-dim, #64748b); }

@media (max-width: 900px) {
    .sub-body { grid-template-columns: 1fr; }
    .sub-clock-grid { grid-template-columns: 1fr 1fr; }
}

/* Phase-evolution iframe modal — opened when a user clicks a clock
   dial. Embeds tc_climatology.html?evoOnly=1 so the full modal
   experience renders inline without leaving the RT Monitor. */
.rt-evo-modal {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    z-index: 1500;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
}
.rt-evo-modal-content {
    position: relative;
    width: min(1200px, 100%);
    height: min(900px, 100%);
    background: var(--surface, #ffffff);
    border-radius: 8px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35);
    overflow: hidden;
}
.rt-evo-modal-iframe {
    width: 100%;
    height: 100%;
    border: 0;
    display: block;
    background: var(--surface, #ffffff);
}
.rt-evo-modal-close {
    position: absolute;
    top: 10px;
    right: 14px;
    z-index: 2;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    border: 1px solid rgba(0, 0, 0, 0.18);
    background: rgba(255, 255, 255, 0.92);
    color: #0f172a;
    font-size: 1.5rem;
    line-height: 1;
    cursor: pointer;
    transition: background 0.15s, transform 0.15s;
}
.rt-evo-modal-close:hover {
    background: #fff;
    transform: scale(1.05);
}

/* Live TC-ATLAS clustering tuner — appears under the method picker
   when TC-ATLAS is the active method. Four sliders that mutate the
   tunables in real time and re-render the disturbance markers on
   every input event. Stays out of the way visually with a faint
   orange border to signal "this only affects the TC-ATLAS path". */
.ir-global-tuner {
    margin: 4px 12px 8px 36px;
    border: 1px dashed rgba(249, 115, 22, 0.45);
    border-radius: 6px;
    background: rgba(249, 115, 22, 0.05);
}
.ir-global-tuner[open] {
    padding: 0 12px 8px;
}
.ir-tuner-summary {
    list-style: none;
    cursor: pointer;
    padding: 7px 12px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    user-select: none;
}
.ir-tuner-summary::-webkit-details-marker { display: none; }
.ir-tuner-summary::before {
    content: "▸";
    font-size: 0.7rem;
    color: #f97316;
    margin-right: 6px;
    display: inline-block;
    transition: transform 0.12s;
}
.ir-global-tuner[open] .ir-tuner-summary::before {
    transform: rotate(90deg);
}
.ir-tuner-summary-label {
    flex: 1;
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--text, #0f172a);
    text-transform: none;
    letter-spacing: 0;
}
.ir-tuner-summary .ir-tuner-status {
    /* Status badge tucks into the summary row when collapsed so the
       analyst still sees the cluster count without expanding. */
    font-variant-numeric: tabular-nums;
}
.ir-global-tuner[open] > :not(summary) {
    margin-top: 6px;
}
.ir-global-tuner[open] .ir-tuner-row + .ir-tuner-row {
    margin-top: 8px;
}
[data-theme="dark"] .ir-tuner-summary-label { color: #e2e8f0; }
.ir-tuner-row {
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.ir-tuner-row label {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    font-size: 0.7rem;
    color: var(--text, #0f172a);
    font-weight: 600;
}
.ir-tuner-val {
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 0.7rem;
    font-weight: 700;
    color: #f97316;
}
.ir-tuner-row input[type=range] {
    width: 100%;
    height: 4px;
    margin: 2px 0;
    accent-color: #f97316;
    cursor: pointer;
}
.ir-tuner-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-top: 4px;
    padding-top: 6px;
    border-top: 1px dashed rgba(249, 115, 22, 0.25);
}
.ir-tuner-status {
    font-size: 0.72rem;
    color: var(--text-dim, #64748b);
}
.ir-tuner-status strong {
    color: var(--text, #0f172a);
    font-variant-numeric: tabular-nums;
}
.ir-tuner-reset {
    font-family: inherit;
    font-size: 0.66rem;
    padding: 3px 9px;
    border: 1px solid rgba(249, 115, 22, 0.45);
    background: transparent;
    color: var(--text, #0f172a);
    border-radius: 4px;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
}
.ir-tuner-reset:hover {
    background: rgba(249, 115, 22, 0.18);
    border-color: #f97316;
}
[data-theme="dark"] .ir-global-tuner {
    background: rgba(249, 115, 22, 0.08);
}
[data-theme="dark"] .ir-tuner-row label { color: #e2e8f0; }
[data-theme="dark"] .ir-tuner-status strong { color: #e2e8f0; }
[data-theme="dark"] .ir-tuner-reset { color: #e2e8f0; }

/* Inline cyclogenesis clustering-method picker.
   Two radio-style chips that switch between DeepMind's track_id
   grouping and our DBSCAN-style spatial clustering. Active chip
   takes the orange brand fill; inactive is clickable to switch. */
.ir-global-method-row {
    display: flex;
    align-items: center;
    padding: 2px 12px 8px 36px;   /* indent matches sub-toggle row */
    gap: 4px;
    cursor: default;
}
.ir-global-method-chip {
    font-family: inherit;
    font-size: 0.72rem;
    font-weight: 600;
    padding: 3px 10px;
    border: 1px solid rgba(249, 115, 22, 0.45);
    border-radius: 11px;
    cursor: pointer;
    line-height: 1.2;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.ir-global-method-chip:hover {
    border-color: #f97316;
}

/* ════════════════════════════════════════════════════════════════
   FNV3 LARGE_ENSEMBLE disturbance markers on the Global Map.
   One per qualifying ensemble cluster (≥5% formation probability),
   labeled "D1", "D2", etc. — ordered by formation confidence so D1
   is the most-likely-to-form. Color = predicted peak Vmax category;
   size scales with formation probability so a high-confidence
   disturbance is bigger and more obvious than a borderline one.
   ════════════════════════════════════════════════════════════════ */
.rt-gen-divicon { background: transparent; border: none; }
.rt-gen-marker {
    display: inline-block;
    border-radius: 50%;
    border: 2px solid #ffffff;
    box-shadow: 0 0 0 1px rgba(0,0,0,0.35), 0 1px 4px rgba(0,0,0,0.55);
    color: #ffffff;
    font-family: 'DM Sans', system-ui, sans-serif;
    font-weight: 700;
    text-align: center;
    letter-spacing: -0.02em;
    cursor: pointer;
    transition: transform 0.12s ease;
}
.rt-gen-marker:hover { transform: scale(1.12); }
/* Name pill for a matched, named storm — sits to the right of the dot so a
   full name ("Amanda") never spills over the circle edge. Positioned against
   the divIcon container (an absolutely-positioned leaflet-marker-icon); the
   marker pane doesn't clip, so the pill is free to extend past iconSize. */
.rt-gen-marker-name {
    position: absolute;
    left: 100%;
    top: 50%;
    transform: translateY(-50%);
    margin-left: 9px;
    padding: 1px 7px;
    border-radius: 7px;
    background: rgba(15, 23, 42, 0.80);
    color: #ffffff;
    font-family: 'DM Sans', system-ui, sans-serif;
    font-weight: 700;
    font-size: 12px;
    line-height: 1.5;
    letter-spacing: -0.01em;
    white-space: nowrap;
    pointer-events: none;
    box-shadow: 0 1px 3px rgba(0,0,0,0.5);
    text-shadow: 0 1px 2px rgba(0,0,0,0.55);
}
[data-theme="dark"] .rt-gen-marker-name {
    background: rgba(2, 6, 23, 0.82);
    box-shadow: 0 1px 4px rgba(0,0,0,0.65);
}
[data-theme="dark"] .rt-gen-marker {
    border-color: rgba(255,255,255,0.85);
    box-shadow: 0 0 0 1px rgba(0,0,0,0.65), 0 1px 6px rgba(0,0,0,0.7);
}
/* Entrance pop so freshly-populated disturbances catch the eye instead
   of silently appearing. Played once per cycle (see _genesisAnimatedInit). */
@keyframes rt-gen-pop {
    0%   { transform: scale(0.15); opacity: 0; }
    60%  { transform: scale(1.22); opacity: 1; }
    100% { transform: scale(1);    opacity: 1; }
}
.rt-gen-marker--enter { animation: rt-gen-pop 0.45s cubic-bezier(0.34, 1.56, 0.64, 1) both; }
@media (prefers-reduced-motion: reduce) {
    .rt-gen-marker--enter { animation: none; }
}

/* Relative "x ago" appended to the storm Last Fix value; turns amber
   when the fix is stale so an old position doesn't read as current. */
.ir-lastfix-ago { color: #94a3b8; font-size: 0.92em; }
.ir-lastfix-ago.stale { color: #fbbf24; font-weight: 600; }

/* Shared retry-able error state for async panels (see _rtStatusError).
   Keeps "load failed" visually distinct from an empty result and always
   one click from a retry. */
.rt-status-error {
    color: #f87171;
    font-size: 0.85em;
}
.rt-retry-link {
    background: none;
    border: none;
    padding: 0;
    margin: 0;
    font: inherit;
    color: #60a5fa;
    text-decoration: underline;
    cursor: pointer;
}
.rt-retry-link:hover { color: #93c5fd; }
.ir-intensity-chart .rt-status-error {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    min-height: 60px;
}

/* Transient toast that announces newly-populated cyclogenesis
   disturbances on the global map (see _genesisAnnounceArrival). */
.rt-gen-toast {
    position: absolute;
    top: 14px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 1200;
    display: flex;
    align-items: flex-start;
    gap: 9px;
    max-width: min(92vw, 420px);
    padding: 10px 13px;
    border-radius: var(--radius-lg, 9px);
    background: var(--surface-raised);
    border: 1px solid var(--border-light);
    box-shadow: 0 6px 22px rgba(0, 0, 0, 0.18);
    color: var(--text);
    font-family: 'DM Sans', system-ui, sans-serif;
    font-size: 12.5px;
    line-height: 1.32;
    cursor: pointer;
    animation: rt-gen-toast-in 0.32s ease both;
}
@keyframes rt-gen-toast-in {
    0%   { opacity: 0; transform: translate(-50%, -10px); }
    100% { opacity: 1; transform: translate(-50%, 0); }
}
.rt-gen-toast--out { opacity: 0; transform: translate(-50%, -10px); transition: opacity 0.3s ease, transform 0.3s ease; }
.rt-gen-toast-dot {
    flex: 0 0 auto;
    width: 9px; height: 9px;
    margin-top: 4px;
    border-radius: 50%;
    background: var(--cyan);
    box-shadow: 0 0 0 3px var(--um-orange-tint);
    animation: ir-pulse 1.6s ease-in-out infinite;
}
.rt-gen-toast-body { display: flex; flex-direction: column; gap: 2px; }
.rt-gen-toast-body b { font-weight: 700; color: var(--text); }
.rt-gen-toast-sub { font-size: 11px; color: var(--text-dim); }
.rt-gen-toast-close {
    flex: 0 0 auto;
    margin-left: 2px;
    font-size: 16px;
    line-height: 1;
    color: var(--text-dim);
    opacity: 0.8;
}
.rt-gen-toast-close:hover { color: var(--text); opacity: 1; }
@media (max-width: 768px) {
    .rt-gen-toast { top: 8px; font-size: 12px; padding: 9px 11px; }
}
@media (prefers-reduced-motion: reduce) {
    .rt-gen-toast, .rt-gen-toast-dot { animation: none; }
}

/* ── DeepMind cycle stepper — row 0 of the animation dock ──
   The run-to-run stepper used to be a separate floating bar that fought
   the colorbar + scrubber for the bottom of the map. It now lives as a thin
   top row INSIDE the animation dock (#ir-dock-cycle), shown only when the
   cyclogenesis layer is on AND ≥2 cycles exist. Sits on the dock's dark
   surface, separated from the scrubber row by a hairline. */
.rt-dock-cycle {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    margin-bottom: 5px;
    padding-bottom: 5px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}
.rt-dock-cycle-text {
    flex: 1 1 auto;
    min-width: 0;
    text-align: center;
    font-family: 'DM Sans', system-ui, sans-serif;
    font-size: 11px;
    font-weight: 600;
    color: #d7e2f2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.rt-dock-cycle.is-pinned .rt-dock-cycle-text { color: var(--blue, #60a5fa); }
.ir-gen-cyc-btn {
    flex: 0 0 auto;
    width: 26px;
    height: 20px;
    border: none;
    border-radius: 5px;
    background: rgba(255, 255, 255, 0.06);
    color: #c0d0ea;
    font-size: 12px;
    line-height: 1;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}
.ir-gen-cyc-btn:hover:not(:disabled) { background: rgba(255, 255, 255, 0.16); color: #fff; }
.ir-gen-cyc-btn:disabled { opacity: 0.3; cursor: default; }

/* Ensemble-size (1000 / 50) toggle beside the run stepper. */
.rt-dock-variant {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 3px;
    margin-left: 8px;
    padding-left: 8px;
    border-left: 1px solid rgba(255, 255, 255, 0.12);
}
.rt-dock-var-btn {
    flex: 0 0 auto;
    height: 20px;
    padding: 0 7px;
    border: none;
    border-radius: 5px;
    background: rgba(255, 255, 255, 0.06);
    color: #c0d0ea;
    font-family: 'DM Sans', system-ui, sans-serif;
    font-size: 10.5px;
    font-weight: 600;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}
.rt-dock-var-btn:hover { background: rgba(255, 255, 255, 0.16); color: #fff; }
.rt-dock-var-btn.is-active {
    background: rgba(249, 115, 22, 0.32);
    color: #f97316;
}

/* ── Compact Tb colorbar chip — right end of the scrubber row ── */
.rt-dock-cbar {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-left: 2px;
    cursor: help;
}
.rt-dock-cbar-grad {
    display: block;
    width: 44px;
    height: 8px;
    border-radius: 2px;
    /* GIBS Band 13 Clean Infrared default colormap (matches the NASA tiles
       on the global map). */
    background: linear-gradient(to right,
        rgb(8,8,8), rgb(90,90,90), rgb(200,200,200), rgb(0,100,255),
        rgb(0,255,0), rgb(255,180,0), rgb(255,0,0), rgb(180,0,180), rgb(255,255,255));
}
.rt-dock-cbar-lbl {
    font-family: 'DM Sans', sans-serif;
    font-size: 9.5px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.65);
    white-space: nowrap;
}

/* ════════════════════════════════════════════════════════════════
   FNV3 LARGE_ENSEMBLE genesis detail modal.
   Opens when a user clicks any genesis spaghetti track on the
   Global Map. Two Plotly figures: a basin scattergeo + an
   intensity-vs-lead-time chart with ±σ ribbons. Layout mirrors
   the rt-evo-modal scaffolding so the visual language stays
   consistent across the page's modal family.
   ════════════════════════════════════════════════════════════════ */
.rt-genesis-modal {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    z-index: 1600;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
}
.rt-genesis-modal-content {
    position: relative;
    width: min(1200px, 100%);
    max-height: 92vh;
    background: var(--surface, #ffffff);
    border-radius: 8px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35);
    overflow: auto;
    padding: 18px 22px 22px;
}
.rt-genesis-modal-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 12px;
}
.rt-genesis-modal-header h2 {
    margin: 0 0 4px 0;
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--text, #0f172a);
}
.rt-genesis-modal-header p {
    margin: 0;
    font-size: 0.78rem;
    color: var(--text-dim, #64748b);
    line-height: 1.4;
}
.rt-genesis-modal-close {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    border: 1px solid rgba(0, 0, 0, 0.18);
    background: rgba(255, 255, 255, 0.92);
    color: #0f172a;
    font-size: 1.5rem;
    line-height: 1;
    cursor: pointer;
    transition: background 0.15s, transform 0.15s;
}
.rt-genesis-modal-close:hover {
    background: #fff;
    transform: scale(1.05);
}
.rt-genesis-modal-save {
    position: absolute;
    top: 4px;
    right: 4px;
    z-index: 3;
    padding: 4px 10px;
    font-family: inherit;
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--text, #0f172a);
    background: rgba(46, 125, 255, 0.12);
    border: 1px solid var(--border, rgba(0, 0, 0, 0.12));
    border-radius: 4px;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
}
.rt-genesis-modal-save:hover {
    background: rgba(46, 125, 255, 0.28);
    border-color: rgba(46, 125, 255, 0.55);
}
/* Use the site's --surface tokens so the modal matches whatever the
   page is showing instead of a separate hardcoded navy. The map
   figure's ocean/land are painted to the same tokens via JS so the
   whole modal reads as one surface, not a panel-on-a-panel. */
.rt-genesis-modal-content {
    background: var(--surface-raised, #ffffff);
    color: var(--text, #0f172a);
}
[data-theme="dark"] .rt-genesis-modal-content {
    background: var(--surface-raised, #161b24);
    color: var(--text, #e2e8f0);
}
[data-theme="dark"] .rt-genesis-modal-header h2 { color: var(--text); }
[data-theme="dark"] .rt-genesis-modal-header p  { color: var(--text-dim, #94a3b8); }
[data-theme="dark"] .rt-genesis-modal-close {
    background: var(--surface, #11161f);
    color: var(--text, #e2e8f0);
    border-color: rgba(255, 255, 255, 0.18);
}
[data-theme="dark"] .rt-genesis-modal-save {
    background: rgba(46, 125, 255, 0.22);
    color: var(--text, #e2e8f0);
    border-color: rgba(148, 163, 184, 0.3);
}
/* ── Ensemble-modal loading overlay ──────────────────────────────
   Shown while the member set fetches AND while the Plotly panels
   render. The spinner is a GPU-composited `transform` animation, so
   it keeps turning even during the synchronous chart-render burst
   that blocks the JS main thread — the user always sees motion. The
   overlay sits inside the body, so the header (title/subtitle/close)
   stays visible and the close button stays clickable. */
.rt-genesis-modal-body { position: relative; }
.rt-genesis-modal-loader {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    /* Pin near the top, not centered: the body holds ~1900 px of empty
       chart scaffolding during load, so a vertically-centered spinner
       would sit far below the fold. */
    justify-content: flex-start;
    padding-top: 120px;
    gap: 14px;
    min-height: 240px;
    z-index: 40;
    background: var(--surface-raised, #ffffff);
    border-radius: 6px;
}
.rt-genesis-modal-loader-spinner {
    width: 40px;
    height: 40px;
    border: 4px solid rgba(148, 163, 184, 0.35);
    border-top-color: #2e7dff;
    border-radius: 50%;
    animation: ir-spin 0.8s linear infinite;
    will-change: transform;
}
.rt-genesis-modal-loader-text {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text-dim, #64748b);
    letter-spacing: 0.01em;
}
[data-theme="dark"] .rt-genesis-modal-loader {
    background: var(--surface-raised, #161b24);
}
[data-theme="dark"] .rt-genesis-modal-loader-text { color: var(--text-dim, #94a3b8); }
/* Sticky jump-nav: keeps panel discovery visible while the user scrolls
   through the modal. position:sticky inside the modal-content scroller
   means it pins to the top of the scroll viewport, not the page. */
.rt-genesis-jump-nav {
    position: sticky;
    top: 0;
    z-index: 5;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    padding: 8px 0;
    margin: 0 0 8px 0;
    background: var(--surface-raised, #ffffff);
    border-bottom: 1px solid var(--border, rgba(0, 0, 0, 0.08));
}
.rt-genesis-jump-label {
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--text-dim, #64748b);
    margin-right: 4px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.rt-genesis-jump-btn {
    padding: 5px 12px;
    font-family: inherit;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--text, #0f172a);
    background: transparent;
    border: 1px solid var(--border, rgba(0, 0, 0, 0.12));
    border-radius: 999px;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.rt-genesis-jump-btn:hover {
    background: rgba(46, 125, 255, 0.08);
    border-color: rgba(46, 125, 255, 0.45);
}
.rt-genesis-jump-btn.active {
    background: rgba(46, 125, 255, 0.18);
    border-color: rgba(46, 125, 255, 0.65);
    color: #2e7dff;
}
[data-theme="dark"] .rt-genesis-jump-nav {
    background: var(--surface-raised, #161b24);
    border-bottom-color: rgba(255, 255, 255, 0.08);
}
[data-theme="dark"] .rt-genesis-jump-btn {
    color: var(--text, #e2e8f0);
    border-color: rgba(148, 163, 184, 0.3);
}
[data-theme="dark"] .rt-genesis-jump-btn:hover {
    background: rgba(46, 125, 255, 0.16);
    border-color: rgba(46, 125, 255, 0.55);
}
[data-theme="dark"] .rt-genesis-jump-btn.active {
    background: rgba(46, 125, 255, 0.28);
    border-color: rgba(46, 125, 255, 0.7);
    color: #7eb8ff;
}
/* Sub-nav inside the "This run" pane: lighter than the tab pills above.
   Lists the stacked panels (tracks, intensity, …) so the user knows
   there's more below the fold and can jump straight to one. */
.rt-genesis-subnav {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px 4px;
    padding: 2px 2px 8px;
    margin: 0 0 8px 0;
    border-bottom: 1px dashed var(--border, rgba(0, 0, 0, 0.1));
}
.rt-genesis-subnav-label {
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--text-dim, #64748b);
    margin-right: 4px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.rt-genesis-subnav-chip {
    padding: 2px 4px;
    font-family: inherit;
    font-size: 0.72rem;
    font-weight: 500;
    color: var(--text-dim, #64748b);
    background: transparent;
    border: none;
    border-bottom: 1px solid transparent;
    cursor: pointer;
    transition: color 0.15s, border-color 0.15s;
}
.rt-genesis-subnav-chip:not(:last-of-type)::after {
    content: "·";
    margin-left: 6px;
    color: var(--border, rgba(0, 0, 0, 0.25));
    pointer-events: none;
}
.rt-genesis-subnav-chip:hover {
    color: #2e7dff;
}
.rt-genesis-subnav-chip.active {
    color: #2e7dff;
    border-bottom-color: #2e7dff;
    font-weight: 600;
}
[data-theme="dark"] .rt-genesis-subnav {
    border-bottom-color: rgba(255, 255, 255, 0.1);
}
[data-theme="dark"] .rt-genesis-subnav-chip {
    color: var(--text-dim, #94a3b8);
}
[data-theme="dark"] .rt-genesis-subnav-chip:hover,
[data-theme="dark"] .rt-genesis-subnav-chip.active {
    color: #7eb8ff;
}
[data-theme="dark"] .rt-genesis-subnav-chip.active {
    border-bottom-color: #7eb8ff;
}
/* ATCF-match pill in the disturbance modal subtitle — signals that
   the FNV3 ensemble is locked to an officially-tracked TC/invest, so
   the user reads our diagnostics knowing it's a known system. Hover
   reveals the storm's name/category and the match distance. */
.rt-genesis-atcf-pill {
    display: inline-block;
    padding: 2px 8px;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    color: #0f172a;
    background: rgba(46, 125, 255, 0.18);
    border: 1px solid rgba(46, 125, 255, 0.55);
    border-radius: 999px;
    cursor: help;
}
[data-theme="dark"] .rt-genesis-atcf-pill {
    color: #cbd5e1;
    background: rgba(46, 125, 255, 0.28);
    border-color: rgba(46, 125, 255, 0.7);
}

/* Pre-genesis-specific stats strip. Three quick-look tiles between
   the header and the figures. Same density / typography as the storm-
   detail attribute pills so it reads as part of the same site. */
.rt-genesis-stat-row {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 10px;
    padding: 8px 10px;
    margin-bottom: 12px;
    background: rgba(249, 115, 22, 0.06);
    border: 1px solid rgba(249, 115, 22, 0.18);
    border-left: 3px solid #f97316;
    border-radius: 6px;
}
.rt-genesis-stat {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 4px 6px;
}
.rt-genesis-stat-label {
    font-size: 0.62rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-dim, #64748b);
}
.rt-genesis-stat-value {
    font-size: 1rem;
    font-weight: 700;
    color: var(--text, #0f172a);
    font-variant-numeric: tabular-nums;
}
.rt-genesis-stat-hint {
    font-size: 0.66rem;
    color: var(--text-dim, #64748b);
    line-height: 1.3;
}
[data-theme="dark"] .rt-genesis-stat-row {
    background: rgba(249, 115, 22, 0.10);
    border-color: rgba(249, 115, 22, 0.32);
}
[data-theme="dark"] .rt-genesis-stat-value { color: #e2e8f0; }
[data-theme="dark"] .rt-genesis-stat-label,
[data-theme="dark"] .rt-genesis-stat-hint  { color: #94a3b8; }
@media (max-width: 720px) {
    .rt-genesis-stat-row { grid-template-columns: 1fr; }
    /* Let the header's title + export cluster + close stack/wrap instead
       of overflowing a phone-width modal. */
    .rt-genesis-modal-header { flex-wrap: wrap; }
    .rt-genesis-summary-actions { gap: 4px; }
    .rt-genesis-modal-summary-save,
    .rt-genesis-modal-summary-view {
        font-size: 12px;
        padding: 4px 7px;
    }
}

/* Run-to-run trend panels (genesis detail modal). Bare chart-wraps, no
   card chrome — consistent with the "This run" figures. Color now lives
   in the plots themselves (current run + prior-run recency ramp). */
.rt-genesis-trend-wrap {
    padding: 8px 2px 4px;
    margin-bottom: 12px;
}
.rt-genesis-trend-head {
    display: flex;
    align-items: baseline;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 2px;
}
.rt-genesis-trend-title {
    font-size: 0.62rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-dim, #64748b);
}
.rt-genesis-trend-note {
    font-size: 0.62rem;
    color: var(--text-dim, #64748b);
    opacity: 0.9;
}
[data-theme="dark"] .rt-genesis-trend-title,
[data-theme="dark"] .rt-genesis-trend-note { color: #94a3b8; }

/* Forecast-hour scrubber buttons in the genesis detail modal. Match
   the .rt-anim-btn look from the Global Map IR scrubber so the
   control reads as the same pattern. */
.rt-genesis-tau-btn {
    background: rgba(15,22,35,0.04);
    color: var(--text);
    border: 1px solid rgba(15,22,35,0.18);
    border-radius: 4px;
    font-size: 13px;
    padding: 4px 9px;
    cursor: pointer;
    transition: background 0.12s ease, border-color 0.12s ease;
    min-width: 30px;
}
.rt-genesis-tau-btn:hover { background: rgba(15,22,35,0.10); }
[data-theme="dark"] .rt-genesis-tau-btn {
    background: rgba(255,255,255,0.04);
    color: #e2e8f0;
    border-color: rgba(255,255,255,0.18);
}
[data-theme="dark"] .rt-genesis-tau-btn:hover {
    background: rgba(255,255,255,0.10);
}
.rt-genesis-tau-btn.playing {
    background: rgba(249,115,22,0.20);
    border-color: rgba(249,115,22,0.50);
}

/* The scrubber row holds 4 tau buttons + a min-160px slider + tau label +
   the Density/Members toggle. On a phone-width modal that overflows a no-wrap
   flex row, shoving the (last) toggle off-screen and squishing it to ~0 width
   — so it was invisible on mobile. Let the row wrap so the toggle drops to a
   second line at its natural size. */
.rt-genesis-tau-bar { flex-wrap: wrap; }

/* Density / Members segmented toggle. */
.rt-genesis-mode-toggle {
    display: inline-flex;
    flex-shrink: 0;            /* never collapse to 0 width when the row is tight */
    border: 1px solid rgba(15,22,35,0.18);
    border-radius: 4px;
    overflow: hidden;
}
[data-theme="dark"] .rt-genesis-mode-toggle {
    border-color: rgba(255,255,255,0.18);
}
.rt-genesis-mode-btn {
    background: rgba(15,22,35,0.04);
    color: var(--text);
    border: none;
    font-size: 12px;
    padding: 5px 10px;
    cursor: pointer;
}
.rt-genesis-mode-btn + .rt-genesis-mode-btn {
    border-left: 1px solid rgba(15,22,35,0.18);
}
.rt-genesis-mode-btn:hover { background: rgba(15,22,35,0.10); }
.rt-genesis-mode-btn.active {
    background: rgba(249,115,22,0.22);
    color: #f97316;
    font-weight: 600;
}
[data-theme="dark"] .rt-genesis-mode-btn {
    background: rgba(255,255,255,0.04);
    color: #e2e8f0;
}
[data-theme="dark"] .rt-genesis-mode-btn + .rt-genesis-mode-btn {
    border-left-color: rgba(255,255,255,0.18);
}
[data-theme="dark"] .rt-genesis-mode-btn:hover { background: rgba(255,255,255,0.10); }
[data-theme="dark"] .rt-genesis-mode-btn.active {
    background: rgba(249,115,22,0.28);
    color: #fdba74;
}

/* Structure anomaly-mode toggle (Raw / Percentile / Z-score) — reuses the
   genesis mode-toggle look so it reads as a sibling control. */
.rt-genesis-struct-mode {
    display: inline-flex;
    flex-shrink: 0;
    border: 1px solid rgba(15,22,35,0.18);
    border-radius: 4px;
    overflow: hidden;
}
[data-theme="dark"] .rt-genesis-struct-mode { border-color: rgba(255,255,255,0.18); }
.rt-genesis-struct-mode-btn {
    background: rgba(15,22,35,0.04);
    color: var(--text);
    border: none;
    font-size: 11px;
    padding: 4px 9px;
    cursor: pointer;
}
.rt-genesis-struct-mode-btn + .rt-genesis-struct-mode-btn {
    border-left: 1px solid rgba(15,22,35,0.18);
}
.rt-genesis-struct-mode-btn:hover { background: rgba(15,22,35,0.10); }
.rt-genesis-struct-mode-btn.active {
    background: rgba(249,115,22,0.22);
    color: #f97316;
    font-weight: 600;
}
[data-theme="dark"] .rt-genesis-struct-mode-btn {
    background: rgba(255,255,255,0.04);
    color: #e2e8f0;
}
[data-theme="dark"] .rt-genesis-struct-mode-btn + .rt-genesis-struct-mode-btn {
    border-left-color: rgba(255,255,255,0.18);
}
[data-theme="dark"] .rt-genesis-struct-mode-btn:hover { background: rgba(255,255,255,0.10); }
[data-theme="dark"] .rt-genesis-struct-mode-btn.active {
    background: rgba(249,115,22,0.28);
    color: #fdba74;
}

/* Density-mode key strip — sits between the scrubber row and the
   map, visible only when Density mode is active. Color swatches +
   bin size + peak count. */
.rt-genesis-density-key {
    display: none;
    align-items: center;
    flex-wrap: wrap;
    gap: 14px;
    padding: 6px 10px;
    margin: 4px 4px 8px 4px;
    border: 1px solid rgba(15,22,35,0.12);
    border-radius: 5px;
    background: rgba(15,22,35,0.03);
    font-size: 11px;
    color: var(--text);
    line-height: 1.4;
}
[data-theme="dark"] .rt-genesis-density-key {
    border-color: rgba(255,255,255,0.10);
    background: rgba(255,255,255,0.03);
    color: #e2e8f0;
}
.rt-genesis-density-key-label { font-weight: 500; opacity: 0.85; }
.rt-genesis-density-key-swatches {
    display: inline-flex; align-items: center; gap: 12px;
}
.rt-genesis-density-key-swatches > span {
    display: inline-flex; align-items: center; gap: 5px;
}
.rt-genesis-density-key-swatches i {
    display: inline-block;
    width: 14px; height: 12px;
    border-radius: 2px;
    border: 1px solid rgba(15,22,35,0.15);
}
[data-theme="dark"] .rt-genesis-density-key-swatches i {
    border-color: rgba(255,255,255,0.15);
}
.rt-genesis-density-key-meta { opacity: 0.7; font-size: 10px; }

/* Summary/export buttons in the modal header — UM green to match the brand
   palette. Theme-aware via --um-green (#005030 light, #4a9b6e dark); solid
   rgba fallbacks first for browsers without color-mix. */
.rt-genesis-modal-summary-save {
    background: rgba(0, 80, 48, 0.12);
    background: color-mix(in srgb, var(--um-green) 13%, transparent);
    color: var(--um-green);
    border: 1px solid rgba(0, 80, 48, 0.40);
    border: 1px solid color-mix(in srgb, var(--um-green) 45%, transparent);
    border-radius: 5px;
    font-size: 13px;
    padding: 5px 10px;
    cursor: pointer;
    font-weight: 500;
    transition: background 0.12s ease;
}
.rt-genesis-modal-summary-save:hover {
    background: rgba(0, 80, 48, 0.20);
    background: color-mix(in srgb, var(--um-green) 22%, transparent);
}
/* Composite-summary export cluster (Overall / Intensity / Trends), each a
   download (⤓) + view-in-new-tab (⤢) pair. Wraps onto multiple rows on
   narrow viewports so the header doesn't overflow. Which group is visible
   follows the active modal tab (toggled in JS). */
.rt-genesis-summary-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
}
.rt-genesis-sum-group {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
/* The ⤢ "view in new tab" button — same palette as the ⤓ download button
   but icon-only and slightly narrower so the pair reads as one control. */
.rt-genesis-modal-summary-view {
    background: rgba(0, 80, 48, 0.12);
    background: color-mix(in srgb, var(--um-green) 13%, transparent);
    color: var(--um-green);
    border: 1px solid rgba(0, 80, 48, 0.40);
    border: 1px solid color-mix(in srgb, var(--um-green) 45%, transparent);
    border-radius: 5px;
    font-size: 13px;
    padding: 5px 8px;
    cursor: pointer;
    font-weight: 500;
    line-height: 1;
    transition: background 0.12s ease;
}
.rt-genesis-modal-summary-view:hover {
    background: rgba(0, 80, 48, 0.20);
    background: color-mix(in srgb, var(--um-green) 22%, transparent);
}
/* "→ IR Detail" button — only visible when the disturbance is matched
   to an active ATCF storm. Sits beside Summary PNG in the modal
   header. Uses the site's primary blue accent so it reads as a
   navigation action rather than another download/save button. */
.rt-genesis-modal-open-storm {
    background: rgba(46, 125, 255, 0.12);
    color: #2e7dff;
    border: 1px solid rgba(46, 125, 255, 0.45);
    border-radius: 5px;
    font-size: 13px;
    padding: 5px 10px;
    cursor: pointer;
    font-weight: 600;
    transition: background 0.12s ease;
}
.rt-genesis-modal-open-storm:hover {
    background: rgba(46, 125, 255, 0.22);
}
[data-theme="dark"] .rt-genesis-modal-open-storm {
    color: #93c5fd;
    border-color: rgba(46, 125, 255, 0.55);
}

/* ════════════════════════════════════════════════════════════════
   Storm-sector microwave passes (right-rail panel on storm detail).
   Chronological list of canvas thumbnails (storm-cropped from the
   full pass PNG), grouped by orbit, switchable across the six
   products via the chip row.
   ════════════════════════════════════════════════════════════════ */
.rt-mw-storm-products {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-bottom: 8px;
}
.rt-mw-storm-chip {
    padding: 3px 8px;
    font-size: 10px;
    font-weight: 600;
    color: var(--text, #0f172a);
    background: transparent;
    border: 1px solid var(--border, rgba(0, 0, 0, 0.12));
    border-radius: 999px;
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.rt-mw-storm-chip:hover {
    background: rgba(46, 125, 255, 0.08);
    border-color: rgba(46, 125, 255, 0.45);
}
.rt-mw-storm-chip.active {
    background: rgba(46, 125, 255, 0.18);
    border-color: rgba(46, 125, 255, 0.65);
    color: #2e7dff;
}
[data-theme="dark"] .rt-mw-storm-chip {
    color: var(--text, #e2e8f0);
    border-color: rgba(148, 163, 184, 0.3);
}
[data-theme="dark"] .rt-mw-storm-chip.active {
    background: rgba(46, 125, 255, 0.28);
    border-color: rgba(46, 125, 255, 0.7);
    color: #93c5fd;
}

/* Upcoming-overpass strip — per-sensor "next pass" ETA above the
   past-pass list. Compact grid so it adds context without crowding. */
.rt-mw-up {
    margin: 4px 0 10px;
    padding: 8px 10px;
    background: rgba(46, 125, 255, 0.06);
    border: 1px solid rgba(46, 125, 255, 0.18);
    border-radius: 6px;
}
.rt-mw-up-title {
    font-size: 0.66rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-dim, #64748b);
    margin-bottom: 6px;
}
.rt-mw-up-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 4px 12px;
}
.rt-mw-up-cell {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 4px 8px;
    font-size: 0.72rem;
    line-height: 1.3;
    cursor: default;
}
.rt-mw-up-cell.far { opacity: 0.6; }
/* Imminent overpass (<90 min): tint the row and pulse the "SOON" badge so an
   approaching pass stands out at a glance instead of reading as plain text. */
.rt-mw-up-cell.imminent {
    background: rgba(0, 229, 255, 0.08);
    border-radius: 4px;
    padding: 2px 5px;
    margin: -2px -5px;
}
.rt-mw-up-cell.imminent .rt-mw-up-val { color: #67e8f9; font-weight: 600; }
.rt-mw-up-soon {
    display: inline-block;
    margin-right: 5px;
    padding: 0 5px;
    border-radius: 6px;
    background: #06b6d4;
    color: #042f3a;
    font-size: 0.58rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    vertical-align: middle;
    animation: rt-mw-soon-pulse 1.8s ease-in-out infinite;
}
@keyframes rt-mw-soon-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.45; }
}
.rt-mw-up-sensor {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    color: var(--text, #cbd5e1);
    font-weight: 500;
}
.rt-mw-up-swatch {
    width: 8px;
    height: 8px;
    border-radius: 2px;
    flex: 0 0 auto;
}
.rt-mw-up-val {
    color: var(--text, #e2e8f0);
    font-variant-numeric: tabular-nums;
    text-align: right;
    white-space: nowrap;
}
.rt-mw-up-eta {
    color: var(--text-dim, #64748b);
    margin-left: 5px;
    font-size: 0.66rem;
}
.rt-mw-up-none { color: var(--text-dim, #64748b); }
/* Coverage badge — drops to its own full-width line under the sensor/ETA
   row. Dot color encodes how much of the inner core the swath captures. */
.rt-mw-up-cov {
    flex: 0 0 100%;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 0.62rem;
    color: var(--text-dim, #94a3b8);
}
.rt-mw-up-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex: 0 0 auto;
    background: #94a3b8;
}
.rt-mw-up-cov.full  { color: #6ee7b7; }
.rt-mw-up-cov.full  .rt-mw-up-dot { background: #34d399; }
.rt-mw-up-cov.most  .rt-mw-up-dot { background: #a3e635; }
.rt-mw-up-cov.part  .rt-mw-up-dot { background: #fbbf24; }
.rt-mw-up-cov.graze .rt-mw-up-dot { background: #94a3b8; }
.rt-mw-up-note {
    margin-top: 6px;
    font-size: 0.62rem;
    color: var(--text-dim, #64748b);
    font-style: italic;
}
/* In the Storm Satellite tab's tight Leaflet column, keep the strip flat
   (no card chrome) so it doesn't steal height from the comparison pane. */
.rt-mw-up-sat {
    margin: 0;
    border-radius: 0;
    border-left: none;
    border-right: none;
    border-top: none;
    background: rgba(15, 22, 36, 0.5);
    padding: 6px 10px;
}
.rt-mw-up-sat .rt-mw-up-note { display: none; }

.rt-mw-storm-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-height: 460px;
    overflow-y: auto;
    padding-right: 4px;
    scrollbar-width: thin;
    scrollbar-color: rgba(148, 163, 184, 0.4) transparent;
}
.rt-mw-storm-list::-webkit-scrollbar { width: 6px; }
.rt-mw-storm-list::-webkit-scrollbar-track { background: transparent; }
.rt-mw-storm-list::-webkit-scrollbar-thumb {
    background-color: rgba(148, 163, 184, 0.4);
    border-radius: 3px;
}

.rt-mw-storm-empty {
    font-size: 0.72rem;
    color: var(--text-dim, #64748b);
    font-style: italic;
    padding: 6px 0;
}

.rt-mw-storm-card {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px;
    background: rgba(15, 22, 36, 0.04);
    border: 1px solid rgba(0, 0, 0, 0.08);
    border-radius: 6px;
    transition: background 0.12s, border-color 0.12s;
}
.rt-mw-storm-card-clickable {
    cursor: pointer;
    outline: none;
}
.rt-mw-storm-card-clickable:focus-visible {
    box-shadow: 0 0 0 2px rgba(46, 125, 255, 0.55);
    border-color: rgba(46, 125, 255, 0.55);
}
.rt-mw-storm-card:hover {
    background: rgba(46, 125, 255, 0.08);
    border-color: rgba(46, 125, 255, 0.30);
}
[data-theme="dark"] .rt-mw-storm-card {
    background: rgba(255, 255, 255, 0.03);
    border-color: rgba(255, 255, 255, 0.08);
}
[data-theme="dark"] .rt-mw-storm-card:hover {
    background: rgba(46, 125, 255, 0.12);
    border-color: rgba(46, 125, 255, 0.40);
}

.rt-mw-storm-thumb-wrap {
    flex-shrink: 0;
    width: 80px;
    height: 80px;
    border-radius: 4px;
    overflow: hidden;
    background: rgba(15, 22, 36, 0.55);
    cursor: pointer;
}
.rt-mw-storm-thumb {
    width: 100%;
    height: 100%;
    display: block;
    image-rendering: -webkit-optimize-contrast;
}
.rt-mw-storm-thumb-missing {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 10px;
    color: rgba(148, 163, 184, 0.7);
    font-style: italic;
}

.rt-mw-storm-meta {
    flex: 1;
    min-width: 0;
    font-size: 0.7rem;
    line-height: 1.35;
}
.rt-mw-storm-sensor {
    display: flex;
    align-items: center;
    gap: 5px;
    margin-bottom: 2px;
}
.rt-mw-storm-swatch {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
}
.rt-mw-storm-platform {
    color: var(--text-dim, #64748b);
    font-size: 0.65rem;
}
.rt-mw-storm-time {
    color: var(--text, #0f172a);
    font-weight: 600;
}
.rt-mw-storm-utc {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 0.62rem;
    color: var(--text-dim, #64748b);
}
[data-theme="dark"] .rt-mw-storm-time { color: var(--text, #e2e8f0); }

/* Storm-Satellite-tab MW panel — wraps the chip bar + scrollable
   card list to fill the right-panel column. The list itself uses
   the shared .rt-mw-storm-list class; the wrapper just controls
   the column layout and lets the list grow with the available
   vertical space (instead of the 460-px cap used in the Global
   Map's storm-detail right rail). */
.sat-mw-panel {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
    padding: 8px 4px 8px 8px;
    overflow: hidden;
}
.sat-mw-panel .rt-mw-storm-list {
    max-height: none;
    flex: 1;
    overflow-y: auto;
}

/* ════════════════════════════════════════════════════════════════
   Phase 1: Storm Satellite tab — Leaflet panes for MW mode.
   Replaces the canvas dual-pane only when "MW" mode is active.
   Left pane = IR (sat-leaflet-ir, hosted inside sat-panel-ir).
   Right pane = MW (sat-leaflet-mw, hosted inside sat-mw-section).
   Pass strip along the bottom of the right pane.
   ════════════════════════════════════════════════════════════════ */
.sat-leaflet-pane {
    width: 100%;
    flex: 1;
    min-height: 320px;
    background: rgba(15, 22, 36, 0.55);
    border-radius: 4px;
    position: relative;   /* Leaflet's tile + control children are
                             absolutely positioned — need a positioned
                             ancestor to anchor them. */
}
/* IR (left) pane sits inside .sat-panel which uses justify-content:
   center / align-items: center to lay out the canvas-wrap. Those
   alignment rules make a flex child shrink to its content unless
   we override — so the Leaflet div would render as a narrow strip
   instead of filling the pane. Absolute positioning sidesteps the
   flex weirdness entirely; #sat-panel-ir is already position:relative
   so inset:0 fills it cleanly. */
#sat-leaflet-ir {
    position: absolute;
    inset: 0;
    z-index: 5;
    min-height: 0;
    flex: none;
    border-radius: 0;
}
/* The MW (right) pane lives inside .sat-mw-leaflet-panel — its own
   flex column with chip row + pass strip, so it behaves normally as
   a flex child. */
.sat-leaflet-pane-mw {
    flex: 1;
    min-height: 240px;
}

.sat-mw-leaflet-panel {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
    padding: 6px;
    gap: 6px;
}
.sat-mw-leaflet-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 6px 8px;
    background: rgba(15, 22, 36, 0.65);
    border-radius: 4px;
    color: var(--text, #e2e8f0);
}
.sat-mw-leaflet-title {
    display: flex;
    align-items: baseline;
    gap: 8px;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--text, #e2e8f0);
}
.sat-mw-leaflet-status {
    font-size: 0.7rem;
    color: #94a3b8;
    font-weight: 500;
    margin-left: auto;   /* push status + toggle to the right edge */
}
.sat-mw-vis-toggle {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 0.7rem;
    font-weight: 500;
    color: #cbd5e1;
    cursor: pointer;
    white-space: nowrap;
    user-select: none;
}
.sat-mw-vis-toggle input {
    accent-color: #38bdf8;
    cursor: pointer;
    margin: 0;
}
.sat-mw-pass-time {
    /* Inherit Inter / DM Sans from the rest of the page instead of
       the monospaced fallback the canvas-era code used. */
    font-family: inherit;
    font-size: 0.72rem;
    color: #94a3b8;
    font-weight: 500;
}

/* MW controls row — product chips + pass dropdown on one line. */
.sat-mw-controls-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}
/* MW product chips in the Storm Satellite tab. Pinned with explicit
   colors (the page-wide --text token isn't always resolved on this
   tab — it was falling back to dark navy on a dark background and
   becoming invisible). Stronger pill backgrounds + a tiny cursor:
   pointer override emphasize that these are clickable. */
.sat-mw-controls-row .rt-mw-storm-chip {
    cursor: pointer;
    color: #cbd5e1;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(148, 163, 184, 0.4);
    font-weight: 600;
}
.sat-mw-controls-row .rt-mw-storm-chip:hover {
    background: rgba(46, 125, 255, 0.22);
    border-color: rgba(46, 125, 255, 0.65);
    color: #ffffff;
}
.sat-mw-controls-row .rt-mw-storm-chip.active {
    background: rgba(46, 125, 255, 0.45);
    border-color: rgba(46, 125, 255, 0.9);
    color: #ffffff;
    box-shadow: 0 0 0 1px rgba(46, 125, 255, 0.35);
}
.sat-mw-pass-select-label {
    font-size: 0.72rem;
    color: #94a3b8;
    font-weight: 500;
    white-space: nowrap;
}
.sat-mw-pass-select {
    flex: 1;
    min-width: 200px;
    /* Explicit hex (not CSS-var fallback) because the Storm Satellite
       tab doesn't inherit the page-wide --text / --surface tokens that
       the rest of the dark-theme code relies on. Without these, the
       dropdown text was the var's fallback navy #0f172a on a near-
       black background — effectively invisible. */
    background-color: #1e293b;
    color: #e2e8f0;
    border: 1px solid rgba(148, 163, 184, 0.5);
    border-radius: 5px;
    padding: 4px 8px;
    font-family: inherit;
    font-size: 0.78rem;
    cursor: pointer;
}
.sat-mw-pass-select option {
    background-color: #1e293b;
    color: #e2e8f0;
}
.sat-mw-pass-select:disabled {
    opacity: 0.55;
    cursor: default;
}

.sat-mw-strip-wrap {
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.sat-mw-strip-label {
    font-size: 0.6rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #94a3b8;
    font-weight: 700;
}
.sat-mw-strip {
    display: flex;
    gap: 6px;
    overflow-x: auto;
    overflow-y: hidden;
    padding: 2px 2px 6px;
    scrollbar-width: thin;
    scrollbar-color: rgba(148, 163, 184, 0.4) transparent;
}
.sat-mw-strip::-webkit-scrollbar { height: 6px; }
.sat-mw-strip::-webkit-scrollbar-thumb {
    background-color: rgba(148, 163, 184, 0.4);
    border-radius: 3px;
}
.sat-mw-strip-empty {
    font-size: 0.72rem;
    color: #64748b;
    font-style: italic;
    padding: 6px 4px;
}
.sat-mw-strip-card {
    flex-shrink: 0;
    min-width: 140px;
    padding: 6px 10px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.10);
    border-radius: 5px;
    color: var(--text, #e2e8f0);
    text-align: left;
    cursor: pointer;
    font-family: inherit;
    transition: background 0.12s, border-color 0.12s, transform 0.12s;
}
.sat-mw-strip-card:hover {
    background: rgba(46, 125, 255, 0.10);
    border-color: rgba(46, 125, 255, 0.45);
}
.sat-mw-strip-card.selected {
    background: rgba(253, 224, 71, 0.16);
    border-color: rgba(253, 224, 71, 0.75);
    box-shadow: 0 0 0 1px rgba(253, 224, 71, 0.30);
}
.sat-mw-strip-card-row {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 0.72rem;
    margin-bottom: 2px;
}
.sat-mw-strip-swatch {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
}
.sat-mw-strip-platform {
    color: #94a3b8;
    font-size: 0.65rem;
}
.sat-mw-strip-card-time {
    font-size: 0.72rem;
    font-weight: 600;
}
.sat-mw-strip-card-utc {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 0.62rem;
    color: #94a3b8;
}

/* Marker icons placed on both Leaflet maps — yellow cross at the
   latest best-track fix, orange filled ring at the interpolated
   position for the MW pass time. The wrapper carries the iconSize/
   iconAnchor; the inner span carries the visual. */
.sat-mw-marker { pointer-events: none; }
.sat-mw-marker-cross .sat-mw-cross {
    position: relative;
    display: block;
    width: 22px;
    height: 22px;
}
.sat-mw-marker-cross .sat-mw-cross::before,
.sat-mw-marker-cross .sat-mw-cross::after {
    content: '';
    position: absolute;
    background: #fde047;
    box-shadow: 0 0 4px rgba(15, 22, 36, 0.85);
}
.sat-mw-marker-cross .sat-mw-cross::before {
    left: 1px; top: 10px;
    width: 20px; height: 2px;
}
.sat-mw-marker-cross .sat-mw-cross::after {
    left: 10px; top: 1px;
    width: 2px; height: 20px;
}
.sat-mw-marker-ring .sat-mw-ring {
    display: block;
    width: 14px;
    height: 14px;
    margin: 2px;
    border-radius: 50%;
    background: rgba(251, 146, 60, 0.92);
    border: 1.5px solid rgba(15, 22, 36, 0.95);
    box-shadow: 0 0 0 1px rgba(251, 146, 60, 0.45);
}

/* ────────────────────────────────────────────────────────────────
   Storm Satellite mobile MW section — reuses the storm-card's
   thumbnail-grid renderer (_rtLoadStormMwPasses with prefix
   'sat-mw-mobile'). Hidden on desktop; revealed by JS only when
   _satIsMobileLayout() && MW mode active. Tap a thumbnail to
   open the existing body-level IR↔MW compare modal full-screen.
   ──────────────────────────────────────────────────────────────── */
.sat-mw-mobile-section {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    padding: 8px 10px 6px;
    overflow-y: auto;
    background: #0a0c12;
    color: #e2e8f0;
    -webkit-overflow-scrolling: touch;
}
.sat-mw-mobile-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 6px;
}
.sat-mw-mobile-title {
    margin: 0;
    font-size: 13px;
    font-weight: 600;
    color: #e2e8f0;
    letter-spacing: 0.02em;
}
.sat-mw-mobile-status {
    font-size: 11px;
    color: #94a3b8;
}
.sat-mw-mobile-products {
    /* Chips wrap into 2 rows on narrow phones — overrides the
       desktop flex-row gap with a tighter mobile spacing. */
    flex-wrap: wrap;
    gap: 4px;
    margin-bottom: 8px;
}
.sat-mw-mobile-list {
    /* Reuses .rt-mw-storm-list base styles for thumbnail grid; this
       override just makes the cards comfortably tap-sized on phones. */
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 8px;
}
.sat-mw-mobile-hint {
    font-size: 11px;
    color: #64748b;
    text-align: center;
    padding: 8px 0 12px;
    border-top: 1px solid #1e2130;
    margin-top: 8px;
}

/* Bottom-left floating legend on each Storm-Satellite Leaflet pane.
   Explains the on-map markers (yellow cross = latest best-track,
   orange ring = position at MW pass time, cyan ⊕ = IR center fix).
   Rows are toggled per-marker so the legend only advertises what's
   actually drawn — see _satLegendSetRow in satellite.js. */
.sat-map-legend {
    background: rgba(15, 22, 36, 0.85);
    color: #e2e8f0;
    border-radius: 4px;
    padding: 5px 8px 5px 6px;
    font-size: 11px;
    line-height: 1.35;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
    pointer-events: none;
    user-select: none;
    max-width: 240px;
}
.sat-map-legend .sat-legend-row {
    display: flex;
    align-items: center;
    gap: 7px;
    white-space: nowrap;
}
.sat-map-legend .sat-legend-row + .sat-legend-row { margin-top: 3px; }
.sat-map-legend .sat-legend-swatch {
    position: relative;
    display: inline-block;
    width: 16px;
    height: 16px;
    flex-shrink: 0;
}
/* Yellow cross — matches sat-mw-cross marker. */
.sat-map-legend .sat-legend-cross::before,
.sat-map-legend .sat-legend-cross::after {
    content: '';
    position: absolute;
    background: #fde047;
    box-shadow: 0 0 2px rgba(15, 22, 36, 0.9);
}
.sat-map-legend .sat-legend-cross::before {
    left: 1px; top: 7px; width: 14px; height: 2px;
}
.sat-map-legend .sat-legend-cross::after {
    left: 7px; top: 1px; width: 2px; height: 14px;
}
/* Orange ring — matches sat-mw-ring marker. */
.sat-map-legend .sat-legend-ring {
    width: 12px;
    height: 12px;
    margin: 2px;
    border-radius: 50%;
    background: rgba(251, 146, 60, 0.92);
    border: 1.5px solid rgba(15, 22, 36, 0.95);
}
/* Cyan circle + crosshair — matches sat-leaflet-centerfix marker. */
.sat-map-legend .sat-legend-cyancross {
    width: 14px;
    height: 14px;
    margin: 1px;
    border: 1.5px solid #00e5ff;
    border-radius: 50%;
}
.sat-map-legend .sat-legend-cyancross::before,
.sat-map-legend .sat-legend-cyancross::after {
    content: '';
    position: absolute;
    background: #00e5ff;
}
.sat-map-legend .sat-legend-cyancross::before {
    left: 0; top: 6px; width: 14px; height: 1.5px;
}
.sat-map-legend .sat-legend-cyancross::after {
    left: 6px; top: 0; width: 1.5px; height: 14px;
}
.sat-map-legend .sat-legend-label {
    color: #e2e8f0;
    font-family: inherit;
}

/* Anchor sat-compare-panel as a positioning context so the WV/Vis
   colorbar (absolute-positioned below) can dock to its bottom edge
   without being clipped by sat-compare-panel's overflow:hidden. */
body.sat-leaflet-active #sat-compare-panel,
body.sat-leaflet-active #sat-mw-section,
body.sat-leaflet-active #sat-panel-ir {
    position: relative;
}

/* Storm Satellite Leaflet colorbars — float over the bottom of
   each pane so the maps stay equal-height (no flex space taken).
   Applied only when body has sat-leaflet-active so canvas modes
   keep the old in-flow layout. z-index:1000 keeps the colorbar
   above Leaflet's internal pane stack (controlPane ~800) so the
   bar doesn't disappear behind the map's own DOM children. */
body.sat-leaflet-active #sat-cb-ir,
body.sat-leaflet-active #sat-cb-right,
.sat-mw-colorbar {
    position: absolute;
    bottom: 6px;
    left: 12px;
    right: 12px;
    z-index: 1000;
    background: rgba(15, 22, 36, 0.85);
    border-radius: 4px;
    padding: 4px 8px;
    pointer-events: none;
}
body.sat-leaflet-active #sat-cb-ir canvas,
body.sat-leaflet-active #sat-cb-right canvas,
.sat-mw-colorbar canvas {
    height: 10px;
}
body.sat-leaflet-active #sat-cb-ir .sat-cb-label-left,
body.sat-leaflet-active #sat-cb-ir .sat-cb-label-right,
body.sat-leaflet-active #sat-cb-right .sat-cb-label-left,
body.sat-leaflet-active #sat-cb-right .sat-cb-label-right,
.sat-mw-colorbar .sat-cb-label-left,
.sat-mw-colorbar .sat-cb-label-right {
    color: #e2e8f0;
    font-weight: 600;
    /* Inherit Inter / DM Sans — the canvas-era CSS used a monospace
       fallback that looked inconsistent next to the rest of the
       tab's typography. */
    font-family: inherit;
}

/* Storm Satellite graticule labels — small white text with a dark
   text-shadow halo so they read on both bright land and dark ocean
   basemap tiles. Same convention as the Global Map's RT graticule. */
.sat-graticule-label {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 10px;
    font-weight: 600;
    color: #f1f5f9;
    text-shadow:
        0 0 4px rgba(15, 22, 36, 0.95),
        0 0 2px rgba(15, 22, 36, 0.95),
        0 0 1px rgba(15, 22, 36, 0.95);
    pointer-events: none;
    white-space: nowrap;
    line-height: 14px;
    background: transparent;
    border: none;
}

/* Floating Leaflet control bar — ⌖ Recenter, 🔗 Sync toggle. Sits
   beneath Leaflet's built-in zoom control on each Storm Satellite
   tab Leaflet map. The active class lights up the sync button when
   panes are linked. */
.sat-map-controls { margin-top: 6px !important; }
.sat-map-ctrl-btn {
    display: block;
    width: 26px;
    height: 26px;
    line-height: 26px;
    text-align: center;
    background: #fff;
    color: #333;
    font-size: 14px;
    text-decoration: none;
    border-bottom: 1px solid #ddd;
}
.sat-map-ctrl-btn:last-child { border-bottom: none; }
.sat-map-ctrl-btn:hover { background: #f4f4f4; }
.sat-map-ctrl-btn.active {
    background: #d4e7ff;
    color: #1d4ed8;
}

/* Phase 2: Leaflet IR animation center-fix marker. Shown when the
   active frame carries a server-detected eye (storms ≥ ~65 kt).
   Cyan circle+cross matches the existing canvas crosshair legend
   in the sidebar (sat-crosshair-legend) so users recognize it. */
.sat-leaflet-centerfix { pointer-events: none; }
.sat-leaflet-centerfix-inner {
    position: relative;
    display: block;
    width: 22px;
    height: 22px;
    border: 1.5px solid #00e5ff;
    border-radius: 50%;
}
.sat-leaflet-centerfix-inner::before,
.sat-leaflet-centerfix-inner::after {
    content: '';
    position: absolute;
    background: #00e5ff;
}
.sat-leaflet-centerfix-inner::before {
    left: -1px; top: 9px;
    width: 22px; height: 2px;
}
.sat-leaflet-centerfix-inner::after {
    left: 9px; top: -1px;
    width: 2px; height: 22px;
}

/* ════════════════════════════════════════════════════════════════
   IR ↔ Microwave side-by-side compare modal. Click a MW pass
   thumbnail in the storm-detail panel to open. Mirrors the genesis
   modal's chrome (header + close + max-height) but with a 2-column
   panel grid that holds large square canvases — IR on the left, MW
   on the right, both showing the same storm-centered geographic
   crop so direct visual comparison is just an eye-flick away.
   ════════════════════════════════════════════════════════════════ */
.rt-mw-compare-modal {
    position: fixed;
    inset: 0;
    z-index: 4500;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(8, 12, 22, 0.72);
    padding: 16px;
}
.rt-mw-compare-content {
    position: relative;
    width: min(1320px, 100%);
    max-height: 92vh;
    background: var(--surface-raised, #ffffff);
    color: var(--text, #0f172a);
    border-radius: 8px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35);
    overflow: auto;
    padding: 18px 22px 22px;
}
[data-theme="dark"] .rt-mw-compare-content {
    background: var(--surface-raised, #161b24);
    color: var(--text, #e2e8f0);
}
.rt-mw-compare-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 12px;
}
.rt-mw-compare-title {
    margin: 0 0 4px 0;
    font-size: 1.05rem;
    font-weight: 700;
}
.rt-mw-compare-sub {
    margin: 0;
    font-size: 0.78rem;
    color: var(--text-dim, #64748b);
    line-height: 1.4;
}
.rt-mw-compare-header-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
}
.rt-mw-compare-save {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: 32px;
    padding: 0 12px;
    border-radius: 16px;
    border: 1px solid rgba(0, 80, 48, 0.4);
    background: rgba(0, 80, 48, 0.10);
    color: var(--um-green);
    font-size: 0.78rem;
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    transition: background 0.15s, color 0.15s, border-color 0.15s, transform 0.15s;
}
.rt-mw-compare-save:hover {
    background: rgba(0, 80, 48, 0.20);
    border-color: rgba(0, 80, 48, 0.55);
    transform: translateY(-1px);
}
.rt-mw-compare-save:active {
    transform: translateY(0);
}
.rt-mw-compare-save:disabled {
    opacity: 0.55;
    cursor: progress;
    transform: none;
}
[data-theme="dark"] .rt-mw-compare-save {
    background: rgba(74, 155, 110, 0.14);
    color: var(--um-green);
    border-color: rgba(74, 155, 110, 0.5);
}
[data-theme="dark"] .rt-mw-compare-save:hover {
    background: rgba(74, 155, 110, 0.26);
    border-color: rgba(74, 155, 110, 0.65);
}
.rt-mw-compare-close {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    border: 1px solid rgba(0, 0, 0, 0.18);
    background: rgba(255, 255, 255, 0.92);
    color: #0f172a;
    font-size: 1.5rem;
    line-height: 1;
    cursor: pointer;
    transition: background 0.15s, transform 0.15s;
}
.rt-mw-compare-close:hover {
    background: #fff;
    transform: scale(1.05);
}
[data-theme="dark"] .rt-mw-compare-close {
    background: var(--surface, #11161f);
    color: var(--text, #e2e8f0);
    border-color: rgba(255, 255, 255, 0.18);
}

.rt-mw-compare-products {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-bottom: 12px;
}
.rt-mw-compare-vis-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-left: auto;
    padding: 4px 10px;
    font-size: 12px;
    color: #475569;
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
}
.rt-mw-compare-vis-toggle input {
    cursor: pointer;
    margin: 0;
    accent-color: #2e7dff;
}
[data-theme="dark"] .rt-mw-compare-vis-toggle {
    color: #94a3b8;
}
.rt-mw-compare-panels {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 14px;
}
.rt-mw-compare-panel {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.rt-mw-compare-panel-label {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--text, #0f172a);
}
.rt-mw-compare-time {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 0.72rem;
    font-weight: 500;
    color: var(--text-dim, #64748b);
}
.rt-mw-compare-canvas {
    width: 100%;
    height: auto;
    aspect-ratio: 1 / 1;
    background: rgba(15, 22, 36, 0.65);
    border-radius: 6px;
    /* `auto` (default) lets the browser pick smooth interpolation when
       the canvas's intrinsic 1100×1100 is rendered at a different display
       size. `-webkit-optimize-contrast` on some browsers maps to
       nearest-neighbor, which exposes per-pixel blockiness when the
       source PNG had to upscale into the storm crop. */
    image-rendering: auto;
}
.rt-mw-compare-status {
    min-height: 14px;
    font-size: 0.72rem;
    color: var(--text-dim, #64748b);
    font-style: italic;
}
.rt-mw-compare-canvas-wrap {
    position: relative;
}
.rt-mw-compare-loading {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    border-radius: 6px;
    background: rgba(15, 22, 36, 0.45);
    pointer-events: none;
}
.rt-mw-compare-loading[hidden] { display: none; }
.rt-mw-compare-spinner {
    width: 28px;
    height: 28px;
    border: 3px solid rgba(148, 163, 184, 0.4);
    border-top-color: #00e5ff;
    border-radius: 50%;
    animation: ir-spin 0.8s linear infinite;
}
.rt-mw-compare-loading-text {
    font-size: 0.78rem;
    font-weight: 600;
    color: #e2e8f0;
    letter-spacing: 0.02em;
}
[data-theme="dark"] .rt-mw-compare-panel-label { color: var(--text, #e2e8f0); }

/* On narrow screens, stack the two panels vertically rather than
   shrinking them past usefulness. */
@media (max-width: 800px) {
    .rt-mw-compare-panels { grid-template-columns: 1fr; }

    /* Mobile scroll fix: the desktop modal centers a tall, internally
       scrolling card. On a phone the stacked panels make the card taller
       than the visual viewport, and centering pushes its top edge (where
       Save PNG / Close live) up behind the address bar — unreachable,
       because the scroll lived inside the card, not the modal. Go
       full-bleed: the whole modal becomes the scroll container, the card
       fills the screen, and the header pins flush to the top so Save/Close
       stay tappable at any scroll position (nothing can peek above it). */
    .rt-mw-compare-modal {
        align-items: flex-start;
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
        padding: 0;
    }
    .rt-mw-compare-content {
        width: 100%;
        max-height: none;
        min-height: 100%;
        overflow: visible;       /* let the modal scroll, not the card */
        border-radius: 0;
        padding: 0 16px 16px;    /* header supplies the top spacing */
    }
    .rt-mw-compare-header {
        position: sticky;
        top: 0;
        z-index: 5;
        margin: 0 -16px 12px;    /* bleed the pinned bar to the screen edges */
        padding: 12px 16px;
        background: var(--surface-raised, #ffffff);
    }
    [data-theme="dark"] .rt-mw-compare-header {
        background: var(--surface-raised, #161b24);
    }
}

/* Legend strip — explains the on-canvas position markers (latest
   best-track fix vs interpolated/extrapolated position at MW pass).
   Sits between the product chips and the canvas panels. */
.rt-mw-compare-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 18px;
    margin: 4px 0 12px 0;
    padding: 8px 10px;
    background: rgba(15, 22, 36, 0.04);
    border: 1px solid rgba(0, 0, 0, 0.08);
    border-radius: 6px;
    font-size: 0.72rem;
    color: var(--text, #0f172a);
}
.rt-mw-compare-legend-item {
    display: flex;
    align-items: center;
    gap: 8px;
}
.rt-mw-compare-marker {
    flex-shrink: 0;
    width: 20px;
    height: 20px;
    position: relative;
}
/* Yellow cross marker — matches the canvas-drawn storm-center cross. */
.rt-mw-compare-marker-cross::before,
.rt-mw-compare-marker-cross::after {
    content: '';
    position: absolute;
    background: #fde047;
    left: 50%; top: 50%;
}
.rt-mw-compare-marker-cross::before {
    width: 16px; height: 2px;
    transform: translate(-50%, -50%);
}
.rt-mw-compare-marker-cross::after {
    width: 2px; height: 16px;
    transform: translate(-50%, -50%);
}
/* Orange filled ring marker — matches the canvas-drawn interp marker. */
.rt-mw-compare-marker-ring {
    width: 14px;
    height: 14px;
    margin: 3px;
    border-radius: 50%;
    background: rgba(251, 146, 60, 0.9);
    border: 1.5px solid rgba(15, 22, 36, 0.95);
    box-shadow: 0 0 0 1px rgba(251, 146, 60, 0.4);
}
.rt-mw-compare-marker-label strong {
    display: block;
    font-weight: 700;
    line-height: 1.2;
}
.rt-mw-compare-marker-time {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 0.66rem;
    color: var(--text-dim, #64748b);
}
[data-theme="dark"] .rt-mw-compare-legend {
    background: rgba(255, 255, 255, 0.03);
    border-color: rgba(255, 255, 255, 0.08);
    color: var(--text, #e2e8f0);
}
[data-theme="dark"] .rt-mw-compare-marker-cross::before,
[data-theme="dark"] .rt-mw-compare-marker-cross::after {
    background: #fde047;
}

/* Microwave jump-button in the storm-detail header. Inherits the
   green tint from .ir-kml-btn — explicit overrides kept here so the
   block stays easy to find next to .ir-sat-viewer-btn semantically. */
.ir-mw-jump-btn {
    background: rgba(0, 80, 48, 0.10);
    border-color: rgba(0, 80, 48, 0.4);
    color: var(--um-green);
}
.ir-mw-jump-btn:hover {
    background: rgba(0, 80, 48, 0.20);
    border-color: rgba(0, 80, 48, 0.55);
}
[data-theme="dark"] .ir-mw-jump-btn {
    color: var(--um-green);
    border-color: rgba(74, 155, 110, 0.5);
    background: rgba(74, 155, 110, 0.14);
}

/* Pulse animation — applied briefly to the Microwave section when the
   user clicks the header pill, so their eye lands on the right panel. */
@keyframes ir-info-section-pulse-kf {
    0%   { box-shadow: 0 0 0 0  rgba(46, 125, 255, 0.55); }
    60%  { box-shadow: 0 0 0 6px rgba(46, 125, 255, 0.10); }
    100% { box-shadow: 0 0 0 0  rgba(46, 125, 255, 0.00); }
}
.ir-info-section-pulse {
    animation: ir-info-section-pulse-kf 1.5s ease-out;
    border-radius: 6px;
}

/* ════════════════════════════════════════════════════════════════
   subOnly=1 iframe-embed mode. Strips all chrome and reduces the
   Subseasonal tab to just the combined Hovmöller, so the climo
   page can embed this page inline and get our own WK-filtered
   convection figure (no CPC GIF dependency). The clocks aside is
   hidden because the climo page already shows them above.
   ════════════════════════════════════════════════════════════════ */
html.sub-only-mode { background: transparent !important; }
html.sub-only-mode body {
    margin: 0; padding: 0; background: transparent !important;
}
/* Hide every page-chrome element. */
html.sub-only-mode .topbar,
html.sub-only-mode .ir-secondary-bar,
html.sub-only-mode .basin-sidebar,
html.sub-only-mode .basin-sidebar-toggle,
html.sub-only-mode #ir-main,
html.sub-only-mode #satellite-main,
html.sub-only-mode #seasonal-main,
html.sub-only-mode .ir-feed-banner,
html.sub-only-mode .skip-link,
html.sub-only-mode .footer,
html.sub-only-mode footer {
    display: none !important;
}
/* Strip the Subseasonal tab down to the Hovmöller stack: hide the
   header (title + lat-band + view-toggle + save-png), hide the
   clocks aside, and let the right column fill the frame. */
html.sub-only-mode #sub-main {
    display: flex !important;        /* force visible (overrides JS-set display:none) */
    margin: 0 !important;
    padding: 0 !important;
}
html.sub-only-mode .sub-header { display: none !important; }
html.sub-only-mode .sub-clocks { display: none !important; }
html.sub-only-mode .sub-body {
    grid-template-columns: 1fr !important;
    gap: 0 !important;
    padding: 4px !important;
}
html.sub-only-mode .sub-hovs > .sub-section-heading { display: none !important; }
html.sub-only-mode .sub-hov-stack {
    border: none !important;
    padding: 4px !important;
    background: transparent !important;
}
html.sub-only-mode .sub-active-tc-list { display: none !important; }

/* ════════════════════════════════════════════════════════════════
   MICROWAVE PASSES (last N hrs) overlay UI — shared with the
   Global Archive's storm-browser map (same .tc-mw-* class block
   is duplicated in global_archive_styles.css so each page ships
   what it needs). RT version lives inside the unified Layers
   panel; Global Archive uses the compact variant in a top-right
   Leaflet control. Both consume tc_mw_layer.js.
   ════════════════════════════════════════════════════════════════ */
.ir-mw-section-slot {
    padding: 4px 10px 8px;
}
.tc-mw-ui {
    display: flex;
    flex-direction: column;
    gap: 6px;
    font-family: inherit;
    color: #e2e8f0;
}
.tc-mw-toggle {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: rgba(255,255,255,0.04);
    border: 1px solid rgba(255,255,255,0.12);
    color: #e2e8f0;
    padding: 5px 10px;
    border-radius: 5px;
    font-size: 0.72rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s;
}
.tc-mw-toggle:hover {
    background: rgba(74, 155, 110, 0.10);
    border-color: rgba(74, 155, 110, 0.45);
}
.tc-mw-toggle .tc-mw-toggle-dot {
    width: 8px; height: 8px; border-radius: 50%;
    background: rgba(255,255,255,0.18);
    transition: background 0.12s, box-shadow 0.12s;
}
.tc-mw-toggle.active {
    background: rgba(74, 155, 110, 0.18);
    border-color: #4a9b6e;
    color: #ffffff;
}
.tc-mw-toggle.active .tc-mw-toggle-dot {
    background: #4a9b6e;
    box-shadow: 0 0 6px #4a9b6e;
}
.tc-mw-controls {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding-left: 4px;
}
.tc-mw-control-row {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.66rem;
    color: #cbd5e1;
}
.tc-mw-product-row {
    flex-wrap: wrap;
}
.tc-mw-product-opt {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    cursor: pointer;
}
.tc-mw-product-opt input[type="radio"] {
    accent-color: #4a9b6e;
    cursor: pointer;
}
.tc-mw-sensor-row {
    flex-wrap: wrap;
    gap: 10px;
}
.tc-mw-sensor-opt {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    cursor: pointer;
    color: #cbd5e1;
}
.tc-mw-sensor-opt input[type="checkbox"] {
    accent-color: #4a9b6e;
    cursor: pointer;
}
.tc-mw-sensor-swatch {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    margin-right: 2px;
    box-shadow: 0 0 0 1px rgba(0,0,0,0.35);
    flex-shrink: 0;
}
.tc-mw-sensor-label {
    font-variant-numeric: tabular-nums;
}
.tc-mw-time-row {
    gap: 6px;
    align-items: center;
}
.tc-mw-cursor-slider {
    flex: 1;
    accent-color: #4a9b6e;
    cursor: pointer;
    min-width: 60px;
}
.tc-mw-play-btn, .tc-mw-live-btn {
    background: rgba(255,255,255,0.06);
    border: 1px solid rgba(255,255,255,0.12);
    color: #cbd5e1;
    font-size: 0.6rem;
    font-weight: 600;
    padding: 2px 6px;
    border-radius: 3px;
    cursor: pointer;
    letter-spacing: 0.04em;
    transition: background 0.12s, color 0.12s;
}
.tc-mw-play-btn { padding: 2px 5px; }
.tc-mw-play-btn:hover, .tc-mw-live-btn:hover {
    background: rgba(74,155,110,0.18);
    color: #e2e8f0;
}
.tc-mw-play-btn.playing {
    background: rgba(74,155,110,0.32);
    color: #fefefe;
}
.tc-mw-live-btn.active {
    background: rgba(74,155,110,0.28);
    color: #e2e8f0;
    border-color: rgba(74,155,110,0.5);
}
.tc-mw-play-icon {
    display: inline-block;
    width: 0; height: 0;
    border-left: 7px solid currentColor;
    border-top: 4px solid transparent;
    border-bottom: 4px solid transparent;
    vertical-align: middle;
}
.tc-mw-play-btn.playing .tc-mw-play-icon {
    border: 0;
    width: 7px; height: 8px;
    border-left: 2.5px solid currentColor;
    border-right: 2.5px solid currentColor;
    box-sizing: border-box;
}
.tc-mw-cursor-readout {
    min-width: 38px;
    text-align: right;
    color: #e2e8f0;
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    font-size: 0.62rem;
}
.tc-mw-legend {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 4px 2px 2px;
    border-top: 1px dashed rgba(255,255,255,0.08);
    border-bottom: 1px dashed rgba(255,255,255,0.08);
}
.tc-mw-legend-title {
    font-size: 0.55rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #94a3b8;
    font-weight: 600;
}
.tc-mw-legend-bar {
    height: 10px;
    width: 100%;
    max-width: 160px;
    border-radius: 2px;
    box-shadow: 0 0 0 1px rgba(255,255,255,0.12) inset;
}
.tc-mw-legend-bar-89 {
    background: linear-gradient(to right,
        #0b1d4f 0%, #1d4ed8 20%, #06b6d4 40%,
        #16a34a 55%, #facc15 75%, #dc2626 100%);
}
.tc-mw-legend-bar-37 {
    /* 37 GHz NRL ramp — similar but slightly shifted gradient since
       37 GHz convective signal lives in a different Tb range. Close
       approximation of _nrl_37ghz_cmap() in microwave_api.py. */
    background: linear-gradient(to right,
        #1e1b4b 0%, #4f46e5 20%, #06b6d4 40%,
        #22c55e 55%, #facc15 75%, #ef4444 100%);
}
.tc-mw-product-select {
    background: rgba(255,255,255,0.06);
    border: 1px solid rgba(255,255,255,0.15);
    border-radius: 3px;
    color: #e2e8f0;
    font-size: 0.68rem;
    padding: 2px 4px;
    cursor: pointer;
    font-family: inherit;
    margin-left: 4px;
}
.tc-mw-product-select:focus { outline: 1px solid #4ade80; }
.tc-mw-product-label {
    display: inline-flex;
    align-items: center;
    color: #94a3b8;
    text-transform: uppercase;
    font-size: 0.58rem;
    letter-spacing: 0.04em;
    font-weight: 600;
}
.tc-mw-legend-chunks {
    display: flex;
    width: 100%;
    max-width: 160px;
    gap: 0;
}
.tc-mw-legend-chunk {
    flex: 1;
    height: 10px;
    box-shadow: 0 0 0 1px rgba(255,255,255,0.10) inset;
}
.tc-mw-legend-chunks .tc-mw-legend-chunk:first-child { border-radius: 2px 0 0 2px; }
.tc-mw-legend-chunks .tc-mw-legend-chunk:last-child  { border-radius: 0 2px 2px 0; }
.tc-mw-legend-ticks,
.tc-mw-legend-labels {
    display: flex;
    justify-content: space-between;
    width: 100%;
    max-width: 160px;
    font-size: 0.5rem;
    color: #94a3b8;
    font-variant-numeric: tabular-nums;
}
.tc-mw-legend-labels span {
    flex: 1;
    text-align: center;
}
.tc-mw-hours-row {
    gap: 6px;
}
.tc-mw-opacity-row {
    gap: 6px;
}
.tc-mw-opacity-label {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: #94a3b8;
    text-transform: uppercase;
    font-size: 0.58rem;
    letter-spacing: 0.04em;
    font-weight: 600;
}
.tc-mw-opacity-label .tc-mw-opacity-val {
    color: #e2e8f0;
    font-variant-numeric: tabular-nums;
    font-weight: 700;
}
.tc-mw-opacity-slider {
    flex: 1;
    accent-color: #4a9b6e;
    cursor: pointer;
}
/* ── Pass schedule per active ATCF storm ──────────────────────── */
.tc-mw-schedule {
    margin-top: 6px;
    padding-top: 6px;
    padding-right: 4px;  /* breathing room next to the scrollbar */
    border-top: 1px dashed rgba(255,255,255,0.10);
    display: flex;
    flex-direction: column;
    gap: 6px;
    /* Cap height so a busy basin (multiple TCs + disturbances) doesn't
       push the popover off the bottom of the viewport. The controls
       above (product / sensors / sliders) stay pinned; only this
       schedule list scrolls. ~360 px ≈ 4-5 storm rows on a typical
       laptop, sized small enough that the popover still fits within
       the IR-Monitor map even on shorter screens. */
    max-height: 360px;
    overflow-y: auto;
    /* Custom scrollbar so it reads as part of the dark popover rather
       than a default OS chrome strip. */
    scrollbar-width: thin;
    scrollbar-color: rgba(148, 163, 184, 0.4) transparent;
}
.tc-mw-schedule::-webkit-scrollbar {
    width: 6px;
}
.tc-mw-schedule::-webkit-scrollbar-track {
    background: transparent;
}
.tc-mw-schedule::-webkit-scrollbar-thumb {
    background-color: rgba(148, 163, 184, 0.4);
    border-radius: 3px;
}
.tc-mw-schedule::-webkit-scrollbar-thumb:hover {
    background-color: rgba(148, 163, 184, 0.65);
}
.tc-mw-schedule-empty {
    font-size: 0.6rem;
    color: #64748b;
    font-style: italic;
}
.tc-mw-schedule-title {
    font-size: 0.55rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #94a3b8;
    font-weight: 700;
}
.tc-mw-schedule-storm {
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.tc-mw-schedule-storm-name {
    font-size: 0.65rem;
    color: #e2e8f0;
    font-weight: 600;
}
.tc-mw-schedule-storm.is-disturbance .tc-mw-schedule-storm-name {
    color: #cbd5e1;
    font-style: italic;
    font-weight: 500;
}
.tc-mw-schedule-forecast-tag {
    display: inline-block;
    background: rgba(168, 85, 247, 0.18);
    color: #c084fc;
    font-style: normal;
    font-size: 0.52rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding: 1px 5px;
    border-radius: 3px;
    margin-left: 4px;
    vertical-align: middle;
}
.tc-mw-schedule-row {
    display: grid;
    grid-template-columns: 60px 1fr 1fr;
    gap: 6px;
    font-size: 0.62rem;
    color: #cbd5e1;
    align-items: center;
}
.tc-mw-schedule-sensor {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: #94a3b8;
}
.tc-mw-schedule-cell {
    font-variant-numeric: tabular-nums;
}
.tc-mw-schedule-cell.dim {
    color: #64748b;
}
/* Predicted pass beyond the 24 h baseline — visually distinguish so
   the user can tell "soon" (≤24 h) from "far" (>24 h, only published
   for single-satellite sensors GMI / AMSR2). Faded text + italic;
   the ETA arrow inside is muted to match. */
.tc-mw-schedule-cell.far {
    color: #94a3b8;
    font-style: italic;
}
.tc-mw-schedule-cell.far .tc-mw-schedule-eta {
    color: #6b8a76;   /* desaturated green so it still reads as ETA */
}
.tc-mw-schedule-eta {
    color: #4ade80;
    margin-left: 2px;
    font-size: 0.95em;
}
.tc-mw-schedule-foot {
    font-size: 0.55rem;
    color: #64748b;
    margin-top: 2px;
}
.tc-mw-hours-label {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: #94a3b8;
    text-transform: uppercase;
    font-size: 0.58rem;
    letter-spacing: 0.04em;
    font-weight: 600;
}
.tc-mw-hours-label .tc-mw-hours-val {
    color: #e2e8f0;
    font-variant-numeric: tabular-nums;
    font-weight: 700;
}
.tc-mw-hours-slider {
    flex: 1;
    accent-color: #4a9b6e;
    height: 14px;
    min-width: 80px;
}
.tc-mw-status {
    font-size: 0.62rem;
    color: #94a3b8;
    min-height: 0.9em;
}
.tc-mw-attribution {
    font-size: 0.55rem;
    color: #64748b;
    opacity: 0.85;
}
.tc-mw-popup {
    font-family: inherit;
    color: #0f1623;
    min-width: 180px;
}
.tc-mw-popup-title {
    font-weight: 700;
    font-size: 0.82rem;
    margin-bottom: 4px;
}
.tc-mw-popup-row {
    font-size: 0.72rem;
    line-height: 1.4;
}
.tc-mw-popup-storms {
    margin-top: 6px;
    padding-top: 4px;
    border-top: 1px dashed rgba(0, 0, 0, 0.18);
}
/* Default (light theme): dark amber title + near-black body so the
   matched-storm callout reads cleanly on Leaflet's white popup. The
   old #fde047 yellow was theme-mismatched (chosen against the dark
   in-app surface) and basically invisible on a light popup. */
.tc-mw-popup-storms-title {
    font-size: 0.6rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #b45309;       /* dark amber, readable on white */
    font-weight: 700;
    margin-bottom: 2px;
}
.tc-mw-popup-storm {
    font-size: 0.72rem;
    color: #1f2937;       /* dark slate, near-black */
    font-weight: 600;
}
/* Dark theme: restore the warmer amber-on-navy palette since the
   popup background flips to the app's dark surface. */
[data-theme="dark"] .tc-mw-popup-storms {
    border-top-color: rgba(255, 255, 255, 0.18);
}
[data-theme="dark"] .tc-mw-popup-storms-title {
    color: #fde047;
}
[data-theme="dark"] .tc-mw-popup-storm {
    color: #fef9c3;
    font-weight: 500;
}

/* Compact variant — used in Leaflet-control placements where
   horizontal space is tight (Global Archive map corner). */
.tc-mw-ui-compact {
    background: rgba(22,27,36,0.93);
    border: 1px solid rgba(255,255,255,0.14);
    border-radius: 6px;
    padding: 6px 8px;
    backdrop-filter: blur(6px);
    box-shadow: 0 2px 8px rgba(0,0,0,0.25);
    min-width: 200px;
}

/* ── Bare satellite-loop popup (storm card "Loop Only" button) ─────────
   In-page modal hosting a Tropical-Tidbits-style co-moving IR animation.
   Mirrors the rt-mw-compare-modal chrome but the body is a single map. */
.ir-loop-modal {
    position: fixed;
    inset: 0;
    z-index: 4500;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(8, 12, 22, 0.72);
    padding: 16px;
}
.ir-loop-modal-content {
    position: relative;
    display: flex;
    flex-direction: column;
    width: min(960px, 100%);
    height: min(820px, 92vh);
    background: var(--surface-raised, #ffffff);
    color: var(--text, #0f172a);
    border-radius: 8px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35);
    overflow: hidden;
}
[data-theme="dark"] .ir-loop-modal-content {
    background: var(--surface-raised, #161b24);
    color: var(--text, #e2e8f0);
}
.ir-loop-modal-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 16px;
    flex-shrink: 0;
}
.ir-loop-modal-titles {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}
.ir-loop-modal-cat {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 34px;
    height: 24px;
    padding: 0 8px;
    border-radius: 12px;
    background: #60a5fa;
    color: #0b1220;
    font-size: 0.78rem;
    font-weight: 800;
    letter-spacing: 0.02em;
}
.ir-loop-modal-title {
    margin: 0;
    font-size: 1.02rem;
    font-weight: 700;
    line-height: 1.2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.ir-loop-modal-sub {
    margin: 2px 0 0 0;
    font-size: 0.76rem;
    color: var(--text-dim, #64748b);
    line-height: 1.3;
}
.ir-loop-modal-close {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    border: 1px solid rgba(0, 0, 0, 0.18);
    background: rgba(255, 255, 255, 0.92);
    color: #0f172a;
    font-size: 1.5rem;
    line-height: 1;
    cursor: pointer;
    transition: background 0.15s, transform 0.15s;
}
.ir-loop-modal-close:hover {
    background: #fff;
    transform: scale(1.05);
}
[data-theme="dark"] .ir-loop-modal-close {
    background: var(--surface, #11161f);
    color: var(--text, #e2e8f0);
    border-color: rgba(255, 255, 255, 0.18);
}
.ir-loop-modal-mapwrap {
    position: relative;
    flex: 1 1 auto;
    min-height: 0;
}
.ir-loop-modal-map {
    position: absolute;
    inset: 0;
    background: #0b1220;
}
.ir-loop-modal-loader,
.ir-loop-modal-error {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 500;
    padding: 10px 16px;
    border-radius: 8px;
    background: rgba(15, 23, 42, 0.82);
    color: #e2e8f0;
    font-size: 0.85rem;
    text-align: center;
    max-width: 80%;
    pointer-events: none;
}
.ir-loop-modal-error {
    background: rgba(120, 30, 30, 0.88);
}

@media (max-width: 640px) {
    .ir-loop-modal {
        padding: 0;
    }
    .ir-loop-modal-content {
        width: 100%;
        height: 100%;
        max-height: none;
        border-radius: 0;
    }
}

/* ── Transient toast (fallback / failure notices) ─────────────────
   Single reusable #rt-toast element created by realtime_ir.js:_rtToast.
   Hidden by default; .rt-toast-show fades it in for ~4 s. */
#rt-toast {
    position: fixed;
    left: 50%;
    bottom: 28px;
    transform: translateX(-50%) translateY(8px);
    z-index: 12000;
    padding: 10px 16px;
    border-radius: 8px;
    background: rgba(15, 23, 42, 0.92);
    border: 1px solid rgba(148, 163, 184, 0.25);
    color: #e2e8f0;
    font-size: 0.85rem;
    text-align: center;
    max-width: min(80%, 420px);
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.25s ease, transform 0.25s ease;
}
#rt-toast.rt-toast-show {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
}

/* ── Experimental tab (GHOST ML diagnostics) ─────────────────────── */
/* Light-first, [data-theme="dark"] overrides — site convention.
   NOTE: this whole section is authored ONCE. Do not machine-insert rules into
   it with a bare str.replace (an earlier pass duplicated every block four
   times and the trailing dark-mode copies then won in light mode). */
.exp-main {
    position: fixed;
    top: calc(var(--topbar-h, 53px) + var(--secondary-bar-h, 32px));
    left: 0; right: 0; bottom: 0;
    overflow: auto;
    padding: 18px 16px 60px;
    color: #334155;
}
[data-theme="dark"] .exp-main { color: #cbd5e1; }
.exp-inner { max-width: 1020px; margin: 0 auto; }

.exp-badge {
    display: inline-block;
    background: #b45309; color: #fff7ed;
    font-size: 11px; font-weight: 700; letter-spacing: 0.08em;
    padding: 2px 8px; border-radius: 4px; vertical-align: middle;
}
.exp-head {
    display: flex; flex-wrap: wrap; align-items: baseline;
    justify-content: space-between; gap: 8px; margin-bottom: 10px;
}
.exp-title { font-size: 19px; font-weight: 600; color: #0f172a; margin-left: 8px; }
[data-theme="dark"] .exp-title { color: #e2e8f0; }
.exp-meta { font-size: 12px; color: #64748b; }
.exp-meta a { color: #2e7dff; }

.exp-lede { font-size: 14px; line-height: 1.55; color: #0f172a; margin-bottom: 10px; }
[data-theme="dark"] .exp-lede { color: #e2e8f0; }

.exp-cite {
    font-size: 12.5px; line-height: 1.5;
    color: #7c2d12; background: #fff7ed; border: 1px solid #fed7aa;
    border-radius: 6px; padding: 10px 12px; margin-bottom: 10px;
}
[data-theme="dark"] .exp-cite {
    color: #fdba74; background: #2a1a0d; border-color: #7c2d12;
}
.exp-cite a { color: inherit; text-decoration: underline; }
.exp-stale {
    font-size: 13px; line-height: 1.5; font-weight: 600;
    color: #7f1d1d; background: #fef2f2; border: 1px solid #fecaca;
    border-left: 3px solid #dc2626;
    border-radius: 6px; padding: 10px 12px; margin-bottom: 10px;
}
[data-theme="dark"] .exp-stale {
    color: #fca5a5; background: #2a0f0f; border-color: #7f1d1d;
    border-left-color: #dc2626;
}
.exp-note {
    font-size: 12.5px; line-height: 1.5;
    color: #475569; background: #f8fafc;
    border: 1px solid #e2e8f0; border-left: 3px solid #b45309;
    border-radius: 6px; padding: 10px 12px; margin-bottom: 14px;
}
[data-theme="dark"] .exp-note {
    color: #94a3b8; background: #111c33; border-color: #1e293b;
    border-left-color: #b45309;
}

/* storm selection = UMiami green; hover accent = UMiami orange */
.exp-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
.exp-chip {
    background: #f1f5f9; border: 1px solid #cbd5e1; border-radius: 999px;
    color: #334155; padding: 6px 14px; font-size: 13px; cursor: pointer;
}
[data-theme="dark"] .exp-chip {
    background: #111c33; border-color: #334155; color: #cbd5e1;
}
.exp-chip span { color: #94a3b8; font-size: 11px; margin-left: 4px; }
[data-theme="dark"] .exp-chip span { color: #64748b; }
.exp-chip:hover:not(.active) {
    border-color: var(--um-orange, #F47321);
    color: var(--um-orange-deep, #d65f12);
}
.exp-chip.active {
    background: var(--um-green, #005030);
    border-color: var(--um-green, #005030);
    color: #fff;
}
.exp-chip.active span { color: #b7d9c9; }

/* view-option row: base pill, then per-toggle accents (declared AFTER the
   generic .active rule so they win at equal specificity) */
.exp-ranges { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-bottom: 10px; }
.exp-ranges-label {
    font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em;
    color: #64748b; margin-right: 2px;
}
.exp-ranges-sep { width: 1px; height: 18px; background: #cbd5e1; margin: 0 4px; }
[data-theme="dark"] .exp-ranges-sep { background: #334155; }
.exp-range {
    background: transparent; border: 1px solid #cbd5e1; border-radius: 6px;
    color: #475569; padding: 4px 10px; font-size: 12px; cursor: pointer;
}
[data-theme="dark"] .exp-range { border-color: #334155; color: #94a3b8; }
.exp-range.active {
    background: var(--um-orange-tint, rgba(244, 115, 33, 0.10));
    border-color: var(--um-orange, #F47321);
    color: var(--um-orange-deep, #d65f12);
    font-weight: 600;
}
[data-theme="dark"] .exp-range.active { color: var(--um-orange, #F47321); }
.exp-comp.active {
    background: rgba(168, 85, 247, 0.10); border-color: #a855f7; color: #a855f7;
}
.exp-shapbtn.active {
    background: rgba(20, 184, 166, 0.10); border-color: #14b8a6; color: #0d9488;
}
[data-theme="dark"] .exp-shapbtn.active { color: #14b8a6; }
.exp-verifbtn.active {
    background: rgba(109, 40, 217, 0.10); border-color: #6d28d9; color: #6d28d9;
}
[data-theme="dark"] .exp-verifbtn.active { color: #a78bfa; }

.exp-plot { min-height: 320px; }
.exp-plan-wrap { margin: 4px 0 16px; text-align: center; }
.exp-plan { max-width: 100%; border-radius: 8px; border: 1px solid #e2e8f0; }
[data-theme="dark"] .exp-plan { border-color: #1e293b; }
.exp-empty { padding: 40px 0; text-align: center; color: #64748b; font-size: 14px; }

/* SHAP driver panel */
.exp-shap { margin-top: 16px; }
.exp-shap-head { font-size: 13px; font-weight: 600; color: #0f172a; margin-bottom: 6px; }
[data-theme="dark"] .exp-shap-head { color: #e2e8f0; }
.exp-shap-sub {
    display: block; font-size: 11.5px; font-weight: 400; line-height: 1.45;
    color: #64748b; margin-top: 2px;
}
.exp-shap-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
/* grid children default to min-width:auto and will NOT shrink below their
   content width -- Plotly then overflows the cell and clips its own axis. */
.exp-shap-grid > div { min-width: 0; width: 100%; }

/* verification tables */
.exp-verif { margin-top: 16px; }
.exp-verif-h { font-size: 13px; font-weight: 600; margin-bottom: 8px; }
.exp-verif-src {
    display: block; font-size: 11.5px; font-weight: 400;
    color: #64748b; margin-top: 2px;
}
.exp-verif-t { overflow-x: auto; margin-bottom: 6px; }
.exp-verif-t table { border-collapse: collapse; font-size: 12.5px; min-width: 340px; }
.exp-verif-t caption {
    caption-side: top; text-align: left; font-size: 12px;
    font-weight: 600; padding: 6px 0 4px; color: #475569;
}
[data-theme="dark"] .exp-verif-t caption { color: #94a3b8; }
.exp-verif-t th, .exp-verif-t td {
    padding: 4px 12px 4px 0; text-align: left; border-bottom: 1px solid #e2e8f0;
}
[data-theme="dark"] .exp-verif-t th,
[data-theme="dark"] .exp-verif-t td { border-bottom-color: #1e293b; }
.exp-verif-t td:not(:first-child), .exp-verif-t th:not(:first-child) {
    text-align: right; font-variant-numeric: tabular-nums;
}
.exp-verif-t tr.me { font-weight: 700; color: var(--um-green, #005030); }
[data-theme="dark"] .exp-verif-t tr.me { color: #34d399; }
.exp-verif-note {
    font-size: 12px; line-height: 1.5; color: #475569;
    margin: 4px 0 14px; max-width: 70ch;
}
[data-theme="dark"] .exp-verif-note { color: #94a3b8; }

/* Latest-estimate stat tiles */
.exp-tiles {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(185px, 1fr));
    gap: 8px; margin-bottom: 12px;
}
.exp-tiles:empty { display: none; }
.exp-tile {
    border: 1px solid #e2e8f0; border-radius: 10px; padding: 9px 12px 8px;
    background: #f8fafc; min-width: 0;
}
[data-theme="dark"] .exp-tile { border-color: #1e293b; background: rgba(15,23,42,0.55); }
.exp-tile-k {
    font-size: 10.5px; font-weight: 600; text-transform: uppercase;
    letter-spacing: 0.04em; color: #64748b; margin-bottom: 2px;
}
[data-theme="dark"] .exp-tile-k { color: #94a3b8; }
.exp-tile-v { font-size: 21px; font-weight: 700; color: #0f172a; line-height: 1.2; }
[data-theme="dark"] .exp-tile-v { color: #e2e8f0; }
.exp-tile-u { font-size: 12px; font-weight: 600; color: #64748b; }
[data-theme="dark"] .exp-tile-u { color: #94a3b8; }
.exp-tile-sub { font-size: 11px; color: #64748b; margin-top: 1px; }
[data-theme="dark"] .exp-tile-sub { color: #94a3b8; }
.exp-tile-d { font-size: 11.5px; color: #475569; margin-top: 3px; }
[data-theme="dark"] .exp-tile-d { color: #94a3b8; }
.exp-tile-sub.exp-ceil { color: #b45309; font-weight: 600; }
[data-theme="dark"] .exp-tile-sub.exp-ceil { color: #fbbf24; }
.exp-cat {
    display: inline-block; font-size: 10.5px; font-weight: 700;
    border-radius: 999px; padding: 1.5px 8px; margin-left: 7px;
    vertical-align: 3px;
}
.exp-up { color: #dc2626; font-weight: 600; }
.exp-down { color: #2563eb; font-weight: 600; }
[data-theme="dark"] .exp-up { color: #f87171; }
[data-theme="dark"] .exp-down { color: #60a5fa; }
.exp-flag {
    display: inline-block; margin-top: 5px; font-size: 10px; font-weight: 700;
    letter-spacing: 0.04em; text-transform: uppercase; border-radius: 4px;
    padding: 2px 7px; background: #dc2626; color: #fff;
}
.exp-flag.down { background: #2563eb; }

/* Season archive */
.exp-arch-h {
    font-size: 12px; font-weight: 700; text-transform: uppercase;
    letter-spacing: 0.05em; color: #64748b; margin: 2px 0 6px;
}
[data-theme="dark"] .exp-arch-h { color: #94a3b8; }
.exp-arch-h span {
    font-weight: 400; text-transform: none; letter-spacing: 0;
    font-size: 11.5px; margin-left: 6px;
}
.exp-chip-arch { opacity: 0.88; }
.exp-chip-off { opacity: 0.55; cursor: not-allowed; }
.exp-arch-toggle {
    font: inherit; font-size: 12px; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.05em;
    color: #334155; background: #f1f5f9; border: 1px solid #cbd5e1;
    border-radius: 6px; padding: 4px 10px; cursor: pointer;
}
.exp-arch-toggle:hover { border-color: #F47321; color: #F47321; }
.exp-arch-toggle b {
    font-weight: 400; display: inline-block; transition: transform 0.15s;
}
.exp-arch-toggle.open b { transform: rotate(180deg); }
[data-theme="dark"] .exp-arch-toggle {
    color: #cbd5e1; background: #111c33; border-color: #1e293b;
}
[data-theme="dark"] .exp-arch-toggle:hover {
    border-color: #F47321; color: #F47321;
}
.exp-arch-body { margin-top: 6px; }
.exp-arch-basin {
    font-size: 11px; font-weight: 700; text-transform: uppercase;
    letter-spacing: 0.06em; color: #64748b; margin: 8px 0 4px;
}
[data-theme="dark"] .exp-arch-basin { color: #94a3b8; }
.exp-empty-sm { padding: 10px 0 14px; text-align: left; font-size: 13px; }
.exp-arch-note {
    grid-column: 1 / -1; font-size: 12px; color: #475569;
    background: #f1f5f9; border: 1px solid #e2e8f0; border-radius: 8px;
    padding: 7px 11px;
}
[data-theme="dark"] .exp-arch-note {
    color: #94a3b8; background: rgba(15,23,42,0.55); border-color: #1e293b;
}

/* Storm-chip intensity stamp */
.exp-chip-int { font-style: normal; font-size: 11px; opacity: 0.85; margin-left: 6px; }
.exp-chip-int:empty { display: none; }
.exp-chip-int i {
    display: inline-block; width: 8px; height: 8px; border-radius: 50%;
    margin-right: 4px; vertical-align: -0.5px;
}

/* Plan-view header row (title + download) */
.exp-plan-head {
    display: flex; justify-content: space-between; align-items: center;
    margin-bottom: 6px; text-align: left;
}
.exp-plan-title { font-size: 13px; font-weight: 600; color: #0f172a; }
[data-theme="dark"] .exp-plan-title { color: #e2e8f0; }

/* Center-track mini-map */
.exp-track { margin-top: 16px; }
#exp-track-map { min-width: 0; width: 100%; }
.exp-track-leg {
    display: flex; flex-wrap: wrap; gap: 10px; justify-content: center;
    font-size: 11px; color: #475569; margin-top: 4px;
}
[data-theme="dark"] .exp-track-leg { color: #94a3b8; }
.exp-track-leg i {
    display: inline-block; width: 9px; height: 9px; border-radius: 50%;
    margin-right: 4px; vertical-align: -0.5px;
}
.exp-track-leg i.open { background: transparent; border: 1.5px solid currentColor; }
.exp-distbtn.active {
    border-color: #f43f5e; color: #be123c; background: rgba(244,63,94,0.08);
}
[data-theme="dark"] .exp-distbtn.active { color: #fb7185; }
.exp-trackbtn.active {
    border-color: #2e7dff; color: #1d4ed8; background: rgba(46,125,255,0.08);
}
[data-theme="dark"] .exp-distbtn.active {
    border-color: #f43f5e; color: #be123c; background: rgba(244,63,94,0.08);
}
[data-theme="dark"] .exp-distbtn.active { color: #fb7185; }
.exp-trackbtn.active { color: #60a5fa; }

@media (max-width: 720px) { .exp-shap-grid { grid-template-columns: 1fr; } }
@media (max-width: 640px) {
    .exp-main { padding: 12px 8px 40px; }
    .exp-title { font-size: 16px; margin-left: 6px; }
    /* the control row is 6 buttons; let it scroll sideways in one line
       instead of wrapping into three stacked rows */
    .exp-ranges {
        flex-wrap: nowrap; overflow-x: auto; gap: 5px;
        padding-bottom: 4px; -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
    }
    .exp-ranges::-webkit-scrollbar { display: none; }
    .exp-ranges > * { flex: 0 0 auto; }
    .exp-range { padding: 5px 9px; font-size: 11.5px; }
    .exp-chip { padding: 5px 11px; font-size: 12.5px; }
    .exp-tiles { grid-template-columns: repeat(2, 1fr); }
    .exp-tile-v { font-size: 18px; }
    .exp-cat { vertical-align: 2px; }
    .exp-lede { font-size: 13px; }
    .exp-cite, .exp-note { font-size: 12px; padding: 9px 10px; }
    .exp-verif-note { font-size: 11.5px; }
}
