/* ==========================================================================
   NBL Player Hub
   Color roles come from the validated data-viz palette. Every value is
   declared for both light and dark; the dark steps are chosen for the dark
   surface, not flipped.
   ========================================================================== */

:root {
  color-scheme: light;

  --surface-1: #fcfcfb;   /* card / chart surface */
  --surface-2: #f9f9f7;   /* page plane */
  --surface-3: #f2f2ee;   /* recessed wells, table stripes */

  --text-primary: #0b0b0b;
  --text-secondary: #52514e;
  --text-muted: #898781;

  --grid: #e1e0d9;
  --axis: #c3c2b7;
  --border: rgba(11, 11, 11, 0.10);
  --border-strong: rgba(11, 11, 11, 0.18);

  --series-1: #2a78d6;   /* blue   - primary / makes */
  --series-2: #eb6834;   /* orange - secondary */
  --series-3: #1baf7a;   /* aqua    - categorical slot 3 */
  --series-4: #eda100;   /* yellow  - categorical slot 4 */
  --series-5: #e87ba4;   /* magenta - categorical slot 5 */
  --series-6: #7d6bd6;   /* violet  - categorical slot 6 */
  --series-7: #5f9f2f;   /* green   - categorical slot 7 */
  --series-8: #e34948;   /* red    - misses / low pole */

  --pos: #2a78d6;        /* diverging warm/cool poles */
  --neg: #e34948;
  --mid: #f0efec;

  /* Diverging ramp for the shot heat map: two hues that read as opposite,
     a neutral gray midpoint, and lightness moving monotonically away from
     that midpoint along each arm. */
  --div-n2: #c0332f;
  --div-n1: #f09492;
  --div-0:  #dcdbd6;
  --div-p1: #7fb2ec;
  --div-p2: #2069c9;

  --good: #0ca30c;
  --warn: #fab219;
  --crit: #d03b3b;

  --shadow: 0 1px 2px rgba(11, 11, 11, .05), 0 8px 24px -12px rgba(11, 11, 11, .18);
  --radius: 14px;
  --font: system-ui, -apple-system, "Segoe UI", sans-serif;
}

@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) {
    color-scheme: dark;
    --surface-1: #1a1a19;
    --surface-2: #0d0d0d;
    --surface-3: #232322;
    --text-primary: #ffffff;
    --text-secondary: #c3c2b7;
    --text-muted: #898781;
    --grid: #2c2c2a;
    --axis: #383835;
    --border: rgba(255, 255, 255, 0.10);
    --border-strong: rgba(255, 255, 255, 0.18);
    --series-1: #3987e5;
    --series-2: #d95926;
    --series-3: #199e70;
    --series-4: #c98500;
    --series-5: #d55181;
    --series-6: #8b7ce0;
    --series-7: #6faf3a;
    --series-8: #e66767;
    --pos: #3987e5;
    --neg: #e66767;
    --mid: #383835;
    /* Dark arms brighten with magnitude, so intensity still reads as "more".
       The neutral sits close to the surface so "no signal" recedes. */
    --div-n2: #f0706e;
    --div-n1: #a34544;
    --div-0:  #2f2f2d;
    --div-p1: #2f6fb8;
    --div-p2: #58a5f5;
    --good: #0ca30c;
    --shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 8px 24px -12px rgba(0, 0, 0, .7);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --surface-1: #1a1a19;
  --surface-2: #0d0d0d;
  --surface-3: #232322;
  --text-primary: #ffffff;
  --text-secondary: #c3c2b7;
  --text-muted: #898781;
  --grid: #2c2c2a;
  --axis: #383835;
  --border: rgba(255, 255, 255, 0.10);
  --border-strong: rgba(255, 255, 255, 0.18);
  --series-1: #3987e5;
  --series-2: #d95926;
  --series-3: #199e70;
  --series-4: #c98500;
  --series-5: #d55181;
  --series-6: #8b7ce0;
  --series-7: #6faf3a;
  --series-8: #e66767;
  --pos: #3987e5;
  --neg: #e66767;
  --mid: #383835;
  /* Dark arms brighten with magnitude, so intensity still reads as "more".
     The neutral sits close to the surface so "no signal" recedes. */
  --div-n2: #f0706e;
  --div-n1: #a34544;
  --div-0:  #2f2f2d;
  --div-p1: #2f6fb8;
  --div-p2: #58a5f5;
  --good: #0ca30c;
  --shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 8px 24px -12px rgba(0, 0, 0, .7);
}

* { box-sizing: border-box; }

html {
  /* Safari on iOS otherwise inflates the body copy in portrait, which throws
     off every fixed-column grid on the page. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  /* The header is sticky, so an in-page anchor lands under it without this. */
  scroll-padding-top: 76px;
}

body {
  margin: 0;
  font-family: var(--font);
  background: var(--surface-2);
  color: var(--text-primary);
  -webkit-font-smoothing: antialiased;
  line-height: 1.45;
  /* Nothing on any page is meant to be reached by dragging the page sideways.
     `clip` rather than `hidden` so the sticky header keeps working. */
  overflow-x: clip;
}

/* Anything that scrolls sideways does so on its own: the gesture stops at the
   panel's edge instead of running on into the page or the browser's back
   swipe, which is what made a phone feel like it was sliding around. */
.tablewrap,
.chartscroll,
.tabs,
.navstrip,
.results,
.srcpanel { overscroll-behavior-x: contain; -webkit-overflow-scrolling: touch; }

/* ---------------------------------------------------------------- header */

.topbar {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 12px 24px;
  background: color-mix(in srgb, var(--surface-2) 88%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border);
}

/* The wordmark is the way home, so it is a control on both pages: a button on
   the hub (it resets in place) and a link on the archetype lab. */
.brand {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 0;
  font: inherit;
  font-weight: 640;
  letter-spacing: -0.015em;
  white-space: nowrap;
  color: var(--text-primary);
  text-decoration: none;
  background: none;
  border: 0;
  border-radius: 7px;
  cursor: pointer;
}
.brand:hover b { color: var(--series-1); }
.brand:focus-visible { outline: 2px solid var(--series-1); outline-offset: 3px; }
/* The mark is a transparent PNG that reads on either surface, so it needs no
   plate behind it — only a fixed box so the header height never shifts. */
.brand-logo {
  flex: none;
  width: 30px;
  height: 30px;
  object-fit: contain;
  margin-right: -2px;
}
.brand b { font-size: 15px; }
.brand span {
  font-size: 11px;
  font-weight: 500;
  color: var(--text-muted);
  letter-spacing: .04em;
  text-transform: uppercase;
}

.search {
  position: relative;
  flex: 1;
  max-width: 460px;
  margin-left: auto;
}
.search input {
  width: 100%;
  padding: 9px 14px 9px 34px;
  font: inherit;
  font-size: 14px;
  color: var(--text-primary);
  background: var(--surface-1);
  border: 1px solid var(--border-strong);
  border-radius: 9px;
  outline: none;
}
.search input:focus { border-color: var(--series-1); }
.search input::placeholder { color: var(--text-muted); }
.search .icon {
  position: absolute;
  left: 11px; top: 50%;
  transform: translateY(-50%);
  color: var(--text-muted);
  pointer-events: none;
  display: flex;
}

.results {
  position: absolute;
  top: calc(100% + 6px);
  left: 0; right: 0;
  max-height: 60vh;
  overflow-y: auto;
  background: var(--surface-1);
  border: 1px solid var(--border-strong);
  border-radius: 11px;
  box-shadow: var(--shadow);
  padding: 5px;
  display: none;
}
.results.open { display: block; }

.result {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 7px 9px;
  border-radius: 8px;
  cursor: pointer;
  border: none;
  background: none;
  width: 100%;
  text-align: left;
  font: inherit;
  color: var(--text-primary);
}
.result:hover, .result.active { background: var(--surface-3); }
.result img, .result .ph {
  width: 30px; height: 30px;
  border-radius: 50%;
  object-fit: cover;
  object-position: top center;
  background: var(--surface-3);
  flex-shrink: 0;
}
.result .ph {
  display: grid;
  place-items: center;
  font-size: 11px;
  font-weight: 640;
  color: var(--text-muted);
}
.result .rn { font-size: 13.5px; font-weight: 550; }
.result .rm { font-size: 11.5px; color: var(--text-muted); }
.result .rr { margin-left: auto; font-size: 11.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }

.icon-btn {
  display: grid;
  place-items: center;
  width: 34px; height: 34px;
  border-radius: 9px;
  border: 1px solid var(--border-strong);
  background: var(--surface-1);
  color: var(--text-secondary);
  cursor: pointer;
  flex-shrink: 0;
}
.icon-btn:hover { color: var(--text-primary); }
/* The section links are wrapped so a phone can lift them onto their own row.
   On anything wider the wrapper is not a box at all, so the buttons stay
   direct children of the bar and lay out exactly as they always did. */
.navstrip { display: contents; }

.nav-btn {
  padding: 7px 11px;
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  border-radius: 8px;
  border: 1px solid var(--border-strong);
  background: var(--surface-1);
  color: var(--text-secondary);
  cursor: pointer;
}
.nav-btn:hover,
.nav-btn[aria-pressed="true"] {
  color: var(--text-primary);
  border-color: var(--axis);
}
/* Sections that exist but are not published yet. Dimmed rather than hidden so
   the nav still reads as the full set, with the hover lift suppressed -- a
   button that lights up under the cursor reads as clickable. */
.nav-btn:disabled {
  opacity: 0.42;
  cursor: not-allowed;
}
.nav-btn:disabled:hover {
  color: var(--text-secondary);
  border-color: var(--border-strong);
}

/* ------------------------------------------------------------------ page */

main { max-width: 1180px; margin: 0 auto; padding: 24px; }
main.wide { max-width: 1540px; }

.empty {
  text-align: center;
  padding: 96px 24px;
  color: var(--text-muted);
}
.empty h1 {
  font-size: 26px;
  font-weight: 640;
  letter-spacing: -0.02em;
  color: var(--text-primary);
  margin: 0 0 8px;
}
.empty p { margin: 0 auto; max-width: 460px; font-size: 14px; }

.chips { display: flex; flex-wrap: wrap; gap: 7px; justify-content: center; margin-top: 22px; }
.chip {
  padding: 6px 12px;
  font: inherit; font-size: 12.5px;
  border-radius: 99px;
  border: 1px solid var(--border-strong);
  background: var(--surface-1);
  color: var(--text-secondary);
  cursor: pointer;
}
.chip:hover { color: var(--text-primary); border-color: var(--axis); }

/* ------------------------------------------------------------------ home */

/* The landing page runs edge to edge so the card rows can slide past the
   viewport bounds; the copy above them keeps the normal measure. */
main.home { max-width: none; padding: 0 0 40px; overflow: hidden; }

.homehead {
  max-width: 1180px;
  margin: 0 auto;
  padding: 46px 24px 26px;
  text-align: center;
  animation: home-rise .7s cubic-bezier(.2, .7, .3, 1) both;
}
.homehead h1 {
  margin: 0 0 9px;
  font-size: 36px;
  font-weight: 660;
  letter-spacing: -0.032em;
  line-height: 1.05;
  color: var(--text-primary);
}
/* The landing headline is the logo lockup: mark and wordmark centred as one
   unit, sized so the mark's optical height matches the cap height of the type. */
.homehead h1.homelock {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  font-size: 48px;
}
.homelock-mark {
  flex: none;
  width: 104px;
  height: 104px;
  object-fit: contain;
}
.homehead p {
  margin: 0 auto;
  max-width: 520px;
  font-size: 14px;
  line-height: 1.55;
  color: var(--text-muted);
}
.homehint {
  margin-top: 16px;
  font-size: 12px;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.homehint kbd {
  font: inherit;
  font-size: 11px;
  padding: 2px 6px;
  border-radius: 5px;
  border: 1px solid var(--border-strong);
  background: var(--surface-1);
  color: var(--text-secondary);
}

@keyframes home-rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

/* Each row is a viewport onto a track holding its cards twice over; the
   track slides exactly one copy's width, so the seam never shows. */
.homerow {
  position: relative;
  overflow: hidden;
  padding: 10px 0;
  /* Cards dissolve rather than clip at the edges. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
  animation: home-rise .8s .1s cubic-bezier(.2, .7, .3, 1) both;
}
.homerow + .homerow { animation-delay: .2s; }

.hometrack {
  display: flex;
  gap: 16px;
  width: max-content;
  padding: 0 8px;
  animation: home-slide 78s linear infinite;
  will-change: transform;
}
.hometrack.rev { animation-direction: reverse; animation-duration: 94s; }

/* -50% is one full copy of the card list, gap included. */
@keyframes home-slide {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

/* Hovering or tabbing into a row holds it still so a card can be read. */
.homerow:hover .hometrack,
.homerow:focus-within .hometrack { animation-play-state: paused; }

.pcard {
  --team-color: var(--series-1);
  position: relative;
  flex: 0 0 auto;
  width: 174px;
  padding: 0;
  font: inherit;
  text-align: left;
  cursor: pointer;
  border: 1px solid var(--border);
  border-radius: 16px;
  overflow: hidden;
  background: var(--surface-1);
  box-shadow: var(--shadow);
  transition: transform .25s cubic-bezier(.2, .7, .3, 1), box-shadow .25s ease;
}
.pcard:hover,
.pcard:focus-visible {
  transform: translateY(-6px) scale(1.025);
  box-shadow:
    0 1px 2px rgb(0 0 0 / .18),
    0 22px 40px -18px color-mix(in srgb, var(--team-color) 55%, transparent),
    0 12px 30px -14px rgb(0 0 0 / .35);
}
.pcard:focus-visible { outline: 2px solid var(--team-color); outline-offset: 2px; }

/* The portrait plate stays light in both themes: the headshots ship on white,
   and multiply only dissolves that white against a light backdrop. */
.pcard-plate {
  position: relative;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  background:
    radial-gradient(115% 85% at 50% 0%,
      #ffffff 0%,
      color-mix(in srgb, var(--team-color) 9%, #ffffff) 58%,
      color-mix(in srgb, var(--team-color) 22%, #f0efec) 100%);
}
.pcard-logo {
  position: absolute;
  left: 50%;
  top: 46%;
  width: 128%;
  transform: translate(-50%, -50%);
  opacity: .17;
  filter: saturate(.75);
  transition: opacity .3s ease, transform .5s cubic-bezier(.2, .7, .3, 1);
}
.pcard:hover .pcard-logo { opacity: .26; transform: translate(-50%, -50%) scale(1.06); }

.pcard-shot {
  position: absolute;
  left: 50%;
  bottom: 0;
  width: 104%;
  transform: translateX(-50%);
  mix-blend-mode: multiply;
  transition: transform .45s cubic-bezier(.2, .7, .3, 1);
}
.pcard:hover .pcard-shot { transform: translateX(-50%) scale(1.045); }

/* Initials stand in when a player has no headshot on file. */
.pcard-ph {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 42px;
  font-weight: 800;
  letter-spacing: .02em;
  color: color-mix(in srgb, var(--team-color) 62%, #0b0b0b);
  opacity: .42;
}

.pcard-season {
  position: absolute;
  top: 9px;
  left: 9px;
  z-index: 2;
  padding: 3px 8px;
  border-radius: 99px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .05em;
  font-variant-numeric: tabular-nums;
  color: #fff;
  background: color-mix(in srgb, var(--team-color) 62%, #0b0b0b);
}
.pcard-abbr {
  position: absolute;
  top: 9px;
  right: 9px;
  z-index: 2;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .06em;
  color: color-mix(in srgb, var(--team-color) 70%, #0b0b0b);
}

/* Team colour is mixed toward black so white text clears contrast on every
   club, including the light oranges and blues. */
.pcard-body {
  position: relative;
  padding: 11px 12px 12px;
  color: #fff;
  background: linear-gradient(165deg,
    color-mix(in srgb, var(--team-color) 55%, #0e0e0e) 0%,
    #0e0e0e 100%);
  border-top: 3px solid var(--team-color);
}
.pcard-name {
  font-size: 14.5px;
  font-weight: 650;
  letter-spacing: -0.015em;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pcard-team {
  margin-top: 2px;
  font-size: 11px;
  color: rgb(255 255 255 / .62);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pcard-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 4px;
  margin-top: 9px;
  padding-top: 8px;
  border-top: 1px solid rgb(255 255 255 / .14);
}
.pcard-stats div { text-align: center; }
.pcard-stats b {
  display: block;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  line-height: 1.15;
}
.pcard-stats span {
  font-size: 9px;
  font-weight: 600;
  letter-spacing: .07em;
  color: rgb(255 255 255 / .55);
}

@media (max-width: 720px) {
  .homehead { padding: 40px 20px 26px; }
  .homehead h1 { font-size: 30px; }
  .homehead h1.homelock { font-size: 34px; gap: 12px; }
  .homelock-mark { width: 74px; height: 74px; }
  .pcard { width: 164px; }
}

/* Reduced motion: the rows stop sliding and become plain scrollers. */
@media (prefers-reduced-motion: reduce) {
  .homehead, .homerow { animation: none; }
  .homerow { overflow-x: auto; }
  .hometrack { animation: none; }
  .pcard:hover, .pcard:focus-visible { transform: none; }
  .pcard-logo, .pcard-shot { transition: none; }
}

/* ------------------------------------------------------- home: layout pick */

/* TEMPORARY: the bake-off switcher. Remove with the losing layouts. */
.homepick {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 14px 20px 0;
}
.homepick-tag {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-muted);
}
/* Enough candidates now that the strip has to wrap on a narrow screen rather
   than push the page wider than the viewport. */
.homepick .seg { flex-wrap: wrap; justify-content: center; }

/* -------------------------------------------------------------- home: board */

/* A ranked list rather than a reel: dense, still, and readable at a glance.
   Two columns on wide screens so the whole top 14 lands above the fold. */
.homeboard {
  max-width: 1080px;
  margin: 0 auto;
  padding: 0 24px;
  animation: home-rise .7s .1s cubic-bezier(.2, .7, .3, 1) both;
}
.homeboard-head {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--border);
}
.homeboard-title {
  font-size: 13px;
  font-weight: 650;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--text-secondary);
}
.homeboard-head .seg { margin-left: auto; }

/* Column-major: 1-7 down the left, 8-14 down the right, so the ranks read in
   order instead of zig-zagging across the gutter. */
.homeboard-list {
  display: grid;
  grid-template-rows: repeat(7, auto);
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: 2px 26px;
  padding: 8px 0 0;
}
.homeboard-note {
  margin-top: 12px;
  font-size: 11.5px;
  color: var(--text-muted);
}

/* The bar is a background stop rather than an element, so the row stays one
   grid and the fill can never push the numbers around. */
.brow {
  --team-color: var(--series-1);
  --fill: 0%;
  position: relative;
  display: grid;
  grid-template-columns: 26px 34px minmax(0, 1fr) auto;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 7px 10px;
  font: inherit;
  text-align: left;
  cursor: pointer;
  border: 0;
  border-radius: 9px;
  background:
    linear-gradient(90deg,
      color-mix(in srgb, var(--team-color) 16%, transparent) 0%,
      color-mix(in srgb, var(--team-color) 5%, transparent) var(--fill),
      transparent var(--fill));
  transition: background-color .18s ease, transform .18s ease;
}
.brow:hover, .brow:focus-visible {
  background-color: var(--surface-3);
  transform: translateX(2px);
}
.brow:focus-visible { outline: 2px solid var(--team-color); outline-offset: -2px; }

.brow-rank {
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-align: right;
  color: var(--text-muted);
}
.brow:hover .brow-rank { color: var(--team-color); }

/* Like the card plate, the face disc stays light in both themes: the headshots
   ship on white, and multiply only dissolves that white against a light one. */
.brow-face {
  position: relative;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  overflow: hidden;
  border-radius: 50%;
  background: color-mix(in srgb, var(--team-color) 18%, #f2f1ee);
  box-shadow: inset 0 0 0 1px rgb(11 11 11 / .10);
}
.brow-face img {
  width: 128%;
  margin-top: 14%;
  mix-blend-mode: multiply;
}
.brow-face span {
  font-size: 11px;
  font-weight: 700;
  color: color-mix(in srgb, var(--team-color) 62%, #0b0b0b);
}

.brow-name {
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: -0.012em;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.brow-team {
  font-size: 10.5px;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.brow-val { text-align: right; }
.brow-val b {
  display: block;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}
.brow-val span {
  font-size: 9px;
  font-weight: 600;
  letter-spacing: .07em;
  color: var(--text-muted);
}

/* ------------------------------------------------------- home: collage tile */

/* The same card the sliding rows use, resized by class. The portrait plate
   stays light in both themes: the headshots ship on white, and multiply only
   dissolves that white against a light backdrop. */
.ctile {
  --team-color: var(--series-1);
  position: relative;
  min-width: 0;
  padding: 0;
  font: inherit;
  text-align: left;
  cursor: pointer;
  border: 1px solid var(--border);
  border-radius: 14px;
  overflow: hidden;
  background: var(--surface-1);
  box-shadow: var(--shadow);
  transition: transform .25s cubic-bezier(.2, .7, .3, 1), box-shadow .25s ease;
}
.ctile:hover, .ctile:focus-visible {
  transform: translateY(-5px);
  box-shadow:
    0 1px 2px rgb(0 0 0 / .18),
    0 20px 36px -18px color-mix(in srgb, var(--team-color) 55%, transparent),
    0 10px 26px -14px rgb(0 0 0 / .35);
}
.ctile:focus-visible { outline: 2px solid var(--team-color); outline-offset: 2px; }

.ctile-plate {
  position: relative;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  background:
    radial-gradient(115% 85% at 50% 0%,
      #ffffff 0%,
      color-mix(in srgb, var(--team-color) 9%, #ffffff) 58%,
      color-mix(in srgb, var(--team-color) 22%, #f0efec) 100%);
}
.ctile-logo {
  position: absolute;
  left: 50%;
  top: 46%;
  width: 128%;
  transform: translate(-50%, -50%);
  opacity: .17;
  filter: saturate(.75);
  transition: opacity .3s ease;
}
.ctile:hover .ctile-logo { opacity: .26; }
.ctile-shot {
  position: absolute;
  left: 50%;
  bottom: 0;
  width: 104%;
  transform: translateX(-50%);
  mix-blend-mode: multiply;
  transition: transform .45s cubic-bezier(.2, .7, .3, 1);
}
.ctile:hover .ctile-shot { transform: translateX(-50%) scale(1.04); }
.ctile-ph {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 38px;
  font-weight: 800;
  color: color-mix(in srgb, var(--team-color) 62%, #0b0b0b);
  opacity: .42;
}
.ctile-abbr {
  position: absolute;
  top: 8px;
  right: 9px;
  z-index: 2;
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: .06em;
  color: color-mix(in srgb, var(--team-color) 70%, #0b0b0b);
}

/* Team colour is mixed toward black so white text clears contrast on every
   club, including the light oranges and blues. */
.ctile-body {
  position: relative;
  padding: 9px 11px 10px;
  color: #fff;
  background: linear-gradient(165deg,
    color-mix(in srgb, var(--team-color) 55%, #0e0e0e) 0%,
    #0e0e0e 100%);
  border-top: 3px solid var(--team-color);
}
.ctile-name {
  font-size: 13.5px;
  font-weight: 650;
  letter-spacing: -0.015em;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ctile-team {
  margin-top: 2px;
  font-size: 10.5px;
  color: rgb(255 255 255 / .62);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ctile-line {
  margin-top: 3px;
  font-size: 11px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: rgb(255 255 255 / .72);
}
.ctile-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 4px;
  margin-top: 8px;
  padding-top: 7px;
  border-top: 1px solid rgb(255 255 255 / .14);
}
.ctile-stats div { text-align: center; }
.ctile-stats b {
  display: block;
  font-size: 14.5px;
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  line-height: 1.15;
}
.ctile-stats span {
  font-size: 8.5px;
  font-weight: 600;
  letter-spacing: .07em;
  color: rgb(255 255 255 / .55);
}

.ctile-small .ctile-body { padding: 8px 10px 9px; }
.ctile-small .ctile-name { font-size: 12.5px; }

/* ------------------------------------------------------------ home: columns */

/* The sliding rows turned on their side. Same trick: each track holds its
   tiles twice and travels exactly one copy, so the loop has no seam. */
.homecols {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 14px;
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 24px;
  height: 560px;
  overflow: hidden;
  /* Tiles dissolve rather than clip at the top and bottom edges. */
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 11%, #000 89%, transparent);
  mask-image: linear-gradient(180deg, transparent, #000 11%, #000 89%, transparent);
  animation: home-rise .8s .1s cubic-bezier(.2, .7, .3, 1) both;
}
.ccol { position: relative; min-width: 0; overflow: hidden; }
.ccol-track {
  display: flex;
  flex-direction: column;
  gap: 14px;
  animation: col-slide var(--dur, 60s) linear infinite;
  will-change: transform;
}
.ccol.down .ccol-track { animation-direction: reverse; }

/* -50% is one full copy of the tile list, gap included. */
@keyframes col-slide {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(0, -50%, 0); }
}

/* Hovering or tabbing into a column holds it still so a tile can be read. */
.homecols:hover .ccol-track,
.homecols:focus-within .ccol-track { animation-play-state: paused; }

/* ---------------------------------------------------------- home: jumbotron */

/* A modern arena video wall: one bright, seamless screen. No dot matrix, no
   amber -- the only texture is the faint join between LED modules and a sheen
   across the glass. It stays dark in both themes because it is a screen, not
   a surface. */
.homejumbo {
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 24px;
  animation: home-rise .8s .1s cubic-bezier(.2, .7, .3, 1) both;
}

.jumbo-screen {
  position: relative;
  overflow: hidden;
  padding: 16px 0;
  border-radius: 18px;
  border: 1px solid rgb(255 255 255 / .09);
  background:
    radial-gradient(120% 140% at 50% -20%, #1b1f27 0%, #0a0c10 60%),
    #0a0c10;
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / .07),
    0 26px 56px -30px rgb(0 0 0 / .8);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 4%, #000 96%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 4%, #000 96%, transparent);
}
/* Module seams: the only nod to the wall being made of panels. */
.jumbo-screen::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background-image:
    repeating-linear-gradient(90deg, rgb(255 255 255 / .035) 0 1px, transparent 1px 96px),
    repeating-linear-gradient(0deg, rgb(255 255 255 / .028) 0 1px, transparent 1px 96px);
}
/* Sheen across the glass. */
.jumbo-screen::after {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 46%;
  z-index: 4;
  pointer-events: none;
  background: linear-gradient(180deg, rgb(255 255 255 / .05), transparent);
}

.jumbo-track {
  display: flex;
  gap: 16px;
  width: max-content;
  padding: 0 8px;
  /* Slow enough to read a panel without having to chase it. */
  animation: home-slide 150s linear infinite;
  will-change: transform;
}
.jumbo-screen:hover .jumbo-track,
.jumbo-screen:focus-within .jumbo-track { animation-play-state: paused; }

.jpanel {
  --team-color: var(--series-1);
  position: relative;
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr);
  align-items: stretch;
  flex: 0 0 auto;
  width: 396px;
  padding: 0;
  font: inherit;
  text-align: left;
  cursor: pointer;
  overflow: hidden;
  border: 1px solid rgb(255 255 255 / .08);
  border-radius: 13px;
  background:
    linear-gradient(115deg,
      color-mix(in srgb, var(--team-color) 34%, #0d1016) 0%,
      #0d1016 68%);
  transition: transform .3s cubic-bezier(.2, .7, .3, 1), box-shadow .3s ease;
}
.jpanel::after {
  /* Club accent along the bottom edge, the way a broadcast bug is keyed. */
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 3px;
  background: var(--team-color);
}
.jpanel:hover, .jpanel:focus-visible {
  transform: translateY(-3px);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--team-color) 55%, transparent),
              0 18px 40px -18px color-mix(in srgb, var(--team-color) 75%, transparent);
}
.jpanel:focus-visible { outline: 2px solid var(--team-color); outline-offset: 2px; }

/* The photo runs in its own lit cell, which is also the light backdrop the
   multiply blend needs to knock the white out of the headshot. */
.jpanel-shot {
  position: relative;
  overflow: hidden;
  background:
    radial-gradient(125% 95% at 50% 0%,
      #ffffff 0%,
      color-mix(in srgb, var(--team-color) 10%, #ffffff) 58%,
      color-mix(in srgb, var(--team-color) 26%, #eceae6) 100%);
}
.jpanel-shot img {
  position: absolute;
  left: 50%;
  bottom: 0;
  width: 112%;
  transform: translateX(-50%);
  mix-blend-mode: multiply;
}
.jpanel-logo {
  position: absolute;
  left: 50%;
  top: 45%;
  width: 128%;
  transform: translate(-50%, -50%);
  opacity: .17;
}
.jpanel-ph {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 32px;
  font-weight: 800;
  color: color-mix(in srgb, var(--team-color) 62%, #0b0b0b);
  opacity: .45;
}

.jpanel-read {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
  padding: 16px 18px 18px;
}
.jpanel-top {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 5px;
}
.jpanel-abbr {
  padding: 2px 7px;
  border-radius: 4px;
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: .1em;
  color: #fff;
  background: color-mix(in srgb, var(--team-color) 78%, #000);
}
.jpanel-season {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .09em;
  font-variant-numeric: tabular-nums;
  color: rgb(255 255 255 / .42);
}
.jpanel-name {
  font-size: 21px;
  font-weight: 680;
  letter-spacing: -0.028em;
  line-height: 1.1;
  color: #fff;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.jpanel-digits {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin-top: 13px;
  padding-top: 11px;
  border-top: 1px solid rgb(255 255 255 / .12);
}
.jpanel-digits b {
  display: block;
  font-size: 21px;
  font-weight: 700;
  letter-spacing: -0.035em;
  font-variant-numeric: tabular-nums;
  line-height: 1.05;
  color: #fff;
}
.jpanel-digits span {
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: .13em;
  color: color-mix(in srgb, var(--team-color) 45%, #9aa0ad);
}

/* -------------------------------------------------------------- home: court */

/* The shot-chart half court reused as a stage, with the leaders standing at
   the spots the game is actually played from. */
.homecourt {
  max-width: 1000px;
  margin: 0 auto;
  padding: 0 24px;
  animation: home-rise .8s .1s cubic-bezier(.2, .7, .3, 1) both;
}
/* The aspect ratio is set inline from the cropped viewBox, so the marker
   percentages and the drawing can never disagree about the frame.
   The selector has to outrank `svg.court` from the shot chart, which sets
   `overflow: visible` -- without that the cropped half of the court still
   paints, spilling up over the page head. */
.court-stage { position: relative; }
.court-stage svg.courtart {
  width: 100%;
  height: 100%;
  display: block;
  overflow: hidden;
}
.courtart .floor { fill: var(--surface-3); }
.courtart .line { fill: none; stroke: var(--axis); stroke-width: .55; }

/* Spots are placed by their centre, so the disc is pulled back by half itself
   rather than the label shifting the whole marker off its mark. */
.cspot {
  --team-color: var(--series-1);
  position: absolute;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 0;
  font: inherit;
  cursor: pointer;
  border: 0;
  background: none;
  transition: transform .22s cubic-bezier(.2, .7, .3, 1);
}
.cspot:hover, .cspot:focus-visible { transform: translate(-50%, -50%) scale(1.12); z-index: 3; }
.cspot:focus-visible { outline: none; }

.cspot-disc {
  position: relative;
  width: 62px;
  height: 62px;
  overflow: hidden;
  border-radius: 50%;
  /* Light disc in both themes: the headshots ship on white. */
  background:
    radial-gradient(100% 100% at 50% 0%,
      #ffffff 0%,
      color-mix(in srgb, var(--team-color) 22%, #f4f3f0) 100%);
  box-shadow:
    0 0 0 2px var(--team-color),
    0 8px 18px -8px rgb(0 0 0 / .55);
}
.cspot-disc img {
  position: absolute;
  left: 50%;
  bottom: -6%;
  width: 122%;
  transform: translateX(-50%);
  mix-blend-mode: multiply;
}
.cspot-ph {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 17px;
  font-weight: 800;
  color: color-mix(in srgb, var(--team-color) 62%, #0b0b0b);
}
.cspot:focus-visible .cspot-disc { box-shadow: 0 0 0 3px var(--team-color), 0 0 0 6px color-mix(in srgb, var(--team-color) 35%, transparent); }

.cspot-tag {
  display: flex;
  align-items: baseline;
  gap: 5px;
  padding: 2px 8px;
  border-radius: 99px;
  white-space: nowrap;
  background: var(--surface-1);
  box-shadow: 0 1px 3px rgb(0 0 0 / .2);
}
.cspot-tag b {
  font-size: 11px;
  font-weight: 650;
  letter-spacing: -0.01em;
  color: var(--text-primary);
}
.cspot-tag span {
  font-size: 10.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--team-color);
}

/* ----------------------------------------------------- home: angled panels */

/* The broadcast panel, cut on the diagonal so a row of them interlocks. The
   cut is driven by --skew so the reel can express it in pixels and tessellate
   exactly; the lineup keeps it proportional. Shared by both layouts. */
.lpanel {
  --team-color: var(--series-1);
  --drop: 0px;
  --skew: 9%;
  position: relative;
  min-width: 0;
  padding: 0;
  font: inherit;
  text-align: left;
  cursor: pointer;
  overflow: hidden;
  border: 0;
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--team-color) 26%, #101215) 0%,
      #101215 62%);
  /* Both cut edges share a slope, so panels overlapped by exactly --skew
     tessellate with no gap and no double-thickness seam. */
  clip-path: polygon(var(--skew) 0, 100% 0, calc(100% - var(--skew)) 100%, 0 100%);
  transition: transform .28s cubic-bezier(.2, .7, .3, 1), filter .28s ease;
}
.lpanel:hover, .lpanel:focus-visible {
  transform: translateY(-8px);
  z-index: 3;
  filter: brightness(1.12);
}
.lpanel:focus-visible { outline: 2px solid var(--team-color); outline-offset: -4px; }

.lpanel-art {
  position: absolute;
  inset: 0 0 118px 0;
  overflow: hidden;
  isolation: isolate;
  /* The lit cell the multiply blend needs, shaped to the panel. */
  background:
    radial-gradient(115% 80% at 50% 4%,
      #ffffff 0%,
      color-mix(in srgb, var(--team-color) 13%, #ffffff) 52%,
      color-mix(in srgb, var(--team-color) 34%, #e8e6e2) 100%);
}
.lpanel-logo {
  position: absolute;
  left: 50%;
  top: 42%;
  width: 132%;
  transform: translate(-50%, -50%);
  opacity: .16;
  z-index: 0;
  pointer-events: none;
}
.lpanel-shot {
  position: absolute;
  left: 50%;
  bottom: 0;
  width: 106%;
  transform: translateX(-50%);
  z-index: 1;
}
.lpanel-ph {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 44px;
  font-weight: 800;
  color: color-mix(in srgb, var(--team-color) 62%, #0b0b0b);
  opacity: .42;
}

.lpanel-foot {
  position: absolute;
  inset: auto 0 0 0;
  height: 118px;
  padding: 12px 20px 14px;
  color: #fff;
  border-top: 3px solid var(--team-color);
}
.lpanel-first {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: rgb(255 255 255 / .58);
}
.lpanel-last {
  font-size: 21px;
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.08;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.lpanel-line {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 4px;
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px solid rgb(255 255 255 / .16);
}
.lpanel-line b {
  display: block;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.lpanel-line span {
  font-size: 8px;
  font-weight: 700;
  letter-spacing: .1em;
  color: rgb(255 255 255 / .5);
}

/* ------------------------------------------------------------- home: lineup */

/* The starting five: a fixed row, arched so the middle panel sits highest. */
.homelineup {
  display: flex;
  justify-content: center;
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 24px 30px;
  animation: home-rise .8s .1s cubic-bezier(.2, .7, .3, 1) both;
}
.homelineup .lpanel {
  flex: 1 1 0;
  max-width: 218px;
  height: 400px;
  margin-top: var(--drop);
}
.homelineup .lpanel + .lpanel { margin-left: -3.2%; }

/* --------------------------------------------------------------- home: reel */

/* The same panels running past instead of standing still. --skew is in pixels
   here so the overlap matches the cut exactly; every panel carries the
   negative margin, including the first, so each advances the track by the
   same amount and the two copies come out identical in width. That is what
   makes the -50% loop land without a seam. */
.homereel {
  padding: 0 0 30px;
  overflow: hidden;
  /* Panels dissolve rather than clip at the edges. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  animation: home-rise .8s .1s cubic-bezier(.2, .7, .3, 1) both;
}
.reel-track {
  display: flex;
  width: max-content;
  animation: home-slide 120s linear infinite;
  will-change: transform;
}
/* Overlapping by less than the cut leaves a diagonal sliver of page between
   panels, which is what makes the angle read as an angle rather than a seam.
   The advance stays uniform, so the loop is still exact. */
.reel-track .lpanel {
  --skew: 26px;
  flex: 0 0 auto;
  width: 236px;
  height: 356px;
  margin-left: -18px;
}
/* Hovering or tabbing into the reel holds it still so a panel can be read. */
.homereel:hover .reel-track,
.homereel:focus-within .reel-track { animation-play-state: paused; }

/* ------------------------------------------------------------- home: locker */

/* A locker room wall: the club kit hanging in each stall, nameplate beneath. */
.homelocker {
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 24px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
  gap: 12px;
  animation: home-rise .8s .1s cubic-bezier(.2, .7, .3, 1) both;
}

.stall {
  --team-color: var(--series-1);
  position: relative;
  min-width: 0;
  padding: 0 0 8px;
  font: inherit;
  text-align: left;
  cursor: pointer;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: 12px;
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--team-color) 13%, var(--surface-3)) 0%,
      var(--surface-1) 58%);
  box-shadow: var(--shadow), inset 0 1px 0 rgb(255 255 255 / .05);
  transition: transform .25s cubic-bezier(.2, .7, .3, 1), box-shadow .25s ease;
}
.stall:hover, .stall:focus-visible {
  transform: translateY(-4px);
  box-shadow:
    0 1px 2px rgb(0 0 0 / .18),
    0 20px 34px -18px color-mix(in srgb, var(--team-color) 55%, transparent);
}
.stall:focus-visible { outline: 2px solid var(--team-color); outline-offset: 2px; }

/* The rail the kit hangs from. */
.stall-hook {
  position: relative;
  height: 14px;
}
.stall-hook::before {
  content: "";
  position: absolute;
  left: 14%;
  right: 14%;
  top: 9px;
  height: 2px;
  border-radius: 2px;
  background: var(--axis);
  opacity: .6;
}

.stall-kit {
  position: relative;
  display: grid;
  place-items: center;
  padding: 2px 14px 10px;
}
.stall-kit img {
  width: 100%;
  max-height: 152px;
  object-fit: contain;
  filter: drop-shadow(0 10px 16px rgb(0 0 0 / .22));
  transition: transform .3s cubic-bezier(.2, .7, .3, 1);
}
.stall:hover .stall-kit img { transform: translateY(-3px) rotate(-1.2deg); }

.stall-plate {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 0 10px;
  padding: 8px 10px;
  border-radius: 9px;
  background: var(--surface-1);
  box-shadow: inset 0 0 0 1px var(--border);
}
.stall-face {
  position: relative;
  width: 30px;
  height: 30px;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  overflow: hidden;
  border-radius: 50%;
  /* Light disc in both themes -- the headshots ship on white. */
  background: color-mix(in srgb, var(--team-color) 18%, #f2f1ee);
}
.stall-face img { width: 128%; margin-top: 14%; mix-blend-mode: multiply; }
.stall-face span {
  font-size: 10px;
  font-weight: 700;
  color: color-mix(in srgb, var(--team-color) 62%, #0b0b0b);
}
.stall-who { min-width: 0; }
.stall-name {
  font-size: 12.5px;
  font-weight: 640;
  letter-spacing: -0.014em;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.stall-line {
  font-size: 10.5px;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}

/* ---------------------------------------------------------------- home: fan */

/* Cards shingled across the page like a hand spread on a table. */
.homefan {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  max-width: 1180px;
  margin: 0 auto;
  padding: 26px 24px 60px;
  animation: home-rise .8s .1s cubic-bezier(.2, .7, .3, 1) both;
}
.ctile-fan {
  --rot: 0deg;
  --lift: 0px;
  flex: 0 0 auto;
  width: 168px;
  transform: rotate(var(--rot)) translateY(var(--lift));
  transform-origin: 50% 100%;
}
/* Negative margin is what makes it a fan rather than a row. Kept shallow
   enough that the name on the covered card still reads. */
.ctile-fan + .ctile-fan { margin-left: -30px; }
.ctile-fan:hover, .ctile-fan:focus-visible {
  z-index: 200 !important;
  transform: rotate(0deg) translateY(calc(var(--lift) - 16px)) scale(1.05);
}

@media (max-width: 940px) {
  .homecols { grid-template-columns: repeat(4, minmax(0, 1fr)); height: 480px; }
  .homecols .ccol:nth-child(n + 5) { display: none; }
  .ctile-fan { width: 140px; }
  .ctile-fan + .ctile-fan { margin-left: -40px; }
  .homelineup .lpanel { height: 340px; max-width: 178px; }
  .reel-track .lpanel { width: 204px; height: 320px; }
  .lpanel-art { inset: 0 0 104px 0; }
  .lpanel-foot { height: 104px; padding: 10px 16px 12px; }
  .lpanel-last { font-size: 17px; }
  .cspot-disc { width: 50px; height: 50px; }
}

@media (max-width: 720px) {
  .homeboard-list { grid-template-rows: none; grid-auto-flow: row; }
  .homeboard, .homecols, .homefan, .homejumbo,
  .homecourt, .homelineup, .homelocker { padding-left: 16px; padding-right: 16px; }
  /* The reel runs edge to edge -- its own mask is the margin. */
  .homepick { flex-wrap: wrap; }
  .homecols { grid-template-columns: repeat(3, minmax(0, 1fr)); height: 420px; }
  .homecols .ccol:nth-child(n + 4) { display: none; }
  /* A fan needs width it does not have on a phone, so it becomes a scroller. */
  .homefan { overflow-x: auto; justify-content: flex-start; padding-bottom: 30px; }
  .ctile-fan { width: 132px; transform: none; }
  .ctile-fan + .ctile-fan { margin-left: 10px; }
  .jpanel { width: 300px; grid-template-columns: 112px minmax(0, 1fr); }
  .jpanel-name { font-size: 17px; }
  .jpanel-digits b { font-size: 17px; }
  /* The court keeps its aspect, so the markers shrink with it. */
  .cspot-disc { width: 34px; height: 34px; box-shadow: 0 0 0 1.5px var(--team-color); }
  .cspot-tag { padding: 1px 5px; gap: 3px; }
  .cspot-tag b { font-size: 8.5px; }
  .cspot-tag span { font-size: 8px; }
  /* Five angled panels will not fit a phone, so the row becomes a scroller. */
  .homelineup { overflow-x: auto; justify-content: flex-start; }
  .homelineup .lpanel { flex: 0 0 auto; width: 156px; height: 300px; margin-top: 0; }
  .reel-track .lpanel { --skew: 18px; width: 172px; height: 288px; margin-left: -12px; }
  .lpanel-art { inset: 0 0 96px 0; }
  .lpanel-foot { height: 96px; padding: 9px 14px 11px; }
  .lpanel-last { font-size: 15px; }
  .homelocker { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 10px; }
  .stall-kit img { max-height: 118px; }
}

@media (prefers-reduced-motion: reduce) {
  .homecols, .homefan, .homejumbo, .homecourt,
  .homelineup, .homereel, .homelocker { animation: none; }
  .ccol-track, .jumbo-track, .reel-track { animation: none; }
  /* Without the slide the reel becomes a plain scroller, so the panels past
     the first are still reachable. */
  .homereel { overflow-x: auto; }
  .homecols { height: auto; overflow: visible; -webkit-mask-image: none; mask-image: none; }
  /* Without the slide the board becomes a plain scroller, so the panels past
     the first are still reachable. */
  .jumbo-screen { overflow-x: auto; }
  .ctile, .ctile-shot, .ctile-logo, .jpanel, .cspot, .lpanel, .stall,
  .stall-kit img { transition: none; }
  .ctile:hover, .ctile:focus-visible, .jpanel:hover, .jpanel:focus-visible,
  .lpanel:hover, .lpanel:focus-visible, .stall:hover, .stall:focus-visible { transform: none; }
  .cspot:hover, .cspot:focus-visible { transform: translate(-50%, -50%); }
  .stall:hover .stall-kit img { transform: none; }
  .ctile-fan:hover, .ctile-fan:focus-visible { transform: rotate(var(--rot)) translateY(var(--lift)); }
}

/* ------------------------------------------------------------------- hub */

/* The landing screen: three equal columns, one per section. Everything here
   is a signpost -- the panels carry pictures of what is behind them, never
   the numbers themselves. */

main.hub { max-width: 1540px; padding: 0 24px 56px; }

.hubtop {
  text-align: center;
  padding: 40px 0 26px;
  animation: home-rise .7s cubic-bezier(.2, .7, .3, 1) both;
}
.hubtop h1.homelock {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin: 0 0 8px;
  font-size: 42px;
  font-weight: 660;
  letter-spacing: -0.032em;
  line-height: 1.05;
}
.hubtop .homelock-mark { width: 88px; height: 88px; }
.hubtop p {
  margin: 0 auto;
  max-width: 540px;
  font-size: 14.5px;
  color: var(--text-muted);
}

.hubgrid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
  align-items: stretch;
}

.hubpanel {
  --panel-accent: var(--series-1);
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding: 22px 22px 16px;
  text-align: left;
  font: inherit;
  color: inherit;
  border: 1px solid var(--border);
  border-radius: 20px;
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--panel-accent) 9%, var(--surface-1)) 0%,
      var(--surface-1) 46%);
  box-shadow: var(--shadow);
  overflow: hidden;
  cursor: pointer;
  transition: transform .18s cubic-bezier(.2, .7, .3, 1), box-shadow .18s ease, border-color .18s ease;
  animation: home-rise .7s cubic-bezier(.2, .7, .3, 1) both;
}
.hub-players { --panel-accent: var(--series-1); animation-delay: .05s; }
.hub-teams   { --panel-accent: var(--series-2); animation-delay: .13s; }
.hub-league  { --panel-accent: var(--series-3); animation-delay: .21s; }

/* The accent reads as a bar of colour along the top edge of the panel. */
.hubpanel::before {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 3px;
  background: var(--panel-accent);
  opacity: .85;
}
.hubpanel:hover,
.hubpanel:focus-within {
  transform: translateY(-3px);
  border-color: color-mix(in srgb, var(--panel-accent) 42%, var(--border));
  box-shadow: 0 2px 4px rgb(0 0 0 / .06), 0 26px 44px -22px color-mix(in srgb, var(--panel-accent) 60%, transparent);
}
.hubpanel:focus-visible { outline: 2px solid var(--panel-accent); outline-offset: 3px; }

.hubkicker {
  font-size: 11px;
  font-weight: 640;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--panel-accent);
}
.hubhead h2 {
  margin: 5px 0 6px;
  font-size: 27px;
  font-weight: 680;
  letter-spacing: -0.026em;
  line-height: 1.1;
}
.hubhead p {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-muted);
}

.hubfoot {
  margin-top: auto;
  width: 100%;
  padding: 12px 0 0;
  border: 0;
  border-top: 1px solid var(--border);
  background: none;
  display: flex;
  align-items: center;
  gap: 8px;
  text-align: left;
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 620;
  letter-spacing: .01em;
  color: var(--panel-accent);
  cursor: pointer;
}
.hubfoot:focus-visible { outline: 2px solid var(--panel-accent); outline-offset: 3px; border-radius: 4px; }
.hubarrow { transition: transform .18s cubic-bezier(.2, .7, .3, 1); }
.hubpanel:hover .hubarrow { transform: translateX(4px); }

.hubstats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
  padding: 10px 0 0;
}
.hubstats div { text-align: center; }
.hubstats b {
  display: block;
  font-size: 17px;
  font-weight: 660;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.hubstats span {
  font-size: 10.5px;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* --- players: a hand of headshot cards, spread from the centre. */

.hubfan {
  position: relative;
  flex: 1 1 auto;
  min-height: 258px;
  display: grid;
  place-items: center;
}
.hubface {
  --team-color: var(--series-1);
  --rot: 0deg; --dx: 0px; --dy: 0px;
  position: absolute;
  width: 120px;
  height: 168px;
  border-radius: 14px;
  overflow: hidden;
  background: var(--surface-1);
  border: 1px solid color-mix(in srgb, var(--team-color) 45%, transparent);
  box-shadow: 0 12px 26px -16px rgb(0 0 0 / .55);
  /* The per-card offsets are set inline; --fan is the one knob a narrow panel
     needs, so the hand can close up rather than be clipped by the panel. */
  transform: translate(calc(var(--dx) * var(--fan, 1)), calc(var(--dy) * var(--fan, 1))) rotate(var(--rot));
  transition: transform .22s cubic-bezier(.2, .7, .3, 1);
}
/* The portrait plate stays light in both themes -- the headshots ship on
   white, and multiply only dissolves that white against a light backdrop. */
.hubface::before {
  content: '';
  position: absolute;
  inset: 0 0 36px 0;
  background:
    radial-gradient(115% 85% at 50% 0%,
      #ffffff 0%,
      color-mix(in srgb, var(--team-color) 10%, #ffffff) 56%,
      color-mix(in srgb, var(--team-color) 26%, #f0efec) 100%);
}
.hubpanel:hover .hubface {
  transform:
    translate(calc(var(--dx) * var(--fan, 1) * 1.12), calc(var(--dy) * var(--fan, 1) * 1.15 - 6px))
    rotate(calc(var(--rot) * 1.15));
}
.hubface-logo {
  position: absolute;
  top: 40%; left: 50%;
  width: 118%;
  transform: translate(-50%, -50%);
  object-fit: contain;
  opacity: .18;
  filter: saturate(.75);
}
.hubface-shot {
  position: absolute;
  bottom: 36px;
  left: 50%;
  width: 108%;
  transform: translateX(-50%);
  mix-blend-mode: multiply;
}
.hubface-ph {
  position: absolute;
  inset: 0 0 36px 0;
  display: grid;
  place-items: center;
  font-size: 30px;
  font-weight: 680;
  color: color-mix(in srgb, var(--team-color) 62%, #0b0b0b);
}
.hubface-tag {
  position: absolute;
  inset: auto 0 0 0;
  height: 36px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 0 9px;
  background: var(--surface-1);
  border-top: 1px solid var(--border);
}
.hubface-tag.flip { align-items: flex-end; text-align: right; }
.hubface-tag b {
  font-size: 12.5px;
  font-weight: 660;
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.hubface-tag span {
  font-size: 10px;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* --- teams: the ten kits, crest over the shoulder of each. */

.hubjerseys {
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 6px 4px;
  align-content: center;
}
.hubjersey {
  --team-color: var(--series-1);
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 8px 4px 7px;
  border: 1px solid transparent;
  border-radius: 12px;
  background: transparent;
  font: inherit;
  color: inherit;
  cursor: pointer;
  transition: background .16s ease, border-color .16s ease, transform .16s cubic-bezier(.2, .7, .3, 1);
}
.hubjersey:hover,
.hubjersey:focus-visible {
  transform: translateY(-3px);
  border-color: color-mix(in srgb, var(--team-color) 45%, transparent);
  background: color-mix(in srgb, var(--team-color) 12%, var(--surface-1));
  outline: none;
}
.hubjersey-kit {
  position: relative;
  width: 100%;
  display: grid;
  place-items: center;
}
.hubjersey-img {
  width: 100%;
  max-width: 92px;
  height: 92px;
  object-fit: contain;
  filter: drop-shadow(0 2px 3px rgb(0 0 0 / .2));
  transition: transform .16s cubic-bezier(.2, .7, .3, 1);
}
.hubjersey:hover .hubjersey-img { transform: scale(1.06); }
/* The crest sits clear of the kit on its own disc, so it never has to compete
   with the jersey's own printing. */
.hubjersey-crest {
  position: absolute;
  right: 0;
  bottom: -3px;
  width: 34px;
  height: 34px;
  object-fit: contain;
  padding: 3px;
  border-radius: 50%;
  background: var(--surface-1);
  box-shadow: 0 1px 3px rgb(0 0 0 / .3);
}
.hubjersey-name {
  margin-top: 6px;
  font-size: 11px;
  font-weight: 680;
  letter-spacing: .06em;
}
.hubjersey-rec {
  font-size: 10.5px;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* --- league: one row per study. */

.hublist {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 6px;
  justify-content: center;
}
.hubrow {
  --row-color: var(--series-1);
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 9px 11px;
  text-align: left;
  font: inherit;
  color: inherit;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface-1);
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease, transform .15s cubic-bezier(.2, .7, .3, 1);
}
.hubrow:hover,
.hubrow:focus-visible {
  transform: translateX(3px);
  border-color: color-mix(in srgb, var(--row-color) 55%, transparent);
  background: color-mix(in srgb, var(--row-color) 8%, var(--surface-1));
  outline: none;
}
.hubglyph {
  flex: none;
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: 10px;
  color: var(--row-color);
  background: color-mix(in srgb, var(--row-color) 14%, var(--surface-1));
}
.hubrow-text { min-width: 0; }
.hubrow-text b {
  display: block;
  font-size: 13.5px;
  font-weight: 640;
  letter-spacing: -0.01em;
}
.hubrow-text span {
  display: block;
  font-size: 11.5px;
  line-height: 1.4;
  color: var(--text-muted);
}
.hubrow-go {
  margin-left: auto;
  flex: none;
  color: var(--text-muted);
  opacity: 0;
  transition: opacity .15s ease, transform .15s ease;
}
.hubrow:hover .hubrow-go,
.hubrow:focus-visible .hubrow-go { opacity: 1; transform: translateX(2px); color: var(--row-color); }

@media (max-width: 1180px) {
  .hubgrid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  /* The league list is the tallest panel, so it takes the full second row. */
  .hub-league { grid-column: 1 / -1; }
  .hublist { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 760px) {
  main.hub { padding: 0 16px 40px; }
  .hubgrid { grid-template-columns: minmax(0, 1fr); }
  .hub-league { grid-column: auto; }
  .hublist { grid-template-columns: minmax(0, 1fr); }
  .hubtop h1.homelock { font-size: 32px; }
  .hubtop .homelock-mark { width: 64px; height: 64px; }
  .hubfan { min-height: 220px; }
  .hubface { width: 108px; height: 150px; }
  .hubjerseys { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .hubjersey-img { height: 58px; }
  .hubjersey-crest { width: 24px; height: 24px; }
}

@media (prefers-reduced-motion: reduce) {
  .hubpanel { animation: none; transition: none; }
  .hubface, .hubjersey, .hubjersey-img, .hubrow, .hubarrow { transition: none; }
  .hubpanel:hover { transform: none; }
  .hubpanel:hover .hubface { transform: translate(calc(var(--dx) * var(--fan, 1)), calc(var(--dy) * var(--fan, 1))) rotate(var(--rot)); }
  .hubjersey:hover, .hubrow:hover { transform: none; }
}

/* ---------------------------------------------------------------- player */

/* One line: face, name block, career jerseys, career stats. The name block is
   the only part that gives ground -- the jerseys scroll and the stats never
   shrink, so nothing is ever pushed onto a second row. */
.hero {
  display: flex;
  align-items: flex-start;
  gap: 22px;
  padding: 0 4px 20px;
  flex-wrap: nowrap;
}
/* The jerseys and the season line keep their old footing on the baseline;
   only the face and the name block share a top edge. */
.teamhistory, .herostatblock { align-self: flex-end; }
/* Face plus name block. Stretch here means the face matches the name block
   exactly -- measured against it alone, not against the jersey row, which on
   a long career is far taller. The floor is wide enough to keep the bio chips
   on a single row so the jerseys can never push them onto a second. */
.heroid {
  display: flex;
  align-items: stretch;
  gap: 22px;
  flex: 1 1 auto;
  min-width: 360px;
}
.heroinfo { flex: 1 1 auto; min-width: 0; }

/* Name and archetype share a baseline; the chip drops under the name only
   when the name block is genuinely too narrow to hold both. */
.heroname {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 6px 12px;
}
/* The face stretches to whatever the name block measures, so both edges line
   up however many rows the bio chips take. Headshots are portraits, so the
   taller-than-wide crop is the natural one. */
.hero .shot {
  width: 96px;
  height: auto;
  min-height: 0;
  align-self: stretch;
  flex: 0 0 96px;
  border-radius: 14px;
  object-fit: cover;
  object-position: top center;
  background: var(--surface-3);
  border: 1px solid var(--border);
}
.hero .shot.ph { display: grid; place-items: center; font-size: 30px; font-weight: 640; color: var(--text-muted); }
.hero h1 {
  margin: 0;
  font-size: 34px;
  font-weight: 680;
  letter-spacing: -0.025em;
  line-height: 1.05;
}
.hero .meta { font-size: 13.5px; color: var(--text-secondary); margin-top: 7px; }
.hero .meta b { font-weight: 550; color: var(--text-primary); }
.dot-sep { color: var(--text-muted); margin: 0 7px; }

/* Archetype beside the name: no container, just a family-coloured dot and
   the label, so it reads as part of the name line rather than a badge. */
.archchip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  line-height: 1.15;
  white-space: nowrap;
  cursor: default;
  transform: translateY(-4px);
}
.archdot {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--arch, var(--text-muted));
  flex: none;
}
.archlabel {
  font-size: 14px;
  font-weight: 620;
  letter-spacing: -0.005em;
  color: var(--text-secondary);
  transition: color .14s ease;
}
.archchip:hover .archlabel { color: var(--text-primary); }

/* One family palette for the whole hub: the hero chip, the archetype map, its
   legend and the trajectory strip all read these three. Declared against the
   series roles so a theme flip carries them without a second table. */
:root {
  --fam-onball: var(--series-1);
  --fam-perimeter: var(--series-4);
  --fam-interior: var(--series-2);
  /* Lightness and chroma for the archetype tab's positional palette; the hue
     comes from where the archetype sits on the map. Dark mode lifts the
     lightness rather than reusing the light-mode step on a dark surface. */
  --arch-l: 0.585;
  --arch-c: 0.155;
}
@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) { --arch-l: 0.73; --arch-c: 0.145; }
}
:root[data-theme="dark"] { --arch-l: 0.73; --arch-c: 0.145; }
.archchip.fam-onball { --arch: var(--fam-onball); }
.archchip.fam-perimeter { --arch: var(--fam-perimeter); }
.archchip.fam-interior { --arch: var(--fam-interior); }

.biochips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 9px;
  margin-top: 12px;
  max-width: 680px;
}
.biochip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 28px;
  padding: 5px 11px 5px 9px;
  border: 1px solid var(--border);
  border-radius: 7px;
  background: var(--surface-2);
  color: var(--text-secondary);
  font-size: 12px;
  line-height: 1.15;
  white-space: nowrap;
  cursor: default;
}
.biogl {
  display: inline-flex;
  color: var(--text-muted);
  flex: none;
}
.biochip:hover .biogl { color: var(--text-secondary); }
.biochip .v {
  font-weight: 650;
  color: var(--text-primary);
}

/* Season and league sit above the numbers, because these are one season's
   averages and the header would otherwise read as a career line. */
.herostatblock { flex: none; margin-left: auto; padding-bottom: 3px; }
.herostatcap {
  font-size: 10.5px;
  font-weight: 620;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--text-secondary);
  margin-bottom: 7px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
  text-align: right;
}
.herostats { display: flex; gap: 22px; justify-content: flex-end; }
.herostat { text-align: right; }
.herostat .v { font-size: 23px; font-weight: 660; letter-spacing: -0.02em; line-height: 1.1; font-variant-numeric: tabular-nums; }
.herostat .l { font-size: 10px; text-transform: uppercase; letter-spacing: .06em; color: var(--text-muted); font-weight: 550; }

/* Career club run: a jersey per stint, years underneath, no heading -- it
   sits on its own line under the name and career stats. */
/* Every stint is visible at once -- a long career wraps onto another row of
   jerseys rather than hiding the early clubs behind a sideways scroll. */
.teamhistory {
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 10px 12px;
  margin-left: 24px;
  padding-bottom: 2px;
  /* Natural width up to the cap. Shrink must stay 0: any shrink factor makes
     the basis resolve to one jersey wide and stacks even a two-club career
     into a column. Past the cap the row wraps instead. */
  flex: 0 0 auto;
  max-width: 36%;
}

/* The jerseys hold their size and their place on the hero line at any normal
   desktop width; a six-club career simply takes a second row of jerseys
   inside its own column. Only below 1024px does the line genuinely run out of
   room, and there they drop under the name rather than shrink. */
@media (max-width: 1024px) {
  .hero { flex-wrap: wrap; }
  .heroid { min-width: 300px; }
  .herostatblock { order: 3; }
  .teamhistory {
    order: 4;
    flex-basis: 100%;
    max-width: 100%;
    margin-left: 0;
    margin-top: 4px;
    justify-content: flex-start;
  }
}

.thitem {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  flex-shrink: 0;
  padding: 4px 6px 3px;
  border-radius: 9px;
  transition: background .14s ease, transform .14s ease;
}
.thitem:hover { background: var(--surface-3); transform: translateY(-1px); }

.thjersey {
  width: 80px; height: 80px;
  object-fit: contain;
  display: block;
  filter: drop-shadow(0 1px 2px rgb(0 0 0 / .18));
}
.thyears {
  font-size: 11.5px;
  font-weight: 580;
  letter-spacing: .02em;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ------------------------------------------------------------------ teams */

.teamhero {
  --team-color: var(--series-1);
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 16px 18px;
  margin-bottom: 16px;
  flex-wrap: wrap;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  /* The team's own colour appears once, as a wash behind the header. Keeping
     it out of the marks means it never competes with the series encodings. */
  background:
    linear-gradient(100deg,
      color-mix(in srgb, var(--team-color) 16%, var(--surface-1)) 0%,
      var(--surface-1) 62%);
}
.teamhero h1 {
  margin: 0;
  font-size: 34px;
  font-weight: 680;
  letter-spacing: -0.025em;
  line-height: 1.1;
}
.teamhero .sub { margin: 4px 0 0; color: var(--text-secondary); font-size: 13.5px; }
.teamhero .meta { margin-top: 5px; font-size: 13.5px; color: var(--text-secondary); }
.teamhero .meta b { font-weight: 620; color: var(--text-primary); }
.teamhero .meta .m { color: var(--text-muted); }
.teamlogo {
  --team-color: var(--series-1);
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--team-color);
  color: #fff;
  border: 2px solid color-mix(in srgb, #fff 65%, var(--team-color));
  font-size: 11px;
  font-weight: 850;
  letter-spacing: .02em;
  box-shadow: var(--shadow);
}
.teamlogo.has-img {
  background: #fff;
  border-color: var(--team-color);
  padding: 5px;
}
.teamlogo.has-img img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}
.teamlogo.large {
  width: 82px;
  height: 82px;
  font-size: 19px;
  flex-shrink: 0;
}
.teamcontrols {
  margin-left: auto;
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.teamcontrols select {
  min-width: 170px;
  padding: 8px 30px 8px 10px;
  font: inherit;
  font-size: 13px;
  color: var(--text-primary);
  background: var(--surface-1);
  border: 1px solid var(--border-strong);
  border-radius: 8px;
}
.contextsplit {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.contextbar {
  display: flex;
  width: 100%;
  height: 14px;
  overflow: hidden;
  border-radius: 4px;
  background: var(--surface-3);
  border: 1px solid var(--border);
}
.contextbar i { display: block; min-width: 1px; }
.contextbar .trans, .contextlegend .sw.trans { background: var(--series-1); }
.contextbar .half, .contextlegend .sw.half { background: var(--pos); }
.contextbar .second, .contextlegend .sw.second { background: var(--warn); }
.contextlegend {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(145px, 1fr));
  gap: 8px 12px;
  margin-top: 10px;
}
.contextitem {
  display: flex;
  align-items: baseline;
  gap: 6px;
  min-width: 0;
  font-size: 12px;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}
.contextitem b { color: var(--text-primary); font-weight: 650; }
.contextitem .m { margin-left: auto; color: var(--text-muted); }
.contextlegend .sw {
  width: 9px;
  height: 9px;
  border-radius: 2px;
  flex-shrink: 0;
}
.teamlogo.mini {
  width: 22px;
  height: 22px;
  font-size: 8px;
  border-width: 1.5px;
  box-shadow: none;
  flex-shrink: 0;
}
.teamlogo.mini.has-img { padding: 2px; }

.teamkpis {
  display: grid;
  grid-template-columns: repeat(8, minmax(0, 1fr));
  gap: 10px;
  margin-bottom: 20px;
}
.teamkpi {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 13px 14px;
  box-shadow: var(--shadow);
}
.teamkpi .v {
  font-size: 23px;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.teamkpi .l {
  margin-top: 4px;
  color: var(--text-muted);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: .06em;
  font-weight: 650;
}
/* Rank sits under the value as a chip, so "118.2" and "1st of 10" are never
   mistaken for two numbers of the same kind. */
.teamkpi .r {
  margin-top: 7px;
  display: inline-block;
  padding: 2px 7px;
  border-radius: 99px;
  font-size: 10.5px;
  font-weight: 620;
  font-variant-numeric: tabular-nums;
  color: var(--text-secondary);
  background: var(--surface-3);
}
.teamkpi .r.good { color: var(--pos); background: color-mix(in srgb, var(--pos) 14%, transparent); }
.teamkpi .r.bad { color: var(--neg); background: color-mix(in srgb, var(--neg) 14%, transparent); }

.teamdash { grid-template-columns: minmax(560px, 1.3fr) minmax(380px, .8fr); align-items: start; }
/* Capped so the map keeps its aspect on a full-width card — stretched to
   1500px the logos drift apart and the quadrant stops reading as a plane. */
.teamquad { display: block; width: 100%; max-width: 760px; margin: 0 auto; height: auto; }
.quadbg { fill: var(--surface-3); }
.quadavg { stroke: var(--axis); stroke-width: 1; stroke-dasharray: 5 7; opacity: .75; }
.quadlabel {
  fill: var(--text-muted);
  font-size: 10px;
  font-weight: 650;
  text-transform: uppercase;
  letter-spacing: .07em;
  opacity: .72;
}
.axislabel {
  fill: var(--text-secondary);
  font-size: 12px;
  font-weight: 650;
}
.teamdot { cursor: pointer; outline: none; }
.teamdot-bg {
  fill: color-mix(in srgb, var(--surface-1) 88%, var(--team-color));
  stroke: color-mix(in srgb, var(--team-color) 78%, #fff);
  stroke-width: 2;
  filter: drop-shadow(0 3px 4px rgba(0,0,0,.28));
  transition: stroke-width .12s, filter .12s, transform .12s;
}
.teamdot.has-logo .teamdot-bg {
  fill: color-mix(in srgb, var(--surface-1) 90%, #fff);
  stroke: color-mix(in srgb, var(--team-color) 80%, #fff);
}
.teamdot:hover .teamdot-bg,
.teamdot:focus .teamdot-bg {
  stroke-width: 3;
  filter: drop-shadow(0 5px 7px rgba(0,0,0,.34));
}
.teamdot.active .teamdot-bg {
  stroke: var(--warn);
  stroke-width: 3.5;
}
.teamdot-logo { pointer-events: none; }
.teamdot-text {
  fill: #fff;
  font-size: 10px;
  font-weight: 850;
  pointer-events: none;
}

/* ------------------------------------------------------------------ tabs */

.tabs {
  display: flex;
  gap: 2px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 22px;
  overflow-x: auto;
}
.tab {
  padding: 10px 15px;
  font: inherit; font-size: 13.5px; font-weight: 550;
  color: var(--text-muted);
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  cursor: pointer;
  white-space: nowrap;
}
.tab:hover { color: var(--text-secondary); }
.tab[aria-selected="true"] { color: var(--text-primary); border-bottom-color: var(--series-1); }

/* ----------------------------------------------------------------- cards */

.grid { display: grid; gap: 16px; }
.grid.two { grid-template-columns: 1fr 1fr; }
/* Court, then zone frequency, then the shot-type table -- three columns that
   read left to right from where the shots went to what they were. */
.grid.shot {
  grid-template-columns: minmax(300px, 380px) minmax(330px, 1fr) minmax(330px, 400px);
  align-items: start;
}
/* Three columns inside the 1180px page leaves the shot chart about 360px, and
   a player with several shot sources puts three controls in its header. At the
   full-size scale they wrapped onto a second and third row and pushed the
   court down out of line with the cards beside it. */
.grid.shot .head .ctl { gap: 5px; }
.grid.shot .head .seg { padding: 1px; }
.grid.shot .head .seg button {
  padding: 3px 7px;
  font-size: 11px;
}

.card {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px 20px;
  box-shadow: var(--shadow);
  min-width: 0;
}
.card > h2 {
  margin: 0 0 3px;
  font-size: 14.5px;
  font-weight: 620;
  letter-spacing: -0.01em;
}
.card > .sub {
  margin: 0 0 16px;
  font-size: 12px;
  color: var(--text-muted);
}
.card .head {
  display: flex; align-items: flex-start; gap: 14px;
  margin-bottom: 16px; flex-wrap: wrap;
}
.card .head h2 { margin: 0 0 3px; font-size: 14.5px; font-weight: 620; letter-spacing: -0.01em; }
.card .head .sub { margin: 0; font-size: 12px; color: var(--text-muted); }
.card .head .ctl { margin-left: auto; display: flex; gap: 6px; flex-wrap: wrap; }

/* Groups the overview tab into a story -- arc, then now, then skills, then
   bottom line -- without the visual weight of another card. */
.section-eyebrow {
  margin: 28px 2px 10px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.section-eyebrow:first-child { margin-top: 0; }

/* ------------------------------------------------------ overview compact */

/* Section label and the colour key on one line, so the key is stated once for
   the tab rather than repeated under every bar card. */
.sechead {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}
.barlegend {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  color: var(--text-muted);
}
.barlegend .sw {
  width: 9px; height: 9px;
  border-radius: 2px;
  flex-shrink: 0;
}
.barlegend .sw + .sw { margin-left: 6px; }

/* Sample-size line at the foot of a card. Quieter than .legend: it is context,
   not a key. */
.cardfoot {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--grid);
  font-size: 11px;
  color: var(--text-muted);
}
.cardfoot .defs { margin-top: 4px; }
.cardfoot .defs b { color: var(--text-secondary); font-weight: 620; }

/* ------------------------------------------------- overview dashboard */

/* The dash header: who/how much on the left, the season picker on the right.
   The picker scrolls rather than wraps, so a ten-season career does not push
   the panels below the fold. */
.dashhead {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 4px 20px;
  margin-bottom: 12px;
}
.dashmeta {
  font-size: 11.5px;
  color: var(--text-muted);
  min-width: 0;
}
.dashpick {
  justify-self: end;
  min-width: 0;
  max-width: 100%;
}
/* A ten-season career scrolls rather than wrapping: a second row of buttons
   would push the panels below the fold, which is the whole point of the dash. */
.dashpick .seg {
  display: flex;
  overflow-x: auto;
  scrollbar-width: none;
  max-width: 100%;
}
.dashpick .seg::-webkit-scrollbar { display: none; }
.dashpick .seg button { padding: 4px 9px; font-size: 11.5px; white-space: nowrap; }
.dashhead .barlegend { justify-self: end; }

/* Panels stretch to the tallest in their row so the card edges line up; the
   rows inside stay top-aligned and a fixed height, so a row in Scoring sits on
   the same line as the row beside it in Playmaking. */
.dashgrid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}
.dashcard {
  display: flex;
  flex-direction: column;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 14px 10px;
  box-shadow: var(--shadow);
  min-width: 0;
}
.dashtitle {
  font-size: 10.5px;
  font-weight: 680;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 6px;
}
.dashrows { display: flex; flex-direction: column; }
.dashempty {
  padding: 10px 2px;
  font-size: 11.5px;
  color: var(--text-muted);
}

/* Label, value, rank rail, percentile. The label and value are fixed widths so
   the value lands right beside the name it belongs to, and the rail takes the
   slack instead of it opening as a gutter between the two. Equal panel widths
   then put all four columns on the same x in every panel. */
.dashrow {
  display: grid;
  grid-template-columns: 148px 56px minmax(56px, 1fr) 20px;
  align-items: center;
  gap: 12px;
  height: 28px;
  padding: 0 5px;
  border-radius: 6px;
}
.dashrow:hover { background: var(--surface-3); }
.dashrow:focus-visible { outline: 2px solid var(--axis); outline-offset: -2px; }
.dashrow .lab {
  font-size: 11.5px;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* The value is the point of the row; the rank is context for it. */
.dashrow .val {
  font-size: 15px;
  font-weight: 660;
  letter-spacing: -0.02em;
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}
.dashrail {
  position: relative;
  height: 4px;
  border-radius: 2px;
  background: var(--surface-3);
}
.dashrail.norank { opacity: .45; }
.dashrail .mid {
  position: absolute;
  left: 50%; top: -3px; bottom: -3px;
  width: 1px;
  background: var(--axis);
}
.dashrail .fill {
  position: absolute;
  top: 0; bottom: 0;
  border-radius: 2px;
}
/* A percentile is a position in the league, so the marker is what carries it;
   the fill back to the median is only there to show which side of it he is. */
.dashrail .dot {
  position: absolute;
  top: 50%;
  width: 8px; height: 8px;
  margin-left: -4px;
  border-radius: 50%;
  transform: translateY(-50%);
  box-shadow: 0 0 0 2px var(--surface-1);
}
.dashrow .pn {
  font-size: 11px;
  font-weight: 620;
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}
/* The headline metric of a panel section: same four columns, more weight, and
   a hairline above it when a second section opens further down the card. */
.dashrow.lead { height: 32px; }
.dashrow.lead .lab {
  font-size: 12px;
  font-weight: 580;
  color: var(--text-primary);
}
.dashrow.lead .val { font-size: 17px; }
.dashrows > .dashrow.lead:not(:first-child) {
  margin-top: 7px;
  border-top: 1px solid var(--grid);
  border-radius: 0 0 6px 6px;
  padding-top: 6px;
  height: auto;
  min-height: 31px;
}

/* What the headline is made of. Segments sit in the categorical order with a
   2px surface gap so adjacent hues never touch, and every segment is named
   underneath -- colour alone never carries the identity. */
/* Bar and its key share one line: the bar is the shape of the split, the key
   names the parts. Stacking them would cost a row of height per section. */
.dashstack {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 2px 5px 6px;
}
.stackbar {
  display: flex;
  gap: 2px;
  height: 6px;
  flex: 0 0 118px;
}
.stackbar i {
  border-radius: 3px;
  min-width: 3px;
}
.stackkey {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 9px;
  min-width: 0;
  font-size: 10px;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.stackkey .ski { display: inline-flex; align-items: center; gap: 4px; }
.stackkey .ski i {
  width: 7px; height: 7px;
  border-radius: 2px;
  flex: none;
}

.dashrow .pn.good { color: var(--pos); }
.dashrow .pn.bad { color: var(--neg); }

/* ------------------------------------------------------ percentile comb */

/* Ten ticks, all the same height. Lit ticks count up from the left, so the
   length is the rank and the hue is only which side of the median it fell on;
   the unlit ticks stay drawn, at half height and in the grid colour, so the
   scale is still there behind a short reading. The exact percentile sits
   beside the comb -- the shape is what you scan a column with, the number is
   what you land on. */
.pctmark {
  display: flex;
  align-items: center;
  gap: 6px;
}
.pctcomb {
  display: flex;
  align-items: center;
  gap: 2px;
  flex: 1 1 auto;
  min-width: 0;
  height: 11px;
}
.pctcomb i {
  flex: 1 1 0;
  min-width: 1px;
  height: 50%;
  border-radius: 1.5px;
  background: var(--grid);
}
/* A wider step at the halfway point marks the median without drawing a rule
   through the comb. */
.pctcomb i:nth-child(5) { margin-right: 3px; }
.pctcomb i.hi,
.pctcomb i.lo { height: 100%; }
/* Strength as well as side: --k is the distance from the median, so a rank
   just off 50 comes out washed toward white and only the ends of the scale
   get the full hue. Capped at a third of the way so the two poles never stop
   reading as red and blue. */
.pctcomb i.hi {
  background: color-mix(in oklab, var(--pos) calc((67 + 33 * var(--k, 1)) * 1%), #fff);
}
.pctcomb i.lo {
  background: color-mix(in oklab, var(--neg) calc((67 + 33 * var(--k, 1)) * 1%), #fff);
}
.pctnumeral {
  flex: 0 0 auto;
  min-width: 16px;
  text-align: right;
  font-size: 12px;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  color: var(--text-secondary);
}

/* ------------------------------------------------ overview stat groups */

.overview-groups {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 10px;
  align-items: stretch;
}
.ogcard {
  display: flex;
  flex-direction: column;
  min-width: 0;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}
/* The head is the section's anchor, not its argument: the per-game line sits
   a step above the rows below it and no further, so the eye moves down into
   the rates instead of stopping on the box score. */
.oghead {
  min-height: 74px;
  padding: 10px 12px 10px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--grid);
}
.ogtitle {
  margin-bottom: 7px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.ogheads {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(64px, 1fr));
  gap: 8px;
}
.ogheadline {
  min-width: 0;
  padding: 1px 0;
  border-radius: 6px;
}
.ogheadline:hover { background: var(--surface-3); }
.ogheadline:focus-visible,
.ogmetric:focus-visible { outline: 2px solid var(--axis); outline-offset: -2px; }
.ognum {
  font-size: 21px;
  font-weight: 680;
  line-height: 1;
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}
.oglabel {
  margin-top: 3px;
  font-size: 9.5px;
  font-weight: 650;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-muted);
}
/* The ranked rates are the body of the card, so they get the room: a row is
   taller than the per-game head is loud, and the value inside it is only a
   step below that head's number. */
.ogmetrics {
  display: flex;
  flex-direction: column;
  padding: 8px 8px 10px;
}
/* Two lines rather than three columns. A metric name like "Own-miss reb %"
   has nowhere to go in a fifth of the page once a value and a rank mark have
   taken their share of the row, so the name gets the full width of the card
   and the value sits under it beside its mark. */
.ogmetric {
  display: grid;
  grid-template-columns: auto minmax(60px, 1fr);
  grid-template-areas:
    'lab lab'
    'val mark';
  align-items: center;
  column-gap: 10px;
  row-gap: 2px;
  padding: 6px 5px 7px;
  border-radius: 6px;
}
.ogmetric:hover { background: var(--surface-3); }
.ogmetric .l {
  grid-area: lab;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 11.5px;
  color: var(--text-secondary);
}
.ogmetric .v {
  grid-area: val;
  font-size: 15px;
  font-weight: 640;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}
.ogmetric .pctmark {
  grid-area: mark;
  justify-self: end;
  width: 100%;
  max-width: 132px;
}

@media (max-width: 1180px) {
  .overview-groups { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 860px) {
  .overview-groups { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 620px) {
  .overview-groups { grid-template-columns: minmax(0, 1fr); }
  .oghead { min-height: auto; }
  .ognum { font-size: 19px; }
}

/* --------------------------------------------- overview dashboard v2 */

.overview-dashboard {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  align-items: stretch;
}
.odcard {
  --od-accent: var(--series-1);
  display: grid;
  grid-template-columns: minmax(160px, .42fr) minmax(0, 1fr);
  min-width: 0;
  min-height: 236px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.odcard.score { --od-accent: var(--series-1); }
.odcard.play { --od-accent: var(--series-3); }
.odcard.defend { --od-accent: var(--series-2); }
.odcard.rebound { --od-accent: var(--series-4); }
.odtop {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 18px;
  min-width: 0;
  padding: 15px 15px 14px;
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--od-accent) 14%, transparent), transparent 74%),
    var(--surface-2);
  border-right: 1px solid var(--grid);
  box-shadow: inset 3px 0 0 var(--od-accent);
}
.odtitle {
  font-size: 11px;
  font-weight: 740;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-secondary);
}
.odheads {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(70px, 1fr));
  gap: 12px;
}
.odheadline {
  min-width: 0;
  padding: 2px 0;
  border-radius: 6px;
}
.odheadline:hover { background: var(--surface-3); }
.odheadline:focus-visible,
.odmetric:focus-visible { outline: 2px solid var(--axis); outline-offset: -2px; }
.odnum {
  font-size: 34px;
  font-weight: 720;
  line-height: .98;
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}
.odnum.good { color: var(--pos); }
.odnum.bad { color: var(--neg); }
.odlabel {
  margin-top: 5px;
  font-size: 10px;
  font-weight: 680;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.odbody {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 8px 14px;
  align-content: start;
  min-width: 0;
  padding: 12px 13px;
}
.odsection {
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.odsectitle {
  margin: 2px 5px 5px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.odmetric {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto 26px;
  align-items: baseline;
  gap: 9px;
  min-height: 29px;
  padding: 4px 5px;
  border-radius: 6px;
}
.odmetric:hover { background: var(--surface-3); }
.odmetric .l {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 11.5px;
  color: var(--text-secondary);
}
.odmetric .v {
  font-size: 13px;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}
.odmetric .p {
  text-align: right;
  font-size: 10.5px;
  font-weight: 680;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}
.odmetric .p.good { color: var(--pos); }
.odmetric .p.bad { color: var(--neg); }

@media (max-width: 1100px) {
  .overview-dashboard { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 620px) {
  .odcard {
    grid-template-columns: minmax(0, 1fr);
    min-height: 0;
  }
  .odtop {
    border-right: none;
    border-bottom: 1px solid var(--grid);
    gap: 12px;
  }
  .odnum { font-size: 28px; }
  .odbody { grid-template-columns: minmax(0, 1fr); }
}

/* ------------------------------------------------------- profile view */

/* The hero: what the section is mostly about, sized so it is the first thing
   read and the only number in the card that needs no label beside it. */
.sigcard { padding: 13px 16px 12px; }
.sighead {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 1px 0 8px;
  border-radius: 6px;
}
.sighead:hover { background: var(--surface-3); }
.signum {
  font-size: 30px;
  font-weight: 680;
  letter-spacing: -0.03em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.signum.good { color: var(--pos); }
.signum.bad { color: var(--neg); }
.sigcap { min-width: 0; }
.sigcaplab {
  font-size: 12px;
  font-weight: 560;
  color: var(--text-primary);
}
.sigcappct { font-size: 11px; color: var(--text-muted); }

/* One axis for the whole section: every measure in it sits somewhere between
   weaker and stronger, so the spread of the dots is the shape of the player. */
.sigaxis {
  position: relative;
  height: 10px;
  margin: 2px 4px 0;
  border-radius: 5px;
  background: var(--surface-3);
}
.sigaxis .sigmid {
  position: absolute;
  left: 50%; top: -2px; bottom: -2px;
  width: 1px;
  background: var(--axis);
}
.sigdot {
  position: absolute;
  top: 50%;
  width: 9px; height: 9px;
  margin-left: -4.5px;
  transition: opacity .12s ease;
  border-radius: 50%;
  transform: translateY(-50%);
  box-shadow: 0 0 0 2px var(--surface-1);
  opacity: .55;
}
.sigdot.is-hero {
  width: 13px; height: 13px;
  margin-left: -6.5px;
  opacity: 1;
}
.sigdot:hover, .sigdot:focus-visible { opacity: 1; outline: none; }
.sigscale {
  display: flex;
  justify-content: space-between;
  margin: 5px 4px 0;
  font-size: 9.5px;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* The two ends of the spread, named. */
.sigcall {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 9px;
}
.sigchip {
  font-size: 10.5px;
  padding: 3px 8px;
  border-radius: 999px;
  background: var(--surface-3);
  color: var(--text-secondary);
}
.sigchip b {
  font-weight: 660;
  letter-spacing: .04em;
  text-transform: uppercase;
  font-size: 9.5px;
}
.sigchip.good b { color: var(--pos); }
.sigchip.bad b { color: var(--neg); }

/* The rest of the section, quiet: name, number, rank. No rails -- the axis
   above already said where each of these sits. */
.sigrows {
  margin-top: 9px;
  padding-top: 8px;
  border-top: 1px solid var(--grid);
  display: flex;
  flex-direction: column;
}
.sigrow {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto 30px;
  align-items: baseline;
  gap: 10px;
  padding: 2px 4px;
  border-radius: 5px;
}
.sigrow:hover { background: var(--surface-3); }
.sigrow:focus-visible { outline: 2px solid var(--axis); outline-offset: -2px; }
.sigrow .l {
  font-size: 11.5px;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sigrow .v {
  font-size: 12.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}
.sigrow .p {
  font-size: 10.5px;
  font-weight: 620;
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}
.sigrow .p.good { color: var(--pos); }
.sigrow .p.bad { color: var(--neg); }

/* Below two comfortable panel widths the rails get too short to read a
   position off, so the grid drops to one column rather than squeezing. */
@media (max-width: 860px) {
  .dashgrid { grid-template-columns: minmax(0, 1fr); }
}
/* Narrow enough that the picker and the sample line cannot share a row without
   the line collapsing to one word per line, so the header stacks instead. */
@media (max-width: 760px) {
  .dashhead { grid-template-columns: minmax(0, 1fr); gap: 8px; }
  .dashpick, .dashhead .barlegend { justify-self: start; }
}
@media (max-width: 620px) {
  .dashrow { grid-template-columns: minmax(0, 118px) 50px minmax(40px, 1fr) 20px; gap: 8px; }
  .dashrow .val { font-size: 14px; }
}

/* Group divider inside a bar list. */
.pctgroup {
  margin: 10px 0 4px;
  padding: 0 6px;
  font-size: 10px;
  font-weight: 660;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.pctgroup:first-child { margin-top: 2px; }

/* Bars in a half-width card: narrower label gutter, tighter rows. */
.pctrows.compact .pctrow {
  grid-template-columns: 126px 1fr 50px;
  gap: 10px;
  padding: 2px 6px;
}
.pctrows.compact .pctrow .lab,
.pctrows.compact .pctrow .val { font-size: 11.5px; }

/* --------------------------------------------------------------- toggles */

.seg {
  display: inline-flex;
  padding: 2px;
  gap: 2px;
  background: var(--surface-3);
  border-radius: 8px;
}
.seg button {
  padding: 5px 11px;
  font: inherit; font-size: 12px; font-weight: 550;
  color: var(--text-muted);
  background: none; border: none; border-radius: 6px;
  cursor: pointer; white-space: nowrap;
}
.seg button:hover { color: var(--text-secondary); }
.seg button[aria-pressed="true"] {
  background: var(--surface-1);
  color: var(--text-primary);
  box-shadow: 0 1px 2px rgba(0, 0, 0, .10);
}
.ghost {
  padding: 5px 10px;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
  background: var(--surface-1);
  border: 1px solid var(--border-strong);
  border-radius: 7px;
  cursor: pointer;
  white-space: nowrap;
}
.ghost:hover { color: var(--text-primary); border-color: var(--axis); }

/* ---------------------------------------------------------------- tables */

.tablewrap { overflow-x: auto; margin: 0 -20px; padding: 0 20px; }

table.stat {
  width: 100%;
  border-collapse: collapse;
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
table.stat th {
  text-align: right;
  padding: 0 0 8px 14px;
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--text-muted);
  border-bottom: 1px solid var(--grid);
}
table.stat th:first-child, table.stat td:first-child { text-align: left; padding-left: 0; }
table.stat td {
  text-align: right;
  padding: 7px 0 7px 14px;
  border-bottom: 1px solid var(--grid);
  color: var(--text-secondary);
}
table.stat tbody tr:last-child td { border-bottom: none; }
table.stat tbody tr:hover td { background: var(--surface-3); }
table.stat td.key { color: var(--text-primary); font-weight: 560; }
table.stat tr.career td {
  border-top: 1px solid var(--axis);
  border-bottom: none;
  font-weight: 600;
  color: var(--text-primary);
  padding-top: 9px;
}
table.stat td.dim { color: var(--text-muted); }

table.swingtable th,
table.swingtable td { vertical-align: top; }
.swingname {
  min-width: 150px;
}
.swingname .m {
  display: block;
  margin-top: 2px;
  color: var(--text-muted);
  font-size: 11px;
  font-weight: 500;
}
.swingcell {
  min-width: 72px;
  font-variant-numeric: tabular-nums;
}
.swingcell b,
.swingcell span,
.swingcell em {
  display: block;
  line-height: 1.22;
  white-space: nowrap;
}
.swingcell b {
  color: var(--text-primary);
  font-weight: 650;
}
.swingcell span {
  color: var(--text-muted);
  font-size: 11px;
}
.swingcell em {
  margin-top: 3px;
  font-style: normal;
  font-size: 11px;
  font-weight: 650;
}
.swingcell em.pos { color: var(--pos); }
.swingcell em.neg { color: var(--neg); }
.swingcell em.neutral { color: var(--text-muted); }

.lineuptable td { vertical-align: middle; }
.lineupcell { min-width: 270px; max-width: 430px; }
.lineupchips {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.lineupchip {
  display: inline-flex;
  align-items: center;
  max-width: 150px;
  height: 22px;
  padding: 0 7px;
  border: 1px solid var(--grid);
  border-radius: 7px;
  background: var(--surface-2);
  color: var(--text-primary);
  font-size: 11.5px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
}
.lineupcell .m {
  display: block;
  margin-top: 5px;
  color: var(--text-muted);
  font-size: 11px;
  font-weight: 500;
}

/* ----------------------------------------------------- percentile chart */

.pctrows { display: flex; flex-direction: column; gap: 2px; }
.pctrow {
  display: grid;
  grid-template-columns: 136px 1fr 56px;
  align-items: center;
  gap: 12px;
  padding: 3px 6px;
  border-radius: 7px;
}
.pctrow:hover { background: var(--surface-3); }
.pctrow .lab { font-size: 12px; color: var(--text-secondary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pctrow .val { font-size: 12px; text-align: right; font-variant-numeric: tabular-nums; color: var(--text-primary); font-weight: 560; }
.pcttrack {
  position: relative;
  height: 15px;
  background: var(--surface-3);
  border-radius: 4px;
  overflow: hidden;
}
.pcttrack .mid {
  position: absolute;
  left: 50%; top: 0; bottom: 0;
  width: 1px;
  background: var(--axis);
}
.pctfill {
  position: absolute;
  top: 2px; bottom: 2px;
  border-radius: 2px;
}
.pctfill.hi { border-radius: 2px 4px 4px 2px; }
.pctfill.lo { border-radius: 4px 2px 2px 4px; }
.pctnum {
  position: absolute;
  top: 50%; transform: translateY(-50%);
  font-size: 10px; font-weight: 600;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}

.legend {
  display: flex; flex-wrap: wrap; gap: 14px;
  margin-top: 14px; padding-top: 12px;
  border-top: 1px solid var(--grid);
  font-size: 11.5px; color: var(--text-secondary);
}
.legend .item { display: flex; align-items: center; gap: 6px; }
.legend .sw { width: 10px; height: 10px; border-radius: 3px; flex-shrink: 0; }
.legend .sw.ring { border-radius: 50%; background: none; border: 2px solid var(--series-8); }

/* ------------------------------------------------------------ shot chart */

/* Stroke widths are in viewBox units (10 per metre), so they are ~4x smaller
   than the equivalent pixel value at render size. */
.courtwrap { position: relative; }
svg.court { width: 100%; height: auto; display: block; overflow: visible; }
.court .line { fill: none; stroke: var(--axis); stroke-width: .5; }
.court .floor { fill: var(--surface-3); }
.shot-make { fill: var(--series-1); stroke: var(--surface-1); stroke-width: .5; }
.shot-miss { fill: none; stroke: var(--series-8); stroke-width: .7; }
.shot-make, .shot-miss { opacity: .88; }
.shot-make:hover, .shot-miss:hover { opacity: 1; stroke: var(--text-primary); }

/* Hex heat map. The surface-coloured stroke is the 2px gap that separates
   touching cells -- not a border drawn around the mark. */
.hexcell { stroke: var(--surface-1); stroke-width: .18; }
/* Hovering fades every cell outside the hovered region, so the block the
   fill actually describes reads as one shape. */
.hexcell.dim { opacity: .25; }
.hexfocus { pointer-events: none; }

/* --------------------------------------------------------- court impact */

.impactgrid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 22px;
}
@media (max-width: 720px) {
  .impactgrid { grid-template-columns: 1fr; }
}
.impactpanel h3 {
  margin: 0 0 2px;
  font-size: 13px;
  font-weight: 640;
}
.impactpanel .sub {
  margin: 0 0 10px;
  font-size: 11.5px;
  color: var(--text-muted);
}

/* ---------------------------------------------------- RAPM influence model */

.rapmxtiles {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 10px;
}
.rapmxtile {
  min-width: 0;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface-3);
}
.rapmxtile .v {
  font-size: 22px;
  line-height: 1.05;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.rapmxtile .l {
  margin-top: 5px;
  font-size: 11px;
  font-weight: 650;
  color: var(--text-secondary);
}
.rapmxgrid { align-items: start; }
.rapmxbars, .rapmxgroups { display: grid; gap: 7px; }
.rapmxbar {
  display: grid;
  grid-template-columns: minmax(150px, 1fr) minmax(120px, 1.1fr) 46px;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 7px 8px;
  border: 1px solid transparent;
  border-radius: 8px;
  color: var(--text-primary);
  background: transparent;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.rapmxbar:hover, .rapmxbar.on {
  background: var(--surface-3);
  border-color: var(--border);
}
.rapmxbar .lab {
  min-width: 0;
  display: grid;
  gap: 1px;
}
.rapmxbar .lab span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 12.5px;
  font-weight: 600;
}
.rapmxbar .lab small { font-size: 10.5px; color: var(--text-muted); }
.rapmxbar .track, .rapmxgroup .track {
  height: 11px;
  background: var(--surface-3);
  border-radius: 999px;
  overflow: hidden;
}
.rapmxbar .track i, .rapmxgroup .track i {
  display: block;
  height: 100%;
  border-radius: inherit;
}
.rapmxbar .track i.pos, .rapmxgroup .track i { background: var(--pos); }
.rapmxbar .track i.neg { background: var(--neg); }
.rapmxbar .val, .rapmxgroup .val {
  text-align: right;
  font-size: 12px;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}
.rapmxbar .val {
  display: grid;
  gap: 2px;
}
.rapmxbar .val small {
  display: block;
  font-size: 10px;
  line-height: 1.15;
  color: var(--text-muted);
  white-space: nowrap;
}
.rapmxgroup {
  display: grid;
  grid-template-columns: minmax(130px, 0.9fr) minmax(120px, 1fr) 52px;
  align-items: center;
  gap: 10px;
  padding: 7px 8px;
  border-radius: 8px;
}
.rapmxgroup:hover { background: var(--surface-3); }
.rapmxgroup .lab {
  display: grid;
  gap: 2px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-secondary);
}
.rapmxgroup .lab small {
  color: var(--text-muted);
  font-size: 10.5px;
  font-weight: 500;
}
table.rapmxtable td {
  font-variant-numeric: tabular-nums;
}
table.rapmxtable tbody tr:not(.dimrow) {
  cursor: pointer;
}
table.rapmxtable tbody tr:not(.dimrow):hover {
  background: var(--surface-3);
}
table.rapmxtable .dimrow {
  opacity: .72;
}
.rapmxscatter {
  display: block;
  width: 100%;
  max-width: 860px;
  margin: 0 auto;
}
.rapmxscatter .gridline { stroke: var(--grid); stroke-width: 1; }
.rapmxscatter .zeroline { stroke: var(--axis); stroke-width: 1.2; }
.rapmxscatter .tick {
  fill: var(--text-muted);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}
.rapmxfit { stroke: var(--series-2); stroke-width: 2; }
.rapmxdot { outline: none; }
.rapmxdotmark {
  fill: color-mix(in srgb, var(--series-1) 68%, transparent);
  stroke: var(--surface-1);
  stroke-width: 2;
}
.rapmxdot:hover .rapmxdotmark,
.rapmxdot:focus-visible .rapmxdotmark {
  fill: var(--series-1);
  stroke: var(--text-primary);
}

/* --------------------------------------------------- event location value */

.eventmaps {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: start;
  margin-top: 16px;
}
.eventmaps .card:first-child { grid-column: 1 / -1; }
.eventtiles {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 10px;
}
.eventtile {
  min-width: 0;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface-3);
}
.eventtile .v {
  font-size: 22px;
  line-height: 1.05;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.eventtile .l {
  margin-top: 5px;
  font-size: 11px;
  font-weight: 650;
  color: var(--text-secondary);
}
.eventtile .s {
  margin-top: 2px;
  font-size: 10.5px;
  color: var(--text-muted);
}
svg.fullcourt {
  max-width: 760px;
  margin: 0 auto;
}
.eventcell {
  stroke: var(--surface-1);
  stroke-width: .8;
  outline: none;
}
.eventcell.thin {
  opacity: .72;
  stroke: var(--border-strong);
  stroke-dasharray: 2 2;
}
.eventcell:hover,
.eventcell:focus-visible {
  stroke: var(--text-primary);
  stroke-width: 1.5;
}
.eventlegend {
  align-items: center;
}
.eventramp {
  display: flex;
  overflow: hidden;
  border-radius: 4px;
}
.eventramp i {
  width: 18px;
  height: 10px;
}

.divscale { display: inline-flex; gap: 2px; }
.divscale i {
  width: 15px;
  height: 10px;
  border-radius: 2px;
}
.divscale i:first-child { border-radius: 4px 2px 2px 4px; }
.divscale i:last-child { border-radius: 2px 4px 4px 2px; }

/* --------------------------------------------------------------- tooltip */

.tip {
  position: fixed;
  z-index: 90;
  pointer-events: none;
  padding: 8px 11px;
  font-size: 12px;
  line-height: 1.5;
  background: var(--surface-1);
  color: var(--text-primary);
  border: 1px solid var(--border-strong);
  border-radius: 9px;
  box-shadow: var(--shadow);
  opacity: 0;
  transition: opacity .1s;
  max-width: 250px;
}
.tip.on { opacity: 1; }
.tip b { font-weight: 620; }
.tip .m { color: var(--text-muted); }

/* ----------------------------------------------------------- trend chart */

.trend .gridline { stroke: var(--grid); stroke-width: 1; }
.trend .baseline { stroke: var(--axis); stroke-width: 1; }
.trend .zeroline { stroke: var(--axis); stroke-width: 1; }
.trend .linepath { fill: none; stroke: var(--series-1); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.trend .area { fill: var(--series-1); opacity: .10; }
.trend .pt { fill: var(--series-1); stroke: var(--surface-1); stroke-width: 2; }
.trend .tick { font-size: 10px; fill: var(--text-muted); font-variant-numeric: tabular-nums; }
.trend .endlab { font-size: 11px; font-weight: 620; fill: var(--text-primary); }
.trend .hit { fill: transparent; cursor: pointer; }
.trend .col { fill: var(--series-1); }
.trend .col.neg { fill: var(--series-8); }

/* -------------------------------------------------------------- impact */

/* Season table and history chart read as one unit: the table is the exact
   numbers, the chart is their shape. Table first so it keeps its natural
   width and the chart takes the slack. */
/* Three panels: the season table trimmed to its headline numbers, the history
   line, and the on/off arrows for whichever season is selected. */
.impactsplit {
  display: grid;
  grid-template-columns: minmax(200px, 0.5fr) minmax(0, 1.15fr) minmax(210px, 0.62fr);
  gap: 20px;
  align-items: start;
}
.impactchart .charttitle, .impactonoff .charttitle {
  margin: 0 0 8px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
  text-align: center;
}
.impactchart .chartscroll > svg { min-width: 420px; }

/* ---- compact season table ---- */

/* Five columns beside two charts: the padding is what gives, not the type. */
table.stat.compactseasons th { padding-left: 9px; }
table.stat.compactseasons td { padding: 5px 0 5px 9px; }
table.stat.compactseasons tbody tr { cursor: pointer; }
table.stat.compactseasons tbody tr:hover td { background: var(--surface-2); }
/* The selected row drives the arrow panel, so it is marked on the season cell
   rather than tinted across the width — the heat cells already carry colour. */
table.stat.compactseasons tbody tr.sel td.key {
  box-shadow: inset 2px 0 0 var(--series-1);
  color: var(--text-primary);
  font-weight: 650;
}

/* ---- on/off arrows ---- */

.impactonoff .onoffsub {
  margin-top: 6px;
  font-size: 11px;
  color: var(--text-muted);
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.impactonoff .onoffaxis {
  margin: 0 0 2px;
  font-size: 10px;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--text-muted);
  text-align: center;
}
/* Capped: stretched past its natural width the arrows scale up with it and the
   type balloons, so it centres in a wider column instead. */
.onoffarrows { display: block; width: 100%; max-width: 360px; height: auto; margin: 0 auto; overflow: visible; }
/* League average, the anchor the whole panel is read against. */
.onoffzero { stroke: var(--text-muted); stroke-width: 1.5; }
.onoffwedge.good { fill: var(--pos); }
.onoffwedge.bad { fill: var(--neg); }
/* Hollow, so the on-court end reads as a marker on the axis rather than as
   more of the wedge's mass. */
.onoffend { fill: var(--surface-1); stroke-width: 2.5; }
.onoffend.good { stroke: var(--pos); }
.onoffend.bad { stroke: var(--neg); }
.onofflab {
  fill: var(--text-secondary);
  font-size: 11px; font-weight: 600;
}
.onoffto {
  font-size: 12px; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.onoffto.good { fill: var(--pos); }
.onoffto.bad { fill: var(--neg); }
.legend .sw.onoffgood { background: var(--pos); }
.legend .sw.onoffbad { background: var(--neg); }

/* Diverging heat behind the value cells. The background carries magnitude;
   the ink stays a text token so the number is legible at every step. */
table.stat.heatable td.heat {
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  /* 2px surface gap, so adjacent cells read as separate marks. */
  box-shadow: inset 0 0 0 2px var(--surface-1);
}
table.stat.heatable td.heat.lead { font-weight: 640; }
table.stat.heatable td.best {
  color: var(--text-primary);
  font-weight: 640;
  background: var(--surface-3);
  border-radius: 5px;
}

/* Three series on one points-per-100 axis: two validated categorical hues for
   the components, ink for the total they sum to. */
.trend.rapmchart .rapmline {
  fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round;
}
.trend.rapmchart .rapmline.off { stroke: var(--series-2); }
.trend.rapmchart .rapmline.def { stroke: var(--series-1); }
.trend.rapmchart .rapmline.net { stroke: var(--text-primary); stroke-width: 2.5; }
.trend.rapmchart .rapmdot { stroke: var(--surface-1); stroke-width: 2; }
.trend.rapmchart .rapmdot.off { fill: var(--series-2); }
.trend.rapmchart .rapmdot.def { fill: var(--series-1); }
.trend.rapmchart .rapmdot.net { fill: var(--text-primary); }
.trend.rapmchart .endlab.off { fill: var(--series-2); }
.trend.rapmchart .endlab.def { fill: var(--series-1); }
.trend.rapmchart .endlab.net { fill: var(--text-primary); }
.legend .sw.off { background: var(--series-2); }
.legend .sw.def { background: var(--series-1); }
.legend .sw.net { background: var(--text-primary); }

/* One column per RAPM window (1/2/3/5-year plus career), so the row stays
   even however many windows the player actually has. */
.windows { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 10px; }
.window {
  padding: 13px 14px;
  background: var(--surface-3);
  border-radius: 11px;
}
.window .wl {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--text-muted); font-weight: 600;
}
.window .wv { font-size: 23px; font-weight: 660; letter-spacing: -0.02em; margin-top: 2px; line-height: 1.15; }
.window .ws { font-size: 11px; color: var(--text-muted); margin-top: 1px; }
.window .wp { margin-top: 9px; }

.minibar { height: 5px; border-radius: 3px; background: var(--mid); overflow: hidden; position: relative; }
.minibar i { position: absolute; top: 0; bottom: 0; border-radius: 3px; }

.note {
  margin-top: 16px; padding-top: 13px;
  border-top: 1px solid var(--grid);
  font-size: 11.5px; color: var(--text-muted);
}
.note b { color: var(--text-secondary); font-weight: 550; }

.nodata {
  padding: 28px 4px;
  text-align: center;
  color: var(--text-muted);
  font-size: 13px;
}

/* --------------------------------------------------------------- diet */

.dietrow {
  display: grid;
  grid-template-columns: 132px 1fr 58px 52px;
  align-items: center;
  gap: 12px;
  padding: 4px 6px;
  border-radius: 7px;
}
.dietrow:hover { background: var(--surface-3); }
.dietrow .lab { font-size: 12px; color: var(--text-secondary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dietrow .num { font-size: 11.5px; text-align: right; font-variant-numeric: tabular-nums; color: var(--text-secondary); }
.dietrow .num.strong { color: var(--text-primary); font-weight: 560; }
.diettrack { position: relative; height: 16px; }
.dietfill {
  position: absolute; top: 2px; bottom: 2px; left: 0;
  background: var(--series-1);
  border-radius: 2px 4px 4px 2px;
}
.dietavg {
  position: absolute; top: 0; bottom: 0;
  width: 2px;
  background: var(--text-muted);
  border-radius: 1px;
}
.dietcmp {
  position: absolute; top: -1px; bottom: -1px;
  width: 3px;
  transform: translateX(-50%);
  background: var(--warn);
  border-radius: 2px;
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--surface-1) 70%, transparent);
}

/* ------------------------------------ shot source picker (leagues/seasons) */

.srcpick { position: relative; }
.srcbtn { display: inline-flex; align-items: center; gap: 6px; }
.srcbtn[aria-expanded="true"] {
  color: var(--text-primary);
  border-color: var(--axis);
}
.srccount {
  padding: 1px 5px;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  background: var(--surface-3);
  border-radius: 5px;
}

.srcpanel {
  position: absolute;
  z-index: 40;
  top: calc(100% + 6px);
  right: 0;
  width: 268px;
  max-height: 60vh;
  overflow-y: auto;
  padding: 12px;
  text-align: left;
  background: var(--surface-1);
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  box-shadow: var(--shadow);
}
.srchint {
  margin: 0 0 10px;
  font-size: 11px;
  line-height: 1.45;
  color: var(--text-muted);
}
.srchead {
  display: flex; align-items: center; gap: 8px;
  margin: 10px 0 4px;
}
.srchead:first-of-type { margin-top: 0; }
.srclg {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.srcall {
  margin-left: auto;
  padding: 1px 6px;
  font: inherit; font-size: 11px; font-weight: 600;
  color: var(--text-muted);
  background: none;
  border: 1px solid var(--border);
  border-radius: 5px;
  cursor: pointer;
}
.srcall:hover { color: var(--text-primary); border-color: var(--border-strong); }

.srcrow {
  display: flex; align-items: center; gap: 8px;
  padding: 5px 6px;
  font-size: 12px;
  border-radius: 6px;
  cursor: pointer;
}
.srcrow:hover { background: var(--surface-3); }
.srcrow input { margin: 0; accent-color: var(--series-1); cursor: pointer; }
.srcname { color: var(--text-secondary); }
.srcrow.on .srcname { color: var(--text-primary); font-weight: 600; }
.srcatt {
  margin-left: auto;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}

.srcreset {
  width: 100%;
  margin-top: 10px;
  padding: 6px;
  font: inherit; font-size: 11.5px; font-weight: 600;
  color: var(--text-secondary);
  background: var(--surface-3);
  border: none;
  border-radius: 7px;
  cursor: pointer;
}
.srcreset:hover { color: var(--text-primary); }

/* NBA twins, stacked above the shot-type table in the same column. */
.shotcol { display: grid; gap: 16px; align-content: start; }
.twincard {
  padding: 10px 12px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.twinhead {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 6px;
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--text-secondary);
}
.twinhead .m { font-weight: 500; letter-spacing: 0; color: var(--text-muted); }
.twin {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 3px 4px;
  border-radius: 7px;
}
.twin:hover { background: var(--surface-3); }
.twin .rank {
  width: 9px;
  font-size: 10px;
  font-weight: 700;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.twinface {
  display: grid;
  place-items: center;
  flex: none;
  width: 26px;
  height: 26px;
  overflow: hidden;
  background: var(--surface-3);
  border-radius: 50%;
}
.twinface img { width: 100%; height: 100%; object-fit: cover; }
.twinface .ph { font-size: 9px; font-weight: 700; color: var(--text-muted); }
.twinwho { display: flex; align-items: baseline; gap: 6px; min-width: 0; }
.twinwho b {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.twinwho .m {
  font-size: 10.5px;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.twintags { margin-left: auto; display: flex; gap: 7px; flex: none; }
/* Unfilled. Three players each carrying three filled pills made the block the
   loudest thing in the column, ahead of the shot chart it is a footnote to.
   The number still carries the colour, so strength is legible without chrome. */
.twintag {
  display: inline-flex;
  align-items: baseline;
  gap: 3px;
  padding: 0;
  border-radius: 4px;
  color: var(--text-muted);
  background: none;
}
.twintag i {
  font-style: normal;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.twintag b {
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text-secondary);
}
.twintag.strong { color: color-mix(in srgb, var(--series-1) 80%, var(--text-muted)); }
.twintag.strong b { color: var(--series-1); }
.twintag.weak b { color: var(--neg); }
.twinfoot {
  margin-top: 6px;
  font-size: 10.5px;
  color: var(--text-muted);
}
.twinfoot.good { color: var(--series-1); }
.twinthin {
  padding: 4px 2px 2px;
  font-size: 12px;
  color: var(--text-secondary);
}
/* Too thin a sample to name anybody is a one-line caption, not a card. Drops
   the border and fill so it sits under the shot-type table as a note rather
   than competing with it as a panel. */
/* Horizontal padding matches .card so the eyebrow starts on the same left edge
   as the titles beside it, and the top padding lands its first line on their
   baseline even though it has no border of its own. */
.twincard.quiet {
  padding: 18px 20px 0;
  background: none;
  border: 0;
}
.twincard.quiet .twinhead { margin-bottom: 3px; }
.twincard.quiet .twinthin { padding: 0; font-size: 11.5px; color: var(--text-muted); }

/* Season picker on the shot-type card: the diet reaches back further than the
   shot map, so it chooses its own span. */
/* Sized to its text rather than stretched: it is one control in a column of
   380px, and at full width it read as the card's main input instead of the
   season qualifier it is. Matches the shrunk segmented buttons beside it. */
.dietpick {
  max-width: 100%;
  padding: 3px 20px 3px 7px;
  font: inherit;
  font-size: 11px;
  color: var(--text-secondary);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 7px;
}
.dietpick:hover { color: var(--text-primary); border-color: var(--axis); }

/* Diet comparison, opened by clicking a twin. Split dimensions are named in
   full here -- it is the vector the match actually ran on. */
.twin { cursor: pointer; }
.twin.on { background: var(--surface-3); }
.twincmp {
  margin: 2px 0 8px;
  padding: 9px 8px 8px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.cmpkey {
  display: flex;
  gap: 14px;
  margin-bottom: 7px;
  font-size: 10.5px;
  color: var(--text-secondary);
}
.cmpwho { display: inline-flex; align-items: center; gap: 5px; min-width: 0; }
.cmpwho i {
  flex: none;
  width: 9px; height: 9px;
  border-radius: 2px;
  background: var(--series-1);
}
.cmpwho.them i { background: var(--warn); }
.cmprow {
  display: grid;
  grid-template-columns: 104px 1fr 40px 40px;
  align-items: center;
  gap: 7px;
  padding: 2px 3px;
  border-radius: 5px;
}
.cmprow:hover { background: var(--surface-3); }
.cmplab {
  font-size: 10.5px;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cmptrack {
  display: grid;
  gap: 2px;
  min-width: 0;
}
.cmpbar {
  height: 5px;
  min-width: 1px;
  border-radius: 2px;
  background: var(--series-1);
}
.cmpbar.them { background: var(--warn); }
.cmpnum {
  font-size: 10.5px;
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}
.cmpnum.them { color: var(--text-muted); }
.cmpfoot {
  margin-top: 7px;
  padding-top: 6px;
  border-top: 1px solid var(--grid);
  font-size: 10.5px;
  color: var(--text-muted);
}

.simsection { margin-top: 16px; }
.simtoggle {
  display: flex;
  align-items: baseline;
  gap: 10px;
  width: 100%;
  justify-content: center;
  padding: 11px 16px;
}
.simtoggle .m { color: var(--text-muted); font-size: 11.5px; }

.shotprofile { display: grid; gap: 10px; }
.zoneblock {
  padding-bottom: 9px;
  border-bottom: 1px solid var(--grid);
}
.zoneblock:last-child { padding-bottom: 0; border-bottom: 0; }
/* Reads as the section eyebrow it is, matching .ogtitle on the overview. It
   was a 19px centred headline, which made five zone names the loudest thing on
   the tab and broke the left edge every other card holds. */
.zonetitle {
  margin: 0 0 5px;
  color: var(--text-muted);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  text-align: left;
}
.shotmetric {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr) 56px 52px;
  align-items: center;
  gap: 8px;
  padding: 2px 0;
  border-radius: 7px;
}
.shotmetric:hover { background: var(--surface-3); }
/* These cells had no rule of their own -- .num was only ever scoped to
   .dietrow -- so the value and its delta sat unaligned with proportional
   figures, and no two zones lined up down the column. */
.shotmetric .num {
  font-size: 11.5px;
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--text-secondary);
}
.shotmetric .num.strong { color: var(--text-primary); font-weight: 560; }
.metriclab {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .07em;
}
.metriclab.vol { color: var(--series-1); }
.metriclab.eff { color: var(--good); }

/* Shot diet: one row per shot type, each number sitting over its gap to the
   league average for that type. */
.typetable td { padding: 6px 0 6px 14px; vertical-align: top; }
.typetable td.key { white-space: normal; line-height: 1.25; }
.typecell b {
  display: block;
  color: var(--text-primary);
  font-weight: 600;
  line-height: 1.25;
}
.typecell .delta {
  display: block;
  min-height: 13px;
  font-size: 11px;
  font-weight: 550;
  line-height: 1.2;
  color: var(--text-muted);
}
.typecell .delta.up { color: var(--pos); }
.typecell .delta.down { color: var(--neg); }
.typecell.dim,
.typetable tr.career td.dim { color: var(--text-muted); font-weight: 500; }

.simgrid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}
.simtile {
  position: relative;
  appearance: none;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-primary);
  border-radius: 8px;
  padding: 9px 12px;
  min-width: 0;
  cursor: pointer;
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
  text-align: left;
}
.simtile:hover,
.simtile.active {
  border-color: color-mix(in srgb, var(--warn) 70%, var(--border));
  background: color-mix(in srgb, var(--warn) 10%, var(--surface-1));
}
.simtile img,
.simtile .ph {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid var(--series-1);
  background: var(--surface-3);
}
.simtile .ph {
  display: grid;
  place-items: center;
  color: var(--text-secondary);
  font-weight: 750;
}
.simrank {
  position: absolute;
  top: 6px;
  left: 6px;
  color: var(--warn);
  font-size: 10.5px;
  font-weight: 800;
}
.simname {
  width: 100%;
  min-height: 0;
  color: var(--text-secondary);
  font-size: 12px;
  line-height: 1.25;
  text-align: left;
  overflow-wrap: anywhere;
}
.simscore {
  color: var(--text-primary);
  font-size: 13px;
  font-weight: 760;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.simactions {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--grid);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  color: var(--text-muted);
  font-size: 12px;
}

@media (max-width: 620px) {
  /* Give the bar track the space back -- fixed side columns squeeze it to
     nothing at phone widths. */
  .dietrow { grid-template-columns: 88px 1fr 44px 44px; gap: 8px; }
  .shotmetric { grid-template-columns: 38px 1fr 54px 48px; gap: 8px; }
  .pctrow { grid-template-columns: 92px 1fr 50px; gap: 8px; }
  .dietrow .lab, .pctrow .lab { font-size: 11.5px; }
  .simgrid { grid-template-columns: 1fr; gap: 7px; }
  .simtile {
    grid-template-columns: 48px minmax(0, 1fr);
    padding: 8px 7px;
  }
  .simscore { grid-column: 2; }
  .simtile img, .simtile .ph { width: 48px; height: 48px; }
}

/* ==========================================================================
   Team dashboard — game charts, rank strips, rotation, splits
   ========================================================================== */

.grid + .grid, .grid + .card, .card + .card, .card + .grid { margin-top: 16px; }
/* Team cards pair a short card with a tall one; top-aligning stops the short
   one from stretching into dead space. */
[role="tabpanel"] > .grid.two { align-items: start; }

/* ----------------------------------------------------- game-by-game charts */

.gamechart { overflow: visible; }
.chartscroll { overflow-x: auto; overflow-y: hidden; margin: 0 -20px; padding: 0 20px; }
.chartscroll > svg { min-width: 680px; }

/* Diverging bars: colour carries polarity only, so the two poles are the
   diverging pair and nothing else in the chart competes with them. */
.gamebar { fill: var(--pos); }
.gamebar.neg { fill: var(--neg); }

/* The rolling line is a summary of the bars, not a third category — it wears
   ink, not a series hue, and carries a surface halo so it stays legible
   crossing them. */
.rollline {
  fill: none;
  stroke: var(--text-primary);
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.rollhalo {
  fill: none;
  stroke: var(--surface-1);
  stroke-width: 5.5;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.rolldot { fill: var(--text-primary); stroke: var(--surface-1); stroke-width: 2; }

.linehalo {
  fill: none;
  stroke: var(--surface-1);
  stroke-width: 5.5;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.offline, .defline {
  fill: none;
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.offline { stroke: var(--series-1); }
.defline { stroke: var(--series-2); }
.offlinedot { fill: var(--series-1); stroke: var(--surface-1); stroke-width: 2; }
.deflinedot { fill: var(--series-2); stroke: var(--surface-1); stroke-width: 2; }
/* Labels stay in ink; the dot beside them carries the identity. */
.offlinelab, .deflinelab { fill: var(--text-primary); }

.avgline { stroke: var(--axis); stroke-width: 1; stroke-dasharray: 4 5; }
.isoline { stroke: var(--axis); stroke-width: 1; stroke-dasharray: 3 6; opacity: .5; }
.isoline.zero { opacity: .8; stroke-dasharray: 5 5; }

.histline {
  fill: none;
  stroke: var(--text-secondary);
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.histdot { fill: var(--pos); stroke: var(--surface-1); stroke-width: 2; }
.histdot.neg { fill: var(--neg); }
.histdot.on { stroke: var(--text-primary); stroke-width: 2.5; }

.legend .sw.line {
  width: 14px; height: 0;
  border-radius: 0;
  border-top: 2px solid var(--text-primary);
}
.legend .sw.dash {
  width: 14px; height: 0;
  border-radius: 0;
  border-top: 2px dashed var(--axis);
}
.legend .sw.teamsw { background: var(--team-color, var(--series-1)); }

/* ----------------------------------------------------- player trajectory */

.perftraj { overflow: visible; }
.trajband { fill: color-mix(in srgb, var(--lg) 9%, transparent); }
.trajband.alt { fill: color-mix(in srgb, var(--lg) 14%, transparent); }
.trajarea { pointer-events: none; }
.trajhalo {
  fill: none;
  stroke: var(--surface-1);
  stroke-width: 7;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.trajline {
  fill: none;
  stroke: var(--lg);
  stroke-width: 2.6;
  stroke-linejoin: round;
  stroke-linecap: round;
  filter: drop-shadow(0 1px 3px color-mix(in srgb, var(--lg) 45%, transparent));
}
.trajdot {
  fill: var(--lg);
  stroke: var(--surface-1);
  stroke-width: 2;
}
.trajglow {
  fill: none;
  stroke: var(--lg);
  stroke-width: 1.5;
  opacity: .3;
}
.trajendpill {
  fill: color-mix(in srgb, var(--lg) 16%, var(--surface-1));
  stroke: color-mix(in srgb, var(--lg) 55%, transparent);
  stroke-width: 1.1;
}
.trajendlab {
  fill: var(--lg);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
}
.perftraj .axis {
  stroke: var(--axis);
  stroke-width: 1;
  opacity: .7;
}
.perftraj .seasoncut {
  stroke: var(--axis);
  stroke-width: 1;
  stroke-dasharray: 3 7;
  opacity: .42;
}
.perftraj .seasonlab {
  fill: var(--text-secondary);
  font-size: 10.5px;
  font-weight: 700;
}
.perftraj .gametick {
  fill: var(--text-muted);
  font-size: 10.5px;
}
.perftraj .baselinelab {
  fill: var(--text-muted);
  font-size: 9px;
  font-weight: 650;
  letter-spacing: .06em;
}

/* --------------------------------------------------- trajectory momentum */

.trajctl { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.trajmomentum {
  display: inline-flex;
  align-items: baseline;
  gap: 3px;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  background: var(--surface-3);
  color: var(--text-secondary);
}
.trajmomentum .arrow { font-size: 9px; }
.trajmomentum .m { font-weight: 500; color: var(--text-muted); }
.trajmomentum.up { color: var(--pos); background: color-mix(in srgb, var(--pos) 14%, var(--surface-3)); }
.trajmomentum.down { color: var(--neg); background: color-mix(in srgb, var(--neg) 14%, var(--surface-3)); }

/* -------------------------------------------------------------- rank rows */

.pctrow.rankrow, .pctrow.diffrow {
  grid-template-columns: 132px 1fr 58px 40px;
}
.pctrow .rank {
  font-size: 11px;
  font-weight: 650;
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}
.pctrow .rank.good { color: var(--pos); }
.pctrow .rank.bad { color: var(--neg); }
.pctrow .rank.mid { color: var(--text-secondary); }

/* A pip per team, left to right. Position is the encoding; the highlighted
   pip's colour only restates whether that position is good or bad. */
.rankstrip { display: flex; gap: 3px; align-items: center; height: 15px; }
.rankstrip i {
  flex: 1;
  height: 9px;
  border-radius: 2px;
  background: var(--surface-3);
  border: 1px solid var(--grid);
}
.rankstrip i:first-child { border-radius: 4px 2px 2px 4px; }
.rankstrip i:last-child { border-radius: 2px 4px 4px 2px; }
.rankstrip i.on { height: 15px; border-color: transparent; }

/* ---------------------------------------------------------------- splits */

.splitgrid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
  margin-bottom: 16px;
}
.splitbox {
  padding: 12px 13px;
  background: var(--surface-3);
  border-radius: 11px;
}
.splitbox .l {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: .06em;
  font-weight: 650;
  color: var(--text-muted);
}
.splitbox .v {
  font-size: 21px;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.2;
  font-variant-numeric: tabular-nums;
}
.splitbox .n { font-size: 11.5px; font-weight: 620; font-variant-numeric: tabular-nums; color: var(--text-secondary); }
.splitbox .n.pos { color: var(--pos); }
.splitbox .n.neg { color: var(--neg); }
.splitbox .m { font-size: 11px; color: var(--text-muted); font-variant-numeric: tabular-nums; }

.kvrow {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 6px 6px;
  border-radius: 7px;
  font-size: 12.5px;
}
.kvrow:hover { background: var(--surface-3); }
.kvrow .lab { color: var(--text-secondary); }
.kvrow .val { font-weight: 560; font-variant-numeric: tabular-nums; }

/* -------------------------------------------------------------- rotation */

.rotation { display: flex; flex-direction: column; gap: 3px; }
.rotrow {
  display: grid;
  grid-template-columns: 138px 1fr 44px 44px;
  align-items: center;
  gap: 12px;
  padding: 3px 6px;
  border-radius: 7px;
}
.rotrow:hover { background: var(--surface-3); }
.rotrow .name {
  font-size: 12px;
  text-align: left;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Two thin bars, 2px of surface between them, each anchored to the same left
   baseline so their lengths are directly comparable down the column. */
.rottrack { display: flex; flex-direction: column; gap: 2px; }
.rotbar { height: 7px; border-radius: 2px 4px 4px 2px; min-width: 2px; }
.rotbar.min { background: var(--series-1); }
.rotbar.pts { background: var(--series-2); }
.rotval {
  font-size: 12px;
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-weight: 560;
}
.rotval.alt { color: var(--series-2); }

/* ---------------------------------------------------------- team tables */

.linkish {
  padding: 0;
  font: inherit;
  font-weight: inherit;
  color: var(--series-1);
  background: none;
  border: none;
  cursor: pointer;
  text-align: left;
}
.linkish:hover { text-decoration: underline; }

table.stat td.teamcell { display: flex; align-items: center; gap: 8px; text-align: left; }

/* ----------------------------------------------------------------- league */

.leaguehero { --team-color: var(--series-1); }

table.stat td.playercell { display: flex; align-items: center; gap: 9px; text-align: left; }
.facemini {
  width: 26px; height: 26px;
  border-radius: 50%;
  object-fit: cover;
  object-position: top center;
  background: var(--surface-3);
  border: 1px solid var(--border);
  flex-shrink: 0;
}
.facemini.ph {
  display: grid; place-items: center;
  font-size: 9px; font-weight: 650;
  color: var(--text-muted);
}
.morebtn { margin-top: 12px; }

/* In-table filter, sitting between the card head and the board itself. */
.rapmtools { display: flex; align-items: center; gap: 10px; margin: 0 0 10px; }
.rapmsearch {
  width: 210px; max-width: 100%;
  padding: 6px 12px;
  font: inherit; font-size: 12px;
  border-radius: 99px;
  border: 1px solid var(--border-strong);
  background: var(--surface-1);
  color: var(--text-primary);
}
.rapmsearch:focus { outline: none; border-color: var(--series-1); }
.rapmsearch::placeholder { color: var(--text-muted); }
.rapmcount {
  font-size: 11px; font-weight: 650;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* Rank, player and team read as labels, not numbers, so they sit left while
   the metric columns stay right-aligned for digit comparison. */
table.rapmboard th:nth-child(2),
table.rapmboard th:nth-child(3),
table.rapmboard td:nth-child(3) { text-align: left; }
table.rapmboard td:nth-child(3) { max-width: 260px; }
table.rapmboard td .mainv { line-height: 1.15; }
table.rapmboard td .rapmdelta {
  margin-top: 2px;
  font-size: 10.5px;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  opacity: .78;
}

table.stat td.pos { color: var(--pos); font-weight: 560; }
table.stat td.neg { color: var(--neg); font-weight: 560; }

.res {
  display: inline-grid;
  place-items: center;
  width: 16px; height: 16px;
  border-radius: 4px;
  font-size: 10px;
  font-weight: 750;
  color: #fff;
  vertical-align: -3px;
  margin-right: 4px;
}
.res.w { background: var(--pos); }
.res.l { background: var(--neg); }

table.sortable th.sortcol { cursor: pointer; user-select: none; }
table.sortable th.sortcol:hover { color: var(--text-secondary); }
table.sortable th.sortcol.on { color: var(--text-primary); }
table.sortable th .arrow { font-size: 9px; }
table.stat tbody tr.on td {
  background: color-mix(in srgb, var(--series-1) 8%, transparent);
}
table.stat tbody tr.on td:first-child { box-shadow: inset 2px 0 0 var(--series-1); }

@media (max-width: 1280px) {
  main.wide { max-width: 1180px; }
  /* Too narrow for three: the court holds the left column over both rows and
     the two profile cards stack down the right. */
  .grid.shot { grid-template-columns: minmax(0, 420px) minmax(0, 1fr); }
  .grid.shot > :first-child { grid-row: span 2; }
  .simgrid { grid-template-columns: 1fr; }
  .teamdash { grid-template-columns: 1fr; }
  /* Not enough room for three side by side: the season table keeps the left
     column over both rows, the history line and the arrows stack at its right. */
  .impactsplit { grid-template-columns: minmax(190px, 0.5fr) minmax(0, 1fr); }
  .impactsplit > .tablewrap { grid-row: span 2; }
}

@media (max-width: 900px) {
  .grid.two, .grid.shot { grid-template-columns: 1fr; }
  .grid.shot > :first-child { grid-row: auto; }
  .pctrows.compact .pctrow { grid-template-columns: 132px 1fr 52px; }
  .impactsplit { grid-template-columns: 1fr; }
  main.wide { max-width: 1180px; }
  .teamkpis { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .pctrow.rankrow, .pctrow.diffrow { grid-template-columns: 100px 1fr 52px 34px; gap: 8px; }
  .rotrow { grid-template-columns: 104px 1fr 40px 40px; gap: 8px; }
  .teamcontrols { margin-left: 0; width: 100%; }
  .teamcontrols select { flex: 1; min-width: 160px; }
  .windows { grid-template-columns: repeat(2, 1fr); }
  /* Below this width the single line stops fitting, so it stacks instead. */
  .hero { flex-wrap: wrap; }
  .herostats { margin-left: 0; width: 100%; gap: 20px; }
  .teamhistory { margin-left: 0; max-width: 100%; width: 100%; margin-top: 4px; }
  .hero h1, .teamhero h1 { font-size: 27px; }
  main { padding: 16px; }
  .topbar { padding: 10px 14px; gap: 10px; }
  .brand span { display: none; }
  .brand-logo { width: 26px; height: 26px; }
}

@media (max-width: 620px) {
  .teamkpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .teamkpi .v { font-size: 20px; }
  .teamlogo.large { width: 64px; height: 64px; font-size: 15px; }
  .splitgrid { grid-template-columns: 1fr; }
  .teamhero { padding: 14px; }
}

/* ==========================================================================
   League conversion
   The matrix is the only place in the hub that paints a continuous scale onto
   a table, so it carries its own ramp helpers. Both ramps are built from the
   validated tokens above -- sequential mixes one hue toward the recessed
   surface, diverging interpolates between the declared --div-* stops.
   ========================================================================== */

.convbar {
  display: flex; flex-wrap: wrap; gap: 10px;
  margin-bottom: 10px;
}
.convprofileactions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 8px;
  align-items: center;
}
.convrule {
  margin: 0 0 16px;
  max-width: 78ch;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--text-secondary);
}
.convrule b { color: var(--text-primary); font-weight: 620; }

/* ---- league profile baseline ---- */

.leagueprofilewrap { max-width: 1180px; margin: 0 auto; }
table.leagueprofile { min-width: 1420px; table-layout: fixed; }
table.leagueprofile th:first-child, table.leagueprofile td:first-child { width: 150px; }
table.leagueprofile th.grouphead {
  text-align: center;
  color: var(--text-secondary);
  text-transform: capitalize;
  border-bottom: 1px solid var(--border);
}
table.leagueprofile tbody tr.baseline td { background: var(--surface-3); }
table.leagueprofile td.key div { font-weight: 640; }
table.leagueprofile td.key span { display: block; margin-top: 2px; }
/* Fewer seasons than the NBL pool this row is measured against. */
table.leagueprofile td.key span.partialwindow {
  border-bottom: 1px dotted var(--border-strong);
  display: inline-block;
  cursor: help;
}
td.leagueprofilecell {
  text-align: right;
  border-left: 3px solid var(--surface-1);
  border-bottom: 3px solid var(--surface-1);
  border-radius: 5px;
  font-variant-numeric: tabular-nums;
}
td.leagueprofilecell b {
  display: block;
  font-size: 13px;
  line-height: 1.15;
}
td.leagueprofilecell span {
  display: block;
  margin-top: 2px;
  font-size: 10.5px;
  color: var(--text-secondary);
}
td.leagueprofilecell.deep,
td.leagueprofilecell.deep span { color: #fff; }

/* ---- headline tiles ---- */

.convtiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }

.convtile {
  display: flex; flex-direction: column; gap: 6px;
  text-align: left;
  padding: 14px;
  border: 1px solid var(--border);
  border-radius: 11px;
  background: var(--surface-3);
  font: inherit; color: inherit;
  cursor: pointer;
  transition: border-color .12s, box-shadow .12s;
}
.convtile:hover { border-color: var(--axis); }
.convtile.on {
  border-color: var(--series-1);
  box-shadow: inset 0 0 0 1px var(--series-1);
}
.convtile .l { font-size: 15px; font-weight: 640; }
.convtile .sub { font-size: 11.5px; color: var(--text-muted); }
.convtile .nodata { padding: 12px 0 4px; }

.convtilestats { display: flex; gap: 18px; margin-top: 6px; }
.convtilestat .v {
  font-size: 21px; font-weight: 660; line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.convtilestat .k { font-size: 11px; color: var(--text-secondary); }
.convtilestat .h { font-size: 10.5px; color: var(--text-muted); }

/* ---- the matrix ---- */

/* Capped so the chips stay chip-sized on a full-width card -- stretched to
   1180px each cell becomes a banner and the grid stops reading as a matrix. */
.convmatrixwrap { max-width: 900px; margin: 0 auto; }
/* Below this the metric names collide with the chips, so the wrap scrolls
   sideways instead of letting the first column crush. */
table.convmatrix { table-layout: fixed; min-width: 480px; }
table.convmatrix th:first-child, table.convmatrix td:first-child { width: 27%; }
table.convmatrix th.num { text-align: center; vertical-align: bottom; }
.convn {
  font-size: 10px; font-weight: 400;
  color: var(--text-muted);
  text-transform: none; letter-spacing: 0;
}
table.convmatrix td.convcell { padding: 3px 4px; text-align: center; cursor: pointer; }
table.convmatrix tbody tr:hover td { background: transparent; }

table.convmatrix tr.convgroup th {
  padding: 14px 0 5px;
  text-align: left;
  font-size: 10.5px; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase;
  color: var(--text-muted);
  border-bottom: 1px solid var(--grid);
}

td.convmetriclab { white-space: nowrap; font-weight: 500; }
td.convmetriclab.on { font-weight: 700; box-shadow: inset 2px 0 0 var(--series-1); }
.convpolarity { color: var(--text-muted); font-weight: 400; }

/* 2px of surface between adjacent fills, so two strong cells never bleed into
   one another and read as a single block. */
.convchip {
  display: block;
  margin: 2px;
  padding: 5px 4px;
  border-radius: 6px;
  font-size: 12px; font-weight: 580;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}
.convchip.deep { color: #fff; }
.convchip.empty { background: var(--surface-3); color: var(--text-muted); font-weight: 400; }
/* Withheld because the leagues' rulebooks differ, not because the sample was
   too thin — a different thing, so it reads differently. */
.convchip.empty.suppressed {
  background: transparent;
  border: 1px dashed var(--border-strong);
  cursor: help;
}
/* A thin fit still has to be readable, so it recedes only slightly and says
   why in the tooltip. */
.convchip.thin { opacity: .7; }
td.convcell.on .convchip { box-shadow: 0 0 0 2px var(--surface-1), 0 0 0 3.5px var(--text-primary); }
td.convcell:focus-visible { outline: none; }
td.convcell:focus-visible .convchip { box-shadow: 0 0 0 2px var(--surface-1), 0 0 0 3.5px var(--series-1); }

.convlegend { align-items: center; }
.convramp { display: flex; gap: 0; border-radius: 4px; overflow: hidden; }
.convramp i { width: 16px; height: 10px; }

/* ---- shared chart furniture ---- */

.convscatter .gridline, .convquad .gridline, .convgaps .gridline {
  stroke: var(--grid); stroke-width: 1;
}
.convscatter .zeroline, .convquad .zeroline, .convgaps .zeroline {
  stroke: var(--axis); stroke-width: 1;
}
.convscatter .tick, .convquad .tick, .convgaps .tick {
  font-size: 10px; fill: var(--text-muted); font-variant-numeric: tabular-nums;
}
.convgaps .hit { fill: transparent; cursor: pointer; }

/* ---- scatter ---- */

.convscatter, .convquad { display: block; width: 100%; max-width: 700px; margin: 0 auto; }
.convidentity { stroke: var(--axis); stroke-width: 2; stroke-dasharray: 5 6; }
.convfit { stroke: var(--series-2); stroke-width: 2; }
.convdot { cursor: default; outline: none; }
/* A 2px surface ring keeps overlapping dots countable in a dense cluster. */
.convdotmark {
  fill: color-mix(in srgb, var(--series-1) 74%, transparent);
  stroke: var(--surface-1); stroke-width: 2;
}
.convdot:hover .convdotmark, .convdot:focus-visible .convdotmark {
  fill: var(--series-1); stroke: var(--text-primary);
}
.legend .sw.fitline { width: 14px; height: 0; border-radius: 0; border-top: 2px solid var(--series-2); }

.convreadout { display: flex; flex-wrap: wrap; gap: 22px; margin-bottom: 6px; }
.convstat .v { font-size: 19px; font-weight: 650; font-variant-numeric: tabular-nums; line-height: 1.15; }
.convstat .k { font-size: 11px; color: var(--text-muted); }

/* ---- quadrant ---- */

.convqdot { cursor: pointer; outline: none; }
.convqmark { fill: var(--series-1); stroke: var(--surface-1); stroke-width: 2; }
.convqdot.on .convqmark { fill: var(--series-2); stroke: var(--text-primary); stroke-width: 2.5; }
.convqdot:hover .convqmark { stroke: var(--text-primary); }
.convqleader { stroke: var(--axis); stroke-width: 1; opacity: .55; }
.convqlabel { font-size: 10.5px; fill: var(--text-secondary); font-weight: 560; }
.convqlabel.on { fill: var(--text-primary); font-weight: 700; }

/* ---- gap bars ---- */

/* Capped like the other plots: 24 rows of viewBox scaled to a 1180px card
   would blow the type up to headline size. */
.convgaps { display: block; width: 100%; max-width: 760px; margin: 0 auto; }
.convgaprow { cursor: pointer; outline: none; }
.convgaprow:hover .convgapbar { opacity: .82; }
.convgaplabel { font-size: 11.5px; fill: var(--text-secondary); }
.convgaplabel.on { fill: var(--text-primary); font-weight: 700; }
.convgapval { font-size: 11px; fill: var(--text-muted); font-variant-numeric: tabular-nums; }
/* Inside a saturated bar the muted ink disappears, so it switches to white. */
.convgapval.inbar { fill: #fff; font-weight: 600; }
.convgapbar.pos { fill: var(--pos); }
.convgapbar.neg { fill: var(--neg); }
.convgaprow:focus-visible .convgapbar { stroke: var(--text-primary); stroke-width: 2; }

/* ---- movers table ---- */

table.convmovers th.num, table.convmovers td.num { text-align: right; }
table.convmovers th.yr, table.convmovers td.yr { text-align: left; font-variant-numeric: tabular-nums; }
.convbarcell {
  display: grid;
  grid-template-columns: 1fr 46px;
  align-items: center;
  gap: 8px;
  min-width: 118px;
  font-variant-numeric: tabular-nums;
}
.convbarcell .track { position: relative; height: 14px; }
/* The zero line is the middle of the track, so the bars read as a
   distribution rather than as a set of unrelated lengths. */
.convbarcell .track::before {
  content: ''; position: absolute; left: 50%; top: 0; bottom: 0;
  border-left: 1px solid var(--grid);
}
.convbarcell i {
  position: absolute; top: 2px; bottom: 2px;
  border-radius: 2px;
  opacity: .5;
}
.convbarcell i.pos { background: var(--pos); }
.convbarcell i.neg { background: var(--neg); }
.convbarcell span { text-align: right; font-weight: 560; }
.convbarcell span.pos { color: var(--pos); }
.convbarcell span.neg { color: var(--neg); }

@media (max-width: 900px) {
  .convtiles { grid-template-columns: 1fr; }
  .convtilestats { gap: 14px; }
  .chartscroll > svg.convscatter, .chartscroll > svg.convquad { min-width: 480px; }
  .chartscroll > svg.convgaps { min-width: 420px; }
  .eventmaps { grid-template-columns: 1fr; }
  .eventmaps .card:first-child { grid-column: auto; }
  .eventtiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* =================================================================== *
   Player showcase
   The filter rail is the page's main control surface, so it gets the
   recessed plane and the results get the card plane -- the eye can tell
   what it is steering from what it is reading.
   =================================================================== */

/* The find card leads with the search band, so it carries a little more
   presence than the cards below it. */
.showfindcard { position: relative; overflow: hidden; }
.showfindcard::before {
  content: '';
  position: absolute; left: 0; right: 0; top: 0; height: 2px;
  background: linear-gradient(90deg,
    var(--series-1), var(--series-2), var(--series-3), var(--series-4));
  opacity: .55;
}

/* ---- search band ---- */

.showsearchband { margin: 14px 0 12px; }
.showsearchwrap {
  position: relative;
  display: flex; align-items: center; gap: 10px;
  padding: 0 14px 0 40px;
  border-radius: 12px;
  background: var(--surface-3);
  border: 1px solid var(--border-strong);
  transition: border-color .12s ease, box-shadow .12s ease;
}
.showsearchwrap:focus-within {
  border-color: var(--series-1);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--series-1) 16%, transparent);
}
.showsearchwrap .ico {
  position: absolute; left: 14px; top: 50%; transform: translateY(-50%);
  display: flex; color: var(--text-muted);
}
.showsearchwrap:focus-within .ico { color: var(--series-1); }
.showsearch {
  flex: 1; min-width: 0;
  padding: 12px 0;
  font: inherit; font-size: 15px;
  color: var(--text-primary);
  background: none;
  border: 0;
}
.showsearch:focus { outline: none; }
.showsearch::-webkit-search-cancel-button { cursor: pointer; }
.showsearchwrap .hits {
  flex-shrink: 0;
  font-size: 11.5px; font-weight: 600; letter-spacing: .02em;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ---- active filter chips ----
   Every cut currently narrowing the pool, in one line, each one removable.
   The panel below is long, and a filter set two scrolls ago is otherwise
   invisible until you wonder why forty players came back. */

.activechips {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--border);
}
.nochips { font-size: 12.5px; color: var(--text-muted); }
.activechip {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 9px 5px 11px;
  font: inherit; font-size: 12px; font-weight: 550;
  border-radius: 8px;
  border: 1px solid color-mix(in srgb, var(--series-1) 40%, transparent);
  background: color-mix(in srgb, var(--series-1) 11%, transparent);
  color: var(--text-primary);
  cursor: pointer;
}
/* A percentile cut is a different kind of claim from a raw one, so it is a
   different colour -- you can see at a glance which of your filters travel
   between leagues and which do not. */
.activechip.pct {
  border-color: color-mix(in srgb, var(--series-4) 45%, transparent);
  background: color-mix(in srgb, var(--series-4) 13%, transparent);
}
.activechip .x { color: var(--text-muted); font-size: 10px; line-height: 1; }
.activechip:hover .x { color: var(--neg); }
.activechip:hover { border-color: var(--axis); }
.activechip.clearall {
  border-style: dashed;
  border-color: var(--border-strong);
  background: none;
  color: var(--text-muted);
}
.activechip.clearall:hover { color: var(--text-primary); }

/* ---- filter grid ---- */

.showfilters {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 16px 22px;
  margin-top: 16px;
}
.showfield.wide { grid-column: 1 / -1; }
.showfield > label {
  display: block;
  font-size: 11px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 6px;
}
.showfield .val {
  font-size: 15px; font-weight: 650;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  margin-bottom: 2px;
}
.showfield .fieldnote {
  margin-top: 6px;
  font-size: 11.5px; line-height: 1.4;
  color: var(--text-muted);
}

/* Label + segmented control sitting above a table (e.g. the rim deterrence
   tab's single-season / 3-year sample switch). */
.sampleseg {
  display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
  margin: 0 0 12px;
}
.sampleseg > label {
  font-size: 11px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-muted);
}

.chiprow { display: flex; flex-wrap: wrap; gap: 7px; }
.lgchip {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 13px 6px 10px;
  font: inherit; font-size: 12.5px; font-weight: 550;
  border-radius: 99px;
  border: 1px solid var(--border-strong);
  background: var(--surface-1);
  color: var(--text-muted);
  cursor: pointer;
}
.lgchip .sw { width: 10px; height: 10px; border-radius: 3px; opacity: .35; }
.lgchip.on { color: var(--text-primary); border-color: var(--axis); }
.lgchip.on .sw { opacity: 1; }
.lgchip:hover { border-color: var(--axis); }

/* ---- two-thumb range ---- */

.dualrange { position: relative; height: 26px; }
.dualrange .track {
  position: absolute; left: 0; right: 0; top: 11px; height: 4px;
  border-radius: 99px; background: var(--surface-3);
  border: 1px solid var(--border);
}
.dualrange .fill {
  position: absolute; top: -1px; height: 4px;
  border-radius: 99px; background: var(--series-1);
}
/* A percentile range is a different scale from a raw one -- 0-100, fixed, the
   same on every metric -- so it wears a different hue than the value ranges. */
.mfrow.pct .dualrange .fill { background: var(--series-4); }
.mfrow.pct .dualrange input[type="range"]::-webkit-slider-thumb { border-color: var(--series-4); }
.mfrow.pct .dualrange input[type="range"]::-moz-range-thumb { border-color: var(--series-4); }
.dualrange input[type="range"] {
  position: absolute; left: 0; top: 0; width: 100%; height: 26px;
  margin: 0; padding: 0;
  -webkit-appearance: none; appearance: none;
  background: none;
  /* The tracks stack, so only the thumbs may take the pointer -- otherwise
     the upper input swallows every click meant for the lower one. */
  pointer-events: none;
}
.dualrange input[type="range"]:focus { outline: none; }
.dualrange input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  pointer-events: auto;
  width: 15px; height: 15px; border-radius: 50%;
  background: var(--surface-1);
  border: 2px solid var(--series-1);
  box-shadow: var(--shadow);
  cursor: grab;
}
.dualrange input[type="range"]::-moz-range-thumb {
  pointer-events: auto;
  width: 15px; height: 15px; border-radius: 50%;
  background: var(--surface-1);
  border: 2px solid var(--series-1);
  cursor: grab;
}
.dualrange input[type="range"]:focus-visible::-webkit-slider-thumb { border-color: var(--text-primary); }
.dualrange input[type="range"]:focus-visible::-moz-range-thumb { border-color: var(--text-primary); }

/* ---- stat filters ---- */

.metricfilters {
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}
.mfhead { display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap; }
.mftitle {
  font-size: 11px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-muted);
}
.mfadd {
  font: inherit; font-size: 12.5px;
  padding: 6px 10px;
  border-radius: 9px;
  border: 1px solid var(--border-strong);
  background: var(--surface-1);
  color: var(--text-secondary);
  cursor: pointer;
}
.mfempty { margin-top: 10px; font-size: 13px; line-height: 1.55; color: var(--text-muted); max-width: 74ch; }
.mfnote { margin-top: 12px; font-size: 11.5px; color: var(--text-muted); }
.mfrow {
  display: grid;
  grid-template-columns: minmax(140px, 200px) auto 1fr 26px;
  align-items: center;
  gap: 12px;
  margin-top: 8px;
  padding: 7px 10px 7px 12px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--surface-1);
}
/* The percentile filters are the ones that mean the same thing in every
   league, so they are marked as a class of their own down the edge. */
.mfrow.pct { border-left: 3px solid var(--series-4); }
.mflabel { display: flex; flex-direction: column; gap: 1px; cursor: help; min-width: 0; }
.mflabel b { font-size: 13px; font-weight: 600; }
.mflabel .v { font-size: 11.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.mfdel {
  width: 26px; height: 26px;
  font: inherit; font-size: 12px; line-height: 1;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--surface-1);
  color: var(--text-muted);
  cursor: pointer;
}
.mfdel:hover { color: var(--neg); border-color: var(--neg); }

/* A compact two- or three-way switch, small enough to sit inside a filter
   row without becoming the row's main event. */
.seg.modeseg button, .seg.poolseg button { font-size: 11.5px; padding: 5px 10px; }
.seg.modeseg { flex-shrink: 0; margin-top: 8px; }
.mfrow .seg.modeseg { margin-top: 0; }
.seg.poolseg { width: 100%; }
.seg.poolseg button { flex: 1; }

/* ---- summary ---- */

.showsummary {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px;
  margin: 16px 0;
}
.showtile {
  position: relative;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px 16px;
  box-shadow: var(--shadow);
  overflow: hidden;
}
.showtile::before {
  content: '';
  position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: var(--series-1); opacity: .5;
}
.showtile .l {
  font-size: 11px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-muted);
}
.showtile .v {
  display: flex; align-items: baseline; gap: 8px;
  font-size: 25px; font-weight: 680; letter-spacing: -.02em;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  margin: 3px 0 1px;
}
.showtile .s { font-size: 12px; color: var(--text-secondary); }
.showtile .pcttag {
  font-size: 11px; font-weight: 650; letter-spacing: 0;
  color: var(--text-muted);
}

/* ---- rank + card stat controls ---- */

.sortrow { display: flex; gap: 8px; align-items: center; }
.sortrow .mfadd { flex: 1; min-width: 0; }
.dirbtn {
  width: 34px; height: 34px; flex-shrink: 0;
  font: inherit; font-size: 14px; line-height: 1;
  border-radius: 9px;
  border: 1px solid var(--border-strong);
  background: var(--surface-1);
  color: var(--text-secondary);
  cursor: pointer;
}
.dirbtn:hover { color: var(--text-primary); border-color: var(--axis); }

.mfcount { font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.statchips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.statchip {
  padding: 5px 11px;
  font: inherit; font-size: 12px;
  border-radius: 99px;
  border: 1px solid var(--border);
  background: var(--surface-1);
  color: var(--text-muted);
  cursor: pointer;
}
.statchip:hover { border-color: var(--axis); color: var(--text-primary); }
.statchip.on {
  color: var(--text-primary);
  border-color: color-mix(in srgb, var(--series-1) 55%, transparent);
  background: color-mix(in srgb, var(--series-1) 12%, transparent);
}
/* A stat you are filtering on is on the card whether you like it or not, so
   it reads as fixed rather than as something to click. */
.statchip.pinned { cursor: default; border-style: dashed; }

/* ---- results header switches ---- */

.showviewctl { display: flex; flex-wrap: wrap; gap: 16px; align-items: center; }
.ctlgroup { display: flex; align-items: center; gap: 8px; }
.ctllab {
  font-size: 10.5px; font-weight: 600; letter-spacing: .05em; text-transform: uppercase;
  color: var(--text-muted);
}

/* ---- player cards ---- */

.showcards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 12px;
  margin-top: 4px;
}
.showcard {
  position: relative;
  display: block;
  width: 100%;
  text-align: left;
  font: inherit;
  padding: 0 0 11px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  /* The banner is full-bleed, so the corners have to clip it. */
  overflow: hidden;
  background: var(--surface-1);
  color: var(--text-primary);
  cursor: pointer;
  transition: transform .13s ease, box-shadow .13s ease, border-color .13s ease;
}
.showcard:hover {
  border-color: color-mix(in srgb, var(--lg) 60%, var(--border));
  transform: translateY(-2px);
  box-shadow: 0 8px 22px -10px rgba(0, 0, 0, .45);
}
.showcard:focus-visible { outline: 2px solid var(--series-1); outline-offset: 2px; }
.showcard.picked { outline: 2px solid var(--series-1); outline-offset: -2px; }
@media (prefers-reduced-motion: reduce) {
  .showcard { transition: none; }
  .showcard:hover { transform: none; }
}

/* ---- card banner ----
   The league's hue arrives as a wash across the top rather than a hairline
   down the edge: a card is read from the top, and the wash is the first thing
   that says which feed this season came from. */

.scbanner {
  display: flex; align-items: center; gap: 8px;
  /* Deep enough that the badge row clears the portrait pushed up into it. */
  padding: 9px 13px 21px;
  background:
    linear-gradient(135deg,
      color-mix(in srgb, var(--lg) 26%, transparent),
      color-mix(in srgb, var(--lg) 6%, transparent) 62%,
      transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--lg) 26%, transparent);
}
.scrank {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 22px; height: 20px; padding: 0 6px;
  font-size: 11.5px; font-weight: 700;
  border-radius: 6px;
  background: color-mix(in srgb, var(--lg) 22%, var(--surface-1));
  border: 1px solid color-mix(in srgb, var(--lg) 40%, transparent);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.scseason { margin-left: auto; font-size: 11.5px; color: var(--text-secondary); font-variant-numeric: tabular-nums; }

/* ---- portrait and name ----
   The portrait straddles the banner's lower edge, which is what makes the
   thing read as a card rather than as a row with a picture in it. */

.scwho {
  display: flex; align-items: center; gap: 11px;
  padding: 0 13px;
  margin-top: -19px;
}
.scface {
  width: 56px; height: 56px; flex-shrink: 0;
  border-radius: 50%;
  object-fit: cover; object-position: top center;
  background: var(--surface-3);
  /* Two rings: the card's own surface so the disc reads as cut out of the
     banner, then the league's hue outside it. */
  box-shadow:
    0 0 0 3px var(--surface-1),
    0 0 0 5px color-mix(in srgb, var(--lg) 62%, transparent);
}
.scface.ph {
  display: flex; align-items: center; justify-content: center;
  font-size: 17px; font-weight: 680; letter-spacing: .01em;
  color: color-mix(in srgb, var(--lg) 80%, var(--text-secondary));
  background: color-mix(in srgb, var(--lg) 14%, var(--surface-3));
}
.scnames { min-width: 0; align-self: flex-end; padding-bottom: 3px; }
.scname {
  font-size: 15px; font-weight: 660; letter-spacing: -.012em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.scteam { font-size: 11.5px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ---- hero stat ----
   Value on one side of the rule, standing on the other. The split is the
   same one the rows below use, at headline size, so the card teaches its own
   layout in the first thing you read. */

.schero { margin: 12px 13px 11px; }
/* The hero sits on the stat block's own grid, so the rule that separates
   value from rank is one line running the height of the card rather than two
   lines at two different offsets. */
.heroline {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 52px 112px;
  gap: 9px;
  align-items: flex-end;
  margin-bottom: 8px;
}
.hval { grid-column: 1 / 3; min-width: 0; display: flex; align-items: baseline; gap: 7px; flex-wrap: wrap; }
.hval .v {
  font-size: 25px; font-weight: 690; letter-spacing: -.025em;
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
}
.hval .k {
  font-size: 11px; font-weight: 550; letter-spacing: .02em;
  color: var(--text-secondary);
}
.hpct {
  grid-column: 3;
  display: flex; flex-direction: column; align-items: flex-end; gap: 1px;
  padding-left: 10px;
  border-left: 1px solid var(--border);
  text-align: right;
}
.hpct .p {
  font-size: 17px; font-weight: 690; letter-spacing: -.015em;
  line-height: 1.1;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.hpct.hi .p { color: var(--pos); }
.hpct.lo .p { color: var(--neg); }
.hpct .c {
  font-size: 9px; font-weight: 600; letter-spacing: .045em; text-transform: uppercase;
  color: var(--text-muted);
  white-space: nowrap;
}

/* In percentile mode the emphasis swaps: the rank takes the headline and the
   rate goes quiet. Both stay on the card either way -- a percentile with no
   value behind it cannot be argued with. */
.showcard.emph-pct .hval .v { font-size: 17px; color: var(--text-secondary); font-weight: 640; }
.showcard.emph-pct .hpct .p { font-size: 25px; letter-spacing: -.025em; }
.showcard.emph-pct .scstat .v { color: var(--text-muted); font-weight: 500; }
.showcard.emph-pct .scstat .rank .p { color: var(--text-primary); font-weight: 680; }

/* ---- stat block ----
   Two columns with a rule between them, because they answer two different
   questions on two different scales: how much, and how good. Either column
   can be read straight down without the other getting in the way. */

.scstats { display: flex; flex-direction: column; gap: 5px; padding: 0 13px; }
.scstat, .scstathead {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 52px 112px;
  align-items: center;
  gap: 9px;
}
.scstathead {
  padding-bottom: 5px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 1px;
}
.scstathead .k, .scstathead .v, .scstathead .p {
  font-size: 8.5px; font-weight: 650; letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.scstathead .v { text-align: right; }
.scstathead .p { padding-left: 10px; border-left: 1px solid var(--border); }

.scstat .k {
  font-size: 11.5px; color: var(--text-secondary);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.scstat .v {
  font-size: 12px; font-weight: 620; text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}
.scstat .rank {
  display: grid; grid-template-columns: 1fr 28px;
  align-items: center; gap: 8px;
  padding-left: 10px;
  border-left: 1px solid var(--border);
}
.scstat .rank .p {
  font-size: 10.5px; font-weight: 600; text-align: right;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* The meter is the card's whole point: same track, same scale, same place on
   every card, so the grid can be read down a column. The hairline at the
   midpoint is what turns "a long bar" into "above the median" -- without it
   the length is only comparable to the bar beside it. */
.scmeter {
  position: relative;
  height: 9px;
  border-radius: 99px;
  background: var(--surface-3);
  overflow: hidden;
}
.scmeter i {
  position: absolute; left: 0; top: 0; bottom: 0; border-radius: 99px;
  transition: width .18s ease;
}
.scmeter b.mid {
  position: absolute; left: 50%; top: 1px; bottom: 1px; width: 1px;
  background: var(--surface-1); opacity: .7;
}
.scmeter .none {
  position: absolute; right: 5px; top: -3px;
  font-size: 9px; font-weight: 600; color: var(--text-muted);
  line-height: 15px;
}
.scmeter.big { height: 11px; }
@media (prefers-reduced-motion: reduce) { .scmeter i { transition: none; } }

.scfoot {
  display: flex; gap: 10px;
  margin: 10px 13px 0; padding-top: 8px;
  border-top: 1px solid var(--border);
  font-size: 10.5px; color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.showmore { margin-top: 14px; }

/* ---- empty state ---- */

.shownone { padding: 34px 10px 30px; text-align: center; }
.shownone .big { font-size: 16px; font-weight: 640; color: var(--text-primary); }
.shownone .sub {
  margin: 6px auto 14px; max-width: 46ch;
  font-size: 13px; line-height: 1.5; color: var(--text-muted);
}

/* ---- leaderboard ---- */

.showtable { width: 100%; }
.showtable td.pcell { font-variant-numeric: tabular-nums; outline: none; }
.showtable tbody tr.picked { outline: 2px solid var(--series-1); outline-offset: -2px; }
.showtable tbody tr:hover { background: var(--surface-3); }
.lgtag {
  display: inline-block;
  padding: 2px 8px;
  font-size: 11px; font-weight: 650; letter-spacing: .02em;
  border-radius: 99px;
  color: var(--text-primary);
  background: color-mix(in srgb, var(--lg) 18%, transparent);
  border: 1px solid color-mix(in srgb, var(--lg) 55%, transparent);
  white-space: nowrap;
}

/* ---- spotlight ---- */

.spotcard { border-left: 3px solid var(--lg); }
.spotactions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin: 2px 0 14px; }
.spotpool { font-size: 11.5px; color: var(--text-muted); }
.openhub { margin: 0; }
/* Wide enough that the percentile bar inside each row is still a bar. Below
   that the label and the value squeeze it to a sliver and it stops reading. */
.spotgroups {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(390px, 1fr));
  gap: 18px 30px;
}
.spotgroup h3 {
  margin: 0 0 6px;
  font-size: 11px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-muted);
}
.spotcareer {
  margin: 20px 0 8px;
  font-size: 11px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-muted);
}
.showcareer tbody tr { cursor: pointer; }
.showcareer tbody tr:hover { background: var(--surface-3); }
.showcareer tbody tr.picked { outline: 2px solid var(--series-1); outline-offset: -2px; }

.showfoot { margin-top: 4px; }
.showfoot .legend { margin: 0; }

/* ---- player career tab ---- */

/* Chart over table, both full width. The box score is 20 columns wide and a
   career can be 20 rows deep, so it needs the whole page rather than a column
   beside the chart. */
.careerstack {
  display: grid;
  gap: 18px;
  min-width: 0;
}

.careerstack > * { min-width: 0; }

/* A long career scrolls the table in both directions, with the header row and
   the season column pinned so a number never loses its labels. */
.careerboxwrap {
  max-height: min(70vh, 700px);
  overflow: auto;
  overscroll-behavior: contain;
}

table.stat.careerbox { border-collapse: separate; border-spacing: 0; }

table.stat.careerbox th,
table.stat.careerbox td {
  white-space: nowrap;
  border-bottom: 1px solid var(--grid);
}

table.stat.careerbox thead th {
  position: sticky;
  top: 0;
  z-index: 3;
  padding-top: 8px;
  background: var(--surface-1);
  box-shadow: inset 0 -1px 0 var(--grid);
}

table.stat.careerbox th:first-child,
table.stat.careerbox td:first-child {
  position: sticky;
  left: 0;
  z-index: 2;
  background: var(--surface-1);
  padding-right: 14px;
}

table.stat.careerbox thead th:first-child { z-index: 4; }
table.stat.careerbox tbody tr:hover td { background: var(--surface-3); }
table.stat.careerbox tbody tr:hover td:first-child { background: var(--surface-3); }

/* The dividers that give the row its shape: identity | volume | box |
   shooting. Marked on the cell rather than by column number, since the
   advanced view has a different column count. */
table.stat.careerbox th.divl,
table.stat.careerbox td.divl {
  border-left: 1px solid var(--grid);
  padding-left: 14px;
}

/* League and team are labels, not numbers -- they read from the left with the
   rest of the row's identity, and only the measurements are right-aligned. */
table.stat.careerbox th:nth-child(2),
table.stat.careerbox td:nth-child(2),
table.stat.careerbox th:nth-child(3),
table.stat.careerbox td:nth-child(3) {
  text-align: left;
}
table.stat.careerbox th:nth-child(3),
table.stat.careerbox td:nth-child(3) { width: 240px; }

table.stat.careerbox td.leaguecell { color: var(--text-secondary); }
table.stat.careerbox .lgdot {
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  margin-right: 6px;
  vertical-align: middle;
}

table.stat.careerbox td.teamcell {
  max-width: 240px;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Linked-league rows sit a shade back -- same columns, but no percentile pool
   behind them and a different standard of opposition. Only the season label is
   dimmed hard; the numbers stay readable. */
table.stat.careerbox tr.linked td.key,
table.stat.careerbox tr.linked td.leaguecell,
table.stat.careerbox tr.linked td.teamcell { color: var(--text-muted); }

table.stat.careerbox tr.career td,
table.stat.careerbox tr.career td:first-child {
  position: sticky;
  bottom: 0;
  z-index: 2;
  background: var(--surface-1);
  border-top: 1px solid var(--axis);
  border-bottom: none;
  color: var(--text-primary);
  font-weight: 620;
  box-shadow: inset 0 1px 0 var(--axis);
}
table.stat.careerbox tr.career td:first-child { z-index: 3; }

@media (max-width: 760px) {
  table.stat.careerbox td.teamcell { max-width: 120px; }
  .careerboxwrap { max-height: 62vh; }
}

/* ============================== WOWY ==================================== */

/* ---- the three-step selector ---- */

.wowystep { margin-top: 20px; }
.wowystep:first-of-type { margin-top: 16px; }

.wowystephead {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
}
.wowysteplabel {
  display: flex; align-items: center; gap: 8px;
  margin-bottom: 10px;
}
.wowystephead .wowysteplabel { margin-bottom: 10px; }
.wowysteplabel .n {
  display: grid; place-items: center;
  width: 17px; height: 17px;
  border-radius: 50%;
  background: var(--surface-3);
  color: var(--text-muted);
  font-size: 10px; font-weight: 700;
}
.wowysteplabel .t {
  font-size: 11px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-muted);
}
.wowysteplabel .h { font-size: 11px; color: var(--text-muted); opacity: .75; }

.wowytools { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.wowycount {
  font-size: 11px; font-weight: 650;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.wowysearch {
  width: 130px;
  padding: 5px 11px;
  font: inherit; font-size: 12px;
  border-radius: 99px;
  border: 1px solid var(--border-strong);
  background: var(--surface-1);
  color: var(--text-primary);
}

/* team crests */
.wowyteams { display: flex; flex-wrap: wrap; gap: 6px; }
.wowyteam {
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  width: 74px; padding: 9px 4px 8px;
  border-radius: 12px;
  border: 1px solid transparent;
  background: none;
  font: inherit;
  cursor: pointer;
}
.wowyteam:hover { background: var(--surface-3); }
.wowyteam.on { background: var(--surface-3); border-color: var(--axis); }
.wowyteam .crest {
  width: 38px; height: 38px;
  display: grid; place-items: center;
  /* Muted, not unreadable: you still have to recognise the crest to click it. */
  filter: saturate(.35); opacity: .72;
  transition: filter .12s, opacity .12s;
}
.wowyteam.on .crest, .wowyteam:hover .crest { filter: none; opacity: 1; }
.wowyteam .crest img { max-width: 100%; max-height: 100%; object-fit: contain; }
.wowyteam .crest .ph {
  width: 100%; height: 100%;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--surface-2);
  font-size: 11px; font-weight: 700; color: var(--text-muted);
}
.wowyteam .nm {
  font-size: 10px; font-weight: 560; line-height: 1.15;
  color: var(--text-muted);
  text-align: center;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 100%;
}
.wowyteam.on .nm { color: var(--text-primary); font-weight: 650; }

/* the pinned selection */
.wowyslots {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 8px;
  margin-bottom: 12px;
}
.wowyslot {
  position: relative;
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px;
  border-radius: 12px;
  border: 1px solid var(--border-strong);
  background: var(--surface-2);
  min-width: 0;
}
.wowyslot .ring {
  width: 36px; height: 36px; flex: 0 0 auto;
  border-radius: 50%;
  overflow: hidden;
  border: 2px solid var(--pos);
  background: var(--surface-3);
}
.wowyslot .ring img { width: 100%; height: 100%; object-fit: cover; display: block; }
.wowyslot .ring .ph {
  width: 100%; height: 100%;
  display: grid; place-items: center;
  font-size: 11px; font-weight: 700; color: var(--text-muted);
}
.wowyslot .meta { min-width: 0; display: flex; flex-direction: column; }
.wowyslot .nm {
  font-size: 12.5px; font-weight: 650;
  color: var(--text-primary);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.wowyslot .mn { font-size: 10.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.wowyslot .x {
  position: absolute; top: 4px; right: 6px;
  border: none; background: none;
  color: var(--text-muted);
  font-size: 16px; line-height: 1;
  padding: 2px 4px;
  cursor: pointer;
}
.wowyslot .x:hover { color: var(--neg); }
.wowyslot.empty {
  border-style: dashed;
  background: none;
}
.wowyslot.empty .ring {
  border: 2px dashed var(--border-strong);
  background: none;
}
.wowyslot.empty .nm { font-size: 12px; font-weight: 560; color: var(--text-muted); }

/* roster faces */
.wowygrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(86px, 1fr));
  gap: 4px;
  /* Caps at four rows of cards; a partial fifth row is the scroll cue. */
  max-height: 400px; overflow-y: auto;
  padding: 2px;
}
.wowycard2 {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 10px 4px 9px;
  border-radius: 12px;
  border: 1px solid transparent;
  background: none;
  font: inherit;
  cursor: pointer;
  text-align: center;
}
.wowycard2:hover { background: var(--surface-3); }
.wowycard2.on { background: var(--surface-3); border-color: var(--pos); }
/* At the pick limit the rest of the roster steps back but stays legible —
   you still need to read it to decide what to swap out. */
.wowycard2.blocked { opacity: .5; cursor: not-allowed; }
.wowycard2.blocked:hover { background: none; }
.wowycard2 .ring {
  position: relative;
  width: 46px; height: 46px;
  border-radius: 50%;
  overflow: hidden;
  border: 2px solid var(--border-strong);
  background: var(--surface-2);
}
.wowycard2.on .ring { border-color: var(--pos); }
.wowycard2 .ring img { width: 100%; height: 100%; object-fit: cover; display: block; }
.wowycard2 .ring .ph {
  width: 100%; height: 100%;
  display: grid; place-items: center;
  font-size: 13px; font-weight: 700; color: var(--text-muted);
}
/* A corner badge, not a scrim — the whole point is that you can still see who
   you picked. */
.wowycard2 .ring .tick {
  position: absolute; right: -1px; bottom: -1px;
  width: 17px; height: 17px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 2px solid var(--surface-1);
  background: var(--pos);
  color: #fff; font-size: 9px; font-weight: 800; line-height: 1;
}
.wowycard2 .ring { overflow: visible; }
.wowycard2 .ring img, .wowycard2 .ring .ph { border-radius: 50%; }
.wowycard2 .nm {
  font-size: 10.5px; font-weight: 560; line-height: 1.2;
  color: var(--text-secondary);
  max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wowycard2.on .nm { color: var(--text-primary); font-weight: 650; }
.wowycard2 .mn {
  font-size: 9.5px; color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* filters */
.wowysettings {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 14px 22px;
  align-items: end;
}
.wowysetting.narrow { max-width: 130px; }
.wowysetting > label {
  display: block;
  font-size: 11px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 6px;
}
.wowysetting .val {
  font-size: 14px; font-weight: 650;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  margin-bottom: 2px;
}
.wowymin {
  width: 100%;
  padding: 6px 10px;
  font: inherit; font-size: 12.5px;
  border-radius: 8px;
  border: 1px solid var(--border-strong);
  background: var(--surface-1);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}

/* folded method notes */
.wowymethod { margin-top: 16px; }
.wowymethod > summary {
  cursor: pointer;
  font-size: 11.5px; font-weight: 600;
  color: var(--text-muted);
  padding: 4px 0;
  list-style: none;
}
.wowymethod > summary::-webkit-details-marker { display: none; }
.wowymethod > summary::before { content: '▸ '; }
.wowymethod[open] > summary::before { content: '▾ '; }
.wowymethod > summary:hover { color: var(--text-secondary); }
.wowymethodgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 10px 22px;
  margin-top: 8px;
  padding-top: 10px;
  border-top: 1px solid var(--grid);
}
.wowymethodgrid dt {
  font-size: 11px; font-weight: 650;
  color: var(--text-secondary);
  margin-bottom: 2px;
}
.wowymethodgrid dd {
  margin: 0;
  font-size: 11.5px; line-height: 1.45;
  color: var(--text-muted);
}

table.wowytable { border-collapse: separate; border-spacing: 0; }
table.wowytable th.grp,
table.wowytable td.grp { border-left: 1px solid var(--grid); }
table.wowytable th.sub { font-size: 9.5px; padding-bottom: 8px; }

/* The combination is the row's label; it stays put while the stats scroll. */
table.wowytable th.wowycombo,
table.wowytable td.wowycombo {
  position: sticky; left: 0; z-index: 1;
  text-align: left; padding-left: 0; padding-right: 14px;
  background: var(--surface-1);
}
table.wowytable th.wowycombo { z-index: 4; }

table.wowytable th.wowymincol, table.wowytable td.wowymincol { padding-right: 4px; }
table.wowytable td.wowymincol .big {
  font-size: 14px; font-weight: 640;
  color: var(--text-primary);
  line-height: 1.15;
}
table.wowytable td.wowymincol .m {
  font-size: 10px; line-height: 1.1;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.minbar {
  height: 3px; width: 100%;
  margin: 4px 0 3px auto;
  border-radius: 99px;
  background: var(--surface-3);
  overflow: hidden;
}
.minbar i { display: block; height: 100%; background: var(--text-muted); opacity: .55; }

/* One number per cell plus an arrow gutter. No fills: the arrows carry the
   distance from the team's own average, the number carries the value. */
table.wowytable td.val {
  font-size: 13.5px; font-weight: 620;
  color: var(--text-primary);
  padding: 7px 10px;
  cursor: default;
  white-space: nowrap;
}
table.wowytable td.val:focus-visible { outline: 2px solid var(--axis); outline-offset: -2px; }

table.wowytable td.val .v { line-height: 1.15; }

/* Second line: arrows and the gap from the team's own average. Quiet enough
   that the value above stays the thing you read first. */
table.wowytable td.val .sub {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 3px;
  margin-top: 3px;
  min-height: 11px;
  font-size: 10px;
  font-weight: 600;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.wowytable .arw {
  font-size: 8px;
  letter-spacing: -0.5px;
  color: var(--text-muted);
}
.wowytable .arw.up { color: var(--pos); }
.wowytable .arw.down { color: var(--neg); }
.wowytable .sub .d { color: var(--text-muted); opacity: .75; }
table.wowytable th.wowyhero { color: var(--text-secondary); }
table.wowytable td.val.wowyhero { font-size: 16px; font-weight: 720; }

table.wowytable tbody tr:hover td { background-color: transparent; }
table.wowytable tbody tr:hover td.wowycombo { background: var(--surface-3); }
/* The all-on row is the reference every other row is read against. */
table.wowytable tr.allon td.wowycombo { box-shadow: inset 2px 0 0 var(--axis); }

/* Below the minutes floor: still there, visibly not to be leaned on. */
table.wowytable tr.thin td { opacity: .42; }

table.wowytable tr.wowydelta td {
  border-top: 1px solid var(--axis);
  border-bottom: none;
  padding-top: 11px;
}
table.wowytable tr.wowydelta td.wowycombo {
  font-size: 10.5px; font-weight: 650;
  letter-spacing: .05em; text-transform: uppercase;
  color: var(--text-secondary);
  vertical-align: middle;
}
table.wowytable tr.wowydelta td.wowymincol {
  font-size: 13px; font-weight: 640;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}

/* Face beside name, so a row stays one band of the heat grid rather than a
   slab three lines tall. ON/OFF is carried by the ring and the ink, not a
   badge — three badges per row was the noisiest thing in the table. */
.wowystrip { display: flex; gap: 5px; align-items: center; }
.wowyface {
  display: flex; align-items: center; gap: 5px;
  padding: 2px 7px 2px 2px;
  border-radius: 99px;
  background: var(--surface-2);
  min-width: 0;
}
.wowyface.off { background: none; }
.wowyface .ring {
  position: relative; flex: 0 0 auto;
  width: 26px; height: 26px;
  border-radius: 50%;
  overflow: hidden;
  border: 2px solid var(--pos);
  background: var(--surface-3);
}
.wowyface.off .ring {
  border-color: var(--border);
  filter: grayscale(1);
  opacity: .45;
}
.wowyface .ring img { width: 100%; height: 100%; object-fit: cover; display: block; }
.wowyface .ring .ph {
  width: 100%; height: 100%;
  display: grid; place-items: center;
  font-size: 9px; font-weight: 700;
  color: var(--text-muted);
}
.wowyface .state { display: none; }
.wowyface .nm {
  font-size: 10.5px; font-weight: 650; line-height: 1.1;
  color: var(--text-primary);
  white-space: nowrap;
}
.wowyface.off .nm { color: var(--text-muted); font-weight: 550; text-decoration: line-through; text-decoration-thickness: 1px; }

@media (max-width: 720px) {
  .mfrow { grid-template-columns: 1fr auto 26px; }
  .mfrow .dualrange { grid-column: 1 / -1; }
  .showsummary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .showcards { grid-template-columns: 1fr; }
  .showviewctl { gap: 10px; }
  /* A card's control rail is wider than a phone. It scrolls inside its own
     header rather than pushing the page sideways. */
  .card > .head > .ctl { overflow-x: auto; min-width: 0; }
}

/* Shot tab for a player with no tracked coordinates: the diet column alone,
   held to a readable width rather than stretched across the empty court. */
.dietonly { display: grid; gap: 16px; }
.dietonly > .card .nodata { text-align: left; }
.shotcol.dietsolo { max-width: 460px; }

/* ==========================================================================
   Phones
   Everything below this line is inside a max-width or a coarse-pointer query,
   so the desktop layout above is untouched. Three things were wrong on a
   phone: the header ran wider than the screen and dragged the whole page
   sideways with it; panels that scroll sideways handed the gesture on to the
   page (and then to the browser's back swipe) once they hit their end; and
   hover was doing work touch has no way to ask for.
   ========================================================================== */

/* ------------------------------------------------------- header: two rows */

@media (max-width: 760px) {
  /* Row one is the wordmark, the search field and the theme switch. The nav
     wrapper has a full-width basis, so it always lands on row two -- no
     guessing about which button happens to fit beside the search box. */
  .topbar {
    flex-wrap: wrap;
    gap: 8px;
    padding: 8px 12px;
  }
  .brand { order: 0; }
  .search { order: 1; flex: 1 1 40%; min-width: 0; max-width: none; margin-left: 0; }
  .topbar > .icon-btn { order: 2; }
  .navstrip {
    order: 3;
    display: flex;
    flex: 1 0 100%;
    gap: 6px;
    /* More links than fit (the archetype pages) scroll rather than wrap into
       a third row of sticky header. */
    overflow-x: auto;
    scrollbar-width: none;
  }
  .navstrip::-webkit-scrollbar { display: none; }
  .nav-btn {
    flex: 1 1 auto;
    min-height: 34px;
    padding: 7px 10px;
    font-size: 12px;
    text-align: center;
    white-space: nowrap;
  }
  /* The results panel hangs off the search box, which is now most of a row. */
  .results { max-height: 56vh; }
}

/* iOS zooms the whole page in when a field under 16px takes focus, and never
   zooms back out -- that alone made every page feel like it was sliding. */
@media (max-width: 760px) {
  input, select, textarea { font-size: 16px; }
  .search input { padding: 10px 12px 10px 32px; }
  .showsearch { font-size: 16px; }
  .wowysearch { width: 100%; font-size: 16px; }
  .rapmsearch { flex: 1; font-size: 16px; }
}

/* ------------------------------------------------- sideways scroll panels */

@media (max-width: 760px) {
  /* A shadow at the edge that only shows while there is more to reach: the
     first pair of gradients scrolls with the content and covers the second. */
  .tablewrap, .chartscroll {
    background:
      linear-gradient(to right, var(--surface-1) 40%, transparent) left center / 28px 100% no-repeat local,
      linear-gradient(to left, var(--surface-1) 40%, transparent) right center / 28px 100% no-repeat local,
      radial-gradient(farthest-side at 0 50%, rgba(0, 0, 0, .13), transparent) left center / 11px 100% no-repeat scroll,
      radial-gradient(farthest-side at 100% 50%, rgba(0, 0, 0, .13), transparent) right center / 11px 100% no-repeat scroll;
  }
  /* Dropping the card bleed puts the scrollport on the content box, which is
     what lets the first column stick to a sensible edge below. */
  .tablewrap { margin: 0; padding: 0; }
  .chartscroll { margin: 0; padding: 0; }
  .tabs { scrollbar-width: none; }
  .tabs::-webkit-scrollbar { display: none; }

  /* A grid item's automatic minimum is its content, and a chart or a nowrap
     table is far wider than a phone -- so the track grew to fit and pushed the
     page out sideways. Letting the items floor at zero hands the width back to
     the scrollers they already contain. */
  .grid > *, .impactsplit > *, .impactgrid > *, .teamdash > *, .careerstack > *,
  .eventmaps > *, .convtiles > *, .splitgrid > *, .spotgroups > * { min-width: 0; }

  /* Segmented pickers with five or six options are wider than the screen on
     the explainer and conversion tabs; they scroll in place. */
  .seg {
    max-width: 100%;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
  }
  .seg::-webkit-scrollbar { display: none; }
}

/* The row label travels with the row. Without it a wide table on a phone is a
   grid of numbers with no idea which player they belong to. */
@media (max-width: 620px) {
  .tablewrap table.stat th:first-child,
  .tablewrap table.stat td:first-child {
    position: sticky;
    left: 0;
    z-index: 1;
    padding-right: 12px;
    background: var(--surface-1);
    /* border-collapse drops borders on sticky cells, so they are drawn as
       insets instead: the row rule, and a hairline marking the split. */
    box-shadow: inset -1px 0 0 var(--border), inset 0 -1px 0 var(--grid);
  }
  .tablewrap table.stat thead th:first-child { z-index: 2; }
  .tablewrap table.stat tbody tr:last-child td:first-child { box-shadow: inset -1px 0 0 var(--border); }

  /* Leaderboards open on a rank, so column one is not what names the row --
     the player is, and that is what stays. The rank slides away underneath
     it, and the face comes off to leave the numbers some width. */
  .tablewrap table.stat:has(td.playercell) th:first-child,
  .tablewrap table.stat:has(td.playercell) td:first-child {
    position: static;
    box-shadow: inset 0 -1px 0 var(--grid);
  }
  .tablewrap table.stat:has(td.playercell) thead th:nth-child(2),
  .tablewrap table.stat:has(td.playercell) td.playercell {
    position: sticky;
    left: 0;
    z-index: 1;
    max-width: 132px;
    background: var(--surface-1);
    box-shadow: inset -1px 0 0 var(--border), inset 0 -1px 0 var(--grid);
  }
  .tablewrap table.stat:has(td.playercell) thead th:nth-child(2) { z-index: 2; }
  .tablewrap table.stat td.playercell .facemini { display: none; }
  .tablewrap table.stat td.playercell .linkish {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

/* ------------------------------------------------------------ page plane */

@media (max-width: 620px) {
  main, main.hub { padding: 14px 12px 40px; }
  .card { padding: 14px; }
  .card > .head { gap: 10px; margin-bottom: 12px; }
  .card .head .ctl { margin-left: 0; }
  .pagehead { padding: 2px 0 14px; }
  .grid, .grid + .grid, .grid + .card, .card + .card, .card + .grid { gap: 12px; }
  .card + .card, .grid + .grid, .grid + .card, .card + .grid { margin-top: 12px; }
  .section-eyebrow { margin: 20px 0 8px; }
  .tabs { margin-bottom: 16px; }
  .tab { padding: 11px 13px; font-size: 13px; }
}

/* Touch targets. A 22px chip is a coin toss with a fingertip. */
@media (hover: none) and (pointer: coarse) {
  .chip, .lgchip, .activechip, .ghost, .seg button, .srcall, .litem, .cseason, .bseason {
    min-height: 34px;
  }
  .seg button { padding: 7px 13px; }
  .icon-btn { width: 38px; height: 38px; }
  /* Nothing here can be reached by hovering, so the hover-only affordances
     are either always on or gone. */
  .hubrow-go { opacity: 1; }
  .pcard:hover, .hubpanel:hover, .hubjersey:hover, .hubrow:hover, .thitem:hover { transform: none; }
  .hubpanel:hover .hubface { transform: translate(calc(var(--dx) * var(--fan, 1)), calc(var(--dy) * var(--fan, 1))) rotate(var(--rot)); }
}

/* ------------------------------------------------------- home + hub panels */

/* The marquee rows slide on a loop that only hover can pause, so on touch
   they become plain swipeable shelves. The duplicate copy of each card is
   there to hide the loop seam; with no loop it is just every player twice. */
@media (hover: none) and (pointer: coarse) {
  .homerow {
    overflow-x: auto;
    scrollbar-width: none;
    overscroll-behavior-x: contain;
    -webkit-mask-image: none;
    mask-image: none;
  }
  .homerow::-webkit-scrollbar { display: none; }
  .hometrack { animation: none; scroll-snap-type: x proximity; }
  .hometrack > [aria-hidden="true"] { display: none; }
  .pcard { scroll-snap-align: center; }
}

@media (max-width: 620px) {
  .homehead { padding: 30px 16px 20px; }
  .homehead h1 { font-size: 26px; }
  .homehead h1.homelock { font-size: 28px; gap: 10px; }
  .homelock-mark { width: 58px; height: 58px; }
  .homecols { grid-template-columns: repeat(2, minmax(0, 1fr)); height: auto; }
  .hubtop { padding: 26px 0 18px; }
  .hubtop h1.homelock { font-size: 27px; gap: 10px; }
  .hubtop .homelock-mark { width: 52px; height: 52px; }
  .hubtop p { font-size: 13.5px; }
  .hubpanel { padding: 18px 16px 14px; gap: 14px; }
  .hubhead h2 { font-size: 22px; }
  /* The hand closes up so the outer two cards stay inside the panel instead
     of being cut off by its rounded edge. */
  .hubfan { min-height: 200px; --fan: .58; }
  .hubface { width: 96px; height: 134px; }
  .hubface-tag { height: 32px; }
  .hubface-tag b { font-size: 11.5px; }
  .hubface::before, .hubface-ph { inset: 0 0 32px 0; }
  .hubface-shot { bottom: 32px; }
  .hubjerseys { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  /* "15-16→25-26" is the widest thing in the strip, and its hyphens give the
     browser somewhere to break it while the other two tiles keep one line. */
  .hubstats b { font-size: 13px; white-space: nowrap; }
  .hubstats span { font-size: 9.5px; letter-spacing: .04em; }
}

@media (max-width: 430px) {
  .hubfan { --fan: .48; min-height: 190px; }
  .hubface { width: 88px; height: 124px; }
}

/* ------------------------------------------------------------ player page */

@media (max-width: 620px) {
  .hero { gap: 14px; padding: 0 0 16px; }
  /* Narrower than desktop but still matched to the name block, so the face
     and the text keep their shared top and bottom edge on a phone too. */
  .hero .shot {
    width: 72px;
    flex: 0 0 72px;
    height: auto;
    align-self: stretch;
    border-radius: 12px;
  }
  .hero h1, .teamhero h1 { font-size: 23px; }
  .hero .meta { font-size: 12.5px; }
  /* Four career numbers on one flex line runs off a phone; as a grid they
     wrap into two rows of two and stay aligned. */
  /* auto-fit against a narrow right-aligned column gave each number its own
     row and 200px of hero. The block goes full width and the four share it. */
  .herostatblock { margin-top: 14px; margin-left: 0; width: 100%; }
  .herostatcap { text-align: left; margin-bottom: 9px; }
  .herostats {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 10px;
    justify-content: start;
  }
  .herostat { text-align: left; }
  .herostat .v { font-size: 20px; }
  .herostat .l { font-size: 9.5px; }

  .thjersey { width: 62px; height: 62px; }
  .teamhistory { margin-left: 0; max-width: 100%; gap: 8px 10px; margin-top: 14px; }
  .heroid { min-width: 0; gap: 14px; flex-basis: 100%; }
  /* Tight enough that the five chips share one row from 430px up, instead of
     stranding nationality on a line of its own. */
  .biochips { gap: 5px; margin-top: 10px; }
  .biochip { font-size: 11px; padding: 4px 7px; gap: 5px; min-height: 24px; }
  .biogl svg { width: 12px; height: 12px; }
  /* Once the name wraps the chip onto its own line the optical nudge that
     sat it on the name's baseline is just a misalignment. */
  .archchip { transform: none; }
  .archlabel { font-size: 12.5px; }
  .teamhero { gap: 12px; padding: 12px; }
  .teamcontrols select { width: 100%; min-width: 0; }
  .teamkpi { padding: 11px 12px; }
}

/* ------------------------------------------------------- archetype tab */

/* The tab is meant to be read in one screen: map and timeline on the left,
   identity over the two twins on the right. Nothing in it grows with the
   length of a career, so an eleven-season player fits the same box as a
   rookie. Below 1080px it stacks and scrolls like any other tab. */
.archhead { margin-bottom: 10px; }
.archhead-title { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; min-width: 0; }
.archhead .section-eyebrow { margin: 0; }

.archtab {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1.75fr);
  gap: 10px;
  align-items: stretch;
}
.archcol { display: flex; flex-direction: column; gap: 7px; min-width: 0; }
.archtab .card { padding: 10px 13px 8px; }
.archmapcard { display: flex; flex-direction: column; min-height: 0; }

/* --- identity */

.archident { border-left: 3px solid var(--arch); }
.archident-main { display: flex; align-items: center; gap: 11px; }
.archident-badge {
  width: 34px; height: 34px;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: 11px;
  background: color-mix(in srgb, var(--arch) 12%, var(--surface-1));
  border: 1px solid color-mix(in srgb, var(--arch) 30%, transparent);
}
.archident-text { min-width: 0; }
.archident-kicker {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 1px;
}
.archident-text h2 {
  margin: 0;
  font-size: 19.5px;
  font-weight: 660;
  letter-spacing: -0.025em;
  line-height: 1.15;
}
/* Fit is the qualifier on the label, so it sits on the same line as it. */
.archfit {
  margin-left: auto;
  text-align: right;
  line-height: 1.05;
  cursor: default;
}
.archfit b {
  display: block;
  font-size: 21px;
  font-weight: 660;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}
.archfit span {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.archident-blurb {
  margin: 5px 0 0;
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--text-secondary);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}
.archblend { margin-top: 6px; cursor: default; }
/* Two runs sharing one track: the split reads as one hundred per cent of the
   player rather than two unrelated bars. */
.archblend-rail { display: flex; gap: 2px; height: 5px; }
.archblend-fill { height: 5px; border-radius: 3px; }
.archblend-fill.second { opacity: .55; }
.archblend-lab { margin-top: 4px; font-size: 11px; color: var(--text-secondary); }

/* --- the map */

.archmapcard { flex: 1; }
.archmapcard .head { margin-bottom: 8px; }
/* The plot takes the slack under the header, so the map card ends exactly
   level with the cards beside it. It is positioned rather than sized: an SVG
   with a viewBox carries an intrinsic height, and left in flow it would set
   the height of the whole row instead of taking it. */
.archmapcard .chartscroll { position: relative; flex: 1; min-height: 150px; }
.archmapcard .chartscroll > svg.archmap {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  min-width: 0;
}
.archmapcard .head h2 { font-size: 13.5px; }
.archmapcard .head .sub { font-size: 11px; }
.archmapcard .seg button { padding: 3px 8px; font-size: 11px; }
/* A map is a shape, not a time series: it scales to the card rather than
   holding the 680px floor the wide time-series charts scroll at. */
.archmap { display: block; }
.archsw { width: 8px; height: 8px; border-radius: 50%; display: inline-block; margin-right: 5px; flex: none; }

/* --- the timeline */

/* One tick per season, the label printed only where it changes. A card per
   season was honest and cost three rows of height on a long career. */
.archtimewrap {
  margin-top: 7px;
  padding-top: 6px;
  border-top: 1px solid var(--grid);
}
.archtime { display: flex; align-items: flex-end; gap: 3px; }
.archtick {
  flex: 1 1 0;
  min-width: 0;
  /* A four-season career would otherwise stretch four ticks across the whole
     card and read as a bar chart of nothing. */
  max-width: 84px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 3px;
  padding: 3px 3px 4px;
  border: 1px solid transparent;
  border-radius: 7px;
  background: none;
  cursor: pointer;
  font: inherit;
}
.archtick:hover { background: var(--surface-3); }
.archtick.on {
  background: color-mix(in srgb, var(--arch) 10%, var(--surface-1));
  border-color: color-mix(in srgb, var(--arch) 45%, transparent);
}
.archtick-season {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--text-muted);
  text-align: center;
}
.archtick.on .archtick-season { color: var(--text-primary); }
/* The bar is a well the height of the row, filled to the season's fit, so an
   uncertain label looks uncertain at a glance. */
.archtick-bar {
  display: block;
  height: 10px;
  border-radius: 3px;
  background: var(--surface-3);
  position: relative;
  overflow: hidden;
}
.archtick-bar::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: var(--fit, 50%);
  background: var(--arch);
  opacity: .85;
}
/* The labels sit under the row as runs -- "Stretch Big 15-16-18-19 -> Connector
   19-20-25-26" -- which is the sentence the ticks are drawing. */
.archtimecap {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 3px 8px;
  margin-top: 5px;
  font-size: 10.5px;
}
.archrun { display: inline-flex; align-items: center; gap: 5px; opacity: .55; }
.archrun.on { opacity: 1; }
.archrun-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--arch); flex: none; }
.archrun-name { font-weight: 620; color: var(--text-primary); }
.archrun-years { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.archrun-arrow { color: var(--text-muted); }
.archtimecap { cursor: default; }

/* --- twins */

/* Side by side rather than stacked: the tab has to end above the fold, and
   two twin cards on one row is the difference between reading the whole
   comparison and scrolling for the second half of it. */
.archtwins {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 9px;
  align-items: stretch;
}
/* The page-wide "stacked cards" spacing rule does not apply inside a grid
   that already has a gap -- it was pushing the second twin 16px down its own
   column and out of line with the first. */
.archtwins .archtwin { display: flex; flex-direction: column; margin-top: 0; }
.archtwin-kicker {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 5px;
  cursor: default;
}
.archcmp-keyitem {
  display: inline-flex;
  align-items: center;
  text-transform: none;
  letter-spacing: 0;
  font-weight: 500;
  font-size: 10px;
}
.archtwin-who { display: flex; align-items: center; gap: 10px; }
.archtwin-face {
  width: 34px; height: 34px;
  flex: none;
  border-radius: 10px;
  object-fit: cover;
  background: var(--surface-3);
}
.archtwin-face.ph {
  display: grid;
  place-items: center;
  font-size: 13px;
  font-weight: 640;
  color: var(--text-muted);
}
.archtwin-meta { min-width: 0; display: flex; flex-direction: column; gap: 1px; line-height: 1.2; }
/* Name, label and season line each hold one line: a wrapped twin card would
   be taller than the one beside it, and the pair is meant to be read across. */
.archtwin-namerow {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
  white-space: nowrap;
}
.archtwin-namerow .archchip { min-width: 0; overflow: hidden; }
.archtwin-namerow .archlabel { overflow: hidden; text-overflow: ellipsis; }
.archtwin-name {
  flex: 0 1 auto;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 14.5px;
  font-weight: 650;
  letter-spacing: -0.02em;
  color: var(--text-primary);
}
.archtwin-name.link {
  padding: 0;
  border: 0;
  background: none;
  font-family: inherit;
  cursor: pointer;
  border-bottom: 1px solid transparent;
}
.archtwin-name.link:hover { border-bottom-color: var(--axis); }
.archtwin-namerow .archchip { transform: none; }
.archtwin-namerow .archlabel { font-size: 11px; }
.archtwin-line {
  font-size: 10.5px;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.archdial { margin-left: auto; text-align: center; cursor: default; flex: none; }
.archdial-svg { display: block; }
.archdial-lab {
  font-size: 8px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-top: -1px;
}

.archcmp { margin-top: 6px; padding-top: 4px; border-top: 1px solid var(--grid); }
.archcmp-key { display: inline-flex; gap: 10px; margin-left: auto; }

/* Label column fixed, axis takes the rest: the rows are the same height in a
   narrow card and a wide one, and only the scale stretches. */
.cmprow {
  display: grid;
  grid-template-columns: minmax(0, 108px) minmax(0, 1fr);
  align-items: center;
  gap: 10px;
  height: 12px;
  cursor: default;
}
.cmprow + .cmprow { margin-top: 0.5px; }
/* The two groups are one chart, but the break says which three are which. */
.cmprow.split { margin-top: 4px; padding-top: 3px; border-top: 1px dashed var(--grid); height: 15px; }
.cmplab {
  font-size: 10px;
  line-height: 1;
  text-align: right;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cmprow.far .cmplab { color: var(--text-primary); }
.cmpscale {
  position: relative;
  height: 11px;
  font-size: 9px;
  color: var(--text-muted);
}
.cmpscale .lo { position: absolute; left: 0; }
.cmpscale .mid { position: absolute; left: 50%; transform: translateX(-50%); }
.cmpscale .hi { position: absolute; right: 0; }
.cmphead { height: 11px; }
.cmptrack {
  position: relative;
  height: 100%;
  border-left: 1px solid var(--grid);
  border-right: 1px solid var(--grid);
}
.cmpzero {
  position: absolute;
  left: 50%; top: 0; bottom: 0;
  width: 1px;
  background: var(--axis);
}
.cmplink {
  position: absolute;
  top: 50%;
  height: 2px;
  margin-top: -1px;
  border-radius: 1px;
  background: var(--axis);
}
.cmprow.near .cmplink { background: var(--series-3); opacity: .55; height: 3px; margin-top: -1.5px; }
.cmpdot {
  position: absolute;
  top: 50%;
  width: 7px; height: 7px;
  margin: -3.5px 0 0 -3.5px;
  border-radius: 50%;
  border: 1px solid var(--surface-1);
}
.cmpdot.self { background: var(--series-1); }
.cmpdot.twin { background: var(--series-2); }
.cmprow:hover .cmpdot { transform: scale(1.16); }

@media (max-width: 1180px) {
  /* Stacked, the map has no neighbour to take its height from, so it states
     one of its own rather than collapsing to the 150px floor. */
  .archtab { grid-template-columns: minmax(0, 1fr); }
  .archmapcard .chartscroll { min-height: 340px; }
}
@media (max-width: 620px) {
  .archtwins { grid-template-columns: minmax(0, 1fr); }
  .archmapcard .chartscroll { min-height: 260px; }
  .cmplab { font-size: 9.5px; }
}

/* ---------------------------------------------------- remaining wide grids */

@media (max-width: 620px) {
  /* Three across keeps the box line to three short rows on a phone. */
  .statstrip { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .sst { padding: 4px 8px; }
  .sst:nth-child(3n+1) { border-left: 0; padding-left: 2px; }
  .sst .v { font-size: 17px; }
  .pctrows.compact .pctrow { grid-template-columns: 112px 1fr 46px; gap: 8px; }
  .rapmxtiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .eventmaps, .eventtiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .convtiles, .splitgrid, .spotgroups, .showcards { grid-template-columns: minmax(0, 1fr); }
  .windows { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .showfilters { grid-template-columns: minmax(0, 1fr); gap: 14px; }
  .msummary { grid-template-columns: minmax(0, 1fr); }
  /* Label / bar / value rows: the bar is the reading, so the fixed side
     columns give way to it rather than the other way round. */
  .rapmxbar { grid-template-columns: minmax(0, 1fr) minmax(90px, 1.1fr) 42px; }
  .rapmxgroup { grid-template-columns: minmax(0, .9fr) minmax(80px, 1fr) 40px; }
  .heroline, .scstat, .scstathead { grid-template-columns: minmax(0, 1fr) 44px 88px; }
  .mfrow { gap: 8px; }
  .wowygrid { grid-template-columns: repeat(auto-fill, minmax(72px, 1fr)); }
  .wowyteam { width: 64px; }
  .jpanel { width: 100%; grid-template-columns: 104px minmax(0, 1fr); }
  .archident-text h2 { font-size: 18px; }
  /* Eleven ticks at phone width leave no room for a label under each; the run
     of bars still carries the shape, and the tooltip carries the names. */
  .archtick-season { font-size: 8px; }
}

/* ------------------------------------------------------------------ misc */

@media (max-width: 620px) {
  /* Anchored panels are pinned to the right edge of a button that may itself
     be near the left one; on a phone they take the width they need. */
  .srcpanel { right: auto; left: 0; width: min(288px, calc(100vw - 32px)); }
  .archgrid { grid-template-columns: minmax(0, 1fr); }
  .controls { gap: 12px 16px; padding: 12px 14px; }
  .ctl { flex: 1 1 150px; }
  .ctl select { width: 100%; min-width: 0; }
  .rangerow { grid-template-columns: minmax(0, 1fr) 40px; }
  .stats { gap: 14px 22px; }
  .lab { gap: 12px; }
  /* The note is absolutely placed over the map, where at this width it sits
     on top of the plot. */
  .pathnote { position: static; margin: 6px 4px 4px; max-width: none; }
}

/* On touch the tooltip is placed by script rather than followed to a cursor,
   so it takes a readable width and sits clear of the finger. */
@media (hover: none) and (pointer: coarse) {
  .tip { max-width: min(320px, calc(100vw - 24px)); font-size: 12.5px; padding: 9px 12px; }
}
