/* polbielytics — a stats terminal. Square edges, hairlines, tabular figures. */

:root {
  /* A blue-black ground rather than the green-black it started on. The shift
     is a few degrees of hue and no lightness, and it sits better under the
     cyan accent — which is unchanged, as are the win-rate colours. Colour
     still encodes a number or it is not used. */
  --bg:    #0B0D12;
  --panel: #141821;
  --row:   #10141B;
  --rule:  #232A36;
  --ink:   #E4E8EE;
  --mute:  #8B95A5;
  --dim:   #5C6575;
  --gold:  #35C6E0;   /* accent — cyan */
  --good:  #3E8E7E;
  --bad:   #B4544A;

  /* Outfit replaces Barlow for text. At the 13px this site runs its tables
     at, Barlow's narrow apertures close up and Outfit stays open; the gain is
     purely legibility at small sizes. Figures stay monospaced — tabular
     numerals are the whole reason a stats table is readable. */
  --cond: "Barlow Condensed", "Arial Narrow", sans-serif;
  --body: "Outfit", system-ui, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, Menlo, monospace;

  /* Square corners were a rule; now they are a default with exceptions. 4px
     is small enough that the page still reads as ruled rather than carded,
     and it takes the hard edge off chips, thumbnails and controls. */
  /* Softened from the original 0, then from 4px. A 6px corner still reads as
     ruled rather than carded at table scale, and takes the hard edge off the
     larger blocks. */
  --r: 6px;

  /* Category accents. These mark which family a figure belongs to, never its
     value — win rate is still the only thing whose colour encodes a number. */
  --acc-amber:  #C8933C;
  --acc-violet: #9B7BD4;
  color-scheme: dark;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
[hidden] { display: none !important; }

/* iOS inflates text in landscape unless told not to, which breaks a layout
   built on fixed column widths and tabular figures. */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--body);
  font-size: 14px;
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }


/* ---------- corners ----------
   Applied by role, not globally. Anything that is an object in its own hand —
   a chip, a thumbnail, a control, a floating panel — gets the 4px; the table
   rules and page structure stay square, which is what keeps the page reading
   as ruled rather than carded. */

.chip, .thumb, .orb, .res, .form i, .lineup-ball, .owner-badge,
.legend-swatch, .tl-item, .tl-card, .omni-results, .omni input,
.gate input, .gate button, .pill, .depth-warn, .banner, .flag,
.ball-hero > img, .player-hero > img, .strip, .kpi,
.conf-track, .conf-fill, .meter-track, .meter-fill,
.tl-pos, .tl-pos::after { border-radius: var(--r); }

/* Pill-ish things that read better fully round. */
.conf-track, .conf-fill, .tl-pos, .tl-pos::after { border-radius: 2px; }
.orb { border-radius: 3px; }

/* Controls keep their square seating in the chrome strip, since they butt
   against each other and a radius would leave gaps between them. */
.subnav button, .leagues button, .nav a { border-radius: 0; }

/* ---------- masthead ---------- */

.top {
  display: flex; align-items: stretch; gap: 0;
  border-bottom: 1px solid var(--rule); background: var(--panel);
  position: sticky; top: 0; z-index: 40;
}
.brand {
  font-family: var(--cond); font-weight: 700; font-size: 19px;
  letter-spacing: 0.08em; text-transform: uppercase;
  padding: 12px 18px; border-right: 1px solid var(--rule);
  display: flex; align-items: center; white-space: nowrap;
}
.brand b { color: var(--gold); font-weight: 700; }

.nav { display: flex; overflow-x: auto; }
.nav a {
  font-family: var(--cond); font-weight: 600; font-size: 14px;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--mute);
  padding: 12px 18px; border-right: 1px solid var(--rule);
  display: flex; align-items: center; white-space: nowrap;
}
.nav a:hover { color: var(--ink); background: var(--row); }
.nav a[aria-current="page"] { color: var(--gold); box-shadow: inset 0 -2px 0 var(--gold); }

.stamp {
  margin-left: auto; font-family: var(--mono); font-size: 11px; color: var(--dim);
  padding: 12px 18px; border-left: 1px solid var(--rule);
  display: flex; align-items: center; white-space: nowrap;
}

/* ---------- chrome: sub-tabs and league picker ---------- */

/* Drawn only where a route asks for it, so pages that filter nothing are bare. */
.chrome {
  display: flex; align-items: stretch; flex-wrap: wrap;
  border-bottom: 1px solid var(--rule); background: var(--row);
}
.chrome.is-tierlist { display: block; }
.tl-view-axes, .tl-scope {
  display: flex; align-items: stretch; flex-wrap: wrap;
}
.tl-view-axes { background: var(--row); }
.tl-scope {
  border-top: 1px solid var(--rule); background: var(--panel);
}
.tl-view-axes .subnav { border-right: 1px solid var(--rule); }
.tl-view-axes .subnav:last-child { border-right: 0; }
.tl-tier-choose { display: flex; align-items: center; gap: 4px; }
.tl-tier-choose select {
  margin: 5px 12px 5px 0; padding: 6px 28px 6px 9px;
  min-width: 138px; border: 1px solid var(--rule); border-radius: var(--r);
  background: var(--row); color: var(--ink); font: 12px var(--body);
  cursor: pointer;
}
.tl-tier-choose select:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
@media (pointer: coarse) {
  .tl-tier-choose select { font-size: 16px; min-height: 40px; }
}

.subnav { display: flex; border-right: 1px solid var(--rule); }
.subnav button {
  font-family: var(--cond); font-weight: 600; font-size: 13px; letter-spacing: 0.07em;
  text-transform: uppercase; background: none; border: 0; color: var(--mute);
  padding: 10px 15px; cursor: pointer; border-right: 1px solid var(--rule);
}
.subnav button:last-child { border-right: 0; }
.subnav button:hover { color: var(--ink); }
.subnav button[aria-pressed="true"] { color: var(--gold); box-shadow: inset 0 -2px 0 var(--gold); }

.leagues { display: flex; align-items: center; }
.flabel {
  font-family: var(--cond); font-size: 12px; font-weight: 700; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--ink); padding: 0 10px 0 15px;
  border-left: 1px solid var(--rule); align-self: stretch; display: flex; align-items: center;
}
.leagues button {
  font-family: var(--cond); font-weight: 600; font-size: 12.5px; letter-spacing: 0.05em;
  text-transform: uppercase; background: none; border: 0; color: var(--mute);
  padding: 9px 11px; cursor: pointer; border-left: 1px solid var(--rule);
}
.leagues button:hover { color: var(--ink); }
.leagues button[aria-pressed="true"] { color: var(--bg); background: var(--gold); }

/* ---------- omnibox ---------- */

.omni { position: relative; margin-left: auto; border-left: 1px solid var(--rule); }
.omni input {
  background: none; border: 0; color: var(--ink); font-family: var(--body);
  font-size: 13px; padding: 13px 16px; width: 250px;
}
.omni input::placeholder { color: var(--dim); }
.omni input:focus { outline: none; background: var(--row); }

.omni-results {
  position: absolute; top: 100%; right: 0; min-width: 330px; z-index: 60;
  background: var(--panel); border: 1px solid var(--rule); border-top: 0;
  max-height: 380px; overflow-y: auto;
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.5);
}
.omni-row {
  display: flex; align-items: center; gap: 9px; width: 100%; text-align: left;
  background: none; border: 0; border-bottom: 1px solid var(--rule);
  padding: 8px 12px; cursor: pointer; color: var(--ink); font-family: var(--body);
}
.omni-row:last-child { border-bottom: 0; }
.omni-row:hover, .omni-row.is-active { background: var(--row); }
.omni-row /* Not yet requested: keep the box, hide the alt text. */
img[data-src]:not([src]) { visibility: hidden; }

.thumb { width: 26px; height: 26px; }
.omni-name { flex: 1; font-size: 13.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.omni-kind {
  font-family: var(--cond); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--dim); border: 1px solid var(--rule); padding: 2px 5px;
}
.omni-empty { padding: 14px 12px; color: var(--dim); font-size: 13px; margin: 0; }

/* ---------- section titles ---------- */

.section-title {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  padding: 16px 18px 8px;
}
.st-label {
  font-family: var(--cond); font-size: 12px; font-weight: 700; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--ink);
}
.st-hint { font-family: var(--mono); font-size: 11.5px; color: var(--dim); }

thead th.nosort { cursor: default; }

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

.wrap { overflow-x: auto; overscroll-behavior-x: contain; }
/* Space consecutive tables so one never reads as a continuation of the last. */
.wrap + .note, table + .note { margin-top: 4px; }

table { border-collapse: collapse; width: 100%; min-width: 720px; }

/* Not sticky. `.wrap` scrolls horizontally, which makes it the scroll
   container for BOTH axes, so a sticky header pins against the page instead
   and paints over the rows above it. A header that scrolls away beats one
   that covers data. */
thead th {
  background: var(--panel); border-bottom: 1px solid var(--rule);
  border-top: 1px solid var(--rule);
  font-family: var(--body); font-weight: 700; font-size: 11.5px;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--mute);
  padding: 9px 12px; text-align: right; white-space: nowrap; cursor: pointer;
  user-select: none;
}
thead th:first-child, thead th.left { text-align: left; }
thead th:hover { color: var(--ink); }
thead th[data-dir]::after { content: " ▾"; color: var(--gold); }
thead th[data-dir="asc"]::after { content: " ▴"; color: var(--gold); }

/* Outfit sets larger on the body than Barlow did at the same px, so the sizes
   come down a notch to hold the row height. Density is the aesthetic; a
   friendlier typeface is not worth losing four rows a screen for. */
tbody td {
  border-bottom: 1px solid rgba(255, 255, 255, 0.035); padding: 6px 12px;
  line-height: 1.35; text-align: right; font-family: var(--mono); font-size: 12.5px;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
tbody td:first-child, tbody td.left { text-align: left; font-family: var(--body); font-size: 13.5px; }
tbody tr:hover td { background: var(--panel); }
tbody tr.thin td { color: var(--dim); }
tbody tr.thin td:first-child { color: var(--dim); }

.rank { color: var(--dim); font-family: var(--mono); font-size: 11px; width: 1%; }

/* Type glyphs sit inline with the name, never on their own line. */
.types { display: inline-flex; gap: 3px; vertical-align: -4px; margin-right: 7px; }
.types img { width: 17px; height: 17px; display: block; }

.name { font-weight: 500; }
.sub { color: var(--dim); font-size: 11px; font-family: var(--mono); margin-left: 7px; }

/* Win rate is the only coloured figure. */
.wr { font-weight: 600; }
.wr.hi { color: var(--good); }
.wr.lo { color: var(--bad); }

/* ---- hierarchy ----
   Seven columns of equal weight is seven columns nobody reads. One column is
   the answer, two or three support it, and the rest are context. */

/* The spanning header row that turns three adjacent win rates into one
   measurement taken three ways. */
thead tr.group-row th {
  border-bottom: 0; padding: 9px 12px 2px; font-size: 10px; font-weight: 700;
  letter-spacing: 0.16em; color: var(--dim); text-align: center;
  cursor: default; background: var(--panel);
}
thead tr.group-row th.group-blank { border-top-color: transparent; }
thead tr.group-row th:not(.group-blank) {
  border-left: 1px solid var(--rule); border-right: 1px solid var(--rule);
}
thead tr.group-row + tr th { border-top: 0; padding-top: 4px; }

thead th.support { color: var(--dim); font-size: 10.5px; }
thead th.primary { color: var(--ink); }

/* Supporting figures step back so the ranked one can step forward. */
tbody td.support { color: var(--dim); font-size: 11.5px; }

/* The ranked figure: the raw rate, with the bound the sort actually uses
   underneath it. That relationship was correct and completely invisible. */
.wr-primary { padding-top: 4px; padding-bottom: 4px; }
.wr-primary b {
  display: block; font-size: 13.5px; font-weight: 600; line-height: 1.15;
  font-variant-numeric: tabular-nums; color: var(--mute);
}
.wr-primary b.hi { color: var(--good); }
.wr-primary b.lo { color: var(--bad); }
.wr-bound {
  display: block; font-size: 9.5px; color: var(--dim); line-height: 1.1;
  font-variant-numeric: tabular-nums;
}

/* ---- hover that surfaces detail ----
   Row hover used to do nothing but tint. These lines are rendered into the
   cell and reserved for at all times, so revealing them costs no reflow and
   the row never jumps under the cursor. */

.cell-detail {
  display: block; font-size: 9.5px; line-height: 1.1; color: var(--dim);
  font-variant-numeric: tabular-nums;
  opacity: 0; transition: opacity 110ms linear;
}
tbody tr:hover .cell-detail, tbody tr:focus-within .cell-detail { opacity: 1; }

.wr-side { padding-top: 4px; padding-bottom: 4px; }
.wr-side b {
  display: block; font-weight: 600; line-height: 1.15;
  font-variant-numeric: tabular-nums; color: var(--mute);
}
.wr-side b.hi { color: var(--good); }
.wr-side b.lo { color: var(--bad); }

/* Hovering a row lifts the ranked figure out of the page slightly, so the eye
   lands on the column the table is actually sorted by. */
tbody tr:hover .wr-primary b { color: var(--ink); }
tbody tr:hover .wr-primary b.hi { color: var(--good); }
tbody tr:hover .wr-primary b.lo { color: var(--bad); }
tbody tr:hover .conf-fill { opacity: 1; }

/* Sample size drawn as confidence. A count makes the reader do the statistics;
   the bar is the interval width, inverted, so long means pinned down. */
.conf { padding-top: 4px; padding-bottom: 4px; }
.conf-box { display: inline-grid; justify-items: end; gap: 1px; min-width: 62px; }
.conf-box b {
  font-size: 12.5px; font-weight: 500; font-variant-numeric: tabular-nums;
  line-height: 1.15; color: var(--ink);
}
.conf-pm {
  font-size: 9.5px; color: var(--dim); line-height: 1.1;
  transition: opacity 110ms linear;
}
/* The ± and the raw split share one slot, so revealing the split costs no
   height and the confidence bar below it never moves. */
.conf-swap { display: grid; }
.conf-swap > * { grid-area: 1 / 1; }
tbody tr:hover .conf-pm { opacity: 0; }
.conf-track {
  width: 100%; height: 2px; background: var(--rule); display: block; margin-top: 2px;
}
.conf-fill { display: block; height: 100%; background: var(--mute); opacity: 0.85; }
tbody tr.thin .conf-box b { color: var(--dim); }

/* ---- info marker ----
   One glyph where a rule changes how a figure should be read. The account
   itself is on #/method; this is the reminder, not the lecture. */

.info {
  display: inline-grid; place-items: center; width: 14px; height: 14px;
  margin-left: 6px; flex-shrink: 0; vertical-align: 1px;
  border: 1px solid var(--rule); border-radius: 50%;
  font-family: var(--mono); font-size: 9px; font-style: italic;
  color: var(--dim); text-decoration: none; cursor: help; line-height: 1;
  background: transparent; padding: 0;
}
.info:hover, .info:focus-visible { color: var(--gold); border-color: var(--gold); }
thead th .info { vertical-align: 0; }

.method-dialog {
  /* A modal <dialog> is centred by the UA stylesheet's `margin: auto`, which
     the `* { margin: 0 }` reset at the top of this file silently removes —
     leaving it pinned to the top-left. Restoring it here is the whole fix. */
  margin: auto;
  width: min(600px, calc(100vw - 28px)); max-height: min(78vh, 720px);
  padding: 0; border: 1px solid var(--gold); border-radius: var(--r);
  background: var(--panel); color: var(--ink);
  box-shadow: 0 24px 80px rgba(0,0,0,.65);
}
.method-dialog::backdrop { background: rgba(4,6,10,.78); }
.method-dialog-head {
  display: flex; justify-content: space-between; align-items: center;
  padding: 14px 18px; border-bottom: 1px solid var(--rule);
}
.method-dialog-head h2 {
  font: 700 20px/1.2 var(--cond); text-transform: uppercase; letter-spacing: .05em;
}
.method-dialog-close {
  background: transparent; border: 1px solid var(--rule); color: var(--mute);
  padding: 6px 10px; cursor: pointer; font: 11px var(--mono);
}
.method-dialog-close:hover, .method-dialog-close:focus-visible {
  border-color: var(--gold); color: var(--gold);
}
.method-dialog-body { overflow: auto; max-height: calc(min(78vh, 720px) - 58px); }
.method-dialog-context {
  padding: 18px; font: 13px/1.65 var(--body); border-bottom: 1px solid var(--rule);
}
.method-dialog-full summary {
  padding: 13px 18px; cursor: pointer; color: var(--gold);
  font: 700 12px var(--cond); letter-spacing: .08em; text-transform: uppercase;
}
.method-dialog-sections { border-top: 1px solid var(--rule); }
.method-dialog-section { padding: 16px 18px; border-bottom: 1px solid var(--rule); }
.method-dialog-section h3 {
  color: var(--gold); font: 700 13px var(--cond); text-transform: uppercase;
  letter-spacing: .1em; margin-bottom: 14px;
}
.method-dialog-section h4 { font: 600 13px var(--body); margin: 12px 0 3px; }
.method-dialog-section p { color: var(--mute); font: 11.5px/1.65 var(--mono); }

/* A hairline bar behind pick rate, so scale reads without a chart. */
.bar { position: relative; }
.bar::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0;
  width: var(--w, 0%); background: var(--rule);
}
.bar span { position: relative; }

/* ---------- matchup grid ---------- */

.grid { border-collapse: collapse; font-family: var(--mono); font-size: 10.5px; }
.grid th {
  position: static; background: var(--panel); color: var(--mute);
  font-family: var(--cond); font-size: 10px; letter-spacing: 0.08em;
  padding: 4px 5px; border: 1px solid var(--rule); text-transform: uppercase;
}
.grid th.rowhead { text-align: left; white-space: nowrap; position: sticky; left: 0; z-index: 10; }
.grid td {
  border: 1px solid var(--rule); padding: 4px 5px; text-align: center;
  font-variant-numeric: tabular-nums; min-width: 42px;
}
.stat-primer {
  display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap;
  padding: 8px 18px; border-bottom: 1px solid var(--rule);
  color: var(--mute); font: 11px/1.5 var(--body);
}
.stat-primer b {
  color: var(--gold); font: 700 11px var(--cond);
  letter-spacing: 0.12em; text-transform: uppercase;
}
.matchup-explorer { border-bottom: 1px solid var(--rule); }
.matchup-head {
  display: flex; align-items: end; justify-content: space-between; gap: 18px;
  padding: 18px; flex-wrap: wrap; border-bottom: 1px solid var(--rule);
}
.matchup-head h2 { font: 700 24px var(--cond); text-transform: uppercase; letter-spacing: 0.04em; }
.matchup-head p { color: var(--mute); font-size: 12px; margin-top: 4px; }
.matchup-choose { display: grid; gap: 5px; min-width: min(300px, 100%); }
.matchup-choose span { color: var(--dim); font: 700 10px var(--cond); text-transform: uppercase; letter-spacing: 0.12em; }
.matchup-choose select {
  width: 100%; min-height: 38px; padding: 7px 10px; background: var(--panel);
  color: var(--ink); border: 1px solid var(--rule); border-radius: var(--r);
  font: 13px var(--body);
}
.matchup-summary { display: flex; gap: 12px; align-items: baseline; flex-wrap: wrap;
  padding: 10px 18px; border-bottom: 1px solid var(--rule); }
.matchup-summary b { color: var(--ink); font-weight: 600; }
.matchup-summary span { color: var(--dim); font: 10.5px var(--mono); }
.matchup-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1px; background: var(--rule); }
.matchup-list section { background: var(--bg); min-width: 0; }
.matchup-list h3, .matchup-balls h4 { padding: 9px 18px; color: var(--dim);
  font: 700 11px var(--cond); letter-spacing: 0.12em; text-transform: uppercase; }
.matchup-result {
  width: 100%; display: grid; grid-template-columns: minmax(0, 1fr) auto auto;
  gap: 12px; align-items: center; text-align: left; padding: 8px 18px;
  color: var(--ink); background: var(--bg); border: 0; border-top: 1px solid var(--rule);
  font: 12.5px var(--body); cursor: pointer;
}
.matchup-result:hover, .matchup-result:focus-visible { background: var(--panel); outline: none; }
.matchup-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.matchup-result b { font: 600 12px var(--mono); }
.matchup-games { color: var(--dim); font: 10px var(--mono); min-width: 86px; text-align: right; }
.matchup-pair { border-top: 1px solid var(--rule); }
.matchup-pair-head { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; padding: 13px 18px 4px; }
.matchup-pair-head h3 { font: 700 17px var(--cond); text-transform: uppercase; }
.matchup-pair-head span, .matchup-pair-note, .matchup-none { color: var(--dim); font: 10.5px/1.5 var(--mono); }
.matchup-pair-note { padding: 0 18px 10px; }
.matchup-none { padding: 12px 18px; }
.matchup-balls { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1px; background: var(--rule); }
.matchup-balls section { background: var(--bg); min-width: 0; }
.matchup-balls a { display: flex; gap: 9px; align-items: center; padding: 5px 18px;
  border-top: 1px solid var(--rule); color: var(--ink); font-size: 12px; }
.matchup-balls a:hover { background: var(--panel); }
.matchup-balls .thumb { width: 26px; height: 26px; }
.matchup-balls a span { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.matchup-balls a i { color: var(--dim); font: normal 10px var(--mono); }
.matchup-full summary { padding: 12px 18px; color: var(--mute); cursor: pointer;
  font: 700 11px var(--cond); letter-spacing: 0.12em; text-transform: uppercase; }
.matchup-full summary:hover { color: var(--ink); }
@media (max-width: 640px) {
  .matchup-list, .matchup-balls { grid-template-columns: minmax(0, 1fr); }
  .matchup-result { gap: 7px; }
  .matchup-games { min-width: 64px; }
}

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

.player-head {
  display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap;
  padding: 18px; border-bottom: 1px solid var(--rule); background: var(--panel);
}
.player-head h1 { font-family: var(--cond); font-size: 26px; letter-spacing: 0.04em;
  text-transform: uppercase; font-weight: 700; }
.player-head .meta { font-family: var(--mono); font-size: 12px; color: var(--mute); }

.form { display: flex; gap: 3px; padding: 14px 18px; flex-wrap: wrap; }
.form i {
  width: 20px; height: 20px; display: grid; place-items: center;
  font-family: var(--mono); font-size: 10px; font-style: normal;
  border: 1px solid var(--rule); color: var(--dim);
}
.form i.w { color: var(--good); border-color: var(--good); }
.form i.l { color: var(--bad); border-color: var(--bad); }

/* ---------- chrome ---------- */

.note {
  padding: 10px 18px; font-size: 12px; color: var(--dim);
  border-bottom: 1px solid var(--rule); font-family: var(--mono);
}
.empty { padding: 40px 18px; color: var(--mute); font-family: var(--mono); font-size: 13px; }

/* ---------- footer ---------- */

footer {
  border-top: 1px solid var(--rule); margin-top: 48px; padding: 16px 18px 22px;
  color: var(--dim); font-size: 11.5px; font-family: var(--mono); line-height: 1.7;
}
.foot-by { color: var(--mute); }
.foot-meta { margin-top: 4px; }
footer a { color: var(--mute); text-decoration: underline; text-underline-offset: 2px; }
footer a:hover { color: var(--gold); }


/* Preview notice. Removed when ingestion moves to the official API. */
.preview {
  background: #06191E; border-bottom: 1px solid var(--rule);
  color: var(--gold); font-family: var(--mono); font-size: 11.5px;
  padding: 7px 18px; letter-spacing: 0.01em;
}
.preview a { color: var(--gold); text-decoration: underline; text-underline-offset: 2px; }

/* ---------- attribute chips ---------- */

.chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 6px 2px 3px; background: color-mix(in srgb, var(--c, #555) 26%, #000);
  border: 1px solid color-mix(in srgb, var(--c, #555) 55%, #000);
  font-family: var(--body); font-size: 10.5px; font-weight: 600;
  letter-spacing: 0.04em; text-transform: uppercase; color: #fff;
  white-space: nowrap; line-height: 1.2;
}
.chip img { width: 15px; height: 15px; display: block; }
.chips { display: inline-flex; gap: 4px; vertical-align: -3px; }

/* ---------- art in tables ---------- */

.thumb {
  width: 34px; height: 34px; object-fit: contain; display: block; flex-shrink: 0;
  background: #0A0E0F; border: 1px solid var(--rule);
}
.cellflex { display: flex; align-items: center; gap: 10px; min-width: 0; }
.cellflex .name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
tbody tr { transition: background 90ms linear; }
tbody td:first-child { padding-left: 12px; }

/* ---------- landing ---------- */

.hero { position: relative; overflow: hidden; border-bottom: 1px solid var(--rule); }
.hero-art {
  position: absolute; inset: 0; display: flex; align-items: center; gap: 34px;
  opacity: 0.17; pointer-events: none; will-change: transform;
  animation: drift 64s linear infinite;
}
.hero-art img { width: 88px; height: 88px; object-fit: contain; flex-shrink: 0; }
@keyframes drift { from { transform: translateX(0); } to { transform: translateX(-50%); } }

.hero-inner { position: relative; padding: 52px 24px 44px; max-width: 1080px; }
.hero h1 {
  font-family: var(--cond); font-weight: 700; text-transform: uppercase;
  font-size: clamp(38px, 8vw, 76px); line-height: 0.92; letter-spacing: 0.01em;
  color: #EAF2F3;
}
.hero h1 b { color: var(--gold); }
.hero-sub {
  font-family: var(--cond); font-size: clamp(15px, 2.4vw, 20px); font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--mute);
  margin-top: 14px; max-width: 44ch; line-height: 1.4;
}

/* top-of-meta strips */
.strips { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(270px, 100%), 1fr)); }
.strip { border-right: 1px solid var(--rule); border-bottom: 1px solid var(--rule); }
.strip h2 {
  font-family: var(--cond); font-size: 11px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--dim); padding: 12px 16px;
  border-bottom: 1px solid var(--rule); background: var(--panel);
}
.home-context { padding: 9px 16px; border-bottom: 1px solid var(--rule);
  color: var(--mute); font: 10.5px/1.45 var(--mono); }
.strip ol { list-style: none; }
.strip li {
  display: flex; align-items: center; gap: 10px; padding: 8px 16px;
  border-bottom: 1px solid var(--rule); font-size: 13px;
}
.strip li:last-child { border-bottom: 0; }
.strip li:hover { background: var(--panel); }
.strip .pos { font-family: var(--mono); font-size: 11px; color: var(--dim); width: 14px; }
.strip .who { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.strip .val { font-family: var(--mono); font-size: 12.5px; font-weight: 600; }

/* entrances, once, from a visible resting state */
.rise { animation: rise 420ms cubic-bezier(.22,.9,.3,1) both; }
@keyframes rise { from { opacity: 0; transform: translateY(9px); } to { opacity: 1; transform: none; } }

/* Switching sub-tab, league or route used to blink straight to new content,
   which reads as a page reload rather than as the same table re-filtered.
   Short and shallow on purpose: long enough to say "this changed", not long
   enough to be in the way of someone clicking through four leagues. */
#view.is-swapping { animation: swap 170ms ease-out both; }
@keyframes swap {
  from { opacity: 0.25; transform: translateY(3px); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .hero-art { animation: none; }
  .rise { animation: none; }
  tbody tr { transition: none; }
  .tl-item, .tl-dist-bar, .tl-pos::after { transition: none; }
  .tl-item:hover, .tl-item:focus-visible { transform: none; }
  .cell-detail, .conf-pm { transition: none; }
  #view.is-swapping { animation: none; }
}

/* ---------- tier list ---------- */

.tl-note {
  padding: 12px 18px; font-family: var(--mono); font-size: 11.5px; color: var(--dim);
  border-bottom: 1px solid var(--rule); line-height: 1.7; max-width: 96ch;
}

/* The distribution the bands are cut from. Band zones sit behind the bars so
   the letters read as slices of one curve rather than as a verdict. */
.tl-dist { padding: 16px 18px 10px; border-bottom: 1px solid var(--rule); }
.tl-dist-plot {
  position: relative; height: 84px; background: var(--row);
  border: 1px solid var(--rule); overflow: hidden;
}
.tl-zone { position: absolute; top: 0; bottom: 0; opacity: 0.16; }
.tl-zone[data-band="S"] { background: #E0574B; }
.tl-zone[data-band="A"] { background: #E08B3E; }
.tl-zone[data-band="B"] { background: #D5B63F; }
.tl-zone[data-band="C"] { background: #6FA86B; }
.tl-zone[data-band="D"] { background: #4C89A8; }
.tl-zone[data-band="F"] { background: #6B6F78; }
.tl-zone-tag {
  position: absolute; top: 3px; left: 4px; font-family: var(--cond);
  font-size: 10px; font-weight: 700; letter-spacing: 0.1em; color: #fff;
  opacity: 0.85;
}
.tl-dist-bars {
  position: absolute; inset: 0; display: flex; align-items: flex-end; gap: 1px;
  padding: 0 1px;
}
.tl-dist-bar {
  flex: 1; background: var(--ink); opacity: 0.55; min-height: 1px;
  transition: opacity 110ms linear;
}
.tl-dist-bar:hover { opacity: 1; }
/* The mean: every z-score on the page is measured from this line. */
.tl-mean {
  position: absolute; top: 0; bottom: 0; width: 1px; background: var(--ink);
  opacity: 0.8;
}
.tl-mean::after {
  content: ""; position: absolute; top: 0; left: -3px;
  border-left: 3px solid transparent; border-right: 3px solid transparent;
  border-top: 4px solid var(--ink);
}
.tl-dist-axis {
  display: flex; justify-content: space-between; gap: 10px; padding-top: 5px;
  font-family: var(--mono); font-size: 10.5px; color: var(--dim);
}
.tl-axis-mid { color: var(--mute); }

/* ---- bands ---- */

.tier { display: grid; grid-template-columns: 86px 1fr; border-bottom: 1px solid var(--rule); }
.tier-label {
  display: grid; align-content: center; justify-items: center; gap: 1px;
  padding: 8px 4px; color: #0B0F10; border-right: 1px solid var(--rule);
}
.tier-label b {
  font-family: var(--cond); font-weight: 700; font-size: 30px;
  letter-spacing: 0.04em; line-height: 1;
}
/* The interval, in the units a reader thinks in. This is the difference
   between "S beats A" and knowing by how much. */
.tier-label .tier-range {
  font-family: var(--mono); font-size: 10px; font-weight: 600;
  opacity: 0.72; white-space: nowrap;
}
.tier-label .tier-count {
  font-family: var(--cond); font-size: 9.5px; letter-spacing: 0.1em;
  opacity: 0.55;
}
.tier[data-band="S"] .tier-label { background: #E0574B; }
.tier[data-band="A"] .tier-label { background: #E08B3E; }
.tier[data-band="B"] .tier-label { background: #D5B63F; }
.tier[data-band="C"] .tier-label { background: #6FA86B; }
.tier[data-band="D"] .tier-label { background: #4C89A8; }
.tier[data-band="F"] .tier-label { background: #6B6F78; }
/* Carry the tier colour in the letter and a narrow edge, leaving the entries
   and their rates as the page's visual centre. */
.tier[data-band] .tier-label { background: var(--panel); border-left: 4px solid var(--band-color); }
.tier-label { color: var(--band-color); }
.tier[data-band="S"] { --band-color: #E0574B; }
.tier[data-band="A"] { --band-color: #E08B3E; }
.tier[data-band="B"] { --band-color: #D5B63F; }
.tier[data-band="C"] { --band-color: #6FA86B; }
.tier[data-band="D"] { --band-color: #4C89A8; }
.tier[data-band="F"] { --band-color: #9299A5; }
.tl-guide { display: flex; gap: 14px; flex-wrap: wrap; padding: 8px 18px;
  border-bottom: 1px solid var(--rule); color: var(--mute); font: 10.5px/1.5 var(--body); }
.tl-guide b { color: var(--ink); font-weight: 600; }

.tier-row { display: flex; flex-wrap: wrap; gap: 8px; padding: 10px; align-items: flex-start; }

.tl-item {
  position: relative; display: flex; align-items: center; gap: 8px;
  padding: 5px 10px 7px 5px; background: var(--panel);
  border: 1px solid var(--rule); cursor: default;
  transition: border-color 110ms, background 110ms, transform 110ms;
}
.tl-item.is-link { cursor: pointer; }
.tl-item:hover, .tl-item:focus-visible {
  border-color: var(--gold); background: var(--row); transform: translateY(-1px);
  outline: none;
}
.tl-item img { width: 30px; height: 30px; object-fit: contain; display: block; }
.tl-text { display: grid; gap: 1px; min-width: 0; }
.tl-item .nm { font-size: 12.5px; font-weight: 500; white-space: nowrap; line-height: 1.2; }
.tl-figs {
  display: flex; align-items: baseline; gap: 6px;
  font-family: var(--mono); font-variant-numeric: tabular-nums;
}
.tl-figs b { font-size: 11px; font-weight: 600; color: var(--mute); }
.tl-figs i { font-size: 9.5px; font-style: normal; color: var(--dim); }
.tl-item .chips { margin-left: 1px; }
.tl-item .chips { opacity: 0.68; }
.tl-item:hover .chips, .tl-item:focus-visible .chips { opacity: 1; }
.tl-item .nm { font-weight: 600; }
.tl-figs i { opacity: 0.8; }

/* Where this entry sits between its band's floor and ceiling. Two chips in the
   same row can be nearly a band apart, and nothing else on the page says so. */
.tl-pos {
  position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: var(--rule);
}
.tl-pos::after {
  content: ""; position: absolute; top: 0; bottom: 0; left: 0;
  width: var(--p, 0%); background: var(--gold); opacity: 0.55;
}
.tl-item:hover .tl-pos::after, .tl-item:focus-visible .tl-pos::after { opacity: 1; }

/* ---- hover detail ---- */

.tl-card {
  position: absolute; z-index: 80; width: 260px; padding: 10px 12px 11px;
  background: var(--panel); border: 1px solid var(--gold);
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.55); pointer-events: none;
}
.tl-card-head { display: flex; align-items: baseline; gap: 8px; }
.tl-card-band {
  font-family: var(--cond); font-weight: 700; font-size: 13px;
  letter-spacing: 0.1em; color: var(--gold);
}
.tl-card-name { font-size: 13.5px; font-weight: 500; }
.tl-card .chips { margin-top: 6px; }
.tl-card-grid { display: grid; gap: 3px; margin-top: 9px; }
.tl-card-row {
  display: grid; grid-template-columns: 1fr auto auto; gap: 8px; align-items: baseline;
  padding: 3px 0; border-top: 1px solid var(--rule);
}
/* The side the placement came from, marked so the card does not read as two
   numbers of equal standing. */
.tl-card-row.is-rated .k { color: var(--ink); }
.tl-card-row.is-rated .k::after {
  content: " ← rated"; font-family: var(--cond); font-size: 9px;
  letter-spacing: 0.1em; color: var(--gold);
}
.tl-card-row .k {
  font-family: var(--cond); font-size: 10.5px; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--dim);
}
.tl-card-row .v {
  font-family: var(--mono); font-size: 12px; font-weight: 600;
  font-variant-numeric: tabular-nums; color: var(--mute);
}
.tl-card-row .v.hi { color: var(--good); }
.tl-card-row .v.lo { color: var(--bad); }
.tl-card-row .n { font-family: var(--mono); font-size: 10px; color: var(--dim); }
.tl-card-foot {
  display: flex; flex-wrap: wrap; gap: 4px 12px; margin-top: 9px; padding-top: 7px;
  border-top: 1px solid var(--rule);
  font-family: var(--mono); font-size: 10px; color: var(--dim);
}

@media (max-width: 640px) {
  .tier { grid-template-columns: 64px 1fr; }
  .tier-label b { font-size: 22px; }
  .tier-label .tier-range { font-size: 9px; }
  .tl-item .nm { font-size: 11.5px; }
  .tl-dist-plot { height: 64px; }
}

/* ---------- ball detail ---------- */

.ball-hero { display: flex; gap: 20px; align-items: center; padding: 22px 18px;
  border-bottom: 1px solid var(--rule); background: var(--panel); flex-wrap: wrap; }
.ball-hero > img { width: 96px; height: 96px; object-fit: contain; }
.ball-hero h1 { font-family: var(--cond); font-size: 34px; text-transform: uppercase;
  letter-spacing: 0.03em; font-weight: 700; line-height: 1; }
.ball-hero .rarity { font-family: var(--cond); font-size: 11px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--mute); }
.ball-stats { display: flex; gap: 26px; margin-top: 12px; flex-wrap: wrap; }
.ball-stats div b { display: block; font-family: var(--mono); font-size: 19px; }
.ball-stats div span { font-family: var(--cond); font-size: 10.5px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--dim); }

.orbs { display: inline-flex; gap: 2px; }
.orb { width: 19px; height: 16px; display: grid; place-items: center;
  font-family: var(--mono); font-size: 9.5px; border: 1px solid var(--rule); color: var(--dim); }
.orb.on { color: var(--bg); background: var(--gold); border-color: var(--gold); }

tbody tr.clickable { cursor: pointer; }
tbody tr.clickable:hover td:first-child { color: var(--gold); }
.backlink { color: var(--gold); font-family: var(--mono); font-size: 12px; }

/* Weekly ladder movement: division I promotes, division IV demotes. */
.move { font-size: 10px; }
.move.up { color: var(--good); }
.move.down { color: var(--bad); }

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

/* Both ladders side by side, the same size. Open and rarity are two standings,
   not a standing and a footnote — and each is now the game's own division
   emblem rather than three stacked lines of text. The strip is the same one
   the badges use, without its padding: the hero already has its own. */
.hero-badges { padding: 0; margin-top: 13px; gap: 9px; }
.hero-badges .badge { width: 180px; min-width: 0; box-sizing: border-box; }
.hero-badges .badge-text { width: 100%; overflow: hidden; }
.hero-badges .badge.is-peak { border-color: var(--good); }
.hero-badges .badge.is-peak .badge-kind { color: var(--good); }
.hero-badges .badge.is-peak:hover,
.hero-badges .badge.is-peak:focus-visible { border-color: var(--good); }

/* ---- alliance crest ----
   Shape, pattern and colours are drawn from stored primitives; the symbol
   itself is not published anywhere readable, so initials stand in. See
   lib/emblem.js. */

.alliance { display: inline-flex; align-items: center; gap: 9px; }
.crest { display: block; flex-shrink: 0; }
.alliance-name {
  font-family: var(--cond); font-size: 13px; font-weight: 600;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--mute);
}
.alliance.is-approximate .alliance-name {
  border-bottom: 1px dotted var(--dim); cursor: help;
}

/* The stat strip is shared with ball pages; only standalone uses need padding. */
.ball-stats.strip-pad {
  padding: 14px 18px; border-bottom: 1px solid var(--rule); margin-top: 0;
}

.note .dim { color: var(--mute); }
p.note.dim { color: var(--mute); }

a.plain { color: inherit; text-decoration: none; }
a.plain:hover { color: var(--gold); }

td .sub {
  font-family: var(--mono); font-size: 10.5px; color: var(--dim); margin-left: 6px;
}

/* Win or loss, then which side of the fight it was. */
.res {
  display: inline-grid; place-items: center; width: 18px; height: 18px;
  font-family: var(--mono); font-size: 10px; border: 1px solid var(--rule);
  color: var(--dim); margin-right: 7px;
}
.res.w { color: var(--good); border-color: var(--good); }
.res.l { color: var(--bad); border-color: var(--bad); }
.side { font-family: var(--cond); font-size: 10px; letter-spacing: 0.1em; color: var(--mute); }

.lineup { display: flex; gap: 2px; }
.lineup-ball {
  width: 26px; height: 26px; display: grid; place-items: center;
  border: 1px solid var(--rule);
}
.lineup-ball img { width: 22px; height: 22px; object-fit: contain; }

@media (max-width: 700px) {
  /* `.leagues { gap: 12px }` sat here unscoped, meant for the hero's league
     blocks. Those are gone, and it was never reaching them anyway — it was
     hitting the chrome strip's tier buttons, which butt together on purpose
     and grew gaps between their seams under 700px. */
  .lineup-ball { width: 22px; height: 22px; }
  .lineup-ball img { width: 18px; height: 18px; }
}

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

.player-hero { position: relative; overflow: hidden; }
.player-banner {
  position: absolute; inset: 0; pointer-events: none; z-index: 0;
}
.player-banner img {
  width: 100%; height: 100%; object-fit: cover; object-position: center 32%;
  opacity: 0.22; filter: saturate(0.85);
}
/* Keep the banner from washing out the text sitting on it. */
.player-banner::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, var(--panel) 0%, rgba(17,23,26,0.72) 45%, rgba(17,23,26,0.35) 100%);
}
.player-hero > *:not(.player-banner) { position: relative; z-index: 1; }
.player-hero > img {
  border: 1px solid var(--rule); background: #0A0E0F;
}

.owner-badge {
  display: inline-block; font-family: var(--mono); font-size: 10.5px; font-weight: 600;
  padding: 2px 6px; border: 1px solid var(--rule); color: var(--mute);
}
.owner-badge.silver { color: var(--ink); border-color: var(--mute); }
.owner-badge.gold {
  color: var(--bg); background: var(--gold); border-color: var(--gold); font-weight: 700;
}

@media (max-width: 900px) {
  .omni { margin-left: 0; border-left: 0; width: 100%; border-top: 1px solid var(--rule); }
  .omni input { width: 100%; }
  .omni-results { left: 0; right: 0; min-width: 0; }
  .top { flex-wrap: wrap; }
}

/* ---------- thin-tier warning ----------
   A tier can be published off a few hundred battles and look exactly as
   authoritative as one built on twelve thousand. This is the site saying so
   before the reader acts on it, rather than in a footnote afterwards. */

.depth-warn {
  display: flex; gap: 9px; flex-wrap: wrap; align-items: center;
  padding: 9px 18px; border-bottom: 1px solid var(--rule);
  background: #1A1408; border-left: 2px solid #C8933C;
  font-family: var(--mono); font-size: 11.5px; line-height: 1.6; color: var(--mute);
}
.depth-warn b {
  font-family: var(--cond); font-size: 11px; letter-spacing: 0.12em;
  text-transform: uppercase; color: #C8933C; font-weight: 700;
}
.depth-warn.is-thin { background: #1C0F0D; border-left-color: var(--bad); }
.depth-warn.is-thin b { color: var(--bad); }

/* An account the ladder has never listed. Shown, because it was in the battle,
   but visibly not somewhere you can go. */
.unknown-player { color: var(--dim); font-style: italic; cursor: help; }

/* ---------- tier list: distribution disclosure ---------- */

.tl-dist-wrap { border-bottom: 1px solid var(--rule); }
.tl-dist-summary {
  font-family: var(--cond); font-size: 11px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--dim); cursor: pointer;
  padding: 10px 18px; list-style: none; user-select: none;
}
.tl-dist-summary::-webkit-details-marker { display: none; }
.tl-dist-summary::before { content: "+ "; color: var(--gold); }
.tl-dist-wrap[open] .tl-dist-summary::before { content: "− "; }
.tl-dist-summary:hover { color: var(--mute); }
.tl-dist { padding: 2px 18px 14px; border-bottom: 0; }
.tl-dist-how {
  font-family: var(--mono); font-size: 11px; color: var(--dim);
  line-height: 1.7; max-width: 82ch; margin-bottom: 12px;
}

/* ---------- tier list: the drill-down drawer ----------
   A tier list says what is strong and immediately raises "on what, and for
   whom". The drawer answers in place rather than sending the reader away. */

.tl-drawer {
  grid-column: 1 / -1; border-top: 1px solid var(--rule);
  background: var(--bg);
}
.tl-drawer-head {
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  padding: 11px 14px; border-bottom: 1px solid var(--rule);
}
.tl-drawer-head b {
  font-family: var(--cond); font-size: 14px; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--gold);
}
.tl-drawer-head span {
  font-family: var(--mono); font-size: 11.5px; color: var(--dim); flex: 1;
}
.tl-drawer-close {
  font-family: var(--cond); font-size: 11px; letter-spacing: 0.1em;
  text-transform: uppercase; background: none; color: var(--mute);
  border: 1px solid var(--rule); border-radius: var(--r);
  padding: 4px 10px; cursor: pointer;
}
.tl-drawer-close:hover { color: var(--ink); border-color: var(--mute); }
.tl-drawer-load {
  padding: 16px 14px; font-family: var(--mono); font-size: 11.5px; color: var(--dim);
}
.tl-drawer-table { min-width: 560px; }
.tl-drawer .wrap { padding-bottom: 2px; }

/* The open entry stays marked while its drawer is below. */
.tl-item.is-open {
  border-color: var(--gold); background: var(--row);
  box-shadow: inset 0 -2px 0 var(--gold);
}

/* "High elo" is a scope across three divisions, not one of them. A hairline
   on its right edge groups it with All rather than with the divisions. */
.leagues button.is-scope { border-right: 1px solid var(--rule); }
.leagues button.is-scope[aria-pressed="true"] { border-right-color: var(--gold); }

/* ---------- profile panes ----------
   A profile answers nine questions, and it used to stack nine full-width
   tables to do it — a two-row "by league" carrying the same weight as a
   five-row head-to-head, and paired opposites sitting one above the other
   instead of side by side.

   The grid separates them with the same 1px rule the tables use, showing the
   page ground through the gaps, so panes read as divided rather than as
   cards. */

/* Exactly two columns, not auto-fit.
   The panes come in pairs — beats against loses to, wins into against loses
   into — and at three columns the flow puts each pair on a diagonal, which is
   the one arrangement that destroys the comparison they exist to make. */
.pgrid {
  display: grid; gap: 1px; background: var(--rule);
  grid-template-columns: repeat(2, minmax(0, 1fr));
  border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule);
  margin-top: 16px;
}
@media (max-width: 720px) { .pgrid { grid-template-columns: minmax(0, 1fr); } }
.pane { background: var(--bg); min-width: 0; padding-bottom: 10px; }
.pane.is-wide { grid-column: 1 / -1; }

.pane-head {
  display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap;
  padding: 12px 16px 9px;
}
.pane-head h3 {
  font-family: var(--cond); font-size: 12px; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink);
}
.pane-head span {
  font-family: var(--mono); font-size: 10.5px; color: var(--dim);
}
.pane-sub {
  font-family: var(--cond); font-size: 10px; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--dim);
  padding: 8px 16px 4px;
}
.pane-body > .pane-sub:first-child { padding-top: 0; }

/* The stat strip sits flush inside a pane rather than carrying its own rule. */
.pane .ball-stats.strip-pad { border-bottom: 0; padding: 4px 16px 8px; gap: 20px; }

/* ---- compact rows ----
   A six-column table is unreadable at half width, so the two supporting rates
   move to the row's title. Same data, legible column count. */

.mini { display: grid; }
.mini-row {
  display: grid; grid-template-columns: 16px 1fr auto auto;
  align-items: baseline; gap: 10px;
  padding: 5px 16px; width: 100%; text-align: left;
  background: none; border: 0; border-top: 1px solid rgba(255, 255, 255, 0.035);
  color: var(--ink); font-family: var(--body); font-size: 13px;
}
.mini-row:first-child { border-top: 0; }
button.mini-row { cursor: pointer; }
.mini-row:hover { background: var(--panel); }
.mini-pos { font-family: var(--mono); font-size: 10.5px; color: var(--dim); }
.mini-who { min-width: 0; display: flex; align-items: baseline; gap: 7px; }
.mini-who b {
  font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mini-who i {
  font-style: normal; font-family: var(--mono); font-size: 10px; color: var(--dim);
  white-space: nowrap;
}
.mini-n {
  font-family: var(--mono); font-size: 11px; color: var(--dim);
  font-variant-numeric: tabular-nums;
}
.mini-wr {
  font-family: var(--mono); font-size: 12.5px; font-weight: 600; color: var(--mute);
  font-variant-numeric: tabular-nums; min-width: 48px; text-align: right;
}
.mini-wr.hi { color: var(--good); }
.mini-wr.lo { color: var(--bad); }

/* ---- account facts ---- */

.facts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(160px, 100%), 1fr));
  gap: 10px 22px; padding: 4px 16px 6px;
}
.facts dt {
  font-family: var(--cond); font-size: 10px; letter-spacing: 0.13em;
  text-transform: uppercase; color: var(--dim);
}
.facts dd {
  font-family: var(--mono); font-size: 14px; color: var(--ink);
  font-variant-numeric: tabular-nums; margin-top: 1px;
}


/* The sample line carries the back link rather than the link owning a row. */
.note-sample { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.note-sample .backlink { flex-shrink: 0; }
.note-sample .note-body { color: var(--mute); }

/* Tables inside a pane are half-width, so they lose the 720px floor that the
   full-width stat tables need. */
.pane table { min-width: 0; }
.pane .wrap { overflow-x: auto; }

/* ---------- ladder switch ----------
   Open and Rarity are separate competitions, so the control that moves
   between them is filled rather than underlined — a different kind of choice
   from picking a tier within one. */

.ladders { display: flex; align-items: center; border-right: 1px solid var(--rule); }
.ladders button {
  font-family: var(--cond); font-weight: 700; font-size: 12.5px;
  letter-spacing: 0.08em; text-transform: uppercase;
  background: none; border: 0; color: var(--mute);
  padding: 9px 14px; cursor: pointer; border-left: 1px solid var(--rule);
}
.ladders button:hover { color: var(--ink); }
.ladders button[aria-pressed="true"] { color: var(--bg); background: var(--gold); }

/* ---------- badges ----------
   Both kinds existed and neither was findable: top-owner placings were a chip
   in the last column of a 150-row table on another tab, and peak rank was not
   shown at all. */

.badges {
  display: flex; flex-wrap: wrap; gap: 8px; padding: 4px 16px 10px;
}
.badge {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 12px 7px 8px; background: var(--panel);
  border: 1px solid var(--rule); border-radius: var(--r);
  text-align: left; font-family: var(--body); color: var(--ink);
  transition: border-color 110ms, background 110ms;
}
button.badge { cursor: pointer; }
button.badge:hover { border-color: var(--gold); background: var(--row); }
.badge .thumb { width: 30px; height: 30px; }
.badge-text { display: grid; gap: 1px; min-width: 0; }
.badge-kind {
  font-family: var(--cond); font-size: 9.5px; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--dim);
}
.badge b {
  font-size: 13px; font-weight: 600; line-height: 1.2;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.badge-note {
  font-family: var(--mono); font-size: 9.5px; color: var(--dim); line-height: 1.3;
}

/* ---- division badges ----
   The peak badge used to be a bordered box with a coloured rail down its left
   edge and three stacked grey lines: a shape that would look at home in any
   product, which is the test `DESIGN.md` sets for getting it wrong. The game
   draws its own emblem for each tier and publishes it, so the emblem carries
   the tier's identity and its colour, and the rail is gone. */

.badge.is-div {
  align-items: center; gap: 11px; padding: 8px 14px 8px 9px;
  cursor: default; text-align: left;
}
.badge.is-div b {
  font-family: var(--cond); font-size: 17px; letter-spacing: 0.06em;
  text-transform: uppercase; line-height: 1.1;
}

/* The art is ~400px square with wide transparent margins and an emblem that
   sits broader than it is tall, so the box is landscape and the image is
   contained in it rather than cropped to a square thumbnail. */
.div-crest {
  width: 46px; height: 38px; object-fit: contain; display: block;
  flex-shrink: 0;
}
.div-crest.is-blank { opacity: 0; }

/* One slot, two lines. The resting figure and the detail are stacked in the
   same grid area — the `.conf-swap` idiom from the stat tables — so revealing
   one costs no reflow and the strip never jumps under the cursor. */
.div-swap { display: grid; min-width: 0; }
.div-swap > * {
  grid-area: 1 / 1;
  font-family: var(--mono); font-size: 9.5px; color: var(--dim);
  line-height: 1.3; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
  transition: opacity 110ms linear;
}
.div-detail { opacity: 0; }
.badge.is-div:hover .div-rest,
.badge.is-div:focus-visible .div-rest,
.badge.is-div[aria-expanded="true"] .div-rest { opacity: 0; }
.badge.is-div:hover .div-detail,
.badge.is-div:focus-visible .div-detail,
.badge.is-div[aria-expanded="true"] .div-detail { opacity: 1; color: var(--mute); }

/* The peak date range may outgrow a uniform badge. Reveal its full length in
   place instead of enlarging the header or cutting the date off. */
.badge.is-peak .div-detail { text-overflow: clip; }
.badge.is-peak .div-detail-text { display: inline-block; white-space: nowrap; }
.badge.is-peak:hover .div-detail.is-overflowing .div-detail-text,
.badge.is-peak:focus-visible .div-detail.is-overflowing .div-detail-text,
.badge.is-peak[aria-expanded="true"] .div-detail.is-overflowing .div-detail-text {
  animation: peak-date-scroll var(--scroll-duration, 5s) ease-in-out infinite;
}
@keyframes peak-date-scroll {
  0%, 12% { transform: translateX(0); }
  70%, 88% { transform: translateX(calc(-1 * var(--scroll-distance, 0px))); }
  100% { transform: translateX(0); }
}
@media (prefers-reduced-motion: reduce) {
  .badge.is-peak .div-detail.is-overflowing { overflow-x: auto; }
  .badge.is-peak .div-detail.is-overflowing .div-detail-text { animation: none !important; }
}

.badge.is-div:hover, .badge.is-div:focus-visible {
  border-color: var(--rule); background: var(--row); outline: none;
}
/* A ladder that exists but has not been read. Shown rather than omitted, so
   an absent standing does not read as "plays only one league". */
.badge.is-div.is-muted b { color: var(--dim); }

@media (prefers-reduced-motion: reduce) { .div-swap > * { transition: none; } }

.badge.is-top { border-color: var(--mute); }
.badge.is-first { border-color: var(--gold); box-shadow: inset 0 0 0 1px rgba(53,198,224,0.25); }
.badge.is-first .badge-kind { color: var(--gold); }
/* Keep every placing visible while giving the profile room to breathe. */
.pane > .badges {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 6px; padding: 6px 12px 10px;
}
.pane > .badges .badge {
  width: 100%; min-width: 0; height: 54px; box-sizing: border-box;
  gap: 7px; padding: 5px 8px 5px 6px;
}
.pane > .badges .badge-text { width: 100%; overflow: hidden; }
.pane > .badges .badge .thumb { width: 24px; height: 24px; }
.pane > .badges .badge .thumb,
.pane > .badges .badge .div-crest { flex-shrink: 0; }
.pane > .badges .badge b { font-size: 11.5px; }
.pane > .badges .badge-kind, .pane > .badges .badge-note { font-size: 8.5px; }
.pane > .badges .badge.is-div { gap: 7px; padding: 5px 8px 5px 6px; }
.pane > .badges .badge.is-div .div-crest { width: 36px; height: 30px; }
.pane > .badges .badge.is-div b { font-size: 12.5px; }
.pane > .badges .badge-name { display: block; overflow: hidden; }
.pane > .badges .badge-name > span { display: inline-block; white-space: nowrap; }
.pane > .badges .badge-name.is-overflow { mask-image: linear-gradient(90deg, #000 88%, transparent); }
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .pane > .badges .badge:hover .badge-name.is-overflow > span {
    animation: badge-name-scroll 4s ease-in-out 250ms infinite alternate;
  }
}
@keyframes badge-name-scroll {
  0%, 14% { transform: translateX(0); }
  86%, 100% { transform: translateX(calc(-1 * var(--name-travel))); }
}
@media (max-width: 600px) {
  .pane > .badges { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.pane-note {
  font-family: var(--mono); font-size: 11px; color: var(--dim);
  padding: 0 16px 10px; line-height: 1.6; max-width: 70ch;
}

@media (prefers-reduced-motion: reduce) { .badge { transition: none; } }

/* Where one CP band ends and the next begins on a ball page. Everything inside
   a band is a CP tie, so its order comes from the tie-breakers; the rule makes
   that visible instead of leaving the sequence looking arbitrary. */
tbody tr.band-start td { border-top: 1px solid var(--rule); }


/* ---------- method page ----------
   Everything the pages used to say in place. One page, linked from the footer,
   so a reader who wants the reasoning can have all of it and a reader who
   wants the ranking is not made to read it first. */

.method-head { padding: 34px 18px 18px; border-bottom: 1px solid var(--rule); }
.method-head h1 {
  font-family: var(--cond); font-size: clamp(26px, 5vw, 38px); font-weight: 700;
  letter-spacing: 0.03em; text-transform: uppercase; color: #EAF2F3;
}
.method-head p {
  font-family: var(--mono); font-size: 11.5px; color: var(--dim); margin-top: 8px;
}

.method {
  display: grid; gap: 1px; background: var(--rule);
  grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr));
  border-bottom: 1px solid var(--rule);
}
.method-sec { background: var(--bg); padding: 18px; }
.method-sec h2 {
  font-family: var(--cond); font-size: 12px; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--gold);
  margin-bottom: 14px;
}
.method-sec dl { display: grid; gap: 14px; }
.method-sec dt {
  font-size: 13.5px; font-weight: 600; color: var(--ink); margin-bottom: 3px;
}
.method-sec dd {
  font-family: var(--mono); font-size: 11.5px; line-height: 1.75; color: var(--mute);
  max-width: 62ch;
}

/* ---------- typing → balls hover ----------
   At a small tier a typing is often one or two balls, so its win rate is
   really a statement about those balls. The card says which. */

.tcard { width: 300px; padding: 0; }
.tcard-head {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  padding: 9px 11px; border-bottom: 1px solid var(--rule);
}
.tcard-head b { font-size: 13px; font-weight: 600; }
.tcard-head span { font-family: var(--mono); font-size: 10px; color: var(--dim); }
.tcard-list { display: grid; max-height: 260px; overflow-y: auto; }
.tcard-row {
  display: grid; grid-template-columns: auto 1fr auto auto;
  align-items: center; gap: 8px; padding: 4px 11px;
  border-top: 1px solid rgba(255, 255, 255, 0.035);
}
.tcard-row:first-child { border-top: 0; }
.tcard-row .thumb { width: 22px; height: 22px; }
.tcard-name {
  font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tcard-n {
  font-family: var(--mono); font-size: 10px; color: var(--dim);
  font-variant-numeric: tabular-nums;
}
.tcard-wr {
  font-family: var(--mono); font-size: 11.5px; font-weight: 600; color: var(--mute);
  font-variant-numeric: tabular-nums; min-width: 44px; text-align: right;
}
.tcard-wr.hi { color: var(--good); }
.tcard-wr.lo { color: var(--bad); }
.tcard-load, .tcard-more {
  font-family: var(--mono); font-size: 10.5px; color: var(--dim); padding: 8px 11px;
}
/* A row that has something to show says so, faintly. */
tbody tr.has-detail td:nth-child(2) { position: relative; }
tbody tr.has-detail:hover td:nth-child(2)::after {
  content: "›"; position: absolute; right: 4px; top: 50%;
  transform: translateY(-50%); color: var(--gold); font-size: 13px;
}

/* ---------- profile groups ----------
   Account, PVP and Raids are three different questions about one person, so
   the page says so instead of running them together. */

.group-title {
  display: flex; align-items: center; gap: 4px;
  font-family: var(--cond); font-size: 13px; font-weight: 700;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--gold);
  padding: 22px 18px 2px;
  border-top: 1px solid var(--rule); margin-top: 8px;
}
.group-title:first-of-type { border-top: 0; margin-top: 0; }
/* The figure strips sit directly under their heading, not in a panel. */
.group-title + .ball-stats.strip-pad { border-bottom: 0; padding-top: 10px; }
.ball-stats.strip-pad + .ball-stats.strip-pad { padding-top: 0; }
.ball-stats.strip-pad .info { align-self: center; }


/* ---------- account compartments ----------
   The account block was two rows of bare figures with tiny labels: a level, a
   CP and a date rendered identically, so nothing said which mattered or how to
   read it. Compartments group them, tiles carry their own unit and context,
   and colour marks the family rather than the value. */

.comparts {
  display: grid; gap: 14px; padding: 12px 18px 18px;
  grid-template-columns: repeat(auto-fit, minmax(min(330px, 100%), 1fr));
}
.compart {
  background: var(--panel); border: 1px solid var(--rule);
  border-radius: 10px; overflow: hidden;
}
.compart-head {
  display: flex; align-items: center; gap: 4px;
  padding: 11px 14px 9px; border-bottom: 1px solid var(--rule);
}
.compart-head h3 {
  font-family: var(--cond); font-size: 11px; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--mute);
}
.compart-grid {
  display: grid; gap: 1px; background: var(--rule);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
/* An odd tile count would otherwise leave a hole in the second column, and
   which tiles exist depends on what is known about the account. */
.compart-grid > .stile:last-child:nth-child(odd) { grid-column: 1 / -1; }
@media (max-width: 420px) {
  .compart-grid { grid-template-columns: minmax(0, 1fr); }
}

.stile {
  display: grid; align-content: start; gap: 2px;
  background: var(--panel); padding: 11px 13px 12px;
  border-top: 2px solid transparent;
}
.stile-label {
  font-family: var(--cond); font-size: 9.5px; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--dim);
}
.stile-value {
  font-family: var(--mono); font-size: 19px; font-weight: 600; line-height: 1.15;
  font-variant-numeric: tabular-nums; color: var(--ink);
}
.stile-sub {
  font-family: var(--mono); font-size: 10px; color: var(--dim); line-height: 1.4;
}
.stile-bar {
  display: block; height: 3px; border-radius: 3px; margin-top: 5px;
  background: rgba(255, 255, 255, 0.07);
}
.stile-bar > span { display: block; height: 100%; border-radius: 3px; background: currentColor; }

/* The family stripe. Colour names the group, never the figure. */
.stile.is-cyan   { border-top-color: color-mix(in srgb, var(--gold) 55%, transparent); }
.stile.is-cyan   .stile-label, .stile.is-cyan   .stile-bar { color: var(--gold); }
.stile.is-amber  { border-top-color: color-mix(in srgb, var(--acc-amber) 55%, transparent); }
.stile.is-amber  .stile-label, .stile.is-amber  .stile-bar { color: var(--acc-amber); }
.stile.is-violet { border-top-color: color-mix(in srgb, var(--acc-violet) 55%, transparent); }
.stile.is-violet .stile-label, .stile.is-violet .stile-bar { color: var(--acc-violet); }
.stile.is-good   { border-top-color: color-mix(in srgb, var(--good) 65%, transparent); }
.stile.is-good   .stile-label, .stile.is-good   .stile-bar { color: var(--good); }
.stile.is-good   .stile-value { color: var(--good); }
.stile.is-bad    { border-top-color: color-mix(in srgb, var(--bad) 65%, transparent); }
.stile.is-bad    .stile-label, .stile.is-bad    .stile-bar { color: var(--bad); }
.stile.is-bad    .stile-value { color: var(--bad); }

/* Softer edges on the larger blocks, now that the corner token is 6px. */
.pgrid, .compart { border-radius: 10px; }
.pgrid { overflow: hidden; margin-left: 18px; margin-right: 18px; width: auto; }
.badge { border-radius: 8px; }
.tl-item, .tl-card, .depth-warn, .omni-results { border-radius: 8px; }


/* ---------- narrow screens ----------
   A phone is not a small desktop and it is not a separate design either. The
   page keeps its density and its columns; what changes is that anything wider
   than the screen scrolls inside its own box rather than dragging the whole
   document sideways, and anything driven by a cursor gets a second way in.

   The one thing allowed to be wider than the viewport is a table, inside
   `.wrap`. Everything else fits. */

/* The filter strip was the only thing forcing a page-level sideways scroll:
   nine tier buttons on one line is 676px, and `.chrome`'s wrap only breaks
   between groups, never inside one. Each group now scrolls on its own, so the
   strip keeps its shape and the document stays 375 wide. */
.subnav, .ladders, .leagues, .nav {
  max-width: 100%;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.subnav::-webkit-scrollbar, .ladders::-webkit-scrollbar,
.leagues::-webkit-scrollbar, .nav::-webkit-scrollbar { display: none; }

/* A strip that scrolls has to say so, or five of the nine tiers are simply
   missing on a phone. The classic two-layer background trick: the opaque
   cover scrolls with the content (`local`) and the darkening does not
   (`scroll`), so the edge shades exactly while there is more beyond it and
   clears itself at both ends. It is not a shadow separating two objects —
   it is the row continuing under its own edge. */
.subnav, .ladders, .leagues { --scroll-ground: var(--row); }
.nav { --scroll-ground: var(--panel); }
.subnav, .ladders, .leagues, .nav {
  background-image:
    linear-gradient(to right, var(--scroll-ground) 14px, transparent),
    linear-gradient(to left,  var(--scroll-ground) 14px, transparent),
    linear-gradient(to right, rgba(0, 0, 0, 0.5), transparent),
    linear-gradient(to left,  rgba(0, 0, 0, 0.5), transparent);
  background-position: left center, right center, left center, right center;
  background-repeat: no-repeat;
  background-size: 24px 100%, 24px 100%, 14px 100%, 14px 100%;
  background-attachment: local, local, scroll, scroll;
}

/* The group's label stays put while its buttons scroll past, so a strip that
   has been pushed along still says what it is filtering. */
.flabel {
  position: sticky; left: 0; z-index: 2; background: var(--row);
  align-self: stretch; display: flex; align-items: center; flex: 0 0 auto;
}
/* A scrolling flex row lets its children shrink by default, which would crush
   the labels rather than move them off-screen. */
.subnav button, .ladders button, .leagues button, .nav a { flex: 0 0 auto; }
/* The strip's own groups must not stretch each other past the screen. */
.chrome > * { max-width: 100%; min-width: 0; }

@media (max-width: 900px) {
  /* The masthead wraps to two rows here, and at two rows a sticky header is
     taking a tenth of the screen from the data. Pulled in rather than
     unpinned: the nav is still one flick away at the top of any page. */
  .brand { font-size: 16px; padding: 10px 13px; }
  .nav a { padding: 10px 13px; font-size: 13px; }
  .omni input { padding: 10px 13px; }
  .stamp { display: none; }
}

/* Under about 400px the brand and three nav items no longer fit on one line,
   and the masthead wrapped to three rows — a brand on a row of its own, then
   the nav, then the search. The nav takes what is left of the row and scrolls
   for the rest, which is what it already does inside its own box. */
@media (max-width: 400px) {
  .top .nav { flex: 1 1 0; min-width: 0; }
  .brand { font-size: 15px; padding: 10px 11px; }
  .nav a { padding: 10px 11px; }
}

@media (max-width: 640px) {
  /* The hero's 64px of air is a desktop proportion; on a phone it is most of
     the first screen. */
  .hero-inner { padding: 34px 16px 30px; }
  .hero-sub { margin-top: 10px; }

  /* Body padding comes in with the screen, so the gutter stays a gutter
     instead of eating a third of the line. */
  .section-title, .note, .tl-note, .tl-dist-summary, .tl-dist,
  .depth-warn, .preview, .empty, .method-sec, .method-head,
  .comparts, .group-title, .ball-hero, .player-head, .form, footer {
    padding-left: 14px; padding-right: 14px;
  }
  thead th, tbody td, tbody td:first-child { padding-left: 10px; padding-right: 10px; }
  .pgrid { margin-left: 14px; margin-right: 14px; }
  .pane-head, .pane-sub, .pane-note, .mini-row, .badges, .facts,
  .pane .ball-stats.strip-pad { padding-left: 14px; padding-right: 14px; }

  /* ---- the row keeps its name ----
     A stat table is 720px wide and a phone is 375, so the ranked column — the
     one the table is sorted by and the whole reason for the page — is a full
     screen to the right of the name. Scrolling to it used to leave seven
     anonymous numbers. Pinning the identity is the one thing that makes a
     wide table usable on a narrow screen, and it is the same device the
     matchup grid already uses for its row heads.

     `.grid` is excluded because it pins its own. */
  .wrap > table:not(.grid) th.rank,
  .wrap > table:not(.grid) td.rank {
    position: sticky; left: 0; z-index: 3;
    width: 34px; min-width: 34px; max-width: 34px;
    padding-left: 8px; padding-right: 2px;
  }
  .wrap > table:not(.grid) th.rank + th,
  .wrap > table:not(.grid) td.rank + td,
  /* Tables that are not ranked put the name first and have nothing to pair. */
  .wrap > table:not(.grid) thead th:first-child:not(.rank),
  .wrap > table:not(.grid) tbody td:first-child:not(.rank) {
    position: sticky; z-index: 3;
    max-width: 52vw; overflow: hidden; text-overflow: ellipsis;
  }
  .wrap > table:not(.grid) th.rank + th,
  .wrap > table:not(.grid) td.rank + td { left: 34px; }
  .wrap > table:not(.grid) thead th:first-child:not(.rank),
  .wrap > table:not(.grid) tbody td:first-child:not(.rank) { left: 0; }

  /* A sticky cell is transparent by default and would let the columns it is
     pinned over show through it. */
  .wrap > table:not(.grid) tbody td.rank,
  .wrap > table:not(.grid) tbody td.rank + td,
  .wrap > table:not(.grid) tbody td:first-child:not(.rank) { background: var(--bg); }
  .wrap > table:not(.grid) tbody tr:hover td.rank,
  .wrap > table:not(.grid) tbody tr:hover td.rank + td,
  .wrap > table:not(.grid) tbody tr:hover td:first-child:not(.rank) { background: var(--panel); }

  /* The seam where the pinned columns end, so the scrolled figures do not
     look like they belong to the name they slide under. */
  .wrap > table:not(.grid) th.rank + th,
  .wrap > table:not(.grid) td.rank + td,
  .wrap > table:not(.grid) thead th:first-child:not(.rank),
  .wrap > table:not(.grid) tbody td:first-child:not(.rank) {
    border-right: 1px solid var(--rule);
  }

  /* Two stat groups per row rather than four across a 375px screen. */
  .ball-stats { gap: 14px 20px; }
  .ball-hero > img, .player-hero > img { width: 72px; height: 72px; }
  .ball-hero h1 { font-size: 26px; }
}

/* ---------- touch ----------
   Two assumptions the desktop page makes that a phone breaks: that a pointer
   can rest on a row, and that a 33px control is easy to hit. */

@media (hover: none) {
  /* The tier chip's card is opened on focus so a keyboard can reach it. On
     touch a tap both focuses the chip and opens its drawer, and the card then
     lands on top of the drawer that already says the same thing. */
  .tl-card:not(.tcard) { display: none; }

  /* The typing card is the other way round: a tap is now the way in (see
     `attachTypingHover`), so the marker that says a row has something behind
     it has to be permanent rather than appearing on hover. */
  tbody tr.has-detail td:nth-child(2)::after {
    content: "›"; position: absolute; right: 4px; top: 50%;
    transform: translateY(-50%); color: var(--gold); font-size: 13px;
  }

  /* The per-side sample split stays where it is. It is rendered into cells
     sized for one figure, and forcing it on makes every rate column overflow
     into its neighbour; the pooled sample is a column of its own either way. */
}

@media (pointer: coarse) {
  /* 33px is a comfortable click and an uncomfortable tap. These are the
     controls a reader works through fastest — tier, ladder, sub-tab — so they
     are the ones worth the extra six pixels. */
  .subnav button { padding: 13px 16px; }
  .leagues button { padding: 12px 13px; }
  .ladders button { padding: 12px 15px; }
  .nav a { padding: 13px 14px; }
  .tl-drawer-close { padding: 8px 12px; }

  /* Under 16px, iOS Safari zooms the page when the field takes focus and does
     not zoom back out. */
  .omni input { font-size: 16px; }
}


/* ---------- item page ----------
   Two things the ball page has no equivalent of: a resonance attribute, which
   is a chip because that is what an attribute is everywhere else here, and an
   effect, which is the one piece of real prose the data carries and so is
   allowed to read as a sentence. */

.item-facts { display: grid; gap: 5px; margin-top: 9px; }
.item-fact { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
/* A fixed label column so resonance and requirement line up as a pair rather
   than as two unrelated lines. */
.item-fact-k {
  font-family: var(--cond); font-size: 10px; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--dim);
  min-width: 74px;
}
.item-fact-v {
  font-family: var(--mono); font-size: 12px; color: var(--ink);
}
.item-effect {
  padding: 0 18px 14px; max-width: 76ch;
  font-family: var(--mono); font-size: 12.5px; line-height: 1.7; color: var(--ink);
}
@media (max-width: 640px) { .item-effect { padding-left: 14px; padding-right: 14px; } }


/* ---------- the UNC easter egg ----------
   One account's profile never loads. See views/unc.js for why this exists and
   what keeps it from being a nuisance; the short version is that it matches
   one exact username and it holds still for `prefers-reduced-motion`. */

.unc { position: relative; overflow: hidden; min-height: 70vh; }

.unc-sky { position: absolute; inset: 0; pointer-events: none; z-index: 0; }
.unc-bit {
  position: absolute; line-height: 1; user-select: none;
  animation-name: unc-fly; animation-timing-function: ease-in-out;
  animation-iteration-count: infinite; animation-direction: alternate;
  will-change: transform;
}
@keyframes unc-fly {
  from { transform: translate3d(0, 0, 0) rotate(0deg); }
  to   { transform: translate3d(var(--drift, 80px), calc(var(--drift, 80px) * -0.6), 0)
                    rotate(var(--spin, 360deg)); }
}

.unc-box {
  position: relative; z-index: 1; padding: 54px 18px 60px;
  max-width: 78ch; margin: 0 auto; text-align: center;
}

/* Two lines, because the joke is that it says it twice. */
.unc-shout {
  display: grid; gap: 2px;
  font-family: var(--cond); font-weight: 700; text-transform: uppercase;
  font-size: clamp(30px, 8vw, 68px); line-height: 0.95; letter-spacing: 0.02em;
  color: var(--bad);
}
.unc-shout span:last-child { color: var(--ink); opacity: 0.55; }
.unc:not(.is-calm) .unc-shout { animation: unc-shake 620ms steps(2, end) infinite; }
@keyframes unc-shake {
  0%, 100% { transform: translateX(0); }
  50%      { transform: translateX(3px); }
}

.unc-sub {
  font-family: var(--mono); font-size: 12.5px; color: var(--mute);
  margin-top: 14px; line-height: 1.7;
}

.unc-log {
  margin: 18px auto 0; padding: 12px 14px; max-width: 74ch;
  background: var(--panel); border: 1px solid var(--rule); border-radius: var(--r);
  font-family: var(--mono); font-size: 11px; line-height: 1.75; color: var(--dim);
  text-align: left; white-space: pre; overflow-x: auto;
}
.unc-status {
  font-family: var(--mono); font-size: 11.5px; color: var(--bad); margin-top: 12px;
}
.unc-fine {
  font-family: var(--mono); font-size: 11px; color: var(--dim); margin-top: 22px;
}

/* Held still, but still told. The scatter stays; only the motion goes. */
@media (prefers-reduced-motion: reduce) {
  .unc-bit { animation: none; }
  .unc-shout { animation: none; }
}

/* "No bonus effect" is an answer, not an absence, so it is set apart from a
   real effect without being hidden. */
.item-effect.is-none { color: var(--dim); }

/* A peak that has no settled week behind it yet. Dimmed rather than hidden:
   it is the honest reading available today and it will be replaced. */
.badge.is-provisional-peak .badge-kind::after {
  content: " · provisional"; color: var(--dim); letter-spacing: 0.08em;
}

/* ---- meta page --------------------------------------------------------- */
.meta-counters { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin: 0 0 8px; }
@media (max-width: 900px) { .meta-counters { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .meta-counters { grid-template-columns: minmax(0, 1fr); } }
.meta-card { border: 1px solid var(--rule); border-radius: var(--r); background: var(--panel); padding: 10px 12px; }
.meta-card-head { display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding-bottom: 8px; margin-bottom: 6px; border-bottom: 1px solid var(--rule); }
.meta-card-list { display: grid; grid-template-columns: 1fr auto; gap: 6px 10px; align-items: center; }
.meta-card-list .right { text-align: right; font-variant-numeric: tabular-nums; font-family: var(--mono); font-size: 12.5px; }
.meta-card-list .hi { color: var(--good); }
.meta-card-cols { font: 600 10.5px var(--cond); letter-spacing: .1em; text-transform: uppercase; color: var(--dim); }
.cell-sub { display: block; font: 10.5px var(--mono); color: var(--dim); margin-top: 1px; }
.meta-tag { margin-left: 8px; font: 10px var(--mono); color: var(--dim); border: 1px solid var(--rule); border-radius: 3px; padding: 1px 5px; white-space: nowrap; }
.meta-pick { gap: 10px; }
.meta-pick label { display: flex; align-items: center; gap: 8px; }
.meta-pick .flabel { border-left: 0; padding: 0; }
.meta-pick select { background: var(--bg); color: var(--ink); border: 1px solid var(--rule); border-radius: var(--r);
  font: 13px var(--body); padding: 6px 8px; max-width: 70vw; }

/* Top-ball placings: the rank is the point, so it is the biggest thing. */
.badge.is-owner { position: relative; }
.badge-rank {
  margin-left: auto; padding-left: 8px; flex-shrink: 0;
  font: 700 26px/1 var(--cond); color: var(--mute); font-variant-numeric: tabular-nums;
}
.badge.is-top .badge-rank { color: var(--ink); }
.badge.is-first .badge-rank { color: var(--gold); }

.thumb.is-blank { display: inline-block; width: 26px; height: 26px; border-radius: 50%; background: var(--panel); }

@media (min-width: 700px) { .pane .wrap table { min-width: 0; } }
.pane td.stars { color: var(--acc-amber); letter-spacing: 1px; }

/* Profiles read centred on wide screens. */
#view.is-centered { max-width: 1240px; margin-left: auto; margin-right: auto; }
@media (min-width: 1300px) { #view.is-centered { border-left: 1px solid var(--rule); border-right: 1px solid var(--rule); } }
a.alliance-link { color: inherit; text-decoration: none; display: inline-block; }
a.alliance-link:hover .alliance-name { color: var(--gold); }
td b.up { color: var(--good); } td b.down { color: var(--bad); }
.hero-patch { display: flex; align-items: center; gap: 10px; margin: 10px 0 0; font-size: 14px; }
.hero-patch .flabel { border-left: 0; padding: 0; color: var(--mute); }
.hero-patch span:last-child { color: var(--mute); font-size: 12px; }
.alliance-dot { display: inline-block; width: 14px; height: 14px; border-radius: 50%; background: var(--dim); flex-shrink: 0; }
.alliance-desc { color: var(--mute); max-width: 640px; margin: 4px 0 10px; }
tr.clickable { cursor: pointer; }

/* Strongest balls strip on the profile overview. */
.strong-row { display: grid; grid-auto-flow: column; grid-auto-columns: 150px; gap: 10px;
  overflow-x: auto; padding: 2px 16px 12px; scroll-snap-type: x proximity; }
.strong-card { display: flex; flex-direction: column; align-items: center; gap: 4px; text-align: center;
  padding: 12px 10px; border: 1px solid var(--rule); border-radius: var(--r); background: var(--panel);
  color: var(--ink); text-decoration: none; scroll-snap-align: start; }
.strong-card:hover { border-color: var(--gold); }
.strong-card .thumb { width: 64px; height: 64px; }
.strong-name { font-size: 13px; line-height: 1.2; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
.strong-cp { font: 600 15px var(--mono); }
.strong-types { justify-content: center; }
.strong-item { display: flex; align-items: center; gap: 5px; font: 11px var(--mono); color: var(--mute); }
.strong-item .thumb { width: 20px; height: 20px; }
.strong-since { font: 10.5px var(--mono); color: var(--dim); }
.effect-term { background: none; border: 0; padding: 0; font: inherit; color: var(--gold);
  text-decoration: underline dotted; text-underline-offset: 3px; cursor: pointer; }
.alliance-dot.is-small { width: 10px; height: 10px; }
tr.has-ally-color td:first-child { box-shadow: inset 3px 0 0 var(--ally); }
tr.has-ally-color .name { color: color-mix(in srgb, var(--ally) 55%, var(--ink)); font-weight: 600; }
.territory-chart { width: 100%; height: auto; max-height: 220px; display: block; padding: 0 16px 12px; box-sizing: border-box; }
.territory-chart polyline { fill: none; stroke: var(--gold); stroke-width: 2; vector-effect: non-scaling-stroke; }
.territory-chart text { fill: var(--dim); font: 11px var(--mono); }
.ball-stats b.up { color: var(--good); } .ball-stats b.down { color: var(--bad); }

/* Raids: effect cards and Mymic pages. */
/* Raids → Effects: a ruled list, one effect per row. */
.fx-tools { display: flex; align-items: center; gap: 16px; padding: 12px 16px; border-bottom: 1px solid var(--rule); }
.fx-search { flex: 0 1 340px; min-width: 0; box-sizing: border-box; background: var(--panel); color: var(--ink);
  border: 1px solid var(--rule); border-radius: var(--r); font: 14px var(--body); padding: 8px 10px; }
.fx-search:focus { outline: none; border-color: var(--gold); }
.fx-count-wrap { display: flex; align-items: center; gap: 6px; margin-left: auto; }
.fx-count { font: 12px var(--mono); color: var(--mute); white-space: nowrap; }
.fx-row { display: grid; grid-template-columns: minmax(200px, 250px) minmax(0, 1fr) minmax(150px, 240px);
  column-gap: 24px; row-gap: 6px; align-items: start; padding: 10px 16px; border-bottom: 1px solid rgba(255, 255, 255, 0.05); }
.fx-row[hidden] { display: none; }
.fx-row:not(.fx-head):hover { background: var(--row); }
.fx-head { background: var(--panel); border-bottom: 1px solid var(--rule); padding-top: 9px; padding-bottom: 9px;
  font: 700 11.5px var(--body); letter-spacing: 0.06em; text-transform: uppercase; color: var(--mute); }
.fx-name { display: flex; align-items: center; gap: 10px; font-weight: 600; font-size: 14px; color: var(--ink); min-width: 0; }
.fx-name .fx-icon { width: 28px; height: 28px; border-radius: var(--r); }
.fx-icon.is-empty { display: block; visibility: hidden; }
.fx-desc { margin: 0; padding-top: 5px; color: var(--mute); font-size: 13.5px; line-height: 1.5; }
.fx-mymics { display: flex; flex-wrap: wrap; gap: 6px 12px; padding-top: 3px; }
.fx-mymic { display: inline-flex; align-items: center; gap: 6px; color: var(--ink); text-decoration: none; font-size: 13px; }
.fx-mymic .thumb { width: 22px; height: 22px; border-radius: 4px; }
.fx-mymic:hover span { color: var(--gold); }
.fx-none { color: var(--dim); font: 12.5px var(--mono); padding-top: 3px; }
/* Boss pages: no Mymics column; inside a boss column each row stacks. */
.fx.is-boss .fx-row { grid-template-columns: minmax(200px, 250px) minmax(0, 1fr); }
.fx.is-boss .fx-row:last-child { border-bottom: 0; }
.fx.is-stacked .fx-row { grid-template-columns: minmax(0, 1fr); padding: 10px 0; }
.fx.is-stacked .fx-row:hover { background: none; }
.fx.is-stacked .fx-desc { padding-left: 38px; padding-top: 0; }
.fx.is-boss .meta-tag { margin-left: 0; }
@media (max-width: 760px) {
  .fx.is-boss .fx-row { grid-template-columns: minmax(0, 1fr); }
  .fx-tools { flex-wrap: wrap; gap: 8px; }
  .fx-search { flex: 1 1 100%; }
  .fx-count-wrap { margin-left: 0; }
  .fx-head { display: none; }
  .fx-row { grid-template-columns: minmax(0, 1fr); padding: 12px 16px; }
  .fx-desc, .fx-mymics { padding-left: 38px; padding-top: 0; }
  .fx-mymics.is-empty { display: none; }
}

.mymic-lore { color: var(--mute); max-width: 760px; padding: 0 16px; font-style: italic; line-height: 1.5; }

/* Phones: five nav items no longer fit beside the brand, and the fifth
   (Raids) was hidden off the edge. Brand and search share the first row; the
   nav gets a full row of its own with every item visible. */
@media (max-width: 640px) {
  .top { flex-wrap: wrap; }
  .top .brand { order: 1; }
  .top .omni { order: 2; flex: 1 1 0; min-width: 0; margin-left: 0; }
  .top .omni input { width: 100%; box-sizing: border-box; }
  .top .nav { order: 3; flex: 1 1 100%; min-width: 0; border-top: 1px solid var(--rule); }
  .top .nav a { flex: 1 1 auto; display: flex; justify-content: center; align-items: center; padding: 10px 4px; font-size: 12.5px; letter-spacing: 0.04em; }
}
/* Phones: the "effect not counted" tag crowds the item name out of a narrow
   table; a small marker keeps the signal, the full text stays in the tooltip. */
@media (max-width: 640px) {
  .meta-tag { font-size: 0; padding: 0 4px; margin-left: 6px; }
  .meta-tag::before { content: "*"; font-size: 11px; }
}

/* Multi-boss encounters: one column per boss. */
.boss-cols { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0; margin: 4px 16px 18px;
  border: 1px solid var(--rule); border-radius: var(--r); background: var(--panel); }
.boss-col { padding: 14px 14px 16px; min-width: 0; }
.boss-col + .boss-col { border-left: 1px solid var(--rule); }
.boss-col-head { display: flex; align-items: center; gap: 12px; margin-bottom: 6px; }
.boss-col-head .thumb { width: 64px; height: 64px; }
.boss-col-head h2 { margin: 0 0 6px; font: 700 22px var(--cond); letter-spacing: .04em; text-transform: uppercase; }
.boss-col .ball-stats { padding: 6px 0 4px; }
.boss-col-title { font: 600 12px var(--cond); letter-spacing: .1em; text-transform: uppercase; color: var(--mute); margin: 14px 0 8px; display: flex; align-items: center; gap: 6px; }
.boss-drops { display: grid; gap: 6px; padding: 0 16px 12px; }
.boss-col .boss-drops { padding: 0; }
.boss-drop { display: grid; grid-template-columns: auto 1fr; grid-template-rows: auto auto; column-gap: 8px; align-items: center;
  color: var(--ink); text-decoration: none; }
.boss-drop .thumb { grid-row: span 2; }
.boss-drop:hover span:first-of-type { color: var(--gold); }
@media (max-width: 900px) {
  .boss-cols { grid-template-columns: minmax(0, 1fr); }
  .boss-col + .boss-col { border-left: 0; border-top: 1px solid var(--rule); }
}

/* First recorded clear: gold, on boss pages and player badges. */
.badge.is-first-clear { border-color: var(--acc-amber); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--acc-amber) 35%, transparent); }
.badge.is-first-clear .badge-kind { color: var(--acc-amber); }
.first-clear { margin: 6px 16px 14px; padding: 12px 14px; border: 1px solid var(--acc-amber); border-radius: var(--r);
  background: color-mix(in srgb, var(--acc-amber) 8%, var(--panel)); }
.first-clear-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.first-clear-badge { font: 700 13px var(--cond); letter-spacing: .12em; text-transform: uppercase; color: var(--bg);
  background: var(--acc-amber); border-radius: 3px; padding: 3px 8px; }
.first-clear-crew { display: flex; flex-wrap: wrap; gap: 6px 14px; margin-top: 10px; font-size: 15px; }
.first-clear-crew a { color: var(--ink); text-decoration: none; font-weight: 600; }
.first-clear-crew a:hover { color: var(--acc-amber); }

/* Touch screens: small controls keep their look but get a finger-sized hit
   area. The (i) marker is 14px drawn; the invisible ring makes it ~34px. */
@media (pointer: coarse) {
  button.info { position: relative; }
  button.info::after { content: ""; position: absolute; inset: -10px; }
  a.backlink { display: inline-block; padding: 8px 0; }
  footer a { display: inline-block; padding: 6px 0; }
}

/* Ball hover card (meta page and anywhere ballLink is used). */
.ball-link { text-decoration: none; }
.ball-link:hover, .ball-link:focus-visible { color: var(--gold); text-decoration: underline; text-underline-offset: 3px; }
.ball-pop { position: fixed; z-index: 90; width: 250px; padding: 10px 12px; background: var(--panel);
  border: 1px solid var(--gold); border-radius: var(--r); box-shadow: 0 14px 34px rgba(0,0,0,.55); pointer-events: none; }
.ball-pop-top { display: flex; gap: 10px; align-items: center; }
.ball-pop-top > img { width: 64px; height: 64px; object-fit: contain; flex-shrink: 0; }
.ball-pop-name { display: block; font-size: 14px; line-height: 1.25; margin-bottom: 3px; }
.ball-pop-rarity { display: block; font: 600 10.5px var(--cond); letter-spacing: .1em; text-transform: uppercase; color: var(--mute); margin-bottom: 5px; }
.ball-pop-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--rule); }
.ball-pop-stats span { display: flex; flex-direction: column; }
.ball-pop-stats b { font: 600 13px var(--mono); }
.ball-pop-stats i { font: normal 10px var(--mono); color: var(--dim); }
.ball-pop-none { grid-column: 1 / -1; color: var(--mute); font-size: 12px; }
.strip li.is-link { cursor: pointer; }
.strip li.is-link:hover .who { color: var(--gold); }

/* Podium places: 1st gold, 2nd silver, 3rd bronze — clear and owner badges alike. */
.badge.is-first-clear.is-place-2 { border-color: #B8C2CC; box-shadow: inset 0 0 0 1px rgba(184,194,204,.3); }
.badge.is-first-clear.is-place-2 .badge-kind { color: #B8C2CC; }
.badge.is-first-clear.is-place-3 { border-color: #B87A4B; box-shadow: inset 0 0 0 1px rgba(184,122,75,.3); }
.badge.is-first-clear.is-place-3 .badge-kind { color: #C98C5C; }
.first-clear-row { display: grid; grid-template-columns: auto 1fr; gap: 4px 10px; align-items: center; padding: 10px 0 0; margin-top: 10px; border-top: 1px solid color-mix(in srgb, var(--acc-amber) 25%, transparent); }
.first-clear-row .first-clear-crew { grid-column: 1 / -1; margin-top: 2px; }
.place-tag { font: 700 12px var(--cond); letter-spacing: .08em; text-transform: uppercase; border-radius: 3px; padding: 2px 7px; color: var(--bg); background: var(--acc-amber); }
.place-tag.is-2 { background: #B8C2CC; } .place-tag.is-3 { background: #B87A4B; }
.place-cell { font: 700 13px var(--mono); }
.place-cell.is-1 { color: var(--acc-amber); } .place-cell.is-2 { color: #B8C2CC; } .place-cell.is-3 { color: #C98C5C; }
.item-link { text-decoration: none; }
.item-link:hover, .item-link:focus-visible { color: var(--gold); text-decoration: underline; text-underline-offset: 3px; }
.strong-card { cursor: pointer; }
a.strong-name { color: var(--ink); text-decoration: none; }
a.strong-name:hover { color: var(--gold); }
.strong-item i { font-style: normal; color: var(--dim); }
.strong-item .item-link { color: var(--mute); }
/* Item early-owner badges past the podium: plain, still marked as an achievement. */
.badge.is-first-clear.is-place-4 { border-color: var(--rule); box-shadow: none; }
.badge.is-first-clear.is-place-4 .badge-kind { color: var(--mute); }

/* Privacy policy and other plain-text pages. */
.legal { max-width: 760px; padding: 28px 18px 40px; }
.legal h1 { font: 700 30px var(--cond); letter-spacing: .03em; text-transform: uppercase; margin: 0 0 4px; }
.legal-date { font: 12px var(--mono); color: var(--dim); margin: 0 0 18px; }
.legal h2 { font: 700 15px var(--cond); letter-spacing: .1em; text-transform: uppercase; color: var(--ink); margin: 26px 0 8px; }
.legal p { color: var(--mute); line-height: 1.65; margin: 0 0 10px; font-size: 14.5px; }
.legal a { color: var(--gold); }
.legal-choices { margin-top: 18px; background: var(--panel); color: var(--ink); border: 1px solid var(--rule);
  border-radius: var(--r); padding: 8px 14px; font: 600 13px var(--body); cursor: pointer; }
.legal-choices:hover { border-color: var(--gold); }

/* Room for the one ad unit, only while it is on (see lib/ads.js). */
body.has-ad-anchor footer { padding-bottom: 120px; }
@media (max-width: 760px) { body.has-ad-anchor footer { padding-bottom: 80px; } }
@media (min-width: 1500px) {
  body.has-ad-rail-right { padding-right: 320px; }
  body.has-ad-rail-left { padding-left: 320px; }
}
