:root {
    --bg-primary: #0a0e1a;
    --bg-secondary: #111827;
    --bg-card: #1a2235;
    --bg-card-hover: #1f2a40;
    --accent: #f59e0b;
    --accent-glow: rgba(245, 158, 11, 0.15);
    --green: #10b981;
    --red: #ef4444;
    --blue: #3b82f6;
    --purple: #8b5cf6;
    --cyan: #06b6d4;
    --text-primary: #f1f5f9;
    --text-secondary: #94a3b8;
    --text-muted: #64748b;
    --border: #1e293b;

    /* Mobile foundation — iOS safe areas (notch/home bar) and bottom tab bar height.
       env(safe-area-inset-*) values resolve to 0px on non-notched devices. */
    --safe-top: env(safe-area-inset-top, 0px);
    --safe-bottom: env(safe-area-inset-bottom, 0px);
    --safe-left: env(safe-area-inset-left, 0px);
    --safe-right: env(safe-area-inset-right, 0px);
    --mobile-tab-height: 64px;
    --mobile-breakpoint: 768px;
}

* { margin: 0; padding: 0; box-sizing: border-box; }
body {
    font-family: system-ui, -apple-system, sans-serif;
    background: var(--bg-primary);
    color: var(--text-primary);
    min-height: 100vh;
    /* Prevent iOS rubber-band overscroll from revealing white behind PWA shell */
    overscroll-behavior-y: none;
    -webkit-tap-highlight-color: transparent;
}

/* ─── Mobile visibility helpers ────────────────────────────────────────
   Used by Phase 2+ to toggle between mobile and desktop nav / drawer UIs
   without inline-style media query hacks. */
.mobile-only { display: none; }
.desktop-only { display: initial; }

@media (max-width: 768px) {
    .mobile-only { display: initial; }
    .desktop-only { display: none !important; }
    /* Reserve space at the bottom for the incoming bottom tab bar (Phase 2).
       Using scroll-padding-bottom so anchor scrolling respects the tab bar too. */
    body { scroll-padding-bottom: calc(var(--mobile-tab-height) + var(--safe-bottom)); }
}

/* v=108: padding-top now respects --safe-top so iOS PWA mode pushes the
   main app's top panel BELOW the status bar (clock/wifi/battery row).
   Desktop browsers + Android Chrome get --safe-top = 0px, so no behavior
   change there. Same calc pattern repeats in the 640px + 420px mobile
   breakpoints below. */
.container { max-width: 1400px; margin: 0 auto; padding: calc(var(--safe-top) + 20px) 20px 20px 20px; }

/* Header */
.header {
    text-align: center;
    padding: 30px 20px 0;
    position: relative;
}
.logo { margin-bottom: 4px; }
.logo img { height: 110px; width: auto; }
.title {
    font-size: 2rem;
    font-weight: 900;
    background: linear-gradient(135deg, var(--accent), #fbbf24, #f59e0b);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    letter-spacing: -0.5px;
}
.subtitle {
    color: var(--text-secondary);
    font-size: 0.95rem;
    margin-top: 8px;
}

/* Stats bar */
.stats-bar {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 32px;
    padding: 18px 24px;
    margin: 12px 0 24px;
    background: var(--bg-secondary);
    border-radius: 12px;
    border: 1px solid var(--border);
    position: relative;
}
.stats-summary {
    display: flex;
    gap: 28px;
    align-items: center;
    justify-content: center;
}
.vegas-btn {
    background: rgba(16, 185, 129, 0.12);
    border: 1px solid rgba(16, 185, 129, 0.3);
    border-radius: 10px;
    padding: 8px 14px;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 6px;
    color: var(--green);
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    transition: all 0.2s;
}
.vegas-btn:hover {
    background: rgba(16, 185, 129, 0.22);
    border-color: rgba(16, 185, 129, 0.5);
}
.vegas-btn svg {
    width: 16px;
    height: 16px;
}

/* What is Blast Score link */
.blast-info-link {
    position: absolute;
    left: 16px;
    top: 50%;
    transform: translateY(-50%);
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 0.7rem;
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 2px;
    font-family: system-ui, -apple-system, sans-serif;
    transition: color 0.2s;
}
.blast-info-link:hover { color: var(--accent); }

/* Tooltip styles */
.tooltip-wrapper {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.tooltip-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.08);
    color: var(--text-muted);
    font-size: 0.55rem;
    font-weight: 700;
    cursor: help;
    flex-shrink: 0;
}
.tooltip-bubble {
    position: absolute;
    bottom: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%);
    background: #1e293b;
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 8px;
    padding: 8px 12px;
    font-size: 0.72rem;
    color: var(--text-secondary);
    white-space: normal;
    width: 220px;
    z-index: 50;
    box-shadow: 0 4px 20px rgba(0,0,0,0.4);
    line-height: 1.4;
    pointer-events: none;
}
.tooltip-bubble::after {
    content: '';
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    border: 5px solid transparent;
    border-top-color: #1e293b;
}

/* Vegas Slide-out Drawer */
.vegas-drawer-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    backdrop-filter: blur(2px);
    z-index: 999;
    transition: opacity 0.3s ease;
}
.vegas-drawer {
    position: fixed;
    top: 0;
    right: 0;
    width: 480px;
    height: 100%;
    background: var(--bg-card);
    border-left: 1px solid var(--border);
    z-index: 1000;
    transform: translateX(100%);
    transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    display: flex;
    flex-direction: column;
    box-shadow: -8px 0 30px rgba(0, 0, 0, 0.4);
}
.vegas-drawer.open {
    transform: translateX(0);
}
.vegas-drawer-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 20px 20px 16px;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
}
.vegas-drawer-title {
    font-size: 1rem;
    font-weight: 700;
    color: var(--green);
    display: flex;
    align-items: center;
    gap: 8px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
.vegas-drawer-close {
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 1.5rem;
    cursor: pointer;
    padding: 4px 8px;
    border-radius: 6px;
    line-height: 1;
}
.vegas-drawer-close:hover {
    background: var(--bg-secondary);
    color: var(--text-primary);
}
.vegas-drawer-body {
    flex: 1;
    overflow-y: auto;
    padding: 12px 20px;
}
/* Right-edge tab handles */
.right-tabs {
    position: fixed;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    z-index: 998;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.right-tabs button {
    writing-mode: vertical-rl;
    border-right: none;
    border-radius: 10px 0 0 10px;
    padding: 14px 8px;
    cursor: pointer;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1px;
    transition: all 0.2s;
    display: flex;
    align-items: center;
    gap: 6px;
}
.vegas-tab {
    background: rgba(16, 185, 129, 0.15);
    border: 1px solid rgba(16, 185, 129, 0.3);
    color: var(--green);
}
.vegas-tab:hover {
    background: rgba(16, 185, 129, 0.25);
    padding-right: 12px;
}

/* Blast Score Slide-out Drawer (left side) */
.blast-drawer {
    position: fixed;
    top: 0;
    right: 0;
    width: 520px;
    height: 100%;
    background: var(--bg-card);
    border-left: 1px solid var(--border);
    z-index: 1000;
    transform: translateX(100%);
    transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    display: flex;
    flex-direction: column;
    box-shadow: -8px 0 30px rgba(0, 0, 0, 0.4);
}
.blast-drawer.open {
    transform: translateX(0);
}
.blast-drawer-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 20px 20px 16px;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
}
.blast-drawer-title {
    font-size: 1rem;
    font-weight: 700;
    color: var(--accent);
    display: flex;
    align-items: center;
    gap: 8px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
.blast-drawer-close {
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 1.5rem;
    cursor: pointer;
    padding: 4px 8px;
    border-radius: 6px;
    line-height: 1;
}
.blast-drawer-close:hover {
    background: var(--bg-secondary);
    color: var(--text-primary);
}
.blast-drawer-body {
    flex: 1;
    overflow-y: auto;
    padding: 20px;
}
.blast-tab {
    background: rgba(245, 158, 11, 0.12);
    border: 1px solid rgba(245, 158, 11, 0.3);
    color: var(--accent);
}
.blast-tab:hover {
    background: rgba(245, 158, 11, 0.22);
    padding-right: 12px;
}

/* Track Record Drawer */
.record-drawer {
    position: fixed;
    top: 0;
    right: 0;
    width: 480px;
    height: 100%;
    background: var(--bg-card);
    border-left: 1px solid var(--border);
    z-index: 1000;
    transform: translateX(100%);
    transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    display: flex;
    flex-direction: column;
    box-shadow: -8px 0 30px rgba(0, 0, 0, 0.4);
}
.record-drawer.open { transform: translateX(0); }
.record-drawer-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 20px 20px 16px;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
}
.record-drawer-title {
    font-size: 1rem;
    font-weight: 700;
    color: #818cf8;
    display: flex;
    align-items: center;
    gap: 8px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
.record-drawer-close {
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 1.5rem;
    cursor: pointer;
    padding: 4px 8px;
    border-radius: 6px;
    line-height: 1;
}
.record-drawer-close:hover {
    background: var(--bg-secondary);
    color: var(--text-primary);
}
.record-drawer-body {
    flex: 1;
    overflow-y: auto;
    padding: 20px;
}
.record-tab {
    background: rgba(129, 140, 248, 0.12);
    border: 1px solid rgba(129, 140, 248, 0.3);
    color: #818cf8;
}
.record-tab:hover {
    background: rgba(129, 140, 248, 0.22);
    padding-right: 12px;
}
.record-stat-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 12px;
    margin-bottom: 20px;
}
.record-stat-card {
    background: var(--bg-secondary);
    border-radius: 10px;
    padding: 16px;
    text-align: center;
}
.record-stat-value {
    font-size: 1.6rem;
    font-weight: 800;
    color: #818cf8;
    line-height: 1.2;
}
.record-stat-label {
    font-size: 0.7rem;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-top: 4px;
}
.record-day-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px 12px;
    border-radius: 8px;
    margin-bottom: 6px;
    background: var(--bg-secondary);
    cursor: pointer;
    transition: background 0.15s;
}
.record-day-row:hover { background: rgba(129, 140, 248, 0.1); }
.record-day-date { font-weight: 600; font-size: 0.85rem; color: var(--text-primary); }
.record-day-stats { display: flex; gap: 12px; align-items: center; font-size: 0.8rem; }
.record-day-hits { color: #818cf8; font-weight: 700; }
.record-day-rate { color: var(--text-muted); }
.record-hit-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    border-radius: 8px;
    margin-bottom: 6px;
    background: var(--bg-secondary);
}
.record-hit-name { font-weight: 600; color: var(--text-primary); font-size: 0.85rem; }
.record-hit-date { color: var(--text-muted); font-size: 0.75rem; }
.record-hit-hr { color: var(--accent); font-weight: 700; font-size: 0.85rem; }
.record-section-title {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: var(--text-muted);
    margin-bottom: 10px;
    margin-top: 20px;
    font-weight: 600;
}
.record-verify-btn {
    background: rgba(129, 140, 248, 0.15);
    border: 1px solid rgba(129, 140, 248, 0.3);
    color: #818cf8;
    font-size: 0.75rem;
    font-weight: 600;
    padding: 6px 14px;
    border-radius: 6px;
    cursor: pointer;
    transition: all 0.15s;
}
.record-verify-btn:hover { background: rgba(129, 140, 248, 0.25); }
.record-empty {
    text-align: center;
    color: var(--text-muted);
    padding: 40px 20px;
    font-size: 0.9rem;
}

/* General Modal (kept for any future modals) */
.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.7);
    backdrop-filter: blur(4px);
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
}
.modal {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 16px;
    width: 100%;
    max-width: 500px;
    max-height: 80vh;
    overflow-y: auto;
    padding: 24px;
}
.modal-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20px;
}
.modal-title {
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--purple);
}
.modal-close {
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 1.5rem;
    cursor: pointer;
    padding: 4px 8px;
    border-radius: 6px;
    line-height: 1;
}
.modal-close:hover {
    background: var(--bg-secondary);
    color: var(--text-primary);
}
.vegas-game-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.05);
    font-size: 0.85rem;
}
.vegas-game-row:last-child { border-bottom: none; }
.vegas-time {
    width: 60px;
    color: var(--text-muted);
    font-size: 0.75rem;
    flex-shrink: 0;
}
.vegas-team {
    flex: 1;
    font-weight: 600;
}
.vegas-ml {
    width: 50px;
    text-align: right;
    font-weight: 700;
}
.vegas-at {
    color: var(--text-muted);
    padding: 0 2px;
}
.vegas-ou {
    width: 55px;
    text-align: right;
    color: var(--purple);
    font-weight: 600;
    font-size: 0.8rem;
}
.stat-item { text-align: center; }
.stat-value {
    font-size: 1.75rem;
    font-weight: 800;
    color: var(--accent);
}
.stat-label {
    font-size: 0.7rem;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 1px;
    margin-top: 2px;
}

/* Controls */
.controls {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20px;
    flex-wrap: wrap;
    gap: 12px;
}
.controls-left { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.controls-right {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 6px;
}

.date-input {
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    color: var(--text-primary);
    padding: 8px 14px;
    border-radius: 8px;
    font-family: system-ui, -apple-system, sans-serif;
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
}
.date-input::-webkit-calendar-picker-indicator { filter: invert(0.7); cursor: pointer; }

/* View toggle */
.view-toggle {
    display: flex;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 6px;
    overflow: hidden;
}
.view-btn {
    padding: 5px 10px;
    background: transparent;
    border: none;
    color: var(--text-muted);
    font-family: system-ui, -apple-system, sans-serif;
    font-size: 0.75rem;
    cursor: pointer;
    transition: all 0.2s;
    display: flex;
    align-items: center;
    gap: 3px;
}
.view-btn:hover { color: var(--text-secondary); }
.view-btn.active {
    background: rgba(241, 245, 249, 0.12);
    color: var(--text-primary);
}

.refresh-btn {
    background: linear-gradient(135deg, var(--accent), #d97706);
    color: #000;
    border: none;
    padding: 10px 24px;
    border-radius: 8px;
    font-weight: 700;
    font-size: 0.9rem;
    cursor: pointer;
    transition: all 0.2s;
    font-family: system-ui, -apple-system, sans-serif;
}
.refresh-btn:hover { transform: translateY(-1px); box-shadow: 0 4px 20px var(--accent-glow); }
.refresh-btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }

/* Phase 8d — admin variant. Subtle ring to remind Joe his click triggers
   a real scan (API spend) vs. a non-admin click which only re-reads cache.
   Same color as the button so it doesn't shout, just adds visual weight. */
.refresh-btn-admin {
    box-shadow: 0 0 0 2px rgba(245, 158, 11, 0.4);
}
.refresh-btn-admin:hover { box-shadow: 0 0 0 2px rgba(245, 158, 11, 0.55), 0 4px 20px var(--accent-glow); }

/* Quick date nav */
.date-nav {
    display: flex;
    gap: 6px;
    align-items: center;
}
.date-nav-btn {
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    color: var(--text-secondary);
    padding: 6px 10px;
    border-radius: 6px;
    font-family: system-ui, -apple-system, sans-serif;
    font-size: 0.8rem;
    cursor: pointer;
    transition: all 0.2s;
}
.date-nav-btn:hover { border-color: var(--accent); color: var(--accent); }

/* Filter bar */
.filter-bar {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 14px;
    flex-wrap: wrap;
}
.filter-label {
    font-size: 0.7rem;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    font-weight: 600;
    margin-right: 2px;
}
.filter-chip {
    padding: 5px 12px;
    border-radius: 20px;
    font-size: 0.72rem;
    font-weight: 600;
    cursor: pointer;
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text-secondary);
    font-family: system-ui, -apple-system, sans-serif;
    transition: all 0.2s;
}
.filter-chip:hover {
    border-color: var(--accent);
    color: var(--accent);
}
.filter-chip.active {
    background: rgba(245, 158, 11, 0.15);
    border-color: var(--accent);
    color: var(--accent);
}
.filter-divider {
    width: 1px;
    height: 18px;
    background: var(--border);
    margin: 0 4px;
}
.filter-actions {
    margin-left: auto;
    display: flex;
    align-items: center;
}

/* Pick Cards — List View */
.picks-list { display: flex; flex-direction: column; gap: 12px; }

/* Pick Cards — Grid View */
.picks-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    align-items: start;
    gap: 12px;
}

.pick-card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 20px;
    transition: all 0.2s;
    position: relative;
    overflow: visible;
    margin-bottom: 24px;
}
.pick-card:hover {
    background: var(--bg-card-hover);
    border-color: rgba(99, 102, 241, 0.3);
}
/* Final/completed game card */
.pick-card.game-final {
    opacity: 0.45;
    filter: grayscale(40%);
}
.pick-card.game-final:hover {
    opacity: 0.65;
    border-color: var(--border);
    box-shadow: none;
}
/* Postponed game card */
.pick-card.game-postponed {
    opacity: 0.35;
    filter: grayscale(60%);
}
/* Live game indicator — minimal dot + text */
.badge-live {
    background: none;
    border: none;
    padding: 0;
    color: #ef4444;
    font-size: 0.65rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin-top: 2px;
}
.badge-live::before {
    content: '';
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: #ef4444;
    animation: liveDot 1.5s ease-in-out infinite;
}
@keyframes liveDot {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.4; transform: scale(0.8); }
}
.badge-final {
    background: rgba(100, 116, 139, 0.2);
    color: var(--text-muted);
    border: 1px solid rgba(100, 116, 139, 0.3);
    border-radius: 6px;
    padding: 2px 8px;
    font-size: 0.65rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
.badge-postponed {
    background: rgba(239, 68, 68, 0.1);
    color: var(--red);
    border: 1px solid rgba(239, 68, 68, 0.25);
    border-radius: 6px;
    padding: 2px 8px;
    font-size: 0.65rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
/* Background refresh bar */
.bg-refresh-bar {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 3px;
    z-index: 1001;
    overflow: hidden;
}
.bg-refresh-bar::after {
    content: '';
    position: absolute;
    top: 0;
    left: -40%;
    width: 40%;
    height: 100%;
    background: linear-gradient(90deg, transparent, var(--accent), transparent);
    animation: bgRefreshSlide 1.5s ease-in-out infinite;
}
@keyframes bgRefreshSlide {
    0% { left: -40%; }
    100% { left: 100%; }
}

/* v=126 — Unified horizontal corner banner. Replaces the diagonal
   .pick-ribbon + .signal-ribbon corner-banners (v=124/v=125) which
   forced asymmetric content padding to avoid overlapping the rotated
   text. New pattern: a small flush pill anchored to the card's
   top-left corner, sized to its text. The card just needs extra
   top padding to clear the banner's height (~26px). Joe's design
   call: "flush, gradient, fit content."

   Modifiers:
     .card-ribbon-top-pick   — green gradient (PickCard)
     .card-ribbon-rlm-alert  — red gradient (SignalCard)
     .compact                — 10px outer corner-radius to match
                               SignalCard's borderRadius:10 (PickCard
                               cards are 12px so default works for them).
*/
.card-ribbon {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 2;
    pointer-events: none;
    padding: 5px 12px;
    font-size: 0.62rem;
    font-weight: 800;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: #fff;
    line-height: 1.2;
    border-radius: 12px 0 8px 0;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
    border-bottom: 1px solid rgba(0, 0, 0, 0.18);
}
.card-ribbon.compact {
    border-radius: 10px 0 8px 0;
}
.card-ribbon-top-pick {
    background: linear-gradient(135deg, var(--green) 0%, #059669 100%);
}
.card-ribbon-rlm-alert {
    background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
}

/* v=126 — When a PickCard carries the Top Pick ribbon, push the
   first row of content down so it doesn't slide under the banner.
   Native padding is 20px; banner is ~26px tall. */
.pick-card.has-ribbon {
    padding-top: 38px;
}

/* Grid card adjustments */
.picks-grid .pick-header {
    flex-direction: column;
    align-items: stretch;
}
.picks-grid .pick-header > div:first-child {
    flex-direction: row;
    align-self: flex-start;
    width: auto !important;
}
.picks-grid .pick-batter { font-size: 1.05rem; }
.picks-grid .pick-score {
    align-self: flex-end;
}
.picks-grid .pick-score .blast-number {
    font-size: 1.5rem;
}
.picks-grid .pick-analysis {
    margin-top: 8px;
}
.picks-grid .pick-matchup { font-size: 0.8rem; gap: 6px 12px; }
.picks-grid .pick-details { flex-wrap: wrap; }
.picks-grid .pick-details .detail-group { min-width: 150px; flex: 1 1 45%; }

/* Player headshot */
.pick-headshot {
    width: 80px;
    height: 80px;
    border-radius: 50%;
    overflow: hidden;
    flex-shrink: 0;
    background: var(--bg-secondary);
    border: 2px solid var(--border);
}
.pick-headshot img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center 25%;
}

/* Wind diamond */
.wind-diamond {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
}
.wind-diamond-label {
    font-size: 0.7rem;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.pick-rank {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 8px;
    font-weight: 800;
    font-size: 0.85rem;
    margin-right: 12px;
    flex-shrink: 0;
}
.rank-1 { background: linear-gradient(135deg, #f59e0b, #d97706); color: #000; }
.rank-2 { background: linear-gradient(135deg, #94a3b8, #64748b); color: #000; }
.rank-3 { background: linear-gradient(135deg, #b45309, #92400e); color: #fff; }
.rank-default { background: var(--bg-secondary); color: var(--text-secondary); }

.pick-header {
    display: flex;
    align-items: stretch;
    gap: 12px;
    padding-top: 6px;
}
.pick-batter {
    font-size: 1.2rem;
    font-weight: 700;
    flex: 1;
}
.pick-score {
    min-width: 70px;
    text-align: center;
    padding: 10px 14px;
    border-radius: 10px;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1px;
}
.pick-score .blast-label {
    font-size: 0.55rem;
    font-weight: 700;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    color: var(--text-muted);
}
.pick-score .blast-number {
    font-size: 1.8rem;
    font-weight: 900;
    line-height: 1;
}
.score-high { color: var(--green); }
.score-high .blast-label { color: rgba(16, 185, 129, 0.5); }
.score-med { color: var(--blue); }
.score-med .blast-label { color: rgba(59, 130, 246, 0.5); }
.score-low { color: var(--text-muted); }
.score-low .blast-label { color: rgba(100, 116, 139, 0.5); }

.pick-matchup {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 20px;
    margin-bottom: 12px;
    font-size: 0.85rem;
    color: var(--text-secondary);
}
.matchup-item { display: flex; align-items: center; gap: 4px; }
.matchup-label { color: var(--text-muted); }

/* Vegas odds display */
.odds-row {
    display: flex;
    align-items: center;
    gap: 16px;
    margin-top: 10px;
    padding: 8px 12px;
    background: rgba(139, 92, 246, 0.08);
    border: 1px solid rgba(139, 92, 246, 0.2);
    border-radius: 8px;
    font-size: 0.82rem;
    flex-wrap: wrap;
}
.odds-label {
    color: var(--purple);
    font-weight: 700;
    text-transform: uppercase;
    font-size: 0.7rem;
    letter-spacing: 0.5px;
}
.odds-book-group {
    display: flex;
    align-items: center;
    gap: 6px;
}
.odds-book-name {
    color: var(--text-muted);
    font-size: 0.75rem;
    font-weight: 600;
    min-width: 28px;
}
.odds-value {
    font-weight: 700;
    color: var(--text-primary);
}
.odds-positive { color: var(--green); }
.odds-divider {
    width: 1px;
    height: 16px;
    background: var(--border);
}

/* AI analysis */
.pick-analysis {
    flex: 1;
    font-size: 0.82rem;
    color: #b0b8c4;
    line-height: 1.4;
    padding: 10px 14px;
    background: rgba(255, 255, 255, 0.04);
    border-radius: 8px;
}

/* Expanded details — smooth slide animation */
.pick-details-wrapper {
    overflow: hidden;
    transition: max-height 0.35s ease, opacity 0.3s ease;
}
.pick-details-wrapper.collapsed {
    max-height: 0;
    opacity: 0;
}
.pick-details-wrapper.expanded {
    max-height: 800px;
    opacity: 1;
}
.pick-details {
    margin-top: 16px;
    padding-top: 16px;
    border-top: 1px solid var(--border);
    display: flex;
    gap: 12px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none; /* Firefox */
    padding-bottom: 4px;
}
.pick-details::-webkit-scrollbar {
    display: none; /* Chrome/Safari */
}
.pick-details .detail-group {
    flex: 1 1 200px;
    min-width: 200px;
    scroll-snap-align: start;
}
/* Carousel wrapper with nav arrows */
.pick-details-carousel {
    position: relative;
}
.carousel-nav {
    display: flex;
    justify-content: center;
    gap: 16px;
    margin-top: 10px;
}
.carousel-nav .carousel-arrow {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.1);
    color: var(--text-secondary);
    font-size: 0.65rem;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: opacity 0.2s, background 0.2s, color 0.2s;
}
.carousel-nav .carousel-arrow:hover:not(.disabled) {
    background: rgba(255, 255, 255, 0.12);
    color: var(--text-primary);
}
.carousel-nav .carousel-arrow.disabled {
    opacity: 0.25;
    cursor: default;
}
/* Fade hint on right edge */
.pick-details-carousel::after {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    width: 40px;
    height: calc(100% - 48px);
    background: linear-gradient(to right, transparent, var(--card-bg));
    pointer-events: none;
    border-radius: 0 8px 8px 0;
    opacity: var(--carousel-fade, 1);
    transition: opacity 0.2s;
}
.detail-group {
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(255, 255, 255, 0.05);
    border-radius: 10px;
    padding: 14px 16px;
}
.detail-group h4 {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: #8b95a5;
    margin-bottom: 10px;
}
.detail-row {
    display: flex;
    justify-content: space-between;
    padding: 3px 0;
    font-size: 0.85rem;
}
.detail-label { color: var(--text-muted); }
.detail-value { font-weight: 600; }

/* Loading */
.loading {
    text-align: center;
    padding: 60px;
    color: var(--text-secondary);
}
.loading-bars {
    display: flex;
    align-items: flex-end;
    justify-content: center;
    gap: 6px;
    height: 64px;
    margin-bottom: 28px;
}
.loading-bars .bar {
    width: 8px;
    border-radius: 4px;
    background: var(--accent);
    animation: bar-bounce 1.2s ease-in-out infinite;
}
.loading-bars .bar:nth-child(1) { height: 18px; animation-delay: 0s; }
.loading-bars .bar:nth-child(2) { height: 30px; animation-delay: 0.1s; }
.loading-bars .bar:nth-child(3) { height: 50px; animation-delay: 0.2s; }
.loading-bars .bar:nth-child(4) { height: 38px; animation-delay: 0.3s; }
.loading-bars .bar:nth-child(5) { height: 24px; animation-delay: 0.4s; }
.loading-bars .bar:nth-child(6) { height: 44px; animation-delay: 0.5s; }
.loading-bars .bar:nth-child(7) { height: 28px; animation-delay: 0.6s; }
@keyframes bar-bounce {
    0%, 100% { transform: scaleY(0.4); opacity: 0.4; }
    50% { transform: scaleY(1); opacity: 1; }
}
.loading-status {
    font-size: 0.9rem;
    color: var(--text-muted);
    height: 24px;
    position: relative;
    overflow: hidden;
}
.loading-status span {
    animation: status-fade 3s ease-in-out infinite;
}
/* Phase 5.5.9 — final-message variant. Single fade-in (no infinite
   pulse) so the last message just sits visible once it lands. The
   cross-fade pulse is intentional during cycling because it
   coordinates with the next message swap; once cycling stops, the
   pulse becomes nervous flicker on the same static text. */
.loading-status span.is-final {
    animation: status-fade-in 0.45s ease-out forwards;
}
@keyframes status-fade {
    0% { opacity: 0; }
    15% { opacity: 1; }
    85% { opacity: 1; }
    100% { opacity: 0; }
}
@keyframes status-fade-in {
    0% { opacity: 0; }
    100% { opacity: 1; }
}
/* Large loading variant */
.loading-large {
    padding: 80px 20px;
}
.loading-bars-large {
    height: 100px !important;
    gap: 10px !important;
    margin-bottom: 28px !important;
}
.loading-bars-large .bar {
    width: 12px !important;
    border-radius: 6px !important;
}
.loading-bars-large .bar:nth-child(1) { height: 28px !important; }
.loading-bars-large .bar:nth-child(2) { height: 48px !important; }
.loading-bars-large .bar:nth-child(3) { height: 80px !important; }
.loading-bars-large .bar:nth-child(4) { height: 60px !important; }
.loading-bars-large .bar:nth-child(5) { height: 38px !important; }
.loading-bars-large .bar:nth-child(6) { height: 70px !important; }
.loading-bars-large .bar:nth-child(7) { height: 44px !important; }
.spinner {
    width: 40px;
    height: 40px;
    border: 3px solid var(--border);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
    margin: 0 auto 16px;
}
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes pulse-dot { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }

/* Error */
.error {
    text-align: center;
    padding: 40px;
    color: var(--red);
    background: rgba(239, 68, 68, 0.1);
    border: 1px solid rgba(239, 68, 68, 0.2);
    border-radius: 12px;
}

/* No games */
.no-games {
    text-align: center;
    padding: 60px;
    color: var(--text-muted);
}
.no-games-icon { font-size: 3rem; margin-bottom: 12px; }

/* Badge */
.badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 3px 8px;
    border-radius: 4px;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    line-height: 1;
}
.badge-platoon { background: rgba(245, 158, 11, 0.15); color: var(--accent); }
/* v=148 — .badge-dome rule removed. The dome badge was retired from
   PickCard in Phase 5.5.6 (WindDiamond's zero-wind read conveys dome
   character in-context); v=148 also removes the orphan legend entry
   in Dashboard.jsx, leaving no consumer for this rule. */
.badge-hot { background: rgba(239, 68, 68, 0.15); color: var(--red); }
.badge-park { background: rgba(16, 185, 129, 0.15); color: var(--green); }
.badge-odds { background: rgba(139, 92, 246, 0.15); color: var(--purple); }
/* Phase 5.5 — BEST HR/9 badge. Stamped on Blast Score pick cards when
   the opposing pitcher is in today's top 3 by HR/9 (with a floor of
   HR/9 > 1.10). Purple-magenta tint to feel premium and stand out from
   the existing badges without screaming. The 🎯 emoji ties the badge
   visually to the "targeting" semantic. */
.badge-best-hr9 {
    background: rgba(168, 85, 247, 0.18);
    color: #c084fc;
    border: 1px solid rgba(168, 85, 247, 0.35);
}

/* Login screen */
.login-screen {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    padding: 20px;
}
.login-card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 16px;
    padding: 40px;
    max-width: 400px;
    width: 100%;
    text-align: center;
}
.login-card .logo { margin-bottom: 8px; }
.login-card .logo img { width: 120px; }
.login-card .title { font-size: 1.5rem; margin-bottom: 8px; }
.login-card .subtitle { margin-bottom: 28px; }

.login-input {
    width: 100%;
    padding: 12px 16px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 8px;
    color: var(--text-primary);
    font-family: system-ui, -apple-system, sans-serif;
    font-size: 1rem;
    outline: none;
    transition: border-color 0.2s;
}
.login-input:focus { border-color: var(--accent); }
.login-input::placeholder { color: var(--text-muted); }

.login-btn {
    width: 100%;
    padding: 12px;
    background: linear-gradient(135deg, var(--accent), #d97706);
    color: #000;
    border: none;
    border-radius: 8px;
    font-family: system-ui, -apple-system, sans-serif;
    font-weight: 700;
    font-size: 1rem;
    cursor: pointer;
    margin-top: 12px;
    transition: all 0.2s;
}
.login-btn:hover { transform: translateY(-1px); box-shadow: 0 4px 20px var(--accent-glow); }
.login-btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }

.login-message {
    font-size: 0.85rem;
    margin-top: 12px;
    padding: 8px 12px;
    border-radius: 6px;
}
.login-message.info { color: var(--cyan); background: rgba(6, 182, 212, 0.1); }
.login-message.error { color: var(--red); background: rgba(239, 68, 68, 0.1); }

.otp-input {
    width: 100%;
    padding: 16px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 8px;
    color: var(--accent);
    font-family: monospace;
    font-size: 2rem;
    font-weight: 900;
    letter-spacing: 12px;
    text-align: center;
    outline: none;
    transition: border-color 0.2s;
}
.otp-input:focus { border-color: var(--accent); }
.otp-input::placeholder { letter-spacing: 4px; font-size: 1rem; color: var(--text-muted); }

.login-back {
    background: none;
    border: none;
    color: var(--text-muted);
    font-family: system-ui, -apple-system, sans-serif;
    font-size: 0.85rem;
    cursor: pointer;
    margin-top: 16px;
}
.login-back:hover { color: var(--text-secondary); }

/* User icon (top-right). Phase 5: relocated from bottom-left to a more
   conventional top-right position. Used as the trigger for the
   AccountDashboard modal — no dropdown anymore (the dashboard owns
   the menu surface). Hidden on mobile via @media (max-width: 768px);
   mobile users open the dashboard from the MORE bottom sheet. */
.user-icon-btn {
    position: fixed;
    top: 16px;
    right: 16px;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--bg-card);
    border: 1px solid var(--border);
    color: var(--text-secondary);
    font-size: 1.1rem;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.2s;
    z-index: 100;
}
.user-icon-btn:hover { border-color: var(--accent); color: var(--accent); }
/* Legacy .user-menu / .user-menu-* dropdown rules retired in Phase 5
   along with the UserMenu component itself. The Account dashboard
   replaces them — see .account-* below. */

/* Admin panel */
.admin-panel {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 20px;
    margin-bottom: 20px;
}
.admin-panel h3 {
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: var(--accent);
    margin-bottom: 12px;
}
.admin-user-list {
    list-style: none;
    margin-bottom: 12px;
}
.admin-user-list li {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 6px 0;
    font-size: 0.85rem;
    color: var(--text-secondary);
    border-bottom: 1px solid var(--border);
}
.admin-user-list li:last-child { border-bottom: none; }
.admin-invite-row {
    display: flex;
    gap: 8px;
}
.admin-invite-row input {
    flex: 1;
    padding: 8px 12px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text-primary);
    font-family: system-ui, -apple-system, sans-serif;
    font-size: 0.85rem;
}
.admin-invite-row button {
    padding: 8px 16px;
    background: var(--accent);
    border: none;
    border-radius: 6px;
    color: #000;
    font-family: system-ui, -apple-system, sans-serif;
    font-weight: 700;
    font-size: 0.85rem;
    cursor: pointer;
}
.admin-remove-btn {
    background: none;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    font-size: 0.8rem;
}
.admin-remove-btn:hover { color: var(--red); }

/* Footer */
.footer {
    text-align: center;
    padding: 30px;
    color: var(--text-muted);
    font-size: 0.8rem;
    border-top: 1px solid var(--border);
    margin-top: 40px;
}

/* ─── Tab Bar (desktop top nav) ──────────────────────────────────────────
   Used in Dashboard at the top of the page. Mobile uses .bottom-tab-bar
   instead (see below). Visibility is handled by media queries. */
.tab-bar {
    display: flex;
    justify-content: center;
    gap: 8px;
    margin-bottom: 2px;
}
.tab-btn {
    background: none;
    border: none;
    font-family: inherit;
    font-size: 0.88rem;
    font-weight: 500;
    color: var(--text-muted);
    cursor: pointer;
    padding: 6px 16px;
    border-bottom: 2px solid transparent;
    transition: color 0.2s, border-color 0.2s, font-weight 0.2s;
    letter-spacing: 0.3px;
    white-space: nowrap;
}
.tab-btn:hover { color: var(--text-secondary); }
.tab-btn.active {
    font-weight: 700;
    color: var(--accent);
    border-bottom-color: var(--accent);
}

/* ─── Bottom Tab Bar (mobile primary nav) ───────────────────────────────
   Fixed to the bottom of the viewport on mobile only. Uses backdrop-filter
   for a native iOS-style blurred translucent bar. Respects iOS safe-area
   inset so content clears the home indicator. */
.bottom-tab-bar { display: none; }

@media (max-width: 768px) {
    /* Hide desktop tab bar on mobile — bottom tab bar takes over */
    .tab-bar { display: none; }

    /* Hide floating bottom-left user icon on mobile — account actions
       have moved into the MORE bottom sheet (see .more-panel-user).
       The floating circle would otherwise sit behind the pill tab bar
       and be unreachable. Desktop keeps the circle as-is. */
    .user-icon-btn { display: none; }

    /* Show bottom tab bar on mobile — floating pill style.

       Why floating pill: iOS Safari paints a translucent dark gradient on
       the bottom ~40-50px of the webview whenever its URL chrome is in
       the expanded state. That gradient is Safari's OS UI layer (above our
       DOM), so no CSS on an edge-to-edge tab bar can stop it from dimming
       our labels. Floating the bar with margin on all sides lifts it out
       of the chrome overlay zone entirely, so the pill always sits on
       clean pixels — and it reads as an intentional iOS pattern
       (Instagram / Lyft / Apple Music style) rather than a bug workaround.

       max(var(--safe-bottom), 16px) keeps a floor of 16px on non-notch
       phones while respecting the larger safe-area inset on notch phones. */
    .bottom-tab-bar {
        display: flex;
        position: fixed;
        bottom: max(var(--safe-bottom), 16px);
        left: 12px;
        right: 12px;
        height: var(--mobile-tab-height);
        padding-bottom: 0;
        background: rgba(17, 24, 39, 0.95);
        backdrop-filter: blur(20px) saturate(180%);
        -webkit-backdrop-filter: blur(20px) saturate(180%);
        border: 1px solid var(--border);
        /* v=123 — was 22px, an arbitrary value not matching any other
           tier in the app. Joe spotted it as a visual outlier. 14px
           aligns with the panel-section tier already used by
           .account-section / .more-panel-section / .more-panel-account-row.
           At 64px tall, 14px corners are subtly rounded but still
           distinctly pill-ish. */
        border-radius: 14px;
        box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
        justify-content: space-around;
        align-items: stretch;
        z-index: 100;
    }
    .bottom-tab-btn {
        flex: 1;
        background: none;
        border: none;
        /* text-secondary (brighter gray) instead of text-muted for inactive
           tabs so labels stay readable against the tab-bar background. */
        color: var(--text-secondary);
        cursor: pointer;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 3px;
        padding: 8px 4px;
        font-family: inherit;
        min-height: var(--mobile-tab-height);
        transition: color 0.15s, transform 0.08s;
    }
    .bottom-tab-btn:active { transform: scale(0.92); }
    .bottom-tab-btn.active { color: var(--accent); }
    .bottom-tab-icon {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 24px;
        height: 24px;
    }
    .bottom-tab-icon svg { width: 22px; height: 22px; }
    .bottom-tab-label {
        font-size: 0.64rem;
        font-weight: 600;
        letter-spacing: 0.3px;
        text-transform: uppercase;
    }

    /* Reserve space at the bottom so content doesn't hide behind the
       floating tab bar. Geometry: tab height + bottom offset (16px or
       safe-area) + breathing room (16px). */
    .container {
        padding-bottom: calc(var(--mobile-tab-height) + max(var(--safe-bottom), 16px) + 16px);
    }

    /* Push the right-edge drawer tabs above the floating bottom tab bar */
    .right-tabs {
        top: auto;
        bottom: calc(var(--mobile-tab-height) + max(var(--safe-bottom), 16px) + 16px);
        transform: none;
    }
}

@media (max-width: 768px) {
    .picks-grid { grid-template-columns: 1fr; }
}

@media (max-width: 640px) {
    /* Use longhand for padding so we don't clobber the bottom-tab-bar
       clearance set in the 768px block above. v=108: padding-top includes
       --safe-top so iOS PWA pushes content below the status bar. */
    .container { padding-top: calc(var(--safe-top) + 12px); padding-left: 8px; padding-right: 8px; }
    .title { font-size: 1.5rem; }
    .stats-bar { gap: 16px; flex-wrap: wrap; }
    .stats-summary { gap: 16px; }
    .stat-item .stat-value { font-size: 1.1rem; }

    /* ── Phase 4b.5: mobile header stack ──────────────────────────────
       Desktop anchors the logo (absolute left) and refresh button
       (absolute right) around a centered stats-summary inside
       .stats-bar-row. At mobile widths, 225px logo + stats + refresh
       button all share one row and overlap badly (~155px of overlap
       on a 323px viewport).

       Fix: stack vertically on mobile.
       Row 1: Logo (shrunk to 160px, centered)
       Row 2: Stats summary (centered)
       Row 3: Refresh button (full width)

       Children carry inline position:absolute / transform styles from
       Dashboard.jsx — !important is required to reset them to normal
       flow. */
    .stats-bar-row {
        flex-direction: column !important;
        gap: 14px !important;
        align-items: stretch !important;
    }
    .stats-bar-row > a {
        position: static !important;
        transform: none !important;
        top: auto !important;
        left: auto !important;
        align-self: center !important;
    }
    .stats-bar-row > a img {
        width: 210px !important;
    }
    /* 2×2 grid instead of flex-wrap. At ~390px viewport, 4 stat items
       can't fit cleanly in one row; the flex-wrap leaves one orphaned
       stat on a second row. Grid gives a balanced 2×2 that reads as
       intentional across phone widths. */
    .stats-bar-row > .stats-summary {
        display: grid !important;
        grid-template-columns: 1fr 1fr;
        gap: 14px 24px;
        width: 100%;
        max-width: 320px;
        margin: 0 auto;
        justify-items: center;
    }
    /* Refresh button wrapper is the last direct-child <div>. */
    .stats-bar-row > div:last-child {
        position: static !important;
        transform: none !important;
        top: auto !important;
        right: auto !important;
        width: 100%;
    }
    .stats-bar-row > div:last-child .refresh-btn {
        width: 100%;
        padding: 12px 20px;
        font-size: 0.95rem;
    }
    .vegas-drawer { width: 100%; }
    .blast-drawer { width: 100%; }
    .record-drawer { width: 100%; }
    /* .right-tabs positioning handled by the 768px block above */

    /* ── Phase 4b: two-row mobile header for list-view PickCard ─────────
       Row 1: [headshot + player info block]  |  [Blast Score — pinned right]
       Row 2: conditions panel (full width)
       Row 3: analysis (full width)

       Flex-wrap alone isn't enough: without `order`, the score (DOM child
       4) sits on its own row because the conditions block (DOM child 2)
       has width:100% and steals Row 2 before the score can be placed.
       We use `order` to reshuffle flex placement — score jumps ahead of
       conditions so it joins the player block on Row 1.

       Grid view (.picks-grid .pick-header) uses flex-direction: column;
       the explicit grid reset below keeps items in DOM order there. */
    .pick-header { flex-wrap: wrap; gap: 10px; align-items: flex-start; }
    /* Player block: override the inline width:340 + flexShrink:0 from
       PickCard.jsx. max-width reserves ~110px of Row 1 for the score
       badge (score natural width ~98px + 10px flex gap + buffer) so the
       score stays pinned top-right instead of wrapping to a later row. */
    .pick-header > div:first-child {
        width: auto !important;
        flex: 1 1 auto !important;
        max-width: calc(100% - 110px);
        min-width: 0;
        gap: 10px !important;
    }
    /* Score: order 1 jumps it ahead of conditions so it lands on Row 1
       beside the player block. margin-left:auto pins it to the right. */
    .pick-header > .pick-score { order: 1; align-self: flex-start; margin-left: auto; }
    /* Conditions panel wrapper (2nd DOM child): order 2 pushes it to
       Row 2; width:100% claims the full row. */
    .pick-header > div:nth-child(2) { order: 2; width: 100% !important; }
    /* Analysis (when present): order 3 puts it on Row 3 below conditions. */
    .pick-header > .pick-analysis { order: 3; width: 100% !important; }
    /* Grid view reset: the order shuffling above breaks column stacking
       in grid cards. Pin everything to default order 0 and unwind the
       player block max-width + conditions width overrides so grid cards
       render naturally at mobile widths. */
    .picks-grid .pick-header > * { order: 0 !important; }
    .picks-grid .pick-header > div:first-child { max-width: none !important; }
    .picks-grid .pick-header > div:nth-child(2) { width: auto !important; }
    /* Trim the 80px desktop headshot for phone cards — 68px balances
       readability with card density (420 block drops it further to 44). */
    .pick-headshot { width: 68px; height: 68px; }
    .pick-headshot img { width: 68px; height: 68px; }
    .pick-batter { font-size: 1.05rem; line-height: 1.2; }
    .pick-analysis { font-size: 0.78rem; }
    .pick-card { padding: 14px 12px; }
    .controls { flex-direction: column; align-items: stretch; }
    .controls-left { flex-direction: column; }
    .filter-bar { flex-wrap: wrap; gap: 6px; }
    .filter-actions { width: 100%; justify-content: space-between; }
    .picks-grid { grid-template-columns: 1fr; }
    .pick-details { flex-direction: row !important; }
    .pick-details .detail-group { min-width: 180px; }
    .date-nav { justify-content: center; }
}

@media (max-width: 420px) {
    /* Longhand to preserve bottom-tab-bar clearance from 768px block.
       v=108: padding-top includes --safe-top for iOS PWA status bar. */
    .container { padding-top: calc(var(--safe-top) + 8px); padding-left: 4px; padding-right: 4px; }
    .pick-card { padding: 12px 10px; }
    .pick-batter { font-size: 0.95rem; }
    .pick-headshot { width: 44px; height: 44px; }
    .pick-headshot img { width: 44px; height: 44px; }
    .stats-summary { gap: 10px; }
    .stat-item .stat-value { font-size: 1rem; }
    .stat-item .stat-label { font-size: 0.6rem; }
    .modal { margin: 8px; max-width: calc(100vw - 16px) !important; }
}

/* ─── BottomSheet Primitive ─────────────────────────────────────────
   Shared mobile bottom-sheet styling used by MorePanel (and any future
   bottom-sheet consumers). The sheet itself animates in/out via JS-driven
   translateY; CSS only provides the resting appearance and transitions.
   ─────────────────────────────────────────────────────────────────── */
.bottom-sheet-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
    z-index: 1099;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.28s ease;
}
.bottom-sheet-backdrop.open {
    opacity: 1;
    pointer-events: auto;
}
.bottom-sheet {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1100;
    background: var(--bg-card);
    border-top: 1px solid var(--border);
    border-radius: 20px 20px 0 0;
    box-shadow: 0 -12px 40px rgba(0, 0, 0, 0.5);
    display: flex;
    flex-direction: column;
    padding-bottom: var(--safe-bottom);
    /* transform + transition set inline by the component; this is the
       starting position for any FOUC-ish paints. */
    transform: translateY(100%);
    will-change: transform;
}
.bottom-sheet-handle-area {
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 10px 0 6px;
    cursor: grab;
    touch-action: none;
}
.bottom-sheet-handle {
    width: 40px;
    height: 4px;
    border-radius: 2px;
    background: var(--border);
}
.bottom-sheet-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 4px 20px 14px;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
}
.bottom-sheet-title {
    font-size: 0.82rem;
    font-weight: 700;
    color: var(--text-primary);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
.bottom-sheet-close {
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 1.6rem;
    cursor: pointer;
    padding: 0 8px;
    line-height: 1;
    border-radius: 6px;
}
.bottom-sheet-close:hover { color: var(--text-primary); }
.bottom-sheet-body {
    flex: 1;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    padding: 14px 18px 22px;
}

/* ─── MorePanel (bottom-sheet content) ──────────────────────────────
   Tappable list of secondary drawer entry points inside the mobile
   "More" sheet. Each row is a large tap target with icon, text, and
   chevron arrow in the Apple-style preferences pattern.
   ─────────────────────────────────────────────────────────────────── */
.more-panel {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.more-panel-btn {
    display: flex;
    align-items: center;
    gap: 14px;
    width: 100%;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 14px 16px;
    cursor: pointer;
    color: var(--text-primary);
    text-align: left;
    font-family: inherit;
    transition: background 0.12s, transform 0.08s;
}
.more-panel-btn:active {
    transform: scale(0.985);
    background: var(--bg-elevated, var(--bg-secondary));
}
.more-panel-icon {
    flex-shrink: 0;
    width: 38px;
    height: 38px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.04);
}
.more-panel-icon svg { width: 20px; height: 20px; }
.more-panel-text {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.more-panel-title {
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--text-primary);
}
.more-panel-desc {
    font-size: 0.72rem;
    color: var(--text-muted);
    line-height: 1.3;
}
.more-panel-arrow {
    flex-shrink: 0;
    color: var(--text-muted);
    display: flex;
    align-items: center;
    justify-content: center;
}
.more-panel-arrow svg { width: 16px; height: 16px; }

/* ─── MorePanel: Account section ────────────────────────────────────
   Housekeeping row at the BOTTOM of the MORE bottom sheet — the
   primary app tools (Vegas / Track Record / Methodology) come first,
   and the Account entry button sits below with an iOS-Settings-style
   section label for clear separation. The button opens the
   AccountDashboard modal (Phase 5). Mobile equivalent of the desktop
   top-right .user-icon-btn (which is hidden on mobile by the
   mobile-overrides block).
   ─────────────────────────────────────────────────────────────────── */
.more-panel-section {
    /* Extra top margin creates clear visual separation from the tool
       rows above, reinforcing that this is a secondary section. */
    margin-top: 20px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.more-panel-section-label {
    /* iOS Settings section header: small uppercase muted text,
       padded horizontally to align with the card content below. */
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted);
    padding: 0 4px;
}
.more-panel-user {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 14px 16px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 14px;
}
.more-panel-user-row {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
}
.more-panel-user-icon {
    flex-shrink: 0;
    width: 38px;
    height: 38px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.04);
    color: var(--text-secondary);
    font-size: 1.2rem;
}
.more-panel-user-email {
    flex: 1;
    min-width: 0;
    color: var(--text-primary);
    font-size: 0.9rem;
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.more-panel-user-actions {
    display: flex;
    gap: 8px;
}
.more-panel-user-btn {
    flex: 1;
    padding: 10px 12px;
    background: transparent;
    border: 1px solid var(--border);
    border-radius: 8px;
    color: var(--text-secondary);
    font-family: inherit;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.15s;
}
.more-panel-user-btn:active { transform: scale(0.98); }
.more-panel-user-btn:hover { border-color: var(--accent); color: var(--accent); }
.more-panel-user-btn.danger:hover { border-color: var(--red); color: var(--red); }

/* ─── Mobile drawer overrides ───────────────────────────────────────
   On mobile, transform the existing right-slide drawers (Vegas / Blast
   Score / Track Record) into bottom-sheet-style panels so they feel
   native. Zero JSX changes — pure CSS override of the desktop rules.
   Also hide the right-edge .right-tabs handles since the MorePanel
   bottom sheet is the new mobile entry point for these drawers.
   ─────────────────────────────────────────────────────────────────── */
@media (max-width: 768px) {
    .right-tabs { display: none; }

    .vegas-drawer,
    .blast-drawer,
    .record-drawer {
        top: auto;
        right: 0;
        left: 0;
        bottom: 0;
        width: 100%;
        height: auto;
        max-height: 88vh;
        border-left: none;
        border-top: 1px solid var(--border);
        border-radius: 20px 20px 0 0;
        transform: translateY(100%);
        box-shadow: 0 -12px 40px rgba(0, 0, 0, 0.5);
        padding-bottom: var(--safe-bottom);
    }
    .vegas-drawer.open,
    .blast-drawer.open,
    .record-drawer.open {
        transform: translateY(0);
    }
}

/* ─── Mobile Sort & Filter: trigger button + bottom sheet ──────────
   Replaces the wrapping chip-rail filter bar on mobile. The trigger is
   a tall rounded button showing current sort state and active filter
   count; tapping it opens FilterSortSheet with grouped controls.

   Desktop (>768px) keeps the chip rail as-is and hides the trigger.
   Mobile (≤768px) hides the chip rail entirely and shows the trigger.
   ─────────────────────────────────────────────────────────────────── */

/* Default (desktop): trigger hidden, chip rail visible */
.filter-trigger { display: none; }

@media (max-width: 768px) {
    .filter-bar { display: none !important; }

    /* v=150→v=154 — `.pickem-filter-bar` rule retired with the Pick'em
       tab itself (v=154 pivot). Pick'em data now surfaces per-card via
       a Pick'em badge on PickCard, not as a top-level tab with its own
       filter row, so the mobile-visible override is unnecessary. */

    .filter-trigger {
        display: flex;
        align-items: center;
        gap: 12px;
        width: 100%;
        background: var(--bg-card);
        border: 1px solid var(--border);
        border-radius: 14px;
        padding: 12px 14px;
        margin-bottom: 14px;
        cursor: pointer;
        color: var(--text-primary);
        font-family: inherit;
        text-align: left;
        transition: background 0.12s, transform 0.08s, border-color 0.12s;
    }
    .filter-trigger:active {
        transform: scale(0.985);
        background: var(--bg-secondary);
    }
    .filter-trigger-icon {
        flex-shrink: 0;
        width: 36px;
        height: 36px;
        display: flex;
        align-items: center;
        justify-content: center;
        border-radius: 10px;
        background: rgba(245, 158, 11, 0.12);
        color: var(--accent);
    }
    .filter-trigger-icon svg { width: 20px; height: 20px; }
    .filter-trigger-text {
        flex: 1;
        display: flex;
        flex-direction: column;
        gap: 2px;
        min-width: 0;
    }
    .filter-trigger-title {
        font-size: 0.88rem;
        font-weight: 600;
        color: var(--text-primary);
    }
    .filter-trigger-sub {
        font-size: 0.72rem;
        color: var(--text-muted);
        display: flex;
        align-items: center;
        gap: 6px;
    }
    .filter-trigger-dot { opacity: 0.5; }
    .filter-trigger-badge {
        flex-shrink: 0;
        min-width: 22px;
        height: 22px;
        padding: 0 7px;
        border-radius: 11px;
        background: var(--accent);
        color: #0a0e1a;
        font-size: 0.7rem;
        font-weight: 700;
        display: flex;
        align-items: center;
        justify-content: center;
    }
    .filter-trigger-arrow {
        flex-shrink: 0;
        color: var(--text-muted);
        display: flex;
        align-items: center;
    }
    .filter-trigger-arrow svg { width: 16px; height: 16px; }
}

/* ─── FilterSortSheet internal styling ─────────────────────────────
   Rendered inside the shared BottomSheet primitive. Two grouped sections
   (Sort / Filter) plus a legend link, using iOS-style rows with check
   marks for radio and toggle switches for boolean filters.
   ─────────────────────────────────────────────────────────────────── */
.fs-sheet {
    display: flex;
    flex-direction: column;
    gap: 18px;
}
.fs-section {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.fs-section-label {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    font-size: 0.7rem;
    font-weight: 700;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.6px;
    padding: 0 6px 6px;
}
.fs-section-count {
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--accent);
    text-transform: none;
    letter-spacing: 0;
}

/* Row shared by sort and filter sections */
.fs-row {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 12px 14px;
    cursor: pointer;
    color: var(--text-primary);
    text-align: left;
    font-family: inherit;
    font-size: inherit;
    transition: background 0.12s, transform 0.08s, border-color 0.12s;
}
.fs-row:active { transform: scale(0.99); }
.fs-row + .fs-row { margin-top: 6px; }

/* ─ Sort rows ─ */
.fs-sort-row.active {
    border-color: var(--accent);
    background: rgba(245, 158, 11, 0.10);
}
.fs-check {
    flex-shrink: 0;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: 1.5px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: center;
    color: #0a0e1a;
}
.fs-sort-row.active .fs-check {
    background: var(--accent);
    border-color: var(--accent);
}
.fs-check svg { width: 14px; height: 14px; }
.fs-direction {
    flex-shrink: 0;
    font-size: 1rem;
    font-weight: 700;
    color: var(--accent);
    min-width: 16px;
    text-align: right;
}
.fs-hint {
    font-size: 0.7rem;
    color: var(--text-muted);
    padding: 8px 6px 0;
    font-style: italic;
}

/* ─ Filter rows ─ */
.fs-filter-row { padding: 10px 14px; }
.fs-row-text {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.fs-row-label {
    flex: 1;
    font-size: 0.88rem;
    font-weight: 600;
    color: var(--text-primary);
}
.fs-row-desc {
    font-size: 0.7rem;
    color: var(--text-muted);
    line-height: 1.3;
}

/* iOS-style toggle switch */
.fs-toggle {
    flex-shrink: 0;
    width: 46px;
    height: 28px;
    border-radius: 14px;
    background: var(--border);
    position: relative;
    transition: background 0.18s ease;
    cursor: pointer;
}
.fs-toggle.on { background: var(--accent); }
.fs-toggle-knob {
    position: absolute;
    top: 2px;
    left: 2px;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: white;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
    transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1);
}
.fs-toggle.on .fs-toggle-knob { transform: translateX(18px); }

/* Legend link — styled like a list row with leading icon and chevron */
.fs-legend-link {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 12px 14px;
    cursor: pointer;
    color: var(--text-primary);
    font-family: inherit;
    font-size: 0.88rem;
    font-weight: 600;
    transition: background 0.12s, transform 0.08s;
}
.fs-legend-link:active { transform: scale(0.99); }
.fs-legend-icon {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.04);
    color: var(--text-muted);
}
.fs-legend-icon svg { width: 18px; height: 18px; }
.fs-legend-text { flex: 1; }
.fs-legend-arrow {
    flex-shrink: 0;
    color: var(--text-muted);
    display: flex;
    align-items: center;
}
.fs-legend-arrow svg { width: 16px; height: 16px; }

/* ─── Phase 4d — Stack Finder + Sharp Signals mobile fixes ────────────
   Stack Finder: on mobile the left info group (headshot + name + meta
   chips) was overflowing its share of the row, squeezing the name down
   to an ellipsis sliver because the chips are flex-shrink:0. Allowing
   the info group to wrap, and giving the name a min-width floor, pushes
   the chips onto a second line when they can't fit while keeping the
   right-side stats column pinned right.

   Sharp Signals: full team names from The Odds API truncate mid-word on
   mobile ("Cleveland Guardia… @ Toronto Blue Ja…"). The header now
   renders both the full name and a 3-letter abbrev (from getTeamAbbr in
   utils.js); this media query toggles which is visible. Desktop shows
   full names, mobile shows abbrevs. */
.sharp-team-abbr { display: none; }

@media (max-width: 768px) {
    .stack-batter-info { flex-wrap: wrap; }
    .stack-batter-name {
        flex: 1 1 auto;
        min-width: 100px;
    }

    .sharp-team-full { display: none; }
    .sharp-team-abbr { display: inline; }
}

/* ─── v=129 — Sharp Signals 2-column card grid (desktop) ───────────────
   Replaces the v=127/v=128 single-card-with-internal-columns layout
   wholesale. v=127 tried to split each full-width card into two
   internal columns (sharp-side text on the left, market panel on the
   right); v=128 polished that with .detail-group + vertical-center.
   But the underlying constraint — every card MUST be full-width —
   was wrong. Cards without sharp-side text (e.g., heavy moneyline
   alerts on lopsided games) had an empty left half and read as
   broken. Joe's pivot: pair cards SIDE-BY-SIDE in a 2-col grid AT
   THE TOOL LEVEL, and let each card stack its content vertically
   (header → badges → sharp-side → market panel). Half-width cards,
   natural vertical stacks, no awkward empty halves.

   Retired alongside this change:
     - v=123 default-expanded filter-aware behavior (always-expanded
       now)
     - Collapse/expand interaction entirely (the maxHeight animation,
       the click-to-toggle wrapper, the "▲ Collapse" hint)
     - .signal-body / .signal-body-left / .signal-body-right
       wrapper classes (CSS deleted in this same change)
   Mobile users on All Games will see a longer scroll than v=128
   (~3000px for 11 cards always-expanded vs the v=123 collapsed-by-
   default state). Joe's accepted trade-off — mobile users on All
   Games are scanning data, not tapping each one.
*/
.signal-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
    align-items: start;
}
/* v=130 — Hardcoded min-height per card so the grid reads as a clean,
   uniform-height set regardless of which optional sections (badges,
   sharp side, sharp lean, range stats, more/fewer book rows) a given
   signal has. Cards with more content than 420px expand naturally;
   cards with less get padded out to 420px. Joe's call after seeing
   v=129 in production with mixed-height rows. Value tuned to roughly
   the height of a typical "alerts" card with full sharp data + 6
   book rows (the most-content common case). Mobile keeps the same
   floor since card width is narrower (text wraps) — typical content
   actually grows on mobile, so 420px is generous; cards with little
   content still stretch cleanly. */
.signal-grid > * {
    min-height: 420px;
}
@media (max-width: 768px) {
    .signal-grid {
        grid-template-columns: 1fr;
    }
}

/* ─── Phase 4f — Scout filter pills alignment ────────────────────────
   Matches Blast's `.filter-bar` alignment: pills sit flush left on
   desktop and re-center on mobile where the content is narrower.
   Copy-wise we also dropped the "Top N batters · Tap to sort · …"
   hand-holder above this row — the UI is self-evident to the target
   user base. */
.scout-filter-row {
    display: flex;
    /* v=117 — align-items: center prevents flex's default stretch from
       making child .filter-chip pills grow to match the taller
       .scout-mode-segmented control on the same row. Without this,
       pills rendered ~40-45px tall on Scouting Table while the same
       .filter-chip class rendered ~28px tall on Blast Scores (where
       .filter-bar has align-items: center). Matches Blast/Stack pill
       size now that all three are vertically centered with no stretch. */
    align-items: center;
    gap: 8px;
    margin-bottom: 10px;
    justify-content: flex-start;
}

/* v=118 — Hide Scouting + Sharp inline controls on mobile. The mobile
   filter sheet (.fs-sheet, opened via .filter-trigger) replaces them.
   Stack Finder's controls live in .filter-bar which already has a
   mobile display:none rule from Phase 4a. */
/* v=130 — Sharp Signals controls row mirrors .filter-bar's layout
   (flex, gap 8px, wrap, 14px bottom margin). Holds the Alerts/All Games
   segmented control AND the new SORT label + Strength/Game Time pills
   inline on one row, left-aligned. Per locked decision §3 #12, all tool
   controls are left-aligned. Hidden on mobile via the @media block
   below — replaced by the bottom-sheet Filter trigger. */
.sharp-controls-row {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-bottom: 14px;
}

@media (max-width: 768px) {
    .scout-filter-row { display: none !important; }
    .sharp-controls-row { display: none !important; }
}

@media (max-width: 768px) {
    .scout-filter-row { justify-content: center; }
}

/* ─── Phase 5 — AccountDashboard ─────────────────────────────────────
   Single component used on both platforms; CSS adapts the shell:
     - Desktop: centered modal with backdrop. Click backdrop to close.
     - Mobile: full-bleed bottom sheet with rounded top corners. Same
       click-backdrop-to-close behavior. Inner content scrolls.

   The .account-overlay is the dimmed full-screen backdrop. The
   .account-dashboard is the actual surface (modal/sheet). */
.account-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    animation: fadeIn 0.18s ease-out;
}

@keyframes fadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}

.account-dashboard {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 16px;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.55);
    width: 100%;
    max-width: 560px;
    max-height: 88vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.account-handle {
    display: none;
}

.account-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 18px 22px 14px;
    border-bottom: 1px solid var(--border);
}

.account-title {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    color: var(--text-primary);
}

.account-close {
    background: transparent;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    padding: 6px;
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.15s;
}

.account-close:hover { color: var(--text-primary); background: rgba(255, 255, 255, 0.04); }

.account-body {
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 6px 22px 22px;
}

.account-section {
    padding: 16px 0;
    border-bottom: 1px solid var(--border);
}

.account-section:last-child { border-bottom: none; }

.account-section-label {
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 10px;
}

.account-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 6px 0;
    font-size: 0.85rem;
}

.account-row-label {
    color: var(--text-muted);
    flex-shrink: 0;
}

.account-row-value {
    color: var(--text-primary);
    font-weight: 500;
    text-align: right;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.account-row-help {
    margin-top: 8px;
    font-size: 0.74rem;
    color: var(--text-muted);
    line-height: 1.5;
}

.account-plan-badge {
    display: inline-flex;
    align-items: center;
    padding: 4px 10px;
    border-radius: 999px;
    background: rgba(245, 158, 11, 0.12);
    color: var(--accent);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.account-role-badge {
    display: inline-flex;
    align-items: center;
    padding: 4px 10px;
    border-radius: 999px;
    background: rgba(16, 185, 129, 0.12);
    color: #10b981;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.account-action-btn {
    appearance: none;
    background: transparent;
    border: 1px solid var(--border);
    border-radius: 10px;
    color: var(--text-secondary);
    padding: 10px 14px;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.15s;
    font-family: inherit;
}

.account-action-btn:hover {
    border-color: var(--accent);
    color: var(--accent);
}

.account-action-btn:disabled { opacity: 0.6; cursor: default; }

.account-action-btn.danger {
    border-color: rgba(239, 68, 68, 0.4);
    color: #ef4444;
}

.account-action-btn.danger:hover {
    border-color: #ef4444;
    background: rgba(239, 68, 68, 0.08);
}

.account-action-btn.ghost {
    border-color: transparent;
    color: var(--text-muted);
}

.account-action-btn.ghost:hover { color: var(--text-secondary); border-color: var(--border); }

.account-action-btn.full { width: 100%; }

.account-confirm-row {
    display: flex;
    gap: 10px;
    align-items: center;
    flex-wrap: wrap;
}

.account-footer { padding-top: 18px; padding-bottom: 6px; }

/* Embedded AdminPanel inside AccountDashboard — ditch the standalone
   modal padding/border so it sits flush in its parent section. */
.admin-panel.admin-panel-embedded {
    background: transparent;
    border: none;
    padding: 0;
    margin: 0;
}

/* Mobile shell — full-bleed bottom sheet treatment. */
@media (max-width: 768px) {
    .account-overlay {
        align-items: flex-end;
        justify-content: stretch;
        padding: 0;
    }
    .account-dashboard {
        width: 100%;
        max-width: 100%;
        max-height: 92vh;
        border-radius: 20px 20px 0 0;
        animation: slideUp 0.22s ease-out;
    }
    .account-handle {
        display: block;
        width: 38px;
        height: 4px;
        border-radius: 999px;
        background: var(--border);
        margin: 10px auto 4px;
        flex-shrink: 0;
    }
    .account-header {
        padding: 6px 18px 12px;
    }
    .account-body {
        padding: 4px 18px calc(22px + var(--safe-bottom, 0px));
    }
}

@keyframes slideUp {
    from { transform: translateY(100%); }
    to   { transform: translateY(0); }
}

/* ─── Phase 5.5 — Scouting mode segmented control ────────────────────
   Sits at the top of the Scouting tab and toggles between the Batters
   view (top 50 by barrel rate) and the Pitchers view (every starter
   on today's slate, sorted by HR/9 desc). Visual grammar matches the
   existing scout-filter-row (left-aligned desktop, centered mobile).
   The pill itself is styled like an iOS-segmented-control. */
.scout-mode-segmented {
    display: inline-flex;
    gap: 2px;
    padding: 3px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 10px;
    margin-bottom: 10px;
}

.scout-mode-btn {
    padding: 6px 18px;
    border: none;
    background: transparent;
    color: var(--text-muted);
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    cursor: pointer;
    border-radius: 7px;
    transition: all 0.15s;
    font-family: inherit;
}

.scout-mode-btn:hover { color: var(--text-secondary); }

.scout-mode-btn.active {
    background: var(--accent);
    color: #1a1a1a;
}

@media (max-width: 768px) {
    /* Center the control on mobile, matching scout-filter-row pattern. */
    .scout-mode-segmented {
        margin-left: auto;
        margin-right: auto;
        display: flex;
        width: fit-content;
    }
}

/* ─── Phase 6c / 6c.2: UpdateBanner ──────────────────────────────────
   Floating "Updates available — Refresh" notification.
   • Desktop: top-right corner toast.
   • Mobile: floating pill above the bottom tab bar (mirrors the tab
     pill aesthetic from Phase 4b.5 — looks intentional, not slapped on).
   Visual treatment: dark frosted card with brand-orange accent border
   and CTA. Notification-feeling, not alarm-feeling — we don't want to
   compete with the orange Refresh Blast Scores button.

   Note: this block was authored in Phase 6c but didn't make it into the
   v=72 commit (6c.2 retroactively patches that omission). If the banner
   ever renders unstyled at the bottom-left of the document, that's the
   tell — the CSS isn't loading. Grep `.update-banner` to verify. */

.update-banner {
    position: fixed;
    z-index: 100;
    top: 16px;
    right: 16px;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 4px 4px 4px;
    background: rgba(20, 27, 45, 0.95);
    color: #fff;
    border: 1px solid rgba(245, 158, 11, 0.45);
    border-radius: 8px;  /* Phase 6c.4 — aligns with .refresh-btn / .install-btn standard */
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
    font-size: 0.85rem;
    font-weight: 500;
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    animation: updateBannerSlideIn 0.3s ease-out;
}

.update-banner-action {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: transparent;
    border: 0;
    color: inherit;
    font: inherit;
    padding: 6px 12px;
    cursor: pointer;
    border-radius: 6px;  /* Phase 5.5.11 — nests inside outer 8px banner; was 10px and spilled past corners on hover */
    transition: background 0.15s;
}

.update-banner-action:hover { background: rgba(245, 158, 11, 0.15); }

.update-banner-icon {
    color: var(--accent);
    flex-shrink: 0;
}

.update-banner-text { color: rgba(255, 255, 255, 0.9); }

.update-banner-cta {
    color: var(--accent);
    font-weight: 700;
    margin-left: 6px;
}

.update-banner-dismiss {
    background: transparent;
    border: 0;
    color: rgba(255, 255, 255, 0.55);
    font-size: 1.4rem;
    line-height: 1;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s, color 0.15s;
    margin-right: 4px;
}

.update-banner-dismiss:hover {
    background: rgba(255, 255, 255, 0.1);
    color: #fff;
}

@keyframes updateBannerSlideIn {
    from { opacity: 0; transform: translateY(-8px); }
    to { opacity: 1; transform: translateY(0); }
}

@keyframes updateBannerSlideUp {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: translateY(0); }
}

@media (max-width: 768px) {
    /* Mobile: pin to the bottom-center, floating above the bottom tab
       bar. The tab bar is at `bottom: max(--safe-bottom, 16px)` with
       64px height (--mobile-tab-height); we clear it with an extra
       20px gap so the banner doesn't touch the pill. */
    .update-banner {
        top: auto;
        right: 12px;
        left: 12px;
        bottom: calc(var(--mobile-tab-height) + max(var(--safe-bottom), 16px) + 20px);
        justify-content: center;
        animation: updateBannerSlideUp 0.3s ease-out;
    }
}

/* ─── Phase 6b: Install button ─────────────────────────────────────────
   Sits to the LEFT of the floating user-icon button in the top-right.
   Visible only when beforeinstallprompt has fired and the app isn't
   already installed (App.jsx gates `canInstall`). Hidden on mobile —
   the install action lives inside MorePanel on small screens. */

.install-btn {
    position: fixed;
    top: 16px;
    right: 64px;  /* leaves room for .user-icon-btn at right: 16px (44px-ish wide + 4px gap) */
    z-index: 50;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 14px 8px 12px;
    /* Phase 6b.3 — green to visually separate from the orange Refresh
       Blast Scores CTA in the same top region. Otherwise both buttons
       compete for the eye and the primary action loses its dominance. */
    background: linear-gradient(135deg, var(--green), #059669);
    color: #fff;  /* Phase 6b.5 — white for stronger contrast on the darker green gradient and to match the conventional install-button pattern */
    border: 0;
    border-radius: 8px;  /* Phase 6b.4 — matches .refresh-btn for visual consistency in the top region */
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    cursor: pointer;
    font-family: inherit;
    box-shadow: 0 4px 14px rgba(16, 185, 129, 0.3);
    transition: transform 0.12s, box-shadow 0.12s;
}

.install-btn:hover {
    transform: translateY(-1px);
    box-shadow: 0 6px 20px rgba(16, 185, 129, 0.45);
}

.install-btn:active {
    transform: translateY(0);
}

.install-btn-label {
    /* Hidden on narrower viewports — icon alone communicates well enough. */
}

@media (max-width: 768px) {
    /* Hidden on mobile — install action lives in MorePanel's first row. */
    .install-btn { display: none; }
}

/* Mobile MorePanel install row uses the existing `.more-panel-btn`
   styling for layout. The green border below visually elevates it
   above the regular tool rows so it reads as a primary action.
   Phase 6b.3 — switched from orange to green to match the desktop
   install button's distinction-from-the-Refresh-CTA story. */
.more-panel-btn-install {
    border: 1px solid rgba(16, 185, 129, 0.45) !important;
    background: rgba(16, 185, 129, 0.04) !important;
}

.more-panel-btn-install:hover,
.more-panel-btn-install:focus-visible {
    background: rgba(16, 185, 129, 0.08) !important;
}

/* ─── Phase 7: IosInstallModal ────────────────────────────────────────
   Bottom sheet on iPhone, centered modal on iPad-sized viewports.
   Auto-shown once on first iOS visit (App.jsx gates via the
   localStorage flag), and manually opened via the Install App button
   on iOS. Two content modes: 'safari' (direct tutorial) and
   'non-safari' (Open in Safari first → tutorial). Same shell. */

.ios-install-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.6);
    z-index: 200;
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    animation: iosOverlayFade 0.25s ease-out;
}

.ios-install-sheet {
    position: fixed;
    z-index: 201;
    background: var(--bg-card);
    color: #fff;
    /* Mobile default: bottom sheet */
    left: 0;
    right: 0;
    bottom: 0;
    border-top-left-radius: 20px;
    border-top-right-radius: 20px;
    padding: 20px 20px calc(env(safe-area-inset-bottom, 16px) + 24px);
    max-height: 88vh;
    overflow-y: auto;
    animation: iosSheetSlideUp 0.32s cubic-bezier(0.32, 0.72, 0, 1);
}

.ios-install-handle {
    width: 36px;
    height: 4px;
    background: rgba(255, 255, 255, 0.2);
    border-radius: 2px;
    margin: 0 auto 12px;
}

.ios-install-close {
    position: absolute;
    top: 12px;
    right: 12px;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: transparent;
    border: 0;
    color: rgba(255, 255, 255, 0.55);
    font-size: 1.5rem;
    line-height: 1;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s, color 0.15s;
}

.ios-install-close:hover {
    background: rgba(255, 255, 255, 0.08);
    color: #fff;
}

.ios-install-header {
    margin: 4px 0 18px;
    text-align: left;
}

.ios-install-title {
    font-size: 1.15rem;
    font-weight: 800;
    margin: 0 0 6px;
    color: #fff;
    letter-spacing: 0.01em;
}

.ios-install-subtitle {
    font-size: 0.85rem;
    color: rgba(255, 255, 255, 0.6);
    margin: 0;
    line-height: 1.4;
}

.ios-install-steps {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.ios-install-step {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 12px;
    background: rgba(16, 185, 129, 0.04);
    border: 1px solid rgba(16, 185, 129, 0.25);
    border-radius: 8px;
}

.ios-install-step-num {
    flex-shrink: 0;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: var(--green);
    color: #052e23;
    font-size: 0.8rem;
    font-weight: 800;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-top: 2px;
}

.ios-install-step-icon {
    flex-shrink: 0;
    color: var(--green);
    width: 24px;
    height: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-top: 2px;
}

.ios-install-step-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 1;
}

.ios-install-step-title {
    font-size: 0.92rem;
    font-weight: 700;
    color: #fff;
    line-height: 1.35;
}

.ios-install-step-desc {
    font-size: 0.8rem;
    color: rgba(255, 255, 255, 0.6);
    line-height: 1.4;
}

.ios-install-footer {
    margin-top: 20px;
    display: flex;
    justify-content: center;
}

.ios-install-dismiss {
    background: transparent;
    border: 1px solid rgba(255, 255, 255, 0.2);
    color: rgba(255, 255, 255, 0.85);
    padding: 10px 28px;
    border-radius: 8px;
    font-size: 0.88rem;
    font-weight: 600;
    cursor: pointer;
    font-family: inherit;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
}

.ios-install-dismiss:hover {
    background: rgba(255, 255, 255, 0.06);
    border-color: rgba(255, 255, 255, 0.35);
    color: #fff;
}

@keyframes iosOverlayFade {
    from { opacity: 0; }
    to { opacity: 1; }
}

@keyframes iosSheetSlideUp {
    from { transform: translateY(100%); }
    to   { transform: translateY(0); }
}

/* Tablet+ — switch from bottom sheet to centered modal */
@media (min-width: 640px) {
    .ios-install-sheet {
        left: 50%;
        right: auto;
        bottom: auto;
        top: 50%;
        transform: translate(-50%, -50%);
        max-width: 460px;
        width: calc(100% - 48px);
        border-radius: 16px;
        padding: 28px;
        max-height: 80vh;
        animation: iosSheetFadeCenter 0.28s ease-out;
    }
    .ios-install-handle { display: none; }

    @keyframes iosSheetFadeCenter {
        from { opacity: 0; transform: translate(-50%, -48%); }
        to   { opacity: 1; transform: translate(-50%, -50%); }
    }
}

/* ─── Phase 9 — Admin Workspace + Admin trigger button ───────────────────
   Full-screen route at /admin (server catch-all in app.py + useRoute hook
   in utils.js). Replaces the cramped admin section that used to live
   inside the AccountDashboard modal. */

.admin-trigger-btn {
    /* Top-right desktop, canonical corner position. Hidden on mobile via the
       768px block below — mobile users open admin via MorePanel.
       v=107: moved from right: 64px (clearing user-icon-btn) to right: 16px
       because the user icon is now hidden for admins. Only one corner icon
       per role: user-icon-btn for non-admins, admin-trigger-btn for admins. */
    position: fixed;
    top: 16px;
    right: 16px;
    display: inline-flex;
    align-items: center;
    padding: 6px 12px;
    border-radius: 8px;
    border: 1px solid rgba(245, 158, 11, 0.4);
    background: rgba(245, 158, 11, 0.08);
    color: var(--accent-orange, #f59e0b);
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    cursor: pointer;
    z-index: 50;
    transition: background 0.15s, border-color 0.15s;
}
.admin-trigger-btn:hover {
    background: rgba(245, 158, 11, 0.16);
    border-color: rgba(245, 158, 11, 0.6);
}
@media (max-width: 768px) {
    .admin-trigger-btn { display: none; }
}

.admin-workspace {
    min-height: 100vh;
    background: var(--bg, #0a0e1a);
    color: var(--text-primary, #e5e7eb);
    padding-bottom: max(env(safe-area-inset-bottom, 0px), 24px);
}

.admin-workspace-header {
    position: sticky;
    top: 0;
    z-index: 10;
    background: rgba(10, 14, 26, 0.92);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border-bottom: 1px solid var(--border, rgba(255, 255, 255, 0.08));
    /* iOS PWA draws under the status bar — pad top by the safe-area inset so
       the Back button doesn't overlap the iOS time/battery row (v=106 fix).
       In browser mode env(safe-area-inset-top) is 0, header stays tight. */
    padding: calc(env(safe-area-inset-top, 0px) + 14px) 0 14px 0;
}
.admin-workspace-header-inner {
    max-width: 980px;
    margin: 0 auto;
    padding: 0 24px;
    display: flex;
    align-items: center;
    gap: 16px;
}
.admin-workspace-title {
    font-size: 1.1rem;
    font-weight: 700;
    margin: 0;
    flex: 1;
    letter-spacing: 0.01em;
}
.admin-workspace-user {
    font-size: 0.78rem;
    color: var(--text-muted, #9ca3af);
}

.admin-back-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border-radius: 8px;
    border: 1px solid var(--border, rgba(255, 255, 255, 0.12));
    background: transparent;
    color: var(--text-secondary, #d1d5db);
    font-size: 0.82rem;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
}
.admin-back-btn:hover {
    background: rgba(255, 255, 255, 0.04);
    border-color: rgba(255, 255, 255, 0.2);
}

.admin-workspace-body {
    max-width: 980px;
    margin: 0 auto;
    padding: 28px 24px;
    display: flex;
    flex-direction: column;
    gap: 28px;
}
.admin-section {
    background: rgba(255, 255, 255, 0.025);
    border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
    border-radius: 12px;
    padding: 20px 22px;
}
.admin-section-header {
    margin-bottom: 14px;
}
.admin-section-title {
    font-size: 1rem;
    font-weight: 700;
    margin: 0 0 4px 0;
    letter-spacing: 0.01em;
}
.admin-section-help {
    font-size: 0.82rem;
    color: var(--text-muted, #9ca3af);
    margin: 0;
}
.admin-workspace-empty {
    max-width: 420px;
    margin: 80px auto 0;
    padding: 0 24px;
    text-align: center;
}
.admin-workspace-empty h2 {
    font-size: 1.2rem;
    margin: 0 0 8px 0;
}
.admin-workspace-empty p {
    color: var(--text-muted, #9ca3af);
    margin: 0 0 20px 0;
}

@media (max-width: 768px) {
    .admin-workspace-header-inner,
    .admin-workspace-body {
        padding-left: 16px;
        padding-right: 16px;
    }
    .admin-workspace-body {
        padding-top: 20px;
        gap: 20px;
    }
    .admin-section {
        padding: 16px 14px;
    }
    .admin-workspace-user {
        display: none; /* tight on mobile; email is in the AccountDashboard */
    }
}

/* v=114 — Always-rendered "refresh strip" between the date row and
   the tab content area. Provides uniform spacing across all four
   tools (Blast / Scout / Stack / Sharp) and acts as the single
   render point for the refresh-spinner.

   Always present in the DOM (not conditionally rendered) so toggling
   refresh state never shifts the layout below it — Joe's "without
   anything being pushed down" requirement. Min-height keeps the
   strip the same size whether or not the spinner is inside it.

   Spinner-only treatment (no "Updating..." text per Joe — the
   spinning circle conveys the state on its own and saves space).
   .refresh-strip-spinner is a sized variant of .spinner — slightly
   smaller (28×28 vs the default 40×40) so it sits comfortably in a
   short strip. Uses the existing @keyframes spin already defined for
   .spinner.

   History recap of the iteration arc:
     - v=110: full-screen overlay containing the bar chart. Heavy.
     - v=111: in-button spinner. Didn't unify with internal loaders.
     - v=112: centered loader in the data area, bar chart vs spinner
       conditional on loadedOnce. Created two visible bugs: (a)
       Sharp's internal loader fired alongside Dashboard's loader =
       duplicate spinner, (b) data render conditions only checked
       `!loading` so during isRefreshing the loader rendered above
       still-visible data = "data pushed down."
     - v=114 (this): single render point at strip level, fixed
       height for layout stability. Bar chart still renders for
       first-load only, in the data area below the strip. Data
       render conditions changed to `(picksLoadedOnce || !loading)`
       so existing data stays visible during all refreshes.
*/
.refresh-strip {
    /* v=121 — Collapsible strip. Height + margin are 0 when idle so
       the empty space below the date row that v=114 reserved is
       reclaimed (~72px). On refresh, the `.is-active` modifier
       expands the strip and the content below smoothly slides down
       to make room. Joe's call after seeing v=120 + v=114 in real
       use: the always-reserved 72px gap was wider than expected
       between the date row and the per-tool controls.

       Transitions on `height` and `margin` (both must animate, since
       both contribute to the layout shift). 0.3s ease feels right —
       slow enough to read as a deliberate slide, fast enough not to
       drag. The spinner inside fades in 100ms after the strip starts
       expanding (and fades out before the strip collapses), so the
       reveal sequence is: strip opens → spinner appears → spinner
       holds → spinner fades → strip closes. Reverse on dismiss.

       History recap of the strip:
         - v=114: introduced as always-rendered with min-height: 56px.
           Solved layout-shift on toggle but reserved permanent empty
           space when idle.
         - v=121 (this): collapsible — height: 0 by default, expands
           on refresh. Reclaims the idle space. Smooth transition
           replaces the always-reserved gap. */
    overflow: hidden;
    height: 0;
    margin: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: height 0.3s ease, margin 0.3s ease;
}

.refresh-strip.is-active {
    height: 56px;
    margin: 4px 0 12px 0;
}

.refresh-strip-spinner {
    /* Override .spinner's default size + margin since the flex
       parent handles centering and we want a smaller visual in a
       compact strip.

       v=121 — opacity transition so the spinner fades in *after*
       the strip starts expanding (delay: 0.1s), and fades out
       *before* the strip starts collapsing. The pair of transitions
       gives a polished reveal/hide sequence rather than the spinner
       appearing/disappearing instantly while the strip animates. */
    width: 28px;
    height: 28px;
    border-width: 3px;
    margin: 0;
    opacity: 0;
    transition: opacity 0.2s ease 0.1s;
}

.refresh-strip.is-active .refresh-strip-spinner {
    opacity: 1;
}

/* ─── v=151 — Brand splash (BrandSplash.jsx) ────────────────────────────
   Full-viewport flaming-baseball brand moment shown on every app-open
   (cold-boot, warm reopen, PWA resume). NOT a loading indicator —
   data layer is independent (stale-while-revalidate in Dashboard).
   ~800ms total: 150ms fade-in → 500ms hold-with-pulse → 200ms fade-out.

   Z-index: above everything (header, modals, drawers, tab bar) so the
   moment is always unobstructed. Pointer-events: none after fade-in
   so accidental taps during the splash window pass through to the
   underlying app — splash is decorative, not interactive.

   Background: dark navy matches the manifest theme color and the
   PWA cold-boot system splash on iOS, so there's no flash of color
   between OS-level launch and our React-level splash. Single visual
   beat. */
.brand-splash {
    position: fixed;
    inset: 0;
    z-index: 9999;
    background: var(--bg, #0a0e1a);
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
    /* Fade-in starts on mount, completes at 150ms. */
    animation: brand-splash-fade-in 150ms ease-out forwards;
}

.brand-splash.is-exiting {
    /* Fade-out kicks in when parent sets isExiting; lasts 200ms. */
    animation: brand-splash-fade-out 200ms ease-in forwards;
}

.brand-splash-logo {
    width: 140px;
    height: auto;
    max-width: 40vw;
    /* Subtle scale pulse during the hold window — gives the splash
       motion language so it doesn't read as static. Plays once
       during the splash window. */
    animation: brand-splash-pulse 700ms ease-out forwards;
    filter: drop-shadow(0 8px 32px rgba(245, 158, 11, 0.35));
}

@keyframes brand-splash-fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

@keyframes brand-splash-fade-out {
    from { opacity: 1; }
    to   { opacity: 0; }
}

@keyframes brand-splash-pulse {
    /*  0% — slightly small + already mostly opaque (parent fades container)
       30% — full size with a subtle overshoot (1.05) so it has bounce
      100% — settled at natural size, ready for fade-out */
    0%   { transform: scale(0.92); }
    30%  { transform: scale(1.05); }
    100% { transform: scale(1.00); }
}

@media (prefers-reduced-motion: reduce) {
    /* Honor system-level reduced-motion preference. Splash still
       shows + fades, but no scale animation (a11y best practice). */
    .brand-splash-logo {
        animation: none;
    }
}
