/* ============================================================================
   mobile.css — phone / small-tablet interface for the tornado site.

   EVERY rule in this file lives inside a media query, so a desktop browser
   loads the file and renders exactly as before. Nothing here can leak onto
   the desktop layout.

   ---------------------------------------------------------------------------
   THE MEDIA QUERY (kept byte-identical in js/mobile.js as MQ)
   ---------------------------------------------------------------------------
     (max-width: 820px) and (hover: none) and (pointer: coarse),
     (max-height: 520px) and (hover: none) and (pointer: coarse),
     (max-width: 480px)

   Rationale, clause by clause:

   1. `(max-width: 820px) and (hover: none) and (pointer: coarse)`
      The primary test. `hover: none` + `pointer: coarse` is true only for
      touch-primary devices (phones, tablets); a laptop dragged down to a
      600px-wide window still reports `hover: hover` / `pointer: fine` and
      therefore keeps the desktop sidebar. 820px keeps phones and small
      tablets in, and leaves 1024px-wide iPads on the desktop layout, which
      they have the room for.

   2. `(max-height: 520px) and (hover: none) and (pointer: coarse)`
      Landscape phones. An iPhone 14/15 Pro Max in landscape is 932px wide —
      wider than clause 1 allows — but only ~430px tall. Without this clause a
      rotation would flip the app out of mobile mode mid-session. Real tablets
      in landscape are much taller than 520px, so they are unaffected.

   3. `(max-width: 480px)`
      Pointer-agnostic fallback. Some browsers (older Android WebViews, a few
      desktop device-emulation modes, kiosk shells) do not report the
      interaction media features. Anything 480px wide is a phone regardless.

   ---------------------------------------------------------------------------
   The bottom sheet (built by js/mobile.js)
   ---------------------------------------------------------------------------
   On the map page the .sidebar is relocated into a fixed #mobile-sheet:

     #mobile-sheet
       #mobile-sheet-header   <- drag handle + quick actions; its height IS the
                                 peek height (JS publishes it as --sheet-peek-h)
       #mobile-sheet-body     <- the scrolling .sidebar
   ============================================================================ */

@media (max-width: 820px) and (hover: none) and (pointer: coarse),
       (max-height: 520px) and (hover: none) and (pointer: coarse),
       (max-width: 480px) {

  /* ---------------------------------------------------------------- tokens */
  :root {
    --nav-h: 52px;
    /* Peek height. js/mobile.js overwrites --sheet-peek-h with the measured
       header height (which already includes the safe-area padding below).
       The 164px seed keeps the first paint sane before JS measures. */
    --sheet-peek-h: 164px;
    --sheet-peek: var(--sheet-peek-h);
    --sheet-h: 88dvh;          /* total sheet height (== the "full" state) */
    --sheet-half: 50dvh;       /* visible height in the "half" state */
    /* how far the bottom-corner map boxes are lifted so they clear the
       colorbar, the Leaflet attribution and the sheet peek */
    --ov-lift: calc(var(--sheet-peek) + 44px);
  }

  /* dvh fallback for pre-iOS-15.4 / old Android */
  @supports not (height: 1dvh) {
    :root { --sheet-h: 88vh; --sheet-half: 50vh; }
  }

  /* ------------------------------------------------------------ page shell */
  html.mobile.mobile-map,
  html.mobile.mobile-map body { overflow: hidden; overscroll-behavior: none; }

  .page {
    height: calc(100vh - var(--nav-h));
    height: calc(100dvh - var(--nav-h));
    flex-direction: row;             /* undoes style.css's <860px stacking */
  }
  .scroll-page {
    height: calc(100vh - var(--nav-h));
    height: calc(100dvh - var(--nav-h));
    padding: 14px;
    -webkit-overflow-scrolling: touch;
  }
  /* js/mobile.js sets the `mobile` class on <html> at script-eval time but
     only relocates .sidebar on DOMContentLoaded — this keeps style.css's
     <860px stacked sidebar from flashing in between. The selector stops
     matching the moment the sidebar lands inside the sheet. */
  html.mobile .page > .sidebar { display: none; }

  /* ------------------------------------------------------- nav + hamburger */
  .nav { padding: 0 10px; gap: 0; }
  .nav .brand { margin-right: auto; font-size: 0.98rem; }
  .nav a.tab { display: none; }      /* links live in the dropdown instead */

  #mobile-nav-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    padding: 0;
    flex: 0 0 auto;
    background: transparent;
    border: 1px solid var(--border);
    border-radius: 8px;
    color: var(--ink);
    -webkit-tap-highlight-color: transparent;
  }
  #mobile-nav-toggle .bars,
  #mobile-nav-toggle .bars::before,
  #mobile-nav-toggle .bars::after {
    display: block;
    width: 20px;
    height: 2px;
    border-radius: 2px;
    background: var(--ink);
    transition: transform .18s ease, opacity .18s ease;
  }
  #mobile-nav-toggle .bars { position: relative; }
  #mobile-nav-toggle .bars::before,
  #mobile-nav-toggle .bars::after { content: ''; position: absolute; left: 0; }
  #mobile-nav-toggle .bars::before { top: -6px; }
  #mobile-nav-toggle .bars::after  { top: 6px; }
  #mobile-nav-toggle[aria-expanded="true"] .bars { background: transparent; }
  #mobile-nav-toggle[aria-expanded="true"] .bars::before { transform: translateY(6px) rotate(45deg); }
  #mobile-nav-toggle[aria-expanded="true"] .bars::after  { transform: translateY(-6px) rotate(-45deg); }

  #mobile-nav-menu {
    position: fixed;
    top: var(--nav-h);
    left: 0;
    right: 0;
    z-index: 1900;
    max-height: calc(100vh - var(--nav-h));
    max-height: calc(100dvh - var(--nav-h));
    overflow-y: auto;
    padding: 6px 0 max(6px, env(safe-area-inset-bottom, 0px));
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    box-shadow: 0 12px 28px rgba(0, 0, 0, 0.5);
    opacity: 0;
    visibility: hidden;
    transform: translateY(-10px);
    transition: opacity .16s ease, transform .16s ease, visibility .16s;
  }
  #mobile-nav-menu.open { opacity: 1; visibility: visible; transform: none; }
  #mobile-nav-menu a {
    display: flex;
    align-items: center;
    min-height: 48px;
    padding: 4px 18px;
    color: var(--ink-2);
    text-decoration: none;
    font-weight: 500;
    font-size: 1rem;
    -webkit-tap-highlight-color: transparent;
  }
  #mobile-nav-menu a.active { color: var(--ink); background: var(--surface-2); }
  #mobile-nav-menu a:active { background: var(--surface-2); }

  #mobile-nav-backdrop {
    position: fixed;
    inset: var(--nav-h) 0 0 0;
    z-index: 1850;
    background: rgba(0, 0, 0, 0.45);
    opacity: 0;
    visibility: hidden;
    transition: opacity .16s ease, visibility .16s;
  }
  #mobile-nav-backdrop.open { opacity: 1; visibility: visible; }

  /* ----------------------------------------------------------- bottom sheet */
  /* z-index budget (shared with style.css):
       1000 map boxes · 1200 cursor tip · 1300 SHEET · 1400 stats panel
       1500 home panel + toast · 1850/1900 nav backdrop + menu             */
  #mobile-sheet {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1300;
    display: flex;
    flex-direction: column;
    height: var(--sheet-h);
    background: var(--surface);
    border-top: 1px solid var(--border);
    border-radius: 14px 14px 0 0;
    box-shadow: 0 -8px 30px rgba(0, 0, 0, 0.55);
    will-change: transform;
    transition: transform .28s cubic-bezier(.32, .72, 0, 1);
  }
  /* --- the three-state machine; JS swaps exactly one of these classes --- */
  #mobile-sheet.sheet-peek { transform: translateY(calc(100% - var(--sheet-peek))); }
  #mobile-sheet.sheet-half { transform: translateY(calc(100% - var(--sheet-half))); }
  #mobile-sheet.sheet-full { transform: translateY(0); }
  /* while a finger is down JS writes an inline transform and kills the easing */
  #mobile-sheet.dragging { transition: none; }

  #mobile-sheet-header {
    flex: 0 0 auto;
    padding: 6px 12px calc(10px + env(safe-area-inset-bottom, 0px));
    border-bottom: 1px solid var(--border);
    touch-action: none;            /* we own the vertical gesture here */
    -webkit-tap-highlight-color: transparent;
    user-select: none;
  }
  #mobile-sheet-grip {
    display: block;
    width: 44px;
    height: 5px;
    margin: 4px auto 10px;
    border-radius: 3px;
    background: var(--ink-3);
    opacity: 0.75;
  }
  /* quick actions: the hazard picker and the Load/Clear/Stats row are moved
     up here by JS so they stay reachable in the peek state */
  #mobile-sheet-quick { display: flex; flex-direction: column; gap: 8px; }
  #mobile-sheet-quick .ctl-row { margin: 0; flex-wrap: nowrap; }
  #mobile-sheet-quick .ctl-row > button { flex: 1 1 0; min-width: 0; }
  #mobile-sheet-quick .hazard-row > .hazard-btn { min-height: 40px; }

  #mobile-sheet-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    touch-action: pan-y;
  }
  /* nothing of the body is on screen while peeking — keep it from eating
     scroll gestures aimed at the sheet itself */
  #mobile-sheet.sheet-peek #mobile-sheet-body { overflow: hidden; }

  /* the relocated sidebar: the sheet supplies the surface + chrome now */
  #mobile-sheet .sidebar,
  #mobile-sheet .sidebar.collapsed {   /* neutralize the desktop collapse state */
    width: auto;
    min-width: 0;
    max-height: none;
    height: auto;
    overflow: visible;
    padding: 12px 14px 28px;
    background: transparent;
    border: none;
    transition: none;
  }
  #mobile-sheet .ctl-group:last-child { padding-bottom: 4px; }
  /* the "Hazard" group is left empty once its buttons move to the header */
  #mobile-sheet .mobile-emptied { display: none; }

  #sidebar-toggle { display: none !important; }

  /* --------------------------------------------------- 44px touch targets */
  .sidebar button,
  #mobile-sheet-quick button,
  .home-card,
  #stats-close { min-height: 44px; }

  .sidebar input[type="date"],
  .sidebar input[type="number"],
  .sidebar input[type="text"],
  .sidebar select,
  #mobile-sheet input[type="date"],
  #mobile-sheet input[type="number"],
  #mobile-sheet input[type="text"],
  #mobile-sheet select {
    min-height: 44px;
    font-size: 16px;      /* < 16px makes iOS Safari zoom the page on focus */
  }
  #mobile-sheet input[type="range"] {
    min-height: 44px;     /* fat, easy-to-grab hit area */
    flex: 1 1 120px;
  }
  #mobile-sheet input[type="checkbox"] {
    width: 22px;
    height: 22px;
    flex: 0 0 auto;
  }

  /* .ctl-row at ~366px of usable width: label + control + output still fit on
     one line; anything wider wraps cleanly instead of overflowing */
  #mobile-sheet .ctl-row { gap: 8px 10px; margin-bottom: 10px; }
  #mobile-sheet .ctl-row > label { min-width: 104px; font-size: 0.9rem; }
  #mobile-sheet .ctl-row > output { min-width: 52px; }
  #mobile-sheet .ctl-group h3 { font-size: 0.86rem; }
  #mobile-sheet .toggle-row { gap: 8px 16px; }
  #mobile-sheet .toggle-row label,
  #mobile-sheet .toggle-list label { min-height: 34px; font-size: 0.92rem; }
  #mobile-sheet .hint { font-size: 0.84rem; }

  /* ----------------------------------------------- map overlays (~390px w) */
  #map-title {
    top: 6px;
    left: 8px;
    right: 8px;
    transform: none;
    max-width: none;
    padding: 5px 8px;
    font-size: 12.5px;
    line-height: 1.25;
    border-width: 1.5px;
    white-space: normal;         /* wrap instead of ellipsing the whole title */
    overflow: visible;
    text-overflow: clip;
  }
  #era-box {
    /* hindcast.js writes an inline `top` from the title's measured height, so
       only the box metrics are adjusted here */
    max-width: 92%;
    padding: 3px 8px;
    font-size: 10px;
    line-height: 1.25;
    white-space: normal;
  }

  /* Bottom-corner boxes: hindcast.js owns the inline `bottom` of #risk-box and
     #reports-box (it stacks them on #max-prob-box / #rank-box), so they are
     lifted with a transform instead — that keeps the JS stacking math intact. */
  #max-prob-box,
  #risk-box,
  #rank-box,
  #reports-box {
    transform: translateY(calc(-1 * var(--ov-lift)));
  }
  #max-prob-box,
  #risk-box { left: 6px; min-width: 84px; padding: 4px 7px; }
  #rank-box,
  #reports-box { right: 6px; padding: 4px 8px; border-width: 1.5px; }
  #max-prob-box .hdr { font-size: 11px; margin-bottom: 3px; }
  #max-prob-box .val { font-size: 16px; }
  #risk-box { font-size: 16px; }
  #rank-box,
  #reports-box { font-size: 11.5px; }

  #colorbar {
    bottom: calc(var(--sheet-peek) + 18px);
    width: calc(100% - 16px);
  }
  #colorbar .cells { height: 16px; }
  #colorbar .cells div { font-size: 7px; }
  #colorbar .caption { margin-top: 3px; font-size: 10px; }

  #watermark {
    bottom: calc(var(--sheet-peek) + 58px);
    font-size: 9px;
    padding: 2px 6px;
  }

  #cursor-tip { font-size: 11px; }

  /* Leaflet's own chrome has to dodge the title and the sheet peek */
  .leaflet-top { top: 46px; }
  .leaflet-bottom { bottom: var(--sheet-peek); }
  .leaflet-control-attribution { font-size: 9px; }
  .leaflet-touch .leaflet-bar a { width: 34px; height: 34px; line-height: 34px; }

  /* --------------------------------------------------------- stats overlay */
  #stats-panel {
    inset: 0;
    border: none;
    border-radius: 0;
    padding: 14px 14px calc(24px + env(safe-area-inset-bottom, 0px));
    -webkit-overflow-scrolling: touch;
  }
  #stats-close {
    width: 44px;
    height: 44px;
    font-size: 18px;
    margin: -4px -4px 0 0;
  }
  #stats-body h2 { font-size: 1.1rem; }
  #stats-body .note,
  #stats-body .rarity { max-width: none; }
  .stat-tiles { gap: 8px; }
  .stat-tile { flex: 1 1 132px; min-width: 0; padding: 9px 12px; }
  .stat-tile .v { font-size: 1.25rem; }

  /* ------------------------------------------------------------- toast etc */
  #status-toast {
    max-width: calc(100% - 28px);
    padding: 10px 14px;
    font-size: 0.9rem;
  }

  /* --------------------------------------------------------- hazard picker */
  #home-panel { padding: 12px; }
  .home-inner { padding: 12px; width: 100%; max-width: 460px; }
  .home-inner h1 { font-size: 1.25rem; }
  .home-inner p { font-size: 0.92rem; margin-bottom: 18px; }
  .home-cards { flex-direction: column; gap: 10px; }
  .home-card { width: 100%; padding: 14px 16px; text-align: left; }
  .home-card .t { font-size: 1.05rem; margin-bottom: 3px; }
  .home-card .d { font-size: 0.8rem; }

  /* ------------------------------------------------ shared non-map pages */
  /* other pages can adopt these by including mobile.css + mobile.js as-is */
  .card { padding: 13px; margin-bottom: 12px; }
  .card h2 { font-size: 1.05rem; }
  .controls-row { gap: 10px; }
  .controls-row .field { flex: 1 1 140px; min-width: 0; }
  .controls-row select,
  .controls-row input { min-height: 44px; font-size: 16px; width: 100%; }
  .chart-wrap { min-height: 34vh; }
  table.data { font-size: 0.8rem; }
  table.data th, table.data td { padding: 5px 8px; }

  /* ==========================================================================
     risk-diagram.html + state-weights.html  (the two chart pages)
     ========================================================================== */

  /* --- hazard tabs (here they live in the .card, not in a sidebar) --- */
  .scroll-page .hazard-row { gap: 8px; }
  .scroll-page .hazard-btn { min-height: 44px; font-size: 0.94rem; }

  /* --- controls -----------------------------------------------------------
     Both pages hard-code pixel widths inline (width:110px / 86px / 70px on
     the year / month / top-N inputs, select[multiple]{min-width:130px}).
     Those are desktop-only sizing decisions; on a phone every control should
     own the full width of the .field it sits in, hence the !important — the
     inline attribute would otherwise win. Checkboxes are excluded: they are
     the one control that must NOT stretch. */
  .controls-row .field > span { font-size: 0.76rem; }
  .controls-row .field input:not([type="checkbox"]),
  .controls-row .field select {
    width: 100% !important;
    min-width: 0 !important;
  }
  .controls-row input[type="checkbox"] {
    width: 20px;
    height: 20px;
    min-height: 0;
    flex: 0 0 auto;
  }
  /* the "normalize by land area" / "anomaly as %" checkbox rows */
  .controls-row .field > label { min-height: 44px; font-size: 0.9rem; }
  /* size="8" multi-selects are ~170px tall; trim them so both list boxes and
     the buttons under them stay on one screen */
  .controls-row select[multiple] { height: 148px; }
  /* two buttons per row at 390px; they grow to fill whatever is left over */
  .controls-row > button { flex: 1 1 44%; min-height: 44px; }

  /* --- charts -------------------------------------------------------------
     Every chart is a fixed-viewBox SVG (1050x720 risk diagram, 1100-wide
     state map / anomaly map / cumulative plot). These used to be floored at
     min-width:720px inside a horizontally scrolling .chart-wrap; they now FIT
     the content column instead, so the whole diagram/map is visible at a
     glance and the page never scrolls sideways:

       - risk diagram: the shrink is compensated by real pinch-zoom + pan
         (js/risk.js binds touch gestures to the same transform the desktop
         wheel/drag uses), so small type is a starting view, not a dead end.
       - state maps + the cumulative curve: the user asked for whole-map fit
         over label size. The maps read fine as shapes; the cumulative plot
         is a time series that survives being squeezed, and keeping it on the
         same footing as the two maps above avoids a lone scrolling chart.

     .chart-wrap keeps overflow-x:auto from style.css as a harmless backstop;
     overscroll-behavior-x stops any residual swipe from turning into a
     browser back-navigation. */
  .chart-wrap {
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
  }
  .chart-wrap svg {
    max-width: none;
    width: 100%;
    min-width: 0;
    height: auto;
  }
  /* risk diagram only (.risk-chart is on that page's #chart-wrap): the chart
     owns one-finger drag, so it must not also scroll/zoom the page — same
     bargain a map widget makes. Everything around it still scrolls normally,
     and the state-weights charts deliberately keep the default touch-action
     so a swipe over a map scrolls the page. */
  .risk-chart,
  .risk-chart svg { touch-action: none; }

  /* --- data tables: scroll in their own box rather than squeezing cells --- */
  #table-wrap,
  #an-table-wrap {
    overflow-x: auto;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
  }
  table.data th,
  table.data td { white-space: nowrap; }

  /* --- hover tip ----------------------------------------------------------
     risk.js / states.js pin .chart-tip to the pointer with inline left/top.
     A tap near the right edge would push a 260px box off-screen (and a
     position:fixed overflow is exactly what produces page-level horizontal
     scroll), so on touch it becomes a bottom banner instead. The !important
     is required to beat the inline styles the scripts write every frame. */
  .chart-tip {
    left: 10px !important;
    top: auto !important;
    right: 10px;
    bottom: calc(10px + env(safe-area-inset-bottom, 0px));
    max-width: none;
    font-size: 0.86rem;
  }

  /* ==========================================================================
     about.html — long-form text
     ========================================================================== */
  .about-page { max-width: none; }
  .about-page h1 { font-size: 1.35rem; }
  .about-page h2 { font-size: 1.1rem; margin-top: 24px; }
  .about-page h3 { font-size: 0.99rem; }
  .about-page p,
  .about-page li { font-size: 0.94rem; line-height: 1.6; }
  /* the browser default 40px list indent costs 11% of a 360px column */
  .about-page ul,
  .about-page ol { padding-left: 21px; }
  .about-page .toc { gap: 0 18px; margin: 8px 0 2px; }
  .about-page .toc a { display: inline-flex; align-items: center; min-height: 42px; }
  /* .hz-table already carries min-width:640px inside .hz-wrap{overflow-x:auto} */
  .about-page .hz-wrap {
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
  }
  .about-page .hz-table { font-size: 0.86rem; }
  /* the creator photo floats right at min(320px,48%); in a ~336px column that
     leaves a 160px-wide ribbon of text beside it. Full-bleed above instead. */
  .about-page img {
    float: none !important;
    width: 100% !important;
    margin: 8px 0 14px !important;
  }

  /* ==========================================================================
     admin.html — single centered card
     ========================================================================== */
  /* the page centers the card with an inline align-items:center; once the
     logged-in card is taller than the viewport that clips its top out of
     reach inside the scroller, so top-align it on a phone */
  .scroll-page.admin-page { align-items: flex-start !important; padding-top: 18px; }
  .admin-page input[type="text"],
  .admin-page input[type="password"] { min-height: 44px; font-size: 16px; }
  .admin-page button { min-height: 44px; }
  .admin-page #login-btn { flex: 1 1 100%; }
  .admin-page input[type="checkbox"] { width: 20px; height: 20px; flex: 0 0 auto; }
  .admin-page label { line-height: 1.5; }

  /* ==========================================================================
     tropics.html — .sidebar + #map, so js/mobile.js gives it the bottom sheet
     ========================================================================== */
  /* This sidebar has no .hazard-row and no #update-btn, so mobile.js leaves
     #mobile-sheet-quick empty and tags the header. Without this the peek
     state is a naked 5px grip with no hint that it opens. */
  #mobile-sheet-header.no-quick::after {
    content: 'Controls';
    display: block;
    padding-bottom: 2px;
    text-align: center;
    font-size: 0.76rem;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--ink-3);
  }
  #mobile-sheet-header.no-quick #mobile-sheet-grip { margin-bottom: 7px; }

  /* The admin gate is position:absolute inside .main at z-index:2000, which
     would paint over the hamburger dropdown (1900). Drop it below the nav
     layer but keep it above the map boxes and the toast. */
  #gate {
    z-index: 1700;
    padding: 0 20px;
    text-align: center;
    font-size: 0.95rem;
    line-height: 1.5;
  }

  .storm-item { min-height: 44px; padding: 9px 10px; font-size: 13.5px; }
  .run-row { min-height: 40px; padding: 5px 0; }
  #upload-box input[type="file"] { max-width: 100%; font-size: 0.85rem; }

  /* ---- tropics: a phone layout, not the desktop one squeezed ----
     Overlays stack bottom-up above the sheet peek: wind colorbar, time
     slider, then the Members / Cities / Compare panels; the title is a
     compact strip at the top. Every card (statistics + trends, landfall,
     run / forecast animation pickers, shortcuts, member card) opens
     FULL SCREEN below the nav with its content in one column. */
  html.mobile #tc-title-arch { font-size: 11.5px !important; }
  html.mobile #map-subtitle { font-size: 12px !important; margin-top: 1px !important; }
  html.mobile #tc-title-sel { font-size: 11px; }
  html.mobile #tc-windlegend {
    bottom: calc(var(--sheet-peek) + 4px);
    width: calc(100% - 24px);
  }
  html.mobile #tc-windlegend .wl-bar { height: 15px; }
  html.mobile #tc-windlegend .wl-bar span { font-size: 9px; }
  html.mobile #tc-windlegend .caption { font-size: 10px; margin-top: 2px; }
  html.mobile #tc-timebar {
    bottom: calc(var(--sheet-peek) + 40px);
    width: calc(100% - 16px);
    padding: 6px 10px;
    gap: 8px;
  }
  html.mobile #tc-time-label { font-size: 11px; white-space: nowrap; }
  html.mobile #tc-timebar input[type="range"] { min-height: 30px; }
  html.mobile #tc-genwindow { font-size: 11px; max-width: calc(100% - 24px); }
  html.mobile #status-toast { max-width: calc(100% - 28px); font-size: 13px; }
  html.mobile #tc-hint { max-width: calc(100% - 24px); font-size: 12px; white-space: normal; }
  html.mobile #tc-newrun { left: 8px !important; right: 8px; transform: none !important; font-size: 12px; }
  /* Members / Cities / Compare: bottom-right, ABOVE the time slider,
     growing upward (button stays put at the bottom of the column) */
  html.mobile #tc-tr {
    top: auto;
    bottom: calc(var(--sheet-peek) + 92px);
    right: 8px;
    left: 8px;
    align-items: flex-end;
    flex-direction: column-reverse;
    max-height: calc(100% - var(--sheet-peek) - 170px);
  }
  html.mobile #tc-membox, html.mobile #tc-citybox, html.mobile #tc-cmp {
    width: auto !important;
    max-width: calc(100vw - 16px);
    max-height: 42dvh;
    overflow-y: auto !important;
    font-size: 11px;
  }
  html.mobile #tc-membox-list { column-count: 2 !important; }
  html.mobile #tc-cmp { min-width: 0; }
  html.mobile #tc-membox-btn, html.mobile #tc-citybox-btn { min-height: 36px; padding: 6px 12px; }
  /* full-screen cards */
  html.mobile #tc-statpop, html.mobile #tc-lfpop, html.mobile #tc-runpick, html.mobile #tc-fcpop, html.mobile #tc-keys, html.mobile #tc-memcard {
    position: fixed !important;
    inset: var(--nav-h) 0 0 0 !important;
    transform: none !important;
    width: auto !important;
    min-width: 0 !important;
    max-width: none !important;
    max-height: none !important;
    border-radius: 0 !important;
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch;
    z-index: 1600 !important;
  }
  html.mobile #tc-statpop .sp-head, html.mobile #tc-lfpop .sp-head {
    position: sticky; top: 0; z-index: 2;
    flex-wrap: wrap; gap: 6px;
    background: rgba(18,20,24,0.98);
  }
  html.mobile #tc-statpop .sp-head button, html.mobile #tc-lfpop .sp-head button { min-height: 36px; }
  html.mobile #tc-statpop .sp-body, html.mobile #tc-lfpop .sp-body { flex-direction: column; padding: 8px 10px 16px; }
  html.mobile #tc-statpop .sp-side, html.mobile #st-side, html.mobile #tc-lfpop .sp-side {
    width: auto !important; max-height: none !important; overflow: visible;
  }
  html.mobile #tc-statpop .sp-ctl { flex-wrap: wrap; row-gap: 6px; }
  html.mobile #sp-chart-wrap { height: 44dvh !important; min-height: 240px; }
  html.mobile #st-chart-wrap { height: 34dvh !important; min-height: 220px; }
  html.mobile #st-chart-wrap.arch { height: 58dvh !important; min-height: 360px; }
  html.mobile #st-heat, html.mobile #st-shift { overflow-x: auto; }
  html.mobile #st-runsel { max-height: 40dvh; }
  html.mobile #tc-runpick-list { max-height: 45dvh !important; }
  html.mobile #tc-runpick-quick button, html.mobile #tc-runpick .fc-row button, html.mobile #tc-fcpop .fc-row button { min-height: 36px; }
  html.mobile #tc-fcpop .fc-prevs { flex-direction: column; }
  html.mobile #tc-fcpop canvas { width: 100% !important; height: auto !important; }
  html.mobile #tc-keys-list { font-size: 12px; }
  /* touch: hover-only helpers are noise */
  html.mobile #tc-cursor-tip { display: none !important; }
}

/* ------------------------------------------------------------------------
   Landscape phones: short viewport, so the sheet gets taller proportionally
   and the peek loses some padding. Guarded by the same touch-only features
   so no desktop window can ever match it.
   ------------------------------------------------------------------------ */
@media (max-height: 520px) and (hover: none) and (pointer: coarse) {
  :root {
    --sheet-h: 94dvh;
    --sheet-half: 62dvh;
  }
  @supports not (height: 1dvh) {
    :root { --sheet-h: 94vh; --sheet-half: 62vh; }
  }
  #mobile-sheet-header { padding-top: 4px; }
  #mobile-sheet-grip { margin: 2px auto 8px; }
  /* Landscape is short but wide: put both quick rows (hazard + load/clear/
     stats) side by side on one line so the peek doesn't eat a third of the
     viewport. Seven buttons (4 hazards + Load/Clear/Stats) across ~800px is
     still ~90px per hazard button and ~120px per action button. */
  #mobile-sheet-quick { flex-direction: row; }
  #mobile-sheet-quick .ctl-row,
  #mobile-sheet-quick .hazard-row { flex: 1 1 0; min-width: 0; }
  #map-title { font-size: 12px; }
  .home-inner h1 { font-size: 1.1rem; }
  .home-inner p { margin-bottom: 10px; }
}
