/* dc-mobile.css — shared responsive layer for DeepCover 2.0.
 * Linked LAST in every page <head> so it overrides per-page inline styles.
 * Backbone fixes (nav + tables + base scaling) live here; per-page polish
 * stays in each page's own <style>. Breakpoint: phones ≤720px. */

/* WCAG-AA: the brand gold #c69200 on a white card is only 2.80:1 — below the 3:1
 * AA-Large bar (and well below 4.5:1 for small gold text like eyebrows / "go" links).
 * In LIGHT mode only, deepen gold to #9b6000 (5.16:1 on white) so gold text passes AA.
 * DARK mode keeps the bright brand gold (it already passes on the dark card). The
 * html[data-theme=...] selector outspecifies each page's :root, so this wins app-wide. */
html[data-theme="light"]{ --gold:#9b6000; }

/* CURSOR HYGIENE (app-wide, desktop): plain text (headings, table cells, labels) showed
 * the text I-beam on hover — it reads like a stray blinking caret sitting on the page.
 * Force the normal arrow everywhere, then restore the pointer on interactive controls and
 * the text caret on real inputs. Text stays selectable (copy still works); only the cursor
 * shape changes. */
body{ cursor:default; }
a[href], button, select, summary, label, [role="button"], [onclick],
th[onclick], th[data-k], th[data-sort], .cddBtn, .dclgBtn, .dcTab, .arTab, .plink{ cursor:pointer; }
input, textarea, [contenteditable]{ cursor:text; }

/* MATCHUP "advantage"/"trouble" strips (.gscroll #advWrap/#trbWrap → table.gtbl):
 * the data rows + stat-pill cells showed the text I-beam on hover. Pin them to the
 * arrow; the SORTABLE column headers (every table.gtbl th carries data-k and a click
 * handler) and the clickable player-name links (a.plink, already pointer above) keep
 * the pointer hand. Cells stay selectable — only the cursor shape changes. */
table.gtbl, table.gtbl tr, table.gtbl td, table.gtbl td .hpill{ cursor:default; }
table.gtbl th{ cursor:pointer; }
table.gtbl td a.plink{ cursor:pointer; }

/* SMOOTH CROSS-DOCUMENT NAVIGATION (Chromium View Transitions, progressive enhancement).
 * The site is multi-page, so every navigation is a full reload and the JS-built shell
 * (sidebar + top bar) used to flash/re-pop. With cross-document view transitions the
 * browser holds the old frame, then cross-fades to the new one — no hard white flash —
 * and naming the shell keeps it visually stable instead of cross-fading. Ignored where
 * unsupported (no effect, no risk). prefers-reduced-motion users get an instant swap. */
@view-transition { navigation: auto; }
aside.dcSide { view-transition-name: dcSidebar; }
header.bar   { view-transition-name: dcTopbar; }
::view-transition-group(dcSidebar), ::view-transition-group(dcTopbar) { animation-duration: 0s; }
@media (prefers-reduced-motion: reduce) { ::view-transition-group(*){ animation: none !important; } }

/* SORT DISCOVERABILITY (app-wide): every clickable column header carries a faint
 * up/down hint so users know they can sort. The ACTIVE column already shows its
 * real ▲/▼ in text (and gets class .on), so the hint is suppressed there. Sortable
 * headers are marked, across the site, by onclick="sortBy" / data-k / data-sort /
 * role="button". Non-sortable headers (rank #, scorecard order, standings) carry
 * none of these, so they stay clean. */
th[onclick]:not(.on), th[data-k]:not(.on), th[data-sort]:not(.on), th[role="button"]:not(.on){ cursor:pointer; }
th[onclick]:not(.on)::after, th[data-k]:not(.on)::after, th[data-sort]:not(.on)::after, th[role="button"]:not(.on)::after{
  content:"⇅"; margin-left:.28em; opacity:.32; font-weight:400; font-size:.92em;
}
th[onclick]:hover::after, th[data-k]:hover::after, th[data-sort]:hover::after, th[role="button"]:hover::after{ opacity:.7; }

/* "Sort by" dropdown rendered above tableHTML()-based tables (team-season, squad,
 * match-centre leaderboards). Keeps the explicit control consistent app-wide. */
.tblSortBar{ display:flex; justify-content:flex-end; margin:2px 0 8px; }
.tblSortBar label{ color:var(--muted); font-weight:800; font-size:.7rem; text-transform:uppercase; letter-spacing:.04em; display:inline-flex; align-items:center; gap:6px; }
.tblSortBar select{ font-family:inherit; font-size:.74rem; font-weight:700; text-transform:none; letter-spacing:0; padding:4px 8px; border:1px solid var(--line); border-radius:8px; background:var(--card); color:var(--ink); cursor:pointer; }

/* NO HORIZONTAL TABLE SLIDERS (app-wide): a 2-up .grid2 that holds a wide table used to
 * shrink the column below the table's width, forcing a horizontal scrollbar. Make .grid2
 * container-aware — it stays 2-up only while each column can be >=520px (enough for the
 * widest dossier/venue/victims table), otherwise it drops to ONE full-width column where
 * the table fits with no slider. (Linked last, so this overrides each page's 1fr 1fr.) */
.grid2{ grid-template-columns:repeat(auto-fit, minmax(560px, 1fr)); }
/* very wide tables (the 9-column Compare opponent tables) need ~740px before going 2-up */
/* min(740px,100%) clamps the column floor to the viewport so a phone narrower than the
   floor stacks to ONE full-width column instead of a 740px column overflowing the page. */
.grid2.wideGrid{ grid-template-columns:repeat(auto-fit, minmax(min(740px,100%), 1fr)); }
/* dcPair / dcPairLg · pair two stacked full-width siblings into a side-by-side strip when the
 * row is wide enough, auto-stacking to 1-up when narrow (phone / tight column). Pure layout,
 * used across the dossiers. dcPair = compact stat-card pairs; dcPairLg = chart/table pairs that
 * need more width before they pair. (auto-fit handles the responsiveness.) */
/* min(floor,100%): on a phone narrower than the floor, the column shrinks to 100% of the
   container and stacks 1-up — without it, auto-fit keeps the hard 300/460px floor and the
   column (and its echarts canvas) overflows the page edge. */
.dcPair  { display:grid; gap:16px; align-items:start; grid-template-columns:repeat(auto-fit, minmax(min(300px,100%), 1fr)); }
.dcPairLg{ display:grid; gap:16px; align-items:start; grid-template-columns:repeat(auto-fit, minmax(min(460px,100%), 1fr)); }
.dcPair > *, .dcPairLg > * { min-width:0; }

/* NOTE: the page-entrance animation (a CSS transform on .wrap) was REMOVED — it is
 * the prime suspect for the mobile touch-scroll freeze. Animating a transform on
 * .wrap (the tall main scroll container) can lock scrolling on Android WebView.
 * Rolled back to guarantee scroll; can return later as an opacity-only fade if wanted. */

/* DESKTOP header: cluster the controls (league · language · dark-mode · refresh) on
 * the right of the top row, evenly aligned, with the nav on its own row below. The
 * theme toggle used to float far-right (margin-left:auto) away from the language
 * button, and Refresh wrapped onto a line of its own under the nav. (Mobile keeps its
 * own @media(max-width:720px) header rules, untouched.) */
/* Legacy in-page desktop header layout. Bumped 721 -> 980 so it ONLY applies where the
 * desktop shell already hides header.bar (>=980, inert) — never in the 721-979px band a
 * landscape phone sits in. Below 980 the mobile shell (next block) fully owns the chrome,
 * so the old horizontal pill-nav can no longer reappear on rotation. */
@media (min-width: 980px) {
  header.bar .dcLeagueBox { order: 2; margin-left: 16px; }   /* LEFT, right after the wordmark — not pushed to the far right */
  header.bar .dcLangBox   { order: 3; margin-left: 8px; }
  header.bar #themeBtn    { order: 4; margin-left: 8px; width: 44px; height: 44px; }
  header.bar .dcHdrShare  { order: 5; margin-left: 8px; }
  header.bar #dcHdrRefresh{ order: 6; margin-left: 8px; }
  header.bar .topnav      { order: 7; flex: 0 0 100%; margin-left: 0; }
}

/* mobile-only chrome hidden on desktop; shown only on mobile (rules in @media) */
.dcHamb, .dcTabbar, .dcScrim, .dcSheet{ display:none; }

/* "No photos" preview mode (set by dc-mobile.js on ?nophotos=1): force every
 * avatar to its initials, hiding the <img> regardless of where the photo URL
 * came from (API or DuckDB parquet). Off by default — zero effect normally. */
html.dc-nophotos .av img{ display:none !important; }
html.dc-nophotos .av i{ display:block !important; }

/* Mobile shell (hamburger header + bottom tab bar + mobile search + layout). Bumped the
 * ceiling 720 -> 979 so it runs right up to the 980px desktop-shell boundary: LANDSCAPE
 * phones and small tablets (721-979px) now get this mobile nav instead of falling into the
 * old gap that re-exposed the legacy horizontal nav. (Table-compaction at line ~270 stays
 * at <=720 — those widths have room for full tables.) */
@media (max-width:979px){
  /* ---- WebView zoom guard (fixes "poora page zoom" + "table slide nahi hota") ----
   * A data table renders full-width for a moment BEFORE dc-mobile.js wraps it in a
   * .tblScroll box. On Android WebView that brief page-level overflow makes the WHOLE
   * page zoom out to fit — and then a horizontal swipe pans the zoomed page instead of
   * scrolling the table. Clipping page-level horizontal overflow keeps the page locked
   * at 1:1 scale; wide tables still scroll inside their own .tblScroll container. */
  /* SCROLL-FREEZE FIX: overflow-x:hidden on the <html> root makes it a scroll
   * container and, on Android WebView, LOCKED vertical document scroll (content
   * frozen — only the fixed bottom tab bar still responded to touch). Use
   * overflow-x:clip instead — it clips the horizontal overflow (keeps the zoom
   * guard) WITHOUT becoming a scroll container, so vertical scroll works. Also
   * dropped overscroll-behavior-y:none (added recently). */
  html, body { overflow-x: clip; max-width: 100%; }

  /* ---- layout shell ---- */
  .wrap{ padding:14px 12px 18px !important; }
  /* clear space for the fixed bottom tab bar so the last row / footer isn't hidden */
  body{ padding-bottom:calc(76px + env(safe-area-inset-bottom)) !important; }

  /* ---- mobile search bar + inline suggestions (injected by dc-mobile.js) ---- */
  /* STICKY: pin the search to the top so it stays reachable while scrolling. Opaque page
   * background fills behind it; z-index above content, below the bottom tab bar (z:200). */
  #dcMobSearch{ position:sticky; top:0; z-index:60; margin:2px 0 15px;
    background:var(--bg,#fff); padding-top:8px; }
  #dcMobSearch .dcMobSRow{ display:flex; align-items:center; gap:9px;
    background:var(--field,#fbfcfe); border:1px solid var(--line,#e8edf5); border-radius:13px;
    padding:2px 14px; box-shadow:0 1px 2px rgba(15,23,42,.04); }
  #dcMobSearch .dcMobSRow:focus-within{ border-color:var(--gold,#c69200); box-shadow:0 0 0 3px #c6920026; }
  #dcMobSearch .dcMobSIc{ color:var(--muted,#64748b); font-size:1.15rem; flex:0 0 auto; }
  #dcMobSearch input{ flex:1; min-width:0; border:0; background:transparent; outline:none;
    font:600 1rem Archivo,sans-serif; color:var(--ink,#0f172a); padding:12px 0; }
  #dcMobSearch input::-webkit-search-cancel-button{ -webkit-appearance:none; }
  .dcMobSugg{ position:absolute; z-index:120; left:0; right:0; top:calc(100% + 6px); max-height:62vh; overflow:auto;
    background:var(--card,#fff); border:1px solid var(--line,#e8edf5); border-radius:13px;
    box-shadow:0 18px 42px rgba(15,23,42,.22); padding:5px; }
  .dcMobSugg[hidden]{ display:none; }
  .dcMobGrp{ font:800 .6rem Archivo,sans-serif; letter-spacing:.13em; text-transform:uppercase;
    color:var(--muted,#64748b); padding:9px 10px 4px; }
  .dcMobOpt{ display:flex; align-items:center; gap:9px; padding:11px 10px; border-radius:9px;
    text-decoration:none; color:var(--ink,#0f172a); font:700 .94rem Archivo,sans-serif; }
  .dcMobOpt:active, .dcMobOpt:hover{ background:var(--soft,#f6f8fc); }
  .dcMobOpt .ic{ flex:0 0 auto; color:var(--gold,#c69200); }
  .dcMobOpt .tt{ flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .dcMobOpt .st{ flex:0 0 auto; color:var(--muted,#64748b); font-size:.72rem; font-weight:700; }

  /* ---- header: tidy SINGLE-ROW mobile chrome ----
   * brand (left) + on the right: league switcher (essential), language, theme toggle.
   * align-items:center keeps every control on one baseline (the .dcLeagueBox /
   * .dcLangBox flex containers used to collapse to ~6px tall — the header's row-gap —
   * letting their .dclgBtn / select children overflow into a ragged second visual row).
   * The per-page Share + the Refresh buttons are REDUNDANT on mobile (Share is offered
   * per-page; Refresh = a page reload) so they're hidden here, freeing the width that
   * was forcing the controls to wrap. The .topnav still wraps to its own full-width row
   * below as the hamburger dropdown. Desktop (>=980px) shell layout is untouched. */
  /* header.bar establishes a stacking context (view-transition-name: dcTopbar), which TRAPPED
   * the open league menu's z-index inside it — so the sticky search (a sibling at z:60) painted
   * OVER the menu's middle, splitting it into the reported "two overlapping panels". Lift the
   * whole header context above the search/band (but below the bottom-nav z:200) so the menu
   * inside it paints on top. THIS is the real fix; the .dclgMenu z:1200 alone was confined. */
  header.bar{ flex-wrap:wrap; align-items:center; row-gap:6px; column-gap:6px; padding:10px 2px 10px; position:relative; z-index:150; }
  /* 1.15rem (down from 1.34) + the trimmed header padding keep brand + league + language +
   * theme on ONE row down to ~360px (inside .wrap's 12px padding the header content box is
   * only ~328px, so the original 1.34rem wordmark pushed theme onto a second row). Below
   * ~360px it wraps gracefully to a clean 2-row layout (the boxes no longer collapse). */
  header.bar .wordmark{ order:1; font-size:1.15rem !important; min-width:0; padding-left:2px; }
  /* explicit height + align-self:center stops the .dcLeagueBox / .dcLangBox flex containers
   * from collapsing to the header's 6px row-gap (the bug that let their button/select spill
   * into a second visual row). flex:0 0 auto keeps each at its natural width, no squeeze. */
  header.bar .dcLeagueBox{ order:2; margin-left:auto; height:34px; align-self:center; flex:0 0 auto; }
  header.bar .dcLangBox{ order:3; margin-left:0; height:34px; align-self:center; flex:0 0 auto; }
  header.bar #themeBtn{ order:4; margin-left:0; flex:0 0 auto; width:40px; height:34px; }
  /* redundant on mobile — hide so the header stays a clean single row */
  header.bar #dcHdrShare, header.bar #dcHdrRefresh, header.bar .dcHamb{ display:none !important; }
  header.bar .topnav{
    order:5; flex:0 0 100%; width:100%; display:none !important;
    flex-direction:column; gap:2px; margin:6px 0 0; padding:6px;
    background:var(--card); border:1px solid var(--line); border-radius:12px;
    box-shadow:0 18px 42px rgba(15,23,42,.18);
  }
  header.bar .topnav.dcOpen{ display:flex !important; }
  header.bar .topnav a{ width:100%; padding:11px 12px; font-size:.96rem; border-radius:8px; }
  /* NAV DE-DUP · one "Matchups" entry. The rail + the More sheet already keep only
   * Matchups; the raw per-page topnav still lists a redundant "Compare" (-> /compare.html,
   * the same target matchups.html redirects to). Hide it so the mobile hamburger shows one. */
  header.bar .topnav a[href="/compare.html"]{ display:none !important; }

  /* ---- tables: scroll sideways inside a wrapper, never break the page ---- */
  /* HORIZONTAL-only scroll: the table slides sideways; the PAGE handles vertical.
   * (A max-height box with a sticky header made the inner vertical scroll fight the
   * page scroll on touch — the leaderboard "slide" felt janky / trapped. Removed.) */
  .tblScroll{ overflow-x:auto; overflow-y:visible; max-width:100%; -webkit-overflow-scrolling:touch;
    overscroll-behavior-x:contain; scrollbar-width:thin; border-radius:12px; }
  .tblScroll table{ white-space:nowrap; }

  /* SELF-WRAPPED TABLES — same clean horizontal-scroll behaviour as .tblScroll.
   * Several pages wrap their own data tables in a private scroll container
   * (tableHTML()'s .tableWrap on team-season / squad / match-centre / live-match /
   * data-trust / records / lab-wasm; venue's inline overflow-x:auto on teamTbl +
   * ledgerTbl; position-rankings' .card.scroll). Because those ancestors already
   * scroll, dc-mobile.js intentionally SKIPS the .tblScroll wrap for them — so they
   * never inherited the white-space:nowrap + touch-scroll affordance and their cells
   * wrapped to 2-3 ragged lines on a phone instead of staying single-line and sliding.
   * Give every self-wrapper the same treatment so wide tables scroll cleanly app-wide.
   * Numbers / colours / sort handlers are untouched — this only sets overflow + nowrap. */
  .wrap .tableWrap, .wrap .gscroll, .wrap .card.scroll{
    overflow-x:auto; -webkit-overflow-scrolling:touch;
    overscroll-behavior-x:contain; scrollbar-width:thin; max-width:100%;
  }
  .wrap .tableWrap > table, .wrap .gscroll > table, .wrap .card.scroll > table{ white-space:nowrap; }
  /* venue.html wraps two tables in a bare inline <div style="overflow-x:auto"> with no
   * class — match it by the inline style so teamTbl + ledgerTbl scroll cleanly too. */
  .wrap [style*="overflow-x:auto"] > table{ white-space:nowrap; }

  /* ---- common multi-column grids → single column ---- */
  .leaders, .boards{ grid-template-columns:1fr !important; }
  /* .grid2's desktop rule demands a 560px (wideGrid: 740px) MIN column so wide tables
   * never get squeezed into a slider. But on a phone that 560px is WIDER than the screen,
   * so the grid — and the strips/charts/tables inside it — overflowed the viewport and got
   * clipped by the page-level overflow-x:clip: frozen, unscrollable (the "trouble matchup
   * slide nahi hota" bug). On mobile there's only ever one column anyway, so force a single
   * shrink-to-fit track; inner wide tables still scroll in their own .tblScroll box. */
  .grid2, .grid2.wideGrid{ grid-template-columns:minmax(0,1fr) !important; }

  /* ---- universal overflow safety net ----
   * Root cause of leftover page-overflow: a flex/grid item defaults to
   * min-width:auto, so wide inner content (a peer-bar, a nowrap toolbar)
   * forces the whole column — and the page — wider than the screen.
   * Letting those items shrink (min-width:0) means inner tables scroll in
   * their .tblScroll box and everything else reflows to fit. */
  .wrap [class*="grid"] > *, .wrap [class*="Grid"] > *,
  .wrap .pstats, .wrap .pstats > *, .wrap .splitRow > *,
  .wrap .edge > *, .wrap .card > * { min-width:0; }
  .wrap .card, .wrap .panel, .wrap .pstats .bar, .wrap .src { max-width:100%; }
  /* loading skeletons sometimes carry hard-coded px widths (e.g. squad/matchup hero
   * bars at width:430px) that exceed a phone's content box and get clipped/frozen by
   * overflow-x:clip until the API resolves. A skeleton must never be wider than its
   * container — cap them so the pre-load state can't overflow the page. */
  .skel{ max-width:100% !important; }
  /* control / toolbar / tab rows wrap instead of pushing the page sideways */
  .wrap .tctl, .wrap .ctl, .wrap .ctrls, .wrap .controls, .wrap .modeRow,
  .wrap .kickRow, .wrap .lbctl, .wrap .heroControls, .wrap .tabRow,
  .wrap .matchTabs, .wrap .modeTabs, .wrap .seg, .wrap .addRow,
  .wrap .tabs, .wrap .filters{ flex-wrap:wrap; }

  /* ---- inputs / dropdown menus never overflow the viewport ---- */
  input, select, textarea, .cddBtn, .pick input, .cddMenu, .playerMenu, .dclgBtn, .dclgMenu{ max-width:100% !important; }
  /* OPEN LEAGUE DROPDOWN must sit ABOVE the sticky mobile search (#dcMobSearch) and the
   * live band — both z-index:60. At equal z the league menu and the search "panel"
   * stacked ambiguously and visually overlapped (the reported "two overlapping panels").
   * Lift it well clear; mobile-only so the desktop top-right menu is untouched. */
  header.bar .dclgMenu{ z-index:1200 !important; }
  .heroControls{ gap:10px; }
  .pick input{ width:100% !important; }

  /* ---- typographic scale-down for big hero text ---- */
  .htitle{ font-size:2rem !important; }
  .hero{ padding:22px 18px !important; }

  /* ---- scatter / peer-map charts: generous height on mobile so the dots spread
   * (the per-page tightened grid already frees the side-axis numbers). Wins over
   * per-page + inline heights so the plot never looks squished ("chipka"). ---- */
  .wrap #peerChart, .wrap #scatter, .wrap #armap,
  .wrap #batScatter, .wrap #bowlScatter{ height:clamp(440px,66vh,560px) !important; min-height:440px; }

  /* ---- BOTTOM TAB BAR + "More" sheet (mobile primary navigation) ----
   * Fixed to the viewport bottom (appended to <body> by dc-nav.js), always
   * reachable no matter how far the page is scrolled. Built from .topnav links. */
  .dcTabbar{
    position:fixed; left:0; right:0; bottom:0; z-index:200; display:flex;
    background:var(--card); border-top:1px solid var(--line);
    padding-bottom:calc(env(safe-area-inset-bottom) + 12px); box-shadow:0 -6px 22px rgba(15,23,42,.12);
  }
  .dcTabbar .dcTab{
    position:relative; flex:1 1 0; min-width:0; border:0; background:transparent; cursor:pointer;
    display:flex; flex-direction:column; align-items:center; justify-content:center; gap:3px;
    padding:9px 2px 9px; color:var(--muted); text-decoration:none;
    font:800 .62rem Archivo,sans-serif; letter-spacing:.02em;
    transition:transform .12s ease, color .12s ease;
  }
  /* tap feedback: the tab dips slightly on press and the gold colour fades in */
  .dcTabbar .dcTab:active{ transform:scale(.93); }
  /* live-match red dot on the Live tab (class set by dc-nav.js when dc-has-band/ticker) */
  .dcTabbar .dcTab.dcTabLive::after{ content:""; position:absolute; top:7px; left:calc(50% + 9px);
    width:6px; height:6px; border-radius:50%; background:#dc2626; box-shadow:0 0 0 2px var(--card); }
  .dcTabbar .dcTab svg{ width:21px; height:21px; }
  .dcTabbar .dcTab span{ max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .dcTabbar .dcTab.dcActive{ color:var(--gold); }
  .dcTabbar .dcTab.dcActive::before{ content:""; position:absolute; top:0; left:50%; transform:translateX(-50%); width:30px; height:2px; background:var(--gold); border-radius:0 0 3px 3px; }

  .dcScrim{ position:fixed; inset:0; z-index:210; display:block; background:rgba(8,12,20,.55); opacity:0; pointer-events:none; transition:opacity .2s ease; }
  .dcScrim.dcShow{ opacity:1; pointer-events:auto; }
  .dcSheet{
    position:fixed; left:0; right:0; bottom:0; z-index:220; display:block; background:var(--card);
    border-top-left-radius:18px; border-top-right-radius:18px;
    padding:8px 14px calc(18px + env(safe-area-inset-bottom));
    transform:translateY(105%); transition:transform .26s cubic-bezier(.22,.61,.36,1);
    max-height:80vh; overflow:auto; box-shadow:0 -16px 44px rgba(15,23,42,.30);
  }
  .dcSheet.dcShow{ transform:translateY(0); }
  .dcSheet .dcGrab{ width:42px; height:4px; border-radius:99px; background:var(--line); margin:6px auto 12px; }
  .dcSheet h4{ font-size:.64rem; font-weight:800; letter-spacing:.14em; text-transform:uppercase; color:var(--muted); margin:0 4px 10px; }
  .dcSheetGrid{ display:grid; grid-template-columns:1fr 1fr; gap:8px; }
  .dcSheetGrid .dcTile{ display:flex; align-items:center; padding:13px 13px; border-radius:12px;
    text-decoration:none; color:var(--ink); font-weight:700; font-size:.9rem;
    background:var(--soft); border:1px solid var(--line);
    min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .dcSheetGrid .dcTile.dcCur{ color:var(--gold); border-color:#c6920055; background:#c692001a; }
}

/* ---- MATCHUP "advantage"/"trouble" strips: PHONE COMPACTION (table.gtbl) ----
 * The "Matchups, venues & conditions" → Bowler/Batter advantage cards (#advWrap /
 * #trbWrap → table.gtbl) rendered tall on phones: a 26px avatar + roomy row padding
 * + .74rem body / .72rem pills meant only a handful of opponents fit per screen. The
 * user wants the whole opponent list digestible in ~one screen, so on ≤720px we:
 *   • HIDE the round avatar (the name + green pills carry the row; the photo is the
 *     biggest vertical cost and least information per pixel),
 *   • cut row padding + line-height so rows are much shorter,
 *   • shrink the stat pills + body font a notch,
 *   • tighten the name-column cap so 6 metric columns + name fit a ~380px viewport
 *     with no ugly horizontal overflow.
 * Numbers, the green control-bar/heat colours (inline DCScales bg) and pointer/sort
 * behaviour are all untouched. Desktop (>720px) keeps its full styling. */
@media (max-width:720px){
  table.gtbl{ font-size:.64rem; }
  table.gtbl th{ padding:3px 2px; font-size:.5rem; letter-spacing:0; }
  table.gtbl td{ padding:2px 2px; line-height:1.12; }
  table.gtbl td.heat{ padding:1px 1px; }
  table.gtbl td.heat .hpill{ padding:2px 2px; font-size:.6rem; border-radius:5px; }
  /* drop the avatar (biggest vertical cost, lowest info); name + pills carry the row */
  table.gtbl .gnmCell{ gap:0; }
  table.gtbl .gnmCell .av{ display:none; }
  table.gtbl .gnmCell .nmtxt{ max-width:64px; font-size:.66rem; }
  /* Cap the MATCHUP player-name text (.gnmCell .nmtxt) tight so the matchup table's Outs
   * column still fits a ~360px phone. The cell cap below is widened to 150px for the VENUE
   * table, whose cell (.gnm2) holds the ground name + "N matches · NN balls" — at 64px that
   * balls sub-line was being cut off. The matchup cell is already ~68px (its .nmtxt is
   * capped), so 150px never loosens it; only the venue cell uses the extra room. */
  table.gtbl td:first-child{ max-width:150px; }
}

/* A11y: visible keyboard focus ring — many controls set outline:none with no
   replacement, so keyboard users couldn't see focus. :focus-visible shows only
   for keyboard nav (not mouse clicks), so pointer users see no extra noise. */
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible,
textarea:focus-visible, [tabindex]:focus-visible, [role="button"]:focus-visible,
[role="tab"]:focus-visible, th[onclick]:focus-visible, [onclick]:focus-visible {
  outline: 2px solid var(--gold, #c69200);
  outline-offset: 2px;
  border-radius: 4px;
}

/* ---- Anti-FLASH: pre-stage the desktop shell layout in SYNCHRONOUS CSS ----
 * dc-shell.js (loaded async) hides the legacy in-page top bar, shifts the content
 * for the fixed rail + top bar, and builds the sidebar. Because it runs a beat
 * AFTER first paint, the OLD horizontal nav used to FLASH on every navigation.
 * Doing the same hide + space-reservation here (render-blocking <link>) means the
 * old bar never paints and the content doesn't jump — dc-shell just fills the rail. */
@media (min-width: 980px) {
  header.bar { display: none !important; }
  body { padding-left: 214px; padding-top: 60px; }
  .wrap { margin-left: 0 !important; margin-right: auto !important; padding-left: 16px !important; }
  /* FROZEN TABLE HEADERS (desktop only · option b) · long tables lost their column labels
   * on scroll. Give the long-table scroll boxes a HEIGHT CAP so they scroll INTERNALLY,
   * then pin the header to the box top. A cap (not a fixed height) leaves short tables at
   * their natural height with NO scrollbar — only genuinely long tables get an inner scroll.
   * Scoped to the leaderboard (#lbTbl, always wrapped in .tblScroll by dc-mobile.js) + the
   * page-level .tableWrap data tables (records / team-season / scorecards). The compact
   * dossier .gtbl / .gscroll heat-pill strips are NOT .tblScroll-wrapped, so untouched.
   * >=980px only — phones keep the horizontal .tblScroll behaviour unchanged. */
  html.dc-shelled .tblScroll, .wrap .tableWrap{ max-height:78vh; }
  /* …EXCEPT the live-match / match-centre scorecards (#scorecards): those are short, fixed
   * innings — an inner vertical scroll there is just annoying, so let them run FULL height
   * and the PAGE scrolls instead (no inner slider). id-specificity beats .wrap .tableWrap. */
  #scorecards .tableWrap{ max-height:none; }
  #scorecards .tableWrap thead th{ position:static; box-shadow:none; }
  #lbTbl thead th, .tableWrap thead th{
    position:sticky; top:0; z-index:5;
    background:var(--card); box-shadow:0 1px 0 var(--line);
  }
}

/* ============================================================================
 * DARK-MODE VISUAL FIXES (app-wide, linked-last overrides).
 * ==========================================================================*/
/* (1) CARD DEPTH — per-page .card shadow (rgba(15,23,42,.05)) is invisible on the
 *     dark canvas, so cards read flat + hover does nothing. Theme-aware tokens. */
html{
  --shadow:0 1px 2px rgba(15,23,42,.04), 0 10px 30px rgba(15,23,42,.05);
  --shadow-lift:0 10px 30px rgba(15,23,42,.12);
}
html[data-theme="dark"]{
  --shadow:0 1px 0 rgba(255,255,255,.04) inset, 0 12px 34px rgba(0,0,0,.5);
  --shadow-lift:0 1px 0 rgba(255,255,255,.06) inset, 0 18px 44px rgba(0,0,0,.62);
}
.card{ box-shadow:0 0 0 1px var(--line), var(--shadow) !important; }
.lift:hover, .card.lift:hover{ box-shadow:0 0 0 1px var(--line), var(--shadow-lift) !important; }

/* (2) HERO IDENTITY CHIPS — hardcoded dark inks (#8a6500 gold, #1e40af blue) go
 *     muddy on dark cards; route to the theme-aware brand gold + a blue-ink token. */
html{ --chip-blue-ink:#1e40af; }
html[data-theme="dark"]{ --chip-blue-ink:#93c5fd; }
.chip, .chip20{ color:var(--gold) !important; }

/* (2.5) BASE SKELETON — ONE canonical .skel placeholder + its `sh` sweep keyframes for
 *       every page (was ~19 near-identical inline copies, radius drifting 10-16px). This
 *       file is linked AFTER each page's inline <style>, so this base governs; pages no
 *       longer ship their own copy. The gold re-skin in (3) below layers on top. */
@keyframes sh { to { background-position:-200% 0; } }
.skel{ background:linear-gradient(90deg,var(--track) 25%,var(--soft) 50%,var(--track) 75%); background-size:200% 100%; animation:sh 1.1s infinite; border-radius:12px; }

/* (3) BRANDED LOADING SHIMMER — a soft gold sweep across every .skel placeholder,
 *     site-wide (overrides the base grey gradient above). Reuses the `sh` keyframes +
 *     background-size on .skel; we only re-skin the gradient so the pre-load state
 *     feels alive + on-brand, not mechanical. */
.skel{ background:linear-gradient(90deg, var(--track) 0%, var(--track) 36%, rgba(198,146,0,.20) 50%, var(--track) 64%, var(--track) 100%) !important; background-size:200% 100% !important; }
.chip.blue{ color:var(--chip-blue-ink) !important; }
