:root{
  --ink:#12161c;          /* page */
  --slate:#1a2029;        /* panes */
  --slate-2:#222a35;      /* rows */
  --line:#2f3946;
  --teal:#2bb3be;         /* the sheet's header teal */
  --orange:#ee7326;       /* the sheet's pick-number orange */
  --gold:#f2b01e;         /* fantasy points */
  --money:#7ce0a6;        /* every dollar value */
  --green:#3fbf7f;
  --pos-wr:#2bb3be;       /* unchanged, the sheet's teal */
  --pos-rb:#3fbf7f;
  --pos-qb:#f06fa8;
  --pos-te:#a78bfa;
  --pos-ink:#10161d;      /* text inside a filled position badge */
  --red:#e2574c;
  --pink:#e8577a;         /* relinquish */
  --blue:#4a9be8;         /* match */
  --text:#e8edf3;
  --muted:#8d9aab;
  --display:'Bitter',Georgia,serif;
  --ui:'Barlow',system-ui,-apple-system,sans-serif;
  --cond:'Barlow Condensed','Barlow',sans-serif;
  --r:10px;
}
*{box-sizing:border-box}
/* class selectors outrank the UA [hidden] rule, so pin it down globally */
[hidden]{display:none!important}
/* The fixtures band's height, so the column below is the right size on
   the very first paint rather than after the script has measured it.
   96px matches the band's own minimum; the script replaces it with the
   real figure once the games are in. */
:root{--slate-h:96px}
html,body{height:100%}
/* Chromium's font boosting reads this off the root element. */
html{-webkit-text-size-adjust:100%;text-size-adjust:100%}
:root{--sat:env(safe-area-inset-top);--sab:env(safe-area-inset-bottom)}
body{
  margin:0;background:var(--ink);color:var(--text);
  font-family:var(--ui);font-size:15px;line-height:1.45;
  -webkit-font-smoothing:antialiased;
  /* Kills the double-tap-to-zoom delay, and stops iOS inflating type when the
     phone is rotated. Pinch is handled in app.js. */
  touch-action:manipulation;
  -webkit-text-size-adjust:100%;
}
button,input,select{font-family:inherit;font-size:inherit;color:inherit}
/* Desktop browsers put spinner arrows on number inputs and let the mouse
   wheel change the value — an easy way to alter a bid by accident. */
input[type=number]{-moz-appearance:textfield;appearance:textfield}
input[type=number]::-webkit-outer-spin-button,
input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
:focus-visible{outline:2px solid var(--teal);outline-offset:2px}

/* ── buttons ─────────────────────────────────────────── */
.btn{
  border:1px solid var(--line);background:var(--slate-2);color:var(--text);
  border-radius:8px;padding:9px 14px;cursor:pointer;font-weight:600;
  transition:background .15s,border-color .15s,transform .08s;
}
.btn:hover{background:#2b3542;border-color:#41506180}
.btn:active:not(:disabled){transform:translateY(2px)}
.btn:disabled{opacity:.4;cursor:not-allowed}
.btn-sm{padding:6px 11px;font-size:13.5px}
.btn-primary{background:var(--orange);border-color:var(--orange);color:#1a1005}
.btn-primary:hover{background:#ff8438;border-color:#ff8438}
.btn-ghost{background:transparent}
#logout{background:transparent;border-color:#5f2723;color:#ff9a92}
#logout:hover{background:var(--red);border-color:var(--red);color:#2a0b08}
.btn-quiet{color:var(--muted)}
.btn-warn{background:var(--gold);border-color:var(--gold);color:#2a1e04}
.btn-warn:hover{background:#ffc03a;border-color:#ffc03a}
.btn-go{background:var(--green);border-color:var(--green);color:#062015}
.btn-go:hover{background:#4fd291;border-color:#4fd291}
.btn-stop{background:var(--red);border-color:var(--red);color:#2a0b08}
.btn-stop:hover{background:#ef6a5f;border-color:#ef6a5f}
.btn-danger{background:transparent;border-color:#7a2c26;color:#ff9a92}
.btn-danger:hover{background:#e2574c1f;border-color:var(--red)}
.btn-match{background:var(--blue);border-color:var(--blue);color:#04131f}
.btn-match:hover{background:#5fabf2;border-color:#5fabf2}
.btn-let{background:var(--pink);border-color:var(--pink);color:#2a0710}
.btn-let:hover{background:#f2688a;border-color:#f2688a}

/* ── sign in ─────────────────────────────────────────── */
.gate{min-height:100dvh;display:grid;place-items:center;padding:24px;
  padding-top:calc(24px + var(--sat,0px));
  padding-bottom:calc(24px + var(--sab,0px));
  background:radial-gradient(1100px 600px at 50% -10%,#1c2836 0%,var(--ink) 62%)}
.gate-card{width:min(360px,100%);background:var(--slate);border:1px solid var(--line);
  border-radius:14px;padding:32px 28px 26px;text-align:center}
.gate-mark{font-size:30px;color:var(--red);line-height:1}
.gate-title{font-family:var(--display);font-weight:800;font-size:31px;margin:8px 0 0;letter-spacing:-.01em}
.gate-sub{margin:2px 0 22px;color:var(--muted);font-family:var(--cond);
  text-transform:uppercase;letter-spacing:.18em;font-size:12px}
.field{display:block;text-align:left;margin-bottom:14px}
/* Direct child only: as a descendant selector this also hit the pick badge,
   the penalty text and the passed note inside .bidin-row, which inherited the
   label's uppercase muted styling and a 5px bottom margin. */
.field > span,.bidin-head{display:block;font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);margin-bottom:5px;font-weight:600}
.field input{width:100%;background:var(--ink);border:1px solid var(--line);
  border-radius:8px;padding:10px 12px;font-size:16px}
.gate-card .btn{width:100%;margin-top:6px}
.gate-error{color:var(--red);font-size:13.5px;min-height:19px;margin:10px 0 0}

/* ── chrome ──────────────────────────────────────────── */
.app{height:100dvh;overflow:hidden;display:flex;flex-direction:column}
.topbar{display:flex;align-items:center;gap:20px;padding:10px 18px;
  background:var(--slate);border-bottom:1px solid var(--red);flex-wrap:wrap;
  position:relative;z-index:90}
.brand{display:flex;align-items:center;gap:9px;font-family:var(--display);
  font-weight:800;font-size:18px}
/* An inline SVG rather than U+2692: the glyph renders differently on every
   platform, and this one also feeds the home screen icon. */
.brand-mark{color:var(--red);display:flex;align-items:center}
.mark-svg{width:1.05em;height:1.05em;display:block}
.gate-mark .mark-svg{width:38px;height:38px;margin:0 auto}
.topbar-right{display:flex;align-items:center;gap:12px;margin-left:auto}
.me-text{line-height:1.15;text-align:right}
.me-text b{display:block;font-size:13.5px;font-weight:600}
.me-text span{font-size:10px;letter-spacing:.13em;text-transform:uppercase;color:var(--muted)}
/* Hidden on desktop; the name and Sign out button cover it there. */
.me-avatar{transition:transform .1s}
.me-avatar:active{transform:translateY(2px)}
.me-avatar{display:block;width:32px;height:32px;padding:0;flex:0 0 auto;
  border:1px solid var(--line);border-radius:50%;background:var(--slate-2);
  overflow:hidden;cursor:pointer;-webkit-tap-highlight-color:transparent}
.me-avatar img{display:block;width:100%;height:100%;object-fit:cover;
  object-position:top center}
.me-initials{display:flex;align-items:center;justify-content:center;
  width:100%;height:100%;font-family:var(--cond);font-weight:700;font-size:13px;
  color:var(--muted)}
.account-row{display:flex;align-items:center;gap:14px}
.account-face{width:56px;height:56px;flex:0 0 auto;border-radius:12px;
  border:1px solid var(--line);background:var(--slate-2);overflow:hidden}
.account-face img{display:block;width:100%;height:100%;object-fit:cover;
  object-position:top center}
.account-face .me-initials{font-size:20px}
.account-row b{display:block;font-family:var(--display);font-size:20px;line-height:1.2}
.account-row span{font-family:var(--cond);font-size:12px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted)}

.adminbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  padding:9px 18px;background:#191f2a;border-bottom:1px solid var(--line)}

/* ── floating actions, bottom right (mobile only) ─────────────────── */
.fabs{display:flex;align-items:center;gap:8px;margin-left:auto;order:1}
.topbar-right .me-avatar{order:2}
.fabs[hidden]{display:none}
.fab{width:32px;height:32px;flex:0 0 auto;padding:0;border-radius:50%;
  border:1px solid #2b3542;background:var(--slate);color:var(--red);
  cursor:pointer;display:flex;align-items:center;justify-content:center;
  -webkit-tap-highlight-color:transparent;transition:transform .12s}
.fab:active{transform:translateY(2px)}
.fab:focus{outline:none}
.fab:focus-visible{outline:2px solid var(--teal);outline-offset:3px}
.fab-svg{width:22px;height:22px;display:block}
/* First in the bar, before the brand. */
/* The leading control is 34px on every page — the hamburger on the hub,
   the home link on the other two — and the header's own 20px gap does the
   spacing. The extra margin here, on top of a narrower box, is what put
   the wordmark in a different place on each page. */
.homefab{width:34px;height:34px;color:var(--muted);text-decoration:none}
.homefab:hover{color:var(--text);border-color:#3a4756}
.homefab .fab-svg{width:18px;height:18px}

/* ── full-screen sheets opened from the floating actions ──────────── */
/* With a sheet up, the page behind holds still — otherwise scrolling drags
   the banners and header out from under the frozen chrome. */
body.sheet-open{overflow:hidden}
.sheet{position:fixed;top:var(--chrome-h,0px);right:0;left:0;
  height:calc(var(--app-h, 100dvh) - var(--chrome-h, 0px));z-index:70;
  padding:8px 0 0;box-sizing:border-box;
  opacity:0;visibility:hidden;
  transition:opacity .24s cubic-bezier(.32,.72,0,1),visibility 0s linear .24s;
  display:flex;align-items:center;justify-content:center;
  padding:12px 12px calc(12px + var(--sab,0px));
  background:#080b0fa6;backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)}
.sheet.open{opacity:1;visibility:visible;
  transition:opacity .24s cubic-bezier(.32,.72,0,1),visibility 0s}
.sheet .sheet-card{transform:translateY(-10px) scale(.985);opacity:0;
  transition:transform .26s cubic-bezier(.32,.72,0,1),opacity .24s ease-out}
.sheet.open .sheet-card{transform:none;opacity:1}
.sheet-card{display:flex;flex-direction:column;width:min(560px,100%);
  max-height:100%;min-height:0;flex:0 1 auto;background:#141a23f2;
  border:1px solid var(--line);border-radius:14px;overflow:hidden;
  box-shadow:0 22px 60px #000000b3}
/* Opens from inside the board sheet, so it has to sit above it — same
   z-index plus later-in-DOM would have put the board on top. */
#playerSheet{z-index:80}
/* Opens from inside the other sheets. The bid overlay (82) sits above it. */
#rosterSheet{z-index:79}
/* Filters change how many rows there are; the card shouldn't resize with
   them. */
#boardSheet .sheet-card{height:100%}
/* Opens from inside the expanded board (70), so it sits above it. */
#filterSheet{z-index:76}
/* The owner and position row, revealed by the Filters button. */
.sheet-subfilter{border-top:1px solid var(--line)}
.sheet-actions .btn.on{border-color:var(--teal);color:var(--teal)}
/* Filled once something is actually filtered, so the state is visible
   without opening the card. */
.sheet-actions .btn.active{background:var(--teal);border-color:var(--teal);
  color:#062026}
#boardClearMarks{background:var(--red);border-color:var(--red);color:#fff}
#boardClearMarks:hover{background:#ef6a60;border-color:#ef6a60}
/* Your own team in an owner picker. */
/* Your own team, in the open owner list. */
option.is-me{color:#fff;font-weight:700}
#filterSheet option.is-me,
#picksSheet option.is-me,
#rosterSheet option.is-me,
#draftSheet option.is-me{color:#fff;font-weight:700}

/* The filter card is content-sized, not full height. */
#filterSheet .sheet-card{height:auto}
#filterSheet .field{display:flex;align-items:center;gap:10px;margin-bottom:10px}
#filterSheet .field > span{flex:0 0 74px;font-family:var(--cond);font-size:11px;
  font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  color:var(--muted)}
#filterSheet select{flex:1;min-width:0;background:var(--ink);
  border:1px solid var(--line);border-radius:8px;padding:9px;font-size:16px;
  color:var(--text)}
#picksSheet .sheet-filter{justify-content:flex-start}
#picksSheet .sheet-count{margin-left:0}
#picksSheet .sheet-count b{color:var(--money);font-size:14px}
/* Room to breathe, unlike the narrow rail pane. */
#picksSheetList{gap:7px}
#picksSheetList .pick{grid-template-columns:34px 1fr;gap:10px;padding:9px 11px}
#picksSheetList .pick-no{font-size:14px}
#picksSheetList .pick-val{font-size:18px}
#picksSheetList .pick-val.unl{font-size:13px}
#picksSheetList .pick-cost{font-size:11px}
#picksSheetList .pick-cost b{font-size:14px}
/* A fourth rounder buys nothing, so it reads as a note rather than a figure. */
.pick.nobid{opacity:.72}
.pick-val.nobid{color:var(--muted);font-family:var(--cond);font-size:12px;
  letter-spacing:.08em;text-transform:uppercase}
#picksSheetList .pick-val.nobid{font-size:13px}
.sheet-head{display:flex;align-items:center;justify-content:space-between;gap:12px;
  flex:0 0 auto;padding:12px 16px;background:#1a2029f2;
  border-bottom:1px solid var(--red)}
/* The whole title is the control: a native select sits invisibly over it so
   tapping the name opens the platform picker. */
.sheet-title{position:relative;display:flex;align-items:center;gap:8px;
  min-width:0;cursor:pointer}
.sheet-caret{flex:0 0 auto;font-size:11px;color:var(--muted)}
.sheet-title select{position:absolute;inset:0;width:100%;height:100%;
  opacity:0;cursor:pointer;font-size:16px}
.sheet-title b{text-decoration:none}
.sheet-head b{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;font-family:var(--cond);font-size:20px;font-weight:700;
  letter-spacing:.13em;text-transform:uppercase;color:var(--text)}
.sheet-x{width:36px;height:36px;flex:0 0 auto;padding:0;border:0;border-radius:50%;
  background:none;color:var(--muted);font-size:30px;line-height:1;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  -webkit-tap-highlight-color:transparent}
.sheet-x:focus{outline:none}
.sheet-x:hover{color:var(--text)}
.sheet-x:focus-visible{outline:2px solid var(--teal);outline-offset:2px}
.sheet-filter{display:flex;align-items:center;gap:9px;flex:0 0 auto;
  flex-wrap:wrap;row-gap:8px;padding:9px 16px;background:#161c25e6;border-bottom:1px solid var(--line)}
.sheet-filter label{font-family:var(--cond);font-size:10.5px;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
#boardSheetFilter{flex:1 0 100%;justify-content:space-between}
#boardSheetFilter button{flex:1;white-space:nowrap}
.sheet-filter select{flex:1;min-width:0;background:var(--ink);
  border:1px solid var(--line);border-radius:7px;padding:6px 8px;
  font-size:16px;color:var(--text)}
.sheet-filter select:focus{outline:none;border-color:var(--teal)}
.sheet-count{flex:0 0 auto;font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
.sheet-actions{display:flex;gap:8px;flex:0 0 auto;padding:10px 16px;
  background:#161c25e6;
  border-bottom:1px solid var(--line)}
.sheet-actions .btn{flex:1;padding:7px 6px;font-family:var(--cond);
  font-size:10.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  white-space:nowrap}
.sheet-body{flex:1 1 auto;min-height:0;overflow-y:auto;
  padding:14px 16px 20px}

/* An owner photo that opens their roster: same picture, now tappable. */
.ownerbtn{padding:0;border:0;background:none;cursor:pointer;display:flex;
  align-items:center;justify-content:center;
  -webkit-tap-highlight-color:transparent}
.ownerbtn:focus{outline:none}
.ownerbtn:focus-visible{outline:2px solid var(--teal);outline-offset:2px;
  border-radius:50%}
.ownerbtn{transition:transform .1s}
.ownerbtn:active{transform:scale(.94)}
.nom-rights .ownerbtn img{display:block}

/* One owner's roster */
.roster-cap{margin-left:auto;font-family:var(--cond);font-size:13px;
  letter-spacing:.06em;color:var(--muted);white-space:nowrap}
.roster-cap b{font-size:17px;color:var(--money)}
.rr-group{margin-bottom:16px}
.rr-head{display:flex;align-items:baseline;justify-content:space-between;
  padding:0 2px 6px;border-bottom:1px solid var(--line);margin-bottom:7px}
.rr-head b{font-family:var(--cond);font-size:15px;letter-spacing:.14em}
.rr-head span{font-family:var(--cond);font-size:11px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted)}
.rr-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;
  gap:5px}
.rr{display:flex;align-items:center;gap:10px;padding:6px 9px;
  background:var(--slate-2);border:1px solid transparent;border-radius:8px}
/* Still in play. */
/* And not for an RFA either. That completes the set: all four auction
   states drew a coloured edge, and each was removed as it was noticed
   rather than all at once — which is why they kept reappearing. */
/* Settled: won from another owner, or kept by matching. */
/* No green outline. It marked how a man was acquired, which is settled
   history and not what a lineup is for — and it read as though the row
   were selected. */
.rr.state-acquired,.rr.state-matched,.rr.state-kept{border-color:var(--line)}
/* No outline for a tagged player either. The three auction states each
   drew a coloured edge, which on a lineup card reads as though the row
   were selected — and the last of them outlasted the other two. */
.rr.tappable{cursor:pointer;transition:transform .1s,background .1s}
/* Sized and spaced in the block below, which comes later. */
.rr-nametext{min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.rr-name .rfa-stat{flex:0 0 auto;color:#4a5666}
.rr.tappable:hover .rfa-stat{color:var(--teal)}
.rr.tappable:active{background:#26303c;transform:scale(.99)}
/* position:relative for the class pill, and no overflow:hidden — the
   pill is wider than the 34px photograph, and clipping the frame cut it
   off. The picture rounds and clips itself instead. */
.rr-face{position:relative;width:34px;height:34px;flex:0 0 auto;
  border-radius:7px;background:#0f141b}
.rr-face img{display:block;width:100%;height:100%;object-fit:cover;
  object-position:top center;border-radius:7px}
.rr-face.blank{background:#141b24}
/* Team mark on the sub-line. Sized explicitly: .rr-face img would otherwise
   have stretched it across the whole photo. */
.rr-sub{display:inline-flex;align-items:center;gap:4px}
.rr-logo{width:13px;height:13px;flex:0 0 auto;object-fit:contain}
/* Three lines now: name, club, fixture. Laid out as a column so the
   spacing above and below is the row's padding on both sides — the old
   line-height left more under the last line than over the first. */
.rr-mid{flex:1;min-width:0;display:flex;flex-direction:column;
  justify-content:center;gap:2px;line-height:1.25}
/* A row, not a block: the line holds a badge and a news mark beside the
   name, and display:block dropped them onto the text baseline — which is
   why the status sat low against the name it belongs to. */
.rr-name{display:flex;align-items:center;gap:5px;min-width:0;
  font-size:14px;font-weight:600}
.rr-sub{font-family:var(--cond);font-size:10.5px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted)}
/* The sub-line stays grey whatever happened at the auction. It carries
   the club, the bye and this week's fixture now — how a man was acquired
   is settled history, and colouring that line by it made a fixture read
   as though it meant something. */
/* The sub-line stays grey too: it carries the club, the bye and this
   week's fixture, none of which is about the tag. */
.rr-sal{flex:0 0 auto;font-family:var(--cond);font-size:16px;font-weight:700;
  color:var(--money)}
.rr-rank{flex:0 0 auto;font-family:var(--cond);font-size:14px;font-weight:700;
  letter-spacing:.04em;color:var(--teal)}

/* Roster and picks side by side; the picks column drops below on a phone. */
.rr-split{display:grid;grid-template-columns:minmax(0,1fr) 172px;gap:16px;
  align-items:start}
.rr-main{min-width:0}
.rr-picks{min-width:0}
.rr-picklist{list-style:none;margin:0;padding:0;display:flex;
  flex-direction:column;gap:4px}
.rr-picklist li{display:flex;align-items:center;gap:6px;padding:5px 7px;
  background:var(--slate-2);border-radius:7px}
.rr-picklist .pick-chip{flex:0 0 auto;min-width:38px;padding:2px 6px;
  font-size:11px;line-height:1.35;text-align:center}
.rr-pickval{flex:1;min-width:0;font-family:var(--cond);font-size:13px;
  font-weight:700;color:var(--money);white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis}
.rr-pickcost{flex:0 0 auto;display:inline-flex;align-items:baseline;gap:4px;
  font-family:var(--cond);font-size:9px;letter-spacing:.04em;
  color:var(--muted);white-space:nowrap}
.rr-pickcost b{font-size:12px;font-weight:700;color:var(--money)}
.rr-pickcost i{font-style:normal}
.rr-nopicks{margin:0;font-size:13px;color:#5a687a}
/* Later years: round badge, then who the pick came from. */
.rr-picklist li.future{gap:8px}
.rr-pickfrom{flex:1;min-width:0;font-family:var(--cond);font-size:11.5px;
  letter-spacing:.04em;color:var(--muted);white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis}
/* A pick you started with reads differently from one you traded for. */
.rr-pickfrom.own{color:#5a687a}
.rr-picks .rr-group{margin-bottom:14px}

/* Lineup */
.rr-list.lineup{gap:6px}
.lu{display:flex;align-items:center;gap:9px}
/* Clearing the lineup. It had no styling at all, so it fell back to the
   browser's own button — a grey slab in the middle of a dark card. */
.lu-clear{display:block;width:100%;margin-top:10px;padding:9px 12px;
  border-radius:8px;cursor:pointer;
  border:1px solid var(--line);background:var(--slate-2);color:var(--muted);
  font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase}
.lu-clear:hover{border-color:#7d3a33;background:#2a1614;color:#ff9b90}

/* The week's projection, where the salary used to be. */
.lu-proj{font-family:var(--cond);font-size:14px;font-weight:700;
  color:var(--text);font-variant-numeric:tabular-nums}

/* Top-aligned: the row grows downward when its drawer opens, and a
   centred label drifted down the card with it. */
.lu-slot{width:44px;flex:0 0 auto;align-self:flex-start;margin-top:9px;
  font-family:var(--cond);font-size:12px;
  font-weight:700;letter-spacing:.1em;text-align:center;color:var(--muted)}
.lu-slot.pos-QB{color:var(--pos-qb)}
.lu-slot.pos-RB{color:var(--pos-rb)}
.lu-slot.pos-WR{color:var(--pos-wr)}
.lu-slot.pos-TE{color:var(--pos-te)}
.lu-slot.pos-FLEX{color:var(--gold)}
/* OP takes anyone, so it gets its own colour rather than borrowing FLEX's. */
.lu-slot.pos-OP{color:#e07b26}
.lu-slot.bn{color:var(--red)}
/* The bench, set apart from the starters above it. */
.rr-list.bench{margin-top:14px;padding-top:12px;border-top:1px solid var(--line)}
.lu-player{flex:1;min-width:0}
.lu-empty{flex:1;display:flex;align-items:center;min-height:48px;
  box-sizing:border-box;padding:6px 9px;
  border:1px dashed var(--line);border-radius:8px;
  font-family:var(--cond);font-size:12px;letter-spacing:.08em;
  text-transform:uppercase;color:#4a5666}

/* League access: who's here, and their sign-in details */
.people{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;
  gap:6px}
.person-pw{display:flex;align-items:center;gap:6px;flex:0 0 auto}
.person-pw-input{width:118px;background:var(--ink);border:1px solid var(--line);
  border-radius:7px;padding:6px 8px;font-family:var(--cond);font-size:13px;
  letter-spacing:.02em;color:var(--text)}
.person-pw-input::placeholder{font-size:10px;letter-spacing:.04em;
  text-transform:uppercase;color:#4a5666}
.person-pw-input:focus{outline:none;border-color:var(--teal)}
.person-pw-save{flex:0 0 auto}
.person{display:flex;align-items:center;gap:11px;padding:8px 10px;
  background:var(--slate-2);border:1px solid transparent;border-radius:9px}
.person.online{border-color:#2f8f5b}
.person-face{position:relative;width:36px;height:36px;flex:0 0 auto;
  border-radius:50%;overflow:visible;background:#0f141b;display:flex;
  align-items:center;justify-content:center;font-family:var(--cond);
  font-size:14px;font-weight:700;color:var(--muted)}
.person-face img{width:100%;height:100%;border-radius:50%;object-fit:cover;
  object-position:top center}
.person-initials{position:absolute;inset:0;display:flex;align-items:center;
  justify-content:center}
/* The presence dot, on the photo rather than beside it. */
.person-dot{position:absolute;right:-1px;bottom:-1px;width:11px;height:11px;
  border-radius:50%;background:#3f4b5c;border:2px solid var(--slate-2)}
.person.online .person-dot{background:var(--green)}
.person-mid{flex:1;min-width:0;line-height:1.25}
.person-name{display:block;font-size:14px;font-weight:600;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.person-sub{font-family:var(--cond);font-size:10.5px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}
.person.online .person-sub{color:var(--money)}

/* A settled row is history: no target colouring, nothing live about it. */
.rfa-row.done,.rfa-row.done.mine,.rfa-row.done.targeted,.rfa-row.done.live{
  background:var(--slate-2);border-color:transparent}
.rfa-row.done .rfa-name,.rfa-row.done .rfa-nametext,
.rfa-row.done .rfa-sub,.rfa-row.done .rfa-n{color:var(--muted)}
.rfa-row.done .pos{color:var(--muted)}
.rfa-row.done .rfa-logo{filter:grayscale(1);opacity:.55}
.rfa-row.done .rfa-stat{color:#4a5666}
.rfa-row.done .rfa-amt{color:var(--muted)}
/* Owner, arrow and salaries run past the row on a phone, so the line drifts
   back and forth rather than truncating. */
.rfa-row.done .rfa-sub{overflow:hidden;contain:paint}
.rfa-row.done .rfa-sub > span{display:inline-block;white-space:nowrap}
/* Only the lines that actually overflow drift, by exactly their overflow —
   measured after layout, since CSS can't work it out. */
.rfa-sub > span.drift{animation:sub-drift 9s ease-in-out infinite alternate}
@keyframes sub-drift{
  0%,16%{transform:translateX(0)}
  84%,100%{transform:translateX(var(--sub-shift, 0px))}
}
@media (prefers-reduced-motion:reduce){
  .rfa-sub > span.drift{animation:none}
}
/* One Shining Moment: a star instead of a nomination number, and a rule
   separating the group from the RFA class below. */
.rfa-row .rfa-n.rfa-star,
.rfa-row.done .rfa-n.rfa-star{color:#fff;font-size:13px;line-height:1}
.rfa-row.mine .rfa-n.rfa-star{color:var(--gold);font-size:13px;line-height:1}
/* Your own One Shining Moment player, named as such. */
.tgt-osm{letter-spacing:.02em}
.rfa-row.shining .rfa-name{font-weight:600}
.rfa-row.last-shining{position:relative;margin-bottom:11px}
.rfa-row.last-shining::after{content:"";position:absolute;left:8px;right:8px;
  bottom:-6px;height:1px;background:var(--line)}
/* The same break, above the group instead, for when it runs last. */
.rfa-row.first-shining{position:relative;margin-top:11px}
.rfa-row.first-shining::before{content:"";position:absolute;left:8px;right:8px;
  top:-6px;height:1px;background:var(--line)}
.rfa-verdict{font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase}
.rfa-verdict.matched{color:var(--green)}
.rfa-verdict.relinquished{color:var(--orange)}
.rfa-verdict.no_bids{color:#5a687a}
/* Tagged: the hammer's own red, so it reads apart from won or kept. */
.rfa-verdict.tagged{color:var(--red)}
.tgt-tagged{width:22px;flex:0 0 auto;display:flex;align-items:center;
  justify-content:center;color:var(--red)}
.tgt-tagged svg{width:15px;height:15px;display:block}
.rfa-row.done .tgt-tagged{color:var(--red)}
.tag-btn{border-color:var(--red);color:var(--red);background:none;
  font-family:var(--cond);font-size:11px;font-weight:700;letter-spacing:.12em;
  text-transform:uppercase}
.tag-btn:hover{background:#e2574c1f}

/* The transfer, spelled out under the rights line. */
.nom-flow{display:flex;align-items:center;gap:10px;padding:10px 0 2px;
  flex-wrap:wrap}
.flow-owner{display:flex;align-items:center;gap:7px;font-size:13px;
  font-weight:600;min-width:0}
.flow-face{width:26px;height:26px;flex:0 0 auto}
.flow-face img{width:26px;height:26px;border-radius:50%;object-fit:cover;
  object-position:top center;display:block}
.flow-arrow{flex:0 0 auto;font-size:17px;color:var(--muted)}

/* Owner badges: a crown for the champion, a throne for the wooden spoon.
   Tucked into the bottom-right corner of the owner's photo. On the viewer's
   own row it stands in for the star. */
.has-badge{position:relative;overflow:visible}
.obadge{position:absolute;right:-4px;bottom:-4px;z-index:3;width:9px;
  height:9px;font-size:9px;line-height:1;pointer-events:none;
  /* A hairline of the pane colour, so it reads apart from the photo. */
  filter:drop-shadow(.7px 0 0 var(--slate)) drop-shadow(-.7px 0 0 var(--slate))
         drop-shadow(0 .7px 0 var(--slate)) drop-shadow(0 -.7px 0 var(--slate))}
.obadge.tiny{font-size:8px;width:8px;height:8px;right:-3px;bottom:-3px}
.lg-row.mine .lg-face.has-badge::after{display:none}

.obadge-trophy::after{content:"\1F3C6";position:absolute;right:0;bottom:0;
  animation:trophy-shine 9s ease-in-out infinite}
@keyframes trophy-shine{
  0%,86%{transform:none;filter:none}
  91%{transform:scale(1.18) rotate(-6deg);
    filter:drop-shadow(0 0 5px #ffd970) brightness(1.55) saturate(1.2)}
  96%{transform:scale(1.06) rotate(3deg);filter:none}
  100%{transform:none;filter:none}
}

/* A shade warmer than the stock porcelain, so it reads on a dark row. */
.obadge-throne::after{content:"\1F6BD";position:absolute;right:0;bottom:0;
  filter:sepia(.45) saturate(1.3) hue-rotate(-8deg) brightness(1.08)}
/* A squirt that arcs out of the bowl now and then. */
.obadge-throne::before{content:"";position:absolute;right:7px;bottom:3px;
  width:3px;height:3px;border-radius:50%;background:#7a4a1e;opacity:0;
  animation:throne-squirt 11s cubic-bezier(.3,-.4,.7,1.4) infinite}
@keyframes throne-squirt{
  0%,88%{opacity:0;transform:translate(0,0) scale(.5)}
  90%{opacity:1;transform:translate(-2px,-5px) scale(1)}
  94%{opacity:1;transform:translate(-6px,-1px) scale(.8)}
  98%{opacity:0;transform:translate(-9px,5px) scale(.4)}
  100%{opacity:0;transform:translate(0,0) scale(.5)}
}

/* The round photo in the draft summary carries one too. */
.dr-face .obadge{right:-2px;bottom:-2px}

@media (prefers-reduced-motion:reduce){
  .obadge-trophy::after,.obadge-throne::before{animation:none}
  .obadge-throne::before{display:none}
}

/* The FantasyPros mark, sitting in a stat card header. */
.fp-btn{flex:0 0 auto;width:20px;height:20px;padding:0;border:0;background:none;
  cursor:pointer;display:flex;align-items:center;justify-content:center;
  -webkit-tap-highlight-color:transparent}
.fp-btn img{display:block;border-radius:50%}
.fp-btn:active{transform:scale(.92)}
.fp-btn:focus{outline:none}
.fp-btn:focus-visible{outline:2px solid var(--teal);outline-offset:2px;
  border-radius:50%}
/* The collapsible header is itself a button, so the logo sits beside it. */
.stat-head-row{display:flex;align-items:center;gap:8px;padding-left:11px;
  background:#161c25;border-bottom:1px solid var(--line)}
.stat-head-row .stat-head{flex:1;padding-left:0;background:none;border-bottom:0}

/* Bid history: the reveal cards again, centred in the card. */
.bidhist{margin-top:12px}
.bidhist-count{margin-left:auto;font-family:var(--cond);font-size:11px;
  letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.bidhist .hist-inner{width:100%}
.bidhist-cards{box-sizing:border-box;width:100%;max-width:520px;margin:0 auto;
  padding:12px}
.bidhist-cards .card{height:46px}
.bidhist-cards .card-face{padding:0 11px;gap:9px}
.bidhist-cards .card-pic{width:26px;height:26px}
.bidhist-none{margin:0;padding:22px 12px;text-align:center;
  font-family:var(--cond);font-size:13px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--muted)}
.bidhist-took{margin:0 12px 12px;text-align:center;font-size:12px;
  color:var(--muted)}
.bidhist-took b{color:var(--text);font-family:var(--cond);font-size:14px}

/* Settled: a plain statement of fact under the header rule. */
.rfa-done-banner{margin:-14px -16px 14px;padding:8px 16px;
  background:#152a20;border-bottom:1px solid #2f8f5b;
  font-family:var(--cond);font-size:11.5px;font-weight:700;letter-spacing:.16em;
  text-transform:uppercase;color:var(--green);text-align:center}
.rfa-done-banner b{color:#fff}
/* A relinquished player left the roster, so the banner carries the same
   orange the board verdict uses. */
.rfa-done-banner.relinquished{background:#2c1c0c;border-bottom-color:#8a5a1c;
  color:var(--orange)}
.rfa-done-banner.no_bids{background:#1a2029;border-bottom-color:#2b3542;
  color:var(--muted)}
.rfa-done-banner.tagged{background:#2a1413;border-bottom-color:#8a3a33;
  color:var(--red)}
.rfa-done-banner.no_bids b{color:var(--text)}

/* Salary that moved: the old figure struck through beside the new one. */
.sal-was{color:var(--muted);text-decoration-color:#5a687a;
  text-decoration-thickness:2px;font-weight:400;margin-right:2px}
.rfa-sal{color:var(--money);font-weight:600}
.rfa-row .rfa-sub .rfa-sal,
.rfa-row.done .rfa-sub .rfa-sal{color:var(--money)}
.rfa-row.done .rfa-sub .sal-was{color:var(--muted);
  text-decoration-color:#5a687a}

/* The winning bid was refused, so it reads as spent rather than won. */
.bidhist-cards.refused .card.top .card-front{background:var(--slate-2)}
.bidhist-cards.refused .card.top .card-front::before{display:none}
.bidhist-cards.refused .card.top .card-front::after{display:none}
.bidhist-cards.refused .card.top{filter:grayscale(1);opacity:.65}

/* Where every team stands. */
#leagueSheet .sheet-card,#rosterSheet .sheet-card,
#draftSheet .sheet-card{height:100%}
#signedSheet .sheet-card{height:100%}
.pane-signed .pane-head{gap:8px}
.pane-signed .signed-totals{margin-left:auto}
.lg-row{display:grid;
  grid-template-columns:minmax(0,1fr) 32px 18px 20px 36px 62px 46px;
  align-items:center;gap:2px;width:100%;padding:8px 3px;margin-bottom:4px;
  background:var(--slate-2);border:1px solid transparent;border-radius:8px;
  color:var(--text);font:inherit;text-align:left;cursor:pointer}
.lg-row{transition:transform .1s}
.lg-row:not(.lg-head):active{transform:scale(.99)}
.lg-row.mine{border-color:var(--gold)}
.lg-row.mine .lg-face::after{content:"\2605";position:absolute;right:-3px;
  bottom:-3px;font-size:10px;line-height:1;color:var(--gold);
  text-shadow:0 0 3px #000,0 0 3px #000}
.lg-row.mine .lg-face{position:relative}
.lg-row.broke{opacity:.55}
.lg-head{background:none;margin-bottom:9px;padding-bottom:6px;
  border-bottom:1px solid var(--line);cursor:default;
  font-family:var(--cond);font-size:10px;font-weight:700;letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted)}
.lg-team{display:flex;align-items:center;gap:4px;min-width:0}
.lg-face{width:18px;height:18px;flex:0 0 auto}
.lg-face img{width:18px;height:18px;border-radius:50%;object-fit:cover;
  object-position:top center;display:block}
.lg-name{min-width:0;font-size:10px;letter-spacing:-.03em;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.lg-num{font-family:var(--cond);font-size:11.5px;font-weight:700;
  text-align:center;letter-spacing:-.02em}
.lg-head .lg-num,.lg-head .lg-team{border:0;background:none;padding:0;
  font-family:var(--cond);letter-spacing:.06em;text-transform:uppercase;
  color:var(--muted);cursor:pointer}
.lg-head .lg-num{font-size:8px;font-weight:700;line-height:1;text-align:center;
  letter-spacing:0;white-space:nowrap}
.lg-head .sorted{color:var(--teal)}
/* Borders, not characters: identical on every device. */
.lg-head i{display:inline-block;width:0;height:0;margin-left:3px;
  vertical-align:middle;border-left:3px solid transparent;
  border-right:3px solid transparent}
.lg-head i.desc{border-top:4px solid currentColor}
.lg-head i.asc{border-bottom:4px solid currentColor}
.lg-head .lg-team{font-size:9px;font-weight:700}
.lg-power{color:var(--money)}
.lg-none{color:var(--red);font-size:9.5px;letter-spacing:0;line-height:1.1;
  text-transform:uppercase}
.lg-dash{color:#4a5666}
.lg-num i{font-style:normal;font-size:inherit;color:var(--red)}
.lg-match{color:var(--gold)}
.lg-back{flex:0 0 auto;background:var(--red);border-color:var(--red);color:#fff}
.lg-roster{flex:0 0 auto;margin-left:auto;background:var(--green);
  border-color:var(--green);color:#062015}
#leagueSheet .sheet-filter{flex-wrap:nowrap}
/* The buttons live inside the count span, so that's what has to be the row
   — otherwise there's no free space for the margin to push against. */
#leagueSheet .sheet-count{display:flex;flex:1;align-items:center;gap:9px;
  min-width:0}
#leagueSheet .sheet-count .lg-roster{margin-left:auto}
.lg-roster:hover{background:#4fd08f;border-color:#4fd08f}
.lg-stripcount{flex:0 0 auto;white-space:nowrap}
/* The card names the team first, then what the card is. */
.lg-title-sub{color:#fff;font-weight:400}
.lg-sortnote{margin-left:auto;text-align:right;font-family:var(--cond);
  font-size:9px;letter-spacing:.04em;text-transform:uppercase;
  color:var(--teal);white-space:nowrap}
.lg-strip-note{margin-left:auto;font-family:var(--cond);font-size:11px;
  letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
#leagueSheet .sheet-filter{gap:10px}
.lg-back:hover{background:#ef6a60;border-color:#ef6a60}
/* The four figures behind a team's position. */
.lg-money{display:grid;gap:1px;background:var(--line)}
.lg-money-2{grid-template-columns:1fr 1fr}
.lg-money-3{grid-template-columns:1fr 1fr 1fr;border-top:1px solid var(--line)}
.lg-money-cell{display:flex;flex-direction:column;align-items:center;
  justify-content:center;gap:3px;padding:11px 6px;background:var(--slate)}
.lg-money-cell b{font-family:var(--cond);font-size:19px;font-weight:700;
  line-height:1.1;text-align:center}
.lg-money-3 .lg-money-cell b{font-size:16px}
.lg-money-cell i{font-style:normal;font-size:11px;color:var(--red)}
.lg-nopicks{font-style:normal;font-family:var(--cond);font-size:8.5px;
  font-weight:700;letter-spacing:.1em;text-transform:uppercase;
  color:var(--red)}
.lg-money-cell b.money{color:var(--money)}
.lg-money-cell span{font-family:var(--cond);font-size:9px;font-weight:700;
  letter-spacing:.08em;text-transform:uppercase;color:var(--muted);
  text-align:center;line-height:1.2}
.lg-group{margin-bottom:10px}
.lg-group-body{padding:9px}
.lg-player{transition:transform .1s}
.lg-player:active{transform:scale(.99)}
.lg-player{display:flex;align-items:center;gap:8px;width:100%;padding:6px 8px;
  margin-bottom:4px;background:var(--slate-2);border:0;border-radius:7px;
  color:var(--text);font:inherit;text-align:left;line-height:1;cursor:pointer}
.lg-player-name{flex:1;min-width:0;font-size:13px;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.lg-player-sal{font-family:var(--cond);font-size:14px;font-weight:700;
  color:var(--money)}

/* The running order: drag to move, or send a player straight up. */
.orderlist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;
  gap:5px}
.ord{display:flex;align-items:center;gap:10px;padding:7px 9px;line-height:1;
  background:var(--slate-2);border:1px solid transparent;border-radius:8px;
  cursor:grab}
.ord{transition:transform .1s}
.ord:active{transform:scale(.99)}
.ord.dragging{opacity:.45}
.ord.over{border-color:var(--teal)}
.ord-n{width:22px;flex:0 0 auto;font-family:var(--cond);font-size:12px;
  color:var(--muted);text-align:center}
.ord-mid{flex:1;min-width:0}
.ord-name{display:flex;align-items:center;gap:6px;font-size:13.5px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ord-sub{font-family:var(--cond);font-size:10.5px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}
.ord-grip{flex:0 0 auto;font-size:16px;color:#4a5666;cursor:grab}
#orderSheet .sheet-card{height:100%}

/* Draft summary rows */
.dr-round{margin-bottom:18px}
.dr-head{display:flex;align-items:baseline;justify-content:space-between;
  padding:0 2px 7px;border-bottom:1px solid var(--line);margin-bottom:8px}
.dr-head b{font-family:var(--display);font-size:17px}
.dr-head span{font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
.dr-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:5px}
.dr-none{padding:10px 0;text-align:center;font-family:var(--cond);font-size:16px;
  color:#3b4756}
.dr-round.empty-round .dr-head{opacity:.55}
.dr-row{display:flex;align-items:center;gap:10px;padding:7px 9px;
  min-height:52px;box-sizing:border-box;
  background:var(--slate-2);border:1px solid transparent;border-radius:8px}
/* Your own picks: a rotating red ring. Rotated with transform rather than by
   animating the gradient's angle — there can be a dozen of these on screen,
   and repainting a conic gradient per row per frame is what makes it chug. */
.dr-row.mine{border-color:transparent;position:relative;overflow:hidden;
  contain:paint}
.dr-row.mine::before{content:"";position:absolute;left:50%;top:50%;
  width:112%;aspect-ratio:1;pointer-events:none;z-index:0;
  background:conic-gradient(#7a2c26,#e2574c,#ff9b2f,#ff5a4d,#c2352b,#e2574c,#7a2c26);
  transform:translate(-50%,-50%) rotate(0deg);
  animation:ring-spin 4.5s linear infinite}
.dr-row.mine::after{content:"";position:absolute;inset:1px;border-radius:7px;
  background:#191519;pointer-events:none;z-index:1}
.dr-row.mine > *{position:relative;z-index:2}
.dr-row.mine .dr-who b{color:var(--gold)}

/* The unlimited picks — the ones with no ceiling — get the full rainbow. */
.dr-row.unl{border-color:transparent;position:relative;overflow:hidden;
  contain:paint}
.dr-row.unl::before{content:"";position:absolute;left:50%;top:50%;
  width:112%;aspect-ratio:1;pointer-events:none;z-index:0;
  background:conic-gradient(#ff5a4d,#ff9b2f,#ffd23f,#3fbf7f,#2bb3be,#5b8cff,
    #a86bff,#ff5a4d);
  transform:translate(-50%,-50%) rotate(0deg);opacity:0;
  animation:ring-spin 5s linear infinite,ring-flash 10s ease-in-out infinite;
  animation-delay:0s,1.7s}
.dr-row.unl::after{content:"";position:absolute;inset:1px;border-radius:7px;
  background:#1a2333;pointer-events:none;z-index:1}
.dr-row.unl > *{position:relative;z-index:2}
/* Both at once: the owner treatment wins the ring and the base colour, and
   the rainbow sweeps across the gold rather than replacing it. */
.dr-row.mine.unl{--unl-base:var(--gold)}
.dr-row.mine.unl::before{
  background:conic-gradient(#7a2c26,#e2574c,#ff9b2f,#ff5a4d,#c2352b,#e2574c,#7a2c26);
  opacity:1;animation:ring-spin 4.5s linear infinite}
.dr-row.mine.unl::after{background:#191519}
.dr-row.unl .dr-bid{
  background:linear-gradient(100deg,
    var(--unl-base,#fff) 0 45%,#ff5a4d 47.5%,#ffd23f 49%,#3fbf7f 50.5%,
    #2bb3be 52%,#5b8cff 53.5%,var(--unl-base,#fff) 56% 100%);
  background-size:700% 100%;background-position:0% 0;
  -webkit-background-clip:text;background-clip:text;color:transparent;
  animation:unl-shine 10s ease-in-out infinite;
  animation-delay:1.7s;font-size:13px;letter-spacing:.02em}

/* Only the viewer's own face keeps its colour. */
.dr-face{position:relative;width:26px;height:26px;flex:0 0 auto;padding:0;
  border:0;background:none}
/* The circle and the greyscale live on the photo, so the badge beside it
   keeps its own shape and colour. */
.dr-face img{display:block;width:100%;height:100%;object-fit:cover;
  object-position:top center;border-radius:50%;background:var(--slate-2);
  filter:grayscale(1);opacity:.62}
.dr-row.mine .dr-face img{filter:none;opacity:1}
.dr-row .pick-chip{flex:0 0 auto;min-width:34px;text-align:center}
.dr-who{flex:1;min-width:0;line-height:1.2}
.dr-who b{display:block;font-size:13.5px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.dr-from{font-family:var(--cond);font-size:10.5px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--gold)}
.dr-vals{flex:0 0 auto;width:92px;text-align:right;line-height:1.15}
.dr-bid{display:block;font-family:var(--cond);font-size:15px;font-weight:700;
  color:var(--money)}
.dr-cost{font-family:var(--cond);font-size:10.5px;letter-spacing:.06em;
  color:var(--muted)}

/* ── the room clock, pinned under the topbar ──────────────────────── */
/* The rookie board's banner shape: the label and the figure centred as a
   pair, and the countdown as a rule along the bottom edge rather than a
   bar competing with them for the same line. */
.roomclock{position:sticky;top:0;z-index:89;display:flex;align-items:center;
  justify-content:center;gap:12px;overflow:hidden;
  padding:9px 18px;background:#161c25;border-bottom:1px solid var(--line)}
.roomclock-label{align-self:center;line-height:1;
  font-family:var(--cond);font-size:12px;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
.roomclock-label.swap{animation:label-roll .34s cubic-bezier(.22,.8,.3,1)}
@keyframes label-roll{
  from{opacity:0;transform:translateY(6px)}
  to{opacity:1;transform:none}
}
@media (prefers-reduced-motion:reduce){ .roomclock-label.swap{animation:none} }
.roomclock-num{font-family:var(--cond);font-size:26px;font-weight:700;
  line-height:1;color:#fff;font-variant-numeric:tabular-nums}
.roomclock-num.urgent{color:var(--red)}
.roomclock-num.paused{color:var(--muted)}
/* Along the bottom of the bar, full at the top of a timer and gone at the
   end — the same rail the rookie draft's banner uses. */
.roomclock-bar{position:absolute;left:0;right:0;bottom:0;height:3px;
  border-radius:0;background:#0e131b;overflow:hidden}
.roomclock-bar i{display:block;height:100%;background:#fff;
  transition:width .25s linear}
.roomclock-bar i.urgent{background:var(--red)}
.roomclock-bar i.paused{background:#4a5666}

/* Room settings row, above the action bar. */
.autobar{gap:12px}
.ab-label{font-family:var(--cond);font-size:10.5px;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted)}
.ab-field{display:flex;align-items:center;gap:5px;font-family:var(--cond);
  font-size:11px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted)}
.ab-field input{width:52px;background:var(--ink);border:1px solid var(--line);
  border-radius:6px;padding:3px 6px;font-family:var(--cond);font-size:13px;
  font-weight:700;color:var(--text);text-align:center}
.ab-field input:focus{outline:none;border-color:var(--teal)}

/* The decision window echoes the countdown. */
.verdict-clock{display:flex;align-items:center;justify-content:center;gap:10px;
  margin:18px 0 14px;padding:10px 14px;border-radius:10px;
  background:#05070a;border:1px solid #2b3542;
  font-family:var(--cond);font-size:11.5px;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;color:#fff;transition:border-color .2s,color .2s}
.verdict-clock b{font-size:21px;line-height:1;color:#fff;
  font-variant-numeric:tabular-nums}
.verdict-clock.urgent{border-color:var(--red);color:var(--red)}
.verdict-clock.urgent b{color:var(--red)}

/* Always-on scroll indicator: iOS hides native overlay scrollbars, so the
   picks list draws its own. */
.pane-picks{position:relative}
.pane-scroll{position:absolute;right:4px;width:4px;border-radius:2px;
  background:#ffffff0f;pointer-events:none;z-index:6;
  opacity:0;transition:opacity .35s ease .4s}
.pane-scroll.showing{opacity:1;transition:opacity .12s ease}
.pane-scroll::after{content:"";position:absolute;left:0;right:0;
  top:var(--thumb-t,0);height:var(--thumb-h,24px);
  background:var(--red);border-radius:2px}

/* ── the two top banners ──────────────────────────────────────────── */
.alerts{display:flex;flex-direction:column;position:relative;z-index:2}
/* The second ribbon slides up behind the first, so the first has to sit
   above it and the pair has to clip at the top. */
.alerts > .alert:first-child{position:relative;z-index:2}
.alerts > .alert{position:relative;z-index:1}
.alert.ascend{animation:ribbon-up .26s cubic-bezier(.4,0,.9,.4) forwards}
/* A restyle of the same player wipes across rather than switching outright. */
.alert-sweep{position:absolute;inset:0;z-index:2;pointer-events:none;
  opacity:0;
  background:linear-gradient(100deg, transparent 0 38%, #ffffff26 46%,
    #ffffff40 50%, #ffffff26 54%, transparent 62% 100%);
  background-size:260% 100%}
.alert.sweep .alert-sweep{animation:alert-sweep .5s cubic-bezier(.25,.6,.3,1) 1}
@keyframes alert-sweep{
  from{background-position:130% 0;opacity:1}
  to{background-position:-70% 0;opacity:0}
}
@media (prefers-reduced-motion:reduce){
  .alert.sweep .alert-sweep{animation:none;display:none}
}
.alert.descend .alert-body{animation:ribbon-down .3s cubic-bezier(.2,.8,.3,1)}
@keyframes ribbon-up{
  0%{transform:translateY(0);opacity:1}
  100%{transform:translateY(-100%);opacity:0}
}
@keyframes ribbon-down{
  0%{transform:translateY(-100%);opacity:0}
  60%{opacity:1}
  100%{transform:translateY(0);opacity:1}
}
@media (prefers-reduced-motion:reduce){
  .alert.ascend,.alert.descend .alert-body{animation:none}
}
/* Passed: the player is still next, but you've said no. Red wash, a red rule
   beneath, and PASS tiled behind everything at a slightly brighter red. */
.alerts .alert.passed .alert-body{background:#2a1210;
  border-bottom:1px solid var(--red)}
.alert.passed .alert-body::before{content:"";position:absolute;inset:0;
  z-index:0;pointer-events:none;
  background-image:repeating-linear-gradient(-24deg,
    transparent 0 2px, #e2574c26 2px 3px, transparent 3px 26px);
  /* The word itself, repeated across the strip. */
  background-image:url("data:image/svg+xml;utf8,\
<svg xmlns='http://www.w3.org/2000/svg' width='52' height='22'>\
<text x='1' y='8' font-family='Barlow Condensed,Arial Narrow,sans-serif'\
 font-size='7' font-weight='700' letter-spacing='1'\
 fill='%23e2574c' fill-opacity='0.07' transform='rotate(-12 1 8)'>PASS</text>\
<text x='27' y='19' font-family='Barlow Condensed,Arial Narrow,sans-serif'\
 font-size='7' font-weight='700' letter-spacing='1'\
 fill='%23e2574c' fill-opacity='0.07' transform='rotate(-12 27 19)'>PASS</text>\
</svg>");
  background-repeat:repeat}
/* Everything else rides above the tiling. */
.alert.passed .alert-face,.alert.passed .alert-pos,.alert.passed .alert-name,
.alert.passed .alert-info,.alert.passed .alert-away,.alert.passed .alert-tag{
  position:relative;z-index:1}
/* The team mark and position lose their colour — this isn't live any more. */
.alert.passed .alert-face img{filter:grayscale(1);opacity:.55}
.alert.passed .alert-pos{color:var(--muted)}
/* The pill matches the rule underneath. */
.alerts .alert.passed .alert-away{color:var(--red);border-color:var(--red)}
.alerts .alert.passed .alert-name{color:#f0928a}
.alerts .alert.passed .alert-body{--shine-tint:transparent}

/* The banner itself is always open; the drawer inside it is what collapses. */
.alert{display:grid;grid-template-rows:1fr}
.alert-clip{overflow:hidden;min-height:0}
.alert-body{position:relative;overflow:hidden;display:flex;align-items:center;
  gap:9px;width:100%;padding:8px 18px;border:0;border-bottom:1px solid transparent;
  background:none;color:inherit;font:inherit;text-align:left;cursor:pointer;
  -webkit-tap-highlight-color:transparent}
.alert-body:focus{outline:none}
.alert-body:focus-visible{outline:2px solid var(--teal);outline-offset:-2px}

/* Up next: the same green as the live board row, with a darker rule beneath.
   A rotating gradient on a 2px strip reads as a flicker, not a sweep. */
.alert.next .alert-body{background:#152a3f;border-bottom-color:#3a6ea8;
  color:var(--text)}
.alert.next .alert-away{color:var(--blue)}
/* Up next and on your board: same green as any other target, still labelled
   UP NEXT. Named with the container so it beats .alert.next above. */
.alerts .alert.next.ontarget .alert-body{background:#14301f;
  border-bottom-color:#2f8f5b;color:var(--money)}
.alerts .alert.next.ontarget .alert-away{color:var(--green);
  border-color:var(--green)}
.alerts .alert.next.ontarget .alert-body{--shine-tint:#3fbf7f2b}
/* The next player you're chasing. */
.alert.hot .alert-body{background:#14301f;border-bottom-color:#2f8f5b;
  color:var(--money)}
/* One of your own RFAs. */
.alert.mine .alert-body{background:#242118;border-bottom-color:#f2b01e4d;
  color:var(--gold)}
.alert.mine .alert-name{color:var(--gold)}


.alert-pos{font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.08em;color:var(--pos-wr)}
.alert-pos.pos-RB{color:var(--pos-rb)}
.alert-pos.pos-QB{color:var(--pos-qb)}
.alert-pos.pos-TE{color:var(--pos-te)}
.alert-name{flex:0 1 auto;min-width:0;font-weight:700;font-size:13.5px;
  color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.alert-away{flex:0 0 auto;margin-left:auto;font-family:var(--cond);font-size:11px;
  font-weight:700;letter-spacing:.1em;text-transform:uppercase;padding:2px 7px;
  border-radius:5px;border:1px solid currentColor;background:#0000004d}
/* The tag sits with the name, so only the away badge is pushed right. */
.alert-tag{flex:0 0 auto}
.alert-info{margin-left:-3px;margin-right:2px}
.alert-info{width:13px;height:13px;flex:0 0 auto;color:currentColor;opacity:.6}
.alert-body:hover .alert-info{opacity:1}
.alert-tag{flex:0 0 auto;font-family:var(--cond);font-size:10px;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:var(--gold);
  border:1px solid #f2b01e66;background:#3d3219;border-radius:5px;padding:2px 7px}
.alert-face{width:26px;height:26px;flex:0 0 auto;border-radius:6px;
  display:flex;align-items:center;justify-content:center}
.alert-face img{display:block;width:100%;height:100%;object-fit:contain}

/* The player summary, folded away until the caret is tapped. */

/* A highlight sweeping across, idle for most of the cycle. */
.alert-body::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(105deg,transparent 26%,
    var(--shine-tint,#ffffff20) 50%,transparent 74%);
  transform:translateX(-140%);
  animation:alert-shine var(--shine-dur,22s) ease-in-out var(--shine-delay,0s) infinite}
.alert.hot .alert-body{--shine-tint:#3fbf7f2b}
.alert.mine .alert-body{--shine-tint:#f2b01e24}
@keyframes alert-shine{
  0%,88%{transform:translateX(-140%)}
  100%{transform:translateX(140%)}
}

/* ── the pinned bar shown once the bidding overlay is closed ──────── */
.bidresume{position:sticky;top:0;z-index:88;display:flex;align-items:center;gap:12px;
  padding:8px 18px;background:#1d2530;border-bottom:1px solid var(--teal)}
.bidresume-chip{display:flex;align-items:center;flex:0 0 auto}
.bidresume-chip .pick-chip{font-size:13px;padding:2px 7px}
.bidresume-txt{flex:1;min-width:0;font-size:13.5px;color:var(--text);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bidresume .btn{flex:0 0 auto}

/* The bidding overlay reuses the splash frame; only the head differs. */
.bidstage .splash-head{flex-direction:column;align-items:stretch;gap:0}
.bidhead-row{display:flex;align-items:center;gap:12px}
.bidstage .splash-head .modal-x{margin-left:0}

/* Third title line: the projected finish, which opens the projection. */
.splash-title .proj-line{display:block;margin-top:4px;font-family:var(--cond);
  font-size:12.5px;font-weight:500;letter-spacing:.1em;text-transform:uppercase;
  color:var(--blue)}
.projdrawer{display:grid;grid-template-rows:0fr;
  transition:grid-template-rows .3s cubic-bezier(.33,0,.15,1)}
.projdrawer.open{grid-template-rows:1fr}
.projdrawer-clip{overflow:hidden;min-height:0;opacity:0;
  transition:opacity .2s ease .04s}
.projdrawer.open .projdrawer-clip{opacity:1}
.projdrawer .stat-grid{margin-top:12px;border:1px solid var(--line);
  border-radius:9px;overflow:hidden;background:var(--slate-2)}
.adminbar-label{font-family:var(--cond);text-transform:uppercase;letter-spacing:.16em;
  font-size:11px;color:var(--teal);font-weight:700;margin-right:4px}
.adminbar-actions{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.adminbar-timer{margin-left:auto;font-size:13px;color:var(--muted);display:flex;
  align-items:center;gap:6px}
.adminbar-timer input{width:62px;background:var(--ink);border:1px solid var(--line);
  border-radius:6px;padding:5px 8px}

.grid{flex:1;min-height:0;display:grid;
  grid-template-columns:372px minmax(0,1fr) 372px;
  /* Spending power sizes to its content; picks takes what's left; the last
     row holds Players Signed under the stage. */
  grid-template-rows:auto minmax(0,1fr) minmax(0,auto);
  gap:14px;padding:14px;align-items:stretch}
/* The commissioner has no team, so no rail — the stage takes the space. */
.grid.no-rail{grid-template-columns:minmax(0,1fr) 372px}
/* The rail dissolves so its panes can be placed individually. */
.rail{display:contents}
/* Explicit placement, desktop only — the phone lays these out with order
   and full-width rows, and would inherit these otherwise. */
@media (min-width:1081px){
  .pane-power{grid-column:1;grid-row:1}
  /* Runs to the bottom of the window. */
  .pane-picks{grid-column:1;grid-row:2/-1;min-height:0;display:flex;
    flex-direction:column;max-height:none}
  .pane-picks .pane-body{min-height:0;overflow-y:auto}
  .pane-stage{grid-column:2;grid-row:1/3}
  .pane-signed{grid-column:2;grid-row:3;max-height:34vh}
  .pane-board{grid-column:3;grid-row:1/-1}
  /* No rail: the stage and the board share two columns. */
  .grid.no-rail .pane-stage{grid-column:1;grid-row:1/3}
  .grid.no-rail .pane-signed{grid-column:1;grid-row:3}
  .grid.no-rail .pane-board{grid-column:2;grid-row:1/-1}
  /* A screen's board carries a face, a name and an owner on every row —
     372px was sized for a column with none of those. */
  html.viewer .grid.no-rail{grid-template-columns:minmax(0,1fr) 470px}
}
.grid > *{min-height:0}
.pane-picks{max-height:calc(52dvh - 130px)}
.pane-signed{min-height:0;display:flex;flex-direction:column}
.pane-signed .pane-body{min-height:0;overflow-y:auto}
.pane-board{min-height:0;display:flex;flex-direction:column}
.pane-board .pane-body{min-height:0;overflow-y:auto}

.pane-power .pane-body{padding:13px 14px 14px;overflow:visible;text-align:center}
.power-label{display:block;font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.18em;text-transform:uppercase;color:var(--muted)}
.power-amt{display:inline-block;align-self:center;
  font-family:var(--cond);font-size:50px;font-weight:700;
  color:var(--text);line-height:1.02;letter-spacing:-.01em;
  margin:10px 0}
.power-amt.over{color:var(--red)}
/* Well funded: a hot fill. Nearly spent: a cold one. Each carries a small
   mark at the bottom right of the figure. */
.power-amt{position:relative}
.pane-power .pane-body{text-align:center}
.power-amt.rich::after,.power-amt.thin::after{position:absolute;
  left:-3px;top:-1px;font-size:9px;line-height:1;
  /* An outline in the pane's own colour that follows the glyph's silhouette
     rather than boxing it: chained drop-shadows expand the alpha a pixel in
     each direction, which a background disc can't do. */
  filter:drop-shadow(.7px 0 0 var(--slate)) drop-shadow(-.7px 0 0 var(--slate))
         drop-shadow(0 .7px 0 var(--slate)) drop-shadow(0 -.7px 0 var(--slate));
  /* The glyph is its own colour — keep the text gradient off it. */
  -webkit-text-fill-color:initial;color:initial}
.power-amt.rich::after{content:"\1F525"}
.power-amt.thin::after{content:"\2744\FE0F"}
.lg-money-cell b.power-amt{position:relative;display:inline-block;margin:0;
  font-size:19px;line-height:1.1;letter-spacing:-.01em}
.lg-money-cell b.power-amt.rich::after,
.lg-money-cell b.power-amt.thin::after{font-size:7px;left:-5px;top:-2px}
.power-amt.rich{background:linear-gradient(160deg,#ffd23f 0%,#ff9b2f 42%,
    #ff5a4d 78%,#e2574c 100%);
  -webkit-background-clip:text;background-clip:text;color:transparent}
.power-amt.thin{background:linear-gradient(160deg,#d6f2ff 0%,#8fd4f2 30%,
    #56b0e4 62%,#2f7fd0 100%);
  -webkit-background-clip:text;background-clip:text;color:transparent}
.power-amt.over{background:none;color:var(--red)}
.power-sub{display:block;font-family:var(--cond);font-size:15px;font-weight:700;
  letter-spacing:.02em;color:#5f6c7d}
.power-note{display:block;font-size:10px;color:#4e5a68;margin-top:10px}
.power-note b{color:var(--red);font-weight:700;text-decoration:underline}
.pane{background:var(--slate);border:1px solid var(--line);border-radius:var(--r);
  overflow:hidden;display:flex;flex-direction:column;max-height:calc(100dvh - 120px)}
/* Expand control beside the board's filters. Hidden until a phone width. */
.pane-expand{display:none;width:26px;height:26px;flex:0 0 auto;padding:0;border:0;
  border-radius:6px;background:none;color:var(--muted);cursor:pointer;
  align-items:center;justify-content:center;-webkit-tap-highlight-color:transparent}
.pane-expand svg{width:18px;height:18px;display:block}
.pane-expand:focus{outline:none}
.pane-expand:focus-visible{outline:2px solid var(--teal);outline-offset:1px}
.pane-head{background:#161c25;border-bottom:1px solid var(--line);
  padding:0 13px;min-height:39px;display:flex;align-items:center;
  font-family:var(--cond);font-size:12px;font-weight:700;letter-spacing:.16em;
  text-transform:uppercase;color:var(--muted)}
.pane-body{padding:13px;overflow:auto;flex:1;
  scrollbar-width:thin;scrollbar-color:var(--red) var(--slate)}
/* Track disappears into the pane; thumb and arrows pick up the hammer's red. */
.pane-body::-webkit-scrollbar{width:13px}
.pane-body::-webkit-scrollbar-track{background:var(--slate)}
.pane-body::-webkit-scrollbar-thumb{background:var(--red);border-radius:7px;
  border:3px solid var(--slate)}
.pane-body::-webkit-scrollbar-thumb:hover{background:#ef6a5f}
.pane-body::-webkit-scrollbar-corner{background:var(--slate)}
.pane-body::-webkit-scrollbar-button:single-button{background:var(--slate);
  display:block;height:13px;width:13px;background-repeat:no-repeat;background-position:center}
.pane-body::-webkit-scrollbar-button:single-button:vertical:decrement{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 13 13'><path d='M6.5 3.6 L10 8.4 L3 8.4 Z' fill='%23e2574c'/></svg>")}
.pane-body::-webkit-scrollbar-button:single-button:vertical:decrement:hover{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 13 13'><path d='M6.5 3.6 L10 8.4 L3 8.4 Z' fill='%23ef6a5f'/></svg>")}
.pane-body::-webkit-scrollbar-button:single-button:vertical:increment{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 13 13'><path d='M6.5 9.4 L3 4.6 L10 4.6 Z' fill='%23e2574c'/></svg>")}
.pane-body::-webkit-scrollbar-button:single-button:vertical:increment:hover{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 13 13'><path d='M6.5 9.4 L3 4.6 L10 4.6 Z' fill='%23ef6a5f'/></svg>")}
.head-count{font-style:normal;font-size:11px;color:var(--text);background:var(--slate-2);
  border-radius:4px;padding:1px 6px;margin-left:7px}
.pane-stage{min-height:460px}
.empty{color:var(--muted);font-size:13.5px;margin:6px 2px}

/* ── picks ───────────────────────────── */
.picks{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:5px}
/* align-items:stretch so the round block runs the full height of the row */
.pick{display:grid;grid-template-columns:44px 1fr auto;align-items:stretch;gap:9px;
  background:var(--slate-2);border:1px solid transparent;border-radius:8px;padding:7px 9px;
  transition:border-color .15s,background .15s}
.pick > *:not(.pick-no){align-self:center}
.pick-no{display:flex;align-items:center;justify-content:center;
  font-family:var(--cond);font-weight:700;font-size:15px;color:var(--pos-ink);
  background:var(--orange);border-radius:5px;text-align:center;padding:2px 0}
.pick-val{font-family:var(--cond);font-size:19px;font-weight:700;color:var(--money)}
.pick-val.unl{
  background:linear-gradient(100deg,
    var(--unl-base,#fff) 0 45%,#ff5a4d 47.5%,#ffd23f 49%,#3fbf7f 50.5%,
    #2bb3be 52%,#5b8cff 53.5%,var(--unl-base,#fff) 56% 100%);
  background-size:700% 100%;background-position:0% 0;
  -webkit-background-clip:text;background-clip:text;color:transparent;
  animation:unl-shine 10s ease-in-out infinite}
.pick-cost{font-size:11px;color:var(--muted)}
/* Unlimited picks: rainbow wordmark and a rotating ring, matching the draft
   summary so the same pick reads the same way in both places. */
.pick.unl{border-color:transparent;position:relative;overflow:hidden;
  contain:paint}
.pick.unl::before{content:"";position:absolute;left:50%;top:50%;
  width:118%;aspect-ratio:1;pointer-events:none;z-index:0;
  background:conic-gradient(#ff5a4d,#ff9b2f,#ffd23f,#3fbf7f,#2bb3be,#5b8cff,
    #a86bff,#ff5a4d);
  transform:translate(-50%,-50%) rotate(0deg);opacity:0;
  animation:ring-spin 5s linear infinite,ring-flash 10s ease-in-out infinite}
.pick.unl::after{content:"";position:absolute;inset:1px;border-radius:6px;
  background:var(--slate-2);pointer-events:none;z-index:1}
.pick.unl > *{position:relative;z-index:2}
.pick.armed{border-color:var(--teal);background:#1e3138;box-shadow:0 0 0 1px var(--teal) inset}
.pick.armed .pick-cost::after{content:' · on offer';color:var(--teal);font-weight:600}

/* ── players signed ──────────────────── */
.signed-totals{margin-left:auto;font-family:var(--cond);font-size:11px;
  letter-spacing:.06em;color:var(--muted)}
.signed-totals b{font-size:inherit;font-weight:700;color:inherit}
.sg-pen{color:var(--red)}

.sg{display:flex;align-items:center;gap:8px;padding:7px 9px;margin-bottom:5px;
  background:var(--slate-2);border-radius:7px;line-height:1}
.sg:last-child{margin-bottom:0}
.sg-logo{width:18px;height:18px;flex:0 0 auto;object-fit:contain;display:block}
.sg-who .pos{line-height:1}
.sg-right{line-height:1}
.sg-who{display:flex;align-items:center;gap:6px;flex:1;min-width:0;
  line-height:1}
.sg-name{min-width:0;font-size:13.5px;font-weight:600;color:var(--text);
  line-height:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sg-rank{flex:0 0 auto;align-self:center;font-family:var(--cond);font-size:11px;
  line-height:1;letter-spacing:.04em;color:var(--teal)}
.sg-info{flex:0 0 auto;width:18px;height:18px;padding:0;border:0;background:none;
  color:#5a687a;cursor:pointer;display:flex;align-items:center;
  justify-content:center;-webkit-tap-highlight-color:transparent}
.sg-info{transition:transform .1s}
.sg-info:active{transform:scale(.9)}
.sg-info:hover{color:var(--teal)}
.sg-info:focus{outline:none}
.sg-info:focus-visible{outline:2px solid var(--teal);outline-offset:2px}
.sg-right{display:flex;align-items:center;gap:8px;flex:0 0 auto}
.sg-right .pick-chip{font-size:10px;padding:1px 5px}
.sg-sal{font-family:var(--cond);font-size:15px;font-weight:700;line-height:1;
  color:var(--money)}

/* Boot splash. Black, the mark fades up, then the whole pane breaks apart
   and the shards fly, revealing whatever finished loading behind. */
/* No width or height here on purpose. Setting top/bottom AND a height
   over-constrains the box: the height wins, bottom is ignored, and any
   shortfall shows as a strip of page along the bottom edge. Insets alone
   always fill the viewport exactly, whatever the browser chrome is doing. */
.boot{position:fixed;inset:0;
  z-index:200;display:flex;align-items:center;justify-content:center;
  background:#000;overflow:hidden}
.boot[hidden]{display:none}
html.booting,html.booting body{background:#000}
/* Pages that fill themselves from state: keep the shell invisible until the
   first paint, so a card can't appear and then change under you. */
html.booting main,html.booting .topbar{opacity:0}
main,.topbar{opacity:1;transition:opacity .18s ease}

/* The pane itself, in pieces. Together they tile the screen exactly. */
.shard{position:absolute;top:-2px;left:-2px;right:-2px;bottom:-2px;
  background:#000;transform-origin:50% 50%}
.shard:nth-child(1){clip-path:polygon(0 0,52% 0,38% 34%,0 47%)}
.shard:nth-child(2){clip-path:polygon(52% 0,100% 0,100% 28%,38% 34%)}
.shard:nth-child(3){clip-path:polygon(100% 28%,100% 62%,63% 58%,38% 34%)}
.shard:nth-child(4){clip-path:polygon(100% 62%,100% 100%,66% 100%,63% 58%)}
.shard:nth-child(5){clip-path:polygon(66% 100%,30% 100%,41% 66%,63% 58%)}
.shard:nth-child(6){clip-path:polygon(30% 100%,0 100%,0 74%,41% 66%)}
.shard:nth-child(7){clip-path:polygon(0 74%,0 47%,38% 34%,41% 66%)}
.shard:nth-child(8){clip-path:polygon(38% 34%,63% 58%,41% 66%)}

.boot-face{position:relative;z-index:2;display:flex;flex-direction:column;
  align-items:center;gap:14px}
.boot-mark{display:block;color:var(--red);opacity:0;transform:scale(.86);
  animation:boot-in .52s cubic-bezier(.22,.9,.3,1) .06s forwards}
.boot-svg{width:78px;height:78px;display:block}
.boot-name{font-family:var(--display);font-size:20px;letter-spacing:.06em;
  color:var(--text);opacity:0;
  animation:boot-in .52s cubic-bezier(.22,.9,.3,1) .18s forwards}
@keyframes boot-in{to{opacity:1;transform:none}}

/* The break: a hammer-blow jolt, the mark snuffed out, then the shards go. */
.boot.done{background:transparent;pointer-events:none;
  animation:boot-jolt .16s ease-out forwards}
.boot.done .boot-face{animation:boot-snuff .18s ease-in forwards}
.boot.done .shard{animation:shard-fly .62s cubic-bezier(.3,.05,.6,1) .1s forwards}

@keyframes boot-jolt{
  0%{transform:translate(0,0)}
  35%{transform:translate(-3px,2px)}
  70%{transform:translate(2px,-2px)}
  100%{transform:translate(0,0)}
}
@keyframes boot-snuff{to{opacity:0;transform:scale(1.14)}}
@keyframes shard-fly{to{opacity:0}}

/* Each piece leaves in its own direction, so it reads as a break rather than
   a fade. The translate distances are in viewport units to clear any screen. */
.boot.done .shard:nth-child(1){--fx:-42vw;--fy:-38vh;--fr:-16deg}
.boot.done .shard:nth-child(2){--fx:34vw;--fy:-44vh;--fr:13deg}
.boot.done .shard:nth-child(3){--fx:52vw;--fy:-10vh;--fr:9deg}
.boot.done .shard:nth-child(4){--fx:46vw;--fy:36vh;--fr:-11deg}
.boot.done .shard:nth-child(5){--fx:6vw;--fy:52vh;--fr:5deg}
.boot.done .shard:nth-child(6){--fx:-40vw;--fy:40vh;--fr:14deg}
.boot.done .shard:nth-child(7){--fx:-50vw;--fy:6vh;--fr:-8deg}
.boot.done .shard:nth-child(8){--fx:0;--fy:-8vh;--fr:22deg}
.boot.done .shard{animation-name:shard-fly}
@keyframes shard-fly{
  0%{transform:translate(0,0) rotate(0);opacity:1}
  12%{transform:translate(0,0) rotate(0);opacity:1}
  100%{transform:translate(var(--fx,0),var(--fy,0)) rotate(var(--fr,0));
       opacity:0}
}

@media (prefers-reduced-motion:reduce){
  .boot-mark,.boot-name{animation:none;opacity:1;transform:none}
  .boot.done{animation:none;opacity:0;transition:opacity .3s}
  .boot.done .shard,.boot.done .boot-face{animation:none}
}

/* ── stage ───────────────────────────────────────────── */
.nom{display:flex;align-items:flex-start;gap:14px;flex-wrap:wrap}
.nom-art .nom-pos{position:absolute;top:-6px;left:-6px;z-index:2;
  font-family:var(--cond);font-weight:700;font-size:12px;letter-spacing:.1em;
  line-height:1.35;background:var(--pos-wr);color:var(--pos-ink);
  border-radius:6px;padding:2px 8px;box-shadow:0 0 0 2px var(--slate)}
.nom-art .nom-pos.pos-RB{background:var(--pos-rb);color:var(--pos-ink)}
.nom-art .nom-pos.pos-QB{background:var(--pos-qb);color:var(--pos-ink)}
.nom-art .nom-pos.pos-TE{background:var(--pos-te);color:var(--pos-ink)}
.nom-art .nom-pos.pos-WR{background:var(--pos-wr);color:var(--pos-ink)}
.nom-name{font-family:var(--display);font-weight:800;font-size:34px;line-height:1.05;margin:0}
/* The dynasty rank is a rating, not chrome — it gets its own colour. */
.dyn{color:var(--teal);font-weight:600}
.nom-meta{color:var(--muted);font-size:13.5px;margin:3px 0 0;
  font-family:var(--cond);font-size:15px;letter-spacing:.06em;text-transform:uppercase}
.nom-bio{margin:5px 0 1px;font-family:var(--cond);font-size:16px;font-weight:700;
  letter-spacing:.09em;text-transform:uppercase;color:var(--text)}
.nom-rights{display:flex;align-items:center;gap:10px;margin-left:auto;
  align-self:flex-start;margin-top:6px;text-align:right}
.nom-rights img{width:36px;height:36px;border-radius:8px;object-fit:cover;
  border:1px solid var(--line);background:var(--slate-2)}
.nom-rights .lbl{display:block;font-family:var(--cond);font-size:10px;font-weight:700;
  letter-spacing:.15em;text-transform:uppercase;color:var(--muted)}
.nom-rights .who{font-size:15px;font-weight:600;line-height:1.15}
@media (max-width:560px){
  .nom-rights{margin-left:0;margin-top:12px;text-align:left;flex-direction:row-reverse;
    justify-content:flex-end}
}
/* No salary yet: the dash reads as "not applicable", not as nothing. */
.nom-sal.none{color:var(--muted)}
.nom-sal{font-family:var(--cond);font-weight:700;font-size:24px;color:var(--money);
  letter-spacing:0;white-space:nowrap}
.nom-name .sal-was{font-family:var(--cond);font-size:18px;margin-left:6px;
  margin-right:0}

.clock{display:flex;align-items:center;gap:12px;margin:20px 0}
.clock-num{font-family:var(--cond);font-size:44px;font-weight:700;line-height:1;
  min-width:66px;font-variant-numeric:tabular-nums}
.clock-bar{flex:1;height:7px;background:var(--slate-2);border-radius:99px;overflow:hidden}
.clock-fill{height:100%;background:#fff;border-radius:99px;transition:width .25s linear}
.clock.urgent .clock-num{color:var(--red)}
.clock.urgent .clock-fill{background:var(--red)}
/* Stopped clock: the number holds and the bar goes flat, so it reads as
   deliberately paused rather than broken. */
.clock.paused .clock-num{color:var(--muted)}
.clock.paused .clock-fill{background:var(--muted);transition:none}
.clock.paused .clock-num::after{content:" paused";font-size:14px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted);vertical-align:middle;margin-left:8px}

/* ── the pick menu inside the bidding overlay ─────────── */
/* Tappable in the bid menu: a pick is a one-tap way to bid its value. */
.pick.pick-tap{cursor:pointer;transition:transform .1s,border-color .1s}
.pick.pick-tap:hover{border-color:var(--teal)}
.pick.pick-tap:active{transform:scale(.99)}
.pick.pick-tap:focus-visible{outline:2px solid var(--teal);outline-offset:2px}
.pickmenu{border:1px solid var(--line);border-radius:9px;background:var(--slate-2);
  overflow:hidden;margin-bottom:14px}
.pickmenu-head{display:flex;align-items:center;gap:10px;width:100%;padding:9px 11px;
  background:none;border:0;color:inherit;font:inherit;cursor:pointer;text-align:left;
  -webkit-tap-highlight-color:transparent}
.pickmenu-head:focus{outline:none}
.pickmenu-head:focus-visible{outline:2px solid var(--teal);outline-offset:-2px}
.pickmenu-title{font-family:var(--cond);font-size:12px;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;color:var(--muted)}
.pickmenu-max{margin-left:auto;font-size:12px;color:var(--muted)}
/* Matches the label beside it in face and size — only weight and colour
   separate them. */
.pickmenu-max b{font-family:inherit;font-size:inherit;font-weight:700;color:#fff}
/* Neon tubing: stroked outlines lit by stacked drop-shadows, each swaying on
   its own clock so they dance instead of pulsing together. */
.flame{display:inline-flex;align-items:center;gap:5px}
/* Sized in px: the svg inherits the 12px label size, not the 16px of the
   figure beside it, so em came out wrong here. overflow:visible keeps the
   glow from being cropped at the viewBox edge. */
.flame-svg{flex:0 0 auto;width:9px;height:10px;
  pointer-events:none;overflow:visible}
.flame-path{fill:none;stroke-linecap:round;stroke-linejoin:round;
  transform-box:fill-box;transform-origin:50% 100%}
.flame-a{stroke:#ff7a1a;stroke-width:4.4;
  filter:drop-shadow(0 0 2px #ffb066) drop-shadow(0 0 6px #ff7a1a)
         drop-shadow(0 0 13px #ff3d1a);
  animation:flame-sway 1.9s ease-in-out infinite alternate}
.flame-b{stroke:#ffd98a;stroke-width:3.2;
  filter:drop-shadow(0 0 2px #fff0c4) drop-shadow(0 0 6px #ffd23f)
         drop-shadow(0 0 11px #ff9b2f);
  animation:flame-sway-b 1.25s ease-in-out infinite alternate}
@keyframes flame-sway{
  from{transform:rotate(-8deg) scaleY(.93) scaleX(1.04)}
  to{transform:rotate(8deg) scaleY(1.07) scaleX(.96)}
}
@keyframes flame-sway-b{
  from{transform:rotate(11deg) scaleY(1.06) scaleX(.94)}
  to{transform:rotate(-11deg) scaleY(.92) scaleX(1.05)}
}
.pickmenu-caret{color:#5a687a;font-size:7px;transition:transform .2s}
.pickmenu.open .pickmenu-caret{transform:rotate(90deg)}
.pickmenu-more{display:grid;grid-template-rows:0fr;
  transition:grid-template-rows .3s cubic-bezier(.33,0,.15,1)}
.pickmenu.open .pickmenu-more{grid-template-rows:1fr}
.pickmenu-clip{overflow:hidden;min-height:0;opacity:0;transition:opacity .2s ease .04s}
.pickmenu.open .pickmenu-clip{opacity:1}
.pickmenu-clip .picks{padding:0 11px 11px}
.pickmenu-clip .footnote{margin:0 11px 11px}

/* Nothing left to bid with. */
.overcap{display:inline-flex;align-items:center;font-family:var(--cond);font-weight:700;
  font-size:15px;letter-spacing:.14em;text-transform:uppercase;color:var(--red);
  border:1px solid #7a2c26;background:#e2574c14;border-radius:9px;padding:11px 16px}

.bidrow{display:flex;gap:9px;align-items:flex-end;flex-wrap:wrap;margin-top:16px}
.bidbtns{display:flex;gap:9px;align-items:stretch}

/* The standing bid, shown where the entry field was. */
.bidin-row{display:flex;align-items:center;justify-content:center;gap:10px;
  padding:0 12px;background:var(--ink);border:1px solid var(--line);
  border-radius:8px;height:var(--bid-h,46px);box-sizing:border-box}
/* Explicit height on the badge so it matches the figure's cap height rather
   than whatever its own padding and line box happen to add up to. */
.bidin-row .pick-chip{flex:0 0 auto;display:inline-flex;align-items:center;
  height:22px;padding:0 8px;font-size:14px;line-height:1}
.bidin-amt{font-family:var(--cond);font-size:19px;font-weight:700;line-height:1;
  color:var(--money)}
/* Same type as the bid figure, so the two sit on one line without any
   per-element box fiddling. */
.bidin-pen{font-family:var(--cond);font-size:26px;font-weight:700;line-height:1;
  color:#ff4a3d;white-space:nowrap}
.bidin-passed{font-size:15px;color:var(--muted)}
.bidrow .field{margin:0}
/* The field and its stepper share one bordered box. */
.bidfield{position:relative;display:flex;align-items:stretch;width:150px}
.bidfield input[type=number]{flex:1;min-width:0;width:auto}
.bidstep{position:absolute;right:5px;top:5px;bottom:5px;display:flex;
  flex-direction:column;gap:2px}
.bidstep-btn{flex:1;width:26px;padding:0;display:flex;align-items:center;
  justify-content:center;background:var(--slate-2);border:1px solid var(--line);
  border-radius:5px;color:var(--text);font-size:10px;line-height:1;
  cursor:pointer;-webkit-tap-highlight-color:transparent;
  transition:transform .1s,background .1s}
.bidstep-btn:hover{background:#2b3542}
.bidstep-btn:active{transform:scale(.94)}
.bidstep-btn:disabled{opacity:.4;cursor:not-allowed}
.bidrow input[type=number]{width:150px;background:var(--ink);border:1px solid var(--line);
  border-radius:8px;padding:0 34px 0 12px;text-align:center;
  font-family:var(--cond);font-size:22px;font-weight:700}
/* The ceiling lives in the field itself until they type over it. */
.bidrow input[type=number]::placeholder{color:#5a687a;font-size:22px;font-weight:700;
  letter-spacing:.04em;text-align:center}
.bidrow input[type=number]:disabled{opacity:.45;cursor:not-allowed}
/* Same height as Submit and Pass, so the row reads as one control group. */
.bidrow .field input[type=number]{height:var(--bid-h,46px);box-sizing:border-box}
.bidbtns .btn{height:var(--bid-h,46px)}
.offer{margin-top:14px;padding:12px 14px;border-radius:9px;background:var(--slate-2);
  border-left:3px solid var(--teal);font-size:14px}
.offer.penalty{border-left-color:var(--red)}
.offer b{color:var(--money)}
.offer .warn{color:#ff9a92;font-weight:600}
.locked .btn{margin-top:9px}
.unl-pick{margin-top:-4px}
.unl-pick{margin-top:16px}
.unl-pick select{width:100%;background:var(--ink);border:1px solid var(--line);
  border-radius:8px;color:var(--text);font:inherit;font-size:15px;padding:9px 10px}
.unl-pick select:focus{outline:none;border-color:var(--teal)}
.locked{margin-top:14px;padding:12px 14px;border-radius:9px;background:#1e3138;
  border-left:3px solid var(--teal)}

.waiting{color:var(--muted);font-size:13.5px;margin-top:14px}
.waiting b{color:var(--text)}
.waiting-cta{text-align:center}
/* The box hugs the text rather than the container, so it reads as a notice. */
.cta-box{display:inline-block;font-weight:700;color:var(--text);
  border:1px solid var(--red);background:#e2574c14;border-radius:8px;
  padding:8px 15px;line-height:1.35;max-width:100%}
/* Fills the leftover height of the stage so the line sits midway between the
   card above it and the bottom of the pane. */
.pane-stage .pane-body{display:flex;flex-direction:column}
.pane-stage .pane-body > *{flex:0 0 auto}
.waiting-fill{flex:1 1 auto;display:flex;align-items:center;justify-content:center;
  text-align:center;margin-top:14px;min-height:56px}

/* ── the reveal (signature) ──────────────────────────── */
.reveal-head{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:12px}
.reveal-head h3{font-family:var(--display);font-size:19px;margin:0}
.reveal-head span{font-size:12px;color:var(--muted);letter-spacing:.1em;text-transform:uppercase}
.cards{display:flex;flex-direction:column;gap:7px}
.card{position:relative;perspective:900px;height:52px}
.card-inner{position:relative;z-index:1;width:100%;height:100%;transform-style:preserve-3d;
  transition:transform .55s cubic-bezier(.2,.75,.3,1)}
.card.open .card-inner{transform:rotateX(180deg)}
.card-face{position:absolute;inset:0;backface-visibility:hidden;border-radius:9px;
  display:flex;align-items:center;gap:12px;padding:0 14px;border:1px solid var(--line)}
.card-back{background:repeating-linear-gradient(135deg,#232c38 0 9px,#1e2530 9px 18px);
  justify-content:center;color:#3f4b5c;font-size:19px}
.card-front{background:var(--slate-2);transform:rotateX(180deg)}
.card-pic{flex:0 0 auto;width:30px;height:30px;border-radius:6px;
  object-fit:cover;object-position:top center;background:#0f141b}
/* The winning bid carries the same rotating rainbow edge as the row on the
   block in the board — see .rfa-row.live for how the ring is drawn. */
.card.top .card-front{background:#152a20;border-color:transparent;
  overflow:hidden}
.card.top .card-front::before{content:"";position:absolute;left:50%;top:50%;
  width:112%;aspect-ratio:1;pointer-events:none;z-index:0;
  background:conic-gradient(#14301f,#2f8f5b,#3fbf7f,#7ce0a6,#c9f7dd,#7ce0a6,
    #3fbf7f,#2f8f5b,#14301f);
  transform:translate(-50%,-50%) rotate(0deg);
  animation:ring-spin 4.5s linear infinite}
.card.top .card-front::after{content:"";position:absolute;inset:1px;
  border-radius:8px;background:#152a20;pointer-events:none;z-index:1}
.card.top .card-front > *{position:relative;z-index:2}

/* The winner's confetti: fires from the middle of the bar, behind it, up over
   the top edge, then falls past the losing bars and out of the card. Each
   piece gets its own drift, height, spin and delay from inline vars. */
.card-pop{position:absolute;left:50%;bottom:26px;width:0;height:0;
  z-index:0;pointer-events:none}
.card-pop i{position:absolute;left:0;top:0;width:7px;height:11px;margin:-5px -3px;
  opacity:0;animation:confetti 1.7s linear var(--d) both}
/* Easing lives on the keyframes, not the animation — a single curve across the
   whole thing warps the 40% peak well off where it reads. */
@keyframes confetti{
  0%{transform:translate(0,0) rotate(0deg) scale(.35);opacity:0;
     animation-timing-function:cubic-bezier(.12,.72,.35,1)}
  9%{opacity:1;animation-timing-function:cubic-bezier(.12,.72,.35,1)}
  40%{transform:translate(calc(var(--x) * .55), var(--rise))
      rotate(calc(var(--rot) * .45)) scale(1);opacity:1;
      animation-timing-function:cubic-bezier(.5,0,.85,.55)}
  82%{opacity:1;animation-timing-function:cubic-bezier(.5,0,.85,.55)}
  100%{transform:translate(var(--x), var(--fall)) rotate(var(--rot)) scale(1);opacity:0}
}
@media (prefers-reduced-motion:reduce){.card-pop{display:none}}
@media (prefers-reduced-motion:reduce){.card-pop{display:none}}
.card-rank{font-family:var(--cond);font-weight:700;color:var(--muted);width:24px}
.card-owner{font-weight:600;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.card-amt{font-family:var(--cond);font-size:25px;font-weight:700;color:var(--money)}
.card-pick{font-family:var(--cond);font-weight:700;font-size:13px;background:var(--orange);
  color:#1a1005;border-radius:5px;padding:2px 7px}
.card-pen{font-size:11.5px;color:#ff9a92;font-weight:600}
.card.pass .card-amt{color:var(--muted);font-size:15px;font-family:var(--ui);font-weight:500}
.card.pass .card-front{opacity:.62}
/* Bids that didn't win recede: everything desaturated, the amount dropped to
   the same type as the name beside it. Filters go on the individual pieces
   rather than .card-front — a filter there would flatten the 3D flip. */
.card.lost .card-pic,.card.lost .card-pick,.card.lost .card-pen{filter:grayscale(1)}
.card.lost .card-owner{color:#93a1b2}
.card.lost .card-amt{font-family:var(--ui);font-size:15px;font-weight:600;
  color:#93a1b2}

/* ── stat tables under the player on the block ─── */
.statwrap{display:flex;flex-direction:column;gap:9px;margin-top:16px}
.stat-card{background:var(--slate-2);border:1px solid var(--line);border-radius:9px;
  overflow:hidden}
.stat-head{display:flex;align-items:center;gap:8px;padding:7px 11px;
  background:#161c25;border-bottom:1px solid var(--line)}
.stat-head b{flex:0 0 auto;line-height:1;font-family:var(--cond);font-size:11px;
  font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted)}
.stat-head .finish{margin-left:auto;font-family:var(--cond);font-size:13px;
  font-weight:700;line-height:1;color:var(--teal)}
.stat-card.proj .stat-head{background:#1b2530}
.stat-card.proj .stat-head b{color:var(--text)}
.stat-card.proj .stat-head .finish{color:var(--teal)}
.stat-grid{display:flex;flex-wrap:wrap}
.stat-grid{display:flex}
.stat-cell{flex:1 1 0;min-width:52px;padding:8px 6px;text-align:center;
  border-right:1px solid #2b3542}
/* Six or seven columns can't hold the default width on a narrow card, so
   they get tighter cells rather than wrapping onto a second line. */
.stat-grid.cells-6 .stat-cell{min-width:0;padding:8px 3px}
.stat-grid.cells-7 .stat-cell{min-width:0;padding:8px 2px}
.stat-grid.cells-6 .stat-cell b{font-size:16px}
.stat-grid.cells-7 .stat-cell b{font-size:14px}
.stat-grid.cells-6 .stat-cell span,
.stat-grid.cells-7 .stat-cell span{font-size:8.5px;letter-spacing:.02em}
.stat-cell:last-child{border-right:0}
.stat-cell b{display:block;font-family:var(--cond);font-size:19px;font-weight:700;
  line-height:1.1}
.stat-cell.pts b{color:var(--gold)}
.stat-cell span{font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}

.hist-head{width:100%;background:#161c25;border:0;border-bottom:1px solid var(--line);
  cursor:pointer;text-align:left;font:inherit;-webkit-tap-highlight-color:transparent}
.hist-head:focus{outline:none}
.hist-head:focus-visible{outline:2px solid var(--teal);outline-offset:-2px}
.hist-caret{margin-left:auto;color:#5a687a;font-size:7px;transition:transform .2s}
.hist-card.open .hist-caret{transform:rotate(90deg)}
.hist-more{display:grid;grid-template-rows:0fr;
  transition:grid-template-rows .3s cubic-bezier(.33,0,.15,1)}
.hist-card.open .hist-more{grid-template-rows:1fr}
.hist-clip{overflow:hidden;min-height:0}

/* Separator between the forecast and the record. */
.stat-sep{height:1px;background:var(--line);margin:4px 2px}

/* Historical table: same type, sizes and dividers as the projected grid,
   laid out as rows so the years line up. */
.hist{width:100%;border-collapse:collapse;table-layout:fixed}
.hist th{font-family:var(--cond);font-size:9px;font-weight:700;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted);text-align:center;padding:7px 3px;
  border-right:1px solid #2b3542;border-bottom:1px solid var(--line);
  hyphens:none;word-break:normal}
.hist td{font-family:var(--cond);font-size:17px;font-weight:500;line-height:1.1;
  text-align:center;padding:9px 3px;white-space:nowrap;border-right:1px solid #2b3542;
  border-bottom:1px solid #2b354280}
.hist th:last-child,.hist td:last-child{border-right:0}
.hist tbody tr:last-child td{border-bottom:0}
.hist .c-year{color:var(--muted)}
.hist .c-fin{color:var(--teal);font-size:16px}
.hist .c-pts{color:var(--gold)}

/* ── pick colours ────────────────────────────────────────
   A pick's round is its rank: gold, silver, bronze, then the plain orange of
   the base badge for round four. One block for every badge that shows a pick
   number, so the three of them can't drift apart. */
.pick-no.r1,.pick-chip.r1{
  background:linear-gradient(155deg,#f8dc86 0%,#e0b44a 45%,#b3831f 100%)}
.pick-no.r2,.pick-chip.r2{
  background:linear-gradient(155deg,#eef3f8 0%,#c3ccd7 45%,#8d99a8 100%)}
.pick-no.r3,.pick-chip.r3{
  background:linear-gradient(155deg,#e8b189 0%,#c9834e 45%,#94582a 100%)}
.pick-chip{display:inline-block;font-family:var(--cond);font-weight:700;font-size:14px;
  line-height:1.35;color:var(--pos-ink);background:var(--orange);
  border-radius:5px;padding:1px 7px;vertical-align:baseline}

/* ── decision ────────────────────────────────────────── */
.verdict{border:1px solid var(--line);border-radius:11px;padding:20px;margin-top:16px;
  background:linear-gradient(180deg,#232c38,var(--slate-2))}
.verdict h3{font-family:var(--display);font-size:21px;margin:0 0 4px;text-align:center}
/* Their own threshold, shown where the decision is made. */
.threshold-banner{margin:-4px 0 14px;padding:9px 12px;border-radius:9px;
  background:#f2b01e1f;border:1px solid #f2b01e5c;text-align:center;
  font-family:var(--cond);font-size:12.5px;font-weight:700;letter-spacing:.12em;
  text-transform:uppercase;color:var(--gold)}
.threshold-banner span{opacity:.6;margin:0 2px}
.threshold-banner b{font-size:17px;color:#ffd36b}
.verdict .nom-meta{text-align:center}
.verdict .nom-meta .pick-chip{vertical-align:-2px;line-height:1;padding:2px 7px;
  margin:0 2px}

/* Two columns, each boxed in its own outcome colour and showing where the cap
   lands if you press that button. */
.verdict-choices{display:flex;flex-wrap:wrap;justify-content:center;align-items:stretch;
  gap:16px 20px;margin-top:20px}
.choice{flex:1 1 250px;max-width:330px;display:flex;flex-direction:column;
  align-items:center;text-align:center;gap:0;
  border:1px solid;border-radius:12px;padding:14px}
.choice.keep{border-color:#4a9be85c;background:#4a9be814}
.choice.let{border-color:#e8577a5c;background:#e8577a14}
.choice-kicker{display:block;width:100%;text-align:center;font-family:var(--cond);
  font-size:10px;font-weight:700;letter-spacing:.18em;text-transform:uppercase;
  color:var(--muted);line-height:1.2;
  padding-bottom:8px;margin-bottom:10px;border-bottom:1px solid var(--line)}
.choice-head{width:100%;display:flex;align-items:center;justify-content:center;
  text-align:center;margin-bottom:18px;padding:9px 12px;
  border:1px solid;border-radius:9px}
.choice-title{font-size:13.5px;font-weight:600;color:var(--text);line-height:1.35;
  min-width:0}
/* The dollar figure sits in the same face and size as the name beside it —
   colour alone marks it out. */
.choice-title b{font-family:inherit;font-size:inherit;font-weight:700;
  color:var(--money);margin-left:5px}
/* line-height:1 keeps the chip inside the text's line box, so the boxed row
   is the same height on both sides. */
.choice-title .pick-chip{vertical-align:-1px;margin-right:1px;
  line-height:1;padding:2px 7px}
.title-pos{font-weight:400;color:var(--muted)}
.title-dot{color:#fff;margin:0 5px}
/* The two verbs carry their buttons' colours into the blurb. */
.verb-keep{color:var(--blue)}
.verb-money{color:var(--money)}
.verb-let{color:var(--pink)}
.choice.keep .choice-kicker{border-bottom-color:#4a9be83d}
.choice.let .choice-kicker{border-bottom-color:#e8577a3d}
.choice.keep .choice-head{border-color:#4a9be852;background:#4a9be81f}
.choice.let .choice-head{border-color:#e8577a52;background:#e8577a1f}

.choice-lines{display:flex;flex-direction:column;gap:3px;margin:auto 0}
.choice-line{font-size:12.5px;color:var(--muted)}
/* Values sit in the same face and size as their labels — only the weight
   and colour separate them. */
.choice-line b{font-family:inherit;font-size:inherit;font-weight:700;color:var(--text)}
.choice-line.power b{color:var(--text)}
.choice-line.power.over b{color:var(--red)}

.choice-rule{width:100%;height:1px;background:var(--line);margin:13px 0 15px}
.choice.keep .choice-rule{background:#4a9be83d}
.choice.let .choice-rule{background:#e8577a3d}
/* Both buttons are one fixed size and centre their contents, so the ring on
   one side can't make it taller than the other. */
.choice .btn{width:100%;height:52px;padding:0 14px;
  display:flex;align-items:center;justify-content:center;gap:8px;
  font-size:15.5px;line-height:1;white-space:nowrap}

.outcome{display:flex;align-items:center;gap:12px;margin-top:16px;padding:16px 18px;
  border-radius:11px;background:var(--slate-2);border-left:4px solid var(--muted)}
.outcome.matched{border-left-color:var(--blue);background:#152a3f}
.outcome.relinquished{border-left-color:var(--red);background:#2a1210}
.outcome-verb{font-family:var(--display);font-size:19px;color:#fff}
.outcome.matched .outcome-verb,
.outcome.relinquished .outcome-verb{color:#fff;font-weight:800}
.outcome.matched span,.outcome.relinquished span{color:var(--text)}

/* ── the board: full RFA class in nomination order ───── */
.pane-head{justify-content:space-between;gap:10px}
.seg{display:flex;gap:2px;background:var(--ink);border:1px solid var(--line);
  border-radius:7px;padding:2px}
.seg button{border:0;background:none;color:var(--muted);cursor:pointer;
  font-family:var(--cond);font-size:11px;font-weight:700;letter-spacing:.1em;
  text-transform:uppercase;padding:3px 8px;border-radius:5px}
.seg button.on{background:var(--slate-2);color:var(--text)}
.seg button{transition:background .12s,color .12s,transform .08s,box-shadow .08s}
.seg button:active{transform:translateY(2px)}
.boardmore{display:block;width:100%;margin-top:8px;padding:9px 12px;
  background:var(--slate-2);border:1px solid var(--line);border-radius:8px;
  color:var(--muted);cursor:pointer;font-family:var(--cond);font-size:12px;
  font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  -webkit-tap-highlight-color:transparent}
.boardmore:hover{background:#2b3542;color:var(--text)}
.boardmore:focus{outline:none}
.boardmore:focus-visible{outline:2px solid var(--teal);outline-offset:-2px}
.pane-foot{border-top:1px solid var(--line);padding:9px 13px;background:#161c25;
  font-size:12.5px;color:var(--muted)}
.pane-foot b{color:var(--money);font-family:var(--cond);font-size:15px}

.rfa{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:3px;
  counter-reset:rfa}
.rfa-row{border-radius:8px;background:var(--slate-2);
  border:1px solid transparent}
.rfa-line{display:grid;grid-template-columns:22px 34px 27px minmax(0,1fr) auto;
  align-items:center;gap:0;padding:6px 9px}
.rfa-row.pending{background:transparent}
.rfa-row.done{opacity:.72}
/* your own restricted free agents — the ones you have to defend */
.rfa-row.mine{background:var(--slate-2);border-color:transparent}
.rfa-row.mine .rfa-name{color:#ffb765}
.rfa-row.mine .rfa-n{color:#8a6a3a}
/* On the block wins over every other row state. */
/* Composited: the browser can hand this to the GPU rather than repainting a
   conic gradient on every frame. */
@keyframes ring-spin{to{transform:translate(-50%,-50%) rotate(360deg)}}
/* The ring is absent most of the time, easing in and out once a cycle. */
@keyframes ring-flash{
  0%,72%{opacity:0}
  80%,90%{opacity:1}
  100%{opacity:0}
}
/* One pass of the band, then base colour again. Both ends of the sweep show
   only base colour, so the loop restart can't be seen. */
@keyframes unl-shine{
  0%,72%{background-position:0% 0}
  100%{background-position:100% 0}
}
@media (prefers-reduced-motion:reduce){
  .pick.unl::before,.dr-row.unl::before,.dr-row.mine::before,
  .card.top .card-front::before{animation:none}
  .pick-val.unl,.dr-row.unl .dr-bid{animation:none;background:none;color:#fff}
}
.rfa-row.live,.rfa-row.mine.live{background:#152a3f;border-color:#3a6ea8}
/* Up next, but you've passed on him. */
.rfa.capped .rfa-row.live.boardpass,
.rfa .rfa-row.live.boardpass,
.rfa-row.live.boardpass,.rfa-row.mine.live.boardpass{background:#2a1210;
  border-color:var(--red)}
.rfa-row.live.boardpass{position:relative}
.rfa-row.live.boardpass::before{content:"";position:absolute;inset:0;z-index:1;
  pointer-events:none;border-radius:inherit;overflow:hidden;
  background-image:url("data:image/svg+xml;utf8,\
<svg xmlns='http://www.w3.org/2000/svg' width='52' height='22'>\
<text x='1' y='8' font-family='Barlow Condensed,Arial Narrow,sans-serif'\
 font-size='7' font-weight='700' letter-spacing='1'\
 fill='%23e2574c' fill-opacity='0.07' transform='rotate(-12 1 8)'>PASS</text>\
<text x='27' y='19' font-family='Barlow Condensed,Arial Narrow,sans-serif'\
 font-size='7' font-weight='700' letter-spacing='1'\
 fill='%23e2574c' fill-opacity='0.07' transform='rotate(-12 27 19)'>PASS</text>\
</svg>");
  background-repeat:repeat}
.rfa-row.live.boardpass .rfa-nametext{color:#f0928a}
.rfa-row.live > *{position:relative;z-index:2}
.rfa-row.live .rfa-name,.rfa-row.live .rfa-n{color:var(--text)}
.rfa-n{font-family:var(--cond);font-size:12px;color:#5a687a;
  text-align:center;margin:0 9px}
/* Target crosshair at the head of the row */
.tgt-icon{width:22px;height:22px;padding:0;flex:0 0 auto;border:0;border-radius:50%;
  background:none;color:#5f6c7d;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  transition:background .15s,color .15s;-webkit-tap-highlight-color:transparent}
/* Fills the button: the red rim left over is then the same weight as the
   rings themselves, and zero margin can't drift off the pixel grid. */
.tgt-icon svg{width:22px;height:22px;display:block}
.tgt-icon:focus{outline:none}
.tgt-icon:focus-visible{outline:2px solid var(--teal);outline-offset:2px}
/* Selected: the ring stays put and a blue dot appears inside it. The halo
   ring and dot pulse once every few seconds rather than continuously. */
.tgt-dot,.tgt-halo{transform-box:fill-box;transform-origin:center;opacity:0}
.tgt-icon.on .tgt-dot{opacity:1;animation:tgt-pulse 4.5s ease-in-out infinite}
.tgt-icon.on .tgt-halo{animation:tgt-halo 4.5s ease-in-out infinite}
@keyframes tgt-pulse{
  0%,82%,100%{transform:scale(1)}
  88%{transform:scale(1.28)}
  94%{transform:scale(.94)}
}
@keyframes tgt-halo{
  0%,80%,100%{opacity:0;transform:scale(1)}
  86%{opacity:.55;transform:scale(1.12)}
  100%{opacity:0;transform:scale(1.45)}
}
@media (prefers-reduced-motion:reduce){
  .tgt-icon.on .tgt-dot,.tgt-icon.on .tgt-halo{animation:none}
  .tgt-icon.on .tgt-halo{opacity:0}
}
.tgt-spacer{width:22px}
.tgt-rfa{width:22px;flex:0 0 auto;text-align:center;font-family:var(--cond);
  font-size:9.5px;font-weight:700;letter-spacing:.02em;color:var(--gold)}
.tgt-poo{width:22px;flex:0 0 auto;text-align:center;font-size:13px;line-height:1}
.tgt-done{width:22px;height:22px;flex:0 0 auto;display:flex;align-items:center;
  justify-content:center;color:var(--green)}
.tgt-done svg{width:16px;height:16px;display:block}

/* The right-hand slot on a board row */
.marks{display:flex;align-items:center;gap:5px;flex:0 0 auto}

/* Prebid on a targeted player, threshold on one of your own. */
.notefield{display:flex;align-items:center;gap:4px;flex:0 0 auto}
.notefield-label{font-family:var(--cond);font-size:9.5px;font-weight:700;
  letter-spacing:.02em;text-transform:uppercase;color:var(--muted);
  white-space:nowrap}
/* The box holds the frame; the value and penalty are a centred pair inside
   it, both at the same size. Fixed outer width so rows stay aligned. */
.note-box,.pass-box{flex:0 0 auto;width:72px;min-height:27px;display:flex;
  align-items:center;justify-content:center;gap:4px;
  background:var(--ink);border:1px solid var(--line);border-radius:6px;
  padding:4px 5px}
.note-box:focus-within{border-color:var(--teal)}
/* Same box as the bid field; the word sits where the $ placeholder would. */
.pass-box{cursor:pointer;-webkit-tap-highlight-color:transparent;
  transition:border-color .15s}
.pass-box{transition:transform .1s}
.pass-box:active{transform:translateY(1px) scale(.97)}
.pass-box:focus{outline:none}
.pass-box:focus-visible{border-color:var(--teal)}
.pass-label{font-family:var(--cond);font-size:11.5px;font-weight:500;
  line-height:20px;color:#4a5666}
.pass-box.on{border-color:var(--red);background:var(--red)}
.pass-box.on .pass-label{color:#fff;font-weight:700}
.note-input{min-width:0;height:20px;line-height:20px;background:none;border:0;
  padding:0;font-family:var(--cond);font-size:11.5px;font-weight:700;
  color:var(--money);text-align:center}
.note-input:focus{outline:none}
.note-input::placeholder{color:#4a5666;font-weight:500}
.notefield.threshold .note-input{color:var(--gold)}
.notefield.threshold .note-input::placeholder{color:#7a6320;font-weight:700}
/* min-width keeps #6 and #11 the same size so the badges line up too. */
.note-chip{flex:0 0 auto;display:inline-flex;align-items:center;
  justify-content:center;min-width:28px;height:20px;padding:0 5px;
  font-size:11px;line-height:1}
.note-pen{flex:0 0 auto;display:inline-flex;align-items:center;height:20px;
  pointer-events:none;font-family:var(--cond);font-size:11.5px;font-weight:700;
  color:#ff4a3d;white-space:nowrap}

.rfa-row.targeted{border-color:#2f8f5b;background:#14301f}
.rfa-row.boardpass .rfa-n,
.rfa-row.boardpass .rfa-logo,
.rfa-row.boardpass .rfa-mid,
.rfa-row.boardpass .rfa-more{filter:grayscale(1);opacity:.5}
/* The trades toggle takes each view's own colour: the block is gold
   wherever it appears, history is the app's red, and an open offer is the
   green everything actionable uses. */
.tradeseg button[data-view="historical"].on{color:var(--red)}
.tradeseg button[data-view="current"].on{color:var(--money)}
.tradeseg button[data-view="drafts"].on{color:#8ecdf5}
.tradeseg button[data-view="block"].on{color:var(--gold)}

.seg button.targets.on{color:#ff9a92}
.seg button.mine.on{color:#ffb765}
.rfa-logo{width:20px;height:20px;object-fit:contain;margin-right:7px}
.rfa-mid{min-width:0;background:none;border:0;padding:0;text-align:left;
  color:inherit;font:inherit}
button.rfa-mid{cursor:pointer;-webkit-tap-highlight-color:transparent;
  transition:transform .1s}
button.rfa-mid:active{transform:scale(.985)}
button.rfa-mid:focus{outline:none}
button.rfa-mid:focus-visible{outline:2px solid var(--teal);outline-offset:2px;
  border-radius:4px}
/* Hover tint only where there's a real pointer. On a touch screen :hover
   sticks after a tap, which is the colour change that wouldn't go away. */
@media (hover:hover) and (pointer:fine){
  button.rfa-mid:hover .rfa-name{color:var(--teal)}
}
.rfa-stat{width:12px;height:12px;margin-left:3px;vertical-align:-2px;
  color:#5a687a;flex:0 0 auto}
.rfa-mid:hover .rfa-stat{color:var(--teal)}

/* the expanded per-player summary */
/* Collapsed height animates via grid-template-rows. The clipped element must
   carry no padding of its own — overflow:hidden cuts at the padding box, which
   leaks a strip of content into a closed row. */
.rfa-more{display:grid;grid-template-rows:0fr;
  transition:grid-template-rows .34s cubic-bezier(.33,0,.15,1)}
.rfa-row.open .rfa-more{grid-template-rows:1fr}
.rfa-more-clip{overflow:hidden;min-height:0;opacity:0;
  transition:opacity .22s ease .04s}
.rfa-row.open .rfa-more-clip{opacity:1}
.rfa-more-body{border-top:1px solid var(--line);padding:8px 9px 9px;
  background:#151b24;border-radius:0 0 7px 7px}
.facts-more{width:22px;height:22px;flex:0 0 auto;padding:0;border:0;
  background:none;color:var(--muted);cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  -webkit-tap-highlight-color:transparent}
.facts-more svg{width:15px;height:15px;display:block}
.facts-more:focus{outline:none}
.facts-more:focus-visible{outline:2px solid var(--teal);outline-offset:1px}
.rfa-facts{display:flex;align-items:center;justify-content:space-between;gap:8px;
  font-family:var(--cond);font-size:12.5px;font-weight:700;
  letter-spacing:.08em;text-transform:uppercase;color:var(--text);margin-bottom:7px}
.mini{width:100%;border-collapse:collapse;table-layout:fixed}
.mini td{font-family:var(--cond);font-size:14px;font-weight:500;padding:3px 2px;
  border-bottom:1px solid #2b354266}
.mini tr:last-child td{border-bottom:0}
.mini .m-year{color:var(--muted);width:34%}
.mini .m-fin{color:var(--teal);text-align:center;width:30%}
.mini .m-pts{color:var(--gold);text-align:right}
.mini tr.proj .m-year{color:var(--text)}
.mini tr.proj td{border-bottom:1px solid var(--line);font-weight:700}
.rfa-name{display:flex;align-items:center;gap:4px;min-width:0;
  font-weight:400;font-size:13.5px}
.rfa-nametext{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.rfa-name .rfa-stat{margin-left:0}
.rfa-row.targeted .rfa-name{font-weight:700}
.pos{color:var(--pos-wr);font-family:var(--cond);font-size:11.5px;
  font-weight:700;letter-spacing:.08em}
.rfa-name .pos{margin-right:5px}
.pos-RB{color:var(--pos-rb)}
.pos-QB{color:var(--pos-qb)}
.pos-TE{color:var(--pos-te)}
.rfa-sub{display:block;color:var(--muted);font-size:11.5px;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.rfa-right{margin-left:10px;display:flex;align-items:center;gap:6px;justify-self:end;
  justify-content:flex-end}
/* Right column matches the Pass and $ boxes so the three line up. */
.rfa-amt{font-family:var(--cond);font-size:16px;font-weight:700;color:var(--money)}
.rfa-live{width:72px;flex:0 0 auto;text-align:center;font-family:var(--cond);
  font-size:11px;font-weight:700;letter-spacing:.1em;
  text-transform:uppercase;color:var(--green)}
.tag{font-size:10px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  padding:2px 5px;border-radius:4px;white-space:nowrap}
.tag.matched{background:#12352a;color:#6fe0aa}
.tag.relinquished{background:#3a2a14;color:#ffb765}
.tag.no_bids{background:#252d38;color:var(--muted)}
.footnote{font-size:11.5px;color:#5f6c7d;margin:10px 2px 0;line-height:1.4}

/* ── player art on the stage ─────────────────────────── */
.nom-art{position:relative;width:82px;height:82px;flex:0 0 auto}
.nom-shot{width:82px;height:82px;border-radius:11px;object-fit:cover;object-position:top center;
  background:var(--slate-2);border:1px solid var(--line);display:block}
.nom-mono{width:82px;height:82px;border-radius:11px;background:var(--slate-2);
  border:1px solid var(--line);display:grid;place-items:center;
  font-family:var(--display);font-weight:800;font-size:27px;color:#4d5a6b}
.nom-badge{position:absolute;right:-7px;bottom:-7px;width:34px;height:34px;
  border-radius:9px;background:var(--slate);border:1px solid var(--line);
  padding:3px;object-fit:contain}

/* ── modal / toast ───────────────────────────────────── */
/* Centred in the usable screen, not the whole one. inset:0 runs behind the
   status bar and the home indicator, so a card centred in it sits high of
   where it looks like it should be — most obviously in the home-screen app,
   where that top strip is tallest. */
/* The same inset top and bottom, so the card centres on the screen rather
   than in the space left over. Uneven padding — a notch at the top, a home
   indicator of a different height at the bottom — still clears both, but
   it moves the middle down, and a centred card that sits low reads as a
   mistake. The larger of the two is used on both sides. */
/* grid-template-rows is the whole trick. Without it the implicit row is
   `auto`, so the row grows to fit the card — and the card's max-height:100%
   then measures against a row that is however tall the card is. It never
   clamps, so every asset added pushed the card further down and the
   buttons off the bottom. One row, exactly the container's height. */
.modal{position:fixed;inset:0;background:#080b0fcc;display:grid;
  grid-template-rows:minmax(0,1fr);place-items:center;z-index:92;
  padding:calc(20px + max(var(--sat,0px),var(--sab,0px))) 20px;
  animation:card-in .26s ease-out both}
/* The veil keeps catching taps while it fades: none while closing meant
   a tap landed on the page behind a card that was still on screen. The
   card inside it stops responding instead, so a second press on a button
   can't fire it twice. */
.modal.closing{animation:card-out .24s ease-in both}
.modal.closing > .modal-card{pointer-events:none}
.modal.closing > .modal-card{animation:card-sink .24s ease-in both}
.modal-card{background:var(--slate);border:1px solid var(--line);border-radius:12px;
  width:min(560px,100%);
  /* Against the space it actually has, so a tall card can't grow into the
     padding and push itself off centre. The dvh is a floor under that: a
     percentage resolves against the grid area, and if anything ever stops
     that resolving, a long trade would push its own buttons off screen
     again — which is the one failure this card can't afford. */
  max-height:min(100%,86dvh);margin:auto;
  display:flex;flex-direction:column;
  animation:card-rise .34s cubic-bezier(.22,.7,.3,1) both}
.modal-head{flex:0 0 auto;display:flex;align-items:center;min-height:39px;
  padding:0 8px 0 14px;
  background:#161c25;border-bottom:1px solid var(--line);border-radius:12px 12px 0 0;
  font-family:var(--cond);font-size:12px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--muted);font-weight:700}
.modal-x{margin-left:auto;background:none;border:0;font-size:22px;color:var(--muted);
  cursor:pointer;line-height:1;padding:4px 9px}
/* flex:1 with min-height:0 is what actually lets this scroll. Without the
   min-height a flex item won't shrink below its own content, so a long
   trade grew the card past its max-height and pushed the buttons off the
   bottom of the screen — the one place they can't be reached from. */
.modal-body{flex:1 1 auto;min-height:0;padding:16px;overflow:auto}
.modal-note{color:var(--muted);font-size:13.5px;margin:0 0 14px}
#accountModal .modal-foot{justify-content:center}
/* Start the trade again: same size as the close beside it, and quiet
   until it's wanted. */

/* The head and the foot hold their size; only the middle gives. */
.modal-foot{flex:0 0 auto;display:flex;gap:9px;justify-content:flex-end;
  flex-wrap:wrap;
  padding:12px 16px;background:#161c25;border-top:1px solid var(--line);
  border-radius:0 0 12px 12px}

/* Bid cap block / overbid confirmation.
   These fire from inside the bidding overlay, which is a .splash at z-index 50,
   so they have to clear it — at the shared .modal z-index of 40 they opened
   behind it and were invisible. */
#bidModal{z-index:84}
.modal-lead{font-size:15px;line-height:1.5;margin:0 0 14px;color:var(--text)}
#bidModalBody .modal-note{margin:14px 0 0}
.capsum{display:flex;flex-direction:column;border:1px solid var(--line);
  border-radius:9px;overflow:hidden}
.capsum-row{display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  padding:8px 12px;font-size:13.5px;color:var(--muted);
  border-bottom:1px solid #2b3542}
.capsum-row:last-child{border-bottom:0}
.capsum-row b{font-family:var(--cond);font-size:18px;font-weight:700;color:var(--text)}
.capsum-row.bad{background:#e2574c14}
.capsum-row.bad b{color:var(--red)}
.reassign-row{display:flex;gap:9px;align-items:center;flex-wrap:wrap;margin-bottom:16px}
.reassign-row select{background:var(--ink);border:1px solid var(--line);border-radius:8px;padding:9px 10px}
.arrow{color:var(--muted)}
.ledger{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:8px}
.ledger-team{background:var(--slate-2);border-radius:8px;padding:9px 10px;font-size:12.5px}
.ledger-team b{display:block;margin-bottom:4px;font-size:13px}
.ledger-team span{color:var(--muted);font-family:var(--cond);font-size:14px;margin-right:6px}

/* ── the reveal splash ──────────────────── */
.splash{position:fixed;inset:0;z-index:82;display:grid;place-items:center;padding:20px;
  background:#080b0fee;backdrop-filter:blur(3px);animation:splash-in .22s ease}
@keyframes splash-in{from{opacity:0}to{opacity:1}}
/* The bidding overlay opens below the frozen chrome and grows downward: with
   the card centred it expanded in both directions, sliding up behind the
   clock as the pick menu opened. Declared after .splash so it actually wins. */
/* Centred in the space under the chrome. The top offset means a growing card
   still can't slide up behind the clock. */
.bidstage{top:var(--chrome-h,0px);align-items:center;padding-top:12px}
.bidstage .splash-card{max-height:calc(100dvh - var(--chrome-h,0px) - 32px)}
.splash-card{width:min(680px,100%);max-height:88dvh;display:flex;flex-direction:column;
  background:var(--slate);border:1px solid var(--line);border-radius:13px;overflow:hidden;
  box-shadow:0 24px 70px #000a}
.splash-head{display:flex;align-items:center;gap:12px;padding:14px 18px;
  background:#161c25;border-bottom:1px solid var(--line)}
/* Square, sized to the two title lines. aspect-ratio can't do this on its own:
   in a flex row the width is resolved before the stretched height is known, so
   the box collapses to its borders. */
.splash-head .face-wrap{position:relative;flex:0 0 auto;width:46px;height:46px;
  border-radius:9px;border:1px solid var(--line);
  background:var(--slate-2);overflow:hidden}
.splash-head img.face{position:absolute;inset:0;display:block;width:100%;height:100%;
  object-fit:cover;object-position:top center}
.splash-title{min-width:0;flex:1}
.splash-title > b{display:block;font-family:var(--display);font-size:21px;line-height:1.15}
.splash-title > span{display:block;font-family:var(--cond);font-size:11.5px;
  letter-spacing:.04em;text-transform:uppercase;color:var(--muted)}
.splash-title .name-money{color:var(--money);font-weight:700;white-space:nowrap}
.splash-step{font-family:var(--cond);font-size:11px;font-weight:700;letter-spacing:.15em;
  text-transform:uppercase;color:var(--teal);white-space:nowrap}
.splash-body{padding:16px 18px;overflow:auto;flex:1}
.splash-foot{display:flex;gap:9px;flex-wrap:wrap;align-items:center;
  padding:12px 18px;background:#161c25;border-top:1px solid var(--line)}
.splash-foot .spacer{flex:1}

/* ── bid breakdown on a settled row ───────── */
.bidlog{width:100%;border-collapse:collapse;margin-top:7px}
.bidlog caption{font-family:var(--cond);font-size:10px;font-weight:700;letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted);text-align:left;padding-bottom:4px}
.bidlog td{font-size:11.5px;padding:3px 2px;border-bottom:1px solid #2b354266}
.bidlog tr:last-child td{border-bottom:0}
.bidlog .b-who{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bidlog .b-pick{font-family:var(--cond);font-weight:700;color:var(--orange);
  text-align:center;width:34px}
.bidlog .b-amt{font-family:var(--cond);font-weight:700;font-size:14px;color:var(--money);
  text-align:right;width:42px}
.bidlog tr.won .b-who{color:var(--text);font-weight:600}
.bidlog tr.out{opacity:.55}
.bidlog tr.out .b-amt{color:var(--muted)}
.rfa-export{display:block;width:100%;margin-top:2px;text-align:center}

.toast{position:fixed;left:50%;bottom:24px;transform:translateX(-50%);z-index:86;
  background:var(--slate-2);border:1px solid var(--line);border-left:3px solid var(--red);
  border-radius:9px;padding:11px 16px;font-size:14px;max-width:90vw}

/* ── responsive ──────────────────────────────────────── */
/* Phones and tablets: a coarse pointer catches an iPad in landscape,
   which is wider than any width breakpoint would allow for. */
/* Sheets get the same red scrollbar the panes use, and a deeper backdrop so
   the board behind reads as out of the way. */

.sheet-body::-webkit-scrollbar{width:13px}
.sheet-body::-webkit-scrollbar-track{background:var(--slate)}
.sheet-body::-webkit-scrollbar-thumb{background:var(--red);border-radius:7px;
  border:3px solid var(--slate)}
.sheet-body::-webkit-scrollbar-thumb:hover{background:#ef6a5f}
.sheet-body::-webkit-scrollbar-corner{background:var(--slate)}
.sheet-body::-webkit-scrollbar-button:single-button{background:var(--slate);
  display:block;height:13px;width:13px;background-repeat:no-repeat;background-position:center}
.sheet-body::-webkit-scrollbar-button:single-button:vertical:decrement{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 13 13'><path d='M6.5 3.6 L10 8.4 L3 8.4 Z' fill='%23e2574c'/></svg>")}
.sheet-body::-webkit-scrollbar-button:single-button:vertical:decrement:hover{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 13 13'><path d='M6.5 3.6 L10 8.4 L3 8.4 Z' fill='%23ef6a5f'/></svg>")}
.sheet-body::-webkit-scrollbar-button:single-button:vertical:increment{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 13 13'><path d='M6.5 9.4 L3 4.6 L10 4.6 Z' fill='%23e2574c'/></svg>")}
.sheet-body::-webkit-scrollbar-button:single-button:vertical:increment:hover{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 13 13'><path d='M6.5 9.4 L3 4.6 L10 4.6 Z' fill='%23ef6a5f'/></svg>")}
.sheet-body .rfa::-webkit-scrollbar{width:13px}
.sheet-body .rfa::-webkit-scrollbar-track{background:var(--slate)}
.sheet-body .rfa::-webkit-scrollbar-thumb{background:var(--red);border-radius:7px;
  border:3px solid var(--slate)}
.sheet-body .rfa::-webkit-scrollbar-thumb:hover{background:#ef6a5f}
.sheet-body .rfa::-webkit-scrollbar-corner{background:var(--slate)}
.sheet-body .rfa::-webkit-scrollbar-button:single-button{background:var(--slate);
  display:block;height:13px;width:13px;background-repeat:no-repeat;background-position:center}
.sheet-body .rfa::-webkit-scrollbar-button:single-button:vertical:decrement{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 13 13'><path d='M6.5 3.6 L10 8.4 L3 8.4 Z' fill='%23e2574c'/></svg>")}
.sheet-body .rfa::-webkit-scrollbar-button:single-button:vertical:decrement:hover{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 13 13'><path d='M6.5 3.6 L10 8.4 L3 8.4 Z' fill='%23ef6a5f'/></svg>")}
.sheet-body .rfa::-webkit-scrollbar-button:single-button:vertical:increment{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 13 13'><path d='M6.5 9.4 L3 4.6 L10 4.6 Z' fill='%23e2574c'/></svg>")}
.sheet-body .rfa::-webkit-scrollbar-button:single-button:vertical:increment:hover{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 13 13'><path d='M6.5 9.4 L3 4.6 L10 4.6 Z' fill='%23ef6a5f'/></svg>")}
#leagueBody::-webkit-scrollbar{width:13px}
#leagueBody::-webkit-scrollbar-track{background:var(--slate)}
#leagueBody::-webkit-scrollbar-thumb{background:var(--red);border-radius:7px;
  border:3px solid var(--slate)}
#leagueBody::-webkit-scrollbar-thumb:hover{background:#ef6a5f}
#leagueBody::-webkit-scrollbar-corner{background:var(--slate)}
#leagueBody::-webkit-scrollbar-button:single-button{background:var(--slate);
  display:block;height:13px;width:13px;background-repeat:no-repeat;background-position:center}
#leagueBody::-webkit-scrollbar-button:single-button:vertical:decrement{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 13 13'><path d='M6.5 3.6 L10 8.4 L3 8.4 Z' fill='%23e2574c'/></svg>")}
#leagueBody::-webkit-scrollbar-button:single-button:vertical:decrement:hover{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 13 13'><path d='M6.5 3.6 L10 8.4 L3 8.4 Z' fill='%23ef6a5f'/></svg>")}
#leagueBody::-webkit-scrollbar-button:single-button:vertical:increment{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 13 13'><path d='M6.5 9.4 L3 4.6 L10 4.6 Z' fill='%23e2574c'/></svg>")}
#leagueBody::-webkit-scrollbar-button:single-button:vertical:increment:hover{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 13 13'><path d='M6.5 9.4 L3 4.6 L10 4.6 Z' fill='%23ef6a5f'/></svg>")}
#draftBody::-webkit-scrollbar{width:13px}
#draftBody::-webkit-scrollbar-track{background:var(--slate)}
#draftBody::-webkit-scrollbar-thumb{background:var(--red);border-radius:7px;
  border:3px solid var(--slate)}
#draftBody::-webkit-scrollbar-thumb:hover{background:#ef6a5f}
#draftBody::-webkit-scrollbar-corner{background:var(--slate)}
#draftBody::-webkit-scrollbar-button:single-button{background:var(--slate);
  display:block;height:13px;width:13px;background-repeat:no-repeat;background-position:center}
#draftBody::-webkit-scrollbar-button:single-button:vertical:decrement{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 13 13'><path d='M6.5 3.6 L10 8.4 L3 8.4 Z' fill='%23e2574c'/></svg>")}
#draftBody::-webkit-scrollbar-button:single-button:vertical:decrement:hover{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 13 13'><path d='M6.5 3.6 L10 8.4 L3 8.4 Z' fill='%23ef6a5f'/></svg>")}
#draftBody::-webkit-scrollbar-button:single-button:vertical:increment{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 13 13'><path d='M6.5 9.4 L3 4.6 L10 4.6 Z' fill='%23e2574c'/></svg>")}
#draftBody::-webkit-scrollbar-button:single-button:vertical:increment:hover{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 13 13'><path d='M6.5 9.4 L3 4.6 L10 4.6 Z' fill='%23ef6a5f'/></svg>")}
@media (min-width:1081px){
  .sheet{background:#04060999;
    backdrop-filter:blur(14px) saturate(.7) brightness(.55);
    -webkit-backdrop-filter:blur(14px) saturate(.7) brightness(.55)}
  /* Native pickers default to a light list; match the app. */
  .sheet select,.sheet option{background:var(--slate);color:var(--text)}
  .sheet select{color-scheme:dark}
}

/* A tablet's status bar overlays the web view even in standalone, and the
   safe-area inset can come back as zero — so guarantee clearance. */
@media (min-width:700px) and (pointer:coarse){
  html.standalone .topbar{padding-top:calc(8px + max(var(--sat,0px),22px))}
}

/* ── wide-screen sheets ───────────────────────────────────────────────
   The draft and the snapshot have far more room on a desktop than a phone,
   so they widen and lay out in columns rather than one long list. */
@media (min-width:1081px){
  #draftSheet .sheet-card{width:min(1500px,96vw);height:100%}
  #draftBody{min-height:0;overflow-y:auto}
  /* Twelve rows plus a heading have to clear the card's height, so the
     rows run tighter here than on a phone. */
  #draftBody .dr-row{min-height:42px;padding:5px 8px;margin-bottom:0}
  #draftBody .dr-list{gap:4px}
  #draftBody .dr-round{margin-bottom:10px}
  #draftBody .dr-head{margin-bottom:6px}
  #draftBody .dr-face{width:22px;height:22px}
  #draftBody .dr-who b{font-size:12.5px}
  #draftBody .dr-from{font-size:9.5px}
  #draftBody .dr-bid{font-size:14px}
  #draftBody .dr-cost{font-size:9.5px}
  #draftBody{column-gap:18px}
  .dr-round{break-inside:avoid;margin-bottom:14px}
  #leagueSheet .sheet-card,
  #rosterSheet .sheet-card{width:min(1180px,94vw)}
  /* Tall enough to be useful, never taller than the window. */
  #leagueSheet .sheet-card,#rosterSheet .sheet-card{height:100%}
  #leagueBody,#rosterBody{min-height:0;overflow-y:auto}
  /* Twelve rows fit in that height, so the list shouldn't need scrolling —
     the rows shrink a little rather than overflowing. */
  #leagueSheet .lg-row{padding:7px 14px;margin-bottom:3px}
  #leagueSheet .lg-face{width:28px;height:28px}
  #leagueSheet .lg-face img{width:28px;height:28px}
  /* Roomier rows, and every figure a size up. */
  #leagueSheet .lg-row{grid-template-columns:minmax(0,1fr) 90px 60px 62px 92px
    120px 104px;gap:8px}
  #leagueSheet .lg-name{font-size:15px;letter-spacing:0}
  #leagueSheet .lg-num{font-size:16px}
  #leagueSheet .lg-head .lg-num{font-size:11px;letter-spacing:.06em}
  #leagueSheet .lg-head .lg-team{font-size:11px}
  #leagueSheet .lg-face{width:32px;height:32px}
  #leagueSheet .lg-face img{width:32px;height:32px}
  #leagueSheet .lg-num i{font-size:12px}
}
/* Four rounds abreast once there's genuinely room. */
@media (min-width:1500px){ #draftBody{columns:4} }
/* Two on a mid-sized window. */
@media (min-width:1081px) and (max-width:1499px){ #draftBody{columns:2} }

/* Between the phone breakpoint and a comfortable desktop there isn't room
   for three columns. Rather than letting the stage wrap under the board,
   hand over to the same pop-out cards the phone uses. */
@media (min-width:1081px) and (max-width:1350px){
  .grid{grid-template-columns:372px minmax(0,1fr)}
  .grid.no-rail{grid-template-columns:minmax(0,1fr)}
  .pane-stage{display:none}
  /* The rail stacks down the left; the board takes the rest. */
  .pane-power{grid-column:1;grid-row:1}
  .pane-picks{grid-column:1;grid-row:2}
  .pane-signed{grid-column:1;grid-row:3;max-height:30vh}
  .pane-board{grid-column:2;grid-row:1/-1}
  .grid.no-rail .pane-board{grid-column:1;grid-row:1/-1}
}

@media (max-width:1080px), (pointer:coarse){
  /* Stacked layout, but spending power and picks ride at the top as a pair.
     display:contents dissolves the rail so its three panes place themselves
     directly on the grid and can be ordered independently — otherwise the
     signed-players pane would be dragged up with them. */
  /* One screenful, no page scroll: the rows are sized so the board takes
     what's left and Players Signed grows with its contents. */
  /* Height measured from visualViewport, not a viewport unit: dvh only
     updates after a scroll, and a fixed inset box sizes to the layout
     viewport, which never grows when the toolbar retracts. No `bottom` here
     — setting top, bottom and height at once over-constrains the box and the
     height silently wins. */
  .app{position:fixed;top:0;left:0;right:0;
    height:var(--app-h, 100dvh);overflow:hidden}
  /* The page behind is the app's own colour, so any strip the app doesn't
     cover is invisible rather than a lighter block. */
  html.standalone,html.standalone body{background:var(--ink)}
  /* The auction is a fixed pane, so the page behind it must not rubber-band.
     Scoped to that page: every other page is an ordinary scrolling document. */
  html:has(.app),html:has(.app) body{height:100%;overflow:hidden;
    overscroll-behavior:none;position:fixed;width:100%}
  /* Anything the measured height can't reach — a home-indicator inset, say —
     shows the app's own colour rather than a grey band. */
  html,body{background:var(--ink)}
  .grid,.grid.no-rail{grid-template-columns:1fr 1fr;
    grid-template-rows:auto minmax(120px,1fr) auto;
    gap:8px;align-items:stretch;align-content:stretch;min-height:0;
    overflow:hidden;
    padding-bottom:max(26px, calc(5px + var(--sat, 0px) / 3))}
  .grid > .pane{min-height:0}
  .pane-board{min-height:0}
  .pane-board .pane-body{min-height:0;overflow:hidden}
  /* Fills the row it's given rather than a fixed number of rows. */
  .rfa.capped{max-height:100%;height:100%;overflow-y:auto;
    overscroll-behavior:none;-webkit-overflow-scrolling:auto}
  /* Native overlay scrollbars already appear only while scrolling and always
     paint above content, so the drawn one isn't needed here. */
  .pane-scroll{display:none}
  .pane-body::-webkit-scrollbar,
  .rfa.capped::-webkit-scrollbar{width:5px}
  .pane-body::-webkit-scrollbar-track,
  .rfa.capped::-webkit-scrollbar-track{background:transparent}
  .pane-body::-webkit-scrollbar-thumb,
  .rfa.capped::-webkit-scrollbar-thumb{background:var(--red);border:0;
    border-radius:3px}
  .pane-body::-webkit-scrollbar-button:single-button{display:none}
  .pane-body,.rfa.capped{scrollbar-width:thin;
    scrollbar-color:var(--red) transparent}
  /* The drifting line on a settled row is transform-animated, so WebKit
     gives it its own layer — and a composited layer can paint over an
     overlay scrollbar. Keep the rows clear of the bar entirely. */
  .rfa.capped{margin-right:-11px;padding-right:11px}
  .pane-signed{max-height:38dvh}
  .pane-signed .pane-body{overflow-y:auto}
  #planFoot{display:none}
  .rail{display:contents}
  .pane{max-height:none}
  .pane-power{order:1;grid-column:1}
  .pane-picks{order:2;grid-column:2;max-height:166px}
  .pane-board{order:3;grid-column:1/-1}
  /* The stage has no room once the rail goes two-up; the player card opens
     as a pop-out instead. */
  /* No stage on a narrow layout — the player card opens as a pop-out. */
  .pane-stage{display:none}
  .pane-stage{order:4;grid-column:1/-1}
  .pane-signed{order:5;grid-column:1/-1}

  /* Half-width now, so the pick rows lose the third column and tighten up. */
  /* Centred, since this pane is stretched to match the taller picks pane. */
  .pane-power .pane-body{padding:10px;display:flex;flex-direction:column;
    justify-content:center}
  .power-amt{font-size:40px;margin:8px 0}
  .power-label{font-size:10px;letter-spacing:.14em}
  .power-sub{font-size:13px}
  .power-note{margin-top:8px}
  .pane-picks .pane-body{padding:9px}
  .picks{gap:4px}
  .pick{grid-template-columns:24px 1fr;gap:6px;padding:4px 6px}
  /* Bid value and contract share a line instead of stacking — halves the row
     height, which is what gets a useful number of picks on screen. nowrap so
     a long pair can never push the row or badge taller. */
  .pick > div{display:flex;align-items:center;gap:5px;flex-wrap:nowrap;min-width:0}
  .pick-val,.pick-cost{white-space:nowrap}
  .pick-cost{overflow:hidden;text-overflow:ellipsis}
  .pick-no{font-size:11.5px;border-radius:4px}
  .pick-val{font-size:14px}
  .pick-val.unl{font-size:9.5px;letter-spacing:0}
  .pick-cost{font-size:8.5px}
  /* The "acquired" tag is the first thing to go at this width. */
  .pick > .pick-cost:last-child{display:none}
  .pick.armed .pick-cost::after{content:' · offer'}
  .footnote{font-size:9.5px}
}
@media (max-width:560px){
  /* Freeze the bar to the top and keep brand, name and Sign out on one line —
     it wrapped to two rows and ate a chunk of a short screen. The horizontal
     padding also clears the notch/rounded corners, since the page is set to
     viewport-fit=cover and those insets are otherwise zero. */
  /* Sits directly under the frozen bar; --topbar-h is measured in app.js
     because the bar's height moves with the type. */
  .roomclock{top:var(--topbar-h,49px)}
  /* Pinned below the resume bar so the next two players stay in view while
     the board scrolls. Sheets sit above them, as before. */
  .alerts{position:sticky;top:var(--chrome-h,49px);z-index:27}
  .bidresume{top:var(--stack-h,49px);padding-left:16px;padding-right:16px;gap:10px}
  .bidresume-chip{display:flex;align-items:center;flex:0 0 auto}
.bidresume-chip .pick-chip{font-size:13px;padding:2px 7px}
.bidresume-txt{font-size:12.5px}
  /* The status bar sits over the web view in standalone mode, so the bar
     pads itself clear of the clock and battery while its background still
     runs to the top edge. */
  .topbar{position:sticky;top:0;z-index:90;gap:10px;flex-wrap:nowrap;
    padding-top:calc(8px + var(--sat,0px));padding-bottom:8px;
    padding-left:calc(16px + env(safe-area-inset-left));
    padding-right:calc(16px + env(safe-area-inset-right))}
  .brand{gap:6px;font-size:16px;min-width:0}
  .brand-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  /* The name and Sign out button collapse into the avatar, which opens a
     sheet with both. Three items wouldn't fit on one line at this width. */
  .me-text,#logout{display:none}
  .me-avatar{display:block}
  .nom-name{font-size:27px}.clock-num{font-size:36px}

  .pane-expand{display:flex;margin-left:auto}
  /* Half-width pane: the title and the control only fit on one line if the
     title is allowed to shrink. */
  .pane-picks .pane-head{gap:6px;padding-left:10px;padding-right:8px}
  .pane-picks .pane-head > span{min-width:0;white-space:nowrap;
    overflow:hidden;text-overflow:ellipsis;font-size:11px;letter-spacing:.1em}
  .pane-picks .head-count{margin-left:5px}
  /* Four filters plus the control is tight; nowrap or the labels break
     across two lines inside their own pills. */
  .pane-board .seg button{padding:5px 6px;font-size:10px;letter-spacing:.02em;
    white-space:nowrap}
  .pane-board .pane-head{gap:6px}

  /* NEXT UP is folded into the top banner on a phone, so the pane would
     only repeat it. The commissioner keeps it — it carries their controls. */
  /* Two selects plus a count is a lot for one line at this width. */
  #boardSheet .sheet-filter select{flex:1 1 30%}
  /* Still two columns at this width — the player rows shrink to pay for it
     rather than the picks dropping below a long roster. */
  .rr-split{grid-template-columns:minmax(0,1fr) 140px;gap:10px}
  .rr-face{width:28px;height:28px;border-radius:6px}
  .rr-name{font-size:12.5px}
  .rr-sub{font-size:9.5px;letter-spacing:.04em}
  .rr-sal{font-size:14px}
  .rr-rank{font-size:12.5px}
  .rr{gap:7px;padding:5px 7px}
  .rr-head b{font-size:13px}
  .rr-head span{font-size:10px}
  .rr-picks .rr-head{gap:6px}
  .rr-picks .rr-head b,.rr-picks .rr-head span{white-space:nowrap}
  /* One line per pick: the badge and the rookie salary. The bid value is
     dropped here — it never fitted, and it is on the bidding screens. */
  .rr-picklist li{flex-wrap:nowrap;gap:6px;padding:5px 6px}
  .rr-picklist .pick-chip{min-width:34px;font-size:10px}
  .rr-pickval{display:none}
  .rr-pickcost{flex:1 1 auto;font-size:9.5px;overflow:hidden}
  .rr-pickcost b{font-size:12px}
  .rr-pickfrom{font-size:10.5px}
  /* Sit in the topbar beside the avatar rather than floating over the page. */
  .fabs{display:flex;gap:8px;position:static;margin-left:auto}
  .topbar .me{margin-left:8px}

  /* One row, with the filters centred: equal side columns put the middle on
     the container's centre line whatever the title and icon measure. */
  .pane-board .pane-head{display:grid;
    grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);
    min-height:0;padding:7px 9px}
  .pane-board .pane-head > span{justify-self:start}
  .pane-board .seg{justify-self:center}
  .pane-board .pane-expand{justify-self:end;margin-left:0}

  /* Clock pinned to the top of the overlay while the rest scrolls under it.
     The negative margins let it span the body's padding so nothing shows
     through at the edges. */
  .bidstage .splash-body{padding-top:0}
  .bidstage .clock{position:sticky;top:0;z-index:5;margin:0 -18px 18px;
    padding:18px 18px;background:var(--slate);border-bottom:1px solid var(--line)}
  /* Roughly the clock's height, so scroll-into-view lands below it rather
     than tucking the target underneath. */
  .bidstage .splash-body{scroll-padding-top:76px}
  .bidstage .bidrow,.bidstage .pickmenu,.bidstage .statwrap,
  .bidstage .locked,.bidstage .offer{scroll-margin-top:76px}

  /* Bid value in white here — the green reads as "money you have", which is
     not what a pick's bid ceiling is. */
  .pick-val{color:var(--text)}

  /* Field spans the width; the two buttons share the row beneath it. */
  .bidrow{flex-direction:column;align-items:stretch;gap:10px}
  .bidrow .field{width:100%}
  .bidrow input[type=number]{width:100%}
  .bidrow .bidfield{width:100%}
  .bidbtns{justify-content:center}
  /* Explicit flex + height: as plain blocks these were sizing off two line
     boxes and coming out 56px tall. */
  .bidbtns > *{flex:1 1 0;display:flex;align-items:center;justify-content:center;
    height:44px;padding:0 8px;white-space:nowrap;line-height:1}

  /* 16px is the threshold below which iOS zooms in on a focused field. */
  .note-input,.unl-pick select,#timerInput,#reassignPick,#reassignOwner{font-size:16px}
}
@media (prefers-reduced-motion:reduce){
  *{animation:none!important;transition-duration:.01ms!important}
}

/* A tablet's status bar overlays the web view even in standalone, and the
   safe-area inset can come back as zero — so guarantee some clearance for
   the clock and battery. Phones are already handled by --sat. */
@media (min-width:700px) and (pointer:coarse){
  html.standalone .topbar{padding-top:calc(8px + max(var(--sat,0px),22px))}
}

/* ── hub ──────────────────────────────────────────────────────────────
   The landing page: which tool are you here for. */
.hub{max-width:640px;margin:0 auto;padding:26px 16px 40px}
.hub-lead{margin:0 0 16px;font-family:var(--cond);font-size:12px;
  font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted)}
.hub-cards{display:flex;flex-direction:column;gap:12px}
.hub-card{display:flex;align-items:center;gap:14px;padding:16px;
  background:var(--slate);border:1px solid var(--line);border-radius:12px;
  color:var(--text);text-decoration:none;transition:transform .1s,border-color .1s}
.hub-card:hover{border-color:#3a4756}
.hub-card:active{transform:scale(.99)}
.hub-card-mark{flex:0 0 auto;width:44px;height:44px;display:flex;
  align-items:center;justify-content:center;border-radius:10px;
  background:var(--slate-2)}
.hub-card-mark svg{width:26px;height:26px}
.hub-card-mark.rfa{color:var(--red)}
.hub-card-mark.rookie{color:var(--teal)}
.hub-card-text{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px}
.hub-card-text b{font-family:var(--display);font-size:19px}
.hub-card-text span{font-family:var(--cond);font-size:12px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}
.hub-card-go{flex:0 0 auto;font-size:20px;color:#4a5666}

@media (min-width:1081px){
  .hub{max-width:760px;padding-top:40px}
  .hub-card{padding:20px}
}

/* ── the sandwich menu and its drawer ─────────────────────────────────
   Mobile-first: on a wide screen the pages have room for their own links,
   so the button steps aside. */
.menubtn{display:flex;flex-direction:column;justify-content:center;gap:4px;
  width:34px;height:34px;padding:0 7px;flex:0 0 auto;background:none;border:0;
  cursor:pointer;-webkit-tap-highlight-color:transparent;
  transition:transform .1s}
.menubtn span{display:block;height:2px;border-radius:2px;background:var(--text);
  transition:transform .2s,opacity .2s}
.menubtn:active{transform:translateY(2px)}
.menubtn.on span:nth-child(1){transform:translateY(6px) rotate(45deg)}
.menubtn.on span:nth-child(2){opacity:0}
.menubtn.on span:nth-child(3){transform:translateY(-6px) rotate(-45deg)}

.drawer-wrap{position:fixed;inset:0;z-index:95}
.drawer-veil{position:absolute;inset:0;background:#04060999;opacity:0;
  transition:opacity .24s}
.drawer-wrap.open .drawer-veil{opacity:1}
.drawer{position:absolute;top:0;bottom:0;left:0;width:min(280px,82vw);
  display:flex;flex-direction:column;background:var(--slate);
  border-right:1px solid var(--line);
  padding:calc(14px + var(--sat,0px)) 0 14px;
  transform:translateX(-100%);transition:transform .26s cubic-bezier(.32,.72,0,1)}
.drawer-wrap.open .drawer{transform:none}
.drawer-head{display:flex;align-items:center;justify-content:space-between;
  padding:4px 16px 12px;border-bottom:1px solid var(--line);margin-bottom:8px}
.drawer-head b{font-family:var(--cond);font-size:12px;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;color:var(--muted)}
.drawer-x{background:none;border:0;color:var(--muted);font-size:24px;
  line-height:1;cursor:pointer;padding:0 4px}
.drawer-x:hover{color:var(--text)}
.drawer-link{display:block;padding:13px 16px;color:var(--text);
  text-decoration:none;font-size:15px;transition:background .1s}
.drawer-link:hover{background:var(--slate-2)}
.drawer-link:active{background:#2b3542}
.drawer-link.soon{display:flex;align-items:baseline;justify-content:space-between;
  gap:10px;color:var(--muted);cursor:default}
.drawer-link.soon:hover{background:none}
.drawer-link.soon em{font-family:var(--cond);font-size:10px;font-weight:700;
  letter-spacing:.12em;text-transform:uppercase;font-style:normal;
  color:#4a5666;white-space:nowrap}
.drawer-rule{height:1px;background:var(--line);margin:8px 16px}

@media (prefers-reduced-motion:reduce){
  .drawer,.drawer-veil{transition:none}
}

/* Repeated rows are self-contained, so changing one doesn't re-lay-out the
   whole list. Cheap on a long roster or a 48-pick board. */
.rrow,.tb-item,.dpick,.trade,.openrow,.note-row,.teamcard,.filterrow{
  contain:layout style}

/* The shared player card borrows the auction's own header and stat cards. */
.playercard{align-items:center;justify-content:center}
.playercard .modal-card{width:min(560px,94vw);margin:auto}
.playercard .nom{margin-bottom:14px}
.playercard .stat-card{margin-top:10px}

/* Cards arrive rather than appear: the veil fades, the card lifts. */
@keyframes card-in{from{opacity:0}to{opacity:1}}
@keyframes card-rise{
  from{opacity:0;transform:translateY(12px) scale(.98)}
  to{opacity:1;transform:none}}
/* The contents follow the card in rather than landing with it. */
@keyframes card-content{from{opacity:0}to{opacity:1}}
@keyframes card-out{from{opacity:1}to{opacity:0}}
@keyframes card-sink{
  from{opacity:1;transform:none}
  to{opacity:0;transform:translateY(10px) scale(.985)}}
/* Leaving takes as long as arriving, so the two feel like one motion. */
.modal.closing{animation:card-out .24s ease-in both}
.modal.closing > .modal-card{pointer-events:none}
.modal.closing > .modal-card{animation:card-sink .24s ease-in both}
.modal-card > .modal-body{animation:card-content .3s ease-out .08s both}
.sheet.open .sheet-body{animation:card-content .3s ease-out .06s both}
body:has(.home) .sheet{transition:opacity .24s ease-in,
  visibility 0s linear .24s}
body:has(.home) .sheet.open{transition:opacity .26s ease-out,visibility 0s}
body:has(.home) .sheet .sheet-card{transition:transform .26s
  cubic-bezier(.22,.7,.3,1),opacity .26s ease-out}
body:has(.home) .sheet:not(.open) .sheet-card{transform:translateY(12px)
  scale(.985);opacity:0}
@media (prefers-reduced-motion:reduce){
  .modal,.modal > .modal-card{animation:none}
}

/* The hub's panels: the same sheet the auction uses, with a filter row. */
body:has(.home) #rosterSheet,body:has(.home) #draftSheet,
/* All three of the hub's sheets start below the header and take what's
   left — the trades one already did, and the other two were laid over the
   whole viewport, so a tall card could reach up behind the banner. */
body:has(.home) #tradesSheet,
body:has(.home) #rosterSheet,
body:has(.home) #draftSheet{top:var(--bar-h,53px);
  height:calc(100dvh - var(--bar-h,53px));
  padding:12px 0 calc(12px + var(--sab,0px))}
body:has(.home) #rosterSheet .sheet-card,
body:has(.home) #draftSheet .sheet-card{width:min(680px,96vw);height:100%}
/* About half the screen: enough to read, and it scrolls for the rest. */
/* Sized to the room rather than to a fixed guess: wide enough for a trade
   card to breathe, tall enough to show three or four, and capped so it
   doesn't become a full-screen panel on a large monitor. */
body:has(.home) #tradesSheet .sheet-card{position:relative;
  width:min(760px,94vw);height:min(76vh,680px)}
/* The panel fills that card. It was keeping its phone width in the middle
   of it, which is where all the empty space came from. */
body:has(.home) #tradesSheet .tradepage{max-width:none;width:100%}
body:has(.home) #tradesSheet .sheet-body{position:static;
  display:flex;flex-direction:column;min-height:0}
/* The toggle stays in view; only what's below it scrolls. */
/* The toggle is fixed furniture; only the lists below it scroll. */
body:has(.home) #tradesSheet .segwrap{flex:0 0 auto;margin:0 0 14px;
  padding:2px 0 4px;background:none;border-bottom:0}
body:has(.home) #tradesSheet .tradelist,
body:has(.home) #tradesSheet .blocklist{flex:1;min-height:0;overflow-y:auto;
  margin:0 -16px;padding:0 16px 60px}
body:has(.home) #tradesSheet .histbar{flex:0 0 auto}
/* Anchored to the panel, so it doesn't land in one place and jump to
   another once the sheet has laid out. */
body:has(.home) #tradesSheet .sheet-card{position:relative}
/* flex:1 fills the sheet body, which is what the cover needs; min-height:0
   is what lets the lists inside scroll. Both are wanted — the cover is
   positioned against this element either way. */
body:has(.home) #tradesSheet .tradepage{display:flex;flex-direction:column;
  min-height:0;flex:1;padding:0;position:relative}
/* Anchored to the card, and breathing — the same treatment the rookie
   board's copy of this panel got. It only ever went on that one, so the
   hub's button sat there quietly doing nothing to catch the eye. */
/* Anchored to the card itself, so it sits in the card's bottom-right
   corner rather than the list's — which moved with whatever was in it. */
body:has(.home) #tradesSheet .fab-trade{position:absolute;right:18px;
  bottom:18px;z-index:6;border-color:var(--green);
  animation:fab-breathe 2s ease-in-out infinite}
@media (prefers-reduced-motion:reduce){
  body:has(.home) #tradesSheet .fab-trade{animation:none}
}
body:has(.home) #rosterSheet .sheet-filter,
body:has(.home) #draftSheet .sheet-filter{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  flex-wrap:wrap}
/* The picker keeps its width, so choosing a team can't shift what's beside
   it, and the count sits next to it rather than across the row. */
#draftSheet .teampick{flex:0 0 auto;width:190px}
/* Everywhere, not only the draft sheet. The roster sheet's row no longer
   wraps, so a long team name has to ellipsise rather than push the money
   off the end. */
.teampick .teampick-name{flex:1;min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}

/* Players on the left, that team's picks on the right. */
.rostercols{display:flex;flex-direction:column;gap:18px}
.rosterpicks{display:flex;flex-direction:column;gap:7px}
.picklist{display:flex;flex-direction:column;gap:16px}
.pgroup{display:flex;flex-direction:column;gap:5px}
.pgroup .rgroup-head{padding-bottom:5px}
.prow{display:flex;align-items:center;gap:8px;padding:7px 9px;
  background:var(--slate);border:1px solid var(--line);border-radius:9px}
.prow-mid{flex:1;display:flex;flex-direction:column;gap:1px;min-width:0}
.prow-spacer{flex:0 0 auto;width:88px}
/* The block control on a pick sits where the trade button does on a
   player's row, so the two columns line up. */
.prow .blockbtn{flex:0 0 auto;margin-left:auto}
.prow-mid b{font-size:12.5px}
.prow-mid span{font-family:var(--cond);font-size:10px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}
.prow-cost{color:var(--money);font-family:var(--cond);font-size:13px}
.prow-from{font-family:var(--cond);font-size:11px;letter-spacing:.06em;
  text-transform:none;color:var(--muted)}
.rrow.lu{gap:9px}
body:has(.home) #rosterBody .rr-list{margin:0;padding:0;list-style:none}
body:has(.home) #rosterBody .rr-list.bench{margin-top:18px;padding-top:14px;
  border-top:1px solid var(--line)}
body:has(.home) #rosterBody .rr-list.bench > li:first-child{margin-top:0}
body:has(.home) #draftSheet .draftboard{display:flex;flex-direction:column;
  gap:18px}

@media (min-width:1081px){
  /* The card fills the space the sheet has rather than a share of the
     viewport: 88vh measured against the whole screen reached past the top
     of that space and sat under the header. */
  body:has(.home) #rosterSheet .sheet-card,
  body:has(.home) #draftSheet .sheet-card{height:100%;max-height:100%}
  body:has(.home) #draftSheet .sheet-card{width:min(1400px,96vw)}
  body:has(.home) #draftSheet .draftboard{display:grid;
    grid-template-columns:repeat(4,minmax(0,1fr));gap:18px;align-items:start}

  /* ── the whole draft on one screen ──────────────────────────────────
     Four rounds side by side, each round's picks sharing the height that's
     left. Forty-nine picks then fit without scrolling, which is the point
     of opening the board on a big screen — you want to see the shape of it,
     not page through it. The rows shrink to fit rather than the board
     growing past the card. */
  body:has(.home) #draftSheet .sheet-body{overflow:hidden;display:flex;
    flex-direction:column;min-height:0}
  body:has(.home) #draftSheet .draftboard{flex:1;min-height:0;
    align-items:stretch;gap:14px}
  body:has(.home) #draftSheet .dround{display:flex;flex-direction:column;
    min-height:0}
  body:has(.home) #draftSheet .dround-head{flex:0 0 auto}
  /* Thirteen rows in every column, not "however many this round has" —
     otherwise the twelve-pick rounds get taller rows than the first and
     nothing lines up across the board.

     minmax(38px,1fr), not minmax(0,1fr): with a floor of nothing the rows
     were squeezed to whatever thirteen of them could be crushed into,
     which is what flattened the later rounds. Below that height the
     column scrolls instead. */
  body:has(.home) #draftSheet .dround-list{flex:1;min-height:0;display:grid;
    grid-template-rows:repeat(13,minmax(38px,1fr));gap:5px;
    overflow-y:auto;align-content:start}

  /* Everything in a pick, sized to whatever row height that leaves. */
  body:has(.home) #draftSheet .dpick{min-height:0;padding:3px 8px;gap:8px;
    align-items:center}
  body:has(.home) #draftSheet .dpick-no{font-size:11px;padding:2px 5px}
  body:has(.home) #draftSheet .dpick-who b{font-size:12px}
  body:has(.home) #draftSheet .dpick-from{font-size:9px}
  body:has(.home) #draftSheet .dpick-face,
  body:has(.home) #draftSheet .dpick-shot{width:26px;height:26px}
  body:has(.home) #draftSheet .dhist-name{font-size:11.5px}
  body:has(.home) #draftSheet .dhist-sub{font-size:9px}
  body:has(.home) #draftSheet .dhist-logo{width:11px;height:11px}
}

/* A live event breathes: brighter for a moment, every few seconds. The
   colours live in the keyframes, which is why setting them on the rule
   alone did nothing — an animation outranks a plain declaration. */
@keyframes live-glow{
  0%,84%{box-shadow:0 0 0 0 #e2574c00}
  90%{box-shadow:0 0 9px 3px #e2574c66}
  100%{box-shadow:0 0 0 0 #e2574c00}
}
@keyframes live-tag{
  0%,84%{border-color:var(--red);color:var(--red)}
  90%{border-color:#ff8f82;color:#ff8f82;box-shadow:0 0 12px #e2574c59}
  100%{border-color:var(--red);color:var(--red)}
}
.evdot.on{animation:live-glow 5s ease-in-out infinite}
.evtag.live{animation:live-tag 5s ease-in-out infinite}
@media (prefers-reduced-motion:reduce){
  .evdot.on,.evtag.live{animation:none}
}

/* ── the trade block ──────────────────────────────────────────────────
   A toggle on your own roster, and the league-wide list on the trades page. */
/* Sized to its words rather than to a fixed 88px. "Trade" and "Block"
   are short, and the difference was coming out of the player's name.
   A minimum keeps the column tidy where the labels differ. */
.blockbtn{flex:0 0 auto;margin-left:8px;min-width:62px;height:30px;
  display:inline-flex;align-items:center;justify-content:center;
  text-align:center;padding:0 10px;border-radius:7px;
  background:var(--slate-2);border:1px solid var(--line);color:var(--muted);
  font-family:var(--cond);font-size:10px;font-weight:700;letter-spacing:.1em;
  text-transform:uppercase;cursor:pointer;-webkit-tap-highlight-color:transparent;
  transition:transform .1s,border-color .1s,color .1s}
/* Only on a device that really hovers — a tap otherwise leaves the outline
   behind until you touch something else. */
@media (hover:hover){ .blockbtn:hover{border-color:var(--gold)} }
.blockbtn:focus{outline:none}
.blockbtn:focus-visible{outline:2px solid var(--teal);outline-offset:2px}
.blockbtn:active:not(:disabled){transform:translateY(2px)}
/* Listed: filled, not outlined — it's a state, not an invitation. */
.blockbtn.on{background:var(--gold);border-color:var(--gold);color:#fff}
.blockbtn.on:hover{background:#ffc24a;border-color:#ffc24a;color:#fff}
/* Solid green: this is the button that starts a trade, and it sat as a
   teal outline among a row of filled controls. */
/* Solid green, white text — the same button as on an opened roster card.
   !important because .blockbtn's own background lands later in some
   builds of this file, and a Trade button that reverts to grey looks
   disabled rather than available. */
.blockbtn.trade{background:var(--money)!important;
  border-color:var(--money)!important;color:#fff!important}
@media (hover:hover){
  .blockbtn.trade:hover{background:#7ce0a6!important;
    border-color:#7ce0a6!important;color:#fff!important}
}
/* Already inside an open offer. */
.blockbtn.pending{background:var(--blue)!important;
  border-color:var(--blue)!important;color:#fff!important}
.blockbtn.pending:disabled{opacity:1;cursor:default}
.blockbtn:disabled{opacity:.5}

.blocklist{display:flex;flex-direction:column;gap:5px}
.blocklist .tb-item{background:var(--slate);cursor:pointer}
.blocklist .tb-item:hover{border-color:var(--teal)}

/* ── open offers ──────────────────────────────────────────────────────
   Current offers use the same card as a settled trade, tagged and tappable.
   Anything closed is greyed and sits below. */
.trade.tappable{display:block;width:100%;text-align:left;font:inherit;
  color:inherit;cursor:pointer;transition:transform .1s,border-color .1s}
.trade.tappable:hover{border-color:#3a4756}
.trade.tappable:active{transform:translateY(2px)}
.trade.undone{opacity:.5;filter:grayscale(1)}
.trade-tag{font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase}
.tag-out{color:var(--gold)}
.tag-in{color:var(--green)}
.tag-dead{color:var(--muted)}
/* Why a closed offer went nowhere. */
.closed-why{margin:14px 0 0;padding:11px 12px;background:var(--slate-2);
  border-radius:9px;font-family:var(--cond);font-size:12.5px;
  letter-spacing:.06em;text-transform:uppercase;color:var(--muted);
  text-align:center}

/* The history filter */
.histbar{display:flex;align-items:center;gap:10px;margin-bottom:12px}
.histfilter{display:flex;align-items:center;gap:6px;font-family:var(--cond);
  font-size:12px;letter-spacing:.06em;text-transform:uppercase;
  color:var(--muted)}
.histclear{background:none;border:0;color:var(--red);font-size:16px;
  line-height:1;cursor:pointer;padding:0 2px}
.filtersearch{width:100%;background:var(--ink);border:1px solid var(--line);
  border-radius:8px;padding:10px 12px;font-family:var(--ui);font-size:15px;
  color:var(--text)}
.filtersearch:focus{outline:none;border-color:var(--teal)}
.filterlist{margin-top:12px;max-height:52vh;overflow-y:auto;display:flex;
  flex-direction:column;gap:4px;scrollbar-color:var(--red) transparent}
.filterlist::-webkit-scrollbar{width:8px}
.filterlist::-webkit-scrollbar-track{background:transparent}
.filterlist::-webkit-scrollbar-thumb{background:var(--red);border-radius:6px}
.filterhead{margin:8px 0 2px;font-family:var(--cond);font-size:10px;
  font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted)}
.filterhead:first-child{margin-top:0}
.filterrow{display:flex;width:100%;padding:9px 10px;background:var(--slate-2);
  border:1px solid transparent;border-radius:8px;color:inherit;font:inherit;
  text-align:left;cursor:pointer;transition:border-color .1s}
.filterrow:hover{border-color:var(--teal)}
.filterrow:active{transform:translateY(2px)}
.filterrow-mid{display:flex;flex-direction:column;gap:1px;min-width:0}
.filterrow-mid b{font-size:14px}
.filterrow-mid span{font-family:var(--cond);font-size:10.5px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}

/* ── notifications ────────────────────────────────────────────────────
   A bell beside the avatar: grey when quiet, red with a count when an offer
   is waiting. */
.bell{position:relative;width:32px;height:32px;flex:0 0 auto;padding:0;
  border-radius:50%;border:1px solid #2b3542;background:var(--slate);
  color:var(--muted);cursor:pointer;display:flex;align-items:center;
  justify-content:center;-webkit-tap-highlight-color:transparent;
  transition:transform .12s,color .15s,border-color .15s}
.bell:focus{outline:none}
.bell:focus-visible{outline:2px solid var(--teal);outline-offset:3px}
.bell svg{width:19px;height:19px;display:block}
/* The rookie board's roster button carries the auction's clipboard, so it
   takes the auction's icon size and its red — .bell's own 19px and muted
   grey are for the bell and the trade arrows beside it. */
#rosterBtn{color:var(--red)}
#rosterBtn svg{width:22px;height:22px;flex:0 0 auto;margin:0}
.bell:active{transform:translateY(2px)}
.bell.on{color:var(--gold);border-color:var(--gold)}
/* A ring every two seconds, so a waiting offer keeps catching the eye. The
   swing itself is about a third of that; the rest is the bell hanging still. */
.bell.on svg{animation:bell-shake 2s ease-in-out infinite;
  transform-origin:50% 20%}
@keyframes bell-shake{
  0%,72%{transform:rotate(0)}
  76%{transform:rotate(12deg)}
  80%{transform:rotate(-10deg)}
  84%{transform:rotate(8deg)}
  88%{transform:rotate(-5deg)}
  92%{transform:rotate(3deg)}
  96%,100%{transform:rotate(0)}
}
.bell-count{position:absolute;top:-3px;right:-3px;min-width:16px;height:16px;
  padding:0 4px;border-radius:99px;background:var(--red);color:#fff;
  font-family:var(--cond);font-size:10px;font-weight:700;line-height:16px;
  text-align:center;box-sizing:border-box;
  /* The count breathes on its own beat, so the two never quite line up and
     the corner always has something moving in it. */
  animation:bell-count-pulse 1.6s ease-in-out infinite}
@keyframes bell-count-pulse{
  0%,100%{transform:scale(1);box-shadow:0 0 0 0 rgba(226,87,76,.55)}
  45%{transform:scale(1.16);box-shadow:0 0 0 5px rgba(226,87,76,0)}
  70%{transform:scale(1);box-shadow:0 0 0 0 rgba(226,87,76,0)}
}
@media (prefers-reduced-motion:reduce){
  .bell.on svg,.bell-count{animation:none}
}

.note-row{display:flex;flex-direction:column;gap:7px;width:100%;padding:12px;
  margin-bottom:8px;background:var(--slate-2);border:1px solid var(--line);
  border-radius:10px;color:inherit;font:inherit;text-align:left;cursor:pointer;
  transition:transform .1s,border-color .1s}
.note-row:hover{border-color:var(--pink)}
.note-row:active{transform:translateY(2px)}
/* News about an offer of your own, rather than one waiting on an answer:
   marked down the edge so the two kinds don't have to be read to be told
   apart — green for a trade that went through, muted for one that didn't. */
/* What an offer would do to both rosters, inside the accept card. */
.offer-tally{margin-top:12px;padding:11px 12px;background:var(--slate-2);
  border:1px solid var(--line);border-radius:10px}
.tally-head{font-family:var(--cond);font-size:10px;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;color:var(--muted);
  margin-bottom:8px}
.tally-row{display:flex;align-items:baseline;flex-wrap:wrap;gap:4px 10px;
  padding:5px 0}
.tally-row + .tally-row{border-top:1px solid #2a3441}
.tally-who{flex:1 1 100%;font-size:13px;font-weight:600}
.tally-fig{display:inline-flex;align-items:baseline;gap:4px;
  font-family:var(--cond);font-size:13px;color:var(--muted)}
/* The figure it's leaving behind, struck through and stepped back. */
.tally-fig s{color:#5c6878;text-decoration-thickness:1px}
.tally-fig i{font-style:normal;color:#5c6878}
.tally-fig b{font-size:15px;font-weight:700}
.tally-wait{font-family:var(--cond);font-size:13px;color:#3d4858;
  letter-spacing:.3em}

.note-row.note-out{border-left-width:3px}
.note-row.note-out.done{border-left-color:var(--green)}
.note-row.note-out.no{border-left-color:#4a5666}
.note-row.note-out .note-kind{color:var(--muted)}
.note-row.note-out.done .note-kind{color:var(--green)}
.note-row.note-out:hover{border-color:var(--line)}
.note-row.note-out.done:hover{border-left-color:var(--green)}
.note-kind{font-family:var(--cond);font-size:10.5px;font-weight:700;
  letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
.note-who{display:flex;align-items:center;gap:9px}
.note-who b{font-size:15px}
.note-face{flex:0 0 auto;width:30px;height:30px;border-radius:50%;
  overflow:hidden;background:var(--slate);display:flex;align-items:center;
  justify-content:center}
.note-face img{width:100%;height:100%;object-fit:cover;object-position:top center}
.note-face .me-initials{font-size:10px}

/* Accept on the left, counter and decline together on the right. */
.foot-offer{justify-content:space-between}
.foot-right{display:flex;gap:9px}

/* ── trades ───────────────────────────────────────────────────────────
   History, and the two-column builder behind it. */
.tradepage{max-width:620px;margin:0 auto;padding:16px 16px 40px}
.tradebar{display:flex;align-items:center;justify-content:space-between;
  gap:12px;margin-bottom:16px}
/* The propose button floats, so it's there whichever view is showing. */
.fab-trade{position:fixed;right:16px;z-index:60;
  bottom:calc(16px + var(--sab,0px));
  width:46px;height:46px;padding:0;border-radius:50%;
  border:1px solid #2b3542;background:var(--slate);
  display:flex;align-items:center;justify-content:center;
  cursor:pointer;box-shadow:0 10px 26px #0009;
  -webkit-tap-highlight-color:transparent;transition:transform .12s}
.fab-trade svg{width:24px;height:24px;display:block}
.fab-trade:hover{border-color:#3a4756}
.fab-trade:active{transform:translateY(2px)}
/* Room to scroll past it. */
.tradepage{padding-bottom:96px}
/* Centred, and only as wide as the three labels need. */
.segwrap{display:flex;flex-direction:column;align-items:center;gap:8px;
  margin:0 0 20px}
.tradeseg{flex:0 0 auto}
/* Clear of the toggle above it. */
.histbar{margin-top:6px}
.tradecount{font-family:var(--cond);font-size:12.5px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}
.tradelist{display:flex;flex-direction:column;gap:10px}
/* Offers and Block share a first line, so switching between them doesn't
   move the text around. */
.tradelist > .empty,.blocklist > .empty{margin:0;padding:18px 0 0;
  text-align:center;font-size:14px;line-height:1.4}
/* The block list has a gap above its first child; the offers list doesn't,
   so without this the two sit a line apart. */
.blocklist{gap:5px}
.blocklist > .empty:first-child{padding-top:18px}
.trade{padding:13px;background:var(--slate);border:1px solid var(--line);
  border-radius:11px}
.trade.undone{opacity:.55}
.trade-head{display:flex;align-items:baseline;justify-content:space-between;
  gap:8px;margin-bottom:9px}
.trade-when{font-family:var(--cond);font-size:11px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted)}
.trade-undone{font-family:var(--cond);font-size:10px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase;color:var(--red);
  border:1px solid var(--red);border-radius:99px;padding:2px 8px}
.trade-body{display:flex;align-items:flex-start;gap:10px}
/* Each side is headed by the team's photo and name, then what they sent. */
.trade-team{display:flex;align-items:center;gap:7px;padding-bottom:7px;
  margin-bottom:7px;border-bottom:1px solid var(--line)}
.trade-team b{font-size:13.5px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.trade-face{flex:0 0 auto;width:26px;height:26px;border-radius:50%;
  overflow:hidden;background:var(--slate-2);display:flex;align-items:center;
  justify-content:center}
.trade-face img{width:100%;height:100%;object-fit:cover;object-position:top center}
.trade-face .me-initials{font-size:9px}
.trade-asset-mid{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.trade-asset-mid .tb-item-sub{gap:3px;font-size:9px}
.trade-asset-mid .tb-item-sub span{font-size:9px}
.trade-asset-mid .tb-teamlogo{width:12px;height:12px}
.trade-asset-mid b{font-size:12.5px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
/* This year's class, marked simply RFA. */
.tb-rfa{color:var(--gold);font-weight:700}
.tb-item-mid .tb-rfa,.trade-asset-mid .tb-rfa{color:var(--gold)}
.confirm-side{margin-top:12px;padding:11px 12px;background:var(--slate-2);
  border-radius:9px;display:flex;flex-direction:column;gap:6px}
.confirm-side > b{font-family:var(--cond);font-size:11px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted)}
/* Where that side's roster lands once the trade goes through. */
/* Where they stand and where this leaves them, worded exactly as the
   builder words it — same labels, same colours, same order. */
.confirm-caps{margin-top:2px;padding-top:9px;
  border-top:1px solid var(--line);display:flex;flex-direction:column;
  gap:2px;align-items:flex-start;
  font-family:var(--cond);font-size:12px;letter-spacing:.04em;
  color:var(--muted)}
/* The cards sit on the card's own background here. */
.confirm-side .tb-item{background:var(--slate);cursor:default}
.notice-line{margin:0;font-size:13.5px;line-height:1.5}
.notice-line b{color:var(--red)}
.trade-side{flex:1;min-width:0;display:flex;flex-direction:column;gap:5px}
.trade-side > b{font-size:14px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.trade-swap{flex:0 0 auto;align-self:center;color:#4a5666;display:flex}
.trade-swap svg{width:22px;height:22px;display:block}
.trade-asset{display:flex;align-items:center;gap:6px;font-size:12.5px;
  min-width:0}
.trade-asset > span:nth-child(2){overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.trade-none{font-family:var(--cond);font-size:12px;color:var(--muted)}
.trade-sal{flex:0 0 auto;font-family:var(--cond);font-weight:700;
  color:var(--money)}
.trade-kind{flex:0 0 auto;font-family:var(--cond);font-size:9px;font-weight:700;
  letter-spacing:.1em;padding:2px 5px;border-radius:4px;color:#12161c}
.kind-pick{background:var(--gold)}
.kind-rfa{background:var(--blue)}
.kind-player{background:var(--muted)}
/* A player's chip carries the position in that position's own colour. */
.trade-pos{flex:0 0 auto;width:var(--badge-w,30px);height:var(--badge-h,34px);
  display:flex;align-items:center;justify-content:center;
  font-family:var(--cond);font-size:11px;font-weight:700;letter-spacing:.08em;
  padding:0;border-radius:6px;color:#fff;background:var(--muted)}
.trade-pos.pos-QB{background:var(--pos-qb)}
.trade-pos.pos-RB{background:var(--pos-rb)}
.trade-pos.pos-WR{background:var(--pos-wr)}
.trade-pos.pos-TE{background:var(--pos-te)}

/* Picks carry the same numbered badge the draft board uses. */
.trade-pick{flex:0 0 auto;width:var(--badge-w,30px);height:var(--badge-h,34px);
  display:flex;align-items:center;justify-content:center;padding:0;
  border-radius:6px;font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.04em;color:#12161c;background:var(--muted)}
.trade-pick.r1{background:linear-gradient(160deg,#ffd23f,#e0a020)}
.trade-pick.r2{background:linear-gradient(160deg,#e8edf3,#aab6c4)}
.trade-pick.r3{background:linear-gradient(160deg,#d9a273,#b07b4c)}
.trade-pick.r4{background:var(--orange)}
.trade-pick.future{background:var(--slate-2);color:var(--text);
  border:1px solid var(--line);font-size:10px;letter-spacing:0}
.trade-pick.future.r1{background:var(--slate-2);border-color:#e0a020;
  color:#ffd23f}
.trade-pick.future.r2{background:var(--slate-2);border-color:#aab6c4;
  color:#e8edf3}
.trade-pick.future.r3{background:var(--slate-2);border-color:#b07b4c;
  color:#d9a273}
.trade-pick.future.r4{background:var(--slate-2);border-color:var(--orange);
  color:var(--orange)}

/* An RFA still reads as a player; this says which. */
.trade-note{margin:9px 0 0;font-size:12.5px;color:var(--muted)}
.trade .btn{margin-top:10px}

/* the builder */
/* These pages have no --chrome-h, so pin the sheet below the header
   rather than behind it. */
.tradepage ~ .sheet,
body:has(.tradepage) .sheet{top:var(--bar-h,53px);
  height:calc(100dvh - var(--bar-h,53px))}
body:has(.tradepage) .sheet-card{max-height:100%}
#builder .sheet-card{height:100%}
/* The body is the flexing part; the lists inside it take what's left after
   the note and the summary, so the card itself never scrolls. */
#builder .sheet-body{display:flex;flex-direction:column;min-height:0;
  overflow:hidden}
#builder .tb-note,#builder .tb-summary{flex:0 0 auto}
/* The close control sits in the card's own header, so it can't be covered. */
#builder .sheet-head{position:sticky;top:0;z-index:3;background:var(--slate)}
.tb-team{flex:1;min-width:0}
/* Each side scrolls on its own, so a long roster doesn't drag the other
   column — or the header — along with it. */
.tb-cols{display:grid;grid-template-columns:1fr 1fr;
  grid-template-rows:auto auto minmax(0,1fr);
  column-gap:10px;row-gap:0;flex:1;min-height:0}
/* Each list keeps its own fade, showing there's more below. */
.tb-listwrap{position:relative;min-width:0;min-height:0;display:flex}
.tb-listwrap::after{content:"";position:absolute;left:0;right:8px;bottom:0;
  height:22px;pointer-events:none;opacity:0;transition:opacity .15s;
  background:linear-gradient(180deg,transparent,var(--slate))}
.tb-listwrap.more::after{opacity:1}
/* No panel behind it: the team picker and its cap line sit straight on the
   card, which is one less box in a window that already has plenty. */
.tb-colhead{align-self:stretch;display:grid;
  grid-template-rows:38px auto;align-content:start;gap:7px;
  min-height:0;padding:0 0 8px;background:none;border-bottom:0}
/* The owner's photo beside their picker. */
.tb-team{display:flex;align-items:center;gap:8px;min-width:0}
.tb-team-face{flex:0 0 auto;width:34px;height:34px;border-radius:50%;
  overflow:hidden;background:var(--slate-2);display:flex;align-items:center;
  justify-content:center}
.tb-team-face img{width:100%;height:100%;object-fit:cover;
  object-position:top center}
.tb-team-face .me-initials{font-size:12px}
.tb-team .tb-pick{flex:1;min-width:0}
.tb-colhead > *{min-width:0;align-self:center}
/* Left, with the picker above it. */
.tb-colhead .tb-cap{justify-content:flex-start}
.tb-colhead > span{text-align:left}
.tb-colhead > span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* The team is chosen on its own column rather than from a row above. */
.tb-pick{width:100%;background:var(--slate-2);border:1px solid var(--line);
  border-radius:7px;padding:6px 7px;font-family:var(--ui);font-size:13px;
  font-weight:600;color:var(--text)}
.tb-pick:focus{outline:none;border-color:var(--teal)}
/* Your own side: shown, but not yours to change. */
/* Your own side: the same control, simply not changeable. The events are
   blocked in script — styling it differently moves it. */
.tb-pick.fixed-side{background:var(--slate);border-color:#2b3542;
  color:var(--text);cursor:default}
.tb-pick{box-sizing:border-box;height:34px;align-self:start;
  line-height:1.1}
/* The two numbers a trade turns on — what this team is at, and how many
   bodies they'd have — with what this trade does to each beside it.
   Left-aligned: they're read left to right as a sentence, and centring put
   the figure that matters in a different place on each column. */
/* Two labelled blocks: where they are, and where this would leave them.
   One font size throughout and nothing bold — the colour carries the
   meaning, and a column of mixed weights reads as emphasis nobody asked
   for. */
.tb-cap{display:flex;flex-direction:column;align-items:flex-start;gap:2px;
  font-family:var(--cond);font-size:12px;letter-spacing:.04em;
  color:var(--muted);min-width:0}
.cap-label{font-size:9.5px;font-weight:700;letter-spacing:.16em;
  text-transform:uppercase;color:var(--muted);opacity:.75}
.cap-label + .cap-line{margin-bottom:5px}
.cap-line{display:flex;align-items:baseline;flex-wrap:wrap;gap:4px;
  min-width:0;color:var(--text);font-variant-numeric:tabular-nums}
.cap-line .cap-dot{opacity:.5}
/* Down is good, up costs. Salary and bodies both. */
.cap-down{color:var(--money)}
.cap-up{color:var(--red)}
/* Past the cap, or past the hard cap. */
.tb-cap.tight .cap-line:last-child{color:var(--gold)}
.tb-cap.over .cap-line:last-child{color:var(--red)}
/* Inside the cap, over it, or past the hard cap. */
.cap-ok{color:var(--money)}
.cap-warn{color:var(--gold)}
.cap-over{color:var(--red)}
.count-over{color:var(--red);font-weight:700}
.tb-colhead > span{font-family:var(--cond);font-size:10.5px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted)}
.tb-list{flex:1;min-height:0;overflow-y:auto;display:flex;
  flex-direction:column;gap:5px;padding-right:6px;
  scrollbar-color:var(--red) transparent}
.tb-list::-webkit-scrollbar{width:8px}
.tb-list::-webkit-scrollbar-track{background:transparent}
.tb-list::-webkit-scrollbar-thumb{background:var(--red);border-radius:6px}
.tb-list::-webkit-scrollbar-thumb:hover{background:#ef6a5f}
/* A rule between sections: players, this year's picks, then each future year. */
.tb-group{margin:9px 0 2px;padding-bottom:4px;border-bottom:1px solid var(--line);
  font-family:var(--cond);font-size:10px;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted)}
.tb-group:first-child{margin-top:0}
.tb-item{display:flex;align-items:center;gap:6px;width:100%;padding:7px 6px;
  background:var(--slate-2);border:1px solid transparent;border-radius:8px;
  color:inherit;font:inherit;text-align:left;cursor:pointer;
  -webkit-tap-highlight-color:transparent;transition:transform .1s,border-color .1s}
.tb-item:active{transform:translateY(2px)}
.tb-item.on{border-color:var(--green);background:#14301f}
.tb-item-mid{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px;
  height:34px;justify-content:center}
.tb-item-mid b{font-size:12.5px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.tb-item-mid span{font-family:var(--cond);font-size:9.5px;letter-spacing:.04em;
  text-transform:uppercase;color:var(--muted)}
.tb-item-sub{display:flex;align-items:center;gap:2px;min-width:0;
  overflow:hidden;white-space:nowrap}
/* The headshot stands where the position chip used to. */
.tb-face{flex:0 0 auto;width:var(--badge-w,30px);height:var(--badge-h,34px);
  border-radius:6px;overflow:hidden;background:var(--slate);display:flex;
  align-items:flex-end;justify-content:center}
.tb-face img{width:100%;height:100%;object-fit:cover;object-position:top center}
.tb-face .me-initials{font-size:11px;align-self:center}
.tb-teamlogo{flex:0 0 auto;width:12px;height:12px;object-fit:contain}
/* The position keeps its own colour; everything else on the line is muted. */
.tb-pos.pos-QB{color:var(--pos-qb)}
.tb-pos.pos-RB{color:var(--pos-rb)}
.tb-pos.pos-WR{color:var(--pos-wr)}
.tb-pos.pos-TE{color:var(--pos-te)}
.tb-item-sub > span{flex:0 0 auto}
.tb-item-sub > span:first-child{flex:0 1 auto;min-width:0;overflow:hidden;
  text-overflow:ellipsis}
.tb-item-sal{flex:0 0 auto;height:34px;display:flex;align-items:center;
  font-family:var(--cond);font-size:14px;font-weight:700;color:var(--money)}
.tb-note{margin-top:16px;display:block}
.tb-summary{grid-column:1 / -1;margin:10px 0 12px;padding:9px 12px;
  background:var(--slate-2);border-radius:9px;font-size:13px;
  color:var(--muted)}
.tb-summary p{margin:0 0 3px;font-size:12.5px}
.tb-summary p:last-child{margin-bottom:0}
/* flex:0 0 auto, like the head above it. Without it the foot can be
   squeezed by a long body — and the foot is where Propose Trade lives, so
   squeezing it is the same as losing it. */
.sheet-foot{flex:0 0 auto;display:flex;align-items:center;
  padding:14px 16px calc(14px + var(--sab,0px));
  border-top:1px solid var(--line)}
.sheet-foot .btn{width:100%}
.sheet-foot .btn:active:not(:disabled){transform:translateY(2px)}
#doTrade{transition:background .12s,box-shadow .09s,transform .09s,filter .12s}
#doTrade{background:var(--red);border-color:var(--red);color:#fff}
#doTrade:disabled{opacity:.45}

@media (min-width:1081px){
  /* The panel follows the card. Trade rows carry two teams' worth of
     assets side by side, so width is the thing they were short of. */
  .tradepage{max-width:1040px;padding-top:26px}
  /* Wider than it was: two asset lists and a running summary is three
     columns of content, and 1000px left all three cramped. */
  #builder .sheet-card{width:min(1320px,95vw)}
}

/* ── rookie draft order ───────────────────────────────────────────────
   Four rounds. One column on a phone, four across on a desktop. */
.draftpage{max-width:620px;margin:0 auto;padding:16px 16px 40px}
.draftbar{display:flex;align-items:center;justify-content:space-between;
  gap:12px;margin-bottom:16px;flex-wrap:wrap}
.draftbar .field{flex:1;min-width:180px}
.draftcount{flex:0 0 auto;min-width:82px;text-align:left;
  font-family:var(--cond);font-size:12.5px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}
.draftboard{display:flex;flex-direction:column;gap:18px}
.dround{display:flex;flex-direction:column;gap:6px;break-inside:avoid}
.dround.empty-round .dround-head{opacity:.55}
.dround-head{display:flex;align-items:baseline;justify-content:space-between;
  gap:8px;padding:0 2px 5px;border-bottom:1px solid var(--line)}
.dround-head b{font-family:var(--display);font-size:16px}
/* A team's owed picks, headed by whose they are. */
.dfuture-who{display:flex;align-items:center;gap:8px;min-width:0}
.dfuture-who b{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dround-head span{font-family:var(--cond);font-size:11px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted)}
.dround-list{display:flex;flex-direction:column;gap:5px}
.dnone{margin:8px 0;text-align:center;font-family:var(--cond);font-size:15px;
  color:#3b4756}
.dpick{display:flex;align-items:center;gap:10px;padding:7px 10px;
  background:var(--slate);border:1px solid var(--line);border-radius:9px;
  min-height:48px;box-sizing:border-box}
.dpick.mine{border-color:var(--gold)}
.draftboard.one-team .dpick.mine{border-color:var(--line)}
.dpick-no{flex:0 0 auto;min-width:40px;text-align:center;padding:3px 7px;
  border-radius:6px;font-family:var(--cond);font-size:13px;font-weight:700;
  color:#12161c;background:var(--muted)}
.dpick-no.r1{background:linear-gradient(160deg,#ffd23f,#e0a020)}
.dpick-no.r2{background:linear-gradient(160deg,#e8edf3,#aab6c4)}
.dpick-no.r3{background:linear-gradient(160deg,#d9a273,#b07b4c)}
.dpick-no.r4{background:var(--orange)}
.dpick-who{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.dpick-who b{font-size:14px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.dpick-from{font-family:var(--cond);font-size:10px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--gold)}
.dpick-face{flex:0 0 auto;width:28px;height:28px;border-radius:50%;
  overflow:hidden;background:var(--slate-2);display:flex;align-items:center;
  justify-content:center}
.dpick-face img{width:100%;height:100%;object-fit:cover;object-position:top center}
.dpick-face .me-initials{font-size:10px}

@media (min-width:1081px){
  .draftpage{max-width:1400px;padding-top:26px}
  .draftboard{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
    gap:18px;align-items:start}
}
@media (min-width:700px) and (max-width:1080px){
  .draftboard{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
    gap:18px;align-items:start}
}

/* ── rosters page ─────────────────────────────────────────────────────
   The same data the auction shows, on its own page. */
/* The mark and league name are a link home on every page; the page's own
   name sits beside it rather than replacing it. */
a.brand{text-decoration:none;color:inherit;flex:0 0 auto;
  transition:opacity .1s}
a.brand:hover{opacity:.82}
a.brand:active{opacity:.65}
.rosterpage{max-width:620px;margin:0 auto;padding:16px 16px 40px}
.rosterpick{display:flex;align-items:center;gap:12px;margin-bottom:16px;
  flex-wrap:wrap}
/* Allowed to shrink: on a row that no longer wraps, this is what should
   give way, and the name inside it already ellipsises. */
.teampick{display:flex;align-items:center;gap:9px;padding:6px 12px 6px 6px;
  min-width:0;flex:0 1 auto;
  background:var(--slate);border:1px solid var(--line);border-radius:99px;
  color:inherit;font:inherit;cursor:pointer;transition:border-color .1s}
.teampick:hover{border-color:var(--gold)}
.teampick:active{transform:translateY(2px)}
.teampick-face{width:30px;height:30px;border-radius:50%;overflow:hidden;
  background:var(--slate-2);display:flex;align-items:center;
  justify-content:center;flex:0 0 auto}
.teampick-face img{width:100%;height:100%;object-fit:cover;
  object-position:top center}
.teampick-face .me-initials{font-size:10px}
.teampick-name{font-size:15px;font-weight:600}
.teampick-caret{color:var(--muted);font-size:11px}

.pc-top{display:flex;align-items:center;gap:12px;padding-bottom:14px;
  border-bottom:1px solid var(--line)}
.pc-top .rrow-face{width:52px;height:56px;border-radius:9px}
.pc-who{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}
.pc-who b{font-family:var(--display);font-size:18px}
.pc-cost{display:flex;flex-direction:column;align-items:flex-end;gap:2px}
.pc-cost b{font-family:var(--cond);font-size:20px;color:var(--money)}
.pc-facts,.pc-stats{display:grid;
  grid-template-columns:repeat(auto-fit,minmax(70px,1fr));gap:8px;
  margin-top:12px}
.pc-fact,.pc-stat{padding:9px 6px;background:var(--slate-2);border-radius:8px;
  text-align:center;display:flex;flex-direction:column;gap:2px}
.pc-fact b,.pc-stat b{font-family:var(--cond);font-size:16px}
.pc-fact span,.pc-stat span{font-family:var(--cond);font-size:9.5px;
  letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.pc-head{margin:16px 0 0;font-family:var(--cond);font-size:10.5px;
  font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted)}

.rosterpick .field{flex:1;min-width:180px}
/* Under the team: money on one line, counts on the next. */
.rostercap{display:flex;flex-direction:column;gap:2px;
  font-family:var(--cond);font-size:12.5px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}
.rostercap b{color:var(--text)}
.rc-money,.rc-counts{white-space:nowrap}
/* Both figures on the money line read as money, at the same size. */
.rc-money b{color:var(--money);font-size:15px;font-weight:700;
  font-variant-numeric:tabular-nums}
/* Except the penalty, which is money you no longer have. */
/* Not scoped to .rc-money: the RFA page's roster card shows the same
   penalty without that wrapper. */
.rc-money b.rc-pen,b.rc-pen{color:var(--red)}
.rc-counts b{font-size:13.5px;font-weight:700;
  font-variant-numeric:tabular-nums}
.rosterbody{display:flex;flex-direction:column;gap:16px}
.rgroup{display:flex;flex-direction:column;gap:5px}
.rgroup-head{display:flex;align-items:center;gap:8px;padding:0 2px 4px;
  border-bottom:1px solid var(--line)}
.rgroup-head b{font-family:var(--cond);font-size:12px;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:var(--teal)}
.rgroup-head span{font-family:var(--cond);font-size:11px;color:var(--muted)}
/* Wraps, so the drawer below can take a line of its own rather than
   squeezing in beside the name. */
.rrow{display:flex;align-items:center;gap:10px;row-gap:0;padding:8px 10px;
  background:var(--slate);border:1px solid var(--line);border-radius:9px;
  flex-wrap:wrap}

/* The chevron that opens it. */
.rrow-more{flex:0 0 auto;width:22px;height:22px;padding:0;margin-left:0;
  border:1px solid var(--line);border-radius:6px;background:var(--slate-2);
  color:var(--muted);cursor:pointer;display:flex;align-items:center;
  justify-content:center}
.rrow-more i{font-style:normal;font-size:8px;line-height:1;
  transition:transform .15s ease}
.rrow-more i::before{content:"\25bc"}
.rrow-more.on{color:var(--text);border-color:#3a4756}
.rrow-more.on i{transform:rotate(180deg)}

/* The drawer. Closed by default; the row carries the state so a list of
   them can't get out of step with their buttons. Two rows: the week
   ahead, then the season. */
/* Opens and closes on a grid row rather than on display, which cannot be
   animated. The child needs min-height:0 or it refuses to be squashed. */
/* Closed, it must take no height at all — the row is a wrapping flex
   line, so a drawer with even a 1px border is a second line of it, and
   that is the gap that appeared under every lineup card. The rule is
   drawn with a box-shadow when open instead, which costs no layout. */
.rrow-drawer{flex-basis:100%;display:grid;grid-template-rows:0fr;
  transition:grid-template-rows .22s cubic-bezier(.22,.7,.3,1),
    margin-top .22s ease,padding-top .22s ease,opacity .16s ease;
  margin-top:0;padding-top:0;opacity:0;
  font-size:0;line-height:0}
.rrow-drawer > *{min-height:0;overflow:hidden}
/* The two blocks, stacked — the layout the drawer itself used to carry
   before it became a collapsing grid. */
.rrow-drawerin{display:flex;flex-direction:column;gap:10px;
  /* Room under the season boxes, so an open drawer doesn't sit against
     the next card. */
  padding-bottom:4px}

/* Nobody has projected him. Said plainly rather than left as an arrow
   that opens onto nothing. */
.rrow-noproj{margin:0;padding:6px 0 2px;text-align:center;
  font-family:var(--cond);font-size:10px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted)}
.rrow.expanded > .rrow-drawer,
.rr.expanded > .rrow-drawer,
.rlist-row.expanded > .rrow-drawer,
.farow.expanded + .rrow-drawer{grid-template-rows:1fr;
  margin-top:8px;padding-top:9px;opacity:1;
  font-size:inherit;line-height:normal;
  box-shadow:inset 0 1px 0 var(--line)}
/* The condensed row is a flex line, so it has to wrap for the drawer to
   take a line of its own beneath it. */
.rlist-row{flex-wrap:wrap}
.rlist-row > .rrow-drawer{flex-basis:100%}

/* Both rows are boxed cells rather than figures floating on a gap. A
   line of numbers with only whitespace between them takes reading; a
   grid of small boxes is taken in at a glance. */
/* One line, always. auto-fit with a minimum width wrapped as soon as the
   cells didn't fit, which put a four-cell row onto two lines and made the
   drawer twice as tall as it needed to be. Equal columns that shrink
   together keep it to one. */
.rrow-week{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;gap:5px}
.rrow-fact{display:flex;flex-direction:column;gap:2px;padding:7px 8px;
  border-radius:7px;background:#131a26;border:1px solid #1e2735;
  min-width:0;overflow:hidden}
/* No longer spans two: with a single row, a wide cell would squeeze the
   rest rather than take a line of its own. */
.rrow-fact.wide{min-width:0}
.rrow-fact b{font-family:var(--cond);font-size:14px;font-weight:700;
  color:var(--text);font-variant-numeric:tabular-nums}
.rrow-fact b,.rrow-fact span{white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis}
.rrow-fact span{font-family:var(--cond);font-size:8px;font-weight:700;
  letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}

/* Both blocks read the same: a small heading, then a line of cells. */
.rrow-block{display:flex;flex-direction:column}
.rrow-season{padding-top:9px;border-top:1px solid #1e2735}
/* Used by both blocks now, so the name says what it is rather than
   which one first needed it. */
.rrow-blockhead{margin-bottom:7px;font-family:var(--cond);
  font-size:9px;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted)}
.rrow-statline{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;
  gap:5px}
.rrow-stat{display:flex;flex-direction:column;gap:1px;padding:7px 8px;
  border-radius:7px;background:#131a26;border:1px solid #1e2735;
  min-width:0;overflow:hidden}
/* The rank leads both tables, in the blue the app uses for a ranking
   everywhere else. */
.rrow-stat.rank b,.rrow-fact.rank b{color:var(--blue)}
.rrow-stat b{font-family:var(--cond);font-size:13.5px;font-weight:700;
  color:var(--text);font-variant-numeric:tabular-nums}
.rrow-stat b,.rrow-stat span{white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis}
.rrow-stat span{font-family:var(--cond);font-size:8px;font-weight:600;
  letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}

/* The class marking, over the foot of the photograph. */
/* The same treatment the UFA grid gives NEXT and NOMIN': a glass pill
   riding the foot of the photograph, half over it and half below. */
/* The photograph is what's positioned absolutely here, filling the face;
   the pill is an ordinary flex child sitting at the bottom of it. That is
   the other way round from the usual arrangement, and it is deliberate:
   an absolutely positioned pill depends on an ancestor being positioned,
   and when that fails it drifts somewhere else entirely. A flow-laid
   child cannot land outside its parent. */

/* The lineup's rows wrap too, so their drawer has a line of its own. */
/* Wraps so the drawer can take a line under the row. row-gap:0 because
   the flex gap applies between those two lines as well as between the
   items on the first — with 10px there, a closed drawer still pushed the
   card 10px taller than it needed to be. The drawer supplies its own
   spacing when it opens. */
.rr{flex-wrap:wrap;row-gap:0}
.rr .rrow-more{margin-left:0;margin-right:2px}

/* The bye, ahead of the club badge, in the line's own grey. */
.rrow-bye{font-family:var(--cond);font-size:10px;font-weight:700;
  letter-spacing:.08em;color:var(--muted)}
/* No border. The word under the name carries it, as with ROOKIE and UFA —
   an outline on every row turned the card into a set of boxes. */
/* No outline. The tag mark under the name says it — a red edge on the
   row said the same thing again, and read as though the row were
   selected rather than as a fact about the player. This is the roster
   card's own class; the lineup's was .rr.state-tagged, which is why
   removing that one left this one behind. */
.rrow-tag{display:inline-flex;align-items:center;gap:4px;color:var(--red);
  font-weight:700}
.rrow-tag svg{width:12px;height:12px;flex:0 0 auto}
/* position:relative for the class pill, which sits over the foot of it.
   overflow stays visible so the pill isn't clipped; the photograph inside
   is what gets the rounding and the clipping now. */
/* position:relative is what the class pill anchors to. It is stated
   again here rather than relied on from elsewhere — without it the pill
   positions against whatever ancestor happens to be positioned, which
   put it low and to the right of the man it belongs to. */
/* No overflow:hidden. That was clipping the class pill — the UFA grid's
   tiles round the image itself and leave the container open, which is why
   their NEXT and NOMIN' badges sit over the photograph rather than being
   cut off by it. */
/* No overflow:hidden on the frame — that is what clipped the pill, which
   is wider than the 34px photograph it sits on. The picture rounds and
   clips itself instead, exactly as the UFA grid's tiles do. */
.rrow-face{position:relative;flex:0 0 auto;width:34px;height:36px;
  border-radius:7px;background:var(--slate-2);display:flex;
  align-items:flex-end;justify-content:center}
.rrow-face > img{position:absolute;inset:0;width:100%;height:100%;
  border-radius:7px;object-fit:cover;object-position:top center}
.rrow-face > .me-initials{position:absolute;inset:0;display:flex;
  align-items:center;justify-content:center;border-radius:7px}
/* Sizing and framing are set on the rule above; only the type size for
   the initials fallback belongs here. */
.rrow-face .me-initials{font-size:11px}
/* The gap does the spacing; the badge and the mark set no margins of
   their own inside here, or the two are added together. */
.rrow-name{display:flex;align-items:center;gap:4px;min-width:0}
.rrow-name .instat,.rr-name .instat{margin-right:0}
.rrow-name .newsmark,.rr-name .newsmark{margin-left:0}
/* A size down: the line carries a designation badge and an info button
   beside the name now, and at the old size a long one ran out of room. */
.rrow-name b{font-size:13.5px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.rrow-info{flex:0 0 auto;width:16px;height:16px;border-radius:50%;padding:0;
  background:var(--slate-2);border:1px solid var(--line);color:var(--muted);
  font-family:var(--display);font-size:10px;line-height:1;cursor:pointer;
  transition:color .1s,border-color .1s}
.rrow-info:hover{color:var(--teal);border-color:var(--teal)}
.rrow-info:active{transform:translateY(2px)}
.rrow-info{transition:transform .12s,color .1s,border-color .1s}
.rrow-sub{display:flex;align-items:center;gap:5px;min-width:0;
  font-family:var(--cond);font-size:10.5px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted);white-space:nowrap;
  overflow:hidden}
.rrow-teamlogo{flex:0 0 auto;width:13px;height:13px;object-fit:contain}
/* The same face and size as ROOKIE and UFA, which this didn't have — it
   set only a colour, so it inherited whatever the row was using. */
/* The contract on a roster row: the year he next reaches restricted free
   agency in gold, or VET in grey once he is past it. */
.rrow-rfa{font-family:var(--cond);font-size:10.5px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase;color:var(--gold)}
.rrow-vet{font-family:var(--cond);font-size:10.5px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.rrow-right .rrow-rank,.pc-cost .rrow-rank{color:var(--blue);font-weight:700;
  font-size:9.5px}
.cap-power{color:var(--money)}
.rrow-mid{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.rrow-mid b{font-size:14px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.rrow-mid > .rrow-sub{font-family:var(--cond);font-size:11px;
  letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
.rrow-name{text-transform:none}
.rrow-name b{font-family:var(--ui);font-size:14px;font-weight:500}
.rrow-right{flex:0 0 auto;display:flex;flex-direction:column;align-items:flex-end;
  gap:1px}
/* A size down on both figures. They sit in a fixed column at the end of
   the row, and every pixel they take is one the name doesn't get. */
.rrow-sal{font-family:var(--cond);font-size:13.5px;font-weight:700;
  color:var(--money)}
.rrow-right span{font-family:var(--cond);font-size:9.5px;color:var(--muted)}

@media (min-width:1081px){ .rosterpage{max-width:760px;padding-top:26px} }

/* ── league home ──────────────────────────────────────────────────────
   A menu, not a tool: what's running, whose roster, and the draft order. */
.home{max-width:620px;margin:0 auto;padding:16px 16px 20px;
  display:flex;flex-direction:column;gap:18px;
  /* One screen, no scrolling: the team grid takes what's left. */
  /* The header, and the fixtures band that now sits under it. */
  height:calc(100dvh - var(--bar-h,53px) - var(--slate-h,0px));
  box-sizing:border-box}
/* The middle column carries what the phone layout carried: events stacked
   on top of the team grid, both the same width. The rails either side of it
   are desktop-only and don't exist below 1081px. */
/* min-width:0 for the same reason as the band below it: this is a flex
   item, and without it the column reports its widest child's content
   width — which is a full week of fixtures — instead of the screen. */
.home-mid{display:flex;flex-direction:column;gap:18px;flex:1;min-height:0}
/* Named hubrail, not rail: the auction app already owns .rail for its own
   sidecar, and a bare .rail rule here would reach across and hide it. */
.hubrail{display:none}
.home-block{margin-bottom:0;min-height:0;display:flex;flex-direction:column}
.home-block:last-child{flex:1;min-height:0}
.home-h{margin:0 0 10px;font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;color:var(--muted)}

/* Events */
.evlist{display:flex;flex-direction:column;gap:8px}
.evrow{display:flex;align-items:center;gap:12px;padding:14px;
  background:var(--slate);border:1px solid var(--line);border-radius:11px;
  color:var(--text);text-decoration:none;transition:transform .1s,border-color .1s}
a.evrow:hover{border-color:#3a4756}
a.evrow:active{transform:translateY(2px)}
.evrow.dormant{opacity:.5}
.evdot{flex:0 0 auto;width:9px;height:9px;border-radius:50%;background:#3b4756}
.evdot.on{background:var(--red)}
.evtext{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.evtext b{font-family:var(--display);font-size:17px}
.evtext span{font-family:var(--cond);font-size:11.5px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted);overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.evtag{flex:0 0 auto;font-family:var(--cond);font-size:10px;font-weight:700;
  letter-spacing:.12em;text-transform:uppercase;color:var(--muted);
  border:1px solid var(--line);border-radius:99px;padding:3px 9px}
.evtag.live{color:var(--red);border-color:#8f3a33}
/* Finished: green, and still: a stage that's over shouldn't be competing
   for attention with one that's running. */
.evtag.done{color:var(--money);border-color:#2f6b4c;animation:none}
.evdot.done{background:var(--money);animation:none}
/* Finished and closed: a div rather than a link, so it shouldn't look
   pressable either. Not dimmed — it's a result, not a disabled control. */
.evrow.shut{cursor:default}
.evrow.shut:hover{border-color:var(--line)}
.evrow.shut:active{transform:none}

/* Rosters */
/* Every row the same height. align-content:stretch shares out the leftover
   space evenly, but it shares it on top of each row's own content height —
   so a row holding a longer name, or a card with a badge on it, ends up
   taller than the rest. Fixed rows take content out of the question. */
.teamgrid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  grid-auto-rows:minmax(0,1fr);
  gap:8px;flex:1;min-height:0;align-content:stretch}

/* Twelve owners in four columns is three rows, and those rows stretch to
   fill whatever height the block is given — on a tall phone that made
   each tile far larger than it needs to be. Half the screen is the most
   it takes; the rows sit at the top of what is left.

   Phone only: the desktop layouts set their own rows and columns and are
   not affected. */
@media (max-width:1080px){
  /* Rows keep an even share of the capped height rather than collapsing
     to their contents — the tiles are sized by their grid row, not by
     what is inside them. */
  .teamgrid{max-height:50dvh;align-content:stretch}
  /* The rosters take half the screen outright — a basis, not a share, or
     two flexible siblings would split the column and the grid would come
     out shorter than the cap it was given. The grid sits at the foot of
     that half, where it has always been. */
  .home-block:last-child{flex:0 0 50dvh;justify-content:flex-end}
  /* And the panel takes everything above them. */
  .home-block:first-child{flex:1;min-height:0;
    padding:9px 0;justify-content:stretch}
}
.teamcard{position:relative;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:5px;min-height:0;
  padding:6px 4px;background:var(--slate);border:1px solid var(--line);
  border-radius:11px;color:var(--text);text-decoration:none;
  transition:transform .1s,border-color .1s}
/* The card sits deeper at the bottom than the top. A gradient rather than a
   blur, so it stays inside the card's own corners. */
#teams .teamcard::before{content:"";position:absolute;z-index:0;
  left:0;right:0;bottom:0;height:52%;border-radius:inherit;
  pointer-events:none;
  background:linear-gradient(to top,rgba(6,9,14,.62),rgba(6,9,14,0))}
#teams .teamcard > *{position:relative;z-index:1}
/* The reigning champion's circle is ringed in gold rather than the card. */
.teamcard.champ .teamface{box-shadow:0 0 0 2.5px var(--gold),
  0 0 12px rgba(242,176,30,.45);background:var(--gold)}
/* The white in these circles is baked into the JPEG, so CSS can only put
   gold behind it — which shows on the ring and on the initials, not through
   the photo. To recolour the photo's own white as well, uncomment this: it
   multiplies the picture into the gold, turning white to gold exactly at
   the cost of warming his face along with it.
.teamcard.champ .teamface img{mix-blend-mode:multiply}
*/
.teamcard:hover{border-color:#3a4756}
.teamcard:active{transform:translateY(2px)}
.teamcard.mine{border-color:var(--line)}
.teamface{position:relative;width:clamp(30px,7.2vh,44px);
  height:clamp(30px,7.2vh,44px);border-radius:50%;
  background:var(--slate-2);display:flex;align-items:center;
  justify-content:center;flex:0 0 auto}
.teamface img{width:100%;height:100%;object-fit:cover;object-position:top center;
  border-radius:50%}
/* The badges sit outside the circle, so the face never clips here — the
   photo rounds itself, so nothing needs the face to do the clipping. */
.teamface,.teamface.has-badge{overflow:visible}
.teambadge{position:absolute;right:-2px;bottom:-2px;line-height:1;
  pointer-events:none}
/* Which one is you: the same live dot the events carry, on its own beat. */
/* Green and breathing: this owner has asked the server for something in
   the last couple of minutes, so they're here. */
.teambadge.you{width:11px;height:11px;border-radius:50%;
  background:var(--green);border:2px solid var(--slate);box-sizing:border-box;
  animation:you-pulse 1.9s ease-in-out infinite}
@keyframes you-pulse{
  0%,100%{box-shadow:0 0 0 0 rgba(63,191,127,.5)}
  55%{box-shadow:0 0 0 5px rgba(63,191,127,0)}
  80%{box-shadow:0 0 0 0 rgba(63,191,127,0)}
}
/* When one team holds both, the dot steps aside. */
/* An original member: the brand's hammer in gold, bottom-left, opposite
   the dot so the two never meet. */
/* An original member: the mark set in a badge — white disc, red rim — so
   it reads as a pin on the photo rather than a hammer floating on it. */
/* A dark disc with a white hammer, so it reads as a pin cut out of the
   page rather than a light sticker laid on top of the photo. Smaller too —
   it marks a team, it isn't the subject. */
.teambadge.og{right:auto;left:0;bottom:0;width:11px;height:11px;
  border-radius:50%;background:var(--ink);border:1px solid var(--red);
  box-sizing:border-box;display:flex;align-items:center;
  justify-content:center;line-height:0;
  filter:drop-shadow(0 1px 2px #000a)}
/* Inset, so the hammer doesn't touch the rim. A whole-pixel rim and a
   square box keep the circle a circle — fractional borders round unevenly
   on some screens, which reads as a wonky outline. */
.teambadge.og svg{width:80%;height:80%;display:block;flex:0 0 auto}

/* ── championships ────────────────────────────────────────────────────
   One star a title, arched over the top of the circle. Each star is a full
   overlay rotated about the face's own centre, so it lands on the circle's
   edge and tilts with it — which is what makes the row read as an arc
   rather than a straight line of stars. The reigning champion's newest one
   is gold. */
.crowns{position:absolute;inset:0;pointer-events:none;
  --step:23deg;--size:8px;--gap:3px}
.crowns i{position:absolute;inset:0;display:flex;justify-content:center;
  align-items:flex-start;transform:rotate(calc(var(--step) * var(--k)));
  color:#fff}
/* Drawn from a path rather than set as the ★ character: a glyph is whatever
   the fallback font decides it is, which is how it came out lopsided at one
   size and not another. This is the same five points at every size.

   Placed by the arc, then turned back upright — the wrapper's rotation puts
   the star on the circle, and the star undoes exactly that rotation about
   its own centre so it still stands straight. The lift is its own height
   plus the gap, so that gap is clear air between it and the rim. */
.crowns i::before{content:"";width:var(--size);height:var(--size);
  background:currentColor;
  transform:translateY(calc(-1 * (var(--size) + var(--gap))))
    rotate(calc(var(--step) * var(--k) * -1));
  -webkit-mask:var(--star) center/contain no-repeat;
  mask:var(--star) center/contain no-repeat}
.crowns i.now{color:var(--gold)}
:root{--star:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M12.00 1.00 14.47 8.60 22.46 8.60 16.00 13.30 18.47 20.90 12.00 16.20 5.53 20.90 8.00 13.30 1.54 8.60 9.53 8.60 Z' fill='black'/></svg>")}
@media (prefers-reduced-motion:reduce){ .teambadge.you{animation:none} }
.teamname{font-size:11px;line-height:1.2;text-align:center;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}
/* Filled in for every card, shown only once the desktop layout has room. */
.teammeta{display:none}

/* The one big card */
.home-card{display:flex;align-items:center;gap:13px;padding:15px;
  background:var(--slate);border:1px solid var(--line);border-radius:11px;
  color:var(--text);text-decoration:none;transition:transform .1s,border-color .1s}
.home-card:hover{border-color:#3a4756}
.home-card:active{transform:translateY(2px)}
.home-card-mark{flex:0 0 auto;width:42px;height:42px;display:flex;
  align-items:center;justify-content:center;border-radius:10px;
  background:var(--slate-2);color:var(--teal)}
.home-card-mark svg{width:24px;height:24px}
.home-card-text{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.home-card-text b{font-family:var(--display);font-size:17px}
.home-card-text span{font-family:var(--cond);font-size:11.5px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}
.home-card-go{flex:0 0 auto;font-size:19px;color:#4a5666}


/* ── the news panel ───────────────────────────────────────────────────
   Worn by the rail on a desktop and by the pull-out drawer on a phone, so
   it lives out here rather than inside either layout. */
.hubrail-head{flex:0 0 auto;display:flex;align-items:baseline;
  justify-content:space-between;gap:8px;padding:15px 16px 12px;
  border-bottom:1px solid var(--line)}
.hubrail-head b{font-family:var(--cond);font-size:12px;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;color:var(--muted)}
.hubrail-more{background:none;border:0;padding:0;cursor:pointer;
  font-family:var(--cond);font-size:11px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--teal);text-decoration:none}
.hubrail-more:hover{color:var(--text)}
.hubrail-body{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;
  padding:10px 12px 16px}
.hubrail-body::-webkit-scrollbar{width:8px}
.hubrail-body::-webkit-scrollbar-thumb{background:#2b3542;border-radius:99px}
.hubrail-empty{margin:14px 4px;font-size:13px;color:var(--muted)}

/* ── the news rail ──────────────────────────────────────────────────
   Someone else's content, so it reads as its own panel: cooler and a
   shade deeper than the league's own slate, with the peacock's six
   colours along the bottom edge and a little of that light rising off
   it. The glow is masked upward and sits under the rows, so it lifts
   the panel without touching the type. */
#newsRail{background:linear-gradient(180deg,#161d2b 0%,#111825 100%)}
#newsRail .hubrail-head{border-bottom-color:#26303f}
#newsRail .hubrail-head,
#newsRail .hubrail-body{position:relative;z-index:1}
#newsRail .newsrow + .newsrow{border-top-color:#212a38}
#newsRail .newsrow:hover{background:#1e2635}
#newsRail .news-face{background:#1e2635}

/* The light coming off it. */
#newsRail::before{content:"";position:absolute;z-index:0;
  left:0;right:0;bottom:0;height:150px;pointer-events:none;
  background:linear-gradient(90deg,#fcb711,#f37021,#cc004c,
    #6460aa,#0089d0,#0db14b);
  filter:blur(26px);opacity:.22;
  -webkit-mask-image:linear-gradient(to top,#000 0%,transparent 100%);
  mask-image:linear-gradient(to top,#000 0%,transparent 100%)}
/* The edge itself. */
#newsRail::after{content:"";position:absolute;z-index:2;
  left:0;right:0;bottom:0;height:3px;pointer-events:none;
  background:linear-gradient(90deg,#fcb711,#f37021,#cc004c,
    #6460aa,#0089d0,#0db14b)}

/* Their mark, at a size that sits on the baseline of the heading. */
.news-logo{display:flex;align-items:center;line-height:0}
.news-logo img{height:17px;width:auto;max-width:120px;opacity:.92}
.news-logo:hover img{opacity:1}

/* The foot of the list: a mark while more is coming, then the way out. */
.news-foot{display:flex;align-items:center;justify-content:center;
  padding:14px 0 6px;min-height:26px}
.news-wait{font-family:var(--cond);font-size:14px;letter-spacing:.3em;
  color:#3d4858}
.news-end{font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:var(--teal);
  text-decoration:none;padding:6px 10px}
.news-end:hover{color:var(--text)}

/* One note. */
.newsrow{display:flex;gap:10px;padding:10px 8px;border-radius:9px;
  color:var(--text);text-decoration:none}
.newsrow + .newsrow{border-top:1px solid #232c37}
.newsrow:hover{background:var(--slate-2)}
.news-face{flex:0 0 auto;width:34px;height:34px;border-radius:50%;
  background:var(--slate-2);overflow:hidden;display:flex;
  align-items:center;justify-content:center}
.news-face img{width:100%;height:100%;object-fit:cover;
  object-position:top center}
.news-face .me-initials{font-size:11px}
.news-mid{min-width:0;display:flex;flex-direction:column;gap:2px}
.news-top{display:flex;align-items:center;gap:7px;min-width:0}
.news-top b{font-size:13px;font-weight:600;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.news-tag{flex:0 0 auto;font-family:var(--cond);font-size:9.5px;
  font-weight:700;letter-spacing:.1em;text-transform:uppercase;
  padding:1px 6px;border-radius:99px;border:1px solid var(--line);
  color:var(--muted)}
.news-tag.injury{color:var(--red);border-color:#5d3330}
.news-tag.transaction{color:var(--teal);border-color:#26535a}
.news-tag.recap{color:var(--gold);border-color:#5c4a1c}
.news-line{font-family:var(--cond);font-size:10.5px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted);overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.news-head{font-size:12.5px;line-height:1.35;margin-top:2px}
/* Enough of the note to know whether to open it. */
.news-body{font-size:11.5px;line-height:1.4;color:var(--muted);
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;
  overflow:hidden}

/* ── the home page on a desktop ───────────────────────────────────────
   The phone layout is one column that fills the screen, the team grid
   taking whatever height is left. On a tall monitor that same rule
   stretches two rows of cards to 400px each, which is why they read as
   empty boxes with a face floating in them.

   So the page turns instead. The middle column keeps the phone's order —
   events stacked above the roster cards, matching their width — and the
   space either side becomes two rails: the draft board on the left, player
   news on the right. The news rail comes in first, at 1081px; the draft
   rail waits for 1440px, below which three columns would squeeze the cards.

   Everything is scoped to .home, so the team pickers in the roster and
   draft sheets keep the compact card they already have. */
@media (min-width:1081px){
  /* One screen here as well. It used to be min-height, so a twelfth team
     card pushed the page taller than the viewport and the whole thing
     scrolled — rails and all. Now the page is fixed to the viewport and
     only the card grid inside it scrolls. */
  .home{max-width:none;padding:0;gap:0;
    /* The band sits above this on every width, so its height comes off
       here too — otherwise the desktop column runs past the screen. */
    height:calc(100dvh - var(--bar-h,53px) - var(--slate-h,0px));
    min-height:0;
    display:grid;grid-template-columns:minmax(0,1fr) 360px;
    align-items:stretch;overflow:hidden}
  /* The rails take the edges, so the page's own margin lives in here.
     Deliberately NOT a scroll container: making it one put the events
     block into a scrolling context where the team cards painted over it. */
  .home-mid{flex:none;gap:22px;padding:24px 26px 30px;min-width:0;
    min-height:0;overflow:visible}
  /* The heading only says what the rows already say. */
  .home-mid .home-block:first-child .home-h{display:none}
  /* Events keep their natural height; the rosters block takes what's left
     and the grid inside it does the scrolling. Only the cards move, so
     nothing can slide over anything above them. */
  .home-block:last-child{flex:1;min-height:0}
  /* max-content rows: a scrolling grid otherwise divides its height among
     the rows it has, which squeezed each card and pushed the cap line and
     its bar out through the bottom edge. Each row is its own height now and
     the grid scrolls past them. */
  .home .evlist{gap:10px}
  .home .evrow{padding:16px 15px}
  .home .evtext b{font-size:18px}

  /* Twelve teams, three across, four rows sharing whatever height is left.
     No scrollbar: the grid never grows past its space, so the cards give
     way instead — the photo shrinks and, once a card is too short for it,
     the name drops. */
  .home .teamgrid{grid-template-columns:repeat(3,minmax(0,1fr));
    grid-template-rows:repeat(4,minmax(0,1fr));gap:12px;
    flex:1;min-height:0;overflow:hidden;align-content:stretch}
  /* Sized against the card, not the page. Zooming in narrows the columns
     while a fixed 64px face and 14px name stayed put — so both clipped, and
     long names ran into the edges. cqw ties them to the card's own width. */
  /* A size container, so what's inside can be measured against the card's
     own height as well as its width — which is what shrinking to fit needs.
     Centred rather than top-aligned, since the contents now vary. */
  .home .teamcard{justify-content:center;gap:7px;padding:10px 12px;
    container-type:size;min-width:0;min-height:0}
  /* cqmin: the smaller of the card's two sides, so the photo fits whichever
     way the card is running out of room. */
  .home .teamface{width:min(64px,46cqmin);height:min(64px,46cqmin)}
  .home .teamface .me-initials{font-size:min(20px,15cqmin)}
  .home .teamname{font-size:clamp(9px,10cqmin,14px);font-weight:600;
    max-width:100%}
  /* Too short for both: the face is the one that identifies the team.
     Only descendants are styled here — never .teamcard itself. A container
     query that restyles its own container re-evaluates itself, and the
     result is a card that flickers forever. The gap needed no rule anyway:
     with one child left there is nothing for it to sit between. */
  @container (max-height:104px){
    .home .teamname{display:none}
  }
  /* Shorter still, and the photo is too small to recognise anyone by. At
     that point a name reads better than a thumbnail, so they swap. */
  @container (max-height:64px){
    .home .teamface{display:none}
    .home .teamname{display:block;font-size:clamp(9px,17cqmin,13px);
      white-space:normal;line-height:1.15}
  }
  /* Where container queries aren't available, fixed sizes and a scrollbar
     rather than a broken layout. */
  @supports not (width:1cqmin){
    .home .teamgrid{grid-template-rows:none;grid-auto-rows:max-content;
      overflow-y:auto;align-content:start}
    .home .teamcard{container-type:normal}
    .home .teamface{width:64px;height:64px}
    .home .teamface .me-initials{font-size:20px}
    .home .teamname{font-size:14px}
  }
  .home .teambadge.you{width:13px;height:13px;right:-3px;bottom:-3px}
  .home .teambadge.og{width:14px;height:14px;left:-1px;bottom:-1px;
    border-width:2px}
  /* A wider circle takes a shallower arc and a little more clearance. */
  .home .crowns{--step:19deg;--size:9px;--gap:4px}

  /* Salary against the cap, and how many picks are still in hand. Pick
     salaries stay out of the money left, as they do everywhere else. */
  .home .teammeta{display:flex;flex-direction:column;gap:6px;
    width:100%;margin-top:3px}
  .teamcap{display:flex;justify-content:space-between;align-items:baseline;
    font-family:var(--cond);font-size:11.5px;letter-spacing:.04em;
    color:var(--muted)}
  .teamcap b{font-weight:700;color:var(--money)}
  .teamcap.tight b{color:var(--red)}
  .teambar{height:4px;border-radius:99px;background:#131820;overflow:hidden}
  .teambar i{display:block;height:100%;border-radius:99px;
    background:var(--money);opacity:.85}
  .teambar.tight i{background:var(--red)}
  .teampicks{font-family:var(--cond);font-size:10.5px;letter-spacing:.12em;
    text-transform:uppercase;color:var(--muted)}

  /* ── the rails ──────────────────────────────────────────────────────
     Each scrolls inside itself and sticks below the header, so reading
     forty picks or thirty notes never moves the page underneath. */
  .home .hubrail{display:flex;flex-direction:column;background:var(--slate);
    isolation:isolate;
    border:0;border-radius:0;
    position:sticky;top:var(--bar-h,53px);
    height:calc(100dvh - var(--bar-h,53px));overflow:hidden}
  /* Only the edge facing the middle is drawn; the outer one is the screen. */
  .home #draftRail{border-right:1px solid var(--line)}
  .home #newsRail{border-left:1px solid var(--line)}

  /* A rail with nothing in it is worse than no rail. */
  .home .hubrail.gone{display:none}
  /* Only two columns at this width — the board waits for the next one. */
  .home #draftRail{display:none}

  /* Left: the board. One line a pick, so all four rounds are reachable. */
  .railround + .railround{margin-top:12px}
  .railround-head{font-family:var(--cond);font-size:10.5px;font-weight:700;
    letter-spacing:.14em;text-transform:uppercase;color:var(--muted);
    padding:0 4px 5px}
  .railpick{display:flex;align-items:center;gap:9px;width:100%;
    padding:5px 6px;background:none;border:0;border-radius:7px;
    color:var(--text);font:inherit;text-align:left;cursor:pointer}
  .railpick:hover{background:var(--slate-2)}
  .railpick.mine{background:#1f2a24}
  .railpick.mine:hover{background:#243026}
  .railpick-no{flex:0 0 auto;width:22px;text-align:center;
    font-family:var(--cond);font-size:11px;font-weight:700;color:var(--muted)}
  /* The medal colours the board already uses for the first three rounds. */
  .railpick-no.r1{color:var(--gold)}
  .railpick-no.r2{color:#c6ced8}
  .railpick-no.r3{color:#c88a52}
  .railpick-who{min-width:0;display:flex;flex-direction:column;line-height:1.25}
  .railpick-who b{font-size:12.5px;font-weight:600;overflow:hidden;
    text-overflow:ellipsis;white-space:nowrap}
  .railpick-who span{font-family:var(--cond);font-size:10.5px;
    letter-spacing:.04em;color:var(--muted)}

}

/* Wide enough for the board as well. */
@media (min-width:1440px){
  /* Matched widths: the two rails frame the middle evenly. */
  .home{grid-template-columns:360px minmax(0,1fr) 360px}
  .home #draftRail{display:flex}
}

/* Wide enough for a fourth card in a row, and a roomier news column. */
@media (min-width:1760px){
  .home{grid-template-columns:400px minmax(0,1fr) 400px}
  .home .teamgrid{grid-template-columns:repeat(4,minmax(0,1fr));
    grid-template-rows:repeat(3,minmax(0,1fr))}
  .home-mid{padding:26px 34px 34px}
}


/* ── one scrollbar, everywhere ────────────────────────────────────────
   The auction's panes and sheets draw a 13px red bar with arrow buttons at
   each end. On a desktop that reads as chrome rather than as an indicator,
   so every scrolling area gets the plain thumb the draft rail uses instead.

   The names are spelled out rather than left to a wildcard because the
   originals are class- and id-led: a wildcard would lose to them on
   specificity and change nothing. Same selectors, later in the file, so
   these win. Touch devices keep their own overlay bars — this is desktop
   only, and the coarse-pointer rules above still stand where they apply. */
@media (min-width:1081px) and (pointer:fine){
  /* Anything scrollable that was never styled at all. */
  *{scrollbar-width:thin;scrollbar-color:#2b3542 transparent}
  *::-webkit-scrollbar{width:9px;height:9px}
  *::-webkit-scrollbar-track{background:transparent}
  *::-webkit-scrollbar-thumb{background:#2b3542;border:0;border-radius:99px}
  *::-webkit-scrollbar-thumb:hover{background:#3a4756}
  *::-webkit-scrollbar-corner{background:transparent}

  /* And the ones that were. */
  .pane-body,.sheet-body,.sheet-body .rfa,#leagueBody,#draftBody,
  .filterlist,.tb-list,.rfa.capped,.hubrail-body{
    scrollbar-width:thin;scrollbar-color:#2b3542 transparent}
  .pane-body::-webkit-scrollbar,.sheet-body::-webkit-scrollbar,
  .sheet-body .rfa::-webkit-scrollbar,#leagueBody::-webkit-scrollbar,
  #draftBody::-webkit-scrollbar,.filterlist::-webkit-scrollbar,
  .tb-list::-webkit-scrollbar,.rfa.capped::-webkit-scrollbar,
  .hubrail-body::-webkit-scrollbar{width:9px;height:9px}
  .pane-body::-webkit-scrollbar-track,.sheet-body::-webkit-scrollbar-track,
  .sheet-body .rfa::-webkit-scrollbar-track,#leagueBody::-webkit-scrollbar-track,
  #draftBody::-webkit-scrollbar-track,.filterlist::-webkit-scrollbar-track,
  .tb-list::-webkit-scrollbar-track,.rfa.capped::-webkit-scrollbar-track,
  .hubrail-body::-webkit-scrollbar-track{background:transparent}
  .pane-body::-webkit-scrollbar-thumb,.sheet-body::-webkit-scrollbar-thumb,
  .sheet-body .rfa::-webkit-scrollbar-thumb,#leagueBody::-webkit-scrollbar-thumb,
  #draftBody::-webkit-scrollbar-thumb,.filterlist::-webkit-scrollbar-thumb,
  .tb-list::-webkit-scrollbar-thumb,.rfa.capped::-webkit-scrollbar-thumb,
  .hubrail-body::-webkit-scrollbar-thumb{background:#2b3542;border:0;
    border-radius:99px}
  .pane-body::-webkit-scrollbar-thumb:hover,
  .sheet-body::-webkit-scrollbar-thumb:hover,
  .sheet-body .rfa::-webkit-scrollbar-thumb:hover,
  #leagueBody::-webkit-scrollbar-thumb:hover,
  #draftBody::-webkit-scrollbar-thumb:hover,
  .filterlist::-webkit-scrollbar-thumb:hover,
  .tb-list::-webkit-scrollbar-thumb:hover,
  .rfa.capped::-webkit-scrollbar-thumb:hover,
  .hubrail-body::-webkit-scrollbar-thumb:hover{background:#3a4756}
  .pane-body::-webkit-scrollbar-corner,.sheet-body::-webkit-scrollbar-corner,
  .sheet-body .rfa::-webkit-scrollbar-corner,#leagueBody::-webkit-scrollbar-corner,
  #draftBody::-webkit-scrollbar-corner{background:transparent}
  /* The arrows at each end go with them. */
  .pane-body::-webkit-scrollbar-button:single-button,
  .sheet-body::-webkit-scrollbar-button:single-button,
  .sheet-body .rfa::-webkit-scrollbar-button:single-button,
  #leagueBody::-webkit-scrollbar-button:single-button,
  #draftBody::-webkit-scrollbar-button:single-button{
    display:none;width:0;height:0;background:none;background-image:none}
}

/* ── the hub answers the pointer ──────────────────────────────────────
   A live event row and a team card are both buttons; on a desktop they
   should say so before they're clicked. Brighter, and the face grows just
   enough to read as a lift rather than a jump. */
@media (min-width:1081px) and (pointer:fine){
  .home a.evrow{transition:background-color .13s ease,border-color .13s ease,
    transform .1s ease}
  .home a.evrow:hover{background:#212a35;border-color:#46566a}
  .home a.evrow:hover .evtext b{color:#fff}
  .home a.evrow:hover .evdot.on{box-shadow:0 0 0 4px #e2574c2e}

  .home .teamcard{transition:background-color .13s ease,border-color .13s ease,
    transform .1s ease}
  .home .teamcard:hover{background:#212a35;border-color:#46566a}
  .home .teamcard:hover .teamname{color:#fff}
  .home .teamface{transition:transform .16s ease}
  .home .teamcard:hover .teamface{transform:scale(1.09)}

  /* The news rail's rows are links too. */
  .home .newsrow{transition:background-color .13s ease}
  .home .news-face{transition:transform .16s ease}
  .home .newsrow:hover .news-face{transform:scale(1.08)}
}


/* ── the news drawer, on a phone ──────────────────────────────────────
   No room for a rail beside anything, so the same panel lives off the
   right edge behind a tab. Translucent, because it sits over the page
   rather than beside it, and it keeps the mark, the rainbow and the glow
   the desktop rail wears.

   The tab is only worth showing once there's something behind it: JS adds
   .ready when the feed lands, and .gone if it never does.

   Up to 1400px, not 1080. There IS an inline rail on a wide screen —
   ".home .hubrail" at 1081 and up — so dropping the cap altogether put the
   drawer over the top of it, which is what emptied the desktop hub. The
   cap just needed raising past the big iPads, which are 1194 and 1366
   across in landscape and were getting the tab with none of its rules. */
@media (max-width:1400px){
  /* 72vw, not 88, and matching the league drawer opposite. At 88 the news
     tab travelled to within 47px of the league chevron on a phone. */
  :root{--newsw:min(72vw,400px)}

  /* The two are alternatives, never both. The inline rail turns on at
     1081, so between there and here it has to be turned back off or the
     drawer opens over the top of it. */
  .home .hubrail{display:none}

  /* top is set in px once it's been dragged; the translate keeps that
     figure meaning the tab's middle either way. touch-action:none is what
     lets a drag up the edge move it instead of scrolling the page. */
  /* Parked off the right edge, a fixed element still counts toward the
     page's scrollable area — and overflow-x:hidden doesn't clip fixed
     descendants. So it waits in place and fades, rather than sliding in
     from beyond the screen. */
  .newstab{position:fixed;z-index:70;right:0;top:50%;
    transform:translateY(-50%) translateX(0);
    opacity:0;pointer-events:none;
    touch-action:none;-webkit-user-select:none;user-select:none;
    display:flex;flex-direction:column;align-items:center;gap:7px;
    padding:14px 7px 12px;border:1px solid #2a3546;border-right:0;
    border-radius:11px 0 0 11px;
    background:rgba(20,27,40,.86);-webkit-backdrop-filter:blur(12px);
    backdrop-filter:blur(12px);color:var(--muted);
    box-shadow:-4px 0 18px #0006;
    transition:transform .28s cubic-bezier(.22,.61,.36,1),opacity .2s ease;
    cursor:pointer;overflow:hidden}
  /* Only after the feed answers. */
  .newstab.ready{opacity:1;pointer-events:auto}
  .newstab.gone{display:none}
  /* Follow the finger exactly; the slide-out easing is for the tap. */
  .newstab.dragging{transition:none;cursor:grabbing}
  .newstab-word{writing-mode:vertical-rl;text-orientation:mixed;
    font-family:var(--cond);font-size:11px;font-weight:700;
    letter-spacing:.18em;text-transform:uppercase}
  .newstab-arrow{font-size:15px;line-height:1;transition:transform .28s ease}
  /* The same six colours, down the tab's own edge. */
  .newstab::after{content:"";position:absolute;left:0;bottom:0;width:100%;
    height:3px;background:linear-gradient(90deg,#fcb711,#f37021,#cc004c,
      #6460aa,#0089d0,#0db14b)}

  /* Open: the tab rides out with the panel and turns to point back. */
  body.news-open .newstab{transform:translateY(-50%) translateX(calc(-1 * var(--newsw)))}
  body.news-open .newstab-arrow{transform:rotate(180deg)}

  /* The drawer is positioned against .home and clipped by it, so the closed
     panel can sit off the right edge without giving the page somewhere to
     scroll to. overflow:hidden rather than contain:paint deliberately —
     containment would make .home a stacking context and drop the open
     drawer underneath its own veil. */
  .home{position:relative;overflow:hidden}
  /* Fixed, not absolute: it is anchored to the screen rather than to
     .home, so it reaches the red line under the header and covers the
     fixtures band on its way — the band sits above .home now, and an
     absolute drawer could only start below it. */
  .home #newsRail{display:flex;flex-direction:column;position:fixed;z-index:69;
    top:var(--bar-h,53px);right:0;bottom:0;width:var(--newsw);
    border:0;border-left:1px solid #2a3546;border-radius:0;
    isolation:isolate;overflow:hidden;
    /* Translucent, since the page is right behind it. */
    background:linear-gradient(180deg,rgba(22,29,43,.93) 0%,
      rgba(15,21,33,.96) 100%);
    -webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);
    box-shadow:-10px 0 30px #0007;
    transform:translateX(100%);
    transition:transform .3s cubic-bezier(.22,.61,.36,1);
    visibility:hidden}
  body.news-open .home #newsRail{transform:translateX(0);visibility:visible}
  /* Momentum scrolling, and the drawer swallows it rather than the page. */
  .home #newsRail .hubrail-body{-webkit-overflow-scrolling:touch;
    overscroll-behavior:contain}
  /* Room to read on a phone. */
  .home #newsRail .news-body{-webkit-line-clamp:4;font-size:12px}
  .home #newsRail .news-head{font-size:13px}

  .newsveil{position:fixed;inset:0;z-index:68;background:#0009;
    opacity:0;pointer-events:none;transition:opacity .3s ease}
  body.news-open .newsveil{opacity:1;pointer-events:auto}
}

/* The tab belongs to the phone. */
@media (min-width:1081px){
  .newstab,.newsveil{display:none}
}


/* ══ TICKER ═══════════════════════════════════════════════════════════
   The hub's skin: deep navy, square corners, block lettering. Scoped to
   body.dhskin — the auction app shares this stylesheet and is deliberately
   left on the slate palette, so lift these into :root when it's time to
   take the whole thing over.

   The accent is spent on one thing only: what is live, and what is now.
   Gold stays on picks and rings, green on money, cyan on rank. */
body.dhskin{
  --ink:#081120;          /* page */
  --slate:#0f1e35;        /* panes */
  --slate-2:#1b2c48;      /* rows */
  --line:#1d3050;
  --text:#f2f7ff;
  --muted:#7d92ae;
  --red:#e8402f;          /* live, and the rule under the header */
  --money:#5fd39b;
  --teal:#54c7d6;
  --blue:#54c7d6;         /* position rank, now the same cyan */
  --gold:#f2b01e;
  --r:4px;
  /* The block face. Used for names, figures and titles — never for prose. */
  --block:'Archivo Black','Archivo',system-ui,sans-serif;
  /* Not background-attachment:fixed — iOS sizes a fixed background against
     the document rather than the viewport, which is its own kind of trouble
     on a page that can scroll. */
  background-color:#081120;
  background-image:linear-gradient(180deg,#0b1526 0%,#081120 60%);
  background-repeat:no-repeat;
  background-size:100% 100dvh;
}

/* ── nothing wider than the screen ────────────────────────────────────
   The wordmark is a good deal wider set in Archivo Black caps than it was
   in Bitter, and .brand-name had no min-width:0 — so it refused to shrink,
   the header ran past the viewport, and the whole page became pannable
   sideways. That pan is what shifted the bar right and cut it off. */
html:has(body.dhskin),body.dhskin{max-width:100%;overflow-x:hidden}
body.dhskin .topbar{width:100%;max-width:100%;box-sizing:border-box}
body.dhskin .brand{min-width:0;flex:0 1 auto}
body.dhskin .brand-name{min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
body.dhskin .brand-mark{flex:0 0 auto}
body.dhskin .topbar-right{flex:0 0 auto;min-width:0}
body.dhskin .topbar{background:#060d18}

/* Square everything the hub draws. */
body.dhskin .evrow,body.dhskin .teamcard,body.dhskin .rrow,body.dhskin .prow,
body.dhskin .dpick,body.dhskin .trade,body.dhskin .tb-item,body.dhskin .note-row,
body.dhskin .offer-tally,body.dhskin .newsrow,body.dhskin .openrow,
body.dhskin .teamcard,body.dhskin .filterrow{border-radius:4px}
body.dhskin .sheet-card,body.dhskin .modal-card{border-radius:6px}
body.dhskin .trade-pick,body.dhskin .dpick-no{border-radius:2px}

/* On a phone a sheet is the screen, not a card floating on it. The inset
   and the rounded corners were invisible while the header was the same
   near-black as everything behind it; against a red bar they read as the
   banner being shifted down and stopping short of both edges. So the card
   fills the space under the header and the bar runs edge to edge. */
/* The hub's home page is exactly one screen at every size: the header, then
   a layout sized to whatever is left. Nothing on the page itself scrolls —
   the drawer, the sheets and the middle column do their own — so the page
   is pinned. This used to be inside the phone breakpoint, which is why a
   full row of team cards made the desktop page scroll. */
html:has(body.dhskin .home),body.dhskin:has(.home){height:100dvh;
  overflow:hidden}

@media (max-width:1080px){
  /* The hub's own sheets fill the phone — they are the page while they're
     open. Scoped to the hub: the rookie board's trade sheet is a card over
     a live draft, and covering the board with it would hide the thing you
     opened it to trade for. */
  /* Inset a little and edged, so the roster and the draft read as cards
     over the page rather than as a second page — the same treatment every
     other card on the phone has. */
  body.dhskin:has(.home) .sheet{padding:10px 10px calc(10px + var(--sab,0px))}
  body.dhskin:has(.home) .sheet-card{width:100%;height:100%;max-height:100%;
    border:1px solid var(--line);border-radius:6px}
  /* Except trades, which is a card wherever it opens: you read it against
     the board or the roster behind it, not instead of them. */
  body.dhskin #tradesSheet{padding:12px 12px calc(12px + var(--sab,0px))}
  body.dhskin #tradesSheet .sheet-card{width:min(560px,100%);height:100%;
    max-height:100%;border:1px solid var(--line);border-radius:6px}
}

/* The filter row: team on the left, the mode toggle and the cap figures at
   the right — the same arrangement the hub's roster sheet uses. */
body.dhskin .rookiepage ~ #rosterSheet .sheet-filter{display:flex;
  align-items:center;gap:10px;flex-wrap:wrap}
body.dhskin .rookiepage ~ #rosterSheet .sheet-filter .teampick{flex:0 1 auto;
  min-width:0}
body.dhskin .rookiepage ~ #rosterSheet .sheet-filter #rosterMode{
  margin-left:auto;flex:0 0 auto}
/* The rookie page's sheet gave this a line of its own back when it
   shared a row with the tabs. It has its own row now, so the override
   only forced a second break. */
body.dhskin .rookiepage ~ #rosterSheet .sheet-filter .rostercap{
  text-align:right}

/* ── the rookie board's sheets ────────────────────────────────────────
   A card, below the banner, with the board still visible around it. */
/* Below the banner, and centred in what's left. align-items:start pinned
   the card to the top of that space, so a tall one started low and ran off
   the bottom — with its buttons. The top padding clears the banner; the
   bottom matches it, so the middle of the space is the middle of what you
   can see. */
/* The UFA page's sheets sit exactly like the rookie board's. Its furniture
   is in normal flow rather than fixed, so the inset comes from the page
   rather than a published banner height. */
/* Below the block banner, never over it: whoever is up and how long is
   left are the two things you must be able to read while looking at
   somebody's roster. --ufatop-h is published by the page. */
/* The veil covers the space between the banner and the hammer card, and
   nothing else. Blurring the banner hides the clock and the bid you're
   deciding against; blurring the card hides the field you'd use. Both are
   the reason you have the roster open in the first place. */
/* Between the banner and the slab — but never squeezed to a sliver. If the
   room is open the slab is tall, and clearing all of it would leave a
   card a few lines high; past these limits the sheet is allowed to lie
   over the furniture instead. */
body.dhskin:has(.ufapage) .sheet{
  top:min(var(--ufatop-h,150px),26vh);
  height:auto;bottom:min(var(--ufafoot-h,0px),24vh);
  padding:10px 12px;align-items:center}
body.dhskin:has(.ufapage) .sheet .sheet-card{width:min(560px,100%);
  height:auto;max-height:100%;border:1px solid var(--line);
  border-radius:6px}
body.dhskin:has(.ufapage) .sheet .sheet-head{background:var(--red)}

/* :not(.ufapage) — the UFA page's main carries both classes, so this
   matched there too, and being later in the file it won: top:0 and a full
   viewport height, which is exactly the blur over the banner and the
   overhang past the bottom. */
body.dhskin .rookiepage:not(.ufapage) ~ .sheet{top:0;
  height:var(--app-h,100dvh);
  padding:calc(var(--rktop-h,110px) + 12px) 12px
          calc(12px + var(--sab,0px));
  align-items:center}
body.dhskin .rookiepage:not(.ufapage) ~ .sheet .sheet-card{
  width:min(560px,100%);
  height:auto;max-height:100%;border:1px solid var(--line);border-radius:6px}
/* Trades has an id-based rule of its own for every other page, and an id
   outranks the classes above — so on this page it needs saying again, or
   the card starts at the top of the screen and its head goes behind the
   banner. */
body.dhskin .rookiepage ~ #tradesSheet{top:0;
  height:var(--app-h,100dvh);
  padding:calc(var(--rktop-h,110px) + 12px) 12px calc(12px + var(--sab,0px));
  align-items:center}
/* Full height by default: the card reaches the bottom of the space it has
   rather than sizing to whatever is in it, so the button below has a fixed
   corner to sit in and the lists scroll inside instead of the card growing. */
/* The hub's proportions: a dialog of a fixed size rather than a panel
   filling the sheet. Same card, same shape, wherever it's opened from. */
body.dhskin .rookiepage ~ #tradesSheet .sheet-card{
  width:min(760px,94vw);height:min(76vh,680px);max-height:100%;
  border:1px solid var(--line);border-radius:6px;position:relative}
body.dhskin .rookiepage ~ #tradesSheet .sheet-body{position:static;
  display:flex;flex-direction:column;min-height:0}
body.dhskin .rookiepage ~ #tradesSheet .tradepage{position:relative;display:flex;
  flex-direction:column;min-height:0;flex:1;padding:0;
  /* As on the hub: the page fills the card rather than keeping the width
     cap it carries when it's a page in its own right. */
  max-width:none;width:100%}
/* The toggle is fixed furniture; only the lists under it scroll. */
body.dhskin .rookiepage ~ #tradesSheet .segwrap{flex:0 0 auto;margin:0 0 14px;
  padding:2px 0 4px;background:none;border-bottom:0}
body.dhskin .rookiepage ~ #tradesSheet .tradelist,
body.dhskin .rookiepage ~ #tradesSheet .blocklist{flex:1;min-height:0;
  overflow-y:auto;margin:0 -16px;padding:0 16px 60px}
body.dhskin .rookiepage ~ #tradesSheet .histbar{flex:0 0 auto}

/* Anchored to the card, not the list — it stays in the corner however far
   the offers scroll. */
body.dhskin .rookiepage ~ #tradesSheet .sheet-card{position:relative}
body.dhskin .rookiepage ~ #tradesSheet .fab-trade{position:absolute;
  right:18px;bottom:18px;z-index:6;
  border-color:var(--green);
  animation:fab-breathe 2s ease-in-out infinite}
/* A glow that is actually visible at both ends: it grows and fades rather
   than starting at zero size, which put it behind the button, and it never
   goes fully transparent, so there's always a green rim on it. */
@keyframes fab-breathe{
  0%,100%{box-shadow:0 0 6px 1px rgba(63,191,127,.4),0 10px 26px #0009}
  50%{box-shadow:0 0 20px 7px rgba(63,191,127,.75),0 10px 26px #0009}
}
@media (prefers-reduced-motion:reduce){
  body.dhskin .rookiepage ~ #tradesSheet .fab-trade{animation:none}
}

/* A sheet announces itself with the bar, not with a rule under it. */
body.dhskin .sheet-head{background:var(--red);border-bottom:0}
body.dhskin .sheet-head b{font-family:var(--block);font-weight:400;font-size:16px;
  letter-spacing:.005em;text-transform:uppercase;color:#fff}
body.dhskin .sheet-x,body.dhskin .sheet-caret{color:#ffffffb8}
/* The builder's own head is green: it's the one card in the app you open
   to make something rather than to be warned about something. Placed after
   the skin's red rather than before it, which is why the first attempt at
   this did nothing. */
body.dhskin #builder .sheet-head{background:var(--money);border-bottom:0}
body.dhskin #builder .sheet-head b{color:#fff}
body.dhskin #builder .sheet-x{color:#ffffffcc}
body.dhskin .modal-head{background:var(--red);border-bottom:0;
  border-radius:6px 6px 0 0;font-family:var(--block);font-weight:400;
  font-size:13px;letter-spacing:.02em;color:#fff}
body.dhskin .modal-x{color:#ffffffb8}

/* ── the block face, where it earns its keep ──────────────────────────
   Names, money and rank are what you scan a card for. Everything else —
   the team, the contract year, the prose — stays in Barlow, or the whole
   card shouts and nothing stands out. */
/* History cards keep the display face; the builder's own asset rows don't.
   You read those name by name while deciding, and a column of caps in a
   display weight is a column you scan rather than read. */
/* The interface face at bold, not the display one. Archivo Black in caps
   is wide, so long names and pick labels ran out of room and truncated —
   and a trade card is exactly where you need to read the whole name. */
body.dhskin .trade-asset-mid b{font-family:var(--ui);font-weight:700;
  text-transform:none;letter-spacing:0}
body.dhskin .tb-item-mid b{font-family:var(--ui);font-weight:500;
  font-size:12px;text-transform:none;letter-spacing:.005em;color:var(--text)}
/* Roster names are the exception: plain, unbold and in mixed case. All
   three earn width — the reading face is narrower than the display one,
   lowercase letters are narrower than caps, and a lighter weight is
   narrower again — so more of a long name fits before it ellipsises. */
body.dhskin .rrow-name b{font-family:var(--ui);font-weight:500;
  font-size:13.5px;text-transform:none;letter-spacing:.005em}
body.dhskin .trade-asset-mid b{font-size:11.5px}
body.dhskin .nom-name{font-family:var(--block);font-weight:400;font-size:29px;
  text-transform:uppercase;letter-spacing:-.02em}

/* Money. Barlow Condensed rather than the wordmark's Archivo Black: the
   block face is a display type — it has no tabular figures, its digits are
   tight, and a $ in front of them reads as part of the shape. Money is the
   most-read number on the site and it should be plainly legible, so it
   takes the same condensed face every other figure uses, at a heavier
   weight and with lining figures so columns of it line up. */
body.dhskin .rrow-sal,body.dhskin .tb-item-sal,body.dhskin .prow-cost,
body.dhskin .nom-sal,body.dhskin .cap-power,body.dhskin .rostercap b,
body.dhskin .tally-fig b,body.dhskin .teamcap b,body.dhskin .stat-cell b{
  font-family:var(--cond);font-weight:700;letter-spacing:.01em;
  font-variant-numeric:tabular-nums}
body.dhskin .rrow-sal{font-size:15px}
body.dhskin .nom-sal{font-size:23px}
body.dhskin .stat-cell b{font-size:18px}

/* Rank. The condensed face, like every other figure — the block face is
   for the wordmark and the clock, not for numbers you read in a column. */
body.dhskin .rrow-right .rrow-rank,body.dhskin .pc-cost .rrow-rank{
  font-family:var(--cond);font-weight:700;font-size:12px;
  letter-spacing:.02em;font-variant-numeric:tabular-nums;color:var(--blue)}

/* Pick numbers are figures too, and they already carry the medal colours. */
body.dhskin .trade-pick,body.dhskin .dpick-no,body.dhskin .railpick-no{
  font-family:var(--block);font-weight:400;letter-spacing:-.01em}

/* Event titles and the wordmark carry the same voice as a sheet title. */
body.dhskin .evtext b{font-family:var(--block);font-weight:400;
  text-transform:uppercase;letter-spacing:-.01em;font-size:15px}
body.dhskin .brand-name{font-family:var(--block);font-weight:400;
  text-transform:uppercase;letter-spacing:0;font-size:16px}
@media (max-width:1080px){
  /* Four controls and a wordmark on one line. It fits at full width with
     room to spare; min-width:0 above is what lets it ellipsis rather than
     push, if a narrower phone ever needs it to. */
  body.dhskin .brand-name{font-size:15.5px;letter-spacing:-.01em}
  body.dhskin .topbar{gap:9px}
}


/* ── the trades sheet, on the skin ────────────────────────────────────
   The button is positioned against the card's padding box, so the card's
   own padding-bottom doesn't lift it — it needs the safe-area inset on its
   own offset or it sits under the home indicator and reads as cut off. */
/* The panel it sits in already clears the home indicator, so adding the
   inset here counted it twice and lifted the button off the corner. It's
   16px from the card's own bottom edge, like the right. */
body.dhskin #tradesSheet .fab-trade{bottom:16px}

/* Nothing in a sheet scrolls sideways. A flex child only honours its
   ellipsis if it is allowed to shrink, and several links in this chain
   never had min-width:0 — so a long name pushed the row wider than the
   card instead of truncating, and the card took the panel with it. */
body.dhskin .sheet-body,body.dhskin .tradepage{overflow-x:hidden;min-width:0}
body.dhskin .tradepage{max-width:100%}
body.dhskin .trade,body.dhskin .trade-body,body.dhskin .trade-head,
body.dhskin .trade-team,body.dhskin .trade-side,body.dhskin .trade-asset,
body.dhskin .tb-item,body.dhskin .tb-item-mid,body.dhskin .openrow,
body.dhskin .note-row,body.dhskin .note-who{min-width:0}
body.dhskin .trade-team b,body.dhskin .trade-asset-mid b,
body.dhskin .tb-item-mid b,body.dhskin .note-who b{min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* The sub-line under a name is the other thing that can run long. */
body.dhskin .tb-item-sub,body.dhskin .trade-asset-mid .tb-item-sub{
  min-width:0;overflow:hidden}


/* ── the trade filter card ────────────────────────────────────────────
   The body is a flex child of a card capped at 82dvh. Without flex:1 and
   min-height:0 it refused to shrink, so the list ran past the bottom of
   the card and was clipped rather than scrolled — the scrollbar was on an
   element that never became shorter than its content.

   With the body holding the height, the search is simply the row above the
   scroller: it stays put while the list moves under it, and it doesn't need
   to be sticky to do it. */
.filtercard .modal-body{flex:1;min-height:0;display:flex;flex-direction:column;
  gap:12px;overflow:hidden}
.filtercard .filtersearch{flex:0 0 auto}
.filtercard .filterlist{flex:1;min-height:0;max-height:none;margin-top:0;
  overflow-y:auto;overscroll-behavior:contain;
  /* Room at the foot so the last row clears the card's edge. */
  padding-bottom:4px}
/* A card that has something to scroll should look like it: give it a floor
   to scroll within rather than hugging two rows. */
.filtercard{height:min(82dvh,560px)}

/* ── the block list ───────────────────────────────────────────────────
   A blocked player's card is the compact asset row the builder uses, but
   here it sits beside full trade cards in the other two toggles. Matching
   the trade card's padding lines the two up edge to edge and, more to the
   point, lines their contents up too. */
body.dhskin .blocklist .tb-item{width:100%;padding:11px 13px;gap:9px}
body.dhskin .blocklist .tb-item .tb-face,
body.dhskin .blocklist .tb-item .trade-pick{margin-left:0}


/* ── the draft board, fifteen years of it ─────────────────────────────
   The strip scrolls: fifteen years never fit on a phone, and shrinking
   them until they do would make every year illegible to save one swipe. */
.yearstrip{width:100%;overflow-x:auto;overscroll-behavior-x:contain;
  -webkit-overflow-scrolling:touch;scrollbar-width:none}
.yearstrip::-webkit-scrollbar{display:none}
.yearstrip .seg{width:max-content;margin:0 auto;flex-wrap:nowrap}
.yearstrip .seg button{flex:0 0 auto;white-space:nowrap}
/* Three states: drafts already held, the one being run now, and the years
   still owed. Unselected they're all quiet; the colour arrives on the one
   you pick, so the strip says which kind of year you're looking at. */
.yearstrip .seg button{position:relative}
.yearstrip .seg button.y-past,.yearstrip .seg button.y-next{color:#6f7f95}
.yearstrip .seg button.y-now{color:var(--text)}
.yearstrip .seg button.y-now::after{content:"";position:absolute;left:50%;
  bottom:3px;width:3px;height:3px;margin-left:-1.5px;border-radius:50%;
  background:var(--red)}
/* A draft that has been held, one that hasn't, and the live one. */
.yearstrip .seg button.on.y-past{color:var(--red)}
.yearstrip .seg button.on.y-next{color:var(--green)}
.yearstrip .seg button.on.y-now{color:#fff}

/* The filter and its count share a line, one at each end. */
.draftrow{display:flex;align-items:center;justify-content:space-between;
  gap:10px;width:100%}
.draftrow .teampick{flex:0 1 auto;min-width:0}
.draftrow .draftcount{flex:0 0 auto;text-align:right}
.draftfilter{flex-direction:column;align-items:stretch;gap:10px}

/* ── a pick from a draft already held ─────────────────────────────────
   The player is the headline; the owner who took him is the footnote. */
.dhist{align-items:center}
.dhist .dpick-who{gap:2px}
/* Same size and shape as the owner's photo opposite it, so the two bookend
   the row and the name and its sub-line sit between them. */
.dhist > .dpick-shot{width:28px;height:28px}
.dhist-sub{display:flex;align-items:center;gap:5px;min-width:0;
  font-family:var(--cond);font-size:10.5px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}
.dpick-shot{flex:0 0 auto;width:28px;height:28px;border-radius:50%;
  overflow:hidden;background:var(--slate-2);display:flex;
  align-items:center;justify-content:center}
.dpick-shot img{width:100%;height:100%;object-fit:cover;
  object-position:top center}
.dpick-shot .me-initials{font-size:10px}
.dhist-logo{flex:0 0 auto;width:14px;height:14px;object-fit:contain}
.dhist-team{flex:0 0 auto}
.dhist-pos{flex:0 0 auto;font-weight:700}
.dhist-dot{flex:0 0 auto;opacity:.6}
.dhist-owner{min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}

/* An owner who has left the league. No photo was ever taken for the app,
   and none is coming — so the slot says so rather than sitting empty. */
.dpick-face.gone,.teamface.gone{display:flex;align-items:center;
  justify-content:center;color:#7d8a9c;background:var(--slate-2)}
.dpick-face.gone svg,.teamface.gone svg{width:66%;height:66%;display:block}
.teamcard.gone .teamname{color:var(--muted)}


/* ── the rookie board ─────────────────────────────────────────────────
   Two halves: the draft order on one side, the class on the other. On a
   phone they stack, board first — you look up whose pick it is far more
   often than you scroll the class. */
/* Four regions, two of them full width: the clock, the commissioner's row,
   then the draft on the left and the class on the right. Same arrangement
   at every size — a phone gets narrower columns, not a different page. */
.rookiepage{display:grid;max-width:1500px;margin:0 auto;
  grid-template-areas:"clock clock" "admin admin" "board car";
  grid-template-rows:auto auto minmax(0,1fr);
  grid-template-columns:minmax(0,0.9fr) minmax(0,1fr);
  gap:8px;padding:8px 8px calc(8px + var(--sab,0px));
  /* The header and banner are fixed, so they take no room in the flow —
     the page is the whole screen, with their height as its top padding. */
  height:100dvh;box-sizing:border-box;overflow:hidden}
.rkclock{grid-area:clock}
.rkadmin{grid-area:admin}
.rkboard{grid-area:board}
.rkcar{grid-area:car}
.rkboard,.rkcar{height:100%;min-height:0}
/* Hidden furniture must not leave its row behind. */
.rkclock[hidden],.rkadmin[hidden]{display:none}

@media (min-width:1081px){
  /* The sidecar is a fixed list; the board is what benefits from width, so
     it takes what's left. Square tiles need more of it than rows did, so
     the page runs wider and the margins are tighter. */
  .rookiepage{max-width:1900px;
    grid-template-columns:minmax(0,1fr) 360px;
    gap:14px 14px;padding:18px 14px 22px}
}
@media (min-width:1500px){
  .rookiepage{grid-template-columns:minmax(0,1fr) 400px;
    gap:14px 18px;padding:20px 20px 26px}
}


/* ── the two columns on a phone ───────────────────────────────────────
   Both are narrow, so everything inside them loses a size and the parts
   that only repeat what's already on screen come out entirely. */
@media (max-width:1080px){
  .rkboard-head{padding:8px 10px}
  .rkboard-head b{font-size:11.5px}
  .rkboard-list{padding:8px 8px 12px}
  .rkround-head{font-size:9.5px;letter-spacing:.1em}
  .rkslot{gap:5px;padding:4px 5px;min-height:32px}
  .rkslot-no{min-width:26px;padding:2px 3px;font-size:9px}
  .rkslot-face{width:19px;height:19px}
  .rkslot-face .me-initials{font-size:7.5px}
  .rkslot-who b{font-size:10px}
  .rkslot-who span{font-size:8.5px}
  /* The slot already says whose pick it is; the tag would wrap the row. */
  .rkslot-tag{display:none}

  .rkcar-top{padding:8px 7px;gap:6px}
  .rksearch{font-size:11px;padding:5px 7px}
  .rkpos button{font-size:10px;letter-spacing:.04em;padding:5px 8px}
  .rktabs button{font-size:10px;padding:6px 8px}
  .rklist{padding:7px 7px 12px;gap:4px}
  .rkrow{gap:6px;padding:6px 7px}
  .rk-target{width:20px;height:20px}
  .rk-target svg{width:18px;height:18px}
  .rk-face{width:26px;height:26px}
  .rk-info{width:14px;height:14px;margin-left:4px;font-size:9px}
  .rk-logo{width:12px;height:12px}
  .rk-name b{font-size:10.5px}
  .rk-sub{gap:4px;font-size:9px}

  .rkadmin{padding:8px 10px;gap:7px}
  .rkadmin input{font-size:12px;padding:4px 6px}
  .rkadmin input[type=number]{width:58px}
  .rkadmin label{font-size:9.5px;letter-spacing:.08em}
}

.rkboard,.rkcar{display:flex;flex-direction:column;min-height:0;
  background:var(--slate);border:1px solid var(--line);border-radius:6px;
  overflow:hidden}
.rkboard-head,.rkcar-top{flex:0 0 auto;padding:11px 13px;
  border-bottom:1px solid var(--line)}
/* Nothing sits beside either title any more, so both centre over their
   own column. */
/* The league's red, so the board's title reads as a header rather than a
   line of text floating at the top of the card. Not the class panel: its
   head borrows this class, and it isn't the draft board. */
/* Above the masks. They're positioned inside the same panel and scroll
   under this heading, so without a stacking order of its own the black
   and the reveal ran over the top of it. */
.rkboard-head{position:relative;z-index:6;display:flex;align-items:baseline;
  justify-content:center;gap:10px}
/* The league's red, so the board's title reads as a header rather than a
   line of text floating at the top of the card. Not the class panel: its
   head borrows this class, and it isn't the draft board. */
.rkboard-head:not(.rkcar-head){background:var(--red);
  border-bottom:1px solid #8f2f26}
.rkboard-head:not(.rkcar-head) b{color:#fff}

/* Complete: a green dot and the word, beside the title. The same pair the
   hub's event row uses, so a finished draft reads the same in both places.
   The header keeps its red — the mark is what changed, not the board. */
.rkboard-done{display:inline-flex;align-items:center;gap:7px;
  font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;color:var(--money)}
.rkboard-done[hidden]{display:none}
.rkdone-dot{width:8px;height:8px;border-radius:50%;background:var(--money);
  flex:0 0 auto}
/* One line, whatever the column width — the year plus two words is short
   enough to shrink rather than wrap. */
.rkboard-head b{font-family:var(--block,'Archivo Black',sans-serif);
  font-weight:400;font-size:15px;text-transform:uppercase;letter-spacing:-.01em;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.rkboard-list{flex:1;min-height:0;overflow-y:auto;padding:10px 12px 14px}

.rkround + .rkround{margin-top:12px}
.rkround-head{display:flex;align-items:baseline;justify-content:space-between;
  padding-bottom:5px;margin-bottom:6px;border-bottom:1px solid var(--line);
  font-family:var(--cond);font-size:11px;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted)}
.rkround-list{display:flex;flex-direction:column;gap:5px}
/* Tall enough for a player before there is one. An empty slot holds a
   22px owner face; a filled one holds a 26px headshot, so the board grew a
   few pixels per pick and everything below it stepped down. The height is
   set for the filled case from the start. */
.rkslot{display:flex;align-items:center;gap:7px;padding:5px 7px;
  min-height:38px;box-sizing:border-box;
  background:#0f1621;border:1px solid #222d3c;border-radius:4px}
.rkslot.mine{border-color:var(--green);background:#14301f}
/* The interface face at bold, not the display one. A pick number is a
   label you read past, and Archivo Black gave it the weight of a headline. */
.rkslot-no{flex:0 0 auto;min-width:32px;text-align:center;padding:2px 5px;
  border-radius:2px;font-family:var(--ui);
  font-weight:700;font-size:11px;color:#1a1408;background:var(--gold)}
.rkslot-no.r2{background:#c6ced8}
.rkslot-no.r3{background:#c88a52}
.rkslot-no.r4{background:var(--slate);color:var(--text);
  box-shadow:inset 0 0 0 1px var(--line)}
.rkslot-face{flex:0 0 auto;width:22px;height:22px;border-radius:50%;
  overflow:hidden;background:var(--slate);display:flex;align-items:center;
  justify-content:center}
.rkslot-face img{width:100%;height:100%;object-fit:cover;
  object-position:top center}
.rkslot-face .me-initials{font-size:9px}
/* Takes the middle, so the owner's photo is pushed to the right edge. */
.rkslot-who{flex:1;min-width:0;display:flex;flex-direction:column;
  line-height:1.25}
/* Plain weight: a board of bold names is a board with no emphasis left
   for the things that need it. */
.rkslot-who b{font-size:11px;font-weight:400;min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.rkslot-who span{font-family:var(--cond);font-size:9px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}

/* ── the sidecar ──────────────────────────────────────────────────────
   Two toggles: which list, then which position. The second is subordinate
   to the first, so it sits under it and reads quieter. */
/* Centred, and never wider than the column. max-content alone pushed the
   fifth position button out of sight on a phone, so the buttons share the
   width they have instead of insisting on the width they'd like. */
.rkcar-top{display:flex;flex-direction:column;align-items:center;gap:8px}
.rktabs,.rkpos{width:100%;max-width:100%;margin:0 auto}
.rktabs button,.rkpos button{flex:1 1 0;min-width:0;padding-left:6px;
  padding-right:6px;white-space:nowrap}
.rkpos button{font-size:11px;letter-spacing:.06em}
/* Targets is the one tab that means something is marked, so selecting it
   says so in the same red the board uses for everything urgent. */
.rktabs button.on[data-view="targets"]{background:var(--red);color:#fff}

/* Each position in its own colour, so the filter says what it filters to. */
.rkpos button[data-pos="QB"]{color:var(--pos-qb)}
.rkpos button[data-pos="RB"]{color:var(--pos-rb)}
.rkpos button[data-pos="WR"]{color:var(--pos-wr)}
.rkpos button[data-pos="TE"]{color:var(--pos-te)}
.rkpos button.on[data-pos="QB"]{background:var(--pos-qb);color:var(--pos-ink)}
.rkpos button.on[data-pos="RB"]{background:var(--pos-rb);color:var(--pos-ink)}
.rkpos button.on[data-pos="WR"]{background:var(--pos-wr);color:var(--pos-ink)}
.rkpos button.on[data-pos="TE"]{background:var(--pos-te);color:var(--pos-ink)}
.rkcount{font-family:var(--cond);font-size:10.5px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted)}
/* Under the position strip, the width of the column. */
.rksearch{width:100%;background:var(--ink);border:1px solid var(--line);
  border-radius:3px;padding:6px 8px;color:var(--text);font-family:var(--ui);
  font-size:12px}
.rksearch::placeholder{color:#4a5666}
.rksearch:focus{outline:none;border-color:var(--teal)}

.rklist{flex:1;min-height:0;overflow-y:auto;padding:8px 10px 14px;
  display:flex;flex-direction:column;gap:5px}
.rkrow{display:flex;align-items:center;gap:8px;padding:7px 9px;min-width:0;
  background:var(--slate-2);border:1px solid transparent;border-radius:4px}
.rkrow.targeted{border-color:var(--gold);background:#241f10}
/* Off the board: greyed and struck, the way a settled RFA reads. */
.rkrow.taken{opacity:.45;background:var(--slate)}
.rkrow.taken .rk-name b{text-decoration:line-through;
  text-decoration-thickness:1px;color:var(--muted)}
.rkrow.taken .rk-target{visibility:hidden}

/* The bullseye, on the left, exactly where the auction board puts it. */
/* The control itself is .tgt-icon, shared with the auction — this only
   sizes it for a narrower row. The gold "on" colour is gone: the green dot
   inside the ring is what says it's selected, as it does there. */
.rk-target{flex:0 0 auto;width:22px;height:22px;
  transition:color .12s,transform .1s}
.rk-target svg{width:20px;height:20px}
.rk-target:active{transform:scale(.9)}

/* Where he sits on the rookie board. The row is already centre-aligned, so
   this lands level with the ring on its left and between the two lines of
   the name on its right. */
/* On the sub-line now, so it takes that line's size and sits in gold
   ahead of the NFL's own draft slot. */
.rk-rank{flex:0 0 auto;font-weight:700;color:var(--gold)}
/* Off the board: the number goes with him. */
.rkrow.taken .rk-rank{color:#7a6528}

/* The little i behind the name. Sized to be tappable without taking room
   from the name it belongs to. */
.rk-info{flex:0 0 auto;width:15px;height:15px;padding:0;margin-left:5px;
  border-radius:50%;border:1px solid var(--line);background:none;
  color:var(--muted);font-family:var(--cond);font-size:10px;font-weight:700;
  line-height:1;cursor:pointer;display:flex;align-items:center;
  justify-content:center;-webkit-tap-highlight-color:transparent}
.rk-info:hover{border-color:var(--teal);color:var(--teal)}
.rk-logo{flex:0 0 auto;width:14px;height:14px;object-fit:contain}
/* Where the NFL took him. */
.rk-slot{flex:0 0 auto;font-weight:700;color:var(--text)}
/* Only the confirmation card carries a portrait now; the list rows are
   narrow enough that a face cost more than it told you. */
.rk-face{flex:0 0 auto;width:30px;height:30px;border-radius:50%;
  overflow:hidden;background:var(--slate);display:flex;align-items:center;
  justify-content:center}
.rk-face img{width:100%;height:100%;object-fit:cover;object-position:top center}
.rk-face .me-initials{font-size:10px}
/* The row's middle gives way when the Draft button appears, rather than
   the button overlapping it: everything here can shrink and truncate, so a
   control arriving at the end pushes the name along instead of over it. */
.rk-mid{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:1px;
  overflow:hidden}
.rk-mid > *{min-width:0;max-width:100%}
.rk-name{min-width:0;display:flex;align-items:center;gap:5px}
/* Half of 12.5px is unreadable, so this is as far down as the name goes
   and still scans — change the two figures together if you want it
   smaller still. */
/* Plain text, not the display face — a column of names is read, not
   glanced at. Targeting one bolds it, which is the difference that should
   stand out in a list of a hundred and thirty. */
.rk-name b{min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;font-size:11.5px;letter-spacing:.005em;
  font-family:var(--ui);font-weight:500}
.rkrow.targeted .rk-name b{font-weight:800;color:#fff}
/* What's wrong with him, before his name. */
.rk-knock{flex:0 0 auto;padding:1px 4px;border-radius:2px;
  background:#3a1d1a;color:#ff9c92;font-family:var(--cond);font-size:8.5px;
  font-weight:700;letter-spacing:.06em}
.rk-sub{display:flex;align-items:center;gap:6px;min-width:0;
  font-family:var(--cond);font-size:10px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}
/* Every other position chip in the app is coloured by pairing the component
   with the position — .tb-pos.pos-WR and so on — and this one had no such
   pairing, so it inherited the sub-line's grey. */
.rk-pos{flex:0 0 auto;font-weight:700}
.rk-pos.pos-QB{color:var(--pos-qb)}
.rk-pos.pos-RB{color:var(--pos-rb)}
.rk-pos.pos-WR{color:var(--pos-wr)}
.rk-pos.pos-TE{color:var(--pos-te)}
.rk-taken{flex:0 0 auto;color:var(--red)}


/* Uppercase, but in the reading face: this is a list you scan name by
   name. Bold marks a target, which is the one distinction worth making
   here — so the weight has to be free to carry it. */
body.dhskin .rk-name b{font-family:var(--ui);font-weight:500;
  text-transform:uppercase;letter-spacing:.01em}
body.dhskin .rkrow.targeted .rk-name b{font-weight:800;color:#fff}


/* A status blurb on the player card, above the numbers it qualifies. */
.nom-knock{display:flex;flex-direction:column;gap:3px;margin:0 0 14px;
  padding:10px 12px;border-radius:4px;background:#2a1614;
  border:1px solid #5d3330}
.nom-knock b{font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:#ff9c92}
.nom-knock span{font-size:13px;line-height:1.45;color:var(--text)}

/* ── the draft banner ─────────────────────────────────────────────────
   ONE box. It says different things before the draft and during it, but
   its size, padding and position are defined here and nowhere else — the
   states below may change colour and wording, never geometry. Two sets of
   box rules is what made it move when the draft started. */
.rkclock{flex:0 0 auto;display:flex;align-items:center;gap:12px;
  padding:13px 14px;min-height:76px;
  border-bottom:1px solid var(--line);
  background:linear-gradient(180deg,#1b2b47 0%,#141f36 100%)}
.rkclock-face{flex:0 0 auto;width:46px;height:46px;border-radius:50%;
  overflow:hidden;background:var(--slate-2);display:flex;align-items:center;
  justify-content:center}
.rkclock-face img{width:100%;height:100%;object-fit:cover;
  object-position:top center}
.rkclock-face .me-initials{font-size:10px}
.rkclock-who{flex:1;min-width:0;display:flex;flex-direction:column;
  line-height:1.2}
/* Direct child only: the sub-line has a <b> of its own for the money, and
   a descendant selector was giving it the owner name's size. */
.rkclock-who > b{font-family:var(--block,'Archivo Black',sans-serif);
  font-weight:400;font-size:19px;text-transform:uppercase;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rkclock-who span{font-family:var(--cond);font-size:10px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted)}
.rkclock-time{flex:0 0 auto;font-family:var(--block,'Archivo Black',sans-serif);
  font-weight:400;font-size:30px;letter-spacing:-.03em;
  font-variant-numeric:tabular-nums;color:var(--text)}
/* Your pick, and a pick that has run over. */
.rkclock.mine{background:#12281c}
.rkclock.mine .rkclock-time{color:var(--green)}
.rkclock.out .rkclock-time{color:var(--red)}

/* The commissioner's row. Two lines: what the draft is set to, and what it
   is doing. Nobody else is sent this markup at all. */
.rkadmin{flex:0 0 auto;display:flex;flex-direction:column;gap:8px;
  padding:10px 13px;border-bottom:1px solid var(--line);background:#0b1526}
.rkadmin-set,.rkadmin-run{display:flex;align-items:center;gap:8px;
  flex-wrap:wrap}
.rkadmin label{display:flex;align-items:center;gap:6px;
  font-family:var(--cond);font-size:10.5px;font-weight:700;letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted)}
.rkadmin input{background:var(--ink);border:1px solid var(--line);
  border-radius:3px;padding:5px 7px;color:var(--text);font-family:var(--ui);
  font-size:13px}
.rkadmin input[type=number]{width:70px}
.rkadmin .btn:disabled{opacity:.4;cursor:default}

/* ── the slot on the clock ────────────────────────────────────────────
   The one place on the board that accepts a player. It says so, and it
   says it differently depending on whether you're the one who can. */
.rkslot.onclock{border-color:var(--gold);background:#241f10}
.rkslot.onclock.mine{border-color:var(--green);background:#12281c}
.rkslot.onclock.over{border-style:dashed;border-width:2px;
  background:#16351f}
.rkslot-tag{flex:0 0 auto;font-family:var(--cond);font-size:9.5px;
  font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  color:var(--muted)}
.rkslot.filled .rkslot-player{font-family:var(--block,'Archivo Black',sans-serif);
  font-weight:400;text-transform:uppercase;font-size:12px}
/* Name and position share the first line, the name giving way first. */
.rkslot-line{display:flex;align-items:baseline;gap:5px;min-width:0}
.rkslot-line .rkslot-player{min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.rkslot-pos{flex:0 0 auto;font-family:var(--cond);font-size:10px;
  font-weight:700;letter-spacing:.08em}
.rkslot-pos.pos-QB{color:var(--pos-qb)}
.rkslot-pos.pos-RB{color:var(--pos-rb)}
.rkslot-pos.pos-WR{color:var(--pos-wr)}
.rkslot-pos.pos-TE{color:var(--pos-te)}
.rkslot.filled{opacity:.92}

/* A row being carried, and the card that follows the finger.
   touch-action:pan-y, not none: none stops the browser scrolling from a
   row at all, and since the rows are the list, that stops the list. pan-y
   keeps vertical scrolling with the browser and leaves the horizontal
   movement a drag begins with to us. */
.rkrow.draggable{cursor:grab;touch-action:pan-y}
/* Once a drag is actually under way, the browser lets go entirely. */
body.rk-dragging .rkrow.draggable{touch-action:none}
.rkrow.lifting{opacity:.35}
body.rk-dragging{cursor:grabbing;-webkit-user-select:none;user-select:none}
.rk-ghost{position:fixed;z-index:120;transform:translate(-50%,-140%);
  pointer-events:none;display:flex;flex-direction:column;gap:1px;
  padding:7px 11px;border-radius:4px;background:var(--slate-2);
  border:1px solid var(--gold);box-shadow:0 12px 28px #000a}
.rk-ghost b{font-family:var(--block,'Archivo Black',sans-serif);
  font-weight:400;font-size:12px;text-transform:uppercase;white-space:nowrap}
.rk-ghost span{font-family:var(--cond);font-size:10px;letter-spacing:.1em;
  color:var(--muted)}

/* The last word before he's yours. */
.rkconfirm-card{width:min(420px,100%)}
.rkconfirm-player{display:flex;align-items:center;gap:11px;padding:11px;
  background:var(--slate-2);border:1px solid var(--line);border-radius:4px;
  margin-bottom:12px}
.rkconfirm-player .rk-face{width:44px;height:44px}
.rkconfirm-mid{min-width:0;display:flex;flex-direction:column;gap:2px}
.rkconfirm-mid b{font-family:var(--block,'Archivo Black',sans-serif);
  font-weight:400;font-size:16px;text-transform:uppercase}
.rkconfirm-sub{display:flex;align-items:center;gap:7px;
  font-family:var(--cond);font-size:10.5px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted)}
.rk-err{color:var(--red)}


/* ── the draft banner ─────────────────────────────────────────────────
   Three states in one strip: counting down to the start, whoever is on the
   clock, and — for about ten seconds — the pick that just landed. */
.rkclock{position:relative;overflow:hidden}
/* The same height and the same type as the live banner, so starting the
   draft changes what the banner says rather than how big it is. */
/* Before it starts. Nothing changes but the colour, the wording and which
   parts are shown — the box is the box. */
.rkclock.pre{justify-content:center}
.rkclock.pre .rkclock-face{display:none}
.rkclock.pre .rkclock-who{flex:0 0 auto}
.rkclock.pre .rkclock-who span:empty{display:none}
.rkclock.pre .rkclock-who > b{font-family:var(--cond);font-size:15px;
  font-weight:700;letter-spacing:.18em;color:var(--muted)}

/* Running. Gold, and green while the pick is yours. */
.rkclock.live{background:linear-gradient(180deg,#7a5c10 0%,#5d4409 100%);
  border-bottom-color:#a87d16}
.rkclock.live .rkclock-who > b{color:#fff}
.rkclock.live .rkclock-who span{color:#f3e3b4}
.rkclock.live .rkclock-time{color:#fff}
/* Over. Green rather than gold, centred where the owner's photo and the
   clock used to sit, and nothing moving. */
.rkclock.live.done{background:linear-gradient(180deg,#155e3b 0%,#0f4a2e 100%);
  border-bottom-color:var(--money);justify-content:center}
.rkclock.done .rkclock-face{display:none}
.rkclock.done .rkclock-who{flex:0 0 auto;align-items:center;text-align:center}
.rkclock.done .rkclock-who > b{color:#fff;letter-spacing:.06em}
.rkclock.done .rkclock-rail i{width:0}
.rkclock.live.mine{background:linear-gradient(180deg,#14512f 0%,#0e3a22 100%);
  border-bottom-color:#2f8f5b}
.rkclock.live.mine .rkclock-time{color:var(--green)}
.rkclock.live.out .rkclock-time{color:var(--red)}

/* 1. black washes across from the left */
.rkwash{position:absolute;inset:0;z-index:3;background:#05070b;
  display:flex;align-items:center;justify-content:center;
  transform:scaleX(0);transform-origin:left center}
.rkwash.washing{transform:scaleX(1);
  transition:transform .88s cubic-bezier(.5,0,.2,1)}
/* 2. the words flash while it sits there */
.rkwash-words{font-family:var(--block,'Archivo Black',sans-serif);
  font-weight:400;font-size:24px;letter-spacing:.02em;text-transform:uppercase;
  color:#fff;opacity:0}
/* Three blinks, three quarters of a second each, then it holds lit for
   the hammer. */
.rkwash.flashing .rkwash-words{animation:pick-flash .75s steps(1) 3 forwards}
@keyframes pick-flash{0%,55%{opacity:1}56%,100%{opacity:0}}
.rkwash.striking .rkwash-words{opacity:1}
/* 3. the hammer arrives and lands */
.rkwash-hammer{position:absolute;right:8%;top:50%;width:54px;height:54px;
  color:var(--red);opacity:0;z-index:6;
  transform:translate(120%,-50%) rotate(-70deg);transform-origin:60% 90%}
.rkwash-hammer svg{width:100%;height:100%;display:block}
.rkwash.striking .rkwash-hammer{opacity:1;
  animation:hammer-strike .74s cubic-bezier(.3,0,.2,1) forwards}
@keyframes hammer-strike{
  0%{opacity:0;transform:translate(120%,-50%) rotate(-70deg)}
  55%{opacity:1;transform:translate(0,-50%) rotate(-38deg)}
  100%{opacity:1;transform:translate(-10%,-50%) rotate(14deg)}
}
/* 4. and it breaks. The black clears rather than the whole element fading,
   which is what lets the shards read as the banner coming apart instead of
   the banner dimming. */
.rkwash.struck{background:transparent;transition:background .18s ease}
.rkwash.struck .rkwash-words{opacity:0;transition:opacity .18s ease}
.rkwash-hammer{z-index:6}
/* It fades on impact. A second animation, not a transition: the swing is
   still held by `forwards`, and a held animation value outranks one. */
.rkwash.struck .rkwash-hammer{animation:hammer-gone .22s ease forwards}
@keyframes hammer-gone{
  0%{opacity:1;transform:translate(-10%,-50%) rotate(14deg)}
  100%{opacity:0;transform:translate(-10%,-50%) rotate(14deg)}
}
.rkshards{position:absolute;inset:0;z-index:4;pointer-events:none}
/* The banner in twelve pieces, each thrown its own way. */
.rkshards i{position:absolute;width:16.67%;height:50%;background:#05070b;
  opacity:0}
.rkshards i:nth-child(1){left:0;top:0;--x:-70px;--y:-52px;--r:-26deg}
.rkshards i:nth-child(2){left:16.67%;top:0;--x:-38px;--y:-70px;--r:18deg}
.rkshards i:nth-child(3){left:33.34%;top:0;--x:-8px;--y:-84px;--r:-12deg}
.rkshards i:nth-child(4){left:50.01%;top:0;--x:16px;--y:-80px;--r:22deg}
.rkshards i:nth-child(5){left:66.68%;top:0;--x:48px;--y:-62px;--r:-18deg}
.rkshards i:nth-child(6){left:83.35%;top:0;--x:82px;--y:-46px;--r:30deg}
.rkshards i:nth-child(7){left:0;top:50%;--x:-78px;--y:44px;--r:20deg}
.rkshards i:nth-child(8){left:16.67%;top:50%;--x:-44px;--y:66px;--r:-24deg}
.rkshards i:nth-child(9){left:33.34%;top:50%;--x:-10px;--y:78px;--r:14deg}
.rkshards i:nth-child(10){left:50.01%;top:50%;--x:18px;--y:74px;--r:-20deg}
.rkshards i:nth-child(11){left:66.68%;top:50%;--x:52px;--y:58px;--r:26deg}
.rkshards i:nth-child(12){left:83.35%;top:50%;--x:88px;--y:40px;--r:-16deg}
.rkshards.breaking i{opacity:1;animation:rk-shard-fly 1.05s
  cubic-bezier(.2,.6,.3,1) forwards}
/* Named apart from the boot splash's shard-fly, which is defined earlier
   and uses its own --fx/--fy/--fr. Two keyframe sets under one name means
   the later one wins everywhere — which was quietly changing how the
   splash broke apart on every page. */
@keyframes rk-shard-fly{
  0%{opacity:1;transform:none}
  15%{opacity:1}
  100%{opacity:0;
    transform:translate(var(--x,40px),var(--y,-40px)) rotate(var(--r,20deg))
      scale(.62)}
}
/* 5. the pick, held underneath */
.rkreveal{position:absolute;inset:0;z-index:2;display:flex;align-items:center;
  gap:14px;padding:10px 16px;background:var(--slate);
  animation:reveal-in .3s ease-out both}
@keyframes reveal-in{from{opacity:.4;transform:scale(.98)}to{opacity:1;
  transform:none}}
.rkreveal.fading{animation:reveal-out .4s ease-in forwards}
@keyframes reveal-out{to{opacity:0}}
.rkreveal-mid{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
/* Position and name share a line; the pick number sits under them. */
.rkreveal-line{display:flex;align-items:baseline;gap:9px;min-width:0}
/* The same size as the name beside it, in the plain face — it's a label,
   not a second headline. */
.rkreveal-pos{flex:0 0 auto;font-family:var(--ui);font-size:30px;
  font-weight:400;line-height:1.05;letter-spacing:.01em;
  text-transform:uppercase}
/* The name only. The sub-line has a <b> of its own for the money, and a
   descendant selector was giving it the name's size. */
.rkreveal-line > b{font-family:var(--block,'Archivo Black',sans-serif);
  font-weight:400;font-size:30px;text-transform:uppercase;letter-spacing:-.03em;
  color:#fff;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;line-height:1.05}
.rkreveal-to{font-family:var(--cond);font-size:11px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted)}
/* The money on the sub-line: the same size as the words beside it. */
.rkreveal-to b,.rkclock-who span b{color:var(--money);font-weight:700;
  font-size:inherit;font-family:var(--cond)}
/* Who took him, on the right. */
.rkreveal-owner{flex:0 0 auto;display:flex;align-items:center;gap:8px;
  font-family:var(--cond);font-size:12px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--text)}
.rkreveal-oimg{flex:0 0 auto;width:40px;height:40px;border-radius:50%;
  overflow:hidden;background:var(--slate-2);display:flex;align-items:center;
  justify-content:center}
.rkreveal-oimg img{width:100%;height:100%;object-fit:cover;
  object-position:top center}
.rkreveal-oimg .me-initials{font-size:13px}

/* A photo with his team's logo on the corner of it — used by the reveal
   and by every filled slot on the board. */
.rkreveal-shot{position:relative;flex:0 0 auto;display:block}
.rkreveal-shot .rk-face{width:46px;height:46px}
.rkreveal-logo{position:absolute;right:-3px;bottom:-3px;width:19px;height:19px;
  object-fit:contain;background:var(--slate);border-radius:50%;padding:1px}

/* ── a filled slot on the board ───────────────────────────────────────  */
.rkslot.filled .rkreveal-shot .rk-face{width:26px;height:26px}
.rkslot.filled .rkreveal-logo{width:13px;height:13px;right:-2px;bottom:-2px}
.rkslot-owner{font-family:var(--cond);font-size:9px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}
/* Built for the desktop tile, which is gone — the row names the owner
   itself. Left in the markup rather than the code so the tile layout can
   come back without a JS change. */
.rkslot-foot{display:none}
.rkslot-sal{flex:0 0 auto;font-family:var(--cond);font-weight:700;
  font-size:12.5px;font-variant-numeric:tabular-nums;color:var(--money)}
.rkslot.filled .rkslot-player{color:#fff}

/* ── the slot on the clock ────────────────────────────────────────────
   Bigger than its neighbours, and breathing, so it's findable in a list of
   forty-nine without hunting. */
.rkslot.onclock{padding:9px 8px;border-width:2px;
  animation:slot-breathe 2.4s ease-in-out infinite}
@keyframes slot-breathe{
  0%,100%{box-shadow:0 0 0 0 rgba(242,176,30,.35)}
  50%{box-shadow:0 0 0 5px rgba(242,176,30,0)}
}
.rkslot.onclock.mine{animation-name:slot-breathe-mine}
@keyframes slot-breathe-mine{
  0%,100%{box-shadow:0 0 0 0 rgba(63,191,127,.4)}
  50%{box-shadow:0 0 0 5px rgba(63,191,127,0)}
}
/* A player dropped here, not yet confirmed. */
.rkslot.pending{border-style:dashed;background:#14301f}
.rkslot.pending .rkslot-owner{color:var(--green)}
.rkslot.onclock .rkslot-no{font-size:12px}
.rkslot.onclock .rkslot-who b{font-size:13px}

@media (prefers-reduced-motion:reduce){
  .rkslot.onclock{animation:none}
  .rkwash.washing{transition:none;transform:scaleX(1)}
  .rkshards.breaking i,.rkwash.striking .rkwash-hammer{animation:none}
}

@media (max-width:1080px){
  /* The same single box, smaller. */
  .rkclock{padding:9px 10px;min-height:60px;gap:9px}
  .rkclock-face{width:34px;height:34px}
  .rkclock-who > b{font-size:14px}
  .rkclock-time{font-size:21px}
  .rkclock.pre .rkclock-who > b{font-size:11px}
  .rkwash-words{font-size:15px}
  .rkwash-hammer{width:34px;height:34px}
  .rkreveal{gap:9px;padding:8px 10px}
  .rkreveal-shot .rk-face{width:34px;height:34px}
  .rkreveal-logo{width:15px;height:15px}
  .rkreveal-line > b{font-size:19px}
  .rkreveal-line{gap:6px}
  .rkreveal-pos{font-size:10px}
  .rkreveal-to{font-size:9px}
  .rkreveal-owner{gap:5px;font-size:9px}
  .rkreveal-oimg{width:28px;height:28px}
  .rkreveal-pos{font-size:19px}
  .rkslot-sal{font-size:10px}
}


/* ── the banner, across the whole screen ──────────────────────────────
   It has to stay visible with a card open, which means nothing can scroll
   over it and nothing can cover it. Its height is published as --rktop-h so
   the page below it and any card can both start underneath. */
/* The header and the banner are one fixed block, with the banner directly
   under the header in normal flow. Nothing measures an offset between them,
   so nothing can drift, and the banner cannot move when its contents change
   — which is what made it jump as the draft started. */
.rktop{position:fixed;top:0;left:0;right:0;z-index:96}
.rktop .topbar{position:static}
/* !important on top: an older cached rookie.js still writes an inline top
   onto this element, which on a relatively-positioned box would push it
   down the page. Nothing should be able to move this banner. */
.rktop .rkclock{position:relative;left:auto;right:auto;top:auto!important;
  border-radius:0;border-left:0;border-right:0;
  border-bottom:1px solid var(--line)}
/* The page begins below the whole block. */
.rookiepage{padding-top:calc(8px + var(--rktop-h,110px))}
@media (min-width:1081px){
  .rookiepage{padding-top:calc(20px + var(--rktop-h,110px))}
}
/* A card opens below it, never over it — padded clear, then centred in
   what's left, so it sits in the middle of the space it can use. */
body.dhskin .rookiepage ~ .modal,
body.dhskin .modal.rkbelow{padding-top:calc(var(--rktop-h,110px) + 12px);
  align-items:center}


/* The rail behind the clock: full at the top of a pick, gone at the end. */
.rkclock-rail{position:absolute;left:0;right:0;bottom:0;height:3px;
  background:#0b1526;overflow:hidden}
.rkclock-rail i{display:block;height:100%;width:0;background:var(--gold);
  transition:width 1s linear}
.rkclock.mine .rkclock-rail i{background:var(--green)}
.rkclock.out .rkclock-rail i{background:var(--red)}

/* ── your pick ────────────────────────────────────────────────────────
   The page itself goes green behind everything — the banners keep their
   own colour, since the clock has to stay readable. It breathes on a slow
   seven-second cycle: enough to catch a glance from across a room, not
   enough to nag while you're reading the board. */
body.dhskin.onclock{background-color:#0d3a24;
  background-image:linear-gradient(180deg,#14512f 0%,#0b2b1b 60%);
  animation:onclock-breathe 7s ease-in-out infinite}
@keyframes onclock-breathe{
  0%,84%{background-color:#0d3a24}
  92%{background-color:#17643a}
  100%{background-color:#0d3a24}
}
/* The panels stay their own colour; only what's behind them changes. */
body.dhskin.onclock .rkboard,
body.dhskin.onclock .rkcar{border-color:#2f8f5b}

@media (prefers-reduced-motion:reduce){
  body.dhskin.onclock{animation:none}
}

/* ── a pick, armed ────────────────────────────────────────────────────
   Dropped on the slot and waiting. Rises from the bottom so it can't be
   missed, and both ways out are on it. */
.rkarm{position:fixed;left:0;right:0;bottom:0;z-index:98;
  display:flex;align-items:center;gap:10px;
  padding:12px 14px calc(12px + var(--sab,0px));
  background:#0b1526;border-top:2px solid var(--green);
  box-shadow:0 -12px 30px #000a;
  transform:translateY(110%);transition:transform .26s
    cubic-bezier(.22,.61,.36,1)}
.rkarm.up{transform:translateY(0)}
.rkarm-who{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.rkarm-who b{font-family:var(--block,'Archivo Black',sans-serif);
  font-weight:400;font-size:15px;text-transform:uppercase;
  min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rkarm-who span{font-family:var(--cond);font-size:10px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted)}
.rkarm .btn{flex:0 0 auto}
/* Held on the board while the bar is up. */
.rkrow.armed{border-color:var(--green);background:#14301f}

/* ── drafting from the row ────────────────────────────────────────────  */
.rk-namebtn{min-width:0;padding:0;border:0;background:none;color:inherit;
  font:inherit;text-align:left;cursor:pointer;display:block;overflow:hidden}
.rk-namebtn b{pointer-events:none}
.rk-namebtn:hover b{color:#fff;text-decoration:underline;
  text-underline-offset:2px}
/* It takes its own space in the row — never sits over what's already
   there. */
.rk-draft{flex:0 0 auto;margin-left:auto;padding:4px 9px;border-radius:3px;
  cursor:pointer;
  background:var(--green);border:0;color:#08130d;
  font-family:var(--cond);font-size:10px;font-weight:700;letter-spacing:.12em;
  text-transform:uppercase;-webkit-tap-highlight-color:transparent;
  animation:draft-in .22s ease-out both}
@keyframes draft-in{from{opacity:0;transform:translateX(8px)}
  to{opacity:1;transform:none}}
.rk-draft:hover{background:#5fd39b}

@media (prefers-reduced-motion:reduce){
  .rk-draft{animation:none}
}

@media (max-width:1080px){
  .rkarm{padding:10px 10px calc(10px + var(--sab,0px))}
  .rkarm-who b{font-size:13px}
  .rk-draft{padding:3px 7px;font-size:9px}
}


/* ── the board, covered and broken ────────────────────────────────────
   The same event as the banner, on the panel that's about to change: the
   board goes black while the pick is announced and breaks open to show the
   slot already filled. */
.rkboard{position:relative}
/* Positioned by JS over the slot that's about to change. */
/* The same arrival as the banner: a wipe from the left, not a fade. Both
   covers are one event, so they have to move the same way and at the same
   rate — one fading while the other swept read as two things happening. */
.rkmask{position:absolute;z-index:5;background:#05070b;border-radius:4px;
  display:flex;align-items:center;justify-content:center;
  transform:scaleX(0);transform-origin:left center}
.rkmask.washing{transform:scaleX(1);
  transition:transform .88s cubic-bezier(.5,0,.2,1)}
.rkmask-words{font-family:var(--block,'Archivo Black',sans-serif);
  font-weight:400;font-size:13px;letter-spacing:.02em;text-transform:uppercase;
  color:#fff;opacity:0}
/* The same hammer, scaled to the row it's breaking. */
.rkmask-hammer{position:absolute;right:6%;top:50%;width:30px;height:30px;
  color:var(--red);opacity:0;
  transform:translate(140%,-50%) rotate(-70deg);transform-origin:60% 90%}
.rkmask-hammer svg{width:100%;height:100%;display:block}
.rkmask.striking .rkmask-hammer{opacity:1;
  animation:hammer-strike .74s cubic-bezier(.3,0,.2,1) forwards}
.rkmask.striking .rkmask-words{opacity:1}
.rkmask.flashing .rkmask-words{animation:pick-flash .75s steps(1) 3 forwards}
.rkmask.struck{background:transparent;transition:background .2s ease}
.rkmask.struck .rkmask-words{opacity:0;transition:opacity .2s ease}
.rkmask-hammer{z-index:6}
.rkmask.struck .rkmask-hammer{animation:hammer-gone .22s ease forwards}

.rkmask-shards{position:absolute;inset:0;pointer-events:none}
.rkmask-shards i{position:absolute;width:25%;height:50%;background:#05070b;
  opacity:0}
.rkmask-shards i:nth-child(1){left:0;top:0;--x:-56px;--y:-44px;--r:-24deg}
.rkmask-shards i:nth-child(2){left:25%;top:0;--x:-18px;--y:-58px;--r:18deg}
.rkmask-shards i:nth-child(3){left:50%;top:0;--x:22px;--y:-56px;--r:-14deg}
.rkmask-shards i:nth-child(4){left:75%;top:0;--x:62px;--y:-40px;--r:26deg}
.rkmask-shards i:nth-child(5){left:0;top:50%;--x:-62px;--y:38px;--r:22deg}
.rkmask-shards i:nth-child(6){left:25%;top:50%;--x:-20px;--y:52px;--r:-18deg}
.rkmask-shards i:nth-child(7){left:50%;top:50%;--x:24px;--y:50px;--r:16deg}
.rkmask-shards i:nth-child(8){left:75%;top:50%;--x:66px;--y:36px;--r:-22deg}
.rkmask-shards i:nth-child(9),.rkmask-shards i:nth-child(10),
.rkmask-shards i:nth-child(11),.rkmask-shards i:nth-child(12){display:none}
.rkmask-shards.breaking i{opacity:1;animation:rk-shard-fly 1.05s
  cubic-bezier(.2,.6,.3,1) forwards}

/* ── the countdown wiped away ─────────────────────────────────────────
   A gold band crosses the banner left to right; under cover of it the
   countdown becomes the clock, and the band carries on off the right. What
   was there isn't replaced in front of you — it's gone when the band
   passes. */
.rkclock.wiping::after{content:"";position:absolute;inset:0;z-index:6;
  background:linear-gradient(90deg,#a87d16,#f2b01e 55%,#a87d16);
  transform-origin:left center;
  animation:banner-wipe 1s cubic-bezier(.5,0,.3,1) forwards}
@keyframes banner-wipe{
  0%{transform:scaleX(0);transform-origin:left center}
  46%{transform:scaleX(1);transform-origin:left center}
  47%{transform:scaleX(1);transform-origin:right center}
  100%{transform:scaleX(0);transform-origin:right center}
}

@media (prefers-reduced-motion:reduce){
  .rkclock.wiping::after{animation:none;display:none}
  .rkmask{transition:none}
  .rkmask-shards.breaking i{animation:none;opacity:0}
}

@media (max-width:1080px){
  .rkmask-words{font-size:11px}
  .rkmask-hammer{width:22px;height:22px}
}


/* ── a rookie just drafted ────────────────────────────────────────────
   New to the roster, and on a contract that runs four years before he
   reaches restricted free agency. */
.rrow-rookie{font-family:var(--cond);font-size:10.5px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase;color:var(--red)}

/* ── the draft, seen from the home page ───────────────────────────────
   The count line becomes the draft's status while it's running, and the
   slot on the clock is outlined wherever the board is shown. */
.draftcount.running{color:var(--red);font-weight:700;
  animation:draft-live 1.6s steps(1) infinite}
@keyframes draft-live{0%,60%{opacity:1}61%,100%{opacity:.25}}
.dpick.onclock{border-color:var(--red);box-shadow:0 0 0 1px var(--red)}
.railpick.onclock{box-shadow:inset 0 0 0 1px var(--red)}
.dpick.dhist{align-items:flex-start}
.dpick.dhist .dpick-who{gap:3px}

@media (prefers-reduced-motion:reduce){ .draftcount.running{animation:none} }

/* A readout for the banner's geometry, shown only with ?debug=1. */
.rkdebug{position:fixed;right:6px;bottom:6px;z-index:999;
  background:#000d;color:#7ce0a6;font:11px/1.5 ui-monospace,monospace;
  padding:8px 10px;border:1px solid #2f8f5b;border-radius:4px;
  pointer-events:none;max-width:70vw}
.rkdebug b{color:#ff9c92}


/* ── a pick changing hands ────────────────────────────────────────────
   The draft's other announcement. Where a pick landing is black and broken
   open, a pick moving is the whole spectrum sliding across — different
   enough that you know which happened before you read a word of it. */
.rktrade{position:absolute;inset:0;z-index:5;overflow:hidden;
  display:flex;align-items:center;justify-content:center;
  background:linear-gradient(90deg,#e8402f,#f2b01e 20%,#3fbf7f 40%,
    #2bb3be 60%,#4a9be8 80%,#a78bfa);
  background-size:220% 100%;
  transform:scaleX(0);transform-origin:left center}
.rktrade.washing{transform:scaleX(1);
  transition:transform .68s cubic-bezier(.5,0,.2,1);
  animation:rainbow-drift 6s linear infinite}
@keyframes rainbow-drift{
  0%{background-position:0% 50%}
  100%{background-position:200% 50%}
}
.rktrade-words{font-family:var(--block,'Archivo Black',sans-serif);
  font-weight:400;font-size:24px;letter-spacing:.02em;text-transform:uppercase;
  color:#fff;opacity:0;text-shadow:0 2px 10px #0006}
.rktrade.flashing .rktrade-words{animation:pick-flash .75s steps(1) 3 forwards}
/* Held lit on the last blink, then swept off to the left. */
.rktrade.handing .rktrade-words{opacity:1;
  animation:trade-sweep .6s cubic-bezier(.5,0,.2,1) forwards}
@keyframes trade-sweep{
  0%{opacity:1;transform:translateX(0)}
  100%{opacity:0;transform:translateX(-130%)}
}

/* Underneath: who had it, and who has it now. */
.rktrade-hands{position:absolute;inset:0;display:flex;align-items:center;
  justify-content:center;gap:18px;padding:0 16px;opacity:0}
.rktrade.handing .rktrade-hands{animation:trade-hands .6s ease-out .22s both}
@keyframes trade-hands{from{opacity:0;transform:scale(.97)}
  to{opacity:1;transform:none}}
.rktrade-side{display:flex;align-items:center;min-width:0}
.rktrade-who{display:flex;align-items:center;gap:9px;min-width:0}
.rktrade-who b{font-family:var(--block,'Archivo Black',sans-serif);
  font-weight:400;font-size:17px;text-transform:uppercase;color:#fff;
  min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  text-shadow:0 2px 8px #0007}
.rktrade-img{flex:0 0 auto;width:42px;height:42px;border-radius:50%;
  overflow:hidden;background:#0009;display:flex;align-items:center;
  justify-content:center;box-shadow:0 0 0 2px #ffffff5c}
.rktrade-img img{width:100%;height:100%;object-fit:cover;
  object-position:top center}
.rktrade-img .me-initials{font-size:13px;color:#fff}
.rktrade-arrows{flex:0 0 auto;width:34px;height:34px;
  background:#00000038;border-radius:50%;padding:5px}
.rktrade-arrows svg{width:100%;height:100%;display:block}
.rktrade.leaving{opacity:0;transition:opacity .5s ease}

/* The same announcement over the slot that moved. */
.rkmask-trade{background:linear-gradient(90deg,#e8402f,#f2b01e 20%,
  #3fbf7f 40%,#2bb3be 60%,#4a9be8 80%,#a78bfa);
  background-size:220% 100%;opacity:0;
  transition:opacity .68s cubic-bezier(.5,0,.2,1)}
.rkmask-trade.washing{opacity:1;animation:rainbow-drift 6s linear infinite}
.rkmask-trade .rkmask-words{color:#fff;text-shadow:0 2px 8px #0006}
.rkmask-trade.flashing .rkmask-words{
  animation:pick-flash .75s steps(1) 3 forwards}

@media (prefers-reduced-motion:reduce){
  .rktrade.washing,.rkmask-trade.washing{animation:none}
  .rktrade.handing .rktrade-words,.rktrade.handing .rktrade-hands{
    animation:none;opacity:1}
}

@media (max-width:1080px){
  .rktrade-words{font-size:15px}
  .rktrade-hands{gap:10px;padding:0 8px}
  .rktrade-who{gap:6px}
  .rktrade-who b{font-size:12px}
  .rktrade-img{width:30px;height:30px}
  .rktrade-arrows{width:26px;height:26px;padding:4px}
}


/* ── the league's trades, in the bell ─────────────────────────────────
   Every trade shows for everyone, in the same card the Historical tab
   draws, each with its own way out. */
.note-head{margin:14px 0 8px;font-family:var(--cond);font-size:10px;
  font-weight:700;letter-spacing:.16em;text-transform:uppercase;
  color:var(--muted)}
.note-head:first-child{margin-top:0}
/* The card was built for the trades panel, which is wider than this modal.
   Everything in it is a flex row, and a flex child won't shrink below its
   content without min-width:0 — so a long name pushed the card past the
   card it sits in. These are scoped to the notification so the panel's own
   layout is untouched. */
.note-trade{position:relative;margin-bottom:8px;max-width:100%;min-width:0}
.note-trade .trade{width:100%;min-width:0;box-sizing:border-box;
  padding:11px;overflow:hidden}
.note-trade .trade-head,.note-trade .trade-body,.note-trade .trade-side,
.note-trade .trade-team,.note-trade .trade-asset,
.note-trade .trade-asset-mid,.note-trade .tb-item,
.note-trade .tb-item-mid{min-width:0}
.note-trade .trade-team b,.note-trade .trade-asset-mid b,
.note-trade .tb-item-mid b,.note-trade .trade-asset > span:nth-child(2){
  min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.note-trade .trade-body{gap:8px}
/* The × sits over the card's top-right, so keep the tag clear of it. */
.note-trade .trade-head{padding-right:26px}
/* One you were in reads a shade louder than one you only heard about. */
.note-trade.mine .trade{border-color:#3a4756}
.note-x{position:absolute;top:6px;right:6px;z-index:2;width:22px;height:22px;
  padding:0;border:0;border-radius:50%;background:none;color:#5c6878;
  font-size:18px;line-height:1;cursor:pointer;display:flex;
  align-items:center;justify-content:center;
  -webkit-tap-highlight-color:transparent}
.note-x:hover{background:var(--slate-2);color:var(--text)}
.trade-tag.tag-mine{color:var(--teal)}

/* The trade button carries a count of its own, same shape as the bell's. */
#tradeBtn{position:relative}
#tradeBtn.on{color:var(--teal);border-color:var(--teal)}


/* ── a pick on the block ──────────────────────────────────────────────
   The badge inverts: black, with the round's own medal colour as the
   lettering rather than behind it. Something available reads differently
   from something merely owned. */
.rkslot.onblock .rkslot-no{background:#0a0d14;color:var(--gold);
  box-shadow:inset 0 0 0 1px #3a2f12}
.rkslot.onblock .rkslot-no.r2{color:#c6ced8;box-shadow:inset 0 0 0 1px #39404a}
.rkslot.onblock .rkslot-no.r3{color:#c88a52;box-shadow:inset 0 0 0 1px #43301e}
.rkslot.onblock .rkslot-no.r4{color:var(--text)}
/* The label overlaps the badge's bottom edge, so it belongs to the badge
   rather than sitting beside it in the row. Absolutely positioned and
   unbacked: it sits over whatever is behind it and takes no space, so the
   badge and the row keep the size they had. */
.rkslot.onblock .rkslot-no{position:relative;overflow:visible}
.rkslot.onblock .rkslot-no i{position:absolute;left:50%;bottom:-4px;
  transform:translateX(-50%);white-space:nowrap;pointer-events:none;
  font-family:var(--cond);font-style:normal;font-size:7.5px;font-weight:700;
  letter-spacing:.08em;text-transform:uppercase;color:var(--red)}

/* ── the pick on the clock is on the block ────────────────────────────
   The banner goes pink and says so behind everything, the way the auction
   marks a player you've passed on. */
.rkclock.live.onblock{background:linear-gradient(180deg,#7a1f45 0%,#571432 100%);
  border-bottom-color:#b03a6b}
.rkclock.live.onblock .rkclock-time{color:#ffd7e6}
.rkclock.onblock::before{content:"";position:absolute;inset:0;z-index:0;
  pointer-events:none;
  /* 210 wide, not 128: rotated at 13px with 2px tracking the phrase runs
     about 90px, and the second copy started at x=64 — so both ran past
     the tile's edge and repeated as "ON THE". The tile has to be wider
     than the text it carries. */
  background-image:url("data:image/svg+xml;utf8,\
<svg xmlns='http://www.w3.org/2000/svg' width='210' height='34'>\
<text x='2' y='13' font-family='Barlow Condensed,Arial Narrow,sans-serif'\
 font-size='13' font-weight='700' letter-spacing='2'\
 fill='%23ffffff' fill-opacity='0.13' transform='rotate(-12 2 13)'>ON THE BLOCK</text>\
<text x='105' y='30' font-family='Barlow Condensed,Arial Narrow,sans-serif'\
 font-size='13' font-weight='700' letter-spacing='2'\
 fill='%23ffffff' fill-opacity='0.13' transform='rotate(-12 105 30)'>ON THE BLOCK</text>\
</svg>");
  background-repeat:repeat}
/* The bar's own contents sit above the watermark — named individually,
   because the wash, the shards, the reveal and the trade card are also
   direct children and they are absolutely positioned. A blanket
   `.rkclock > *` turned those into flow elements and they stopped
   covering the banner at all. */
.rkclock > .rkclock-face,
.rkclock > .rkclock-who,
.rkclock > .rkclock-time{position:relative;z-index:1}
/* The rail is absolute already; it only needs to sit above the watermark. */
.rkclock-rail{z-index:1}

@media (max-width:1080px){
  .rkslot.onblock .rkslot-no i{font-size:6.5px;bottom:-3px}
}


/* The armed player's way back off the slot, without reaching for the bar. */
.rkslot-x{flex:0 0 auto;width:20px;height:20px;padding:0;border:0;
  border-radius:50%;background:none;color:#7d8a9c;font-size:16px;line-height:1;
  cursor:pointer;display:flex;align-items:center;justify-content:center;
  -webkit-tap-highlight-color:transparent}
.rkslot-x:hover{background:#ffffff14;color:var(--text)}


/* ── steadier pictures ────────────────────────────────────────────────
   Every photo on these pages is a fixed size, so reserving it up front
   stops the row settling as each one arrives. Fading in rather than
   appearing keeps a slow one from popping. */
.rk-face img,.rkslot-face img,.rkclock-face img,.rkreveal-shot img,
.rktrade-img img,.teampick-face img{
  background:var(--slate-2);
  animation:photo-in .18s ease-out}
/* The trades panel's faces are not faded. A dozen of them arrive together
   when the panel opens, and a dozen fades at once is the flicker rather
   than the cure for it. */
#tradesSheet .tb-face img,#tradesSheet .rk-face img{animation:none}
/* The home grid's dozen photos are deliberately not faded: they are all on
   screen at once, so any repaint would flash the whole page. */
.teamface img{background:var(--slate-2)}
@keyframes photo-in{from{opacity:0}to{opacity:1}}
/* The badge and logo images too — small, but there are dozens per screen. */
.rk-logo,.rkreveal-logo,.dhist-logo{background:transparent}

/* Toggling a view or a filter reorders rows that already exist rather than
   rebuilding them, so this is the only movement left. */
/* No content-visibility here. It skips rendering offscreen rows, which
   sounds right for a list this long — but every pass over the list makes
   the browser re-decide what's visible, and rows crossing that boundary
   blink as they're rendered again. The row cache is what actually made
   this list cheap; this was making it flicker. */
.rkrow{transition:background-color .14s ease,border-color .14s ease,
  opacity .14s ease}
.rkslot{transition:background-color .14s ease,border-color .14s ease}
.rktabs button,.rkpos button,.blockbtn{transition:background-color .14s ease,
  color .14s ease,border-color .14s ease}

@media (prefers-reduced-motion:reduce){
  .rk-face img,.rkslot-face img,.rkclock-face img,.rkreveal-shot img,
  .rktrade-img img,.teampick-face img,.teamface img{animation:none}
  .rkrow,.rkslot,.rktabs button,.rkpos button,.blockbtn{transition:none}
}


/* ── the board on a desktop ───────────────────────────────────────────
   The same list a phone shows, in the same order and the same shape — the
   square-tile grid read as a wall of faces and made a pick harder to find,
   not easier. Only the rows are taller: a desktop has the height, and a
   roomier row is easier to aim a drag at. */
@media (min-width:1081px){
  .rkboard-list{padding:14px 14px 18px}
  .rkround + .rkround{margin-top:16px}

  /* The desktop headshot is 32px, so the row is that plus its padding. */
  .rkslot{padding:9px 10px;gap:10px;border-radius:6px;min-height:52px}
  .rkslot-no{min-width:38px;padding:4px 7px;font-size:12px}
  .rkslot-face{width:32px;height:32px}
  .rkslot-who b{font-size:13.5px}
  .rkslot-who span{font-size:10px}
  .rkslot.filled .rkreveal-shot .rk-face{width:32px;height:32px}
  .rkslot.filled .rkreveal-logo{width:15px;height:15px}
  .rkslot-sal{font-size:13px}
  .rkslot.onclock{padding:12px 10px}

  /* The class list beside it, to match. */
  .rklist{gap:6px}
  .rkrow{padding:9px 11px;gap:10px}
  .rk-face{width:36px;height:36px}
  .rk-name b{font-size:13px}
  .rk-sub{font-size:10.5px;gap:6px}
  .rk-logo{width:16px;height:16px}
  .rk-target{width:26px;height:26px}
  .rk-target svg{width:24px;height:24px}
}



/* ── a card with a pinned trade button ────────────────────────────────
   The same corner button the trades panel has, on a card: it holds the
   bottom-right however far the card scrolls, and pulses so it reads as the
   thing to do next rather than as decoration. */
.modal-card.has-fab{position:relative}
.modal-card.has-fab .modal-body{padding-bottom:74px}
/* The block control, in the corner opposite the trade one. Same size and
   the same footing, so the two read as a pair. */
.modal-card.has-fab-left{position:relative}
.modal-card.has-fab-left .modal-body{padding-bottom:74px}
/* On the card it's the full-size pill, in the corner opposite the trade
   button. */
.card-fab-left{position:absolute;left:16px;bottom:22px;z-index:3;
  width:88px;height:34px;margin-left:0;font-size:10px}
/* Cut, on a player's card. Round and red, the mirror of the trade fab on
   the right — the .card-fab-left size above is for the builder's text
   button, which this is not. */
.card-fab-left.card-cut{width:46px;height:46px;bottom:16px;
  border-radius:50%;border:1px solid var(--red);background:var(--slate);
  color:var(--red);display:flex;align-items:center;justify-content:center;
  padding:0;font-size:0;cursor:pointer;transition:transform .12s}
.card-fab-left.card-cut svg{width:22px;height:22px}
.card-fab-left.card-cut:hover{background:#3a1b18}
.card-fab-left.card-cut:active{transform:translateY(2px)}
/* Room at the foot for it, as the right-hand fab already claims. */
.modal-card.has-fab-left .modal-body{padding-bottom:74px}

/* The same info icon on a condensed row, which had no way into the card. */
.rlist-info{margin-left:7px;flex:0 0 auto}
.card-fab{position:absolute;right:16px;bottom:16px;z-index:3;
  width:46px;height:46px;padding:0;border-radius:50%;
  border:1px solid var(--green);background:var(--slate);
  display:flex;align-items:center;justify-content:center;cursor:pointer;
  -webkit-tap-highlight-color:transparent;transition:transform .12s;
  animation:fab-breathe 2s ease-in-out infinite}
.card-fab svg{width:24px;height:24px;display:block}
.card-fab:active{transform:translateY(2px)}
@media (prefers-reduced-motion:reduce){ .card-fab{animation:none} }

/* ── a pick, opened from the board ────────────────────────────────────  */
.slotcard{width:min(420px,100%)}
.slotcard-who{display:flex;align-items:center;gap:12px;padding:12px;
  background:var(--slate-2);border:1px solid var(--line);border-radius:4px}
.slotcard-face{flex:0 0 auto;width:46px;height:46px;border-radius:50%;
  overflow:hidden;background:var(--slate);display:flex;align-items:center;
  justify-content:center}
.slotcard-face img{width:100%;height:100%;object-fit:cover;
  object-position:top center}
.slotcard-mid{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.slotcard-mid b{font-family:var(--block,'Archivo Black',sans-serif);
  font-weight:400;font-size:16px;text-transform:uppercase;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.slotcard-mid span{font-family:var(--cond);font-size:10.5px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted)}
.slotcard-sal{flex:0 0 auto;font-family:var(--cond);font-weight:700;
  font-size:21px;font-variant-numeric:tabular-nums;color:var(--money)}
.slotcard-facts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:8px;margin-top:12px}
.slotcard-fact{padding:9px 11px;background:var(--slate-2);
  border:1px solid var(--line);border-radius:4px;display:flex;
  flex-direction:column;gap:2px;min-width:0}
.slotcard-fact span{font-family:var(--cond);font-size:9.5px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted)}
.slotcard-fact b{font-family:var(--block,'Archivo Black',sans-serif);
  font-weight:400;font-size:14px;min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}

/* The rows say they can be opened. */
.rkslot{cursor:pointer}


/* ── the trade, as it stands ──────────────────────────────────────────
   A running summary beside the two lists: who gets what, and what it does
   to each side's money. Built from the same picked() lists the submit uses,
   so it can't describe a different trade from the one that would be made. */
.tb-side{display:flex;flex-direction:column;
  color:var(--text);margin-top:12px;padding:12px;border-radius:6px;
  background:var(--slate-2);border:1px solid var(--line);min-width:0}
.tb-side-title{font-family:var(--cond);font-size:10px;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;color:var(--muted);
  margin-bottom:9px}
.tb-side-empty{margin:0;font-size:12.5px;color:var(--muted);line-height:1.5}
/* Why the trade can't be sent yet — said here rather than left to a
   disabled button with no explanation. */
.tb-side-warn{margin:0 0 10px;padding:7px 9px;border-radius:4px;
  background:#3a1d1a;border:1px solid #5d3330;color:#ff9c92;
  font-family:var(--cond);font-size:11px;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase}
/* Fills what's left of the panel, so each block has a bottom for its
   salary line to sit at rather than ending wherever its rows do. */
.tb-side-pair{flex:1;min-height:0;display:flex;flex-direction:column}
.tb-side-block + .tb-side-block{margin-top:10px;padding-top:10px;
  border-top:1px solid var(--line)}
/* Between the two sides. Rotated flat where they're stacked, upright where
   they sit beside each other. */
.tb-side-swap{display:none}
.tb-side-swap svg{width:22px;height:22px;display:block}
.tb-side-head{grid-row:1;display:flex;align-items:baseline;gap:8px;
  margin-bottom:6px;min-width:0}
.tb-side-head b{font-family:var(--block,'Archivo Black',sans-serif);
  font-weight:400;font-size:13px;text-transform:uppercase;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tb-side-head span{flex:0 0 auto;font-family:var(--cond);font-size:10px;
  letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
.tb-side-none{margin:0;font-size:12px;color:var(--muted)}
.tb-side-row{display:flex;align-items:center;gap:8px;padding:4px 0;
  min-width:0}
/* The asset's own art rather than a bullet: a headshot for a player, a
   round-coloured badge for a pick. */
.tb-side-art{flex:0 0 auto}
.tb-side-art.tb-face{--badge-w:28px;--badge-h:32px}
.tb-side-art.trade-pick{min-width:30px;font-size:10px;padding:2px 5px}
/* The position, in its own colour, after the name. */
.tb-side-fullwrap{display:flex;align-items:baseline;gap:5px;min-width:0}
.tb-side-fullwrap .tb-side-full{min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.tb-side-pos{flex:0 0 auto;font-family:var(--cond);font-size:9.5px;
  font-weight:400;letter-spacing:.08em}
.tb-side-pos.pos-QB{color:var(--pos-qb)}
.tb-side-pos.pos-RB{color:var(--pos-rb)}
.tb-side-pos.pos-WR{color:var(--pos-wr)}
.tb-side-pos.pos-TE{color:var(--pos-te)}

/* One label at a time: the full one here, the short one on a phone. */
/* The phone's short label. !important because it is easy to write another
   rule that outranks a plain display:none by accident — which is exactly
   what happened, and it duplicated every name on the desktop. It is shown
   in one place only: the phone block at the end of this file. */
.tb-side-short{display:none!important;min-width:0;align-items:baseline;gap:4px}
/* Which round a pick is, in the medal order the board uses — and blue for
   a fourth, which has no medal. Phone only: there the label is all you get,
   so the colour carries the round. The desktop rows have the round in
   words on the line below, so the label stays white. */
/* The team a future pick came from, after the dot. */
.tb-side-own{flex:0 0 auto;color:var(--muted);font-weight:600}
.tb-side-mid{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.tb-side-mid b{font-size:12.5px;min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
/* The running "gives N" line, everywhere: the summary panel says what each
   team gives in full, so this only repeated it in shorthand. */
#builder #outA,#builder #outB{display:none}

/* The sub-line by name, not "any span in here" — that was more specific
   than .tb-side-short and forced the phone's short label to show on the
   desktop, and hid it on the phone. */
.tb-side-sub{display:flex;align-items:center;gap:5px;
  font-family:var(--cond);font-size:9.5px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted);min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.tb-side-sub > span{min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.tb-side-logo{flex:0 0 auto;width:13px;height:13px;object-fit:contain}
.tb-side-sal{flex:0 0 auto;font-family:var(--cond);font-weight:700;
  font-size:13px;font-variant-numeric:tabular-nums;color:var(--money)}
/* Out of the trade from here too. */
.tb-side-x{flex:0 0 auto;width:20px;height:20px;padding:0;border:0;
  border-radius:50%;background:none;color:#5c6878;font-size:15px;line-height:1;
  cursor:pointer;display:flex;align-items:center;justify-content:center;
  -webkit-tap-highlight-color:transparent}
.tb-side-x:hover{background:var(--slate);color:var(--text)}
/* Always last in its block, and worded exactly like the column head so the
   two don't have to be reconciled. */
/* The middle row: all the assets, however many. */
.tb-side-rows{grid-row:2;min-width:0}

/* The last grid row, so it sits at the foot of its block whatever is
   above it. */
.tb-side-net{grid-row:3;margin-top:0;padding-top:9px;
  border-top:1px solid var(--line);display:flex;flex-direction:column;
  gap:2px;align-items:flex-start}
/* A grid rather than a flex column: three rows — the heading, the assets,
   and the salary — with the middle one taking whatever is spare. That
   pins the salary to the bottom of the block by structure, instead of
   relying on the block having been stretched to a height first. Flex and
   margin-top:auto only work if something above has already agreed to
   stretch it, and here that kept quietly not happening. */
.tb-side-block{flex:1;min-height:0;display:grid;
  grid-template-rows:auto 1fr auto;align-content:stretch}

/* Wide enough, and it sits beside the lists rather than under them. */
@media (min-width:900px){
  /* align-items:start let the columns be as tall as their contents, which
     broke the chain the asset lists scroll on — they grew instead of
     scrolling. Stretch, with min-height:0 all the way down, so the lists
     get a definite height and overflow inside it. */
  /* Three rows, not two: the All / Picks toggle is a child of this grid
     and had no placement, so it landed in an implicit row at the foot of
     the card. It belongs at the top, over the lists it filters — the same
     order the phone has. */
  #builder .sheet-body{display:grid;grid-template-columns:minmax(0,1fr);
    grid-template-rows:auto minmax(0,1fr) auto auto;
    column-gap:14px;align-items:stretch;min-height:0;overflow:hidden}
  /* justify-self, not align-self: this is a grid item here, and a grid
     item stretches across its column unless told otherwise. That's why the
     toggle ran the width of the card. */
  #builder .tbdensity{grid-column:1;grid-row:1;margin:0 0 10px;
    justify-self:start}
  #builder .tb-cols{grid-column:1;grid-row:2;min-height:0}
  /* The sidecar has room beside the lists, so the tab has no job here. */
  /* Under the lists, not beside them — the same order the phone uses, so
     the card reads the same whichever you open it on. */
  /* One rule: placement and display together, rather than two that a
     reorder could put in the wrong order. The drawer is the phone's, now
     that the summary sits under the lists rather than beside them — a tab
     you press, and the sides beneath it. It was hidden here because there
     used to be a column to put the summary in. */
  #builder .tb-fold{grid-column:1 / -1;grid-row:3;min-height:0;
    display:flex;flex-direction:column}
  #builder .tb-fold-tab{display:flex;align-items:center;gap:8px;
    width:100%;padding:9px 12px;border:1px solid rgba(74,155,232,.5);
    border-left:0;border-right:0;
    background:rgba(28,74,124,.78);-webkit-backdrop-filter:blur(12px);
    backdrop-filter:blur(12px);color:#eaf3ff;cursor:pointer;
    font-family:var(--cond);font-size:11.5px;font-weight:700;
    letter-spacing:.16em;text-transform:uppercase}
  #builder .tb-fold-word{flex:0 0 auto}
  #builder .tb-fold-count{flex:1;min-width:0;text-align:right;
    letter-spacing:.08em;color:#a8cdf2}
  #builder .tb-fold-arrow{flex:0 0 auto;font-size:12px;line-height:1;
    transition:transform .2s ease}
  #builder .tb-fold.open .tb-fold-arrow{transform:rotate(180deg)}
  #builder .tb-side{display:none;flex:0 0 auto;margin-top:0;max-height:34vh;
    overflow-y:auto;padding:10px;border-radius:0;border:0}
  #builder .tb-fold.open .tb-side{display:flex}
  /* The two sides across the card with the swap between them — the phone's
     arrangement, now that the summary is full width here too. One grid for
     both sides, so their headings, rows and salary lines share rows and
     can't disagree about heights. */
  #builder .tb-side-pair{display:grid;
    grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);
    grid-template-rows:auto 1fr auto;column-gap:12px}
  #builder .tb-side-pair > .tb-side-block{display:contents}
  #builder .tb-side-pair > .tb-side-block:first-child > *{grid-column:1}
  #builder .tb-side-pair > .tb-side-block:last-child > *{grid-column:3}
  #builder .tb-side-pair > .tb-side-swap{grid-column:2;grid-row:1 / -1;
    align-self:center}
  #builder .tb-side-head{grid-row:1}
  #builder .tb-side-rows{grid-row:2}
  #builder .tb-side-net{grid-row:3}
  #builder .tb-side-block + .tb-side-block{margin-top:0;padding-top:0;
    border-top:0}
  #builder .tb-side-swap{display:flex;flex:0 0 auto;align-self:center;
    color:var(--muted)}
  #builder .tb-side-swap svg{width:20px;height:20px}
  #builder .tb-note{grid-column:1 / -1;grid-row:4}
}


/* ── the builder on a phone ───────────────────────────────────────────
   The two lists take the screen and the summary is frozen under them. The
   running totals, the prompt and the note came out to make the room: the
   totals repeat what the summary says properly, and a note is something
   you can add from the offer itself. */
@media (max-width:899px){
  #builder #tbSummary,#builder .tb-note{display:none}

  #builder .sheet-body{display:flex;flex-direction:column;min-height:0;
    overflow:hidden;gap:10px}
  #builder .tb-cols{flex:1;min-height:0;
    /* Two rows now the prompt row is gone, so the lists start higher. */
    grid-template-rows:auto minmax(0,1fr)}
  /* The third row held "gives nothing", which is hidden here — so the head
     is two rows now and everything below it starts that much higher. */
  #builder .tb-colhead{gap:6px;grid-template-rows:34px auto;padding-bottom:2px}
  #builder .tb-team-face{width:28px;height:28px}
  #builder .tb-cap{font-size:11px}
  #builder .cap-label{font-size:9px}
  /* The head is taller now, so the foot gives its room back — every pixel
     here is a pixel the two roster columns don't have.

     Even top and bottom, with no safe-area inset: the sheet around this
     already pads for the home indicator, and adding it again here pushed
     the button up so it sat against the rule instead of between it and the
     bottom edge. */
  #builder .sheet-foot{padding:9px 10px;justify-content:center}
  #builder .sheet-foot .btn{padding:9px;font-size:13px}

  /* A tab on the card rather than a panel under it. Closed it's one line
     saying how big the trade is; open it's the trade. The red glass is the
     rookie board's tab, so the gesture is one people have already met. */
  #builder .tb-fold{flex:0 0 auto;margin-top:0;display:flex;
    flex-direction:column;min-height:0}
  /* Steel rather than red. Red is the app's warning colour and this is
     just a drawer — the pale rule and the light lettering are enough to
     find it without it reading as something gone wrong. */
  #builder .tb-fold-tab{display:flex;align-items:center;gap:8px;
    width:100%;padding:10px 12px;border:1px solid rgba(74,155,232,.5);
    border-left:0;border-right:0;
    background:rgba(28,74,124,.78);-webkit-backdrop-filter:blur(12px);
    backdrop-filter:blur(12px);color:#eaf3ff;cursor:pointer;
    font-family:var(--cond);font-size:11.5px;font-weight:700;
    letter-spacing:.16em;text-transform:uppercase;
    -webkit-tap-highlight-color:transparent}
  #builder .tb-fold-word{flex:0 0 auto}
  #builder .tb-fold-count{flex:1;min-width:0;text-align:right;
    letter-spacing:.08em;color:#a8cdf2}
  #builder .tb-fold-arrow{flex:0 0 auto;font-size:12px;line-height:1;
    transition:transform .2s ease}
  #builder .tb-fold.open .tb-fold-arrow{transform:rotate(180deg)}

  /* Closed by default: the lists are what you came here to use. */
  #builder .tb-side{display:none;flex:0 0 auto;margin-top:0;max-height:44vh;
    overflow-y:auto;padding:10px;border-radius:0;border:0;
    box-shadow:0 -10px 20px #0000004d}
  /* flex, not block: the salary lines sit at the bottom of equal-height
     blocks, and that only works while this is a flex column. display:block
     quietly undid the whole arrangement. */
  #builder .tb-fold.open .tb-side{display:flex}

  /* Small enough that a four-piece trade still fits. */
  #builder .tb-side-title{font-size:9px;margin-bottom:6px}
  /* Side by side, with the swap mark between: a phone has width to spare
     here and height it doesn't. */
  /* One grid for both sides, not two blocks hoping to match heights.
     display:contents dissolves each block so its three parts become items
     of this grid directly — which means both headings share row 1, both
     asset lists share row 2, and both salary lines share row 3. They can't
     disagree, because they are the same row. */
  #builder .tb-side-pair{display:grid;
    grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);
    grid-template-rows:auto 1fr auto;column-gap:8px}
  #builder .tb-side-pair > .tb-side-block{display:contents}
  #builder .tb-side-pair > .tb-side-block:first-child > *{grid-column:1}
  #builder .tb-side-pair > .tb-side-block:last-child > *{grid-column:3}
  #builder .tb-side-pair > .tb-side-swap{grid-column:2;grid-row:1 / -1;
    align-self:center}
  #builder .tb-side-head{grid-row:1}
  #builder .tb-side-rows{grid-row:2}
  #builder .tb-side-net{grid-row:3}
  #builder .tb-side-block + .tb-side-block{margin-top:0;padding-top:0;
    border-top:0}
  #builder .tb-side-swap{display:flex;flex:0 0 auto;align-self:center}
  #builder .tb-side-swap svg{width:18px;height:18px}
  /* Stacked, the head could run along one line; in a column it can't. */
  #builder .tb-side-head{flex-direction:column;align-items:flex-start;gap:0}
  #builder .tb-side-head b{font-size:11.5px}
  #builder .tb-side-head span{font-size:9px}
  #builder .tb-side-row{gap:6px;padding:2px 0}
  #builder .tb-side-art{display:none}
  #builder .tb-side-full{display:none!important}
  #builder .tb-side-fullwrap{display:none}
  /* Explicit colour and flex sizing. It inherited both before, and an
     inherited colour is one stray rule away from being the muted grey the
     rest of this panel uses — which reads as missing text on a dark
     background rather than as dim text. */
  #builder .tb-side-short{display:flex!important;font-size:11px;
    font-weight:600;min-width:0;color:var(--text)}
  #builder .tb-side-short b{flex:0 1 auto;min-width:0;overflow:hidden;
    text-overflow:ellipsis;white-space:nowrap;color:inherit}
  #builder .tb-side-own{font-size:10px}
  /* A pick's round, over the inherited white. */
  #builder .tb-side-short b.pk-r1{color:var(--gold)}
  #builder .tb-side-short b.pk-r2{color:#c6ced8}
  #builder .tb-side-short b.pk-r3{color:#c88a52}
  #builder .tb-side-short b.pk-r4{color:var(--teal)}
  #builder .tb-side-sub{display:none}
  #builder .tb-side-sal{font-size:10.5px}
  #builder .tb-side-x{width:17px;height:17px;font-size:13px}
  #builder .tb-side-net{margin-top:4px;padding-top:4px}
  #builder .tb-side-net span{font-size:8.5px}
  #builder .tb-side-net b{font-size:11px}

  /* The salary beside each asset in the lists, a size down. */
  #builder .tb-item-sal{font-size:11px}
}


/* ── the confirmation's two answers ───────────────────────────────────
   Solid, and white on both. The dark ink these carried by default reads as
   a disabled button at this size, and these are the two most consequential
   taps in the app. */
body.dhskin .btn-go{background:var(--money);border-color:var(--money);
  color:#fff}
body.dhskin .btn-go:hover{background:#7ce0a6;border-color:#7ce0a6;color:#fff}
body.dhskin .btn-stop{background:var(--red);border-color:var(--red);
  color:#fff}
body.dhskin .btn-stop:hover{background:#ef6a5f;border-color:#ef6a5f;
  color:#fff}
body.dhskin .btn-go:disabled{background:var(--slate-2);
  border-color:var(--line);color:var(--muted)}
/* The builder's own submit, which is a .btn-go too — stated here so it
   can't be left behind if that class is ever restyled. */
body.dhskin #doTrade{background:var(--money);border-color:var(--money);
  color:#fff}
body.dhskin #doTrade:hover:not(:disabled){background:#7ce0a6;
  border-color:#7ce0a6;color:#fff}
body.dhskin #doTrade:disabled{background:var(--slate-2);
  border-color:var(--line);color:var(--muted)}

/* What the trade does to each side's money, on the confirmation. */


/* ── the three views, one shape ───────────────────────────────────────
   Offers, History and Block are three different lists of the same thing: a
   trade, or a piece of one. They had grown their own spacings, their own
   row gaps and their own filter bars, so switching tabs moved everything
   on the page. These give the three a common frame — same bar height, same
   gap, same row background — so a toggle changes the contents and nothing
   else. */
/* Both bars carry .histbar — the block view reuses it — so one rule sets
   the height both views reserve. */
#tradesSheet .histbar{min-height:34px;margin:0 0 12px;display:flex;
  align-items:center;gap:10px}
#tradesSheet .tradelist,#tradesSheet .blocklist{display:flex;
  flex-direction:column;gap:8px;margin:0;padding:0}
/* One row treatment across all three — including the padding, so a block
   row's contents start on the same line a trade card's do. */
#tradesSheet .trade,#tradesSheet .blocklist .tb-item,
#tradesSheet .openrow{background:var(--slate);border:1px solid var(--line);
  border-radius:4px}
/* The same box as a trade card: same padding, same radius, same rule, and
   a floor under the height. A trade card holds two team rows and a block
   row holds one asset, so matching the padding alone still leaves the
   block cards noticeably shorter — they sit a tab apart and the difference
   reads as a mistake. */
#tradesSheet .blocklist .tb-item{padding:13px;gap:11px;width:100%;
  box-sizing:border-box;border-radius:4px;min-height:74px}
/* The face grows with the card rather than floating in it. */
#tradesSheet .blocklist .tb-item .tb-face{--badge-w:44px;--badge-h:48px}
#tradesSheet .blocklist .tb-item .tb-item-mid{height:auto;gap:3px}
#tradesSheet .blocklist .tb-item .tb-item-mid b{font-size:14px}
/* And the group heading runs the full width rather than sitting inset. */
#tradesSheet .tb-group{margin:14px 0 6px;padding:0 0 5px}
#tradesSheet .tb-group:first-child{margin-top:0}
#tradesSheet .trade:hover,#tradesSheet .blocklist .tb-item:hover,
#tradesSheet .openrow:hover{border-color:#3a4756}
/* And one empty state. */
#tradesSheet .empty{margin:18px 0;text-align:center;font-size:13px;
  color:var(--muted)}
/* The count sits with the toggle rather than above each list. */
#tradesSheet .segwrap{margin:0 0 14px}


/* ── the block, as rows ───────────────────────────────────────────────
   Each row carries its owner's photo at the head and a rule beneath it,
   instead of a heading above a run of rows. A filtered list then still
   says whose everything is, and every row is the same shape. */
#tradesSheet .blockrow{position:relative;gap:11px}
.blockrow-owner{flex:0 0 auto;display:flex;align-items:center}
.blockrow-face{width:32px;height:32px;border-radius:50%;overflow:hidden;
  background:var(--slate-2);display:flex;align-items:center;
  justify-content:center}
.blockrow-face img{width:100%;height:100%;object-fit:cover;
  object-position:top center}
.blockrow-face .me-initials{font-size:11px}
/* A rule between rows rather than a gap, so the list reads as one table. */
#tradesSheet .blocklist{gap:0}
#tradesSheet .blockrow{border-radius:0;border-left:0;border-right:0;
  border-top:0}
#tradesSheet .blockrow:first-child{border-top-left-radius:4px;
  border-top-right-radius:4px;border-top:1px solid var(--line)}
#tradesSheet .blockrow:last-child{border-bottom-left-radius:4px;
  border-bottom-right-radius:4px}
#tradesSheet .blocklist{border-left:1px solid var(--line);
  border-right:1px solid var(--line);border-radius:4px;overflow:hidden}



/* ── cutting a player ─────────────────────────────────────────────────
   A round red control, the only one of its shape on the row: it's the one
   action here that can't be undone. */
.cutbtn{flex:0 0 auto;width:20px;height:20px;padding:0;border-radius:50%;
  /* Tight to the Block button beside it: the row's own gap would otherwise
     put it out on its own, which reads as a third column. */
  margin-right:-7px;
  background:var(--red);border:1px solid var(--red);color:#fff;
  display:flex;align-items:center;justify-content:center;cursor:pointer;
  -webkit-tap-highlight-color:transparent;transition:transform .1s,
  background-color .12s}
.cutbtn svg{width:12px;height:12px;display:block}
.cutbtn:hover{background:#ef6a5f;border-color:#ef6a5f}
.cutbtn:active{transform:translateY(2px)}

/* The card that asks. Outlined and tinted red, because the answer costs
   money and can't be taken back. */
.cutcard{width:min(420px,100%);border-color:var(--red)}
/* The tint runs the whole card, footer included — a grey bar under a red
   warning reads as a different dialogue's buttons. */
.cutcard .modal-body{background:#2a1614;text-align:center}
.cutcard .modal-foot{background:#2a1614;border-top-color:#5d3330;
  justify-content:center}
.cutcard-who{display:flex;align-items:center;gap:11px;padding:11px;
  border-radius:4px;background:#3a1d1a;border:1px solid #5d3330;
  text-align:left}
.cutcard-face{flex:0 0 auto;width:44px;height:44px;border-radius:50%;
  overflow:hidden;background:#4a2622;display:flex;align-items:flex-end;
  justify-content:center}
.cutcard-face img{width:100%;height:100%;object-fit:cover;
  object-position:top center}
.cutcard-face .me-initials{font-size:14px;align-self:center;color:#ffd9d4}
.cutcard-mid{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.cutcard-mid b{font-size:16px;min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.cutcard-mid span{font-family:var(--cond);font-size:10.5px;letter-spacing:.08em;
  text-transform:uppercase;color:#e2a9a2}
.cutcard-sal{flex:0 0 auto;font-family:var(--cond);font-weight:700;
  font-size:19px;font-variant-numeric:tabular-nums;color:var(--money)}
.cutcard .modal-lead{color:#f4d5d1}

/* What it costs, centred and in red — the figure this decision turns on. */
.cutcard-hit{margin-top:14px;padding:12px;border-radius:4px;
  background:#00000038;border:1px solid #5d3330;text-align:center;
  display:flex;flex-direction:column;gap:3px}
.cutcard-hit span{font-family:var(--cond);font-size:10px;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;color:#e2a9a2}
.cutcard-hit b{font-family:var(--cond);font-weight:700;font-size:30px;
  font-variant-numeric:tabular-nums;color:var(--red);line-height:1.05}
.cutcard-when{color:#c98d86!important;letter-spacing:.1em!important}

/* Cut is red on white; Cancel stays the quiet grey it is elsewhere. */
.btn-cut{background:var(--red);border-color:var(--red);color:#fff}
.btn-cut:hover:not(:disabled){background:#ef6a5f;border-color:#ef6a5f;
  color:#fff}
.btn-cut:disabled{opacity:.5}


/* ── cuts, under the trade history ────────────────────────────────────
   The commissioner's own section: who released whom, what it cost, and a
   way to undo it. Nobody else is served this at all. */
.cutsec{margin-top:18px;padding-top:14px;border-top:1px solid var(--line);
  display:flex;flex-direction:column;gap:8px}
.cutsec-head{font-family:var(--cond);font-size:10px;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;color:var(--muted)}
.cutrow{display:flex;align-items:center;gap:11px;padding:13px;
  background:var(--slate);border:1px solid var(--line);border-radius:4px}
.cutrow-cost{flex:0 0 auto;display:flex;flex-direction:column;
  align-items:flex-end;gap:1px;margin-left:auto}
.cutrow-sal{font-family:var(--cond);font-weight:700;font-size:14px;
  font-variant-numeric:tabular-nums;color:var(--money)}
.cutrow-pen{font-family:var(--cond);font-size:10.5px;font-weight:700;
  letter-spacing:.06em;text-transform:uppercase;color:var(--red)}
/* Put back: the row stays as a record of what happened. */
#tradesSheet .cutrow.undone{opacity:.55}
#tradesSheet .cutrow.undone .cutrow-pen{color:var(--muted)}




/* ── the document viewer ──────────────────────────────────────────────
   One screen: the header, then the document filling what's left. */
.docpage{display:flex;flex-direction:column;
  height:calc(100dvh - var(--bar-h,53px));box-sizing:border-box;
  padding:0 0 var(--sab,0px)}
.docbody{flex:1;min-height:0;display:flex;flex-direction:column;
  overflow:auto;background:#0b1526}
/* A single sheet rather than a run of pages: centred in the space it has,
   with margin:auto so it still scrolls from the top when it's taller than
   the screen — centring with justify-content would cut the top off. */
.docbody.center{padding:12px}
.docbody.center .docimg{margin:auto;max-width:100%;width:auto;
  border-radius:4px}
/* A poster, or one page of a document: full width, scrolled if it's
   taller than the screen. Pages stack with a hairline between them. */
.docimg{width:100%;height:auto;display:block;background:#fff}
.docimg + .docimg{border-top:1px solid #00000033}
.docnote{flex:0 0 auto;margin:0;padding:12px 16px;text-align:center;
  font-size:13px;color:var(--muted);border-top:1px solid var(--line)}
.docnote a{color:var(--teal)}
/* No title strip: the document is the page, and the header above it
   already says where you are. */
.docpage{height:calc(100dvh - var(--bar-h,53px))}


/* ── the franchise tag, from a roster ─────────────────────────────────
   The commissioner's control on an RFA row. Gold when it's on, since a
   tagged player is settled — the same colour the auction uses for one. */
.tagbtn{flex:0 0 auto;padding:5px 9px;border-radius:4px;
  background:transparent;border:1px solid var(--line);color:var(--muted);
  font-family:var(--cond);font-size:11px;font-weight:700;letter-spacing:.1em;
  text-transform:uppercase;cursor:pointer;
  -webkit-tap-highlight-color:transparent}
.tagbtn:hover{border-color:var(--gold);color:var(--gold)}
.tagbtn.on{background:var(--gold);border-color:var(--gold);color:#fff}
.tagbtn.on:hover{background:#ffc24a;border-color:#ffc24a;color:#fff}
.tagbtn:disabled{opacity:.5}


/* The commissioner's two controls on a trade sit on one line: reprocess
   first, revert second — the harmless one before the destructive one. */
.trade .trade-redo{margin-right:8px}


/* ── offers that moved assets ─────────────────────────────────────────
   A repair list, shown to the commissioner only when there is something to
   repair. Red-edged: every row here is the database disagreeing with what
   the league agreed to. */
.ghostsec .cutsec-head{color:var(--red)}
.ghost-lead{margin:0 0 10px;font-size:12.5px;line-height:1.5;
  color:var(--muted)}
.trade.ghost{border-color:#5d3330;background:#241715}
.ghost-who{margin:0 0 8px;font-family:var(--cond);font-size:12px;
  letter-spacing:.08em;text-transform:uppercase;color:var(--muted)}
.ghost-item{display:flex;align-items:baseline;gap:8px;padding:4px 0;
  min-width:0}
.ghost-item b{font-size:13px;min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.ghost-item > span{flex:1;font-family:var(--cond);font-size:10.5px;
  letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
.ghost-sal{flex:0 0 auto!important;font-family:var(--cond);font-weight:700;
  font-size:12.5px;color:var(--money)}
.trade.ghost .btn{margin-top:10px}


/* ── the rookie page holds still ──────────────────────────────────────
   The two boards scroll inside themselves; the page behind them must not,
   or a flick that misses a list drags the whole thing and the banner
   leaves the screen. */
html:has(body.dhskin .rookiepage),
body.dhskin:has(.rookiepage){height:100dvh;overflow:hidden;
  overscroll-behavior:none}
.rookiepage .rkboard-list,
.rookiepage .rklist{overscroll-behavior:contain}

/* ── the class list, folded away ──────────────────────────────────────
   Room for the board when you want it, and the list back with one tap. */
/* An extra wash sits in the same layer as the first, positioned per slot. */
.rkmask-extra{position:absolute;z-index:inherit}

.rkcar-head{display:flex;align-items:center;gap:8px}
.rkcar-head .rkcar-title{flex:1;min-width:0}
.rkcar-fold{flex:0 0 auto;width:26px;height:26px;padding:0;border-radius:4px;
  background:none;border:1px solid var(--line);color:var(--muted);
  cursor:pointer;display:flex;align-items:center;justify-content:center;
  -webkit-tap-highlight-color:transparent}
.rkcar-fold:hover{color:var(--text);border-color:#3a4756}
.rkcar-fold svg{width:14px;height:14px;display:block;
  transition:transform .18s ease}
.rookiepage.folded .rkcar-fold svg{transform:rotate(180deg)}

@media (min-width:1081px){
  /* Folded: the sidecar goes entirely and the edge tab takes its place.
     It used to narrow to a 44px spine with the search and the filters
     squashed into it — a panel pretending to be a control. The UFA page
     shares this grid, so both rooms fold the same way.

     The column animates rather than snapping, and the panel is laid out
     at its own width and clipped by the column, so nothing re-wraps on
     the way out. */
  .rookiepage{transition:grid-template-columns .3s cubic-bezier(.22,.7,.3,1)}
  .rookiepage.folded{grid-template-columns:minmax(0,1fr) 0}
  .rookiepage > .rkcar{justify-self:start;width:360px;min-width:360px;
    box-sizing:border-box;transition:opacity .22s ease}
  .rookiepage.folded > .rkcar{opacity:0;pointer-events:none;
    transition:opacity .18s ease .1s}

  /* One control, in one place, for both states: the tab rides the panel's
     outer edge at a fixed height rather than a chevron that appears in
     the panel head only when the panel is there. */
  .rookiepage .rkcar-fold{display:none}
  /* Full bleed, as the UFA page is: no max-width, no centring gutter, no
     page padding. The class column runs flush to the right edge and the
     full height of the page, and the draft board takes what's left.

     That also makes the tab's position a single known number — the column
     width — instead of four that each move on their own. No measuring, so
     no lag. */
  /* Sides and bottom to zero, but the top still has to clear the fixed
     header and banner — that padding is what keeps the board out from
     under them. Setting padding:0 wholesale took it with the rest. */
  /* No page padding, but the board keeps a margin on every side except
     the one that meets the class column — that gap is the grid's, so the
     two panels don't touch. */
  .rookiepage{max-width:none;margin:0;gap:0 14px;
    padding:calc(20px + var(--rktop-h,110px)) 0 0}
  .rookiepage > .rkboard{margin:0 0 14px 14px}
  /* The class column runs from the banner to the bottom: no top margin to
     leave a strip of page showing above it. */
  .rookiepage > .rkcar{margin:0}
  .rookiepage > .rkcar{border-radius:0;border-right:0;border-top:0;
    border-bottom:0;border-left:1px solid var(--line);height:100%;
    align-self:stretch;
    /* Up by the page's own 20px, which is the strip of page that showed
       above it. Not a row span: rows one and two are the banner and the
       commissioner's bar, and spanning them would put the column over the
       admin controls whenever they're on screen. */
    margin-top:-20px}

  .rookiepage .rkcartab{display:flex;position:fixed;z-index:70;
    right:360px;top:50%;transform:translateY(-50%);
    flex-direction:column;align-items:center;gap:7px;
    padding:14px 7px 12px;border:1px solid rgba(226,87,76,.55);
    border-right:0;border-radius:11px 0 0 11px;
    background:rgba(150,42,35,.62);-webkit-backdrop-filter:blur(12px);
    backdrop-filter:blur(12px);color:#ffd9d4;
    box-shadow:-4px 0 18px #0006;cursor:pointer;
    transition:right .3s cubic-bezier(.22,.7,.3,1)}
  /* Folded: the screen's edge, which is simply 0 now. */
  .rookiepage.folded .rkcartab{right:0}
  .rookiepage .rkcartab-word{writing-mode:vertical-rl;
    font-family:var(--cond);font-size:11px;font-weight:700;
    letter-spacing:.2em;text-transform:uppercase}
  .rookiepage .rkcartab-arrow{font-size:13px;line-height:1;
    transition:transform .3s ease}
  .rookiepage.folded .rkcartab-arrow{transform:rotate(180deg)}
  .rookiepage .rkcarveil{display:none}
}
@media (min-width:1500px){
  /* The page's own columns and gaps widen here, so the tab follows. */
  .rookiepage > .rkcar{width:400px;min-width:400px}
  .rookiepage .rkcartab{right:400px}
  .rookiepage.folded .rkcartab{right:0}
}


/* ── the class, off the edge on a phone ───────────────────────────────
   A two-column board on a 390px screen gives neither column enough room.
   So below the desktop breakpoint the class comes out of the grid and
   waits off the right edge behind a tab — the same shape the hub's news
   rail uses, and the same gesture. */
@media (max-width:1080px){
  .rookiepage{grid-template-areas:"clock clock" "admin admin" "board board";
    grid-template-columns:minmax(0,1fr)}

  .rkcar{position:fixed;top:var(--rktop-h,110px);right:0;
    width:min(340px,86vw);
    height:calc(100dvh - var(--rktop-h,110px) - var(--sab,0px));
    z-index:71;border-radius:8px 0 0 8px;border-right:0;
    transform:translateX(101%);transition:transform .28s
      cubic-bezier(.22,.61,.36,1);
    box-shadow:-8px 0 26px #0008}
  body.rkcar-open .rkcar{transform:translateX(0)}

  /* The tab: parked at the edge, riding out with the panel. */
  /* Red glass: the league's own colour, seen through it. touch-action:none
     is what lets a drag up the edge move the tab instead of scrolling the
     page underneath. */
  .rkcartab{position:fixed;z-index:70;right:0;top:52%;
    transform:translateY(-50%);
    display:flex;flex-direction:column;align-items:center;gap:7px;
    padding:14px 7px 12px;border:1px solid rgba(226,87,76,.55);
    border-right:0;border-radius:11px 0 0 11px;
    background:rgba(150,42,35,.62);-webkit-backdrop-filter:blur(12px);
    backdrop-filter:blur(12px);color:#ffd9d4;
    box-shadow:-4px 0 18px #0007;cursor:pointer;
    touch-action:none;-webkit-user-select:none;user-select:none;
    -webkit-tap-highlight-color:transparent;
    transition:transform .28s cubic-bezier(.22,.61,.36,1)}
  /* Following a finger, not easing to a tap. */
  .rkcartab.dragging{transition:none;cursor:grabbing}
  .rkcartab-word{writing-mode:vertical-rl;text-orientation:mixed;
    font-family:var(--cond);font-size:11px;font-weight:700;
    letter-spacing:.18em;text-transform:uppercase}
  .rkcartab-arrow{font-size:15px;line-height:1;transition:transform .28s ease}
  body.rkcar-open .rkcartab{
    transform:translateY(-50%) translateX(calc(-1 * min(340px,86vw)))}
  body.rkcar-open .rkcartab-arrow{transform:rotate(180deg)}

  /* Tap anywhere else to put it away. */
  .rkcarveil{position:fixed;inset:0;z-index:69;background:#080b0f00;
    pointer-events:none;transition:background .28s ease}
  body.rkcar-open .rkcarveil{background:#080b0f99;pointer-events:auto}
  /* Held for a third of a second after the panel closes, so the tap that
     closed it can't also press what was under it. */
  body.tap-shield .rkcarveil{pointer-events:auto}

  /* The desktop fold has nothing to do here — this is the fold. */
  .rkcar-fold{display:none}
}


/* ── moving a target ──────────────────────────────────────────────────
   Two small arrows at the end of the row, on your own board only. They sit
   before the Draft button, which pushes them along rather than over. */
.rk-move{flex:0 0 auto;display:flex;flex-direction:column;gap:1px;
  margin-left:auto}
.rk-move-btn{width:20px;height:14px;padding:0;border:0;border-radius:3px;
  background:none;color:var(--muted);font-size:8px;line-height:1;
  cursor:pointer;display:flex;align-items:center;justify-content:center;
  -webkit-tap-highlight-color:transparent}
.rk-move-btn:hover{color:var(--gold);background:#ffffff0f}
.rk-move-btn:active{transform:translateY(1px)}
/* With arrows present, the Draft button stops claiming the free space —
   otherwise it pushes itself hard against them. */
.rk-move + .rk-draft{margin-left:8px}


/* ── UFA ──────────────────────────────────────────────────────────────
   The floor, the money and the bidding. It borrows the rookie board's
   shape deliberately: same banner, same sidecar, same tab on a phone, so
   there is one board to learn rather than two. */
/* The rookie board's header and banner are fixed, so it can claim the
   whole screen. This page's furniture — header, clock, the twelve faces,
   the state line — is all in normal flow above the grid, so claiming
   100dvh made the page exactly that much too tall and the bottom of the
   summary ran off the screen.
   The body becomes the column instead, and the grid takes what's left. */
html:has(.ufapage),body:has(.ufapage){height:100%;overflow:hidden}
body:has(.ufapage){display:flex;flex-direction:column}
body:has(.ufapage) > .topbar,
body:has(.ufapage) > .rkclock{flex:0 0 auto}
/* The hero takes whatever room is going; this hugs what's in it and sits
   at the bottom. It was flex:1, which is why a slate box stretched down
   the screen behind the card. */
/* No grid-template-areas here. .rookiepage declares them, and the mobile
   rule collapses them to one column — re-declaring "board car" after that
   asked for a second column the page doesn't have, and the browser made
   an implicit one. That empty column was the gap down the right. */
/* The page's own grid, rather than borrowing the rookie board's. Three
   rows on a phone — the commissioner's bar, the man on the block, the
   slab — with the pool off-canvas behind its tab.

   It borrowed .rookiepage's columns before, which put the slab in one
   half of a two-column grid and left the hero outside the grid entirely.
   That is the narrow centred column on a desktop. */
.ufapage{display:grid;height:auto;flex:1 1 auto;min-height:0;
  max-width:none;margin:0;gap:0;padding:0;overflow:hidden;
  transition:grid-template-columns .3s cubic-bezier(.22,.7,.3,1);
  grid-template-areas:"admin" "hero" "floor";
  grid-template-columns:minmax(0,1fr);
  grid-template-rows:auto minmax(0,1fr) auto}
.ufapage > .rkadmin{grid-area:admin}
.ufapage > .ufahero{grid-area:hero;min-height:0}
.ufapage > .ufafloor{grid-area:floor}

@media (min-width:1081px){
  /* Wide: the man on the block takes the room, the pool sits beside him,
     and the slab runs the full width underneath both — it's the floor of
     the page, so it shouldn't stop halfway across. */
  /* The pool runs the full height of the page and the room and the hammer
     compress beside it, rather than the slab cutting across underneath.
     That way the list stays readable to the bottom of the screen instead
     of stopping wherever the slab starts. */
  .ufapage{grid-template-areas:"admin admin" "hero car" "floor car";
    grid-template-columns:minmax(0,1fr) 380px}
  /* Laid out at its full width and clipped by the column, rather than
     reflowed at every width the animation passes through. Without the
     fixed width the tabs, the filters and every row re-wrap sixty times a
     second on the way out — which is the text piling up on itself. */
  /* The slab stops at the pool's edge now rather than running under it,
     so it needs a border on that side to meet the column cleanly. */
  .ufapage > .ufafloor{border-right:1px solid var(--line)}
  .ufapage.folded > .ufafloor{border-right:0}
  .ufapage > .rkcar{grid-area:car;justify-self:start;align-self:stretch;
    width:380px;min-width:380px;box-sizing:border-box;
    height:auto;min-height:0;
    border-left:1px solid var(--line);border-radius:0;
    display:flex;flex-direction:column;overflow:hidden;
    transition:opacity .22s ease}
  /* The list is the only part that scrolls; the tabs and the search stay
     put at the top of the column. Each holds the panel's width, so none of
     them re-wraps while the column animates. */
  .ufapage > .rkcar > .rklist{flex:1 1 auto;min-height:0;overflow-y:auto;
    width:380px;box-sizing:border-box}
  .ufapage > .rkcar > .rkcar-top,
  .ufapage > .rkcar > .rkboard-head{flex:0 0 auto;
    width:380px;box-sizing:border-box}
  /* No veil on a desktop: the panel is a column beside the page, not a
     sheet over it. */
  .ufapage .rkcarveil{display:none}
  /* Folded, the column goes entirely — a 44px spine with the tabs and the
     search squashed into it is a panel pretending to be a control. */
  .ufapage.folded{grid-template-columns:minmax(0,1fr) 0}
  .ufapage.folded > .rkcar{opacity:0;pointer-events:none;
    transition:opacity .18s ease .1s}

  /* One control, in one place, for both states: the tab rides the panel's
     outer edge and stays at the same height whether the panel is open or
     away. The chevron inside the panel head was a second control that
     appeared only in one state and moved when it did. */
  .ufapage .rkcar-fold{display:none}
  .ufapage .rkcartab{display:flex;position:fixed;z-index:70;
    right:380px;top:50%;transform:translateY(-50%);
    flex-direction:column;align-items:center;gap:7px;
    padding:14px 7px 12px;border:1px solid rgba(226,87,76,.55);
    border-right:0;border-radius:11px 0 0 11px;
    background:rgba(150,42,35,.62);-webkit-backdrop-filter:blur(12px);
    backdrop-filter:blur(12px);color:#ffd9d4;
    box-shadow:-4px 0 18px #0006;cursor:pointer;
    transition:right .3s cubic-bezier(.22,.7,.3,1)}
  .ufapage.folded .rkcartab{right:0}
  .ufapage .rkcartab-word{writing-mode:vertical-rl;
    font-family:var(--cond);font-size:11px;font-weight:700;
    letter-spacing:.2em;text-transform:uppercase}
  /* Pointing at what it will do: inward to bring the panel back, outward
     to send it away. */
  .ufapage .rkcartab-arrow{font-size:13px;line-height:1;
    transition:transform .3s ease}
  .ufapage.folded .rkcartab-arrow{transform:rotate(180deg)}

  /* The photo's offsets are percentages, which were set against a 390px
     phone. On a 1440px hero the same -30% is 432px — most of the man off
     the side of the page. Fixed pixels here, because what matters is how
     far his shoulder sits from the edge, not what share of the width that
     happens to be. */
  .ufapage .hero-shot{right:-24px}
  body.teams-folded .ufapage .hero-shot{right:-48px}

  /* The mark is the backdrop and follows the same reasoning. */
  .ufapage .hero-mark{left:50%}


}
/* Edge to edge, and it doesn't scroll: everything in it — the summary and
   the bid box — has to fit. If it ever doesn't, the elements shrink rather
   than the panel scrolling, because a bid button below the fold is a bid
   that doesn't happen. */
/* No panel around the panels — the summary and the bid box are the cards,
   and a third box around them was a frame for nothing. */
/* The bottom block: the full width of the screen, no rounding, no margin.
   A slab rather than a card — it's the floor of the page, not something
   resting on it. */
/* height:auto against .rkboard's height:100% — the rookie board wants its
   column filled, this one wants the slab to be exactly as tall as what's
   in it. */
.ufafloor{flex:0 0 auto;height:auto;min-height:0;margin:0;
  border:0;border-radius:0;
  background:var(--slate-2);border-top:1px solid var(--line)}
/* No safe-area inset here: .rookiepage already pads for the home
   indicator, and adding it again left a gap under the card the width of
   the indicator. The card ends where the page ends. */
/* The slab runs to the bottom edge of the screen. The home indicator's
   inset is padding under the card rather than a gap under the slab, so
   the colour goes all the way down and nothing is cut off. */
.ufafloor .rkboard-list{position:relative;overflow:visible;
  padding:0 0 var(--sab,0px);display:flex;flex-direction:column}
/* A shade along the very bottom, so the slab sits on the screen's edge
   rather than running off it. */
.ufafloor .rkboard-list::after{content:"";position:absolute;
  left:0;right:0;bottom:0;height:26px;pointer-events:none;
  background:linear-gradient(180deg,#00000000 0%,#00000059 100%)}

/* Where it's tight, the panels give up their padding before anything is
   cut off. */
@media (max-height:740px){
  .ufafloor .rkboard-list{padding:8px 10px 0}
  .hammer-body{padding:7px;gap:8px}
  .hammer-figs{gap:4px}
  .hammer .ufa-bid{gap:4px;min-height:82px}
  .ufa-fig{padding:5px 6px}
  .ufa-fig b{font-size:13px}
  .ufa-bidfield{font-size:19px;padding:0 32px 0 12px}
  .ufa-steps{width:25px}
  .ufa-bidgo{font-size:13px}
}

/* ── folding the room away ────────────────────────────────────────────
   A thin bar under the grid. Twelve faces are worth watching while the
   bidding is live and in the way while you're reading a roster. */
.ufafold{flex:0 0 auto;display:flex;align-items:center;justify-content:center;
  gap:6px;width:100%;padding:7px 12px;border:0;background:var(--red);
  color:#fff;cursor:pointer;
  font-family:var(--cond);font-size:9px;font-weight:700;letter-spacing:.16em;
  text-transform:uppercase;-webkit-tap-highlight-color:transparent}
.ufafold:hover{background:#ef6a5f}
.ufafold-arrow{font-size:9px;line-height:1}
/* The deck sits above the card; folded, only the bar remains. */
.ufadeck{padding:0}
/* Folded: rolled up rather than vanished, so the slab grows and shrinks
   instead of jumping. grid-template-rows animates where height:auto
   can't. */
/* The room rolls up. Every bit of spacing lives on the grid inside, not
   on the deck or the grid's own box — padding on a 0fr row is still
   painted, which is what kept a strip of it showing when folded. */
/* No align-items:start here. An item that isn't stretched keeps its own
   height, so at 0fr the faces stayed full size and spilled out of the
   collapsed row — behind the hammer card, which has no background of its
   own. Stretched, the item is the row's height, which is what makes the
   fold work at all. overflow:hidden is the belt to that braces. */
.ufadeck{display:grid;grid-template-rows:1fr;overflow:hidden;
  transition:grid-template-rows .26s cubic-bezier(.22,.7,.3,1)}
body.teams-folded .ufadeck{grid-template-rows:0fr}
/* The same dark the top bar uses, flat. The room is furniture, not a
   feature — it shouldn't be the most colourful thing on the page. */
/* The room grows down from the bar, so it collapses towards it. */
.ufadeck > .ufateams{position:relative;min-height:0;overflow:hidden;
  padding:0 12px;
  background:linear-gradient(135deg,#1e2836 0%,var(--slate) 46%,#10161f 100%)}
/* A red glow rising off the card below, so the room looks lit from the
   hammer rather than sitting on top of it. */
/* z-index:0 against the tiles' z-index:1 — as a positioned pseudo-element
   it painted over them, which is why the faces and the money boxes looked
   washed rather than lit from below. */
.ufadeck > .ufateams::after{content:"";position:absolute;z-index:0;
  left:0;right:0;bottom:0;height:64px;pointer-events:none;
  background:linear-gradient(0deg,rgba(226,87,76,.22) 0%,
    rgba(226,87,76,.07) 45%,transparent 100%)}
/* The Up / Next words sit above the faces, and the room clips what leaves
   it — so the top margin has to clear them. */
.ufadeck > .ufateams > *{margin:14px 0 8px}

/* Whoever is up, tight under the faces. */
.ufastate{flex:0 0 auto;padding:6px 12px;text-align:center;
  display:flex;align-items:baseline;justify-content:center;gap:8px;
  background:#5d4409;border-bottom:1px solid #a87d16}
.ufastate[hidden]{display:none}
.ufastate-name{font-family:var(--block,'Archivo Black',sans-serif);
  font-weight:400;font-size:17px;text-transform:uppercase;color:#fff;
  letter-spacing:.01em}
.ufastate-pos{font-family:var(--cond);font-size:12px;font-weight:700;
  letter-spacing:.14em}
.ufastate-pos.pos-QB{color:var(--pos-qb)}
.ufastate-pos.pos-RB{color:var(--pos-rb)}
.ufastate-pos.pos-WR{color:var(--pos-wr)}
.ufastate-pos.pos-TE{color:var(--pos-te)}

/* Odds and ends the block and the roster card need. */
.ufablock-none{margin:0;font-size:12.5px;color:var(--muted)}
.ufablock-tag{font-size:8.5px;letter-spacing:.14em;color:var(--gold);
  border:1px solid #6d5620;border-radius:99px;padding:1px 6px}
#rosterSheet .rrow-list{display:flex;flex-direction:column;gap:6px}
.ufacard-sub{margin:14px 0 6px;font-family:var(--cond);font-size:10px;
  font-weight:700;letter-spacing:.16em;text-transform:uppercase;
  color:var(--muted)}
/* Signed at the summit, wherever the row appears.

   No border: a coloured outline on every row turned the card into a set
   of boxes rather than a list. The word under the name says it, the same
   way ROOKIE and RFA do — and at the same size, which this wasn't. It
   set only a colour, so it inherited whatever face the row used. */
.rrow-ufa,.rr-ufa{font-family:var(--cond);font-size:10.5px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase;color:#a78bfa}

/* Show him on the board without putting him up. */
.rk-preview{flex:0 0 auto;width:30px;height:30px;margin-left:6px;padding:0;
  border:1px solid var(--line);border-radius:6px;background:var(--slate-2);
  color:var(--muted);cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  -webkit-tap-highlight-color:transparent}
.rk-preview svg{width:17px;height:17px;display:block}
.rk-preview:hover{color:var(--text);border-color:#3a4756}
/* The one currently on the board. */
.rk-preview.on{background:var(--blue);border-color:var(--blue);color:#fff}

/* A rehearsal, said plainly and constantly — a sandbox that looks like the
   real thing is only safe if nobody can forget which one they're in. */
.ufasandbox{flex:0 0 auto;padding:5px 12px;text-align:center;
  background:repeating-linear-gradient(135deg,#6d5620 0 10px,#5a4619 10px 20px);
  color:#ffe9b0;border-bottom:1px solid var(--gold);
  font-family:var(--cond);font-size:10px;font-weight:700;letter-spacing:.18em;
  text-transform:uppercase}
.ufasandbox[hidden]{display:none}
/* And a gold edge on the slab, so it reads from anywhere on the screen
   rather than only at the top. */
body.in-sandbox .ufafloor{border-top-color:var(--gold)}

/* ── the room, twelve across ──────────────────────────────────────────
   Under the hammer card, folding out of it: every owner, in nomination
   order, with what they've committed under their face. */
.ufateams{flex:0 0 auto;
  display:grid;grid-template-columns:repeat(6,minmax(0,1fr));
  gap:8px 5px;background:none;border:0}
.ufateam{display:flex;flex-direction:column;align-items:center;gap:4px;
  min-width:0;cursor:pointer;-webkit-tap-highlight-color:transparent;
  transition:transform .08s ease}
.ufateam:hover .ufateam-face{border-color:var(--blue)}
.ufateam:active{transform:translateY(2px)}

/* Just the face. The counts that flanked it are on the owner's own card,
   which is a tap away — twelve tiles each carrying three numbers was more
   arithmetic than a glance can take. */
.ufateam-top{display:flex;align-items:center;justify-content:center;
  width:100%;min-width:0}

/* position + overflow visible so the dot can sit on the rim; the photo is
   clipped by its own radius instead. */
.ufateam-face{position:relative;width:42px;height:42px;border-radius:50%;
  background:var(--slate);border:2px solid #2b3542;flex:0 0 auto;
  display:flex;align-items:center;justify-content:center}
.ufateam-face img{width:100%;height:100%;object-fit:cover;
  object-position:top center;border-radius:50%}
/* The dot rides the rim, and takes the room's colour for its ring so it
   reads as sitting on the face rather than floating over it. */
.ufateam-face .teambadge{right:-1px;bottom:-1px}
.ufateam-face .teambadge.you{border-color:#141b26}

/* The box: grey by default — a number nobody is winning with. */
/* Solid, not 60% — a translucent box over a red glow takes the glow's
   colour, which is the other half of the money looking washed out. */
.ufateam-box{width:72%;padding:8px 2px;border-radius:4px;text-align:center;
  background:#0b1119;border:1px solid var(--line);color:var(--muted);
  font-family:var(--cond);font-weight:700;font-size:14px;
  font-variant-numeric:tabular-nums;line-height:1.2}
.ufateam-box.quiet{color:#4a5666}
.ufateam-box.max{color:var(--muted)}

/* Top bid: green and moving, so the room can see who is winning without
   reading twelve numbers. */
.ufateam.leading .ufateam-face{border-color:var(--money)}
.ufateam.leading .ufateam-box{background:#155e3b;border-color:var(--money);
  color:#fff;animation:ufa-top 1.1s ease-in-out infinite}
@keyframes ufa-top{
  0%,100%{opacity:.72;transform:scale(.99)}
  50%{opacity:1;transform:scale(1.03)}
}
@media (prefers-reduced-motion:reduce){
  .ufateam.leading .ufateam-box{animation:none}
}

/* Out of money, but not out of it: a dollar player is still possible. */
.ufateam.out .ufateam-face{opacity:.45;filter:grayscale(1)}
.ufateam.out .ufateam-box{opacity:.55}
/* Full at twenty-five: that one is over. */
.ufateam.done .ufateam-face{filter:grayscale(1);opacity:.5}
.ufateam.done .ufateam-box{color:var(--red);border-color:#5d3330;
  font-size:9px;letter-spacing:.06em;padding:11px 2px}

/* ── your hammer ──────────────────────────────────────────────────────
   Figures on the left, bidding on the right, in one card. */
/* Its own background rather than none. It sits over the room's drawer, so
   transparency means anything that overflows the fold shows through it. */
.hammer{margin:0;border:0;border-radius:0;overflow:hidden;
  position:relative;z-index:1;background:var(--slate-2)}
.hammer-head{display:flex;align-items:center;gap:7px;padding:6px 12px;
  background:var(--ink);border-bottom:1px solid var(--line);color:#fff;
  font-family:var(--cond);font-size:10.5px;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase}
.hammer-mark{flex:0 0 auto;width:15px;height:15px;color:#fff;line-height:0}
.hammer-mark svg{width:100%;height:100%;display:block}

/* Both halves are the same two rows with the same gap, so the field's top
   sits level with the top pair of figures and the button's bottom with the
   lower pair. */
/* The side room lives here rather than on the slab, so the head's
   gradient runs the full width of the screen. */
.hammer-body{display:flex;align-items:stretch;gap:9px;padding:9px 12px}
.hammer-figs{flex:1 1 0;min-width:0;display:grid;
  grid-template-columns:1fr 1fr;grid-template-rows:1fr 1fr;gap:5px}
.hammer .ufa-bid{flex:1 1 0;min-width:0;display:grid;
  grid-template-rows:1fr 1fr;gap:5px;min-height:92px}

/* The figures: plain, since four of them don't need four weights. */
/* The same dark as the chips beside the player, so the two sets of
   figures on this screen read as the same kind of thing. */
.ufa-fig{min-width:0;padding:6px 8px;border-radius:4px;
  background:#0b1119e6;border:1px solid #33415a;
  display:flex;flex-direction:column;gap:2px;justify-content:center}
.ufa-fig span{font-family:var(--cond);font-size:8.5px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ufa-fig i{font-style:normal}
.ufa-fig .fig-short{display:none}
.ufa-fig b{font-family:var(--cond);font-weight:700;font-size:14px;
  font-variant-numeric:tabular-nums;color:var(--text);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.ufa-fig.warn b{color:var(--gold)}
.ufa-fig.over b{color:var(--red)}
@media (max-width:620px){
  .ufa-fig .fig-long{display:none}
  .ufa-fig .fig-short{display:inline}
}

/* The arrows sit inside the field's box, against its right edge. */
.ufa-bidrow{position:relative;display:flex;align-self:stretch;
  height:100%;min-height:0}
/* Room on the left for the sign, room on the right for the arrows. */
.ufa-bidsign{position:absolute;left:14px;top:50%;transform:translateY(-50%);
  z-index:1;pointer-events:none;
  font-family:var(--cond);font-weight:700;font-size:18px;color:var(--muted)}
.ufa-bidfield{flex:1;width:100%;min-width:0;height:100%;
  background:var(--ink);
  border:1px solid var(--line);border-radius:4px;
  padding:0 36px 0 30px;box-sizing:border-box;
  font-family:var(--cond);font-size:21px;font-weight:700;
  font-variant-numeric:tabular-nums;text-align:center;color:var(--money)}
.ufa-bidfield:focus{outline:none;border-color:var(--money)}
.ufa-bidfield:disabled{color:var(--muted);opacity:.7}
/* Between nominations it shows what you could spend, not a bid. */
.ufa-bidfield.idle{color:var(--muted);border-color:var(--line)}
.ufa-bidfield.atmax{color:var(--red);border-color:#5d3330}
.ufa-bidfield.over{color:var(--muted);border-color:var(--line)}
.ufa-bidfield::-webkit-outer-spin-button,
.ufa-bidfield::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.ufa-bidfield{-moz-appearance:textfield}

.ufa-steps{position:absolute;top:3px;right:3px;bottom:3px;width:26px;
  display:flex;flex-direction:column;gap:2px}
.ufa-step{flex:1;width:100%;padding:0;border-radius:3px;
  background:#ffffff0f;border:0;color:var(--text);
  font-size:10px;line-height:1;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  -webkit-tap-highlight-color:transparent}
.ufa-step:hover:not(:disabled){background:#ffffff22}
.ufa-step:disabled{opacity:.35;cursor:default}

/* Dormant it still has to read as the thing you press. */
.ufa-bidgo{width:100%;height:100%;align-self:stretch;margin:0;padding:0;
  font-size:14px;font-weight:700;letter-spacing:.04em;
  background:#26313f;border:1px solid #46566b;color:#c6d2e0}
.ufa-bidgo.on{background:var(--money);border-color:var(--money);color:#fff}
.ufa-bidgo:disabled{cursor:default;opacity:1}

/* ── the man on the block ─────────────────────────────────────────────
   His club's mark behind, his photo over it, three figures floating at the
   foot, and his season underneath. The art takes whatever height is going;
   the table under it is what gives way when the room is opened. */
.ufahero{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;
  background:linear-gradient(180deg,#0d1420 0%,#0a1018 100%);
  transition:opacity .16s ease}
/* Mid-swap while a different player is being looked at. */
.ufahero.swapping{opacity:0}
.ufahero[hidden]{display:none}

/* He stands right of centre, with the mark behind him and the chips in the
   space that leaves on the left — the reference layout, and the reason the
   chips don't sit on top of his face. */
/* He stands at the right. The box takes whatever height is going, so the
   room folding away is what makes him big. */
/* Both children are positioned rather than laid out in flow: an image
   that grows wider than its box can't be held to one side by flex
   alignment, which is why he kept drifting. */
/* The club's colour is set on this element per player, so nothing here
   paints over it. */
.hero-art{position:relative;flex:1 1 auto;min-height:96px;overflow:hidden}
/* The backdrop: big, faint, behind him rather than behind the whole box. */
/* The mark grows with him, and further — it's the backdrop, so it's meant
   to run past the edges rather than fit inside them. */
.hero-mark{position:absolute;top:50%;left:50%;width:auto;height:145%;
  object-fit:contain;
  transform:translate(-50%,-50%);opacity:.16;
  filter:grayscale(.15);pointer-events:none;z-index:0;
  transition:left .26s cubic-bezier(.22,.7,.3,1)}
/* Centred when the room is folded and he's large. With the room open the
   hero is short and he sits close to the right, so the mark moves left to
   stay behind him rather than beside him. After the base rule, or the
   left:50% above would simply win. */
/* He fills whatever height the hero has — folding the room away makes him
   bigger, which is the point of folding it. No width cap: capping it was
   what stopped him growing. He grows from the right edge, so the chips
   keep their corner. */
/* Pinned to the right edge and the floor. He grows upward and leftward
   from there as the hero gets taller. */
/* He sizes to the hero's height, as he always did — that's what makes him
   big. Only where he sits changes. */
.hero-shot{position:absolute;z-index:1;right:-2%;bottom:0;top:0;
  display:flex;align-items:flex-end;justify-content:flex-end;
  pointer-events:none;
  /* The room's fold takes .26s, and so does this — otherwise he snaps to
     his new offset while the hero is still growing, which is the jump
     leftwards and then off the edge. */
  transition:right .26s cubic-bezier(.22,.7,.3,1)}
.hero-shot img,.hero-shot svg{height:100%;width:auto;
  display:block;object-fit:contain;object-position:bottom right;
  filter:drop-shadow(0 6px 16px #0009)}
/* Folded, the hero is tall and he's wide with it. Anchoring the right
   edge alone left him looking centred, because the picture's transparent
   margin is on his right — so he's nudged over by that margin's width.
   Nothing else about him changes. */
body.teams-folded .hero-shot{right:-30%}
/* Room open, he moves off the right edge — the hero is short here, so he's
   wide and there's space to shift him without losing him. The folded view
   keeps its -30%. */
body:not(.teams-folded) .hero-shot{right:6%}
body:not(.teams-folded) .hero-mark{left:38%}

/* Rank, age and club, floating at the foot of the art. */
/* His name, sitting on the chips. Given name quietly above, surname in
   the display face — the thing you read from across a room. */
/* Everything the fold changes about the name transitions on the fold's own
   curve. Without this the size and position snapped the instant the class
   changed while the hero was still animating under them — which is the
   flash of a large name in the wrong place before it settles. */
.hero-name{position:absolute;z-index:2;left:12px;bottom:58px;
  display:flex;flex-direction:column;gap:1px;max-width:64%;
  transition:bottom .3s cubic-bezier(.22,.7,.3,1),
             left .3s cubic-bezier(.22,.7,.3,1)}
.hero-first{transition:font-size .3s cubic-bezier(.22,.7,.3,1);
  font-family:var(--cond);font-size:12px;font-weight:400;
  letter-spacing:.14em;text-transform:uppercase;color:var(--muted);
  text-shadow:0 1px 3px #000a}
.hero-last{transition:font-size .3s cubic-bezier(.22,.7,.3,1);
  font-family:var(--block,'Archivo Black',sans-serif);
  font-weight:400;font-size:26px;line-height:1;letter-spacing:.005em;
  text-transform:uppercase;color:#fff;text-shadow:0 2px 8px #000c;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.hero-chips{position:absolute;z-index:2;left:12px;bottom:10px;
  display:flex;gap:6px;align-items:stretch;
  transition:bottom .3s cubic-bezier(.22,.7,.3,1),
             left .3s cubic-bezier(.22,.7,.3,1),
             gap .3s cubic-bezier(.22,.7,.3,1)}
/* Over the photo now that he's allowed to fill the box — solid enough to
   read against a shoulder rather than only against the background. */
.hero-chip{width:64px;min-width:64px;padding:4px 9px;border-radius:5px;
  text-align:center;align-items:center;
  transition:width .3s cubic-bezier(.22,.7,.3,1),
             min-width .3s cubic-bezier(.22,.7,.3,1),
             padding .3s cubic-bezier(.22,.7,.3,1);
  background:#0b1119e6;-webkit-backdrop-filter:blur(10px);
  backdrop-filter:blur(10px);border:1px solid #33415a;
  display:flex;flex-direction:column;gap:1px;justify-content:center}
.hero-chip span{font-family:var(--cond);font-size:8px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted)}
.hero-chip b{font-family:var(--cond);font-size:15px;font-weight:700;
  font-variant-numeric:tabular-nums;color:#fff}
/* Same box as the other two — it was sizing to its picture, which made
   it the odd one out in a row of three. */
/* The same width as the two beside it. min-width let it shrink to its
   picture whenever that was narrower, which is how it ended up the odd
   one out. */
.hero-chip-logo{width:64px;min-width:64px;padding:4px 9px;
  align-items:center;justify-content:center}
.hero-chip-logo img{width:30px;height:30px;object-fit:contain;display:block;
  margin:0 auto}

/* The season, under the art. */
/* Ruled off from the art above it, in the slab's own line colour. */
/* The season, under the art — the app's own stat card, so a projection
   reads the same here as on a roster's player card. */
.hero-stats{flex:0 0 auto;padding:9px 12px 11px;
  border-top:1px solid var(--line)}
.hero-stats .stat-card{border-radius:7px}
.hero-stats .ufablock-none{padding:10px 11px}
@media (min-width:1081px){
  .hero-stats{padding:11px 16px 13px}
  .hero-stats .stat-cell b{font-size:22px}
  .hero-stats .stat-cell span{font-size:10px}
}
.hero-stats-head{display:flex;align-items:baseline;gap:8px;margin-bottom:6px;
  font-family:var(--cond);font-size:9.5px;font-weight:700;letter-spacing:.16em;
  text-transform:uppercase;color:var(--muted)}
.hero-grid{display:grid;
  grid-template-columns:repeat(auto-fit,minmax(56px,1fr));gap:5px}
.hero-cell{padding:5px 7px;border-radius:4px;background:var(--slate-2);
  border:1px solid var(--line);display:flex;flex-direction:column;gap:1px;
  min-width:0}
.hero-cell span{font-family:var(--cond);font-size:8px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hero-cell b{font-family:var(--cond);font-size:13px;font-weight:700;
  font-variant-numeric:tabular-nums;color:var(--text)}

/* Waiting for a nomination. */
/* The waiting outline sat in the art's flex flow, which no longer exists —
   it's placed where he would stand instead. */
.hero-ghost{position:absolute;right:8%;bottom:14px;
  width:92px;height:92px;border-radius:50%;
  border:1px dashed #35435a;background:#ffffff05}
.ufahero.sample .hero-shot svg{opacity:.8}

/* ── the block banner ─────────────────────────────────────────────────
   Player, clock, leading bid. Its colour is the answer to "where do I
   stand": gold while somebody else leads, green while you do, red once
   the bidding is past what you could pay. */
/* Him, the money, the clock — in that order, left to right. */
.ufatop{flex:0 0 auto;position:relative;display:grid;
  grid-template-columns:minmax(0,1fr) auto auto;
  align-items:center;gap:12px;padding:9px 12px 11px;
  background:linear-gradient(180deg,#7a5c10 0%,#5d4409 100%);
  border-bottom:1px solid #a87d16}
.ufatop[hidden]{display:none}
.ufatop.mine{background:linear-gradient(180deg,#155e3b 0%,#0f4a2e 100%);
  border-bottom-color:var(--money)}
.ufatop.beyond{background:linear-gradient(180deg,#7a2822 0%,#5d1f1a 100%);
  border-bottom-color:var(--red)}
/* The intermission: he's up, nobody can bid yet. Blue rather than gold, so
   "look at him" and "the money is moving" aren't the same colour. */
.ufatop.opening{background:linear-gradient(180deg,#1c4a7c 0%,#14375e 100%);
  border-bottom-color:var(--blue)}
.ufatop.opening .ufatop-rail i{background:var(--blue);opacity:1}
/* Held by the commissioner: the clock stops and says so. */
.ufatop.held .ufatop-time{opacity:.5}
.ufatop.held .ufatop-rail i{opacity:.4}
/* Nobody up: the same bar, saying what it's waiting on. */
/* The same height whether or not somebody is up: a bar that shrinks
   between nominations moves everything below it twice a minute. */
.ufatop{min-height:66px}
.ufatop.resting{background:linear-gradient(180deg,#1b2432 0%,#141b26 100%);
  border-bottom-color:var(--line)}
.ufatop.resting .ufatop-name b{font-family:var(--cond);font-size:12px;
  letter-spacing:.16em;color:var(--muted)}
/* Counting down to the summit: the label stays grey and the clock beside
   it does the talking. */
/* Counting down to the summit there is no player and no bid, so the clock
   takes the middle rather than hugging a right edge with nothing beside
   it. */
/* The rookie board's pre-start bar, matched: the whole thing centred, the
   label in condensed bold and tracked, the figure in the display face.
   Two rooms waiting for the same kind of thing should look the same while
   they wait. */
.ufatop.counting{display:flex;justify-content:center;align-items:center;
  gap:14px}
.ufatop.counting .ufatop-bid{display:none}
.ufatop.counting .ufatop-who{flex:0 0 auto;min-width:0}
.ufatop.counting .ufatop-shot{display:none}
.ufatop.counting .ufatop-sub{display:none}
.ufatop.counting .ufatop-name b{font-family:var(--cond);font-size:15px;
  font-weight:700;letter-spacing:.18em;text-transform:uppercase;
  color:var(--muted)}
.ufatop.counting .ufatop-clock{flex:0 0 auto;justify-self:auto}
.ufatop.counting .ufatop-time{font-family:var(--block,'Archivo Black',sans-serif);
  font-weight:400;font-size:30px;letter-spacing:-.03em;color:var(--text)}
.ufatop.counting .ufatop-lead{display:none}
/* Past your ceiling, the man is somebody else's problem. */
.ufatop.beyond .ufatop-shot{filter:grayscale(1);opacity:.75}

.ufatop-who{display:flex;align-items:center;gap:9px;min-width:0}
.ufatop-shot{position:relative;flex:0 0 auto}
.ufatop-shot .rk-face{width:44px;height:44px;border-radius:50%;
  overflow:hidden;background:#0006;display:flex;align-items:center;
  justify-content:center}
.ufatop-shot .rk-face img{width:100%;height:100%;object-fit:cover;
  object-position:top center}
.ufatop-logo{position:absolute;right:-3px;bottom:-3px;width:20px;height:20px;
  object-fit:contain;background:var(--ink);border-radius:50%;padding:2px;
  box-sizing:border-box}
.ufatop-name{display:flex;flex-direction:column;gap:1px;min-width:0}
.ufatop-name b{font-family:var(--block,'Archivo Black',sans-serif);
  font-weight:400;font-size:14px;text-transform:uppercase;color:#fff;
  min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ufatop-sub{display:flex;align-items:baseline;gap:5px;min-width:0}
.ufatop-pos{font-family:var(--cond);font-size:10px;font-weight:700;
  letter-spacing:.14em}
.ufatop-dot,.ufatop-rank{font-family:var(--cond);font-size:10px;
  font-weight:700;letter-spacing:.1em;color:#fff}
.ufatop-dot[hidden]{display:none}
.ufatop-pos.pos-QB{color:var(--pos-qb)}
.ufatop-pos.pos-RB{color:var(--pos-rb)}
.ufatop-pos.pos-WR{color:var(--pos-wr)}
.ufatop-pos.pos-TE{color:var(--pos-te)}

.ufatop-clock{flex:0 0 auto;justify-self:end;
  display:flex;align-items:baseline;gap:8px}
/* The same grey label the summit countdown uses, so "waiting for
   something" looks the same wherever it appears. */
.ufatop-lead{font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;color:#ffffff8c;
  white-space:nowrap}
.ufatop-lead[hidden]{display:none}
.ufatop-time{font-family:var(--cond);font-weight:700;font-size:26px;
  font-variant-numeric:tabular-nums;color:#fff;line-height:1}
.ufatop.out .ufatop-time{color:var(--red)}

.ufatop-bid{display:flex;align-items:center;justify-content:flex-end;gap:8px;
  min-width:0;flex:0 0 auto}
.ufatop-bid b{font-family:var(--cond);font-weight:700;font-size:22px;
  font-variant-numeric:tabular-nums;color:#fff}
/* Holds the bidder's name and their face now, so it sizes to its contents
   rather than staying a 34px circle — the circle moved to the img. */
.ufatop-owner{flex:0 0 auto;display:flex;align-items:center;gap:9px;
  background:none}
.ufatop-owner img,.ufatop-owner .me-initials{width:34px;height:34px;
  border-radius:50%;overflow:hidden;background:#0004;flex:0 0 auto;
  display:flex;align-items:center;justify-content:center;object-fit:cover}
/* Nothing in it means nothing there. Clearing the photo left the dark
   disc behind, which is the circle still showing on the blue bar. */
.ufatop-owner:empty{display:none}
/* Sized above, in the rule it shares with the initials fallback. Only the
   framing belongs here — 100% of a parent that now sizes to its contents
   would have collapsed the face to nothing. */
.ufatop-owner img{object-position:top center}

.ufatop-rail{position:absolute;left:0;right:0;bottom:0;height:3px;
  background:#0006;overflow:hidden}
.ufatop-rail i{display:block;height:100%;width:0;background:#fff;
  opacity:.85;transition:width 1s linear}
/* Emptying it is not a countdown: with the transition it took a further
   second to drain, so the line was still there under the black. */
.ufatop-rail i.snap{transition:none}
.ufatop.mine .ufatop-rail i{background:var(--money);opacity:1}
.ufatop.beyond .ufatop-rail i{background:var(--red);opacity:1}

/* Desktop: the hero has far more room than a phone, and a 26px surname in
   the middle of it looks like a caption rather than a headline. */
@media (min-width:1081px){
  /* The slab has the whole width here, so nothing needs to be squeezed:
     the figures get room, the field gets height, and the two halves stop
     fighting for the same 400px they share on a phone. */
  .hammer-head{padding:8px 16px;font-size:11.5px}
  .hammer-mark{width:17px;height:17px}
  .hammer-body{padding:12px 16px;gap:16px;align-items:stretch}
  .hammer-figs{flex:1 1 0;gap:9px}
  .ufa-fig{padding:9px 12px;border-radius:5px}
  .ufa-fig span{font-size:9.5px;letter-spacing:.12em}
  .ufa-fig b{font-size:19px}
  .hammer .ufa-bid{flex:0 0 clamp(320px,32%,460px);gap:9px;min-height:104px}
  .ufa-bidfield{font-size:26px;padding:0 44px 0 34px}
  .ufa-bidsign{left:18px;font-size:21px}
  .ufa-steps{width:32px;top:5px;right:5px;bottom:5px;gap:3px}
  .ufa-step{font-size:12px}
  .ufa-bidgo{font-size:16px;letter-spacing:.06em}

  .hero-name{left:20px;bottom:78px;max-width:52%}
  .hero-first{font-size:15px;letter-spacing:.16em}
  .hero-last{font-size:44px}
  .hero-chips{left:20px;bottom:14px;gap:8px}
  .hero-chip{width:88px;min-width:88px;padding:7px 12px;border-radius:6px}
  .hero-chip span{font-size:9.5px}
  .hero-chip b{font-size:20px}
  .hero-chip-logo{width:88px;min-width:88px}
  .hero-chip-logo img{width:38px;height:38px}

  /* With the room open the hero is a good deal shorter, so the name and
     the chips come down with it — at full size they crowd the man they're
     supposed to be labelling. */
  /* Further left with the room open — the hero is shorter and he stands
     nearer the middle, so the name would otherwise crowd him. The folded
     view is left exactly as it is. */
  body:not(.teams-folded) .hero-name{bottom:64px;left:12px;max-width:46%}
  body:not(.teams-folded) .hero-chips{left:12px}
  /* And him with them: the hero is short here, so he's wide and there's
     room to move him off the right edge without losing him. */
  body:not(.teams-folded) .ufapage .hero-shot{right:8%}
  body:not(.teams-folded) .hero-first{font-size:12px}
  body:not(.teams-folded) .hero-last{font-size:32px}
  body:not(.teams-folded) .hero-chips{bottom:12px;gap:6px}
  body:not(.teams-folded) .hero-chip{width:70px;min-width:70px;
    padding:5px 9px}
  body:not(.teams-folded) .hero-chip span{font-size:8.5px}
  body:not(.teams-folded) .hero-chip b{font-size:16px}
  body:not(.teams-folded) .hero-chip-logo{width:70px;min-width:70px}
  body:not(.teams-folded) .hero-chip-logo img{width:30px;height:30px}
}

@media (max-width:560px){
  .ufatop{gap:8px;padding:8px 10px 10px}
  .ufatop-shot .rk-face{width:38px;height:38px}
  .ufatop-name b{font-size:12.5px}
  .ufatop-time{font-size:22px}
  .ufatop-bid b{font-size:18px}
  .ufatop-owner{width:28px;height:28px}
  /* Two lines rather than one long row on a narrow screen. */
  .ufatop-clock{flex-direction:column;align-items:flex-end;gap:1px}
  .ufatop-lead{font-size:9px;letter-spacing:.1em}
  /* Less room on a phone, so the surname comes down a size. */
  .hero-last{font-size:22px}
  .hero-first{font-size:11px}
  body:not(.teams-folded) .hero-last{font-size:18px}
  body:not(.teams-folded) .hero-name{bottom:50px}
  body:not(.teams-folded) .hero-chip{width:56px;min-width:56px;padding:3px 7px}
  body:not(.teams-folded) .hero-chip b{font-size:13px}
  body:not(.teams-folded) .hero-chip-logo{width:56px;min-width:56px}
  body:not(.teams-folded) .hero-chip-logo img{width:24px;height:24px}
  /* Four across on a phone: six would make thumbnails of the faces. */
  .ufateams{grid-template-columns:repeat(4,minmax(0,1fr))}
  .ufateam-face{width:38px;height:38px}
  .ufateam-box{font-size:13px;padding:7px 2px}
}


/* ── a sale, in the banner ────────────────────────────────────────────
   The banner goes black, flashes BIDDING CLOSED, gives way to a rainbow
   carrying the price, and then gold sweeps in with whoever is up next.
   All of it inside the banner's own box, so nothing else on the page
   moves while it plays. */
/* z-index above the rail, which is the banner's own bottom edge — the
   announcement should cover the whole bar, not stop 3px short of it. */
.ufawin{position:absolute;inset:0;z-index:9;overflow:hidden}
.ufawin[hidden]{display:none}
.ufawin.leaving{opacity:0;transition:opacity .36s ease}

.ufawin-mask{position:absolute;inset:0;background:#05070b;opacity:0;
  display:flex;align-items:center;justify-content:center;
  transition:opacity .4s ease}
.ufawin-mask.on{opacity:1}
/* Gone, once the rainbow is under it. */
.ufawin-mask.gone{opacity:0;transition:opacity .45s ease}
.ufawin-word{font-family:var(--block,'Archivo Black',sans-serif);
  font-weight:400;font-size:22px;letter-spacing:.06em;text-transform:uppercase;
  color:#fff;opacity:0}
.ufawin-mask.flashing .ufawin-word{
  animation:ufa-flash .5s steps(1) 3 forwards}
@keyframes ufa-flash{0%,49%{opacity:1}50%,100%{opacity:0}}

/* The rainbow, laid out like the banner it replaces. */
.ufawin-card{position:absolute;inset:0;z-index:1;
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:9px 12px;
  /* The same six colours at 62%. At full strength white sat at 1.9:1 over
     the gold band — pretty, and unreadable. This clears 4.5:1 across the
     whole sweep and still reads as the rainbow. */
  background:linear-gradient(90deg,#90281d,#966d13 20%,#27764f 40%,
    #1b6f76 60%,#2e6090 80%,#68569b)}
.ufawin-card[hidden]{display:none}

.ufawin-who{display:flex;align-items:center;gap:9px;min-width:0}
/* overflow visible so the club can hang off the shoulder; the photo is
   clipped by its own radius instead. */
.ufawin-shot{position:relative;flex:0 0 auto;width:44px;height:44px;
  display:flex;align-items:flex-end;justify-content:center}
/* The same badge the banner puts on him: 20px, same offsets, same disc.
   It was 22px against a 44px photo here and stayed 22px when the photo
   dropped to 36px on a phone — which is where "huge" came from. */
.ufawin-logo{position:absolute;right:-3px;bottom:-3px;width:20px;height:20px;
  object-fit:contain;background:var(--ink);border-radius:50%;padding:2px;
  box-sizing:border-box}
/* :not(.ufawin-logo) — the badge is an img inside this box too, and
   ".ufawin-shot img" outranks ".ufawin-logo" on specificity, so the photo's
   width:100% was being applied to the badge and blowing it up to the full
   44px. The banner's equivalent is scoped inside .rk-face, which is why it
   never had this problem. */
.ufawin-shot img:not(.ufawin-logo),.ufawin-shot svg{
  width:100%;height:100%;object-fit:cover;
  object-position:top center;display:block;border-radius:50%;
  background:#0006}
.ufawin-name{display:flex;flex-direction:column;gap:1px;min-width:0}
.ufawin-name b{font-family:var(--block,'Archivo Black',sans-serif);
  font-weight:400;font-size:14px;text-transform:uppercase;color:#fff;
  text-shadow:0 1px 4px #0006;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ufawin-pos{font-family:var(--cond);font-size:10px;font-weight:700;
  letter-spacing:.14em;color:#ffffffd9}

.ufawin-money{display:flex;align-items:center;gap:10px;flex:0 0 auto}
.ufawin-figures{display:flex;flex-direction:column;align-items:flex-end;
  gap:1px}
.ufawin-figures b{font-family:var(--cond);font-weight:700;font-size:24px;
  line-height:1;font-variant-numeric:tabular-nums;color:#fff;
  text-shadow:0 2px 8px #0007}
.ufawin-figures span{font-family:var(--cond);font-size:9.5px;
  letter-spacing:.1em;text-transform:uppercase;color:#ffffffe0}
.ufawin-face{flex:0 0 auto;width:34px;height:34px;border-radius:50%;
  overflow:hidden;background:#0004;display:flex;align-items:center;
  justify-content:center;border:2px solid #ffffff5c}
.ufawin-face img{width:100%;height:100%;object-fit:cover;
  object-position:top center}

/* And the gold, sweeping over the lot with the next nomination. */
.ufawin-next{position:absolute;inset:0;z-index:2;
  display:flex;align-items:center;justify-content:center;
  background:linear-gradient(180deg,#7a5c10 0%,#5d4409 100%);
  transform:scaleX(0);transform-origin:left center;
  font-family:var(--cond);font-size:13px;font-weight:700;letter-spacing:.18em;
  text-transform:uppercase;color:#fff}
.ufawin-next[hidden]{display:none}
.ufawin-next.in{transform:scaleX(1);
  transition:transform .5s cubic-bezier(.5,0,.2,1)}

@media (max-width:560px){
  .ufawin-shot{width:36px;height:36px}
  .ufawin-logo{width:17px;height:17px;right:-2px;bottom:-2px}
  .ufawin-name b{font-size:12px}
  .ufawin-figures b{font-size:20px}
  .ufawin-face{width:28px;height:28px}
  .ufawin-word{font-size:17px}
  .ufawin-next{font-size:11px;letter-spacing:.12em}
}
@media (prefers-reduced-motion:reduce){
  .ufawin-mask,.ufawin-next{transition:none}
  .ufawin-mask.flashing .ufawin-word{animation:none;opacity:1}
}


/* ── held, and whose turn it is ───────────────────────────────────────  */

/* Paused: the banner goes red and the clock says so instead of showing a
   number that isn't moving. */
.ufatop.paused{background:linear-gradient(180deg,#7a2822 0%,#5d1f1a 100%);
  border-bottom-color:var(--red)}
.ufatop.paused .ufatop-rail i{background:var(--red);opacity:.5}
.ufatop.paused .ufatop-time{font-family:var(--cond);font-size:18px;
  letter-spacing:.14em;text-transform:uppercase}
/* Your nomination: gold, because this is the one state waiting on you. */
.ufatop.resting.yours{background:linear-gradient(180deg,#7a5c10 0%,#5d4409 100%);
  border-bottom-color:#a87d16}
.ufatop.resting.yours .ufatop-name b{color:#fff}

/* The button matches the banner when the room is held. */
.ufa-bidgo.held{background:var(--red);border-color:var(--red);color:#fff}

/* Whose turn it is, and whose it is next. */
/* Above the glow, so the faces and the boxes sit in the light rather than
   under it. */
.ufateam{position:relative;z-index:1}
/* A pale glass pill, so the word reads over a face as well as over the
   room's background. */
.ufateam-turn{position:absolute;top:-9px;left:50%;transform:translateX(-50%);
  z-index:2;padding:1px 6px;border-radius:99px;
  background:#ffffff26;-webkit-backdrop-filter:blur(6px);
  backdrop-filter:blur(6px);border:1px solid #ffffff2e;
  font-family:var(--cond);font-size:8.5px;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;white-space:nowrap}
/* Up: the blue the block's banner uses while a player is being read.
   Next: gold, one step behind it. */
.ufateam.nominating .ufateam-turn{color:var(--blue)}
.ufateam.onnext .ufateam-turn{color:var(--gold)}
.ufateam.nominating .ufateam-face{border-color:var(--blue)}
.ufateam.onnext .ufateam-face{border-color:var(--gold)}

/* The celebration's second line, matching the banner's. */
.ufawin-sub{display:flex;align-items:baseline;gap:5px}
.ufawin-dot,.ufawin-rank{font-family:var(--cond);font-size:10px;
  font-weight:700;letter-spacing:.1em;color:#fff}


/* ── the results card ─────────────────────────────────────────────────
   Everything signed tonight, newest first. Reads the pool, so a sandbox's
   results appear here exactly as a real night's do. */
.results-to{flex:0 0 auto;display:flex;align-items:center;gap:8px}
.results-face{width:28px;height:28px;border-radius:50%;overflow:hidden;
  background:var(--slate-2);flex:0 0 auto;
  display:flex;align-items:center;justify-content:center}
/* Every team: the league's own mark on black, rather than an empty disc
   that reads as a photo that failed to load. */
.results-face.is-league{background:#05070b;color:var(--red);
  border:1px solid #2b3542}
.results-face.is-league svg{width:17px;height:17px;display:block}
.results-face img{width:100%;height:100%;object-fit:cover;
  object-position:top center}
#resultsSheet .rrow-list{display:flex;flex-direction:column;gap:6px}
/* The filter sits where a team picker would. */
.seg-select{flex:0 0 auto;background:var(--slate-2);color:var(--text);
  border:1px solid var(--line);border-radius:6px;padding:6px 9px;
  font-family:var(--cond);font-size:11px;font-weight:700;letter-spacing:.1em;
  text-transform:uppercase}
.seg-select:focus{outline:none;border-color:var(--money)}


/* ── the roster sheet's team picker, on this page ─────────────────────
   The name is a button here, as it is on the hub. It was a plain label
   that looked identical and did nothing when pressed. */
body:has(.ufapage) #rosterTeamBtn{cursor:pointer}

/* The list inside it. These class names come from the hub's lineup
   picker, but that stylesheet section isn't loaded on this page — so they
   needed writing rather than assuming. */
.lu-pick{display:flex;flex-direction:column;gap:6px}
.lu-pick-row{display:flex;align-items:center;gap:10px;width:100%;
  padding:9px 11px;border-radius:4px;background:var(--slate-2);
  border:1px solid transparent;color:inherit;font:inherit;text-align:left;
  cursor:pointer;-webkit-tap-highlight-color:transparent}
.lu-pick-row:hover{border-color:#3a4756}
.lu-pick-row.on{border-color:var(--money);background:#14301f}
.lu-pick-mid{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.lu-pick-mid b{font-size:13.5px;min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.lu-pick-mid span{font-family:var(--cond);font-size:10px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted)}


/* Cards on the UFA page sit between the banner and the slab, like the
   sheets do. A picker that covers the clock and the bid field takes away
   the two things you would be checking while you use it. */
body:has(.ufapage) .modal{
  top:min(var(--ufatop-h,150px),26vh);
  bottom:min(var(--ufafoot-h,0px),24vh);
  inset-inline:0;
  padding:10px 12px}


/* ── a roster on one line each ────────────────────────────────────────
   Club, name, position, his season, what he costs. For reading a squad
   quickly; the full view keeps the photos and the depth-chart grouping. */
/* Tighter gaps and narrower figures than before: the name was being
   squeezed by columns holding four characters. */
.rlist-row{display:flex;align-items:center;gap:7px;row-gap:0;
  padding:6px 9px;border-radius:4px;background:var(--slate-2);
  border:1px solid transparent}
/* The expander sits with the position, not out in the row. */
.rlist-row > .rrow-more{margin:0}

/* The list view, likewise, keeps its own border. */
/* Position leads — it's what the eye runs down — then the club sits on
   his name. */
.rlist-pos{flex:0 0 auto;width:26px;text-align:center;
  font-family:var(--cond);font-size:9.5px;font-weight:700;letter-spacing:.1em}
.rlist-pos.pos-QB{color:var(--pos-qb)}
.rlist-pos.pos-RB{color:var(--pos-rb)}
.rlist-pos.pos-WR{color:var(--pos-wr)}
.rlist-pos.pos-TE{color:var(--pos-te)}
.rlist-logo{flex:0 0 auto;width:16px;height:16px;object-fit:contain}
/* White, said outright. The row inherits whatever colour its surroundings
   carry, and in a position-coloured group that meant the names took the
   position's colour too. */
/* A flex row, not a truncating block: it holds the name and the info icon
   now, and overflow:hidden on the container would have clipped the icon
   off the end of a long name rather than the name itself. */
.rlist-name{flex:1;min-width:0;display:flex;align-items:center;
  font-size:13px;font-weight:600;color:var(--text)}
.rlist-nametext{min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
/* Both figures right-aligned in fixed columns, so the eye can run down
   them instead of hunting along each row. */
/* 52px each held four characters and took 104px between them; the name
   was paying for it. Narrower, and a size down. */
.rlist-rank{flex:0 0 auto;width:36px;text-align:right;
  font-family:var(--cond);font-size:11.5px;font-weight:700;
  font-variant-numeric:tabular-nums;color:var(--blue)}
.rlist-sal{flex:0 0 auto;width:40px;text-align:right;
  font-family:var(--cond);font-size:13px;font-weight:700;
  font-variant-numeric:tabular-nums;color:var(--money)}
/* The density switch, under the cap line. */
.rdensity{margin:0 0 8px;align-self:flex-start}
.seg-sm{margin:0 0 8px}
.seg-sm button{padding:5px 12px;font-size:10px}
.rbody{display:block}
@media (max-width:560px){
  .rlist-name{font-size:12.5px}
  .rlist-rank{width:44px;font-size:11.5px}
  .rlist-sal{width:44px;font-size:14px}
}


/* ── this year's class, in the pool ───────────────────────────────────
   Undrafted rookies land here, and they're worth spotting: a first-year
   player at a dollar is a different proposition from a veteran at one. */
.rk-rookie{margin-left:7px;padding:1px 5px;border-radius:3px;
  background:#3a1a17;border:1px solid #6d2f28;color:#ff8b7e;
  font-family:var(--cond);font-size:8.5px;font-weight:700;
  letter-spacing:.12em;text-transform:uppercase;vertical-align:2px}
/* Its own row under the positions, so the two filters read as two
   questions rather than one long strip of buttons. */
.rkclass{margin-top:6px}
.rkclass button{flex:1 1 0}


/* The heading takes its position's colour, so a roster reads as four
   blocks rather than four identical teal labels. Scoped to the roster
   sheet: elsewhere the teal heading is doing its own job. */
#rosterSheet .rgroup.pos-QB .rgroup-head b{color:var(--pos-qb)}
#rosterSheet .rgroup.pos-RB .rgroup-head b{color:var(--pos-rb)}
#rosterSheet .rgroup.pos-WR .rgroup-head b{color:var(--pos-wr)}
#rosterSheet .rgroup.pos-TE .rgroup-head b{color:var(--pos-te)}
#rosterSheet .rgroup.pos-QB .rgroup-head{border-bottom-color:#5c3247}
#rosterSheet .rgroup.pos-RB .rgroup-head{border-bottom-color:#25543d}
#rosterSheet .rgroup.pos-WR .rgroup-head{border-bottom-color:#1f4e55}
#rosterSheet .rgroup.pos-TE .rgroup-head{border-bottom-color:#453d63}


/* The roster's Block pill, sized for a draft row — those are tighter than
   a roster row, so it comes down rather than being restyled. Everything
   else about it is .blockbtn's. */
.rkslot-block{margin-left:0;width:72px;height:24px;font-size:9px;
  border-radius:5px}
.rkslot-block:disabled{opacity:.5;cursor:default}
@media (max-width:560px){
  .rkslot-block{width:60px;height:21px;font-size:8px;letter-spacing:.06em}
}


/* The lineup's bench control: a grey cross, nothing more. It had no rule
   of its own, so it was inheriting the app's button styling — a filled
   pill where a plain × belongs. */
.lu-bench{flex:0 0 auto;width:22px;height:22px;padding:0;margin-left:2px;
  border:0;border-radius:50%;background:none;color:var(--muted);
  font-family:var(--ui);font-size:16px;line-height:1;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  -webkit-tap-highlight-color:transparent;
  transition:color .12s ease,background-color .12s ease}
.lu-bench:hover{color:#fff;background:#ffffff14}
.lu-bench:focus{outline:none}
.lu-bench:focus-visible{outline:2px solid var(--teal);outline-offset:2px}


/* Every team, wherever a face stands for the whole league: the brand's
   hammer in red on black, rather than an empty disc that reads as a photo
   that failed to load. The mark itself is drawn white, so the fill is
   overridden here instead of keeping a second copy of it. */
.teampick-face.is-league,.teamface.is-league,
.dpick-face.is-league,.rr-face.is-league{background:#05070b;
  border:1px solid #2b3542;box-sizing:border-box;
  display:flex;align-items:center;justify-content:center}
.teampick-face.is-league svg,.teamface.is-league svg,
.dpick-face.is-league svg,.rr-face.is-league svg{width:72%;height:72%;
  display:block}
.teampick-face.is-league svg g,.teamface.is-league svg g,
.dpick-face.is-league svg g,.rr-face.is-league svg g{fill:var(--red)}


/* ── the builder's density switch ─────────────────────────────────────
   The same Detailed / List idea as the roster card: one line per asset
   when a team's list is long, the full row when it isn't. */
.tbdensity{margin:0 0 10px;align-self:flex-start}

/* Picks only: the same rows the All view draws, with the bodies hidden.
   Nothing about a pick changes between the two views — it's a filter, not
   a second way of drawing them. The group headings are marked in
   builder.js, since a heading's rows are its following siblings up to the
   next heading and a selector can't express that. */
#builder.picksonly .tb-item[data-kind="player"],
#builder.picksonly .tb-item[data-kind="rfa"]{display:none}
#builder.picksonly .tb-group.no-picks{display:none}

/* ── keeping a trade without sending it ───────────────────────────────
   Gold, beside the green — a different kind of action, so it shouldn't
   read as a second way to do the same thing. */
.btn-blueprint{background:var(--gold);border-color:var(--gold);color:#fff}
.btn-blueprint:hover:not(:disabled){background:#ffc24a;border-color:#ffc24a}
.btn-blueprint:disabled{opacity:.45}
/* The two together fill the space the one button had: an even split with
   a gap between them, so the row is the same width and the same height it
   always was. flex-basis:0 rather than auto — with auto the wider label
   would take more of the row than the other. */
.sheet-foot:has(.btn-blueprint){display:flex;gap:10px}
.sheet-foot:has(.btn-blueprint) > .btn{flex:1 1 0;width:auto;min-width:0}
/* A hidden button must not hold a share of the row — [hidden] on a flex
   item still lays out unless display is taken away. */
.sheet-foot > .btn[hidden]{display:none}

/* A blueprint card: the historical card in blue, so a sketch never reads
   as a live offer at a glance. */
.trade.blueprint{background:#1d4c86;border-color:#4a86c4}
.trade-tag.is-blueprint{color:#8ecdf5}
/* Can't be sent as the rosters stand. Red, and the Propose button with
   it — Edit and Delete are still the point of the card in this state. */
.trade.blueprint.illegal{background:#5c1f1a;border-color:#a4443a}
.trade-tag.is-blueprint.is-illegal{color:#ff9b8f}
.trade.blueprint.illegal .blueprint-caps,
.trade.blueprint.illegal .blueprint-foot{border-top-color:#a4443a}
.trade.blueprint.illegal .blueprint-cap .cap-label{color:#f0b4ac}
.blueprint-illegal{margin:8px 0 0;font-family:var(--cond);font-size:11px;
  letter-spacing:.04em;color:#ff9b8f}
.btn.btn-dead,.btn.btn-dead:hover{background:var(--slate-2);
  border-color:var(--line);color:#5c6675;cursor:default}

/* The cap figures on a card are a summary, not the builder's live
   readout — smaller, so a long line stays on one. */
.blueprint-cap .cap-label{font-size:8.5px;letter-spacing:.14em}
.blueprint-cap .cap-line{font-size:11px;gap:3px}
.blueprint-stale{margin:8px 0 0;font-family:var(--cond);font-size:11px;
  letter-spacing:.04em;color:var(--gold)}
/* The two sides' cap lines, side by side under the trade — the same two
   blocks the builder shows, in the same order as the teams above them. */
.blueprint-caps{display:flex;gap:14px;margin-top:12px;padding-top:10px;
  border-top:1px solid #4a86c4}
.blueprint-cap{flex:1;min-width:0;display:flex;flex-direction:column}
.blueprint-cap .cap-label{color:#a8c8e8}

.blueprint-foot{display:flex;justify-content:flex-end;gap:8px;
  margin-top:12px}
/* Edit: open the draft in the builder and leave it there, as against
   Propose which goes straight to the final question. */
.btn-edit{background:var(--gold);border-color:var(--gold);color:#1a1408}
.btn-edit:hover:not(:disabled){background:#ffc24a;border-color:#ffc24a}
/* Blueprint cards carry a trade, two cap summaries and three buttons —
   far more than a block row — so they need real air between them, not the
   5px the block list uses.

   By id, not by class: the list also carries .blocklist, and two rules of
   equal weight setting the same property leave the winner to source order
   — which is a fragile thing for the spacing to depend on. */
#draftList.draftlist{display:flex;flex-direction:column;gap:18px;
  padding-bottom:18px}


/* Pass, on the clock banner and only on your own. Sits beside the time
   rather than in the arm bar, which only exists once a player is held. */
/* Left of the time, at the banner's right-hand end. .rkclock-who already
   takes the free space, so no auto margin is needed to push these two
   over — just a gap between the button and the clock. */
.rkclock-pass{flex:0 0 auto;margin:0 12px 0 0}
.rkclock-pass[hidden]{display:none}


/* A forfeited pick. Red and done — no owner photo to press, no block
   button, and the draft never comes back to it. */
.rkslot.passed{background:#4a1a16;border-color:#8c342b}
.rkslot.passed .rkslot-who b,
.rkslot.passed .rkslot-who span{color:#f3b8b0}
.rkslot.passed .rkslot-no{background:#8c342b;color:#fff}
.rkslot-passed{flex:0 0 auto;font-family:var(--cond);font-size:11px;
  font-weight:700;letter-spacing:.16em;text-transform:uppercase;color:#fff}

/* Pass is a red action: it gives the pick up for good. */
.rkclock-pass{background:var(--red);border-color:var(--red);color:#fff}
.rkclock-pass:hover:not(:disabled){background:#ef6a5f;border-color:#ef6a5f}


/* ── picks, condensed ─────────────────────────────────────────────────
   In the roster card's List view the picks come down to the height of a
   player row. The badge sets that height, and it's driven by two custom
   properties — so shrinking those does most of the work. */
body.roster-dense .prow{gap:9px;padding:6px 10px;border-radius:4px;
  --badge-w:26px;--badge-h:20px}
body.roster-dense .trade-pick{font-size:9.5px;border-radius:4px}
/* One line, not two: the cost and the contract sit side by side rather
   than stacked, which is what a stacked pair costs in height. */
body.roster-dense .prow-mid{flex-direction:row;align-items:baseline;gap:7px}
body.roster-dense .prow-cost{font-size:12.5px}
body.roster-dense .prow-mid > span{font-size:10.5px;color:var(--muted)}
body.roster-dense .prow-from{font-size:10px}
/* The controls come down with the row so they don't set the height
   themselves. */
body.roster-dense .prow .blockbtn{width:66px;height:22px;font-size:8.5px}
body.roster-dense .prow-spacer{width:66px}
body.roster-dense .pgroup{gap:2px}

/* The player rows carry the same controls, at the size the picks' are —
   small enough that the row keeps a player row's height rather than the
   button setting it. */
/* Every button on a condensed row, whatever it says. Stated for the
   trade variant too — that one carries its own rules elsewhere, and
   leaving it to inherit meant it sat larger than Block beside it. */
.rlist-row .blockbtn,
.rlist-row .blockbtn.trade,
.rlist-row .blockbtn.pending{flex:0 0 auto;margin-left:6px;
  width:auto;min-width:52px;height:22px;font-size:8.5px;border-radius:5px;
  padding:0 8px}
/* The cut button is already 20px and sits tight to Block by design —
   nothing to change about it here. */
.rlist-row .tgt-icon,.rlist-row .tagbtn{flex:0 0 auto}
/* The money gives up its fixed column when controls follow it, so the
   buttons aren't pushed off the end on a narrow card. */
.rlist-row:has(.blockbtn) .rlist-sal{width:auto;min-width:40px}


/* A roster being fetched. The card holds what it had and dims, rather than
   emptying — the eye reads a dim card as "coming", and an empty one as
   "gone". Pointer events stay on, since the picker and the tabs still
   work while it loads. */
#rosterSheet.busy .rosterbody,
#rosterSheet.busy .picklist{opacity:.45;transition:opacity .12s ease}
#rosterSheet .rosterbody,
#rosterSheet .picklist{transition:opacity .18s ease}


/* ── a screen watching the room ───────────────────────────────────────
   A viewer session signs in to be projected, not to act. The server
   refuses its writes outright; this is the other half — nothing on screen
   invites a press that would only be refused.

   Scoped to html.viewer, set from the state on every page. */
html.viewer .adminbar,
html.viewer .autobar,
html.viewer .fab-trade,
html.viewer .blockbtn,
html.viewer .cutbtn,
html.viewer .tgt-icon,
html.viewer .rkclock-pass,
html.viewer .rkslot-block,
html.viewer #tradeBtn,
html.viewer #rosterBtn,
html.viewer #bellBtn,
html.viewer #fabs,
html.viewer .sandwich{display:none !important}
/* The account circle stays — it's how you sign the screen out. */
html.viewer .me-avatar{display:inline-flex !important}

/* The commissioner and the screen have no team photo, so the circle
   carries the league's mark: red on black, the same disc "All teams"
   uses elsewhere. */
.me-avatar.is-league{background:#05070b;border:1px solid #2b3542;
  color:var(--red);display:inline-flex;align-items:center;
  justify-content:center;overflow:hidden}
.me-avatar.is-league svg{width:64%;height:64%;display:block}
.me-avatar.is-league svg g{fill:var(--red)}

/* No team, so no spending power and no picks pane. Same as the
   commissioner's layout, which has never had them either. */
html.viewer .pane-power,
html.viewer .pane-picks,
html.viewer #rail{display:none !important}

/* The bid controls and anything else that submits. A screen showing the
   auction should read as a scoreboard, not a dead form. */
html.viewer .bidbar,
html.viewer .ufahammer,
html.viewer .rkarm{display:none !important}

/* Room for the board itself once the controls are gone. */
html.viewer .rkboard-list{padding-bottom:18px}

/* Bigger across the board — this is being read from the other side of a
   room, not held at arm's length. */
@media (min-width:1081px){
  html.viewer .rkslot{min-height:44px}
  html.viewer .rkslot-who b{font-size:15px}
  html.viewer .rkslot-no{font-size:13px;min-width:38px}
  html.viewer .rkboard-head b{font-size:16px}
  html.viewer .rfa-row{font-size:15px}
}


/* ── the stage, on a screen ───────────────────────────────────────────
   The auction's hero, borrowed: the club's colour washed behind, its mark
   large and centred, the player alongside, and his numbers stacked under
   them filling whatever height is left. */
@media (min-width:1081px){
  html.viewer .pane-stage{position:relative;overflow:hidden}

  /* The club's colour, read off the logo in app.js. Falls back to the
     pane's own dark when the canvas can't be read. */
  /* Above the tint, or the wash paints over it — it has a background of
     its own but no stacking order. */
  html.viewer .pane-stage .pane-head{position:relative;z-index:1}
  html.viewer .pane-stage .stage-tint{position:absolute;inset:0;z-index:0;
    pointer-events:none;
    background:linear-gradient(160deg,
      color-mix(in srgb, var(--stage-tint, #16202e) 62%, #05070b) 0%,
      color-mix(in srgb, var(--stage-tint, #16202e) 28%, #05070b) 52%,
      #06090e 100%);
    transition:background .5s ease}

  /* Its own element: the card's badge lives inside .nom-art, which anchors
     the position chip, so moving that one would take the chip's anchor. */
  html.viewer .pane-stage .stage-wash{position:absolute;
    top:38%;left:52%;transform:translate(-50%,-50%);
    width:auto;height:132%;max-width:none;object-fit:contain;
    opacity:.13;filter:grayscale(.1);pointer-events:none;z-index:0}

  /* Everything sits centred in whatever height the pane has. */
  html.viewer .pane-stage .pane-body{position:relative;z-index:1;
    display:flex;flex-direction:column;justify-content:center;
    gap:26px;height:100%;min-height:0}

  /* Top-aligned: bottom-aligning the frame pushed his head down level
     with the meta line, which is what made him sit so low. From the top
     he starts alongside the name and runs down past it. */
  /* One rule, so four of them can't disagree about how the row aligns —
     which is what the last few passes left behind. The row is as tall as
     the player, and the name block sits at the foot of it. */
  html.viewer .nom{position:relative;display:flex;gap:36px;
    align-items:flex-end;flex-wrap:nowrap;flex:0 0 auto;
    min-height:clamp(240px,27vh,340px)}
  /* The frame holds width but no height, so it can't push him down the
     row — every previous attempt tied his top to a frame height that kept
     changing. He is anchored to the top of the row itself and runs down
     from there, past the card below. */
  html.viewer .nom-art{width:clamp(230px,26vh,360px);height:0;
    overflow:visible;align-self:flex-start}
  /* Anchored to the TOP of the frame, not the bottom. bottom:0 aligned the
     photo's foot with the frame's foot, so the extra height went upward —
     which is why he never reached down over the card. From the top, the
     difference between the two heights hangs below. */
  /* He sits inside the row rather than hanging above it — a negative top
     put his head off the top of the pane. The row is given his height,
     and the cards below are pulled up over his chin instead. */
  html.viewer .nom-shot,
  html.viewer .nom-mono{position:absolute;left:0;top:0;
    width:clamp(240px,27vh,340px);height:clamp(240px,27vh,340px);
    border-radius:0}

  /* ESPN's headshots are cut out, so the player stands on the club's
     colour rather than on a navy slab. */
  html.viewer .nom-shot{background:none;border:0;object-fit:contain;
    object-position:bottom center;z-index:0}
  /* The projections card passes in front of him — that overlap is what
     makes him look stood on it rather than pasted over it. */

  html.viewer .nom-art .nom-badge{display:none}
  html.viewer .nom-mono{font-size:88px}
  /* The position is already in the board row and the resume bar above; on
     a screen it was a pink tab floating over the club's colour. */
  html.viewer .nom-art .nom-pos{display:none}
  /* The name stacks: given name light and spaced above, surname in the
     display face below — the auction hero's treatment. */
  html.viewer .nom-stack{display:flex;flex-direction:column;gap:2px}
  html.viewer .nom-first{font-family:var(--cond);font-size:22px;
    font-weight:400;letter-spacing:.22em;text-transform:uppercase;
    color:#9fb4cd}
  html.viewer .nom-last{font-family:var(--block,'Archivo Black',sans-serif);
    font-weight:400;font-size:64px;line-height:1;letter-spacing:.005em;
    text-transform:uppercase;color:#fff;text-shadow:0 2px 10px #0009}

  /* The block sits low in the row, just clear of the card below. */
  /* On the boxes themselves, not on ":last-child" — the rights block is
     appended after the name, so that padding was landing there and the
     boxes never moved. The card below is pulled up 34px over his chin,
     so they clear it by 18px. */
  /* Above the card regardless, so nothing can push them back under it. */
  html.viewer .nom-stack{position:relative;z-index:2}
  html.viewer .nom-bio{font-size:21px;margin-top:8px}
  html.viewer .nom-meta{font-size:24px;margin-top:6px}

  /* Rank, age and club as three boxes — the auction hero's chips, in the
     same glass-on-dark treatment. */
  /* One rule for the boxes. The 52px foot clears the card below, which is
     pulled up 34px over his chin — earlier this sat on ":last-child",
     which is the rights block, so it never reached the boxes at all. */
  html.viewer .nom-chips{position:relative;z-index:2;display:flex;gap:12px;
    margin:18px 0 24px}
  html.viewer .nom-chip{width:104px;min-width:104px;min-height:74px;
    padding:9px 12px;border-radius:8px;
    display:flex;flex-direction:column;align-items:center;
    justify-content:center;gap:3px;text-align:center;
    background:#0b1119e6;-webkit-backdrop-filter:blur(10px);
    backdrop-filter:blur(10px);border:1px solid #33415a}
  html.viewer .nom-chip span{font-family:var(--cond);font-size:11px;
    font-weight:700;letter-spacing:.16em;text-transform:uppercase;
    color:var(--muted)}
  html.viewer .nom-chip b{font-family:var(--cond);font-size:26px;
    font-weight:700;line-height:1;color:var(--text)}
  html.viewer .nom-chip-logo img{width:44px;height:44px;object-fit:contain}
  html.viewer .nom-chip-money b{color:var(--money)}

  /* Stacked, projections above historical, both stretched to fill the
     height left under the player. */
  /* Pulled up over his chin by a constant amount, whatever size he is. */
  html.viewer .statwrap{position:relative;z-index:1;
    margin-top:-34px;display:flex;flex-direction:column;
    gap:18px;flex:1 1 auto;min-height:0}
  /* flex-basis auto, not 0: with a basis of zero the two cards split the
     height evenly, so one row of projections got as much room as four
     rows of seasons — and the seasons overflowed their card, which clips.
     From their natural heights, the spare space is shared on top. */
  /* The seasons card takes the spare height; the projections card is one
     row and stretching it only left an empty band under the figures. */
  html.viewer .statwrap > .stat-card{display:flex;flex-direction:column;
    flex:0 0 auto}
  html.viewer .statwrap > .stat-card:last-child{flex:1 1 auto;
    min-height:min-content}
  html.viewer .stat-card > .stat-grid,
  html.viewer .stat-card table{flex:1 1 auto}
  /* The rows stretch with the card rather than sitting at its top. */
  html.viewer .stat-card table{height:100%}
  /* The title is .stat-head b, not the bar — 16px on the container did
     nothing to it. */
  html.viewer .stat-head{padding:14px 18px}
  html.viewer .stat-head b{font-size:19px;letter-spacing:.18em;
    color:#dbe7f4}
  html.viewer .stat-head .finish{font-size:16px}
  /* A rule in the gap between the two sections, so the seasons read as
     their own block. Drawn in the gap rather than as a border on the
     card: the card is rounded and clips its overflow, so a top border
     would read as a cap on it instead of a line between the two. */
  html.viewer .statwrap > .stat-card + .stat-card{position:relative}
  html.viewer .statwrap > .stat-card + .stat-card::before{content:"";
    position:absolute;left:0;right:0;top:-10px;height:2px;
    background:#ffffff3d;border-radius:2px}
  html.viewer .stat-card table{font-size:18px}
  html.viewer .stat-card th{font-size:13px;padding:10px 13px}
  html.viewer .stat-card td{padding:14px 13px}
  /* Bigger and brighter across the seasons table. The figures inherited a
     17px condensed face and the year column was --muted, which is legible
     on a desk and not from across a room. */
  html.viewer .hist td{font-size:22px;font-weight:600;color:var(--text)}
  html.viewer .hist th{font-size:12px;letter-spacing:.12em;color:#93a7bd}
  html.viewer .hist .c-year{color:#cddcec;font-weight:700}
  html.viewer .hist .c-fin{font-size:21px}
  /* The projection figures are the headline of that card. The cells-6/7
     rules shrink them by column count, so those are what must be beaten. */
  html.viewer .stat-cell{padding:14px 10px}
  html.viewer .stat-cell b,
  html.viewer .stat-grid.cells-6 .stat-cell b,
  html.viewer .stat-grid.cells-7 .stat-cell b{font-size:30px}
  html.viewer .stat-cell span,
  html.viewer .stat-grid.cells-6 .stat-cell span,
  html.viewer .stat-grid.cells-7 .stat-cell span{font-size:12px;
    letter-spacing:.06em}
  /* A stacked-layout device from the narrow pane; the gap does it here. */
  html.viewer .stat-sep{display:none}

  /* ── the board, on a screen ──────────────────────────────────────
     Nothing on a row is pressable, so the controls come off and the
     names take the width they were sharing. */
  html.viewer .rfa-right,
  html.viewer .pass-box,
  html.viewer .note-box,
  html.viewer .notefield{display:none}
  /* No filters either — a screen shows the board as it stands. */
  html.viewer #boardFilter{display:none}
  html.viewer .pane-expand{display:none}

  /* Players Signed is a working list, not something to project — and with
     it gone the stage takes the whole column, so its foot lines up with
     the board beside it rather than stopping a row short. */
  html.viewer .pane-signed{display:none}
  html.viewer .grid.no-rail .pane-stage{grid-row:1 / -1}

  /* The row's own grid, minus the columns a screen doesn't use. The
     target ring goes, the trailing controls column goes, and what's left
     of the width belongs to the name — which was wrapping onto two lines
     and truncating in the space it had. */
  /* Flex, not grid. The row's grid has a fixed column per child, so
     hiding any of them shifts the rest along and the name lands in a
     27px slot — which is what left it reading "Bra...". As a flex row
     the name simply takes whatever the hidden controls gave up, however
     many of them there are. */
  html.viewer .rfa-line{
    display:flex;align-items:center;gap:10px;padding:9px 14px}
  html.viewer .tgt-icon,
  html.viewer .tgt-rfa,
  html.viewer .tgt-poo,
  html.viewer .tgt-spacer{display:none}
  /* The face leads the row, then the rank. */
  html.viewer .rfa-face{flex:0 0 auto;width:42px;height:42px;
    border-radius:8px;object-fit:cover;object-position:top center;
    background:var(--slate-2);border:1px solid var(--line)}
  html.viewer .rfa-face-none{display:block}
  html.viewer .rfa-n{flex:0 0 auto;min-width:30px;
    text-align:right}
  /* The summary icon opens a card nobody can press on a screen. */
  html.viewer .rfa-stat{display:none}
  html.viewer .rfa-logo{flex:0 0 auto}
  /* The name block takes the rest — this is the whole point. */
  html.viewer .rfa-mid{flex:1 1 auto;min-width:0}
  html.viewer .rfa-nametext{flex:1 1 auto}
  html.viewer .rfa-name{min-width:0;flex-wrap:nowrap}
  html.viewer .rfa-nametext{font-size:19px;
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  html.viewer .rfa-sub{font-size:13px}
  html.viewer .rfa-n{font-size:15px}
  html.viewer .rfa-logo{width:26px;height:26px}
  html.viewer .rfa-row{padding:9px 12px}
  html.viewer .pane-head > span{font-size:15px}
}

/* The reveal and the decision, on a screen. Already a full-screen overlay
   over the stage — this only sizes it for a room, and takes away the
   close button a television has nobody to press. */
@media (min-width:1081px){
  html.viewer .splash{padding:34px}
  html.viewer .splash-card{width:min(1500px,94vw);max-width:none}
  html.viewer .splash-head{font-size:20px}
  html.viewer .splash-head .modal-x{display:none}
  html.viewer .splash-body{font-size:19px}
  html.viewer .splash-foot{display:none}
  html.viewer .reveal-head h3{font-size:24px}
  html.viewer .reveal-head span{font-size:16px}
  html.viewer .splash-body .cards .card{font-size:20px}
  html.viewer .outcome{font-size:24px}
}


/* Two buttons in the account card's foot rather than one. */
.modal-foot.accountfoot{display:flex;gap:10px}
.modal-foot.accountfoot .btn{flex:1 1 0;width:auto;min-width:0}


/* ── the league drawer ────────────────────────────────────────────────
   The news rail's mirror: same glass tab, same slide, from the left. */
.leaguerail{position:fixed;top:0;left:0;bottom:0;z-index:69;
  /* 72vw, not 88: at 88 the drawer and its tab reached within 47px of the
     news chevron on a phone, which put the two almost on top of each
     other. This leaves the right edge clear. */
  width:min(72vw,360px);display:flex;flex-direction:column;
  background:linear-gradient(180deg,rgba(22,29,43,.95) 0%,
    rgba(15,21,33,.97) 100%);
  -webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);
  border-right:1px solid #2a3546;
  transform:translateX(-100%);transition:transform .28s cubic-bezier(.22,.7,.3,1);
  padding-top:var(--sat,0px)}
body.league-open .leaguerail{transform:translateX(0)}

/* Red glass with white lettering, the same tab the pool and the class use
   on the other pages. */
.leaguetab{position:fixed;left:0;top:50%;transform:translateY(-50%);z-index:70;
  display:flex;flex-direction:column;align-items:center;gap:6px;
  padding:14px 7px 12px;border:1px solid rgba(226,87,76,.55);border-left:0;
  border-radius:0 8px 8px 0;
  background:rgba(150,42,35,.62);
  -webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);
  color:#fff;cursor:pointer;
  transition:transform .28s cubic-bezier(.22,.7,.3,1)}
body.league-open .leaguetab{transform:translateY(-50%) translateX(min(72vw,360px))}
.leaguetab-word{writing-mode:vertical-rl;text-orientation:mixed;
  font-family:var(--cond);font-size:11px;font-weight:700;letter-spacing:.18em;
  text-transform:uppercase}
.leaguetab-arrow{font-size:15px;line-height:1;transition:transform .28s ease}
body.league-open .leaguetab-arrow{transform:rotate(180deg)}
/* While it's being dragged the slide transition would fight the pointer. */
.leaguetab.dragging{transition:none;cursor:grabbing}

.leagueveil{position:fixed;inset:0;z-index:68;background:#05070b8c}
.leagueveil[hidden]{display:none}

/* Twelve teams and a header, in one view. The rows share whatever height
   is left rather than each taking a fixed one, so nothing scrolls on a
   short phone and nothing looks stranded on a tall screen. */
/* Scoped to the snapshot. This is a thirteen-row grid — a heading and
   twelve owners sharing the height — and it was landing on the moves
   list too, which gave that list thirteen fixed rows and squashed every
   card into a slice of one. */
#leagueRailBody{flex:1;min-height:0;overflow:hidden;
  padding:0 8px 14px;margin-top:-4px;display:grid;
  grid-template-rows:auto repeat(12,minmax(0,1fr));gap:4px}

/* One grid shared by the header and every row, so the columns line up
   without either having to know the other's widths. */
/* Six columns now. Everything shrinks a little so the name still has
   room to breathe — a truncated owner is worse than a smaller figure. */
/* Five columns, not six. The name gets what the dropped one was using —
   an owner squeezed to three letters helps nobody. */
.lghead,.lgrow{display:grid;
  grid-template-columns:26px minmax(0,1fr) 56px 40px 42px;
  align-items:center;gap:7px}
/* Padded top and bottom so the headers sit off the drawer's edge and off
   the first card, rather than touching both. */
/* Well clear of the rule under "The League" above it — at 9px the labels
   read as part of that heading rather than as headers for the list. */
.lghead{padding:20px 8px 9px;font-family:var(--cond);font-size:8.5px;
  font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  color:var(--muted)}
/* Centred over their columns. Right-aligning them put each label at the
   far edge of a column whose figures sit inset from it. */
/* The headers sort, so they are buttons. */
.lghead button{background:none;border:0;padding:0;cursor:pointer;
  font:inherit;letter-spacing:inherit;text-transform:inherit;
  color:var(--muted);display:flex;align-items:center;justify-content:center;
  gap:3px}
.lghead button:first-of-type{justify-content:flex-start}
.lghead button.on{color:var(--text)}
.lghead button i{display:none;font-style:normal;font-size:7px}
.lghead button.on i{display:inline}
.lghead button.on i::before{content:"\25bc"}
.lghead button.on.up i::before{content:"\25b2"}

/* A hair shorter, with the space going to the gaps between them — twelve
   cards packed edge to edge read as one block rather than twelve. */
/* No height of its own: the body is a grid of twelve equal rows and
   shares out whatever is left below the toggle, so a row takes its share
   rather than a fixed size. A snapshot that scrolls isn't a snapshot. */
.lgrow{padding:0 8px;border-radius:7px;background:var(--slate-2);
  border:1px solid transparent;cursor:pointer;transition:border-color .12s;
  min-height:0;margin:0}
.lgrow:hover{border-color:#3a4756}
.lgrow.me{border-color:#3a5f7d;background:#16273a}
.lgface{width:28px;height:28px;border-radius:50%;
  overflow:hidden;background:var(--slate);display:flex;
  align-items:center;justify-content:center}
.lgface img{width:28px;height:28px;object-fit:cover}
.lgname{min-width:0;font-size:12.5px;font-weight:600;color:var(--text);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* All three figures the same size and the same white, right-aligned with
   tabular numerals so they line up down the drawer. The cap and the roster
   limit ride alongside in a smaller grey — they're the same on every row,
   so they shouldn't compete with the figure that isn't. */
.lgnum{display:flex;align-items:baseline;justify-content:center;gap:2px;
  font-family:var(--cond);font-variant-numeric:tabular-nums}
.lgnum b{font-size:12.5px;font-weight:700;color:var(--text)}
/* Nobody has set a lineup yet, so there is nothing to total. */
.lgnum b.lgun{color:var(--muted);font-weight:400}
.lgnum b.over{color:var(--red)}
.lgof{font-size:8.5px;color:var(--muted)}


/* Stood down from the summit. The tile already greys via .out; this marks
   it as a choice rather than a team that ran out of money. */
.ufateam.resigned .ufateam-face{filter:grayscale(1);opacity:.5}
.ufateam.resigned::after{content:"OUT";position:absolute;left:50%;bottom:-2px;
  transform:translateX(-50%);z-index:3;
  font-family:var(--cond);font-size:8px;font-weight:700;letter-spacing:.16em;
  color:var(--muted)}

/* Resigning, on the account card. */
.accountout{padding:0 16px 4px}
.accountout .btn{width:100%}
.accountout-note{margin:7px 0 0;font-family:var(--cond);font-size:11px;
  line-height:1.4;color:var(--muted)}


/* ── the league drawer's second view ──────────────────────────────────
   Everyone this summit has sold: who, to whom, for how much. */
.lgseg{margin:10px 12px 0}
.lgfilter{padding:8px 12px 0}
.lgfilter[hidden]{display:none}
.lgfilter select{width:100%;padding:7px 9px;border-radius:7px;
  background:var(--slate-2);border:1px solid var(--line);color:var(--text);
  font-family:var(--cond);font-size:12.5px}

.lgshead{display:flex;justify-content:space-between;align-items:baseline;
  padding:12px 8px 8px;font-family:var(--cond);font-size:10px;
  font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted)}

.lgsrow{display:grid;grid-template-columns:30px minmax(0,1fr) auto;
  align-items:center;gap:9px;padding:7px 8px;border-radius:7px;
  background:var(--slate-2);margin:2px 0}
.lgspos{font-family:var(--cond);font-size:10px;font-weight:700;
  letter-spacing:.06em;text-align:center}
.lgspos.pos-QB{color:var(--pos-qb)}
.lgspos.pos-RB{color:var(--pos-rb)}
.lgspos.pos-WR{color:var(--pos-wr)}
.lgspos.pos-TE{color:var(--pos-te)}
.lgsmid{min-width:0;display:flex;flex-direction:column;gap:1px}
.lgsmid > b{font-size:13px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.lgsmid > span{font-family:var(--cond);font-size:10.5px;color:var(--muted);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lgsprice{font-family:var(--cond);font-size:15px;font-weight:700;
  color:var(--money);font-variant-numeric:tabular-nums}

/* The signings list scrolls; the team view is twelve rows and doesn't. */
#leagueRailBody:has(.lgsrow){overflow-y:auto;
  grid-template-rows:none;display:block}
/* A team that has stood down, in the drawer as on the floor. */
.lgrow.resigned .lgface{filter:grayscale(1);opacity:.55}
.lgrow.resigned .lgname{color:var(--muted)}


/* The leading bidder's name, beside their face in the banner. Its own
   class: .ufatop-who is the player block on the other side of the bar. */
.ufatop-bidder{font-family:var(--cond);font-size:14px;font-weight:700;
  letter-spacing:.02em;color:var(--text);white-space:nowrap}
@media (max-width:560px){
  /* A phone has the face and the figure and no room for a name between
     them. */
  .ufatop-bidder{display:none}
}


/* ── the free agent list ──────────────────────────────────────────────
   Everyone nobody owns. A long list, so it reads as a table rather than
   as cards: the eye runs down the names and the ranks. */
/* The topbar on this page is position:relative — it takes its own space
   in the flow rather than sitting over the content. So there is nothing
   to clear, and --top-h was never defined anyway: that padding was 64px
   of empty page between the banner and the title. */
/* scrollbar-gutter keeps the space for the scrollbar reserved whether or
   not one is showing. Without it, switching between a list that overflows
   and one that doesn't changes the viewport width by the scrollbar's
   thickness — and everything on the page, the search bar included,
   shifts sideways. */
html{scrollbar-gutter:stable}
.fapage{max-width:820px;margin:0 auto;padding:0 14px 40px}

.fahead{position:sticky;top:0;z-index:4;
  background:var(--bg);padding:14px 0 8px;margin-bottom:2px;
  border-bottom:1px solid var(--line)}

/* On a phone the page itself doesn't move: the banner, the title, the
   search and the toggles are fixed, and only the pool scrolls beneath
   them. A sticky header still lets the page scroll under it, so rows
   showed through the gaps around it — this makes the list the only thing
   with anywhere to go. */
@media (max-width:760px){
  html,body{height:100%;overflow:hidden}
  body.dhskin{display:flex;flex-direction:column}
  /* The banner is the first child of that column and never scrolls. */
  .topbar{flex:0 0 auto}
  .fapage{flex:1;min-height:0;display:flex;flex-direction:column;
    padding-bottom:0;overflow:hidden}
  .fahead{position:static;flex:0 0 auto;
    /* Opaque, and above the list, so nothing shows through it. */
    background:var(--bg);z-index:5}
  .falist{flex:1;min-height:0;overflow-y:auto;scrollbar-gutter:stable;
    -webkit-overflow-scrolling:touch;
    padding-bottom:28px;
    /* Clear of the phone's home indicator. */
    padding-bottom:calc(28px + env(safe-area-inset-bottom))}
}
.fatitle{display:flex;align-items:baseline;gap:10px;margin-bottom:10px}
.fatitle b{font-family:var(--display);font-size:20px;letter-spacing:.01em}
.fatitle span{font-family:var(--cond);font-size:12px;color:var(--muted)}
.fatools{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
/* 16px, because Safari on iPhone zooms the page when a field smaller
   than that is focused. The condensed face keeps it from reading large,
   so this is the same size on the eye and no longer moves the screen. */
#faSearch{display:block;width:100%;padding:9px 11px;border-radius:8px;
  background:var(--slate-2);border:1px solid var(--line);color:var(--text);
  font-family:var(--cond);font-size:16px}
#faSearch:focus{outline:none;border-color:#3a5f7d}

/* Centred, and each only as wide as its own buttons — a seg stretched
   across the page reads as a bar rather than a choice. */
.fatoggles{display:flex;flex-direction:column;align-items:center;gap:7px;
  margin-top:9px}
/* Both the same width. Sized to their own words, "Free agents / All
   rostered" came out wider than "All QB RB WR TE", and two stacked
   controls of different widths read as a mistake. */
.fatoggles .seg{display:inline-flex;width:min(360px,100%)}
.fatoggles .seg button{flex:1}

/* Which half of the pool: its own colour, so it isn't mistaken for the
   position filter under it. */
#faScope button.on{background:#1d4c86;color:#fff}

/* The position filter takes each position's own colour, the same one
   the badges and the depth chart use. */
#faPos button[data-pos="QB"].on{background:var(--pos-qb);color:#0b1018}
#faPos button[data-pos="RB"].on{background:var(--pos-rb);color:#0b1018}
#faPos button[data-pos="WR"].on{background:var(--pos-wr);color:#0b1018}
#faPos button[data-pos="TE"].on{background:var(--pos-te);color:#0b1018}
/* "All" carries an empty data-pos, so it needs naming exactly. */
#faPos button[data-pos=""].on{background:var(--slate-2);color:var(--text)}

/* Which club, under the position toggles. */
/* The club filter: a button and a panel, because a native select can't
   show a club's mark and the mark is what the eye goes to. */
.fateamwrap{position:relative;margin:7px auto 0;max-width:220px;width:100%}
.fateamsel{display:flex;align-items:center;justify-content:space-between;
  gap:8px;width:100%;padding:6px 10px;border-radius:7px;
  background:var(--slate-2);border:1px solid var(--line);color:var(--text);
  font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.08em;text-transform:uppercase;cursor:pointer}
.fateamsel:hover{border-color:#3a4756}
.fateamcaret{color:var(--muted);font-size:9px}

.fateammenu{position:absolute;z-index:20;top:calc(100% + 4px);left:0;right:0;
  max-height:300px;overflow-y:auto;-webkit-overflow-scrolling:touch;
  padding:4px;border-radius:8px;background:#131a26;
  border:1px solid var(--line);box-shadow:0 10px 26px #0008}
.fateamopt{display:flex;align-items:center;gap:8px;width:100%;
  padding:6px 8px;border:0;border-radius:6px;background:none;
  color:var(--text);cursor:pointer;
  font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.08em;text-transform:uppercase;text-align:left}
.fateamopt:hover{background:var(--slate-2)}
.fateamopt.on{background:#1d4c86;color:#fff}
.fateamopt img{width:18px;height:18px;flex:0 0 auto;object-fit:contain}
.fateamgap{width:18px;flex:0 0 auto}

/* The note under the toggles. */
.fanote{margin:7px 0 0;text-align:center;font-family:var(--cond);
  font-size:10px;letter-spacing:.06em;color:var(--muted)}

/* The sort header shares the row grid below, so a label sits over its
   own column. */
/* A photo at the head of the row, whose he is near the end, the action
   last. The name column takes everything left over — it carries the
   longest text on the row and was being squeezed by fixed columns that
   only ever hold four or five characters. */
/* The gap before the owner's face and the button is wider than the rest:
   the figures were running right up against the controls. */
/* Nine columns: face, position, name, salary, rank, overall, week,
   owner, action. Tighter than before — the new column and the smaller
   buttons come out of the room the old ones were wasting. */
/* Six columns: chevron, face, position, name and club, this week, the
   action. Everything else is in the drawer, which is where it belongs —
   five columns of small figures between a name and a button is what made
   these rows unreadable. */
/* Seven columns: chevron, face, position, name and club, salary, this
   week's projection, the action. */
.fahdr,.falist .farow{display:grid;
  grid-template-columns:20px 32px 26px minmax(0,1fr) 52px 64px 56px;
  align-items:center;gap:8px}
/* The projection sits well clear of the button. Sixth cell now, the
   salary having come back before it. */
.falist .farow > .fawk,.fahdr > *:nth-child(6){padding-right:18px}
/* Spacing is the grid's gap now, not per-cell margins — those were
   written for a layout with two fewer columns. */
/* The same 1px border the rows carry, transparent here. Without it the
   header's columns started a pixel inside the rows' and everything below
   read as very slightly out of line. */
.fahdr{border:1px solid transparent;
  padding:10px 11px 6px;font-family:var(--cond);font-size:9.5px;
  font-weight:700;letter-spacing:.12em;text-transform:uppercase}
.fahdr button{background:none;border:0;padding:0;cursor:pointer;
  font:inherit;letter-spacing:inherit;text-transform:inherit;
  color:var(--muted);display:flex;align-items:center;gap:4px}
/* Positions from the old layout. Name is the fourth cell now and the
   figures follow it, which the two rules below already say. */

.fahdr button.on{color:var(--text)}
/* The arrow only on the column being sorted. */
.fahdr button i{display:none;font-style:normal;font-size:8px}
.fahdr button.on i{display:inline}
.fahdr button.on i::before{content:"\25bc"}
.fahdr button.on.up i::before{content:"\25b2"}

.falist{display:flex;flex-direction:column;gap:3px}
/* Even padding. The extra 14px on the right was added back when the
   action button had no column of its own and sat against the edge; with
   a column for it, that padding is just a gap to the right of the
   button. */
.farow{padding:9px 11px;border-radius:8px;
  background:var(--slate-2);border:1px solid transparent}
/* Injured reserve: still held, not taking a place. */
.farow.is-ir{opacity:.62}

/* Money to the left of the ranking. Green, because it is money. */
.fasal{font-family:var(--cond);font-size:13px;font-weight:700;
  text-align:right;color:var(--money);font-variant-numeric:tabular-nums}

.faadd{border:1px solid #2f6b4c;background:#14301f;color:var(--money)}

/* Not for signing. Sized with Add and Trade so the column still lines up
   down the list, and left at full strength rather than dimmed like an
   ordinary disabled button — it is saying something, not unavailable. */
.falocked{border:1px solid var(--red);background:var(--red);color:#fff;
  cursor:not-allowed;opacity:1}
.faadd:hover{background:#1a4029}
.faadd:disabled{opacity:.5;cursor:default}
.faadd-gap{display:block}
.fapos{font-family:var(--cond);font-size:10.5px;font-weight:700;
  letter-spacing:.06em;text-align:center;color:var(--muted)}
.fapos.pos-QB{color:var(--pos-qb)}
.fapos.pos-RB{color:var(--pos-rb)}
.fapos.pos-WR{color:var(--pos-wr)}
.fapos.pos-TE{color:var(--pos-te)}
.famid{min-width:0;display:flex;flex-direction:column;gap:2px}
/* The name and its designation on one line, the name truncating alone. */
.faname{display:flex;align-items:center;gap:6px;min-width:0}
.faname > b{font-size:14px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.famid > b{font-size:14px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.famid > span{font-family:var(--cond);font-size:11px;color:var(--muted);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* The rank where there is one. Most of this list has none — nobody
   projected them — so the column is often empty, which is honest. */
.fanum{display:flex;flex-direction:column;align-items:flex-end;gap:1px;
  font-family:var(--cond);font-variant-numeric:tabular-nums}
.fanum b{font-size:13px;font-weight:700;color:var(--text)}
/* Nobody ranked him — a dash rather than a number he never earned. */
.fanum b.faun{color:var(--muted);font-weight:400}
.fanum span{font-size:10.5px;color:var(--money)}


/* ── injury designations ──────────────────────────────────────────────
   Ahead of the name, the mirror of the info circle that follows it. IR
   and PUP in red because those are the ones that mean something here —
   they open the injured list. The rest are shown quietly: worth knowing,
   not worth alarm. */
/* A gap after it, so the badge and the name aren't touching. */
/* Smaller. It is a mark beside a name, not a label in its own right —
   at the old size it competed with the name it belongs to. */
.instat{flex:0 0 auto;display:inline-flex;align-items:center;
  justify-content:center;min-width:18px;height:14px;padding:0 4px;
  margin-right:4px;
  border-radius:3px;background:var(--slate);border:1px solid var(--line);
  color:var(--muted);font-family:var(--cond);font-size:8px;font-weight:700;
  letter-spacing:.04em}
.instat.bad{background:#3a1b18;border-color:#7d3a33;color:#ff9b90}
/* Graded by how likely he is to play: green probable, yellow
   questionable, orange doubtful, red out. One alarm colour for all four
   would have wasted the distinction they exist to make. */
.instat.fine{background:#14301f;border-color:#2f6b4c;color:#7ce0a6}
.instat.iffy{background:#332b12;border-color:#7d6a2f;color:#ffd970}
.instat.doubt{background:#382312;border-color:#8a5a2a;color:#ffab5e}
.modal-head .instat{margin-right:8px}
.modal-headname{min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
/* The bye, at the end of the card's header line. */
.card-bye{margin-left:auto;margin-right:8px;flex:0 0 auto;
  font-family:var(--cond);font-size:10px;font-weight:700;
  letter-spacing:.1em;color:var(--muted)}

/* The injured list, on a player's card. */
.card-irbar{display:flex;flex-direction:column;gap:6px;
  margin:14px 0 2px;padding:12px;border-radius:9px;
  background:var(--slate-2);border:1px solid var(--line)}
.irbtn{padding:9px 12px;border-radius:8px;cursor:pointer;
  border:1px solid #7d3a33;background:#3a1b18;color:#ff9b90;
  font-family:var(--cond);font-size:12px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase}
.irbtn:hover{background:#4a221e}
/* Coming back off it is an ordinary action, not a warning. */
.irbtn.on{border-color:#2f6b4c;background:#14301f;color:var(--money)}
.irbtn.on:hover{background:#1a4029}
.card-irnote{font-family:var(--cond);font-size:11px;line-height:1.45;
  color:var(--muted)}


/* The player's face, at the head of his row. Initials underneath, so a
   missing picture leaves something rather than a hole — this list runs to
   thousands and plenty of them have no photograph anywhere. */
/* 32px, matching its column. At 36 it overflowed by four and made rows
   with a photograph taller than rows without one — which is why the two
   views looked like different sizes. */
.faface{position:relative;width:32px;height:32px;border-radius:50%;
  overflow:hidden;background:var(--slate);display:flex;align-items:center;
  justify-content:center;flex:0 0 auto}
.faface-mono{font-family:var(--cond);font-size:11px;font-weight:700;
  color:var(--muted)}
.faface img{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;object-position:top center}

/* Whose he is, at the end. */
.faown{width:26px;height:26px;border-radius:50%;overflow:hidden;
  background:var(--slate);display:flex;align-items:center;
  justify-content:center;flex:0 0 auto}
.faown img{width:100%;height:100%;object-fit:cover}
.faown-mono{font-family:var(--cond);font-size:10px;font-weight:700;
  color:var(--muted)}
.faown-gap{display:block}

/* Offer for somebody else's player. Blue rather than green: this isn't a
   signing, it's an approach. */
/* Blue with white lettering, the league's trade colour. */
/* Smaller: they sit in a fixed column, and the room they were taking
   belongs to the name. */
.fatrade,.faadd,.falocked{width:100%;padding:5px 3px;border-radius:6px;
  font-family:var(--cond);font-size:9.5px;font-weight:700;
  letter-spacing:.04em;text-transform:uppercase;cursor:pointer}
.fatrade{border:1px solid #2f6ba8;background:#1d4c86;color:#fff}
.fatrade:hover{background:#245a9e}

/* Choosing who to drop. The same rows as the list, in a card. */
/* On a phone there isn't room for all seven. The projection column and
   the owner's face go first — the name, the money and the action are
   what the row is for. */
@media (max-width:560px){
  /* The rank column goes; the week's projection is the number people
     actually want on a phone. */
  /* The same six, a little tighter. Nothing is dropped — there is
     nothing left to drop. */
  .fahdr,.falist .farow{
    grid-template-columns:18px 30px 24px minmax(0,1fr) 46px 56px 52px;
    gap:6px}
  .falist .farow > .fawk,.fahdr > *:nth-child(6){padding-right:12px}
  /* Nothing hidden here any more. This used to drop the salary, rank and
     owner columns on a phone; with six columns those are gone from the
     row entirely, and the rule was hiding the Proj header instead —
     nth-child(5) means something different now. */
  .faface{width:32px;height:32px}
}

.dropcard{max-width:520px}
.dropnote{margin:0 0 12px;font-family:var(--cond);font-size:12.5px;
  line-height:1.5;color:var(--muted)}
.dropwarn{color:#ff9b90}
.droprow{display:grid;grid-template-columns:36px 28px minmax(0,1fr) 52px auto;
  align-items:center;gap:9px;padding:7px 8px;border-radius:8px;
  background:var(--slate-2);margin-bottom:4px}


/* The club's badge, ahead of its abbreviation. */
.fasub{display:flex;align-items:center;gap:5px;min-width:0;
  font-family:var(--cond);font-size:11px;color:var(--muted)}
.fasub > span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.falogo{width:15px;height:15px;object-fit:contain;flex:0 0 auto}

/* This week's projection. */
.fawk{font-family:var(--cond);text-align:right;
  font-variant-numeric:tabular-nums}
.fawk b{font-size:13px;font-weight:700;color:var(--text)}
.fawk b.faun{color:var(--muted);font-weight:400}

/* Injured reserve, at the foot of the rostered list. */
.irbreak{height:1px;background:var(--line);margin:16px 0 0}
.irhead{display:flex;align-items:baseline;justify-content:space-between;
  padding:12px 2px 8px;font-family:var(--cond);font-size:10px;
  font-weight:700;letter-spacing:.14em;text-transform:uppercase}
.irhead b{color:#ff9b90}
.irhead span{color:var(--muted)}
/* Their rows read as set aside rather than dimmed out of usefulness. */
.falist .farow.is-ir{opacity:1;background:#2a1614;border-color:#5c2a25}


/* Injured reserve, at the foot of a roster card. Set aside from the depth
   chart above it — held, but not taking a place. */
.rgroup-ir .rgroup-head b{color:#ff9b90}
.rgroup-ir{margin-top:6px;padding-top:10px;border-top:1px solid var(--line)}
.rgroup-ir .rrow,.rgroup-ir .rlist-row{background:#2a1614}


/* The roster card's money, beside the team rather than under it. Short,
   because it shares that line with the team picker and the tabs. */
/* One line, whatever it holds. Small enough that the money, the penalty
   and both counts fit beside the team picker rather than wrapping under
   it — this line is a glance, not a paragraph. */
/* A row of its own now that the tabs have moved down, so it can be read
   at a size worth reading. */
/* flex-direction stated: an earlier rule sets column, and this one never
   overrode it — which is why the penalty sat on a line of its own however
   much room there was beside the money. */
/* The money and its penalty on one line, the counts under them. Written
   as a grid rather than a wrapping flex row: wrapping decided where the
   break fell by how much room was left, which put the penalty on its own
   line whenever the figures ran a little long. A grid puts it where it
   is told. */
/* Two stacked lines, each laid out on its own. Written as blocks rather
   than as a grid or a wrapping row: both of those decide where a line
   breaks from the room available, and every version of that put the
   penalty somewhere I didn't ask for. A block ends where it is told. */
/* Two stacked lines. A flex column rather than a block: as a block it
   was a flex item with no basis of its own and collapsed to nothing,
   which took the money, the penalty and the counts off the card
   altogether. The column still lays each line out on its own, which is
   what the penalty needed. */
.rostercap{display:flex;flex-direction:column;align-items:flex-end;
  gap:1px;margin-left:auto;flex:0 0 auto;text-align:right;
  font-family:var(--cond);font-size:12px;color:var(--muted);
  white-space:nowrap}
.rostercap > .rc-money,
.rostercap > .rc-counts{display:block;white-space:nowrap}
/* Written into the line's text, so it needs no layout of its own — only
   a colour. Anything that gave it a box is what kept breaking the line. */
.rostercap .rc-pen{display:inline;white-space:nowrap}
.rostercap > span{white-space:nowrap}
/* The row it sits in wraps by default. It mustn't here — the money
   dropping to a line of its own is exactly what this avoids. */
#rosterSheet .sheet-filter:first-of-type{flex-wrap:nowrap}
.rostercap b{font-weight:700}
.rostercap .rc-money{font-size:16px;color:var(--text)}
/* Past the soft cap, then at the hard one. */
.rostercap .rc-money.warn{color:#ffd970}
.rostercap .rc-money.over{color:var(--red)}
.rostercap .rc-money .rc-pen{font-size:11px}
.rostercap .rc-pen{color:var(--red);font-weight:700;font-size:11px}
/* The dot between the money and the penalty. */
/* No separator here: home.js already writes one before the penalty, and
   the two together read as "$249 / $250 · · $1 PEN". Spacing only. */
.rostercap .rc-pen{margin-left:1px}
/* The counts go first when there isn't room: the money is the figure
   this line exists for. */
/* The counts move under the money on a narrow card rather than
   vanishing — the row is theirs alone now, so there is room. */
@media (max-width:560px){
  /* gap here is the space between the two rows, not between figures on a
     line — 7px was pushing the counts away from the money. */
  .rostercap{font-size:11px}
  .rostercap .rc-money{font-size:14px}
}

/* The second filter row: how to show them, then what to show — stacked,
   each on its own line. The id as well as the class, so this can't be
   outweighed by anything the shared .sheet-filter rule sets. */
/* Switching view, owner or density redraws the card. A short fade covers
   the swap so it reads as a change rather than a flicker. Driven by a
   class the script sets, not by a bare animation: the body is emptied
   and refilled rather than replaced, and an animation on an element that
   was never replaced does not play again. */
#rosterBody.swapped,#rosterPicks.swapped{animation:rosterIn .18s ease}
@keyframes rosterIn{from{opacity:0;transform:translateY(3px)}
  to{opacity:1;transform:none}}

/* Row two: which view of the team. The primary choice on this card, and
   styled to say so — wide, tall, and the chosen side filled rather than
   merely tinted, so it reads as a switch rather than a hint. */
#rosterSecond.sheet-filter-second{display:flex;justify-content:center;
  align-items:center;gap:7px;padding:10px 16px;flex-wrap:nowrap}
/* The seg is a flex child of a centred row; without this it takes the
   whole width and its buttons centre inside it rather than the pair
   sitting centred on the row. */
#rosterSecond .seg{margin:0 auto}
#rosterSecond .seg{width:100%;max-width:320px;flex:0 1 auto;padding:3px}
#rosterSecond .seg button{flex:1;padding:9px 10px;font-size:12px;
  letter-spacing:.16em;border-radius:6px}
/* A colour each, so which view you are in is read from the switch itself
   rather than from what happens to be below it. */
#rosterSecond .seg button[data-mode="roster"].on{background:#1d4c86;
  color:#fff;box-shadow:0 1px 0 #0004}
#rosterSecond .seg button[data-mode="lineup"].on{background:#2f6b4c;
  color:#fff;box-shadow:0 1px 0 #0004}

/* Row three: two halves, one question each. Goes away with the lineup,
   which has neither to answer. */
#rosterThird.sheet-filter-third{display:flex;align-items:center;gap:8px;
  padding:8px 16px;flex-wrap:nowrap}
#rosterThird[hidden]{display:none}
.rthird-half{flex:1 1 0;min-width:0;display:flex;justify-content:center}
.rthird-half .seg{width:auto;flex:0 0 auto}
/* The density switch is put here by script; without this it keeps the
   margin it had at the top of the list. */
/* align-self as well as margin: the rule where this seg is defined pins
   it to flex-start, which beat the container's centring for that one
   child and left it sitting left while the toggle below it was centred. */
#rosterSecond .rdensity{margin:0;align-self:center}

/* One or the other, not both. They are always both built — this is which
   one you asked for, so switching costs nothing. */
/* Players and Picks swap on a class, which is instant. The one arriving
   fades in so the change reads rather than blinks. */
body.roster-picks .rosterbody{display:none}
body:not(.roster-picks) .rosterpicks{display:none}
body.roster-picks .rosterpicks,
body:not(.roster-picks) .rosterbody{animation:rosterIn .18s ease}


/* The end of a picker row: the projection, then where he is now. The
   name in the middle takes the slack, so only the first of these needs
   pushing right. */
.lu-pick-mid{flex:1;min-width:0}
.lu-pick-proj{flex:0 0 auto;margin-left:auto;font-family:var(--cond);
  font-size:14px;font-weight:700;color:var(--text);
  font-variant-numeric:tabular-nums}
.lu-pick-row.benched .lu-pick-proj{color:var(--muted)}
/* Where he is now is styled with the picker's card, further down — it
   moved to the front of the row and took the lineup's slot width. */


/* The slot picker's rows are the lineup's rows now, so they only need
   wrapping and a state colour rather than a layout of their own. */
.lu-pickwrap{display:block;margin-bottom:5px;border-radius:9px;
  border:1px solid transparent}
.lu-pickwrap.on{border-color:#2f6b4c}
.lu-pickwrap .rr{width:100%}
.lu-pickwrap.benched .lu-proj{color:var(--muted)}


/* The slot picker's card. Its head takes the slot's own colour instead
   of the app's red, so opening a FLEX and opening a QB are visibly
   different cards. */
.lu-pickcard .modal-head{background:#161c25;color:var(--text)}
.lu-pickcard.slot-QB .modal-head{background:var(--pos-qb);color:#0b1018}
.lu-pickcard.slot-RB .modal-head{background:var(--pos-rb);color:#0b1018}
.lu-pickcard.slot-WR .modal-head{background:var(--pos-wr);color:#0b1018}
.lu-pickcard.slot-TE .modal-head{background:var(--pos-te);color:#0b1018}
.lu-pickcard.slot-FLEX .modal-head{background:var(--gold);color:#0b1018}
.lu-pickcard.slot-OP .modal-head{background:#e07b26;color:#0b1018}
.lu-pickcard .modal-head .modal-x{color:#0b1018;opacity:.7}

/* Where he is now, at the front of the row. The same width as the
   lineup's own slot column, so the two line up. */
.lu-pick-at{width:44px;flex:0 0 auto;font-family:var(--cond);font-size:9px;
  font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  text-align:center;color:var(--muted)}
.lu-pick-at.starting{color:var(--gold)}
.lu-pick-at.here{color:var(--money)}
/* Not in the lineup at all. Red, so a man on the bench is told apart at
   a glance from one taken out of another slot. */
.lu-pick-at.bn{color:var(--red)}


/* The commissioner's penalty correction, beside the money it changes. */
/* A third child of that column, so it sits under the counts rather than
   stretching across them. */
.rc-fix{align-self:flex-end;margin-top:3px;
  flex:0 0 auto;padding:2px 7px;border-radius:5px;cursor:pointer;
  border:1px solid #7d3a33;background:#2a1614;color:#ff9b90;
  font-family:var(--cond);font-size:8.5px;font-weight:700;
  letter-spacing:.08em;text-transform:uppercase}
.rc-fix:hover{background:#3a1b18}

.penrow{display:flex;align-items:center;gap:8px;margin-top:12px}
.peninput{flex:1;min-width:0;padding:9px 11px;border-radius:8px;
  background:var(--slate-2);border:1px solid var(--line);color:var(--text);
  font-family:var(--cond);font-size:15px;font-weight:700;
  font-variant-numeric:tabular-nums}
.peninput:focus{outline:none;border-color:#3a5f7d}


/* The rule under whoever holds the slot now: below it are the men who
   could take it from him. */
.lu-pick-break{height:1px;margin:9px 2px 10px;background:var(--line)}

/* Clearing the slot, at the foot of its card. */
.lu-clearslot{margin-top:12px}


/* The eleven's projected total, above them. */
.lu-total{display:flex;flex-direction:column;align-items:center;gap:1px;
  margin:0 0 12px}
.lu-total b{font-family:var(--cond);font-size:30px;font-weight:700;
  line-height:1;color:#fff;font-variant-numeric:tabular-nums}
.lu-total span{font-family:var(--cond);font-size:9px;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;color:var(--muted)}

/* The lineup's one instruction, centred over the slots it refers to. It
   had no styling at all and inherited a paragraph's left edge. */
.lu-hint{margin:0 0 10px;text-align:center;font-family:var(--cond);
  font-size:11px;letter-spacing:.06em;color:var(--muted)}

/* Clearing the whole lineup is a destructive act and now says so. */
.lu-clear{border-color:#7d3a33;background:#2a1614;color:#ff9b90}
.lu-clear:hover{border-color:var(--red);background:#3a1b18;color:#fff}


/* A starter's row takes a wash of the slot he fills, so the lineup reads
   as a set of positions rather than a list of names. Kept faint: it is
   the background, and the name on top of it has to stay legible. */
.rr.starting.start-QB{background:color-mix(in srgb,var(--pos-qb) 14%,var(--slate))}
.rr.starting.start-RB{background:color-mix(in srgb,var(--pos-rb) 14%,var(--slate))}
.rr.starting.start-WR{background:color-mix(in srgb,var(--pos-wr) 14%,var(--slate))}
.rr.starting.start-TE{background:color-mix(in srgb,var(--pos-te) 14%,var(--slate))}
.rr.starting.start-K{background:color-mix(in srgb,var(--gold) 14%,var(--slate))}
/* FLEX and OP have colours of their own — they are slots, not positions,
   and borrowing a position's colour would say the wrong thing. */
.rr.starting.start-FLEX{background:color-mix(in srgb,var(--gold) 14%,var(--slate))}
.rr.starting.start-OP{background:color-mix(in srgb,#e07b26 14%,var(--slate))}
/* Browsers without color-mix fall back to the plain card rather than to
   nothing, so the row is never invisible. */
@supports not (background:color-mix(in srgb,red 10%,blue)){
  .rr.starting{background:var(--slate)}
}

/* The picker's card, likewise: the men who could fill the slot are shown
   against it. */
.lu-pickwrap.in.start-QB .rr{background:color-mix(in srgb,var(--pos-qb) 14%,var(--slate))}
.lu-pickwrap.in.start-RB .rr{background:color-mix(in srgb,var(--pos-rb) 14%,var(--slate))}
.lu-pickwrap.in.start-WR .rr{background:color-mix(in srgb,var(--pos-wr) 14%,var(--slate))}
.lu-pickwrap.in.start-TE .rr{background:color-mix(in srgb,var(--pos-te) 14%,var(--slate))}
/* The one already in this slot keeps his green edge — that is selection,
   which is a different thing from which position he plays. */
.lu-pickwrap.on{border-color:#2f6b4c}


/* The drawer is a sibling of the row, not a cell inside it — eleven
   items in a ten-column grid was spilling into an implicit column, and
   that column is the space that kept appearing beside the button. */
.farowwrap{display:block}
.farowwrap > .rrow-drawer{padding-left:11px;padding-right:11px}
/* And a little below it, so an open card doesn't touch the next one. */
.farowwrap > .rrow-drawer .rrow-drawerin{padding-bottom:8px}
.farow > .rrow-more{width:18px;height:18px;margin:0;justify-self:center}
/* Figures right-aligned in both header and rows, so the columns read as
   columns rather than as text that happens to be near each other. */
/* Name aligns left; every other header sits over its figures. */
.fahdr > button:not(:nth-child(4)),
.falist .farow > .fasal,
.falist .farow > .fanum,
.falist .farow > .fawk{justify-self:end;text-align:right}
.fahdr > button:nth-child(4){justify-self:start}
/* Where a row has nothing to show, so the columns still line up. */
.famore-gap{display:block}

/* The action finishes the row, hard against the right edge. stretch,
   not end: justify-self:end shrinks a grid item to its content and
   parks it at the edge, which left the rest of the column empty beside
   it — the gap that kept appearing to the right of the button. */
.falist .farow > .faadd,
.falist .farow > .fatrade,
.falist .farow > .falocked,
.falist .farow > .faadd-gap{justify-self:stretch;width:100%;margin:0}
.falist .farow > .faown,
.falist .farow > .faown-gap{justify-self:center}
.farow > .rrow-more i{font-size:7px}
.farow > .rrow-drawer .rrow-week,
.farow > .rrow-drawer .rrow-statline{gap:5px}


/* Every row the same height, whatever it holds — a photograph, initials,
   a designation badge or none of them. */
.falist .farow{min-height:46px}
.fahdr{min-height:0}

/* The club, and whose he is, under the name. */
.fasub{display:flex;align-items:center;gap:5px;min-width:0;
  font-family:var(--cond);font-size:10px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted);overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.fateam{width:13px;height:13px;flex:0 0 auto;object-fit:contain}
.faowner{color:var(--blue);font-weight:700}
/* No NFL club. Not the league's UFA summit — this is the man being
   unsigned, which is why he has no badge beside him. */
.faufa{color:var(--muted);font-weight:700}


/* The league drawer's two views. */
/* The rail is a fixed column; its parts have to be laid out as one or
   the moves list has no height to scroll within. */
.leaguerail{display:flex;flex-direction:column}
.leaguerail .hubrail-head,.leaguerail .railseg{flex:0 0 auto}
/* Both bodies take the space that is left; what they do with it differs
   and is set on each by id. */
.leaguerail > .hubrail-body{flex:1;min-height:0}

/* Room above and below. It sat hard against the heading and the first
   card, which read as cramped on a drawer that has the height to spare. */
.railseg{margin:18px 10px 4px;width:calc(100% - 20px);display:flex}
.railseg button{flex:1;padding:7px 8px}
#leagueView button.on{background:#1d4c86;color:#fff}

/* Snapshot stays as it was: a clean look-in, no scrolling. Transactions
   is a column of moves and does scroll — that is the difference between
   the two, so it is stated here rather than left to the content. */
/* Stated by id as well, so the shared .hubrail-body rules further up the
   file can't decide this one's layout. It is a plain scrolling column. */
#leagueMovesBody.hubrail-moves{flex:1;min-height:0;
  display:flex;flex-direction:column;gap:7px;
  overflow-y:auto;overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;padding:0 10px 16px}
/* Every card its own height. Flex children shrink to fit by default, so
   a long list squashed them all — flex:0 0 auto is what stops that and
   lets the column scroll instead. */
.hubrail-moves > .movecard{flex:0 0 auto}

.movecard{padding:9px 11px;border-radius:8px;background:var(--slate-2);
  border:1px solid var(--line);border-left-width:3px;
  min-height:64px;display:flex;flex-direction:column;justify-content:center}
/* A trade opens the panel where trades are actually laid out. */
.movecard.tappable{cursor:pointer}
.movecard.tappable:hover{border-color:#3a4756}
.movecard.is-trade .moverow b{white-space:normal}
/* A colour each, so the kind of move is read before the words are. */
.movecard.is-trade{border-left-color:var(--gold)}
.movecard.is-cut{border-left-color:var(--red)}
.movecard.is-signing{border-left-color:var(--money)}

.movecard-head{display:flex;align-items:baseline;justify-content:space-between;
  gap:8px;margin-bottom:5px;font-family:var(--cond);font-size:9px;
  font-weight:700;letter-spacing:.14em;text-transform:uppercase}
.movecard.is-trade .movecard-head b{color:var(--gold)}
.movecard.is-cut .movecard-head b{color:#ff9b90}
.movecard.is-signing .movecard-head b{color:var(--money)}
.movecard-when{color:var(--muted);letter-spacing:.06em}

.moverow{display:flex;align-items:baseline;gap:7px;min-width:0}
.moverow b{font-size:12.5px;color:var(--text);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.moverow span{font-family:var(--cond);font-size:9.5px;color:var(--muted);
  letter-spacing:.06em;text-transform:uppercase;min-width:0;
  overflow:hidden;text-overflow:ellipsis}

.moveteam{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;color:var(--text);font-weight:700}
.movefoot{display:flex;align-items:baseline;gap:8px;margin-top:4px;
  font-family:var(--cond);font-size:9.5px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}
.movecost{color:var(--money);font-weight:700}
.movecard.is-cut .movecost{color:var(--red)}
.movedrop{color:var(--muted)}


/* ── male in search of ─────────────────────────────────────────────── */

/* The bar above the notices, with the ring at its right-hand end. */
.misobar{display:flex;align-items:center;justify-content:space-between;
  gap:10px}

/* The ring sits beside the trade button, same size and shape, one place
   further along the edge. It glows rather than sitting still, because it
   is the one thing you can do from this tab. */
/* Level with the trade button and clear of it: that one is 46px wide
   with 16px of margin, so this sits at 16 + 46 + 12. */
/* The ring shadows the trade button: the same shape, and the same place
   in each of the contexts the sheet positions that button — just one
   button's width further left. 58px in a 46px button plus 12px of gap.

   Stated in each of those contexts rather than once, because the sheet
   sets the button's position through selectors of differing weight and
   a single rule would lose to some of them. */

/* The ring stands on its own rather than depending on which other class
   the markup happens to carry. That dependency is what kept moving it:
   the class has changed several times while this was being fitted, and a
   browser holding an older trades.js would give it a class the stylesheet
   no longer knew — leaving it with no size and no position at all, which
   is an ordinary button sitting wherever it falls in the panel.

   So: the full box here, and the same position the trade button takes in
   each context, offset by one button's width. It works whether or not it
   is also carrying .fab-trade. */
/* Hooked on the id, not the class.

   The ring kept landing unpositioned — behind the trade button and up in
   the flow, ignoring z-index, which only a static element does. Its
   class has been four different things while this was being fitted, and
   trades.js is a plain cached script: a browser holding any older copy
   gives the element a class this stylesheet no longer knows, and it gets
   no rules at all.

   #misoRing has been its id in every version. The id cannot fall out of
   step with a stale script, so the placement hangs off that. */
/* Appearance, and a place to stand if it is never measured.

   placeRing in trades.js puts it beside the trade button by reading that
   button's own offsets — the sheet moves the button through several
   rules and transforms the card it sits in, so coordinates written here
   could not be kept in step. But the button is hidden for a viewer
   account, and there is nothing to measure then, so these give the ring
   somewhere sensible to be in the meantime. */
#misoRing{position:fixed;z-index:61;
  right:calc(16px + 58px);bottom:calc(16px + var(--sab,0px));
  width:46px;height:46px;
  padding:0;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:var(--slate);box-shadow:0 10px 26px #0009;cursor:pointer;
  transition:transform .12s,border-color .12s,background .12s;
  border:1px solid #c25a9a;color:#ff8fd0;
  animation:misoglow 2.2s ease-in-out infinite}
#misoRing svg{width:30px;height:21px;display:block}
#misoRing:hover{background:#3a1b2c;color:#ffb3e0;border-color:#ff8fd0}
#misoRing:active{transform:translateY(2px)}
#misoRing[hidden]{display:none}

/* No placement rules at all: anything here would be overwritten by the
   inline styles placeRing sets, and two sources of truth is what caused
   the trouble. */

@media (prefers-reduced-motion:reduce){ #misoRing{animation:none} }

@keyframes misoglow{
  0%,100%{box-shadow:0 0 0 0 #ff8fd000;border-color:#8a4270}
  50%{box-shadow:0 0 16px 3px #ff8fd066;border-color:#ff8fd0}
}
/* Somebody who would rather it didn't move. */
@media (prefers-reduced-motion:reduce){
  .misoring{animation:none}
}

/* A notice reads like a block listing — the same card, the same owner
   chip, the same trade button — tinted so the board is recognisable at a
   glance without anything on it being loud. Named through the sheet
   because the block's own rules set the background there. */
#tradesSheet .blocklist .tb-item.misorow,
.misorow{background:#241520;border-color:#6b3352}
#tradesSheet .blocklist .tb-item.misorow:hover,
.misorow:hover{border-color:#c25a9a}

/* A notice reads like a block listing: the same card, the same owner
   chip, the same trade button. Only the words differ. */
/* One size for the whole line, so "male in search of" and the positions
   inside it read as one sentence. The words are white; the positions
   carry the only colour, which is what the eye is meant to find. */
/* Your own notice opens for editing when tapped. */
.misorow.tappable{cursor:pointer}
#tradesSheet .blocklist .tb-item.misorow.tappable:hover{border-color:#ff8fd0}

.misorow .misotext{color:var(--text);font-family:var(--cond);
  font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;
  white-space:normal}
/* The positions sit in the same line and read at the same size as the
   words around them — inheriting rather than setting their own. */
/* Named through the sheet, because "#tradesSheet .blocklist .tb-item
   .tb-item-mid b" sets 14px on any bold element in this card — an id and
   three classes, which a lone .misopos was never going to beat. That is
   why these read larger and white however they were styled. */
#tradesSheet .blocklist .tb-item .tb-item-mid .misotext .misopos,
.misopos{font-size:inherit;font-family:inherit;letter-spacing:inherit;
  text-transform:inherit;font-weight:700;line-height:inherit}
#tradesSheet .misopos.pos-QB,.misopos.pos-QB{color:var(--pos-qb)}
#tradesSheet .misopos.pos-RB,.misopos.pos-RB{color:var(--pos-rb)}
#tradesSheet .misopos.pos-WR,.misopos.pos-WR{color:var(--pos-wr)}
#tradesSheet .misopos.pos-TE,.misopos.pos-TE{color:var(--pos-te)}
/* Picks are gold wherever they appear, as they are on a trade. */
#tradesSheet .misopos.pos-PICKS,.misopos.pos-PICKS{color:var(--gold)}

/* The tab reads like the others until it is chosen; then the words turn
   pink. The panel behind stays the same grey the other tabs use. */
#tradeView button[data-view="miso"].on{color:#ff8fd0}

/* Choosing what you're after. */
/* Five now, with PICKS. Auto-fit rather than a fixed count, so adding
   another later doesn't need this touching. */
.misopick{display:grid;grid-template-columns:repeat(5,1fr);gap:6px;
  margin:14px 0 4px}
.misopick .misopick-opt{padding:12px 2px;font-size:12px}
.misopick .misopick-opt.on{padding:11px 1px;font-size:13px}
/* PICKS is the long word; it gets a size of its own so it fits. */
.misopick .misopick-opt[data-pos="PICKS"]{font-size:9.5px;
  letter-spacing:.04em}
.misopick .misopick-opt.on[data-pos="PICKS"]{font-size:10.5px}
.misopick-opt{padding:12px 6px;border-radius:8px;cursor:pointer;
  background:var(--slate-2);border:1px solid var(--line);color:var(--muted);
  font-family:var(--cond);font-size:13px;font-weight:700;
  letter-spacing:.1em}
.misopick-opt:hover{border-color:#3a4756}
/* Chosen, and plainly so: the word takes the position's colour, the
   edge takes it too, and a tick sits in the corner. A colour change
   alone was too quiet to read at a glance. */
.misopick-opt{position:relative}
.misopick-opt.on{background:#1b2431;border-width:2px;padding:11px 5px;
  font-size:14px}
.misopick-opt.on::after{content:"\2713";position:absolute;top:2px;right:5px;
  font-size:9px;line-height:1;opacity:.9}
.misopick-opt.on[data-pos="QB"]{color:var(--pos-qb);border-color:var(--pos-qb)}
.misopick-opt.on[data-pos="RB"]{color:var(--pos-rb);border-color:var(--pos-rb)}
.misopick-opt.on[data-pos="WR"]{color:var(--pos-wr);border-color:var(--pos-wr)}
.misopick-opt.on[data-pos="TE"]{color:var(--pos-te);border-color:var(--pos-te)}
.misopick-opt.on[data-pos="PICKS"]{color:var(--gold);border-color:var(--gold)}

/* The second question sits under the first, with room to read as its
   own thing rather than a continuation. */
.misocard .modal-body .modal-lead + .misopick{margin-bottom:16px}
.misocard .modal-body .misopick + .modal-lead{margin-top:4px}
.misosave{width:100%;margin-top:14px}


/* The M.I.S.O. card: pink where the app is normally red, since this is
   the league's own notice board rather than a warning. */
/* body.dhskin sets the red on every card header and carries a tag as
   well as a class, so it outweighs a plain .misocard rule whatever the
   order. Matched at the same weight to beat it. */
body.dhskin .misocard .modal-head{background:#c25a9a;color:#0b1018}
body.dhskin .misocard .modal-head .modal-x{color:#0b1018;opacity:.75}
/* And the way out is red, as a dismissal should be. */
body.dhskin .misocard .modal-foot .btn-go{background:var(--red);
  border-color:var(--red);color:#fff}
body.dhskin .misocard .modal-foot .btn-go:hover{background:#c0362c;
  border-color:#c0362c}
/* Post it stays the app's green — it is the same "yes, do it" as every
   other card, and only the header needed to stop being a warning. */

/* Taking your own notice down. */
.blockbtn.misodrop{background:var(--red)!important;
  border-color:var(--red)!important;color:#fff!important}
.blockbtn.misodrop:hover{background:#c0362c!important;
  border-color:#c0362c!important}


/* ── player news ──────────────────────────────────────────────────── */

/* A small page beside a name: there is something recent about him. */
/* The league's red, and tucked in against the name it belongs to. */
.newsmark{display:inline-flex;align-items:center;flex:0 0 auto;
  width:13px;height:13px;margin-left:3px;color:var(--red)}
.newsmark svg{width:100%;height:100%;display:block}

/* The card scrolls now that it can carry a run of items. */
.playercard .modal-card{max-height:88vh;display:flex;flex-direction:column}
.playercard .modal-body{overflow-y:auto;-webkit-overflow-scrolling:touch;
  overscroll-behavior:contain}

.pc-news{margin-top:14px;padding-top:12px;
  border-top:1px solid var(--line)}
.pc-newshead{display:flex;align-items:center;justify-content:space-between;
  gap:8px;margin-bottom:8px;font-family:var(--cond);font-size:9px;
  font-weight:700;letter-spacing:.16em;text-transform:uppercase;
  color:var(--muted)}
.pc-newshead .fp-btn{flex:0 0 auto}

/* Where the figures came from. Not a link — there is no page to open. */
.sleeper-mark{display:inline-flex;align-items:center;flex:0 0 auto;
  opacity:.85}
.sleeper-mark img{display:block;width:16px;height:16px;object-fit:contain}
.pc-newslist{display:flex;flex-direction:column;gap:8px}
.pc-newsitem{padding:9px 11px;border-radius:8px;background:var(--slate-2);
  border:1px solid var(--line)}
.pc-newstop{display:flex;align-items:baseline;justify-content:space-between;
  gap:10px}
.pc-newstop b{font-size:12.5px;color:var(--text);line-height:1.35}
.pc-newswhen{flex:0 0 auto;font-family:var(--cond);font-size:9px;
  letter-spacing:.08em;text-transform:uppercase;color:var(--muted)}
.pc-newsbody{margin:5px 0 0;font-size:12px;line-height:1.45;
  color:var(--muted)}
.pc-newssrc{display:inline-block;margin-top:6px;font-family:var(--cond);
  font-size:8.5px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--muted)}
/* A player note reads differently from a league headline, so its source
   is marked rather than left to be inferred from the wording. */
.pc-newsitem:has(.pc-newssrc){border-left:2px solid var(--line)}
.pc-newsnone{margin:0;font-size:12px;color:var(--muted)}

/* Placeholders while the items are fetched. They stand at the height a
   real item stands at, so the card doesn't grow under the reader. */
.pc-newsghost{pointer-events:none}
.pc-ghostline{display:block;height:11px;border-radius:3px;
  background:linear-gradient(90deg,#1c2531,#232e3d,#1c2531);
  background-size:200% 100%;animation:pc-ghost 1.4s ease-in-out infinite}
.pc-ghostline.short{width:62%;margin-top:7px}
@keyframes pc-ghost{
  0%,100%{background-position:0% 0}
  50%{background-position:100% 0}
}
@media (prefers-reduced-motion:reduce){ .pc-ghostline{animation:none} }


/* On a lineup row the news mark is its own target: the row itself
   changes who plays, so this has to be reachable without triggering it. */
.newsmark-btn{cursor:pointer;padding:2px;margin:-2px;border-radius:4px}
.newsmark-btn:hover{color:#ff6b5e;background:#2a1614}
.newsmark-btn:focus-visible{outline:2px solid var(--red);outline-offset:1px}


/* The fixture line on a lineup row. */
.rr-game{display:inline-flex;align-items:center;gap:4px;flex-wrap:wrap}
.rr-at{font-weight:700;color:var(--text)}
.rr-home{color:var(--money);font-weight:700}
.rr-away{color:var(--red);font-weight:700}
.rr-day{color:var(--muted)}
/* Kickoff, in white: it is the one figure on this line somebody plans
   around, and grey put it level with the day beside it. */
.rr-time{color:#fff;font-weight:700}


/* iPhone zooms the page whenever a field smaller than 16px takes focus,
   and then leaves it zoomed. Every field is set to 16px on a touch
   screen only — the sizes above still apply with a mouse, where the
   behaviour doesn't exist and the smaller type reads better.

   Stated once, here, rather than chased field by field as each one is
   noticed. */
@media (hover:none) and (pointer:coarse){
  input,select,textarea,
  .person-pw-input,.ab-field input,.note-input,.filtersearch,
  .rksearch,.rkadmin input,.seg-select,.peninput,
  .unl-pick select,.lgfilter select,.fateamsel{
    font-size:16px}
}


/* ── content settling in ──────────────────────────────────────────────
   Rows arrive a little after the one above, so a list assembles down the
   card rather than appearing whole. Short — 26ms apart, 180ms each — so
   it reads as the content settling rather than as an animation to sit
   through.

   Only the first eight are staggered. Past that the wait would be longer
   than anybody wants before they can read the bottom of a roster, and
   the eye has stopped following individual rows anyway. */
@keyframes settle-in{
  from{opacity:0;transform:translateY(-4px)}
  to{opacity:1;transform:none}
}

.settle > *{animation:settle-in .18s ease-out both}
.settle > *:nth-child(1){animation-delay:0ms}
.settle > *:nth-child(2){animation-delay:26ms}
.settle > *:nth-child(3){animation-delay:52ms}
.settle > *:nth-child(4){animation-delay:78ms}
.settle > *:nth-child(5){animation-delay:104ms}
.settle > *:nth-child(6){animation-delay:130ms}
.settle > *:nth-child(7){animation-delay:156ms}
.settle > *:nth-child(n+8){animation-delay:182ms}

/* Somebody who would rather the screen held still. */
@media (prefers-reduced-motion:reduce){
  .settle > *{animation:none}
}


/* ── the week's slate ─────────────────────────────────────────────────
   A band of fixtures under the header, running on its own and draggable
   by hand. It sits where the auction, draft and summit buttons were. */
/* No margin: .home-mid is a column with its own 18px gap, and a margin
   here is added to that — which is what moved the rosters down the page.
   The band takes the place the Events block had and nothing else shifts. */
/* Edge to edge. The page has 16px of padding either side, so the band
   is pulled back out by that much and given it back inside — a full-width
   band under the header rather than a card floating in the column.

   No side borders or corners for the same reason: it meets the edges. */
/* The same box the three buttons had: the column's own width, inside its
   padding, with their background, border and corners.

   Both attempts to reach the screen edges — a stated 100vw, then a
   negative margin — changed what the column measured itself against, and
   the team grid is sized from that. Those buttons set the width for
   everything below them, so this takes their shape exactly and the grid
   is laid out as it always was. */
/* min-width:0 and width:100% are what make this work.

   The track inside is max-content wide — the whole week, twice — and a
   flex item will not shrink below its own content unless told to. So
   the band grew to the track's full width and carried the column with
   it, and overflow:hidden never got the chance to clip anything. That
   is what was pushing the team grid off the screen, in every version of
   this, whatever the margins were.

   Otherwise it is the box the three buttons had: the column's width,
   their background, border and corners. */
/* A sibling of the main column, not a child of it — see home.html. It
   spans the window and clips its own track, and nothing about its width
   reaches the team grid because they share no container whose width
   either one sets. */
/* Its height is held from the first paint, before the fixtures arrive:
   appearing a beat later pushed the whole page down as it landed. Empty
   it simply reads as a bar under the header. */
.slate{position:relative;overflow:hidden;
  width:100%;max-width:100%;box-sizing:border-box;
  min-height:96px;
  margin:0;padding:8px 0 10px;
  background:var(--slate-2);
  border-bottom:1px solid var(--line);
  cursor:grab;touch-action:pan-y;user-select:none}
.slate.dragging{cursor:grabbing}
/* Faded at both ends, so games arrive and leave rather than being cut. */
.slate::before,.slate::after{content:"";position:absolute;top:0;bottom:0;
  width:34px;z-index:2;pointer-events:none}
.slate::before{left:0;background:linear-gradient(90deg,
  var(--slate-2),transparent)}
.slate::after{right:0;background:linear-gradient(270deg,
  var(--slate-2),transparent)}
/* Clear of the week heading above the games. */
.slate::before,.slate::after{top:auto;height:58px;bottom:10px}

/* Tighter again: each game carries its own padding inside its pane, so
   the gap only has to separate the panes. */
.slate-track{display:flex;align-items:center;gap:8px;
  width:max-content;will-change:transform}

/* The week, centred on a bar of the league's red. Sits above the games
   and spans the band, so it reads as a heading for the whole slate
   rather than a label on the first fixture. */
/* Hidden until there is a week to name, so an empty band shows a bar
   rather than the word "undefined". */
.slate-week:empty{display:none}
.slate-week{margin:-8px 0 8px;padding:5px 12px;text-align:center;
  background:var(--red);color:#fff;
  font-family:var(--cond);font-size:12px;font-weight:700;
  letter-spacing:.22em;text-transform:uppercase}

/* Thursday, Sunday, Monday — a mark before each day's first game, with
   its date beneath. Larger than the abbreviations, since it is what the
   eye uses to find its place in the band. */
/* The day stands between the panes. No rule of its own: the space and
   the gold are enough to mark where one day's run ends. */
.slate-day{flex:0 0 auto;display:flex;flex-direction:column;
  align-items:flex-start;justify-content:center;gap:1px;
  padding:0 14px 0 12px;margin:0 2px;align-self:stretch}
.slate-day b{font-family:var(--cond);font-size:13px;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;color:var(--gold)}
/* The date belongs to the day above it, so it takes the same gold. */
.slate-day span{font-family:var(--cond);font-size:8.5px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase;color:var(--gold);
  opacity:.75}

/* No rule between games — the panes already divide them. Just space. */
.slate-split{flex:0 0 auto;width:2px}

/* More room between games on a wide screen. A phone shows three or four
   at a time and needs them close; a desktop has the width to let them
   breathe, and at the phone's spacing they read as a single run. */
@media (min-width:1081px){
  /* 38px between games, against a pane about 80 wide — a little under
     half, which separates them without stranding each on its own. */
  .slate-track{gap:16px}
  .slate-split{width:6px}
  .slate-day{padding:0 18px 0 16px;margin:0 4px}
}

/* Each fixture sits on its own pane: a little lighter than the band
   behind it, blurred, with a thin edge catching the light at the top.
   It gives every game a shape of its own as the band moves past. */
.slate-game{flex:0 0 auto;display:flex;flex-direction:column;
  align-items:center;gap:3px;padding:6px 10px 5px;
  border-radius:10px;
  background:linear-gradient(180deg,#ffffff14,#ffffff06);
  border:1px solid #ffffff1f;
  box-shadow:inset 0 1px 0 #ffffff1a,0 1px 3px #0000003d;
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
.slate-pair{display:flex;align-items:center;gap:7px}
.slate-side{display:flex;flex-direction:column;align-items:center;gap:2px}
/* The mark carries the club; the letters underneath only confirm it, so
   they are smaller and quieter than the logo they sit beneath. */
.slate-side img{width:26px;height:26px;object-fit:contain;display:block}
.slate-side span{font-family:var(--cond);font-size:7.5px;font-weight:700;
  letter-spacing:.1em;color:var(--muted);line-height:1}
/* Level with the middle of the logos, not the whole tile — the letters
   below make the sides taller than the marks they belong to. */
.slate-at{font-family:var(--cond);font-size:10px;font-weight:700;
  color:var(--muted);align-self:flex-start;margin-top:7px}
.slate-time{font-family:var(--cond);font-size:9.5px;font-weight:700;
  letter-spacing:.06em;color:#fff}

/* The full week, when the band is tapped.

   Two columns of fixtures, so sixteen games and their headings fit one
   screen. A single column ran past the bottom and had to be scrolled,
   which defeats the point of opening it. */
/* The whole week in one view, read down the left as a list is. It fits,
   so it doesn't scroll — the modal body allows scrolling by default, and
   a card that can be scrolled invites the reader to look for something
   that isn't there. */
.slate-card{display:block;text-align:left;overflow:visible}
/* Wider and taller than a plain notice: the week has to fit at a size
   worth reading, and two columns of games want the room.

   margin:auto is restated because it is what centres the card — setting
   a width without it left the card at its natural place and running off
   the right edge. */
.modal-card:has(.slate-card){width:min(600px,92vw);
  max-height:min(100%,92dvh);margin:auto}

/* Day, and its time where the day holds only one game. */
/* A rule under each heading and under the last game of a group, so the
   week reads as separated blocks rather than one long column. */
.slate-cardday{display:flex;align-items:baseline;gap:10px;
  margin:14px 0 6px;padding-bottom:5px;
  border-bottom:1px solid var(--line);
  font-family:var(--cond);font-size:14px;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;color:var(--gold)}
.slate-cardday:first-child{margin-top:0}
/* Sunday's windows, each with the time its games kick off. */
/* No rule under a window heading — the day above it has one, and two
   lines that close together fenced every group twice. */
.slate-cardslot{display:flex;align-items:baseline;gap:9px;
  margin:10px 0 4px;
  font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
.slate-cardwhen{font-weight:700;color:#fff;letter-spacing:.06em}

/* The games under a heading, two across. */
.slate-cardgames{display:flex;flex-wrap:wrap;gap:5px 22px;
  padding-bottom:8px}
/* The last group needs no rule under it — the card ends there. */
.slate-card > .slate-cardgames:last-child{padding-bottom:0}
.slate-cardgames > *{flex:0 0 auto;min-width:120px}
.slate-cardrow{display:flex;align-items:center;gap:7px;padding:3px 0}
.slate-cardrow img{width:24px;height:24px;object-fit:contain;flex:0 0 auto}
.slate-cardrow b{font-family:var(--cond);font-size:12px;
  letter-spacing:.06em}
.slate-cardat{font-family:var(--cond);font-size:11px;color:var(--muted);
  flex:0 0 auto}

/* What is coming, where the three buttons used to be. */
/* Centred, with a hammer either side. The gap above and below is the
   column's own, so this adds none. */
/* What is still to come, in the room left above the team grid. Red
   glass: the league's own colour, held back so it reads as a panel
   waiting to be filled rather than as a warning. */
/* Fills the room between the band above and the rosters below, with the
   same cushion at each end — the block it sits in is centred, so the gap
   above and below is whatever is left, shared. */
.tocome{flex:1;min-height:0;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:9px;
  margin:0;padding:14px 16px;border-radius:12px;
  background:linear-gradient(180deg,#e5484d24,#e5484d10);
  border:1px solid #e5484d3d;
  box-shadow:inset 0 1px 0 #ffffff1f,0 2px 10px #0000002e;
  -webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}

.tocome-h{margin:0;font-family:var(--cond);font-size:12px;font-weight:700;
  letter-spacing:.2em;text-transform:uppercase;color:#fff}

.tocome-list{margin:0;padding:0;list-style:none;
  display:flex;flex-direction:column;align-items:center;gap:5px;
  font-family:var(--cond);font-size:11px;letter-spacing:.08em;
  text-transform:uppercase;color:#ffc9cb}
/* A mark before each, drawn rather than a list bullet — a centred list
   with real bullets hangs them off to one side. */
.tocome-list li{display:flex;align-items:center;gap:7px}
.tocome-list li::before{content:"";width:4px;height:4px;flex:0 0 auto;
  border-radius:50%;background:var(--red)}
