/* ==========================================================================
   Hoops Redraft — broadcast-terminal design system.

   The organising idea: every screen carries three weights — HERO (one number
   that answers "how am I doing"), SUPPORT (the data), CHROME (labels, prose).
   An earlier version had one font at one size inside identical boxes, so
   nothing was more important than anything else and the eye had nowhere to
   land.

   Two families do the work. A proportional display face carries names and big
   numerals; mono carries data. The contrast between them is what reads as a
   stats broadcast — mono alone just reads as a wall of text.

   Colour has exactly three jobs:
     amber      = you, and now. Your row, your pick, the live thing.
     green/red  = won and lost. Nothing else.
     warm ramp  = quality, expressed as brightness rather than hue, so a
                  rating can never be mistaken for a result.
   ========================================================================== */

:root {
  --bg: #0b0d10;
  --panel: #14181d;
  --panel-2: #1b2027;
  --line: #262d36;
  --ink: #e8edf2;
  --ink-2: #aab6c2;
  --muted: #7d8996;
  --accent: #ffb400;
  --good: #35c98a;
  --bad: #e2574c;

  /* Quality ramp — luminance, not hue. */
  --tier-4: #f2d999;
  --tier-3: #d7dee6;
  --tier-2: #94a1ae;
  --tier-1: #8794a1;

  /* .topbar's own rendered height, measured (46px at every width from 360 to
     1280 — its tallest child is a .phase tab, which does not change size
     across breakpoints). Used below as .topbar's own min-height, so its
     sticky-top strip does not reflow as content loads in beneath it.

     This used to also be the fix for a real collision: .onclock/.waiting
     were position:sticky;top:0 too, so they fought .topbar for the same
     strip of screen, and this variable was the offset that separated them.
     That box has since moved into .actionbar, sticky to the BOTTOM of the
     screen on every screen in the game — there is no second sticky-top box
     left to collide with .topbar, so this variable no longer does that
     job. */
  --topbar-h: 46px;

  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --display: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
             "Helvetica Neue", Arial, sans-serif;
  --display-cond: "Helvetica Neue Condensed", "Arial Narrow",
                  "Roboto Condensed", var(--display);

  --t-hero: clamp(40px, 8vw, 60px);
  --t-1: clamp(21px, 3.2vw, 28px);
  --t-2: 20px;
  --t-3: 16px;
  --t-body: 14px;
  --t-micro: 11px;
  /* The uppercase tracked labels. They were 9px — legible on the machine this
     was built on, a squint on anything else. A label you have to lean in to
     read is not doing the job a label exists for. */
  --t-label: 10px;

  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 24px; --sp-6: 40px;
}

* { box-sizing: border-box; }

/* The browser's own [hidden] rule is display:none, but it lives in the
   user-agent stylesheet, and an author rule wins any specificity tie against
   the UA origin regardless of source order. .phasenav and .status are both a
   plain class selector — the same specificity as [hidden] — so their own
   `display: flex` silently beat `hidden` and both rendered on the setup
   screen, before a run even exists, at every width. Any future element using
   the `hidden` attribute would hit the same trap the moment it also had an
   author `display` rule, so the fix is general rather than patching the two
   selectors that happened to be caught this time. */
[hidden] { display: none !important; }

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

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

.topbar {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  gap: var(--sp-4); align-items: center;
  padding: 0 var(--sp-4);
  min-height: var(--topbar-h);
  border-bottom: 1px solid var(--line);
  background: var(--panel);
  position: sticky; top: 0; z-index: 20;
}
/* Abandon's own row, off the crowded nav — see the comment on #btn-reset in
   index.html. :has() collapses the row to nothing on the setup screen,
   where the button itself is [hidden], instead of leaving an empty strip
   with its own border sitting above the setup form.

   Now a child of .topbar (moved inside <header> for the landmark fix — see
   index.html), which makes it a FOURTH grid item on .topbar's three-column
   template. Without its own placement it auto-flows into a new implicit
   row starting at column 1 — and, still being an in-flow grid item, its
   content width feeds into that "auto" column's sizing across every row,
   not just its own. Column 1 had only ever sized itself to .brand before;
   with .subbar added to the pressure on it too, the "auto" column grew and
   the middle minmax(0, 1fr) column (.phasenav) lost the width, which was
   tight enough already (17-20px of slack at the two required phone widths)
   to overflow again — the exact bug the phase-nav-fit commit fixed.
   Spanning the full row keeps it out of that column-sizing calculation. */
.subbar { grid-column: 1 / -1; display: flex; justify-content: flex-end;
          padding: var(--sp-2) var(--sp-4); border-bottom: 1px solid var(--line); }
.subbar:has(#btn-reset[hidden]) { display: none; }
.brand {
  font-family: var(--display-cond); font-weight: 800; font-size: 15px;
  letter-spacing: .04em; text-transform: uppercase; white-space: nowrap;
}
.brand span { color: var(--accent); margin-left: 5px; }
/* privacy.html links the wordmark home; index.html's is plain text and never
   sees this rule. */
.brand a { color: inherit; text-decoration: none; }

/* Phase nav. Past phases stay reachable, so a run stops being a one-way
   corridor where every screen ends in a single button. */
.phasenav { display: flex; gap: 2px; overflow-x: auto; scrollbar-width: none; }
.phasenav::-webkit-scrollbar { display: none; }
.phase {
  background: none; border: 0; border-bottom: 2px solid transparent;
  color: var(--muted); font-family: var(--mono); font-size: var(--t-micro);
  font-weight: 700; letter-spacing: .14em; padding: 15px var(--sp-3);
  cursor: pointer; white-space: nowrap;
}
.phase[aria-current="page"] { color: var(--accent); border-bottom-color: var(--accent); }
.phase[data-state="done"] { color: var(--ink-2); }
.phase[data-state="done"]:hover { color: var(--ink); }
.phase[data-state="locked"] { opacity: .28; pointer-events: none; }

.status { display: flex; gap: var(--sp-4); }
.status .stat span {
  display: block; font-size: 10px; letter-spacing: .14em;
  color: var(--muted); text-transform: uppercase;
}
.status .stat b {
  font-family: var(--display); font-size: var(--t-3); font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Progress belongs to the whole run, so it rides on the bar rather than
   floating loose above a panel. */
.runbar { position: absolute; left: 0; bottom: -1px; height: 2px;
          background: var(--accent); transition: width .12s linear; }

main { max-width: 1240px; margin: 0 auto; padding: var(--sp-5) var(--sp-4) var(--sp-6); }

/* A plain reading column, for the pages that are only words. */
.prose { max-width: 62ch; margin: 0 auto; padding: 24px 16px 48px; }
.prose h2 { margin-top: 28px; }
.prose ul { padding-left: 20px; }
.prose li { margin-bottom: 8px; }
/* No base a{} rule exists sitewide, so links here would otherwise fall back
   to the browser default blue instead of the site's own palette. */
.prose a { color: var(--accent); }

.footnote {
  max-width: 1240px; margin: 0 auto; padding: var(--sp-4);
  color: var(--muted); font-size: var(--t-micro); line-height: 1.7;
  border-top: 1px solid var(--line);
}
.footnote p { margin: 0; }
.footnote a, .footnote summary { color: var(--muted); }
.footnote summary { cursor: pointer; display: inline; }
.footnote details { display: inline; }

/* ------------------------------------------------------------------ sign-up */

/* Capped so the field and button size to their content on a wide screen
   instead of stretching the row to the footer's full width, which is what
   made this the loudest ask on the page. */
#signup { margin: 0 0 10px; max-width: 420px; }
#signup label { display: block; margin-bottom: 4px; font-weight: 600; }
.signup-row { display: flex; flex-wrap: wrap; gap: 8px; }
/* 16px is not a design choice: iOS Safari zooms any input below it on focus
   and never zooms back, which strands you on a sideways-scrolling page. */
#signup input[name="email"] {
  flex: 1 1 220px; min-height: 44px; padding: 0 12px; font-size: 16px;
}
/* Sizing only: the .ghost class on the button (in the markup) carries the
   outline look, so this stays the same shape as "Abandon" rather than the
   site's one amber primary. */
#signup button { min-height: 44px; padding: 0 16px; font-size: 16px; cursor: pointer; }
#signup-msg { margin: 4px 0 0; min-height: 1.2em; }
#signup-msg[data-state="bad"] { color: var(--bad); }

/* Out of sight without display:none, which some bots skip. The UA stylesheet
   puts a border and padding on every text input; without zeroing them here
   the border-box floor keeps this at 8px wide no matter what width says. */
#signup input[name="website"] {
  position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0;
  border: 0; padding: 0;
}

/* ------------------------------------------------------------------- type */

h1 {
  font-family: var(--display-cond); font-size: var(--t-1); font-weight: 800;
  letter-spacing: -.02em; text-transform: uppercase; margin: 0 0 var(--sp-2);
}
/* Section headings recede rather than compete — there are four to six per
   screen and they used to sit at nearly body size. */
h2 {
  font-family: var(--mono); font-size: var(--t-micro); font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase; color: var(--muted);
  margin: 0 0 var(--sp-3);
}
h3.subhead {
  font-family: var(--mono); font-size: var(--t-micro); font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase; color: var(--muted);
  margin: var(--sp-4) 0 var(--sp-2);
}
h3.subhead:first-of-type { margin-top: 0; }

/* Prose goes proportional so it can never be mistaken for data. */
.lede, .hint { font-family: var(--display); color: var(--muted); max-width: 56ch; }
.hint { font-size: 13px; }
.lede { font-size: var(--t-3); margin: 0 0 var(--sp-5); }
/* The setup screen's cost line ("Free, no account...") sits directly under
   the lede, not a panel — .hint has no margin of its own everywhere else it
   is used, so without this it would butt straight up against the lede above
   and run straight into the first panel below. */
.lede + .hint { margin: calc(-1 * var(--sp-3)) 0 var(--sp-5); }

/* ------------------------------------------------------------------- hero */

.hero { display: flex; align-items: baseline; gap: var(--sp-5); flex-wrap: wrap;
        margin: 0 0 var(--sp-4); }
.hero-main { display: flex; flex-direction: column; }
/* Sits directly above the number it belongs to, so a label like "Projected"
   reads as this number's name rather than a caption for the whole hero. */
.hero-label {
  font-family: var(--mono); font-size: 10px; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase; color: var(--muted);
  margin-bottom: 2px;
}
.hero-num {
  font-family: var(--display-cond); font-size: var(--t-hero); font-weight: 800;
  letter-spacing: -.03em; line-height: .85; font-variant-numeric: tabular-nums;
}
/* Stacked directly under .hero-num, inside .hero-main, so the word reads as
   this number's own — sitting beside it instead made it look like it
   belonged to whatever followed. */
.hero-qual {
  font-family: var(--mono); font-size: var(--t-micro); font-weight: 700;
  letter-spacing: .18em; color: var(--accent); text-transform: uppercase;
  margin-top: 4px;
}
/* Off and Def: a clear step down from the hero number, but on the same
   league-relative scale, so each gets the same treatment — a size nothing
   in .hero-sub competes with, and its own quality word, not just a bare
   rating beside one that has none. */
.hero-stats { display: flex; gap: var(--sp-5); flex-wrap: wrap;
              align-self: flex-end; padding-bottom: .1em; }
.hero-stat { display: flex; flex-direction: column; }
.hero-stat b {
  font-family: var(--display-cond); font-size: var(--t-1); font-weight: 800;
  line-height: .9; font-variant-numeric: tabular-nums;
}
.hero-stat i {
  font-style: normal; font-family: var(--mono); font-size: 9px; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase; color: var(--accent);
}
.hero-stat span {
  font-family: var(--mono); font-size: var(--t-label); letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted); margin-top: 2px;
}
.hero-sub { display: flex; gap: var(--sp-5); flex-wrap: wrap;
            align-self: flex-end; padding-bottom: .35em; }
.hero-sub b {
  font-family: var(--display); font-size: 20px; font-weight: 700;
  font-variant-numeric: tabular-nums; display: block; line-height: 1.1;
}
.hero-sub span {
  display: block; font-size: 10px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--muted);
}
/* The line under the hero that finishes its sentence — "of 12 in the Western
   Conference" — rather than splitting the ordinal and its field across two
   separate boxes on opposite sides of the word that explains them. */
.hero-caption { margin: -6px 0 var(--sp-4); }

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

.panel { background: var(--panel); border: 1px solid var(--line);
         padding: var(--sp-4); margin-bottom: var(--sp-4); }
.grid { display: grid; gap: var(--sp-4); }
/* Panels size to their contents. Stretching each to its tallest neighbour left
   the season-preview rotation as a short list floating in half a screen of
   empty box. */
.grid { align-items: start; }
.grid.two { grid-template-columns: 1fr 1fr; }
.grid.side { grid-template-columns: 1.4fr 1fr; }
/* The other way round, for a screen whose subject is the table rather than your
   own eight men. */
.grid.wide-right { grid-template-columns: 1fr 1.7fr; }
/* A two-column grid holding one panel is a page with a hole in it. The squad
   screen before the draft was the worst of them: a 695px list of six men beside
   490px of nothing, on a screen 1,210px wide. When there is no second column,
   the one panel takes a comfortable measure and the rest reads as margin
   instead of as a missing sidebar. */
.grid.two:has(> :only-child),
.grid.side:has(> :only-child),
.grid.wide-right:has(> :only-child) { grid-template-columns: minmax(0, 900px); }

@media (max-width: 900px) { .grid.two, .grid.side, .grid.wide-right { grid-template-columns: 1fr; } }

/* --------------------------------------------------------------- controls */

button {
  font-family: var(--mono); font-size: var(--t-body);
  background: var(--accent); color: #16181b; border: 0;
  padding: 11px 20px; cursor: pointer; font-weight: 700; letter-spacing: .06em;
}
button:hover { filter: brightness(1.1); }
button:disabled { opacity: .35; cursor: not-allowed; filter: none; }
button.ghost {
  background: transparent; color: var(--muted); border: 1px solid var(--line);
  font-weight: 500; padding: 7px 13px;
}
button.ghost:hover { color: var(--ink); border-color: var(--muted); }

/* The primary action is always in reach, never 1,300px down the page. */
.actionbar {
  position: sticky; bottom: 0; z-index: 10;
  display: flex; gap: var(--sp-3); align-items: center; justify-content: space-between;
  padding: var(--sp-3) var(--sp-4); margin: var(--sp-5) calc(var(--sp-4) * -1) 0;
  /* Solid, not a fade. The gradient was transparent across its top third, so
     whatever you were reading kept showing through the bar that sits on top of
     it — two things occupying one strip of screen. A bar you cannot see
     through is easier to read past. */
  background: var(--bg);
  border-top: 1px solid var(--line); flex-wrap: wrap;
}

.choices { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.choice {
  background: var(--panel-2); border: 1px solid var(--line); color: var(--ink);
  padding: 9px 15px; cursor: pointer; font-family: var(--mono);
  font-size: var(--t-body); font-weight: 500; letter-spacing: 0;
}
.choice:hover { border-color: var(--muted); }
.choice[aria-pressed="true"] { border-color: var(--accent); color: var(--accent);
                               background: #1e1a10; }

/* The years revealed under an open decade — set apart from the decade row
   above it with its own top margin, rather than a second .choices block that
   would look like a sibling group rather than something the decade above it
   opened. */
.choices.years { margin-top: var(--sp-3); }
/* The random pick is a real convenience, not the decision the screen is
   asking you to make — a dashed border and muted colour keep it visibly
   secondary to the year buttons beside it, even though it is a full-size
   target. */
.choice.random { border-style: dashed; color: var(--muted); }
.choice.random:hover { color: var(--accent); border-color: var(--accent); }

.actions { display: flex; gap: var(--sp-3); align-items: center;
           margin-top: var(--sp-4); flex-wrap: wrap; }

/* Used by rec() in app.js to keep a win-loss record ("181–229") on one line
   wherever it's printed — table cell, hero number, or mid-sentence. Without
   it the browser treats the en dash as a break point and tears the record
   in half the moment its line wraps. */
.nowrap { white-space: nowrap; }

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

table { width: 100%; border-collapse: collapse; font-size: var(--t-body); }
th {
  text-align: left; color: var(--muted); font-weight: 700;
  font-size: 10px; letter-spacing: .12em; text-transform: uppercase;
  padding: var(--sp-2); border-bottom: 1px solid var(--line);
}
td { padding: 6px var(--sp-2); border-bottom: 1px solid #171b21; }
tr.me td { background: #1a1710; }
tr.me td:first-child { box-shadow: inset 2px 0 0 var(--accent); }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
td.name { font-family: var(--display); font-weight: 600; }
.scroll { max-height: 460px; overflow-y: auto; }
.tablewrap { overflow-x: auto; }
tr.cutline td { border-bottom: 1px solid var(--muted); }

/* "Every bet you made" has nine columns and three of them are names, so
   width:100% above squeezes it until player names split mid-word instead of
   the wrapper scrolling. 1100px is the measured floor: the widest real name
   in the dataset (24 characters) still needs ~1032px across all nine columns
   to render on one line, so below this the table scrolls sideways instead
   of crushing itself. */
table.picks { min-width: 1100px; }

@media (max-width: 620px) {
  table { font-size: 13px; }
  td, th { padding: 5px 6px; }
  .hide-sm { display: none; }
  /* .hide-sm above already drops three of nine columns, so the 1100px floor
     set for the widest desktop layout is oversized here — measured at 759px
     for the six columns that remain, even with the dataset's longest real
     names. 800px covers that with room, instead of forcing a phone to
     scroll roughly 300px further sideways than the content needs. */
  table.picks { min-width: 800px; }
}

/* --------------------------------------------------------------- ratings */

/* Brightness, not hue — so a rating never competes with a win or a loss. */
.rate { font-family: var(--display); font-weight: 700; font-size: 14px;
        font-variant-numeric: tabular-nums; }
.r-elite { color: var(--tier-4); }
.r-good  { color: var(--tier-3); }
.r-ok    { color: var(--tier-2); }
/* Was #5f6a76, which is 2.97:1 on the panel — the one real contrast failure in
   the game, and it sat on the number a player reads most. */
.r-poor  { color: var(--tier-1); }

.pos { color: var(--muted); font-size: var(--t-micro); }

/* ------------------------------------------------------------ team select */

.teamgrid { display: grid; gap: var(--sp-2);
            grid-template-columns: repeat(auto-fill, minmax(215px, 1fr)); }
.teamcard {
  display: grid; gap: 2px; text-align: left; padding: var(--sp-3);
  background: var(--panel-2); border: 1px solid var(--line);
  border-left: 3px solid var(--line); font-family: var(--mono); cursor: pointer;
}
.teamcard:hover { border-color: var(--muted); }
.teamcard[aria-pressed="true"] { border-color: var(--accent);
  border-left-color: var(--accent); background: #1e1a10; }
.tc-city { font-family: var(--display-cond); font-size: var(--t-2); font-weight: 800;
           letter-spacing: -.02em; color: var(--ink); }
.tc-real { font-size: 12px; color: var(--muted); }
/* What you inherit, and what you are chasing. */
.tc-nums { display: flex; gap: var(--sp-4); margin-top: var(--sp-2); }
.tc-nums b { display: block; font-family: var(--display-cond); font-size: 24px;
             font-weight: 800; font-variant-numeric: tabular-nums; line-height: 1;
             color: var(--ink); }
.tc-nums i { display: block; font-style: normal; font-size: 10px;
             letter-spacing: .12em; color: var(--muted); text-transform: uppercase;
             margin-top: 3px; }

/* ----------------------------------------------------------------- draft */

.draftgrid { display: grid; grid-template-columns: 205px minmax(0, 1fr) 300px;
             gap: var(--sp-4); align-items: start; }
@media (max-width: 1100px) {
  .draftgrid { grid-template-columns: 175px minmax(0, 1fr); }
  .myteam { grid-column: 1 / -1; }
}
@media (max-width: 720px) {
  .draftgrid { grid-template-columns: 1fr; }
  /* .orderrail is NOT here. See below the base rule — a media query adds no
     specificity, so an override written above the rule it overrides simply
     loses. This one lost, and the rail stayed 72vh tall and sticky on phones:
     pinned over the board, swallowing every tap meant for a player. */
}

/* The order rail is where the tension lives: you can see who picks before you
   and watch the names land. It used to be one grey line of text. */
.orderrail { position: sticky; top: 62px; max-height: 72vh; overflow-y: auto;
             border: 1px solid var(--line); background: var(--panel); }
.orow { display: grid; grid-template-columns: 24px 34px minmax(0, 1fr);
        gap: var(--sp-2); align-items: center; padding: 5px var(--sp-2);
        font-size: 12px; border-left: 2px solid transparent; }
.orow > span:first-child { color: var(--muted); font-variant-numeric: tabular-nums; }

/* On a phone the rail is a short strip above the board, not a pinned column
   beside it. This must stay AFTER .orderrail's base rule to win the cascade. */
@media (max-width: 720px) {
  .orderrail { max-height: 150px; position: static; }
}
.orow .oteam { color: var(--muted); font-size: 11px; letter-spacing: .04em;
               overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.orow b { font-family: var(--display); font-weight: 600; color: var(--ink);
          overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.orow:not(.done) b { color: var(--muted); }
.orow.mine { border-left-color: var(--accent); background: #1a1710; }
.orow.mine .oteam { color: var(--accent); }
.orow.live { outline: 1px solid var(--accent); outline-offset: -1px; }

.poolbar { display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap;
           padding-bottom: var(--sp-3); margin-bottom: var(--sp-2);
           border-bottom: 1px solid var(--line); }
.tabs { display: flex; gap: 2px; }
.tab { background: var(--panel-2); border: 1px solid var(--line); color: var(--muted);
       font-family: var(--mono); font-size: var(--t-micro); font-weight: 700;
       letter-spacing: .1em; padding: 7px 11px; }
.tab[aria-selected="true"] { color: var(--accent); border-color: var(--accent);
                             background: #1e1a10; }
.search { flex: 1; min-width: 130px; background: var(--panel-2); color: var(--ink);
          border: 1px solid var(--line); font-family: var(--mono);
          font-size: var(--t-body); padding: 8px 10px; }
.search:focus { outline: 0; border-color: var(--accent); }
.toggle { display: flex; align-items: center; gap: 6px; color: var(--muted);
          font-size: var(--t-micro); letter-spacing: .1em; cursor: pointer;
          white-space: nowrap; }

.board { display: grid; gap: 1px; max-height: 60vh; overflow-y: auto; }
.boardhead { display: grid; gap: var(--sp-2); padding: 0 var(--sp-2) 6px;
             color: var(--muted); font-size: 10px; letter-spacing: .12em;
             text-transform: uppercase; }
/* The quality band is gone: what a player becomes is the bet, and printing
   "SOLID" beside his name made it for you. Age, height, position, college. */
.pickrow, .boardhead { grid-template-columns: 28px minmax(0, 1fr) 30px 44px minmax(0, 150px); }
.boardhead span:nth-child(3), .boardhead span:nth-child(4) { text-align: right; }
/* The free-agency board has no number column: there is no order to announce.
   See the alphabetical sort in viewSignings for why. */
.boardhead.fa, .board-fa .pickrow {
  grid-template-columns: minmax(0, 1fr) 30px 44px minmax(0, 150px); }
.boardhead.fa span:nth-child(2), .boardhead.fa span:nth-child(3) { text-align: right; }
.pickrow {
  display: grid; gap: var(--sp-2); align-items: center;
  padding: 8px var(--sp-2); background: var(--panel-2);
  border: 0; border-left: 2px solid transparent; width: 100%; text-align: left;
  font-family: var(--mono); color: var(--ink); font-size: var(--t-body);
  font-weight: 400; letter-spacing: 0; cursor: pointer;
}
.pickrow:hover:not(:disabled) { background: #232a33; border-left-color: var(--accent); }
.pickrow:disabled { cursor: default; opacity: .5; }
.pickrow .idx { color: var(--muted); font-size: var(--t-micro); }
.pickrow .who { font-family: var(--display); font-weight: 600; font-size: 14px;
                overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The phone's second line — "College · 19" — duplicates age/college, which
   stay their own columns above 620px. See the phone block for the rest. */
.pickrow .sub { display: none; }
.age { color: var(--muted); font-size: 12px; text-align: right;
       font-variant-numeric: tabular-nums; }
.col { color: var(--muted); font-size: 12px; overflow: hidden;
       text-overflow: ellipsis; white-space: nowrap; }
.empty { color: var(--muted); padding: var(--sp-4) var(--sp-2); font-family: var(--display); }

/* The on-clock/waiting status lives in the actionbar now (.actionbar.onclock/
   .actionbar.waiting, below the tables section) rather than its own sticky
   box at the top of the screen — see the .topbar collision comment in :root
   for why two sticky-top bars could never share the page. */
/* Scoped to the actionbar's own "on the clock" dot. A bare .live selector
   also matches .orow.live (the order rail's row for whoever is on the
   clock) and made that whole row blink from full opacity to 25%, once a
   second, for the entire phase — unguarded motion nobody asked for, and a
   signal .orow.live's amber outline already carries on its own. */
.actionbar .live { color: var(--accent); animation: pulse 1s ease-in-out infinite; }
@keyframes pulse { 0%,100% { opacity: 1 } 50% { opacity: .25 } }

/* Said once, when the browser refuses to store anything. */
.nosave { margin: 0; padding: var(--sp-2) var(--sp-4); background: #2a1d12;
          color: #e8c48a; font-family: var(--mono); font-size: var(--t-micro);
          border-bottom: 1px solid var(--line); }

/* The holding line before the game boots. */
.booting { color: var(--muted); font-family: var(--mono); font-size: var(--t-body);
           padding: var(--sp-6) var(--sp-4); }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important;
                           animation-iteration-count: 1 !important;
                           transition-duration: .01ms !important; }
}

/* ---------------------------------------------------------------- lineup */

.lineup { display: grid; gap: 2px; }
/* Fixed final columns, not `auto`. Sized to their contents, the age and rating
   columns only lined up because every age and every rating happens to be two
   digits — the moment a column header sits above them, or a rating reads "—",
   the numbers step sideways. */
.slotrow, .lineup-cols {
           display: grid; grid-template-columns: 20px minmax(0, 1fr) 26px 30px;
           gap: var(--sp-2); align-items: center; }
.slotrow { padding: 6px var(--sp-2); background: var(--panel-2); }
.slotrow .age, .slotrow .rate { text-align: right; }

/* Two numbers with nothing to say what they are. Deliberately NOT a .slotrow:
   anything reading the rotation off .slotrow — the harness does, and so does a
   screen reader walking the list — would otherwise count the header as an
   eleventh player named "Player". */
.lineup-cols { padding: 0 var(--sp-2) 5px;
               font-family: var(--mono); font-size: var(--t-label);
               letter-spacing: .12em; text-transform: uppercase;
               color: var(--muted); border-bottom: 1px solid var(--line); }
.lineup-cols .age, .lineup-cols .rate { text-align: right; }
.lineup-cols + .lineup-head { margin-top: var(--sp-2); }
.slotrow.hole { background: #241412; color: #d98a80; }
.slotrow .lbl { color: var(--muted); font-size: var(--t-micro); }
.slotrow.bench { opacity: .75; }
.slotrow .sname { font-family: var(--display); font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A pick you just made flashes, which is where the hidden rating is revealed. */
.slotrow.fresh { animation: flash 1.4s ease-out; }
@keyframes flash { 0% { background: #4a3a12; } 100% { background: var(--panel-2); } }

/* --------------------------------------------------- roster by position */

/* ------------------------------------------------------------ the squad list

   ONE list, ordered the way a side is actually picked: five starters, three off
   the bench, then everyone else.

   It was two. The left column split the roster into guards / forwards / centres
   while the right column repeated the same men under "best eight" with their
   real roles — so every player was on screen twice, three position columns left
   about ninety pixels for a name ("Mo Willia…", "Al Jeffers…"), and the fact
   that actually decides a season — WHERE each man plays, and whether he counts
   at all — was in neither list but in the caption under one of them.

   Role is now a column, so it reads straight down, and every name has the full
   width of the panel. */
.rgroup { margin-bottom: var(--sp-5); }
.rgroup:last-child { margin-bottom: 0; }
.rgrouphead {
  display: flex; align-items: baseline; gap: var(--sp-3);
  font-size: var(--t-label); letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink-2); border-bottom: 1px solid var(--line);
  padding-bottom: 6px; margin-bottom: var(--sp-2);
}
.rgrouphead i { font-style: normal; color: var(--muted); letter-spacing: .06em;
                text-transform: none; }

/* Header and rows are driven from ONE template so they cannot drift apart —
   --pgap lives here too, not just --pcols. The header and the rows used to
   set their own `gap: var(--sp-2)` independently, which was fine while both
   copies happened to agree; the day one changed without the other, the two
   grids shared column widths but not the space between them, and every
   column after the first drifted out of alignment with its own header.
   Off and Def sit beside Ovr at the same column width — the game already
   tells you your defence is weak on the team totals above; hiding which
   player is responsible would make the number an accusation with no name
   attached. Age sits before the name, not between it and Off/Def/Ovr — it is
   a fact about the man, not a fourth rating, and reading it next to three
   numbers made it look like one. */
.panel { --pcols: 30px 38px minmax(0, 1fr) 46px 46px 46px 54px; --pgap: var(--sp-2); }
.pcard { display: grid; grid-template-columns: var(--pcols);
         gap: var(--pgap); align-items: center; padding: 9px var(--sp-2);
         margin-bottom: 3px; background: var(--panel-2);
         border-left: 2px solid transparent; }
/* The slot a man fills: G/F/C for a starter, his own position on the bench. */
.prole { font-family: var(--mono); font-size: var(--t-label); color: var(--muted);
         letter-spacing: .06em; }
.pcard.best .prole { color: var(--good); }
.pcard.best { border-left-color: var(--good); background: #171e1b; }
.pcard.hole { background: #241412; border-left-color: var(--bad); color: #d98a80; }
.pcard.hole .prole { color: var(--bad); }
.pcard.empty-slot { background: transparent; border: 1px dashed var(--line);
                    border-left: 2px dashed var(--line); color: var(--muted); }
/* A man you released but can still get back. Dimmed and struck through reads
   as "gone for now", not "gone" — the RESTORE button beside him says the
   rest. Opacity on the whole card would dim RESTORE along with everything
   else, and dimming is this app's own vocabulary for "not actionable"
   (.pickrow.gone, .cut-off) — so the one live control in the row would wear
   the disabled costume. Dim every cell except the button instead. */
.pcard.released > :not(button) { opacity: .55; }
.pcard.released .pname { text-decoration: line-through; }
.ppos { color: var(--muted); font-size: 11px; margin-left: 6px;
        font-family: var(--mono); }
/* Age gets its own column so it can never be squeezed out by a long name — it
   was truncating to "G · …" and vanishing entirely. */
.page { color: var(--ink-2); font-size: 12px; text-align: right;
        font-variant-numeric: tabular-nums; }
.pname { font-family: var(--display); font-weight: 600; font-size: 15px;
         overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Ratings hang off the right edge of their cell, so a one- or three-digit value
   cannot nudge the column out of line the way a left-set span does. */
.pcard .rate { text-align: right; }
/* Narrow enough that the fixed columns start eating the name again, so shrink
   them rather than the thing you came to read. */
@media (max-width: 620px) {
  .panel { --pcols: 24px 28px minmax(0, 1fr) 38px 46px; }
  /* On a phone there is no width left to buy, and the longest names in the data
     ("Timothé Luwawu-Cabarrot") still run past the cell. Two lines is a readable
     name; one line ending in an ellipsis is not. */
  .pname { white-space: normal; overflow: visible; text-overflow: clip; line-height: 1.3; }
  /* Off and Def first tried to survive here by shrinking every column,
     including Role and the name itself — which made the exact wrapping this
     screen was already clean of worse, not better, on the one screen the
     diagnosis found nothing wrong with. The hero above already prints the
     team's Off and Def, same as the boards already hide columns below this
     width (.hide-sm), so the two per-player cells hide here instead: fourth
     and fifth of the seven .pcard/.rosterhead cells, in every row shape
     (row, holeRow, spotRow, the "Out this season" card) — Age moving before
     the name did not change which POSITIONS those are. --pcols drops back
     to its pre-Off/Def five tracks so the remaining five cells — Role, Age,
     Player, Ovr, Cut — land on them exactly as they did before. */
  .pcard > :nth-child(4), .pcard > :nth-child(5),
  .rosterhead > :nth-child(4), .rosterhead > :nth-child(5) { display: none; }
}
.pmeta { color: var(--muted); font-size: 12px; margin-left: 4px; font-family: var(--mono); }
/* A sixth cell would need every .pcard to carry the same column, including
   the ones with nothing to put in it — so this spans the row instead, as a
   second line under the name, only on the cards that use it. */
.pback { grid-column: 1 / -1; color: var(--muted); font-size: 12px;
         font-family: var(--mono); margin-top: -2px; }
/* Small and quiet until wanted, so the name gets the room instead. */
/* Always visible. Hiding it until hover made the single most consequential
   control on the screen undiscoverable — and invisible on touch. */
button.cut { background: transparent; border: 1px solid var(--line); color: var(--muted);
             font-size: 10px; font-weight: 700; letter-spacing: .1em;
             line-height: 1; padding: 5px 7px; }
button.cut:hover { border-color: var(--bad); color: var(--bad); background: #241412;
                   filter: none; }

/* --------------------------------------------------------- offence/defence */

/* Number plus word, no bar. A full-width meter spent the whole panel saying
   what two characters say better. */
.split { display: grid; grid-template-columns: 34px 54px 1fr; gap: var(--sp-3);
         align-items: baseline; margin-bottom: var(--sp-3); }
.split .lbl { color: var(--muted); font-size: 10px; letter-spacing: .12em; }
.split b { font-family: var(--display-cond); font-size: 26px; font-weight: 800;
           font-variant-numeric: tabular-nums; line-height: 1; text-align: right; }
.split i { font-style: normal; font-size: 10px; letter-spacing: .14em; }

/* --------------------------------------------------------- live season */

/* One row, always — a fixed-column grid rather than flex-wrap, so the strip
   never depends on how many pixels happened to be left over. It used to hold
   a fixed 40 games and wrap to four rows of ten, which the owner found hard
   to follow — at four rows there was no obvious reading order, so you could
   not tell which end was recent. app.js now hands this a window sized for
   the screen (20 games at 620px and up, 10 on a phone — see the JS section
   below the .live-season comment); the column count here just has to match
   it. Columns use minmax(0, 1fr) rather than a fixed pixel width so the row
   always fills the panel and never needs a scrollbar, at either count. */
.formline { display: grid; grid-template-columns: repeat(20, minmax(0, 1fr));
            gap: 3px; }
@media (max-width: 620px) {
  .formline { grid-template-columns: repeat(10, minmax(0, 1fr)); }
}
/* A letter in every chip, and the win/loss colours pushed to the ends of the
   palette (not the muted #1d4433/#47211d pair a phone screenshot showed as
   one grey smear) so W and L are legible before the letter is even read. */
.chip { display: flex; align-items: center; justify-content: center;
        aspect-ratio: 1; border-radius: 3px; font-family: var(--mono);
        font-weight: 800; font-size: 13px; }
.chip.cw, .chip.cl { color: var(--bg); }
.cw { background: var(--good); }
.cl { background: var(--bad); }
/* Four or more of the same result in a row: a ring, so a hot or cold spell
   reads as a shape in the grid rather than something you count chip by chip. */
.chip.streak { box-shadow: 0 0 0 2px var(--accent) inset; }
.streaktext { margin: 6px 0 0; font-weight: 600; color: var(--ink-2); }

.feed { max-height: 440px; overflow-y: auto; }
.res { display: grid; grid-template-columns: 20px minmax(0, 1fr) 44px 58px;
       gap: var(--sp-3); align-items: center; padding: 7px 2px;
       border-bottom: 1px solid #171b21; }
.res .rchip { width: 12px; height: 12px; }
.res .resmain { overflow: hidden; font-family: var(--display); font-size: 13px; }
.res .stars { display: block; font-family: var(--mono); font-size: 11px; color: var(--muted); }
.res .wp { font-size: 12px; color: var(--muted); text-align: right;
           font-variant-numeric: tabular-nums; }
/* The cheapest drama available: an upset picks up the accent. */
.res.upset .wp { color: var(--accent); font-weight: 700; }
.res.choke .wp { color: var(--bad); }
.res .score { font-family: var(--display); font-weight: 700; font-size: 15px;
              text-align: right; font-variant-numeric: tabular-nums; }
@media (max-width: 620px) {
  .res { grid-template-columns: 20px minmax(0, 1fr) auto; }
  .res .wp { display: none; }
}

/* --------------------------------------------------------------- results */

.bigstat { display: flex; gap: var(--sp-5); flex-wrap: wrap; }
.bigstat div span { display: block; color: var(--muted); font-size: 10px;
  letter-spacing: .12em; text-transform: uppercase; }
/* Preserve the gap between listed picks: "R1 #5  R1 #10  R1 #13" collapsed to
   one space and read as a single unbroken number. */
.bigstat div b { white-space: pre-wrap;
                 font-family: var(--display); font-size: 22px; font-weight: 700;
  font-variant-numeric: tabular-nums; }
.win { color: var(--good); }
.loss { color: var(--bad); }
.title-banner {
  padding: var(--sp-4); background: #1e1a10; border: 1px solid var(--accent);
  color: var(--accent); margin-bottom: var(--sp-4);
  font-family: var(--display-cond); font-size: var(--t-2); font-weight: 800;
  letter-spacing: .04em; text-transform: uppercase;
}
.history td.res { color: var(--muted); display: table-cell; padding: 6px var(--sp-2);
                  border-bottom: 1px solid #171b21; }
.warn { color: var(--bad); }

/* ------------------------------------------------------------- playoffs */

.bracket { max-height: none; }
.serieswrap { display: grid; gap: var(--sp-2);
              grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }
.series { border: 1px solid var(--line); background: var(--panel-2); }
.series.mine { border-color: var(--accent); }
.series.pending { opacity: .35; }
.series .team { display: grid; grid-template-columns: 18px minmax(0, 1fr) 20px;
                gap: var(--sp-2); align-items: center; padding: 6px var(--sp-2);
                font-size: 13px; }
.series .team + .team { border-top: 1px solid var(--line); }
.series .sd { color: var(--muted); font-size: 11px; font-variant-numeric: tabular-nums; }
.series .sn { font-family: var(--display); font-weight: 600; color: var(--muted);
              overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.series .team.won .sn { color: var(--ink); }
.series .team b { text-align: right; font-variant-numeric: tabular-nums;
                  color: var(--muted); font-family: var(--display); }
.series .team.won b { color: var(--good); }

/* Wandering off the live game is a detour, and it should look like one. */
.actionbar.browsing { border-top-color: var(--accent); }

/* A control that does nothing should not look like a control. */
.cut-off { color: var(--line); font-size: 12px; text-align: center; width: 34px; }

/* A coarse band: enough to weigh a 20-year-old against a 31-year-old,
   not enough to rank the board. */
.band { font-size: 10px; letter-spacing: .1em; text-align: right; }

/* A pick you would take back. */
tr.regret td { background: #241412; }
tr.regret td:first-child { box-shadow: inset 2px 0 0 var(--bad); }

/* A column header, so 25 is legibly an age and not a second rating. */
.rosterhead {
  display: grid; grid-template-columns: var(--pcols);
  gap: var(--pgap); padding: 0 var(--sp-2) 6px;
  color: var(--muted); font-size: 10px; letter-spacing: .12em; text-transform: uppercase;
  border-bottom: 1px solid var(--line); margin-bottom: var(--sp-3);
}
/* Right-aligns Age, Off, Def, Ovr — the four numeric columns. Must track
   --pcols' order above (Role, Age, Player, Off, Def, Ovr, blank): this drifted
   once already when Age moved in front of Player and only the width template
   moved with it, leaving Age's label over Off's numbers. */
.rosterhead span:nth-child(2), .rosterhead span:nth-child(4),
.rosterhead span:nth-child(5), .rosterhead span:nth-child(6) { text-align: right; }

/* The two halves of the draw, side by side. */
.confsplit { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-4); }
@media (max-width: 760px) { .confsplit { grid-template-columns: 1fr; } }
.conflabel { display: block; font-size: 10px; letter-spacing: .12em; text-transform: uppercase;
             color: var(--muted); margin-bottom: 6px; }

/* A club that jumped in the draw. */
.jumped { color: var(--accent); font-size: 10px; letter-spacing: .1em; text-transform: uppercase; }

/* ------------------------------------------------------------------ awards */

/* Six awards in auto-fill tracks of 210px fits five across, so the sixth sat
   alone on a second row beside four empty cells. Six divides by three and by
   two, so these always come out as full rows. */
.awards { display: grid; gap: var(--sp-2); grid-template-columns: repeat(3, 1fr); }
@media (max-width: 1100px) { .awards { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px)  { .awards { grid-template-columns: 1fr; } }
.award { display: grid; gap: 2px; padding: var(--sp-3); background: var(--panel-2);
        border-left: 2px solid var(--line); }
.award.ours { border-left-color: var(--accent); background: #1a1710; }
.aw-label { font-size: 10px; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.aw-name { font-family: var(--display-cond); font-size: var(--t-2); font-weight: 800;
           letter-spacing: -.01em; }
.aw-meta { font-size: 12px; color: var(--muted); }
/* Twelve names per conference as wrapped chips read as a word cloud: you could
   not find your own player, and the order — which is a ranking — was invisible.
   A numbered list says both. */
ol.starlist { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px;
              counter-reset: star; }
ol.starlist .star {
  display: grid; grid-template-columns: minmax(0, 1fr) 36px 54px;
  gap: var(--sp-2); align-items: baseline;
  background: var(--panel-2); color: var(--ink-2);
  padding: 6px var(--sp-2) 6px 28px; position: relative;
  font-family: var(--display); font-size: 14px;
}
ol.starlist .star::before {
  counter-increment: star; content: counter(star);
  position: absolute; left: var(--sp-2); color: var(--muted);
  font-family: var(--mono); font-size: var(--t-label);
}
ol.starlist .st-n { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
ol.starlist .star i { font-style: normal; color: var(--muted);
                      font-family: var(--mono); font-size: var(--t-label); }
ol.starlist .star em { font-style: normal; color: var(--muted);
                       font-family: var(--mono); font-size: 10px;
                       letter-spacing: .1em; text-transform: uppercase; }
ol.starlist .star.ours { background: #1a1710; color: var(--accent); }
ol.starlist .star.ours i, ol.starlist .star.ours em { color: var(--accent); opacity: .8; }


/* Series odds sit between the club and its wins. */
.series .team { grid-template-columns: 18px minmax(0, 1fr) 34px 20px; }
.series .sp { color: var(--muted); font-size: 11px; text-align: right;
              font-variant-numeric: tabular-nums; }

/* ------------------------------------------------- taken players on the board

   A player used to vanish from the board the instant somebody took him — the
   single most watchable moment in a draft, deleted. He now stays exactly where
   he was, struck through, with the club that took him where his college was. */
.pickrow.gone { opacity: .45; }

.pickrow.gone:hover { background: none; border-left-color: transparent; }
.tookby { font-style: normal; font-family: var(--mono); font-size: var(--t-label);
          letter-spacing: .08em; color: var(--accent); }

/* A panel that is telling you something is wrong. */
.warnpanel { border-color: #4a2a26; background: #1c1413; }
.warnpanel h2 { color: #e8968c; }

/* A club's picks, listed rather than crammed into one line of code-speak. */
.picklist { list-style: none; margin: 0 0 var(--sp-3); padding: 0; display: grid; gap: 3px; }
.picklist li { font-family: var(--display); font-size: 17px; font-weight: 700;
               background: var(--panel-2); padding: 7px var(--sp-3); }

/* Envelopes not yet opened. */
tr.pending td { color: var(--muted); opacity: .5; font-style: italic; }
tr.fresh td { animation: flash 1.2s ease-out; }

/* The count that decides every pick on a draft or free-agency board. */
.spots { display: flex; gap: var(--sp-4); flex-wrap: wrap;
         padding: 0 0 var(--sp-3); margin-bottom: var(--sp-3);
         border-bottom: 1px solid var(--line); }
.spots span { display: flex; align-items: baseline; gap: 5px; }
.spots b { font-family: var(--display); font-size: 18px; font-weight: 700;
           font-variant-numeric: tabular-nums; }
.spots i { font-style: normal; font-size: var(--t-label); letter-spacing: .08em;
           text-transform: uppercase; color: var(--muted); }

/* Where the five ends and the bench begins. */
.lineup-head { font-size: var(--t-label); letter-spacing: .12em; text-transform: uppercase;
               color: var(--muted); margin: var(--sp-3) 0 4px; }
.lineup-head:first-child { margin-top: 0; }

/* ---------------------------------------------- the free-agency board

   It carries a name, an age, a height and a college. No stat line.

   A veteran's last season used to sit under his name, on the reasoning that
   every GM in 1985 knew what Gus Williams averaged. True, and it still wrecked
   the game: the rating this board hides is COMPUTED from those very numbers —
   per-36 production and shooting efficiency against the league average — so
   printing them showed a low-resolution copy of the hidden answer, and the pool
   ranked itself without you knowing a thing about basketball. It also buried the
   best moments in the game: David Robinson, hurt, reads like a bench player.
   Knowing better than the stat line is the whole point. */
.pickrow .who { line-height: 1.25; }

/* A player who has gone should read as gone at a glance. It was a faint dim and
   a three-letter tag, and people kept trying to draft men who were already off
   the board. */
.pickrow.gone { opacity: .38; }
/* Strike the NAME, not the whole cell — the line was running through the stat
   line underneath it and turning a readable row into a smear. */
.pickrow.gone .nm { text-decoration: line-through 2px; text-decoration-color: var(--bad); }

button.cut { padding: 4px 6px; white-space: nowrap; overflow: hidden; }
/* The undo, not the destructive action — quiet like CUT, but never red, so
   the two controls in this column never look like the same kind of button. */
button.restore { background: transparent; border: 1px solid var(--line);
                 color: var(--muted); font-size: 10px; font-weight: 700;
                 letter-spacing: .1em; line-height: 1; padding: 4px 6px;
                 white-space: nowrap; overflow: hidden; }
button.restore:hover { border-color: var(--good); color: var(--good); filter: none; }

/* The bar that says whose turn it is now lives in the actionbar, sticky to
   the BOTTOM of the screen (.actionbar already is). It used to be its own
   box stuck to the TOP — the confirm prompt raised there while the click
   that triggered it happened forty rows down the page, so the prompt was
   off-screen and picking a player looked like it had done nothing — and
   that box shared .topbar's own sticky-top slot, which is the collision the
   earlier fix in this file patched with an offset. Moving it to the bottom
   removes the collision at the root instead of just offsetting around it,
   and puts Autofill/Skip under a thumb rather than at arm's length. Amber
   modifier for your own turn, muted for a rival's, same colours the old
   standalone box used. */
.actionbar.onclock { border-top-color: var(--accent); background: #1e1a10; }
.actionbar.onclock .hint { color: var(--accent); font-weight: 700; letter-spacing: .06em; }
.actionbar.onclock b { color: var(--ink); }


.pickrow .nm { font-family: var(--display); font-weight: 600; }

/* A rating you have not earned the right to see yet. */
.rate.unknown { color: var(--muted); text-align: right; }

/* A place on the list nobody fills yet — distinct from an empty ROTATION slot,
   which is a hole in the side you would put out tonight. */
.slotrow.empty-spot { opacity: .5; font-style: italic; }

/* A control that lives inside a sentence. */
button.ghost.inline { padding: 3px 8px; margin-left: 4px; font-size: var(--t-label);
                      vertical-align: baseline; }

/* The word beside a club's rating. */
td.qual { font-family: var(--mono); font-size: var(--t-label); letter-spacing: .1em;
          padding-left: var(--sp-3); white-space: nowrap; }

/* Five words where a paragraph used to be. */
h1 .sub { font-family: var(--mono); font-size: var(--t-label); letter-spacing: .1em;
          text-transform: uppercase; color: var(--muted); margin-left: var(--sp-3);
          vertical-align: middle; }

/* ------------------------------------------------------------- the verdict

   The end of a run should answer one question before any table does: was that
   good? The only honest standard we have is the club's own history over the
   very same seasons, so the grade comes from the gap. */
.verdict { display: grid; grid-template-columns: auto 1fr auto; gap: var(--sp-5);
           align-items: center; background: var(--panel); border: 1px solid var(--line);
           padding: var(--sp-5); margin-bottom: var(--sp-4); }
.grade { font-family: var(--display-cond); font-size: clamp(52px, 9vw, 84px);
         font-weight: 800; line-height: .85; letter-spacing: -.04em; color: var(--ink-2); }
.grade.good { color: var(--accent); }
.grade.bad { color: var(--bad); }
.verdict-body b { display: block; font-family: var(--mono); font-size: var(--t-label);
                  letter-spacing: .18em; text-transform: uppercase; color: var(--accent);
                  margin-bottom: 6px; }
.verdict-body .hint { max-width: 62ch; margin: 0; }
.verdict-body .hint b { display: inline; font-family: var(--display); font-size: inherit;
                        letter-spacing: 0; text-transform: none; color: var(--ink); margin: 0; }

.moments { display: grid; gap: var(--sp-2); margin-bottom: var(--sp-4);
           grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.moment { display: grid; gap: 2px; padding: var(--sp-3); background: var(--panel-2);
          border-left: 2px solid var(--line); }
@media (max-width: 720px) {
  .verdict { grid-template-columns: auto 1fr; }
  .verdict button { grid-column: 1 / -1; }
}

/* Two yardsticks: the club's own history, and — one day — everyone else's runs. */
.compare { display: grid; gap: var(--sp-3); grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.compare > div { display: grid; gap: 2px; padding: var(--sp-3); background: var(--panel-2);
                 border-left: 2px solid var(--line); }
.compare .pending-compare { opacity: .55; border-left-style: dashed; }

/* ==========================================================================
   THE PHONE — deliberately the last thing in this file.

   Everything here was measured on a 390x844 and a 360x740 screen, where the
   game was not cramped but unplayable: names on the draft board 22px wide (0px
   at 360), the order rail pinned on top of the board swallowing every tap, the
   page scrolling sideways for ever, and the phase nav zero pixels wide.

   It lives at the bottom because that is the whole lesson. A media query adds
   NO specificity, so an override written above the rule it overrides simply
   loses — silently, and invisibly to anyone testing on a desktop. The order
   rail had that bug for its whole life. Writing these rules mid-file
   reintroduced it twice in one sitting: the board columns and the search font
   size both lost to base rules further down, and only the phone checks in
   tests/smoke.mjs caught it. Keep this block last.
   ========================================================================== */
@media (max-width: 620px) {
  /* The single most valuable change in this block. .board was a 511px box
     holding up to 989px of the draft pool (5,399px on the free-agency
     board — ten and a half screenfuls) behind its own inner scrollbar, so a
     phone had THREE nested scrolls stacked inside one another: the page,
     the order rail, and this. A swipe on the board never moved the page
     until the board bottomed out first. Letting it flow into the page
     removes one of the three and means the pool is reachable with an
     ordinary swipe, the same as everything else on the screen. */
  .board { max-height: none; overflow-y: visible; }

  /* Your squad, 624px of content sitting 1,088px down the draft screen where
     in practice nobody scrolls to it — it is already a separate screen, just
     one you reached by scrolling instead of tapping. It stays out of the
     draft/free-agency flow here; SQUAD in the phase nav reaches the same
     information in one tap, and returns with the "Back to the draft" /
     "Back to free agency" bar (see drawScreen's browsing bar in app.js). */
  .myteam { display: none; }

  /* Two lines per row instead of five columns squeezed across one: the name
     on its own line, "College · 19" (or who took him) on the next — see
     poolSub() in app.js, which is where that second line's text comes from.
     This is what deletes the college cell (23% of it truncated at the old
     86px) and the header that wrapped to describe it — .boardhead has
     nothing left to say once the row states its own facts, so it goes
     rather than getting patched again. */
  .boardhead { display: none; }
  .pickrow { grid-template-columns: 22px minmax(0, 1fr); }
  /* :not(.board-fa) matters: a bare `.pickrow > span:nth-child(3,4,5)` also
     matches the free-agency row below, whose 5th child is .sub, not .col —
     it has no pick-number column, so every one of its children sits one
     position earlier than the draft board's. Without the exclusion this
     rule and the free-agency-specific one below fight over the same slot,
     and `.sub`'s nth-child(5) — more specific than the plain `.pickrow .sub`
     it needs to beat — silently wins and hides it again. */
  .board:not(.board-fa) .pickrow > span:nth-child(3),
  .board:not(.board-fa) .pickrow > span:nth-child(4),
  .board:not(.board-fa) .pickrow > span:nth-child(5) { display: none; }
  .pickrow .sub {
    display: block; grid-column: 1 / -1; color: var(--muted);
    font-family: var(--mono); font-size: 11px; margin-top: -2px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  /* The free-agency row has no pick-number column, so its own spans shift
     one to the left of the draft board's — age is 2nd, not 3rd. */
  .board-fa .pickrow { grid-template-columns: minmax(0, 1fr); }
  .board-fa .pickrow > span:nth-child(2), .board-fa .pickrow > span:nth-child(3),
  .board-fa .pickrow > span:nth-child(4) { display: none; }

  /* The status trio goes: TEAM / RUN / SEASON are all printed in the hero of
     the screen you are looking at, and Abandon is off in its own row now
     (see .subbar) — between the two, the phase nav gets its width back. It
     was 0px wide holding 397px of five tabs including "FREE AGENCY", so
     "past phases stay reachable" did not exist on a phone at all; five
     one-word tabs (see index.html) now fit 393px without scrolling. */
  .topbar { gap: 6px; padding: 0 var(--sp-2); }
  .subbar { padding: 6px var(--sp-2); }
  .status { display: none; }
  .brand { font-size: 12px; }
  /* Five one-word tabs still needed more than the room left once the brand
     and the nav share one row — the vertical padding (fingers, unrelated to
     width) stays; only the horizontal padding shrinks, from 12px a side to
     4px, and the letter-spacing that was tuned for a desktop label tightens
     from .14em to .06em — still a clearly tracked capital, just not as wide
     a one. This tier alone is only good down to about 400px — narrower
     phones, including 390 and 393 (the two most common phone widths in
     use), fall through to the tighter tier below, which trims further. */
  .phase { padding: 15px 4px; letter-spacing: .06em; }

  /* Fingers. .pickrow is the verb of the game and it was 34px; the cut button
     is destructive and was 20px. */
  .pickrow { min-height: 44px; }
  .tab { padding: 12px 11px; }
  button.cut, button.restore { padding: 9px 4px; }
  /* RESTORE is twice the letters of CUT, in the same 46px column that only
     just fits CUT at the desktop size — the phone screenshot showed it
     clipped mid-word. */
  button.restore { font-size: 9px; letter-spacing: .02em; }
  .choice { padding: 13px 15px; }

  /* iOS Safari zooms any input under 16px on focus and never zooms back out, so
     one tap on the search box left you on a zoomed, sideways-scrolling page for
     the rest of the draft. */
  .search { font-size: 16px; }

  /* A third scorer clipped beats a third scorer orphaned on a line of its own:
     the results feed was showing six games where it should show eleven. */
  .res .stars { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
}

/* A narrower tier within the phone block above, for real phones under 400px
   (360x740, 390x844 and 393x852 are all real device sizes, not hypotheticals
   — see the comment at the top of this section; 390 and 393 are the two most
   common phone widths in use). "SIGNINGS" is the longest of the five tabs.

   This tier used to start at 380px, tuned only for 360's ~20px shortfall.
   That left 390 and 393 on the loose tier above, which looked fine by an
   arithmetic that forgot .phasenav has a 2px gap between each of its four
   gaps — real slack was 2.2px at 390 and 5.2px at 393, not the double-digit
   number the loose tier's own comment claimed. 2.2px is a font-rendering
   hiccup away from the exact silent failure this tier exists to prevent, so
   it now starts at 400px and covers all three widths, not just the
   narrowest one. Shaving 2px off each side of .phase's padding and zeroing
   the nav's own gap recovers real margin at all three: about 10px at 360,
   40px at 390, 43px at 393 (measured via each tab's own rendered width, not
   .phasenav's clientWidth/scrollWidth, which read 0 slack once nothing
   overflows and say nothing about how much room is actually left — see
   tests/smoke.mjs's phone checks, which assert this directly at all three
   widths now instead of only 360). */
@media (max-width: 400px) {
  .phasenav { gap: 0; }
  .phase { padding: 15px 2px; letter-spacing: .03em; }
}
