/* Megatron — war-room board. Single committed dark look. */
:root {
  --board: #1B2127;
  --board-raised: #232A31;
  --chalk: #E9E4D8;
  --chalk-dim: #9AA3AB;
  --rule: #39424B;
  --qb: #D64545; --rb: #3FA46A; --wr: #4A90D9; --te: #E8A33D;
  --band-track: #2E363E;

  /* Elevation — these values were previously inlined per rule. */
  --sunken: #161C22;
  --hairline: #1E262D;
  --accent: var(--te);

  /* Spacing step. */
  --s1: .25rem; --s2: .5rem; --s3: .75rem; --s4: 1.1rem; --s5: 1.75rem;

  /* Type scale. Every value below is copied VERBATIM from a declaration that
     already ships, so adopting a token is a pure refactor with no visual
     change. Do not "round" them to a prettier ramp -- see Step 3. */
  --t-display:  400 1.35rem/1 "Bruno Ace", "Barlow Condensed", sans-serif; /* .wordmark */
  --t-nav:      600 .95rem/1 "Barlow Condensed", sans-serif;   /* masthead nav     */
  --t-chip:     600 .85rem/1 "Barlow Condensed", sans-serif;   /* filter buttons   */
  --t-micro:    600 .7rem/1.5 "Barlow Condensed", sans-serif;  /* small captions   */
  --t-num:      500 .92rem/1.4 "IBM Plex Mono", monospace;     /* td.num, th.num   */
  --t-mono-sm:  500 .78rem/1.2 "IBM Plex Mono", monospace;     /* stamps           */

  /* New surfaces only -- no existing declaration matches these. */
  --t-name:     600 1rem/1.15 "Barlow Condensed", sans-serif;
  --t-label:    600 .62rem/1 "IBM Plex Mono", monospace;
  --t-edge:     500 .58rem/1 "IBM Plex Mono", monospace;
}

* { box-sizing: border-box; }
html { color-scheme: dark; }
body {
  margin: 0; background: var(--board); color: var(--chalk);
  font: 400 16px/1.55 "Source Sans 3", system-ui, sans-serif;
}
a { color: var(--chalk); }
:focus-visible { outline: 2px solid var(--te); outline-offset: 2px; }

/* -- header ------------------------------------------------------------ */
.masthead {
  display: flex; align-items: baseline; gap: 1.25rem; flex-wrap: wrap;
  padding: 1.1rem 1.25rem .9rem; border-bottom: 1px solid var(--rule);
}
.wordmark {
  font: var(--t-display);
  letter-spacing: .01em; text-transform: uppercase; margin: 0;
}
.wordmark .logo { height: 1.05em; width: auto; vertical-align: -0.16em; margin-right: .35rem; }
.masthead nav { display: flex; flex-wrap: wrap; gap: 1rem; margin-left: auto; }
.masthead nav a {
  font: var(--t-nav); letter-spacing: .09em;
  text-transform: uppercase; text-decoration: none; color: var(--chalk-dim);
  padding: .3rem 0; border-bottom: 2px solid transparent;
}
.masthead nav a[aria-current="page"] { color: var(--chalk); border-bottom-color: var(--chalk); }
.stamp {
  width: 100%; font: var(--t-mono-sm);
  color: var(--chalk-dim); letter-spacing: .02em;
}
.stale {
  background: var(--te); color: #1B2127; padding: .55rem 1.25rem;
  font: 600 .9rem/1.3 "Source Sans 3", sans-serif;
}

/* Wide enough for the 10-column board to fit without a horizontal scrollbar on
   a 1280 screen (the table measures ~1212px; 1400 - 2*1.25rem padding clears it
   whenever the viewport does). Prose is capped separately at 68ch and the about
   page's charts at 62ch, so nothing text-heavy gets wider with it. */
main { max-width: 1400px; margin: 0 auto; padding: 1.25rem; }
.eyebrow {
  font: 600 .8rem/1 "Barlow Condensed", sans-serif; letter-spacing: .14em;
  text-transform: uppercase; color: var(--chalk-dim); margin: 0 0 .35rem;
}
h1, h2 { font-family: "Barlow Condensed", sans-serif; letter-spacing: .02em; }
h1 { font-size: 2rem; font-weight: 700; margin: 0 0 1rem; }
h2 { font-size: 1.3rem; font-weight: 600; margin: 2rem 0 .6rem; }

/* -- position chips ------------------------------------------------------ */
.pos-chip {
  display: inline-block; min-width: 2.4em; text-align: center;
  font: 600 .78rem/1.5 "Barlow Condensed", sans-serif; letter-spacing: .06em;
  border-radius: 3px; color: #10151A;
}
.pos-qb { background: var(--qb); } .pos-rb { background: var(--rb); }
.pos-wr { background: var(--wr); } .pos-te { background: var(--te); }

/* -- tables -------------------------------------------------------------- */
.table-wrap { overflow-x: auto; }
/* The board is wider than its scrollport (10 columns, ~1212 vs ~1040), which is
   what `overflow-x: auto` above is for. Making the board's wrap a size query
   container lets the expanded detail panel size itself to the width the reader
   can actually see (`100cqi`) instead of the table's full width. Scoped with
   `:has()` so the other pages' wraps are untouched. */
.table-wrap:has(#board) { container-type: inline-size; }
table { border-collapse: collapse; width: 100%; }
th, td { padding: .45rem .6rem; text-align: left; white-space: nowrap; }
thead th {
  font: 600 .78rem/1.2 "Barlow Condensed", sans-serif; letter-spacing: .1em;
  text-transform: uppercase; color: var(--chalk-dim);
  border-bottom: 1px solid var(--rule); cursor: pointer; user-select: none;
  /* Headers wrap, data cells do not. "Season pts (p50, my league)" is the
     widest string in the board and, held on one line, it forced that column
     about 90px past what its numbers need -- pushing the whole table into a
     horizontal scrollbar. Only the header row grows a line; row rhythm and
     density are untouched. */
  white-space: normal;
  vertical-align: bottom;
}
thead th[aria-sort="descending"]::after { content: " ▾"; }
thead th[aria-sort="ascending"]::after { content: " ▴"; }
tbody tr { border-bottom: 1px solid color-mix(in srgb, var(--rule) 45%, transparent); }
tbody tr:hover { background: var(--board-raised); }
td.num, th.num { text-align: right; font: var(--t-num);
  font-variant-numeric: tabular-nums; }

/* -- signature: the range band ------------------------------------------- */
.band { position: relative; width: 170px; height: 15px; }
.band::before {
  content: ""; position: absolute; top: 7px; left: 0; right: 0;
  height: 2px; background: var(--band-track); border-radius: 2px;
}
.band .fill { position: absolute; top: 6px; height: 4px; border-radius: 2px; opacity: .9; }
.band .tick { position: absolute; top: 1px; width: 1px; height: 13px; background: var(--chalk); }
/* An out-of-range median is a real upstream defect; make it unmissable. */
.band .tick.outside { background: var(--qb); width: 2px; }
.band .edge {
  position: absolute; top: -3px; font: var(--t-edge);
  color: var(--chalk-dim); font-variant-numeric: tabular-nums;
}
/* Fallback: the track ends. The page positions the two numbers at the FILL's
   real ends when it can measure them (see `edges-placed`) -- pinned to the
   container they said "the ceiling is the right end of the track", which for
   anyone below about rank 50 is the wrong end by most of the cell. */
.band .edge.lo { left: 0; } .band .edge.hi { right: 0; }
.band.edges-placed .edge.hi { right: auto; }

/* -- draft board tier shelves --------------------------------------------- */
.tier-break { border: 0; border-top: 1px solid var(--rule); position: relative;
  margin: 1.4rem 0 1.1rem; overflow: visible; }
.tier-break::after {
  content: attr(data-label); position: absolute; top: -0.72em; left: 0;
  background: var(--board); padding-right: .6rem;
  font: 600 .8rem/1.4 "Barlow Condensed", sans-serif; letter-spacing: .14em;
  text-transform: uppercase; color: var(--chalk-dim);
}

/* -- filter chips ---------------------------------------------------------- */
.filters { display: flex; gap: .5rem; flex-wrap: wrap; margin: 0 0 1rem; }
.filters button {
  background: none; border: 1px solid var(--rule); color: var(--chalk-dim);
  font: var(--t-chip); letter-spacing: .08em;
  text-transform: uppercase; padding: .45rem .8rem; border-radius: 4px; cursor: pointer;
}
.filters button[aria-pressed="true"] { color: var(--chalk); border-color: var(--chalk); }

.league-links { display: flex; flex-wrap: wrap; gap: .5rem; margin: 0 0 1rem; }
#league-context { display: flex; align-items: center; gap: .6rem 1rem; padding: .8rem 1rem; border: 1px solid var(--rule); }
main #league-context > label { display: flex; flex-direction: row; align-items: center; gap: .6rem; min-width: 0; }
#league-context select { padding: .5rem; font: inherit; max-width: 100%; }
#league-context p { flex-basis: 100%; order: 2; margin: 0; font-size: .85rem; color: var(--chalk-dim); }
#league-context > a { margin-left: auto; }
/* Identity chip (session design spec §6). The line (name · league · roster ·
   age) sits beside the league select; its controls -- the username form or
   the refresh/change/forget buttons -- sit below it and reuse the filter-chip
   button look. Text only: the controller sets textContent, never markup. */
.session-chip { display: flex; flex-wrap: wrap; align-items: center; gap: .35rem .8rem; flex: 1 1 14rem; min-width: 0; }
.session-text { flex: 1 1 12rem; min-width: 0; font-size: .9rem; color: var(--chalk); overflow-wrap: anywhere; }
.session-controls { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem .6rem; flex-basis: 100%; }
.session-controls:empty { display: none; }
.session-controls button, .session-form button {
  background: none; border: 1px solid var(--rule); color: var(--chalk-dim);
  font: var(--t-chip); letter-spacing: .08em;
  text-transform: uppercase; padding: .45rem .8rem; border-radius: 4px; cursor: pointer;
}
.session-controls button:hover, .session-form button:hover { color: var(--chalk); border-color: var(--chalk); }
.session-controls button[disabled] { opacity: .5; cursor: progress; }
.session-form { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem .6rem; margin: 0; }
.session-form label { display: flex; align-items: center; gap: .4rem; font-size: .85rem; color: var(--chalk-dim); }
.session-form input[type="text"] {
  background: var(--board-raised); border: 1px solid var(--rule); color: var(--chalk);
  padding: .4rem .6rem; border-radius: 4px; font: 400 .9rem/1.3 "Source Sans 3", sans-serif; min-width: 11rem;
}
.session-notice, #session-who { font-size: .85rem; color: var(--chalk-dim); }
.session-settings { font-size: .8rem; color: var(--chalk-dim); }
.session-settings:empty { display: none; }
.session-controls label { display: flex; align-items: center; gap: .4rem; font-size: .85rem; color: var(--chalk-dim); }
#session-who { color: var(--chalk); }
@media (max-width: 560px) {
  /* One compact row: league select · the chip line; details wrap below. */
  #league-context > label { flex: 0 1 auto; }
  #league-context select { min-width: 0; flex: 1; }
  #league-context > a { margin-left: 0; }
  .session-chip { flex: 1 1 8rem; }
  .session-text { font-size: .85rem; }
  .session-form input[type="text"] { min-width: 0; flex: 1; }
}
.league-links a {
  color: var(--chalk-dim); border: 1px solid var(--rule); border-radius: 4px;
  padding: .5rem .8rem; font: var(--t-chip); text-decoration: none;
}
.league-links a[aria-current="page"] { color: var(--chalk); border-color: var(--chalk); }

/* -- about page ------------------------------------------------------------ */
.prose { max-width: 68ch; }
.prose p { color: var(--chalk); }
.prose .lim { color: var(--chalk-dim); }
.report-meta { font: 500 .8rem/1.4 "IBM Plex Mono", monospace; color: var(--chalk-dim); }

/* -- about page: the evidence charts --------------------------------------
   Two figures carry the page's strongest claim (measured quantile coverage,
   then the walk-forward bake-off), so they sit on a sunken card above the
   prose. Every colour below is a token; the SVG marks are styled here rather
   than by inline attributes so the chart builder stays pure geometry. */
.evidence {
  background: var(--sunken); border: 1px solid var(--hairline);
  border-radius: 6px; padding: var(--s4); margin: 0 0 var(--s5);
}
.evidence h2 { margin: 0 0 var(--s2); }
.chart-lead { max-width: 62ch; margin: 0 0 var(--s4); color: var(--chalk); }
.chart-lead b {
  font: var(--t-num); font-size: 1.05rem; font-variant-numeric: tabular-nums;
  color: var(--chalk); white-space: nowrap;
}
/* max-width, NOT width: the SVG is authored at a measured pixel size so its
   labels render at their true token size. Stretching it to 100% would scale
   the type up with the viewBox. */
.chart svg { display: block; max-width: 100%; height: auto; }
.chart-note {
  font: 400 .8rem/1.5 "Source Sans 3", system-ui, sans-serif;
  color: var(--chalk-dim); max-width: 62ch; margin: var(--s3) 0 0;
}
/* The stated-absence path. A chart we cannot honestly draw says so. */
.chart-none {
  font: var(--t-num); color: var(--chalk-dim); margin: 0;
  padding: var(--s4); border: 1px dashed var(--rule); border-radius: 4px;
}
.chart-legend {
  display: flex; flex-wrap: wrap; gap: var(--s2) var(--s4); margin: 0 0 var(--s3);
}
.chart-legend > span { display: inline-flex; align-items: center; gap: var(--s2);
  font: var(--t-label); letter-spacing: .1em; text-transform: uppercase;
  color: var(--chalk-dim); }
.chart-legend .sw { display: inline-block; flex: none;
  width: .7rem; height: .7rem; border-radius: 2px; background: var(--chalk); }

/* SVG marks and furniture. */
.ax-grid { stroke: var(--hairline); stroke-width: 1; }
.ax-ref { stroke: var(--chalk); stroke-width: 1.5; }
.ax-tick { font: var(--t-edge); fill: var(--chalk-dim); }
.ax-title { font: var(--t-edge); fill: var(--chalk-dim); letter-spacing: .08em; }
.ax-ref-label { font: var(--t-label); letter-spacing: .14em; fill: var(--chalk); }
.row-label { font: var(--t-label); letter-spacing: .12em; fill: var(--chalk-dim); }
.val-label { font: var(--t-num); fill: var(--chalk); font-variant-numeric: tabular-nums; }
.val-sub { font: var(--t-edge); fill: var(--chalk-dim); font-variant-numeric: tabular-nums; }
.cal-bar { fill: var(--te); }
.dot-connector { stroke: var(--hairline); stroke-width: 2; stroke-linecap: round; }
/* 2px surface ring keeps overlapping dots readable (chart sits on --sunken). */
.dot { fill: var(--chalk); stroke: var(--sunken); stroke-width: 2; }
/* Colour follows the model, not its rank: the transformer is amber on both
   charts. Validated for CVD separation against the board surface. */
.m-transformer { fill: var(--te); }
.m-xgboost { fill: var(--wr); }
.m-naive_last4 { fill: var(--qb); }
.chart-legend .sw.m-transformer { background: var(--te); }
.chart-legend .sw.m-xgboost { background: var(--wr); }
.chart-legend .sw.m-naive_last4 { background: var(--qb); }

footer { max-width: 1080px; margin: 2rem auto 0; padding: 1rem 1.25rem 2rem;
  border-top: 1px solid var(--rule); color: var(--chalk-dim); font-size: .85rem; }

@media (max-width: 560px) {
  .band { width: 110px; }
  .band .edge { display: none; }
  main { padding: .9rem; }
  .evidence { padding: var(--s3); }

  /* Compact masthead. At 390px the five links wrapped onto three lines and,
     with the stamp and the flex row-gaps, the header alone consumed ~260px
     before the league panel. Nothing is hidden here -- every link, its
     "· Gabagool only" / "· not connected" suffix, the active-page rule and
     the stamp stay visible -- the rows are just tighter and the type a step
     smaller so the nav settles onto two lines instead of three. */
  .masthead { gap: .5rem .9rem; padding: .8rem .9rem .6rem; }
  .wordmark { font-size: 1.15rem; }
  .masthead nav { gap: .15rem .7rem; margin-left: 0; width: 100%; }
  .masthead nav a { font-size: .82rem; letter-spacing: .06em; padding: .25rem 0; }
  .stamp { font-size: .7rem; line-height: 1.3; }

  /* The league panel and page title follow the same rhythm. */
  #league-context { padding: .6rem .8rem; gap: .5rem .8rem; }
  #league-context p { font-size: .8rem; }
  h1 { font-size: 1.55rem; margin-bottom: .7rem; }
}

/* -- draft mode ----------------------------------------------------------- */
.draft-panel { border: 1px solid var(--rule); border-radius: 6px; margin: 0 0 1rem; }
.draft-panel summary {
  cursor: pointer; padding: .55rem .9rem;
  font: var(--t-nav); letter-spacing: .09em;
  text-transform: uppercase; color: var(--chalk-dim);
}
.draft-panel[open] summary { color: var(--chalk); border-bottom: 1px solid var(--rule); }
.draft-status {
  margin-left: .6rem; font: var(--t-mono-sm);
  text-transform: none; letter-spacing: .02em;
}
.draft-body { padding: .8rem .9rem; display: grid; gap: .6rem; }
.draft-row { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; }
.draft-row input[type="text"] {
  background: var(--board-raised); border: 1px solid var(--rule); color: var(--chalk);
  padding: .4rem .6rem; border-radius: 4px;
  font: 400 .9rem/1.3 "Source Sans 3", sans-serif; min-width: 14rem;
}
.draft-row button {
  background: none; border: 1px solid var(--rule); color: var(--chalk-dim);
  font: var(--t-chip); letter-spacing: .08em;
  text-transform: uppercase; padding: .45rem .8rem; border-radius: 4px; cursor: pointer;
}
.draft-row button:hover { color: var(--chalk); border-color: var(--chalk); }
#manual-panel textarea { background: var(--board-raised); color: var(--chalk);
  border: 1px solid var(--rule); border-radius: 4px; padding: .5rem;
  font: 400 .9rem/1.5 "IBM Plex Mono", monospace; resize: vertical; }
#manual-panel details > label { display: block; margin-top: .5rem; }
#manual-panel details button { background: var(--board-raised); color: var(--chalk);
  border: 1px solid var(--rule); border-radius: 4px; padding: .35rem .6rem;
  cursor: pointer; margin: .25rem; }
#manual-history { overflow-wrap: anywhere; }
#manual-save-note { border-left: 3px solid var(--chalk-dim); padding-left: .6rem; }
.draft-row label { font: 500 .85rem/1.3 "Source Sans 3", sans-serif; color: var(--chalk-dim); }
.draft-roster, .draft-note, .draft-ticker, .draft-shortlist-panel, .draft-late { margin: 0; font: 500 .82rem/1.4 "IBM Plex Mono", monospace;
  color: var(--chalk-dim); }

tr.drafted td { opacity: .38; }
tr.drafted td:nth-child(3) { text-decoration: line-through; }
tr.mine td { opacity: 1; }
tr.mine { background: color-mix(in srgb, var(--te) 12%, transparent); }
tr.mine td:nth-child(3) { text-decoration: none; }

/* -- rookie chip ---------------------------------------------------------- */
.rookie-chip {
  display: inline-block; margin-left: .35rem; padding: 0 .3rem;
  font: var(--t-micro); letter-spacing: .06em;
  border: 1px solid var(--te); border-radius: 3px; color: var(--te);
}

/* Returning from a season-ending injury. Deliberately louder than the rookie
   chip: it is the one mark on this board that says a number BELOW is lower on
   purpose, and an unexplained low floor reads as a bad projection. */
.returning-chip {
  display: inline-block; margin-left: .35rem; padding: 0 .3rem;
  font: var(--t-micro); letter-spacing: .06em;
  border: 1px solid var(--rb); border-radius: 3px; color: var(--rb);
  background: rgba(255, 255, 255, .04);
}

/* Pick-time optimizer shortlist. Read top-down on the clock: chip for
   position, name, what passing costs, then the reasoning. */
.draft-shortlist { margin: .45rem 0 0; padding: 0; list-style: none; }
.draft-shortlist .pick {
  display: grid; gap: .1rem .5rem; align-items: baseline;
  grid-template-columns: 2.6em 1fr auto;
  padding: .3rem .45rem; border-left: 2px solid transparent; border-radius: 3px;
}
.draft-shortlist .pick + .pick { margin-top: .15rem; }
/* The recommendation. Everything below it is an alternative, so only this row
   gets weight -- a shortlist where all five rows shout says nothing. */
.draft-shortlist .pick-top {
  background: color-mix(in srgb, var(--te) 10%, transparent);
  border-left-color: var(--te);
}
.pick-name { font: 600 .9rem/1.4 "Source Sans 3", sans-serif; color: var(--chalk); }
.pick-top .pick-name { font-size: .97rem; }
.pick-cost { font: 600 .8rem/1.4 "IBM Plex Mono", monospace; color: var(--chalk-dim);
  text-align: right; font-variant-numeric: tabular-nums; }
.pick-top .pick-cost { color: var(--te); letter-spacing: .05em; text-transform: uppercase;
  font-size: .72rem; }
.pick-role {
  font: 600 .68rem/1.5 "Barlow Condensed", sans-serif; letter-spacing: .07em;
  text-transform: uppercase; color: var(--chalk); border: 1px solid var(--rule);
  border-radius: 3px; padding: 0 .3rem;
}
.pick-why {
  grid-column: 2 / -1; font: 500 .76rem/1.5 "IBM Plex Mono", monospace;
  color: var(--chalk-dim); display: flex; flex-wrap: wrap; gap: .15rem .45rem;
  align-items: baseline;
}
.pick-fell { color: var(--rb); }      /* bargain: he lasted past his ADP */
.pick-reach { color: var(--qb); }     /* you would be paying ahead of market */
.pick-bye { color: var(--te); }
/* what is still empty in your lineup -- the one thing the counts don't say */
.roster-open { color: var(--te); }
.roster-set { color: var(--rb); }
.draft-basis { margin: .5rem 0 0; font: 500 .74rem/1.5 "IBM Plex Mono", monospace;
  color: var(--chalk-dim); opacity: .85; }
.draft-basis em { font-style: normal; color: var(--chalk); }
/* Why there is no shortlist. Reads as a notice, not as a recommendation. */
.draft-blocked { margin: 0; padding: .5rem .6rem; border-left: 2px solid var(--te);
  background: rgba(255, 255, 255, .03); font: 500 .78rem/1.5 "IBM Plex Mono", monospace;
  color: var(--chalk-dim); }
/* The one thing the shortlist below it CANNOT tell you. It sits above the
   recommendations rather than beside them because the workflow is "read the
   list, take number one" -- a notice off to the side was drafted straight past
   in two consecutive mocks, both ending with no kicker and no defense. */
.draft-late-need { margin: 0 0 .6rem; padding: .5rem .6rem;
  border-left: 2px solid var(--qb); background: rgba(214, 69, 69, .10);
  font: 500 .78rem/1.5 "IBM Plex Mono", monospace; color: var(--chalk); }
.draft-late-need strong { color: var(--qb); }
.draft-late-names { color: var(--chalk-dim); }
.draft-late-need em { font-style: normal; opacity: .75; }
.draft-late { margin-top: .4rem; }
.draft-late em { opacity: .75; }

@media (max-width: 33rem) {
  .draft-shortlist .pick { grid-template-columns: 2.6em 1fr; }
  .pick-cost { grid-column: 2; text-align: left; }
}

/* Trade calculator. Two asset columns; a selected asset is part of the offer. */
.trade-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-top: 1rem; }
@media (max-width: 700px) { .trade-cols { grid-template-columns: 1fr; } }
.trade-cols h2 { margin: 0 0 .2rem; }
.trade-col-note { margin: 0 0 .5rem; font: 500 .86rem/1.5 "IBM Plex Mono", monospace;
  color: var(--chalk-dim); }
.trade-assets { list-style: none; margin: 0; padding: 0; max-height: 36rem; overflow-y: auto; }
.trade-assets li { display: flex; justify-content: space-between; align-items: center; gap: .6rem;
  padding: .55rem .65rem; border-bottom: 1px solid rgba(255,255,255,.08);
  font: 500 1rem/1.45 "IBM Plex Mono", monospace; cursor: pointer; }
.trade-assets input[type="checkbox"] { width: 1.15rem; height: 1.15rem; flex: none; accent-color: var(--rb); }
.trade-assets li:hover { background: rgba(255,255,255,.04); }
.trade-assets li.picked { background: rgba(255,255,255,.09); border-left: 2px solid var(--rb); }
/* An ineligible player is not a quiet zero -- he is worth nothing to trade and
   the page has to say why, because it is the least intuitive rule in the league.
   An unpriced player is dimmed the same way but for a different reason, so it
   gets its own class: "we have no opinion" must not read as "he is worthless". */
.trade-assets li.trade-ineligible { opacity: .55; cursor: not-allowed; }
.trade-assets li.trade-ineligible .trade-why { color: var(--te); }
.trade-assets li.trade-unvalued { opacity: .55; cursor: not-allowed; }
.trade-asset-name { color: var(--chalk); white-space: nowrap; }
/* The reason wraps, the name does not: a name broken across two lines is
   harder to scan than a reason that is already a sentence. */
.trade-why { opacity: .85; font-size: .86rem; text-align: right; min-width: 0; }
.trade-gain-pos { color: var(--rb); }
.trade-gain-neg { color: var(--te); }
/* The three numbers. Sized above the reasoning beneath them, which is the
   thing you check them against. */
#trade-grade, #trade-suggestions { margin-top: 1rem; }
.trade-verdict {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s3);
  font: 700 1.5rem/1.1 "Barlow Condensed", sans-serif;
  font-variant-numeric: tabular-nums;
  padding: var(--s3) 0; border-bottom: 1px solid var(--rule);
}
.trade-verdict strong { font-size: 1.9rem; }
.trade-market { font: var(--t-num); color: var(--chalk-dim); }
/* Trade page only: the shared .draft-basis disclaimer paragraph (also used by
   the draft board's shortlist copy) gets a readable-prose override here
   instead of a global rewrite, so this task's typography change doesn't
   bleed into the unrelated draft board page. */
#trade-grade .draft-basis {
  font: 400 .78rem/1.6 "Source Sans 3", system-ui, sans-serif;
  color: var(--chalk-dim); max-width: 68ch;
}
.trade-suggestions { margin: .45rem 0 0; padding: 0 0 0 1.4rem; }
.trade-suggestions li { margin-bottom: .45rem; }
.trade-offer { display: block; color: var(--chalk);
  font: 500 .82rem/1.5 "IBM Plex Mono", monospace; }
.trade-nums { display: block; font: 500 .78rem/1.5 "IBM Plex Mono", monospace; }
.trade-load { margin-top: .15rem; background: none; border: 1px solid var(--rule);
  color: var(--chalk-dim); font: 600 .7rem/1 "Barlow Condensed", sans-serif;
  letter-spacing: .08em; text-transform: uppercase; padding: .25rem .5rem;
  border-radius: 4px; cursor: pointer; }
.trade-load:hover { color: var(--chalk); border-color: var(--chalk); }
.draft-row select { background: var(--board-raised); border: 1px solid var(--rule);
  color: var(--chalk); padding: .35rem .4rem; border-radius: 4px;
  font: 400 .9rem/1.3 "Source Sans 3", sans-serif; }
.draft-row input[type="number"] { background: var(--board-raised);
  border: 1px solid var(--rule); color: var(--chalk); padding: .35rem .4rem;
  border-radius: 4px; font: 400 .9rem/1.3 "Source Sans 3", sans-serif; }
/* A disabled button must not look pressable -- the suggester freezes the page
   for ~8 seconds and the button is the only thing saying so. */
.draft-row button[disabled] { opacity: .5; cursor: progress; }
.draft-row button[disabled]:hover { color: var(--chalk-dim); border-color: var(--rule); }
/* [hidden] has to WIN. The UA sheet's `[hidden] { display: none }` is beaten by
   any author rule that sets display -- `.draft-row { display: flex }` and
   `.trade-cols { display: grid }` both do -- so panels marked hidden in the
   markup rendered anyway. Measured in Chrome before this rule: #draft-live (the
   "Disconnect / hide drafted" row, index.html, pre-existing) and #trade-controls
   / #trade-cols (trade.html) all had display:flex|grid and non-zero height while
   el.hidden was true, i.e. the trade page opened showing an empty partner
   dropdown and two empty asset columns before a league was ever loaded. */
[hidden] { display: none !important; }

/* -- in-season trade scenario (trade.html, #season-trade) ---------------- */
/* Rows are checkbox labels, not click-to-toggle items, and each may carry an
   "assume unavailable weeks" field that wraps under the name. */
#season-trade .trade-assets li { flex-wrap: wrap; cursor: default; }
#season-trade .trade-assets li label { display: flex; align-items: center; gap: .35rem;
  cursor: pointer; flex: 1 1 auto; color: var(--chalk); }
#season-trade .trade-assets li.season-disabled { opacity: .55; }
#season-trade .trade-assets li.season-disabled label { cursor: not-allowed; }
.season-weeks { flex: 1 1 100%; background: var(--board-raised); border: 1px solid var(--rule);
  color: var(--chalk); padding: .25rem .4rem; border-radius: 4px;
  font: 400 .95rem/1.35 "Source Sans 3", sans-serif; }
.season-weeks-error { flex: 1 1 100%; color: var(--te); font-size: .86rem; }
/* A side over the roster limit marks its drops in its own column (Drop buttons on the rows); this line says how many. */
.season-drop-prompt { display: block; color: var(--chalk); padding: .45rem .65rem; border-left: 3px solid var(--accent);
  background: rgba(255,255,255,.05); font: 600 .95rem/1.4 "Source Sans 3", sans-serif; }
.season-drop-btn { flex: none; margin-left: auto; padding: .2rem .65rem; border: 1px solid var(--rule); border-radius: 4px;
  background: transparent; color: var(--chalk); cursor: pointer; font: 600 .86rem/1.3 "Source Sans 3", sans-serif; }
.season-drop-btn:hover { border-color: var(--chalk-dim); }
.season-drop-btn[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); }
#season-trade .trade-assets li.season-dropping label { text-decoration: line-through; opacity: .6; }
/* The note/status "overlap": .draft-note and .draft-row both carry zero
   margin (they were written for the draft panel's grid, which spaces them with
   `gap`), so outside that grid the status line sat flush against the note's
   last line, and the status font's line-height (1.2) is shorter than its glyph
   box, so the two lines' ink touched. Space the section's blocks explicitly. */
#season-note { margin: 0 0 .9rem; max-width: 68ch; }
#season-connect, #season-controls { margin-bottom: .6rem; }
#season-connect .draft-status { margin-left: 0; line-height: 1.4; }
.season-steps { margin: .2rem 0 .6rem; padding-left: 1.4rem;
  font: 400 .95rem/1.5 "Source Sans 3", sans-serif; color: var(--chalk); }
.season-weeks-toggle { background: none; border: none; padding: 0 0 0 1.6rem;
  color: var(--chalk-dim); text-decoration: underline; cursor: pointer;
  font: 400 .9rem/1.3 "Source Sans 3", sans-serif; }
.season-weeks-toggle:hover { color: var(--chalk); }
.season-summary { margin: 0 0 .9rem; padding: .6rem .8rem; border-left: 3px solid var(--chalk-dim);
  background: var(--board-raised); }
.season-summary p { margin: .15rem 0; font: 400 .95rem/1.45 "Source Sans 3", sans-serif; color: var(--chalk); }
.season-detail { margin: .5rem 0; }
.season-detail > summary { cursor: pointer; font: 600 .8rem/1.2 "Barlow Condensed", sans-serif;
  letter-spacing: .08em; text-transform: uppercase; color: var(--chalk-dim); }
.season-detail[open] > summary { color: var(--chalk); margin-bottom: .2rem; }
#season-result { margin-top: 1rem; }
#season-result h3 { margin: .8rem 0 .2rem; font: 600 .8rem/1.2 "Barlow Condensed", sans-serif;
  letter-spacing: .08em; text-transform: uppercase; color: var(--chalk-dim); }
.season-headline { margin: 0; }
.season-headline strong { font: 700 1.2rem/1.2 "Barlow Condensed", sans-serif; color: var(--chalk); }
.season-subline { margin: .3rem 0 .6rem; }
.season-table { margin: .4rem 0 .8rem; }
.season-table th, .season-table td { white-space: normal; font-size: .78rem; padding: .3rem .5rem; }
.season-list { margin: .2rem 0; padding-left: 1.2rem; }
.season-eval { margin: .15rem 0; }

/* -- keeper panel ------------------------------------------------------ */
.keeper-panel {
  background: var(--sunken); border: 1px solid var(--rule);
  padding: var(--s3) var(--s4); margin: var(--s4) 0;
}
.keeper-panel > summary {
  font: var(--t-chip); letter-spacing: .13em; text-transform: uppercase;
  color: var(--chalk-dim); cursor: pointer;
}
.keeper-panel > summary::marker { color: var(--rule); }
.keeper-help, .keeper-depletion {
  font: 400 .8rem/1.5 "Source Sans 3", system-ui, sans-serif;
  color: var(--chalk-dim); margin: var(--s2) 0 0;
}
.keeper-load, .keeper-add { display: flex; gap: var(--s2); margin-top: var(--s3); flex-wrap: wrap; }
.keeper-load input:not([type="checkbox"]), .keeper-add input:not([type="checkbox"]), .keeper-load select, .keeper-add select {
  background: var(--board); color: var(--chalk);
  border: 1px solid var(--rule); padding: var(--s1) var(--s2);
  font: var(--t-num);
}
.keeper-load button, .keeper-add button {
  background: var(--board-raised); color: var(--chalk);
  border: 1px solid var(--rule); padding: var(--s1) var(--s3);
  font: var(--t-label); letter-spacing: .1em; text-transform: uppercase;
  cursor: pointer;
}
.keeper-load button:hover, .keeper-add button:hover { border-color: var(--chalk-dim); }
/* These print CHANGING values (keepers.js:274,278) in the proportional body
   font, so their digits reflow as numbers update. This is the one surface on
   the site that genuinely needed tabular figures -- the board and weekly
   tables already declare them (style.css `td.num, th.num`). */
.keeper-rec {
  font: var(--t-num); font-variant-numeric: tabular-nums;
  display: block; padding: var(--s1) 0; color: var(--rb);
}
.keeper-out {
  font: var(--t-num); font-variant-numeric: tabular-nums;
  margin: var(--s2) 0 0; padding-left: var(--s5); color: var(--chalk-dim);
}
.keeper-out li { padding: var(--s1) 0; }

/* `th, td { white-space: nowrap }` is inherited here, which makes every
   paragraph in the panel one unwrappable line and widens the whole table
   (1212 -> 1364 at 1280 on an ADP-less row). The panel is prose; it wraps. */
tr.detail > td { background: var(--sunken); border-bottom: 1px solid var(--rule); padding: var(--s4); white-space: normal; }
/* The `colspan` cell is as wide as the table, so a full-width grid put its third
   column ~155px past the scrollport's right edge (clipped mid-word). Size the
   panel to the wrap's visible width instead, and stick it at the same inset as
   the cell's padding so horizontal scrolling of the board leaves it in place
   (it holds still rather than sliding out of view). */
.detail-grid {
  display: grid; grid-template-columns: 1.35fr 1fr 1fr; gap: var(--s5); align-items: start;
  position: sticky; left: var(--s4); width: calc(100cqi - 2 * var(--s4));
}
.detail-grid .label { font: var(--t-label); letter-spacing: .14em; text-transform: uppercase; color: var(--chalk-dim); margin-bottom: var(--s2); }
.ridge { width: 100%; height: 54px; display: block; }
/* Fallback layout, used only when a player has no band to place against.
   `.placed` is set by the page once the real p10/p50/p90 fractions are known:
   `space-between` pinned FLOOR/MED/CEILING to 0/50/100% of the SVG while the
   ridge is drawn at the player's true position on the shared domain. */
.ridge-cap { display: flex; justify-content: space-between; font: 500 .6rem/1 "IBM Plex Mono", monospace; color: var(--chalk-dim); font-variant-numeric: tabular-nums; }
.ridge-cap.placed { display: block; position: relative; height: .6rem; }
.ridge-cap.placed > * { position: absolute; top: 0; white-space: nowrap; }
.ridge-cap b { color: var(--chalk); }
.detail-grid .kv { display: flex; justify-content: space-between; padding: var(--s1) 0; border-bottom: 1px solid var(--hairline); font: var(--t-num); font-variant-numeric: tabular-nums; }
.detail-grid .kv b { color: var(--chalk); }
.detail-grid .kv b.good { color: var(--rb); }
.detail-grid .kv b.warn { color: var(--te); }
.detail-grid .big { font: 700 1.5rem/1 "Barlow Condensed", sans-serif; color: var(--chalk); font-variant-numeric: tabular-nums; }
.detail-grid .big .unit { font-size: 1rem; color: var(--chalk-dim); }
.detail-note, .detail-none { font: 400 .72rem/1.5 "Source Sans 3", system-ui, sans-serif; color: var(--chalk-dim); margin: var(--s2) 0 0; }
/* Figure footnote: names the assumption the ridge draws. Set below the note
   it qualifies so it reads as apparatus, not as another finding. */
.detail-fine { font: 400 .66rem/1.45 "Source Sans 3", system-ui, sans-serif; color: var(--chalk-faint, var(--chalk-dim)); opacity: .72; margin: var(--s2) 0 0; }
@media (max-width: 800px) { .detail-grid { grid-template-columns: 1fr; gap: var(--s3); } }

/* Which opponent a league-wide suggestion belongs to. Sits above the offer so
   the team is read before the assets: in a sweep the same package can be worth
   trading with one manager and not another. */
.trade-suggestions .trade-with {
  display: block;
  font: 600 0.78rem/1.4 "Barlow Condensed", system-ui, sans-serif;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted, #8a949c);
}
