/* ---------- palette: night field, NFL red as the highlight ----------

   One committed dark look rather than a light/dark pair: the drawer and the
   login field are always dark, and a light page between them read as a
   different site. The menu's language carries across every page -- dark green
   panel, hairline edge, red only for hover and the current thing.

   Surfaces are OPAQUE on purpose. .matrix .rowhead is position:sticky and has
   to paint over the columns scrolling under it, so a translucent --surface
   would let them bleed through. Real translucency is kept for the topbar and
   drawer, which are single large panels where it is both safe and cheap. */
:root {
  --bg:        #131d19;
  --surface:   #1b2823;
  --raised:    #23332c;
  --line:      rgba(232,239,235,.10);
  --line-soft: rgba(232,239,235,.06);
  --ink:       #e8efeb;
  --muted:     #9fb3a9;

  --green:      #8fc9ad;
  --green-deep: #1f3a2f;
  --green-soft: rgba(143,201,173,.16);
  --green-tint: rgba(143,201,173,.075);

  --red:        #f0928a;
  --red-soft:   rgba(240,146,138,.16);
  --red-tint:   rgba(240,146,138,.09);

  --amber:      #e6c48f;
  --amber-soft: rgba(230,196,143,.15);

  /* A player currently on the field. Brighter than --green, which is the
     furniture colour here and reads as dim next to a live number. */
  --live:  #a8e6c4;
  /* 25 points and climbing. */
  --ember: #f4a77a;

  --shadow: 0 1px 2px rgba(0,0,0,.22);
  /* what makes a panel read as hovering over the field */
  --lift: 0 10px 28px rgba(0,0,0,.28), 0 1px 0 rgba(232,239,235,.04) inset;
  --radius: 10px;
  /* The sticky top bar's real height: 15px padding + a 34px burger + 15px
     padding + the 3px red border. Page furniture that sticks below it offsets
     by this rather than by a guess. */
  --topbar-h: 67px;

  /* NFL shield red, the drawer and topbar accent */
  --nfl-red:  #e8857c;
  /* text on any accent fill */
  --on-accent: #131d19;

  /* field green for the scoreboard block */
  --field:      #26463a;
  --field-deep: #1d362d;
  --chalk:      rgba(232,239,235,.14);

  /* Condensed athletic face for headings and numerals, with a system fallback
     so the site still reads right with no network. */
  --display: "Barlow Condensed", "Helvetica Neue Condensed", "Arial Narrow",
             ui-sans-serif, system-ui, sans-serif;

  /* One width for both the featured matchup and every compact card below it,
     so the two are tied together and cannot drift apart the next time either
     changes. */
  --card-w: 1260px;

  /* desktop layout */
  --gutter: 20px;          /* 32px >=1024, 40px >=1440 */
  --page-max: 1880px;      /* lg/xl pages with a rail */
  --rail-w: 320px;         /* 360px >=1920 */
  --col-gap: 28px;
  --rail-top: calc(var(--topbar-h) + 16px);
  --prose-max: 72ch;

  /* motion */
  --dur-1: 120ms;  /* hover, press, chip out */
  --dur-2: 200ms;  /* chip in, toggles, fades */
  --dur-3: 320ms;  /* re-sort, panel enter */
  --dur-4: 600ms;  /* count-up, bars */
  --ease-out: cubic-bezier(.2,.7,.2,1);
  --ease-io:  cubic-bezier(.4,0,.2,1);
  --ease-in:  cubic-bezier(.4,0,1,1);   /* exits */
  --hover-line: rgba(232,239,235,.22);  /* hover border */
  --lift-hover: 0 12px 30px rgba(0,0,0,.30), 0 1px 0 rgba(232,239,235,.05) inset;
  --main-px: 20px;                      /* main inline padding, read by full-bleed children */
  --td-size: 15px;                      /* touchdown football */
  --stagger: 18ms;
}
@media (min-width: 1024px) { :root { --gutter: 32px; } }
@media (min-width: 1440px) { :root { --gutter: 40px; } }
@media (min-width: 1920px) { :root { --rail-w: 360px; } }
@media (prefers-reduced-motion: reduce) {
  :root { --dur-2: 0ms; --dur-3: 0ms; --dur-4: 0ms; --stagger: 0ms; }
}
* { box-sizing: border-box; }
body {
  margin: 0; min-height: 100vh; color: var(--ink); background: var(--bg);
  font: 15px/1.55 ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
a { color: var(--green); }

/* ---------- the pitch behind every page ----------

   The same field.svg the login uses, but dimmed and set far back so panels
   read as hovering over it. It is a sibling of the content rather than a body
   background because a body background is painted onto the canvas, behind even
   negative z-index children, and could not be layered under the panels this
   way. Scroll drives it: scrolling the page walks us up the field. */
.pitch {
  position: fixed; inset: 0; z-index: 0; overflow: hidden;
  background: linear-gradient(#0e1714 0%, #111a17 26%, #131d19 30%);
  perspective: 1100px; perspective-origin: 50% 30%;
}
/* Half-scale markings and low opacity: this is a texture under the page, not
   the login's hero. At full size the yard numbers were bigger than the text
   sitting on them. */
.pitch-plane {
  position: absolute; top: 30%; left: 50%;
  width: 2600px; height: 1200px; margin-left: -1300px;
  overflow: hidden; opacity: .17;
  transform-origin: 50% 0; transform: rotateX(84deg);
}
.pitch-plane::before {
  content: ""; position: absolute; left: 0; right: 0; top: -720px; bottom: 0;
  background: url("/static/field.svg") repeat 0 0 / 1300px 720px;
}
/* Sink the far distance into the dark and keep the near turf from competing
   with the text sitting on top of it. */
.pitch::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(#0e1714 24%, rgba(14,23,20,.62) 34%, rgba(19,29,25,.88) 100%);
}
@keyframes pitchrun {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(0, 1440px, 0); }
}
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .pitch-plane::before {
      animation: pitchrun linear;
      animation-timeline: scroll(root block);
      animation-range: 0% 100%;
    }
  }
}
main, .banner { position: relative; z-index: 1; }

/* ---------- top bar ---------- */
.topbar {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center;
  padding: 15px 20px; min-height: 62px; gap: 16px;
  background: rgba(27, 40, 35, .84); color: var(--ink);
  backdrop-filter: blur(16px) saturate(1.1);
  -webkit-backdrop-filter: blur(16px) saturate(1.1);
  border-bottom: 3px solid var(--nfl-red);
}
/* hash marks along the bar, like yard lines on a field */
.topbar::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 3px;
  background: repeating-linear-gradient(90deg,
    transparent 0 46px, rgba(232,239,235,.40) 46px 48px);
  pointer-events: none;
}
/* ---------- the running ticker ----------
   Best three in every lineup slot. The run is rendered twice and the track
   slides exactly -50%, so the second copy is under the cursor at the moment
   the first ends and the loop has no seam. Duration scales with nothing --
   the content length is fixed by the number of lineup slots. */
.ticker {
  flex: 1 1 auto; min-width: 0; overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 40px,
                        #000 calc(100% - 40px), transparent);
          mask-image: linear-gradient(90deg, transparent, #000 40px,
                        #000 calc(100% - 40px), transparent);
}
.ticker-track {
  display: flex; align-items: center; gap: 26px; width: max-content;
  animation: tickerrun 70s linear infinite;
}
.ticker:hover .ticker-track { animation-play-state: paused; }
@keyframes tickerrun {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .ticker-track { animation: none; }
  .ticker { overflow-x: auto; }
}
/* A phone's bar is the burger and the status chip with nothing to spare -- a
   marquee between them has nowhere to run. The touchdown strip below stays:
   it only appears when a rostered player has just scored. */

.tk-group { display: inline-flex; align-items: center; gap: 12px; white-space: nowrap; }
.tk-pos {
  font-family: var(--display); font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .12em; color: var(--on-accent);
  background: var(--nfl-red); border-radius: 3px; padding: 2px 7px;
}
.tk-p { display: inline-flex; align-items: baseline; gap: 6px; font-size: 13px;
        color: var(--ink); white-space: nowrap; }
.tk-rank { font-family: var(--display); font-size: 11px; font-weight: 700;
           color: var(--muted); }
.tk-team { font-family: var(--display); font-size: 10.5px; font-weight: 700;
           letter-spacing: .06em; color: var(--muted); }
.tk-val { font-weight: 700; font-variant-numeric: tabular-nums; color: var(--ink); }

/* ---------- touchdown strip ----------
   Only appears when a rostered player has just scored, so it is allowed to be
   loud. Every row here is owned by definition: only rostered players are ever
   polled into the table the count is diffed from. */
.tdstrip {
  position: relative; z-index: 1;
  overflow: hidden; white-space: nowrap;
  padding: 8px 0; font-size: 13.5px;
  background: linear-gradient(90deg, rgba(232,133,124,.22), rgba(232,133,124,.10));
  border-bottom: 1px solid rgba(232,133,124,.45);
}
/* padding-left:100% parks the line just off the right edge, and translating
   -100% of the track's own width carries it all the way off the left. That
   works whatever the line is worth -- one touchdown or six -- where a -50%
   two-copy loop would leave a hole on a wide screen when only one had
   landed. */
.tdtrack {
  display: inline-flex; align-items: baseline; gap: 44px;
  padding-left: 100%;
  animation: tdrun 26s linear infinite;
}
.tdstrip:hover .tdtrack { animation-play-state: paused; }
@keyframes tdrun {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-100%, 0, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .tdtrack { padding-left: 20px; animation: none; }
  .tdstrip { overflow-x: auto; }
}
.td-item { display: inline-flex; align-items: baseline; gap: 7px; }
.td-badge {
  font-family: var(--display); font-size: 11px; font-weight: 700;
  letter-spacing: .12em; color: var(--on-accent); background: var(--nfl-red);
  border-radius: 3px; padding: 2px 7px;
}
.td-team { font-family: var(--display); font-size: 10.5px; font-weight: 700;
           letter-spacing: .06em; color: var(--muted); }
.td-mult { font-weight: 700; color: var(--red); }
.td-owner { font-size: 12px; color: var(--muted); }
.td-owner::before { content: "\2192 "; }

.topbar .status {
  margin-left: auto; display: flex; align-items: center; gap: 8px;
  flex: 0 0 auto; white-space: nowrap;
}
.topbar .muted { color: rgba(255,255,255,.7); }

.burger {
  width: 34px; height: 34px; flex: 0 0 34px; display: grid; place-content: center; gap: 5px;
  background: transparent; border: 1px solid rgba(255,255,255,.28);
  border-radius: 8px; cursor: pointer; padding: 0;
}
.burger:hover { background: rgba(255,255,255,.12); }
.burger span {
  display: block; width: 16px; height: 1.5px; background: #fff; border-radius: 2px;
  transition: transform var(--dur-2) var(--ease-out), opacity var(--dur-1) var(--ease-out);
}
.nav-open .burger span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.nav-open .burger span:nth-child(2) { opacity: 0; }
.nav-open .burger span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

.chip {
  white-space: nowrap;
  font-size: 10.5px; font-weight: 650; letter-spacing: .05em; text-transform: uppercase;
  padding: 3px 9px; border-radius: 4px; background: rgba(255,255,255,.16); color: #fff;
}
.chip.green { background: var(--red); color: var(--on-accent); }          /* live is the loud state */
.chip.amber { background: rgba(255,255,255,.16); }
.chip.violet { background: var(--ink); color: var(--green-deep); }
.chip.pulse { animation: pulse 1.9s ease-in-out infinite; }
@keyframes pulse { 50% { opacity: .5; } }

/* ---------- side drawer ---------- */
/* Glass over the page in deep field green, red only as the hover/active accent. It
   sits above the topbar, so the green bar tinting through the blur is the
   intended look. Always dark, in either colour scheme. */
.drawer {
  position: fixed; top: 0; left: 0; bottom: 0; width: 256px; z-index: 60;
  background: rgba(27, 40, 35, .86); color: var(--ink);
  backdrop-filter: blur(14px) saturate(1.1);
  -webkit-backdrop-filter: blur(14px) saturate(1.1);
  border-right: 1px solid var(--line);
  transform: translateX(-24px);
  opacity: 0;
  visibility: hidden;
  box-shadow: none;
  /* close: quick and accelerating; visibility flips after the fade */
  transition:
    transform var(--dur-1) var(--ease-in),
    opacity   var(--dur-1) var(--ease-in),
    box-shadow var(--dur-1) var(--ease-in),
    visibility 0s linear var(--dur-1);
  display: flex; flex-direction: column; overflow-y: auto;
}
/* No backdrop-filter (older Firefox): fall back to the opaque surface. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .drawer { background: var(--surface); }
}
.nav-open .drawer {
  transform: none;
  opacity: 1;
  visibility: visible;
  box-shadow: 1px 0 0 var(--line-soft), 8px 0 24px rgba(0,0,0,.22);
  /* open: slightly longer, decelerating */
  transition:
    transform var(--dur-2) var(--ease-out),
    opacity   var(--dur-2) var(--ease-out),
    box-shadow var(--dur-2) var(--ease-out),
    visibility 0s;
}
.drawer-head {
  padding: 16px 18px 14px; color: var(--ink);
  border-bottom: 1px solid var(--line);
}
.drawer-title { font-family: var(--display); font-weight: 700; font-size: 19px;
                text-transform: uppercase; letter-spacing: .05em; }
.drawer-sub { font-size: 12px; color: var(--muted); }
.drawer-nav { padding: 10px 8px; display: flex; flex-direction: column; gap: 1px; }
.drawer-nav a {
  display: block; padding: 9px 13px; border-radius: 7px; text-decoration: none;
  font-family: var(--display); font-size: 14.5px; font-weight: 500;
  text-transform: uppercase; letter-spacing: .085em;
  color: rgba(232,239,235,.84); border-left: 2px solid transparent;
  transition: background var(--dur-1), color var(--dur-1), border-color var(--dur-1);
}
.drawer-nav a:hover {
  background: rgba(232,239,235,.06); color: var(--ink); border-left-color: rgba(232,133,124,.5);
}
.drawer-nav a.on {
  background: rgba(232,133,124,.18); color: var(--ink); font-weight: 600;
  border-left-color: var(--nfl-red);
}
.drawer-nav a:focus-visible { outline: 2px solid var(--green); outline-offset: -2px; }
.scrim {
  position: fixed; inset: 0; z-index: 50;
  background: rgba(10,16,14,.32);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity var(--dur-1) var(--ease-in), visibility 0s linear var(--dur-1);
}
.nav-open .scrim {
  opacity: 1; visibility: visible; pointer-events: auto;
  transition: opacity var(--dur-2) var(--ease-out), visibility 0s;
}

/* Reduced motion for the drawer, scrim, burger and live chip. Sits after those
   rules so it wins the cascade. */
@media (prefers-reduced-motion: reduce) {
  .drawer, .nav-open .drawer { transform: none; }
  .drawer      { transition: opacity var(--dur-1) linear, visibility 0s linear var(--dur-1); }
  .nav-open .drawer { transition: opacity var(--dur-1) linear, visibility 0s; }
  .scrim       { transition: opacity var(--dur-1) linear, visibility 0s linear var(--dur-1); }
  .nav-open .scrim  { transition: opacity var(--dur-1) linear, visibility 0s; }
  .burger span { transition: none; }
  .chip.pulse  { animation: none; }
}

/* ---------- layout ---------- */
/* Never narrower than the old fixed width, roughly 80% of the viewport on a
   wide monitor, and capped so a line of text on an ultrawide doesn't run the
   full screen. */
main { padding: 22px 20px 60px; max-width: clamp(1180px, 80vw, 1560px); margin: 0 auto; }
h1 { font-family: var(--display); font-size: 30px; margin: 2px 0 16px; font-weight: 700;
     text-transform: uppercase; letter-spacing: .01em; line-height: 1.1; }
h2 { font-family: var(--display); font-size: 15px; margin: 30px 0 10px; font-weight: 600;
     text-transform: uppercase; letter-spacing: .1em; color: var(--ink);
     display: flex; align-items: center; gap: 9px; }
/* end-zone tick before every section heading */
h2::before { content: ""; width: 3px; height: 14px; background: var(--red); border-radius: 1px; }
h3 { font-family: var(--display); font-size: 15px; margin: 0 0 8px; font-weight: 600;
     text-transform: uppercase; letter-spacing: .07em; }
.muted { color: var(--muted); font-weight: 400; }
.small { font-size: 11.5px; }
.empty { color: var(--muted); padding: 26px 0; }
code { background: var(--green-soft); color: var(--green); padding: 1.5px 5px;
       border-radius: 4px; font-size: 12.5px; }

.banner { padding: 10px 20px; font-size: 13.5px; }
.banner.error { background: var(--red-soft); color: var(--red); border-bottom: 1px solid var(--red); }
.banner.warn  { background: var(--amber-soft); color: var(--amber); border-bottom: 1px solid var(--amber); }
.notice {
  background: var(--surface); border: 1px solid var(--line); border-left: 2px solid var(--red);
  border-radius: var(--radius); padding: 12px 15px; font-size: 13.5px; margin: 14px 0;
  box-shadow: var(--lift);
}
.scope { display: flex; gap: 6px; margin: -4px 0 16px; flex-wrap: wrap; }
.scope a {
  color: var(--muted); text-decoration: none; font-size: 12.5px; font-weight: 550;
  padding: 4px 11px; border-radius: 5px; background: var(--surface); border: 1px solid var(--line);
}
.scope a:hover { border-color: var(--red); color: var(--red); }
.scope a.on { background: var(--red); color: var(--on-accent); border-color: var(--red); }

/* ---------- hero / countdown ---------- */
.hero { display: flex; justify-content: space-between; align-items: flex-start; gap: 22px; flex-wrap: wrap; }
.countdown {
  background: var(--surface); border: 1px solid var(--line); border-top: 2px solid var(--red);
  border-radius: var(--radius); padding: 13px 20px; text-align: right; min-width: 205px;
  box-shadow: var(--lift);
}
.cd-label { font-size: 10px; text-transform: uppercase; letter-spacing: .09em; color: var(--muted); }
.cd-clock { font-size: 25px; font-weight: 650; font-variant-numeric: tabular-nums;
            color: var(--red); margin: 1px 0; }
.cd-when { font-size: 12px; color: var(--muted); }

/* ---------- games ---------- */
.games { display: grid; gap: 10px; grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr)); }
.game {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 13px 15px; display: block; position: relative; box-shadow: var(--lift);
}
.side { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.side:last-child { text-align: right; align-items: flex-end; }
.side .name { color: var(--ink); font-size: 13.5px; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
.side .pts { font-size: 20px; font-weight: 650; font-variant-numeric: tabular-nums; }
.side.winning .pts { color: var(--red); }
.side .proj { font-size: 11px; color: var(--muted); }
.vs { color: var(--muted); font-size: 11.5px; font-variant-numeric: tabular-nums; }
.rev { position: absolute; top: 4px; right: 9px; font-size: 10px; font-weight: 650; color: var(--amber); }

a.teamlink { text-decoration: none; color: inherit; border-radius: 6px;
             padding: 4px 6px; margin: -4px -6px; transition: background .12s ease; }
a.teamlink:hover { background: var(--red-soft); cursor: pointer; }
a.teamlink:hover .name { color: var(--red); }

/* ---------- tables ---------- */
table { border-collapse: separate; border-spacing: 0; width: 100%; margin-top: 8px;
        background: var(--surface); border: 1px solid var(--line);
        border-radius: var(--radius); overflow: hidden; box-shadow: var(--lift); }
th, td { padding: 8px 12px; border-bottom: 1px solid var(--line-soft); text-align: left; }
thead th { background: var(--green-tint); color: var(--muted); font-weight: 650;
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .07em; }
tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover { background: var(--red-tint); }
tbody tr:target { background: var(--red-soft); box-shadow: inset 2px 0 0 var(--red); }
.num { text-align: right; font-variant-numeric: tabular-nums; }
.good { color: var(--green); font-weight: 600; }
.bad { color: var(--red); font-weight: 600; }

.scroll { overflow-x: auto; border-radius: var(--radius); }
/* The wrapper carries the lift so the table inside keeps square corners -- and
   it does the clipping and the rounding too, so the base rule's overflow:hidden
   has to come back off here. That overflow makes the table its own scroll
   container, and .rowhead's position:sticky then resolves against a box that
   never scrolls, which is why the first column has never actually held. */
.scroll table { box-shadow: none; overflow: visible; }
.matrix { min-width: 100%; width: auto; }
.matrix th, .matrix td { border-right: 1px solid var(--line-soft); white-space: nowrap; }
.matrix .rowhead { text-align: left; font-weight: 600; position: sticky; left: 0;
  background: var(--surface); z-index: 2; box-shadow: 1px 0 0 var(--line); }
/* The corner cell holds with them, or the header row slides out from over its
   own column. Its tint is translucent, so it is stacked over the opaque surface
   rather than swapped for it -- the weeks passing underneath must not show
   through the one cell that is supposed to stay put. */
.matrix thead .rowhead {
  background: linear-gradient(var(--green-tint), var(--green-tint)), var(--surface);
  z-index: 3;
}
.matrix .rot { font-size: 10.5px; text-align: center; max-width: 92px;
  overflow: hidden; text-overflow: ellipsis; }
.matrix .cell { text-align: center; font-variant-numeric: tabular-nums; }
.matrix .self { background: var(--green-tint) !important; }
.matrix .cell.champ { background: var(--red-soft) !important; }
.matrix .cell.champ .muted { color: var(--red); font-weight: 650; }
.draftboard .pname { font-size: 12.5px; font-weight: 600; }
.draftboard .cell { text-align: left; max-width: 155px; }

/* ---------- rules search ---------- */
.searchbar { position: relative; margin: 4px 0 18px; }
.searchbar input {
  width: 100%; padding: 11px 16px 11px 40px; font-size: 15px; color: var(--ink);
  background: var(--surface); border: 1px solid var(--line); border-radius: 8px; outline: none;
}
.searchbar input:focus { border-color: var(--red); box-shadow: 0 0 0 3px var(--red-soft); }
.searchbar .mag { position: absolute; left: 15px; top: 50%; transform: translateY(-50%); opacity: .45; }
.searchbar .count { position: absolute; right: 15px; top: 50%; transform: translateY(-50%);
  font-size: 12px; color: var(--muted); }
.rulecat { margin-bottom: 20px; }
.rulecat h2 { margin: 0 0 8px; }
.rules { display: grid; gap: 7px; grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr)); }
.rule { background: var(--surface); border: 1px solid var(--line); border-radius: 8px;
        padding: 9px 13px; box-shadow: var(--lift); }
.rule .k { font-size: 11.5px; color: var(--muted); font-weight: 550; }
.rule .v { font-weight: 600; word-break: break-word; }
.rule .h { font-size: 11px; color: var(--muted); }
mark { background: var(--amber-soft); color: inherit; border-radius: 3px; padding: 0 2px; }

/* ---------- players ---------- */
.posgrid { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(min(290px, 100%), 1fr)); }
/* The position row is the secondary choice, so it tucks under the availability
   toggle above it. */
.posscope { margin-top: -10px; }
.poscard { background: var(--surface); border: 1px solid var(--line);
           border-radius: var(--radius); padding: 12px 14px; box-shadow: var(--lift); }
.poscard h3 { color: var(--red); border-bottom: 1px solid var(--line-soft); padding-bottom: 7px; }
.plist { list-style: none; margin: 0; padding: 0; }
.plist li { display: grid; grid-template-columns: 20px 1fr auto; align-items: baseline;
            gap: 8px; padding: 5px 0; border-bottom: 1px solid var(--line-soft); }
.plist li:last-child { border-bottom: 0; }
.plist .rank { color: var(--muted); font-size: 11px; font-variant-numeric: tabular-nums; }
.plist .pn { font-size: 13.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.plist .pl { font-variant-numeric: tabular-nums; color: var(--muted); text-align: right; }
.plist .pp { font-weight: 650; font-variant-numeric: tabular-nums; font-size: 13.5px; }
.plist li:nth-child(-n+3) .pp.on { color: var(--red); }

/* ---------- matchup cards (bigger) ---------- */
.games { grid-template-columns: repeat(auto-fill, minmax(min(430px, 100%), 1fr)); gap: 14px; }
.game { padding: 16px 18px; }
/* The scoreline. The lineup below it spans the whole card, so this is the only
   part still split three ways. */
.mhead {
  display: grid; grid-template-columns: 1fr auto 1fr;
  align-items: start; gap: 5px;
}
/* Name and total on one line, with the total on the inside edge of the side --
   so the two scores meet either side of the margin in the middle of the card
   rather than sitting out at the corners. That is also what closes the gap a
   wide card used to open up: the slack now falls outside the numbers instead
   of between a name and the centre. `row-reverse` mirrors the right-hand side
   without a second set of rules. */
.mside { display: flex; flex-direction: row; align-items: baseline;
         justify-content: flex-end; gap: 14px; min-width: 0; }
.mside.right { flex-direction: row-reverse; text-align: right; }
/* The identity block hugs the centre too: a manager line wider than the team
   name would otherwise push the name away from the score it belongs to. */
.mid { display: flex; flex-direction: column; gap: 2px; min-width: 0;
       align-items: flex-end; }
.mside.right .mid { align-items: flex-start; }
/* The numbers never shrink -- a long franchise name ellipsises instead. */
.mnum { display: flex; flex-direction: column; flex: none; align-items: flex-end;
        text-align: right; }
.mside.right .mnum { align-items: flex-start; text-align: left; }
.mteam { display: flex; align-items: center; gap: 6px; text-decoration: none;
         color: inherit; border-radius: 6px; }
.mside.right .mteam { flex-direction: row-reverse; }
.mname { font-size: 16px; font-weight: 650; color: var(--ink);
         overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mteam:hover .mname { color: var(--green); text-decoration: underline; }
.titles { font-size: 12px; letter-spacing: -2px; white-space: nowrap; }
.tcount { font-size: 10px; font-weight: 700; color: var(--red); letter-spacing: 0; margin-left: 3px; }
/* ×n beside a 2-3 trophy row is for phones only, where the extra trophies go. */
.tcount.tc-xs { display: none; }

.mmanager { position: relative; font-size: 12px; color: var(--muted);
            cursor: help; border-bottom: 1px dotted var(--line); align-self: flex-end;
            width: fit-content; outline: none; }
.mside.right .mid .mmanager { align-self: flex-start; }
.hovercard {
  position: absolute; left: 0; top: calc(100% + 6px); z-index: 30; min-width: 190px;
  background: var(--surface); border: 1px solid var(--line); border-top: 2px solid var(--red);
  border-radius: 8px; padding: 9px 12px; box-shadow: 0 6px 20px rgba(20,32,26,.16);
  opacity: 0; visibility: hidden; transform: translateY(-3px);
  transition: opacity .13s ease, transform .13s ease, visibility .13s;
  text-align: left; color: var(--ink); font-size: 12px;
}
.mside.right .hovercard { left: auto; right: 0; }
.mmanager:hover .hovercard, .mmanager:focus-within .hovercard, .mmanager:focus .hovercard {
  opacity: 1; visibility: visible; transform: none;
}
.hc-name { font-weight: 700; margin-bottom: 5px; padding-bottom: 4px;
           border-bottom: 1px solid var(--line-soft); }
.hc-row { display: flex; justify-content: space-between; gap: 16px; padding: 1px 0; }
.hc-row span { color: var(--muted); }

.mscore { font-size: 27px; font-weight: 700; font-variant-numeric: tabular-nums;
          line-height: 1.1; }
.mproj { font-size: 11px; color: var(--muted); }

/* One lineup down the middle of the card. The slot is a property of the row,
   so it is printed once between the two scores rather than twice at the outer
   edges -- which is where the width was going, and why the names had none.

   The three middle tracks are fixed, so the scores stay against the slot with
   nothing between them and every row lines up. The two name tracks take
   everything else: that is what makes a row span its card instead of leaving a
   484px island centred in a 940px one, with the names inside it clipped. */
.lineup { list-style: none; margin: 10px 0 0; padding: 8px 0 0;
          border-top: 1px solid var(--line-soft); }
.lineup li {
  display: grid; align-items: baseline;
  grid-template-columns: minmax(0, 1fr) 52px 48px 52px minmax(0, 1fr);
  column-gap: 4px; padding: 3px 4px; border-radius: 4px; font-size: 12.5px;
}
.lineup .lp { display: flex; align-items: baseline; gap: 5px; min-width: 0;
              padding: 1px 5px; border-radius: 3px; }
.lineup .lp.away { flex-direction: row-reverse; }
.lineup .pname { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lineup .pro {
  font-family: var(--display); font-size: 10px; font-weight: 700;
  letter-spacing: .05em; color: var(--muted); flex: 0 0 auto;
}
.lineup .ppts { font-weight: 650; font-variant-numeric: tabular-nums;
                text-align: center; }
.lineup .slot {
  font-family: var(--display); font-size: 9.5px; font-weight: 700;
  letter-spacing: .06em; text-align: center; color: var(--green);
  background: var(--green-soft); border-radius: 3px; padding: 1px 3px;
}
/* Tint the player, not the row: one row now holds two players from different
   NFL teams, and colouring the whole thing would pick a side. */
.lineup .lp.tinted {
  background: color-mix(in srgb, var(--tc) 26%, transparent);
  box-shadow: inset 2px 0 0 var(--tc);
}
.lineup .lp.away.tinted { box-shadow: inset -2px 0 0 var(--tc); }
.lineup-empty { margin: 10px 0 0; }

.rookie {
  display: inline-block; margin-left: 5px; font-size: 9px; font-weight: 800;
  line-height: 1; padding: 2px 4px; border-radius: 3px;
  background: var(--red); color: var(--on-accent); vertical-align: middle;
}

/* ---------- who is hurt, who is playing, who is on fire ---------- */

/* Same shape as the rookie badge, different alphabet: O is out, Q questionable.
   Outlined rather than filled so a lineup with six questionable players does
   not read as six alarms. */
.inj {
  display: inline-block; margin-left: 4px; font-size: 8.5px; font-weight: 800;
  line-height: 1; padding: 2px 3px; border-radius: 3px; vertical-align: middle;
  letter-spacing: .02em;
}
.inj-o, .inj-ir { color: #ff8b85; background: var(--red-soft); }
.inj-q, .inj-d  { color: var(--amber); background: var(--amber-soft); }
.inj-s          { color: var(--muted); background: var(--line-soft); }

/* Kickoff before the game, quarter and clock during it. */
.lineup .gtime {
  font-family: var(--display); font-size: 9.5px; font-weight: 700;
  letter-spacing: .03em; color: var(--muted); flex: 0 0 auto;
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.lineup .gtime.live { color: var(--live); }
.lineup .gtime.done { color: var(--muted); opacity: .6; }

/* The number carries the state of the player's game. A projection is a guess,
   so it is faded; a live score is the only thing on the page still moving, so
   it is the one green thing in the row; a final score has stopped being news
   and goes plain white. */
.lineup .ppts.pre  { opacity: .42; font-weight: 550; }
.lineup .ppts.live { color: var(--live); }
.lineup .ppts.done { color: #fff; font-weight: 750; }
.lineup .ppts.bye  { color: var(--muted); opacity: .4; font-weight: 500; }

/* 25 points is a week worth looking up from your phone for. */
.lineup .ppts.fire {
  color: var(--ember); font-weight: 800; opacity: 1;
  text-shadow: 0 0 6px rgba(255,120,20,.5), 0 0 14px rgba(255,60,0,.26);
}
@keyframes ember {
  0%, 100% { color: var(--ember);
             text-shadow: 0 0 5px rgba(255,120,20,.42), 0 0 12px rgba(255,60,0,.2); }
  50%      { color: #ffd777;
             text-shadow: 0 0 10px rgba(255,155,45,.75), 0 0 24px rgba(255,70,0,.4); }
}
@media (prefers-reduced-motion: no-preference) {
  .lineup .ppts.fire { animation: ember 1.6s ease-in-out infinite; }
}

/* ---------- the matchup, on its own ---------- */

.game[data-dialog] { cursor: pointer; }
.mdl {
  padding: 0; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); color: var(--ink); box-shadow: var(--lift);
  width: min(780px, calc(100vw - 28px)); max-height: min(88vh, 940px);
  overflow: hidden;
}
.mdl::backdrop { background: rgba(3,14,10,.66); backdrop-filter: blur(2px); }
.mdl-in { position: relative; padding: 16px 18px 20px; overflow-y: auto;
          max-height: inherit; }
.mdl-x {
  position: absolute; top: 10px; right: 10px; z-index: 1;
  width: 28px; height: 28px; padding: 0; line-height: 1;
  font-size: 19px; color: var(--muted); cursor: pointer;
  background: var(--raised); border: 1px solid var(--line); border-radius: 6px;
}
.mdl-x:hover { color: var(--ink); }
/* The modal is rendered inside .games, so the compact card's tighter row sizing
   would otherwise follow it in. This is the full view; it gets full spacing. */
.games .mdl .lineup li {
  grid-template-columns: minmax(0, 1fr) 54px 52px 54px minmax(0, 1fr);
  column-gap: 5px; padding: 3px 5px; font-size: 12.5px;
}
.games .mdl .lineup .slot { font-size: 9.5px; }
.games .mdl .lineup .pro  { font-size: 10px; }
/* Bench and IR are on the roster, not in the game: present but stood down. */
.mdl .lineup li.benched { opacity: .72; }
.mdl .lineup li.benched .slot { color: var(--muted); background: var(--line-soft); }
.mdl .lineup li.lsep {
  display: block; margin: 9px 0 3px; padding: 0;
  font-family: var(--display); font-size: 9.5px; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase; color: var(--muted);
  border-top: 1px solid var(--line-soft); padding-top: 7px;
}
.rdlg-name { margin: 4px 28px 2px 0; font-size: 18px; font-weight: 700; }
.rdlg-mgr { margin-left: 8px; font-size: 12px; font-weight: 500; color: var(--muted); }
.rdlg-hist { display: inline-block; margin-bottom: 8px; font-size: 12px; }
/* One franchise, not two, so the paired grid the rest of the lineup uses
   would leave an empty away column beside every player. This is the same
   three pieces of information -- slot, player, points -- read left to right
   instead of split down the middle. */
.games .rdlg .lineup li {
  grid-template-columns: 44px minmax(0, 1fr) 54px;
  align-items: center; column-gap: 6px; padding: 3px 5px; font-size: 12.5px;
}
.rdlg .lineup .slot { font-size: 9.5px; }
.mmid { display: flex; flex-direction: column; align-items: center; gap: 3px;
        padding-top: 6px; min-width: 0; }
.mmid .vs { font-size: 11px; text-transform: uppercase; letter-spacing: .08em; }
.mmid .margin { font-size: 13px; font-weight: 650; color: var(--muted);
                font-variant-numeric: tabular-nums; }
.mmid .rev { position: static; }
.provisional {
  display: inline-block; font-size: 10px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .05em; color: var(--amber); background: var(--amber-soft);
  border-radius: 4px; padding: 2px 7px; margin-left: 8px;
}


/* ---------- rest of the week ---------- */
/* No frame of its own. It used to be a panel -- surface, border, shadow, 12px
   of padding a side -- which cost the cards inside 26px of width and drew a
   second box around things that are already boxes. What is left is a bare
   wrapper: it still groups the rest of the week under one heading and one
   hint, and the cards inside are free to use the full column. */
.restbox { margin-bottom: 4px; }
/* One card per row. Three across left about 33px for a name -- four
   characters -- which is not a name at all. Full width buys the whole name and
   the NFL team, and makes opening one a change of depth rather than of shape.

   Capped, though: a row is four tracks and only the name flexes, so on a
   1100px card every spare pixel piles up between the name and the points --
   which is the middle of the card, and reads as a hole in it.

   The cap is --card-w, the same variable the featured card below uses, so
   your matchup and the rest of the week are always the same width and cannot
   drift apart the next time one of them changes without the other. */
.restbox .games.compact { grid-template-columns: 1fr; gap: 8px; }
.restbox .games.compact .game { max-width: var(--card-w); margin-inline: auto; width: 100%; }
/* With the panel gone there is nothing left carrying these, so they go back to
   looking like the cards they are -- flat --raised blocks on the page ground
   read as unfinished rather than as deliberate. Only the pointer survives from
   the flattened version. */
.restbox .games.compact .game { cursor: pointer; }
.restbox .games.compact .game:focus-visible {
  outline: 2px solid var(--green); outline-offset: 2px;
}
.resthint { margin: 8px 0 8px; text-align: center; }
/* A card shows a top three; the modal it opens shows everything. The rows are
   always in the page, so opening costs no request. */
.games.compact .game .lineup li:nth-child(n+4) { display: none; }

/* ---------- draft scoreboard (the hub's focal point) ---------- */
.scoreboard {
  position: relative; overflow: hidden;
  background: var(--field);
  border-radius: 12px; border-bottom: 3px solid var(--red);
  padding: 26px 20px 22px; margin: 4px 0 16px;
  text-align: center; color: #fff;
}
/* yard lines across the field */
.scoreboard::before {
  content: ""; position: absolute; inset: 0;
  background: repeating-linear-gradient(90deg,
    transparent 0 62px, var(--chalk) 62px 64px);
  pointer-events: none;
}
/* end-zone shading at both edges */
.scoreboard::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, var(--field-deep) 0 6%, transparent 16% 84%, var(--field-deep) 94% 100%);
  pointer-events: none;
}
.scoreboard > * { position: relative; z-index: 1; }

.sb-eyebrow {
  font-family: var(--display); font-size: 13px; text-transform: uppercase;
  letter-spacing: .18em; color: rgba(255,255,255,.72);
  display: flex; align-items: center; justify-content: center; gap: 9px;
}
.sb-eyebrow .pill {
  background: var(--red); color: var(--on-accent); border-radius: 3px;
  padding: 2px 8px; letter-spacing: .1em; font-size: 11px; font-weight: 700;
}
.sb-clock { display: flex; justify-content: center; gap: 10px; margin: 12px 0 10px; }
.sb-clock .seg { min-width: 74px; }
.sb-clock b {
  display: block; font-family: var(--display); font-size: 54px; font-weight: 700;
  line-height: 1; font-variant-numeric: tabular-nums; letter-spacing: .01em;
  color: #fff; text-shadow: 0 2px 0 rgba(0,0,0,.25);
}
.sb-clock span {
  display: block; margin-top: 5px; font-size: 10px; text-transform: uppercase;
  letter-spacing: .17em; color: rgba(255,255,255,.6);
}
.sb-clock .seg + .seg { border-left: 1px solid rgba(255,255,255,.14); padding-left: 10px; }
.sb-when { font-size: 13px; color: rgba(255,255,255,.85); }
.sb-when .tz { color: rgba(255,255,255,.62); }
.scoreboard.live .sb-clock b { color: var(--red); }

/* ---------- stat line ---------- */
.statline {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 1px; background: var(--line); border: 1px solid var(--line);
  border-radius: 10px; overflow: hidden; margin-bottom: 18px;
}
.statline > div { background: var(--surface); padding: 12px 14px; text-align: center; }
.statline b {
  display: block; font-family: var(--display); font-size: 27px; font-weight: 700;
  line-height: 1; font-variant-numeric: tabular-nums; color: var(--ink);
}
.statline .of { color: var(--muted); font-size: 17px; }
.statline span {
  display: block; margin-top: 4px; font-size: 10px; text-transform: uppercase;
  letter-spacing: .11em; color: var(--muted);
}

/* ---------- sportier card details ---------- */
.game { border-top: 2px solid var(--green); }
.mname { font-family: var(--display); font-size: 19px; font-weight: 600;
         text-transform: uppercase; letter-spacing: .02em; }
.mscore { font-family: var(--display); font-size: 34px; font-weight: 700; }
.mmid .vs, .mmid .margin { font-family: var(--display); letter-spacing: .12em; }
.mmid .margin { font-size: 15px; }

.plist .pp, .num, .matrix .cell { font-variant-numeric: tabular-nums; }
.poscard h3 { color: var(--ink); }
.poscard h3::after {
  content: ""; display: block; height: 2px; background: var(--green);
  margin-top: 6px; border-radius: 1px;
}
.chip { font-family: var(--display); letter-spacing: .1em; font-size: 12px; }
.scope a { font-family: var(--display); text-transform: uppercase; letter-spacing: .07em;
           font-size: 13px; }
thead th { font-family: var(--display); letter-spacing: .1em; font-size: 12px; }



.poscard { padding-bottom: 6px; }
.plist { max-height: 620px; overflow-y: auto; }
/* The draft page's value cards used to borrow these from the players cards,
   whose rules were removed with them: a fixed track for the value, set right,
   behind a hairline that separates it from the points. */
.plist li { grid-template-columns: 20px 1fr 44px; }
.plist .pp {
  text-align: right; border-left: 1px solid var(--line-soft);
  margin-left: -4px; padding-left: 4px;
}

.mr { font-variant-numeric: tabular-nums; text-align: right; font-size: 12.5px; color: var(--muted); }
.mr.soft { color: var(--green); }
.mr.tough { color: var(--red); }
/* Neutral rather than the green/red tint above: the governing column has to
   read as the one that matters regardless of which way its own rank leans. */
.mr.gov { font-weight: 700; background: var(--raised); border-radius: 3px; }
.opp { font-family: var(--display); font-size: 11.5px; letter-spacing: .04em;
       color: var(--muted); text-align: right; }

/* ---------- players table ---------- */
/* The box scrolls both ways so the header can stick to its top and the player
   column to its left -- a sticky header cannot stick to the page from inside a
   horizontal scroller, only to whichever box actually scrolls. */
.ptab-scroll {
  overflow: auto; max-height: calc(100dvh - var(--topbar-h) - 24px); min-height: 360px;
  border: 1px solid var(--line-soft); border-radius: var(--radius);
  animation: none;
}
/* The base `table` rule draws its own border, radius and shadow -- .ptab-scroll
   already does that job, so the inner table resets them rather than nesting a
   box inside a box. */
.ptab {
  border-collapse: separate; border-spacing: 0; width: max-content; min-width: 100%;
  font-size: 12.5px; margin-top: 0; background: none; border: 0; border-radius: 0;
  overflow: visible; box-shadow: none;
}
.ptab th {
  position: sticky; top: 0; z-index: 2; background: var(--surface);
  font-family: var(--display); font-size: 10px; text-transform: uppercase;
  letter-spacing: .1em; color: var(--muted); text-align: right; white-space: nowrap;
  padding: 6px 8px;
}
.ptab th a { color: inherit; text-decoration: none; }
.ptab th a:hover { color: var(--ink); }
.ptab th.on a { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
.ptab th .arrow { font-size: 8px; margin-left: 2px; }
.ptab td {
  padding: 4px 8px; text-align: right; font-variant-numeric: tabular-nums;
  white-space: nowrap; border-bottom: 1px solid var(--line-soft);
}
.ptab .c-rank, .ptab .c-player {
  position: sticky; background: var(--surface);
}
.ptab { --rank-w: 28px; }
.ptab .c-rank { left: 0; width: var(--rank-w); min-width: var(--rank-w); max-width: var(--rank-w); color: var(--muted); z-index: 1; }
/* The rank cell is 28px wide including its own padding, so the player column
   picks up right where it ends -- any gap would show scrolled cells passing
   under a strip of nothing. */
.ptab .c-player {
  left: var(--rank-w); text-align: left; max-width: 240px; overflow: hidden; z-index: 1;
  text-overflow: ellipsis; border-right: 1px solid var(--line-soft);
  box-shadow: 4px 0 6px -4px rgba(0,0,0,.45);
}
.ptab th.c-rank, .ptab th.c-player { z-index: 4; }
/* A thin team-colour bar carries the team; the fill behind the name stays faint. */
.ptab td.c-player.tinted { box-shadow: inset 3px 0 0 var(--tc), 4px 0 6px -4px rgba(0,0,0,.45); }
/* Layered over the opaque surface rather than swapped for it, the same
   strength .plist li.tinted uses -- a sticky cell still has to stay opaque as
   the columns behind it scroll under it. */
.ptab td.c-player.tinted {
  background: linear-gradient(color-mix(in srgb, var(--tc) 9%, transparent),
              color-mix(in srgb, var(--tc) 9%, transparent)), var(--surface);
}
.ptab .c-text { text-align: left; color: var(--muted); }
.ptab .c-pts { color: #fff; font-weight: 600; }
.ptab .c-total { color: #fff; font-weight: 750; }
/* Proj is a forecast, never a score, so it stays faded even when it is the
   active sort -- the same distinction the scoreboard draws between a final
   score and its pre-kickoff number (.lineup .ppts.pre). It must never reach
   the white that c-pts/c-total use, or a glance could mistake a projection
   for a result. */
.ptab .c-proj { color: var(--muted); font-weight: 400; }
.ptab .c-own, .ptab .c-int, .ptab .c-pct { color: var(--ink); font-weight: 400; }
.ptab td.on { background: var(--raised); }
.ptab td.c-proj.on { color: var(--ink); font-weight: 650; }
.ptab .blk { border-left: 1px solid var(--line-soft); }
.ptab tbody tr:hover td { background: var(--raised); }
.ptab tbody tr:hover td.c-player.tinted {
  background: linear-gradient(color-mix(in srgb, var(--tc) 9%, transparent),
              color-mix(in srgb, var(--tc) 9%, transparent)), var(--raised);
}



/* ---------- signed-in franchise ---------- */
.topbar .who {
  font-family: var(--display); font-size: 12.5px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .08em;
  max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  padding: 3px 9px; border-radius: 4px;
  background: rgba(255,255,255,.14); color: #fff;
}
/* It is a link to your own roster now, so it has to look like one can be
   pressed -- the corner is the one place every page shows your franchise. */
a.who { text-decoration: none; transition: background .12s ease; }
a.who:hover { background: var(--nfl-red); color: var(--on-accent); }
/* the nav takes the slack, so the draft note and the account block always sit
   on the floor of the drawer whether or not both are present */
.drawer-nav { margin-bottom: auto; }
.drawer-note { padding: 14px 18px; border-top: 1px solid rgba(255,255,255,.1); font-size: 13px; }
.drawer-note .muted { color: rgba(255,255,255,.5); }
.drawer-foot {
  margin-top: 0; display: flex; align-items: center; justify-content: space-between;
  gap: 10px; padding: 12px 18px 14px; border-top: 1px solid rgba(255,255,255,.1);
}
.drawer-foot .muted { color: rgba(255,255,255,.5); }
.whoami {
  font-family: var(--display); font-size: 17px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .03em; line-height: 1.15; color: #fff;
}
.signout {
  font-family: var(--display); font-size: 12px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .08em; cursor: pointer;
  padding: 6px 11px; border-radius: 6px; color: rgba(255,255,255,.72);
  background: transparent; border: 1px solid rgba(255,255,255,.22);
  transition: background .14s, color .14s, border-color .14s;
}
.signout:hover {
  border-color: var(--nfl-red); background: rgba(232,133,124,.18); color: var(--ink);
}

/* ---------- login ---------- */
/* The login page is its own world -- always the dark field, in either colour
   scheme -- so these rules use literal colours instead of the theme tokens. */
.loginpage { background: #050f0c; color: #eaf2ed; overflow: hidden; }

/* The field: one plane tipped away from the camera, lines running at you.
   Pure CSS, no JS.

   Geometry: only the part of the plane in front of the camera is drawn, so the
   depth actually visible is perspective / sin(tilt) -- about 1100px here. That
   over an 80px line spacing is roughly a dozen yard lines converging on the
   horizon. Shortening the perspective magnifies the near field until only two
   or three lines fit on screen, which reads as a close-up, not a field.

   The turf translates rather than shifting background-position: a transform is
   composited on the GPU, where animating a background position repaints the
   whole layer on the main thread every frame. */
.field {
  /* Out of focus, so the card is the only sharp thing on the page. The inset
     overhang matters: blur samples beyond the element, and at inset:0 the four
     edges fade to transparent and show a pale seam against the page. */
  position: fixed; inset: -40px; z-index: 0; overflow: hidden;
  filter: blur(3.5px);
  background:
    /* the sun we are running at -- the plane is a child painted over this
       background, so it swallows the lower half at the horizon for free */
    radial-gradient(circle 78px at 50% 36%,
      rgba(255,248,227,1) 0 40%, rgba(255,206,124,.88) 68%, rgba(255,170,80,0) 100%),
    /* its haze along the horizon */
    radial-gradient(ellipse 52% 22% at 50% 36%, rgba(255,146,54,.44), transparent 74%),
    /* dawn sky: cold overhead, warm where the light is */
    linear-gradient(#04070c 0%, #080f18 16%, #16151a 27%, #3d2418 34%, #0a2418 36%);
  perspective: 1100px; perspective-origin: 50% 36%;
}
/* Top edge on the horizon line, so the plane's vanishing point lands exactly
   at the perspective origin. */
/* overflow:hidden clips the turf to the near side of the horizon. Without it
   the part of the plane past y=0 projects back above the horizon line as a
   smear of upside-down field, and it also makes the loop wrap exact: both ends
   of the cycle then show the same clipped region. */
.field-plane {
  position: absolute; top: 36%; left: 50%;
  width: 2600px; height: 1200px; margin-left: -1300px;
  overflow: hidden;
  transform-origin: 50% 0; transform: rotateX(84deg);
}
/* The turf. Every marking lives in field.svg -- sidelines, end zones, goal
   lines, 5-yard lines, hash marks, numbers and mown stripes -- because a real
   pitch has no longitudinal grid and gradients cannot clip lines to the
   sidelines or draw glyphs. One tile is a whole 120-yard field at 12px to the
   yard, so travelling exactly one tile length loops seamlessly by
   construction. It starts one tile behind the horizon so sliding forward
   never uncovers the far edge. */
.field-plane::before {
  content: ""; position: absolute; left: 0; right: 0; top: -1440px; bottom: 0;
  background: url("/static/field.svg") repeat 0 0 / 2600px 1440px, #071c14;
  will-change: transform; backface-visibility: hidden;
  animation: fieldrun 15s linear infinite;
}
/* Local +Y is the near ground, so +1440 comes toward the camera. */
@keyframes fieldrun {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(0, 1440px, 0); }
}

/* The stadium: two raked stands converging on the vanishing point, floodlights
   above them. It sits after .field-plane in the DOM so it paints over the
   turf's dark surround -- which is exactly the ground the stands stand on --
   and stretches to 100% 100% so its horizon stays on the page's horizon at any
   aspect ratio. A gap is left at the vanishing point for the sun. */
.stands {
  position: absolute; inset: 0; pointer-events: none;
  background: url("/static/stadium.svg") no-repeat 50% 0 / 100% 100%;
}

/* Dissolve the far distance into the sky: hides the horizon seam and the
   moire the yard lines would otherwise make as they converge. */
.field::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    /* sunlight washing back down the near turf */
    linear-gradient(rgba(255,170,90,0) 36%, rgba(255,152,70,.18) 42%,
                    rgba(255,150,70,.05) 58%, rgba(255,150,70,0) 72%),
    /* Frames the sides and the very bottom only. A centred vignette put .68 of
       darkness straight over the sun and flattened it to a smudge. */
    linear-gradient(90deg, rgba(4,12,9,.72) 0%, rgba(4,12,9,0) 20%,
                    rgba(4,12,9,0) 80%, rgba(4,12,9,.72) 100%),
    linear-gradient(rgba(4,12,9,0) 62%, rgba(4,12,9,.42) 100%);
}
@media (prefers-reduced-motion: reduce) { .field-plane::before { animation: none; } }

.loginwrap {
  position: relative; z-index: 1; max-width: none;
  display: grid; place-items: center; padding: 24px;
  min-height: 100vh; min-height: 100dvh;
}
.loginbox {
  width: 100%; max-width: 340px; padding: 30px 28px 28px; text-align: center;
  background: rgba(6,20,15,.55);
  border: 1px solid rgba(255,255,255,.13);
  border-top: 3px solid #c4352f;
  border-radius: 14px;
  box-shadow: 0 24px 60px rgba(0,0,0,.5);
  backdrop-filter: blur(16px) saturate(1.3);
  -webkit-backdrop-filter: blur(16px) saturate(1.3);
}
.loginbox h1 { margin: 3px 0 4px; font-size: 27px; color: #fff; }
.login-eyebrow {
  font-family: var(--display); font-size: 11px; text-transform: uppercase;
  letter-spacing: .2em; color: rgba(255,255,255,.42);
}
.loginbox label {
  display: block; margin: 18px 0 6px; font-family: var(--display);
  font-size: 11.5px; text-transform: uppercase; letter-spacing: .13em;
  color: rgba(255,255,255,.5);
}
.loginbox input {
  width: 100%; padding: 12px 14px; font-size: 15px; color: #fff; text-align: center;
  background: rgba(255,255,255,.06);
  border: 1px solid rgba(255,255,255,.14); border-radius: 9px; outline: none;
  transition: border-color .15s, box-shadow .15s, background .15s;
}
.loginbox input::placeholder { color: rgba(255,255,255,.26); }
.loginbox input:focus {
  background: rgba(255,255,255,.09);
  border-color: #c4352f; box-shadow: 0 0 0 3px rgba(196,53,47,.3);
}
/* Chrome paints autofilled fields opaque white, which would punch a hole in
   the card -- the inset shadow is the only way to override it. */
.loginbox input:-webkit-autofill,
.loginbox input:-webkit-autofill:focus {
  -webkit-text-fill-color: #fff; caret-color: #fff;
  -webkit-box-shadow: 0 0 0 1000px #12241c inset;
  transition: background-color 9999s ease-in-out 0s;
}
.loginbox button {
  width: 100%; margin-top: 26px; padding: 12px; cursor: pointer;
  font-family: var(--display); font-size: 15px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .12em;
  color: var(--on-accent); background: var(--green); border: 0; border-radius: 9px;
  transition: background .15s, transform .06s;
}
.loginbox button:hover { filter: brightness(1.06); }
.loginbox button:active { transform: translateY(1px); }
.loginerror {
  margin: 16px 0 0; padding: 9px 12px; font-size: 13px; border-radius: 8px;
  background: rgba(196,53,47,.16); color: #ff9c96;
  border-left: 2px solid #e8615b;
}

/* ---------- your matchup, then everyone else's ---------- */
.mine-head::before { background: var(--red); }
/* One centred column rather than the full page width: the card carries two
   16-man lineups, so it needs room, but stretched edge to edge on a wide screen
   the two sides drift so far apart they stop reading as one matchup. Capped at
   --card-w, the same variable the rest of the week is capped at below. */
.games.feature { grid-template-columns: minmax(0, var(--card-w)); justify-content: center;
                 margin-bottom: 4px; }
.games.feature .game {
  padding: 22px 26px; border-top: 3px solid var(--red);
  box-shadow: 0 4px 18px rgba(20,32,26,.10);
}
.games.feature .mname { font-size: 24px; }
.games.feature .mscore { font-size: 46px; }
.games.feature .mmid { min-width: 24px; }
.games.feature .mmid .margin { font-size: 19px; }
.games.feature .lineup li { font-size: 13.5px; }

/* the rest of the week: no lineups, so the card is one line of name + score */
.games.compact { grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr)); gap: 8px; }
.games.compact .game { padding: 10px 13px; gap: 2px; align-items: center; border-top-width: 2px; }
.games.compact .mname { font-size: 15.5px; }
.games.compact .mscore { font-size: 22px; margin-top: 1px; }
.games.compact .mproj { font-size: 10.5px; }
.games.compact .mmid { padding-top: 0; min-width: 0; }
.games.compact .mmid .margin { font-size: 12.5px; }
.games.compact .titles { font-size: 10px; }
.mmanager.plain { font-size: 11px; cursor: default; border-bottom: 0; }

/* your side of a card, and your row/column in every table */
.mside.me .mname { color: var(--red); }
.game.mine { border-left: 2px solid var(--red); }
tbody tr.me > td { background: var(--green-soft); }
tbody tr.me:hover > td { background: var(--green-soft); }
tbody tr.me > td:first-child { font-weight: 700; box-shadow: inset 2px 0 0 var(--red); }
/* Same opaque stacking as the corner, and the sticky column's right-hand
   hairline has to be restated beside the red inset -- one box-shadow property. */
.matrix .rowhead.me {
  background: linear-gradient(var(--green-soft), var(--green-soft)), var(--surface);
  color: var(--ink); font-weight: 700;
  box-shadow: inset 2px 0 0 var(--red), 1px 0 0 var(--line);
}
.matrix th.rot.me { color: var(--red); font-weight: 700; }
.matrix td.mecell { background: var(--green-soft); font-weight: 600; }



/* ---------- full lineup rows, tinted by NFL team ---------- */


/* The tint is the team's primary colour at low alpha, with the full-strength
   colour as an edge stripe -- several teams are near-black, and a stripe reads
   where a 14% wash of #0B162A does not. */
/* The tint needs more weight on a dark ground than it did on a light one. */
.plist li.tinted {
  background: color-mix(in srgb, var(--tc) 26%, transparent);
  box-shadow: inset 2px 0 0 var(--tc);
}

/* ---------- NFL usage ---------- */
.proteam {
  display: inline-block; margin-left: 6px; padding: 1px 5px; border-radius: 3px;
  font-family: var(--display); font-size: 10.5px; font-weight: 700;
  letter-spacing: .05em; color: var(--muted); vertical-align: middle;
}
.proteam.tinted {
  color: var(--ink);
  background: color-mix(in srgb, var(--tc) 32%, transparent);
  box-shadow: inset 2px 0 0 var(--tc);
}
td .pn { font-weight: 600; }
td .slot {
  font-family: var(--display); font-size: 10.5px; font-weight: 700;
  letter-spacing: .08em; color: var(--green); background: var(--green-soft);
  border-radius: 3px; padding: 1px 5px;
}
.credit { margin-top: 26px; padding-top: 12px; border-top: 1px solid var(--line-soft); }

/* ---------- season schedule markers ---------- */
.schedule .rot .wk { display: block; }
.schedule .wkmark { display: block; font-size: 11px; line-height: 1.4; }
.schedule th.rot.nowweek { color: var(--red); }
.schedule td.nowweek, .schedule th.rot.nowweek { background: var(--red-tint); }
.wklegend {
  display: flex; flex-wrap: wrap; gap: 6px 18px;
  margin: 8px 0 0; font-size: 12.5px;
}
.wklegend b { font-style: normal; }

/* ---------- transaction feed ---------- */
.move {
  font-family: var(--display); font-size: 10.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .07em;
  padding: 2px 7px; border-radius: 3px;
  background: var(--green-soft); color: var(--green);
}
.move.dropped { background: var(--red-soft); color: var(--red); }
.move.traded  { background: var(--amber-soft); color: var(--amber); }

/* ---------- news feed ---------- */
.newsfeed { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; }
.newsitem { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
            padding: 12px 15px; }
.ni-head { display: flex; align-items: center; gap: 9px; margin-bottom: 4px; }
.ni-byline { font-size: 12.5px; font-weight: 600; color: var(--green); }
.newsitem h3 { margin: 0 0 4px; font-size: 15px; }
.newsitem h3 a { text-decoration: none; }
.newsitem h3 a:hover { text-decoration: underline; }
.ni-players { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
/* Same pill as td .slot (the lineup slot badge) -- this is a badge too, just
   naming a rostered player instead of a lineup position, and it lives outside
   a table so the selector is repeated here rather than scoped to td. */
.ni-players .slot {
  font-family: var(--display); font-size: 10.5px; font-weight: 700;
  letter-spacing: .08em; color: var(--green); background: var(--green-soft);
  border-radius: 3px; padding: 1px 5px;
}
.premium {
  font-family: var(--display); font-size: 10.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .07em;
  padding: 2px 7px; border-radius: 3px;
  background: var(--amber-soft); color: var(--amber);
}

/* ---------- compact cards keep a top three ---------- */
/* The lineup row carries four columns (slot, name, NFL team, points) that were
   sized for the full-width featured card. A compact card gives each side about
   a third of that, so the fixed columns tighten rather than the badge being
   dropped -- losing the team only on the small cards would be an odd exception. */
.games.compact { grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr)); }
.games.compact .mhead { align-items: start; }
.games.compact .lineup { margin-top: 6px; padding-top: 6px; }
.games.compact .lineup li {
  grid-template-columns: minmax(0, 1fr) 46px 42px 46px minmax(0, 1fr);
  column-gap: 3px; padding: 2px 3px; font-size: 11.5px;
}

.games.compact .lineup .slot { font-size: 9px; padding: 1px 3px; letter-spacing: .04em; }
.games.compact .lineup .pro { font-size: 9px; letter-spacing: .02em; }
/* A 320px card cannot carry the NFL team and the kickoff both without eating
   the name between them. The kickoff wins: the colour tint already says which
   team a player belongs to, and it is the fact that changes. The feature card
   and the modal are wide enough for both. */
.games.compact .game .lineup .pro { display: none; }
.games.compact .game .lineup .gtime { font-size: 9px; }
.games.compact .lineup .rookie { margin-left: 3px; font-size: 8px; padding: 1px 3px; }

/* The players list is 50 rows deep, so tinted and untinted rows need the same
   horizontal inset or the tint would shunt half the list sideways. */
.plist li { padding: 5px 6px; border-radius: 4px; }

/* ---------- coming up the field ----------

   Panels arrive small and grow to full size as they scroll in, so moving down
   the page reads as closing on them. Scroll-driven, so it tracks the scrollbar
   rather than a clock and reverses when you scroll back up.

   Everything is inside @supports on purpose: the fallback has to be the
   finished state. Without animation-timeline the rules never apply at all, so
   a browser that cannot do this gets plain, fully visible panels rather than a
   page frozen mid-fade.

   The range ends at a fixed 340px rather than a percentage. A percentage of
   `entry` is a percentage of the element's own height, so a tall panel -- a
   single-position card is 60 rows -- would still be growing thousands of
   pixels later. A length gives every panel the same arrival. */
@keyframes rise {
  from { opacity: .25; transform: translateY(34px) scale(.94); }
  to   { opacity: 1; transform: none; }
}
@keyframes rise-blur {
  from { opacity: .2; filter: blur(7px); transform: translateY(40px) scale(.94); }
  to   { opacity: 1; filter: blur(0); transform: none; }
}
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .game, .poscard, .rule, .countdown, .notice, .newsitem, .scroll, table {
      animation: rise linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 340px;
    }
    /* Only the name and the range are overridden, so the timeline and fill
       carry over from the rule above instead of being restated and drifting.
       A longer range than the 340px everything else uses: coming into focus
       wants to be felt, and at 340px it had resolved before you noticed it
       had started. */
    .games.compact .game {
      animation-name: rise-blur;
      animation-range: entry 0% entry 260px;
    }
    /* The wrapper already animates, and .matrix .rowhead is position:sticky --
       transforming the table too compounds the scale for no gain. .ptab has
       no animating wrapper at all -- its sticky header and player column
       would break under a transform with nothing above it to carry the
       motion instead. */
    .scroll table, .ptab { animation: none; }
  }
}

/* ---------- lineup rows on a narrow screen ----------

   A row cannot carry the slot, the full name, the NFL team and the points at
   phone width -- the name is what gets clipped, and it is the one thing worth
   reading. Below 560px the team column goes and the name shortens to
   "Derrick H.". Both spellings are in the markup; only one is ever shown.

   Hiding .pro is not enough on its own: these rows are a grid with explicit
   tracks, and a display:none child leaves its track sitting there at full
   width. The columns have to be restated without it, including for the
   mirrored right-hand side. */
.nm-abbr { display: none; }



/* ---------- NFL usage, per roster ---------- */

/* One block per franchise, so the page reads as eight rosters rather than one
   long league-wide list somebody has to filter first. */
.roster { margin: 0 0 34px; scroll-margin-top: 76px; }   /* clears the sticky topbar */
.roster > h2 { margin-bottom: 4px; }
.roster.mine > h2 { color: var(--red); }
.roster.mine { border-left: 3px solid var(--red); padding-left: 14px; margin-left: -17px; }
.roster h3 { font-family: var(--display); font-size: 12.5px; font-weight: 600;
             text-transform: uppercase; letter-spacing: .1em; color: var(--muted);
             margin: 16px 0 6px; }
.rmeta { margin: 0 0 10px; }
.roster h2 .chip.small { font-size: 9px; padding: 2px 6px; vertical-align: middle;
                         background: var(--red); }
.totals-head { margin-top: 34px; }

/* The two four-column blocks of per-down counters. The spanning header is what
   makes eight bare numbers legible, so it carries the rule that groups them. */
.usage .grouphead th { border-bottom: 0; padding-bottom: 0; }
.usage th.group {
  font-family: var(--display); font-size: 9.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted);
  border-bottom: 1px solid var(--line); text-align: center;
}
.usage th.down, .usage td.down { width: 26px; padding-left: 2px; padding-right: 2px; }
.usage th.down { text-align: right; color: var(--muted); }
/* A zero here is the point -- a receiver with no third-down targets is telling
   you something -- but it should not shout as loudly as a real count. */
.usage td.down.zero { color: var(--muted); opacity: .35; }
.usage td.down { font-variant-numeric: tabular-nums; }

/* The week strip can run to eighteen entries; keep it on one tidy line. */
.scope.weeks { gap: 4px; }
.scope.weeks a { min-width: 26px; text-align: center; padding-left: 6px; padding-right: 6px; }

/* ---------- page foot ---------- */

/* Where the staleness stamp lives now. In the top bar it sat beside the league
   state and read as part of the chrome; down here it reads as what it is, a
   note about the data above it. */
.pagefoot {
  max-width: clamp(1180px, 80vw, 1560px); margin: 0 auto; padding: 0 20px 40px;
  display: flex; justify-content: flex-end;
}
.pagefoot .stamp {
  font-size: 11.5px; color: var(--muted);
  padding: 5px 10px; border: 1px solid var(--line-soft); border-radius: 999px;
}
.pagefoot .stamp b { color: var(--ink); font-weight: 650; }



/* ---------- wide tables with the name column pinned ---------- */

/* The all-time table is sixteen columns wide. Unwrapped it had nowhere to go
   but down: names broke over two lines, the numbers ragged along beside them,
   and the columns that matter sat off the right of a phone with no way to
   reach them. Scrolling it sideways only helps if the name stays put, so the
   first cell is a row head that sticks -- the same mechanic the season matrix
   uses, which works only because .scroll (not the table) is the scroll box. */
.stick th, .stick td { white-space: nowrap; }
.stick .rowhead {
  position: sticky; left: 0; z-index: 2;
  text-align: left; font-weight: 600;
  background: var(--surface); box-shadow: 1px 0 0 var(--line);
}
/* Opaque stacking, or the rows travelling underneath show through the one
   cell that is meant to hold still. */
.stick thead .rowhead {
  background: linear-gradient(var(--green-tint), var(--green-tint)), var(--surface);
  z-index: 3;
}
.stick tbody tr:hover .rowhead {
  background: linear-gradient(var(--red-tint), var(--red-tint)), var(--surface);
}
.stick tbody tr.me > td { background: var(--green-soft); }
.stick .rowhead.me {
  background: linear-gradient(var(--green-soft), var(--green-soft)), var(--surface);
  font-weight: 700;
  box-shadow: inset 2px 0 0 var(--red), 1px 0 0 var(--line);
}
/* A former name is context for the name, not a second line of it. */
.stick .was { margin-left: 6px; font-weight: 400; }


/* ---------- desktop layout: paragraphs, rail grid, rail cards ---------- */
main > p.muted, .notice { max-width: var(--prose-max); }

/* Below 1440 the rail is just more content: its cards sit under the page. */
.rail { margin-top: 28px; display: grid; gap: 12px;
        grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr)); align-items: start; }
.main-col { min-width: 0; }

@media (min-width: 1440px) {
  main.has-rail {
    display: grid; grid-template-columns: minmax(0, 1fr) var(--rail-w);
    gap: var(--col-gap); max-width: var(--page-max); padding-inline: var(--gutter);
    --card-w: 100%;
  }
  body:has(main.has-rail) .pagefoot { max-width: var(--page-max); padding-inline: var(--gutter); }
  .rail {
    margin-top: 0; display: flex; flex-direction: column; align-items: stretch; gap: 12px;
    position: sticky; top: var(--rail-top); align-self: start;
    max-height: calc(100dvh - var(--rail-top) - 16px); overflow: auto;
  }
}

.rail-card {
  background: var(--surface); border: 1px solid var(--line); border-top: 2px solid var(--green);
  border-radius: var(--radius); padding: 12px 14px; box-shadow: var(--lift);
}
.rail-card.mine { border-top-color: var(--red); }
.rail-card h3 {
  display: flex; justify-content: space-between; align-items: baseline;
  font-family: var(--display); font-size: 12.5px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .1em; color: var(--muted); margin: 0 0 8px;
}
.rail-card h3 a { font-size: 11.5px; letter-spacing: .04em; color: var(--muted); text-decoration: none; }
.rail-card h3 a:hover { color: var(--red); }
.rail-row {
  display: grid; grid-template-columns: minmax(0, 1fr) 84px 46px; align-items: center; gap: 8px;
  height: 28px; border-bottom: 1px solid var(--line-soft);
  font-size: 12.5px; font-variant-numeric: tabular-nums;
}
.rail-row:last-child { border-bottom: 0; }
.rail-row.me { background: var(--green-soft); box-shadow: inset 2px 0 0 var(--red); padding-left: 6px; }
.rail-row .rn { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rail-row .rv { text-align: right; }
.rail-row.plain { grid-template-columns: minmax(0, 1fr) auto; }
.rail-card .muted.small { margin: 0; }

/* bars: static for now, filled by --v (0..1) */
.bar { display: block; position: relative; height: 3px; background: var(--line-soft); border-radius: 2px; }
.bar > i { position: absolute; inset: 0; background: var(--green); border-radius: 2px;
           transform: scaleX(var(--v, 0)); transform-origin: left; }
.bar.div::after { content: ""; position: absolute; left: 50%; top: -3px; bottom: -3px; width: 1px;
                  background: var(--line); }
.bar.div > i { left: 50%; right: 0; transform-origin: left; }
.bar.div > i.neg { left: 0; right: 50%; background: var(--red); transform-origin: right; }
.bar.div > i { inset-block: 0; }

.pill { font-family: var(--display); font-size: 11px; font-weight: 700; letter-spacing: .06em;
        padding: 1px 6px; border-radius: 4px; }
.pill.w { color: var(--green); background: var(--green-soft); }
.pill.l { color: #ff8b85; background: var(--red-soft); }

/* ---------- standings ---------- */
table.data { max-width: 1200px; }
table.data td.num, table.data th.num { width: 84px; }
table.data td.wl, table.data th.wl { width: 64px; }
table.data td.empty-row { text-align: center; padding: 26px 12px; }
.eff-cell b { display: block; }
.eff-cell .bar { margin-top: 4px; }
.st-pair > section { min-width: 0; }
@media (min-width: 1920px) {
  .st-pair { display: grid; grid-template-columns: 1.6fr 1fr; gap: var(--col-gap); align-items: start; }
  .st-pair table.data { max-width: none; }
  .st-pair table.data td.num, .st-pair table.data th.num { width: auto; padding-inline: 8px; }
}

/* ---------- home: projection bars, share bar, rail lists ---------- */
.lineup .lp { position: relative; }
.lineup .pbar {
  position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--line-soft);
  pointer-events: none; overflow: hidden; border-radius: 1px;
}
.lineup .pbar::after {
  content: ""; position: absolute; inset: 0; background: var(--green);
  transform: scaleX(var(--v, 0)); transform-origin: left;
}
.lineup .lp.away .pbar::after { transform-origin: right; }
.lineup .pbar.pre::after  { background: var(--muted); opacity: .3; }
.lineup .pbar.in::after   { background: var(--live); }
.lineup .pbar.post::after { background: var(--ink); opacity: .5; }
.bar.share { width: 72px; height: 4px; margin-top: 2px; }
.games.compact .bar.share { width: 48px; }
.share-l { font-family: var(--display); font-size: 9.5px; letter-spacing: .08em;
           text-transform: uppercase; color: var(--muted); }

.rail-row.st { grid-template-columns: 18px minmax(0, 1fr) 44px 46px; }
.rail-row.st .rk { color: var(--muted); }
.rail-row.st.me .rk { color: var(--ink); }
.rail-row.g { grid-template-columns: minmax(0, 1fr) auto; }
.rail-card .day { font-family: var(--display); font-size: 11px; font-weight: 700; letter-spacing: .1em;
                  text-transform: uppercase; color: var(--muted); margin: 8px 0 2px; }
.rail-card .day:first-of-type { margin-top: 0; }
.rail-row.g.final { opacity: .6; }
.rail-row .gt { font-family: var(--display); font-size: 11.5px; font-weight: 700; color: var(--muted); }
.rail-row .gt.live { color: var(--live); }
.rail-row.inj-row { grid-template-columns: 22px minmax(0, 1fr) auto; }
.rail-row.inj-row .sl { font-family: var(--display); font-size: 10.5px; font-weight: 700; color: var(--muted);
                        letter-spacing: .05em; }
.rail-card .who { font-size: 11px; color: var(--muted); margin: 8px 0 2px; }

/* ---------- players: filter bar, form, chips ---------- */
.pf .fld { display: flex; flex-direction: column; gap: 4px; margin: 0; padding: 0; border: 0; min-width: 0; }
.pf .fld > label, .pf legend, .pf .fgrp > summary {
  font-family: var(--display); font-size: 11px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .1em; color: var(--muted); padding: 0;
}
.pf input[type=search], .pf input[type=number], .pf select {
  height: 32px; background: var(--surface); color: var(--ink); border: 1px solid var(--line);
  border-radius: 8px; font: inherit; font-size: 13px; padding: 0 10px; width: 100%;
}
.pf input:focus, .pf select:focus { outline: 0; border-color: var(--red); box-shadow: 0 0 0 3px var(--red-soft); }
.pf input[type=number] { width: 72px; }
.pf .fld.num { flex-direction: row; align-items: center; justify-content: space-between; }
.pf-top { display: flex; flex-direction: column; gap: 12px; }
.fsheet { display: flex; flex-direction: column; gap: 14px; }
.fsheet > * + * { padding-top: 14px; border-top: 1px solid var(--line-soft); }
.fsheet > .fgrp + .fgrp { padding-top: 14px; }

/* segmented radios / checkbox chips share the .scope a look */
.seg { flex-direction: row !important; flex-wrap: wrap; align-items: center; gap: 4px 6px !important; }
.seg legend { float: left; width: 100%; margin-bottom: 4px; }
.seg label, .chk {
  position: relative; display: inline-flex; cursor: pointer;
  font-family: var(--display); text-transform: uppercase; letter-spacing: .07em;
  font-size: 12.5px; font-weight: 550;
}
.seg label span, .chk span {
  color: var(--muted); padding: 4px 11px; border-radius: 5px; background: var(--surface);
  border: 1px solid var(--line); min-height: 28px; display: inline-flex; align-items: center;
}
.seg input, .chk input { position: absolute; opacity: 0; inset: 0; margin: 0; cursor: pointer; }
.seg label:hover span, .chk:hover span { border-color: var(--red); color: var(--red); }
.seg input:checked + span, .chk input:checked + span { background: var(--red); color: var(--on-accent); border-color: var(--red); }
.seg label:has(:focus-visible) span, .chk:has(:focus-visible) span { outline: 2px solid var(--red); outline-offset: 2px; }

.fgrp > summary { cursor: pointer; list-style: none; display: block; padding: 2px 0; }
.fgrp > summary::-webkit-details-marker { display: none; }
.fgrp-panel { display: flex; flex-wrap: wrap; gap: 8px 6px; padding-top: 8px; }
.fgrp-panel .fld.num { width: 100%; }
.pf-foot { display: flex; align-items: center; gap: 14px; }
.pf .apply {
  height: 32px; padding: 0 16px; border-radius: 8px; border: 1px solid var(--red); background: var(--red);
  color: var(--on-accent); font-family: var(--display); font-size: 13px; letter-spacing: .08em; text-transform: uppercase; cursor: pointer;
}
.freset { color: var(--muted); font-size: 12.5px; }
.freset:hover { color: var(--red); }
.fbtn { display: none; }
.fbtn .s-open { display: none; }

.quick { display: flex; flex-direction: row; flex-wrap: wrap; gap: 6px 16px; align-items: baseline; margin: 8px 0 4px; }
.quick h3 { margin: 0; }
.quick a { color: var(--ink); text-decoration: none; font-size: 13px; padding: 5px 0; }
.quick a:hover { color: var(--red); }

.pcount { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; margin: -6px 0 10px; min-height: 26px; }
.fchips { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.fchip {
  display: inline-flex; align-items: center; gap: 5px; height: 26px; padding: 0 6px 0 10px; border-radius: 13px;
  background: var(--red-tint); border: 1px solid var(--red-soft); color: var(--ink); text-decoration: none;
  font-family: var(--display); font-size: 12px; letter-spacing: .06em; text-transform: uppercase;
}
.fchip b { font-weight: 700; }
.fchip .x { width: 16px; text-align: center; color: var(--muted); font-size: 14px; line-height: 1; }
.fchip:hover .x { color: var(--red); }

.legend { margin: 0 0 10px; }
.legend > summary { cursor: pointer; color: var(--muted); font-size: 12.5px; width: max-content; }
.legend > summary:hover { color: var(--ink); }
.legend p { max-width: var(--prose-max); }

.ptab td .inj { margin-left: 5px; }
.ptab .gtime { font-family: var(--display); font-size: 10px; font-weight: 700; color: var(--muted); letter-spacing: .03em; }
.ptab .gtime.live { color: var(--live); }
.ptab .gtime.done { opacity: .6; }
.ptab tr.noresult td { text-align: center; padding: 28px 12px; white-space: normal; color: var(--muted); position: static; }
.ptab tr.noresult p { margin: 0 0 8px; }
.ptab tr.noresult .fchip { margin: 0 3px; }

/* The form's groups are plain sections wherever there is room (lg, and inside
   the phone sheet); only md folds them into drop-downs. Where ::details-content
   is not supported the summaries simply stay clickable. */
@supports selector(::details-content) {
  .fgrp::details-content { content-visibility: visible; }
  .fgrp > summary { pointer-events: none; }
}

/* >=1024: one top bar -- search, Availability, Position, "More filters" panel */
@media (min-width: 1024px) {
  .pf { position: relative; margin-bottom: 10px; }
  .pf-top { flex-direction: row; align-items: flex-end; gap: 10px 16px; }
  .pf-top .grow { flex: 0 1 320px; }
  .fsheet { flex-direction: row; flex-wrap: nowrap; align-items: flex-end; gap: 10px 16px; }
  .fsheet > * + * { padding-top: 0; border-top: 0; }
  .fsheet .seg { flex-wrap: wrap; }
  .fmore-btn { height: 32px; display: inline-flex; align-items: center; gap: 6px; padding: 0 12px;
    border: 1px solid var(--line); border-radius: 8px; background: var(--surface); color: var(--ink);
    font-family: var(--display); font-size: 12.5px; letter-spacing: .08em; text-transform: uppercase;
    cursor: pointer; list-style: none; }
  .fmore-btn::-webkit-details-marker { display: none; }
  .fmore-btn::after { content: "▾"; font-size: 10px; color: var(--muted);
    transition: transform var(--dur-1) var(--ease-out); }
  .fmore[open] > .fmore-btn { border-color: var(--hover-line); background: var(--raised); }
  .fmore[open] > .fmore-btn::after { transform: rotate(180deg); }
  .fmore-btn:hover { border-color: var(--hover-line); }
  .fmore-btn:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; }
  .fmore-n { min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px; background: var(--red);
    color: var(--on-accent); font-size: 11px; font-weight: 700; display: inline-grid; place-items: center; }
  .fmore[open] > .fmore-panel {
    position: absolute; left: 0; right: 0; top: calc(100% + 6px); z-index: 20;
    display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 16px 20px;
    padding: 16px; background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--radius); box-shadow: var(--lift);
    animation: fmore-in var(--dur-2) var(--ease-out);
  }
  @keyframes fmore-in { from { opacity: 0; transform: translateY(-4px); } }
  .fmore-panel .fgrp > summary { pointer-events: none; }              /* sections always expanded */
  .fmore-panel .fgrp::details-content { content-visibility: visible; }
  .fsheet-wrap::details-content { content-visibility: visible; }
  .fsheet-wrap > summary { display: none; }
  .pf-foot { margin-left: auto; }
  main.wide { --main-px: var(--gutter); }
}
@media (prefers-reduced-motion: reduce) { .fmore[open] > .fmore-panel { animation: none; } }

/* The full-width players page. */
main.wide { max-width: none; padding-inline: var(--main-px); }

/* sm/xs: search + Filters button; everything else in a full-screen sheet */
@media (max-width: 1023px) {
  /* The table scrolls with the page and only sideways inside its wrapper. The
     header row does not stick on phones: the wrapper is an overflow-x scroll
     container, so a sticky th would stick to it, not to the page. */
  .ptab-scroll {
    max-height: none; min-height: 0; overflow-x: auto;
    overscroll-behavior-x: contain; touch-action: pan-x pan-y;
  }
  .ptab-scroll:has(tr.noresult) { min-height: 200px; }
  main.wide { overflow-x: clip; }
  main.wide .ptab-scroll { margin-inline: calc(-1 * var(--main-px)); border-inline: 0; border-radius: 0; }
  main.wide .pf { margin-inline: calc(-1 * var(--main-px)); padding-inline: var(--main-px); }  /* full-bleed sticky bar */
  .ptab { --rank-w: 36px; }
  .ptab .c-rank { padding-left: 10px; }      /* the digit doesn't touch the screen edge */
  .fmore-panel { display: flex; flex-direction: column; gap: 18px; }
  @supports selector(::details-content) { .fmore-btn { display: none; } .fmore::details-content { content-visibility: visible; } }
  .pf {
    position: sticky; top: var(--topbar-h); z-index: 5; background: var(--bg);
    padding: 8px 0; margin-bottom: 8px;
  }
  .pf:has(#pf-sheet[open]) { z-index: 72; }
  .pf-top { flex-direction: row; align-items: flex-end; gap: 8px; }
  .pf-top .grow { flex: 1 1 auto; }
  .pf input[type=search], .pf select, .pf input[type=number] { height: 44px; }
  .fbtn {
    display: inline-flex; align-items: center; height: 44px; padding: 0 16px; cursor: pointer; list-style: none;
    border: 1px solid var(--line); border-radius: 8px; background: var(--surface); color: var(--ink);
    font-family: var(--display); letter-spacing: .08em; text-transform: uppercase; font-size: 13px;
  }
  .fbtn::-webkit-details-marker { display: none; }
  .fsheet-wrap:not([open]) > .fsheet { display: none; }
  /* main is its own stacking context below the topbar, so the sheet starts under
     the topbar rather than trying to cover it. */
  .fsheet-wrap[open] > .fbtn { position: fixed; top: calc(var(--topbar-h) + 10px); right: 12px; z-index: 72; }
  .fsheet-wrap[open] .s-closed { display: none; }
  .fsheet-wrap[open] .s-open { display: inline; }
  .fsheet-wrap[open] > .fsheet {
    position: fixed; inset: var(--topbar-h) 0 0 0; z-index: 71; background: var(--bg); overflow: auto;
    padding: 64px 16px 88px; gap: 18px;
  }
  .pf-foot { position: fixed; left: 0; right: 0; bottom: 0; z-index: 72; padding: 12px 16px;
    background: var(--surface); border-top: 1px solid var(--line); }
  .pf .apply { height: 44px; flex: 1; }
  .seg label span, .chk span { min-height: 44px; }
  .fgrp-panel { padding-top: 10px; }
  .pf .fgrp > summary { pointer-events: none; }
  .quick { overflow-x: auto; white-space: nowrap; }
  .quick a { padding: 4px 0; }
  .pcount { flex-wrap: nowrap; overflow-x: auto; }
  .fchips { flex-wrap: nowrap; white-space: nowrap; }
}
.fgrp-panel .fld.num { flex-direction: column; align-items: stretch; width: calc(50% - 4px); gap: 2px; }
.fgrp-panel .fld.num input[type=number] { width: 100%; }
.fsheet { gap: 10px; }
.fsheet > * + * { padding-top: 10px; }
.fgrp-panel .fld.num label { text-align: left; }

/* ---------- players.js hooks ---------- */
.ptab.off-weeks .f-weeks, .ptab.off-proj .f-proj, .ptab.off-matchup .f-matchup,
.ptab.off-usage .f-usage, .ptab.off-pass .f-pass, .ptab.off-rush .f-rush,
.ptab.off-rec .f-rec, .ptab.off-kick .f-kick, .ptab.off-def .f-def { display: none; }
@media (min-width: 1024px) { .js-pf .pf .apply { display: none; } }
@keyframes rowin { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: no-preference) {
  /* opacity only: .ptab has sticky cells that a transform would break */
  .ptab tbody.reveal tr:nth-child(-n+12) {
    animation: rowin 240ms var(--ease-out) both;
    animation-delay: calc(var(--i, 0) * var(--stagger));
  }
}
.pcount [tabindex="-1"]:focus { outline: 0; }

/* NFL games card: days after the first sit in a <details>. From 1024px up it is
   forced open and the summary is gone, so the card looks as it always did. */
.rail-card .more > summary { display: none; }
.rail-card .more > .day:first-of-type { margin-top: 8px; }
@media (min-width: 1024px) {
  .rail-card .more::details-content { content-visibility: visible; display: block; }
}
@media (max-width: 1023px) {
  .rail-card .more > summary {
    display: flex; align-items: center; min-height: var(--tap, 44px); cursor: pointer;
    color: var(--muted); font-size: 12.5px; list-style: none;
  }
  .rail-card .more > summary::-webkit-details-marker { display: none; }
  .rail-card .more > summary::after { content: "▾"; margin-left: 6px; }
  .rail-card .more[open] > summary::after { content: "▴"; }
}

/* Schedule scroll cue and the generic full/short name swap: phone-only. */
.swipe { display: none; }

/* ---------- phones: one breakpoint ---------- */
/* Everything at or below 640px lives in this single block, at the end of the
   sheet so it wins over the base rules it overrides. Desktop is untouched. */
@media (max-width: 640px) {
  :root {
    --gutter: 12px;          /* page side padding */
    --card-pad: 10px 12px;   /* .game, .rail-card */
    --tap: 44px;             /* minimum touch target */
    --name-w: 132px;         /* sticky team/player column */
    --score: clamp(24px, 7vw, 30px);
    --main-px: 12px;
    --td-size: 14px;
  }
  main { padding: 16px var(--gutter) 48px; }
  .pagefoot { padding-inline: var(--gutter); }
  .ticker { display: none; }
  .games { grid-template-columns: minmax(0, 1fr); }
  .game { min-width: 0; }
  .game, .games.feature .game, .games.compact .game { padding: var(--card-pad); gap: 2px; }
  .mname { font-size: 14.5px; }
  .sb-clock { gap: 4px; }
  .sb-clock .seg { min-width: 58px; }
  .sb-clock b { font-size: 38px; }
  .sb-clock .seg + .seg { padding-left: 4px; }
  .scoreboard { padding: 20px 12px 18px; }
  /* .c-rank and .c-player are fixed-width sticky boxes (border-box), so a
     smaller td/th padding does not move where .c-player's left offset has to
     land -- the 28px from the base rule already accounts for it. */
  .ptab .c-player { max-width: 132px; }
  .ptab .c-player .pn > .muted.small { display: none; }
  .ptab { font-size: 12px; }
  .ptab td, .ptab th { padding: 4px 6px; }
  .topbar .who { display: none; }
  .games.feature .mname { font-size: 19px; }
  .games.feature .mscore { font-size: 34px; }
  .lineup .nm-full { display: none; }
  .lineup .nm-abbr { display: inline; }
  .lineup .pro { display: none; }

  /* Names take whatever is left; the scores tuck against the slot. */
  .lineup li,
  .games.compact .lineup li {
    grid-template-columns: minmax(0, 1fr) 46px 38px 46px minmax(0, 1fr);
    column-gap: 2px; font-size: 12px;
  }
  .games.feature .lineup li { font-size: 12px; }
  .lineup .lp { padding: 1px 3px; }
  .lineup .ppts { white-space: nowrap; }
  .lineup .slot, .games .mdl .lineup .slot { padding-inline: 1px; letter-spacing: .02em; white-space: nowrap; }

  /* A phone row has no width for a kickoff beside a name -- the NFL team
     abbreviation has already been dropped above for the same reason. The modal
     keeps it: that is the view you open when you want the detail. */
  .game .lineup .gtime { display: none; }
  .mdl .lineup .gtime { display: inline; }

  /* Full screen: a matchup is 30-odd rows, and a centred card would spend half
     the phone on the backdrop behind it. */
  .mdl {
    width: 100vw; max-width: 100vw; height: 100dvh; max-height: 100dvh;
    border: 0; border-radius: 0;
  }
  .mdl-in { padding: 14px 12px 24px; }
  .games .mdl .lineup li {
    grid-template-columns: minmax(0, 1fr) 50px 42px 50px minmax(0, 1fr);
    column-gap: 3px; font-size: 12px;
  }
  .games .rdlg .lineup li { grid-template-columns: 44px minmax(0, 1fr) 54px; column-gap: 6px; }
  .rdlg .lineup .ppts { white-space: nowrap; }
  .games .mdl .lineup .nm-full { display: none; }
  .games .mdl .lineup .nm-abbr { display: inline; }
  /* Twenty columns will not fit a phone. The per-down counters are the reason
     to open this page, so they stay and the derived columns go. */
  .usage th.wide, .usage td.wide { display: none; }
  .roster.mine { margin-left: 0; padding-left: 10px; }
  .pagefoot { justify-content: center; padding-bottom: 28px; }

  /* -- matchup header (spec 5): scores face each other across a 64px middle,
        names sit under their own score and clamp to two lines -- */
  .mhead { grid-template-columns: minmax(0, 1fr) 72px minmax(0, 1fr); column-gap: 6px; }
  .mside, .mside.right { flex-direction: column; justify-content: flex-start; gap: 2px; }
  .mside { align-items: flex-end; text-align: right; }
  .mside.right { align-items: flex-start; text-align: left; }
  .mnum { order: -1; min-width: 0; }
  .mscore { white-space: nowrap; }
  .mside.right .mteam { flex-direction: row; }
  .games .mnum .mscore { font-size: var(--score); }
  .games.compact .mnum .mscore { font-size: 22px; }
  .mproj, .games.compact .mproj { font-size: 11px; }
  .mid, .mside.right .mid { width: 100%; }
  .mteam { min-width: 0; max-width: 100%; align-items: flex-start;
           padding-block: 16px; margin-block: -16px; }
  .mname, .games .mside .mname {
    font-size: 15px; line-height: 1.1; white-space: normal; overflow-wrap: anywhere;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden; min-width: 0;
  }
  .games.compact .mside .mname { font-size: 14px; }
  .titles { flex: none; }
  .tx { display: none; }
  .tcount.tc-xs { display: inline; }
  .mmanager { position: relative; z-index: 1; max-width: 100%; font-size: 11.5px; line-height: 1.3; align-self: auto; }
  .mside.right .mid .mmanager { align-self: auto; }
  .mm-t { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .hovercard { display: none; }
  .mmid { width: 72px; min-width: 0; }
  .mmid .margin, .games.feature .mmid .margin, .games.compact .mmid .margin {
    font-size: 13px; letter-spacing: .02em; white-space: nowrap;
  }
  .games .mmid .bar.share { width: 56px; }
  .share-l { font-size: 9px; line-height: 1.1; text-align: center; }

  /* -- tap targets, type floor, spacing (spec 10) -- */
  body { font-size: 13px; }
  h1 { font-size: 26px; }
  h2 { font-size: 14px; margin: 24px 0 8px; }
  .topbar { padding-block: 10px; }
  .burger { width: var(--tap); height: var(--tap); flex-basis: var(--tap); }
  .signout { min-height: var(--tap); padding-inline: 14px; }
  .mdl-x { width: var(--tap); height: var(--tap); top: 6px; right: 6px; }
  .scope a { min-height: var(--tap); display: inline-flex; align-items: center; padding-inline: 14px; }
  .legend > summary { min-height: var(--tap); display: flex; align-items: center; }
  :is(.burger, .signout, .mdl-x, .scope a, .legend > summary, .mteam):focus-visible {
    outline: 2px solid var(--red); outline-offset: 2px;
  }

  /* -- home rail (spec 6): one column, injuries first when there are any -- */
  .rail { display: flex; flex-direction: column; align-items: stretch; gap: 12px; margin-top: 24px; }
  .rail-card { padding: var(--card-pad); }
  .rail-card:has(.inj-row) { order: -1; }
  .rail-card[aria-labelledby="rc-nfl"] { order: 1; }
  .rail-card[aria-labelledby="rc-inj"]:not(:has(.inj-row)) { order: 2; }
  .rail-row { font-size: 13px; height: 32px; }
  .more > summary:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }
  .games.compact .game { animation-name: rise; }
  .scroll, table, .tscroll { animation: none; }

  /* -- defects on home: the scroll-driven reveal left cards below the fold
        dim (opacity .25, shifted 40px, so the hint sat on top of the last
        one). Phones get plain cards. -- */
  .games.compact .game { animation: none; }
  .resthint { margin: 12px 0 8px; }

  /* -- season schedule (spec 7) -- */
  .nm-swap .nm-full { display: none; }
  .nm-swap .nm-abbr { display: inline; }
  .schedule .rowhead { width: 100px; min-width: 0; max-width: 100px; overflow: hidden; text-overflow: ellipsis; }
  .schedule .rot { max-width: 56px; font-size: 10.5px; }
  .schedule .cell { font-size: 11px; overflow: hidden; text-overflow: ellipsis; }
  .schedule .cell, .schedule .rot { padding-inline: 4px; }
  .sch-scroll:not(.at-end) {
    -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 24px), transparent);
            mask-image: linear-gradient(90deg, #000 calc(100% - 24px), transparent);
  }
  .swipe { display: block; margin: 6px 0 0; text-align: right; }
  .wklegend { margin-top: 12px; flex-direction: column; gap: 4px; }

  /* -- standings (spec 8): tables scroll sideways, team column pinned -- */
  .tscroll { overflow-x: auto; border-radius: var(--radius); box-shadow: var(--lift); margin-top: 8px; }
  .tscroll table { box-shadow: none; overflow: visible; width: max-content; min-width: 100%; margin-top: 0; }
  .tscroll th, .tscroll td { white-space: nowrap; padding: 8px; }
  table.data td.num, table.data th.num, table.data .wl { width: auto; }
  .st-team { position: sticky; left: 0; z-index: 2; width: var(--name-w); max-width: var(--name-w);
             overflow: hidden; text-overflow: ellipsis;
             background: var(--surface); box-shadow: 1px 0 0 var(--line); }
  thead .st-team { background: linear-gradient(var(--green-tint), var(--green-tint)), var(--surface); z-index: 3; }
  tr.me > .st-team { background: linear-gradient(var(--green-soft), var(--green-soft)), var(--surface);
                     box-shadow: inset 2px 0 0 var(--red), 1px 0 0 var(--line); }
  .st-rank { position: sticky; left: 0; width: 28px; min-width: 28px; max-width: 28px; padding-inline: 4px;
             background: var(--surface); z-index: 2; text-align: center; }
  thead .st-rank { background: linear-gradient(var(--green-tint), var(--green-tint)), var(--surface); z-index: 3; }
  tr.me > .st-rank { background: linear-gradient(var(--green-soft), var(--green-soft)), var(--surface); }
  .st-rank + .st-team { left: 28px; }
  td.empty-row { white-space: normal; position: sticky; left: 0; max-width: calc(100vw - 2 * var(--gutter)); }
  .notice a { padding-block: 10px; }

  /* -- players (spec 9): table kept, pinned # and player, sideways scroll -- */
  .ptab th { font-size: 11px; padding: 0; }
  .ptab th a { display: flex; align-items: center; justify-content: flex-end;
               min-height: var(--tap); min-width: 32px; padding: 0 6px; }
  .ptab th.c-player a { justify-content: flex-start; }
  .ptab th.c-rank { padding: 0; }
  .ptab td { padding: 6px; font-size: 12px; }
  .ptab .c-player { width: min(132px, 34vw); max-width: min(132px, 34vw); white-space: normal; }
  .ptab .c-player .pn { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
                        overflow: hidden; font-size: 12.5px; line-height: 1.15; }
  .ptab td.c-text { max-width: 104px; overflow: hidden; text-overflow: ellipsis; }
  .pcount, .fchips {
    -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 24px), transparent);
            mask-image: linear-gradient(90deg, #000 calc(100% - 24px), transparent);
  }
  .quick { flex-wrap: wrap; overflow: visible; white-space: normal; gap: 0 18px; }
  .quick a { min-height: var(--tap); display: inline-flex; align-items: center; padding: 0; }
}

/* ---------- matchup picker, full matchup view, touchdowns ---------- */
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden;
           clip: rect(0 0 0 0); white-space: nowrap; border: 0; padding: 0; }

.mpick { margin: 0 0 16px; }
.mpick-list {
  list-style: none; margin: 0; padding: 2px 0 6px;          /* room for the focus ring and lift */
  display: grid; grid-auto-flow: column;
  grid-auto-columns: minmax(156px, 240px); gap: 8px;
  overflow-x: auto; scroll-snap-type: x proximity; scrollbar-width: thin;
  overscroll-behavior-x: contain; position: relative;
}
.mpick-list > li { scroll-snap-align: start; min-width: 0; }
.mpk {
  display: grid; gap: 3px; height: 100%;
  padding: 8px 10px 9px; border-radius: var(--radius);
  background: var(--surface); border: 1px solid var(--line); box-shadow: var(--shadow);
  color: var(--ink); text-decoration: none; position: relative;
}
.mpk-state { display: flex; justify-content: space-between; align-items: center; height: 14px;
  font-family: var(--display); font-size: 10.5px; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted); }
.mpk.is-live .mpk-st { color: var(--live); }
.mpk.is-live .mpk-st::before { content: ""; display: inline-block; width: 6px; height: 6px;
  border-radius: 50%; background: var(--live); margin-right: 5px; vertical-align: 1px; }  /* static, no pulse */
.mpk-you { color: var(--on-accent); background: var(--green); border-radius: 3px; padding: 0 4px;
  letter-spacing: .08em; }
.mpk-row { display: grid; grid-template-columns: minmax(0,1fr) auto; gap: 8px; align-items: baseline;
  font-size: 13px; line-height: 18px; color: var(--muted); }
.mpk-row.lead { color: var(--ink); }
.mpk-tm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mpk-sc { font-family: var(--display); font-size: 16px; font-weight: 700; font-variant-numeric: tabular-nums; }
.mpk[aria-current="true"] {
  background: linear-gradient(var(--red-tint), var(--red-tint)), var(--surface);
  border-color: var(--red); box-shadow: inset 0 2px 0 var(--red), var(--shadow);
}
.mpk:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; }
#sb.is-loading .mview { opacity: .6; transition: opacity var(--dur-2) var(--ease-out); }

/* card and picker hover: quiet */
.mpk, .game[role=button], a.game {
  transition: transform var(--dur-1) var(--ease-out), border-color var(--dur-1) var(--ease-out),
              background-color var(--dur-1) var(--ease-out), box-shadow var(--dur-2) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .mpk:hover, .game[role=button]:hover, a.game:hover {
    transform: translateY(-1px); border-color: var(--hover-line);
    background-image: linear-gradient(var(--green-tint), var(--green-tint));
    box-shadow: var(--lift-hover);
  }
  .mpk[aria-current="true"]:hover { border-color: var(--red);
    background-image: linear-gradient(var(--red-tint), var(--red-tint)); }
}
.mpk:active, .game[role=button]:active { transform: none; transition-duration: var(--dur-1); }
@media (prefers-reduced-motion: reduce) {
  .mpk, .game[role=button], a.game { transition: border-color var(--dur-1) linear,
    background-color var(--dur-1) linear, box-shadow var(--dur-1) linear; }
  .mpk:hover, .game[role=button]:hover, a.game:hover { transform: none; }
}

/* the full matchup view */
.mview { max-width: min(var(--card-w), 1260px); margin: 0 auto; padding: 22px 26px 18px;
  border-top: 3px solid var(--red); box-shadow: var(--lift); }
.mview .mname { font-size: 24px; }  .mview .mscore { font-size: 46px; }  .mview .mmid .margin { font-size: 19px; }
.mview .mmid { min-width: 24px; }
.mtab { width: 100%; table-layout: fixed; border-collapse: separate; border-spacing: 0;
  margin: 14px 0 0; padding: 0; background: none; border: 0; box-shadow: none; font-size: 13.5px;
  border-radius: 0; overflow: visible; }
.mtab td, .mtab th { padding: 0; }
.mtab col.c-pts { width: 72px; }  .mtab col.c-slot { width: 56px; }
.mtab tr:not(.grp-h) > * { height: 32px; vertical-align: middle; border-bottom: 1px solid var(--line-soft); }
.mtab .mp .lp { display: flex; align-items: baseline; gap: 6px; min-width: 0; padding: 0 8px; }
.mtab .mp.away .lp { flex-direction: row-reverse; }
.mtab .pname { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.mtab .lp-meta { display: contents; }
.mtab .mpts { text-align: center; font-weight: 650; font-variant-numeric: tabular-nums; line-height: 1.1; }
.mtab .pproj { display: block; font-size: 10px; font-weight: 500; color: var(--muted); }
.mtab .mslot { font-family: var(--display); font-size: 10px; font-weight: 700; letter-spacing: .06em;
  color: var(--green); text-align: center; text-transform: none; }
.mtab .mslot::before { content: none; }
.mtab .grp-h > th { padding: 16px 8px 6px; text-align: center; font-family: var(--display);
  font-size: 11px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--muted);
  border-bottom: 1px solid var(--line); background: none; }
.mtab .grp-start .grp-h > th { padding-top: 4px; }
.mtab .grp-bench .pname, .mtab .grp-ir .pname { opacity: .8; }   /* dim the name only: muted text keeps its contrast */
.mtab .grp-bench .mslot, .mtab .grp-ir .mslot { color: var(--muted); }
@media (hover: hover) and (pointer: fine) {
  .mtab tbody tr:not(.grp-h):hover > * { background: var(--line-soft); }
}

/* touchdowns */
.tds { display: inline-flex; align-items: center; gap: 2px; flex: none; color: var(--red);
  vertical-align: -1px; margin-inline: 4px; }
.td-fb { width: calc(var(--td-size) * 1.25); height: calc(var(--td-size) * .75); display: block; }
.tds-n { margin-left: 2px; font-family: var(--display); font-size: 11px; font-weight: 700;
  color: var(--red); font-variant-numeric: tabular-nums; }
.lineup .lp-meta { display: contents; }

@media (max-width: 640px) {
  .mpick { margin-inline: calc(-1 * var(--main-px)); }              /* chips scroll off the screen edge */
  .mpick-list { grid-auto-columns: 148px; padding-inline: var(--main-px);
    scroll-padding-inline: var(--main-px); scrollbar-width: none; }
  .mpick-list::-webkit-scrollbar { display: none; }
  .mpk { min-height: var(--tap); padding: 8px 10px; }
  .mpk-row { font-size: 12.5px; }
  .mview { margin-inline: calc(-1 * var(--main-px)); border-radius: 0; border-inline: 0;
    padding: 14px var(--main-px) 12px; }
  .mview .mname { font-size: 15px; } .mview .mnum .mscore { font-size: var(--score); }
  .mtab { font-size: 12px; }
  .mtab col.c-pts { width: 46px; } .mtab col.c-slot { width: 34px; } .mtab .mslot { font-size: 9.5px; }
  .mtab tr:not(.grp-h) > * { height: 40px; }
  .mtab .mp .lp { display: grid; grid-template-columns: minmax(0,1fr); row-gap: 1px; padding: 0 7px; }
  .mtab .mp.away .lp { justify-items: end; text-align: right; }
  .mtab .nm-full { display: none; } .mtab .nm-abbr { display: inline; }
  .mtab .lp-meta { display: flex; gap: 4px; align-items: center; font-size: 10px; color: var(--muted); }
  .mtab .mp.away .lp-meta { flex-direction: row-reverse; }
  .mtab .pro, .game .mtab .gtime { display: inline; }
}

/* Matchup view: neutral cell, thin team-colour bar on the outer edge (as the
   players page does), instead of a full team-colour fill. */
.mtab .lp.tinted { background: none; box-shadow: inset 3px 0 0 var(--tc); }
.mtab .lp.away.tinted { box-shadow: inset -3px 0 0 var(--tc); }

/* Phones: 2-3 footballs collapse to one plus the count, so the meta line fits
   its cell with room before the score column. */
.tds-ph { display: none; }
@media (max-width: 640px) {
  .mtab .td-x { display: none; }
  .mtab .tds-ph { display: inline; }
  .mtab .tds { margin-inline: 0; }
  .mtab .mp .lp > .pname, .mtab .mp .lp > .lp-meta { max-width: 100%; }
  .mtab .lp-meta { gap: 3px; min-width: 0; }
  .mtab .mp .lp { padding-inline: 7px 9px; }
  .mtab .mp.away .lp { padding-inline: 9px 7px; }
}
