/* ──────────────────────────────────────────────────────────────────────────
   styles.css — shared global stylesheet for Prime Draft Pro
   ──────────────────────────────────────────────────────────────────────────
   Loaded from the user-facing HTML pages (index.html, app.html, view.html,
   playbook.html, results.html, terms.html, privacy.html, support.html,
   audio-audit.html, board-audio-audit.html, coming-soon.html, admin.html,
   espn-relay.html) ahead of any inline <style> blocks so per-page CSS can
   reference the variables defined here.
   Purpose:
     - Centralize shared design tokens (breakpoints, etc.)
     - Apply global mobile / touch-device rules
   The bulk of the project's CSS still lives inline in HTML files and in
   CSS-in-JS injected style blocks. This file is intentionally minimal —
   foundation only, not a wholesale CSS extraction. Future phases of the
   mobile UX pass will adopt these tokens; the existing scattered @media
   rules are left untouched.
   ────────────────────────────────────────────────────────────────────── */

/* ── Shared breakpoint tokens ───────────────────────────────────────────────
   Defined for future @media rules to reference. The existing scattered
   breakpoints (14 distinct values across the codebase per the mobile audit)
   will migrate to these tokens in subsequent phases of the mobile pass.
   These specific values match the most-commonly-used existing breakpoints:
   768px (mobile threshold — used in board.js + auctionBoard.js mobile rules
   + the viewer-mobile layout shipped in feat/viewer-mobile-layout) and
   1024px (tablet threshold).
   Usage in a future @media query (CSS Nesting / Modern syntax):
     @media (max-width: 768px) { ... }
   Note: classic @media queries cannot reference CSS variables for the
   width values themselves (variables are evaluated at element-resolution
   time, not at media-query-parse time). These tokens are useful as inline
   var() references in container queries and as named references in code
   comments / future PostCSS-style transforms. For now they primarily serve
   as documentation. */
:root {
  --bp-mobile: 768px;
  --bp-tablet: 1024px;
}

/* ── iOS tap-highlight + dark backstop ─────────────────────────────────────
   Replace iOS Safari's default semi-transparent blue tap flash with a subtle
   neutral overlay. Confirms the tap registered without the harsh default
   color, which often clashes with the project's dark + accent-heavy palette.
   Applied at the <html> element so it cascades to every tappable descendant
   on every page. Desktop unaffected (this property is iOS-specific).

   Dark backstop on html + body — without an explicit dark background here,
   the iOS PWA status-bar area (apple-mobile-web-app-status-bar-style is
   black-translucent, which renders the system area transparent over the
   underlying document) and any frame between paint flushes (fast scroll,
   overscroll) reveal the browser default white. Setting background-color
   with !important ensures the app's deepest navy (#05070e) wins over
   app.html's later-in-source-order inline gradient declaration as a paint
   fallback. The gradient still paints on top via its own background-image,
   but any frame the gradient hasn't composited reads dark, not white. */
html, body {
  background-color: #05070e !important;
}
html {
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0.08);
}

/* ── Custom-player Add/Edit modal — narrow-phone polish ─────────────────────
   The Add Custom Player modal (lib/customPlayerModal.js) uses inline styles
   on every element. At ≤480px viewport (small phones), the default 28px+32px
   inner padding squeezes the form content uncomfortably, and the 14px input
   font triggers iOS Safari's auto-zoom on focus (anything <16px does).
   Polish at narrow phones:
     • Tighten padding so form has more horizontal room
     • Bump input/select font-size to 16px (kills iOS focus-zoom)
     • Widen button tap targets (Save / Cancel each ~half-width)
     • Inline-style overrides need !important because inline styles win
       against external CSS by default. Scoped to #_addPlayerOverlay so
       the rules can only affect this modal. */
@media (max-width: 480px) {
  #_addPlayerOverlay > div {
    padding: 20px 18px !important;
  }
  #_addPlayerOverlay input,
  #_addPlayerOverlay select {
    font-size: 16px !important;
    padding: 11px 12px !important;
  }
  #_addPlayerOverlay button {
    flex: 1 !important;
    padding: 12px 16px !important;
    font-size: 14px !important;
    min-height: 44px !important;
  }
}

/* ── 44×44px touch-target floor on coarse-pointer devices ────────────────────
   Apple HIG + Material Design minimum tap target = 44px. Without this, dense
   button clusters (header pill bar, modal action rows, etc.) shrink below
   thumb-friendly size on mobile.
   Scope is conservative: native <button>, [role="button"], and the standard
   input button types. Project-specific <span>-as-button styling (.pill chips,
   etc.) is intentionally NOT included — those tend to live in dense rows
   where forcing 44px would push the row past viewport and undo deliberate
   density choices. They can opt in case-by-case in future commits.
   Known visible-impact: the draft-board secondary header is icon-only at
   ≤768px (existing rule hides .hdrBtnLabel). With this floor each icon is
   ≥44px wide, which expands the row. The header was already at risk of
   overflowing on 375px after the May 17 SFX clip fix removed horizontal
   scroll. If overflow surfaces, Phase 2 will address via Phase 2's auction
   work or a follow-up to restore icon-row scroll cleanly. */
@media (pointer: coarse) {
  button,
  [role="button"],
  input[type="button"],
  input[type="submit"],
  input[type="reset"] {
    min-height: 44px;
    min-width: 44px;
  }

  /* ── iOS rubber-band overscroll lock — scoped to the board page only ──────
     ARCHITECTURE
     - body.board-active locks body to viewport height with overflow:hidden.
       Body itself cannot scroll, so iOS has no scrollable document to
       bounce. NO position:fixed — that broke non-board pages in 22d8adfa.
     - .board (inside body.board-active) becomes the actual scroll
       container with height:100vh + overflow-y:auto. Vertical scroll of
       rounds happens INSIDE .board, not on body.
     - .frame keeps its overflow-x:auto from the board's own styles
       (horizontal team-grid scroll inside .frame is unchanged).
     - The class is set in board.js renderBoard and cleared by every
       non-board renderer in app.js. Homepage, dashboard, settings,
       playbook, etc. don't get the class so they scroll normally. */
  html, body { overscroll-behavior: none; }
  .board { overscroll-behavior: none; }

  /* iOS safe-area top inset — viewport-fit=cover lets the document
     extend behind the status bar, so the board's primary header would
     otherwise sit UNDER the iOS status bar. iPad PWA reserves the top
     ~24px for status bar touches, making the header's leftmost controls
     (+ / undo / − / clock) unclickable. Adding padding-top: env(safe-
     area-inset-top) to .hdrPrimary pushes its content below the status
     bar. content-box (default) keeps the existing 96/80px content
     height, the padding adds ON TOP, so the total rendered height
     grows by the inset amount — that's the desired behavior. */
  body.board-active .hdrPrimary {
    padding-top: env(safe-area-inset-top);
  }

  /* iOS safe-area top + bottom insets — on non-board pages (dashboard,
     settings, Start Here, playbook, marketing homepage, etc.), iPhone
     PWA mode (saved to homescreen + apple-mobile-web-app-capable=yes +
     status-bar-style=black-translucent) extends content behind the iOS
     status bar. Without top padding, the dashboard's Home button and
     other top-aligned controls sit UNDER the status bar clock/battery
     and become unclickable (iOS reserves touches over the status bar).
     The bottom-padding fix landed in 63a80c8d covered the home-indicator
     area; the top fix mirrors the same model.
     Why one rule for both insets: same scope (non-board pages on touch),
     same max() floor (preserves the existing 28px body padding when the
     safe-area-inset value is smaller — non-PWA Safari typically reports
     0). The board page has its own .hdrPrimary padding-top rule above
     because it sets body.board-active and uses overflow-hidden, so the
     body-padding model wouldn't apply there. */
  body:not(.board-active) {
    padding-top:    max(28px, env(safe-area-inset-top));
    padding-bottom: max(28px, env(safe-area-inset-bottom));
  }

  /* ── Scroll-flicker mitigation on touch devices ──────────────────
     iPad PWA scrolling on the dashboard was showing brief content
     un-rendering / re-rendering flashes as cards came into view. Root
     cause: backdrop-filter: blur(18px) on .card (app.html:249) and
     other scrolling surfaces. iOS Safari has to recompute the blur
     based on the underlying content on every scroll frame, and on
     scroll-into-view it briefly paints the card without the blur
     (transparent / wrong color) before computing it — that's the
     flash.
     Fix: disable backdrop-filter on the major scroll surfaces on
     touch devices only. Desktop keeps the frosted glass look; touch
     gets a slightly simpler (and noticeably smoother) presentation.
     Solid card surface still reads as a distinct panel thanks to the
     existing border + box-shadow + opaque var(--bg2) bg on draftCard. */
  .card,
  .draftCard {
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
  }

  /* GPU-layer hints on dashboard cards — force each into its own
     composited layer so iOS doesn't re-rasterize on every scroll
     frame. translate3d(0,0,0) is the magic incantation; will-change:
     transform tells the engine to keep the layer warm. */
  .card,
  .draftCard {
    transform: translate3d(0, 0, 0);
    will-change: transform;
    backface-visibility: hidden;
  }
  /* .frame uses 'contain' (was 'none'). On iOS PWA mode, 'contain' has
     historically been honored more reliably than 'none' for suppressing
     elastic bounce INSIDE the scroll container itself (not just chaining
     to a parent). Set both axes explicitly so the value can't get
     partially shadowed. */
  .frame {
    overscroll-behavior: contain;
    overscroll-behavior-x: contain;
    overscroll-behavior-y: contain;
    touch-action: pan-x pan-y;
  }

  body.board-active {
    overflow: hidden;
    height: 100vh;
    max-height: 100vh;
  }

  /* Option B — JS transform-pan on .frame for touch devices. .frame
     becomes non-scrollable (overflow:hidden, touch-action:none); JS
     translates .frame-inner on touchmove. iOS can't engage rubber-band
     on content it doesn't natively scroll, so the bounce is impossible
     by construction. board.js _attachManualPan owns the math. */
  body.board-active .frame {
    overflow: hidden !important;
    position: relative;
    touch-action: none;
    overscroll-behavior: none;
  }
  /* .frame-header — separate <table> with the cloned thead row, painted
     ON TOP of .frame-inner. Translates horizontally only with the body
     so columns stay aligned; stays pinned to top of .frame vertically
     so the team header is always visible. */
  body.board-active .frame-header {
    position: relative;
    z-index: 10;
    /* Explicit width matches .frame-inner (1500px). Without this, the
       header sized to .frame's clientWidth (994px on iPad) while the
       1500px-wide table inside got clipped by contain:paint, hiding
       cells 9-12. Both width AND min-width carry !important to defeat
       any inherited width:100% rule. */
    width: 1500px !important;
    min-width: 1500px !important;
    will-change: transform;
    transform: translate3d(0, 0, 0);
    backface-visibility: hidden;
    /* contain: layout only (NOT layout paint) — paint containment
       clips descendants to the element's padding box, which was the
       second half of the cells-9-12 invisibility bug. layout-only
       still wins us the perf isolation without the clipping. */
    contain: layout;
  }
  body.board-active .frame-header table {
    table-layout: fixed;
    width: 100%;
    min-width: 1500px;
    border-collapse: separate;
    border-spacing: 0;
    margin: 0;
  }
  /* .frame-inner — body table (tbody only; thead is display:none here).
     JS translates this on every touchmove for both axes. Explicit
     width:1500px (not just min-width) with !important to defeat any
     inherited width:100% from upstream rules. */
  body.board-active .frame-inner {
    position: relative;
    z-index: 1;
    will-change: transform;
    transform: translate3d(0, 0, 0);
    backface-visibility: hidden;
    contain: layout paint;
    /* display:block (was inline-block) — block elements with explicit
       width are more predictable than inline-block, which can shrink to
       content despite width settings if a parent has white-space or
       overflow rules. */
    display: block;
    width: 1500px !important;
    min-width: 1500px !important;
  }
  /* Body table — explicit width + min-width so column widths hold the
     full 1500px even though the original thead is display:none.
     Without an active first row defining widths (thead.display:none),
     tbody's empty cells could collapse the table to a narrower width
     and the pan clamp would cut off teams 9-12. !important defeats the
     base table { width:100% } rule that would otherwise win on equal
     specificity since it loads later in source order. */
  body.board-active .frame-inner table {
    table-layout: fixed !important;
    width: 1500px !important;
    min-width: 1500px !important;
  }
  /* Base CSS already sets tbody th { width: 46px } and thead th.roundHead
     { width: 46px } — both anchor the round col at 46px. Leave those.
     Team cols inherit table-layout:fixed distribution: (1500-46)/12 ≈
     121px each. The min-width below acts as a safety floor in case the
     base rules ever change. */
  body.board-active .frame-inner table td {
    min-width: 121px;
  }

  /* Rd column is HOISTED out of the table into .frame-side (see below).
     Original Rd cells inside .frame-inner / .frame-header become
     visibility:hidden — they still occupy column-width for the table's
     fixed layout (round col = 46px) but don't paint. Avoids the iOS
     Safari paint-order quirk where descendant stacking contexts inside
     transform-animated parents could leak above sibling cells. */
  body.board-active .frame-inner table tbody tr > th:first-child,
  body.board-active .frame-inner table tbody tr > td:first-child {
    visibility: hidden;
  }
  body.board-active .frame-header thead tr > th:first-child,
  body.board-active .frame-header thead tr > td:first-child {
    visibility: hidden;
  }

  /* .frame-corner — TOP-LEFT LOCKED Rd header overlay. Built by JS
     in _attachManualPan: a single-cell table holding the cloned Rd
     header (<th class="roundHead">Rd</th>). Position-absolute at
     top:0 left:0. NO transform — stays anchored regardless of pan.
     Height set inline by JS to match the team header row's measured
     offsetHeight so it sits flush with .frame-header. z-index:200
     keeps it above .frame-side (z:100), .frame-header (z:10), and
     .frame-inner (z:1). pointer-events:none lets taps fall through. */
  body.board-active .frame-corner {
    position: absolute;
    top: 0;
    left: 0;
    width: 46px !important;
    min-width: 46px !important;
    max-width: 46px !important;
    /* height set inline via JS at attach time */
    z-index: 200;
    pointer-events: none;
    /* overflow:hidden RESTORED — earlier overflow:visible let the
       inner table (which inherits 1500px width from the body table's
       class) paint over the entire board. Inner table width is now
       hard-locked to 46px via inline setProperty('important') in JS,
       so overflow:hidden here is just a safety belt against future
       inheritance accidents. */
    overflow: hidden !important;
    contain: layout;
  }
  body.board-active .frame-corner table {
    width: 46px !important;
    min-width: 46px !important;
    max-width: 46px !important;
    table-layout: fixed !important;
    border-collapse: collapse;
    border-spacing: 0;
    margin: 0;
    overflow: hidden !important;
  }
  /* Disable the base "thead th { position: sticky; top: 0; z-index: 20 }"
     rule inside .frame-corner — we position the parent, cells just flow. */
  body.board-active .frame-corner thead th,
  body.board-active .frame-corner thead td {
    position: static !important;
    z-index: auto !important;
    background: linear-gradient(180deg, #FFCF4D 0%, #F0A020 100%) !important;
    color: #000 !important;
    font-size: 14px !important;
    font-weight: 900 !important;
    text-align: center !important;
    vertical-align: middle !important;
    padding: 4px 2px !important;
    line-height: 1.2 !important;
    text-overflow: clip !important;
    overflow: visible !important;
    white-space: nowrap !important;
    width: 46px !important;
    min-width: 46px !important;
    box-sizing: border-box !important;
    border: 0 !important;
    box-shadow: none !important;
  }

  /* .frame-side — Rd BODY column overlay (round numbers only — header
     lives in .frame-corner). Built by JS: tbody-only <table> with one
     cloned Rd cell per <tr>. Position-absolute at left:0, top offset
     set inline by JS to start BELOW .frame-corner. JS sets
     translate3d(0, translateY, 0) so rounds scroll vertically with
     body cells; X stays pinned regardless of horizontal pan. z-index:
     100 keeps it above .frame-inner (z:1) and .frame-header (z:10),
     below .frame-corner (z:200). Row heights set inline by JS to
     match the body table's measured offsetHeight — static CSS would
     drift from per-league/per-render variations. */
  body.board-active .frame-side {
    position: absolute;
    /* top + height set inline via JS at attach time. Height is the
       FULL body table height (not capped at viewport) so all rounds
       render inside .frame-side; the outer .frame has overflow:hidden
       which clips excess that extends below the viewport. As Y
       translates the overlay up, later rows scroll into view. */
    left: 0;
    height: auto;
    max-height: none !important;
    width: 46px !important;
    min-width: 46px !important;
    max-width: 46px !important;
    z-index: 100;
    pointer-events: none;
    background: rgb(8, 11, 22);
    /* overflow:hidden lets the inner table extend past .frame-side's
       computed-box without paint leakage — width is hard-locked at
       46px so nothing leaks horizontally either. */
    overflow: hidden !important;
    will-change: transform;
    transform: translate3d(0, 0, 0);
    backface-visibility: hidden;
    contain: layout;
  }
  body.board-active .frame-side table {
    width: 46px !important;
    min-width: 46px !important;
    max-width: 46px !important;
    table-layout: fixed !important;
    border-collapse: collapse;
    border-spacing: 0;
    margin: 0;
    overflow: hidden !important;
  }
  body.board-active .frame-side tbody th,
  body.board-active .frame-side tbody td {
    /* height set inline by JS — vertical-align: middle handles centering */
    color: #FFCF4D !important;
    font-weight: 900 !important;
    font-size: 18px !important;
    text-align: center !important;
    vertical-align: middle !important;
    background: rgb(8, 11, 22) !important;
    padding: 0 !important;
    line-height: 1.2 !important;
    text-overflow: clip !important;
    overflow: visible !important;
    white-space: nowrap !important;
    width: 46px !important;
    min-width: 46px !important;
    box-sizing: border-box !important;
    /* Subtle gold dividers — bottom separates rounds; right closes the
       column off from the panning team cells so the Rd column reads as
       a distinct sticky panel. Left edge is the screen edge, so no
       border needed there. */
    border-top: 0 !important;
    border-left: 0 !important;
    border-bottom: 1px solid rgba(240, 192, 64, 0.15) !important;
    border-right: 1px solid rgba(240, 192, 64, 0.15) !important;
    box-shadow: none !important;
  }
  body.board-active .frame-side table {
    border: 0 !important;
    box-shadow: none !important;
  }
  /* Corner header gets the same gold right border to align with the
     Rd column underneath + a dark bottom border to match the team
     header strip's bottom edge (base `thead th` rule's divider). */
  body.board-active .frame-corner thead th,
  body.board-active .frame-corner thead td {
    border-bottom: 2px solid rgba(0, 0, 0, 0.45) !important;
    border-right: 1px solid rgba(240, 192, 64, 0.15) !important;
  }
}

/* ── Audio Settings consolidated dropdown (Present mode + narrow viewport) ─
   When the commissioner is presenting on iPad-sized viewports (≤1180px),
   the 5 inline header pills (3 main + 2 viewer) overflow the secondary
   row. This dropdown consolidates them into one button + panel.
   Visibility is media-query controlled here; the button is rendered by
   board.js inside .hdrSecRight whenever _isPresenting() is true.
   body.presenting is toggled in openPresentationMode subscribe + _teardown-
   PresenterChannel so the inline-pill hide is scoped to the live-present
   state only — non-presenting state keeps the inline pills on all
   viewports as today. */
#audioSettingsBtn {
  display: none;
}
@media (max-width: 1180px) {
  body.presenting #audioSettingsBtn {
    display: inline-flex;
    align-items: center;
    gap: 4px;
  }
  /* Hide the inline pills this dropdown replaces. DOM nodes stay so
     _setHeaderPill dual-sync (broadcast + rotation-to-desktop) still
     reaches them by ID — only the visual surface is swapped. */
  body.presenting #alertsTogglePill,
  body.presenting #audioMuteTogglePill,
  body.presenting #rankingsTogglePill {
    display: none !important;
  }
  body.presenting .viewerCtrlGroup {
    display: none !important;
  }
}

/* Panel — position:fixed with JS-set top/left so it escapes any ancestor
   overflow box (per CLAUDE.md "Don't add overflow-x: auto…"). Mirrors
   .sfxPanel architecture. Two columns at iPad portrait+; collapses to
   single column under 460px so portrait-phone viewports don't overflow. */
.audioSettingsPanel {
  position: fixed;
  z-index: 10000;
  background: #0e1521;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 12px;
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.55);
  padding: 14px 16px 16px;
  min-width: 340px;
  max-width: calc(100vw - 16px);
  color: #e6ecf5;
  font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
}
.audioSettingsHeader {
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(240, 192, 64, 0.85);
  margin-bottom: 10px;
}
.audioSettingsCols {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.audioSettingsRow .headerPill {
  width: 100%;
  justify-content: center;
}

/* Desktop fallback: pointer:fine devices keep CSS overflow:auto scroll
   on .frame (from board.js base rule). .frame-inner is invisible to
   layout via display:contents so the desktop table renders exactly as
   before — column widths, sticky thead, all native. .frame-header is
   only injected by _attachManualPan (which gates on pointer:coarse) so
   it never exists on desktop. */
@media (pointer: fine) {
  .frame-inner { display: contents; }
}
