: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}
/* Pinned, not merely painted at the top. It was position:relative
   here and only became sticky inside the phone-width query, so on a
   tablet or a desktop window the whole bar — menu, wordmark, trade
   and draft buttons, the avatar — scrolled away with the page. */
.topbar{display:flex;align-items:center;gap:20px;padding:10px 18px;
  background:var(--slate);border-bottom:1px solid var(--red);flex-wrap:wrap;
  position:sticky;top:0;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)}
/* The commissioner's message box, at the foot of the account card. */
.account-say{margin-top:14px;padding-top:14px;
  border-top:1px solid var(--line);display:flex;flex-direction:column;
  gap:8px}
.account-saylabel b{display:block;font-size:14px;font-weight:600}
.account-saylabel span{display:block;margin-top:3px;font-size:12px;
  line-height:1.35;color:var(--muted)}
.account-sayinput,.account-saybody{width:100%;box-sizing:border-box;
  padding:8px 10px;border-radius:8px;background:var(--slate-2);
  border:1px solid var(--line);color:var(--text);
  font:inherit;font-size:13px}
.account-saybody{resize:vertical;min-height:64px;line-height:1.4}
.account-sayinput:focus,.account-saybody:focus{outline:none;
  border-color:#3a5f7d}
.account-sayfoot{display:flex;align-items:center;gap:10px}
.account-saynote{flex:1 1 auto;font-size:12px;color:var(--muted)}
.account-sayfoot .btn{flex:0 0 auto}

/* Notifications, under the name in the account card. */
.account-push{display:flex;align-items:center;gap:12px;
  margin-top:14px;padding-top:14px;border-top:1px solid var(--line)}
.account-pushlabel{display:flex;flex-direction:column;min-width:0;
  flex:1 1 auto;gap:3px}
.account-pushlabel b{font-size:14px;font-weight:600}
.account-pushnote{font-size:12px;line-height:1.35;color:var(--muted)}
.account-push .btn{flex:0 0 auto;white-space:nowrap}

.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:-3px;bottom:-3px;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;position:relative}
/* His age, over the top-left corner of the photograph, floating clear of
   it. The position chip moves to the right so the two don't sit on top
   of one another. */


/* His age, over the top-left corner of the photograph.

   Drawn as a pseudo-element from a data attribute rather than as a
   child. A child span is a flex item inside these faces, so where the
   stylesheet is a version behind the script it sits in the row and
   shoves the picture aside. A pseudo-element cannot do that. */
.nom-art[data-age]::after{content:attr(data-age);
  position:absolute;top:-5px;left:-5px;z-index:3;
  min-width:17px;height:17px;padding:0 3px;box-sizing:border-box;
  display:flex;align-items:center;justify-content:center;
  border-radius:999px;background:#fff;color:#0b1018;
  border:1px solid #0b101833;box-shadow:0 1px 3px #0007;
  font-family:var(--cond);font-size:11px;font-weight:700;line-height:1}

/* The position badge takes the corner the club mark used to hold —
   the club is named in full on the line beneath, so it needed no
   second mark up here. */
/* His club, in the photograph's lower corner — where the position
   badge used to be. The position is a coloured word on the line below
   now, which says the same thing without a second badge. */
.nom-clubmark{position:absolute;bottom:-7px;right:-7px;z-index:2;
  width:34px;height:34px;object-fit:contain;
  filter:drop-shadow(0 1px 4px #000c)}

.nom-pos{position:absolute;bottom:-6px;right:-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}
/* His name, stacked: given name over surname, with the salary beside
   it. The same shape on every card, wherever it was opened from. */
.nom-name{display:flex;flex-direction:column;align-items:flex-start;
  gap:0;margin:0}
/* The column beside the photograph is as tall as it is, with the club
   line pushed to the bottom. */
.nom-mid{display:flex;flex-direction:column;min-height:96px;
  min-width:0;flex:1 1 0;justify-content:space-between}
/* Only the name needs to clear the owner in the corner above it — the
   lines below sit well clear and can use the full width. */
.nom-mid .nom-name{padding-right:104px}

/* His rank, under his name. Quiet: it is context rather than a
   headline, and at the old weight it competed with the name above it. */
.nom-rank{display:flex;align-items:center;min-width:0}
.nom-rank .dyn{font-family:var(--cond);font-size:10.5px;font-weight:600;
  letter-spacing:.1em;text-transform:uppercase;color:#5f7183}
/* Sized so the club line beneath sits level with the foot of the
   photograph — the owner moved out to the corner, and the name grew
   into the room that left. */
/* Set tight, so the surname sits directly on the given name rather
   than floating a few pixels below it — the gap was leading, not
   spacing, so this is line-height rather than a margin. */
.nom-first{font-family:var(--cond);font-size:18px;font-weight:600;
  line-height:0.95;color:var(--muted);letter-spacing:.02em}
.nom-last{font-family:var(--ui);font-size:30px;font-weight:700;
  line-height:0.98;color:#fff;letter-spacing:-.015em;margin-top:1px}

/* His club, beneath the name. */
.nom-meta{display:flex;align-items:center;gap:7px;flex-wrap:wrap}
.nom-clublogo{width:19px;height:19px;flex:0 0 auto;object-fit:contain}
.nom-club{font-family:var(--cond);font-size:13px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase;color:var(--text)}
/* His position, coloured as it is everywhere else — a word rather than
   a badge, since the club mark now has the corner. */
.nom-posword{font-family:var(--cond);font-size:13px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase}
.nom-posword.pos-QB{color:var(--pos-qb)}
.nom-posword.pos-RB{color:var(--pos-rb)}
.nom-posword.pos-WR{color:var(--pos-wr)}
.nom-posword.pos-TE{color:var(--pos-te)}
/* His age, and when he was born in brackets after it. */
/* gap rather than a literal space — these are flex items, and a flex
   item's leading whitespace is trimmed, so " (24)" lost its space. */
.nom-age{display:inline-flex;align-items:center;gap:5px;
  font-family:var(--cond);font-size:12px;font-weight:600;
  letter-spacing:.04em;color:var(--muted)}
.nom-brack{opacity:.6}
/* The cake sits just left of the date and matches its size — an em
   rather than a fixed height, so it tracks the text it belongs to. */
.nom-born{display:inline-flex;align-items:center;gap:3px}
.nom-born svg{width:1em;height:1em;flex:0 0 auto;display:block}
/* CLUB · 2029 · $32 — the year he next reaches free agency, then what
   he is paid. The dots are their own elements so either part can be
   missing without leaving one stranded. */
.nom-dot{color:#4a5666;font-size:13px;line-height:1}
.nom-rfa{font-family:var(--cond);font-size:13px;font-weight:700;
  letter-spacing:.08em;color:var(--gold)}
/* What the year means, after it and quieter than it. */
.nom-rfa-what{margin-left:4px;font-size:9.5px;letter-spacing:.12em;
  opacity:.75}

/* What he is paid, over the photograph's top-right corner — the depth
   chart's badge, in the place the depth chart puts it. */
.pc-deal{position:absolute;top:-7px;left:-7px;z-index:3;
  padding:3px 9px;border-radius:6px;
  /* A deeper green than the depth chart's ring: white on #22c55e is
     2.3:1, which is unreadable at this size. #15803d gives 5:1 and
     still reads as the same colour. */
  background:#15803d;border:1.5px solid #0b1018;color:#fff;
  font-family:var(--cond);font-size:13px;font-weight:700;
  letter-spacing:.02em;line-height:1.25;white-space:nowrap;
  font-variant-numeric:tabular-nums}
/* An asking price rather than a salary somebody pays — grey where a
   real salary is green, so the two don't read alike. */
.pc-deal.ask{background:#4a5666;border-color:#0b1018;color:#fff}
.nom-paid{font-family:var(--cond);font-size:13px;font-weight:700;
  letter-spacing:.04em;color:var(--money);
  font-variant-numeric:tabular-nums}

/* Who holds him, in the card's top-right corner — his face, then his
   name to its left, opposite the photograph. */
.nom-held{position:absolute;top:0;right:0;z-index:2;
  display:flex;align-items:center;gap:7px}
.nom-ownerface{width:26px;height:26px;flex:0 0 auto;border-radius:999px;
  object-fit:cover;border:1px solid var(--line)}
.nom-owner{font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.08em;color:var(--muted);white-space:nowrap}
/* Grey whoever holds him. Green here was marking the reader's own men,
   but the corner already says whose he is by name and face — colouring
   it as well was saying the same thing twice. */
.nom-owner.mine{color:var(--muted)}
/* The same button the list view uses — squared, in that blue, so a
   Trade looks like a Trade wherever it is offered. It sits under the
   owner's name rather than beside it, where the corner has no room. */
.nom-held .nom-trade{position:absolute;top:32px;right:0}
.nom-trade{display:inline-flex;align-items:center;
  padding:5px 14px;border-radius:6px;cursor:pointer;
  border:1px solid #2f6ba8;background:#1d4c86;color:#fff;
  text-decoration:none;
  font-family:var(--cond);font-size:9.5px;font-weight:700;
  letter-spacing:.04em;text-transform:uppercase;
  transition:background .12s ease,transform .1s ease}
.nom-trade:hover{background:#245a9e}
.nom-trade:active{transform:translateY(1px)}

.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:27px;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}
/* min-height, so a stripe with only a heading in it stands as tall
   as one holding an expander or a source note. Without it the
   metrics stripe collapsed to its text and read shorter than the
   contract's beside it. */
.stat-head{display:flex;align-items:center;gap:8px;padding:7px 11px;
  min-height:31px;
  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:21px;font-weight:700;
  line-height:1.1;color:#fff}
.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:96px;height:96px;flex:0 0 auto}
.nom-shot{width:96px;height:96px;border-radius:12px;object-fit:cover;object-position:top center;
  background:var(--slate-2);border:1px solid var(--line);display:block}
/* The initials, shown where no headshot loads. Sized with the frame and
   the picture — it was left at 82 when those went to 96, so any player
   without a photograph kept the old, smaller box. */
.nom-mono{width:96px;height:96px;border-radius:12px;background:var(--slate-2);
  border:1px solid var(--line);display:grid;place-items:center;
  font-family:var(--display);font-weight:800;font-size:32px;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. */
/* A fixed overlay spans the whole viewport, scrollbar included, while
   the page behind it stops short of it — so anything centred in the
   overlay sits half a scrollbar right of the page's own centre.
   
   The overlay itself is narrowed by that width. Padding was the wrong
   lever: the cards inside use margin:auto, which simply re-centres
   within whatever padding leaves, undoing the shift. Moving the
   overlay's right edge cannot be undone from inside it.
   
   --sbw is measured at load and is 0 wherever scrollbars float, which
   is every phone — there it changes nothing. */
.modal{position:fixed;top:0;bottom:0;left:0;
  right:var(--sbw, 0px);
  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 .38s 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 .5s cubic-bezier(.22,.7,.3,1) both}
/* Its full width from the first frame.
   
   The panels arrive after the card does, and until they had it the
   card was as wide as its head alone — so it opened skinny and
   snapped. Stating the width means nothing inside it can change how
   wide it is. */
.modal-card{width:min(560px,100%);min-width:min(560px,100%)}
/* The panels are fetched after the card is on screen, so it opens at
   the height of its header and grows as each lands. Rather than try
   to outrun that, the card is given the height it will end up at and
   the panels fill into it — so nothing moves, it only fills. */
/* .cardviews is the panel stack the player card builds — .c-card was
   a class that does not exist, so this never matched and the card
   went on opening at whatever height its header gave it. */
.modal-card:has(.cardviews){height:min(560px,82dvh)}
.modal-card:has(.cardviews) .modal-body{flex:1 1 auto;overflow-y:auto}
.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}
/* A link with a note beside it — the year a finished board belongs to.
   Same shape as a "coming soon" row, but it goes somewhere. */
.drawer-link:has(em){display:flex;align-items:baseline;
  justify-content:space-between;gap:10px}
.drawer-link.soon:hover{background:none}
.drawer-link.soon em,
.drawer-link 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}

/* Something added recently, marked in the menu until it isn't new. */
.drawer-link .isnew{margin-left:7px;font-family:var(--cond);font-size:9px;
  font-weight:700;letter-spacing:.16em;text-transform:uppercase;
  font-style:normal;color:var(--red);white-space:nowrap;
  animation:isnew-blink 1.4s ease-in-out infinite}
@keyframes isnew-blink{
  0%,100%{opacity:1}
  50%{opacity:.25}
}
/* Somebody who would rather things held still gets a steady mark. */
@media (prefers-reduced-motion:reduce){
  .drawer-link .isnew{animation:none}
}
.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}
/* Of the veil, not the viewport: 97vw ignored both the scrollbar and
   the veil's padding, so on a narrow window the card was wider than
   the space it centres in. 100% then made it wider than it had been —
   the veil is the full page. 97% of the veil is the width it always
   was, measured against the right box. */
/* The width it always had. 97vw measured the viewport and so ignored
   the veil's padding and the scrollbar; 100% measures the veil's
   content box, which is the space it actually has. */
/* Its full width from the first frame.
   
   The veil is a grid with place-items:center, which makes justify-
   items center too — and a centred grid item is sized to its own
   content. Before the panels land that content is just the name in
   the header, so the card opened narrow and widened as they filled.
   justify-self:center keeps it centred while the stated width is
   what decides how wide it is. */
.playercard .modal-card{width:min(680px,100%);
  min-width:min(680px,100%);justify-self:center;margin:auto}
/* Bottom-aligned, so his name sits level with the foot of the
   photograph rather than floating at the top of a tall column.
   
   min-width:0 on the row and the column below: a flex item defaults
   to min-width:auto, which means a grid of nowrap boxes inside it can
   push the whole card wider than the card's own width rule. That is
   what widened this on a phone — not the width, but what was in it. */
.playercard .nom{margin-bottom:14px;align-items:flex-end;
  gap:14px;flex-wrap:nowrap;min-width:0;
  /* A rule in the club's colour between this block and the toggle
     below it. The header clips to it, so the photograph and the
     watermark both stop cleanly at the line rather than crossing
     into the panel underneath — which is what the fade was there
     to hide. Falls back to the ordinary divider where a man has no
     club. */
  padding-bottom:10px;
  /* Clipped, and genuinely clipped: overflow:clip cuts the paint AND
     stops the contents counting toward the scrollable area. clip-path
     alone only hid them — a scrim at left:-100vw still told the card
     it was two screens wide, which is what made the whole thing
     scroll sideways.
     
     overflow-clip-margin lets him keep spilling past the edges by a
     fixed amount, which overflow:hidden would not allow.
     
     The rule is drawn separately below rather than as a border here:
     a border sits inside the clipped box, so he would have been cut
     at the far side of it and could still show over the line. */
  /* The header bleeds to the card's own edges and up to the title
     bar: the wash, the watermark and the photograph all run the full
     width rather than stopping at the body's padding.

     The padding goes on the CONTENTS, not on this element. Padding
     here would be inside the box, so the absolutely positioned
     children — which is all three of those things — would measure
     from the padding edge and start 16px short of the card. Pulling
     out on all four sides and indenting the two children instead
     puts the backgrounds at the edge while the text stays put.

     Clipped, so none of it counts toward the card's scroll width —
     that is what made the whole card scroll sideways. */
  /* No bottom padding: the toggle's own margin sets the gap on both
     sides, and padding here would add to the top one only. */
  /* Down a little: the photograph, the watermark and the break all
     move with it, while the fact boxes and the owner corner keep
     their own offsets and stay put. */
  margin:-16px -16px 0;
  padding-top:26px;padding-bottom:0;

  overflow:hidden;
  position:relative}
/* The three things that must stay at the original margin — the
   header itself now runs to the card's edges, so anything meant to
   line up with the tables below has to be indented back. */
.playercard .nom > .nom-art{margin-left:16px}
.playercard .nom > .nom-mid{padding-right:16px}
.playercard .nom > .nom-held{top:16px;right:16px}
/* Pulled back up by what the header gained, so the text column stays
   where it was while the picture behind it moves down. */
.playercard .nom > .nom-mid{margin-top:-10px}

.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 .38s 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,body.hassheets .sheet{transition:opacity .24s ease-in,
  visibility 0s linear .24s}
body:has(.home) .sheet.open,body.hassheets .sheet.open{transition:opacity .26s ease-out,visibility 0s}
body:has(.home) .sheet .sheet-card,body.hassheets .sheet .sheet-card{transition:transform .26s
  cubic-bezier(.22,.7,.3,1),opacity .26s ease-out}
body:has(.home) .sheet:not(.open) .sheet-card,body.hassheets .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.hassheets #rosterSheet,body:has(.home) #draftSheet,body.hassheets #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.hassheets #tradesSheet,
body:has(.home) #rosterSheet,body.hassheets #rosterSheet,
body:has(.home) #draftSheet,body.hassheets #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.hassheets #rosterSheet .sheet-card,
body:has(.home) #draftSheet .sheet-card,body.hassheets #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,body.hassheets #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,body.hassheets #tradesSheet .tradepage{max-width:none;width:100%}
body:has(.home) #tradesSheet .sheet-body,body.hassheets #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,body.hassheets #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.hassheets #tradesSheet .tradelist,
body:has(.home) #tradesSheet .blocklist,body.hassheets #tradesSheet .blocklist{flex:1;min-height:0;overflow-y:auto;
  margin:0 -16px;padding:0 16px 60px}
body:has(.home) #tradesSheet .histbar,body.hassheets #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,body.hassheets #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,body.hassheets #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,body.hassheets #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,body.hassheets #tradesSheet .fab-trade{animation:none}
}
body:has(.home) #rosterSheet .sheet-filter,body.hassheets #rosterSheet .sheet-filter,
body:has(.home) #draftSheet .sheet-filter,body.hassheets #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,body.hassheets #rosterBody .rr-list{margin:0;padding:0;list-style:none}
body:has(.home) #rosterBody .rr-list.bench,body.hassheets #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,body.hassheets #rosterBody .rr-list.bench > li:first-child{margin-top:0}
body:has(.home) #draftSheet .draftboard,body.hassheets #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.hassheets #rosterSheet .sheet-card,
  body:has(.home) #draftSheet .sheet-card,body.hassheets #draftSheet .sheet-card{height:100%;max-height:100%}
  body:has(.home) #draftSheet .sheet-card,body.hassheets #draftSheet .sheet-card{width:min(1400px,96vw)}
  body:has(.home) #draftSheet .draftboard,body.hassheets #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,body.hassheets #draftSheet .sheet-body{overflow:hidden;display:flex;
    flex-direction:column;min-height:0}
  body:has(.home) #draftSheet .draftboard,body.hassheets #draftSheet .draftboard{flex:1;min-height:0;
    align-items:stretch;gap:14px}
  body:has(.home) #draftSheet .dround,body.hassheets #draftSheet .dround{display:flex;flex-direction:column;
    min-height:0}
  body:has(.home) #draftSheet .dround-head,body.hassheets #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,body.hassheets #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,body.hassheets #draftSheet .dpick{min-height:0;padding:3px 8px;gap:8px;
    align-items:center}
  body:has(.home) #draftSheet .dpick-no,body.hassheets #draftSheet .dpick-no{font-size:11px;padding:2px 5px}
  body:has(.home) #draftSheet .dpick-who b,body.hassheets #draftSheet .dpick-who b{font-size:12px}
  body:has(.home) #draftSheet .dpick-from,body.hassheets #draftSheet .dpick-from{font-size:9px}
  body:has(.home) #draftSheet .dpick-face,body.hassheets #draftSheet .dpick-face,
  body:has(.home) #draftSheet .dpick-shot,body.hassheets #draftSheet .dpick-shot{width:26px;height:26px;flex:0 0 auto;border-radius:6px;
  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:9px}
  body:has(.home) #draftSheet .dhist-name,body.hassheets #draftSheet .dhist-name{font-size:11.5px}
  body:has(.home) #draftSheet .dhist-sub,body.hassheets #draftSheet .dhist-sub{font-size:9px}
  body:has(.home) #draftSheet .dhist-logo,body.hassheets #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{position:relative;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}
/* Where a team carries dead money, said under the total that includes
   it — quieter than the figure, since it explains rather than reports. */
/* A cut or signing in the transactions rail: what he was carrying,
   his position in its own colour, and his club with its mark. */
/* Behind the name rather than in front of it — the name is what you
   look for, the figure is what you check once you have found it. */
.move-cost{flex:0 0 auto;
  font-family:var(--cond);font-size:12px;font-weight:700;
  color:#4ade80}
/* Follows the name rather than being pushed to the far side: with the
   dots between them the line reads as one description. Its own gap is
   tighter than the row's, since a dot already does the separating. */
.move-meta{display:inline-flex;align-items:center;gap:5px;
  flex:0 1 auto;min-width:0}
.moverow{gap:5px}
.move-dot{color:#4a5666;font-size:11px}
.move-pos{font-family:var(--cond);font-size:10px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase}
.move-pos.pos-QB{color:var(--pos-qb)}
.move-pos.pos-RB{color:var(--pos-rb)}
.move-pos.pos-WR{color:var(--pos-wr)}
.move-pos.pos-TE{color:var(--pos-te)}
.move-logo{width:15px;height:15px;flex:0 0 auto;object-fit:contain}
.move-nfl{font-family:var(--cond);font-size:10px;font-weight:600;
  letter-spacing:.08em;text-transform:uppercase;color:var(--muted)}

/* The footer: who did it on the left, the money on the right, and the
   Add button after them. Wrapping is allowed but the money block is
   kept whole, so the button drops to its own line rather than the
   penalty being orphaned on a third. */
/* One line, never two. The team name is allowed to shrink and ellipse;
   the money and the button keep their width. Wrapping put the button on
   a third line and shoved the penalty sideways to make room. */
.movefoot{flex-wrap:nowrap;min-width:0}
.movefoot .moveteam{flex:0 1 auto;min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.movemoney{display:inline-flex;align-items:baseline;gap:8px;
  margin-left:auto;flex:0 0 auto;white-space:nowrap}

/* Signing a cut player straight from the rail. The colours come from
   .faadd on the players page — the same act, so the same button.

   Two class names, because .fatrade,.faadd,.falocked sets width:100%
   further down the sheet and would otherwise win on order alone.
   align-self, because the footer aligns on the baseline and a button
   with padding sits oddly against text that way. */
/* Beside the word "Cut" in the heading. No taller than the text it sits
   against — a full-size button there would set the height of the whole
   row and push the card open. */
.movecard-head .faadd.move-add{flex:0 0 auto;
  width:auto;min-width:0;padding:1px 8px;border-radius:5px;
  cursor:pointer;font-family:var(--cond);font-size:8.5px;
  line-height:1.5;font-weight:700;letter-spacing:.1em;
  text-transform:uppercase}

/* A signing that cost something, so a free pickup reads differently. */
.movecost.paid{color:var(--money)}

/* A player marked for release, in the asset lists above. Struck
   through so the two panels agree about who is going. */
.tb-item.cut{border-color:#5d3330;background:#2a151599}
.tb-item.cut .tb-name{text-decoration:line-through;
  text-decoration-color:#e2574c99}

/* A trade that breaks the hard cap. Marked on the bar rather than only
   at the last step, because it cannot be cut down to size — at the
   current rate a release frees a place but no money — and because the
   bar is visible whether the panel is open or shut.

   The blue becomes red, band and panel together, so the whole block
   reads as one refusal rather than a warning inside a normal panel. */
#builder .tb-fold-tab.bad{
  border-color:rgba(226,87,76,.5);
  background:rgba(124,34,28,.82);color:#ffe9e7}
#builder .tb-fold-tab.bad .tb-fold-count{color:#ffc9c4}
#builder .tb-fold.bad .tb-side{
  background:#2a1515;border-color:#5d3330}

.tb-illegal{margin-left:8px;padding:1px 7px;border-radius:999px;
  border:1px solid #ffb4ae;background:#00000033;
  font-family:var(--cond);font-size:9px;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:#fff}

/* The releases band, under "This trade". Red, because it is the one
   thing in this panel that ends a contract rather than moving it —
   and its own block rather than a control on each row, so picking who
   moves and picking who goes are two decisions, not one. */
.tb-cuts{margin:0 0 12px;padding:10px 12px 12px;
  border:1px solid #5d3330;border-radius:10px;
  background:linear-gradient(180deg,#2a151533,#1a0f0f22)}
.tb-cuts-head{display:flex;align-items:baseline;gap:8px;
  margin-bottom:8px;font-family:var(--cond);font-size:11px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--red)}
.tb-cuts-count{margin-left:auto;font-size:9.5px;color:var(--muted)}
.tb-cuts-cost{margin:0 0 6px;font-family:var(--cond);font-size:10px;
  letter-spacing:.06em;text-transform:uppercase;color:#c98b86}
.tb-cuts-none{margin:0;font-size:12px;color:var(--muted)}
.tb-cuts-list{display:flex;flex-direction:column;gap:5px}
/* The dialog: arriving players in their own band above the roster,
   each band broken by position and dearest first. */
/* The confirm bar, held at the foot of the dialog while the list
   scrolls behind it. */
/* Releases in an owner's own column, in line with the assets above —
   no heading, no rule. Each row is veiled instead, which says the same
   thing without breaking the column into sections. */
.trade-cuts-foot{margin-top:5px;padding-top:5px;
  border-top:1px solid var(--red);text-align:right;
  font-family:var(--cond);font-size:10.5px;font-weight:700;
  letter-spacing:.06em;color:var(--red)}
/* CUT across the photograph itself, rather than a panel over the whole
   row — the mark belongs on the man, not on his figures. */
.trade-asset.is-cut > span:first-child{position:relative;
  filter:grayscale(1) sepia(.45) hue-rotate(-25deg) saturate(2.2)
    brightness(.8)}
.trade-asset.is-cut > span:first-child::after{content:"Cut";
  position:absolute;inset:0;z-index:2;
  display:flex;align-items:center;justify-content:center;
  background:#1a0f0f66;
  font-family:var(--cond);font-size:10px;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:#ff6b60;
  text-shadow:0 1px 3px #000;pointer-events:none}
/* The club mark tinted with him. */
.trade-asset.is-cut .tb-teamlogo{filter:grayscale(1) sepia(.45)
  hue-rotate(-25deg) saturate(2.2) brightness(.85)}
.trade-asset.is-cut b{color:#e0a5a0}
.trade-asset.is-cut .tb-item-sub{color:#a0797a}
.trade-asset.is-cut .trade-sal{color:var(--red)}

/* Releases, inside the side that makes them: the same rows as the
   assets above, under a red rule, so the eye reads one list of people
   with a line drawn where the leaving starts. */
/* No rule above: the veil on each row already says these men are
   leaving, and a second marker made the column read as two lists. */
.tb-side-gone{margin-top:6px}
.tb-side-gone-head{display:flex;align-items:center;gap:8px;
  font-family:var(--cond);font-size:9px;
  letter-spacing:.14em;text-transform:uppercase;color:var(--red);
  margin-bottom:5px}
/* Left, not right: it belongs with the releases it edits, and on a
   phone column the right edge is where the money lives. */
.tb-side-gone-head .tb-side-gone-edit{margin-right:auto}
/* Only the colour differs from the crosses above — the size and place
   come from .tb-side-x, so the column lines up. */
.tb-side-gone-x{color:#a0797a}
.tb-side-gone-x:hover{color:var(--red)}
.tb-side-gone-foot{margin-top:5px;padding-top:5px;
  border-top:1px solid var(--red);
  display:flex;align-items:center;
  gap:8px;justify-content:flex-end;
  font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.06em;color:var(--red)}
.tb-side-gone-edit{flex:0 0 auto;padding:2px 9px;border-radius:5px;
  border:1px solid #5d3330;background:transparent;color:#c98b86;
  cursor:pointer;font-family:var(--cond);font-size:9px;
  font-weight:700;letter-spacing:.12em;text-transform:uppercase}
.tb-side-gone-edit:hover{background:#2a151599;color:#fff}

/* The released rows carry the same figures as the assets above them —
   these classes had no base rule at all, only the is-cut overrides, so
   the money was rendering at the browser's default size. */
.tb-side-sub{font-family:var(--cond);font-size:9.5px;
  letter-spacing:.08em;text-transform:uppercase;color:var(--muted)}

/* A man on his way out: his photograph drained and tinted red, the
   rest of the row quietened. No veil across it — the tint and the red
   figure say it without covering the man up. */
.tb-side-row.is-cut .tb-side-art{filter:grayscale(1) sepia(.45)
  hue-rotate(-25deg) saturate(2.2) brightness(.8)}
.tb-side-row.is-cut b{color:#e0a5a0}
.tb-side-row.is-cut .tb-side-sub{color:#a0797a}
.tb-side-row.is-cut .tb-side-sal{color:var(--red)}


.tb-cuts-bar{position:sticky;bottom:0;z-index:2;
  margin:10px -14px -14px;padding:10px 14px 12px;
  display:flex;align-items:center;gap:10px;
  background:var(--slate);border-top:1px solid var(--line)}
.tb-cuts-bar .tb-cuts-cost{margin:0;flex:1 1 auto}
.tb-cuts-bar .btn{flex:0 0 auto}

.tb-cuts-band{margin:10px 0 2px;font-family:var(--cond);font-size:10px;
  font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  color:var(--red)}
.tb-cuts-band:first-child{margin-top:0}
.tb-cuts-pos{margin:6px 0 1px;font-family:var(--cond);font-size:9px;
  letter-spacing:.14em;text-transform:uppercase;color:#6b7684}
.tb-cuts-face{width:30px;height:30px;flex:0 0 auto;border-radius:7px;
  overflow:hidden;background:var(--slate-2);
  display:flex;align-items:center;justify-content:center}
.tb-cuts-face img{width:100%;height:100%;object-fit:cover;
  object-position:top center}
.tb-cuts-face .me-initials{font-size:10px}
.tb-cuts-logo{width:14px;height:14px;flex:0 0 auto;object-fit:contain}
.tb-cuts-row{display:flex;align-items:center;gap:8px;width:100%;
  padding:7px 9px;border-radius:8px;text-align:left;cursor:pointer;
  border:1px solid var(--line);background:var(--slate);color:var(--text)}
.tb-cuts-row:hover{border-color:#5d3330}
.tb-cuts-row.on{border-color:var(--red);background:#2a151599}
.tb-cuts-row.on b{text-decoration:line-through;
  text-decoration-color:#e2574c99}
.tb-cuts-mid{display:flex;flex-direction:column;min-width:0;flex:1 1 auto}
.tb-cuts-mid b{font-size:13px;font-weight:600}
/* A row of small facts — club mark, club, money — so it lays out as a
   line rather than stacking. Merged with the rule that used to sit
   above: two .tb-cuts-note blocks meant the later silently won. */
.tb-cuts-note{display:flex;align-items:center;gap:5px;
  font-family:var(--cond);font-size:9.5px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted);margin-top:1px}
.tb-cuts-add{flex:0 0 auto;font-family:var(--cond);font-size:9.5px;
  letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.tb-cuts-by{flex:0 0 auto;font-family:var(--cond);font-size:9.5px;
  letter-spacing:.1em;text-transform:uppercase;color:var(--red)}
/* Under each option in the who-pays picker. */
.tb-cut-note{display:block;margin-top:2px;
  font-family:var(--cond);font-size:9px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted);font-weight:400}

.cap-note{display:block;margin:-3px 0 6px;
  font-family:var(--cond);font-size:9px;letter-spacing:.08em;
  text-transform:uppercase;color:#7d8899}
.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;background:var(--slate);display:flex;
  align-items:flex-end;justify-content:center;
  /* Anchors the age badge, which overlaps the corner — so this can't
     clip. The headshot inside keeps its own rounded corners. */
  position:relative;overflow:visible}
.tb-face > img{border-radius:6px}

/* His age, on the corner of the photograph — in the trade builder, the
   historical trades, the block and the offers, all of which are built on
   this face. Small: these are 30px pictures. */
.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)}
/* The player taken, beside the owner who took him — the same size as
   the owner's own face, so the row reads as a pair. */
.dpick-player{flex:0 0 auto;width:34px;height:38px;border-radius:7px;
  overflow:hidden;background:var(--slate-2);
  display:flex;align-items:center;justify-content:center}
.dpick-player img{width:100%;height:100%;object-fit:cover;
  object-position:top center}
.dpick-player .me-initials{font-size:11px}

.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 /* position:relative so the age badge can sit in its corner. */
.rrow-face{width:52px;height:56px;border-radius:9px;position:relative}

/* His contract on the second line: the year he next reaches restricted
   free agency in gold, VET in grey once he is past it. The same pair the
   roster rows use. */
.farfa{flex:0 0 auto;font-family:var(--cond);font-size:9.5px;
  font-weight:700;letter-spacing:.1em;text-transform:uppercase;
  color:var(--gold)}
.farfa.vet{color:var(--muted)}
/* The dots between. White, not the border grey — at this size a dim dot
   reads as a gap rather than as a separator. */
.fadot{flex:0 0 auto;color:#fff}
/* One size across this line, the owner included. */
.fasub,.fasub > *{font-size:9.5px}

/* His age, over the top-left of the photograph. White on a dark disc so
   it reads against a light shirt or a dark one alike. */
/* Straddling the corner rather than tucked inside it: pulled out by
   about a third of its own width so it reads as a badge pinned to the
   photograph, not a label sitting on top of one. */
.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)}
/* A comment had been inserted between these two selectors, which broke
   the pair — .rc-money lost its nowrap. */
.rc-money,
.rc-counts{white-space:nowrap}

/* Three items on this line now — players, average age, picks — so the
   words read smaller than the money above them. The figures are sized
   further down, where they were already set. */
.rostercap .rc-counts{font-size:9.5px;letter-spacing:.04em}
@media (max-width:400px){
  .rostercap .rc-counts{font-size:9px;letter-spacing:.02em}
  .rostercap .rc-counts b{font-size:10px}
}
/* 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)}
/* Smaller than it was: three figures share this line now, and at 13.5
   they carried more weight than the money above them. */
.rc-counts b{font-size:11px;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. */
/* The dots on a roster line, matching the players page. */
.rrow-dot{flex:0 0 auto;color:#fff}

.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}
/* The news mark on the depth chart, sized for a name on the turf. */
.dcname .newsmark svg,.dcrowname .newsmark svg{width:11px;height:11px}
.dcname .newsmark,.dcrowname .newsmark{display:inline-flex;
  align-items:center;color:#ffffffb3}
.dcname .newsmark.fresh,.dcrowname .newsmark.fresh{color:#ff6b6b}
/* 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}
/* One size for everything on this line — club, contract, bye. They were
   10.5 and 10, which reads as a mistake rather than a hierarchy. */
.rrow-sub{display:flex;align-items:center;gap:5px;min-width:0;
  font-family:var(--cond);font-size:9.5px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted);white-space:nowrap;
  overflow:hidden}
.rrow-sub > *{font-size:9.5px}
.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. */
/* A red glow rising from the foot of the hub, behind everything.
   
   Fixed rather than in the flow, so it stays at the bottom of the
   screen; pointer-events none so it never intercepts a press. */
body:has(.home)::after{content:"";position:fixed;
  left:0;right:0;bottom:0;height:34vh;z-index:-1;pointer-events:none;
  background:linear-gradient(0deg,#c9d6e81f 0%,#c9d6e80d 38%,
    transparent 100%)}
/* The glow sits behind everything with a negative index, so nothing
   above it needs lifting.
   
   Giving .home a z-index made it a stacking context, and the news
   rail lives inside it — which trapped the rail below the veil at 68
   and left it dark and unpressable. */

.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.
     
     Letting this grow instead pushed the fixtures band off the top,
     which is worse than a tight grid — so the matchup card is sized
     to fit rather than the page being allowed to overflow. */
  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;text-align:center;
  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. */
/* The grid fades with the drawer rather than being covered by it.
   
   Hidden until the hub has painted once: the tiles are built from
   the state, and before it lands the grid drew empty at full
   opacity and then faded — which read as a flash of the wrong
   thing rather than a load. */
.teamgrid{transition:opacity .6s cubic-bezier(.4,0,.2,1)}
.teamgrid:empty{opacity:0}
/* Keyed on is-open, not on hidden.
   
   hidden is only removed once the drawer has finished fading, so the
   grid sat at nought for the whole close and then came back all at
   once. is-open goes the moment the close begins, so the two move
   together. */
body:has(.mxfull.is-open) .teamgrid{opacity:0}
/* Its heading goes with it — a title over a faded grid reads as a
   mistake. */
/* Its heading waits for it, so the two arrive together. */
.home-block .home-h{transition:opacity .6s cubic-bezier(.4,0,.2,1)}
.home-block:has(.teamgrid:empty) .home-h{opacity:0}
body:has(.mxfull.is-open) .home-block .home-h{opacity:0}

.teamgrid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  grid-auto-rows:minmax(0,1fr);
  gap:8px;flex:1 1 auto;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. */
/* The news tab when there is something an owner hasn't read: blank,
   then red, on a two-second cycle. Colour rather than opacity, so it
   reads as a light coming on rather than the tab fading. */
@keyframes newstab-alert{
  0%,45%{background:var(--slate-2);color:var(--muted)}
  50%,95%{background:var(--red);color:#fff}
  100%{background:var(--slate-2);color:var(--muted)}
}
.newstab.unread{animation:newstab-alert 2s steps(1,end) infinite}
@media (prefers-reduced-motion:reduce){
  /* Steady red rather than blinking — the tab still says there is
     something, without the movement. */
  .newstab.unread{animation:none;background:var(--red);color:#fff}
}

/* The rail's scope toggle, under its banner. */
.newsscope{flex:0 0 auto;margin:0 10px 8px;align-self:stretch}
.newsscope button{flex:1 1 0}
/* Each feed in its own colour when chosen: the league's red for the
   reader's own men, the wire in the spectrum it draws from. */
.newsscope button[data-scope="mine"].on{background:var(--red);color:#fff}
.newsscope button[data-scope="all"].on{color:#fff;
  background:linear-gradient(90deg,#c2565c,#c9803f,#b3a441,
    #4f9a6a,#4a86c4,#6d6bb8)}

/* What a note says about his availability, beside his name.
   His designation from Sleeper — what he is TODAY, not what a note
   said when it was written. The same pill the wire's rows wear, graded
   from yellow through amber to red as it gets worse, so the colour
   says how bad it is before the word is read. */
/* The badge keeps its width and the name gives way — "Questionable" is
   twelve characters, and truncating the status to fit a long name would
   defeat the point of writing it out. */
.news-state{flex:0 0 auto;padding:1px 7px;border-radius:999px;
  border:1px solid currentColor;
  font-family:var(--cond);font-size:8.5px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase;line-height:1.5;
  white-space:nowrap}
/* The card header, as a portrait rather than a boxed thumbnail. His
   club's mark large and faint behind, his cut-out over it with no
   frame — the shape the auction board uses, which reads as a person
   rather than as a row in a list. */
/* The photograph, unframed. Its foot lines up with the foot of the
   fact boxes beside it — the row is bottom-aligned, so the two end
   together whatever the name wraps to. The negative margin lets the
   faded edge overlap the gap below rather than leaving a band of
   empty card under him. */
#playerCard .nom-art,
.playercard .nom-art{position:relative;overflow:visible;
  background:none;border:0;border-radius:0;box-shadow:none;
  /* Twice the size, and allowed to spill. The photograph is the
     card's subject, so it is given the room and the layout works
     around it — the column beside it still shrinks first, and the
     negative side margins let him break the padding rather than
     squeezing the fact boxes.

     The width is what it reserves in the row; the image inside is
     scaled past that on purpose. */
  width:clamp(120px,38%,190px);aspect-ratio:1;height:auto;
  flex:0 1 auto;min-width:0;
  margin-bottom:-6px;z-index:1}

.playercard .nom-art .nom-shot{
  /* Half again as large as the box that holds it, anchored to the
     left so it grows up and outward rather than pushing the text
     column sideways. It is meant to spill past the card's padding —
     he is the subject, and the layout works around him.

     Behind the fact boxes rather than in front: where he overlaps
     them he should pass under, not obscure a figure. */
  /* Down onto the line and larger again — the negative bottom sets
     him against the rule rather than floating above it.
     
     The header clips now, so he spills within it rather than past
     the card: left:-20% takes him to the header's own left edge,
     which is the card's padding. Any further and he is simply cut. */
  position:absolute;left:-14%;bottom:-8px;
  width:155%;height:155%;max-width:none;object-fit:contain;
  object-position:bottom center;
  /* Above the scrim, below the text. */
  z-index:2;
  /* A gentle fade over the last tenth. Slight, because the scrim
     below already softens the join — this only takes the hard edge
     off the crop. */
  /* (Sleeper's square photos are handled separately below.) */
  -webkit-mask-image:linear-gradient(180deg,
    #000 0%, #000 97%, transparent 100%);
  mask-image:linear-gradient(180deg,
    #000 0%, #000 97%, transparent 100%);
  /* The base rule gives every headshot a slate background, a radius
     and a border — right for a thumbnail in a list, wrong for a
     cut-out that is meant to sit on the card itself. All three are
     undone here rather than only the radius. */
  background:none;border:0;border-radius:0;box-shadow:none;
  /* No fade. Masking his feet let the watermark behind him show
     through, which read as the logo running into his legs. A rule in
     the club's colour under the whole header does the same job —
     it gives the cut-out something to stand on. */
  }
/* The club's mark behind him, centred on the whole header rather
   than on the photograph, and much larger — it is a watermark, not a
   badge. Pinned to the row so it sits behind the text as well. */
.playercard .nom{position:relative}
.playercard .nom-clubmark{position:absolute;
  top:50%;left:50%;transform:translate(-50%,-50%);
  width:230px;height:230px;object-fit:contain;opacity:.10;
  border:0;background:none;border-radius:0;padding:0;
  z-index:0;pointer-events:none}

/* Sleeper's photographs are a different shape entirely: a square
   head-and-shoulders shot on a background, where ESPN's are
   transparent cut-outs from the waist up. Blown up to 155% and
   anchored to its bottom, a Sleeper photo puts the man's head off
   the top of the box — which is the "halfway up" look.

   So they are drawn as they were meant to be: at their own size,
   anchored to the top, cropped square, with the corner rounded since
   there is no transparency to soften the edge. */
.playercard .nom-art .nom-shot[data-shot="sleeper"]{
  left:0;right:0;bottom:auto;top:0;
  width:100%;height:100%;
  object-fit:cover;object-position:top center;
  border-radius:12px;
  -webkit-mask-image:none;mask-image:none}

/* A band of the card's own colour over the watermark, under him.
   
   Every previous attempt at fading his feet failed the same way: a
   mask makes him transparent, and what shows through is whatever is
   behind — which is the club mark. This puts the card between the
   two. Where he thins out, the logo has already been covered, so the
   fade reveals the card and nothing else. */
/* Between the watermark and the photograph, and reaching past both.
   
   It has to live inside nom-art, because that is the box the
   watermark is in — a scrim on the header would sit outside them
   both and cover the picture entirely.
   
   Two extents matter. Sideways: the mark is wider than the picture,
   so a scrim the width of the picture left it showing either side of
   him. Downward: the mark is TALLER than the box it is centred on
   and hangs below it, which is why the logo kept appearing beneath
   his feet — so the scrim runs past the box's foot as well. The
   header's clip trims it at the club line. */
.playercard .nom-art::after{content:"";position:absolute;
  left:-500px;right:-500px;bottom:-70px;height:120px;
  z-index:1;pointer-events:none;
  background:linear-gradient(180deg,
    transparent 0%, var(--slate) 52%, var(--slate) 100%)}

/* The text column: his name, then three facts in their own boxes.
   Bottom-aligned with the photograph so the boxes and the foot of the
   cut-out sit on one line. */
.playercard .nom-mid{display:flex;flex-direction:column;
  justify-content:flex-end;gap:0;min-width:0;flex:1 1 auto}
.playercard .nom-name{margin:0 0 9px;position:relative;z-index:2}

/* Three across, the shape the auction board uses. */
/* Four across in the space three used to take, so each is a little
   narrower rather than the row being taller. */
.playercard .nom-facts{display:grid;
  grid-template-columns:repeat(4,minmax(0,1fr));gap:5px}
/* min-width:0 on the box itself, not only on the track. A grid item
   defaults to min-width:auto and will refuse to go below its own
   content — minmax(0,1fr) frees the column but not the thing inside
   it, so three boxes of unbreakable text still pushed the card wider
   than its width rule allowed. */
.playercard .nom-fact{position:relative;z-index:2;
  padding:7px 7px;border-radius:8px;
  background:#0b152699;border:1px solid var(--line);
  display:flex;flex-direction:column;justify-content:center;gap:3px;
  min-width:0;overflow:hidden}
.playercard .nom-factlabel{font-family:var(--cond);font-size:7.5px;
  letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
/* Left-aligned and centred in the space under the label, a little
   larger than before. Wrapping is allowed — "Nov 18, 2001" in a
   third of a phone's width has nowhere to go otherwise, and a box
   that cannot shrink drags the card open with it. */
.playercard .nom-factvalue{font-size:13px;font-weight:700;
  line-height:1.15;min-width:0;overflow-wrap:anywhere}
.playercard .nom-factnote{font-family:var(--cond);font-size:8.5px;
  letter-spacing:.06em;text-transform:uppercase;color:#7d8899}
/* This year's RFA class in yellow — those are the men an owner is
   deciding about now, and the year is the reason to look. */
.playercard .nom-fact.is-soon .nom-factvalue{color:#f5c518}
.playercard .nom-fact.is-soon{border-color:#5a4a12}

/* The position box in its own colour, as the position always is. */
.playercard .nom-fact.pos-QB .nom-factvalue{color:var(--pos-qb)}
.playercard .nom-fact.pos-RB .nom-factvalue{color:var(--pos-rb)}
.playercard .nom-fact.pos-WR .nom-factvalue{color:var(--pos-wr)}
.playercard .nom-fact.pos-TE .nom-factvalue{color:var(--pos-te)}

/* The club's own colour, washed up from the foot of the card. Set as
   a variable by the page, so a card with no club just gets nothing. */
.playercard .modal-card{position:relative}
/* The card below the club line: slate into something darker, from
   one corner. Quiet enough that the tables read over it. */
.playercard .modal-card::before{content:"";position:absolute;
  inset:0;border-radius:inherit;pointer-events:none;z-index:0;
  background:linear-gradient(150deg,
    var(--slate) 0%, #070d18 78%)}
.playercard .modal-card > *{position:relative;z-index:1}

/* The club's colour fills the header only, stopping at the line —
   it belonged to the portrait rather than to the whole card, and
   washing the tables in it made them harder to read. */
/* The header ends in the colour the panel below it begins in, so
   the join reads as one surface rather than two blocks meeting.
   
   Its own layer rather than a background on the header: .nom::before
   carries the club wash at z-index -1, and a background here would
   paint straight over it. This sits above the wash and below him. */
.playercard .nom::after{content:"";position:absolute;
  /* z0: above the club wash at -1, below the photograph and the text
     at 1 and 2. An ::after at the same level as the picture would sit
     over him, since it comes last in the DOM. */
  left:0;right:0;bottom:0;height:44px;z-index:0;pointer-events:none;
  background:linear-gradient(180deg,
    transparent 0%, var(--slate) 100%)}

.playercard .nom::before{content:"";position:absolute;
  left:-500px;right:-500px;top:-100px;bottom:0;
  z-index:-1;pointer-events:none;
  background:linear-gradient(158deg,
    var(--club, transparent) 0%,
    transparent 82%);
  opacity:.8}

/* The metrics panel. A portrait rather than a table: his club's mark
   behind and above, his face large and clear of any frame, his name
   beside it. The whole block runs up under the toggle, which is why
   the negative margin — the photograph is meant to be cut by it, the
   way the auction board shows a man. */
/* Nothing of its own: it holds the same block the contract tab does,
   so the spacing comes from that block. */
.cardview-gym{display:flex;flex-direction:column}
/* No container: the cut-out sits on the card itself. */

/* The measured facts, as boxes — the same shape the contract table
   uses below, so the two views read as one card. */
/* Two rows of three, filling the panel rather than scrolling inside
   it. The panel is a fixed height — the card is sized to whichever
   view is tallest — so the boxes stretch to meet it instead of
   leaving a well of empty space or spilling past the edge. */
/* Each box is a small table: a striped header row, then its body.
   Same background, weight and rule as the contract table below, so
   the panel reads as one set of tables rather than boxes above one.
   
   Everything in the body is the same size and the same white — a
   value and its detail are both facts about him, and grading one
   quieter than the other made the boxes look half-filled. */
/* Six facts where the contract has three: two rows of three, in the
   same width. Nothing else changes — they are the contract's own
   .c-fact boxes, so the fill, the radius and the type all come from
   there. */
/* Two class names, because .c-facts sets display:flex much further
   down the sheet and would otherwise win on order alone. */
/* College across the top, then the four facts two by two beneath —
   which gives the two draft boxes room for "2019 · Rd 2, pick 36"
   without breaking it over three lines. */
/* The whole block fits the panel rather than spilling past it: the
   college row takes what it needs, the four beneath share the rest
   equally, and the gaps top and bottom match. */
/* Up toward the stripe. The grid fills whatever room the block
   gives it, so moving the boxes up means giving less away at the
   top and more at the foot — justify-content alone would do nothing
   against a grid set to fill. */
/* Three class names, to beat `.cardviews .cardview .c-sum` further
   down the sheet — that rule sets flex:1 1 auto so the block fills
   the panel, and the panel's height is worked out per card. With it
   winning, my flex:0 0 auto never applied and these boxes went on
   stretching to whatever that card's height came to. */
.cardviews .cardview-gym .c-sum{padding-top:4px;padding-bottom:18px;
  flex:0 0 auto;min-height:0;justify-content:flex-start}
/* A fixed height on the college row, not auto. Auto took whatever
   its contents needed, so a taller logo or a school name that wrapped
   made that box grow and the four below shrink — which is why the
   panel looked different from one player to the next. Fixed, it is
   the same on every card and the four below always get the rest. */
/* Rows of a fixed height, not fractions of the panel.
   
   The panel's height is worked out per card: it is what the screen
   leaves after the header and that player's news, so a man with four
   stories gets a shorter panel than a man with none. Rows set to 1fr
   divided up whatever that came to, which is why these boxes were
   roomy on one card and squashed on the next.
   
   Fixed rows are the same everywhere. Where the panel is shorter than
   they need, the view scrolls — as the contract table already does. */
/* How good a week or a season was, as a band behind the figure.
   Twelve to a round in this league, so the tiers follow what a
   starting spot is worth: a top-twelve week was a start, a
   top-forty-eight was not. */
.rk-1{background:#15803d33;color:#7ee2a8}
.rk-2{background:#4d7c0f33;color:#bfe07a}
.rk-3{background:#a1620033;color:#f0cd6a}
.rk-4{background:#9a3d0033;color:#f2ab6d}
.rk-5{background:#7f1d1d33;color:#f0918b}
/* In the summary rows the band fills the whole cell. */
.statline .pc-stat.rk-1,.statline .pc-stat.rk-2,
.statline .pc-stat.rk-3,.statline .pc-stat.rk-4,
.statline .pc-stat.rk-5{border:1px solid currentColor}
.statline .pc-stat b{color:inherit}

/* Two rows of compact figures, not a grid of cards — more fits in
   the same room and it reads at a glance. */
.statline{grid-template-columns:repeat(auto-fit,minmax(52px,1fr));
  gap:5px;margin-top:0}
.statline + .statline{margin-top:5px}
.statline .pc-stat{padding:6px 4px}
.statline .pc-stat b{font-size:14px}
.statline .pc-stat span{font-size:8px;letter-spacing:.06em}

/* The finish and the points at the front of the log. */
.gamelog-lead{font-weight:700;text-align:center}

/* The game log: three boxes, only the middle one moves.
   
   Sticky cells inside one table would not hold on iOS, and rows kept
   painting over the heading as they passed. Three separate tables
   cannot do either — the heading and the totals are simply not in
   the scrolling box. */
/* Two halves side by side: the first five columns frozen, the rest
   scrolling under them.
   
   That split is also what stopped the sway. Keeping a heading in
   step with a scrolling body means moving it from a scroll handler,
   which runs after the browser has already painted — so it always
   arrived a frame late and swung back into place. The frozen half
   never moves at all, and the scrolling half carries its own
   heading, so there is nothing to keep in step. */
.gl{display:flex;min-height:0;flex:1 1 auto;overflow:hidden}
.gl-host{display:flex;flex-direction:column;min-height:0;
  flex:1 1 auto}
.gl-side{display:flex;flex-direction:column;min-height:0}
.gl-frozen{flex:0 0 auto;position:relative;z-index:2;
  border-right:1px solid var(--line);
  box-shadow:6px 0 10px -6px #000a}
/* The right half scrolls sideways as one box, so its heading, its
   weeks and its totals move together — a heading stays above the
   column it names. Only the weeks move up and down. */
.gl-rest{flex:1 1 auto;min-width:0;
  display:flex;flex-direction:column;
  overflow-x:auto;overflow-y:hidden;
  overscroll-behavior-x:contain;
  scrollbar-width:none}
.gl-rest::-webkit-scrollbar{display:none}

/* As wide as the table inside them, not as wide as the window on
   it — overflow:hidden here would have clipped the heading to the
   visible part and never shown the rest. The box around them is
   what does the scrolling. */
.gl-head,.gl-foot{flex:0 0 auto;width:max-content;min-width:100%}
.gl-rest .gl-body{width:max-content;min-width:100%}
/* No gutter to reserve now that neither bar is shown, so the three
   line up on their own. */
.gl-rest .gl-body table{width:100%}
.gl-body{flex:1 1 auto;min-height:0;
  overflow:auto;
  /* No bounce and no dragging the card behind it. */
  overscroll-behavior:none;-webkit-overflow-scrolling:auto}
/* The frozen half never scrolls sideways. Neither half shows a
   vertical bar: the right one's would sit off the edge of a box as
   wide as its table, and a bar on the left alone reads as though
   only that half moves. The two are tied in script, and a card that
   is read on a phone does not need one. */
.gl-frozen .gl-body{overflow-x:hidden;overflow-y:auto;
  /* Explicit rather than inherited: this is the half that actually
     scrolls, and it should stop dead at the first and last week. */
  overscroll-behavior:none;-webkit-overflow-scrolling:auto;
  scrollbar-width:none}
.gl-frozen .gl-body::-webkit-scrollbar{display:none}
/* The weeks on the right scroll up and down with no bar of their
   own: the box is as wide as the table, so a scrollbar on it would
   sit off the right-hand edge where nobody could reach it. The
   frozen half carries the visible bar and the two are tied. */
.gl-rest .gl-body{overflow-x:hidden;overflow-y:auto;
  scrollbar-width:none}
.gl-rest .gl-body::-webkit-scrollbar{display:none}

/* The two halves are separate tables, so a row in one has to be
   exactly as tall as the row beside it or the join drifts. Fixed
   heights rather than content-sized ones settle that — a club's
   mark is the tallest thing in any cell and it is 16px. */
.gl th{height:26px;padding-top:0;padding-bottom:0}
.gl td{height:26px;padding-top:0;padding-bottom:0}
.gl .gamelog-total td{height:28px}
/* The three carry no rounding of their own — the frame does it. */
.gl table{border-radius:0}
.gl-head table{border-bottom:1px solid var(--line)}
.gl-foot table{border-top:1px solid var(--line)}

/* The season, added up, at the foot of the log — and held there
   while the weeks scroll past it, so the totals are readable
   wherever you are in the table. */
.gamelog-total td{background:#101826;font-weight:700}
.gamelog-total td:first-child{font-family:var(--cond);
  letter-spacing:.1em}
/* The bands stay, a shade stronger than a single week's. */
.gamelog-total .gl-good{background:#15803d33}
.gamelog-total .gl-bad{background:#7f1d1d33}

/* Touchdowns, and the things that cost points. Only where there is
   a figure — a zero is neither good nor bad and stays plain. */
.gl-good{color:#7ee2a8;font-weight:700;background:#15803d1f}
.gl-bad{color:#f0918b;font-weight:700;background:#7f1d1d1f}

/* Every season at once: a row a year. Centred in the panel, and the
   same table styling as everything else on the card. */
/* Sideways where it needs to be — the columns will not all fit a
   phone, and dropping one would cost a figure worth having.

   min-width:0 on the wrapper is what keeps the card its own size: a
   flex or grid item defaults to min-width:auto and will not go below
   its contents, so without it the wide table dragged the wrapper,
   the panel and the whole card open with it. */
/* No sideways scroll at all now — the table is laid out to the room
   it has rather than to its contents.

   min-width:max-content was the whole trouble: it asks for whatever
   the widest row needs, and caps on the boxes around it stop the
   card growing but not the table wanting. table-layout:fixed removes
   the wanting — the columns divide what there is, and no content can
   make the table wider than its container. */
.stacked-wrap{margin:0;padding:0;border:0;overflow-x:hidden;
  min-width:0;max-width:100%;width:100%}
.stacked{table-layout:fixed;width:100%;min-width:0;max-width:100%}
/* Tight enough that most of it fits without scrolling at all. */
/* No ellipsis on a figure. A truncated number is worse than a small
   one — "124..." tells you nothing and looks like a fault. The type
   shrinks to fit instead, and the columns are sized so it rarely has
   to. */
.stacked th,.stacked td{padding:4px 2px;text-align:center;
  white-space:nowrap;font-size:10px;overflow:visible}
.stacked th{font-size:7.5px;letter-spacing:.04em;padding:5px 2px}
.stacked th:first-child,.stacked td:first-child{text-align:left}
.stacked-year{font-family:var(--cond);font-weight:700;
  letter-spacing:.06em}
/* A projected season, set apart from the ones that happened. */
.stacked-proj td{color:var(--muted);font-style:italic}
.proj-tag{margin-left:3px;font-size:7.5px;font-style:normal;
  letter-spacing:.1em;color:#a83a6b;vertical-align:top}
/* Room for a long career without the card growing: it scrolls both
   ways inside the panel. */
.cardview-stats .stacked-wrap{max-height:100%;overflow:auto}
/* The heading stays put while the years scroll under it. It needs
   a solid fill of its own — a sticky cell over a transparent one
   lets the rows show straight through as they pass. */
.stacked thead th{position:sticky;top:0;z-index:1;
  background:var(--slate-2)}

/* In the expanded log the wrapper scrolls both ways, so the sticky
   headings have one box to stick against.
   
   overflow-x:auto on it already made it a scroll container in both
   directions — a sticky cell was measuring against that rather than
   against .contract-body, and the body's own scrolling moved the
   whole table past it. Giving the wrapper the height and the body
   none settles which box is which. */
/* The picker inside the expanded log sits above its table, and
   stays there while eighteen weeks scroll under it. A solid fill of
   its own, or the rows show through as they pass. */
/* The same height as every other .seg on the card — the padding I
   gave it for its sticky fill made this one taller than the toggle
   above it. The fill comes from the shadow instead, which costs no
   height. */
.contract-body .yearpick{position:sticky;top:0;z-index:3;
  margin:0 auto 12px;
  background:var(--slate);
  box-shadow:0 -10px 0 6px var(--slate), 0 0 0 6px var(--slate)}

/* A week he did not play. Dimmed rather than left out — a season is
   as long as it is, and a gap in the table says something a shorter
   table would not. */
.gamelog-out td{color:#6b7688}
.gamelog td:first-child,.gamelog th:first-child{text-align:left}
.gamelog td{font-variant-numeric:tabular-nums;white-space:nowrap}
/* Wide on purpose: the table scrolls sideways inside its wrapper,
   so a column can be added without another being dropped. */
.gamelog{min-width:max-content}
/* The headings hold their places while eighteen weeks pass under
   them.
   
   z-index 5 and an opaque fill, both needed: a club's mark is an
   image inside a cell, and an image paints over a background at the
   same level however solid that background is. The rows were showing
   through the headings as they passed.
   
   The shadow closes the hairline between cells, where a row would
   otherwise be visible in the gap. */
.gamelog th{white-space:nowrap;background:#161c25}
/* The body gets a stacking context of its own, so nothing inside it
   — a club's mark especially — can composite above the headings.
   
   isolation rather than a transform: a transform on the thead would
   have made the header cells stick INSIDE the thead, which is one
   row tall, so they would have had nowhere to travel and would not
   have stuck at all. isolation confines the body's painting without
   touching what the cells stick within. */
.gamelog tbody{isolation:isolate;position:relative;z-index:1}
.gamelog td{position:relative;z-index:1}
.gamelog-mark{position:relative;z-index:0}
/* The opponent, as a mark and its letters. */
.gamelog-opp{text-align:left}
.gamelog-opp span{vertical-align:middle}
.gamelog-mark{width:16px;height:16px;object-fit:contain;
  margin-right:5px;vertical-align:middle}

/* Matchup and schedule: two lineups facing each other, the slot
   they are filling down the middle. */
html:has(.mu){height:100%;overflow:hidden}
body:has(.mu){height:100dvh;min-height:100dvh;width:100%;max-width:100%;
  overflow:hidden;overscroll-behavior:none;
  position:fixed;top:0;left:0;
  display:flex;flex-direction:column}
body:has(.mu) .topbar{flex:0 0 auto}
.mu{width:100%;margin:0 auto;flex:1 1 auto;min-height:0;
  display:flex;flex-direction:column;align-items:center;
  /* Clipped sideways so a wash running off the page cannot make it
     scrollable; upright it is the column that scrolls inside. */
  overflow-x:clip;overflow-y:hidden;box-sizing:border-box}
.mu > .slate{flex:0 0 auto;width:100%}
.mu-bar{flex:0 0 auto;width:100%;display:flex;flex-direction:column;
  align-items:center;gap:7px;padding:9px 8px;
  background:var(--ink);border-bottom:1px solid var(--line)}
.mu-weeks{width:fit-content;max-width:100%;margin:0;
  overflow-x:auto;scrollbar-width:none}
.mu-weeks::-webkit-scrollbar{display:none}
.mu-w{flex:0 0 auto;min-width:26px}
.mu-w.on{background:var(--red);color:#fff}
/* The seg control paints its own selected state; this beats it. */
.mu-weeks .mu-w.on{background:var(--red);color:#fff}
/* The playoff weeks were red to set them apart; now every selected
   week is, so they take gold instead and keep the distinction. */
.mu-w.is-po.on{background:var(--gold);color:#0b1220}
.mu-w.is-tbd{color:#5a6577}
.mu-owner{width:fit-content;max-width:82%;padding:5px 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:600;
  letter-spacing:.06em}

/* The two owners across the top: a face, the name with an arrow
   either side, the record, and what the lineup comes to. */
/* The Top 6 tab: the News tab's own look and behaviour, with its
   own word. Every class here is prefixed lt- rather than mu- —
   .mu-line already belongs to a player's second line, and reusing it
   put grey boxes round every club abbreviation. */

/* Sidecars, not cards: they slide in from the edge and leave the
   page behind them, the way the hub's news rail does. */
/* One width and one motion for both the rail and its tab — they were
   .3s on one curve and .28s on another, which is why the tab drifted
   off the edge of the rail as it moved. */
:root{--railw:min(78vw,380px);
  --railmove:transform .3s cubic-bezier(.22,.61,.36,1)}

.siderail{position:fixed;z-index:69;top:var(--bar-h,53px);bottom:0;
  width:var(--railw);
  display:flex;flex-direction:column;overflow:hidden;
  background:linear-gradient(180deg,rgba(22,29,43,.95) 0%,
    rgba(15,21,33,.97) 100%);
  -webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);
  transition:var(--railmove);
  visibility:hidden}
.siderail-right{right:0;border-left:1px solid #2a3546;
  box-shadow:-10px 0 30px #0007;transform:translateX(100%)}
.siderail-left{left:0;border-right:1px solid #2a3546;
  box-shadow:10px 0 30px #0007;transform:translateX(-100%)}
body.line-open .siderail-right,
body.chat-open .siderail-left{transform:translateX(0);visibility:visible}
/* The tabs ride out with their rail. */

.siderail-head{flex:0 0 auto;display:flex;align-items:center;
  justify-content:space-between;gap:10px;padding:11px 13px;
  border-bottom:1px solid var(--line);
  font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase}
.siderail-x{border:0;background:none;color:var(--muted);cursor:pointer;
  font-size:20px;line-height:1;padding:0 2px}
.siderail-body{flex:1 1 auto;min-height:0;overflow-y:auto;
  overscroll-behavior:contain;padding:8px 10px 12px}
/* The twelve fill the rail rather than leaving a gap under them. */
#lineBody{display:flex;flex-direction:column;padding:8px 10px 10px}

/* Behind an open rail: it blurs the page and takes every press.
   
   The blur is on the page's own children rather than on this, since
   a backdrop-filter here would fight the rail's own. z-index 68 puts
   it under both rails (69) and under the tabs (70), so those stay
   live while nothing else is. */
.railveil{position:fixed;inset:0;z-index:68;
  background:#080b0f70;cursor:pointer;
  transition:opacity .3s ease}
/* On its way out: invisible, but still there and still taking the
   press — so the tap that closed the rail cannot fall through onto
   whatever is underneath. */
.railveil.is-going{opacity:0;background:transparent}
body.line-open .mu > *,
body.chat-open .mu > *{filter:blur(4px);pointer-events:none;
  transition:filter .3s ease}
/* The banner stays sharp and usable — it is how you leave the page,
   and blurring it made the app look broken rather than busy. */

/* Condensed: the ticker, the week picker and the tabs are put away,
   and the rows tighten, so the owners and all ten starters fit the
   screen without scrolling.
   
   The pieces that go fade and collapse rather than vanishing —
   display:none cannot be animated, so height and opacity carry it
   and visibility hides what is left at the end. */
/* No transitions on these any more: the whole page fades for the
   change, and a second animation underneath it only made the pieces
   arrive at different moments. */
.slate,.mu-bar{overflow:hidden}
/* Padding and border go too, not only the height — 9px top and
   bottom plus a rule is 19px of the gap that kept the owners off
   the banner even with max-height at zero. */
/* No max-height here: the script sets it inline, from the element's
   own measured height, so the transition covers the distance it
   actually travels. A flat value in this rule would override that
   and put the snap back. */
body.mu-tight .slate,
body.mu-tight .mu-bar{opacity:0;margin:0;
  padding-top:0;padding-bottom:0;border-width:0;
  pointer-events:none}
/* And out of the flow entirely once the fade has run.
   
   Collapsing by max-height alone kept failing: the week picker is
   its own scroll container and does not shrink under a parent's
   max-height, and there is always another child holding a pixel.
   The script adds .is-away when the transition ends, which removes
   them outright — the fade still shows, and nothing is left behind
   to hold the owners off the banner. */
body.mu-tight .slate.is-away,
body.mu-tight .mu-bar.is-away{display:none}
.linetab,.chattab{transition:opacity .26s ease,transform .28s
  cubic-bezier(.22,.7,.3,1)}
body.mu-tight .linetab,
body.mu-tight .chattab{opacity:0;pointer-events:none;visibility:hidden}
/* The owners keep their size — the point is more room, not less. */
/* The glow hangs from the teams row; the header's own bottom
   padding was pushing it clear of the rule beneath. It starts at the
   header's foot now, whatever that padding is. */
/* Tight to the banner above, and given twice the room: the owners
   are the point of this view, so the space comes out of the rows
   below rather than out of them. */
/* Twice the height, stated rather than added up from padding — the
   pieces inside it grew but the box barely did, which is not what
   was asked for. */
/* Half again rather than twice: at double, the summary took so much
   of the screen that the last starters were pushed under the fold.
   
   Only the height changes — making it a flex column shrank the
   five-column grid inside to its content instead of letting it fill
   the width, which drew everything narrower. */
body.mu-tight .mu-head{padding-top:6px;padding-bottom:6px;
  min-height:calc(var(--headh,86px) * 1.12)}

/* The teams row fills the taller box, so the glow — which hangs off
   its foot — sits at the bottom of the section rather than partway
   up it. */
body.mu-tight .mu-teams{height:100%;align-content:center}
/* The owner photograph keeps its normal size. Growing it pushed the
   name along and crowded the totals beside it — the column it sits
   in is a fixed 52px, and the face was eating into it. */
body.mu-tight .mu-side{gap:9px}
body.mu-tight .mu-oname b{font-size:10px}
body.mu-tight .mu-sums .mu-got{font-size:19px}
body.mu-tight .mu-sums .mu-ptotal{font-size:14px}
body.mu-tight .mu-worth{font-size:9px}
body.mu-tight .mu-vs{width:56px;height:50px}
body.mu-tight .mu-vstext{font-size:20px}
/* Room to spare in this view, so the figures take some of it. */
body.mu-tight .mu-proj{font-size:13px}
/* Anchored to the header's own foot, not the teams row's — with the
   header's bottom padding at 6px the two are all but the same, and
   this way the wash cannot drift if that padding changes. */
body.mu-tight .mu-teams::after{top:calc(100% + 6px);height:20px;
  background:linear-gradient(180deg,#1d4c8624,transparent)}

/* The rows grow instead of shrinking: with the ticker and the week
   picker away, the ten starters share the whole screen. The height
   is measured and set as --rowh, since it depends on what the
   screen actually gives them. */



/* The bench stays — it is below the fold rather than removed, so
   scrolling still reaches it. */
body.mu-tight .mu-benchhead{margin:8px 0 2px;padding-top:7px}
/* The button says which way it will go. */
.bell.on{background:#ffffff14;border-radius:8px}

/* The draft history as a page rather than a card.
   
   Named drafthist, not rookiepage: that class already belongs to the
   live rookie draft — a grid with a carousel, a clock and a fixed
   top bar — and this page was silently inheriting the lot, which is
   what stretched it off the screen. */
.drafthist{flex:1 1 auto;min-height:0;width:100%;max-width:900px;
  margin:0 auto;display:flex;flex-direction:column;
  padding:0 8px;box-sizing:border-box}
/* The filter block was a sheet's header, so it brings that header's
   padding and background with it. Only those are changed — the
   flex-wrap it relies on is left alone. */
.drafthist .sheet-filter{padding:0 0 8px;background:none;
  border-bottom:0}
.drafthist .stats-title{margin:0}

/* The matchup card on the hub.
   
   box-shadow rather than a border: a real border shrinks the padding
   box, and the graph behind is absolutely positioned — it could only
   ever fill the padding box, leaving a hairline gap at each edge. */
/* The card holds its full height.
   
   .home is a fixed-height flex column and .home-block carries
   min-height:0, so the section shrinks below its content to fit —
   and with overflow hidden on the card that showed as the pick
   buttons being cut off the bottom. The section that holds this card
   is told not to shrink. */
.home-block:has(.mx-card){flex:0 0 auto;min-height:auto}
/* Its full height before the figures arrive, so nothing below it
   moves when they do. The number is what the card comes to once
   drawn: the owner row, then the pick band at 75. */
/* Its own width and height are fixed while it swipes: the body is
   what fades, and letting the card follow its contents made it grow
   wider and lose height between fixtures. */
.mx-card{min-height:129px;width:100%;box-sizing:border-box;
  position:relative;overflow:hidden;border-radius:12px;
  background:#0b1220;box-shadow:inset 0 0 0 1px #1d4c8655;
  flex:0 0 auto;
  /* Swiped, not pressed — so no pointer, and the browser is told to
     leave horizontal drags to us. */
  touch-action:pan-y}
.mx-graph,.mx-wash{position:absolute;inset:0;pointer-events:none}
.mx-graph svg{width:100%;height:100%;display:block}
.mx-wash{background:linear-gradient(90deg,#15803d26 0%,#15803d0a 26%,
  transparent 46%,transparent 54%,#7f1d1d0a 74%,#7f1d1d2b 100%)}
.mx-body{position:relative;padding:9px 4px 0}
/* Swiping moves the contents out and the next one in, rather than
   swapping them where they stand. */
/* Waiting: the frame is there, the contents are not — a quiet pulse
   rather than a spinner, since it is usually gone in a blink. */
.mx-card.is-waiting .mx-body{opacity:0}
.mx-card.is-waiting::after{content:"";position:absolute;inset:0;
  background:#ffffff05;animation:mxwait 1.1s ease-in-out infinite}
@keyframes mxwait{0%,100%{opacity:.5}50%{opacity:1}}

/* A spark running each line, one after the other.
   
   offset-path is set from the very path string the line is drawn
   with, so the dot is on the line by construction rather than by
   matching coordinates. */
/* The run takes about two seconds of a ten-second cycle, so there is
   a long pause between passes rather than a constant stream. The
   keyframe percentages carry the wait: it reaches the end a fifth of
   the way through and sits there, unseen, for the rest. */
@keyframes mxspark{
  0%{offset-distance:0%;opacity:0}
  2%{opacity:.95}
  18%{offset-distance:100%;opacity:.95}
  21%{offset-distance:100%;opacity:0}
  100%{offset-distance:100%;opacity:0}}
.mx-spark{offset-rotate:0deg;opacity:0}
/* The two set off at different moments. */
.mx-spark.is-them{animation-delay:3.4s}

/* The glint is a pulse in the halo, not in the opacity — two
   animations both writing opacity would fight, and the later one
   would keep the spark visible through the eight seconds it is
   meant to be dark. */
@keyframes mxpulse{
  0%,100%{filter:url(#mxglow) brightness(1)}
  50%{filter:url(#mxglow) brightness(1.7)}}
.mx-spark{animation:mxspark 10s cubic-bezier(.45,0,.5,1) infinite,
  mxpulse .8s ease-in-out infinite}

/* One rate for every part of the card, so a swipe or an expand moves
   as a single thing rather than in pieces. */
.mx-body,.mx-graph,.mx-wash,.mx-wash2{
  transition:transform .26s cubic-bezier(.22,.61,.36,1),
    opacity .26s cubic-bezier(.4,0,.2,1)}
.mxfull-rows{transition:opacity .26s cubic-bezier(.4,0,.2,1),
  transform .26s cubic-bezier(.22,.61,.36,1)}
/* The lineup board travels with the card it belongs to. */
.mx-card.slide-l ~ * .mxfull-rows,
body:has(.mx-card.slide-l) .mxfull-rows{
  transform:translateX(-14px);opacity:0}
body:has(.mx-card.slide-r) .mxfull-rows{
  transform:translateX(14px);opacity:0}
.mxfull:not(.is-open) .mxfull-rows{opacity:0}
.mx-card.slide-l .mx-body,.mx-card.slide-l .mx-graph,
.mx-card.slide-l .mx-wash,.mx-card.slide-l .mx-wash2{
  transform:translateX(-14px);opacity:0}
.mx-card.slide-r .mx-body,.mx-card.slide-r .mx-graph,
.mx-card.slide-r .mx-wash,.mx-card.slide-r .mx-wash2{
  transform:translateX(14px);opacity:0}

/* The wash behind each side says whether he is projected top six —
   green above the line, red below, fading toward the middle. The same
   colours the lineups page uses for the same thing. */
.mx-wash.l-top{background-image:linear-gradient(90deg,#15803d2e 0%,
  #15803d0a 30%,transparent 48%)}
.mx-wash.l-low{background-image:linear-gradient(90deg,#7f1d1d33 0%,
  #7f1d1d0d 30%,transparent 48%)}
.mx-card.r-top .mx-wash2{background:linear-gradient(270deg,#15803d2e 0%,
  #15803d0a 30%,transparent 48%)}
.mx-card.r-low .mx-wash2{background:linear-gradient(270deg,#7f1d1d33 0%,
  #7f1d1d0d 30%,transparent 48%)}
.mx-wash2{position:absolute;inset:0;pointer-events:none}

/* Every column stated, so nothing inside can change how wide the
   card is: the two owners are fixed, the middle takes exactly what
   is left, and the row itself fills the card. */
.mx-top{display:flex;align-items:flex-start;gap:1px;
  width:100%;box-sizing:border-box}
/* Pushed down, clear of the expander in the corner. */
.mx-arrow{background:none;border:0;color:#ffffff4d;width:18px;
  height:62px;font-size:21px;line-height:1;cursor:pointer;
  flex:0 0 auto;padding:0;align-self:flex-end;margin-bottom:-4px}
.mx-owner{text-align:center;width:96px;flex:0 0 auto;
  min-width:0;overflow:hidden}
/* The favoured side in green, the other in red. */
.mx-owner.is-up .mx-oname{color:#a8e6c1}
.mx-owner.is-down .mx-oname{color:#f0a8ae}
.mx-ohr{height:1px;background:#ffffff1f;margin:4px 12px 4px}
.mx-opct{font-family:var(--cond);font-size:11.5px;font-weight:700}
.mx-owner.is-up .mx-opct{color:#7ee2a8}
.mx-owner.is-down .mx-opct{color:#e0707c}
/* No photograph here: the card is about the week, not the owners. */
.mx-oname{padding-top:2px;font-family:var(--cond);font-size:13px;
  font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  color:#fff;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mx-orec{font-family:var(--cond);font-size:11.5px;color:#aab4c4;
  margin-top:2px}
/* Where he is projected to finish. Green inside the six, red out. */
.mx-oodds{font-family:var(--cond);font-size:11px;margin-top:2px;
  letter-spacing:.06em;font-weight:700}
.mx-oodds.is-in{color:#7ee2a8}
.mx-oodds.is-out{color:#e0707c}
.mx-oodds i{font-style:normal;color:#5a6270;font-weight:400}
/* The scores sit on the card's own centre line, not at the top of
   the row — the owner blocks beside them are taller. */
.mx-mid{text-align:center;flex:1 1 0;min-width:0;
  align-self:center;padding-top:0}
.mx-score{display:flex;align-items:center;justify-content:center;
  gap:12px;line-height:1.1;width:100%;min-width:0}
/* The projection sits over the total and shares its centre. */
.mx-stack{display:flex;flex-direction:column;align-items:center;
  line-height:1.1}
.mx-got{font-size:26px;font-weight:700;color:#fff;
  text-shadow:0 2px 12px #000c}
.mx-proj{font-family:var(--cond);font-size:17px;font-weight:700;
  margin-top:3px}
.mx-proj.is-up{color:#7ee2a8}
.mx-proj.is-down{color:#e0707c}

/* VS, not a dash — it reads as a fixture rather than a subtraction. */
/* VS and the way through, stacked on the centre line. */
.mx-vs{display:flex;flex-direction:column;align-items:center;
  gap:4px;flex:0 0 auto;margin-top:-14px}
.mx-lineup{display:block;margin:0;padding:2px 8px;
  border:0;border-radius:6px;background:#ffffff0f;
  box-shadow:inset 0 0 0 1px #ffffff17;cursor:pointer;
  font-family:var(--cond);font-size:8px;font-weight:700;
  letter-spacing:.18em;text-transform:uppercase;color:var(--muted)}
.mx-lineup:hover{background:#ffffff1a;color:#fff}

.mx-dash{font-family:var(--cond);font-size:18px;font-weight:700;
  letter-spacing:.1em;color:#fff;margin:0 2px;
  text-shadow:0 1px 6px #000a}
.mx-rule{height:1px;background:#ffffff1f;margin:6px 14px}
.mx-pcts{display:flex;justify-content:center;gap:14px}
.mx-pct{font-size:12px;font-weight:700}

.mx-cols{display:grid;grid-template-columns:1fr 1fr;column-gap:96px;
  row-gap:8px;margin-top:16px;padding:0 8px}
.mx-col{min-width:0}
.mx-col.mx-right{text-align:right}
.mx-col.mx-up{padding-top:6px;box-shadow:inset 0 1px 0 #ffffff12}
.mx-lab{font-family:var(--cond);font-size:7px;color:var(--muted);
  letter-spacing:.16em;text-transform:uppercase;margin-bottom:4px}
/* Three rows exactly: 28 tall, 4 apart. The fourth sits below the
   fold rather than half-showing. */
.mx-scroll{height:92px;overflow-y:auto;
  scrollbar-width:thin;scrollbar-color:#ffffff24 transparent}
.mx-scroll::-webkit-scrollbar{width:8px}
.mx-scroll::-webkit-scrollbar-track{background:transparent}
.mx-scroll::-webkit-scrollbar-thumb{background:#ffffff24;
  border-radius:3px;border:2px solid transparent;background-clip:content-box}
/* The left column's bar belongs on its own outer edge. */
.mx-rtl{direction:rtl}
.mx-rtl > *{direction:ltr}
.mx-row{display:flex;align-items:center;gap:5px;height:28px;
  margin-bottom:4px}
.mx-face{width:24px;height:24px;border-radius:50%;flex:0 0 auto;
  overflow:hidden;background:#2a3546}
.mx-face img{width:100%;height:100%;object-fit:cover}
.mx-box{flex:1;min-width:0;height:28px;border-radius:5px;
  padding:0 6px;display:flex;gap:6px;align-items:center;
  box-sizing:border-box;background:#ffffff0a;
  box-shadow:inset 0 0 0 1px #ffffff17}
/* His side has the ball; and they are inside the twenty. */
.mx-box.has-ball{background:#15803d29;
  box-shadow:inset 0 0 0 1px #7ee2a877}
.mx-box.in-red{background:#7f1d1d33;
  box-shadow:inset 0 0 0 1px #e0707cbb,0 0 7px #e0707c3d}
.mx-n{font-size:9.5px;font-weight:700;color:#dbe3ee;flex:0 0 auto}
.mx-box.has-ball .mx-n,.mx-box.in-red .mx-n{color:#fff}
.mx-t{font-size:7px;line-height:1.3;min-width:0;flex:1;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  color:var(--muted);text-align:right}
.mx-right .mx-t{text-align:left}
.mx-box.has-ball .mx-t{color:#a8e6c1}
.mx-box.in-red .mx-t{color:#f0a8ae}
.mx-sub{opacity:.65}
.mx-list{font-family:var(--cond);font-size:8px;color:#dbe3ee;
  line-height:1.6}
.mx-list span{color:var(--muted)}

/* The same corner brackets the stats table carries. .pane-expand is
   display:none by default — it only shows where a panel asks for it
   — so this turns it back on and places it. */
/* The football, top left. Grey while nothing is on; red, blinking
   and wearing LIVE when a game of yours is being played. */
.mx-ball{position:absolute;top:3px;left:3px;z-index:3;
  width:26px;height:26px;padding:0;border:0;background:none;
  cursor:pointer;display:flex;align-items:center;justify-content:center}
.mx-ball svg{width:18px;height:18px;fill:#39424f;stroke:#525d6d;
  stroke-width:1.1;transition:fill .3s ease,stroke .3s ease}
.mx-ball .mx-ball-seam{stroke:#8b95a6;fill:none;stroke-width:1.3;
  stroke-linecap:round}
.mx-ball-live{position:absolute;font-family:var(--cond);font-size:6px;
  font-weight:700;letter-spacing:.06em;color:#fff;opacity:0;
  text-shadow:0 1px 3px #000c;pointer-events:none}
.mx-ball.is-live svg{fill:var(--red);stroke:#f2604f}
.mx-ball.is-live .mx-ball-seam{stroke:#ffffffcc}
.mx-ball.is-live .mx-ball-live{opacity:1}
.mx-ball.is-live{animation:ballpulse 1.4s ease-in-out infinite}
@keyframes ballpulse{0%,100%{opacity:1}50%{opacity:.45}}

.mx-expand{display:flex;position:absolute;top:2px;right:2px;z-index:3}
/* The tabs stay reachable over the open drawer, so a rail can be
   pulled out while the lineup is showing. */
.newstab,.leaguetab{z-index:72}
.mx-expand svg{width:15px;height:15px}
.mx-expand:hover{color:#fff}

/* The drawer the card opens into.
   
   It sits under the fixtures band so the scores stay in view, and
   carries the hub's own padding and width so the card lands exactly
   where it was rather than shifting or growing. */
/* Below the player card, which is z-index 92. The drawer animates
   its own opacity, and an element mid-transition makes a stacking
   context — so while it was fading, a card opened from a row was
   painting against the wrong layer for a frame. Held at a flat
   opacity once open, it does not. */
/* Below the rails, which are also 70 — the drawer comes later in the
   document, so it was winning the tie and covering them. */
.mxfull{position:fixed;left:0;right:0;bottom:0;
  top:calc(var(--bar-h,53px) + var(--slate-h,0px));
  z-index:64;
  /* The page's own colour, not a scrim over it.
     
     A translucent black plus a blur darkened everything behind the
     card, so the expanded view never matched the collapsed one. This
     is the same background the hub has, so the edges are identical. */
  /* The page's own colour, and the glow at the foot showing through
     it — the drawer is part of the page, not a lid over it. */
  background:linear-gradient(0deg,#c9d6e81f 0%,#c9d6e80d 24%,
    transparent 42%),var(--ink);
  overflow-y:auto;overscroll-behavior:contain;
  opacity:0;transition:opacity .6s cubic-bezier(.4,0,.2,1)}

/* will-change is dropped once open, so the layer is discarded and
   anything above it is composited normally. */
.mxfull.is-open{opacity:1;will-change:auto}
.mxfull-inner{width:100%;box-sizing:border-box;
  padding:0 0 16px;min-height:100%;
  display:flex;flex-direction:column}


/* The rows below, sharing whatever is left. */
/* The rows take the card's own width.
   
   This held width:calc(100% - 72px) — thirty-six pixels a side kept
   clear because the news and league tabs used to sit against both
   edges and a photograph at the end of a row passed behind them.
   The tabs come off now while a drawer is open, so that reservation
   was seventy-two pixels held for something no longer there, and it
   was coming straight out of the names. */
.mxfull-rows{flex:1 1 auto;display:flex;flex-direction:column;
  max-width:620px;margin:10px auto 0;width:100%;
  border-radius:12px;overflow:hidden;
  /* Lighter than the card above it, and lit from the top left. */
  background:linear-gradient(135deg,#16233a 0%,#101a2c 55%,#0d1524 100%);
  box-shadow:inset 0 0 0 1px #24406b;
  padding:2px 10px}
.mxf-row{display:grid;
  grid-template-columns:minmax(0,1fr) 44px 42px 44px minmax(0,1fr);
  align-items:center;gap:5px;flex:1 1 auto;min-height:38px;
  border-bottom:1px solid #ffffff0a}
.mxf-row:last-child{border-bottom:0}
/* The colours are scoped to .mu-slot on the lineups page, so they
   have to be named again here rather than inherited. */
.mxf-slot{font-family:var(--cond);font-size:10px;font-weight:700;
  letter-spacing:.06em;text-align:center;border-radius:5px;
  padding:4px 0;color:#0b1220;background:#3a4150}
.mxf-slot.s-QB{background:var(--pos-qb)}
.mxf-slot.s-RB{background:var(--pos-rb)}
.mxf-slot.s-WR{background:var(--pos-wr)}
.mxf-slot.s-TE{background:var(--pos-te)}
.mxf-slot.s-FLEX{background:#d4a63c}
.mxf-slot.s-OP{background:#e0803c}
.mxf-man{display:flex;align-items:center;gap:6px;min-width:0}
/* The wash behind a man who is not certain to play, and his letter —
   the same colours the lineups page uses. */
.mxf-man.is-p{background:linear-gradient(90deg,#15803d5c,#15803d1a 62%,transparent)}
.mxf-man.is-q{background:linear-gradient(90deg,#a1620066,#a162001f 62%,transparent)}
.mxf-man.is-d{background:linear-gradient(90deg,#9a3d0070,#9a3d0022 62%,transparent)}
.mxf-man.is-o{background:linear-gradient(90deg,#7f1d1d85,#7f1d1d2b 62%,transparent)}
/* Mirrored on the right, so both washes fade toward the middle. */
.mxf-man.is-right.is-p{background:linear-gradient(270deg,#15803d5c,#15803d1a 62%,transparent)}
.mxf-man.is-right.is-q{background:linear-gradient(270deg,#a1620066,#a162001f 62%,transparent)}
.mxf-man.is-right.is-d{background:linear-gradient(270deg,#9a3d0070,#9a3d0022 62%,transparent)}
.mxf-man.is-right.is-o{background:linear-gradient(270deg,#7f1d1d85,#7f1d1d2b 62%,transparent)}
/* On the corner of the photograph: top left on the left column, top
   right on the right, so the two mirror each other and the mark is
   always on the outer edge. The face has to stop clipping it. */
.mxf-face{overflow:visible;position:relative}
.mxf-face img{border-radius:50%}
.mxf-flag{position:absolute;top:-3px;left:-4px;z-index:2;
  font-family:var(--cond);font-size:7.5px;font-weight:700;
  letter-spacing:.04em;line-height:1;padding:1px 3px;
  border-radius:4px;box-shadow:0 0 0 1.5px #0b1220}
.mxf-man.is-right .mxf-flag{left:auto;right:-4px}
/* Filled with a pale version of its own colour, with the letter dark
   on top — a translucent chip over a headshot was hard to read. */
.mxf-flag.is-p{background:#b8ecc9;color:#0d3a1e}
.mxf-flag.is-q{background:#f6e2ae;color:#4a3208}
.mxf-flag.is-d{background:#f7cfb0;color:#4d2408}
.mxf-flag.is-o{background:#f5c2be;color:#4d1414}

.mxf-man.can-open{cursor:pointer;border-radius:6px;
  padding:2px 3px;margin:-2px -3px;transition:background .15s ease}
.mxf-man.can-open:hover{background:#ffffff0d}
.mxf-man.is-right{flex-direction:row-reverse}
.mxf-face{width:24px;height:24px;border-radius:50%;flex:0 0 auto;
  background:#2a3546}
.mxf-face img{width:100%;height:100%;object-fit:cover}
/* A column: these are spans, so without this the name and the
   fixture sat on the same line beside each other. */
.mxf-text{min-width:0;line-height:1.25;
  display:flex;flex-direction:column}
.mxf-man.is-right .mxf-text{align-items:flex-end}

.mxf-name{font-size:10.5px;color:#fff;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap;max-width:100%}
/* The row is reversed on the right, so the photograph is already at
   the outer end and a plain ellipsis lands there. rtl put it at the
   front of the name, which is the wrong end. */
.mxf-man.is-right .mxf-name{text-align:right}
/* Its own line, under the name. */
.mxf-sub{display:flex;align-items:baseline;gap:3px;
  font-family:var(--cond);font-size:8.5px;color:#6d7684;
  overflow:hidden;white-space:nowrap;margin-top:1px}
.mxf-man.is-right .mxf-sub{justify-content:flex-end}
/* Home or away, said by the colour rather than by a word. */
.mxf-at{font-weight:700}
.mxf-at.is-home{color:#7ee2a8}
.mxf-at.is-away{color:#e0707c}
.mxf-day{color:#4e5663}
.mxf-num{text-align:center;line-height:1.1}
.mxf-num b{font-size:13px;color:#fff;display:block}
/* The two faces share one spot: stacked rather than swapped, so the
   column does not jump as they cross over. */
.mxf-under{position:relative;display:inline-flex;justify-content:center;
  min-height:1em;width:100%}
.mxf-flip{position:absolute;left:0;right:0;top:0;opacity:0;
  font-family:var(--cond);font-size:11px;font-weight:700;
  color:var(--muted);
  white-space:nowrap;transition:opacity .38s ease}
.mxf-flip.is-on{opacity:1}
.mxf-flip.is-rank{color:#8fd0f7}

/* The chat's own backdrop, its glow, and the fade at the top.
   
   The rail is the positioning parent, so the glow and the fade sit
   over the scrolling lines without scrolling with them. */
.leaguerail .chat-body{position:relative;
  /* No background of its own: the other two views show the rail's
     gradient through them, and a fill here made the chat the odd one
     out. */
  overscroll-behavior:contain;
  /* No padding at the top.
     
     A sticky child sits below its parent's top padding, so twelve
     pixels of that strip stayed uncovered and lines were visible
     scrolling through it. The first row carries the space instead. */
  padding:0 12px 8px}
/* Both views start clear of the pane, so nothing is faded before it
   has been scrolled — the first card is fully lit on arrival and
   only dims once it moves under. */
.leaguerail .chat-body > .chat-row:first-of-type{margin-top:14px}

/* The rule under the tabs, and the fade beneath it.
   
   Both in one sticky ::before rather than two: ::after is the last
   child of the scroller, so it sat at the foot of the conversation
   and the lines went on scrolling past the top untouched. One
   element, two background layers — the hairline on top, the fade
   under it — and it holds at the top of the scroll. */
/* The fade pane, fixed to the rail rather than living in the scroll.
   
   It was a sticky child of the conversation with a backdrop blur —
   which samples what is behind it, so the lines passing under showed
   as a blurred copy of themselves and read as duplicated text. This
   is a plain gradient on the rail itself: it never moves, never
   samples, and covers whichever view is showing. */
.leaguerail{position:relative}
/* The fade under the tabs.
   
   Its own element, straight after the bar in the rail's flex column,
   taking no height — so top:0 on its child is exactly the bar's
   lower edge, with no arithmetic to get wrong. Sitting outside the
   bar is what lets it pass behind it: a child paints above its
   parent's background no matter what index it is given. */
.railfade{position:relative;height:0;flex:0 0 auto;z-index:2}
.railfade::after{content:"";position:absolute;
  top:0;left:0;right:0;height:26px;pointer-events:none;
  background:linear-gradient(180deg,#161d2b 0%,#161d2b 42%,
    #161d2b4d 72%,transparent 100%)}

/* Each view its own colour, so the rail says which it is on before
   you have read the word. */
/* The base .seg button carries border:0, so the edge is an inset
   shadow rather than a border that would never draw. */
.leaguerail .railseg button.on[data-view="chat"]{
  background:#7e2a26;box-shadow:inset 0 0 0 1px #a03a33;
  color:#fbe4e0}
.leaguerail .railseg button.on[data-view="snapshot"]{
  background:#1c5136;box-shadow:inset 0 0 0 1px #2c7a51;
  color:#d8f3e4}
.leaguerail .railseg button.on[data-view="moves"]{
  background:#1b3f6b;box-shadow:inset 0 0 0 1px #2b5f9c;
  color:#d9e8fa}

/* Each scope its own colour when it is the one showing. The base
   .seg button carries border:0, so the edge is an inset shadow. */
#faScope button.on[data-scope="free"]{
  background:#25567f;box-shadow:inset 0 0 0 1px #3b7bb0;color:#dcecfb}
#faScope button.on[data-scope="all"]{
  background:#15304d;box-shadow:inset 0 0 0 1px #24507d;color:#c3d6ea}
#faScope button.on[data-scope="targets"]{
  background:#7a5c14;box-shadow:inset 0 0 0 1px #b8912a;color:#fbeec4}

/* The target star on a free agent row. */
.fastar{flex:0 0 auto;width:26px;height:26px;padding:0;border:0;
  background:none;cursor:pointer;display:flex;align-items:center;
  justify-content:center;-webkit-tap-highlight-color:transparent}
.fastar svg{width:15px;height:15px;fill:none;stroke:#5a6270;
  stroke-width:1.7;stroke-linejoin:round;
  transition:fill .18s ease,stroke .18s ease,transform .18s ease}
.fastar:hover svg{stroke:#9fb0c6}
.fastar.on svg{fill:#e8b84b;stroke:#e8b84b}
.fastar:active svg{transform:scale(.86)}

/* Name over record in the snapshot rail. */
.lgwho{display:flex;flex-direction:column;min-width:0;gap:0;
  line-height:1.15}
.lgrec{font-family:var(--cond);font-size:8.5px;color:var(--muted);
  letter-spacing:.04em}

/* The unread mark on the Chat tab in the league rail. */
.rail-dot{display:inline-block;width:5px;height:5px;margin-left:5px;
  border-radius:50%;background:var(--red);vertical-align:middle;
  animation:raildot 1.3s ease-in-out infinite}
@keyframes raildot{0%,100%{opacity:1}50%{opacity:.35}}
/* And on the tab that opens the rail, when it is shut. */
.leaguetab.has-unread{animation:raildot 1.4s ease-in-out infinite}
/* The chat fills the rail below the segmented control. */
.leaguerail .chat-body{flex:1 1 auto;min-height:0;overflow-y:auto}
.leaguerail .chat-form{flex:0 0 auto}
.chat-none{padding:14px 12px;font-size:12px;color:var(--muted);
  text-align:center}

/* The same light rising from the foot of the page the hub has. */
body:has(.gdpage)::after{content:"";position:fixed;
  left:0;right:0;bottom:0;height:34vh;z-index:-1;pointer-events:none;
  background:linear-gradient(0deg,#c9d6e829 0%,#c9d6e814 30%,
    #c9d6e807 58%,transparent 100%)}

/* Game day, full screen. */
.gdfull{position:fixed;inset:0;z-index:80;background:var(--ink);
  overflow-y:auto;overscroll-behavior:contain;
  opacity:0;transition:opacity .3s ease}
.gdfull.is-open{opacity:1}
.gdfull-in{max-width:620px;margin:0 auto;padding:0 0 28px}
.gdhead{position:sticky;top:0;z-index:4;display:flex;
  align-items:center;justify-content:space-between;
  background:var(--red);padding:8px 12px}
.gdhead-t{font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.18em;text-transform:uppercase;color:#fff}
.gdshut{background:none;border:0;color:#ffffffcf;font-size:20px;
  line-height:1;cursor:pointer;padding:0 2px}

/* The matchup, pinned under the banner. */
/* Room under the banner: the owner names were sitting against the
   red rule above them. */
.gdmatch{display:flex;align-items:center;justify-content:space-between;
  gap:2px;padding:16px 8px 13px;background:#0b1220;
  box-shadow:inset 0 -1px 0 #ffffff12}
.gdarrow{background:none;border:0;color:#ffffff4d;width:18px;
  font-size:21px;line-height:1;cursor:pointer;flex:0 0 auto;padding:0}
.gdarrow:hover{color:#fff}
.gdside{min-width:0;display:flex;align-items:center;gap:9px}
.gdside.r{text-align:right}
.gdstext{min-width:0}
/* His photograph, on the outside of the block. */
.gdoface{width:34px;height:34px;border-radius:50%;flex:0 0 auto;
  overflow:hidden;background:var(--ink);display:flex;
  align-items:center;justify-content:center}
.gdoface img{width:100%;height:100%;object-fit:cover}
.gdoinit{font-family:var(--cond);font-size:12px;font-weight:700;
  color:var(--muted)}
/* A rule between the figures rather than a dot. */
.gdside.r .gdsub{justify-content:flex-end}
.gdbar{color:#3f4855}
.gdname{font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.08em;text-transform:uppercase}
.gdside.a .gdname{color:#a8e6c1}
.gdside.b .gdname{color:#f0a8ae}
.gdpts{font-size:24px;color:#fff;font-weight:700;line-height:1.1}
.gdsub{font-family:var(--cond);font-size:8.5px;
  display:flex;align-items:center;gap:6px;white-space:nowrap}
.gdside.a .gdsub{color:#7ee2a8}
.gdside.b .gdsub{color:#e0707c}
.gdvs{text-align:center;font-size:14px;color:#fff;font-weight:700;
  letter-spacing:.12em}

/* Which game you are watching. */
/* On the field, top left. */
.gdstrip{position:absolute;top:7px;left:7px;right:7px;z-index:3;
  display:flex;gap:6px;overflow-x:auto;scrollbar-width:none}
.gdstrip::-webkit-scrollbar{display:none}
/* The game chip: two badges, a dash, and the counts. It was cramped
   because the badges sat in a box sized for text. */
.gdchip{flex:0 0 auto;padding:4px 8px;border-radius:8px;border:0;
  background:#0b1220b8;box-shadow:inset 0 0 0 1px #ffffff1f;
  -webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);
  font-family:var(--cond);font-size:9px;color:var(--muted);
  cursor:pointer;white-space:nowrap;
  display:flex;align-items:center;gap:5px;min-height:30px}
.gdchip.on{background:#15304de0;box-shadow:inset 0 0 0 1px #3b7bb0;
  color:#dcecfb}
.gdchip.live{box-shadow:inset 0 0 0 1px var(--red)}
.gdchip b{font-weight:700;color:#7ee2a8}
.gdchip i{font-style:normal;color:#e0707c}

/* The game itself. */
/* Room under the score before the field starts — the two were
   sitting flush against each other. */
.gdscore{display:flex;align-items:center;justify-content:center;
  gap:12px;padding:10px 12px 14px}
/* The club badge: its logo, with the code as a fallback. */
.gdclub{width:26px;height:26px;flex:0 0 auto;display:flex;
  align-items:center;justify-content:center}
.gdclub img{width:100%;height:100%;object-fit:contain}
.gdclub-t{font-family:var(--cond);font-size:8px;font-weight:700;
  color:#fff;background:#2a3546;border-radius:5px;padding:4px 5px}
.gdchip .gdclub{width:19px;height:19px}
.gdchip-v{color:#5a6270;font-size:9px;margin:0 1px}
.gdchip-n{margin-left:6px;padding-left:7px;font-size:10px;
  letter-spacing:.02em;display:flex;align-items:center;gap:3px;
  box-shadow:inset 1px 0 0 #ffffff1a}
.gdchip-n b{font-weight:700;color:#7ee2a8}
.gdchip-n i{font-style:normal;font-weight:700;color:#e0707c}
.gdchip-slash{color:#4e5663;font-size:9px}
/* The field holds still; the men scroll beneath it. */
.gdfixed{position:sticky;top:0;z-index:6;background:var(--ink);
  padding-bottom:2px;
  box-shadow:0 8px 18px -10px #000a}
/* Room to scroll into. The board used to be a flex column with a
   minimum height that pushed the football half to the foot; the
   scrolling half wants the opposite — it grows with its contents
   and the page scrolls. */
.gdscroll{display:block;min-height:0;
  padding-bottom:calc(24px + env(safe-area-inset-bottom))}

/* Summary or box score. Placed at the end of the file — see below. */
.gdview button{flex:1;padding:7px 8px;text-transform:uppercase;
  letter-spacing:.14em;font-size:9px}

/* Which club's box score. */

.gdbox-side button{flex:1;padding:6px 8px;display:flex;
  align-items:center;justify-content:center;gap:6px;
  font-family:var(--cond);font-size:10px;font-weight:700;
  letter-spacing:.08em}
.gdbox-side .gdclub{width:18px;height:18px}

/* The lines themselves. */
.gdbox{margin:12px 12px 0}
.gdbox-h{font-family:var(--cond);font-size:7.5px;color:#5a6270;
  letter-spacing:.16em;text-transform:uppercase;margin-bottom:5px}
.gdbox-row{display:grid;
  grid-template-columns:minmax(0,1fr) repeat(5,38px);
  align-items:center;gap:4px;padding:5px 7px;border-radius:5px;
  font-size:10px;color:#dbe3ee}
.gdbox-row > span:not(.gdbox-who){text-align:right;
  font-family:var(--cond);font-size:10.5px}
.gdbox-row.is-head{color:#5a6270;font-size:7px;padding:0 7px 3px}
.gdbox-row.is-head > span{font-family:var(--cond);font-size:7px;
  letter-spacing:.1em;text-transform:uppercase}
.gdbox-row:not(.is-head):nth-child(odd){background:#ffffff06}
/* A man either owner is starting. */
.gdbox-row.is-mine{background:#15803d24;
  box-shadow:inset 0 0 0 1px #7ee2a877}
.gdbox-who{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* The page itself. */
/* Full width up to the reading measure. Without the stated width it
   sized to its contents, which on a phone left the board sitting in
   a column narrower than the banner above it. */
.gdpage{width:100%;max-width:620px;margin:0 auto;padding:0;
  box-sizing:border-box}
.gdmatch,.gdstrip,.gdboard{width:100%;box-sizing:border-box}
.gdnum{font-size:19px;color:#fff;font-weight:700}
.gdnum.dim{color:var(--muted)}
.gdclock{text-align:center;min-width:54px}
/* Quarter over the clock, down and distance under it. */
.gdclock b{display:block;font-size:14px;color:#fff;font-weight:700;
  line-height:1.15}
.gdclock span{display:block;font-family:var(--cond);font-size:8px;
  color:var(--muted);letter-spacing:.14em}
.gdq{color:#8b95a6}
.gddown{color:#e8b84b;font-weight:700;margin-top:1px}

/* The field. */
/* One height, whatever the game. */
.gdfield{position:relative;height:110px;margin:0 12px;border-radius:6px;
  overflow:hidden;box-shadow:inset 0 0 0 2px #ffffff1a;
  /* Lit from above, the way a field under floodlights reads. */
  background:linear-gradient(180deg,#16311f 0%,#102418 46%,
    #0a1611 100%)}
.gdfield.waiting{background:linear-gradient(180deg,#161d2b,#11161f);
  box-shadow:inset 0 0 0 2px #ffffff0f}
.gdyards{position:absolute;inset:0;width:100%;height:100%}
/* Each end zone in its own club's colour. A side always drives
   toward the other's, so the colour says which way they are going. */
.gdend{position:absolute;top:0;bottom:0;width:13%;
  background:#ffffff0a;display:flex;align-items:center;
  justify-content:center;overflow:hidden}
/* The club's mark, large and faint behind its colour. */
.gdendmark{width:78%;height:auto;opacity:.5}
.gdendmark img{width:100%;height:100%;object-fit:contain;
  filter:drop-shadow(0 1px 3px #0009)}
/* The end being attacked glows a little. */
.gdend.is-target{box-shadow:inset 0 0 18px #ffffff2b}

/* The play, drawn from where the ball was to where it is.
   
   A solid gold line for ground made, red for ground lost, red and
   dashed for a throw that was not caught — the line runs out to
   where it was aimed. */
.gdpath{position:absolute;top:50%;height:2px;margin-top:-1px;
  pointer-events:none;z-index:1;border-radius:2px;
  background:#e8b84b;box-shadow:0 0 8px #e8b84b7a;
  animation:gdgrow .5s ease-out both}
.gdpath.is-back{background:var(--red);box-shadow:0 0 8px #c8404f7a}
.gdpath.is-miss{background:none;box-shadow:none;height:0;
  border-top:2px dashed #e0707cc4}
@keyframes gdgrow{from{opacity:0;transform:scaleX(.1)}
  to{opacity:1;transform:scaleX(1)}}
.gdpath{transform-origin:left center}

/* The ball itself, sliding along it. */
.gdmove{position:absolute;top:50%;width:13px;height:9px;
  margin-top:-4.5px;margin-left:-6.5px;
  border-radius:50%/50%;background:#e8b84b;border:1px solid #fff3c4;
  box-shadow:0 0 12px #e8b84bcc;pointer-events:none;z-index:3;
  transition:left .85s cubic-bezier(.3,.7,.35,1)}
.gdend.l{left:0;box-shadow:inset -1px 0 0 #ffffff1f}
.gdend.r{right:0;box-shadow:inset 1px 0 0 #ffffff1f}
.gdlos{position:absolute;top:0;bottom:0;width:2px;background:#e8b84b;
  box-shadow:0 0 10px #e8b84b8a;
  transition:left .5s cubic-bezier(.35,.7,.3,1)}
.gdball{position:absolute;top:50%;transform:translate(-50%,-50%);
  display:flex;flex-direction:column;align-items:center;gap:3px;
  z-index:2;transition:left .5s cubic-bezier(.35,.7,.3,1)}

/* The last movement, centred along the foot of the field. */
.gdlast{position:absolute;left:0;right:0;bottom:6px;text-align:center;
  font-family:var(--cond);font-size:9px;color:#dbe3ee;
  letter-spacing:.04em;padding:0 10px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  text-shadow:0 1px 4px #000a}
/* ESPN's own words, in a box that can run to two lines. */
.gdlast.has-play{left:8px;right:8px;bottom:6px;
  background:#050a12a8;border-radius:6px;padding:5px 8px;
  box-shadow:inset 0 0 0 1px #ffffff17;
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);
  white-space:normal;text-overflow:clip}
.gdplay{color:#dbe3ee;display:-webkit-box;-webkit-line-clamp:2;
  -webkit-box-orient:vertical;overflow:hidden;line-height:1.35}
.gdlast b{font-weight:700}
.gdlast b.is-mine{color:#7ee2a8}
.gdlast b.is-them{color:#e0707c}
.gdlast-sep{color:#5a6270;margin:0 5px}
.gdlast-dd{color:#e8b84b;font-weight:700;letter-spacing:.06em}

.gdwait{position:absolute;inset:0;display:flex;align-items:center;
  justify-content:center;font-family:var(--cond);font-size:10px;
  color:#5a6270;letter-spacing:.16em;text-transform:uppercase}

/* Both sides' men on that field. */
.gdmen{display:grid;grid-template-columns:1fr 1fr;gap:10px;
  padding:16px 12px 0}
.gdfield .gdyards,.gdfield .gdend{top:0}
.gdsec{font-family:var(--cond);font-size:7px;color:#5a6270;
  letter-spacing:.14em;margin-bottom:6px;
  display:flex;align-items:center;gap:6px;min-height:11px}
.gdsec.r{flex-direction:row-reverse}
.gdcol{min-width:0}
/* Which page this side is on, when it has a bench to show. */
.gdtabs{display:flex;gap:4px}
.gddot{width:5px;height:5px;border-radius:50%;background:#3a4150;
  cursor:pointer;flex:0 0 auto;transition:background .2s ease}
.gddot.on{background:#8b95a6}
/* Four rows fit; beyond that the side scrolls rather than growing. */
.gdlist{touch-action:pan-y;
  transition:transform .17s ease,opacity .17s ease}
.gdlist.out-l{transform:translateX(-16px);opacity:0}
.gdlist.out-r{transform:translateX(16px);opacity:0}
.gdlist.scrolls{max-height:150px;overflow-y:auto;
  overscroll-behavior:contain;scrollbar-width:thin;
  scrollbar-color:#ffffff24 transparent}
.gdlist.scrolls::-webkit-scrollbar{width:4px}
.gdlist.scrolls::-webkit-scrollbar-thumb{background:#ffffff24;
  border-radius:2px}
.gdrow{display:flex;align-items:center;gap:6px;padding:6px;
  border-radius:6px;background:#ffffff08;
  box-shadow:inset 0 0 0 1px #ffffff12;margin-bottom:4px}
/* Roomier with few men, tighter with many. */
.gdmen.roomy .gdrow{padding:8px 7px;margin-bottom:5px}
.gdmen.roomy .gdface{width:26px;height:26px}
.gdmen.roomy .gdwho b{font-size:10.5px}
.gdmen.roomy .gdval{font-size:12px}
.gdmen.snug .gdrow{padding:6px}
.gdmen.tight .gdrow{padding:4px 5px;margin-bottom:3px}
.gdmen.packed .gdrow{padding:3px 5px;margin-bottom:3px}
.gdmen.packed .gdface{width:19px;height:19px}
.gdmen.packed .gdwho b{font-size:9px}

/* A man on the bench is there for reference, not for reading — the
   colour belongs to whoever is actually playing for you. */
.gdlist.is-bench .gdrow{filter:grayscale(1);opacity:.72}
.gdrow.r{flex-direction:row-reverse}
.gdrow.hot{background:#15803d24;box-shadow:inset 0 0 0 1px #7ee2a877}
.gdrow.rz{background:#7f1d1d2e;box-shadow:inset 0 0 0 1px #e0707cbb}
.gdface{width:21px;height:21px;border-radius:50%;flex:0 0 auto;
  overflow:hidden;background:#2a3546}
.gdface img{width:100%;height:100%;object-fit:cover}
.gdwho{flex:1;min-width:0}
.gdwho b{display:block;font-size:9.5px;color:#fff;font-weight:400;
  line-height:1.15;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
/* His line, said properly: it is the reason to look at the row at
   all, and at 7px in the dimmest grey it was the quietest thing on
   the card. */
.gdwho i{display:block;font-style:normal;font-family:var(--cond);
  font-size:9px;color:#a8b6c8;margin-top:2px;letter-spacing:.01em;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* A man on the field reads brighter still. */
.gdrow.hot .gdwho i{color:#c9e6d5}
.gdrow.rz .gdwho i{color:#f3c9cc}
/* Tighter only where the column is crowded. */
.gdmen.packed .gdwho i{font-size:8px}
/* How much of his offence he was on the field for: a thin track with
   a fill, and the figure at the end. */
.gdsnap{display:flex;align-items:center;gap:5px;margin-top:3px}
.gdtrack{flex:1;min-width:0;height:2.5px;border-radius:2px;
  background:#ffffff0f;overflow:hidden}
.gdsnap i{display:block;height:100%;border-radius:2px}
.gdsnap u{flex:0 0 auto;text-decoration:none;font-family:var(--cond);
  font-size:6.5px;color:#8b95a6}

.gdval{flex:0 0 auto;text-align:right;font-size:10.5px;
  font-weight:700;color:#fff}
.gdrow.r .gdval{text-align:left}
.gdval u{display:block;text-decoration:none;font-family:var(--cond);
  font-size:6.5px;color:#6d7684;font-weight:400}

/* The summary tiles. */
.gdtiles{display:grid;gap:1px;background:#ffffff0d;border-radius:8px;
  overflow:hidden;margin:10px 12px 0}
.gdtiles>div{background:#0b1220;padding:7px 4px;text-align:center}
.gdtiles b{display:block;font-size:13px;color:#fff;font-weight:700;
  line-height:1.15}
.gdtiles span{font-family:var(--cond);font-size:6.5px;color:#5a6270;
  letter-spacing:.12em;line-height:1.2;display:block;margin-top:2px}
/* Three a side, and then four: the summary gives way to the men. */
.gdtiles.roomy>div{padding:9px 4px}
.gdtiles.roomy b{font-size:14px}
.gdtiles.snug>div{padding:6px 4px}
.gdtiles.snug b{font-size:13px}
.gdtiles.tight>div{padding:4px 4px}
.gdtiles.tight b{font-size:12px}
.gdtiles.packed>div{padding:3px 4px}
.gdtiles.packed b{font-size:11px}
.gdtiles.packed span{font-size:6px;margin-top:0}
.gdtiles b.none{color:#3a4150}

/* The rule between the fantasy half and the football half. */
/* The football half is pushed to the bottom of what is left, so the
   page ends where the screen does rather than trailing off. */
/* The football half sits under the men rather than being pushed to
   the foot: the page scrolls now, so there is no bottom to reach. */
.gdteams{margin-top:16px}
.gdrule{height:1px;margin:14px 12px 4px;position:relative;
  background:linear-gradient(90deg,transparent,#c8404f80 20%,
    #c8404f80 80%,transparent)}
.gdrule b{position:absolute;left:50%;top:-6px;transform:translateX(-50%);
  background:var(--ink);padding:0 9px;font-family:var(--cond);
  font-size:7px;color:var(--red);letter-spacing:.2em;font-weight:700}

/* The football half: both clubs' figures as one split bar. */
.gdteams{padding:0 12px}
/* The badge row mirrors a stat row exactly — 52px, the bar's space,
   52px — so each club's figures fall under its own badge instead of
   at the outer edges. */
.gdclubs{display:flex;align-items:center;gap:7px;margin-bottom:8px}
.gdclubs .gdclub{width:28px;height:28px;flex:0 0 52px}
.gdclubs .gdgap{flex:1;text-align:center;font-family:var(--cond);
  font-size:8px;font-weight:700;letter-spacing:.2em;color:#fff}
/* Two bars sharing the middle column, so the pair is the same width
   as the single bar on every other row. */
.gdpair{flex:1;display:flex;gap:8px}
.gdpair .gdsplit{flex:1}
.gdtsr{display:flex;align-items:center;gap:7px;
  justify-content:space-between}
.gdtsr>b{font-size:10px;color:#dbe3ee;flex:0 0 52px;
  font-weight:400;text-align:center}
.gdsplit{flex:1;height:6px;border-radius:3px;overflow:hidden;display:flex;
  background:#ffffff0d}
.gdsplit i{display:block;height:100%}
.gdtlab{font-family:var(--cond);font-size:6.5px;color:#5a6270;
  letter-spacing:.13em;text-align:center;margin:3px 0 7px}

/* Waiting for kickoff: the shape of a figure, without one. */
.gdbar{height:5px;border-radius:3px;background:#ffffff0d;
  overflow:hidden;flex:1}
.gdbar i{display:block;height:100%;border-radius:3px;background:#2a3546}

/* Pick 'em. */
/* The band sits on the card's own bottom edge, so it carries the
   corner radius and enough padding to clear it — without that the
   buttons were being cut by the rounding. */
.mx-pick{margin:10px -4px 0;padding:7px 12px 11px;
  background:#00000038;box-shadow:inset 0 1px 0 #ffffff12;
  border-radius:0 0 12px 12px}
/* Its own height too: the vote count is appended once the tally is
   read, and a label that grows moves everything under it. */
.mx-picklab{width:100%;min-width:0;text-overflow:ellipsis;
  text-align:center;font-family:var(--cond);font-size:7.5px;
  color:var(--muted);letter-spacing:.24em;text-transform:uppercase;
  height:10px;line-height:10px;margin-bottom:5px;
  overflow:hidden;white-space:nowrap}
.mx-picklab span{color:#dbe3ee}
.mx-pickrow{display:flex;gap:10px;width:100%;min-width:0}
/* A stated height, so voting does not resize the button.
   
   The percentage only appears once a pick is in, and at 13px it is
   taller than the name beside it — so the button grew, the band grew
   with it, and the card pushed off the bottom of the screen. */
.pk-btn{position:relative;flex:1;min-width:0;border:0;cursor:pointer;
  height:30px;padding:0 9px;border-radius:8px;overflow:hidden;
  display:flex;align-items:center;
  background:#ffffff0d;box-shadow:inset 0 0 0 1px #ffffff1f;
  color:#dbe3ee;font-family:var(--cond);font-size:10px;
  font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  transition:box-shadow .2s ease,background .2s ease}
.pk-btn:hover{background:#ffffff14}
.pk-btn:active{background:#ffffff1f}
.pk-btn.on{background:#15803d33;box-shadow:inset 0 0 0 1px #7ee2a8,
  0 0 12px #7ee2a83d;color:#a8e6c1}
.pk-btn[disabled]{cursor:default;opacity:.8}
.pk-btn[disabled]:hover{background:#ffffff0d}
/* How the league split, shown behind the name once a pick is in. */
.pk-fill{position:absolute;left:0;top:0;bottom:0;background:#7ee2a814;
  pointer-events:none;transition:width .45s cubic-bezier(.22,.7,.3,1)}
.pk-btn.on .pk-fill{background:#7ee2a824}
.pk-row{position:relative;display:flex;align-items:center;
  justify-content:space-between;gap:6px;width:100%}
.pk-pct{font-size:12px;font-weight:700;letter-spacing:.02em;
  line-height:1;flex:0 0 auto;color:var(--muted)}
.pk-btn.on .pk-pct{color:#a8e6c1}
.pk-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* One banner for every page that names itself.
   
   The pages had three different title rules between them and the
   Free Agents page had none at all — its heading sat inline with a
   count. This is the single shape they all use now. */
.pagebanner{flex:0 0 auto;box-sizing:border-box;
  /* A band across the page, directly under the top bar.
     
     It sits outside <main> now rather than inside it. The negative
     margin it used before assumed the parent was padded evenly on
     both sides, and it is not — which is why one page had a gap on
     the left and another on the right. As a sibling of the header it
     is simply full width, with nothing to escape from. */
  width:100%;margin:0 0 10px;
  padding:9px 14px;border-radius:0;
  background:var(--red);
  display:flex;align-items:center;justify-content:center;gap:10px;
  font-family:var(--cond);font-size:15px;font-weight:700;
  letter-spacing:.2em;text-transform:uppercase;color:#fff;
  text-align:center}
/* A count or a second figure beside the name, quieter than it. */
.pagebanner .pagebanner-sub{font-size:11px;letter-spacing:.12em;
  color:#ffffffc4}
/* Free Agents pads its sticky block 14px from the top, which is
   right when the banner is above it rather than inside it. */
.fahead{padding-top:10px}

/* The drawer names the league, with the same mark the banner carries. */
.drawer-brand{display:flex;align-items:center;gap:8px;min-width:0}
.drawer-brand b{font-family:var(--cond);font-size:15px;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:#fff}
.drawer-mark{width:22px;height:22px;flex:0 0 auto;color:var(--red)}
.drawer-mark svg{width:100%;height:100%;display:block}

/* What each run of links is for. Quiet enough to be read as a label
   rather than as another link — the rule above it already separates
   the groups, so this only has to name them. */
.drawer-section{padding:2px 16px 6px;
  font-family:var(--cond);font-size:9px;font-weight:700;
  letter-spacing:.18em;text-transform:uppercase;color:var(--muted)}
.drafthist-card{flex:1 1 auto;min-height:0;display:flex;
  flex-direction:column}
.drafthist-body{flex:1 1 auto;min-height:0;overflow-y:auto;
  overscroll-behavior:contain;padding:4px 0 20px}
body:has(.drafthist){height:100dvh;min-height:100dvh;
  overflow:hidden;position:fixed;top:0;left:0;width:100%;
  display:flex;flex-direction:column}

/* On a wide screen the rounds go into columns rather than one long
   run — twelve picks a round leaves a page mostly empty otherwise.
   
   CSS columns rather than a grid: a round is a variable height and
   break-inside:avoid is already on it, so the browser fills the
   columns evenly and never splits a round across two. */
@media (min-width:900px){
  .drafthist{max-width:1500px}
  .drafthist .draftboard{column-width:300px;column-gap:22px;
    display:block}
  .drafthist .dround{display:inline-flex;width:100%;
    margin:0 0 18px}
}
@media (min-width:1400px){
  .drafthist{max-width:1800px}
  .drafthist .draftboard{column-width:320px;column-gap:26px}
}

/* The two tabs on this page.
   
   Their own class rather than .newstab: that one is defined later in
   the file and inside a media query, so it won its colour, its radius
   and its side back however these were written. Nothing is inherited
   from it now. */
.sidetab{position:fixed;top:50%;z-index:70;
  transform:translateY(-50%);
  display:flex;flex-direction:column;align-items:center;gap:7px;
  padding:14px 7px 12px;
  -webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);
  color:#fff;cursor:pointer;
  font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;
  transition:var(--railmove)}
.sidetab-word{writing-mode:vertical-rl;color:#fff}
.sidetab-arrow{font-size:15px;line-height:1;color:#fff;
  transition:var(--railmove)}

/* Blue glass, flat against the right edge. */
.linetab{right:0;left:auto;
  border:1px solid rgba(93,150,214,.6);border-right:0;
  border-radius:11px 0 0 11px;
  background:rgba(29,76,134,.62);
  box-shadow:-4px 0 18px #0006}
/* Blue glass, flat against the left — the rounded corners on the
   inside, mirroring the gold one rather than repeating it. */
.chattab{left:0;right:auto;
  border:1px solid rgba(93,150,214,.6);border-left:0;
  border-radius:0 11px 11px 0;
  background:rgba(29,76,134,.62);
  box-shadow:4px 0 18px #0006}

body.line-open .linetab{transform:translateY(-50%)
  translateX(calc(-1 * var(--railw)))}
body.chat-open .chattab{transform:translateY(-50%)
  translateX(var(--railw))}
body.line-open .linetab .sidetab-arrow,
body.chat-open .chattab .sidetab-arrow{transform:rotate(180deg)}

/* Unread: the whole tab pulses red, since a dot on the screen's
   edge is easy to miss. */
@keyframes chatnudge{
  0%,100%{border-color:rgba(93,150,214,.6);
    background:rgba(29,76,134,.62)}
  50%{border-color:var(--red);background:rgba(122,26,38,.66)}}
.chattab.has-unread{animation:chatnudge 1.3s ease-in-out infinite}

.chattab-dot{position:absolute;top:6px;right:6px;
  width:8px;height:8px;border-radius:50%;background:var(--red);
  animation:chatblink 1.1s ease-in-out infinite}
@keyframes chatblink{0%,100%{opacity:1}50%{opacity:.2}}

/* A message: who said it, then what they said. Mine to the right,
   everyone else to the left. */
.chat-row{display:flex;flex-direction:column;gap:3px;margin-bottom:10px}
.chat-row.is-mine{align-items:flex-end}
.chat-row.is-them{align-items:flex-start}
.chat-who{display:flex;align-items:center;gap:6px}
.chat-row.is-mine .chat-who{flex-direction:row-reverse}
.chat-face{width:20px;height:20px;border-radius:50%;overflow:hidden;
  background:var(--ink);flex:0 0 auto;display:flex;
  align-items:center;justify-content:center}
.chat-face img{width:100%;height:100%;object-fit:cover}
.chat-name{font-family:var(--cond);font-size:8.5px;font-weight:700;
  letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
.chat-said{max-width:82%;padding:7px 10px;border-radius:11px;
  font-size:13px;line-height:1.35;
  background:var(--slate-2);border:1px solid var(--line)}
.chat-row.is-mine .chat-said{background:#173049;border-color:#2c4a6b}
/* Mine in the league's own red. Stated after the line above rather
   than before it — the two have the same weight, so the later one
   wins and my first attempt was simply ignored. */
.chat-row.is-mine .chat-said{background:#7e2a26;
  border-color:#a03a33;color:#f6ded9}
.chat-row.is-mine .chat-name{color:#e0a49c}
/* Lifted clear of the home indicator and the screen's own corner
   rounding, which was clipping the Send button. */
.chat-form{flex:0 0 auto;display:flex;gap:7px;
  padding:9px 12px calc(16px + env(safe-area-inset-bottom, 0px));
  border-top:1px solid var(--line)}
/* 16px exactly: iOS zooms the page in on any input smaller than
   that when it takes focus, and there is no way to refuse it other
   than not being smaller. */
.chat-text{flex:1 1 auto;min-width:0;padding:9px 11px;border-radius:9px;
  background:var(--slate-2);border:1px solid var(--line);
  color:var(--text);font:inherit;font-size:16px}
.chat-text:focus{outline:none;border-color:#3a5f7d}
.chat-send{flex:0 0 auto;padding:8px 14px;border-radius:9px;
  background:var(--red);border:0;color:#fff;cursor:pointer;
  font-family:var(--cond);font-size:10px;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase}
/* Each owner a card, and the twelve share the height between them so
   the last one reaches the foot. */
.lt-row{flex:1 1 0;min-height:34px;
  display:grid;grid-template-columns:20px 26px minmax(0,1fr) 46px 34px;
  align-items:center;gap:9px;padding:0 8px;margin-bottom:4px;
  border-radius:8px;
  background:var(--slate-2);border:1px solid var(--line)}
/* The heading is a label, not a card. */
.lt-head{flex:0 0 auto;min-height:0;margin-bottom:5px;
  background:none;border:0;padding:0 8px;
  font-family:var(--cond);letter-spacing:.16em;
  text-transform:uppercase;color:var(--muted)}
/* Owner, Proj and Left all one size, as headings of a table are. */
.lt-head .lt-name,.lt-head .lt-proj,.lt-head .lt-left{
  font-family:var(--cond);font-size:8.5px;font-weight:700;
  letter-spacing:.16em;color:var(--muted)}

/* The cut, and everything under it in red rather than grey — out on
   this week's projections, and the colour says which way. */
.lt-row.is-cut{margin-top:9px;position:relative}
.lt-row.is-cut::before{content:"";position:absolute;
  left:0;right:0;top:-6px;height:2px;background:var(--red)}
.lt-row.is-out{background:#2a1418;border-color:#7f1d1d59;
  color:#e0a0a6}
/* Grey first, then a red wash over it.
   
   sepia() was the wrong tool: it makes everything yellow-brown
   before anything else happens, so a white background came out
   cream. Desaturating and laying red over in multiply leaves the
   photograph readable and genuinely red. */
.lt-row.is-out .lt-face{position:relative;filter:grayscale(1)}
.lt-row.is-out .lt-face::after{content:"";position:absolute;inset:0;
  background:#c8404f;mix-blend-mode:multiply;pointer-events:none}
.lt-row.is-out .lt-no,.lt-row.is-out .lt-proj{color:#e0707c}
.lt-no{font-family:var(--cond);font-size:10px;font-weight:700;
  color:var(--muted);text-align:right}
.lt-face{width:26px;height:26px;border-radius:50%;overflow:hidden;
  background:var(--ink);display:flex;align-items:center;
  justify-content:center}
.lt-face img{width:100%;height:100%;object-fit:cover}
.lt-init{font-family:var(--cond);font-size:8px;color:var(--muted)}
.lt-name{font-size:14.5px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
/* The two figures match each other. */
.lt-proj{font-size:13.5px;font-weight:700;text-align:right}
.lt-left{font-size:13.5px;font-weight:700;color:var(--muted);
  text-align:right}

.mu-head{flex:0 0 auto;width:100%;max-width:900px;padding:10px 8px;
  position:relative;
  /* The washes reach past the page's edges, so this must not clip
     them — .mu still does, which keeps the page from scrolling
     sideways. */
  overflow:visible;
  /* The line between the two owners and the men they are fielding.
     Neutral, with a coloured length growing out from the middle
     toward whichever side is more likely to win. */
  border-bottom:1px solid var(--line)}
/* A plain rule, and a wash falling from beneath the owners.
   
   Hung off .mu-teams rather than the header: the header's ::before
   and ::after are already the two edge washes, and putting it there
   silently replaced one of them. From the teams row it starts where
   the owners end, which is where the glow should come from. */
.mu-teams::after{content:"";position:absolute;left:-8px;right:-8px;
  top:calc(100% + 11px);height:30px;pointer-events:none;z-index:0;
  background:linear-gradient(180deg,#1d4c8633,transparent)}

/* A wash in from each edge: green where that side is projected to
   finish in the week's top six, red where it is not. Top six of
   twelve is the half that would make the playoffs. */
.mu-side{position:relative}
/* Behind the side's own content, not behind the page: without a
   stacking context of its own the negative z-index would put this
   under .mu and it would never be seen. */
/* The washes are drawn on the HEADER, not on each side.
   
   A side's own box is inset and not centred in the page, so an edge
   anchored to it never reached the screen. The header spans the full
   width, so a gradient on it lands where the page ends — solid at
   the edge, gone by halfway across. */
.mu-side{isolation:isolate}
.mu-head::before,.mu-head::after{
  content:"";position:absolute;top:0;bottom:0;width:50%;
  z-index:0;pointer-events:none;opacity:0;
  transition:opacity .3s ease}
.mu-head::before{left:calc(50% - 50vw)}
.mu-head::after{right:calc(50% - 50vw)}
.mu-head.l-top::before,.mu-head.l-low::before,
.mu-head.r-top::after,.mu-head.r-low::after{opacity:1}
/* The owners sit above their wash. */
.mu-teams{position:relative;z-index:1}

.mu-head.l-top::before{
  background:linear-gradient(90deg,#15803d8f 0%,#15803d38 46%,
    transparent 100%)}
.mu-head.l-low::before{
  background:linear-gradient(90deg,#7f1d1d9e 0%,#7f1d1d42 46%,
    transparent 100%)}
.mu-head.r-top::after{
  background:linear-gradient(270deg,#15803d8f 0%,#15803d38 46%,
    transparent 100%)}
.mu-head.r-low::after{
  background:linear-gradient(270deg,#7f1d1d9e 0%,#7f1d1d42 46%,
    transparent 100%)}
/* The same five columns the rows below use, so each side's total
   sits over the scores that make it and the VS sits over the slot
   labels. The owner block takes the outer column and shrinks to
   leave the figures their room. */
.mu-teams{display:grid;
  grid-template-columns:minmax(0,1fr) 52px 46px 52px minmax(0,1fr);
  align-items:center;gap:6px}
/* Two grid items a side: who he is in the outer column, his two
   figures in the score column. display:contents would have scattered
   the arrow, the face and the text as five separate items needing
   five column rules — this keeps the pieces together. */
.mu-side{grid-column:1;display:flex;align-items:center;gap:8px;
  min-width:0;overflow:hidden}
.mu-side.mu-right{grid-column:5;justify-content:flex-end}
.mu-sums{grid-column:2;display:flex;flex-direction:column;
  align-items:center;line-height:1.05}
.mu-sums.mu-right{grid-column:4}
/* The week's best projection, starred on the corner of his own
   photograph. */
.mu-oface.is-best::after{content:"\2605";position:absolute;
  top:-5px;left:-5px;z-index:2;
  font-size:14px;line-height:1;color:var(--gold);
  text-shadow:0 1px 3px #000, 0 0 6px #0009;pointer-events:none}
.mu-oface{position:relative;overflow:visible;
  width:30px;height:30px;flex:0 0 auto;border-radius:50%;
  overflow:hidden;background:var(--ink);display:flex;
  align-items:center;justify-content:center}
.mu-oface img{width:100%;height:100%;object-fit:cover;
  border-radius:50%}
.mu-oinit{font-family:var(--cond);font-size:14px;font-weight:700;
  color:var(--muted)}
/* Name and record on the left of the block, the two figures on the
   right of it — so the total sits on the name's line and the
   projection on the record's. */
.mu-otext{display:flex;flex-direction:column;gap:1px;min-width:0}
/* The right side reads inward: its name, record and value all sit
   against the photograph rather than against the middle. */
.mu-right .mu-oname{justify-content:flex-end}
.mu-right .mu-rec,.mu-right .mu-worth{text-align:right}
.mu-right .mu-oname,.mu-right .mu-rec,.mu-right .mu-worth{
  justify-self:end}
.mu-oname{display:flex;align-items:center;gap:4px;min-width:0}
/* The name clips rather than running into the totals beside it. The
   parents need min-width:0 too, or a flex child refuses to shrink
   below its content and pushes instead. */
.mu-oname{min-width:0;overflow:hidden}

/* On the right, the text block takes the room left over and the name
   reads from its left edge — pushed right by justify-content it
   started against the photograph and ran the other way into the
   totals, so the ellipsis fell on the wrong end. */
.mu-right .mu-otext{flex:1 1 auto;min-width:0;align-items:stretch}
/* The two lines under the name keep to the same left edge as it. */
.mu-right .mu-rec,.mu-right .mu-worth{align-self:flex-start}
.mu-right .mu-oname{justify-content:flex-start}
.mu-right .mu-oname b{text-align:left;width:100%}
.mu-right .mu-rec,.mu-right .mu-worth{text-align:left}
.mu-oname b{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  min-width:0;
  font-family:var(--cond);font-size:8.5px;font-weight:700;
  letter-spacing:.08em;text-transform:uppercase;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mu-arrow{flex:0 0 auto;border:0;background:none;cursor:pointer;
  color:var(--muted);font-size:22px;line-height:1;padding:2px 4px}
.mu-arrow:hover{color:var(--text)}
.mu-arrow:active{transform:translateY(1px)}
.mu-rec{font-family:var(--cond);font-size:9.5px;letter-spacing:.14em;
  color:var(--muted)}
/* What the ten on the field are being paid. */
.mu-worth{font-family:var(--cond);font-size:8.5px;letter-spacing:.1em;
  text-transform:uppercase;color:#fff}
.mu-gap{display:block}
/* The two totals sit in the score columns, directly over the figures
   that make them up. */
.mu-totrow{padding-bottom:8px;margin-bottom:4px}
.mu-sum{gap:0}
.mu-total{font-size:19px;font-weight:700;line-height:1.1}
/* The summary's projection, larger than the players' own below —
   it is a total, and should read as one. */
/* Smaller than it was: the total above is the headline, and the
   fourth-quarter share now sits under this. */
.mu-ptotal{font-family:var(--cond);font-size:13px;font-weight:700;
  color:var(--muted)}
/* How much of it came late. */
.mu-q4{font-family:var(--cond);font-size:9px;font-weight:700;
  letter-spacing:.08em;color:#8fd0f7}
/* Favoured on the projections, and not. The figure being compared
   is the one that carries the colour. */
/* The projection moved out of .mu-otext into its own block, so this
   is scoped to the class itself rather than to a parent it no longer
   has — it would simply have stopped applying. */
.mu-ptotal.is-fave{color:#7ee2a8;font-weight:700}
.mu-ptotal.is-dog{color:#c8404f;font-weight:700}

/* The day a fixture is played on. Thursday and Monday are the two
   that catch people out, so they are the two that are coloured. */
.mu-day{font-weight:700}
.mu-day.d-thu{color:#5b9ce0}
.mu-day.d-sun{color:#8b95a6}
.mu-day.d-mon{color:#3fbfa8}
.mu-day.d-odd{color:#a982e0}
.mu-totslot{background:none;color:var(--muted);font-size:8.5px}
/* The VS, between the two totals: the hammer behind it in the
   league's red, and no plate around either. */
.mu-vs{grid-column:3;justify-self:center;position:relative;
  display:flex;align-items:center;justify-content:center;
  width:52px;height:46px}
/* The shadow stays: it lifts the letters off whatever is behind
   them, which is now the page rather than a mark. */
.mu-vstext{position:relative;z-index:1;
  font-family:var(--cond);font-size:19px;font-weight:700;
  letter-spacing:.04em;color:#fff;
  text-shadow:0 1px 2px #000, 0 0 8px #000c, 0 0 3px #000}

/* The season, folded away at the foot — it opens in place rather
   than covering the page. */
/* The tab is at the foot and the sheet grows upward from it, over
   the board rather than below it — a fold that pushed the board up
   would move what somebody was reading.
   
   The tab is first and the sheet second, in an ordinary column
   anchored at the bottom — so the tab sits on top of the sheet and
   the pair rise together as it opens. Column-reverse would have put
   the tab underneath, which is the wrong way round. */
/* A strip below the tab in the page's own colour, so the tab has
   something to sit on rather than a line at the very edge. Half what
   it was. */
/* The strip the tab sits on. Deep enough that the tab is clear of
   the screen edge — 7px put it hard against it, 14 was too much, so
   this sits between. */
/* No strip at the foot any more: the schedule opens from the banner,
   so nothing sits down there to need a shelf. */

.mu-fold{position:absolute;left:0;right:0;bottom:22px;z-index:60;
  width:100%;max-width:900px;margin:0 auto;
  display:flex;flex-direction:column;align-items:center;
  padding:0;box-sizing:border-box;pointer-events:none}
.mu-fold > *{pointer-events:auto}
.mu{position:relative}
/* The tab stays fixed to the top edge of the sheet: column-reverse
   puts the sheet above it in the flow, so as the sheet grows the tab
   is carried up with it rather than staying at the foot. */
.mu-fold .mu-open{position:relative;z-index:2;margin-bottom:-1px}
/* Open, it runs from the tab up to the foot of the header — the whole
   page below the title, rather than a strip at the bottom. */
.mu-sheet{width:100%;max-height:0;overflow:hidden;
  /* The slate the top banner uses, solid — nothing shows through
     the card any more. */
  background:var(--slate);
  border-top:1px solid var(--red);
  border-radius:12px 12px 0 0;
  transition:max-height .34s cubic-bezier(.22,.7,.3,1)}
.mu-fold.on .mu-sheet{overflow-y:auto;overscroll-behavior:none;
  padding:10px 8px 14px;box-sizing:border-box}
.mu-chev{transition:transform .3s cubic-bezier(.22,.7,.3,1)}
.mu-fold.on .mu-chev{transform:rotate(180deg)}

/* The same glass the news tab uses, and straight where it meets the
   foot of the screen — a tab pulled up from the edge rather than a
   button floating above it. */
/* The tab in the sheet's own colour, so the two read as one piece
   rather than a button sitting on a card. */
.mu-open{flex:0 0 auto;margin:0 auto;display:flex;
  align-items:center;gap:7px;padding:9px 22px 11px;
  border:1px solid #2a3546;border-bottom:0;
  border-radius:11px 11px 0 0;
  /* The banner's own red, solid — no glass, nothing showing
     through. */
  background:var(--red);
  box-shadow:0 -4px 18px #0006;
  color:#fff;cursor:pointer;
  font-family:var(--cond);font-size:10px;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase}
.mu-open:hover{filter:brightness(1.12)}
.mu-open svg{width:14px;height:14px}
.mu-sheethead{display:flex;justify-content:center;padding:0 0 8px}
.mu-sheetbody{padding:0 0 8px}

/* The schedule as a card, in the shape the banner's others use. */
.mu-schedcard{width:min(560px,100%);max-height:82dvh;
  display:flex;flex-direction:column}
.mu-schedpick{flex:0 0 auto;padding:10px 12px 0}
.mu-schedcard .mu-owner{max-width:100%}
.mu-schedcard .mu-sheetbody{flex:1 1 auto;min-height:0;
  overflow-y:auto;overscroll-behavior:contain;padding:10px}

/* A week, in the same shape as the board above it. */
.mu-wk{display:grid;
  grid-template-columns:minmax(0,1fr) 86px minmax(0,1fr);
  align-items:center;gap:8px;width:100%;
  padding:7px 10px;margin-bottom:4px;border-radius:9px;
  /* A shade up from the card, as a row on slate should be. */
  background:var(--slate-2);border:1px solid var(--line);
  color:var(--text);cursor:pointer;text-align:left}
.mu-wk.on{border-color:var(--red);background:#1b2536}
.mu-wkside{display:flex;align-items:center;gap:7px;min-width:0}
.mu-wkside.mu-right{justify-content:flex-end}
.mu-wkface{width:26px;height:26px;flex:0 0 auto;border-radius:50%;
  overflow:hidden;background:var(--ink);display:flex;
  align-items:center;justify-content:center}
.mu-wkface img{width:100%;height:100%;object-fit:cover}
.mu-wkface .mu-oinit{font-size:9px}
.mu-wktext{font-size:12px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.mu-wkmid{display:flex;flex-direction:column;align-items:center;
  gap:1px;text-align:center}
.mu-wkmid b{font-family:var(--cond);font-size:10px;font-weight:700;
  letter-spacing:.12em;text-transform:uppercase}
.mu-wknote{font-family:var(--cond);font-size:9px;color:var(--muted)}
.mu-wk.is-po .mu-wknote{color:#f0cd6a}
.mu-wk.is-tbd .mu-wknote{color:#6b7688}

/* The board. One row a slot: his man on the left, the slot in the
   middle, theirs on the right. */
/* The board takes what is left and scrolls; the button below it
   keeps its place at the foot rather than being pushed off by a long
   bench. */
.mu-board{flex:1 1 auto;min-height:0;width:100%;max-width:900px;
  /* The offset parent for the rows inside it: sizeBenchPush reads
     offsetTop to place the bench without depending on scroll, and
     that is only measured from here if this is positioned. */
  position:relative;
  /* overflow-x stated: overflow-y alone makes the other axis auto
     too, and the full-width rule below would then add a sideways
     scrollbar. */
  overflow-y:auto;overflow-x:hidden;overscroll-behavior:none;
  /* Less at the foot: the bench heading is measured to sit just
     inside this edge, and a deep pad pushed it out of view. */
  padding:14px 8px 8px;box-sizing:border-box;
  /* Rows fade out before they reach the owners rather than sliding
     under them — the mask thins the top 30px to nothing, and stays
     at the top edge as content scrolls through it. */
  -webkit-mask-image:linear-gradient(180deg,transparent 0,
    #000 30px,#000 100%);
  mask-image:linear-gradient(180deg,transparent 0,#000 30px,#000 100%)}
/* A stated height, not one that follows its contents.
   
   A card is three lines with a fixture and two without, so an empty
   slot, a bye or a missing badge made that row shorter — and ten
   rows came to a different total on every matchup, which is why the
   board shifted when the arrows were pressed. */
.mu-row{display:grid;
  grid-template-columns:minmax(0,1fr) 52px 46px 52px minmax(0,1fr);
  align-items:center;gap:6px;padding:0;position:relative;
  height:var(--rowh,54px);box-sizing:border-box}
/* A hairline between one row and the next, faded at both ends so it
   reads as a separator rather than a border. Never on the first of a
   run, so the bench — which the heading separates from the starters
   — begins clean too. */
.mu-row + .mu-row::before{
  content:"";position:absolute;left:8%;right:8%;top:0;height:1px;
  background:linear-gradient(90deg,transparent,#ffffff1a 22%,
    #ffffff1a 78%,transparent)}

.mu-man{display:flex;align-items:center;gap:8px;min-width:0}
.mu-man.mu-right{justify-content:flex-end;text-align:right}
.mu-face{width:34px;height:34px;flex:0 0 auto;border-radius:50%;
  overflow:hidden;background:var(--ink)}
.mu-face img{width:100%;height:100%;object-fit:cover;
  object-position:top center}
.mu-text{display:flex;flex-direction:column;min-width:0;gap:1px}
.mu-right .mu-text{align-items:flex-end}
.mu-name{font-size:12.5px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;min-width:0}
.mu-line{display:flex;align-items:center;gap:4px;
  font-family:var(--cond);font-size:8.5px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted)}
.mu-pos{font-weight:700}
.mu-pos.pos-QB{color:var(--pos-qb)}
.mu-pos.pos-RB{color:var(--pos-rb)}
.mu-pos.pos-WR{color:var(--pos-wr)}
.mu-pos.pos-TE{color:var(--pos-te)}
.mu-club{width:12px;height:12px;object-fit:contain}
/* Opponent, day and time on one line. Smaller and tighter than the
   name above it, and it will not wrap — a fourth line would push
   every row taller. */
.mu-fx{display:flex;align-items:center;gap:3px;min-width:0;
  font-family:var(--cond);font-size:8px;letter-spacing:.04em;
  text-transform:uppercase;color:#6b7688;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mu-right .mu-fx{flex-direction:row-reverse}
.mu-fx > span{flex:0 0 auto}
/* At home or away, in a word of one or two letters. */
.mu-at{font-weight:700}
.mu-at.is-home{color:#7ee2a8}
.mu-at.is-away{color:#e0707c}
.mu-empty{color:#5a6577}

/* His designation, as a letter beside the name and a wash behind the
   card. The wash is what does the work — a letter has to be found,
   where a tinted row is seen. */
.mu-named{display:flex;align-items:center;gap:5px;min-width:0}
.mu-right .mu-named{flex-direction:row-reverse}
.mu-flag{flex:0 0 auto;font-family:var(--cond);font-size:8px;
  font-weight:700;letter-spacing:.06em;padding:1px 4px;
  border-radius:4px;line-height:1.4}
.mu-man.is-p{background:linear-gradient(90deg,#15803d5c,#15803d1a 62%,transparent)}
.mu-man.is-q{background:linear-gradient(90deg,#a1620066,#a162001f 62%,transparent)}
.mu-man.is-d{background:linear-gradient(90deg,#9a3d0070,#9a3d0022 62%,transparent)}
.mu-man.is-o{background:linear-gradient(90deg,#7f1d1d85,#7f1d1d2b 62%,transparent)}
/* Mirrored, so the wash runs inward on both sides. */
.mu-man.mu-right.is-p{background:linear-gradient(270deg,#15803d5c,#15803d1a 62%,transparent)}
.mu-man.mu-right.is-q{background:linear-gradient(270deg,#a1620066,#a162001f 62%,transparent)}
.mu-man.mu-right.is-d{background:linear-gradient(270deg,#9a3d0070,#9a3d0022 62%,transparent)}
.mu-man.mu-right.is-o{background:linear-gradient(270deg,#7f1d1d85,#7f1d1d2b 62%,transparent)}
.mu-flag.is-p{background:#15803d33;color:#7ee2a8}
.mu-flag.is-q{background:#a1620033;color:#f0cd6a}
.mu-flag.is-d{background:#9a3d0033;color:#f2ab6d}
.mu-flag.is-o{background:#7f1d1d33;color:#f0918b}
/* The name clips already, but only if its parents will let it: a
   flex or grid child will not shrink below its content unless told
   to, so the text pushed the whole card into the scores instead of
   truncating. */
.mu-man{border-radius:8px;padding:3px 4px;min-width:0;overflow:hidden}
.mu-text{min-width:0;overflow:hidden}

/* A game in progress.
   
   No border at all when his side does not have the ball — the
   absence is the signal. Green when they do, red and pulsing inside
   the twenty. The border is drawn inset rather than as a real border
   so the row height does not change when one appears. */
.mu-man.is-live{border-radius:9px}
.mu-man.has-ball{box-shadow:inset 0 0 0 1.5px #7ee2a8cc;
  background:linear-gradient(90deg,#15803d1f,#15803d08)}
.mu-man.in-red{box-shadow:inset 0 0 0 1.5px #e0707c;
  background:linear-gradient(90deg,#7f1d1d2e,#7f1d1d0f);
  animation:redzone 1.4s ease-in-out infinite}
@keyframes redzone{
  0%,100%{box-shadow:inset 0 0 0 1.5px #e0707ccc}
  50%{box-shadow:inset 0 0 0 2px #ff5f6e, 0 0 12px #e0707c66}}
.mu-livetext{font-weight:700;color:#dbe3ee}
.mu-man.has-ball .mu-livetext{color:#a8e6c1}
.mu-man.in-red .mu-livetext{color:#f0a8ae}
.mu-liveclock{color:var(--muted)}

/* On a bye: drained of colour, with a grey wash behind him, so a
   week he cannot score in reads as one at a glance. */
/* The wash starts at his own edge and is gone before the middle, so
   it does not run into the figures. Each side fades inward. */
.mu-man.is-bye{position:relative}
/* mu-left and mu-right are on the card itself, not on a wrapper —
   so these are one element, not a descendant. */
.mu-man.mu-left.is-bye{
  background:linear-gradient(90deg,#8b95a630 0%,#8b95a614 45%,
    transparent 100%)}
.mu-man.mu-right.is-bye{
  background:linear-gradient(270deg,#8b95a630 0%,#8b95a614 45%,
    transparent 100%)}
.mu-man.is-bye .mu-face,.mu-man.is-bye .mu-club{filter:grayscale(1)}
.mu-man.is-bye .mu-name{color:#8b95a6}
/* The position on his own line is coloured by pos-QB and the rest;
   those carry a colour of their own, so this has to be specific
   enough to beat them. */
.mu-man.is-bye .mu-pos[class]{color:#8b95a6}
.mu-man.is-bye .mu-line,.mu-man.is-bye .mu-dot{color:#8b95a6}
.mu-byeword{font-family:var(--cond);font-size:9px;font-weight:700;
  letter-spacing:.16em;color:#8b95a6}

/* A slot loses its position colour when neither side has anybody
   playing — a bright green RB above two greyed-out players read as
   a mistake, but greying it for one of them would mislabel the
   other, since the pill belongs to both. */
.mu-row.is-bye .mu-slot{background:#3a4150;color:#0b1220}
.mu-row.is-bye .mu-slot::before{opacity:.35}

/* The drag-and-drop lineup styles stood here — the ghost that
   followed a finger, the drop markers, and the touch-action that
   stopped the board scrolling under a held card. Setting a lineup is
   a tap and a list now, so none of them has anything to attach to. */

/* A player opens his card. */
.mu-man.can-open{cursor:pointer}
.mu-man.can-open:hover{background-color:#ffffff0f}
.mu-man.can-open:active{transform:translateY(1px)}

/* The bench, below the starters. */
/* Pushes the bench to the foot of the screen so the starters have
   the view to themselves.
   
   A measured height rather than flex-grow: .mu-board is a scroller,
   and a flex child inside one grows to the content's height, not the
   box's — the spacer would have been zero every time. The script
   sets --benchpush from what the starters actually left. */
.mu-benchpush{flex:0 0 auto;height:var(--benchpush,0px);
  transition:height .3s ease}

/* A red glow falling from the rule under the starting lineup. The
   rule reaches the screen's edges rather than the board's, so it
   reads as a division of the page. */
.mu-benchhead{position:relative;margin:14px 0 4px;padding-top:10px;
  border-top:0;text-align:center;
  font-family:var(--cond);font-size:9px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--muted)}
.mu-benchhead::before{content:"";position:absolute;top:0;height:1px;
  left:calc(50% - 50vw);width:100vw;
  background:var(--red);pointer-events:none}
.mu-benchhead::after{content:"";position:absolute;top:0;height:26px;
  left:calc(50% - 50vw);width:100vw;pointer-events:none;
  background:linear-gradient(180deg,#c8404f3d,transparent)}

.mu-benchrow{opacity:.82;height:var(--benchh,48px)}

/* What he scored, over what he was projected for. */
.mu-score{display:flex;flex-direction:column;align-items:center;
  line-height:1.1}
.mu-got{font-size:14px;font-weight:700}
/* The projection is the figure being read before a game is played,
   so it carries weight rather than sitting as a footnote. */
/* The projection and his rank share this spot, one showing at a
   time. Stacked rather than swapped in the DOM, so the box holds
   its width and the column does not jump as they turn over. */
/* Bigger, brighter and less tightly set than they were — these are
   figures being read at arm's length on a phone. */
/* Smaller than the score above it, and smaller than the totals in
   the summary — those are the headline figures, these are the
   supporting ones. */
.mu-proj{position:relative;display:inline-flex;
  font-family:var(--cond);font-size:12.5px;font-weight:700;
  letter-spacing:.02em;color:#aab4c4;min-height:1em}
/* Both faces stay stacked and absolutely positioned all the time.
   
   The showing one used to switch to position:relative, which moved
   it in the same instant its opacity changed — so the box jumped
   rather than the text fading. The parent holds the height instead,
   and only opacity ever moves. */
.mu-flip{position:absolute;left:0;right:0;top:0;
  opacity:0;pointer-events:none;white-space:nowrap;
  transition:opacity .38s ease}

.mu-flip.is-on{opacity:1}
/* One face is always absolute now, so the box needs its own height
   and width — taken from a hidden copy of the longer of the two. */
/* The two faces sit under the score and share its centre. The box
   spans the column's full width, so without this the figure inside
   it drifted away from the number above. */
.mu-proj.has-two{min-width:34px}
.mu-score .mu-flip{text-align:center}
.mu-right .mu-proj .mu-flip,
.mu-left .mu-proj .mu-flip{text-align:center}
.mu-proj.has-two::after{content:attr(data-wide);visibility:hidden;
  white-space:nowrap}
/* The rank in sky blue, so a glance tells the two apart. */
.mu-flip.mu-rank{color:#8fd0f7;letter-spacing:.04em}
/* Pressable, and it should look it. */
.mu-proj.has-two{cursor:pointer;padding:2px 4px;margin:-2px -4px;
  border-radius:6px}
.mu-proj.has-two:hover{background:#ffffff0f}
.mu-proj.has-two:active{background:#ffffff1a}

/* The slot, down the middle. */
/* The slot down the middle, in the colour that position wears
   everywhere else. FLEX is gold and OP orange — neither is a real
   position, so neither has a colour of its own to borrow. */
/* Glass rather than flat paint: the position's colour sits under a
   light sheen with a soft edge, so a slot reads as a button. */
.mu-slot{position:relative;overflow:hidden;
  text-align:center;font-family:var(--cond);font-size:11.5px;
  font-weight:700;letter-spacing:.04em;color:#0b1220;
  background:#0f1a2c;border-radius:7px;padding:5px 0;
  border:1px solid #ffffff2e;
  box-shadow:inset 0 1px 0 #ffffff5c, inset 0 -2px 6px #0000003d,
             0 1px 3px #0006}
.mu-slot::before{content:"";position:absolute;inset:0 0 52% 0;
  background:linear-gradient(180deg,#ffffff59,#ffffff12);
  pointer-events:none}
.mu-slot.s-QB{background:var(--pos-qb)}
.mu-slot.s-RB{background:var(--pos-rb)}
.mu-slot.s-WR{background:var(--pos-wr)}
.mu-slot.s-TE{background:var(--pos-te)}
.mu-slot.s-FLEX{background:#d4a63c}
.mu-slot.s-OP{background:#e0803c}
/* A bench row names a position rather than a slot, and reads quieter
   than the starters above it. */
/* A bench row names a position rather than a slot, so it keeps the
   shape but not the shine. */
.mu-bslot{background:#0b1526;color:var(--muted);font-size:9px;
  border-color:#ffffff14;box-shadow:none}
.mu-bslot::before{display:none}
/* Pressable on your own lineup. */
/* His game has started: the slot cannot be changed, and says so
   quietly rather than looking like a button that does nothing. */
.mu-slot.is-locked{opacity:.72;cursor:default}
.mu-slot.can-pick{cursor:pointer;border:1px solid #ffffff14}
.mu-slot.can-pick:hover{background:#16263f;color:var(--text)}
.mu-slot.can-pick:active{transform:translateY(1px)}

/* Choosing a man for a slot. */
/* Choosing a man for a slot.
   
   The shape, corners, veil and animation come from .modal and
   .modal-card — these were a near-copy of them that had already
   drifted. Only what is particular to this card is set here. */
/* The week's other fixtures, from the VS in the middle. */
.mu-vs.can-open{cursor:pointer}
.mu-vs.can-open:active{transform:scale(.94)}
.mu-fixcard{width:min(460px,100%);display:flex;flex-direction:column}
.mu-fixlist{padding:8px 10px 12px}
.fx-row{display:grid;
  grid-template-columns:minmax(0,1fr) 44px 14px 44px minmax(0,1fr);
  align-items:center;gap:6px;width:100%;
  padding:7px 8px;margin-bottom:5px;border-radius:9px;
  background:var(--slate-2);border:1px solid var(--line);
  color:var(--text);cursor:pointer;text-align:left}
.fx-row:hover{border-color:#3a5f7d}

/* The same wash the header carries: green behind a side in the top
   six, red behind one below the line, fading out toward the middle.
   Drawn under the row's contents rather than as its background, so
   two different sides can be shown at once. */
.fx-row::before,.fx-row::after{content:"";position:absolute;
  top:0;bottom:0;width:52%;z-index:0;pointer-events:none;opacity:0;
  border-radius:9px}
.fx-row{position:relative;overflow:hidden}
/* The five real cells sit above the wash. `> *` does not match a
   pseudo-element, so this cannot pull ::before and ::after back into
   the grid — but the absolute positioning above is what keeps them
   out of it, and both are needed. */
.fx-row > .fx-side,.fx-row > .fx-nums,.fx-row > .fx-v{
  position:relative;z-index:1}
.fx-row::before{left:0}
.fx-row::after{right:0}
.fx-row.l-top::before,.fx-row.l-low::before,
.fx-row.r-top::after,.fx-row.r-low::after{opacity:1}
.fx-row.l-top::before{background:linear-gradient(90deg,#15803d70 0%,
  #15803d2b 48%,transparent 100%)}
.fx-row.l-low::before{background:linear-gradient(90deg,#7f1d1d7a 0%,
  #7f1d1d30 48%,transparent 100%)}
.fx-row.r-top::after{background:linear-gradient(270deg,#15803d70 0%,
  #15803d2b 48%,transparent 100%)}
.fx-row.r-low::after{background:linear-gradient(270deg,#7f1d1d7a 0%,
  #7f1d1d30 48%,transparent 100%)}

/* Yours, wherever the board is pointing — red, and always first. */
.fx-row.is-mine{border-color:var(--red)}
/* And the one on screen now — green, and not worth pressing. */
.fx-row.is-here{border-color:#7ee2a8;cursor:default}
/* Both at once is the usual case: the green border wins, since it
   says something about right now rather than about the season. */
.fx-row.is-mine.is-here{border-color:#7ee2a8}
.fx-side{display:flex;align-items:center;gap:6px;min-width:0;
  overflow:hidden}
.fx-side.fx-right{justify-content:flex-end}
.fx-face{width:22px;height:22px;flex:0 0 auto;border-radius:50%;
  overflow:hidden;background:var(--ink)}
.fx-face img{width:100%;height:100%;object-fit:cover}
.fx-who{display:flex;flex-direction:column;gap:1px;min-width:0;
  overflow:hidden}
.fx-right .fx-who{align-items:flex-end}
.fx-name{font-family:var(--cond);font-size:9px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* His record: the fixture and the victory point together. */
.fx-rec{font-family:var(--cond);font-size:8.5px;letter-spacing:.08em;
  color:var(--muted);white-space:nowrap}
/* What he has scored, and what he is projected for under it. */
.fx-nums{display:flex;flex-direction:column;align-items:center;
  line-height:1.1}
.fx-nums b{font-size:14px}
.fx-nums.is-up b{color:#7ee2a8}
.fx-proj{font-family:var(--cond);font-size:10px;color:var(--muted)}
.fx-v{font-family:var(--cond);font-size:9px;color:var(--muted);
  text-align:center}

.mu-pickcard{width:min(460px,100%);display:flex;flex-direction:column}
.mu-picklist{padding:8px 10px 12px}
/* The head is .modal-head; only the slot's own colour is added, and
   the class must beat that rule's own background — which is why
   these carry .modal-head too. */
.modal-head.mu-pickhead.s-QB{background:var(--pos-qb);color:#0b1220}
.modal-head.mu-pickhead.s-RB{background:var(--pos-rb);color:#0b1220}
.modal-head.mu-pickhead.s-WR{background:var(--pos-wr);color:#0b1220}
.modal-head.mu-pickhead.s-TE{background:var(--pos-te);color:#0b1220}
.modal-head.mu-pickhead.s-FLEX{background:#d4a63c;color:#0b1220}
.modal-head.mu-pickhead.s-OP{background:#e0803c;color:#0b1220}
.mu-pickhead[class*=" s-"] .modal-headname,
.mu-pickhead[class*=" s-"] .modal-x{color:#0b1220}

/* Who is where: a heading above each run of choices. */
.mu-picksec{margin:10px 4px 5px;font-family:var(--cond);font-size:8.5px;
  font-weight:700;letter-spacing:.16em;text-transform:uppercase;
  color:var(--muted)}
.mu-picklist > .mu-picksec:first-child{margin-top:2px}

/* What he adds over the man in the slot now. */
.mu-pickfigs{display:flex;align-items:center;gap:7px;justify-self:end}
/* The slot pill keeps the width it has in the middle of the board.
   Without this it shrank to fit its letters, so OP and QB came out
   narrow beside a FLEX. */
.mu-pickfigs .mu-slot{width:46px;flex:0 0 auto;padding:5px 0}
.mu-gain{font-family:var(--cond);font-size:11px;font-weight:700;
  color:#7ee2a8}
.mu-pickrow.is-better{border-color:#7ee2a880;background:#12241d}
.mu-pickrow.is-better:hover{border-color:#7ee2a8}

/* Where a bench man could start. */
.mu-spot{display:flex;align-items:center;gap:9px;min-width:0}
.mu-spot .mu-slot{width:46px;flex:0 0 auto;padding:5px 0}
.mu-spotwho{font-size:12px;color:var(--muted);overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.mu-picklist{flex:1 1 auto;min-height:0;overflow-y:auto;
  overscroll-behavior:none;padding:8px}
/* A row is the board's own card with its figures beside it. */
.mu-pickrow{display:grid;grid-template-columns:minmax(0,1fr) auto;
  align-items:center;gap:8px;width:100%;
  padding:5px 9px;margin-bottom:4px;border-radius:9px;
  background:var(--slate-2);border:1px solid var(--line);
  color:var(--text);cursor:pointer;text-align:left}
.mu-pickrow:hover{border-color:#3a5f7d;background:#16263f}
.mu-pickrow:active{transform:translateY(1px)}
/* Move him out without choosing a replacement. */
.mu-pickdrop{display:block;width:100%;margin:6px 0 2px;
  padding:9px 10px;border-radius:8px;
  background:#2a1a1f;border:1px solid #7f1d1d80;
  color:#f0918b;cursor:pointer;text-align:center;
  font-family:var(--cond);font-size:10px;font-weight:700;
  letter-spacing:.12em;text-transform:uppercase}
.mu-pickdrop:hover{border-color:#c8404f;background:#33202a}
.mu-pickdrop:active{transform:translateY(1px)}

.mu-none{margin:36px 0;text-align:center;color:var(--muted)}

/* On a week that is not the one being played, the betting line and
   the favourite mark come off the band — they are this week's
   figures and would be read as that week's. */
.mu.not-now .slate-ou,
.mu.not-now .slate-dot,
.mu.not-now .slate-side.is-fav::after{display:none}

/* Everything behind the open schedule goes soft — the slate, the
   week bar, the two owners and the board. Only the topbar stays
   sharp, since that is how you leave the page.
   
   Listing them one by one left the bar and the slate looking crisp
   against a blurred board; naming every child of .mu except the fold
   catches whatever else is added later too.
   
   The sheet's own backdrop-filter is dropped while this is on: a
   blur behind a blur composites badly, and the filter here already
   does the work. */
.mu > *{transition:filter .3s ease}
.mu.is-open > *:not(.mu-fold){filter:blur(4px);pointer-events:none}
/* The sheet keeps its own blur: it is what makes it read as glass,
   and the page behind it is blurred by the filter above rather than
   by a second backdrop-filter. */

/* Out and in, when the fixture changes.
   
   Slower coming in than going out — a new fixture arriving gently
   reads as a change; arriving at the same speed it left reads as a
   flicker. */
/* The whole page fades for a change of view. */
.mu{transition:opacity .42s ease}
.mu.is-going{opacity:0}

/* The tiles are anchors, so the browser underlines their text. They
   are not links to be read as links — the whole tile is the target. */
.slate-game,.slate-game:hover,.slate-game:visited{
  text-decoration:none;color:inherit}
.slate-game *{text-decoration:none}

.mu-head,.mu-board,.mu .slate{transition:opacity .5s ease}
.mu-head.is-going,.mu-board.is-going,
.mu .slate.is-going{opacity:0;transition:opacity .26s ease}

@media (max-width:560px){
  .mu-row{grid-template-columns:minmax(0,1fr) 40px 38px 40px minmax(0,1fr);
    gap:4px}
  .mu-face{width:28px;height:28px}
  .mu-name{font-size:11.5px}
}

/* Player statistics: a season's leaderboard, sortable.
   
   The same fixed frame the summit uses — page pinned, controls held,
   one scrolling table — and the same split the game log uses inside
   it, so the headings never lag. */
html:has(.stats){height:100%;overflow:hidden}
body:has(.stats){height:100dvh;min-height:100dvh;
  width:100%;max-width:100%;
  overflow:hidden;overscroll-behavior:none;
  position:fixed;top:0;left:0;
  display:flex;flex-direction:column}
body:has(.stats) .topbar{flex:0 0 auto}
.stats{width:100%;margin:0 auto;padding:0 8px;box-sizing:border-box;
  flex:1 1 auto;min-height:0;
  display:flex;flex-direction:column;overflow:hidden;
  align-items:center}
.stats-title{flex:0 0 auto;width:100%;margin:8px 0 10px;
  font-family:var(--cond);font-size:19px;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;text-align:center}
.stats-bar{flex:0 0 auto;width:calc(100% + 16px);
  display:flex;flex-direction:column;
  align-items:center;gap:7px;padding:0 0 9px;margin:0 -8px 8px;
  background:var(--ink);border-bottom:1px solid var(--line)}
.stats-search{width:min(320px,92%);padding:6px 11px;border-radius:8px;
  background:var(--slate-2);border:1px solid var(--line);
  color:var(--text);font:inherit;font-size:13px}
.stats-search:focus{outline:none;border-color:#3a5f7d}
.stats-pos,.stats-year{width:fit-content;max-width:100%;margin:0;
  overflow-x:auto;scrollbar-width:none}
.stats-pos::-webkit-scrollbar,
.stats-year::-webkit-scrollbar{display:none}
.st-b{flex:0 0 auto;white-space:nowrap}
/* Each position in its own colour when chosen, and the labels in
   the table to match — so a column of positions and the button that
   filtered it are plainly the same thing. */
.stats-pos .st-b.on{background:#1d4c86;color:#fff}
.stats-pos .st-b[data-pos="QB"].on{background:var(--pos-qb);color:#0b1220}
.stats-pos .st-b[data-pos="RB"].on{background:var(--pos-rb);color:#0b1220}
.stats-pos .st-b[data-pos="WR"].on{background:var(--pos-wr);color:#0b1220}
.stats-pos .st-b[data-pos="TE"].on{background:var(--pos-te);color:#0b1220}
.stats-pos .st-b[data-pos="ROOK"].on{background:#a83a6b;color:#fff}
.st-pos{font-weight:700}
.st-pos.pos-QB{color:var(--pos-qb)}
.st-pos.pos-RB{color:var(--pos-rb)}
.st-pos.pos-WR{color:var(--pos-wr)}
.st-pos.pos-TE{color:var(--pos-te)}
.st-fin{font-weight:700}
.stats-year .st-b.on{background:#a83a6b;color:#fff}
.stats-count{flex:0 0 auto;width:100%;max-width:1000px;
  margin:0 auto 6px;font-family:var(--cond);
  font-size:9px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);text-align:right}
.stats-none{margin:36px 0;text-align:center;color:var(--muted)}

/* The table: frozen name, position and club; everything else
   scrolls under them. */
.stats-table{flex:1 1 auto;min-height:0;width:100%;
  display:flex;flex-direction:column;align-items:center;
  overflow:hidden;padding-bottom:8px}
/* A column: the headings, then one box holding both halves' rows.
   
   Two scrollers tied together always left the follower a frame
   behind, because a scroll event fires after the paint. One box
   cannot lag behind itself.
   
   No wider than the table needs, and centred — on a desktop the
   columns came to about 900px in a window twice that, and sat
   against the left edge. */
.st-frame{display:flex;flex-direction:column;min-height:0;
  flex:1 1 auto;overflow:hidden;
  width:100%;max-width:1000px;margin:0 auto}

/* The headings. They never move down; sideways they follow. */
.st-heads{display:flex;flex:0 0 auto;overflow:hidden}
.st-headscroll{flex:1 1 auto;min-width:0;overflow:hidden}

/* The rows. This is the only thing that scrolls up and down, and it
   holds both halves, so they cannot come apart. */
.st-bodies{display:flex;flex:1 1 auto;min-height:0;
  overflow-y:auto;overflow-x:hidden;
  /* none, not contain: contain stops the scroll reaching the page
     behind but still lets the box bounce at its own ends. */
  overscroll-behavior:none;-webkit-overflow-scrolling:auto;
  scrollbar-width:none}
.st-bodies::-webkit-scrollbar{display:none}
/* And the right half's own sideways scrolling lives here. */
/* As tall as its own rows, not as tall as the box it sits in — a
   child that scrolls sideways inside one that scrolls down would
   otherwise take the parent's height and clip its rows. */
.st-bodyscroll{flex:1 1 auto;min-width:0;align-self:flex-start;
  overflow-x:auto;overflow-y:hidden;
  overscroll-behavior-x:contain;scrollbar-width:none}
.st-bodyscroll::-webkit-scrollbar{display:none}

.st-frozen{flex:0 0 auto;position:relative;z-index:2;
  border-right:1px solid var(--line);
  box-shadow:6px 0 10px -6px #000a}
.st-head,.st-body{flex:0 0 auto}
/* The rows start at the top of their box rather than stretching. */
.st-bodies > .st-body,.st-bodyscroll > .st-body{align-self:flex-start}

/* A heading you can press. */
.st-th{cursor:pointer;user-select:none;white-space:nowrap;
  background:#161c25}
.st-th.on{color:var(--text)}
.st-caret{font-size:8px}
/* A long surname is cut rather than allowed to set the column's
   width — the four columns beside it matter more than the last few
   letters of a name. */
.st-name{text-align:left;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;max-width:0}
.st-frame th,.st-frame td{height:26px;padding-top:0;padding-bottom:0}
/* Fixed layout, so the colgroup widths are obeyed rather than
   treated as suggestions — without it a long name widens its own
   column and the two halves stop lining up. */
.st-frame table,.gl table{table-layout:fixed}

/* The summit summary: three boards of what the summit did. */
/* The page scrolls on its own rather than relying on the document.
   html and body are height:100% across the app, and several pages
   pin them further — so a page that wants to scroll says so itself
   rather than hoping the one above it allows it.
   
   100dvh minus the topbar, which is the room actually left. */
/* A fixed frame with one scrolling panel in it.
   
   The page itself does not move in either direction: the topbar, the
   title and the controls hold their places, and only the list of
   players scrolls. Measuring against the topbar's height was the
   alternative, but --topbar is never set anywhere in this stylesheet
   — the calc would have used its fallback on every screen. */
html:has(.summit){height:100%;overflow:hidden}
body:has(.summit){height:100dvh;min-height:100dvh;
  width:100%;max-width:100%;
  /* Neither way: the page is a frame, not a canvas. */
  overflow:hidden;overscroll-behavior:none;
  position:fixed;top:0;left:0;
  display:flex;flex-direction:column}
body:has(.summit) .topbar{flex:0 0 auto}
.summit{max-width:720px;width:100%;margin:0 auto;
  padding:0 10px;box-sizing:border-box;
  flex:1 1 auto;min-height:0;
  display:flex;flex-direction:column;
  /* Nothing scrolls here. The panel below does. */
  overflow:hidden}
.summit-title{flex:0 0 auto;
  margin:8px 0 12px;font-family:var(--cond);font-size:20px;
  font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  text-align:center}
/* The toggle and the filter stay put while the board scrolls under
   them — a hundred rows is a long way back to the top otherwise. */
/* Outside the scrolling panel entirely, so it does not move at all
   rather than being stuck to the top of something that does. */
.summit-bar{flex:0 0 auto;
  display:flex;flex-direction:column;align-items:center;gap:8px;
  padding:8px 0 10px;margin:0 -10px 10px;
  background:var(--ink);border-bottom:1px solid var(--line)}
.summit-pick{width:fit-content;max-width:100%;margin:0}
.summit-owner{width:fit-content;max-width:82%;padding:5px 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:600;
  letter-spacing:.06em}
.summit-count{flex:0 0 auto;
  margin:0 0 8px;font-family:var(--cond);font-size:9px;
  letter-spacing:.14em;text-transform:uppercase;color:var(--muted);
  text-align:right}
.summit-none{margin:36px 0;text-align:center;color:var(--muted)}

/* The one thing on this page that moves. */
.summit-body{flex:1 1 auto;min-height:0;
  overflow-y:auto;overflow-x:hidden;
  -webkit-overflow-scrolling:touch;overscroll-behavior:contain;
  padding-bottom:20px}

/* A card the full width of the page: the player across the top, who
   did what to him beneath. */
/* Every card the same width, whichever board it is on.
   
   The three boards carry different things — an RFA row has a price,
   a verdict and two owners; a rookie row has a pick and a college —
   and as flex rows the widest content set the width, so the cards
   changed size when the toggle changed. A grid with fixed tracks
   settles it: the columns are the same on all three, and content
   that will not fit is ellipsed rather than allowed to push. */
.sm-card{width:100%;box-sizing:border-box;
  border-radius:9px;background:var(--slate-2);
  border:1px solid var(--line);margin-bottom:5px;
  padding:7px 10px 6px}
.sm-row{display:grid;
  grid-template-columns:34px minmax(0,1fr) 132px;
  align-items:center;gap:10px;min-width:0}
/* Who took him, and what it cost besides money. */
.sm-foot{display:flex;align-items:center;gap:8px;min-width:0;
  margin:5px 0 0;padding-top:5px;border-top:1px solid #ffffff0d;
  font-family:var(--cond);font-size:9.5px;letter-spacing:.1em;
  text-transform:uppercase;overflow:hidden}
.sm-move{color:var(--text);font-weight:700;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* The pick, the old salary, how many bid. Shrinks before the owner
   does — who won him matters more than what it cost. */
.sm-pick{color:var(--muted);min-width:0;flex:0 1 auto;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sm-move{flex:0 1 auto}
.sm-pen{margin-left:auto;color:#f0918b;font-weight:700}
/* The first grid track is 34px, and the face fills it. */
.sm-face{width:34px;height:34px;border-radius:50%;
  overflow:hidden;background:var(--ink)}
.sm-face img{width:100%;height:100%;object-fit:cover;
  object-position:top center}
.sm-mid{display:flex;flex-direction:column;min-width:0}
.sm-mid b{font-size:13.5px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.sm-sub{font-family:var(--cond);font-size:8.5px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted)}
/* A fixed width, so a card with three figures on the right is the
   same width as one with two — the boards read as one page rather
   than three sets of ragged rows. */
.sm-end{display:flex;align-items:center;justify-content:flex-end;
  gap:8px;min-width:0;overflow:hidden;
  font-family:var(--cond);font-size:11px;letter-spacing:.06em}
.sm-end > span{white-space:nowrap}
.sm-was{color:var(--muted)}
.sm-bid{font-size:14px;font-weight:700;color:var(--money)}
.sm-no{color:var(--muted);min-width:34px;text-align:right}
.sm-who{min-width:78px;text-align:right;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sm-kept{color:#7ee2a8;font-weight:700}
.sm-lost{color:#f0918b;font-weight:700}

@media (max-width:520px){
  /* The owner moved to the line below, so only the old salary goes —
     the name and the price are what is being read across the top. */
  .sm-was{display:none}
  .summit{padding-left:8px;padding-right:8px}
  /* Narrower right column on a phone, so the name keeps its room. */
  .sm-row{grid-template-columns:30px minmax(0,1fr) 104px;gap:8px}
  .sm-face{width:30px;height:30px}
}

/* The year picker: the same .seg control the view toggle uses, so
   the two read as one idea. Centred in the panel, and scrolling
   sideways where a career runs longer than the card is wide. */
.yearpick{width:fit-content;max-width:100%;margin:10px auto;
  overflow-x:auto;scrollbar-width:none}
.yearpick::-webkit-scrollbar{display:none}
.yearpick-b{flex:0 0 auto;white-space:nowrap}
.yearpick .yearpick-b.on{background:#a83a6b;color:#fff}
/* Six boxes in three rows, and a year picker above them — so the
   rows have to be shorter than the profile's to fit the same panel.
   Three at 46px with the picker comes to what 229px allows. */
/* Every box in the chain from the panel down, so a wide table
   cannot push any of them open. */
.cardview-stats,
.cardview-stats .stat-card{min-width:0;max-width:100%;overflow:hidden}

.cardview-stats .c-facts.gym-facts{grid-template-rows:none;
  grid-auto-rows:46px;gap:5px}
/* The summary rows keep their own height inside a block that now
   fills the panel — without this they would stretch to fill it too,
   and a two-row summary would look nothing like a six-row one. */
.cardview-stats .statline{flex:0 0 auto}
.cardview-stats .c-facts.gym-facts .c-fact{padding:6px 6px}
.cardview-stats .c-facts.gym-facts .c-fact b{font-size:13px}
/* The block below the picker takes what is left, and no more. In
   the stacked view that means the table scrolls inside it rather
   than growing the panel — a ten year career would not fit. */
.cardviews .cardview-stats .c-sum{flex:1 1 auto;min-height:0;
  min-width:0;max-width:100%;
  padding:0 10px 10px;justify-content:flex-start;overflow:hidden}

.c-facts.gym-facts{display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  grid-template-rows:52px repeat(2,56px);
  gap:6px;align-content:start}
.c-facts.gym-facts .c-fact{padding:8px 6px;min-width:0;min-height:0;
  display:flex;flex-direction:column;justify-content:center}
/* Smaller than the contract's three, because five boxes share the
   same room and one of them holds a school name. */
/* White, not the money green the contract's figures use — these are
   dates and measurements, not sums. */
.c-facts.gym-facts .c-fact b{display:block;font-size:12.5px;
  line-height:1.25;overflow-wrap:anywhere;color:var(--text)}
/* Except where he was not drafted, which is worth seeing at once. */
.c-facts.gym-facts .c-fact.is-undrafted b{color:var(--red);
  text-transform:uppercase;letter-spacing:.08em}
/* Who did it, after the label: the drafting club, or the owner who
   took him here. Quieter than the label it follows. */
/* On the label's own line and in the label's own type.
   
   display:inline is the point of it: `.c-fact span` sets every span
   in the box to display:block, and this one is nested inside the
   label — so without this it became a block of its own and dropped
   underneath, which is exactly what it was doing. Everything else
   is inherited, so it matches the label rather than restating it. */
.c-fact .c-fact-who{display:inline;margin:0;
  font-family:inherit;font-size:inherit;font-weight:inherit;
  letter-spacing:inherit;text-transform:inherit;
  color:#7d8899;white-space:nowrap}
/* The label keeps to one line, so "NFL · SF" cannot break apart. */
.c-facts.gym-facts .c-fact > span{white-space:nowrap}

.c-facts.gym-facts .c-fact > span{font-size:8px}
/* His school's mark beside the name. A grid rather than a flex row:
   the mark in the first column spanning both lines, the name and its
   label stacked in the second — a flex row would put all three side
   by side. */
/* The mark and the name together in the middle of the box rather
   than pushed to its left edge: an inline-grid inside a centred box
   is only as wide as its contents, so the pair centres as one thing
   while the two lines still stack beside the mark. */
.c-facts.gym-facts .c-fact.has-logo{text-align:center}
.c-facts.gym-facts .c-fact.has-logo > b{display:inline-grid;
  grid-template-columns:auto minmax(0,1fr);
  column-gap:10px;align-items:center;text-align:left;
  max-width:100%}
/* A shadow rather than a plate — it lifts the mark off whatever is
   behind it without putting a disc in the way. drop-shadow follows
   the mark's own outline, where box-shadow would trace its square. */
/* A fixed box whatever the mark's own proportions — object-fit
   keeps it undistorted inside, and the row cannot be stretched by
   an unusually tall logo. */
.c-fact-logo{width:32px;height:32px;flex:0 0 auto;object-fit:contain;
  filter:drop-shadow(0 1px 3px #000000b3)}

/* College takes the whole first row to itself, and only the height
   its contents need — the four below get everything else. */
.c-facts.gym-facts .c-fact.is-wide{grid-column:1 / -1;
  padding:0 12px;min-height:0;overflow:hidden}
.c-facts.gym-facts .c-fact.is-wide b{font-size:16px}
/* One line, cut with an ellipsis rather than wrapping — a second
   line would push the row taller on some cards than others. It also
   has to override the label rule, which sets every span in a fact
   box to display:block at 9.5px. */
.c-fact .c-fact-school{display:block;margin:0;
  font-family:inherit;font-size:inherit;font-weight:inherit;
  letter-spacing:normal;text-transform:none;color:inherit;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  min-width:0}
/* No label on it: the school's own mark and name say what it is,
   and the room goes to the name instead. */
.c-facts.gym-facts .c-fact.is-wide > span{display:none}

/* Washed in the school's own colour, over the panel's own
   background rather than the box's usual fill.
   
   The base .c-fact carries a faint white fill, so a gradient fading
   to transparent revealed that instead of the panel — one shade
   giving way to another rather than a colour fading out. Naming the
   panel's colour as the far stop makes the school's colour the only
   thing that changes. */
.c-facts.gym-facts .c-fact.is-wide{
  background:linear-gradient(110deg,
    var(--school, var(--slate-2)) 0%,
    var(--school, var(--slate-2)) 42%,
    var(--slate-2) 96%)}
/* The detail under the label — a school's conference, a draft pick. */
.c-fact-note{display:block;margin-top:3px;font-family:var(--cond);
  font-size:8.5px;letter-spacing:.08em;text-transform:uppercase;
  color:#7d8899;overflow-wrap:anywhere}



.gym-box{padding:9px 8px;border-radius:9px;background:var(--slate-2);
  border:1px solid var(--line);display:flex;flex-direction:column;
  gap:2px;min-width:0}
.gym-label{font-family:var(--cond);font-size:8.5px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted)}
/* A figure is never cut. The boxes are wide enough for what goes in
   them, and a school name — the one thing here that can be long —
   wraps rather than truncating. */
.gym-value{font-size:14px;overflow-wrap:anywhere;white-space:normal;
  padding-top:7px}
.gym-note{font-family:var(--cond);font-size:9px;letter-spacing:.06em;
  text-transform:uppercase;color:#7d8899}
.gym-when{margin:9px 0 0;text-align:right;font-family:var(--cond);
  font-size:9px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--muted)}
.gym-none{margin:18px 0;text-align:center;color:var(--muted);
  font-size:13px}

@media (max-width:420px){
  /* Two across on a phone — three makes "South Carolina" a stack of
     single letters. */
    }

/* His designation, as a band across the card. Same grading as the
   pill, but this is the first thing you should see about a man who
   might not play — so it takes the full width and says the word. */
.nom-state{display:block;width:100%;box-sizing:border-box;
  margin:10px 0 0;padding:8px 10px;border-radius:8px;
  border:1px solid currentColor;text-align:center;
  font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.18em;text-transform:uppercase}
.nom-state.st-probable{color:#4ade80;background:#14301f99}
.nom-state.st-limited{color:#c8d049;background:#2f3a0a99}
.nom-state.st-questionable{color:#f5c518;background:#3a300a99}
.nom-state.st-doubtful{color:#e8963a;background:#3a250a99}
.nom-state.st-out{color:#e8603a;background:#3a190f99}
.nom-state.st-ir{color:#ff6b60;background:#3d1418cc}

/* Green where he is expected to play, through yellow and orange, to
   red where he is not. The NFL dropped "probable" from the injury
   report years ago, but some feeds still carry it — cheap to keep. */
.news-state.st-probable{color:#4ade80;background:#14301f66}
.news-state.st-limited{color:#c8d049;background:#2f3a0a66}
.news-state.st-questionable{color:#f5c518;background:#3a300a66}
.news-state.st-doubtful{color:#e8963a;background:#3a250a66}
.news-state.st-out{color:#e8603a;background:#3a190f66}
.news-state.st-ir{color:var(--red);background:#3d141899}

/* Who wrote a note and when, under it in the rail. */
.news-credit{display:flex;align-items:baseline;gap:7px;margin-top:4px;
  font-family:var(--cond);font-size:8.5px;letter-spacing:.08em;
  text-transform:uppercase;color:#5a6672}
.news-at{margin-left:auto;white-space:nowrap}

/* Each feed keeps its rows; only the chosen one is in the rail. */
.news-feed{display:flex;flex-direction:column;gap:6px}

/* When the feed was last brought in. Outside the scrolling body, so it
   holds its place, and opaque so nothing passes behind it. */
.news-stamp{flex:0 0 auto;padding:0 12px 7px;
  background:var(--slate);
  border-bottom:1px solid var(--line);margin-bottom:6px;
  font-family:var(--cond);font-size:9.5px;letter-spacing:.1em;
  text-transform:uppercase;color:#6b7684}

/* His club, under his name rather than beside it — that line is his. */
.news-clubline{display:flex;align-items:center;gap:5px;margin-top:1px}
.news-clublogo{width:14px;height:14px;flex:0 0 auto;object-fit:contain}
.news-club{font-family:var(--cond);font-size:9px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}

/* A note in full, opened from the rail. */
.notecard-veil{z-index:95}
/* The header carries a photograph now, so it needs room for one. */
.notecard-box .modal-head{display:flex;align-items:center;gap:10px}
/* margin:auto comes from .modal-card and is what centres it in the
   veil's grid — nothing here may override it. */
/* min(94vw) against a viewport that includes the scrollbar gutter puts
   the card a few pixels right of centre on a phone. 100% resolves
   against the grid area the veil actually gives it, which is centred. */
.notecard-box{width:min(94%,460px);max-height:min(82dvh,100%);
  display:flex;flex-direction:column;pointer-events:auto;
  background:var(--slate);border:1px solid var(--line);
  border-radius:14px;overflow:hidden}
.notecard-body{flex:1 1 auto;min-height:0;overflow-y:auto;
  padding:12px 16px 18px}
.note-club{display:flex;align-items:center;gap:6px;margin-bottom:8px}
/* His face in the card's header, beside his name. */
.note-face{width:34px;height:34px;flex:0 0 auto;border-radius:8px;
  overflow:hidden;background:var(--slate-2);
  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:12px}

/* Who wrote it and when, at the foot. */
.note-foot{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;
  margin-top:12px;padding-top:9px;border-top:1px solid var(--line)}
.note-stamp{font-family:var(--cond);font-size:9.5px;letter-spacing:.06em;
  color:#5a6672;margin-left:auto}
.note-head{margin:0 0 8px;font-family:var(--ui);font-size:16px;
  font-weight:600;line-height:1.3;color:var(--text)}
.note-body{margin:0 0 10px;font-size:13.5px;line-height:1.55;
  color:var(--muted)}
.note-source{font-family:var(--cond);font-size:9px;letter-spacing:.12em;
  text-transform:uppercase;color:#5a6672}

/* A row from the reader's own feed opens the note in full rather than
   leaving for somebody's website. The body is clipped here, and some of
   these carry a paragraph of analysis worth reading. */
div.newsrow.is-tappable{cursor:pointer}
div.newsrow.is-tappable:hover{background:#ffffff0a}
div.newsrow.is-tappable:focus-visible{outline:2px solid var(--teal);
  outline-offset:-2px}

.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}
/* His name shortens before the badge does. */
.news-top > b{min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.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. */
  /* A column that fits its cell rather than running past it.
     flex:none with overflow:visible let the events block and the roster
     grid come to more than the screen and simply spill — the tiles at
     the bottom went off the foot of the window with nothing to scroll.
     The column is a flex box now, so the grid inside it can give way. */
  /* A column that fits its cell rather than running past it, with a
     little air under the last row of tiles so none sits flush against
     the foot of the window. */
  .home-mid{display:flex;flex-direction:column;
    gap:22px;padding:24px 26px 48px;min-width:0;
    min-height:0;height:100%;overflow:hidden;box-sizing:border-box}
  /* 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. */
  /* Same again for the block that holds the grid: without a basis of
     zero it is sized by its contents, and passes that on. */
  .home-block:last-child{flex:1 1 0;height:0;min-height:0;
    overflow:hidden}
  /* The events above keep their own height but no more — flex:0 0 auto
     without a shrink meant a long fixtures list pushed the grid below
     it down and the last row of tiles off the screen. */
  .home-mid .home-block:first-child{flex:0 1 auto;min-height:0;
    overflow:hidden}
  /* 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. */
  /* Four rows that share whatever is left, and never more than that.
     grid-template-rows:1fr divides the height it is GIVEN — but a grid
     with no height of its own is given its content's, so the rows grew
     to fit the cards and the last one went off the bottom of the
     window. min-height:0 lets it shrink; height:0 with flex:1 makes it
     take its size from the column rather than from what is in it. */
  /* A hard ceiling as well as a flexible one.
     flex:1 1 0 with height:0 should be enough, and on a well-behaved
     column it is — but this grid has been spilling past the foot of the
     window through several attempts to size it from its parent, so it
     is also given a maximum it cannot exceed whatever the column does.
     The subtraction is the header, the ticker, the events block above
     it and the padding below. */
  .home .teamgrid{grid-template-columns:repeat(3,minmax(0,1fr));
    grid-template-rows:repeat(4,minmax(0,1fr));gap:12px;
    flex:1 1 0;height:0;min-height:0;overflow:hidden;
    max-height:calc(100dvh - var(--bar-h,53px) - var(--slate-h,0px)
      - 260px);
    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){
    /* Without container queries the cards can't shrink to fit, so the
       grid scrolls instead — but it keeps its ceiling, or it would run
       past the foot of the window the way it used to. */
    .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}
  /* His picture, between the number and the names. The roster face it
   borrows is 52px, which is a roster row's size — a rail row is a
   third of that, so it is cut down here. */
.railpick-face{flex:0 0 auto;width:26px;height:29px;border-radius:6px}
.railpick-face > img{border-radius:6px}
/* A pick still to come keeps the space, so the names stay in a column
   rather than shuffling left where nobody has been taken yet. */
.railpick-empty{background:#ffffff0a;
  border:1px dashed #ffffff1f;box-sizing:border-box}

.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}
  /* Four across and three down here, and a little more room at the
     foot since this is the widest window. */
  .home .teamgrid{grid-template-columns:repeat(4,minmax(0,1fr));
    grid-template-rows:repeat(3,minmax(0,1fr));
    max-height:calc(100dvh - var(--bar-h,53px) - var(--slate-h,0px)
      - 280px)}
  .home-mid{padding:26px 34px 52px}
}


/* ── 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;
    /* The same duration and the same curve as the panel below.
       They were .28s cubic-bezier(.22,.7,.3,1) against the rail's
       .3s cubic-bezier(.22,.61,.36,1) — two curves over two
       durations, so the tab ran ahead of the panel, came away from
       its edge, and caught up again at the end. That is the bounce.
       One timing, stated once, for both. */
    transition:transform .3s cubic-bezier(.22,.61,.36,1),
      opacity .2s ease;
    /* No overflow property at all — the league tab has none and its
       chevron turns cleanly. overflow:hidden was clipping this one
       mid-rotation; even overflow:visible creates a paint context
       that made the arrow flicker as the tab slid. */
    cursor:pointer}
  /* 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}
  /* The same curve as the rail it belongs to. It was on plain `ease`
   while the rail used a cubic-bezier, so over the same 280ms the two
   moved at different rates and the chevron visibly led the panel. */
/* Exactly the league tab's arrow. That one turns cleanly, and the
   difference was never the glyph — it was the tab around it. */
.newstab-arrow{font-size:15px;line-height:1;
  transition:transform .3s cubic-bezier(.22,.61,.36,1)}
  /* The same six colours, down the tab's own edge. */
  /* Its own rounded bottom-left corner, now that the tab no longer
   clips it — matching the tab's radius so the stripe still sits
   inside the shape. */
.newstab::after{content:"";position:absolute;left:0;bottom:0;width:100%;
    height:3px;border-bottom-left-radius:11px;
    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}

  /* Behind an open rail on the hub: the page goes soft and takes no
   presses, and the banner stays sharp — it is how you leave. Held
   for a moment after closing, still invisible and still swallowing,
   so the tap that shut it does not land on something behind. */
body.news-open .home > *:not(#newsRail),
body.league-open .home > *:not(#newsRail){
  filter:blur(4px);pointer-events:none;transition:filter .3s ease}
/* The news rail lives inside .home, so a bare .home > * blurred the
   rail along with the page behind it. */
body.news-open #newsRail{filter:none;pointer-events:auto}

/* The ticker sits outside .home and was left sharp. */
body.news-open .slate,
body.league-open .slate{filter:blur(4px);pointer-events:none;
  transition:filter .3s ease}
/* The news veil is opacity-driven from body.news-open, so it cannot
   linger the way the league one does. Instead the body keeps a class
   for a moment after closing, and that keeps the veil live and
   invisible for exactly as long. */
.leagueveil.is-going{opacity:0;background:transparent;
  pointer-events:auto}
body.rail-settling .newsveil,
body.rail-settling .leagueveil{opacity:0;background:transparent;
  pointer-events:auto}

.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}
/* The name is stacked now — given name over surname — so the skin
   styles the two lines rather than the block that holds them. */
body.dhskin .nom-first{font-family:var(--cond);font-weight:600;
  font-size:16px;text-transform:uppercase;letter-spacing:.06em}
body.dhskin .nom-last{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:20px}

/* 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-gone{grid-row:3}
.tb-side-net{grid-row:4;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. */
/* Four rows, not three: head, assets, releases, then the money. The
   releases block had no row of its own, so it auto-placed after the
   money — which is pinned to the last row — and appeared below it on a
   phone while reading correctly on a desktop. */
.tb-side-block{flex:1;min-height:0;display:grid;
  grid-template-rows:auto 1fr auto 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 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-gone{grid-row:3}
  #builder .tb-side-net{grid-row:4}
  #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 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-gone{grid-row:3}
  #builder .tb-side-net{grid-row:4}
  #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);
  /* Left edge only. inset-inline:0 would put the right edge back to
     the viewport and undo the scrollbar allowance above. */
  left:0;
  right:var(--sbw, 0px);
  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}
/* A stated width, not one taken from the contents.
   
   With max-width alone the column shrank to fit whatever was in it,
   so an empty Targets list or a search that found nobody pulled the
   toggles and the search box in with it. */
.fapage{width:100%;max-width:820px;margin:0 auto;padding:0 14px 40px;
  box-sizing:border-box}
.fahead,.falist,.fatoggles,.fahdr{width:100%;box-sizing:border-box}

/* Opaque, since the list scrolls under it — but painted with the
   page's own gradient rather than a flat colour. The skin paints the
   body #0b1526 fading to #081120, so a flat --ink header read as a
   darker block sitting on top of it. Sized to the viewport and
   pinned to its top, the header becomes a window onto that same
   background instead of a panel over it. */
.fahead{position:sticky;top:0;z-index:4;
  background-color:#081120;
  background-image:linear-gradient(180deg,#0b1526 0%,#081120 60%);
  background-size:100% 100dvh;background-position:top center;
  background-repeat:no-repeat;
  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;
    /* The gradient is set once, above — the header inherits it there
       rather than each layout painting its own flat colour. */
    z-index:5}
  /* overflow-y:scroll rather than auto: the gutter is then always
   drawn, on every browser, whether or not there is enough to scroll.
   scrollbar-gutter alone is ignored by older Safari, which is where
   the width was jumping. */
.falist{flex:1;min-height:0;overflow-y:scroll;scrollbar-gutter:stable;
    -webkit-overflow-scrolling:touch;
    /* Up and down only.
       
       Without these the list rubber-bands sideways and hands the
       drag on to the page underneath — which is the wiggle the
       rostered list does not have. */
    overscroll-behavior:contain;touch-action:pan-y;
    /* And nothing to pan to: a row wider than the list would give it
       something to slide, which is what was moving under the
       finger. */
    overflow-x:hidden;
    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. */
/* The photograph's column follows its width, so the position chip beside
   it isn't pushed over when the picture grows. */
/* No position column: it sits on the picture now. */
.fahdr,.falist /* Seven columns now: the star sits between the chevron and the
   face. The gap comes down a little so the row is no wider than it
   was. */
.farow{display:grid;
  grid-template-columns:20px 24px 44px minmax(0,1fr) 34px 60px 54px;
  align-items:center;gap:6px}
/* The projection sits well clear of the button. Sixth cell now, the
   salary having come back before it. */
.falist .farow > .fawk,.fahdr > *:nth-child(7){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. */
/* The header reserves the same scrollbar gutter the list below it
   does. Without it the columns shift sideways whenever a search
   narrows the results enough for the scrollbar to disappear — the
   header stayed full width while the rows lost the gutter. */
.fahdr{border:1px solid transparent;scrollbar-gutter:stable;
  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 salary column, said in the colour of money rather than the
   word — it is the narrowest column and the label no longer fits. */
.fahdr button[data-sort="salary"]{color:#7ee2a8;letter-spacing:.02em}
.fahdr button[data-sort="salary"].on{color:#a8e6c1}
/* 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. */
/* What a free agent would cost, as against what a rostered man is paid.
   Gold, because it is a price rather than a commitment. */
.facost{color:var(--gold)}

.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}

/* The row opens his card, so it reads as pressable — the arrow and the
   button at the end keep their own presses. */
.farow.is-tappable{cursor:pointer}
.farow.is-tappable:hover{background:#ffffff08}
.fapos{font-family:var(--cond);font-size:10.5px;font-weight:700;
  letter-spacing:.06em;text-align:center;color:var(--muted)}

/* His position, on the bottom-right of the picture: a rounded square in
   that position's own colour, the letters in white on top. */
.faposbadge{position:absolute;right:-2px;bottom:-2px;z-index:3;
  min-width:14px;padding:0 2px;box-sizing:border-box;
  display:flex;align-items:center;justify-content:center;
  border-radius:4px;background:var(--slate-2);color:#fff;
  border:1px solid #0b101859;box-shadow:0 1px 2px #0008;
  font-family:var(--cond);font-size:6.5px;font-weight:700;
  letter-spacing:.02em;line-height:1.5}
.faposbadge.pos-QB{background:var(--pos-qb)}
.faposbadge.pos-RB{background:var(--pos-rb)}
.faposbadge.pos-WR{background:var(--pos-wr)}
.faposbadge.pos-TE{background:var(--pos-te)}
.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}
/* The name in the interface font and in white: the condensed block face
   the rest of this row uses is built for short labels, and a full name
   set in it is harder to read than it needs to be. */
.faname > b{font-family:var(--ui);font-size:13px;font-weight:600;
  letter-spacing:-.01em;text-transform:none;color:#fff;
  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}

/* Cut, beside his name in the bar: white, with red scissors. The × keeps
   the far corner, so this sits with the name rather than opposite it. */
.head-cut{flex:0 0 auto;margin-left:10px;
  width:24px;height:24px;padding:0;
  display:flex;align-items:center;justify-content:center;
  border:0;border-radius:999px;background:#fff;color:var(--red);
  cursor:pointer;box-shadow:0 1px 3px #0006;
  transition:transform .1s,background .1s}
.head-cut svg{width:14px;height:14px;display:block}
.head-cut:hover{background:#ffe9ea}
.head-cut:active{transform:scale(.94)}
/* 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. */
/* The same box the roster rows use, not a circle — a headshot is taller
   than it is wide, and a circle crops the face to fit. overflow stays
   visible so the age badge can overlap the corner; the picture inside
   keeps its own rounded corners. */
/* Larger, now that a row carries three lines — the photograph was
   shorter than the text beside it. */
.faface{position:relative;width:42px;height:46px;border-radius:8px;
  background:var(--slate);display:flex;align-items:flex-end;
  justify-content:center;flex:0 0 auto}
/* A first-year man: the box behind him is a deep red rather than the
   usual slate, which marks him without putting anything over the
   picture. */
/* A first-year man's backdrop, everywhere he appears. The rainbow says
   "new" without reading as an injury the way the old red did — which
   mattered, since red already means hurt on these pages. */
/* A first-year man's backdrop. A deep blue, and solid: red already
   means injured on these cards, green means the reader owns him, and
   yellow means in doubt.

   Brighter than the blue on the Trade button and the list toggle
   (#1d4c86) rather than darker — a deeper navy sat within a few points
   of them and read as the same colour at a glance. */
:root{--rookie-wash:#2f6fd0}
.faface[data-rookie]{background:var(--rookie-wash)}


/* His age, over the top-left corner. Same badge as everywhere else. */
/* Its own corners, now that the box no longer clips — it has to let the
   age badge overlap. */
.faface > img{position:absolute;inset:0;width:100%;height:100%;
  border-radius:8px;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 22px 42px minmax(0,1fr) 30px 54px 50px;
    gap:5px}
  .falist .farow > .fawk,.fahdr > *:nth-child(7){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. */
  /* A touch smaller than the desktop's 48, but keeping the picture's
     proportions — square crops the sides off a headshot. This was a flat
     32x32, which is what kept overriding the larger frame on a phone. */
  .faface{width:38px;height:42px}
}

.dropcard{max-width:520px}
/* The confirmation card: his face, his name, what he cost. */
.signedwho{display:flex;align-items:center;gap:11px;
  padding-bottom:10px;margin-bottom:2px}
.signedwho .faface{width:44px;height:44px;flex:0 0 auto;
  border-radius:9px;overflow:hidden;background:var(--slate-2);
  display:flex;align-items:center;justify-content:center}
.signedwho .faface img{width:100%;height:100%;object-fit:cover;
  object-position:top center}
.signedmid{display:flex;flex-direction:column;min-width:0;flex:1 1 auto}
.signedmid b{font-size:15px;font-weight:600}
.signedsub{font-family:var(--cond);font-size:9.5px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted);margin-top:2px}
.signedpay{flex:0 0 auto;font-family:var(--cond);font-size:15px;
  font-weight:700;color:var(--money)}

.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. */
/* A height whether or not there is anything on it: a man with no
   contract on file would otherwise leave this line empty and his row
   would sit shorter than the ones either side. */
.fasub{display:flex;align-items:center;gap:6px;min-width:0;min-height:14px;
  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}
/* A man being watched. Stated after the injured row above so a
   targeted man on IR still shows the gold — the star is the thing
   being looked for. */
.falist .farow.is-target{border-color:#e8b84b;
  box-shadow:0 0 0 1px #e8b84b40, 0 0 10px #e8b84b26}


/* 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. */
/* Salary and Proj sit over columns of figures, so their headings are
   right-aligned to match. Name is the third cell now that the position
   column has gone onto the picture — these were keyed to the fourth,
   which after that change was Salary. */
/* The Name button is the fourth cell now, not the third — the star
   took a column ahead of it, so this was right-aligning the name and
   left-aligning the salary. */
.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;text-align:left}
/* 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}

/* Everything on this page holds the page's width, whatever is in it.
   With only the "nothing found" line in the list, there were no grid
   rows to hold the columns open — and because .fapage is a flex
   column, its children shrank to their content, taking the search bar
   and the toggles in with them. Each part is pinned instead, so a
   search that matches nothing changes only the list's contents. */
.fapage > *{width:100%;box-sizing:border-box}
.falist{width:100%}
.falist > .empty{display:block;width:100%}
.fahdr{width:100%}
.fahead{width:100%;box-sizing:border-box}

/* 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. */
/* Nobody holds him: the league's own red, so it reads as a state rather
   than as another line of grey detail. */
.fafree{color:var(--red);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}
/* The strip between the tabs and the conversation, closed up rather
   than filled — the rail behind is a gradient, so any flat colour
   painted into the gap would show as a band against it. */
.leaguerail .railseg{position:relative;z-index:3;margin-bottom:0}
/* The rail is its own scroll world: a drag that runs past the end of
   the conversation stays there rather than pulling the page behind
   it. */
.leaguerail{overscroll-behavior:contain}
/* Transparent, so the tabs sit on whatever is behind them.
   
   The other two views have no background of their own and show the
   rail's gradient; only the chat paints itself. A flat colour here
   would match the chat and clash with the other two, so the strip
   takes the chat's top colour only while the chat is the one
   showing. */
.leaguerail .railseg{background:none;border-color:#1d3050}
.leaguerail:has(.chat-body:not([hidden])) .railseg{background:none}
.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;
  /* A cushion under the tabs so the first card is not tight against
     them. */
  -webkit-overflow-scrolling:touch;padding:14px 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:center;
  gap:8px;margin-bottom:5px;font-family:var(--cond);font-size:9px;
  font-weight:700;letter-spacing:.14em;text-transform:uppercase}
/* The time goes to the far right; the Add button sits just after the
   word it belongs to. space-between did this before the button
   existed — with three children it spread them instead. */
.movecard-head .movecard-when{margin-left:auto}
.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. */
/* As tall as the screen allows.

   96vh was never reachable: the veil around it pads 20px plus the safe
   area at each end, so on a phone about 120px was gone before the card
   began and it capped well short of its own maximum. Filling the space
   the veil actually leaves is what "as big as it needs" means here.

   The veil's own padding is trimmed below to match. */
/* A fixed height, not a measured one.
   
   The panel height used to be worked out in card.js from the header,
   the news and the content — a sum with a term for everything that
   varies between players, so every card came out slightly different
   and each fix only removed one term. This takes the whole
   calculation away: the card fills the veil, the body is a column,
   and the panels take whatever is left after the header and the
   news. Identical on every card by construction. */
.playercard .modal-card{height:100%;max-height:100%;
  display:flex;flex-direction:column}
/* As much of the screen as a card can honestly take.

   The safe area at each end is the phone's — the notch and the home
   indicator — and 8px either side of that is the whole margin. The veil
   stays full-screen because it is the tap-to-close area as well as the
   shade; only its padding changed. */
.modal.playercard{padding:calc(8px + var(--sat,0px)) 8px
  calc(8px + var(--sab,0px))}

/* Held back while its two views are measured, then let in at the size it
   keeps — one movement rather than a card that appears and then resizes
   twice. The veil's own fade still runs, so the shade arrives on time
   and only the card waits.

   The rise is delayed rather than dropped: it starts when the class
   comes off, so the card still lifts in the way every other card does. */
.modal.playercard.sizing .modal-card{visibility:hidden;
  animation-play-state:paused}
/* Scrolls up and down, and does not clip sideways — the photograph
   is meant to break the padding. A box with overflow-y:auto gets
   overflow-x:auto whether it is asked for or not, which cut him off
   at the card's edge, so the header is given room of its own
   instead. */
/* The card holds still. The header, the toggle and the panels are
   all fixed sizes now, so the only thing that can need more room is
   the news — and it takes what is left and scrolls inside itself. */
.playercard .modal-body{overflow:hidden;
  display:flex;flex-direction:column}
.playercard .modal-body > .nom,
.playercard .modal-body > .cardseg,
.playercard .modal-body > .cardviews{flex:0 0 auto}
/* Flush with everything below it. The negative margins were there to
   let the photograph break the padding, but they also made the header
   wider than the panels and the news — so nothing on the card lined
   up. The spill is handled by the image's own negative offset
   instead, which moves the picture without moving the block. */


/* Takes the room the panels do not. On a tall screen that means more
   stories on show; on a short one it falls back to its own minimum
   and scrolls, as before. */
/* The one part of the card that moves. Its heading holds still and
   the list beneath it scrolls. */
.pc-news{margin-top:14px;padding-top:12px;
  border-top:1px solid var(--line);
  flex:1 1 auto;min-height:0;display:flex;flex-direction:column;
  overflow:hidden}
.pc-newshead{flex:0 0 auto}
.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}
/* The notes scroll on their own rather than growing the card.
   Five of them at full length is taller than a phone, and a card that
   grows with whoever happens to be in the news is a card that changes
   size every time it opens. */
/* No ceiling now: the block above gives it a height, and the
   list fills it. The 190px cap was there to stop the list
   growing the card — the card is a fixed height now, so the
   cap only stopped it using the room it was given. */
.pc-newslist{display:flex;flex-direction:column;gap:8px;
  /* A ceiling and a floor rather than a fixed height. The floor is
     what the two placeholders come to, so the card measures right
     before the fetch lands; the ceiling is what five notes would
     overflow, so they scroll instead of growing the card. A man with
     one short note gets a box that fits it rather than empty space. */
  min-height:96px;max-height:none;flex:1 1 auto;
  overflow-y:auto;overscroll-behavior:contain;
  padding-right:4px;
  scrollbar-width:thin;scrollbar-color:#ffffff26 transparent}
.pc-newslist::-webkit-scrollbar{width:5px}
.pc-newslist::-webkit-scrollbar-thumb{
  background:#ffffff26;border-radius:3px}
.pc-newslist::-webkit-scrollbar-track{background:transparent}
/* A story that can be opened in full. */
.pc-newsitem.is-tappable{cursor:pointer}
.pc-newsitem.is-tappable:hover{background:#1b2536}
.pc-newsitem.is-tappable:focus-visible{outline:2px solid #3a5f7d;
  outline-offset:2px}

.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. */
/* How recent his latest note is, in the mark's own colour.

   Red within a day, white within three, muted beyond that. Three months
   of news is kept now, so a mark that means only "there is something
   here" says very little — a story from this morning and one from six
   weeks ago both existed, and the difference is the whole point.

   These come after .fresh in the file so they win where both apply. */
.newsmark.news-hot{color:var(--red)}
.newsmark.news-warm{color:#fff}
.newsmark.news-cold{color:#ffffff5c}
.dcname .newsmark.news-hot,.dcrowname .newsmark.news-hot{color:var(--red)}
.dcname .newsmark.news-warm,.dcrowname .newsmark.news-warm{color:#fff}
.dcname .newsmark.news-cold,.dcrowname .newsmark.news-cold{color:#ffffff5c}

.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. */
/* One height for every tile, fixtures and rankings alike, so the
   band does not change size as it cycles. Stated rather than left to
   the contents, which differ between the two. */
.slate-game{flex:0 0 auto;display:flex;flex-direction:column;
  align-items:center;gap:4px;padding:7px 16px 6px;
  height:67px;box-sizing:border-box;
  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)}
/* The band's other face: the week's best projections, in the same
   glass boxes the fixtures use. */
/* A row, not a column — .slate-game stacks its two lines, and a
   ranking reads across: place, face, name, club and figure.
   
   Same height as a fixture tile, so the band does not change size as
   it cycles: the photograph is taller than the box and is clipped by
   it rather than setting it. */
.slate-rank{flex-direction:row;align-items:stretch;gap:8px;
  padding:0 14px 0 10px;overflow:hidden;position:relative}
/* The portrait is taller than the tile and clipped by it, so it can
   reach the foot without making the box grow. */
.slate-rank .slate-face{height:67px}
/* The owner's own man — his glass in green. */
.slate-rank.is-held{
  background:linear-gradient(180deg,#15803d3d,#15803d14);
  border-color:#7ee2a84d}
/* A man in the opponent's ten this week — the same glass in red. */
.slate-rank.is-against{
  background:linear-gradient(180deg,#7f1d1d47,#7f1d1d1a);
  border-color:#e0707c4d}
/* The rank between one tile and the next, in the day separators'
   own style — gold, and outside the glass. */
.slate-rankno{padding:0 8px;margin:0}
.slate-rankno b{font-size:12px;letter-spacing:.1em}

/* Where the rank was: what he is projected for. */
.slate-rk{align-self:center;flex:0 0 auto;
  font-size:14px;font-weight:700;color:#fff;
  min-width:34px;text-align:center}

/* Not a circle: a taller portrait, held to the foot of the tile and
   fading out at its own bottom. */
.slate-face{flex:0 0 auto;width:38px;align-self:flex-end;
  position:relative;overflow:hidden}
/* Lifted a few pixels off the foot, so he is not planted on the
   very bottom edge of the glass. */
.slate-face img{position:absolute;left:50%;bottom:4px;
  transform:translateX(-50%);
  width:auto;height:62px;object-fit:contain;object-position:bottom;
  -webkit-mask-image:linear-gradient(180deg,#000 62%,transparent);
  mask-image:linear-gradient(180deg,#000 62%,transparent)}

/* Three lines in the same 67px: the name, the club, the figures.
   Tighter leading and a touch smaller, so nothing has to grow. */
.slate-rktext{align-self:center;display:flex;flex-direction:column;
  gap:2px;min-width:0;line-height:1.2}
.slate-rktext b{font-size:11.5px;white-space:nowrap}
.slate-rkline{display:flex;align-items:center;gap:5px;
  font-family:var(--cond);font-size:8.5px;letter-spacing:.06em;
  color:var(--muted);white-space:nowrap}
.slate-rkclub{width:12px;height:12px;object-fit:contain}

/* The label takes the colour of the position it is naming — red
   for the fixtures, then each position's own. The block is
   .slate-week, which is the red panel at the head of the band. */
.slate-week{transition:background .4s ease}
.slate.band-QB .slate-week{background:var(--pos-qb);color:#0b1220}
.slate.band-RB .slate-week{background:var(--pos-rb);color:#0b1220}
.slate.band-WR .slate-week{background:var(--pos-wr);color:#0b1220}
.slate.band-TE .slate-week{background:var(--pos-te);color:#0b1220}

/* The figures behind a projection, under the club and quieter. */
.slate-rkline2{font-family:var(--cond);font-size:8px;
  letter-spacing:.04em;color:#7d8797;white-space:nowrap}

/* The week label steps the band on by hand. */
.slate-week.can-step{cursor:pointer}
.slate-week.can-step:hover{color:var(--text)}
/* Out and back as a face changes, at the board's own rates. */
.mu .slate-week{transition:opacity .5s ease}
.mu .slate-week.is-going{opacity:0;transition:opacity .26s ease}

/* A game in progress in the band: the drive in place of a kickoff,
   the score in place of the club code, and a green mark on whoever
   has the ball. */
.slate-game.is-live{border-color:#7ee2a83d}
.slate-drive{font-weight:700;color:#dbe3ee}
.slate-score{font-size:13px;font-weight:700;color:#fff}
.slate-side.has-ball .slate-score{color:#7ee2a8}

/* A fixture opens on ESPN, so it should look like it can be. */
.slate-game.can-open{cursor:pointer}
.slate-game.can-open:hover{background:#ffffff0d}
.slate-game.can-open:active{transform:translateY(1px)}
.slate-pair{display:flex;align-items:center;gap:11px}
.slate-side{display:flex;flex-direction:column;align-items:center;gap:2px}
/* A dot in the outer corner of the favoured club — the away side
   carries it on the left, the home side on the right, so it is
   always on the outside of the pair. */
.slate-side{position:relative}
.slate-side.is-fav::after{content:"";position:absolute;top:-1px;
  width:5px;height:5px;border-radius:50%;background:#7ee2a8;
  box-shadow:0 0 5px #7ee2a8aa}
.slate-pair > .slate-side:first-child.is-fav::after{left:-2px}
.slate-pair > .slate-side:last-child.is-fav::after{right:-2px}

/* The over/under, beside the kickoff. */
.slate-dot{opacity:.5;margin:0 3px}
.slate-ou{color:var(--muted)}
/* 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{display:flex;align-items:center;justify-content:center;
  font-family:var(--cond);font-size:9.5px;font-weight:700;
  letter-spacing:.06em;color:#fff;white-space:nowrap}

/* 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. */
/* Side by side, equal, with room between — at every width.
   
   There was a max-width:520px rule here that stacked them, which is
   wider than most phones: it switched off the two columns on exactly
   the screen this is read on. The text shrinks instead. */
.tocome-pair{flex:1;min-height:0;display:grid;
  grid-template-columns:1fr 1fr;gap:10px;align-items:stretch}

.tocome{flex:1;min-width:0;min-height:0;display:flex;
  flex-direction:column;
  align-items:center;justify-content:center;gap:9px;
  margin:0;padding:14px 10px;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)}

/* What is already working: the same box in green.
   
   After .tocome, not before it: one class each, so at equal
   specificity the later rule wins and an earlier one would simply
   have been painted over in red. */
.tocome.tocome-done{background:linear-gradient(180deg,#15803d26,#15803d10);
  border-color:#7ee2a83d}
.tocome-done .tocome-list{color:#a8e6c1}
.tocome-done .tocome-list li::before{background:#7ee2a8}

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

/* Two to a row now, so the lines are set a touch smaller and left
   aligned — centred text at this width broke into ragged pieces. */
.tocome-list{margin:0;padding:0;list-style:none;
  display:flex;flex-direction:column;align-items:flex-start;gap:6px;
  font-family:var(--cond);font-size:10px;letter-spacing:.06em;
  line-height:1.25;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:flex-start;gap:6px}
/* The dot holds its line with the first row of the text. */
.tocome-list li::before{margin-top:5px}
.tocome-list li::before{content:"";width:4px;height:4px;flex:0 0 auto;
  border-radius:50%;background:var(--red)}


/* The commissioner's exports, in the account card. */
.exports{padding:0 16px 14px;border-top:1px solid var(--line);
  margin-top:2px;padding-top:12px}
.exports-h{margin-bottom:8px;font-family:var(--cond);font-size:9px;
  font-weight:700;letter-spacing:.16em;text-transform:uppercase;
  color:var(--muted)}
.exports-row{display:flex;gap:8px}
.exports-row .btn{flex:1;text-align:center;text-decoration:none;
  display:flex;align-items:center;justify-content:center}


/* ── rookies, and news worth catching ─────────────────────────────── */

/* A first-year man: a red glass disc on the bottom-left of his
   photograph, diagonally opposite the age. One letter — a banner across
   the foot took his chin off, and at this size a word is unreadable. */
.rrow-face[data-rookie]::before,
.tb-face[data-rookie]::before,
.nom-art[data-rookie]::before{content:"R";
  position:absolute;right:-3px;bottom:-3px;z-index:2;
  width:12px;height:12px;box-sizing:border-box;
  display:flex;align-items:center;justify-content:center;
  border-radius:999px;
  background:var(--rookie-wash);
  border:1px solid #ffffff4d;box-shadow:0 1px 3px #0007;
  color:#fff;font-family:var(--cond);font-size:9px;font-weight:700;
  line-height:1}
/* Smaller on a trade card's face, larger on the player card's. */
.tb-face[data-rookie]::before{right:-2px;bottom:-2px;width:10px;height:10px;
  font-size:7px}
/* On this card the bottom-right corner already holds the club badge, so
   the R takes the bottom-left. The age is top-left and the position chip
   top-right, which leaves each of the four corners to one thing. */
.nom-art[data-rookie]::before{right:auto;left:-5px;bottom:-5px;
  width:19px;height:19px;font-size:12px}

/* A note that landed in the last few hours. The mark glows, and its row
   draws a red edge every seven seconds — often enough to be noticed on
   a page somebody is reading, rare enough not to nag. */
.newsmark.fresh{color:#ff5a4e;
  filter:drop-shadow(0 0 3px #ff5a4e99);
  animation:news-glow 7s ease-in-out infinite}
@keyframes news-glow{
  0%,82%,100%{filter:drop-shadow(0 0 3px #ff5a4e99)}
  88%{filter:drop-shadow(0 0 7px #ff5a4ecc)}
}

.rrow.hasfresh,.farow.hasfresh{position:relative}
.rrow.hasfresh::after,.farow.hasfresh::after{content:"";
  position:absolute;inset:0;z-index:1;pointer-events:none;
  border-radius:inherit;border:1px solid transparent;
  animation:news-edge 7s ease-in-out infinite}
@keyframes news-edge{
  0%,80%,100%{border-color:transparent;
    box-shadow:0 0 0 0 #e5484d00}
  88%{border-color:#e5484d80;
    box-shadow:0 0 10px 1px #e5484d3d}
}

@media (prefers-reduced-motion:reduce){
  .newsmark.fresh,.rrow.hasfresh::after,.farow.hasfresh::after{
    animation:none}
  .rrow.hasfresh::after,.farow.hasfresh::after{border-color:#e5484d59}
}


/* The rookie filter sits with the positions but isn't one — red when
   chosen, the same red the banner on a photograph uses.

   Five buttons where there were four, and this one is a word rather
   than two letters, so they share the width evenly instead of each
   taking its own padding. */
#faPos{width:100%}
#faPos button{flex:1;padding:3px 4px;letter-spacing:.06em}
/* The rookie toggle moved out of the position strip into its own, so
   this follows it rather than staying scoped to where it used to be. */
#faClass .rookiepick.on{background:var(--red);color:#fff}


/* A third line on a players-page row: who holds him, or the game his
   club plays this week. Same size as the line above it. */
.fathird{display:flex;align-items:center;gap:5px;min-width:0;
  font-family:var(--cond);font-size:9.5px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted);white-space:nowrap}
.fathird > *{font-size:9.5px}
.faat{flex:0 0 auto;font-weight:700;color:var(--muted)}


/* ── the player card's two views ───────────────────────────────────── */

/* The toggle sits between his details and the tables below, centred and
   only as wide as its two words — a full-width bar reads as navigation
   rather than as a pair of views. */
/* Each view in its own colour when chosen — blue for the projections,
   green for the contract, amber for the metrics, so the card says
   which of the three you are looking at without the words being
   read. */
.cardseg button.cardseg-proj.on{background:#1d4c86;color:#fff}
.cardseg button.cardseg-deal.on{background:#15803d;color:#fff}
.cardseg button.cardseg-gym.on{background:#8f2230;color:#fff}
.cardseg button.cardseg-stats.on{background:#a83a6b;color:#fff}

/* Down a little and closer to the table it switches — it was sitting
   nearer the details above than the figures below, which read as
   belonging to the wrong half of the card. */
.cardseg{width:fit-content;max-width:100%;/* The same gap above and below, so the toggle sits centred between
   the header it closes and the table it opens. It was 10 above and
   6 below, which read as leaning upward. */
  margin:18px auto 16px}
.cardseg button{flex:0 0 auto;padding:4px 14px}

.cardview{display:none}
.cardview.on{display:block}

/* Laid out but not seen: a panel with display:none has no height to
   read, so measuring the taller of the two means putting each on the
   page for an instant without showing it or moving anything. */
.cardview.measuring{display:block;position:absolute;left:0;right:0;
  top:0;visibility:hidden;pointer-events:none;height:auto}

/* The two views sit in a box that keeps whatever height the projections
   need, and each view scrolls inside it. Without this the card grew and
   shrank as the reader switched tabs; with it, everything above the
   toggle — his picture, his name, his details — stays put.

   The height is taken from the projections panel once, in card.js, and
   set here as a variable. */
/* The gutter is on both panels from the start, not added when the height
   locks — adding padding afterwards narrows the panel, which reflows the
   projections taller than the height just measured for them.

   Balanced, not right-only: a gutter on one side alone left everything
   in these panels sitting off-centre against the header above and the
   news below. Both sides get it, and the block is pulled out by the
   same amount — so the contents line up with the header and the news
   while the scrollbar still has its lane. */
/* A fixed height, the same for all three views.
   
   It is what the metrics panel comes to exactly — stripe, the college
   row, two rows of two, and the padding around them. The projections
   and the contract live in that same box and scroll inside it when
   their content runs longer, which is what they already did.
   
   Fixed rather than filling: the space left over belongs to the news
   below, so a card with plenty of room shows more stories rather than
   three taller panels. */
.cardviews{position:relative;margin:0 -10px;
  flex:0 0 auto;height:229px}
.cardviews .cardview{padding-right:10px;padding-left:10px}
/* --viewh is still set by card.js for the reveal to work, but it no
   longer sizes anything — the flex chain above does. Left as a
   minimum so a very long contract can still push the panel taller. */
.cardviews[style*="--viewh"]{min-height:0}
/* The panel is a fixed box, and the view fills it. The contract holds
   only a summary now, so rather than sitting at its natural height and
   leaving a gap it stretches — the card ends in the same place on both
   tabs, which is what stops the news moving when you switch. */
.cardviews .cardview.on{
  height:100%;overflow-y:auto;overscroll-behavior:contain;
  display:flex;flex-direction:column}

/* The contract card grows to fill, and the summary inside it with it —
   three figures worth reading rather than three small boxes at the top
   of an empty panel. */
.cardviews .cardview .stat-card{flex:1 1 auto;min-height:0;
  display:flex;flex-direction:column}
.cardviews .cardview .c-sum{flex:1 1 auto;min-height:0;
  display:flex;flex-direction:column;justify-content:center;
  border-bottom:0}
.cardviews .cardview .c-facts{margin-top:12px}
/* The scrollbar sits in a gutter of its own rather than over the last
   column of figures. scrollbar-gutter reserves the space whether or not
   a bar is showing, so the table doesn't shift width when one appears;
   the padding is the fallback where that isn't supported. */
.cardviews .cardview{height:100%;overflow-y:auto;
  scrollbar-gutter:stable;
  -webkit-overflow-scrolling:touch;overscroll-behavior:contain}

/* A thin bar, in the card's own colours rather than the system's. */
.cardviews .cardview{scrollbar-width:thin;
  scrollbar-color:#ffffff33 transparent}
.cardviews .cardview::-webkit-scrollbar{width:6px}
.cardviews .cardview::-webkit-scrollbar-track{background:transparent}
.cardviews .cardview::-webkit-scrollbar-thumb{
  background:#ffffff33;border-radius:999px}
.cardviews .cardview::-webkit-scrollbar-thumb:hover{background:#ffffff4d}

/* The contract table, in the same frame the stat cards use. Scrolls
   sideways on a phone rather than crushing eight columns. */
/* The deal above its seasons: a line saying what it is, then the money
   as a row of figures. */
.c-sum{padding:10px 10px 12px;border-bottom:1px solid var(--line)}
.c-sumline{display:flex;align-items:center;gap:6px;margin-bottom:9px;
  font-family:var(--cond);font-size:10px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted)}
.c-sumline .c-club{width:15px;height:15px;flex:0 0 auto;object-fit:contain}

.c-facts{display:flex;flex-wrap:wrap;gap:8px}

/* The expander on the contract header, and the card it opens.
   .pane-expand is display:none until a wide screen shows it — here it
   is always wanted, so this puts it back. */
/* The status pill sits ahead of the name in the card's bar. */
.modal-head .news-state{flex:0 0 auto;margin-right:2px}

.stat-head .c-expand{display:flex;margin-left:auto;
  width:22px;height:22px}
.stat-head .c-expand svg{width:15px;height:15px}
/* Nothing behind it moves: a drag on the veil itself is the veil's
   to swallow, not the page's to act on. */
.contract-veil{z-index:96;overscroll-behavior:none;touch-action:none}
/* …except inside the table, which is the one thing meant to move.
   touch-action is inherited by painting order, so the scroller has
   to claim its own back. */
.contract-veil .contract-wrap{touch-action:pan-x pan-y}
/* .modal-card is pointer-events:none so the veil behind can be tapped
   to close — this one holds a scrolling table, so it takes them back. */
/* 100% of the veil, not 94vw. vw is the viewport including the
   scrollbar, and it ignores the veil's own padding — so on a narrow
   window the box was wider than the space it sits in and pushed off
   to the right instead of centring. Percentages measure the parent,
   which is what it actually has to fit inside. */
/* A fixed height, not a ceiling. With only max-height the card
   sized itself to its contents, and on iOS a touch that began
   outside the scrolling table dragged the page behind the veil
   instead of doing nothing. A card of a known height has somewhere
   for every touch to land. */
.contract-box{width:min(100%,520px);margin:auto;
  height:86dvh;max-height:86dvh;
  overscroll-behavior:contain;touch-action:pan-y;
  display:flex;flex-direction:column;pointer-events:auto;
  background:var(--slate);border:1px solid var(--line);
  border-radius:14px;overflow:hidden}
/* The body no longer scrolls: the wrapper inside it does, both
   ways, so the sticky headings have one box to stick against.
   
   With the body scrolling vertically and the wrapper horizontally,
   a sticky cell measured against the wrapper — the nearer of the
   two — while the body moved the whole table past it. That is why
   the headings scrolled away. */
.contract-body{flex:1 1 auto;min-height:0;overflow:hidden;
  overscroll-behavior:none;
  display:flex;flex-direction:column;
  padding:12px 14px 16px}
.contract-body .contract-wrap,
.contract-body .gl-host{flex:1 1 auto;min-height:0;
  overflow:auto;max-height:none;margin:0;padding-top:0;border-top:0;
  /* Stops at its own ends: no rubber-banding past the last week,
     and no scrolling the page behind when it reaches the bottom. */
  overscroll-behavior:contain;-webkit-overflow-scrolling:touch}
/* …except the log's host, which does not scroll at all — the box
   of weeks inside it does. */
.contract-body .gl-host{overflow:hidden}
/* Nothing holding the table in here — that is the point of opening it.
   It scrolls with the card rather than inside a box of its own. */
.contract-body .contract-wrap{max-height:none;margin-top:12px;
  padding-top:12px;border-top:1px solid var(--line)}
.contract-body .stat-card{background:none;border:0;padding:0}
/* The summary is all the panel shows now, and it fills the space the
   projections table occupies on the other tab — so these are the size
   of a figure worth reading rather than a label. */
.c-fact{flex:1 1 0;min-width:64px;padding:16px 6px;text-align:center;
  background:#ffffff08;border-radius:10px}
.c-fact b{display:block;font-family:var(--cond);font-size:24px;
  font-weight:700;line-height:1.1;color:var(--money);
  font-variant-numeric:tabular-nums}
.c-fact span{display:block;margin-top:5px;font-family:var(--cond);
  font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted)}
/* The year his club could walk away reads as a date, not as money. */
.c-fact.c-out b{color:var(--gold)}

/* Eight columns won't fit a phone, so the table scrolls sideways. Its
   bar sits under the rows in a gutter rather than across the bottom one,
   and it is thin and in the card's colours. */
/* The panel above is what bounds this now, so the table needs no
   ceiling of its own — one scrolling box rather than two nested. */
.contract-wrap{overflow-x:auto;padding-bottom:6px;
  border-radius:8px;
  -webkit-overflow-scrolling:touch;
  scrollbar-width:thin;scrollbar-color:#ffffff33 transparent}
.contract-wrap::-webkit-scrollbar{height:6px}
.contract-wrap::-webkit-scrollbar-track{background:transparent}
.contract-wrap::-webkit-scrollbar-thumb{
  background:#ffffff33;border-radius:999px}
/* border-collapse would square the corners off again — separate,
   with no gap, keeps the hairlines looking identical while letting
   the table round. Applies to the metrics tables too, since they
   carry this same class, so the two can never drift apart. */
/* No overflow:hidden here. It was rounding the corners, but a
   sticky heading inside a box with hidden overflow has nothing to
   stick against — the scrolling happens on .contract-wrap, further
   out, and the headings scrolled away with the rows.
   
   The corners are rounded on the wrapper instead, which does the
   same job and leaves the table free. */
.contract{width:100%;border-collapse:separate;border-spacing:0;
  font-family:var(--cond);font-variant-numeric:tabular-nums}
.contract th{padding:6px 8px;text-align:right;white-space:nowrap;
  font-size:8.5px;font-weight:700;letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted);
  border-bottom:1px solid var(--line)}
.contract td{padding:6px 8px;text-align:right;white-space:nowrap;
  vertical-align:middle;
  font-size:12px;color:var(--text);
  border-bottom:1px solid #ffffff0f}
.contract tr:last-child td{border-bottom:0}
.contract th:first-child,.contract td:first-child,
.contract th:nth-child(3),.contract td:nth-child(3){text-align:left}
.contract .c-year{font-weight:700;color:#fff}
.contract /* A year past the end of the deal, carrying only dead money. */
.c-void{font-family:var(--cond);font-size:9.5px;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:#8b6f6f}
/* Dead cap sits with the other money columns. */
.c-dead{font-weight:700;font-variant-numeric:tabular-nums;
  color:#c98b86}

.c-hit{font-weight:700;font-variant-numeric:tabular-nums;
  color:var(--money)}
.contract .c-status{font-size:10px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}
/* His club that year: the mark, then its letters.

   The cell stays a table cell — display:flex on a td takes it out of the
   row's own alignment, which is what lifted it above the line. The mark
   and the letters are laid out inside it instead. */
.contract .c-status{vertical-align:middle}
.contract .c-status > span{vertical-align:middle}
.contract .c-club{width:14px;height:14px;margin-right:5px;
  vertical-align:middle;object-fit:contain}

/* Where we have nothing filed on him. */
.cardnone{margin:0;padding:18px 4px;text-align:center;
  font-family:var(--cond);font-size:11px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted)}


/* ── depth charts ──────────────────────────────────────────────────── */

/* Room at the sides and below, and clear of the home indicator. */
/* The page is exactly as wide as the header above it.

   --bar-w is measured from that bar, which is the one element certain
   to match the visible screen. 100vw does not: it includes any sideways
   scroll room the page has created, which is how a box sized from it
   ends up centred off to the right.

   overflow-x:clip rather than hidden: hidden would make this a scroll
   container on the vertical axis too. */
/* A column the height of the screen, so the field can take whatever is
   left rather than a height guessed at in advance. */
.dcpage{width:var(--bar-w,100%);
  margin-left:auto;margin-right:auto;min-width:0;
  overflow-x:clip;
  display:flex;flex-direction:column;
  height:calc(100dvh - var(--bar-h,53px));
  /* No padding at all — the club row carries its own band, and the
     field runs to the edges of the screen so the drawers come off the
     edges too. The list keeps its own inset. */
  padding:0}

.dcview{margin-left:auto;margin-right:auto}
/* The parts either side of the field keep their own size. */
.dcpick,.dcnote{flex:0 0 auto}
/* The drawers sit against the board rather than the field, so they hold
   their place when the view switches to the list. */
.dcboard{position:relative;display:flex;flex-direction:column;
  flex:1 1 auto;min-height:0}
/* And on a phone, pinned to the header's own left edge rather than
   centred — margin:auto centres it in whatever the body turns out to
   be, which is the thing that put it off to the right. Above 900px the
   page is narrower than the screen and centring is what you want. */
/* Pinned to the header's own left edge — margin:auto would centre it in
   whatever the body turns out to be, which is what put it off to the
   right. The page spans the full width at every size now, so the club
   row and the field run edge to edge on desktop too. */
.dcpage{margin-left:var(--bar-left,0px);margin-right:0}

/* The clubs, as a row of marks that scrolls. */
/* min-width:0 and max-width:100% are what make the scrolling work.

   Thirty-two buttons come to about 1850px, and a flex container will
   not shrink below its own content unless told to — so the row grew to
   that width, took the page with it, and the field at width:100% grew
   too. overflow-x:auto can only clip once the box is allowed to be
   narrower than what is inside it. */
/* A band of its own behind the clubs, so the row reads as a selector
   rather than as marks floating above the field. */
.dcpick{display:flex;gap:6px;overflow-x:auto;
  padding:10px 14px;
  background:linear-gradient(180deg,#151d28,#101720);
  border-bottom:1px solid var(--line);
  box-shadow:0 2px 10px #0006;
  min-width:0;max-width:100%;
  -webkit-overflow-scrolling:touch;scrollbar-width:thin;
  scrollbar-color:#ffffff26 transparent}
.dcpick::-webkit-scrollbar{height:5px}
.dcpick::-webkit-scrollbar-thumb{background:#ffffff26;border-radius:999px}
.dcteam{flex:0 0 auto;display:flex;flex-direction:column;align-items:center;
  gap:2px;width:52px;padding:6px 2px;border:1px solid transparent;
  border-radius:9px;background:none;cursor:pointer}
.dcteam img{width:26px;height:26px;object-fit:contain}
.dcteam span{font-family:var(--cond);font-size:8.5px;font-weight:700;
  letter-spacing:.08em;color:var(--muted)}
.dcteam.on{background:var(--slate);border-color:var(--line)}
.dcteam.on span{color:#fff}

/* The two men above the field. */
/* The head coach, on a stripe across the top of the field in the club's
   own colour — the same banner the stats card wears. */
/* The club's banner, above whichever view is showing — in the flow
   rather than floating on the turf, so it holds its place when the
   field gives way to the list. */
.dchcbar{position:relative;z-index:4;flex:0 0 auto;
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:7px 14px;
  border-bottom:1px solid #00000059}
.dchc-club{display:flex;align-items:center;gap:8px;min-width:0}
.dchc-mark{width:30px;height:30px;flex:0 0 auto;object-fit:contain;
  filter:drop-shadow(0 2px 4px #0009)}
/* The club, the way the stats card names it: city bold, name light. */
.dchc-name{display:flex;flex-direction:column;min-width:0;
  font-family:var(--cond);font-size:11px;line-height:1.15;
  text-transform:uppercase;letter-spacing:.08em;color:#fff;
  text-shadow:0 1px 3px #0009;
  overflow:hidden}
.dchc-name b{font-weight:700}
.dchc-name span{font-weight:400;opacity:.85}
.dchc-text{display:flex;flex-direction:column;align-items:flex-end;
  min-width:0;text-align:right}
.dcman{display:flex;flex-direction:column;align-items:center;gap:2px;
  min-width:0;text-align:center}
.dccoachname{max-width:60vw;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;
  font-family:var(--cond);font-size:13px;font-weight:700;color:#fff;
  letter-spacing:.04em;text-shadow:0 1px 3px #0009}
.dctenure{font-family:var(--cond);font-size:8px;letter-spacing:.12em;
  text-transform:uppercase;color:#ffffffb3;
  text-shadow:0 1px 3px #0009}
/* A first season, in green — the whole line, not just the word. */
.dctenure.new{color:#4ade80;font-weight:700}
.dcrole{font-family:var(--cond);font-size:7.5px;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:#ffffff8a}
.dcnostaff{font-family:var(--cond);font-size:11px;color:#4a5666}

/* ── the field ─────────────────────────────────────────────────────── */

/* Looking at the posts from the twenty: the lines converge toward the
   top and the far end fades to black, so the goal line reads as
   distance rather than as a stripe. */
/* The field keeps its shape, and shrinks where the screen is short.

   aspect-ratio gives it a height from its width, which is the honest
   way round — min-height:340px was fighting that on a phone and pushing
   the box past the fold. max-height is the backstop: everything above
   and below the field comes to roughly 220px, so that is what it can't
   exceed on a short screen. */
/* Sized against the SCREEN, not against its parent.

   width:100% is 100% of whatever the page turns out to be — and if
   anything on the page is wider than the viewport, the field inherits
   that and runs off to the right. Measuring from the viewport itself
   means it cannot, whatever else the page does.

   28px is the page's own padding either side; the height leaves the
   same cushion at the foot. */
.dcfield{position:relative;
  /* Edge to edge, and down to the foot of the screen. */
  width:100%;
  border-radius:0;border-left:0;border-right:0;border-bottom:0;
  /* Everything the page has left. The club row above it and the note
     below are the only other things on the page, so this is what is
     free — no fixed ceiling, so a tall phone gets a tall field. */
  flex:1 1 auto;min-height:300px;
  margin:0 auto;
  overflow:hidden;border-top:1px solid var(--line);
  background:#0a1a10}

/* A blue-grey field, darker at the far end so the turf itself recedes
   before the fade over it takes hold. */
.dcturf{position:absolute;inset:0;
  background:linear-gradient(180deg,#141d26 0%,#1d2b38 38%,#2a3d4d 100%)}



/* The yard lines, edge to edge in the league's own red, thinning and
   fading as they recede. */
.dcyard{position:absolute;left:0;right:0;height:2px;
  background:var(--red)}
.dcyard.y1{bottom:6%;opacity:.85}
.dcyard.y2{bottom:23%;opacity:.55;height:2px}
.dcyard.y3{bottom:39%;opacity:.34;height:1px}
.dcyard.y4{bottom:53%;opacity:.2;height:1px}
.dcyard.y5{bottom:64%;opacity:.1;height:1px}

/* Everything past the halfway mark goes to black. */
/* The far end goes to black, and quickly — the distance is meant to
   read as distance rather than as a gradient. Clear of the receivers,
   who stand at half the field's depth. */
.dcfade{position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,#000 0%,#000000d9 5%,
    #00000038 11%,transparent 17%)}

/* The club's own mark, faint, behind the play. */
.dcboard{--dclogo:none}
.dcfield::before{content:"";position:absolute;left:50%;top:62%;
  width:180px;height:180px;margin:-90px 0 0 -90px;
  background-image:var(--dclogo);background-size:contain;
  background-repeat:no-repeat;background-position:center;
  opacity:.09;pointer-events:none}

/* ── the lineup ────────────────────────────────────────────────────── */

/* The lineup keeps clear of the home indicator, since the turf now
   runs under it. */
.dcline{position:absolute;left:0;right:0;top:0;
  bottom:var(--sab,0px);
  transition:filter .24s ease,opacity .24s ease}
/* With a drawer open, what is behind it softens — the panel is the
   thing being read, and a lineup in sharp focus underneath competes
   with it. */
/* Whichever view is showing softens behind an open drawer. */
.dcboard.veiled .dcline,
.dcboard.veiled .dcir,
.dcboard.veiled .dclist{filter:blur(3px);opacity:.5}
.dcboard.veiled .dcturf{filter:blur(2px)}
.dcir,.dcturf,.dclist{
  transition:filter .24s ease,opacity .24s ease}
.dcspot{position:absolute;transform:translate(-50%,-50%);
  display:flex;flex-direction:column;align-items:center;gap:4px;
  width:88px;min-width:0}
.dcspot.open{z-index:5}

/* The slot, in its position's own colour — a stripe across the foot of
   his card rather than a tag over his head. */
.dcman-btn .dcslot{width:100%;margin-top:1px;border-radius:0 0 8px 8px;
  text-align:center}
.dcslot{padding:1px 6px;border-radius:4px;
  font-family:var(--cond);font-size:8px;font-weight:700;
  letter-spacing:.12em;text-transform:uppercase;
  background:#0b1018b3;color:#ffffffb3}
.dcslot.pos-QB{background:var(--pos-qb);color:var(--pos-ink)}
.dcslot.pos-RB{background:var(--pos-rb);color:var(--pos-ink)}
.dcslot.pos-WR{background:var(--pos-wr);color:var(--pos-ink)}
.dcslot.pos-TE{background:var(--pos-te);color:var(--pos-ink)}
.dcempty{font-family:var(--cond);font-size:12px;color:#ffffff4d}

.dcman-btn{display:flex;flex-direction:column;align-items:center;gap:3px;
  padding:0;border:0;background:none;cursor:pointer;
  transition:transform .12s ease}
.dcman-btn:active{transform:scale(.96)}
/* What he is paid, on the corner of his card: white, ringed in green,
   so it reads against any photograph behind it. */
.dcdeal{position:absolute;top:-5px;right:-6px;z-index:4;
  padding:1px 5px;border-radius:5px;
  background:#fff;border:1.5px solid #22c55e;color:#0b1018;
  font-family:var(--cond);font-size:8.5px;font-weight:700;
  letter-spacing:.04em;line-height:1.35;white-space:nowrap;
  box-shadow:0 1px 4px #0009}
/* A price nobody has paid yet, rather than a salary — ringed in grey so
   the two aren't read as the same thing. */
.dcdeal.ask{border-color:#8b98a8;color:#3d4854}

.dcface{position:relative;width:54px;height:60px;border-radius:9px;
  background:#0b1018cc;border:1px solid #ffffff33;
  box-shadow:0 2px 8px #0006;
  display:flex;align-items:flex-end;justify-content:center}
/* A first-year man on red, one the reader holds on green — the same
   pair the players page uses, read before his picture even loads. */
.dcface.rookie{background:var(--rookie-wash);border-color:#bfdbfe99}
/* In doubt for the week: bright yellow, ringed. Loud on purpose — it
   is the one thing on this chart that changes a lineup decision. */
.dcface.iffy{background:#f5c518;border-color:#ffe066;
  box-shadow:0 0 0 2px #f5c51859,0 2px 8px #0006}
.dcface.mine{background:#14532d;border-color:#22c55e66}
.dcface > img{position:absolute;inset:0;width:100%;height:100%;
  border-radius:9px;object-fit:cover;object-position:top center}

.dcname{display:flex;align-items:center;gap:3px}
.dcname b{font-family:var(--cond);font-size:12px;font-weight:700;
  letter-spacing:.03em;color:#fff;text-shadow:0 1px 3px #000c}
.dcinj{font-family:var(--cond);font-size:7.5px;font-weight:700;
  letter-spacing:.06em;color:#ff6b6b}

/* Who holds him. Grey for anybody, green where it is the reader. */
.dcowner{font-family:var(--cond);font-size:8.5px;font-weight:700;
  letter-spacing:.06em;text-transform:uppercase;color:#ffffff8a;
  text-shadow:0 1px 3px #000c}
.dcowner.mine{color:#4ade80}
/* Nobody holds him, in the league's own red — the thing worth spotting
   when you are reading a chart for somebody to sign. */
.dcowner.free{color:var(--red)}
/* The arrow saying there are more men behind him. Just the arrow, and
   big enough to read as a control. */
/* The arrow is a button now, so it needs stripping — a button brings
   its own background, border and padding, which is the grey box that
   appeared behind it. */
.dccaret{display:block;margin-top:-1px;padding:2px 8px;
  background:none;border:0;-webkit-appearance:none;appearance:none;
  font-family:inherit;font-size:15px;line-height:1;color:#fff;
  text-shadow:0 1px 3px #000c;cursor:pointer;
  transition:transform .16s ease,color .16s ease}
.dcspot.open .dccaret{transform:rotate(180deg);color:var(--red)}

/* The men behind him, opened by pressing his name. */
/* Opened under the man it belongs to. The outside receivers sit near
   the touchline, so theirs is nudged inward by the rules below rather
   than hanging off the field. */
.dcdeep{position:absolute;top:calc(100% + 4px);left:50%;
  transform:translateX(-50%);z-index:6;min-width:132px;max-width:170px;
  padding:5px 7px;border-radius:8px;
  background:#0b1018f2;border:1px solid var(--line);
  box-shadow:0 6px 18px #000a}
.dcdeeprow{display:flex;align-items:center;gap:6px;
  padding:4px 6px;border-radius:6px;
  font-family:var(--cond);font-size:10px;color:var(--text);
  white-space:nowrap}
.dcdeeprow + .dcdeeprow{margin-top:2px}
/* The same pair as everywhere: red for a first-year man, green for one
   the reader holds. */
/* Softer on a row, where the wash sits behind text rather than behind a
   photograph: the violet sits at low strength so the names stay
   readable and the colour still shows. */
.dcdeeprow.rookie{background:#2f6fd04d}
.dcdeeprow.iffy{background:#f5c5182e;
  box-shadow:inset 0 0 0 1px #f5c51859}
.dcdeeprow.mine{background:#12352480}
/* His picture in the list, smaller than on the field. */
.dcdeep .dcface{flex:0 0 auto;width:26px;height:29px;border-radius:5px;
  box-shadow:none}
.dcdeep .dcface > img{border-radius:5px}
.dcdeepmid{display:flex;flex-direction:column;gap:0;min-width:0}
.dcdeeptop{display:flex;align-items:center;gap:5px;min-width:0}
.dcdeepname{overflow:hidden;text-overflow:ellipsis}
.dcdeepmid .dcowner{font-size:8px;text-shadow:none}

/* Whatever went wrong, in place of the clubs. */
.dcsay{margin:24px auto;text-align:center;max-width:340px;
  font-family:var(--cond);font-size:12px;letter-spacing:.06em;
  color:var(--muted)}

/* Ruled out for the week: he keeps his place on the chart but sits at
   the foot of his slot, dimmed, so the order says who is playing. */
.dcdeeprow.isout,.dcrow.isout{opacity:.55}
.dcdeeprow.isout .dcdeepname,.dcrow.isout .dcrowname b{
  text-decoration:line-through;text-decoration-color:#ff6b6b80}

/* The men at the edges open theirs inward. */
.dcspot-LWR .dcdeep{left:0;transform:none}
.dcspot-RWR .dcdeep{left:auto;right:0;transform:none}
/* The back is the lowest man and opens upward — the field clips its own
   overflow, so a list hung below him would be cut in half. The
   quarterback opens downward into the gap above the back, which is
   clearer than a list rising into the receivers. */
.dcspot-RB .dcdeep{top:auto;bottom:calc(100% + 4px)}

/* Empty most of the time — it only speaks when a slot has nobody in
   it — so it takes no room at all unless it has something to say. */
.dcnote:empty{display:none}
.dcnote{margin:8px 14px calc(8px + var(--sab,0px));
  text-align:center;font-family:var(--cond);
  font-size:10px;letter-spacing:.08em;text-transform:uppercase;
  color:var(--muted)}

@media (max-width:560px){
  .dcspot{width:82px}
  .dcface{width:54px;height:60px;border-radius:10px}
  .dcface > img{border-radius:10px}
  .dcname b{font-size:11.5px}
  .dcslot{font-size:8px;padding:1px 6px}
  .dcowner{font-size:9px}
}


/* ── the depth chart as a list ─────────────────────────────────────── */

/* Field or list, over the board. */
.dcview{width:fit-content;margin:10px auto;flex:0 0 auto}
.dcview button{flex:0 0 auto;padding:4px 16px}
/* Each view has its own colour when it is the one showing — green for
   the field, blue for the list — so the toggle says which you are
   looking at without reading the words. */
.dcview button[data-view="field"].on{background:#166534;color:#fff}
.dcview button[data-view="list"].on{background:#1d4c86;color:#fff}

/* Both views fade rather than cut. */
.dcfield,.dclist{transition:opacity .16s ease}
.dcfield.fading,.dclist.fading{opacity:0}

/* The list keeps its inset — only the field runs to the edges. */
.dclist{padding:0 14px calc(14px + var(--sab,0px));
  flex:1 1 auto;min-height:0;overflow-y:auto;
  -webkit-overflow-scrolling:touch;
  scrollbar-width:thin;scrollbar-color:#ffffff26 transparent}
.dclist::-webkit-scrollbar{width:6px}
.dclist::-webkit-scrollbar-thumb{background:#ffffff26;border-radius:999px}

.dcgroup{margin-bottom:12px}
.dcgrouphead{margin-bottom:5px}

.dcrow{display:flex;align-items:center;gap:9px;padding:5px 8px;
  border-radius:9px;background:var(--slate);
  border:1px solid var(--line);cursor:pointer;
  transition:background .12s ease}
.dcrow:hover{background:var(--slate-2)}
.dcrow + .dcrow{margin-top:4px}
/* The same pair as on the field. */
/* In the list the wash sits behind the photograph only — a whole row of
   it fought with the text and said less than a marked face does. */
.dcrow.rookie{background:var(--slate);border-color:var(--line)}
.dcrow.iffy{background:#f5c5181f;border-color:#f5c51866}
.dcrow.rookie .dcface{background:var(--rookie-wash);
  border-color:#ffffff4d}

/* A man on injured reserve gets the red backdrop his roster card has. */
.dcrow-ir{opacity:1;background:#3d1418;border-color:#ff3b3040}
.dcrow-ir .dcrowname b{color:#ffd9d9}
.dcrow.mine{background:#123524;border-color:#22c55e40}
.dcrow-none{font-family:var(--cond);font-size:10px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted);justify-content:center}

.dcrowno{flex:0 0 auto;width:12px;text-align:center;
  font-family:var(--cond);font-size:10px;font-weight:700;
  color:var(--muted)}
/* The list's photographs are smaller than the field's. */
.dclist .dcface{width:34px;height:38px;border-radius:7px;
  box-shadow:none}
.dclist .dcface > img{border-radius:7px}

.dcrowmid{display:flex;flex-direction:column;gap:1px;min-width:0;
  flex:1 1 auto}

/* What he costs and what he is projected for, before the button. */
.dcfigs-row{display:flex;flex-direction:column;align-items:flex-end;
  gap:1px;flex:0 0 auto;margin-right:2px}
.dcsal{font-family:var(--cond);font-size:13px;font-weight:700;
  color:var(--money);font-variant-numeric:tabular-nums}
/* A price nobody has paid yet reads differently from a salary. */
.dcsal.ask{color:var(--muted)}
.dcproj{font-family:var(--cond);font-size:11px;font-weight:700;
  color:var(--text);font-variant-numeric:tabular-nums}
.dcproj.none{color:#4a5666}

/* And in the dropdown, what he is paid. */
.dcdeepsal{font-family:var(--cond);font-size:9px;font-weight:700;
  color:var(--money)}

/* The button at the end of a row — the players page's own Add and
   Trade, which are sized for a grid column, so they are given a width
   here rather than filling the row. */
.dcrow .faadd,.dcrow .fatrade,.dcrow .falocked{
  flex:0 0 auto;width:auto;min-width:62px;padding:5px 12px}
.dcrow .faadd-gap{flex:0 0 auto;width:62px}
.dcrowname{display:flex;align-items:center;gap:5px;min-width:0}
.dcrowname b{font-family:var(--ui);font-size:13px;font-weight:600;
  color:#fff;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}


/* ── the team stats drawer ─────────────────────────────────────────── */

/* A tab on the field's right edge, in red glass. It opens a panel that
   will hold this club's tendencies — run share, pass share, plays per
   game. Empty for now; the shape is here so the figures have somewhere
   to land. */
.dctab{position:absolute;right:0;top:50%;z-index:7;
  transform:translateY(-50%);
  display:flex;flex-direction:column;align-items:center;gap:5px;
  padding:12px 5px;border:0;border-right:0;
  border-radius:9px 0 0 9px;
  background:linear-gradient(180deg,#e5484dcc,#c1272dd9);
  box-shadow:-2px 0 10px #0007,inset 1px 0 0 #ffffff26;
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
  color:#fff;cursor:pointer;
  transition:transform .24s cubic-bezier(.22,.7,.3,1)}
.dctab-word{writing-mode:vertical-rl;text-orientation:mixed;
  font-family:var(--cond);font-size:9px;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase}
.dctab-arrow{font-size:9px;line-height:1;
  transition:transform .24s ease}
.dctab.on{transform:translateY(-50%) translateX(calc(-1 * var(--dcsidew)))}
.dctab.on .dctab-arrow{transform:rotate(180deg)}

/* The panel slides on the same curve and over the same time as its tab,
   so the two edges travel together. It used to appear and vanish
   outright, which left the tab crossing an edge that was already there
   — the clip you saw at each end of the movement. */
.dcside{--dcsidew:min(78vw,280px);
  /* Below the club's banner, which stays visible either side of an
     open drawer. */
  position:absolute;top:var(--dcbannerh,46px);right:0;bottom:0;z-index:6;
  display:flex;flex-direction:column;
  width:var(--dcsidew);box-sizing:border-box;
  background:#0b1018f2;border-left:1px solid var(--line);
  box-shadow:-8px 0 24px #0009;
  overflow:hidden;
  transform:translateX(100%);
  /* Off the field and out of reach until it is open — it sits over the
     turf, so a closed panel must not take taps meant for a player. */
  visibility:hidden;
  transition:transform .24s cubic-bezier(.22,.7,.3,1),
    visibility 0s linear .24s}
.dcside.on{transform:translateX(0);visibility:visible;
  transition:transform .24s cubic-bezier(.22,.7,.3,1),
    visibility 0s}
.dcside-left{transform:translateX(-100%)}
.dcside-left.on{transform:translateX(0)}
/* Above the glow, which sits at 0 — the rows, the filter and the
   header all read over it rather than under it. */
.dcside-body{position:relative;z-index:2;
  flex:1 1 auto;min-height:0;padding:10px 12px 12px;
  overflow-y:auto;-webkit-overflow-scrolling:touch;
  scrollbar-width:thin;scrollbar-color:#ffffff26 transparent}
.dcside-body::-webkit-scrollbar{width:5px}
.dcside-body::-webkit-scrollbar-thumb{background:#ffffff26;
  border-radius:999px}

/* The club's own colour across the top, with its mark and name. */
.dcside-stripe{position:relative;z-index:2;
  flex:0 0 auto;display:flex;align-items:center;gap:8px;
  padding:8px 10px;border-bottom:1px solid #00000059}
/* The mark alone on the left, with the record opposite — no name
   between them, so it can be a little larger. */
.dcside-stripe img{width:32px;height:32px;flex:0 0 auto;
  object-fit:contain;filter:drop-shadow(0 1px 3px #0009)}
.dcside-name{display:flex;flex-direction:column;min-width:0;
  font-family:var(--cond);font-size:12px;line-height:1.15;
  text-transform:uppercase;letter-spacing:.06em;color:#fff;
  text-shadow:0 1px 3px #0009}
.dcside-name b{font-weight:700}
.dcside-name span{font-weight:400;opacity:.9}
/* Solid at the right end rather than fading out — the gradient let the
   glow behind show through exactly where the two meet. */
.dcside-stripe-ranks{background:linear-gradient(90deg,#166534,#14532d)}

/* The ranks drawer opens from the other side. */
.dcside-left{right:auto;left:0;
  transform:translateX(-100%);
  border-left:0;border-right:1px solid var(--line);
  box-shadow:8px 0 24px #0009}
.dctab-left{right:auto;left:0;
  border-radius:0 9px 9px 0;
  background:linear-gradient(180deg,#22c55ecc,#166534d9);
  box-shadow:2px 0 10px #0007,inset -1px 0 0 #ffffff26}
/* A glow inside the panel's right edge, coloured by how far down the
   table you have read — green among the best clubs, red among the
   worst. Contained rather than bleeding outward: an inset gradient,
   so nothing spills onto the field beside it.

   z-index 1 keeps it under the header stripe, which sits at 2. */
.dcside-left::after{content:"";position:absolute;top:0;bottom:0;
  right:0;width:34px;pointer-events:none;z-index:0;
  /* One colour, faded out by a mask rather than by mixing — mixing
     needs color-mix, which older Safari on a phone doesn't have. */
  background:var(--dcglow,#22c55e);
  -webkit-mask-image:linear-gradient(270deg,#000 0%,#0000006b 40%,
    transparent 100%);
  mask-image:linear-gradient(270deg,#000 0%,#0000006b 40%,transparent 100%);
  opacity:.45;
  transition:background .18s linear}
/* The edge itself, a thin line in the same colour. */
.dcside-left::before{content:"";position:absolute;top:0;bottom:0;
  right:0;width:2px;pointer-events:none;z-index:0;
  background:var(--dcglow,#22c55e);opacity:.8;
  transition:background .18s linear}
.dctab-left.on{transform:translateY(-50%) translateX(var(--dcsidew))}

/* Which metric the table is sorted by. */
.dcrankpick{width:100%;margin-bottom:8px;padding:5px 7px;
  border-radius:7px;background:var(--slate);color:#fff;
  border:1px solid var(--line);
  font-family:var(--cond);font-size:11px;letter-spacing:.06em}

.dcranklist{display:flex;flex-direction:column;gap:3px}
.dcrankrow{display:flex;align-items:center;gap:9px;
  padding:6px 8px;border-radius:7px;cursor:pointer;
  font-family:var(--cond);font-size:13px;color:var(--text)}
.dcrankrow:hover{background:#ffffff0a}
.dcrankrow.on{background:#22c55e26;
  box-shadow:inset 0 0 0 1px #22c55e4d}
.dcrankno{flex:0 0 auto;width:20px;text-align:right;font-size:12px;
  font-weight:700;color:var(--muted)}
.dcrankmark{width:24px;height:24px;flex:0 0 auto;object-fit:contain}
.dcrankteam{flex:1 1 auto;font-weight:700;letter-spacing:.08em;
  font-size:13px}
.dcrankval{flex:0 0 auto;font-size:13px;font-weight:700;
  font-variant-numeric:tabular-nums;color:#fff}
/* The tabs read the panels' width from here. */
.dcboard{--dcsidew:min(78vw,280px)}

.dcside-head{margin-bottom:10px;font-family:var(--cond);font-size:10px;
  font-weight:700;letter-spacing:.16em;text-transform:uppercase;
  color:var(--muted)}
.dcside-soon{margin:0;font-family:var(--cond);font-size:11px;
  letter-spacing:.08em;text-transform:uppercase;color:#4a5666}

/* The run and pass split, as a bar before the figures. */
.dcsplit{margin-bottom:12px}
.dcbar{display:flex;height:8px;border-radius:999px;overflow:hidden;
  background:#ffffff14}
.dcbar-pass{background:var(--pos-wr)}
.dcbar-run{background:var(--pos-rb)}
.dckeys{display:flex;justify-content:space-between;margin-top:5px}
.dckey{display:flex;flex-direction:column}
.dckey b{font-family:var(--cond);font-size:15px;font-weight:700;
  line-height:1.1;font-variant-numeric:tabular-nums}
.dckey.pass b{color:var(--pos-wr)}
.dckey.run b{color:var(--pos-rb)}
.dckey span{font-family:var(--cond);font-size:8px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted)}
.dckey.run{text-align:right}

/* Passing on the left, rushing on the right, and what belongs to
   neither below a rule. */
.dchalves{display:grid;grid-template-columns:1fr 1fr;gap:6px;
  margin-bottom:10px}
.dchalf{display:flex;flex-direction:column;gap:5px;min-width:0}
.dchalf-head{padding-bottom:3px;border-bottom:1px solid #ffffff1f;
  font-family:var(--cond);font-size:9px;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;color:#ffffffb3}

.dcrule{height:1px;margin:2px 0 10px;background:#ffffff1f}

/* Every figure under a banner saying where it ranks. */
.dcfigs{display:grid;grid-template-columns:1fr 1fr;gap:6px}
.dcfig{text-align:center;border-radius:7px;overflow:hidden;
  background:#ffffff0a}
.dcfig-rank{padding:2px 3px;
  font-family:var(--cond);font-size:8px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase}
/* Top ten green, bottom ten red, the middle plain. */
.dcfig-rank.good{background:#22c55e;color:#052e16}
.dcfig-rank.bad{background:#ef4444;color:#450a0a}
.dcfig-rank.mid{background:#fff;color:#0b1018}
.dcfig b{display:block;margin-top:5px;font-family:var(--cond);
  font-size:15px;font-weight:700;line-height:1.1;color:#fff;
  font-variant-numeric:tabular-nums}
/* Below zero — EPA mostly, where a minus is the whole point. */
.dcfig b.under{color:#ff6b6b}
.dcfig span{display:block;margin:2px 0 6px;font-family:var(--cond);
  font-size:7.5px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted)}

.dcside-note{margin:10px 0 0;text-align:center;font-family:var(--cond);
  font-size:8px;letter-spacing:.1em;text-transform:uppercase;
  color:#4a5666}


/* ── injured reserve, and whose chart this is ──────────────────────── */

/* Those set aside, under the head coach. Not in the rotation, so not on
   the field — but worth seeing without leaving the page. */
/* Those set aside, in the near-left corner — clear of the coaches at
   the top and of the back, who stands centre. */
.dcir{position:absolute;left:10px;
  bottom:calc(10px + var(--sab,0px));z-index:5;
  max-width:42%;padding:6px 8px;border-radius:8px;
  background:#0b1018d9;border:1px solid #ffffff1f}
/* Tighter tracking and no wrap: "Injured Reserve" is twice the width
   of "IR" and this box is capped at 42% of the field. */
.dcirhead{display:block;margin-bottom:4px;
  font-family:var(--cond);font-size:8px;font-weight:700;
  letter-spacing:.08em;text-transform:uppercase;color:#ff6b6b;
  white-space:nowrap}
.dcirlist{display:flex;flex-direction:column;gap:2px;
  max-height:104px;overflow-y:auto;
  scrollbar-width:thin;scrollbar-color:#ffffff26 transparent}
.dcirlist::-webkit-scrollbar{width:4px}
.dcirlist::-webkit-scrollbar-thumb{background:#ffffff26;border-radius:999px}
.dcirrow{display:flex;align-items:baseline;gap:5px;white-space:nowrap;
  font-family:var(--cond);font-size:9.5px;color:#ffffffcc}
.dcirpos{flex:0 0 auto;width:16px;color:var(--muted);font-weight:700}
.dcirname{overflow:hidden;text-overflow:ellipsis}
.dcirrow .dcowner{font-size:8px;text-shadow:none}

/* Last season, opposite the club's name on the stats banner. */
.dcside-rec{margin-left:auto;display:flex;flex-direction:column;
  align-items:flex-end;gap:1px;flex:0 0 auto}
.dcrecord{font-family:var(--cond);font-size:19px;font-weight:700;
  line-height:1;color:#fff;letter-spacing:.02em;
  font-variant-numeric:tabular-nums;
  text-shadow:0 1px 3px #0009}
/* Bottom ten by wins. */
.dcrecord.poor{color:#ff6b6b}
/* And the champion, in gold. */
.dcrecord.champ{color:#f5c518;
  text-shadow:0 0 14px #f5c51859,0 2px 6px #000d}
.dcrecnote{font-family:var(--cond);font-size:7.5px;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:#ffffffb3;
  text-shadow:0 1px 3px #0009;white-space:nowrap}
.dcrecnote.champ{color:#f5c518}

/* The list view's own IR group. */
.dcslot-ir{background:#3d1418;color:#ff9b9b}


/* ── the depth chart on a larger screen ────────────────────────────── */

/* Everything here was sized for a phone held in one hand. On a desktop
   that leaves a lot of empty turf and type too small to read at arm's
   length, so the whole chart scales up — but only past the width where
   there is genuinely room for it. */
@media (min-width:900px){
  /* The club row: bigger marks, more air. */
  .dcpick{gap:10px;padding:14px 20px}
  .dcteam{width:70px;padding:8px 4px;gap:4px}
  .dcteam img{width:36px;height:36px}
  .dcteam span{font-size:10px}

  /* The banner above the field. */
  .dchcbar{padding:11px 20px}
  .dchc-mark{width:40px;height:40px}
  .dchc-name{font-size:14px}
  .dccoachname{font-size:17px}
  .dctenure{font-size:10px}

  /* The men on the field. */
  .dcspot{width:118px;gap:5px}
  .dcface{width:74px;height:82px;border-radius:12px}
  .dcface > img{border-radius:12px}
  .dcname b{font-size:15px}
  .dcslot{font-size:10px;padding:2px 8px;border-radius:5px}
  .dcowner{font-size:11px}
  .dcinj{font-size:9.5px}
  .dccaret{font-size:19px;padding:3px 10px}

  /* The men behind him. */
  .dcdeep{min-width:180px;max-width:230px;padding:7px 9px}
  .dcdeeprow{font-size:12.5px;gap:8px;padding:5px 7px}
  .dcdeep .dcface{width:34px;height:38px;border-radius:6px}
  .dcdeep .dcface > img{border-radius:6px}
  .dcdeepmid .dcowner{font-size:10px}

  /* Those set aside. */
  .dcir{max-width:26%;padding:9px 12px;left:16px;
    bottom:calc(16px + var(--sab,0px))}
  .dcirhead{font-size:10px;margin-bottom:6px}
  .dcirrow{font-size:12px;gap:7px}
  .dcirpos{width:22px}
  .dcirlist{max-height:170px;gap:4px}

  /* The toggle and the list. */
  .dcview button{padding:6px 22px;font-size:12px}
  .dclist{padding:0 20px 20px}
  .dcgroup{margin-bottom:16px}
  .dcrow{gap:12px;padding:8px 12px;border-radius:11px}
  .dclist .dcface{width:46px;height:52px;border-radius:9px}
  .dclist .dcface > img{border-radius:9px}
  .dcrowname b{font-size:16px}
  .dcrowno{width:26px;font-size:14px}

  /* The lineup keeps its shape rather than spreading across the whole
     window — at 1440px the receivers would stand a thousand pixels
     apart, which reads as scattered rather than as a formation. The
     turf still fills the screen; only the men are held in. */
  .dcline{left:50%;right:auto;width:min(100%,980px);
    transform:translateX(-50%)}

  /* Both drawers, and what is in them. */
  .dcside{--dcsidew:min(38vw,380px)}
  .dcboard{--dcsidew:min(38vw,380px)}
  .dctab{padding:16px 7px;gap:7px}
  .dctab-word{font-size:11px}
  .dcside-stripe{padding:11px 14px}
  .dcside-stripe img{width:40px;height:40px}
  .dcside-name{font-size:14px}
  .dcrecord{font-size:24px}
  .dcrecnote{font-size:9px}
  .dcside-body{padding:14px 16px 16px}
  .dcside-head{font-size:12px}
  .dckey b{font-size:19px}
  .dckey span{font-size:10px}
  .dcbar{height:11px}
  .dchalf-head{font-size:11px}
  .dcfig-rank{font-size:9.5px;padding:3px}
  .dcfig b{font-size:19px;margin-top:7px}
  .dcfig span{font-size:9px}
  .dcrankpick{font-size:13px;padding:7px 9px}
  .dcrankrow{font-size:15px;gap:11px;padding:8px 10px}
  .dcrankmark{width:30px;height:30px}
  .dcrankteam{font-size:15px}
  .dcrankval{font-size:15px}
  .dcrankno{width:26px;font-size:14px}
}

/* Wider still — a full desktop window rather than a small laptop. */
@media (min-width:1280px){
  .dcspot{width:140px}
  .dcface{width:88px;height:98px}
  .dcname b{font-size:17px}
  .dcteam{width:80px}
  .dcteam img{width:42px;height:42px}
  .dccoachname{font-size:19px}
  .dcside{--dcsidew:420px}
  .dcboard{--dcsidew:420px}
}


/* Rosters and trades, beside the account circle. They lead to the hub,
   which holds both — a second copy here would drift out of step. */
.barbtn{display:flex;align-items:center;gap:5px;flex:0 0 auto;
  padding:5px 10px;border-radius:8px;
  background:var(--slate-2);border:1px solid var(--line);
  color:var(--text);text-decoration:none;
  font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase;
  transition:background .12s ease,transform .1s ease}
.barbtn svg{width:15px;height:15px;flex:0 0 auto}
.barbtn:hover{background:var(--slate)}
.barbtn:active{transform:translateY(1px)}
.topbar-right .barbtn{order:1}

/* On a phone the words go and the marks stay — the bar has room for
   two small buttons, not two labelled ones. */
@media (max-width:560px){
  .barbtn{padding:6px;gap:0}
  .barbtn span{display:none}
  .barbtn svg{width:17px;height:17px}
}


/* ── the players page on a larger screen ───────────────────────────── */

/* Sized for a phone, like the rest of this app. On a desktop the page
   sat 820px wide in the middle of the window with type meant to be read
   at arm's length, so the whole list scales up past the width where
   there is room for it. */
@media (min-width:900px){
  /* Only the list scrolls. The banner, the title and the filters stay
     put — this layout existed for phones and stopped at 760px, so on a
     desktop the whole page scrolled and the header went with it.

     A column the height of the window, with the list taking what is
     left. */
  .fapage{flex:1;min-height:0;display:flex;flex-direction:column;
    height:calc(100dvh - var(--bar-h,53px));box-sizing:border-box;
    overflow:hidden;
    max-width:1080px;padding:0 24px 0}
  .fahead{position:static;flex:0 0 auto;z-index:5}
  .falist{flex:1 1 0;height:0;min-height:0;overflow-y:auto;
    scrollbar-gutter:stable;-webkit-overflow-scrolling:touch;
    padding-bottom:28px}

  /* Wider columns and more air between them. The header shares this
     grid with the rows, so both are widened together — changing one
     alone would put the labels out of line with the figures. */
  .fahdr,.falist .farow{
    grid-template-columns:26px 28px 56px minmax(0,1fr) 42px 76px 64px;
    gap:10px}
  .fahdr{padding:12px 13px 7px;font-size:11px}
  .farowwrap{padding:2px 0}

  /* His photograph, and the badge on it. */
  .faface{width:54px;height:60px;border-radius:10px}
  .faposbadge{min-width:18px;padding:0 3px;font-size:8px;
    border-radius:5px}

  /* Name, club line and the figures. */
  .faname > b{font-size:15px}
  .fasub{font-size:11px;gap:7px;min-height:16px}
  .falogo{width:16px;height:16px}
  .fasal{font-size:16px}
  .fanum{font-size:15px}
  .fapos{font-size:12px}
  .faowner,.faown{font-size:11px}
  .fafree{font-size:11px}

  /* The head of the page and its controls. */
  .fatitle b{font-size:22px}
  .fahead{padding:20px 0 10px}
  .fatools{gap:10px}
  .fatoggles .seg button{padding:6px 16px;font-size:12px}
  #faSearch{font-size:14px;padding:8px 12px}
  .fateamsel{font-size:13px;padding:7px 11px}

  /* The buttons at the end of a row. */
  .faadd,.fatrade,.fab-trade{font-size:11px;padding:5px 14px}
}

/* Wider still. The page stops growing here — a list of names does not
   read better at 1600px, it just makes the eye travel. */
@media (min-width:1280px){
  .fapage{max-width:1180px}
  .faface{width:60px;height:66px}
  .faname > b{font-size:16px}
  .fasal{font-size:17px}
  .fanum{font-size:16px}
}

/* ── game day, last word ───────────────────────────────────────────
   
   These sit at the end of the file on purpose. .seg-sm comes far
   later than the game-day block and sets its own margin, so the
   toggles were being pushed left however they were written up
   there. Same weight, later rule, so this one wins. */
.gdpage .gdview,
.gdpage .gdbox-side{
  display:flex;box-sizing:border-box;
  width:calc(100% - 24px);margin-left:auto;margin-right:auto}
.gdpage .gdview{margin-top:20px;margin-bottom:0}
.gdpage .gdbox-side{margin-top:12px;margin-bottom:0}

/* And the scrolling half grows with its contents, whatever the
   board's older flex rules said. */
/* The page is a column the height of the screen: the field and the
   toggles take what they need, and everything below them scrolls in
   the room that is left.
   
   A guessed max-height was clipping the last row before; this asks
   the browser for the space that actually remains instead. */
.gdpage{display:flex;flex-direction:column;
  height:calc(100dvh - var(--bar-h,53px));overflow:hidden}
.gdpage .gdmatch,.gdpage .gdfixed{flex:0 0 auto}
.gdpage .gdfixed{position:static;box-shadow:none}
.gdpage .gdscroll{flex:1 1 auto;min-height:0;
  overflow-y:auto;overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;
  padding-bottom:calc(28px + env(safe-area-inset-bottom));
  scrollbar-width:thin;scrollbar-color:#ffffff24 transparent}
.gdpage .gdscroll::-webkit-scrollbar{width:4px}
.gdpage .gdscroll::-webkit-scrollbar-thumb{background:#ffffff24;
  border-radius:2px}
.gdpage .gdteams{margin-top:16px}

/* The hub's drawer and the lineups page are left alone: .mxf-sub is
   theirs, not game day's, and restyling it here changed pages that
   had not asked to change. */
.gdpage .gdwho i{font-size:9.5px;color:#aebdd0}
.gdpage .gdrow.hot .gdwho i{color:#c9e6d5}
.gdpage .gdrow.rz .gdwho i{color:#f3c9cc}
.gdpage .gdmen.packed .gdwho i{font-size:8.5px}

/* The chosen club fills its own toggle. */
.gdpage .gdbox-side button.on{
  background:var(--club, var(--slate-2));
  color:#fff;text-shadow:0 1px 3px #0006;
  box-shadow:inset 0 0 0 1px #ffffff2b}
.gdpage .gdbox-side button{border-radius:5px}

/* The box score is not short of scrolling — it was short of room.
   
   A guessed max-height cut the last man off at the bottom whether or
   not there was anything below him. So no inner scroller: it grows
   with its contents, the page scrolls as it always did, and the foot
   of the page has room for the last row to clear the glow and the
   phone's own bottom edge. */
.gdpage .gdbox-wrap{overflow:visible}
.gdpage .gdbox-wrap > .gdbox:last-child{padding-bottom:10px}

/* A man who is not certain to play: the same wash and letter the
   lineups page and the hub's drawer use. */
.gdpage .gdrow.is-p{background:linear-gradient(90deg,#15803d5c,#15803d1a 62%,transparent)}
.gdpage .gdrow.is-q{background:linear-gradient(90deg,#a1620066,#a162001f 62%,transparent)}
.gdpage .gdrow.is-d{background:linear-gradient(90deg,#9a3d0070,#9a3d0022 62%,transparent)}
.gdpage .gdrow.is-o{background:linear-gradient(90deg,#7f1d1d85,#7f1d1d2b 62%,transparent)}
.gdpage .gdrow.r.is-p{background:linear-gradient(270deg,#15803d5c,#15803d1a 62%,transparent)}
.gdpage .gdrow.r.is-q{background:linear-gradient(270deg,#a1620066,#a162001f 62%,transparent)}
.gdpage .gdrow.r.is-d{background:linear-gradient(270deg,#9a3d0070,#9a3d0022 62%,transparent)}
.gdpage .gdrow.r.is-o{background:linear-gradient(270deg,#7f1d1d85,#7f1d1d2b 62%,transparent)}
.gdpage .gdface{overflow:visible;position:relative}
.gdpage .gdface img{border-radius:50%}
.gdflag{position:absolute;top:-3px;left:-4px;z-index:2;
  font-family:var(--cond);font-size:7.5px;font-weight:700;
  letter-spacing:.04em;line-height:1;padding:1px 3px;
  border-radius:4px;box-shadow:0 0 0 1.5px #0b1220}
.gdrow.r .gdflag{left:auto;right:-4px}
.gdflag.is-p{background:#b8ecc9;color:#0d3a1e}
.gdflag.is-q{background:#f6e2ae;color:#4a3208}
.gdflag.is-d{background:#f7cfb0;color:#4d2408}
.gdflag.is-o{background:#f5c2be;color:#4d1414}

/* And the same at the foot of the summary side, so the last team
   metric is not sitting against the phone's bottom edge either. */
.gdpage .gdteams{padding-bottom:10px}
/* The glow is decoration and must never take a tap or cover a row. */
body:has(.gdpage)::after{z-index:-1;pointer-events:none}

/* Numbered yard lines, low and faint — they place the ball without
   competing with it. */
.gdpage .gdnums{position:absolute;inset:0;pointer-events:none;z-index:1}
.gdpage .gdnum-t{position:absolute;bottom:5px;transform:translateX(-50%);
  font-family:var(--cond);font-size:8px;font-weight:700;
  color:#ffffff3d;letter-spacing:.04em}
/* Out of the way of the play summary when there is one. */
.gdpage .gdfield:has(.gdlast.has-play) .gdnum-t{bottom:auto;top:6px}

/* Whoever has the ball, pointing the way he is going. */
.gdpage .gdpos{color:#7ee2a8;font-size:9px;line-height:1;
  filter:drop-shadow(0 0 5px #7ee2a86b);
  animation:gdposbeat 1.8s ease-in-out infinite}
@keyframes gdposbeat{0%,100%{opacity:1}50%{opacity:.45}}

/* A longer, softer rise of light from the foot of the page. */
body:has(.gdpage)::after{height:46vh;
  background:linear-gradient(0deg,#c9d6e836 0%,#c9d6e81c 24%,
    #c9d6e80f 46%,#c9d6e806 68%,transparent 100%)}

/* Win probability: where it stands, over how it got there. */
.gdpage .gdodds{position:relative;margin-bottom:4px}
.gdpage .gdodds-line{position:absolute;inset:-16px 0 8px;
  pointer-events:none;opacity:.55}
.gdpage .gdodds-line svg{width:100%;height:100%}
.gdpage .gdodds-bar{position:relative;height:7px;border-radius:4px;
  overflow:hidden;background:#7f1d1d5c}
.gdpage .gdodds-bar i{display:block;height:100%;border-radius:4px;
  background:linear-gradient(90deg,#5d96d6,#7ee2a8);
  transition:width .6s cubic-bezier(.35,.7,.3,1)}
.gdpage .gdodds-t{display:flex;align-items:center;justify-content:center;
  gap:6px;margin-top:7px}
.gdpage .gdodds-t .gdclub{width:18px;height:18px}
.gdpage .gdodds-t b{font-size:13px;color:#fff;font-weight:700}
.gdpage .gdodds-t span{font-family:var(--cond);font-size:8px;
  color:#5a6270;letter-spacing:.14em;text-transform:uppercase}

/* Every drive, newest first. */
.gdpage .gddrives{margin:16px 12px 0}
.gdpage .gddrive{display:flex;align-items:center;gap:8px;padding:6px 7px;
  border-radius:6px;background:#ffffff06;margin-bottom:4px}
.gdpage .gddrive.is-score{background:#15803d1f;
  box-shadow:inset 0 0 0 1px #7ee2a844}
.gdpage .gddrive .gdclub{width:20px;height:20px;flex:0 0 auto}
.gdpage .gddrive-mid{flex:1;min-width:0}
.gdpage .gddrive-mid b{display:block;font-size:10px;color:#dbe3ee;
  font-weight:400;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.gdpage .gddrive.is-score .gddrive-mid b{color:#a8e6c1;font-weight:700}
.gdpage .gddrive-mid i{display:block;font-style:normal;
  font-family:var(--cond);font-size:8px;color:#7d8ea4;margin-top:1px}
.gdpage .gddrive-bar{flex:0 0 54px;height:4px;border-radius:2px;
  background:#ffffff0d;overflow:hidden}
.gdpage .gddrive-bar i{display:block;height:100%;border-radius:2px;
  background:#5d96d6}
.gdpage .gddrive.is-score .gddrive-bar i{background:#7ee2a8}

/* The club name down its own end zone, painted as it would be: up
   the left end, down the right. */
.gdpage .gdendname{font-family:var(--cond);font-weight:700;
  font-size:11px;letter-spacing:.22em;color:#ffffffbf;
  text-shadow:0 1px 4px #0009;white-space:nowrap;
  text-transform:uppercase}
.gdpage .gdendname.up{writing-mode:vertical-rl;transform:rotate(180deg)}
.gdpage .gdendname.down{writing-mode:vertical-rl}
.gdpage .gdfield.packed .gdendname{font-size:9px;letter-spacing:.16em}

/* A smaller rule, for a break inside a section. */
.gdpage .gdrule-sm{margin-top:18px;
  background:linear-gradient(90deg,transparent,#ffffff2b 22%,
    #ffffff2b 78%,transparent)}
.gdpage .gdrule-sm b{color:#8b95a6;background:var(--ink)}

/* The team metrics, said a size up so they can be read. */
.gdpage .gdtsr > b{font-size:11.5px;color:#e4ebf3}
.gdpage .gdtlab{font-size:7.5px;letter-spacing:.14em;color:#6d7684}
.gdpage .gdhalf-t{font-size:10.5px}

/* Drives, by quarter. */
.gdpage .gdqhead{font-family:var(--cond);font-size:8px;color:#7d8ea4;
  letter-spacing:.16em;text-transform:uppercase;
  margin:12px 0 6px;padding-bottom:4px;
  box-shadow:inset 0 -1px 0 #ffffff12}
.gdpage .gddrives > .gdqhead:first-of-type{margin-top:8px}
.gdpage .gddrive-mid b{font-size:11.5px;color:#e4ebf3}
.gdpage .gddrive-mid i{font-size:9px;color:#8b9bb0}
.gdpage .gddrive-at{flex:0 0 auto;font-family:var(--cond);font-size:9px;
  color:#6d7684;letter-spacing:.02em;min-width:34px;text-align:right}

/* Room under the win-probability heading, so the bar and its line
   are not sitting against the rule above them. */
.gdpage .gdodds{margin-top:26px;margin-bottom:6px}
.gdpage .gdodds-line{inset:-20px 0 9px}
.gdpage .gdrule-sm{margin-top:22px}

/* The box score, said at a size worth reading. */
.gdpage .gdbox-row{grid-template-columns:minmax(0,1fr) 46px repeat(4,40px);
  font-size:13px;padding:7px 7px;gap:5px}
.gdpage .gdbox-row > span:not(.gdbox-who){font-size:13px}
.gdpage .gdbox-who{font-size:13px}
.gdpage .gdbox-row.is-head{font-size:8px;padding:0 7px 5px}
.gdpage .gdbox-row.is-head > span{font-size:8px}
.gdpage .gdbox-h{font-size:9px}
/* The points column reads as the reason this page exists — gold,
   the colour the app already uses for a figure that matters. */
.gdpage .gdbox-pts{color:#4e5663;text-align:right;
  font-family:var(--cond);font-weight:700;font-size:13.5px}
.gdpage .gdbox-pts.has{color:#e8b84b}
.gdpage .gdbox-row.is-head .gdbox-pts{color:#e8b84b;font-weight:700;
  font-size:8px;opacity:.85}

/* The owner's chance of taking the week, at the top of the page. */
.gdpage .gdsub-odds{gap:6px;align-items:center}
.gdpage .gdmine-bar{flex:1;min-width:44px;height:5px;border-radius:3px;
  background:#ffffff12;overflow:hidden}
.gdpage .gdmine-bar i{display:block;height:100%;border-radius:3px}
.gdpage .gdside.a .gdmine-bar i{background:linear-gradient(90deg,#5d96d6,#7ee2a8)}
.gdpage .gdside.b .gdmine-bar i{background:linear-gradient(90deg,#c8404f,#e0707c)}
.gdpage .gdmine-pc{flex:0 0 auto;font-family:var(--cond);font-size:10px;
  font-weight:700}
.gdpage .gdside.a .gdmine-pc{color:#7ee2a8}
.gdpage .gdside.b .gdmine-pc{color:#e0707c}

/* Game day, brought up from the foot of the hub. */
.gdsheet-veil{position:fixed;inset:0;z-index:88;background:#040810c4;
  opacity:0;transition:opacity .3s ease;-webkit-backdrop-filter:blur(2px);
  backdrop-filter:blur(2px)}
.gdsheet-veil.is-open{opacity:1}
.gdsheet{position:fixed;left:0;right:0;bottom:0;z-index:89;
  height:92dvh;background:var(--ink);border-radius:16px 16px 0 0;
  box-shadow:0 -12px 40px -12px #000d;overflow:hidden;
  display:flex;flex-direction:column;
  transform:translateY(100%);transition:transform .32s cubic-bezier(.25,.8,.3,1)}
.gdsheet.is-open{transform:translateY(0)}
.gdsheet-grab{flex:0 0 auto;padding:9px 0 7px;display:flex;
  align-items:center;justify-content:center;cursor:pointer;
  background:var(--ink);touch-action:none}
.gdsheet-grab span{width:38px;height:4px;border-radius:3px;
  background:#ffffff2b;display:block}
.gdsheet-frame{flex:1 1 auto;width:100%;border:0;display:block}

/* Framed in the hub's sheet: the app bar and the splash belong to
   the page around us, not to this one. */
html.in-sheet .topbar,
html.in-sheet .pagebanner,
html.in-sheet .boot{display:none}
html.in-sheet .gdpage{height:100dvh}

/* Which day a game is, on its chip. */
.gdpage .gdchip-day{margin-left:5px;font-size:8px;color:#7d8ea4;
  letter-spacing:.06em}
.gdpage .gdchip.on .gdchip-day{color:#bcd4ea}

/* Three views now, so each takes a little less room. */
.gdpage .gdview button{padding:7px 5px;letter-spacing:.1em;
  font-size:8.5px}

/* Who is hurt. */
.gdpage .gdhurts{margin:12px 12px 0}
.gdpage .gdhurt{display:flex;align-items:center;gap:9px;padding:8px 8px;
  border-radius:7px;background:#ffffff06;margin-bottom:5px}
.gdpage .gdhurt .gdclub{width:22px;height:22px;flex:0 0 auto}
.gdpage .gdhurt-mid{flex:1;min-width:0}
.gdpage .gdhurt-mid b{display:block;font-size:12.5px;color:#e4ebf3;
  font-weight:400;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.gdpage .gdhurt-mid i{display:block;font-style:normal;
  font-family:var(--cond);font-size:9px;color:#8b9bb0;margin-top:2px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gdpage .gdhurt-said{flex:0 0 auto;font-family:var(--cond);
  font-size:9px;font-weight:700;letter-spacing:.08em;
  text-transform:uppercase;padding:3px 7px;border-radius:5px;
  background:#ffffff0f;color:#8b95a6}
.gdpage .gdhurt-said.is-o{background:#f5c2be;color:#4d1414}
.gdpage .gdhurt-said.is-d{background:#f7cfb0;color:#4d2408}
.gdpage .gdhurt-said.is-q{background:#f6e2ae;color:#4a3208}
.gdpage .gdhurt-said.is-p{background:#b8ecc9;color:#0d3a1e}
/* One of yours, or your opponent's. */
.gdpage .gdhurt.is-mine{box-shadow:inset 0 0 0 1px #7ee2a866;
  background:#15803d1a}
.gdpage .gdhurts > .gdhurt:last-child{
  margin-bottom:calc(16px + env(safe-area-inset-bottom))}

/* The week's games, above the scoreboard: one block each, all the
   same size so the strip reads as a row rather than a ragged line. */
.gdpage .gdstrip{position:static;padding:10px 12px 2px;gap:7px;
  display:flex;overflow-x:auto;overflow-y:hidden;
  -webkit-overflow-scrolling:touch;touch-action:pan-x;
  scrollbar-width:none}
.gdpage .gdstrip::-webkit-scrollbar{display:none}
.gdpage .gdchip{flex:0 0 auto;width:104px;min-height:52px;
  flex-direction:column;align-items:stretch;justify-content:center;
  gap:5px;padding:7px 8px;border-radius:9px;
  background:#0e1728;box-shadow:inset 0 0 0 1px #ffffff14;
  -webkit-backdrop-filter:none;backdrop-filter:none}
.gdpage .gdchip.on{background:#15304d;box-shadow:inset 0 0 0 1px #4d8fc9}
.gdpage .gdchip.live{box-shadow:inset 0 0 0 1px var(--red)}
.gdpage .gdchip-line{display:flex;align-items:center;gap:3px}
.gdpage .gdchip-line .gdclub{width:18px;height:18px;flex:0 0 auto}
.gdpage .gdchip-s{font-family:var(--cond);font-size:11px;
  font-weight:700;color:#e4ebf3;min-width:15px}
.gdpage .gdchip-at{font-size:8px;color:#5a6270;margin:0 1px}
.gdpage .gdchip-when{display:flex;align-items:center;
  justify-content:space-between;gap:5px;
  font-family:var(--cond);font-size:8.5px;color:#7d8ea4;
  letter-spacing:.04em;white-space:nowrap}
.gdpage .gdchip-when.is-done{color:#8b95a6;font-weight:700;
  text-transform:uppercase;letter-spacing:.1em}
.gdpage .gdchip-when.is-live{color:#f0918b;font-weight:700}
.gdpage .gdchip-n{display:flex;align-items:center;gap:2px;
  margin:0;padding:0;box-shadow:none;font-size:8.5px}
.gdpage .gdchip-n b{color:#7ee2a8;font-weight:700}
.gdpage .gdchip-n i{font-style:normal;color:#e0707c;font-weight:700}
.gdpage .gdchip-slash{color:#4e5663}

/* The score, and where the week is heading, on one line. */
.gdpage .gdscoreline{display:flex;align-items:baseline;gap:6px}
.gdpage .gdside.b .gdscoreline{justify-content:flex-end}
.gdpage .gdproj{font-family:var(--cond);font-size:11px;
  color:#7d8ea4;font-weight:700;white-space:nowrap}
.gdpage .gdside.a .gdproj{color:#8fc2a4}
.gdpage .gdside.b .gdproj{color:#c99a9d}

/* What it is like there, and where there is. */
/* The weather, in a pane of its own on the turf. */
.gdpage .gdsky{position:absolute;top:7px;left:7px;z-index:3;
  display:flex;align-items:baseline;gap:5px;
  padding:4px 8px;border-radius:7px;
  background:#050a12a3;box-shadow:inset 0 0 0 1px #ffffff1a;
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);
  font-family:var(--cond)}
.gdpage .gdsky b{font-size:12px;color:#e4ebf3;font-weight:700}
.gdpage .gdsky i{font-style:normal;font-size:8px;color:#a8b6c8}
/* The ground, one line under the field. */
.gdpage .gdvenue{display:flex;justify-content:flex-end;
  padding:5px 12px 0;font-family:var(--cond);font-size:8.5px;
  color:#7d8ea4;letter-spacing:.03em}
.gdpage .gdvenue span{overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}

/* The sheet, while a finger is on it. */
.gdsheet-grab{touch-action:none;user-select:none}

/* The field is the same size in every game. */
.gdpage .gdfield{height:124px}
.gdpage .gdfield.packed,.gdpage .gdfield.tight,
.gdpage .gdfield.snug,.gdpage .gdfield.roomy{height:124px}

/* One card size, whatever the game.
   
   The rows used to tighten as a column filled up, from the days when
   the whole page had to fit one screen. It scrolls now, so a crowded
   side simply runs longer and pushes what follows down — which is
   what scrolling is for. */
.gdpage .gdmen .gdrow,
.gdpage .gdmen.roomy .gdrow,
.gdpage .gdmen.snug .gdrow,
.gdpage .gdmen.tight .gdrow,
.gdpage .gdmen.packed .gdrow{padding:7px 6px;margin-bottom:4px}
.gdpage .gdmen .gdface,
.gdpage .gdmen.roomy .gdface,
.gdpage .gdmen.packed .gdface{width:24px;height:24px}
.gdpage .gdmen .gdwho b,
.gdpage .gdmen.roomy .gdwho b,
.gdpage .gdmen.packed .gdwho b{font-size:10.5px}
.gdpage .gdmen .gdwho i,
.gdpage .gdmen.packed .gdwho i{font-size:9.5px}
.gdpage .gdmen .gdval,
.gdpage .gdmen.roomy .gdval{font-size:11.5px}

/* And a side no longer caps itself at four: it runs as long as it
   needs to and the page scrolls past it. */
.gdpage .gdlist.scrolls{max-height:none;overflow:visible}

/* The summary tiles hold one size too. */
.gdpage .gdtiles>div,
.gdpage .gdtiles.roomy>div,
.gdpage .gdtiles.snug>div,
.gdpage .gdtiles.tight>div,
.gdpage .gdtiles.packed>div{padding:7px 4px}
.gdpage .gdtiles b,
.gdpage .gdtiles.roomy b,
.gdpage .gdtiles.snug b,
.gdpage .gdtiles.tight b,
.gdpage .gdtiles.packed b{font-size:13px}
.gdpage .gdtiles span,
.gdpage .gdtiles.packed span{font-size:6.5px;margin-top:2px}

/* ── game day: the lineups drawer ─────────────────────────────────
   The drawer itself is the hub's .mxfull, rows and all — those
   rules are above and are not repeated here. This is only what has
   to differ, plus the flash on the card jumped to.
   Appended at the end for the same reason the game-day toggles are:
   .seg and .seg-sm come later in this file than the game-day block,
   so a rule written up there loses. */

/* The brackets sit in the corner of the matchup summary, which has
   to be a positioning context for them. The arrows either side stop
   short of the corner, so nothing is covered. */
.gdpage .gdmatch{position:relative}
.gd-expand{display:flex;position:absolute;top:3px;right:4px;z-index:3}
.gd-expand svg{width:15px;height:15px}
.gd-expand:hover{color:#fff}
/* Lit while the drawer is open, so the summary says which state it
   is in without having to look below it. */
.gdpage .gdmatch.is-open .gd-expand{color:#bcd4ea}

/* On the hub the rows are inset to clear the news and league tabs
   against both edges. Game day has neither — in the sheet it has no
   chrome at all — so they take the width the board below them does. */
/* The sheet's own drawer, the same: it reserved 24px for edges that
   are not there. */
.gdfull .mxfull-rows{width:100%;margin-top:8px}
/* Above the sheet's own furniture but below a player card. The page
   under it has its own lighter --ink, and the drawer sits outside
   .gdpage — so it is given the same one, or it opens a shade darker
   than the page it is covering. */
.gdfull{z-index:64;--ink:#101a2b}

/* A man with nowhere to go — on a bye, or a week whose fixtures have
   not been fetched — is left unlit rather than given a tap that
   does nothing. .can-open is what the hub uses for the opposite. */
.gdfull .mxf-man:not(.can-open){opacity:.55}

/* ── the card that was jumped to ──────────────────────────────────
   Three flashes of red and then back to whatever the row was, which
   may be a designation stripe or the possession glow — hence the
   animation rather than a class that sets a colour and then has to
   know what to put back. */
.gdpage .gdrow.gdfound{animation:gdfound .42s ease-in-out 3}
/* The bench is drawn grey on purpose, and a grey flash is no flash
   at all — so a man being pointed out comes back to full colour for
   as long as he is lit. */
.gdpage .gdlist.is-bench .gdrow.gdfound{filter:none;opacity:1}

@media (prefers-reduced-motion: reduce){
  /* Held once rather than flashed, so it still says which man it
     means without anything moving. */
  .gdpage .gdrow.gdfound{animation:none;background:#7f1d1d;
    box-shadow:inset 0 0 0 1.4px #e0707c}
}

/* ── game day: the summary, and the cards under the field ─────────
   Later than the block above on purpose — these override rules set
   there, and the cascade decides it by order. */

/* A bit of colour behind the two owners rather than flat navy: his
   green from the left, the other's red from the right, both barely
   there. Kept low — the scores and the win bar are what should read
   first, and the wash is only meant to separate this band from the
   board below it. */
.gdpage .gdmatch{
  background:
    radial-gradient(120% 150% at 0% 50%, #15803d2e 0%, transparent 58%),
    radial-gradient(120% 150% at 100% 50%, #7f1d1d33 0%, transparent 58%),
    linear-gradient(180deg, #101a2c 0%, #0b1220 100%)}

/* The right-hand pair, mirrored: projection, arrow, then the score,
   so the two owners read outward from the VS. The arrow itself is
   turned in gameday.js. */
.gdpage .gdside.b .gdscoreline{flex-direction:row-reverse;
  justify-content:flex-start}

/* The right-hand column's cards read to their own edge.
   His name, his line and his figures were all pushed to the far side
   of the card, away from the photograph they belong to — so the eye
   had to cross the whole row to put a face to a number. */
.gdpage .gdrow.r .gdwho{text-align:right}
.gdpage .gdrow.r .gdval{text-align:right}
.gdpage .gdrow.r .gdsnap{justify-content:flex-end}

/* The cards themselves, on a neutral of their own.
   #ffffff08 over the page is barely a card at all; this is a flat
   slate a shade above the background, so a row reads as a thing
   rather than as a slightly lighter patch. The possession and red
   zone states still win — they are set further up and are what a
   glance is looking for. */
.gdpage .gdrow{background:#1b2434;
  box-shadow:inset 0 0 0 1px #ffffff14}
.gdpage .gdlist.is-bench .gdrow{background:#151c28}
/* The flash on a card jumped to from the drawer: three beats of red
   and then back to the neutral above. Defined here rather than with
   the drawer rules so the two colours are written next to each
   other and cannot drift apart. */
@keyframes gdfound{
  0%,100%{background:#1b2434;
    box-shadow:inset 0 0 0 1px #ffffff14}
  40%{background:#7f1d1d;
    box-shadow:inset 0 0 0 1.4px #e0707c,0 0 16px -3px #e0707caa}
}

/* ── game day: lines, results, and moving between matchups ────────*/

/* The favourite, before kickoff. A dot on the corner of his badge
   rather than a word in the line — the chip is 100px wide and has
   the score, the total and two counts in it already. */
.gdpage .gdclub.is-fav::after{content:"";position:absolute;
  top:-1px;right:-1px;width:6px;height:6px;border-radius:50%;
  background:#7ee2a8;box-shadow:0 0 0 1.5px #0b1220}
.gdpage .gdclub{position:relative}

/* A finished game, said by colour: the winner's score green, the
   beaten club and his figure drained. Better than reading two
   numbers and comparing them, which is what a scoreboard is for. */
.gdpage .gdchip-s.is-win,
.gdpage .gdnum.is-win{color:#7ee2a8}
.gdpage .gdchip-s.is-lost,
.gdpage .gdnum.is-lost{color:#5d6673}
.gdpage .gdclub.is-lost{filter:grayscale(1);opacity:.45}
/* dim is set on every scoreboard figure outside a live game; a
   winner has to beat it. */
.gdpage .gdnum.dim.is-win{color:#7ee2a8}
.gdpage .gdnum.dim.is-lost{color:#5d6673}

/* The total. Quiet — it is context, not the thing being read. */
.gdpage .gdchip-ou{font-family:var(--cond);font-size:7.5px;
  color:#6d7684;letter-spacing:.04em;white-space:nowrap}

/* ── the summary's own layout ─────────────────────────────────────
   Fixed tracks rather than space-between. The faces used to sit
   wherever the names and the numbers left them, so stepping from a
   short name to a long one slid both photographs sideways — which
   read as the page shifting rather than the matchup changing. Now
   each side owns a column of the same width and the photographs are
   pinned to its outer edge, whatever is written between them. */
.gdpage .gdmatch{display:grid;
  grid-template-columns:18px minmax(0,1fr) auto minmax(0,1fr) 18px;
  align-items:center;justify-content:initial}
.gdpage .gdmatch .gdstext{flex:1 1 auto;min-width:0}
.gdpage .gdside{flex-wrap:nowrap}

/* Out and back rather than swapped where it stands. The fetch
   happens behind the fade, so the wait is the transition. */
.gdpage .gdmatch,
.gdpage .gdfixed,
.gdpage .gdscroll{transition:opacity .22s ease}
.gdpage .is-turning{opacity:0}

/* The VS is a button now. It was a div, so it needs the resets. */
.gdpage button.gdvs{border:0;background:none;padding:4px 6px;
  border-radius:6px;cursor:pointer;font-family:inherit;
  -webkit-tap-highlight-color:transparent}
.gdpage button.gdvs:active{transform:translateY(1px)}
.gdpage button.gdvs::after{content:"";display:block;margin:3px auto 0;
  width:12px;height:2px;border-radius:2px;background:#ffffff2e}

/* ── every matchup this week ──────────────────────────────────────*/
.gdmxmenu .modal-body{padding:10px 12px 14px;display:flex;
  flex-direction:column;gap:6px}
.gdmx-row{display:grid;grid-template-columns:1fr auto 1fr;
  align-items:center;gap:8px;width:100%;padding:8px 10px;border:0;
  border-radius:8px;background:#1b2434;
  box-shadow:inset 0 0 0 1px #ffffff14;cursor:pointer;color:inherit;
  font:inherit;-webkit-tap-highlight-color:transparent}
.gdmx-row:active{transform:translateY(1px)}
/* The one already on screen, so the menu says where you are. */
.gdmx-row.on{box-shadow:inset 0 0 0 1.4px #4d7ab8;background:#22304a}
.gdmx-side{display:flex;align-items:center;gap:7px;min-width:0}
.gdmx-side.r{flex-direction:row;justify-content:flex-end}
.gdmx-side .gdoface{width:26px;height:26px}
.gdmx-who{min-width:0}
.gdmx-who > b{display:block;font-size:10.5px;color:#e4ebf3;
  font-weight:700;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.gdmx-who i{display:block;font-style:normal;font-family:var(--cond);
  font-size:8px;color:#6d7684}
.gdmx-side.r .gdmx-who{text-align:right}
.gdmx-pts{font-family:var(--cond);font-size:14px;font-weight:700;
  color:#8b95a6;flex:0 0 auto}
/* Whoever is ahead reads brighter — the point of the line. */
.gdmx-side.is-up .gdmx-pts{color:#7ee2a8}
.gdmx-side.is-up .gdmx-who b{color:#fff}
.gdmx-v{font-family:var(--cond);font-size:9px;color:#4e5663;
  letter-spacing:.1em}

@media (prefers-reduced-motion: reduce){
  .gdpage .gdmatch,.gdpage .gdfixed,.gdpage .gdscroll{transition:none}
}

/* ── the week's band: a game that has been played ─────────────────*/
.slate-score{display:flex;align-items:center;gap:3px;
  font-family:var(--cond);font-size:12px;font-weight:700;
  flex:0 0 auto;padding:0 2px}
.slate-score b{font-weight:700;color:#e4ebf3}
.slate-score i{font-style:normal;color:#4e5663;font-size:9px}
.slate-score b.is-win{color:#7ee2a8}
.slate-score b.is-lost{color:#5d6673}
.slate-side.is-lost img{filter:grayscale(1);opacity:.45}
.slate-side.is-lost span{color:#5d6673}
/* Over, and said so — in the league's red, on the hub's band and
   in the sheet's strip alike, since both draw this same tile. */
.slate-time.is-done{color:var(--red);letter-spacing:.1em;
  font-weight:700}
.slate-time.is-live{color:#7ee2a8}

/* ── game day: the forecast ───────────────────────────────────────
   Smaller than it was. INDOORS and PENDING are conditions, not
   headlines — the mark beside them carries the meaning and the word
   is only there to remove any doubt. */
.gdpage .gdsky{display:flex;align-items:center;gap:4px}
.gdpage .gdsky-i{font-size:9px;line-height:1}
.gdpage .gdsky.is-indoor b,
.gdpage .gdsky.is-pending b{font-family:var(--cond);font-size:7.5px;
  letter-spacing:.12em;color:#8b95a6}
.gdpage .gdsky.is-pending{opacity:.7}

/* ── in play, left to play ────────────────────────────────────────
   In the summary and again in the menu, from the same two numbers. */
.gdpage .gdstate{display:flex;align-items:center;gap:9px;
  margin-top:3px;color:#6d7684}
.gdpage .gdside.r .gdstate{justify-content:flex-end}
.gdstate-bit,.gdmx-bit{display:inline-flex;align-items:baseline;gap:3px}
.gdstate-bit b,.gdmx-bit b{font-size:10px;color:#c4cede;font-weight:700}
.gdstate-bit i,.gdmx-bit i{font-style:normal;font-family:var(--cond);
  font-size:7px;letter-spacing:.1em;color:#6d7684;text-transform:uppercase}
/* Anybody actually on the field reads live. */
.gdstate-bit.is-live b,.gdmx-bit.is-live b{color:#7ee2a8}

/* ── every matchup this week ──────────────────────────────────────
   Names, not photographs. Six lines of two owners each was twelve
   faces on one card, and at 26px none of them was recognisable
   anyway — the names do the work and leave room for the figures. */
.gdmx-side{display:flex;align-items:center;gap:6px;min-width:0;
  justify-content:flex-end}
.gdmx-side.r{flex-direction:row;justify-content:flex-start}
.gdmx-who{min-width:0;flex:1 1 auto;line-height:1.3}
.gdmx-side.r .gdmx-who{text-align:right}
.gdmx-who > b{display:block;font-size:10.5px;color:#e4ebf3;
  font-weight:700;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
/* His record and where his ten is, both on their own line and both
   the same size, so the three read as a block rather than as a name
   with two afterthoughts. */
.gdmx-rec,.gdmx-play{display:block;font-style:normal;
  font-family:var(--cond);font-size:8px;letter-spacing:.06em;
  color:#8b95a6;text-transform:uppercase;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
/* The play line is the longest thing in a narrow column — six
   fixtures of two owners each leaves it about seventy pixels. Small
   and lower case so it fits on the one line it is meant to be on;
   nowrap is on the children too, since it was the figures inside it
   breaking away rather than the line itself. */
.gdmx-play{font-size:7px;letter-spacing:.01em;text-transform:none;
  color:#6d7684}
.gdmx-play *{white-space:nowrap}
/* The two figures read as part of the sentence, not as headlines:
   same size and same weight as the words around them. */
/* Said again here, so no rule above can turn them into lines of
   their own — the whole point of this line is that it is one. */
.gdmx-play b{display:inline;font-weight:inherit;font-size:inherit;
  color:#c4cede}
.gdmx-play b.is-live{color:#7ee2a8}

/* The figures, pushed to the middle so the four meet at the v. */
.gdmx-pts{flex:0 0 auto;text-align:right;line-height:1.15}
.gdmx-side.r .gdmx-pts{text-align:left}
.gdmx-pts b{display:block;font-family:var(--cond);font-size:15px;
  font-weight:700;color:#8b95a6}
/* Nobody has played: a white dash rather than a grey nought. */
.gdmx-pts b.is-none{color:#fff}
.gdmx-side.is-up .gdmx-pts b{color:#7ee2a8}
.gdmx-side.is-up .gdmx-who b{color:#fff}
/* The projection, on its own line and unlabelled — the big figure
   above it is the score, so what else would this be. Grey: the
   badge beside his name already carries a colour, and two of them
   on one line competed rather than said different things. */
.gdmx-pts u{display:block;text-decoration:none;font-family:var(--cond);
  font-size:9px;font-weight:700;letter-spacing:.04em;color:#6d7684}

/* Where he stands now, on the outside of his name. Green in the top
   half of the field, red below it. */
.gdmx-place{flex:0 0 auto;width:18px;text-align:center;
  font-family:var(--cond);font-size:11px;font-weight:700;
  border-radius:5px;padding:3px 0;color:#8b95a6;
  background:#ffffff0d}
.gdmx-side.is-in .gdmx-place{color:#bff0d2;
  background:linear-gradient(160deg,#15803db8,#15803d38)}
.gdmx-side.is-out .gdmx-place{color:#f5c2be;
  background:linear-gradient(160deg,#7f1d1dbf,#7f1d1d3d)}

/* ── game day: the week's other games, folded away ────────────────
   They used to sit above the scoreboard, six tiles wide, and were
   the first thing the eye landed on — ahead of the game actually
   being watched. Now they hang off the summary and stay shut until
   they are wanted. */
/* A red rail between the summary and the scoreboard. It is a
   handle, not a heading — so the band is only as tall as its own
   type, and the type sits in the middle of it. */
.gdpage .gdgames{background:var(--red)}
/* The band's height is stated rather than left to the padding, and
   the row centres in it — so the words and the chevron sit on the
   middle of the red whatever size either of them is. */
.gdpage .gdgames-tab{display:flex;align-items:center;
  justify-content:center;gap:6px;width:100%;min-height:20px;
  padding:0 12px;border:0;background:none;cursor:pointer;
  color:#fff;font:inherit;line-height:1;
  -webkit-tap-highlight-color:transparent}
.gdpage .gdgames-tab:active{background:#00000024}
/* Centred, not on a shared baseline: the two are different sizes,
   and a baseline would hang the smaller one low. */
.gdpage .gdgames-t{display:flex;align-items:center;gap:6px;
  min-width:0;line-height:1}
.gdpage .gdgames-t b{font-family:var(--cond);font-size:8px;
  font-weight:700;letter-spacing:.12em;color:#fff}
.gdpage .gdgames-t i{font-style:normal;font-family:var(--cond);
  font-size:7px;letter-spacing:.1em;color:#ffffffc2;
  text-transform:uppercase;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
/* A chevron from a border, pointing down when shut and up when the
   strip is out. The nudge either way is what centres the rotated
   square on the line rather than hanging it below. */
.gdpage .gdgames-v{flex:0 0 auto;width:5px;height:5px;
  border-right:1.5px solid #fff;border-bottom:1.5px solid #fff;
  transform:translateY(-2px) rotate(45deg);
  transition:transform .18s ease}
.gdpage .gdgames.open .gdgames-v{transform:translateY(1px) rotate(-135deg)}
.gdpage .gdgames-body{overflow:hidden;background:#0a111e}

/* ── the scoreboard ───────────────────────────────────────────────
   A box of its own rather than two club-coloured washes. The washes
   put a different background under each half, which meant the score
   and the clock were read against whatever colour the fixture
   happened to bring; this is one surface and one border, and the
   end zones on the field below still carry the clubs' colours. */
/* Shallower than it was, and standing clear of both neighbours: the
   red rail above it and the field below. It was hard against both,
   which read as one tall block rather than as three things. */
.gdpage .gdscore{position:relative;margin:9px 12px 10px;
  padding:5px 12px 6px;
  border:1px solid #ffffff5c;border-radius:9px;
  background:#0d1626}

@media (prefers-reduced-motion: reduce){
  .gdpage .gdgames-v{transition:none}
}

/* ── game day: the leader boards under the men ────────────────────
   The same card as the lineups above them — a row means the same
   thing wherever it appears on this page — with the club badge over
   each column instead of an owner's name. */
.gdpage .gdtops{margin-top:2px}
.gdpage .gdtops .gdsec{gap:5px}
.gdpage .gdtops .gdsec .gdclub{width:14px;height:14px}
.gdpage .gdtops .gdsec span{font-family:var(--cond);font-size:7px;
  letter-spacing:.14em;color:#8b95a6}
/* Slightly quieter than a man somebody is starting: these are for
   watching, not for counting. */
/* Darker and flatter than an owner's man, and further from him than
   it was — the two were a shade apart, which reads as a rendering
   difference rather than as a distinction. */
.gdpage .gdrow.gdtop{background:#0f141d;
  box-shadow:inset 0 0 0 1px #ffffff0f}
.gdpage .gdrow.gdtop .gdwho b{color:#c2cbd8}

/* Nobody in this game. Red, and a card rather than a dash — an
   empty column read as something that had failed to load. */
.gdpage .gdrow.gdnone{background:#3a1414;
  box-shadow:inset 0 0 0 1px #e0707c7a;justify-content:center}
.gdpage .gdrow.gdnone .gdwho{flex:0 0 auto;text-align:center}
.gdpage .gdrow.gdnone .gdwho b{font-family:var(--cond);font-size:9px;
  font-weight:700;letter-spacing:.14em;color:#f5c2be}
.gdpage .gdrow.gdnone .gdwho i{font-size:7.5px;letter-spacing:.1em;
  color:#c98b8b;text-transform:uppercase}

/* Four tabs rather than three, so each has less room to say its
   name in. */
.gdpage .gdview button{font-size:8.5px;letter-spacing:.06em;
  padding:7px 3px}

/* ── the leader board's own rule ──────────────────────────────────
   Its own class rather than the shared .gdrule: this one closes the
   fantasy half and opens a new list, so it wants more air above it
   and a heading that reads as one. */
.gdpage .gdrule.gdtoprule{margin:22px 12px 6px}
.gdpage .gdrule.gdtoprule b{top:-8px;font-size:10px;color:#fff;
  letter-spacing:.16em;padding:0 11px}

/* ── the leader cards are the cards above ─────────────────────────
   No sizes of their own. They were pinned to figures that were meant
   to match the lineup cards, which is a promise that holds only
   until one of the two is changed. Governed by the same rules
   instead, so they cannot come apart. */

/* ── nobody in this game ──────────────────────────────────────────
   Words where the cards would be, rather than a card with no man on
   it. Red, because it is the reason the column is empty. */
.gdpage .gdnone{font-family:var(--cond);font-size:9px;font-weight:700;
  letter-spacing:.16em;color:#e0707c;text-align:center;padding:14px 0}

/* ── whose card is whose ──────────────────────────────────────────
   The two owners' men on a blue-grey of their own, so the leader
   boards underneath read as a different list rather than as more of
   the same one. A leader either owner holds takes the same colour —
   the point of marking him is that he is not a stranger. */
.gdpage .gdmen:not(.gdtops):not(.gdhurts) .gdrow:not(.gdnone),
.gdpage .gdrow.gdtop.is-held{background:#26374f;
  box-shadow:inset 0 0 0 1px #ffffff29}

/* ── the injured list, a column a club ────────────────────────────*/
.gdpage .gdhurts .gdsec{gap:5px}
.gdpage .gdhurts .gdsec .gdclub{width:14px;height:14px}
.gdpage .gdhurts .gdsec span{font-family:var(--cond);font-size:7px;
  letter-spacing:.14em;color:#8b95a6}
.gdpage .gdhurts .gdhurt{display:flex;align-items:center;gap:6px;
  padding:6px;margin-bottom:4px;border-radius:6px;
  background:#ffffff08;box-shadow:inset 0 0 0 1px #ffffff12}
.gdpage .gdhurts .gdhurt.r{flex-direction:row-reverse;text-align:right}
/* A man one of them is starting, on the same blue-grey his card
   carries above — the only ones on this list that change a Sunday. */
.gdpage .gdhurts .gdhurt.is-mine{background:#26374f;
  box-shadow:inset 0 0 0 1px #ffffff26}
.gdpage .gdhurts .gdhurt-mid{flex:1;min-width:0}
.gdpage .gdhurts .gdhurt-mid b{display:block;font-size:9.5px;color:#fff;
  font-weight:400;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.gdpage .gdhurts .gdhurt-mid i{display:block;font-style:normal;
  font-family:var(--cond);font-size:8px;color:#8b95a6;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gdpage .gdhurts .gdhurt-said{flex:0 0 auto;font-family:var(--cond);
  font-size:8px;font-weight:700;letter-spacing:.08em;color:#8b95a6}

/* ── a colour a tab ───────────────────────────────────────────────
   Tinted always, so which is which can be learned; filled when it is
   the one showing. The type goes dark on the filled one, which is
   the only way these stay readable at four across. */
.gdpage .gdview button.v-summary{color:#8fbdf0}
.gdpage .gdview button.v-game{color:#e2c069}
.gdpage .gdview button.v-box{color:#7ee2a8}
.gdpage .gdview button.v-hurt{color:#e0707c}
.gdpage .gdview button.v-summary.on{background:#2f6fb8;color:#eaf3ff}
.gdpage .gdview button.v-game.on{background:#a8811f;color:#fff8e6}
.gdpage .gdview button.v-box.on{background:#1f7a4a;color:#e8fff2}
.gdpage .gdview button.v-hurt.on{background:#9e3038;color:#ffeceb}

/* ── the page under it all ────────────────────────────────────────
   Lighter than the hub's flat navy, and graded rather than flat.
   Everything on this page is a dark card on a dark ground, and at
   #081120 the two were close enough that the cards had to carry the
   whole separation themselves. Raising the floor lets them read.

   --ink is redefined here rather than only the background: the
   fixed block, the rule labels and the drawer all paint themselves
   with it, and lightening one without the others would have left a
   seam across the sheet. */
.gdpage{--ink:#101a2b;
  background:linear-gradient(180deg,#16223a 0%,#101a2b 46%,#0b1322 100%)}
/* No longer needs to paint over anything — it is static in this
   layout, so it can let the gradient through. */
.gdpage .gdfixed{background:transparent}
.gdpage .gdgames-body{background:#131e33}
.gdpage .gdscore{background:#131e33}
.gdpage .gdmatch{
  background:
    radial-gradient(120% 150% at 0% 50%, #15803d33 0%, transparent 58%),
    radial-gradient(120% 150% at 100% 50%, #7f1d1d3d 0%, transparent 58%),
    linear-gradient(180deg, #1b2942 0%, #16223a 100%)}

/* ── the injured list's own colours ───────────────────────────────
   A designation is the whole point of the row, so it is said in the
   card rather than in a word beside it: dark, solid, and white on
   top. The gradients the player cards use are for a stripe down the
   side of a man you are starting — here the card IS the status. */
.gdpage .gdhurts .gdhurt.is-p{background:#123a22;
  box-shadow:inset 0 0 0 1px #7ee2a85c}
.gdpage .gdhurts .gdhurt.is-q{background:#463107;
  box-shadow:inset 0 0 0 1px #e8b84b5c}
.gdpage .gdhurts .gdhurt.is-d{background:#4a2a0e;
  box-shadow:inset 0 0 0 1px #e08a4b5c}
.gdpage .gdhurts .gdhurt.is-o{background:#4a1414;
  box-shadow:inset 0 0 0 1px #e0707c66}
.gdpage .gdhurts .gdhurt.is-p .gdhurt-mid b,
.gdpage .gdhurts .gdhurt.is-q .gdhurt-mid b,
.gdpage .gdhurts .gdhurt.is-d .gdhurt-mid b,
.gdpage .gdhurts .gdhurt.is-o .gdhurt-mid b{color:#fff}
.gdpage .gdhurts .gdhurt.is-p .gdhurt-mid i,
.gdpage .gdhurts .gdhurt.is-q .gdhurt-mid i,
.gdpage .gdhurts .gdhurt.is-d .gdhurt-mid i,
.gdpage .gdhurts .gdhurt.is-o .gdhurt-mid i{color:#ffffffb8}
/* The word itself, white on the dark card rather than the tone it
   already sits on. */
.gdpage .gdhurts .gdhurt-said,
.gdpage .gdhurts .gdhurt-said.is-p,
.gdpage .gdhurts .gdhurt-said.is-q,
.gdpage .gdhurts .gdhurt-said.is-d,
.gdpage .gdhurts .gdhurt-said.is-o{color:#fff}
/* A man one of them is starting keeps his blue-grey edge, over
   whatever the designation painted. */
.gdpage .gdhurts .gdhurt.is-mine{box-shadow:inset 0 0 0 1.6px #8fbdf0a8}

/* ── the injured list's status word ───────────────────────────────
   Outlined, not filled. The pale fills further up this file were
   written for a light row; on the dark cards the word is white, and
   white on pale pink is unreadable. A hairline box carries it
   instead. */
.gdpage .gdhurts .gdhurt-said,
.gdpage .gdhurts .gdhurt-said.is-p,
.gdpage .gdhurts .gdhurt-said.is-q,
.gdpage .gdhurts .gdhurt-said.is-d,
.gdpage .gdhurts .gdhurt-said.is-o{background:none;color:#fff;
  border:1px solid #ffffffa8;border-radius:5px;padding:2px 6px;
  font-size:7.5px;letter-spacing:.1em;text-transform:uppercase}

/* ── the box score's figures ──────────────────────────────────────
   Bigger, brighter, and set in the same condensed face the rest of
   the page counts in — with tabular figures, so a column of numbers
   lines up on the decimal instead of wandering. */
.gdpage .gdbox-row > span:not(.gdbox-who){font-size:14px;
  font-weight:700;color:#e7edf6;letter-spacing:.01em;
  font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}
.gdpage .gdbox-row .gdbox-who{font-size:11px;color:#c4cede}
.gdpage .gdbox-row .gdbox-pts{color:#8b95a6}
.gdpage .gdbox-row .gdbox-pts.has{color:#7ee2a8}

/* ── win probability ──────────────────────────────────────────────
   The bar is gone: it said the same thing the line already says, at
   one moment rather than across the game. Room on the right for the
   two badges that sit at the ends of the lines. */
.gdpage .gdodds-bar{display:none}
.gdpage .gdodds-line{position:relative;margin-right:15px}
.gdpage .gdodds-mark{position:absolute;right:0;
  transform:translate(50%,-50%);z-index:2;line-height:0}
.gdpage .gdodds-mark .gdclub{width:17px;height:17px;
  background:#0d1626;border-radius:50%;padding:1px;
  box-shadow:0 0 0 1px #ffffff2e}

/* ── win probability, in a box of its own ─────────────────────────
   It was running straight on from the team metrics above it with
   nothing between, so the chart read as another metric rather than
   as its own thing. A container, and air on both sides of the
   heading. */
.gdpage .gdodds{margin:0 0 4px;padding:12px 14px 10px;
  border:1px solid #ffffff1f;border-radius:10px;background:#131e33}
/* Room above, so it clears the metrics; the heading keeps its own
   space below it. */
.gdpage .gdteams .gdrule.gdtoprule{margin-top:26px;margin-bottom:12px}
.gdpage .gdodds-line{height:96px}

/* The quarters, under the chart. Equal bands, because the line is
   sampled evenly across the part of the game that has been played. */
.gdpage .gdodds-x{display:flex;margin:5px 15px 0 0;
  border-top:1px solid #ffffff14;padding-top:4px}
.gdpage .gdodds-x span{flex:1;text-align:center;font-family:var(--cond);
  font-size:7px;letter-spacing:.14em;color:#6d7684}
.gdpage .gdodds-t{margin-top:9px}

/* ── the chart's own box ──────────────────────────────────────────
   .gdodds-line was written as a backdrop BEHIND the bar: absolute,
   and bleeding sixteen pixels above its box on purpose. With the bar
   gone it is the content, so it takes its place in the flow and a
   height of its own — the bleed is what was spilling out of the
   top. */
.gdpage .gdodds-line{position:relative;inset:auto;height:104px;
  margin-right:15px;overflow:visible}
.gdpage .gdodds-line svg{display:block;width:100%;height:100%}

/* ── reading a point on it ────────────────────────────────────────
   A finger anywhere on the chart moves the two dots to that sample
   and rewrites the line underneath. Nothing shows until it does. */
.gdpage .gdodds-cursor,
.gdpage .gdodds-dot{position:absolute;opacity:0;pointer-events:none;
  transition:opacity .12s ease}
.gdpage .gdodds-line.is-reading .gdodds-cursor,
.gdpage .gdodds-line.is-reading .gdodds-dot{opacity:1}
.gdpage .gdodds-cursor{top:0;bottom:0;width:1px;
  background:#ffffff6b;transform:translateX(-50%)}
.gdpage .gdodds-dot{width:7px;height:7px;border-radius:50%;
  transform:translate(-50%,-50%);box-shadow:0 0 0 2px #131e33}
.gdpage .gdodds-face{display:inline-flex;line-height:0}

/* The summary under it. Its figures move as the finger does, so it
   is worth a little more room than a static caption. */
.gdpage .gdodds-t{margin-top:9px;gap:7px}

/* ── the scoreboard's club colours, back inside its box ───────────
   Behind each half, into the middle and gone by the clock. Clipped
   by the box's own corners, and laid under everything else — the
   :not() is what keeps the two bands out of the flex row, which is
   what shoved the badges off centre the last time these existed. */
.gdpage .gdscore{overflow:hidden}
/* Everything except the stripes behind it and the clock, which is
   centred absolutely. This rule is three classes deep and beat the
   clock's own two, so the clock kept position:relative and sat
   wherever the flex row left it — the second time this selector has
   quietly won an argument it was not meant to be in. */
.gdpage .gdscore > *:not(.gdstripe):not(.gdclock){position:relative;
  z-index:1}
.gdpage .gdscore .gdstripe{position:absolute;top:0;bottom:0;width:58%;
  pointer-events:none;z-index:0}
.gdpage .gdscore .gdstripe.l{left:0}
.gdpage .gdscore .gdstripe.r{right:0}

/* ── the games rail, under the same wash as the owners ────────────
   It was a red stripe across the sheet. The summary's own wash now
   runs on through it, so the two read as one band with a rule
   between them rather than as a header and a bar. */
.gdpage .gdgames{background:
  radial-gradient(120% 260% at 0% 0%, #15803d2b 0%, transparent 62%),
  radial-gradient(120% 260% at 100% 0%, #7f1d1d33 0%, transparent 62%),
  #16223a;
  box-shadow:inset 0 -1px 0 #ffffff12}
.gdpage .gdgames-t b{color:#dbe6f5}
.gdpage .gdgames-t i{color:#8ea3bd}
.gdpage .gdgames-v{border-right-color:#a9bcd4;
  border-bottom-color:#a9bcd4}
.gdpage .gdgames-tab:active{background:#ffffff0f}

/* ── arriving all at once ─────────────────────────────────────────
   Only inside the sheet. On its own page the splash covers the same
   ground; here there is none, and the parts were landing one after
   another behind a sheet that had already opened. */
html.gd-holding .gdpage{opacity:0}
html.in-sheet .gdpage{transition:opacity .18s ease}
@media (prefers-reduced-motion: reduce){
  html.in-sheet .gdpage{transition:none}
}

/* ── the summary, flat ────────────────────────────────────────────
   No washes behind the two owners. They were meant to say who was
   ahead, but the win bar and the scores already do that, and a
   coloured field behind white type is the one thing on this sheet
   that made the type harder to read rather than easier.

   var(--ink) is what the toggle row paints itself, so the band at
   the top of the sheet and the controls further down are the same
   colour rather than two dark blues that nearly match. */
.gdpage .gdmatch{background:var(--ink);
  box-shadow:inset 0 -1px 0 #ffffff12}

/* ── the games rail, red again ────────────────────────────────────*/
.gdpage .gdgames{background:var(--red);
  box-shadow:inset 0 -1px 0 #00000033}
.gdpage .gdgames-t b{color:#fff}
.gdpage .gdgames-t i{color:#ffffffc2}
.gdpage .gdgames-v{border-right-color:#fff;border-bottom-color:#fff}
.gdpage .gdgames-tab:active{background:#00000024}

/* ── the chart, a little further down ─────────────────────────────
   More air under the heading: it was close enough to read as the
   chart's own caption rather than as the section's title. */
.gdpage .gdteams .gdrule.gdtoprule{margin-bottom:18px}
.gdpage .gdodds{margin-top:4px}

/* ── the injured list, in the fantasy cards' clothes ──────────────
   The same card and the same washes the player cards use: the tone
   strongest at the man's own edge and gone by the middle, rather
   than a solid block of colour. Mirrored on the right, as those are.
   The solid fills that were here read as four different kinds of
   card; this reads as one kind, coloured. */
.gdpage .gdhurts .gdhurt{background:#0f141d;
  box-shadow:inset 0 0 0 1px #ffffff0f}
.gdpage .gdhurts .gdhurt.is-p{
  background:linear-gradient(90deg,#15803d5c,#15803d1a 62%,transparent)}
.gdpage .gdhurts .gdhurt.is-q{
  background:linear-gradient(90deg,#a1620066,#a162001f 62%,transparent)}
.gdpage .gdhurts .gdhurt.is-d{
  background:linear-gradient(90deg,#9a3d0070,#9a3d0022 62%,transparent)}
.gdpage .gdhurts .gdhurt.is-o{
  background:linear-gradient(90deg,#7f1d1d85,#7f1d1d2b 62%,transparent)}
.gdpage .gdhurts .gdhurt.r.is-p{
  background:linear-gradient(270deg,#15803d5c,#15803d1a 62%,transparent)}
.gdpage .gdhurts .gdhurt.r.is-q{
  background:linear-gradient(270deg,#a1620066,#a162001f 62%,transparent)}
.gdpage .gdhurts .gdhurt.r.is-d{
  background:linear-gradient(270deg,#9a3d0070,#9a3d0022 62%,transparent)}
.gdpage .gdhurts .gdhurt.r.is-o{
  background:linear-gradient(270deg,#7f1d1d85,#7f1d1d2b 62%,transparent)}
/* Back to the player cards' own type, now that the card is theirs. */
.gdpage .gdhurts .gdhurt-mid b{color:#fff;font-weight:400}
.gdpage .gdhurts .gdhurt-mid i{color:#a8b6c8}
/* A man one of them is starting keeps his edge over the wash. */
.gdpage .gdhurts .gdhurt.is-mine{box-shadow:inset 0 0 0 1.6px #8fbdf0a8}
/* The word stays outlined — it is the one thing here the player
   cards have no equivalent of. */
.gdpage .gdhurts .gdhurt-said,
.gdpage .gdhurts .gdhurt-said.is-p,
.gdpage .gdhurts .gdhurt-said.is-q,
.gdpage .gdhurts .gdhurt-said.is-d,
.gdpage .gdhurts .gdhurt-said.is-o{background:none;color:#fff;
  border:1px solid #ffffff8a}

/* Further under the heading again. */
.gdpage .gdteams .gdrule.gdtoprule{margin-bottom:26px}

/* ── the box score's sizes ────────────────────────────────────────
   The figures were set at 14px by a rule that also caught the header
   row — .gdpage .gdbox-row > span:not(.gdbox-who) weighs the same as
   the header's own rule and came later, so the column names grew
   with them. Excluded here, and both brought down. */
.gdpage .gdbox-row:not(.is-head) > span:not(.gdbox-who){font-size:11px}
.gdpage .gdbox-row.is-head > span,
.gdpage .gdbox-row.is-head .gdbox-pts{font-size:7px;letter-spacing:.1em}
.gdpage .gdbox-row:not(.is-head) .gdbox-who{font-size:10px}
.gdpage .gdbox-row:not(.is-head) .gdbox-pts{font-size:11px}

/* ── the chart's scale ────────────────────────────────────────────
   Percentages down the left, on the same six-per-cent inset the
   lines are drawn to, so a tick sits exactly on its own value. */
.gdpage .gdodds-line{padding-left:22px;box-sizing:border-box}
.gdpage .gdodds-y{position:absolute;left:0;top:0;bottom:0;width:20px;
  pointer-events:none}
.gdpage .gdodds-y span{position:absolute;right:2px;
  transform:translateY(-50%);font-family:var(--cond);font-size:6.5px;
  letter-spacing:.04em;color:#5d6673}

/* ── the injured list, card for card with the fantasy ones ────────
   Same face, same widths, same type. It was a list of its own
   before, and read like one. */
.gdpage .gdhurts .gdhurt{padding:6px;gap:7px}
.gdpage .gdhurts .gdhurt .gdface{width:21px;height:21px;flex:0 0 auto}
.gdpage .gdhurts .gdhurt-mid b{font-size:9.5px}
.gdpage .gdhurts .gdhurt-mid i{font-size:9.5px;font-family:var(--cond)}
.gdpage .gdhurts .gdhurt-said{font-size:7px;padding:2px 5px}

/* ── the injured list sits where the men do ───────────────────────
   It is a .gdmen now, which already pads itself twelve pixels a
   side; the margin left over from when it was a flat list of its own
   was adding twelve more, so the two tabs' columns did not line up
   with each other. */
.gdpage .gdmen.gdhurts{margin:0}

/* Room for the total beside the kickoff time. */
.gdpage .gdclock span{white-space:nowrap}

/* ── the game-day page, out of the menu ───────────────────────────
   The sheet that pulls up from the hub is the game-day view now, so
   there is no reason to send anybody to the page that view is an
   iframe of — arriving there whole means the topbar, the banner and
   no way back to the hub but the brand.

   Hidden here rather than cut out of eleven files' drawers: the
   route has to keep working, because the sheet is that route. One
   rule, every page, and one line to put back if the standalone page
   is ever wanted again. */
.drawer-link[href="/gameday"]{display:none}

/* ── one pager for the pair ───────────────────────────────────────
   Above both columns and to the right, rather than one set of dots
   over each saying the same thing twice. */
.gdpage .gdmen .gdpager{grid-column:1 / -1;display:flex;
  justify-content:flex-end;align-items:center;gap:5px;
  margin:0 0 -6px}
.gdpage .gdmen .gdpager .gddot{cursor:pointer}

/* ── a fixture with no score yet ──────────────────────────────────
   Two badges and an @, spread across the tile. With the scores gone
   there is nothing between them to push them apart, so centring
   left the three huddled in the middle of a tile that is the same
   width as every other. */
.gdpage .gdscore.is-pre{gap:18px}

/* ── the games drawer holds the hub's own tiles ───────────────────
   Same markup, same classes, same stylesheet — so the band across
   the top of the hub and the strip inside the sheet are one design
   rather than two that looked alike until one of them changed.
   Only the two things the hub has no use for are set here. */
.gdpage .gdstrip .slate-game{flex:0 0 auto}
/* Which fixture the sheet is showing. The hub's band opens a game;
   this strip chooses one, and has to say which. */
.gdpage .gdstrip .slate-game.is-picked{
  box-shadow:inset 0 0 0 1.4px #8fbdf0a8;background:#ffffff0f}

/* ── the whole app stops bouncing ─────────────────────────────────
   The hub and the depth chart rubber-banded past their own ends —
   an ordinary document does on a phone, and in a home-screen app it
   reads as the page coming loose. Ordinary scrolling is untouched;
   only the overscroll past either end stops. The auction already
   set this on itself; this is the same thing for every page. */
html,body{overscroll-behavior:none}

/* ── the toggles, closer to the ground under them ─────────────────*/
.gdpage .gdview{margin-top:12px}


/* ── the six, opposite the expander ───────────────────────────────
   The other corner of the matchup card. A numeral rather than a
   glyph: it is the cut line, and the table it opens is read against
   it — six through, six not. */
.mx-six{display:flex;position:absolute;top:2px;left:2px;z-index:3}
.mx-six b{font-family:var(--cond);font-size:13px;font-weight:700;
  line-height:1;letter-spacing:.02em}
.mx-six.on{color:#bcd4ea;background:var(--slate-2)}

/* ── the week's table ─────────────────────────────────────────────
   The lineup drawer's twin: same .mxfull, same width, opened from
   the other side. Only the rows differ. */
.mxtable .mxfull-rows{display:flex;flex-direction:column;gap:4px;
  overflow-y:auto;overscroll-behavior:contain}
.mxt-row{display:flex;align-items:center;gap:8px;flex:0 0 auto;
  min-height:38px;padding:6px 9px;border-radius:8px;
  background:#151d2c;box-shadow:inset 0 0 0 1px #ffffff12}
/* Whose row is whose: the top half through, the bottom half not,
   said the same way the game-day menu says it. */
.mxt-row.is-in .mxt-place{color:#bff0d2;
  background:linear-gradient(160deg,#15803db8,#15803d38)}
.mxt-row.is-out .mxt-place{color:#f5c2be;
  background:linear-gradient(160deg,#7f1d1dbf,#7f1d1d3d)}
/* And your own, marked — twelve names is a lot to find yourself in. */
.mxt-row.is-mine{background:#26374f;
  box-shadow:inset 0 0 0 1.4px #8fbdf0a8}

.mxt-place{flex:0 0 auto;width:20px;text-align:center;padding:3px 0;
  border-radius:5px;font-family:var(--cond);font-size:11px;
  font-weight:700;color:#8b95a6;background:#ffffff0d}
.mxt-face{width:26px;height:26px;border-radius:50%;flex:0 0 auto;
  overflow:hidden;background:var(--ink);display:flex;
  align-items:center;justify-content:center}
.mxt-face img{width:100%;height:100%;object-fit:cover}
.mxt-who{flex:1 1 auto;min-width:0}
.mxt-who b{display:block;font-size:11px;color:#e4ebf3;font-weight:700;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mxt-who i{display:block;font-style:normal;font-family:var(--cond);
  font-size:8px;letter-spacing:.06em;color:#6d7684;
  text-transform:uppercase;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.mxt-pts{flex:0 0 auto;text-align:right;line-height:1.15}
.mxt-pts b{display:block;font-family:var(--cond);font-size:15px;
  font-weight:700;color:#e4ebf3}
.mxt-pts b.is-none{color:#fff}
.mxt-pts u{display:block;text-decoration:none;font-family:var(--cond);
  font-size:9px;font-weight:700;color:#6d7684}

/* ── the games drawer opens and shuts ─────────────────────────────
   The height is moved rather than the element hidden outright, so
   the strip rolls down and back up instead of appearing. The
   transition itself is set in script, since the distance is only
   known once the strip has been measured. */
.gdpage .gdgames-body{overflow:hidden}

/* ── a half arriving ──────────────────────────────────────────────
   Each block of the chosen half comes in a beat after the one above
   it. Only on a tab press — the poll repaints too, and a cascade
   every thirty seconds would be a fidget. */
@keyframes gd-in{
  from{opacity:0;transform:translateY(7px)}
  to{opacity:1;transform:none}
}
.gdpage .gdscroll > .gd-in{animation:gd-in .26s ease both}

@media (prefers-reduced-motion: reduce){
  .gdpage .gdscroll > .gd-in{animation:none}
  .gdpage .gdgames-body{transition:none !important}
}

/* ── all twelve at once ───────────────────────────────────────────
   The table opened with rows of a fixed height and scrolled, which
   meant the bottom of the league was out of sight — and the bottom
   of the league is half the reason to open it. The rows share the
   drawer's height instead, so twelve fit whatever it is. A floor is
   kept so a short screen scrolls rather than squashing them into
   unreadable slivers. */
.mxtable .mxfull-rows{gap:3px;overflow-y:auto;
  overscroll-behavior:contain;padding-bottom:2px}
.mxt-row{flex:1 1 auto;min-height:28px;padding:3px 9px}
.mxt-face{width:22px;height:22px}
.mxt-place{font-size:10px;padding:2px 0}
.mxt-who b{font-size:10px}
.mxt-who i{font-size:7.5px}
.mxt-pts b{font-size:13px}
.mxt-pts u{font-size:8px}

/* ── the matchup card holds its width ─────────────────────────────
   Defensive rather than diagnosed: the card is width:100% of a flex
   column that stretches, and its owner blocks are a fixed 96px, so
   nothing in these files explains a per-fixture change. These stop
   the card being widened from inside, which is the one cause the
   CSS could hide.

   No overflow-x here: body.dhskin already sets hidden, further up,
   and would win over anything written at this level anyway. */
/* .home is a flex item as well as a flex container, and one with no
   stated width is sized from its contents — so the column, and the
   card in it, moved with whichever fixture was showing. Stating the
   width pins it to the space it is given.

   The min-width:0 rules that stood with it are gone: they let a
   block shrink BELOW its content, which is what squeezed the rosters
   grid. Only the width was ever doing the work. */
.home{width:100%;box-sizing:border-box}
.mx-card{max-width:100%}
/* And a long name stays inside its own 96px rather than pushing at
   the sides of the card. */
.mx-oname{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ── every tile the same size ─────────────────────────────────────
   A tile is as wide as what is in it, and what is in it differs: a
   finished game carries "10–13" between the badges where an unplayed
   one carries a bare "@", so FINAL came out the widest of the row.
   Fixed here so the strip reads as a row of equal things.

   148px is the widest case with room to spare — the two badges and
   a score between them, and, on the line under, a kickoff time with
   a total beside it.

   Only in the sheet. The hub's band scrolls continuously and past
   the edges of the screen, where tiles of different widths read as
   a ticker rather than as a list. */
.gdpage .gdstrip .slate-game{width:148px;padding-left:8px;
  padding-right:8px;justify-content:center}
.gdpage .gdstrip .slate-pair{width:100%;justify-content:center}
/* And if a fixture ever carries more than fits, it is trimmed
   rather than allowed to push the tile out of line again. */
.gdpage .gdstrip .slate-time{max-width:100%;overflow:hidden;
  text-overflow:ellipsis}

/* ── the lineup drawer, ten rows filling it ───────────────────────
   Back to what it was before the bench toggle sat above them: the
   ten share the drawer's height between them, with nothing else in
   it to take room. */
.gdfull .mxfull-rows .mxf-row{flex:1 1 auto}

/* ── the week's table, as a list rather than a stack of cards ─────
   Twelve cards in a column was twelve boxes to read past. A rule
   between each says the same thing and leaves the names to carry
   the row. */
.mxt-row{background:none;box-shadow:none;border-radius:0;
  border-bottom:1px solid #ffffff14;padding:3px 4px}
.mxt-row:last-child{border-bottom:0}
/* Except the cut. The line under sixth is the one that matters, so
   it is the one drawn in the league's own red. */
.mxt-row.is-cut{border-bottom:1.5px solid var(--red)}
/* Your own row still stands out, but as a wash rather than a card. */
.mxt-row.is-mine{background:#ffffff0f;box-shadow:none;
  border-radius:6px}

/* Out of it. Six others are already past what he can still reach,
   so his row is drained and turned red — a result rather than a
   standing. */
/* Reddened, without turning the white behind him yellow.
   sepia() tints EVERYTHING toward brown, whites included, and the
   hue-rotate then pushed that to a dull gold — which is why the ring
   behind an eliminated owner's head went yellow.
   Greyscale for the picture and a red laid over it in `color` blend
   instead: that takes its hue from the red and its lightness from
   the photograph, so white stays white and the rest goes red. */
.mxt-row.is-done .mxt-face{position:relative;isolation:isolate}
.mxt-row.is-done .mxt-face img{filter:grayscale(1) brightness(.92)}
.mxt-row.is-done .mxt-face::after{content:"";position:absolute;
  inset:0;border-radius:50%;background:#b3403a;
  mix-blend-mode:color;pointer-events:none}
.mxt-row.is-done .mxt-who b{color:#c98b8b}
.mxt-row.is-done .mxt-who i{color:#8d5f5f}
.mxt-row.is-done .mxt-pts b{color:#c98b8b}
.mxt-row.is-done .mxt-pts u{color:#8d5f5f}
.mxt-row.is-done .mxt-place{color:#f5c2be;
  background:linear-gradient(160deg,#7f1d1dbf,#7f1d1d3d)}

/* ── the six itself ───────────────────────────────────────────────
   Gold, and brighter while its table is open. No plate behind it:
   the numeral is the control, and a filled box around a single
   character read as a badge rather than a button. */
.mx-six{color:#d2a53c}
.mx-six.on{color:#ffcf5c;background:none}
.mx-six:active{transform:translateY(1px)}

/* ── the strip's own spacing and drift ────────────────────────────
   Room between the tiles: pressed up against each other they read
   as one long block rather than as a row of fixtures. */
.gdpage .gdstrip{gap:9px;scroll-behavior:auto}

/* ── the six catches the eye now and then ─────────────────────────
   A slow pulse every twelve seconds. Not a blink: it is a way in,
   not an alarm, and the hub is quiet enough that a steady beat
   would be the loudest thing on it. */
@keyframes mx-six-beat{
  0%,88%,100%{transform:scale(1);opacity:1}
  92%{transform:scale(1.22);opacity:.72}
  96%{transform:scale(1);opacity:1}
}
.mx-six b{display:block;animation:mx-six-beat 12s ease-in-out infinite}
/* Still while its own table is open — it has been found. */
.mx-six.on b{animation:none}

/* ── the hub's band, tiles of one size ────────────────────────────
   The same fix the sheet's strip has: a finished game carries a
   score between the badges where an unplayed one carries an "@",
   so FINAL came out the widest tile in the band. */
.slate-game{width:148px;padding-left:8px;padding-right:8px;
  justify-content:center}
.slate-pair{width:100%;justify-content:center}
.slate-time{max-width:100%;overflow:hidden;text-overflow:ellipsis}

@media (prefers-reduced-motion: reduce){
  .mx-six b{animation:none}
}

/* ── where the game stands, under the field ───────────────────────
   The down, the ball's spot and who has it, then the last play — the
   same three facts a broadcast keeps on screen, and the words that
   go with the marker the field above already draws. */
.gdpage .gddrive{margin:8px 12px 0;padding:8px 11px;border-radius:9px;
  background:#131e33;border:1px solid #ffffff1f}
.gdpage .gddrive-head{display:flex;align-items:center;gap:14px;
  flex-wrap:wrap}
.gdpage .gddrive-bit{display:flex;flex-direction:column;gap:1px;
  min-width:0}
.gdpage .gddrive-bit i{font-style:normal;font-family:var(--cond);
  font-size:7px;letter-spacing:.16em;color:#6d7684;
  text-transform:uppercase}
.gdpage .gddrive-bit b{font-family:var(--cond);font-size:12px;
  font-weight:700;color:#e4ebf3;white-space:nowrap}
.gdpage .gddrive-who{display:flex;align-items:center;line-height:0}
.gdpage .gddrive-who .gdclub{width:17px;height:17px}
.gdpage .gddrive-last{margin-top:7px;padding-top:7px;
  border-top:1px solid #ffffff14}
.gdpage .gddrive-last i{display:block;font-style:normal;
  font-family:var(--cond);font-size:7px;letter-spacing:.16em;
  color:#6d7684;text-transform:uppercase;margin-bottom:2px}
.gdpage .gddrive-last p{margin:0;font-size:10.5px;color:#c4cede;
  line-height:1.35}

/* ── the score by quarter ─────────────────────────────────────────
   Four columns and a total, the way every scoreboard has drawn one.
   Tabular figures so the columns line up as the numbers change. */
.gdpage .gdline{margin:0 0 6px;padding:8px 10px;border-radius:9px;
  background:#131e33;border:1px solid #ffffff1f}
.gdpage .gdline-row{display:grid;
  grid-template-columns:1fr repeat(var(--qs,4),26px) 34px;
  align-items:center;gap:2px;padding:3px 0}
.gdpage .gdline-row > span{text-align:center;font-family:var(--cond);
  font-size:12px;font-weight:700;color:#e4ebf3;
  font-variant-numeric:tabular-nums}
.gdpage .gdline-row.is-head > span{font-size:7.5px;letter-spacing:.14em;
  color:#6d7684;font-weight:700}
.gdpage .gdline-row + .gdline-row{border-top:1px solid #ffffff0f}
.gdpage .gdline-club{display:flex;align-items:center;gap:6px;
  justify-content:flex-start}
.gdpage .gdline-club .gdclub{width:18px;height:18px}
.gdpage .gdline-club b{font-family:var(--cond);font-size:10px;
  letter-spacing:.1em;color:#c4cede}
.gdpage .gdline-tot{color:#fff}
.gdpage .gdline-row.is-head .gdline-tot{color:#8b95a6}

/* ── Face ID ──────────────────────────────────────────────────────
   The switch in the account card, and the button on the gate. Both
   are hidden until the script has established the device can do it,
   so neither is styled for a disabled state — there isn't one. */
.faceid-row{display:flex;align-items:center;gap:10px;margin-top:12px;
  padding-top:12px;border-top:1px solid #ffffff14}
.faceid-said{flex:1 1 auto;min-width:0}
.faceid-said b{display:block;font-size:12px;color:#e4ebf3;
  font-weight:700}
.faceid-said i{display:block;font-style:normal;font-family:var(--cond);
  font-size:9px;letter-spacing:.06em;color:#8b95a6;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.faceid-go{flex:0 0 auto}

.btn-face{display:flex;align-items:center;justify-content:center;
  gap:8px;width:100%;margin-top:9px;padding:10px 14px;border:0;
  border-radius:9px;cursor:pointer;
  background:#ffffff12;color:#cfe0f5;
  font-family:var(--cond);font-size:12px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase}
.btn-face svg{width:19px;height:19px;flex:0 0 auto}
.btn-face:active{transform:translateY(1px)}
.btn-face:disabled{opacity:.55}

/* ── the matchup card's contents ──────────────────────────────────
   Contents only. Nothing below names .mx-card, .mx-body, .mx-top,
   .home or .home-block — those set the card's size and the hub's
   spacing, and a rule on any of them moves furniture outside the
   card. That is what went wrong the last time this was attempted.

   Sized to the height the old contents occupied: the card's contents
   came to 149px — 9 of body padding, 72 for the row, 68 for the band
   below. The row is 72 and the band is 68 again, so the card stands
   exactly where it did. */

/* Each owner: a name column, a hairline, a figure column. */
/* flex-basis written as 0% rather than a bare 0. A unitless zero is
   valid in the spec and accepted by browsers, but stricter parsers
   drop the whole declaration — and when this one was dropped the
   original rule's flex:0 0 auto won, so each column sized to its
   own contents and .mx-mid swallowed the middle of the card. */
.mx-owner{width:auto;flex:1 1 0%;display:flex;align-items:stretch;
  gap:8px;text-align:left;min-width:0}
/* And the middle is only as wide as the VS, not a third of the row. */
.mx-mid{flex:0 0 auto;min-width:0}
/* No row-reverse. mxOwnerBlock already appends the right side in
   mirrored order — figure, hairline, name — so reversing the row as
   well turned it back the way it came and put the name in the middle
   with the score against the outside edge. The order is the JS's job
   here; this only sets which way the text sits in it. */
.mx-owner.mx-owner-r{text-align:right}
.mx-who{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;
  justify-content:center}
.mx-hair{width:1px;flex:0 0 auto;background:#ffffff1f}
/* Pushed off the VS so the two totals are not crowding the middle. */
.mx-fig{flex:0 0 auto;display:flex;flex-direction:column;
  justify-content:center;text-align:center;padding-right:6px}
.mx-owner-r .mx-fig{padding-right:0;padding-left:6px}

.mx-oname{font-family:var(--cond);font-size:16px;font-weight:700;
  letter-spacing:.04em;text-transform:uppercase;color:#a8e6c1;
  line-height:1.3;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis}
.mx-owner-r .mx-oname{color:#f0a8ae}
.mx-orec{font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.1em;color:#5c6674;line-height:1.6}

.mx-bits{font-family:var(--cond);font-size:9.5px;letter-spacing:.07em;
  color:#6d7684;line-height:1.6;white-space:nowrap;
  text-transform:uppercase}
.mx-bit b{font-size:12px;font-weight:700;color:#c4cede}
.mx-bit i{font-style:normal}
.mx-bit.is-live b{color:#7ee2a8}
.mx-bitdot{color:#3c4453;padding:0 3px}

.mx-got{font-family:var(--cond);font-size:32px;font-weight:700;
  color:#fff;line-height:1.05}
.mx-owner-r .mx-got{color:#c4cede}
.mx-proj{font-family:var(--cond);font-size:13px;font-weight:700;
  line-height:1.25}
.mx-proj.is-up{color:#8fc2a4}
.mx-proj.is-down{color:#c99a9d}

.mx-vs{display:flex;flex-direction:column;align-items:center;gap:5px}
.mx-dash{font-family:var(--cond);font-size:14px;font-weight:700;
  letter-spacing:.1em;color:#fff}

/* ── the band at the foot ─────────────────────────────────────────
   Its own segment, so the card reads as this fixture above and the
   judgement on it below. The curve is clipped to the half above it. */
.mx-foot{margin:9px -4px 0;padding:9px 12px 8px;
  background:#00000038;box-shadow:inset 0 1px 0 #ffffff14}
.mx-footrow{display:flex;align-items:center;gap:9px}
.mx-footl,.mx-footr{flex:0 0 auto;font-family:var(--cond);
  font-size:13px;font-weight:700}
.mx-footl{color:#5dcaa5}
.mx-footr{color:#c99a9d}
.mx-bar{flex:1 1 auto;min-width:0;display:flex;height:9px;
  border-radius:5px;overflow:hidden}
.mx-bar-a{background:linear-gradient(90deg,#4a86c8,#5dcaa5)}
.mx-bar-b{background:#e0707c}
.mx-footlab{margin-top:5px;text-align:center;font-family:var(--cond);
  font-size:9px;letter-spacing:.16em;text-transform:uppercase;
  color:#4e5663}

/* The curve keeps to the top of the card, clear of the band. */
.mx-graph{bottom:56px}
/* The washes went with the two coloured halves they belonged to. */
.mx-wash,.mx-wash2{display:none}
/* The vote is off the card for now. */
.mx-pick{display:none}
/* The star on the six, in whatever colour the button is wearing. */
.mx-six svg{width:21px;height:21px}

/* ── filling the container ────────────────────────────────────────
   The contents above came to 115px against the 149 the old ones
   occupied, which would have left the card shorter than the one it
   replaces — the mistake that cost several rounds last time. The 34
   goes back as air rather than as type: width is what is scarce on
   this card, not height, and a bigger score costs the name column
   the room it needs. */
.mx-owner,.mx-mid{margin-top:14px}
.mx-oname{line-height:1.45}
.mx-orec{line-height:1.75}
.mx-bits{line-height:1.75}
.mx-foot{margin-top:15px;padding:12px 12px 11px}
.mx-bar{height:10px}
.mx-footlab{margin-top:7px}

/* ── the six on the game-day summary ──────────────────────────────
   Mirrors the brackets in the other corner and wears what the hub's
   own six wears. Inert unless gameday.js builds the button. */
.gd-six{display:flex;position:absolute;top:3px;left:4px;z-index:3;
  color:#d2a53c}
.gd-six b{font-family:var(--cond);font-size:13px;font-weight:700;
  line-height:1;letter-spacing:.02em}
.gd-six.on{color:#ffcf5c;background:none}
.gdtable .mxfull-rows{gap:3px;overflow-y:auto;
  overscroll-behavior:contain;padding-bottom:2px}

/* ── the star, white ──────────────────────────────────────────────
   The star fills with currentColor, so the button's colour is the
   star's — white, and a shade brighter while its table is open. The
   numeral inside stays the card's own dark, knocked out of it. */
.mx-six{color:#fff}
.mx-six.on{color:#fff;background:none}
.mx-six svg{width:21px;height:21px}

/* ── the counts, with room to breathe ─────────────────────────────
   The figure and its word were butted together — 0IN PLAY rather
   than 0 IN PLAY. The gap is set on the pair rather than left to a
   space character, which collapses at these sizes. */
.mx-bit{display:inline-flex;align-items:baseline;gap:4px}
.mx-bit b{font-size:12px;font-weight:700;color:#c4cede;line-height:1}
.mx-bit i{font-style:normal;line-height:1}
.mx-bitdot{padding:0 5px}

/* ── the drive, drawn on the field ────────────────────────────────
   A band from where this drive began to where the ball is now,
   fading in from the start so the direction of travel reads without
   an arrowhead. Behind the yard lines and the ball, so neither is
   obscured. */
/* A line across the field, not a band down it. As a tall block it
   read as a coloured region of the pitch — a thin rule at the
   ball's own height reads as the distance travelled. */
.gdpage .gddriveline{position:absolute;top:calc(50% - 1.5px);
  height:3px;border-radius:2px;z-index:1;pointer-events:none;
  background:#ffffff3d;transition:left .9s ease,width .9s ease}
.gdpage .gddrivefrom{position:absolute;top:calc(50% - 5px);height:10px;
  width:2px;margin-left:-1px;border-radius:2px;background:#ffffff5c;
  z-index:1;pointer-events:none;transition:left .9s ease}

/* The down, the spot and the ball had styles here for the field's
   bar. They are gone with the markup — the bar carries the last play
   and nothing else again. */

/* ── the tiles, while a game is on ────────────────────────────────
   The dot that marked the favourite becomes an arrow on whoever has
   the ball, pointing the way that club attacks. */
.gdpage .gdstrip .slate-side{position:relative}
/* Level with the badge and just outside it, aimed the way that club
   attacks — so the two sides' arrows point away from each other
   rather than both one way. */
.gdpage .gdstrip .slate-side.has-ball::after{content:"";position:absolute;
  top:7px;width:0;height:0;
  border-top:4px solid transparent;border-bottom:4px solid transparent}
.gdpage .gdstrip .slate-side.runs-l::after{left:-7px;
  border-right:6px solid #7ee2a8}
.gdpage .gdstrip .slate-side.runs-r::after{right:-7px;
  border-left:6px solid #7ee2a8}
.gdpage .gdstrip .slate-down{font-family:var(--cond);font-size:8px;
  letter-spacing:.06em;color:#c4cede;white-space:nowrap}

/* ── where each man's game is ─────────────────────────────────────
   Three states, told apart at a glance rather than read:

     playing   a green edge, and his face at full strength
     done      no edge, his face a little down — he is finished
     waiting   dimmed, with a faint edge; nothing has happened yet

   An edge rather than a tint on the row, because the rows already
   carry injury tones and a second background would fight them. */
.mxf-man{position:relative}
.mxf-man::before{content:"";position:absolute;top:3px;bottom:3px;
  width:2px;border-radius:2px;background:transparent}
.mxf-man::before{left:-5px}
.mxf-man.is-right::before{left:auto;right:-5px}

.mxf-man.is-playing::before{background:#7ee2a8}
.mxf-man.is-waiting::before{background:#ffffff14}
.mxf-man.is-done::before{background:#ffffff00}

/* ── and on the figure, which is what the eye runs down ───────────
   The edge alone was too quiet to scan. The number carries it too:

     playing   green, on a faint green ground
     done      white and plain — the figure is final
     waiting   grey, and his kickoff in place of a nought

   Showing the kickoff rather than a dash is the biggest part of it.
   A man yet to play used to read "0.0", which is indistinguishable
   from a man who played and did nothing. */
.mxf-num.is-playing b{color:#7ee2a8}
.mxf-num.is-done b{color:#fff}
.mxf-num.is-waiting b{color:#68717f;font-size:11px;letter-spacing:.04em}
.mxf-num.is-waiting .mxf-under{opacity:.5}

/* ── who is still to come, and who is done ───────────────────────
   Turned round. A man who has finished is settled — nothing about
   him will change again — so his row goes grey and the men still to
   play keep their colour and stand out against it. It used to be the
   other way about, which dimmed the only rows worth watching.

   The flame on a top-twelve finish is left alone: that is a result
   worth seeing however grey the line around it. */
.mxf-man.is-done{opacity:.62}
.mxf-man.is-done .mxf-face{filter:grayscale(1)}
.mxf-man.is-done .mxf-name{color:#8b95a6}
.mxf-man.is-done .mxf-sub,
.mxf-man.is-done .mxf-stat{color:#5f6b7d}
.mxf-num.is-done b{color:#9aa7ba}

.mxf-man.is-waiting{opacity:1}
.mxf-man.is-waiting .mxf-face{filter:none}
.mxf-man.is-waiting .mxf-name{color:#e4ebf3}
.mxf-man.is-playing .mxf-name{color:#fff}

/* A top-twelve finish no longer lifts the row out of the grey.
   That exception is why some finished men looked greyed and others
   did not — the ones who had a good week were being let off. The
   flame on the rank is the only mark it needs. */


/* ── a live man, across the whole row ─────────────────────────────
   The green was on the edge and the figure only. It runs the width
   of his half of the row now — a wash under the card and the number
   together, so the eye catches the row rather than hunting the
   marker on it. */
.mxf-row .mxf-man.is-playing,
.mxf-row .mxf-num.is-playing{background:#7ee2a812}
.mxf-row .mxf-man.is-playing{border-radius:7px 0 0 7px}
.mxf-row .mxf-man.is-playing.is-right{border-radius:0 7px 7px 0}
.mxf-row .mxf-num.is-playing{border-radius:0 7px 7px 0}
.mxf-row .mxf-man.is-right + .mxf-num.is-playing,
.mxf-row .mxf-num.is-playing:first-child{border-radius:7px 0 0 7px}

/* The scoreboard's third line, held open when it is empty. */
.gdpage .gddown.is-blank{visibility:hidden}

/* ── the possession arrow, aimed at its badge ─────────────────────
   Smaller, and pointing in at the club that has the ball rather than
   out at the edge of the tile — an arrow beside a badge reads as
   naming it, not as leaving it. */
.gdpage .gdstrip .slate-side.has-ball::after{top:8px;
  border-top:3px solid transparent;border-bottom:3px solid transparent}
/* A CSS triangle points AWAY from the coloured border: border-left
   coloured makes an arrowhead facing right. So the one sitting left
   of a badge colours its left border to point in at it, and the one
   sitting right of a badge colours its right. Written the other way
   round, both pointed off the tile. */
.gdpage .gdstrip .slate-side.runs-l::after{left:-7px;
  border-left:5px solid #7ee2a8;border-right:0}
.gdpage .gdstrip .slate-side.runs-r::after{right:-7px;
  border-right:5px solid #7ee2a8;border-left:0}

/* ── a man's line, under his fixture ──────────────────────────────
   The third line in the lineup drawer. Quieter than the fixture
   above it and clipped rather than wrapped: a long line from a
   quarterback would otherwise push the row taller than its
   neighbours and the two sides would stop lining up. */
.mxf-stat{display:block;font-family:var(--cond);font-size:8.5px;
  letter-spacing:.04em;color:#7f8b9c;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;margin-top:1px}
.mxf-man.is-playing .mxf-stat{color:#9fd3b6}
.mxf-man.is-right .mxf-stat{text-align:right}

/* ── the hub's band, while a game is on ───────────────────────────
   The same two marks the sheet's strip uses, so a tile means the
   same in both places: the down where the total was, and an arrow
   aimed in at whoever has the ball. */
.slate-side{position:relative}
.slate-side.has-ball::after{content:"";position:absolute;top:8px;
  width:0;height:0;
  border-top:3px solid transparent;border-bottom:3px solid transparent}
.slate-side.runs-l::after{left:-7px;border-left:5px solid #7ee2a8;
  border-right:0}
.slate-side.runs-r::after{right:-7px;border-right:5px solid #7ee2a8;
  border-left:0}
.slate-down{font-family:var(--cond);font-size:8px;letter-spacing:.06em;
  color:#c4cede;white-space:nowrap}

/* ── the clock, pinned to the middle ──────────────────────────────
   It sat between the two scores as a flex child, so a two-digit
   score on one side and a one-digit on the other pushed it off
   centre — and it moved again every time either changed. Absolutely
   centred now, so it stands over the halfway line whatever the
   score, and the scores flow around it. */
.gdpage .gdscore{position:relative}
.gdpage .gdclock{position:absolute;left:50%;transform:translateX(-50%);
  width:38%;text-align:center;pointer-events:none;z-index:2}
/* And the space it used to occupy is held open, so the badges and
   the scores still sit either side of it rather than meeting in the
   middle. */
.gdpage .gdclock-gap{flex:0 0 38%}

/* ── folding the field away ───────────────────────────────────────*/
.gdpage .gdfield{transition:max-height .28s ease,opacity .2s ease}
.gdpage .gdfield.is-shut{max-height:26px;overflow:hidden;
  background:#101a2b;box-shadow:inset 0 0 0 1px #ffffff14}
/* Nothing of the pitch shows through — a 26px band of grass with the
   end zones cut off read as a rendering fault rather than a folded
   panel. */
.gdpage .gdfield.is-shut > *:not(.gdfold){display:none}
.gdpage .gdfield.is-shut::after{content:"Expand field view";
  position:absolute;inset:0;display:flex;align-items:center;
  justify-content:center;font-family:var(--cond);font-size:8.5px;
  letter-spacing:.18em;text-transform:uppercase;color:#8b95a6;
  pointer-events:none}
.gdpage .gdfold{position:absolute;top:2px;right:6px;z-index:6;
  width:22px;height:20px;border:0;background:none;cursor:pointer;
  -webkit-tap-highlight-color:transparent}
.gdpage .gdfold::before{content:"";position:absolute;top:7px;left:6px;
  width:7px;height:7px;border-right:1.6px solid #ffffff8a;
  border-bottom:1.6px solid #ffffff8a;transform:rotate(-135deg);
  transition:transform .2s ease}
.gdpage .gdfield.is-shut .gdfold::before{transform:rotate(45deg);
  top:4px}

@media (prefers-reduced-motion: reduce){
  .gdpage .gdfield{transition:none}
  .gdpage .gdfold::before{transition:none}
}

/* ── the scoreboard, tightened around the middle ──────────────────
   The clock's reserved column was 38% of the board, which held the
   badges and the scores out at the edges. Narrower, so the two sides
   sit closer in to the clock between them. */
.gdpage .gdclock{width:30%}
.gdpage .gdclock-gap{flex:0 0 30%}
/* And the quarter sits up against the clock rather than floating
   above it — it was on its own line with the block's full leading
   between them. */
.gdpage .gdclock .gdq{line-height:1;margin-bottom:1px}
.gdpage .gdclock b{line-height:1.05}
.gdpage .gdclock span{line-height:1.25}
/* A touch more room in the box, so the three lines are not pressed
   against its edges now that they are closer together. */
.gdpage .gdscore{padding-top:7px;padding-bottom:8px}

/* ── the possession arrow, out of the flow ────────────────────────
   It used to be a flex child of the scoreboard, so a side with a man
   in the game was laid out differently from one without and the
   whole board shifted when possession changed. It hangs off the
   outside of its own badge now and takes no space at all. */
.gdpage .gdscore .gdclub{position:relative;overflow:visible}
.gdpage .gdpos{position:absolute;top:50%;transform:translateY(-50%)}
.gdpage .gdpos.l{left:-11px}
.gdpage .gdpos.r{right:-11px}

/* The projection under a total, in the table behind the six. */
.mxt-pts u.is-in{color:#7ee2a8}
.mxt-pts u.is-out{color:#e0707c}

/* The six on the game-day summary wears the hub's star. */
.gd-six{color:#fff}
.gd-six.on{color:#fff;background:none}
.gd-six svg{width:21px;height:21px;display:block}

/* ── the linescore, squared up with the graph below it ────────────
   It carries a 1px border and 10px of side padding with no
   box-sizing, so its 100% became 100% plus 22px and it sat wider
   than the win-probability block underneath. And a little air
   between it and the toggle bar above. */
.gdpage .gdline{box-sizing:border-box;width:100%;margin:10px 0 6px}

/* ── the lineup page's preview, in the hub card's language ────────
   Colour and weight only. Every size stays exactly as it was, so the
   strip holds the height it has always had — the point is that an
   owner reads the same here as on the hub, not that this block
   changes shape.

   What is borrowed: his name in the side's own colour, the record in
   the quiet grey under it, the total in white against the other
   side's muted blue, and the projection in the green or red pair the
   card uses for a favourite and an underdog. */
.mu-left .mu-oname b{color:#a8e6c1}
.mu-right .mu-oname b{color:#f0a8ae}
.mu-rec{color:#5c6674;letter-spacing:.1em}
.mu-worth{color:#68717f;font-weight:700}

.mu-total{font-family:var(--cond);color:#fff}
.mu-right .mu-total{color:#c4cede}

/* The projection pair. is-fave and is-dog are already set by the
   page on whichever side is projected ahead, so they only need the
   card's own two colours rather than new logic. */
.mu-ptotal{color:#8b95a6}
.mu-ptotal.is-fave{color:#8fc2a4}
.mu-ptotal.is-dog{color:#c99a9d}

/* A hairline between the owner and his figures, as the card has
   between its name column and its score. Drawn on the figures so it
   falls on the inner edge of each side. */
.mu-sums{position:relative}
.mu-sums.mu-left::before,.mu-sums.mu-right::after{content:"";
  position:absolute;top:4px;bottom:4px;width:1px;background:#ffffff1f}
.mu-sums.mu-left::before{left:-7px}
.mu-sums.mu-right::after{right:-7px}

/* ── the linescore, aligned to the graph rather than the container ─
   Both blocks are the same outer width, so squaring the boxes did
   not help: the win-probability block has no border, and the graph
   it draws sits 14px inside it. The linescore DOES have a border, so
   its visible edge was landing 14px wider than the line it sits
   above.

   Inset by that 14px, so the bordered box and the graph share their
   left and right edges. */
.gdpage .gdline{width:auto;margin:10px 14px 6px}

/* ── setting somebody else's lineup ───────────────────────────────
   Shown only to the commissioner, and only while the side on screen
   is not his own. Editing another owner's lineup looked exactly like
   editing your own, which is the wrong way round for something this
   consequential. */
.mu-bossnote{margin:0 12px 8px;padding:6px 10px;border-radius:8px;
  background:#e8402f1f;box-shadow:inset 0 0 0 1px #e8402f4d;
  font-family:var(--cond);font-size:9.5px;letter-spacing:.06em;
  color:#f0b4ac;display:flex;gap:6px;align-items:baseline}
.mu-bossnote b{color:#fff;font-size:11px;text-transform:uppercase;
  letter-spacing:.05em}

/* The opponent's block, when the commissioner may take it over. A
   quiet affordance: it should be findable without announcing itself
   on a page most people cannot use it on. */
.mu-side.can-take{cursor:pointer;border-radius:9px;
  transition:background .15s ease}
.mu-side.can-take:hover{background:#ffffff0a}
.mu-side.can-take:active{background:#ffffff14}

/* ── the two points a week pays ───────────────────────────────────
   One for the man opposite, one for the top half. The row says both:
   the fixture and whether the blend has him ahead of it, then the
   record those two add up to. */
.mxt-h2h{flex:0 0 auto;display:flex;align-items:baseline;gap:4px;
  min-width:52px}
.mxt-h2h b{font-family:var(--cond);font-size:11px;font-weight:700}
.mxt-h2h b.is-w{color:#7ee2a8}
.mxt-h2h b.is-l{color:#e0707c}
.mxt-h2h i{font-style:normal;font-family:var(--cond);font-size:8.5px;
  letter-spacing:.04em;color:#7f8b9c;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;max-width:52px}

.mxt-wk{flex:0 0 auto;min-width:28px;text-align:center;
  font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.06em}
.mxt-wk.is-two{color:#7ee2a8}
.mxt-wk.is-one{color:#c4cede}
.mxt-wk.is-none{color:#e0707c}

/* ── who he still has to come ─────────────────────────────────────
   A pressed row opens into his remaining men, in kickoff order.
   "4 left" does not say whether that is four running backs or four
   kickers, which is the only thing anybody wants to know from it. */
.mxt-row.can-open{cursor:pointer}
.mxt-row.can-open::after{content:"";flex:0 0 auto;width:5px;height:5px;
  margin-left:2px;border-right:1.4px solid #6d7684;
  border-bottom:1.4px solid #6d7684;transform:rotate(45deg)
  translateY(-1px);transition:transform .18s ease}
.mxt-row.can-open.is-open::after{transform:rotate(225deg)
  translateY(-1px)}

.mxt-still{flex:0 0 auto;display:flex;flex-wrap:wrap;gap:5px;
  margin:-2px 0 4px;padding:7px 10px;border-radius:8px;
  background:#0e1522;box-shadow:inset 0 0 0 1px #ffffff0f}
.mxt-stillman{display:flex;flex-direction:column;gap:1px;
  padding:4px 7px;border-radius:6px;background:#ffffff08;min-width:0}
.mxt-stillman b{font-family:var(--cond);font-size:10px;
  font-weight:700;color:#e4ebf3;white-space:nowrap}
.mxt-stillman i{font-style:normal;font-family:var(--cond);
  font-size:7.5px;letter-spacing:.08em;color:#6d7684;
  text-transform:uppercase;white-space:nowrap}

/* ── a fixture that is over ───────────────────────────────────────
   The bar reads 100 and 0 because the server says the result is
   settled, not because a logistic happened to round there. The
   winning score turns green and says so; the loser's drains. */
.mx-got.has-won{color:#7ee2a8}
.mx-got.has-lost{color:#8d5f5f}
.mx-victory{font-family:var(--cond);font-size:8px;font-weight:700;
  letter-spacing:.18em;text-transform:uppercase;color:#7ee2a8;
  line-height:1.2;margin-top:1px}
/* The word takes the projection's place, so the block keeps its
   height and the row does not shift when a game ends. */

/* The same on the game-day summary. */
.gdpage .gdpts.has-won{color:#7ee2a8}
.gdpage .gdpts.has-lost{color:#8d5f5f}
.gdpage .gdproj.is-victory{color:#7ee2a8;letter-spacing:.16em;
  text-transform:uppercase;font-weight:700}

/* ── the table's columns, squared to the right ────────────────────
   Figures line up on their last digit rather than their first, so a
   column of records and a column of totals can be read down. */
.mxt-h2h{justify-content:flex-end;text-align:right}
.mxt-h2h i{text-align:right}
.mxt-wk{text-align:right;min-width:30px}
.mxt-pts{text-align:right}

/* The two counts under a name. The figure carries the colour; the
   word beside it stays quiet. */
.mxt-who i{display:inline-flex;align-items:baseline;gap:2px}
.mxt-who i .mxt-sep{color:#3c4453;padding:0 3px}
.mxt-n{font-weight:700;color:#c4cede}
.mxt-n.is-live{color:#7ee2a8}
.mxt-n.is-left{color:#7ee2a8}

/* Nobody left to come. */
.mxt-nobody{font-family:var(--cond);font-size:9px;letter-spacing:.1em;
  text-transform:uppercase;color:#5c6674;padding:2px 4px}

/* ── a long stat line stays in its own column ─────────────────────
   .mxf-text is a flex column, and the right-hand side aligns its
   children to the end — which makes each child size to its own
   content rather than to the column. A quarterback's line is wider
   than the column, so it ran left across the position pill instead
   of clipping. Given the full width, the ellipsis can do its job. */
.mxf-stat,.mxf-sub,.mxf-name{max-width:100%;width:100%}
.mxf-man.is-right .mxf-stat,
.mxf-man.is-right .mxf-sub,
.mxf-man.is-right .mxf-name{text-align:right}

/* ── the head-to-head column ──────────────────────────────────────
   The opponent first and the result behind him — "Neff W" reads as
   a sentence where "W Neff" reads as a label. Right-aligned with a
   fixed letter box, so every W and L falls in the same column and
   the eye can run down it. */
.mxt-h2h{flex-direction:row;justify-content:flex-end;
  min-width:74px;gap:5px}
.mxt-h2h i{order:1;max-width:58px;text-align:right}
.mxt-h2h b{order:2;width:9px;text-align:right;flex:0 0 auto}

/* ── the board gets the ticker's room ─────────────────────────────
   Opening the table folds the week's fixtures away and gives the
   height to the drawer. The band is the least useful thing on screen
   while twelve owners are being read, and it comes straight back. */
body.mx-tableup{--slate-h:0px}
/* min-height has to go too. The band carries min-height:96px, and
   min-height beats max-height — so max-height:0 was ignored and the
   fold left a 96px hole where the fixtures had been. That hole is
   what stopped the card moving up. */
body.mx-tableup .slate{min-height:0;height:0;max-height:0;
  padding-top:0;padding-bottom:0;margin:0;
  opacity:0;overflow:hidden;border-bottom-width:0}
.slate{transition:height .28s ease,min-height .28s ease,
  opacity .2s ease,padding .28s ease}
@media (prefers-reduced-motion: reduce){.slate{transition:none}}

/* The other half of a finished fixture. Same place, same size as the
   winner's word, in the pink the losing side already wears. */
.mx-defeat{font-family:var(--cond);font-size:8px;font-weight:700;
  letter-spacing:.18em;text-transform:uppercase;color:#e0707c;
  line-height:1.2;margin-top:1px}

/* ── the columns hold their width ─────────────────────────────────
   Every column but the name is fixed now. They were sized to their
   own contents, so "Neff W" and "Eisenhauer L" made different-width
   boxes and the W and the L landed at a different x on every row —
   a column you cannot run your eye down is not a column.

   The name absorbs whatever is left. */
.mxt-who{flex:1 1 auto;min-width:0}
.mxt-h2h{flex:0 0 86px;width:86px;min-width:86px}
.mxt-h2h i{max-width:66px}
.mxt-wk{flex:0 0 34px;width:34px;min-width:34px}
.mxt-pts{flex:0 0 58px;width:58px;min-width:58px}

/* ── the row is two lines now ─────────────────────────────────────
   Name and figures across the top, his counts underneath. The fixed
   columns left about eighty pixels for a name and the counts needed
   a hundred and forty, so one line could never hold both. */
.mxt-row{flex-wrap:wrap;row-gap:2px}
.mxt-who{flex:1 1 auto;min-width:0;overflow:hidden}
.mxt-who b{display:block;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.mxt-sub2{flex:1 0 100%;display:flex;align-items:baseline;
  font-family:var(--cond);font-size:9px;letter-spacing:.06em;
  color:#6d7684;text-transform:uppercase;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;
  /* Indented to start under the name rather than under the place
     badge, so the two lines read as one block. */
  padding-left:54px}
.mxt-sub2 .mxt-sep{color:#3c4453;padding:0 4px}

/* A touch narrower, now that the name has the top line to itself. */
.mxt-h2h{flex:0 0 80px;width:80px;min-width:80px}
.mxt-h2h i{max-width:60px}

/* ── the snap share, made readable ────────────────────────────────
   A 2.5px track and a 6.5px figure is a decoration, not a reading.
   Both up: a 4px track holds its colour at a glance and the figure
   is legible without leaning in. */
.gdpage .gdtrack{height:4px;border-radius:3px;background:#ffffff1a}
.gdpage .gdsnap{gap:6px;margin-top:4px}
.gdpage .gdsnap u{font-size:8.5px;font-weight:700;color:#c4cede;
  letter-spacing:.04em;min-width:26px;text-align:right}
.gdpage .gdrow.r .gdsnap u{text-align:left}

/* ── the standings row, rebuilt ───────────────────────────────────
   Two lines instead of one, and no photograph.

   Everything used to sit across a single row: a face, a name, two
   counts, the fixture, the week's record and two figures. A phone
   gives that about three hundred pixels, and the name — the whole
   point of the row — was the part that gave way. So the owner gets
   the top line to himself and the figures share the one below. */
.mxt-row{display:flex;flex-direction:column;align-items:stretch;
  flex-wrap:nowrap;gap:0;row-gap:0;padding:8px 10px}

/* Who he is: place, name, record — centred, and the only things on
   the line. */
.mxt-head{display:flex;align-items:center;justify-content:center;
  gap:7px;min-width:0}
.mxt-name{font-family:var(--cond);font-size:13px;font-weight:700;
  color:#e4ebf3;letter-spacing:.02em;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;min-width:0}
.mxt-rec{font-family:var(--cond);font-size:9.5px;letter-spacing:.12em;
  color:#6d7684;flex:0 0 auto}

/* How his week is going: spread across the line beneath, each part
   holding its own share so the columns line up down the table. */
.mxt-cols{display:flex;align-items:baseline;gap:8px;margin-top:5px;
  min-width:0}
.mxt-bits{flex:1 1 auto;min-width:0;display:flex;align-items:baseline;
  gap:3px;font-family:var(--cond);font-size:8.5px;letter-spacing:.06em;
  color:#6d7684;text-transform:uppercase;white-space:nowrap}
.mxt-bits i{font-style:normal}
.mxt-cols .mxt-h2h{flex:0 0 74px;width:74px;min-width:74px}
.mxt-cols .mxt-h2h i{max-width:54px}
.mxt-cols .mxt-wk{flex:0 0 30px;width:30px;min-width:30px}
.mxt-cols .mxt-pts{flex:0 0 54px;width:54px;min-width:54px}

/* The arrow moves to the head, where there is room for it. */
.mxt-row.can-open::after{position:absolute;right:10px;top:12px;
  margin:0}
.mxt-row{position:relative}
.mxt-head{padding-right:14px}

/* The sub-line and the face are gone. */
.mxt-sub2,.mxt-face{display:none}

/* ── all twelve on one screen ─────────────────────────────────────
   The drawer gets roughly 620px once the week's band has folded, so
   a row has about 48 to play with if twelve are to fit without
   scrolling. Measured: 6 + 16 + 4 + 11 + 6 = 43, and 3 of gap
   between them, which is 552 for the dozen.

   Names to the left, where a list is read from. */
.mxt-head{justify-content:flex-start;gap:8px}
.mxt-name{flex:1 1 auto}
.mxt-rec{margin-left:auto;padding-right:2px}

.mxt-row{padding:6px 10px}
.mxt-name{font-size:12.5px;line-height:1.25}
.mxt-place{width:19px;font-size:10.5px;padding:2px 0}
.mxt-cols{margin-top:4px}
.mxt-bits{font-size:8px}
.mxt-bits b{font-size:10px}
.mxt-h2h b{font-size:10px}
.mxt-h2h i{font-size:8px}
.mxt-wk{font-size:10px}
.mxt-pts b{font-size:11.5px;line-height:1.1}
.mxt-pts u{font-size:8.5px}
.mxt-row.can-open::after{top:10px;width:4.5px;height:4.5px}

/* Tighter between rows, and the list only scrolls if it has to. */
.mxfull-rows{gap:3px}
.gdtable .mxfull-rows{gap:3px}

/* ── the losing side, in one red ──────────────────────────────────
   The name, the score, the word and the projection were four
   different reds — #f0a8ae, #8d5f5f, #e0707c and #c99a9d — which
   read as four unrelated things rather than one result. */
.mx-owner-r .mx-oname,
.mx-got.has-lost,
.mx-defeat,
.mx-proj.is-down{color:#e0707c}

/* ── the projection moves out from under the total ────────────────
   It was stacked beneath, which made the figures line two rows tall
   and was most of why twelve would not fit. Beside it instead, in a
   column of its own. */
.mxt-pts{display:flex;align-items:baseline;justify-content:flex-end;
  gap:6px;flex:0 0 86px;width:86px;min-width:86px}
.mxt-pts b{flex:0 0 auto}
.mxt-pts u{flex:0 0 auto;text-decoration:none;min-width:34px;
  text-align:right}

/* ── the owner's line, on a ground of its own ─────────────────────
   A wash behind the name and the standing, so the row reads as a
   heading with its figures under it rather than four lines of
   similar-looking text. */
.mxt-head{background:#ffffff0d;border-radius:6px;padding:3px 8px;
  margin:-1px -2px 0}
.mxt-row.is-mine .mxt-head{background:#8fbdf01f}
.mxt-row.is-done .mxt-head{background:#7f1d1d33}

/* Where each owner stands, in his name. */
.mxt-name.is-out{color:#e0707c}
.mxt-name.is-idle{color:#8b95a6}

/* A fixture that can still change keeps its figures white — a
   coloured W on a half-played game is a guess dressed as a result. */
.mxt-h2h b.is-open{color:#e4ebf3}
.mxt-wk.is-open{color:#e4ebf3}

/* The head band's padding put the height straight back — twelve rows
   came to 648 against about 620. Two pixels off each band and one
   off each gap is the 36 needed, without touching a type size. */
.mxt-head{padding:2px 8px}
.mxt-cols{margin-top:3px}
.mxt-row{padding:5px 10px}
.mxfull-rows{gap:2px}
.gdtable .mxfull-rows{gap:2px}

/* ── tighter again, and the arrow comes down a line ───────────────
   One size for everything on the figures line, so it reads as a row
   rather than four separate labels. The total comes down and the
   projection comes up to meet it — they are the same kind of number
   and were two sizes apart. */
.mxt-row{padding:4px 9px}
.mxt-head{padding:1px 7px;margin:0 -2px}
.mxt-place{width:16px;font-size:9.5px;padding:1px 0;border-radius:4px}
.mxt-name{font-size:12px;line-height:1.2}
.mxt-rec{font-size:9px;letter-spacing:.1em}
.mxt-cols{margin-top:3px;align-items:center}

.mxt-bits{font-size:9.5px}
.mxt-bits b{font-size:9.5px}
.mxt-h2h b{font-size:9.5px}
.mxt-h2h i{font-size:9.5px;text-transform:none}
.mxt-wk{font-size:9.5px}
.mxt-pts b{font-size:9.5px;line-height:1.2}
.mxt-pts u{font-size:9.5px}

/* The chevron rides at the end of the figures line, where there is
   room, rather than floating in the row's top corner. */
.mxt-row.can-open::after{display:none}
.mxt-cols::after{content:"";flex:0 0 auto;width:5px;height:5px;
  margin-left:4px;border-right:1.4px solid #6d7684;
  border-bottom:1.4px solid #6d7684;
  transform:rotate(45deg) translateY(-1px);
  transition:transform .18s ease}
.mxt-row.is-open .mxt-cols::after{transform:rotate(225deg)
  translateY(-1px)}

/* The columns come in a little, now that everything is one size. */
.mxt-cols .mxt-h2h{flex:0 0 70px;width:70px;min-width:70px}
.mxt-cols .mxt-h2h i{max-width:52px}
.mxt-cols .mxt-wk{flex:0 0 28px;width:28px;min-width:28px}
.mxt-pts{flex:0 0 78px;width:78px;min-width:78px}
.mxt-pts u{min-width:32px}

/* ── room between the columns, and the odds behind the letter ─────
   Some of them were four pixels apart, which read as one figure run
   into the next. Ten, and the columns re-cut to pay for it. */
.mxt-cols{gap:10px}
.mxt-cols .mxt-h2h{flex:0 0 96px;width:96px;min-width:96px;gap:5px}
.mxt-cols .mxt-h2h i{max-width:40px}
.mxt-cols .mxt-wk{flex:0 0 26px;width:26px;min-width:26px}
.mxt-pts{flex:0 0 72px;width:72px;min-width:72px;gap:5px}
.mxt-pts u{min-width:30px}

/* His chance of taking the fixture, after the W or L. Quieter than
   the letter — it qualifies the call rather than making it. */
.mxt-odds{text-decoration:none;font-family:var(--cond);font-size:9px;
  font-weight:700;color:#6d7684;flex:0 0 auto;min-width:26px;
  text-align:right}
.mxt-h2h b.is-w ~ .mxt-odds{color:#7ee2a8}
.mxt-h2h b.is-l ~ .mxt-odds{color:#c99a9d}

/* ── the result, over the owner's name ────────────────────────────
   In the space above the name rather than beside it, and absolutely
   placed so it takes no height of its own. The summary keeps the
   same shape all afternoon and then names the winner without
   anything under it moving.

   Each side reads outward from the middle, as everything else on
   that bar does. */
.gdpage .gdmatch .gdstext{position:relative}
.gdpage .gdcalled{position:absolute;top:-11px;
  font-family:var(--cond);font-size:8px;font-weight:700;
  letter-spacing:.2em;text-transform:uppercase;line-height:1;
  white-space:nowrap;pointer-events:none}
.gdpage .gdcalled.is-won{color:#7ee2a8}
.gdpage .gdcalled.is-lost{color:#e0707c}
.gdpage .gdside.l .gdcalled{left:0}
.gdpage .gdside.r .gdcalled{right:0}

/* The old inline mark is gone with it. */
.gdpage .gdwon{display:none}

/* ── who still has men to come ────────────────────────────────────
   The band behind the name says it, so a live owner is obvious from
   the shape of the list rather than from reading twelve sets of
   counts.

     a man on a field now   green ground, a green edge down the left
     men still to come      a lighter ground than a finished row
     finished               the quiet ground it always had
     out of it              red, as before

   The edge is on the left because that is where the eye starts, and
   it costs no height. */
.mxt-head{border-left:2px solid transparent;padding-left:6px}
.mxt-row.is-alive .mxt-head{background:#ffffff1a}
.mxt-row.is-alive .mxt-name{color:#fff}
.mxt-row.is-onfield .mxt-head{background:#7ee2a81f;
  border-left-color:#7ee2a8}
/* Your own row and an eliminated one keep their own grounds — being
   yours, or being out, matters more than having men left. */
.mxt-row.is-mine .mxt-head{background:#8fbdf01f}
.mxt-row.is-mine.is-onfield .mxt-head{border-left-color:#7ee2a8}
.mxt-row.is-done .mxt-head{background:#7f1d1d33;
  border-left-color:transparent}

/* ── the top five, stacked ────────────────────────────────────────
   One list rather than two mirrored columns. The leaders of a game
   are one thing; mirroring half of them meant reading right to left
   for no reason. */
.gdpage .gdtops.is-stacked{display:flex;flex-direction:column;gap:5px}
.gdpage .gdtop-flat{width:100%}
.gdpage .gdtop-at{flex:0 0 auto;width:14px;text-align:center;
  font-family:var(--cond);font-size:11px;font-weight:700;
  color:#6d7684}

/* ── the bench ────────────────────────────────────────────────────
   The starters' cards, quieter. Still his men, still with a game,
   but nothing they do counts this week. */
.gdpage .gdbenchrule b{color:#8b95a6;letter-spacing:.16em}
.gdpage .gdbench .gdrow{background:#1b2738;
  box-shadow:inset 0 0 0 1px #ffffff14}
.gdpage .gdrow.is-benched .gdface img{filter:grayscale(.45)}
.gdpage .gdrow.is-benched .gdwho b{color:#c4cede;font-size:13px}
.gdpage .gdrow.is-benched .gdval{color:#8b95a6;font-size:18px}
/* A bench projection is not a figure anybody acts on; the snap
   share is, because it says whether points were left sitting. */
.gdpage .gdrow.is-benched .gdproj{display:none}
.gdpage .gdrow.is-benched .gdsnap i{background:#5f6b7d}
.gdpage .gdrow.is-benched .gdsnap u{color:#8b95a6}

/* ── the player cards, at the size they were drawn ────────────────
   .gdval was 10.5px for every card, so the bench's 18px made a
   reserve read louder than a starter. The starters take the size
   instead, and the bench sits a step under them. */
/* Four classes deep on purpose. The block above sets these in a
   grouped selector whose other halves carry a fourth class, and
   rather than trust every engine to score each half of a group
   separately, this simply outranks all of them. */
.gdpage .gdmen .gdrow .gdwho b{font-size:14px;line-height:1.25}
.gdpage .gdmen .gdrow .gdwho i{font-size:11px;line-height:1.3}
.gdpage .gdmen .gdrow .gdval{font-size:22px;line-height:1.05}
.gdpage .gdmen .gdrow .gdval u{font-size:11px;font-weight:700;
  line-height:1.3}
.gdpage .gdmen.packed .gdrow .gdwho b{font-size:13px}
.gdpage .gdmen.packed .gdrow .gdval{font-size:19px}

/* The bench, a step quieter than the starters rather than louder. */
.gdpage .gdbench .gdrow .gdwho b{font-size:13px}
.gdpage .gdbench .gdrow .gdwho i{font-size:10.5px}
.gdpage .gdbench .gdrow.is-benched .gdval{font-size:18px;color:#8b95a6}

/* The stacked leaders keep the same treatment. */
.gdpage .gdtops .gdrow .gdwho b{font-size:13px}
.gdpage .gdtops .gdrow .gdwho i{font-size:11px}
.gdpage .gdtops .gdrow .gdval{font-size:18px}

/* ── the counts, sized to the record above them ───────────────────
   The figures were 12px against an 11px record, so the quieter fact
   was the louder type and the line ran wider than its column. */
.mx-bits{font-size:8.5px}
.mx-bit b{font-size:11px}

/* ── the bench, dimmer than a starter ─────────────────────────────
   Same cards, lower on the page and lower in weight. A reserve
   should not compete with a man whose points are counting. */
.gdpage .gdbench .gdrow{background:#16202f;
  box-shadow:inset 0 0 0 1px #ffffff0f;opacity:.82}
.gdpage .gdbench .gdrow .gdwho b{color:#aebdd0}
.gdpage .gdbench .gdrow .gdwho i{color:#77839a}
.gdpage .gdbench .gdface img{filter:grayscale(.55);opacity:.85}

/* ── the result, and the space it always occupies ─────────────────
   Drawn only when a fixture had been called, the line came and went
   as the arrows walked between a finished matchup and one still
   being played, and the card changed height under the thumb. It is
   always drawn now; without a result it is invisible. */
.mx-called{font-family:var(--cond);font-size:8px;font-weight:700;
  letter-spacing:.18em;text-transform:uppercase;line-height:1.2;
  margin-top:1px}
.mx-called.is-won{color:#7ee2a8}
.mx-called.is-lost{color:#e0707c}
.mx-called.is-none{visibility:hidden}

/* ── the bench, darker again ──────────────────────────────────────
   Far enough from a starter that the two sections are told apart
   before either is read. */
.gdpage .gdbench .gdrow{background:#0e1622;
  box-shadow:inset 0 0 0 1px #ffffff0a;opacity:.74}
.gdpage .gdbench .gdrow .gdwho b{color:#9aa7ba}
.gdpage .gdbench .gdrow .gdwho i{color:#68758a}
.gdpage .gdbench .gdrow .gdval{color:#7d8798}
.gdpage .gdbench .gdface img{filter:grayscale(.7);opacity:.75}
.gdpage .gdbenchrule b{color:#6d7684}

/* ── the card's three parts on two lines ──────────────────────────
   Photograph, name and score across the top; the snap bar spanning
   underneath. The bar used to live inside the name column, which
   made that column three lines tall — and the score, centred on the
   row, sank to the middle of all three and sat level with the bar
   rather than with his name. */
.gdpage .gdmen .gdrow{flex-wrap:wrap;row-gap:5px}
.gdpage .gdmen .gdrow .gdsnap{flex:1 0 100%;margin-top:0}
.gdpage .gdmen .gdrow .gdval{align-self:center}

/* ── whoever has the ball ─────────────────────────────────────────
   A green ring while his offence is on the field, red in the red
   zone. The bench keeps it too — a reserve whose side has the ball
   is exactly the man you want to see, since he is the one you left
   out. */
.gdpage .gdbench .gdrow.hot{background:#15803d1f;
  box-shadow:inset 0 0 0 1px #7ee2a866;opacity:.9}
.gdpage .gdbench .gdrow.rz{background:#7f1d1d29;
  box-shadow:inset 0 0 0 1px #e0707c99;opacity:.9}
.gdpage .gdbench .gdrow.hot .gdwho b,
.gdpage .gdbench .gdrow.rz .gdwho b{color:#e4ebf3}

/* ── the drawers move rather than jump ────────────────────────────
   Their top is set from the card's bottom edge, and set again once
   the week's band has folded — so without a transition on `top` the
   second reading was a jump. Both now slide on the same curve and
   over the same 280ms the band takes, so the card rising and the
   drawer following read as one movement. */
.mxfull{transition:opacity .34s cubic-bezier(.4,0,.2,1),
  top .28s cubic-bezier(.4,0,.2,1)}
@media (prefers-reduced-motion: reduce){
  .mxfull{transition:none}
}

/* ── the hub's lineup rows, at a readable size ────────────────────
   The middle column — the position badge — is untouched. Everything
   either side of it comes up: the name from 10.5 to 13, his fixture
   and stat line from 8.5 to 10, and the score from 13 to 19.

   The score columns widen to carry it and the name columns absorb
   the difference, so the badge stays exactly where it was. */
.mxf-row{grid-template-columns:minmax(0,1fr) 38px 42px 38px minmax(0,1fr);
  gap:6px;min-height:44px}
.mxf-name{font-size:13px;line-height:1.25}
.mxf-sub{font-size:10px}
.mxf-stat{font-size:10px}
.mxf-num b{font-size:19px;line-height:1.1}
.mxf-num .mxf-under{font-size:10px}

/* The figure sits hard against the middle, level with the name and
   the lines under it. */
.mxf-num{text-align:right;padding-right:2px}
.mxf-man.is-right + .mxf-num,
.mxf-row > .mxf-num:first-of-type{text-align:right}
.mxf-row > .mxf-num:last-of-type{text-align:left;padding-right:0;
  padding-left:2px}
.mxf-face{width:30px;height:30px}

/* ── the drawer arrives with the card, not after it ───────────────
   The fade ran 340ms against the band's 280, so the rows were still
   coming up as the card finished moving and the two read as separate
   events. The fade is shorter than the movement now and starts with
   it, so the drawer is there by the time the card settles. */
.mxfull{transition:opacity .16s linear,
  top .28s cubic-bezier(.4,0,.2,1)}
.gdpage .gdfull{transition:opacity .16s linear}

/* ── the rows take the card's full width ──────────────────────────
   The arrows are a control for walking between fixtures, and there
   is no fixture to walk to while a lineup is open — so they come off
   and the rows get the 34px they were holding. Names were losing
   about six characters to it. */
.mx-card.is-open .mx-arrow{opacity:0;pointer-events:none;
  transition:opacity .14s linear}
.mxfull-rows{padding-left:0;padding-right:0}
.mxfull-inner{padding-left:10px;padding-right:10px}
.mxf-row{grid-template-columns:minmax(0,1fr) 34px 42px 34px minmax(0,1fr);
  gap:7px}

/* ── the rails step aside for a drawer ────────────────────────────
   League and News sit over the page at all times, which is right
   when the hub is the hub — and wrong when a drawer has taken the
   screen. They come off with the arrows, for the same reason: there
   is nothing to pull out from behind a panel that already covers
   what they would open onto. */
body.mx-tableup .newstab,
body.mx-tableup .leaguetab{opacity:0;pointer-events:none;
  transition:opacity .14s linear}

/* ── the drawer as wide as the card above it ──────────────────────
   The card is inset 16px by the hub column and 10 by its own row;
   the drawer was inset 10 and looked narrower than the thing it
   opens from. Same inset now, so the two edges line up. */
.mxfull-inner{padding-left:16px;padding-right:16px;box-sizing:border-box}

/* ── a man in the first twelve at his position ────────────────────
   A warm wash behind his card and his rank in the same heat. Twelve
   is the line because a starting lineup is twelve deep across the
   league — inside it he is somebody worth having started. */
/* The wash behind the card is gone — the rank itself carries the
   heat, and a gradient behind the row as well was the same thing
   said twice and made the grey around it harder to read. */
.mxf-num.is-top12 .mxf-flip{
  background:linear-gradient(90deg,#ffd24a,#ff8a3d 48%,#e8402f);
  -webkit-background-clip:text;background-clip:text;
  -webkit-text-fill-color:transparent;color:#ff8a3d;font-weight:700}

/* ── every pixel that is not the name ─────────────────────────────
   A row is 358 wide on a phone, and the name gets whatever is left
   after two score columns, the position badge, four gaps and a
   photograph. Measured, that was 74px — and "D. Montgomery" needs
   about 88.

   The badge is untouched. Everything else comes in: the photograph
   to 24, the gaps to 4, and the score columns sized to exactly what
   a 19px figure needs rather than a round number. That buys about
   twelve characters back. */
.mxf-row{grid-template-columns:minmax(0,1fr) 34px 42px 34px minmax(0,1fr);
  gap:4px}
.mxf-face{width:24px;height:24px;flex:0 0 24px}
.mxf-man{gap:5px}
.mxf-text{min-width:0;flex:1 1 auto}
.mxf-name{font-size:12.5px;letter-spacing:-.01em}
.mxf-num b{font-size:18px}

/* And the inner padding comes off the drawer, since the rows are
   what needs the room — the card above sets the edge, not this. */
.mxfull-inner{padding-left:12px;padding-right:12px}

/* ── the drawer matches the card, and nothing touches its edge ────
   The inner padding is the hub column's own 16, so the rows end
   exactly where the card above them does. And each row carries a
   little of its own, because the rows box is rounded and clipped —
   a photograph or an injury letter flush against that edge was
   being cut by the corner.

   Paid for by the columns rather than the names: the photograph to
   22, the score columns to 32, the gaps to 3. */
.mxfull-inner{padding-left:16px;padding-right:16px}
.mxf-row{grid-template-columns:minmax(0,1fr) 32px 42px 32px minmax(0,1fr);
  gap:3px;padding:0 5px}
.mxf-face{width:22px;height:22px;flex:0 0 22px}
.mxf-man{gap:5px}
.mxf-num b{font-size:17px}
/* The letter on a photograph's corner needs somewhere to sit. */
.mxfull-rows{overflow:visible}
.mxfull-rows > .mxf-row:first-child{border-top-left-radius:12px;
  border-top-right-radius:12px}
.mxfull-rows > .mxf-row:last-child{border-bottom-left-radius:12px;
  border-bottom-right-radius:12px}

/* ── the two figure columns face the middle ───────────────────────
   The left owner's score, projection and finish sit hard against
   the centre; the right owner's start there. Marked with a class
   rather than by position, because :last-of-type breaks the moment
   anything is appended after it. */
.mxf-num{text-align:right;padding-right:3px;padding-left:0}
.mxf-num.is-right{text-align:left;padding-right:0;padding-left:3px}

/* ── room for the letter on a photograph's corner ─────────────────
   The flag hangs 4px outside the face, and 5px of row padding left
   it a pixel from the edge — near enough to read as clipped. */
.mxf-row{padding:0 8px}
.mxf-man{overflow:visible}
.mxf-text{overflow:hidden}

/* ── the fixture line, with the result on it ──────────────────────
   Club, score, club, score — the winner's abbreviation in green.
   The "v" and the "@" have gone: which ground it was played on
   matters far less than who won, and those two characters were the
   room the score needed. */
.mxf-club{font-weight:700;color:#8b95a6}
.mxf-club.is-won{color:#7ee2a8}
.mxf-pts{color:#c4cede;font-weight:700;padding:0 5px 0 2px}
.mxf-man.is-done .mxf-club{color:#68717f}
.mxf-man.is-done .mxf-club.is-won{color:#5f9b7c}
.mxf-man.is-done .mxf-pts{color:#6d7684}

/* ── a man yet to play ────────────────────────────────────────────
   His kickoff sits where a score would, so it reads at the same
   size as one rather than as a footnote. */
.mxf-num.is-waiting b{font-size:17px;color:#8b95a6;letter-spacing:.02em}

/* ── the badge, spent ─────────────────────────────────────────────
   Grey once both men in the row have finished. The colour down the
   middle column then marks the rows still worth watching rather
   than every row equally. */
.mxf-slot.is-spent{background:#ffffff0f !important;color:#6d7684 !important;
  box-shadow:none !important}

/* ── a man still to come reads bolder ─────────────────────────────
   Weight rather than colour, so it survives the grey around a
   finished row and the flame on a good one. */
.mxf-man.is-waiting .mxf-name,
.mxf-man.is-playing .mxf-name{font-weight:700}
.mxf-man.is-done .mxf-name{font-weight:400}

/* The ground marker, once the game is over: a join between two
   scores rather than a fact about the fixture. */
.mxf-at.is-over{color:#4e5663;background:none;padding:0 4px}

/* ── one spacing on the fixture line ──────────────────────────────
   The row is a flex with a 3px gap, and the score and the ground
   marker each carried padding of their own on top — so "KC 27 @ BUF
   17" had four different gaps in it. The padding comes off and the
   gap does the work. */
.mxf-sub{gap:4px}
.mxf-pts{padding:0}
.mxf-at.is-over{padding:0}
.mxf-at{padding:0}
.mxf-day{margin-left:2px}

/* ── played, and about to play ────────────────────────────────────
   A settled figure is the quietest thing in the row: nothing about
   it will change. A man yet to kick off keeps his, because that is
   the number still in play.

     done      dim, and his finish dimmer still
     waiting   plain, and his kickoff plain with it
     playing   white

   The flame on a top-twelve finish is untouched. */
.mxf-num.is-done b{color:#767f8d}
.mxf-num.is-done .mxf-flip{color:#5a6472}
.mxf-num.is-done .mxf-under{opacity:.55}

.mxf-num.is-waiting b{color:#aebdd0}
.mxf-num.is-waiting .mxf-flip{color:#8b95a6}

.mxf-num.is-playing b{color:#fff}
.mxf-num.is-playing .mxf-flip{color:#9fd3b6}

/* ── the six, as a dial ───────────────────────────────────────────
   The mark colours itself, so the button no longer sets a colour of
   its own — the ticks and the numeral carry it. */
.mx-six svg,.gd-six svg{width:23px;height:23px;display:block}
.mx-six,.gd-six{color:inherit}
.mx-six.on svg,.gd-six.on svg{filter:brightness(1.18)}

/* ── the card's three marks ───────────────────────────────────────
   Positioned exactly as the two always were: the card's own corners,
   absolutely placed, nothing in the flow. I had put them in a flow
   row instead, which pushed the whole card down and broke it — the
   layout was never the thing that needed changing.

   A dial an owner in the corner nearest him; the lineups mark
   centred between them. */
.mx-six{position:absolute;top:7px;left:9px;right:auto;z-index:3;
  width:20px;height:20px;padding:0;background:none;border:0;
  line-height:0}
.mx-six svg{width:20px;height:20px;display:block}

/* Between the two, on the same line. The mark is the shape of the
   drawer it opens, as a dial is the shape of the table. */
/* right:auto matters. An earlier rule pins this to right:2px, and
   setting left:50% without clearing it left the button stretched
   between the two edges rather than centred on one. */
/* In the middle column now, under the VS — so it sits in the gap
   between the two projections rather than in the card's top edge.
   Static, because the column already centres it. */
.mx-vs .mx-expand{position:static;transform:none;margin-top:1px}
/* No box: the mark is the button. A panel round it made it the
   loudest thing on the card's top edge, which a control that opens a
   drawer does not need to be. */
.mx-expand{position:absolute;top:7px;right:9px;left:auto;
  transform:none;z-index:3;
  display:flex;align-items:center;justify-content:center;
  width:26px;height:20px;padding:0;border-radius:0;
  background:none;box-shadow:none;border:0}
.mx-expand svg{width:19px;height:15px;display:block}
.mx-expand:active{opacity:.6}
.mx-card.is-open .mx-expand svg{filter:brightness(1.3)}


/* The row is in the flow rather than over it, so the names below are
   pushed down by it and nothing has to be nudged clear by hand —
   and the card's own containers stay untouched. */

/* A man on a field now, inside an opened row. */
.mxt-stillman.is-live{background:#7ee2a81f;
  box-shadow:inset 0 0 0 1px #7ee2a840}
.mxt-stillman.is-live b{color:#fff}
.mxt-stillman.is-live i{color:#9fd3b6}

/* ── the sheet's own three marks ──────────────────────────────────
   The same as the card's: a dial an owner in the corner nearest him,
   the lineups between them. */
.gdpage .gd-six{position:absolute;top:8px;left:10px;right:auto;
  z-index:4;width:20px;height:20px;padding:0;background:none;border:0;
  line-height:0}
.gdpage .gd-six svg{width:20px;height:20px;display:block}

.gdpage .gd-expand{position:absolute;top:8px;right:10px;left:auto;
  transform:none;z-index:4;
  display:flex;align-items:center;justify-content:center;
  width:26px;height:20px;padding:0;border-radius:0;
  background:none;box-shadow:none;border:0}
.gdpage .gd-expand svg{width:19px;height:15px;display:block}
.gdpage .gd-expand:active{opacity:.6}
.gdpage .gd-expand[aria-expanded="true"] svg{filter:brightness(1.3)}

/* ── whoever has the ball, on a starter's card ────────────────────
   .gdrow.hot is two classes; .gdpage .gdrow is three, so the plain
   card background was quietly winning and the ring never drew on a
   starter. It only ever showed on the bench because I happened to
   write that rule deeper. Stated at the same depth here. */
.gdpage .gdmen .gdrow.hot{background:#15803d2e;
  box-shadow:inset 0 0 0 1px #7ee2a888}
.gdpage .gdmen .gdrow.rz{background:#7f1d1d3d;
  box-shadow:inset 0 0 0 1px #e0707ccc}
.gdpage .gdmen .gdrow.hot .gdwho b,
.gdpage .gdmen .gdrow.rz .gdwho b{color:#fff}

/* ── the in-play band, one height across the row ──────────────────
   The man's half is three lines tall and the figure's is one, so two
   grounds of the same colour still read as two blocks with a step
   between them. Both stretch to the row now and centre their own
   contents, so the wash is a single band. */
.mxf-row .mxf-man,
.mxf-row .mxf-num{align-self:stretch}
.mxf-row .mxf-num{display:flex;flex-direction:column;
  justify-content:center}
.mxf-row .mxf-man{align-items:center}

/* The drag now lives on the game-day summary rather than the hub's
   card — see .gd-drag-hint below. */

/* ── the VS keeps its place, the mark hangs below it ──────────────
   Putting the button in the column pushed the VS up, because the
   column centres whatever is in it — so adding a second child moved
   the first. The mark is taken out of that flow and hung under the
   column instead, which leaves the VS exactly between the two
   totals where it was. */
/* The mark is back in the corner, so the middle column holds the VS
   alone again. */

/* And the names come down a step — 16 was louder than the record and
   the counts under it needed. */
.mx-oname{font-size:14px}

/* ── the sheet's summary under a finger ───────────────────────────
   The same drag the hub's card has, on the bar that actually carries
   the fixtures. */
.gdpage .gdmatch{position:relative}
/* The name hint is gone: it sat over the owner's face during a drag,
   and the ghost beside it now shows the whole fixture anyway — the
   name was answering a question the picture had already answered. */
.gd-drag-hint{display:none;position:absolute;top:50%;
  transform:translateY(-50%);
  z-index:6;pointer-events:none;
  font-family:var(--cond);font-size:11px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase;color:#6d7684;
  white-space:nowrap;max-width:36%;overflow:hidden;
  text-overflow:ellipsis;transition:color .12s linear}
.gd-drag-hint.is-l{left:10px}
.gd-drag-hint.is-r{right:10px}
.gd-drag-hint.is-past{color:#7ee2a8}

/* ── the turn is instant ──────────────────────────────────────────
   The three parts used to fade to nothing and back over 220ms each
   way, so a committed drag let go and then waited nearly half a
   second before the new fixture appeared. The load is awaited before
   anything is painted, so there was never a half-drawn state for the
   fade to hide — it was covering a wait that does not exist.

   The drag already moves the bar off under the finger; what comes
   back should simply be there. */
.gdpage .gdmatch,
.gdpage .gdfixed,
.gdpage .gdscroll{transition:none}
.gdpage .is-turning{opacity:1}

/* The field needs a corner for its own hint. */
.gdpage .gdfield{position:relative}

/* ── what is coming in ────────────────────────────────────────────
   Sitting in the space the drag opens, so the gap shows the next
   fixture rather than the page behind. A child of the bar, pushed a
   full width the other way — it travels with the drag and arrives as
   the old one leaves. */
.gd-ghost{position:absolute;inset:0;z-index:5;pointer-events:none;
  display:flex;align-items:center;justify-content:center;gap:10px;
  padding:0 14px;box-sizing:border-box;opacity:0}
.gd-ghost-side{flex:1;min-width:0;display:flex;flex-direction:column;
  gap:2px;overflow:hidden}
.gd-ghost-side.r{text-align:right;align-items:flex-end}
.gd-ghost-side b{font-family:var(--cond);font-size:13px;font-weight:700;
  color:#c4cede;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis;max-width:100%}
.gd-ghost-side.l b{color:#a8e6c1}
.gd-ghost-side.r b{color:#f0a8ae}
.gd-ghost-side i{font-style:normal;font-family:var(--cond);
  font-size:20px;font-weight:700;color:#e4ebf3}
.gd-ghost-vs{flex:0 0 auto;font-family:var(--cond);font-size:11px;
  font-weight:700;letter-spacing:.12em;color:#6d7684}
.gd-ghost.is-past .gd-ghost-side i{color:#fff}

/* The field's own ghost sits on its dark ground. */
.gd-ghost-field{background:#0d1626;border-radius:10px}
.gd-ghost-field .gd-ghost-side{align-items:center;text-align:center}
.gd-ghost-field .gd-ghost-side b{color:#c4cede;font-size:14px}
.gd-ghost-field .gd-ghost-side i{font-size:22px}

/* ── the field's ghost, beside it ─────────────────────────────────
   A sibling of the field rather than a child: .gdfield clips its own
   contents, which is right for yard lines and wrong for a copy
   parked a full width to the side.

   The parent has to stop clipping too, or the ghost is cut off at
   its edge instead. */
.gdpage #gdFixed{overflow:visible}
/* Placed and sized from the field's own box in JS, because the
   parent holds more than the field. */
.gd-ghost-field{position:absolute;background:none;padding:0;
  z-index:5;pointer-events:none;opacity:0;box-sizing:border-box}
.gd-ghost-field .gdfield.is-ghosted{width:100%;height:100%;
  pointer-events:none;margin:0}

/* The field's parent is the anchor the ghost is placed against. */
.gdpage .gdfixed{position:relative}

/* ── the sheet stops clipping its own bar ─────────────────────────
   .gdsheet clips at its edge, which is right for the page beneath it
   and wrong for a ghost parked a width out — the copy was cut away
   until the drag had pulled it most of the way in, which is exactly
   when it stops being useful.

   The bar is given its own clipping box instead, so the ghost is
   masked by the BAR rather than by the whole sheet, and its leading
   edge shows from the first pixel of a drag. */
/* The summary fades rather than sliding, so it needs no ghost and no
   clipping rule of its own. */
.gd-ghost{position:absolute;background:var(--ink);z-index:6;
  pointer-events:none;box-sizing:border-box;opacity:0;
  display:block;padding:0}

/* ── the summary turn fades ───────────────────────────────────────
   It goes down and comes back rather than sliding. A slide needs the
   neighbouring bar drawn, and that needs a fetch — a copy that
   arrives late, or not at all, is worse than a fade that always
   works.

   Stated last on purpose: an earlier block sets these to none for
   the instant version, and last wins. Written above it, this did
   nothing at all.

   The field keeps its slide — one self-contained picture, with all
   its data already in hand. */
.gdpage .gdmatch,
.gdpage .gdscroll{transition:opacity .2s ease}
.gdpage .gdmatch.is-turning,
.gdpage .gdscroll.is-turning{opacity:0}
.gdpage .gdfixed{transition:none}
.gdpage .gdfixed.is-turning{opacity:1}

/* ── a man's share of the snaps ───────────────────────────────────
   On the depth chart, in both views. A bar and a figure: the bar so
   a glance down a column says who plays and who does not, the figure
   for when the answer matters exactly.

   Coloured by the share itself — green at seventy, amber at forty,
   red below — so "hardly plays" reads before the number does. */
/* The row wraps so this can have a line of its own beneath the name,
   the figures and the button — a bar squeezed beside a name is a
   different thing from a bar that spans what it describes. */
.dcrow{flex-wrap:wrap;row-gap:4px}
.dcsnap{flex:1 0 100%;display:flex;flex-direction:column;gap:2px;
  font-family:var(--cond);line-height:1}
.dcsnap-line{display:flex;align-items:center;gap:7px}
.dcsnap-bar{flex:1 1 auto;min-width:0;height:4px;border-radius:3px;
  background:#00000040;overflow:hidden}
.dcsnap-fill{display:block;height:100%;border-radius:3px}
.dcsnap b{flex:0 0 auto;font-weight:700;font-size:11px;
  min-width:30px;text-align:right}
/* Only where the scale has not set one — "Inactive" has no share to
   colour by. */
.dcsnap b.off{color:#6d7684}
.dcsnap u{text-decoration:none;font-size:8.5px;letter-spacing:.14em;
  color:#6d7684}

/* ── the field card's own ──────────────────────────────────────────
   One line under the name — bar, figure, then the word — centred,
   with the position stripe below it. The word stays: "88% SNAPS" on
   one line says what it is, where a bare 88% under a name could be
   anything.

   The bar is sized rather than stretched, because a card is narrow
   and a full-width track would push the figure off it. */
/* No width of its own.
   
   .dcman-btn is already a flex column that centres its children, so
   the box only has to size to its contents and the card puts it in
   the middle. width:100% asked for a share of a parent whose width
   is itself decided by its widest child — which resolved against the
   name above it and left the bar sitting off to one side. */
/* Centred the way the stripe below it is: a block that spans the
   card, with its contents centred as text.
   
   Two goes at this with flex centring both left it off to one side,
   because the card's width is decided by its widest child and a
   percentage inside it resolves against a moving target. text-align
   on a block does not care how wide the block turned out to be. */
.dcsnap.sm{display:block;flex:0 0 auto;width:100%;margin:3px 0 1px;
  text-align:center}
/* The line has to FIT, not merely be centred.
   
   A fixed 30px bar plus a gap plus "100%" comes to about sixty
   pixels, and a player's card on the field is narrower than that —
   so the unit overflowed its card and centring spread the overflow
   evenly, which reads as the bar sitting central and the figure
   hanging off the side.
   
   Capped at the card's width, with the bar giving way: the figure
   never shrinks, because a percentage half-drawn is worse than a
   short bar. */
.dcsnap.sm .dcsnap-line{display:inline-flex;vertical-align:middle;
  gap:4px;max-width:100%}
.dcsnap.sm .dcsnap-bar{flex:1 1 auto;min-width:12px;max-width:26px;
  height:3px}
.dcsnap.sm b{flex:0 0 auto;font-size:9.5px;min-width:0;
  text-align:left;white-space:nowrap}
/* No word on the field card. The bar and the figure sit under a
   name on a player's own card, where there is nothing else they
   could be counting — the label was spending a line on something
   the context already said. The list view keeps it, because a row
   there carries several figures and one of them needs naming. */
.dcsnap.sm u{display:none}
/* The figure sets its own colour inline, so nothing here may claim
   it — a colour stated here would win over the scale. */
.dcsnap.sm b:not(.off){color:inherit}

/* Nobody dressed: an empty track and a word in its place. */
.dcsnap.none .dcsnap-bar{background:#00000059;
  box-shadow:inset 0 0 0 1px #ffffff14}
.dcsnap b.off{color:#6d7684;font-size:9.5px;letter-spacing:.08em;
  text-transform:uppercase;min-width:0}

/* The latest week, where it differs from the season by enough to
   mean something — an arrow's worth of news, not a second statistic. */
.dcsnap i{font-style:normal;font-size:9px;font-weight:700;
  padding-left:1px}
.dcsnap i.up{color:#7ee2a8}
.dcsnap i.up::before{content:"\2191"}
.dcsnap i.down{color:#e0707c}
.dcsnap i.down::before{content:"\2193"}

/* ── the sidecar's years ──────────────────────────────────────────
   Which season the figures are for. Built from the seasons the club
   actually has, so it offers what exists rather than a list written
   down and left to go stale. */
/* The house segmented control, centred above whatever it governs.
   No colours of its own — .seg already knows what a toggle looks
   like on this site, and a second opinion about that is how two
   pages end up disagreeing. */
.dcyearwrap{display:flex;justify-content:center;margin:0 0 10px}
.dcyears{flex:0 0 auto}

/* ── portrait only, on anything held in a hand ────────────────────
   The app is laid out in one column: a card the width of a phone,
   drawers that come up from the bottom, a field drawn to the screen.
   Turned sideways none of that has anywhere to go, and every width
   we have fought over this week is measured against a portrait
   screen.

   There is no way to actually prevent rotation from a web page —
   screen.orientation.lock() needs fullscreen, and a browser tab is
   not that. The manifest's "orientation": "portrait" handles the
   installed app; this handles the tab, by saying plainly what to do
   rather than showing a broken layout.

   Touch only: hover:none and pointer:coarse together mean a finger,
   not a mouse, so a desktop window that happens to be wide is left
   alone. */
@media (orientation: landscape) and (hover: none) and (pointer: coarse) {
  body::after{
    content:"Turn back to portrait";
    position:fixed;inset:0;z-index:99999;
    display:flex;align-items:center;justify-content:center;
    padding:0 40px;text-align:center;
    background:var(--ink);color:#8b95a6;
    font-family:var(--cond);font-size:15px;font-weight:700;
    letter-spacing:.14em;text-transform:uppercase}
  /* Nothing behind it can be reached, so a stray tap cannot act on a
     layout nobody can see. */
  body > *{pointer-events:none}
}

/* ── the doom table ───────────────────────────────────────────────
   Every owner's season on one line, sortable, with the differentials
   behind an opened row. Same sheet as the trades card. */

/* The head is a red band rather than the usual dark one — this is the
   league's own table, and it should announce itself. */
.doom-head{background:var(--red);border-bottom:0}
.doom-head b{color:#fff;letter-spacing:.14em}
.doom-head .sheet-x{color:#ffffffd9}
.doom-head .sheet-x:active{background:#00000026}

/* No side padding: the striped rows and the opened block run to the
   card's own edge rather than floating inside a margin. The cells
   carry the inset instead. */
.doomtable{padding:12px 0 14px;font-variant-numeric:tabular-nums}

.dt-head{display:flex;align-items:flex-end;padding:0 10px 9px;
  border-bottom:1px solid #ffffff1f}
/* One size and one weight for everything but the owner's name, so a
   row reads as a line rather than as ten competing figures. */
/* A button centres its text by default, and that default was
   beating this rule — so the headings sat centred over right-aligned
   figures. Stated on the element as well, which wins. */
/* Centred, not right-aligned: a column of three-figure numbers of
   the same width reads better centred, and it gives every heading
   the same relationship to the rule beneath it. Rank and owner stay
   left, since those are labels rather than figures. */
button.dt-h,.dt-h{font-family:var(--cond);font-size:9px;font-weight:700;
  letter-spacing:.06em;color:#5c6674;background:none;border:0;padding:0;
  cursor:pointer;text-align:center;
  -webkit-tap-highlight-color:transparent}
/* The owner heading sits over the names, so it is the one label that
   is not right-aligned. */
button.dt-h.l,.dt-h.l{text-align:left}
/* The owner heading carries the same inset its names do, so the two
   start on the same pixel rather than one sitting proud of the
   other. */
button.dt-h.owner,.dt-h.owner{padding-left:5px}
/* The sorted column is lit rather than tabbed: the heading goes
   green and its figures carry a faint wash all the way down, which
   says the same thing without a shape that crowds its neighbour. */
.dt-h.on{color:var(--money)}

/* align-items:stretch, not centre: the sorted column's wash has to
   run the row's full height to read as a column rather than as a
   floating box round one number. */
.dt-row{display:flex;align-items:stretch;padding:0 10px;
  border-bottom:1px solid #ffffff0a;cursor:pointer;
  -webkit-tap-highlight-color:transparent}
.dt-row.alt{background:#ffffff05}
.dt-row.mine{box-shadow:inset 3px 0 0 var(--money)}
.dt-row.is-cut{border-bottom:2px solid var(--red)}

/* Every figure the same: one size, one weight, one colour. Rank and
   efficiency take a colour, and the name is larger — nothing else
   varies. */
/* The cell carries the row's height, so the divider is a full-height
   rule and the wash fills the row.
   
   No ellipsis on a figure: a truncated number is worse than a
   slightly tight one, and "1.." for eleventh was the symptom. The
   name is the only cell allowed to trim. */
.dt-c{display:flex;align-items:center;justify-content:center;
  font-family:var(--cond);font-size:11px;font-weight:700;
  color:#b8c2cf;white-space:nowrap;overflow:visible;
  border-left:1px solid #ffffff0f;padding:15px 0}
/* The first two carry no rule — a divider before the rank would sit
   on the card's edge. */
.dt-c.dt-place{border-left:0;padding-left:0;justify-content:flex-start}
/* The name keeps its inset from the rank; only the rule goes. Written
   at this specificity because .dt-c.dt-name beats a bare .dt-name,
   and the padding set there was being overridden to nothing while the
   heading above it kept its own. */
.dt-c.dt-name{border-left:0;padding-left:5px;
  justify-content:flex-start;overflow:hidden}
.dt-c.dt-name b{overflow:hidden;text-overflow:ellipsis}
.dt-place{font-size:12.5px}
.dt-place.is-in{color:var(--money)}
.dt-place.is-out{color:var(--red)}
.dt-name{font-size:12.5px;color:#fff}
/* The sorted column, washed top to bottom. */
.dt-lit{background:#7ee2a80f}
/* Points for and points against carry their own colour, total and
   average alike, so the two halves of the table read apart at a
   glance without a rule between them. */
.dt-for{color:#7ee2a8}
.dt-against{color:#e0707c}
.dt-eff.is-up{color:var(--money)}
.dt-eff.is-mid{color:#e8b84b}
.dt-eff.is-down{color:var(--red)}

/* ── an opened owner ──────────────────────────────────────────── */
/* A deeper green behind an opened owner. The old wash was so faint
   the block read as the same surface as the table, which defeated
   the border round it. */
.dt-open{border-top:1px solid #7ee2a866;
  border-bottom:1px solid #7ee2a84d;background:#0d1f1d}
.dt-open .dt-row{background:#7ee2a814;border-bottom:0}
.dt-openbody{padding:14px 12px 15px}

.dt-capt{display:flex;align-items:baseline;justify-content:space-between;
  font-family:var(--cond);font-size:9px;font-weight:700;
  letter-spacing:.12em;color:#6d7684;margin-bottom:13px}
.dt-capt-r{color:#4e5663;letter-spacing:.08em}
.dt-capt-2{margin:17px 0 13px;padding-top:14px;
  border-top:1px solid #ffffff14}

.dt-diff{display:flex;align-items:center;gap:7px;margin-bottom:13px}
.dt-diff:last-of-type{margin-bottom:0}
.dt-diff-pos{flex:0 0 24px;font-family:var(--cond);font-size:11.5px;
  font-weight:700;color:#b8c2cf}
.dt-track{flex:1;height:10px;border-radius:5px;background:#00000040;
  position:relative;overflow:hidden}
.dt-fill{position:absolute;top:0;bottom:0;border-radius:5px}
/* Above the league grows away from the centre to the right, below it
   to the left — so the fill reads as a direction, not a quantity. */
.dt-fill.is-up{left:0;background:linear-gradient(90deg,#15803d,#7ee2a8)}
.dt-fill.is-down{right:0;background:linear-gradient(90deg,#e0707c,#7f1d1d)}
.dt-avg{flex:0 0 36px;text-align:center;font-family:var(--cond);
  font-size:11.5px;font-weight:700;color:#dde5ef}
.dt-delta{flex:0 0 32px;text-align:right;font-family:var(--cond);
  font-size:11.5px;font-weight:700;color:#b8c2cf}
.dt-delta.is-up{color:var(--money)}
.dt-delta.is-down{color:var(--red)}
.dt-rank{flex:0 0 24px;text-align:right;font-family:var(--cond);
  font-size:11.5px;font-weight:700;color:#6d7684}
.dt-rank.is-last{color:var(--red)}

/* The per-week figures, which used to be two columns of their own.
   Here they read as a sentence rather than as a pair of numbers
   nobody sorted by. */
.dt-perweek{display:flex;justify-content:space-between;gap:10px;
  margin-top:16px;padding-top:13px;border-top:1px solid #ffffff14}
.dt-pw{display:flex;flex-direction:column;gap:2px}
.dt-pw i{font-style:normal;font-family:var(--cond);font-size:9px;
  letter-spacing:.1em;color:#5c6674}
.dt-pw b{font-family:var(--cond);font-size:14px;font-weight:700;
  color:#dde5ef}
.dt-pw b.dt-for{color:#7ee2a8}
.dt-pw b.dt-against{color:#e0707c}

.dt-foot{display:flex;justify-content:space-between;margin-top:15px;
  padding-top:12px;border-top:1px solid #ffffff14;
  font-family:var(--cond);font-size:11.5px;font-weight:700;
  color:#6d7684}

/* ── an owner's season, on his card ───────────────────────────────
   Record and points for under the name. Two figures, not a row of
   them: the card is a way in to the roster, and anything more turns
   a grid of faces into a second table. */
/* A stripe across the whole card, not a line under the name. Both
   figures the same size and the same grey — the record bold, the
   points regular — with a rule between them so they read as two
   things rather than one number with a space in it. */
.teamline{display:flex;align-items:center;justify-content:center;
  align-self:stretch;margin:4px -4px -6px;padding:5px 0;
  background:#00000038;border-top:1px solid #ffffff0f;
  border-radius:0 0 10px 10px;font-family:var(--cond);line-height:1}
.teamline b{padding:0 8px;font-size:11px;font-weight:700;color:#8b95a6}
.teamline i{padding:0 8px;font-style:normal;font-size:11px;
  font-weight:400;color:#8b95a6;border-left:1px solid #ffffff1f}




/* The club filter on the statistics page, beside the year buttons.
   Sized to hold three letters and a caret, no more. */
.stats-club{min-width:76px;font-family:var(--cond);font-size:11px;
  font-weight:700;letter-spacing:.06em}
