* { box-sizing: border-box; }

/* Belt-and-suspenders with index.html's viewport meta (maximum-scale=1, user-scalable=no) and
   its gesturestart/touchmove JS guard: this is the part of "no pinch/double-tap zoom" that
   non-Safari touch browsers (Chrome/Android in particular) actually honor, via touch-action,
   rather than the viewport meta. pan-x/pan-y keeps normal scrolling working, only the zoom
   gestures are disabled.
   Universal selector, not just html/body: #screen-root (and a few other panels — the pick
   stack, the profile favorite-team list) are their own independently-scrolling
   `overflow-y: auto` containers, not html/body itself. A pinch that starts once one of those
   is already mid-scroll targets that inner element, and touch-action isn't reliably picked up
   from an ancestor once a touch sequence is already an active scroll on a descendant — this
   was reported as "I can still pinch-zoom if I initiate a scroll first" after html/body alone
   had `touch-action: pan-x pan-y`. Applying it universally (lowest possible specificity) means
   every scrollable panel is covered, including any added later, while the few elements that
   deliberately need `touch-action: none` for their own drag gestures (.swipe-card,
   .standings-chart__svg, the avatar cropper) still win via their higher-specificity class
   selectors. */
*, *::before, *::after {
  touch-action: pan-x pan-y;
}

html, body {
  /* `min-height`, NOT `height` — changed 2026-08-18, and this is the root cause of the iPad
     "sizing is weird and bad" report rather than a tidy-up. `height: 100%` pinned BOTH elements to
     exactly the viewport (measured: 1180px at 820x1180) while #app inside them ran to 2009px, so
     the document's own two boxes did not contain the page. That is invisible below 700px, where
     html and body are painted the same colour — but the desktop media query below gives body the
     #050505 letterbox while html keeps var(--bg), and because html's background propagates to the
     canvas and body's does not, the disagreement showed up as a hard horizontal line across the
     full width at exactly 100vh, with the letterbox colour above it and the app colour below.
     A floor rather than a fixed height keeps everything this was here for — the rubber-band
     overscroll colour noted below still works, and a short page still fills the viewport — while
     letting both grow with a long game list. */
  min-height: 100%;
  /* Matches #app's own --bg. html's background is what's actually visible during a mobile
     rubber-band overscroll bounce past the top/bottom of a scrollable screen (the bounce
     exposes the page underneath, not #app itself) — it used to fall through to body's
     near-black desktop letterbox color below, which flashed as a jarring black mismatch
     against the app's lighter charcoal background on every overscroll.
     Re-applied 2026-08-16 on its own, deliberately isolated from the #screen-root/#app sizing
     work it originally shipped alongside (see git history around 2026-08-16) — that other work
     got fully reverted after real-phone testing, but this specific fix was confirmed working
     and wanted before any of that piled on top of it, and doesn't depend on it: whichever
     element actually ends up scrolling (the document, today — #screen-root doesn't yet contain
     its own overflow, a separate known issue noted in Documents/roadmap.md), matching this
     color is correct either way. */
  background: var(--bg);
}

body {
  margin: 0;
  color: var(--text-on-dark);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

button {
  font-family: inherit;
}

/* Mobile-first: fills the viewport. On wider (desktop) screens it becomes a centered
   phone-width column, per the "mobile-first but still usable on desktop" requirement,
   rather than stretching game rows/buttons uncomfortably wide. */
#app {
  position: relative;
  width: 100%;
  max-width: var(--app-max-width);
  margin: 0 auto;
  min-height: 100vh;
  background: var(--bg);
  display: flex;
  flex-direction: column;
}
/* `overflow: hidden` removed here 2026-08-16 (see #screen-root's own comment just below for the
   full story — this is one half of the same fix). No known reason it was needed: no border-
   radius on #app itself, and nothing in this codebase positions a child to deliberately spill
   past #app's own box on purpose (checked before removing it, not just assumed) — the desktop
   "floating phone" look (the media query below) comes entirely from box-shadow, which paints
   regardless of overflow. Flagged here in case something surfaces later that did quietly depend
   on this clipping and nobody's found yet.*/
/* `width: 100%` above (added 2026-08-15, fixing a real bug found while writing a Playwright
   verification script) is load-bearing at >=700px, not just belt-and-suspenders: base.css's own
   desktop media query below makes `body` a flex container, and a flex item's `width: auto` sizes
   to its content (fit-content) rather than filling the container the way a plain block element's
   `width: auto` would. Whenever #app's only in-flow content happens to be empty or fully
   position:fixed/absolute — true specifically during the pre-login auth-gate state, where
   #screen-root is empty and the nav/toast-host/status-overlay are all taken out of flow — #app
   had no content left to size itself by and collapsed toward 0 width, squeezing the absolutely-
   positioned .auth-screen overlay down to just its own padding. An explicit width fixes this the
   same way it would for any flex item that's supposed to fill (then be clamped by max-width),
   not shrink-to-fit. */

@media (min-width: 700px) {
  body {
    /* The viewport strip outside the phone-width column, on wide/desktop screens. */
    background: #050505;
    display: flex;
    justify-content: center;
    /* `align-items: flex-start` fixes a REAL, VISIBLE BUG ON iPAD, reported from a real device
       2026-08-18 ("scrolling/sizing is weird and bad") and then reproduced in WebKit at 820x1180.
       Without it, this flex container's default `align-items: stretch` sizes #app to the container's
       cross size rather than to its own content — measured: #app was 1180px tall (exactly 100vh)
       while the pick list inside it ran to 2009px. So a third of the page rendered OUTSIDE #app's
       box, and since #app is what paints `--bg` (#1f1f1f) while body paints #050505, scrolling down
       crossed a hard horizontal seam where the app's background simply stopped, full width.
       flex-start lets #app size to its content, with `min-height: 100vh` still acting as the floor
       it was always meant to be.
       Only reachable at >=700px, which is why every iPhone looked fine: below the breakpoint `body`
       is not a flex container at all and #app is an ordinary block that grows normally. iPads sit
       above it in BOTH orientations, so this was every tablet, all the time. */
    align-items: flex-start;
  }
  #app {
    min-height: 100vh;
    box-shadow: 0 0 40px rgba(0, 0, 0, 0.6);
  }
}

/* `overflow-y: auto` (and `-webkit-overflow-scrolling: touch`, which only ever meant anything
   alongside it) removed here 2026-08-16, fixing a real bug found while chasing why the pick
   screen's new sticky day-headers (screens/pick.js) didn't stick on real iOS Safari. Root cause,
   confirmed by actually inspecting computed layout in both a headless Chromium and a real
   WebKit engine (Playwright), not just eyeballing a screenshot: #app above has `min-height:
   100vh` — a floor, not a ceiling — so #app (and this flex child along with it, sized to its own
   content) just grows taller than the viewport instead of ever actually overflowing its own
   box; `#screen-root`'s clientHeight always equaled its scrollHeight in every case checked. The
   *document* (`html`/`body`) is what has genuinely been scrolling this whole app the entire
   time — already correctly documented elsewhere (see html/body's own comment above, and
   components/bottomNav.js's scroll-collapse listener, which deliberately listens on `window` for
   exactly this reason) — but this element's own `overflow-y: auto`, despite never having
   anything to actually scroll, still counted as the *nearest* CSS "scroll container" ancestor for
   `position: sticky` purposes, which is what actually broke it: a sticky element positions itself
   relative to its nearest scroll container's own scrollport, and a scrollport that never
   genuinely scrolls gives sticky nothing to react to. Chromium and WebKit apparently resolve that
   specific ambiguity differently, which is exactly why this looked fine in this project's own
   Chromium-based screenshot verification and not on a real iPhone.
   This is the second attempt at touching this area — the first (2026-08-15/16, see
   Documents/roadmap.md's "Sticky Podium/Previous headers + pull-to-refresh" entry) changed
   #app/#screen-root's actual sizing model (to make #screen-root contain a real internal scroll)
   bundled together with sticky headers elsewhere, pull-to-refresh, and a Profile scroll-lock, and
   was fully reverted after real-phone testing surfaced problems with those other pieces. This
   time is deliberately narrower: #app's height model is untouched (still just `min-height:
   100vh`, still unbounded, still exactly what components/bottomNav.js's window-scroll listener
   depends on), and this only removes two `overflow` declarations that never did anything
   functional to begin with, since they never had genuine overflow to manage — verified with the
   same computed-layout inspection, not just assumed safe. Checked against
   screens/pickStack.js's lockScreenScroll (the most recent commit in this repo as of this fix,
   which temporarily sets this element's own *inline* `style.overflow`) before removing this: that
   still works exactly the same afterward — it's a plain inline-style toggle, unaffected by
   whether a class rule also sets the same property, and the "resting" state it restores to
   behaves identically either way, since this element already never scrolled in that resting
   state regardless of whether it says `auto` or the unset default.
   Still worth a real-device check before trusting this fully — see the exact conversation this
   shipped from for why the sticky bug in this codebase's own history isn't glued to Chromium
   testing. */
#screen-root {
  flex: 1 1 auto;
  /* --nav-float-gap added 2026-08-14: the nav bar now floats above the screen edge instead of
     sitting flush against it, so scrolled content needs that extra room reserved too, not just
     the bar's own height. */
  padding-bottom: calc(var(--nav-height) + var(--nav-float-gap) + 8px);
  position: relative;
}

a { color: var(--accent); }

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
