/* Westlake stats — phone first.
   One stylesheet for every page. Loaded from /assets/m.css so a phone that
   opens three games in a row fetches it once.

   The rule the whole file is written to: nothing is reachable only by hovering.
   A phone has no hover, and the season board's sparklines were the proof — a
   line with no axis and its values in a tooltip is a picture of a shape. Every
   number on this site is on the page. */

:root{
  color-scheme:light dark;

  --bg:#faf9f7;  --surface:#ffffff;  --surface-2:#f2f0ec;
  --ink:#14140f;  --ink-2:#44443c;   --muted:#6f6f64;
  --hair:#e3e0d9; --grid:#d5d1c8;
  --good:#1a7f45; --bad:#b0342a;

  /* The pair is set per page from the two teams' fitted colors; these are the
     fallbacks and the season-page default (validated: light pair 9a0027/1f5fa8,
     dark pair bc3142/5a97dd). */
  --us:#9a0027; --them:#1f5fa8;
  --us-ink:#ffffff; --them-ink:#ffffff;

  --r:0.6rem;
  --tap:44px;              /* nothing interactive is smaller than this */
  --pad:0.85rem;
  --safe-l:max(0.85rem, env(safe-area-inset-left));
  --safe-r:max(0.85rem, env(safe-area-inset-right));
}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    --bg:#111110; --surface:#1b1b19; --surface-2:#232320;
    --ink:#f4f3ef; --ink-2:#c9c7be; --muted:#918f84;
    --hair:#32322e; --grid:#3d3d38;
    --good:#4caf70; --bad:#e2695c;
    --us:#bc3142; --them:#5a97dd;
  }
}
:root[data-theme="dark"]{
  --bg:#111110; --surface:#1b1b19; --surface-2:#232320;
  --ink:#f4f3ef; --ink-2:#c9c7be; --muted:#918f84;
  --hair:#32322e; --grid:#3d3d38;
  --good:#4caf70; --bad:#e2695c;
  --us:#bc3142; --them:#5a97dd;
}

*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0; background:var(--bg); color:var(--ink);
  font:400 16px/1.45 ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  padding-bottom:env(safe-area-inset-bottom);
  overflow-x:hidden;                 /* belt and braces; nothing should need it */
}
a{color:inherit}
b,strong{font-weight:650}

/* ---------------------------------------------------------------- top bar */
.top{
  position:sticky; top:0; z-index:20; background:var(--surface);
  border-bottom:1px solid var(--hair);
  padding:calc(env(safe-area-inset-top) + 0.5rem) var(--safe-r) 0.5rem var(--safe-l);
}
.top .row{display:flex; align-items:center; gap:0.6rem; min-height:var(--tap)}
.back{
  display:inline-flex; align-items:center; justify-content:center;
  min-width:var(--tap); min-height:var(--tap); margin-left:-0.5rem;
  text-decoration:none; color:var(--ink-2); font-size:1.4rem; line-height:1;
}
.top h1{margin:0; font-size:1.02rem; font-weight:700; letter-spacing:-0.01em;
        white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.top .sub{font-size:0.76rem; color:var(--muted); margin-top:-0.1rem}
.spacer{margin-left:auto}
.btn{
  appearance:none; background:var(--surface-2); color:var(--ink-2);
  border:1px solid var(--hair); border-radius:var(--r);
  min-height:var(--tap); padding:0 0.8rem; font:inherit; font-size:0.8rem;
  cursor:pointer;
}
.btn:active{background:var(--hair)}

/* Tabs. A horizontal strip, because five sections stacked is a scroll nobody
   finishes. All five have to be VISIBLE at 360px: the strip scrolls, but a
   fifth tab parked off the right edge is a section most readers never find —
   and the one that was falling off happened to be the play-by-play. Measured,
   the five labels need 410px at the old padding; 0.55rem brings them to 352. */
.tabs{
  display:flex; gap:0.1rem; overflow-x:auto; scrollbar-width:none;
  margin:0.45rem calc(var(--safe-l) * -1) -0.5rem;
  padding:0 var(--safe-l) 0.35rem;
}
.tabs::-webkit-scrollbar{display:none}
.tab{
  appearance:none; background:none; border:0; border-bottom:2px solid transparent;
  color:var(--muted); font:inherit; font-size:0.86rem; font-weight:600;
  padding:0.5rem 0.55rem; min-height:var(--tap); white-space:nowrap; cursor:pointer;
}
.tab[aria-selected="true"]{color:var(--ink); border-bottom-color:var(--us)}

/* ------------------------------------------------------------------ shell */
.wrap{padding:0.75rem var(--safe-r) 2.5rem var(--safe-l); max-width:46rem; margin:0 auto}
.card{
  background:var(--surface); border:1px solid var(--hair); border-radius:var(--r);
  padding:var(--pad); margin:0 0 0.7rem;
}
.card > h2{
  margin:0 0 0.65rem; font-size:0.68rem; font-weight:700;
  letter-spacing:0.1em; text-transform:uppercase; color:var(--muted);
}
.card > h2 .rt{float:right; font-weight:600; letter-spacing:0; text-transform:none}
.note{font-size:0.76rem; color:var(--muted); margin:0.5rem 0 0}
/* Everything the tab bar and the team picker hide carries the `hidden`
   attribute, and every layout rule below that sets `display` on one of those
   elements outranks a plain attribute selector. That cost three separate bugs
   — all five panels drawing at once, then Score sticking, then the team
   picker doing nothing — so the guard is stated once, here, and wins outright.
   The noscript rule is also !important and more specific, so a browser with
   JS off still gets all five panels. */
[hidden]{display:none !important}

/* --------------------------------------------------------------- the score */
.score{display:flex; align-items:center; gap:0.5rem; margin-bottom:0.35rem}
.score .t{flex:1 1 0; min-width:0; display:flex; align-items:center; gap:0.5rem}
.score .t.a{flex-direction:row-reverse; text-align:right}
.score .key{width:0.3rem; align-self:stretch; border-radius:0.15rem; min-height:2.2rem}
.score .t.h .key{background:var(--us)} .score .t.a .key{background:var(--them)}
/* A white plate under every crest, in both themes. School artwork is whatever
   the school made it: Westlake's reads anywhere, Vandegrift's is black line art
   and disappears on a dark surface. A missing crest renders nothing at all —
   an empty plate is worse than none. */
.crest,.gcrest{background:#fff; border:1px solid var(--hair); border-radius:0.3rem;
               object-fit:contain; flex:none; display:block}
.crest{width:34px; height:34px; padding:2px}
.gcrest{width:20px; height:20px; padding:1px; margin-right:0.4rem;
        display:inline-block; vertical-align:middle}
/* The crest costs 34px plus a gap, which at 360px squeezes this block until
   the abbreviation under the name runs out of room. Ellipsis on .nm only
   clips .nm's own inline text — the <small> is a nested block and needs its
   own, or it is cut mid-letter instead of trailing off. */
.score .nm{font-size:0.82rem; font-weight:650; line-height:1.15; min-width:0;
           overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.score .nm small{display:block; font-size:0.68rem; color:var(--muted); font-weight:500;
                 overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.score .nm .full{display:block; overflow:hidden; text-overflow:ellipsis}
/* Phones: each side of the scoreboard is one row - color bar, crest, name, a
   two-digit score at 2.1rem - and that leaves about 30px for the name, so
   every school came out "W..." or "Roun...". The three-letter code always
   fits and is unique per school, and the header directly above already says
   who the opponent is. So below 48rem - the tablet breakpoint, the first
   width where "Dripping Springs" fits - the code is the label. */
@media (max-width:47.99rem){
  /* ...and the code goes UNDER the crest, not beside it. Beside it, even
     three letters got 28px at 390 wide; under it, the row holds only the
     crest and the score, and the code has the crest's own width to sit in.
     Grid areas rather than reordering the markup, so the desktop layout and
     the away side's mirror both come from the same HTML. */
  .score .t{display:grid; grid-template-columns:auto auto 1fr;
            grid-template-areas:"key crest pts" "key nm pts";
            column-gap:0.45rem; row-gap:0.15rem}
  .score .t.a{grid-template-columns:1fr auto auto;
              grid-template-areas:"pts crest key" "pts nm key"}
  .score .key{grid-area:key}
  .score .crest{grid-area:crest; justify-self:center}
  .score .nm{grid-area:nm; justify-self:center; text-align:center; overflow:visible}
  .score .spacer{display:none}
  .score .t.h .pts{grid-area:pts; justify-self:end}
  .score .t.a .pts{grid-area:pts; justify-self:start}
  .score .nm .full{display:none}
  .score .nm small{font-size:0.72rem; font-weight:700; color:var(--ink);
                   letter-spacing:0.04em; overflow:visible}
}
.score .pts{font-size:2.1rem; font-weight:700; line-height:1; letter-spacing:-0.02em}
.score .mid{font-size:0.66rem; color:var(--muted); text-align:center; flex:none;
            text-transform:uppercase; letter-spacing:0.08em}
.wl{font-weight:700} .wl.W{color:var(--good)} .wl.L{color:var(--bad)}
/* A game in progress has no result yet. Our color, and a dot, so it reads as
   "happening" at a glance without borrowing the win green or the loss red. */
.wl.LIVE{color:var(--us)}
.wl.LIVE::before{content:""; display:inline-block; width:0.42em; height:0.42em;
                 border-radius:50%; background:currentColor; margin-right:0.3em;
                 vertical-align:0.12em}
.score .mid.live{color:var(--us); font-weight:700}
.score .mid{display:flex; flex-direction:column; align-items:center; line-height:1.15}
.score .mid .mb{font-variant-numeric:tabular-nums; font-weight:600; opacity:0.85}

/* Quarter-by-quarter. tabular-nums because these align in columns. */
table.ls{width:100%; border-collapse:collapse; font-variant-numeric:tabular-nums}
table.ls th,table.ls td{padding:0.25rem 0.3rem; text-align:center; font-size:0.86rem}
table.ls thead th{font-size:0.6rem; letter-spacing:0.06em; text-transform:uppercase;
                  color:var(--muted); font-weight:700}
table.ls tbody th{text-align:left; font-size:0.78rem; font-weight:700}
table.ls td.tot{font-weight:700}
table.ls tbody tr+tr th,table.ls tbody tr+tr td{border-top:1px solid var(--hair)}
.lsdot{display:inline-block; width:0.42rem; height:0.42rem; border-radius:0.1rem;
       margin-right:0.35rem; vertical-align:middle}

/* ------------------------------------------------------- comparison track
   One shared track per stat: our share solid on the left, theirs on the right,
   the loser's half washed back. The numbers sit OUTSIDE the track at both ends,
   so the value is read without touching anything. A 2px surface gap does the
   separating — no stroke around either fill. */
.cmp{display:flex; flex-direction:column; gap:0.55rem}
.crow{display:grid; grid-template-columns:auto 1fr auto; align-items:center;
      column-gap:0.5rem; row-gap:0.2rem}
.clab{grid-column:1/-1; font-size:0.62rem; font-weight:700; letter-spacing:0.09em;
      text-transform:uppercase; color:var(--muted); text-align:center;
      display:flex; align-items:center; gap:0.5rem}
.clab::before,.clab::after{content:""; flex:1; height:1px; background:var(--hair)}
.cval{font-size:0.95rem; font-weight:700; font-variant-numeric:tabular-nums;
      white-space:nowrap}
.cval small{display:block; font-size:0.62rem; font-weight:500; color:var(--muted)}
.cval.r{text-align:right}
.trk{display:flex; height:0.5rem; border-radius:0.25rem; overflow:hidden;
     background:var(--surface-2)}
.trk .fu{background:var(--us)} .trk .ft{background:var(--them)}
.trk .gap{width:2px; flex:none; background:var(--surface)}
/* The side that lost this row keeps its hue and drops to a wash, so identity
   never moves but the winner is obvious at a glance. */
.trk .lose{opacity:0.34}

/* ------------------------------------------------------------------ tables
   Every stat table is a two-column label/value/value grid rather than a wide
   scroller: a phone can show three columns comfortably and no more. */
table.kv{width:100%; border-collapse:collapse; font-variant-numeric:tabular-nums}
table.kv th,table.kv td{padding:0.34rem 0.3rem; font-size:0.84rem; text-align:right}
table.kv thead th{font-size:0.6rem; letter-spacing:0.06em; text-transform:uppercase;
                  color:var(--muted); font-weight:700; border-bottom:1px solid var(--grid)}
table.kv td.lab,table.kv th.lab{text-align:left; color:var(--ink-2); font-weight:400;
                                width:auto; white-space:normal}
table.kv tbody tr:nth-child(odd) td{background:var(--surface-2)}
table.kv td.u{color:var(--ink); font-weight:650}
table.kv td.t{color:var(--ink); font-weight:650}
table.kv tr.grp th{text-align:left; font-size:0.6rem; letter-spacing:0.09em;
  text-transform:uppercase; color:var(--muted); font-weight:700;
  padding:0.8rem 0.3rem 0.2rem; background:transparent; border-bottom:1px solid var(--grid)}
/* The column heads of the team table name two schools, so they show the two
   crests. Stacked above the code rather than beside it: the heads are narrow
   and a crest on the same line would push the numbers' column out. */
table.kv thead th .kvhead{display:flex; flex-direction:column; align-items:flex-end;
                          gap:0.18rem}
.kvcrest{display:block; width:26px; height:26px; background:#fff; padding:1px;
         border:1px solid var(--hair); border-radius:0.3rem; object-fit:contain;
         box-sizing:border-box}
.swatch{display:inline-block; width:0.5rem; height:0.5rem; border-radius:0.12rem;
        margin-right:0.3rem; vertical-align:middle}
.sw-u{background:var(--us)} .sw-t{background:var(--them)}

/* Player tables can genuinely need more columns than a phone has. They get the
   one horizontal scroller on the site, with the name column pinned, and the
   card says so rather than letting a reader miss two columns. */
/* The one horizontal scroller on the site, and it has to announce itself: a
   reader who cannot see that Defense has nine columns will never swipe for the
   last three. The mask fades the right edge only while there is more to reach. */
.xscroll{overflow-x:auto; -webkit-overflow-scrolling:touch; margin:0 -0.3rem;
         scrollbar-width:thin;
         -webkit-mask-image:linear-gradient(to right,#000 calc(100% - 1.6rem),transparent);
         mask-image:linear-gradient(to right,#000 calc(100% - 1.6rem),transparent)}
.xscroll.end{-webkit-mask-image:none; mask-image:none}
table.pl{width:100%; border-collapse:collapse; font-variant-numeric:tabular-nums;
         min-width:max-content}
table.pl th,table.pl td{padding:0.34rem 0.42rem; font-size:0.82rem; text-align:right;
                        white-space:nowrap}
table.pl thead th{font-size:0.6rem; letter-spacing:0.05em; text-transform:uppercase;
                  color:var(--muted); font-weight:700; border-bottom:1px solid var(--grid)}
table.pl td.who,table.pl th.who{
  text-align:left; position:sticky; left:0; background:var(--surface);
  padding-left:0.1rem; max-width:9.5rem; overflow:hidden; text-overflow:ellipsis}
table.pl thead th.gh{text-align:center; padding:0.32rem 0.3rem 0.3rem; line-height:1.2}
.ghlink{display:block; color:inherit; text-decoration:none}
.ghlink:active{opacity:0.6}
.hcrest{display:block; margin:0 auto 0.2rem; width:28px; height:28px;
        background:#fff; border:1px solid var(--hair); border-radius:0.3rem;
        padding:1px; object-fit:contain; box-sizing:border-box}
.hcrest.nc{background:var(--surface-2); border-style:dashed}
table.pl tbody tr:nth-child(odd) td{background:var(--surface-2)}
table.pl tbody tr:nth-child(odd) td.who{background:var(--surface-2)}
table.pl td .jn{color:var(--muted); font-size:0.7rem; margin-right:0.3rem}
/* The category's team line. Ruled off rather than striped, so it reads as the
   sum of the rows above and not as one more player. */
table.pl tfoot td{border-top:1px solid var(--grid); font-weight:700;
                  background:var(--surface); color:var(--ink)}
table.pl tfoot td.who{background:var(--surface); color:var(--muted);
                      letter-spacing:0.06em; text-transform:uppercase;
                      font-size:0.66rem}

/* ------------------------------------------------------------------ drives */
.drv{display:grid; grid-template-columns:1.6rem auto 1fr auto; gap:0.4rem;
     align-items:center; padding:0.3rem 0; border-top:1px solid var(--hair)}
.drv:first-child{border-top:0}
.drv .q{font-size:0.66rem; color:var(--muted); font-variant-numeric:tabular-nums}
.drv .tm{font-size:0.66rem; font-weight:700; padding:0.08rem 0.32rem;
         border-radius:0.25rem; color:#fff}
.drv .tm.u{background:var(--us); color:var(--us-ink)}
.drv .tm.t{background:var(--them); color:var(--them-ink)}
.drv .bar{height:0.45rem; border-radius:0.22rem 0.22rem 0.22rem 0.22rem;
          background:var(--grid); position:relative; overflow:hidden}
.drv .bar i{display:block; height:100%; border-radius:0 0.22rem 0.22rem 0;
            background:var(--grid)}
.drv .bar i.u{background:var(--us)} .drv .bar i.t{background:var(--them)}
.drv .out{font-size:0.7rem; color:var(--ink-2); white-space:nowrap;
          font-variant-numeric:tabular-nums}
.drv .out b{color:var(--ink)}
.drvline{grid-column:2/-1; font-size:0.68rem; color:var(--muted);
         display:flex; gap:0.5rem; flex-wrap:wrap}

/* ---------------------------------------------------------------- scoring */
.sc{border-top:1px solid var(--hair); padding:0.5rem 0; display:grid;
    grid-template-columns:auto 1fr auto; gap:0.35rem 0.5rem; align-items:baseline}
.sc:first-child{border-top:0}
.sc .when{font-size:0.68rem; color:var(--muted); font-variant-numeric:tabular-nums;
          white-space:nowrap}
/* justify-self, or the chip stretches across the grid's 1fr middle column and
   a three-letter abbreviation becomes a full-width color bar. */
.sc .tm{font-size:0.64rem; font-weight:700; padding:0.06rem 0.3rem; border-radius:0.25rem;
        justify-self:start}
.sc .tm.u{background:var(--us); color:var(--us-ink)}
.sc .tm.t{background:var(--them); color:var(--them-ink)}
.sc .txt{grid-column:1/-1; font-size:0.86rem; line-height:1.35}
.sc .meta{grid-column:1/-1; font-size:0.7rem; color:var(--muted)}
.sc .meta .bad{color:var(--bad)}
.sc .run{font-weight:700; font-variant-numeric:tabular-nums; white-space:nowrap}

/* ------------------------------------------------------------ play by play */
.qbar{display:flex; gap:0.3rem; overflow-x:auto; scrollbar-width:none;
      margin:0 0 0.6rem}
.qbar::-webkit-scrollbar{display:none}
.qbar button{
  appearance:none; background:var(--surface-2); border:1px solid var(--hair);
  color:var(--ink-2); border-radius:999px; font:inherit; font-size:0.78rem;
  min-height:var(--tap); padding:0 0.85rem; white-space:nowrap; cursor:pointer;
}
.qbar button[aria-pressed="true"]{background:var(--us); border-color:var(--us);
                                  color:var(--us-ink)}
/* A left gutter carries the quarter, and on a drive rule the drive's clock.
   The gutter is a fixed 2.5rem so every play's text starts on the same line
   down the page, whether or not its row is the one that names the quarter. */
.play{padding:0.4rem 0; border-top:1px solid var(--hair); display:grid;
      grid-template-columns:2.5rem auto 1fr; gap:0.1rem 0.45rem}
.play:first-child{border-top:0}
.play .pq{grid-row:1/3; font-size:0.66rem; font-weight:700; color:var(--muted);
          font-variant-numeric:tabular-nums; padding-top:0.1rem}
.play .tm{font-size:0.62rem; font-weight:700; padding:0.06rem 0.3rem;
          border-radius:0.25rem; align-self:start; margin-top:0.12rem;
          justify-self:start}
.play .tm.u{background:var(--us); color:var(--us-ink)}
.play .tm.t{background:var(--them); color:var(--them-ink)}
.play .at{font-size:0.68rem; color:var(--muted)}
.play .tx{grid-column:3; font-size:0.85rem; line-height:1.35}
.play.td .tx{font-weight:650}
.play.td{background:color-mix(in srgb, var(--us) 9%, transparent);
         margin:0 -0.4rem; padding-left:0.4rem; padding-right:0.4rem; border-radius:0.3rem}
.play.td.them{background:color-mix(in srgb, var(--them) 9%, transparent)}
/* The drive rule keeps the same 2.5rem gutter as the plays above and below it,
   so the quarter column runs unbroken down the whole list. */
.pdrive{display:grid; grid-template-columns:2.5rem auto 1fr auto; gap:0.1rem 0.45rem;
        align-items:baseline;
        background:var(--surface-2); border-radius:0.35rem; margin:0.35rem -0.4rem;
        padding:0.35rem 0.5rem; font-size:0.72rem; color:var(--muted)}
.pdrive .pq{font-size:0.66rem; font-weight:700; color:var(--ink-2);
            font-variant-numeric:tabular-nums}
.pdrive .pclk{font-variant-numeric:tabular-nums; white-space:nowrap;
              color:var(--ink-2); font-weight:650}
.pdrive .pd{min-width:0}
.pdrive b{color:var(--ink-2)}
.pdrive .run{font-variant-numeric:tabular-nums; white-space:nowrap}
@media (max-width:23.5rem){
  .pdrive{grid-template-columns:2.5rem 1fr auto}
  .pdrive .pd{grid-column:2/-1}
}

/* ----------------------------------------------------------------- lists */
.gl{display:flex; flex-direction:column; gap:0.45rem}
.gcard{
  display:grid; grid-template-columns:auto 1fr auto; align-items:center;
  gap:0.2rem 0.65rem; text-decoration:none; color:inherit;
  background:var(--surface); border:1px solid var(--hair); border-radius:var(--r);
  padding:0.6rem 0.75rem; min-height:var(--tap);
}
.gcard:active{background:var(--surface-2)}
/* G1 is two characters and G10 is three, so without a floor the auto column
   is a different width on every card and the crests march left and right
   down the list. The floor is set by the widest label the season can hold. */
.gcard .n{font-size:0.68rem; color:var(--muted); font-variant-numeric:tabular-nums;
          min-width:1.6rem}
.gcard .opp{font-weight:650; font-size:0.95rem; overflow:hidden;
            text-overflow:ellipsis; white-space:nowrap}
.gcard .chip{display:inline-block; width:0.5rem; height:0.5rem; border-radius:0.12rem;
             margin-right:0.4rem; vertical-align:middle}
.gcard .res{font-variant-numeric:tabular-nums; font-weight:700; white-space:nowrap}
.gcard .sub{grid-column:2/-1; font-size:0.7rem; color:var(--muted)}

/* ----------------------------------------------------------------- season */
.stats{display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:0.5rem}
.stat{background:var(--surface-2); border-radius:var(--r); padding:0.6rem 0.7rem}
.stat .k{font-size:0.6rem; letter-spacing:0.08em; text-transform:uppercase;
         color:var(--muted); font-weight:700}
.stat .v{font-size:1.5rem; font-weight:700; line-height:1.1; letter-spacing:-0.02em}
.stat .s{font-size:0.7rem; color:var(--muted)}

/* Per-game charts. All three variants share these tokens so the comparison is
   about the form, not the styling. */
.chart{margin:0 0 1rem}
.chart:last-child{margin-bottom:0}
.chart .ct{display:flex; align-items:baseline; gap:0.5rem; margin-bottom:0.4rem}
.chart .ct h3{margin:0; font-size:0.86rem; font-weight:650}
.chart .ct .agg{margin-left:auto; font-size:0.74rem; color:var(--muted);
                font-variant-numeric:tabular-nums}
.axis{font-size:0.62rem; color:var(--muted); font-variant-numeric:tabular-nums}

/* A: line with a real scale */
/* A real aspect ratio and xMidYMid, NOT preserveAspectRatio="none": stretching
   a 100-unit viewBox across 360px scales x and y differently, which squashed
   every value label into wide distorted type and pushed the first and last
   ones off both edges. The plot is inset instead so the end labels have room. */
.spark{width:100%; height:auto; aspect-ratio:320/86; display:block}
.spark .grid{stroke:var(--grid); stroke-width:1}
.spark .ln{fill:none; stroke:var(--us); stroke-width:2;
           stroke-linejoin:round; stroke-linecap:round}
.spark .dot{fill:var(--us); stroke:var(--surface); stroke-width:2}
.spark .vlab{fill:var(--ink-2); font-size:11px; font-weight:650;
             font-family:inherit; text-anchor:middle}
.spark .xlab{fill:var(--muted); font-size:10px; font-family:inherit; text-anchor:middle}

/* B: value-labeled columns.
   The cap label is taken OUT of flow. In flow it sets the column's minimum
   width, and at sixteen games a 360px card gives each column about 20px — so
   a three-digit number widened its own slot and pushed the chart past the
   card. Out of flow it is free to overhang its neighbours' airspace, which is
   safe because only three of sixteen are ever labeled. */
.cols{display:flex; align-items:flex-end; gap:2px; height:92px; padding-top:1rem;
      border-bottom:1px solid var(--grid)}
.cols .c{flex:1 1 0; position:relative; display:flex; flex-direction:column;
         justify-content:flex-end; align-items:center; min-width:0; height:100%}
.cols .c .v{position:absolute; bottom:100%; left:50%; transform:translateX(-50%);
            margin-bottom:2px; white-space:nowrap;
            font-size:0.62rem; font-weight:650; color:var(--ink-2);
            font-variant-numeric:tabular-nums}
.cols .c i{display:block; width:100%; max-width:24px; background:var(--us);
           border-radius:4px 4px 0 0; min-height:2px}
.colx{display:flex; gap:2px; margin-top:0.2rem}
.colx span{flex:1 1 0; min-width:0; text-align:center; font-size:0.6rem;
           color:var(--muted); overflow:hidden}

/* C: table with the bar behind the number.
   table-layout:fixed because the two columns are declared as 5.4rem + the rest;
   with auto layout the browser adds the bar cell's own 100% to the label's
   5.4rem and the table grows past its card. */
table.bars{width:100%; table-layout:fixed; border-collapse:collapse;
           font-variant-numeric:tabular-nums}
table.bars th,table.bars td{padding:0.28rem 0.4rem; font-size:0.82rem; text-align:right}
table.bars thead th{font-size:0.6rem; letter-spacing:0.06em; text-transform:uppercase;
                    color:var(--muted); font-weight:700; border-bottom:1px solid var(--grid)}
table.bars td.g,table.bars th.g{text-align:left; color:var(--muted); font-size:0.74rem;
                                width:6.8rem; white-space:nowrap}
table.bars td.b{position:relative; width:auto; padding-right:0.5rem}
/* The bar is absolutely positioned inside the cell, so its percentage width
   resolves against the cell — but it also starts 0.4rem in, which pushed the
   full-width bar (the season best, every time) 0.4rem past the cell's right
   edge and overflowed the table. The cap takes the inset back off. */
table.bars td.b i{position:absolute; left:0.4rem; top:50%; transform:translateY(-50%);
                  height:0.85rem; border-radius:0 3px 3px 0; background:var(--us);
                  opacity:0.26; max-width:calc(100% - 0.9rem)}
/* The value has its own column now. The bar cell can be any width the table
   gives it and the digits are never drawn over. */
table.bars td.v{width:4.4rem; font-weight:650; white-space:nowrap}
/* The game label is a link with the opponent's crest on it. 2.2rem of row
   keeps the tap target honest on a phone without stretching the bar. */
.glink{display:flex; align-items:center; gap:0.38rem; min-height:1.5rem;
       color:inherit; text-decoration:none}
.glink:active{opacity:0.6}
.bcrest{flex:0 0 auto; width:18px; height:18px; background:#fff; padding:1px;
        border:1px solid var(--hair); border-radius:0.25rem; object-fit:contain;
        box-sizing:border-box}
.bcrest.nc{background:var(--surface-2); border-style:dashed}
table.bars tr.hi td.b i{opacity:0.5}
table.bars tfoot td{border-top:1px solid var(--grid); font-weight:700}

/* Home / away / neutral, plus the stadium. The site chip is a word, not a
   color: "H" and "A" in a colored pill is a legend the reader has to learn,
   and there is room for the word. */
.venue{display:flex; flex-wrap:wrap; align-items:center; gap:0.4rem;
       margin:0.1rem 0 0.55rem; font-size:0.74rem; color:var(--muted)}
.site{display:inline-block; font-size:0.6rem; letter-spacing:0.06em;
      text-transform:uppercase; font-weight:700; padding:0.1rem 0.36rem;
      border-radius:0.25rem; border:1px solid var(--hair); color:var(--ink-2)}
.site.home{background:var(--surface-2)}
.site.away{background:transparent; border-style:dashed}
.site.neutral{background:transparent; border-style:dotted}
.site.tag{background:var(--surface-2); color:var(--muted)}

.legend{display:flex; gap:0.9rem; flex-wrap:wrap; font-size:0.72rem;
        color:var(--ink-2); margin:0 0 0.5rem}
.legend span{display:inline-flex; align-items:center; gap:0.32rem}
.legend i{width:0.55rem; height:0.55rem; border-radius:0.12rem; display:inline-block}

/* -------------------------------------------------------------- utilities */
.muted{color:var(--muted)}
.right{text-align:right}
.hide{display:none !important}
details.pl > summary{
  list-style:none; cursor:pointer; min-height:var(--tap);
  display:flex; align-items:center; gap:0.5rem; font-size:0.9rem;
  border-top:1px solid var(--hair); padding:0.3rem 0;
}
details.pl:first-of-type > summary{border-top:0}
details.pl > summary::-webkit-details-marker{display:none}
details.pl > summary::before{content:"▸"; color:var(--muted); font-size:0.8rem;
                             transition:transform .12s}
details.pl[open] > summary::before{transform:rotate(90deg)}
details.pl > summary .jn{color:var(--muted); font-size:0.75rem; min-width:1.5rem}
details.pl > summary .agg{margin-left:auto; color:var(--muted); font-size:0.76rem;
                          font-variant-numeric:tabular-nums}

@media (min-width:34rem){
  .stats{grid-template-columns:repeat(4,minmax(0,1fr))}
  .score .pts{font-size:2.5rem}
}
@media (prefers-reduced-motion:reduce){
  *{transition:none !important; animation:none !important}
}

/* ===================================================================== wide
   Phone-first everywhere above this line. Nothing below reorders, hides or
   replaces anything — it only spends the extra room a bigger screen gives.
   Under 48rem the build is byte-for-byte what it was.
   ------------------------------------------------------------------------ */

/* tablet portrait: the same single column, just less cramped */
@media (min-width:48rem){
  .wrap{max-width:54rem; padding-top:1rem}
  .card{padding:calc(var(--pad) * 1.15)}
}

/* laptop: game lists go two-up and the wide tables stop scrolling */
@media (min-width:64rem){
  .wrap{max-width:64rem}
  .gl{display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:0.4rem}
  .stats{grid-template-columns:repeat(auto-fit,minmax(8rem,1fr))}
  .score .pts{font-size:3rem}
}

/* desktop: each page type packs the way its own content wants to.
   80rem (1280px), not 92rem: 92 put the cut at 1472px, which a 1440-wide
   laptop window never reaches, so the machine most of this is read on got the
   tablet layout and 400px of margin on either side. */
@media (min-width:80rem){
  .wrap{max-width:96rem}
  .gl{grid-template-columns:repeat(3,minmax(0,1fr))}

  /* The season page is read top to bottom and its bars get silly past a
     point, so it stays one column - just not a narrow one. */
  .p-season .wrap{max-width:78rem}

  /* Players is eight position groups of wildly different heights, and the
     two-column packing that used to live here made the page WORSE at this
     width: a 16-game table needs about 960px, so splitting 1536px in half put
     every table back into a horizontal scroller that had been fine at 1024.
     
     Grid instead, and a card holding an open player takes the full width. The
     page is read closed — eight lists of names, which pack two-up happily —
     and goes wide exactly when a table is on screen and needs the room. */
  .p-players .wrap{
    display:grid; grid-template-columns:repeat(auto-fit,minmax(31rem,1fr));
    gap:0.7rem 0.9rem; align-items:start;
  }
  .p-players .wrap > .card{margin:0}
  .p-players .wrap > .card:has(details[open]){grid-column:1 / -1}

  /* The five panels are not the same shape, so they do not take the same
     layout. Gridding all of them was wrong twice over: `display:grid` on a
     two-class selector beat `.panel[hidden]{display:none}`, so the tab bar
     stopped hiding anything and every panel drew at once; and the two panels
     that hold a single child got a phantom empty column beside it.
     Each panel opts in for itself instead. */

  /* Score is three cards: the line across the top, then the two comparisons
     side by side. */
  .p-game #p-sum{
    display:grid; grid-template-columns:repeat(2,minmax(0,1fr));
    column-gap:0.9rem; align-items:start;
  }
  .p-game #p-sum > .card:has(.score){grid-column:1 / -1}

  /* Players is a team switch and then one box per side. The box is what
     should pair up - passing beside rushing - not the switch beside the box. */
  .p-game #p-players > [data-sidebox]{
    display:grid; grid-template-columns:repeat(2,minmax(0,1fr));
    column-gap:0.9rem; align-items:start;
  }

  /* Team stats is one long label-and-two-numbers table. Full width would
     strand the numbers a foot from their labels. */
  .p-game #p-team > .card{max-width:62rem}

  /* Drives and play-by-play are wide by nature: one column, full width. */
}
