/* Draftout-matched dark theme.
 *
 * Chrome tokens (surfaces, borders, heading treatment, square corners) are
 * lifted from the site's own stylesheet. Data-mark colors are NOT: the brand
 * cyan #22d3ee sits at OKLCH L 0.80, well above the 0.48-0.67 band that keeps
 * marks legible, so the series colors are the brightest brand-hue steps that
 * pass validation -- see the palette note in charts.js.
 */

@font-face {
  font-family: "DM Sans Variable"; font-style: normal; font-display: swap;
  font-weight: 100 1000; src: url("/cdn/fonts/dm-sans.woff2") format("woff2-variations");
}
@font-face {
  font-family: "Inter Variable"; font-style: normal; font-display: swap;
  font-weight: 100 900; src: url("/cdn/fonts/inter.woff2") format("woff2-variations");
}
@font-face {
  font-family: "JetBrains Mono Variable"; font-style: normal; font-display: swap;
  font-weight: 100 800; src: url("/cdn/fonts/jetbrains-mono.woff2") format("woff2-variations");
}
@font-face {
  font-family: "Minecraft"; src: url("/cdn/fonts/MinecraftRegular.otf") format("opentype");
  font-weight: 400; font-display: swap;
}

:root {
  --bg: #0a0a0a;
  --panel: #101010;
  --panel-2: #161616;
  --border: rgba(103, 232, 249, 0.20);
  --border-soft: rgba(255, 255, 255, 0.07);

  --ink: #e5e5e5;
  --ink-dim: #a3a3a3;
  --ink-mute: #737373;
  --accent: #67e8f9;          /* cyan-300, chrome only -- never a data mark */
  --accent-dim: rgba(103, 232, 249, 0.55);

  /* Validated data series (dark, surface #0a0a0a, all-pairs): all six checks pass. */
  --series-me: #00a8b5;
  --series-opp: #ea4f68;
  --series-none: #6f7275;     /* absence, not an identity -- always direct-labeled */

  /* Emphasis for a hovered mark, not a series of its own: the same hue as
     --series-me a couple of steps lighter (it is --ramp-5). Identity has to
     survive the highlight, so this may never be a different hue. */
  --series-me-hi: #56d2df;

  /* Sequential ramp, single hue, validated with --ordinal. */
  --ramp-1: #004b58; --ramp-2: #006b78; --ramp-3: #008c99;
  --ramp-4: #27afbc; --ramp-5: #56d2df;

  --grid: rgba(255, 255, 255, 0.09);
  /* Chrome, not data: a neutral grey so a scrollbar is never mistaken
     for a series. --grid alone is too faint to aim at. */
  --scrollbar: rgba(255, 255, 255, 0.18);
  --scrollbar-hover: rgba(255, 255, 255, 0.30);

  /* The height every ranked list stops growing at: 25 bar rows of 20px content
     plus 2px padding either side, with a 3px gap between. Shared so a bar list
     and the pairs list beside it stay the same height. */
  --list-cap: calc(25 * 24px + 24 * 3px);
  --font-head: "DM Sans Variable", system-ui, sans-serif;
  --font-body: "Inter Variable", system-ui, sans-serif;
  --font-mono: "JetBrains Mono Variable", ui-monospace, monospace;
}

* { box-sizing: border-box; }

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

h1, h2, h3, .head {
  font-family: var(--font-head);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 700;
  margin: 0;
}

a { color: var(--accent); }
.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------------ shell */

.topbar {
  position: sticky; top: 0; z-index: 50;
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 10px 20px;
  background: rgba(10, 10, 10, 0.96);
  border-bottom: 1px solid var(--border);
  backdrop-filter: blur(8px);
}
.brand {
  font-family: "Minecraft", var(--font-head);
  font-size: 18px; color: #fff; text-shadow: 2px 2px 0 rgba(0,0,0,0.9);
  letter-spacing: 0.04em;
  background: none; border: 0; padding: 0; cursor: pointer;
}
.brand:hover span { color: #fff; }
.brand:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.brand span { color: var(--accent); }

/* Support link, far right of the topbar.
   Sits at the accent, with a faint cyan fill, so it reads as a thing you can
   click without shouting -- the same treatment .rank-chip gets. Hover deepens
   the fill and brings the border most of the way up rather than changing
   colour, so the step is felt more than seen. Square, like everything else.
   The dots in the icon are zero-length strokes; round linecaps render them as
   the indicator LEDs, which is why stroke-linecap below is load-bearing. */
.support {
  margin-left: auto;              /* the only thing pushing it right */
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 10px;
  border: 1px solid var(--border);
  background: rgba(103, 232, 249, 0.07);
  color: var(--accent); text-decoration: none;
  font-family: var(--font-head); font-size: 11px;
  letter-spacing: 0.07em; text-transform: uppercase; white-space: nowrap;
  transition: color 120ms ease, border-color 120ms ease, background-color 120ms ease;
}
.support svg {
  width: 14px; height: 14px; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.3;
  stroke-linecap: round; stroke-linejoin: round;
}
.support:hover {
  border-color: var(--accent-dim);
  background: rgba(103, 232, 249, 0.16);
}
.support:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The topbar wraps on narrow screens. Once it does, margin-left:auto would
   strand this alone on its own line, so let it sit inline with the rest. */
@media (max-width: 720px) {
  .support { margin-left: 0; }
  .support span { display: none; }   /* icon only, to keep the bar one line */
}

/* The match count and date range. Was --ink-mute, which is 4.2:1 on this
   surface and so actually below WCAG AA -- the complaint that it was hard to
   read was measurably correct, not a preference. The accent is 13.7:1 and
   matches the support link at the other end of the bar. */
#dataset-note { color: var(--accent); font-size: 11px; }

/* The accent here too, matching the rest of the bar. The usual objection --
   that a placeholder coloured like real input reads as already filled -- does
   not apply: typed text is --ink, near-white, so the two stay obviously
   distinct. `opacity: 1` because Firefox dims placeholders on top of whatever
   colour is set, which would undo this. */
input[type="search"]::placeholder { color: var(--accent); opacity: 1; }

.picker { position: relative; display: flex; align-items: center; gap: 8px; }
input[type="search"], select, input[type="number"] {
  background: rgba(0,0,0,0.55);
  border: 1px solid var(--border);
  color: var(--ink);
  font-family: var(--font-head);
  font-size: 13px;
  padding: 6px 10px;
  border-radius: 0;
  min-height: 32px;
}
input:focus, select:focus, button:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px; border-color: var(--accent);
}

.suggest {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 60;
  min-width: 260px; max-height: 320px; overflow-y: auto;
  background: rgba(8,8,8,0.98); border: 1px solid var(--border);
}
.suggest button {
  display: flex; justify-content: space-between; gap: 12px; width: 100%;
  background: none; border: 0; color: var(--ink); cursor: pointer;
  padding: 7px 10px; font-family: var(--font-head); font-size: 13px; text-align: left;
}
.suggest button:hover, .suggest button[aria-selected="true"] { background: rgba(103,232,249,0.12); }
.suggest .n { color: var(--ink-mute); font-family: var(--font-mono); }

/* --------------------------------------------------- checklist popover */

/* The rank scope picker. A <select multiple> could not carry the per-rank
   counts, and the counts are most of the reason to open it at all. */
.picker-menu { position: relative; display: inline-flex; }
.menu-button {
  background: none; border: 1px solid var(--border); color: var(--ink);
  font-family: var(--font-head); font-size: 12px; letter-spacing: 0.04em;
  padding: 5px 10px; cursor: pointer;
}
.menu-button:hover { border-color: var(--accent); color: #e8feff; }
.menu-panel {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 60;
  min-width: 316px; max-height: 380px; overflow-y: auto;
  background: rgba(8,8,8,0.98); border: 1px solid var(--border);
  padding: 4px;
}

/* One template for the header and every row, in fixed widths rather than
   content widths: a per-row `auto` column is sized by that row alone, so the
   numbers would still step in and out as the rank names changed length. */
.menu-row, .menu-head {
  display: grid;
  grid-template-columns: 13px 8px minmax(88px, 1fr) 46px 44px;
  align-items: center; gap: 8px; padding: 6px 8px;
}
.menu-head {
  font-family: var(--font-head); font-size: 10px; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--ink-mute);
  padding-bottom: 2px; border-bottom: 1px solid var(--border); margin-bottom: 2px;
}
.menu-head span { text-align: right; }
.menu-head-gap { grid-column: 1 / 4; }   /* the checkbox, swatch and name cells */
.menu-row {
  font-size: 12px; color: var(--ink); cursor: pointer;
  /* Not .controls label: that rule uppercases and mutes, which is right for a
     field name and wrong for the values being chosen between. */
  font-family: var(--font-head); letter-spacing: 0;
}
.menu-row:hover { background: rgba(103,232,249,0.10); }
.menu-row input { accent-color: var(--accent); width: 13px; height: 13px; margin: 0; }
/* "All ranks" is the reset, not a sibling of the bands -- ruled off so the list
   below reads as one group rather than fourteen peers. */
.menu-all { border-bottom: 1px solid var(--border); margin-bottom: 2px; }
.menu-dot { width: 8px; height: 8px; }
.menu-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.menu-n {
  color: var(--ink-mute); font-family: var(--font-mono); font-size: 11px;
  text-align: right; font-variant-numeric: tabular-nums;
}
.menu-apply {
  width: 100%; margin-top: 4px; padding: 7px; cursor: pointer;
  background: rgba(103,232,249,0.18); color: #e8feff;
  border: 1px solid var(--border); font-family: var(--font-head);
  font-size: 12px; letter-spacing: 0.06em; text-transform: uppercase;
}
.menu-apply:hover { border-color: var(--accent); }

main { padding: 20px; max-width: 1500px; margin: 0 auto; }

/* -------------------------------------------------------------- identity */

.identity { display: flex; gap: 18px; align-items: stretch; margin-bottom: 18px; flex-wrap: wrap; }
.avatar {
  width: 84px; height: 128px; overflow: hidden; flex: none;
  border: 1px solid var(--border); background: var(--panel);
}
.avatar img { width: 100%; display: block; image-rendering: pixelated; margin-top: -6px; }
.identity-main { flex: 1 1 260px; min-width: 240px; }
.identity h1 { font-size: 30px; color: #fff; }
.identity .sub { color: var(--ink-dim); font-size: 13px; margin-top: 4px; }
.rank-chip {
  display: inline-block; padding: 2px 8px; margin-left: 8px;
  border: 1px solid var(--border); font-family: var(--font-head);
  font-size: 11px; letter-spacing: 0.08em; color: var(--accent);
}

/* Twelve tiles in two even rows of six. Halves to 3-up, then 2-up, so the
   rows stay even at every width rather than leaving an orphan. */
.kpis { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 8px; }
@media (max-width: 1180px) { .kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 640px)  { .kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.kpi { border: 1px solid var(--border-soft); background: var(--panel); padding: 9px 11px; }
.kpi .k { font-family: var(--font-head); font-size: 10px; letter-spacing: 0.09em;
          text-transform: uppercase; color: var(--ink-mute); }
.kpi .v { font-family: var(--font-mono); font-size: 21px; color: #fff; margin-top: 3px;
          font-variant-numeric: tabular-nums; line-height: 1.15; }
.kpi .d { font-size: 11px; color: var(--ink-dim); margin-top: 1px; }

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

.tabs { display: flex; gap: 2px; margin: 18px 0 14px; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.tabs button {
  background: none; border: 0; border-bottom: 2px solid transparent;
  color: var(--ink-mute); cursor: pointer; padding: 8px 14px;
  font-family: var(--font-head); font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase;
}
.tabs button:hover { color: var(--ink); }
.tabs button[aria-selected="true"] { color: var(--accent); border-bottom-color: var(--accent); }

/* ---------------------------------------------------------------- panels */

.grid { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(420px, 1fr)); }
.grid.wide { grid-template-columns: 1fr; }

/* Panels sharing a row line up inside as well as at their edges: each hands its
   heading, note, controls and body to the parent grid as separate rows, so a
   description that wraps to two lines pushes every panel's controls and bars
   down together rather than only its own. Without it the trio on the Match tab
   starts its bars at three different heights.

   `display: contents` is what lets the header's children become grid items of
   the panel. Where subgrid is unsupported this is skipped and the panels align
   at their edges only, as they did before. */
@supports (grid-template-rows: subgrid) {
  .grid.align-rows { grid-template-rows: auto auto auto 1fr; row-gap: 0; }
  .grid.align-rows > .panel {
    display: grid; grid-template-rows: subgrid; grid-row: span 4; row-gap: 0;
  }
  /* Panels whose filters live in a shared bar above rather than in the card:
     three tracks to line up (heading, note, body) instead of four. */
  .grid.align-rows.no-controls { grid-template-rows: auto auto 1fr; }
  .grid.align-rows.no-controls > .panel { grid-row: span 3; }
  .grid.align-rows > .panel > header { display: contents; }
  /* The header's own margin-bottom goes with it under display: contents. */
  .grid.align-rows > .panel > div:last-child { margin-top: 12px; }
}

/* The paired draft lists collapse to one column only when two no longer fit. */
@media (max-width: 900px) {
  .grid[style*="repeat(2"] { grid-template-columns: 1fr !important; }
}

/* ------------------------------------------------------------ goal view */

.goal-browser { margin-bottom: 18px; }
.goal-browser-bar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 8px;
}
.goal-browser-bar input { min-width: 240px; flex: 0 1 340px; }
.goal-count {
  font-family: var(--font-head); font-size: 11px; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--ink-mute);
}

/* Icon mosaic, matching the column steps and 3px cyan gutters of the site's
   own wiki grid: the container colour shows through the gaps as the rules. */
.goal-grid {
  display: grid; grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 3px; padding: 3px;
  background: rgba(103, 232, 249, 0.10);
  box-shadow: inset 0 0 0 1px rgba(34, 211, 238, 0.18);
}
@media (min-width: 640px)  { .goal-grid { grid-template-columns: repeat(8, minmax(0, 1fr)); } }
@media (min-width: 768px)  { .goal-grid { grid-template-columns: repeat(10, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .goal-grid { grid-template-columns: repeat(12, minmax(0, 1fr)); } }
@media (min-width: 1280px) { .goal-grid { grid-template-columns: repeat(14, minmax(0, 1fr)); } }

.goal-grid button {
  position: relative; aspect-ratio: 1 / 1; width: 100%;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid rgba(103, 232, 249, 0.08);
  background: rgba(10, 10, 10, 0.85);
  padding: 4px; cursor: pointer; color: var(--ink-mute); font-size: 10px;
  transition: border-color 150ms, background-color 150ms, box-shadow 150ms;
}
.goal-grid button:hover {
  z-index: 10; border-color: rgba(103, 232, 249, 0.45);
  background: rgba(103, 232, 249, 0.08);
  box-shadow: 0 0 18px rgba(34, 211, 238, 0.35);
}
.goal-grid button:focus-visible {
  z-index: 10; border-color: rgba(103, 232, 249, 0.55);
  outline: 2px solid var(--accent); outline-offset: -2px;
}
.goal-grid button[aria-pressed="true"] {
  z-index: 10; border-color: rgba(103, 232, 249, 0.55);
  background: rgba(103, 232, 249, 0.12);
}
.goal-grid img {
  width: 100%; height: 100%; object-fit: contain; image-rendering: pixelated;
}
/* Retired goals, and goals this player has no data for, stay browsable but
   read as inactive. */
.goal-grid button.retired img { opacity: 0.4; }
.goal-grid button.unplayed { background: rgba(10, 10, 10, 0.5); }
.goal-grid button.unplayed img { opacity: 0.3; }
.goal-grid button:hover img { opacity: 1; }
.goal-grid .empty { grid-column: 1 / -1; }

.goal-head { margin-bottom: 16px; }
.goal-head .goal-id { display: flex; align-items: center; gap: 14px; margin-bottom: 12px; }
.goal-head .goal-icon {
  width: 48px; height: 48px; image-rendering: pixelated; flex: none;
  border: 1px solid var(--border-soft); background: var(--panel); padding: 4px;
}
.goal-head h1 { font-size: 22px; color: #fff; }
.goal-head .sub { color: var(--ink-mute); font-size: 12px; margin-top: 3px; }

/* Divider introducing a subsection inside a tab. */
.section-head {
  grid-column: 1 / -1; display: flex; align-items: center; gap: 12px;
  margin: 12px 0 -2px; min-width: 0;
}
.section-head h2 { font-size: 12px; color: var(--accent); white-space: nowrap; }
.section-head .line { flex: 1 1 auto; height: 1px; background: var(--border); min-width: 16px; }
.section-head .sub-note {
  color: var(--ink-mute); font-size: 12px; flex: 0 1 auto;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.panel { border: 1px solid var(--border-soft); background: var(--panel); padding: 14px 16px 16px; min-width: 0; }
.panel > header { margin-bottom: 12px; }
.panel h2 { font-size: 13px; color: var(--ink); }
.panel .note { color: var(--ink-mute); font-size: 12px; margin-top: 3px; line-height: 1.45; }
/* A note that reports something is wrong, not just context. */
.panel .note.warn {
  color: var(--series-opp); border-left: 2px solid var(--series-opp); padding-left: 8px;
}

.controls { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 10px; }
.controls label { font-size: 11px; color: var(--ink-mute); font-family: var(--font-head);
                  letter-spacing: 0.06em; text-transform: uppercase; }
.seg { display: flex; border: 1px solid var(--border); }
.seg button {
  background: none; border: 0; color: var(--ink-mute); cursor: pointer;
  padding: 5px 10px; font-family: var(--font-head); font-size: 11px;
  letter-spacing: 0.06em; text-transform: uppercase;
}
.seg button[aria-pressed="true"] { background: rgba(103,232,249,0.18); color: #e8feff; }
.seg button:hover { color: var(--ink); }
.controls input[type="range"] { accent-color: var(--accent); width: 110px; }

/* ------------------------------------------------------------- bar lists */

.barlist { display: flex; flex-direction: column; gap: 3px; }
.barrow {
  /* 96px on the value column, not 88: the availability lists write a rate and
     its fraction together ("33.4% 116/347"), which needs 94px. At 88 it spilled
     invisibly; inside a scrolling list it would be clipped instead. */
  display: grid; grid-template-columns: 20px 1fr 96px; gap: 9px;
  align-items: center; padding: 2px 0; position: relative;
}

/* Past 25 rows a list scrolls rather than stretching the panel (see
   ROWS_BEFORE_SCROLL in charts.js), so raising the row control from 25 to 50
   adds a scrollbar and leaves the page the same length. scrollbar-gutter keeps
   the bar off the value column instead of overlapping the numbers.

   The `.panel.fill` selector has to be repeated here: that rule clears the
   max-height so a panel's list can stretch to its neighbour's height, and it
   would otherwise out-specify the cap and let the list grow unbounded again. */
.barlist.capped, .scroll.capped, .panel.fill .scroll.capped {
  max-height: var(--list-cap);
  overflow-y: auto;
  scrollbar-gutter: stable;
}
.barlist.capped, .scroll { scrollbar-width: thin; scrollbar-color: var(--scrollbar) transparent; }
.barlist.capped::-webkit-scrollbar, .scroll::-webkit-scrollbar { width: 8px; }
.barlist.capped::-webkit-scrollbar-track, .scroll::-webkit-scrollbar-track { background: transparent; }
.barlist.capped::-webkit-scrollbar-thumb, .scroll::-webkit-scrollbar-thumb {
  background: var(--scrollbar); border-radius: 4px;
}
.barlist.capped::-webkit-scrollbar-thumb:hover, .scroll::-webkit-scrollbar-thumb:hover {
  background: var(--scrollbar-hover);
}
.barrow .icon { width: 20px; height: 20px; image-rendering: pixelated; }
.barrow .icon.missing { background: var(--panel-2); }
.barrow .track { position: relative; height: 20px; min-width: 0; }
.barrow .fill {
  position: absolute; inset: 0 auto 0 0; height: 20px;
  border-radius: 0 4px 4px 0;   /* rounded data-end, square at baseline */
  background: var(--series-me);
}
.barrow .lbl {
  position: absolute; left: 7px; top: 0; height: 20px; display: flex; align-items: center;
  font-size: 12px; color: var(--ink); white-space: nowrap; pointer-events: none;
  text-shadow: 0 1px 2px rgba(0,0,0,0.85);
}
.barrow .val {
  font-family: var(--font-mono); font-size: 12px; color: var(--ink-dim);
  text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap;
}
.barrow .val b { color: #fff; font-weight: 500; }
.barrow:hover .fill { filter: brightness(1.18); }
.barrow.retired .icon { opacity: 0.45; }
.barrow.retired .lbl::after {
  content: "retired"; margin-left: 8px; font-size: 10px; color: var(--ink-mute);
  font-family: var(--font-head); letter-spacing: 0.06em; text-transform: uppercase;
}

/* Stacked variant: 2px surface gaps do the separating, never strokes. */
.barrow .seg-fill { position: absolute; top: 0; height: 20px; }
.barrow .seg-fill:last-child { border-radius: 0 4px 4px 0; }

/* A magnified matrix is wider than its panel by design, so the panel scrolls
   sideways rather than the page doing it. */
.zoomable { overflow-x: auto; overflow-y: hidden; scrollbar-width: thin;
            scrollbar-color: var(--scrollbar) transparent; }
.zoomable::-webkit-scrollbar { height: 8px; }
.zoomable::-webkit-scrollbar-track { background: transparent; }
.zoomable::-webkit-scrollbar-thumb { background: var(--scrollbar); border-radius: 4px; }
.zoomable svg { display: block; }

/* The hovered matrix cell, redrawn a few pixels larger with an outline. The
   stroke is the page's brightest ink so it reads against every step of the
   ramp, including the lightest one. */
.cell-lift {
  stroke: var(--ink);
  stroke-width: 1.5;
  paint-order: stroke;
  pointer-events: none;
}

.legend { display: flex; gap: 14px; flex-wrap: wrap; margin-bottom: 10px; }
.legend .item { display: flex; align-items: center; gap: 6px; font-size: 11px; color: var(--ink-dim);
                font-family: var(--font-head); letter-spacing: 0.05em; text-transform: uppercase; }
.legend .sw { width: 10px; height: 10px; flex: none; }

/* A panel whose scroller should fill the height the grid row gives it, so a
   capped list sits flush beside a taller neighbour instead of leaving a gap. */
.panel.fill { display: flex; flex-direction: column; }
.panel.fill > div:last-child { flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0; }
.panel.fill .scroll { flex: 1 1 auto; max-height: none; min-height: 0; }

/* A chart told to fill its card (see fillHeight in app.js). The SVG is taken
   out of flow so redrawing it at a measured height cannot change the host's
   height and re-trigger the observer doing the measuring. The min-height is
   the floor for when this panel is alone in its grid row and has no taller
   neighbour to take its height from -- without it the box would collapse. */
.panel.fill .chart-fill { position: relative; flex: 1 1 auto; min-height: 300px; }
.panel.fill .chart-fill > svg { position: absolute; inset: 0; width: 100%; height: 100%; }

/* Reroll pairs: two goals discarded together, one row each. */
.pair-list { display: flex; flex-direction: column; }
.pair-row {
  display: grid; grid-template-columns: 1fr auto 1fr 34px;
  align-items: center; gap: 8px; padding: 3px 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.04); min-width: 0;
}
.pair-row:hover { background: rgba(103, 232, 249, 0.06); }
.pair-goal {
  display: flex; align-items: center; gap: 6px; min-width: 0;
  font-size: 12px; color: var(--ink);
}
.pair-goal img { width: 18px; height: 18px; image-rendering: pixelated; flex: none; }
.pair-goal span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pair-plus { color: var(--ink-mute); font-size: 11px; flex: none; }
.pair-row .val { text-align: right; font-size: 11px; color: var(--accent); }

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

table { width: 100%; border-collapse: collapse; font-size: 12px; }
th {
  text-align: left; font-family: var(--font-head); font-size: 10px; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--ink-mute); font-weight: 600;
  padding: 6px 8px; border-bottom: 1px solid var(--border-soft); position: sticky; top: 0;
  background: var(--panel); user-select: none; white-space: nowrap;
}
/* A header sits over its own column, so numeric headers align right like the
   values under them. */
th.num { text-align: right; }
/* Only a sortable table's headers advertise themselves as clickable. */
table.sortable th { cursor: pointer; }
table.sortable th:hover { color: var(--ink); }
th[aria-sort] { color: var(--accent); }
td { padding: 5px 8px; border-bottom: 1px solid rgba(255,255,255,0.04); }
/* Dates and durations must not wrap mid-value. */
td.num {
  font-family: var(--font-mono); text-align: right;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
tbody tr:hover { background: rgba(103,232,249,0.06); }
.scroll { max-height: 460px; overflow-y: auto; }
/* Match logs are the thing you actually read down, so give them the room. */
.scroll.tall { max-height: min(85vh, 1100px); }

/* Rows that open the match on draftoutmc.com. */
table.linked tbody tr { cursor: pointer; }
table.linked tbody tr:focus-visible {
  outline: 2px solid var(--accent); outline-offset: -2px;
}
table.linked a { color: inherit; text-decoration: none; }
table.linked tr:hover a { color: var(--accent); text-decoration: underline; }

/* Rows picked out by clicking a chart bucket: filled, not just outlined, so
   they are findable while scanning a long table. */
tbody tr.hit-row > td {
  background: rgba(103, 232, 249, 0.22);
  color: #eafdff;
  border-top: 1px solid rgba(103, 232, 249, 0.75);
  border-bottom: 1px solid rgba(103, 232, 249, 0.75);
}
tbody tr.hit-row > td:first-child {
  border-left: 3px solid var(--accent);   /* a spine to catch the eye */
}
tbody tr.hit-row > td:last-child { border-right: 1px solid rgba(103, 232, 249, 0.75); }
tbody tr.hit-row:hover > td { background: rgba(103, 232, 249, 0.30); }
tbody tr.hit-row a { color: #eafdff; }

.link-button {
  background: none; border: 1px solid var(--border); color: var(--accent);
  cursor: pointer; padding: 4px 10px; font-family: var(--font-head);
  font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase;
}
.link-button:hover { background: rgba(103, 232, 249, 0.12); }

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

#tip {
  position: fixed; z-index: 100; pointer-events: none; opacity: 0;
  transition: opacity 90ms ease; max-width: 300px;
  background: rgba(6,6,6,0.97); border: 1px solid var(--border);
  padding: 8px 10px; font-size: 12px; line-height: 1.45;
  box-shadow: 0 10px 30px rgba(0,0,0,0.5);
}
#tip .t { font-family: var(--font-head); font-size: 11px; letter-spacing: 0.05em;
          text-transform: uppercase; color: var(--accent); margin-bottom: 4px; }
#tip .r { display: flex; justify-content: space-between; gap: 16px; color: var(--ink-dim); }
#tip .r b { color: #fff; font-family: var(--font-mono); font-weight: 500; }

/* ------------------------------------------------------------------- svg */

svg { display: block; width: 100%; overflow: visible; }
svg text { font-family: var(--font-mono); font-size: 10px; fill: var(--ink-mute); }
svg .axis-line, svg .grid-line { stroke: var(--grid); stroke-width: 1; }
svg .mark-me { fill: var(--series-me); }
svg .mark-opp { fill: var(--series-opp); }
svg .hit { fill: transparent; }
svg .hit.selectable { cursor: pointer; }
svg .hit.selectable:hover { fill: rgba(103, 232, 249, 0.07); }
/* The clicked bucket keeps a visible frame while its rows stay picked out. */
svg .band-selected {
  fill: rgba(103, 232, 249, 0.08); stroke: var(--accent);
  stroke-width: 1; pointer-events: none;
}
svg .bar-selected { filter: brightness(1.25); }

/* Matrix: the redundant mirror half and the self-pair diagonal are inert. */
svg .cell-muted { fill: rgba(255, 255, 255, 0.025); }
svg .cell-diagonal { fill: rgba(255, 255, 255, 0.10); }
svg .axis-icon-bg { fill: rgba(255, 255, 255, 0.03); cursor: help; }
svg .axis-icon-bg:hover { fill: rgba(103, 232, 249, 0.22); }
svg .dot-ring { stroke: var(--panel); stroke-width: 2; }

/* Scatter marks. The resting ring is the surface colour, so overlapping dots
   read as separate marks rather than one blob. */
svg .dot {
  fill: var(--series-me);
  stroke: var(--panel);
  stroke-width: 2;
  opacity: 0.85;
}

/* The one the crosshair has snapped to: a lighter step of the same hue -- the
   identity must not change, only its emphasis -- plus a pale ink outline.
   Deliberately not the chrome cyan: against a fill this close to it the ring
   disappeared, and the whole job of the ring is to be findable in a dense
   field. Bigger and fully opaque does the rest. r is set in charts.js, since
   it also decides the hit maths. */
svg .dot-active {
  fill: var(--series-me-hi);
  stroke: var(--ink);
  stroke-width: 1.5;
  opacity: 1;
}

svg .crosshair-line {
  stroke: var(--accent-dim);
  stroke-width: 1;
  stroke-dasharray: 3 3;
}

/* Sits on the same baseline as the axis ticks it replaces, in chrome cyan so it
   reads as a readout rather than as another tick. */
svg .crosshair-tag {
  fill: var(--accent);
  font-size: 10px;
  font-weight: 600;
  paint-order: stroke;
  stroke: var(--panel);
  stroke-width: 3;
}

.empty { color: var(--ink-mute); font-size: 12px; padding: 22px 0; text-align: center; }
.hint { color: var(--ink-mute); font-size: 11px; margin-top: 8px; }
