/* ============================================================================
   league.css -- the Yowmings League's screens, designed rather than diffed.

   WHY THIS FILE EXISTS, AND WHY IT IS A DELETION FIRST.  Jayden, 2026-08-28:
   "delete all the ui for the yowmings mode and rebuild it to the best of your
    ability in an apple like style using the apple.md skill and our design
    system, a remake not small changes, no lazy work."

   WHAT WAS THERE.  The League had no visual layer of its own.  It had ~400
   lines spread across play.css and tournament.css that SUBTRACTED soccer's
   broadcast scoreboard one instruction at a time -- hide the digits, hide the
   grain, hide the meta, hide the trophy, un-tilt the card, un-paint the plate,
   re-pin the End button to the viewport, re-pin it again to the nav.  Every one
   of those lines was a correct answer to a question that should never have been
   asked, because a fantasy-football draft settled by one-score matches has
   nothing to do with a dark TV bug that holds a running total.  Reading the
   cascade was the only way to know what the League looked like.

   SO: play.css keeps the PITCH (uprights, football, eye black, the dropper) and
   nothing else about this mode.  tournament.css keeps the screen every cup
   shares.  This file is the League, and it is written from tokens.css upward.

   FIVE THINGS IT MUST GET RIGHT, each of which cost a round to learn:

   1. `body.hmYow` IS ONLY ON AT KICKOFF.  `body.hmYowCup` is on from the first
      qualifying screen to the last drain.  A League rule hung on hmYow is
      absent from every screen this file draws -- which is how a "removed"
      scoreboard stayed on four times running, and how tournament.css's own
      panel material and champion-shrink rules shipped never having run once.
      EVERY rule below is scoped hmYowCup (the cup) or hmYowHdr (the match bar).
   2. NOTHING HERE CASTS A SHADOW.  Not one `box-shadow` in this file is
      anything but `none`.  The League separates with hairlines (`border`, so
      the rim is not even spelled as a shadow) and with translucency.  Only the
      companion heads cast, because only they stand on something.
   3. THE SELECTORS ARE READ OFF THE BUILT MARKUP, never guessed.  The captain's
      name is `.sbNm`; the story is `.tvQual.tvStory`; the round in the bar is
      `.sbRound.hmHdrRound`.  A selector that matches nothing fails in silence
      and this mode has three shipped examples of exactly that.
   4. ELEMENTS MOVED OUT OF A CONTAINER LOSE EVERY DESCENDANT RULE.
      headerBuild() lifts `.sbCard` out of `.hmScore` and into `.jbGrpC`, so
      anything written as `.hmScore .sbNm` stops applying the moment it matters.
      The bar's rules are written against `.hmHdrMatch`, which travels WITH it.
   5. IT LINKS LAST.  After controls.css and site-theme.css, so an
      equal-specificity League rule wins on source order and does not lose
      silently the way four earlier ones did.

   THE TYPE, four rungs and two weights, one role each:
     eyebrow  --fs-label 12 / 600 / caps / --tr-caps / muted   the screen's name
     title    --fs-h5  17-20 / 600 /       --tr-sub            captains, champion
     row      --fs-small  15  / 400 /      --tr-body           every list row
     prose    --fs-label 12  / 400 / --lh-body / muted         stake, tape, drain
   Everything on these screens used to be 12px grey except the two captain
   names: one size doing four jobs.  The rows are the texture of a bracket and a
   draft board, so they take the site's list size and the prose stays under them.

   THE ONE ACCENT IS THE PICK.  1.01 is what this cup is for, so wherever a pick
   appears -- the stake line, the drain report, the tie tag, the draft board, the
   round in the match bar -- it is drawn in ink at 600 with tabular figures and
   everything around it stays muted.  --accent is ink site-wide, so this spends
   the accent rather than inventing one.  Nothing here is coloured.

   AND ARCHIVO DOES NOT COME IN HERE.  `.bcNum` is the broadcast board's
   condensed 800 numeral and it is the last piece of that component; the League
   sets its numerals in Geist with tabular figures instead.  The class stays on
   the node (the soccer cup's contract counts it), it simply is not painted with
   a second typeface on a screen that is a ledger.  No rule in this file names
   Archivo, so play.css is still its single declaration site.
   ============================================================================ */

/* ---------------------------------------------------------------------------
   THE LEAGUE'S SCALE.  Rebinding the tournament screen's own layout tokens is
   what they are for -- one place decides how big a row and a face are in this
   mode, and every component below reads it.  (This is not "rebinding --accent":
   these are a component's private geometry, not a site-wide signal.)
   --tvRow is measured, not chosen.  The tallest pane is a round of four ties at
   two rows each; at 1440x900 the band leaves the list 266px, so a tie may cost
   at most 66 and a row at most 24 + its air.
   --------------------------------------------------------------------------- */
body.hmYowCup{
  --tvPanel:460px;                        /* 420 -> 460: the fixture is the hero */
  --tvFace:clamp(42px, 5.4svh, 56px);     /* the two captains */
  --tvRow:clamp(22px, 2.5svh, 26px);      /* every list row */
  --lgRule:var(--theme-rim, rgba(9,11,36,.10));
  --lgPad:var(--sp-24);
}

/* ---------------------------------------------------------------------------
   THE PANEL.
   IT SAT AT THE TOP OF ITS BAND AND THAT IS WHY THE SCREEN LOOKED EMPTY.
   Screenshotted at 1440x900 before anything was touched: a 420px card pinned at
   y=88 with 500px of white under it before the heads.  The band (88 -> 58svh) is
   the League's room and the panel was using the first quarter of it.  Centred in
   the band it lands at y~180 and the air above and below it is equal, which is
   the whole fix -- nothing moved except `align-items`.
   THE MATERIAL IS GLASS, not a lid: a head that drifts under an opaque card is
   sliced through by its bottom edge and reads as a collision even though z-order
   is correct.  --mat-2 + --blur-2 are the site's own tokens (apple-design.md
   §12: floating chrome is a translucent layer with content passing under it).
   THE RIM IS A BORDER, NOT AN INSET SHADOW, and that is deliberate rather than
   stylistic: `box-shadow` is the property this mode is forbidden to spend, and a
   hairline that is spelled as a border cannot be mistaken for elevation by a
   reader or by the gate.  .surface's own shadow is turned off explicitly.
   --------------------------------------------------------------------------- */
body.hmYowCup .tvScreen{align-items:center}

body.hmYowCup .tvPanel.surface{
  box-shadow:none;
  border:var(--hair-w) solid var(--lgRule);
  border-radius:var(--r-xl);corner-shape:var(--corner);
  padding:var(--lgPad);
  gap:var(--sp-12);
  /* --theme-material, NOT --mat-2.  The --mat-* rungs are PAPER values --
     rgba(253,253,253,.86) -- and this panel draws its text in --theme-ink, which
     inverts with the theme and does not. Screenshotted in dark on 2026-08-28 with
     --mat-2 in place: a near-white slab carrying near-white type, unreadable, and
     it was a regression I introduced by spending a literal material rung where a
     semantic one exists. --theme-material is the same .86 opacity on whichever
     ground the theme is actually on. */
  background:var(--theme-material, var(--mat-2));
  -webkit-backdrop-filter:blur(var(--blur-2)) saturate(180%);
          backdrop-filter:blur(var(--blur-2)) saturate(180%);
}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  /* No blur: an opaque ground beats a see-through card with sharp heads legible
     through it, which is worse than the slice it was meant to fix. */
  body.hmYowCup .tvPanel.surface{background:var(--surface-ground)}
}
/* THE FINAL'S EDGE.  tournament.css marks the final by putting the cup's gold
   into .tvPanel's inset ring -- a box-shadow, which this mode may not spend and
   which body.hmFinal would otherwise apply here on the League's final too.  Same
   statement, drawn in the border this panel already has. */
body.hmYowCup.hmFinal .tvPanel{
  box-shadow:none;
  border-color:color-mix(in srgb, var(--gold-ink) 55%, transparent);
}

/* ---------------------------------------------------------------------------
   THE TABS.  The rail keeps the library's travelling underline and the shared
   hairline; what changes is that the row is given air of its own so the
   indicator is not drawn on top of the rule that closes the panel's first band.
   --------------------------------------------------------------------------- */
body.hmYowCup .tvTabs{
  gap:0;
  border-block-end:var(--hair-w) solid var(--lgRule);
  margin-inline:calc(var(--lgPad) * -1);
  padding-inline:var(--sp-8);
}
body.hmYowCup .tvPane{gap:var(--sp-8)}

/* ---------------------------------------------------------------------------
   THE HEAD ROW.  One caps run per pane -- the screen's name on the left, the
   optional fact on the right, both on the label rung so the row is one line of
   type rather than two competing ones.
   --------------------------------------------------------------------------- */
body.hmYowCup .tvEyebrow{
  font-weight:600;font-size:var(--fs-label);line-height:var(--lh-flat);
  letter-spacing:var(--tr-caps);text-transform:uppercase;
  color:var(--theme-muted,var(--c500));
}
/* THE FINAL KEEPS ITS GOLD.  tournament.css marks it with `.tvEyebrowGold` at
   (0,1,0); the League's own eyebrow rule is (0,2,1) and silently took it back to
   muted -- screenshotted at 1440, the final's eyebrow was the same grey as a
   quarter-final's. Restated at the League's own specificity so the mark survives. */
body.hmYowCup .tvEyebrowGold{color:var(--gold-ink)}
body.hmYowCup .tvOptL{
  font-weight:400;font-size:var(--fs-label);letter-spacing:var(--tr-body);
  color:var(--theme-muted,var(--c500));
}

/* ---------------------------------------------------------------------------
   PROSE, AND THE PICK INSIDE IT.  The stake sentence, the tape and the drain
   report are one voice: 12/--lh-body, muted, sentence case.  The picks inside
   them are the only thing that steps forward, and it is the same <em> the tape
   has always used for a winner's name, so there is one emphasis mechanism on
   this screen rather than two.
   --------------------------------------------------------------------------- */
body.hmYowCup .tvQual,
body.hmYowCup .tvTape{
  font-weight:400;font-size:var(--fs-label);line-height:var(--lh-body);
  letter-spacing:var(--tr-body);color:var(--theme-muted,var(--c500));
}
/* ONE EXCEPTION, AND IT IS THE SCREEN WITH NOTHING ELSE ON IT.  The qualifying
   panel has no tabs, no captains and no bracket -- the paragraph IS the screen,
   and the prose rung is sized to sit UNDER a match-up rather than to be read on
   its own. It takes the row rung there, which is the size the rest of the site
   sets a sentence at. Keyed on the absence of the tab rail, which is the actual
   difference between this screen and every other one. */
body.hmYowCup .tvPanel:not(:has(.tvTabs)) .tvQual{
  font-size:var(--fs-small);line-height:var(--lh-body);
}
body.hmYowCup .tvQual em,
body.hmYowCup .tvTape em{
  font-style:normal;font-weight:600;color:var(--theme-ink,var(--c950));
  font-variant-numeric:tabular-nums lining-nums;
}

/* ---------------------------------------------------------------------------
   THE FIXTURE.  Two captains, and a hairline between them carrying the "v".

   WHAT WAS WRONG: the two names sat in a loose stack with "v." floating at a
   hard-coded indent of face-width-plus-gap, which is a number that has to be
   kept in sync by hand and looked like a stray character at every size.  The
   rule IS the versus -- it is the site's own separator -- and the mark sits in
   the face column, centred under the two portraits, so the row has one grid and
   no invented offsets.  The anonymous text node is grid item 1, the rule is
   item 2; they cannot drift apart because they are the same grid as the rows
   above and below.
   THE STAKE MOVED UNDER THE MATCH-UP (see play-tournament.js).  It is the
   answer to "what is this for", which is a thing you ask after you have seen
   who is playing, not before.
   --------------------------------------------------------------------------- */
body.hmYowCup .tvVs{gap:0}
body.hmYowCup .tvSideBig{
  gap:var(--sp-16);min-height:var(--tvFace);padding-block:var(--sp-8);
}
body.hmYowCup .tvSideBig .tvNm{
  font-weight:600;font-size:var(--fs-h5);line-height:var(--lh-auto);
  letter-spacing:var(--tr-sub);color:var(--theme-ink,var(--c950));
}
body.hmYowCup .tvV{
  display:grid;grid-template-columns:var(--tvFace) minmax(0,1fr);
  align-items:center;gap:var(--sp-16);padding:0;
  font-weight:400;font-size:var(--fs-caption);line-height:var(--lh-flat);
  letter-spacing:var(--tr-caps);text-transform:uppercase;text-align:center;
  color:var(--theme-muted,var(--c500));
}
body.hmYowCup .tvV::after{
  content:"";height:var(--hair-w);background:var(--lgRule);
}
/* The final stands its poster beside the captains, at the picture's own
   proportions.  Nothing here animates: the 2026-08-04 wipe stays cancelled. */
/* THE POSTER IS THE HEIGHT OF THE PAIR IT STANDS BESIDE.  --tvPosterH was
   clamp(124px, 20svh, 168px), which at 1440x900 made the picture 168 tall against
   a captains' column of 150: the art drove the row and the two halves lined up on
   neither edge. Measured on the pane, that also cost the final-plus-drain-report
   more height than the band had.
   IT IS DERIVED FROM --tvFace RATHER THAN CLAMPED AGAINST THE VIEWPORT, so the two
   sides of the row track each other by construction: the column is two faces plus
   their air plus the v-rule, and 2.7 faces is that number at every size this ships
   at (measured 131 against 127 at 900, 123 against 121 at 844).
   TRIED AND REJECTED: align-self:stretch with aspect-ratio, which reads the
   picture's own height back through a width:100%/height:100% child and resolved to
   1388px -- the pane's scrollHeight went from 258 to 1388. Measured, not guessed.
   The APERTURE keeps the picture's own 1000:1295, so the whole artwork is still
   inside the frame and the crop that made "the poster isn't even showing" true is
   not reopened. */
body.hmYowCup .tvMeet{gap:var(--sp-20)}
body.hmYowCup .tvPoster{
  --tvPosterH:clamp(72px, calc(var(--tvFace) * 2.7), 152px);
  border-radius:var(--r-lg);corner-shape:var(--corner);
  box-shadow:none;
  border:var(--hair-w) solid var(--lgRule);
}

/* ---------------------------------------------------------------------------
   A ROUND PANE -- the bracket as a ledger.

   WHAT WAS WRONG: four ties of two rows each, separated only by a 16px gap, at
   12px.  Eight near-identical grey lines with no statement about which two
   belonged together, and the right-hand cell ("Next", or the two picks the tie
   decides) marooned at the far edge of a 420px card.
   NOW: the row takes the site's list size, and a hairline BETWEEN ties says
   where one fixture ends and the next begins -- which is the site's own way of
   separating and costs no elevation.  The ties are what you read; the tag is
   what you read second, so it stays on the label rung.
   --------------------------------------------------------------------------- */
body.hmYowCup .tvTies{gap:0}
body.hmYowCup .tvTie{
  column-gap:var(--sp-12);
  padding-block:var(--sp-4);
}
body.hmYowCup .tvTie + .tvTie{
  border-block-start:var(--hair-w) solid var(--lgRule);
}
body.hmYowCup .tvSide{gap:var(--sp-10);min-height:var(--tvRow)}
body.hmYowCup .tvNm{
  font-weight:400;font-size:var(--fs-small);letter-spacing:var(--tr-body);
  color:var(--theme-ink,var(--c950));
}
body.hmYowCup .tvSide.tvWon .tvNm{font-weight:600}
body.hmYowCup .tvSide.tvLost .tvNm{font-weight:400;color:var(--theme-muted,var(--c500))}
/* The colour stripe is the team's, and it is a hairline rather than a bar: at
   3px against a 15px name it was a swatch competing with the portrait beside it. */
body.hmYowCup .tvChipC{
  flex:0 0 var(--sp-2);width:var(--sp-2);
  height:calc(var(--tvRow) - var(--sp-8));
  border-radius:var(--r-hair);
}
body.hmYowCup .tvTieTag{
  font-weight:600;font-size:var(--fs-label);line-height:var(--lh-flat);
  letter-spacing:var(--tr-body);color:var(--theme-ink,var(--c950));
}
/* The picks a settled tie decides are a fact, not a call to action: same rung,
   muted, with the numerals themselves in ink so the column still scans. */
body.hmYowCup .tvTieTag.tvTieStake{
  font-weight:400;color:var(--theme-muted,var(--c500));
  font-variant-numeric:tabular-nums lining-nums;
}
body.hmYowCup .tvSide.tvTBD .tvNm{color:var(--theme-muted,var(--c500))}
/* ONE SCORE WINS, SO THERE IS NO SCORE COLUMN.  At a target of one every played
   tie reads 1 and 0 -- a stripe of ones and zeros restating what the weight of
   the name already says.  The winner is carried by the ink, never by a numeral. */
body.hmYowCup .tvSc{display:none}

/* ---------------------------------------------------------------------------
   THE DRAIN REPORT -- the consolation matches nobody watched.

   WHAT WAS WRONG, and it was invisible rather than ugly: tournament.css shrank
   the champion's portrait only for `.tvPane:has(.tvStoryL)`, and buildStory()
   has always emitted `.tvQual`.  The rule never fired once.  Screenshotted at
   1440x900 and 390x844 on 2026-08-28, the report's last line was drawn UNDER
   the Leave button and the champion pane overran its band -- exactly the
   overrun that rule's own comment describes as fixed.
   The class is `.tvStory` now, the JS writes it, and the shrink is keyed on it.
   A hairline above says "these are results, not the sentence about the fixture"
   without spending a line of height on a heading the pane cannot afford.
   --------------------------------------------------------------------------- */
body.hmYowCup .tvStory{
  display:grid;gap:var(--sp-4);
  padding-block-start:var(--sp-10);
  border-block-start:var(--hair-w) solid var(--lgRule);
}
/* (the champion's portrait size is decided in THE CHAMPION below, where both
   of its cases can be read side by side.) */

/* ---------------------------------------------------------------------------
   THE DRAFT BOARD -- the thing the whole cup exists to produce.

   THE RANK COLUMN IS GONE, and that is subtraction rather than tidying: the row
   printed "1" and then "1.01", which is the same fact twice.  In a draft the
   pick IS the ordinal, so it leads the row, set in ink at 600 with tabular
   figures so the column of 1.01 ... 1.12 aligns on the dot.
   TWO COLUMNS AT EVERY SIZE.  A twelve-team field is twelve rows and the pane
   has room for about nine; the existing two-up only appeared under 640px of
   HEIGHT, so the case that overflowed -- a tall phone with a full field -- was
   the one it did not cover.  Six rows a column reads as a draft board and fits
   at 320 as well as at 1440.
   --------------------------------------------------------------------------- */
body.hmYowCup .tvDraft{
  grid-template-columns:repeat(2,minmax(0,1fr));
  grid-template-rows:repeat(var(--tvDraftRows, 6), auto);
  grid-auto-flow:column;
  column-gap:var(--sp-24);row-gap:var(--sp-2);
}
body.hmYowCup .tvDraftRow{gap:var(--sp-10);min-height:var(--tvRow)}
body.hmYowCup .tvDraftN{display:none}
body.hmYowCup .tvDraftOut{
  order:-1;flex:0 0 auto;margin:0;max-width:none;
  font-weight:600;font-size:var(--fs-small);letter-spacing:var(--tr-body);
  font-variant-numeric:tabular-nums lining-nums;
  color:var(--theme-ink,var(--c950));
}
body.hmYowCup .tvDraftRow:first-child .tvNm{font-weight:600}
/* Where a seat was not settled on the pitch, the row says so in the row --
   there is no legend under the table and there is not going to be one. */
body.hmYowCup .tvDraftTie{
  margin-inline-start:auto;margin-inline-end:0;
  font-size:var(--fs-caption);letter-spacing:var(--tr-caps);text-transform:uppercase;
  color:var(--theme-muted,var(--c500));
}
/* The running order shares the board's shape; only its two states differ. */
body.hmYowCup .tvOrder .tvChipC{flex:0 0 var(--sp-2);width:var(--sp-2)}
body.hmYowCup .tvOrder .tvMoving .tvNm{color:var(--theme-muted,var(--c500))}

/* ---------------------------------------------------------------------------
   THE CHAMPION.  Portrait, name, and the prize said out loud -- because the
   prize in this cup is a pick and not a trophy, and the screen that ends the
   cup was the one screen that never named it.
   --------------------------------------------------------------------------- */
/* THE CAPS EYEBROW GOES ON THIS ONE PANE.  "CHAMPION" over "Player 4 wins the
   Yowmings League" is the same fact twice, in two voices, and the caps run is
   arguing with the only h2 on the screen. Dropping it is subtraction that also
   buys the pane 26px -- which is what the drain report needs to fit under the
   name instead of under the Leave button. */
body.hmYowCup .tvPane:has(.tvChampWrap) > .tvHead{display:none}
/* TWO SIZES, WRITTEN TOGETHER, because as two rules in two sections they were the
   same specificity and the file's order decided which won -- the portrait stayed
   at its full size on the pane that also carries the drain report, which is the
   one case the shrink exists for. The second selector carries both :has() tests
   so it wins on specificity and not on where it happens to sit. */
body.hmYowCup .tvPane:has(.tvChampWrap){--tvChamp:clamp(60px, 11svh, 120px)}
body.hmYowCup .tvPane:has(.tvChampWrap):has(.tvStory){--tvChamp:clamp(50px, 8.4svh, 100px)}
body.hmYowCup .tvChampNm{
  font-weight:600;font-size:var(--fs-h5);line-height:var(--lh-auto);
  letter-spacing:var(--tr-sub);color:var(--theme-ink,var(--c950));text-align:center;
}
body.hmYowCup .tvPrize{
  margin:0;flex:0 0 auto;text-align:center;
  font-weight:400;font-size:var(--fs-label);line-height:var(--lh-flat);
  letter-spacing:var(--tr-body);color:var(--theme-muted,var(--c500));
}
body.hmYowCup .tvPrize em{
  font-style:normal;font-weight:600;color:var(--theme-ink,var(--c950));
  font-variant-numeric:tabular-nums lining-nums;
}

/* ---------------------------------------------------------------------------
   THE FOOTER.  A hairline closes the pane, so the panel reads head / body /
   actions instead of three things in a column.  The first quiet control hangs
   back onto the panel's ink edge: a quiet control has no box, so what the eye
   reads is its label, and a label sits --ctl-pad inside the box.  Measured at
   1440 the moment the variant changed: everything else on the panel started at
   526 and "Leave" started at 542 -- a 16px step in one corner of the card.
   --------------------------------------------------------------------------- */
body.hmYowCup .tvFoot{
  gap:var(--sp-8);
  /* FULL-BLEED, LIKE THE TAB RAIL'S.  A rule inset to the padding box under one
     that runs edge to edge reads as two different kinds of line; they are the
     same kind -- the two edges of the pane -- so they are drawn the same. */
  margin-inline:calc(var(--lgPad) * -1);
  padding-block-start:var(--sp-12);
  padding-inline:var(--lgPad);
  border-block-start:var(--hair-w) solid var(--lgRule);
}
body.hmYowCup .tvFoot > .ctl--quiet:first-child{
  margin-inline-start:calc(var(--ctl-pad) * -1);
}
/* Disabled while a simulation runs.  The library's dim is right for a control
   that might come back under a finger; this one cannot -- "Simulating..." is a
   status, so it takes status ink rather than a faded button. */
body.hmYowCup .tvGo:disabled,
body.hmYowCup .tvGo[aria-disabled="true"]{
  opacity:1;background:none;box-shadow:none;
  color:var(--theme-muted,var(--c500));
}

/* ---------------------------------------------------------------------------
   THE LEAGUE HAS NO SCOREBOARD, AND NOW IT HAS NO SHELL OF ONE EITHER.

   The old answer was to hide the board's parts one at a time -- the digits, the
   ball, the meta, the trophy, the grain, the paint, the tilt -- and leave the
   empty plate pinned to the viewport.  headerBuild() lifts the card OUT of
   .hmScore and into the nav, so what is left behind has nothing in it: the
   whole element goes.  One rule instead of fourteen.
   .hmScore is also the home the card is returned to at the whistle, which is
   why this hides the CONTAINER and never the card -- the card is in the bar by
   then and hiding it would blank the header.
   --------------------------------------------------------------------------- */
body.hmYowCup .hmScore,
body.hmYowCup .hmStake,
body.hmYowCup .battleCount,
body.hmYowCup .hmRaceRow,
/* transform:none IS LOAD-BEARING HERE. The board carries
   matrix(1, 0, 0, 1, 0, 0) -- an IDENTITY transform, which changes nothing
   visually and still creates a containing block for position:fixed. So the
   End button inside it computed `right:126px` correctly and was measured
   off-screen at -114, because "fixed" resolved against the board rather than
   the viewport. An identity matrix counts; that is the whole trap and it is
   the fifth time this containing-block rule has bitten in this mode. */
body.hmYowCup .hmRaceBoard{display:none;transform:none}
/* The race board's own End button is the way out of qualifying and must survive
   its container -- it is re-shown in the bar rather than pinned to the viewport
   corner, where a racer drifting past used to sit on top of it. */
/* ── THE RACE'S END SITS WHERE CONTACT SITS.  2026-08-27 ───────────────────
   "the end button should be where the contact is."
   Measured: it was at left=12, top=432 -- pinned to nothing, halfway down the
   left edge, because .hmRaceBoard is display:none and the button was left to
   whatever containing block it inherited. There is no nav row to move it into
   on the race screen, so it is placed rather than re-parented.
   THE INSET IS THE NAV'S COLUMN, NOT THE VIEWPORT'S EDGE. The bar is a centred
   1200px column, so on a wide screen Contact sits (100vw-1200)/2 in from the
   glass -- 120px at 1440 -- while a flat right:40px would put End 80px outside
   the line every other control in the header aligns to. That mismatch is
   exactly what he caught in the match bar earlier. max() keeps the 40px
   gutter on screens narrower than the column. */
body.hmYowCup .hmRaceBoard button{
  display:inline-flex;
  position:fixed;
  top:var(--sp-16);
  right:max(var(--sp-40), calc((100vw - 1200px) / 2 + var(--sp-6)));
  z-index:60;pointer-events:auto;margin:0;border-left:0;
}
body.hmYowCup .bcGrain{display:none}

/* ---------------------------------------------------------------------------
   THE IN-MATCH BAR.  Logo LEFT, match-up CENTRE, round RIGHT, End RIGHT, and
   nothing else in it.  That arrangement is settled and headerBuild() builds it
   by moving the real nodes into .jbGrpC / .jbGrpR; what is rebuilt here is how
   it LOOKS.

   VISIBILITY, NOT OPACITY, because play.html hides the bar's groups with
   `visibility:hidden` while a game owns the viewport -- an opacity rule leaves
   correct geometry painting nothing, which is how this looked "broken" once
   with every rect measuring right.

   IT IS A MATERIAL NOW.  The bar was transparent, so three pieces of text
   floated on the pitch with heads passing through them.  --mat-1 + --blur-1 and
   a hairline underneath give them somewhere to stand: over white it is nearly
   invisible and over a head it frosts, which is the point (apple-design.md §12).
   No elevation -- the separation is the hairline.
   --------------------------------------------------------------------------- */
/* ── THE HEADER IS VISIBLE FOR THE WHOLE CUP, NOT JUST A MATCH.  2026-08-27 ─
   "header gets glitched easily completely disappearing."
   Reproduced: after End the bar measured logo 0, links 0, matchup 0, round 0,
   End 0 -- entirely empty. The play screen sets .jbGrp* to visibility:hidden
   while it owns the viewport, and this un-hide was scoped to hmYowHdr, which
   headerBuild() only sets DURING A MATCH. So the moment a fixture finished,
   the League's own items left the bar and nothing restored the site's, and
   the header vanished on the bracket, the drains and the champion.
   THE TWO SCOPES DO DIFFERENT JOBS AND THAT IS THE FIX: hmYowCup makes the bar
   exist for the whole cup; hmYowHdr, below, is only what a live match swaps
   INTO it. */
body.hmYowCup .jbGrpL,
body.hmYowCup .jbGrpC,
body.hmYowCup .jbGrpR{visibility:visible;opacity:1;pointer-events:auto}
body.hmYowHdr .jbGrpL,
body.hmYowHdr .jbGrpC,
body.hmYowHdr .jbGrpR{visibility:visible;opacity:1;pointer-events:auto}
body.hmYowHdr .jbGrpC > a,
body.hmYowHdr .jbGrpC > button:not(.hmHdrMatch),
body.hmYowHdr .jbGrpR > a,
/* .lgMute is exempt for the same reason .hmHdrEnd is: it BELONGS to the bar.
   This sweep clears the site's own nav controls out of the League header, and
   it is written as "every button that is not End" -- so the sound control, a
   button the League itself puts there, was swept out with them and measured
   display:none / 0x0 while its audio played on with no way to silence it.
   2026-08-28. */
body.hmYowHdr .jbGrpR > button:not(.hmHdrEnd):not(.lgMute),
/* ── THE SITE'S CONTROLS STAND DOWN FOR THE WHOLE CUP, NOT JUST A MATCH.
   2026-08-27. These were scoped to hmYowHdr, which only exists during a
   fixture -- so on the QUALIFYING RACE the bar still showed Contact and the
   time button, and the race's own End was placed at exactly the inset Contact
   occupies. Two controls in one slot, and the screenshot shows Contact
   winning. Same scope error as the disappearing header: hmYowCup is the class
   that means "a cup owns this screen". */
body.hmYowCup .jbContactBtn,
body.hmYowCup .heroTime,
body.hmYowCup #heroTimeBtn,
body.hmYowHdr .jbContactBtn,
body.hmYowHdr .heroTime,
body.hmYowHdr #heroTimeBtn{display:none}
/* On a race screen there is no matchup to put in the centre, so the site's own
   links stay where they are; only the two right-hand controls step aside. */
body.hmYowCup:not(.hmYowHdr) .jbGrpC > a{display:inline-flex}
body.hmYowHdr .hmHdrMatch,
body.hmYowHdr .hmHdrRound,
body.hmYowHdr .hmHdrEnd{visibility:visible}
/* THE NAV'S OWN ITEMS STEP ASIDE BETWEEN FIXTURES -- but NOT during one, when
   this zone is where the match-up lives. Written as :not(.hmYowHdr) rather than
   relying on a later rule to win it back: both selectors are (0,2,1), so the one
   that happens to be lower in the file decides, and it silently blanked the
   match-up at every size on the first pass. */
body.hmYowCup:not(.hmYowHdr) .jbGrpC{opacity:0;pointer-events:none}

/* ── ONE RULE UNDER THE BAR, NOT TWO.  2026-08-27 ──────────────────────────
   Jayden: "there is an extra line in the header." Measured at 1440: .jbStick
   already draws the site's own full-width hairline as a box-shadow at y=72,
   and this rule added a SECOND one as .jbNav's bottom border at y=60 -- inset
   to the 1200 column, so it read as a short line floating above the real one.
   Two rules under one bar, at two widths, twelve pixels apart.
   The material stays -- that is this bar's job while a cup owns the screen --
   and the edge is left to the element that already owned it. */
body.hmYowHdr .jbNav{
  visibility:visible;box-shadow:none;border:0;
  background:var(--theme-material, var(--mat-1));
  -webkit-backdrop-filter:blur(var(--blur-1));
          backdrop-filter:blur(var(--blur-1));
}

/* ══ THE ROOM TAKES THE WINNER'S COLOUR, FULL BLEED.  2026-08-27 ═══════════
   Three passes on this and each one was his correction, so all three are here.

   IT WAS ON .hero::after AND THAT IS WHY IT CUT OFF. "with the gradient wash
   i think it would look good if it actually did the whole screen like it cuts
   off on the ground it shoul be the whole bottom of the screen." The hero is
   540px of a 900px viewport, so a gradient bounded by it stops at the pitch
   floor and leaves a hard edge across the page. It is position:fixed on the
   body now and reaches the bottom of the SCREEN.

   IT CLEARS AT KICKOFF. "the color has to go away between matches like right
   now it shows it on the next match." It used to persist until the next
   result, which meant a fixture opened wearing the previous winner's colour --
   the room saying something about a match that was already over. play-engine
   clears --lgWin when a match starts, so the colour belongs to the match that
   earned it and to nothing else.

   AND IT IS A WASH, NOT A FILL. Transparent through the top half so the
   header, the cards and the type never sit on a tint; .10 at three quarters,
   .22 at the very bottom. z-index 0 keeps it under the pitch and its chrome.
   No --lgWin means no wash at all -- the fallback is transparent, not grey, so
   nothing shows before anything has been won. */
body.hmYowCup::after{
  content:"";display:block;position:fixed;inset:0;
  z-index:0;pointer-events:none;
  /* FIVE STOPS, NOT THREE. "gradient is still not full screen it looks odd"
     -- and the box was already fixed:inset:0, so it WAS full screen. What
     read as odd is the ramp: 0 to .10 across thirty percent of the height is
     steep enough to show as a band with a visible top edge, which looks like
     a panel rather than light in a room. Spread over five stops from a third
     of the way down, no edge is locatable anywhere. */
  background:linear-gradient(180deg,
    rgba(var(--lgWin,0 0 0),0) 30%,
    rgba(var(--lgWin,0 0 0),.03) 52%,
    rgba(var(--lgWin,0 0 0),.08) 70%,
    rgba(var(--lgWin,0 0 0),.15) 86%,
    rgba(var(--lgWin,0 0 0),.24) 100%);
  transition:background var(--theme-duration,640ms) var(--ease-out);
}
@media(prefers-reduced-motion:reduce){ body.hmYowCup::after{transition:none} }

/* ══ THE MATCH-UP: TWO TEAMS, IN THEIR COLOURS, BREATHING.  2026-08-27 ══════
   Three things he asked for, and they solve each other.

   1. "the spacing is a bit off like the secound name is a bit too far."
      Measured: every gap in the row was the same 10px -- face, name, dash,
      name, face. With uniform gaps the row is five things in a line and
      nothing groups, so the dash reads as belonging to the second name and
      that name looks pushed out. A team is a FACE AND A NAME: 6px inside a
      team, 18px either side of the dash. Same total width, and now the eye
      sees two objects with a separator instead of five evenly spaced items.

   2. "the color of the teams should show in the header." --tc is already on
      each .sbTeam (the engine writes it per fixture), so the name simply
      takes it. It is the only colour in the bar, which is what makes it read
      as identity rather than decoration -- the round and End stay muted ink.
      Against paper a raw team colour can fall under 3:1, so it is mixed 12%
      toward ink: enough to hold contrast at 12px, not enough to stop being
      the team's colour.

   3. "header should do the glowing effect like the old scoreboard did that
      pulsing light effect."
      THE OLD ONE IS A BOX-SHADOW RING (@keyframes sbFlashPulse) AND THIS MODE
      MAY NOT SPEND box-shadow -- the heads cast the only shadow on this site,
      and play-yowmings-contract fails on any value that is not `none`. So the
      light is a radial gradient behind the row instead: same read, no
      elevation, and it tints itself from the same --tc the names use.
      It breathes rather than flashes -- 3.2s, and only while a match is live
      (hmYowHdr), because a pulse on a static screen is a distraction rather
      than a sign of life. */
/* The spacing and the team colour are set on the CANONICAL rules further down
   rather than here: those are the same specificity and later in the file, so a
   second block up here would simply lose. Only the glow lives at this point,
   because nothing competes with it. */

/* The glow. A pseudo-element so it sits behind the row without touching it,
   and a gradient so no shadow is spent. */
body.hmYowHdr .hmHdrMatch{position:relative}
body.hmYowHdr .hmHdrMatch::before{
  content:"";display:block;position:absolute;
  left:-12%;right:-12%;top:-40%;bottom:-40%;
  z-index:-1;pointer-events:none;border-radius:var(--r-pill);
  background:radial-gradient(60% 100% at 50% 50%,
    rgba(var(--lgWin,17,18,20),.10), rgba(var(--lgWin,17,18,20),0) 72%);
  animation:lgBreathe 3.2s var(--ease-out) infinite;
}
@keyframes lgBreathe{0%,100%{opacity:.45}50%{opacity:1}}
@media(prefers-reduced-motion:reduce){
  body.hmYowHdr .hmHdrMatch::before{animation:none;opacity:.7}
}

/* ══ THE WIN, AND IT IS THE LOUDEST THING ON THE SCREEN.  2026-08-27 ═══════
   "make it so that the winner is clearly stated in the message ... its not
   that noticable or really in the right place and its not obvious."
   FIRST VERSION WAS TOO POLITE: page-head sized, muted ink, sitting at 38% --
   above the play, where nothing else is, so it read as a caption floating in
   empty space rather than as the result.
   IT IS THE RESULT OF THE WHOLE MATCH, so it is sized like one. Dead centre
   of the pitch, display rung, and it carries the WINNER'S OWN COLOUR -- which
   is where that colour belongs: naming who won, not tinting the room around
   them. The colour is mixed toward ink so a pale team stays readable, the
   same problem the header names had.
   A ground behind it, because at this size over a busy pitch the words need
   to sit on something -- the site's own material and a hairline, no shadow.
   It arrives on the settle spring, holds, and leaves with the celebration. */
body.hmYowCup .hmLowerThird{
  left:50%;right:auto;bottom:auto;top:50%;
  transform:translate(-50%,-50%) scale(.94);
  display:block;text-align:center;
  padding:var(--sp-16) var(--sp-32);
  border-radius:var(--r-xl);
  background:var(--mat-3, rgba(253,253,253,.96));
  box-shadow:none;
  border:var(--hair-w) solid var(--lgRule, rgba(17,18,20,.12));
  opacity:0;z-index:64;
  transition:opacity var(--dur-state) linear,
             transform var(--sp-settle-dur) var(--sp-settle);
}
body.hmYowCup .hmLowerThird.in{
  transform:translate(-50%,-50%) scale(1);
  opacity:1;
}
body.hmYowCup .hmLowerThird .hmL3Face,
body.hmYowCup .hmLowerThird .hmL3Tag{display:none}
body.hmYowCup .hmLowerThird .hmL3Txt{display:block}
body.hmYowCup .hmLowerThird .hmL3Nm{
  display:block;
  font-family:var(--sans);font-weight:600;
  font-size:var(--fs-title);line-height:var(--lh-tight);
  letter-spacing:var(--tr-head);
  color:color-mix(in srgb, rgb(var(--lgWin,17,18,20)) 62%, var(--c950));
  white-space:nowrap;
}
@media(prefers-reduced-motion:reduce){
  body.hmYowCup .hmLowerThird{transition:opacity var(--dur-state) linear}
  body.hmYowCup .hmLowerThird,
  body.hmYowCup .hmLowerThird.in{transform:translate(-50%,-50%)}
}



/* ══ THE MATCH BAR, SETTLED.  2026-08-27 ═══════════════════════════════════
   These are at the END of the sheet on purpose. Every one of them has been
   fixed once already and come back, because the rules that undo them live
   further down league.css at the same specificity -- so the fix has to be the
   last word rather than an earlier opinion.

   1. THE NAMES WERE ILLEGIBLE, and it is the same fault as the first time:
      .sbNm computes rgb(236,233,221) -- the ink the near-black broadcast
      board was built for -- printed on white paper. About 1.1:1. "the matchup
      isnt legible."

   2. "remove the One score wins". It is said on the fixture card before
      kick-off and by the round line beside it; a third copy in the bar is the
      clutter he keeps asking me to take out.

   3. "remove the green outline around the score". .sbClutch paints an emerald
      edge on the plate whose NEXT goal ends the match -- match point. AT ONE
      SCORE EVERY PLATE IS ALWAYS MATCH POINT, so the state is on from kick-off
      for both teams and marks nothing. A signal that is always true is not a
      signal. It goes in this mode only; the soccer cup still earns it.

   4. He likes the score cards and wants them to sit better: the row gets the
      header's own rhythm -- 6px inside a team, 16px around the pair, and the
      plates take the gap between them rather than crowding the dash. */
body.hmYowHdr .hmHdrMatch .sbNm{
  color:var(--theme-ink,var(--c950));
}
body.hmYowHdr .hmHdrMatch .sbFoot,
body.hmYowHdr .hmHdrMatch .sbRule,
body.hmYowHdr .hmHdrMatch .sbMeta{display:none}
body.hmYowHdr .hmHdrMatch .sbClutch .bcCell,
body.hmYowHdr .hmHdrMatch .bcCell{box-shadow:none;outline:0}
body.hmYowHdr .hmHdrMatch .sbInner{gap:var(--sp-16)}
body.hmYowHdr .hmHdrMatch .sbTeam{gap:var(--sp-6)}
body.hmYowHdr .hmHdrMatch .sbScore,
body.hmYowHdr .hmHdrMatch .sR,
body.hmYowHdr .hmHdrMatch .sB{display:inline-flex;margin:0 var(--sp-4)}

/* ── NO TROPHY, BELT AND BRACES.  2026-08-27 ───────────────────────────────
   "also make sure the trophy isnt there."
   play-engine's handTrophy() already returns early on YOW, and that is the
   real guard. But the trophy has now come back twice by routes that had
   nothing to do with that function -- once as .sbTrophy riding into the nav
   inside the card headerBuild() moves, where body.hmFinal .sbTrophy (0,2,1)
   beat the bar's hide (0,2,0). A CSS backstop costs nothing and closes every
   route at once, including any the engine guard does not sit on. */
body.hmYowCup .sbTrophy,
body.hmYowCup .hmTrophyFly,
body.hmYowCup .tvTrophy,
body.hmYowHdr .sbTrophy,
body.hmFinal.hmYowCup .sbTrophy{display:none}

/* ── THE ROUND LINE, LEGIBLE.  2026-08-27 ──────────────────────────────────
   Measured on a live match: .hmHdrRound computed rgb(185,182,168) against
   paper -- 2.00:1, under the 3:1 floor and the same dark-board ink that made
   the names invisible. .sbRound carries a component rule of its own, so a
   bare .hmHdrRound (0,1,0) loses to it; both classes together settle it. */
.sbRound.hmHdrRound,
body.hmYowHdr .hmHdrRound{
  color:var(--theme-muted,var(--c500));
}

/* ── THE SCORE CARDS.  2026-08-27 ──────────────────────────────────────────
   "i actually do like the score cards there but I do want them to fit the
   spacing a bit better."

   Kept: the cream plate and the split-flap flip. That IS the card he likes.
   Subtracted: the hardware. Measured on a live bar, .bcCell::after is a
   32.39px axle across a 28.80px plate -- it pokes 1.8px out of BOTH sides,
   and at bar size those two stubs read as stray tick marks, not as a hinge
   pin. And ::before is a 2px bar in rgb(34,31,24) straight through the middle
   of the digit, which at 29px wide is a strikethrough on the score.

   A split-flap still reads as one with a hairline seam; it is the thing the
   site already uses to separate chrome. So the seam stays, at 1px and 10%,
   and the axle goes. Subtraction, not a tune. */
/* ── AND THE HARDWARE CAME BACK.  2026-08-28 ──────────────────────────────
   "the old scorecards looked better I just wanted to change the green glow on
   them."

   I removed the hinge and the axle as well as the glow. That was over-reach:
   he asked for ONE thing off these cards and I took three. The hinge and the
   axle are restored exactly as they were -- the split-flap reads as a
   split-flap because of them, which is his point and not mine.

   What stays removed is only the green: the emerald edge on .bcCell, which
   marked match point, and at a target of one every plate is permanently match
   point, so it was lit in every frame of every fixture and marked nothing.
   That rule lives above with the rest of the bar. */

/* SPACING. The plate is 29x46 inside a 54px-tall .sR, so the card was
   floating in 8px of dead box; and the em dash carried the same 16px gap as
   the name did, which put the two cards 60px apart on a 290px bar. Pull the
   pair together and let each name sit against its own card. */
body.hmYowHdr .hmHdrMatch .sbInner{gap:var(--sp-10)}
body.hmYowHdr .hmHdrMatch .sbScore,
body.hmYowHdr .hmHdrMatch .sR,
body.hmYowHdr .hmHdrMatch .sB{margin:0 var(--sp-2)}
body.hmYowHdr .hmHdrMatch .bcNum{line-height:1}

/* ── THE END BUTTON, WORD ONLY.  2026-08-27 ────────────────────────────────
   The stop square is a rounded rect at 14px on a white bar, sitting to the
   left of a word, and in the render it reads as an unchecked CHECKBOX rather
   than a stop control -- the same "why is the black box still there" shape he
   has already pulled me up on once. Everything else in this bar is a word:
   the wordmark, the two team names, QUARTER-FINAL. "End" alone is the one
   that matches, and it is one fewer thing on screen.

   Scoped to the League bar on purpose: soccer's own scoreboard keeps the
   icon, where it sits on the dark plate it was drawn for. */
body.hmYowHdr .hmHdrEnd svg{display:none}

/* And it was 55x38 measured, under the site's 44px floor -- the exception in
   CLAUDE.md is inline prose links, not buttons. Height only; the bar is 86px
   so nothing below it moves. */
body.hmYowHdr .hmHdrEnd{min-height:44px}

/* ── THE SECOND HEAD SAT TOO FAR OUT.  2026-08-28 ──────────────────────────
   "why is the secound head so far aways."

   .sbNm was `flex:1 1 auto` with `text-align:start`, so the two name boxes
   grow to the SAME width whatever they contain -- measured 28.36px each for
   "Fitz" and "Dot" -- and the shorter name's slack sits to the RIGHT of its
   text. On the left team that slack falls harmlessly between the name and the
   score. The right team is mirrored, so on that side it falls between the name
   and the FACE, and the head is pushed out by exactly the difference in name
   lengths. With his MALBERT vs DAD that is ~40px, which is the gap he saw.

   The name should be as wide as the name. flex:0 0 auto sizes each box to its
   own text, so the only thing between a name and its head is the 6px gap, on
   both sides. `overflow:hidden` alone was also cutting long names with no
   ellipsis, so a real cap replaces the shared-growth one. */
body.hmYowHdr .hmHdrMatch .sbNm{
  flex:0 0 auto;
  width:auto;
  max-width:120px;
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}

/* ── THE MATCH BAR ON A PHONE.  2026-08-28 ─────────────────────────────────
   "is all the ui for the yowmings league mobile friendly."  It was not.

   Measured at 390x844 in a real mobile context, mid-match:
     .jbGrpL   x=  22..66    the wordmark
     .jbGrpC   x=  74..394   the matchup, already 4px past the edge
     .jbGrpR   x= 402..580   the round and End -- ENTIRELY off-screen
   The End button started at x=499 on a 390px viewport, so on a phone there
   was no way to end a League match at all, and the round read "QUA".
   Total wanted 542px of 390. Nothing shrank because the three groups are
   flex items at their natural width.

   Everything in the bar is information he asked to keep, so this shrinks
   rather than drops: the faces, the names, the cards and the round label each
   take a phone size, and the centre group is allowed to shrink at all. The one
   thing that does NOT shrink is the End button's 44px tap floor. */
@media (max-width:640px){
  body.hmYowHdr .jbGrpC{min-width:0;flex:0 1 auto;overflow:visible}
  body.hmYowHdr .jbGrpR{min-width:0;flex:0 0 auto}

  body.hmYowHdr .hmHdrMatch .sbInner{gap:var(--sp-4)}
  body.hmYowHdr .hmHdrMatch .sbTeam{gap:var(--sp-4)}
  body.hmYowHdr .hmHdrMatch .sbFace{width:22px;height:22px;min-width:22px}
  body.hmYowHdr .hmHdrMatch .sbNm{font-size:10px;max-width:52px;letter-spacing:.02em}
  body.hmYowHdr .hmHdrMatch .bcCell{font-size:20px}
  body.hmYowHdr .hmHdrMatch .sbScore,
  body.hmYowHdr .hmHdrMatch .sR,
  body.hmYowHdr .hmHdrMatch .sB{margin:0}

  body.hmYowHdr .hmHdrRound{font-size:9px;letter-spacing:.04em;max-width:74px;
    white-space:normal;line-height:1.15;text-align:right}
  body.hmYowHdr .hmHdrEnd{min-height:44px;min-width:44px;padding-inline:var(--sp-8)}
}

/* ══ THE AUDIT PASS.  2026-08-28 ═══════════════════════════════════════════
   Four things off one screenshot, all of them subtraction. */

/* 1. THE WASH BEHIND THE SCOREBOARD.
   "idk if theres like a gradient on the scoreboard but remove that."
   Measured: .sbCard::before is a radial-gradient(60% 100%, rgba(17,18,20,.1),
   transparent 72%) drawn at 350x139 behind a card that is 282x78 -- a dark
   halo half again the size of the thing it sits behind, bleeding onto white
   paper on both sides. It is elevation by another name, and this site
   separates with hairlines and translucency, never with a glow. */
body.hmYowHdr .hmHdrMatch::before,
body.hmYowHdr .sbCard::before{display:none}

/* 2. THE LINE ACROSS THE HEADER.
   "remove the line across from the header I just want it to be clear."
   It is not a border: the header's own box-shadow, rgba(9,11,36,.1) 0 1px 0,
   drawn the full 1512 across. On the play screen the bar already sits on
   paper with nothing under it to divide from. */
/* It is on .jbStick, the sticky wrapper -- 1512x97 -- not on <header> and not
   on .jbNav, both of which measured box-shadow:none. Targeting the wrong two
   elements first is why the line survived a pass. */
body.hmYowCup .jbStick,
body.hmYowHdr .jbStick{box-shadow:none;border-bottom:0}

/* 3. THE WORDMARK, LOUDER.
   "make the logo in the top left more prominent." It was a 22px mark in the
   nav's muted ink -- the quietest thing on a bar whose whole job is to say
   whose league this is. Bigger and in full ink; it stays a wordmark, not a
   badge, so nothing is added around it.

   The mark sits in a BUTTON.jbHome.ctl.ctl--nav and controls.css sizes it
   through that variant, so a bare `.jbGrpL svg` (0,1,1) set the colour and
   lost the width -- which is why it stayed 22px through the first attempt.
   Naming the button wins it. The button was also 44x38, six short of the
   site's own tap floor, so it takes that here too.

   AND THIS COMMENT ATE THE RULE BELOW IT ONCE. The first version closed with
   `*/` after "nothing is added around it", so the five lines that followed
   parsed as a SELECTOR and the stray `*/` swallowed the declaration block --
   the wordmark measured 22x30 and the button 44x38 with rules sitting right
   there in the file that read perfectly and never ran. CLAUDE.md's line:
   a stylesheet that reads correctly is not one that runs correctly. Proven
   live off document.styleSheets below, not by reading it again. */
/* AND THE SIZE IS A TRANSFORM, NOT A WIDTH. Measured after the comment was
   repaired: `width:30px` on the svg still rendered 22x30 -- the height took and
   the width did not, so controls.css is holding that axis through the .ctl--nav
   variant and out-specifying a (0,4,1) selector. Rather than escalate to
   !important against the library -- which is the "patch a control property by
   property" move CLAUDE.md names -- scale it. A transform is composited, owes
   nothing to the cascade, and cannot be out-specified. 22 -> 30 is 1.36.
   The button's own height needed a third attempt. min-height:44px did nothing,
   then padding-block:11px did nothing -- because .ctl--nav sets an explicit
   `height` and the box is border-box, so padding is ABSORBED rather than added
   and a min-height under the used height never binds. The property that is
   actually in play is `height`, so that is the one to set. */
body.hmYowCup .jbGrpL .jbHome,
body.hmYowHdr .jbGrpL .jbHome{color:var(--theme-ink,var(--c950));opacity:1;height:44px}
body.hmYowCup .jbGrpL .jbHome svg,
body.hmYowHdr .jbGrpL .jbHome svg{transform:scale(1.36);transform-origin:50% 50%;
  color:var(--theme-ink,var(--c950));opacity:1}

/* 4. NO DISCO ON A LEAGUE FINAL.
   "remove the disco animation from the end it doesnt look that good in this
   mode so just keep it clean like the rest of the wins."
   The championship kept the dark, the spotlight and the ball. Every other
   result in this cup is announced on white; the final should read like the
   rest of them, only bigger. party.js builds #party and #discoWrap and turns
   them on with .on, so shutting them off here needs no JS and cannot leave a
   half-lit room behind if the class ever sticks. */
body.hmYowCup #party,
body.hmYowCup #discoWrap,
body.hmYowCup #party.on,
body.hmYowCup #discoWrap.on{display:none !important}

/* ── THE SOUND CONTROL.  2026-08-28 ────────────────────────────────────────
   "a mute button in the header at all times put in a clean way that matches
   the token."

   It is a .ctl and inherits everything -- height, radius, press feedback, the
   44px floor -- from controls.css, which is the rule: do not rebuild a button
   privately and do not patch one toward the system property by property. What
   is declared here is only the two things the library has no opinion about:
   the icon's stroke, which the site owns centrally rather than baking into
   each SVG, and the muted state's quieter ink. */
.lgMute.ctl{display:inline-flex;align-items:center;justify-content:center;
  /* Icon-only, so the library's text padding would leave a 51x38 lozenge round
     a 19px glyph -- wide, short, and six under the site's own tap floor. Square
     it off at the floor instead: measured 51x38 before, 44x44 after. */
  min-height:44px;min-width:44px;padding-inline:var(--sp-10)}
/* .lgMute alone is (0,1,0) and ties with .ctl--sm, which sets the 38px
   height; league.css links last so a tie went my way -- but .ctl.ctl--sm is
   (0,2,0) and does not, which is why the first attempt still measured 51x38.
   Naming .ctl here settles it rather than relying on link order. */
.lgMute svg{width:19px;height:19px;stroke-width:1.7}
.lgMute.isMuted{color:var(--theme-muted,var(--c500))}
body:not(.hmYowCup) .lgMute{display:none}

/* ── THE REFEREE'S CAP.  2026-08-29 ────────────────────────────────────────
   Positioned by league-hat.js against the head's own box; everything about how
   it LOOKS lives here.

   The art is baked with its own key light from the upper left, matching the
   head plates', so nothing here re-lights it -- the only thing this adds is
   the shade the brim throws onto the brow, which a real peak does and which is
   the difference between a hat sitting ON a head and a sticker over one.

   THAT SHADE IS ON HIS FACE, NOT ON THE PITCH. CLAUDE.md: only a companion
   head standing on something casts a contact shadow, and chrome never does.
   This is neither -- it is shading inside a picture of a head, the same
   licence the goalposts' own gradients have. Nothing falls on the ground. */
.lgRefHat{
  position:absolute;
  /* NO z-index, AND THAT IS LOAD-BEARING. A positioned element with a z-index is
     a stacking context, and a stacking context ISOLATES blending: with z-index:2
     here the shade below multiplied against the cap's own artwork and nothing
     else, so it was invisible on his brow. Two screenshots with the shade
     display:none'd and shown were pixel-identical. Without it the cap still
     paints over the face -- it is the last positioned child of the clone, and
     they are all z-index:auto, so DOM order decides -- and the shade now reaches
     the skin. */
  background-repeat:no-repeat;
  background-size:100% 100%;
  pointer-events:none;
  /* He tumbles, and the cap tumbles with him: it is a descendant of the head
     root, so it inherits the root's own transform and needs no maths of its own.
     Box size is written by league-hat.js in percentages of his mirrored face
     box, so one write covers every head size and every viewport. */
}
/* The brow shade -- the whole of "keeping in mind realistic shadow", and the only
   part of this that is not the picture of a hat.
   It starts at 87% of the cap's own height, which is just inside the peak's front
   edge at 88.1%, so the band is tucked under the brim rather than starting below
   it with a gap. It is inset 19% from the cap's sides because the PEAK IS WIDER
   THAN THE FACE IT SHADES: at full width it would have run past his temples and
   multiplied the pitch. Proven by painting it solid black and looking -- the band
   stays inside his silhouette on every side.
   Multiplied rather than painted, so it darkens his skin instead of greying it,
   and its ink is gone by 78% of its own height, which lands just above his eyes:
   his brows read shaded, his eyes stay open. */
.lgRefHatShade{
  position:absolute;left:19%;right:19%;top:87%;height:24%;
  display:block;pointer-events:none;
  border-radius:50% 50% 42% 42% / 70% 70% 30% 30%;
  background-image:linear-gradient(180deg,rgba(18,14,8,.42),rgba(18,14,8,.17) 40%,rgba(18,14,8,0) 78%);
  mix-blend-mode:multiply;
}

/* ── THE PHONE BAR, AFTER THE MUTE BUTTON JOINED IT.  2026-08-29 ───────────
   The earlier phone pass fitted three groups into 390px and then the sound
   control arrived and took 44 of them back. The measurement still passed --
   nothing was off-SCREEN -- and the render showed the wordmark sitting on top
   of a captain's face and a long name running underneath "QUARTER-FINAL".

   That is because the centre group is absolutely CENTRED, not a flex sibling:
   it does not push the groups either side of it, it slides under them. So an
   overflow check on the viewport can never see this, and only the picture can.
   Counting is not looking, again, in the same session.

   Everything shrinks one more step, and the round label is the piece that
   gives most: it is the least load-bearing thing in the bar (the bracket screen
   states the round in full a moment earlier) and it is the widest. */
@media (max-width:640px){
  body.hmYowHdr .hmHdrMatch .sbFace{width:18px;height:18px;min-width:18px}
  body.hmYowHdr .hmHdrMatch .sbNm{font-size:9px;max-width:40px}
  body.hmYowHdr .hmHdrMatch .bcCell{font-size:17px}
  body.hmYowHdr .hmHdrMatch .sbInner{gap:var(--sp-2)}
  body.hmYowHdr .hmHdrMatch .sbTeam{gap:var(--sp-2)}
  /* The centre group is absolutely centred, so it does not push this one -- it
     grows toward it. After the shrink the second captain's face landed 4px off
     the "Q", which reads as touching. The separation has to come from THIS
     side, because the side that is growing cannot give it. */
  body.hmYowHdr .hmHdrRound{font-size:8px;max-width:52px;line-height:1.1;
    padding-left:var(--sp-8)}
  body.hmYowHdr .hmHdrEnd{padding-inline:var(--sp-6)}
  body.hmYowHdr .jbGrpL .jbHome svg{transform:scale(1.12)}
}
