:root{
  color-scheme:dark;
  --dur-in:340ms;--dur-out:180ms;--stagger:60ms;
  --ease-in:cubic-bezier(.16,1,.3,1);
  --ease-pop:cubic-bezier(.34,1.56,.64,1);
  --ease-out:cubic-bezier(.7,0,.3,1);
  --ease-slam:cubic-bezier(.12,.9,.2,1.02);
  --skew:-9deg;
  --font-display:'Big Shoulders Display',sans-serif;  /* branded display type — config-overridable */
}

/* ===================== CHROME ===================== */
*{box-sizing:border-box}
html,body{height:100%}
body{margin:0;background:#05070A;color:#E6EBF1;font-family:'Saira',system-ui,sans-serif;
  -webkit-font-smoothing:antialiased;overflow:hidden}

/* The app is a real in-flow box. Everything else positions inside it, so the
   document always has an intrinsic height — required by any host that sizes
   its frame to content (artifact viewers, embeds, CMS previews). */
.app{position:relative;width:100%;height:100dvh;min-height:560px;overflow:hidden;background:#05070A}
.app:fullscreen{height:100vh;min-height:0}
/* HUD floats over the picture — no chrome bar stealing height */
.hud{position:absolute;top:14px;left:16px;z-index:900;display:flex;align-items:center;gap:10px;
  pointer-events:none;text-shadow:0 2px 8px rgba(0,0,0,.8)}
.tally{font-family:'JetBrains Mono',monospace;font-size:10px;font-weight:700;letter-spacing:.16em;
  padding:4px 8px;border-radius:2px;background:#FF3B2F;color:#0B0D11}
.panel-head h1{font-family:var(--font-display);font-weight:900;font-size:15px;
  letter-spacing:.06em;text-transform:uppercase;margin:0;flex:1}
.combo{font-family:'JetBrains Mono',monospace;font-size:10px;color:#FFB020;letter-spacing:.1em;white-space:nowrap}
.tc{font-family:'JetBrains Mono',monospace;font-size:12px;color:#7C8896;font-variant-numeric:tabular-nums}

/* ===== FULL-BLEED STAGE ===== */
.stage{position:absolute;inset:0;width:100%;height:100%;overflow:hidden;
  background:var(--stage-bg,radial-gradient(120% 90% at 50% 15%,#1A2130 0%,#0A0D13 62%,#05070A 100%));
  container-type:size}
.pixelgrid{position:absolute;inset:0;pointer-events:none;opacity:.3;z-index:20;
  background:repeating-linear-gradient(0deg,rgba(255,255,255,.05) 0 1px,transparent 1px 4px),
             repeating-linear-gradient(90deg,rgba(255,255,255,.05) 0 1px,transparent 1px 4px)}
.safe{position:absolute;inset:5%;border:1px dashed rgba(255,59,47,.5);pointer-events:none;display:none;z-index:21}
.safe::after{content:'TITLE SAFE';position:absolute;top:4px;left:6px;font-family:'JetBrains Mono',monospace;
  font-size:9px;color:rgba(255,59,47,.7);letter-spacing:.12em}
.stage[data-safe="on"] .safe{display:block}
.shake{position:absolute;inset:0;z-index:2}

/* Optional full-bleed stage background image (config: bgImage). Sits under the
   dark gradient's content but over the base — cover-fit, dimmed slightly. */
.stage-bg{position:absolute;inset:0;z-index:0;background-size:cover;background-position:center;
  background-repeat:no-repeat;display:none}
.stage[data-bg] .stage-bg{display:block}
.stage[data-bg]{background:#05070A}   /* let the image show instead of the gradient */

.stage[data-brand="paris"]     {--b1:#0A2FFF;--b2:#4CE0FF;--ink:#FFFFFF}
.stage[data-brand="fiba"]      {--b1:#F25C05;--b2:#FFD400;--ink:#14100A}
.stage[data-brand="handball"]  {--b1:#D6002B;--b2:#FF7A93;--ink:#FFFFFF}
.stage[data-brand="alouettes"] {--b1:#00263E;--b2:#E4002B;--ink:#FFFFFF}
/* --plate/--panel: card & panel fills · --field: impact flood.
   All default to the brand accent so presets keep their look, and switch to the
   background-colour family when the Styles section themes them (see mapStyles). */
.stage{--plate:#0C1017;--plate-2:#161C26;--field:var(--b1);--panel:var(--b1)}

/* Sponsor / client logo — persistent corner bug, config-driven (url + corner). */
.brand-logo{position:absolute;z-index:22;height:9cqh;max-width:34cqw;object-fit:contain;
  pointer-events:none;display:none;filter:drop-shadow(0 .3cqh 1cqh rgba(0,0,0,.55))}
.stage[data-logo] .brand-logo{display:block}
.stage[data-logo="tl"] .brand-logo{top:4cqh;left:4cqw}
.stage[data-logo="tr"] .brand-logo{top:4cqh;right:4cqw}
.stage[data-logo="bl"] .brand-logo{bottom:4cqh;left:4cqw}
.stage[data-logo="br"] .brand-logo{bottom:4cqh;right:4cqw}
.stage[data-logo="tc"] .brand-logo{top:4cqh;left:50%;transform:translateX(-50%)}
.stage[data-logo="bc"] .brand-logo{bottom:4cqh;left:50%;transform:translateX(-50%)}

/* ===================== LOGO OPENER ===================== */
/* Centered reveal above the impact burst backdrops. z-index over .impact (2). */
.gfx.opener{position:absolute;inset:0;display:grid;place-items:center;z-index:20;pointer-events:none}
.op-stack{display:flex;flex-direction:column;align-items:center;gap:2.6cqh}
.op-logo{width:min(50cqw,50cqh);height:min(50cqw,50cqh);display:grid;place-items:center;
  filter:drop-shadow(0 1cqh 3cqh rgba(0,0,0,.5))}
/* Subtle broadcast tagline under the logo — themed by --font-display / --ink. */
.op-tag{font-family:var(--font-display);font-weight:700;font-size:3cqh;letter-spacing:.34em;
  padding-left:.34em;text-transform:uppercase;color:var(--secondary-color);opacity:.8;white-space:nowrap;text-align:center;
  position:relative}
.op-tag:empty{display:none}
.op-tag::before{content:"";position:absolute;top:-1.4cqh;left:50%;transform:translateX(-50%);
  width:7cqh;height:2px;background:var(--b2);opacity:.85;border-radius:2px}
.op-logo svg,.op-logo img{width:100%;height:100%;object-fit:contain;display:block;overflow:visible}
.op-logo svg *{vector-effect:non-scaling-stroke}
.op-ph{font-family:var(--font-display);font-weight:900;font-size:5cqh;color:#4a5666;
  text-transform:uppercase;letter-spacing:.1em;text-align:center;line-height:1.2}
/* Lens flare that sweeps across as the fill lands. */
.op-flare{position:absolute;top:50%;left:50%;width:70cqw;height:70cqw;transform:translate(-50%,-50%);
  border-radius:50%;opacity:0;pointer-events:none;mix-blend-mode:screen;
  background:radial-gradient(closest-side,rgba(255,255,255,.9),rgba(255,255,255,.25) 30%,transparent 62%)}

/* ===================== SHARED ===================== */
.gfx{position:absolute;opacity:0;will-change:transform,opacity,clip-path;z-index:3}
.plate{position:relative;background:var(--plate);overflow:hidden}
.plate::before{content:'';position:absolute;left:0;top:0;bottom:0;width:3.2cqw;
  background:linear-gradient(180deg,var(--b1),var(--b2));transform:skewX(var(--skew));transform-origin:bottom left}
.shine{position:absolute;inset:-20% -40%;pointer-events:none;mix-blend-mode:screen;
  background:linear-gradient(100deg,transparent 42%,rgba(255,255,255,.5) 50%,transparent 58%);
  transform:translateX(-140%) skewX(-16deg)}
.dsp{font-family:var(--font-display);font-weight:900;text-transform:uppercase;line-height:.86}
.ital{display:inline-block;transform:skewX(var(--skew))}
.num{font-variant-numeric:tabular-nums lining-nums}

/* ===================== LOWER THIRDS ===================== */
.scorebug{top:4cqh;left:4cqw}
.sb-plate{display:flex;align-items:stretch;height:8.4cqw;box-shadow:0 1cqw 3cqw rgba(0,0,0,.6)}
.sb-team{display:flex;align-items:center;gap:1.4cqw;padding:0 1.6cqw 0 4.4cqw}
.sb-team+.sb-team{padding-left:1.8cqw;background:var(--plate-2)}
.sb-code{font-family:var(--font-display);font-weight:700;font-size:3.4cqw;color:#C7D1DC}
.sb-score{font-family:var(--font-display);font-weight:900;font-size:5.2cqw;color:#fff;font-variant-numeric:tabular-nums}
/* score numbers are written as textContent by countUp() — CSS counter() can't
   display an animated @property value (renders 0) */
.sb-clock{display:flex;flex-direction:column;justify-content:center;padding:0 1.8cqw;
  background:linear-gradient(180deg,var(--panel),color-mix(in srgb,var(--panel) 70%,#000));color:var(--secondary-color);min-width:11cqw}
.sb-per{font-family:'JetBrains Mono',monospace;font-size:1.15cqw;letter-spacing:.2em;opacity:.85}
.sb-time{font-family:var(--font-display);font-weight:700;font-size:3.2cqw;font-variant-numeric:tabular-nums}
.sb-bonus{margin-top:.7cqw;display:inline-block;padding:.35cqw 1cqw;background:var(--b2);color:#0A0D13;
  font-family:'JetBrains Mono',monospace;font-size:1.1cqw;font-weight:700;letter-spacing:.18em}

.lower{left:6cqw;bottom:9cqh;display:flex;align-items:flex-end;gap:1.6cqw}
.lt-num{width:11cqw;height:11cqw;display:grid;place-items:center;position:relative;overflow:hidden;
  background:linear-gradient(150deg,var(--panel),color-mix(in srgb,var(--panel) 55%,#000));color:var(--secondary-color)}
.lt-num span{font-family:var(--font-display);font-weight:900;font-size:6.6cqw}
.lt-name{font-size:7.2cqw;color:#fff;text-shadow:0 .4cqw 2cqw rgba(0,0,0,.7)}
.lt-name .w{display:inline-block;overflow:hidden;vertical-align:bottom}
.lt-name .w i{display:inline-block;font-style:normal}
.lt-rule{display:block;width:34cqw;height:.5cqw;margin:.9cqw 0 .8cqw}
.lt-rule .s0{stop-color:var(--b1)} .lt-rule .s1{stop-color:var(--b2)}
.lt-meta{display:flex;align-items:center;gap:1.2cqw;font-family:'JetBrains Mono',monospace;
  font-size:1.35cqw;letter-spacing:.22em;color:#AFBCC9}
.lt-meta b{color:var(--b2);font-weight:700}

.stats{right:5cqw;top:16cqh;width:31cqw}
.st-head{background:linear-gradient(100deg,var(--panel),color-mix(in srgb,var(--panel) 60%,#000));
  color:var(--secondary-color);padding:1.3cqw 1.8cqw;position:relative;overflow:hidden}
.st-head h2{margin:0;font-size:3.4cqw}
.st-head p{margin:.2cqw 0 0;font-family:'JetBrains Mono',monospace;font-size:1.1cqw;letter-spacing:.2em;opacity:.8}
.st-body{background:rgba(12,16,23,.94);padding:1.6cqw 1.8cqw 1.9cqw;transform-origin:top center}
.st-row{margin-bottom:1.5cqw} .st-row:last-child{margin-bottom:0}
.st-top{display:flex;align-items:baseline;justify-content:space-between;margin-bottom:.6cqw}
.st-label{font-family:'JetBrains Mono',monospace;font-size:1.15cqw;letter-spacing:.18em;color:#8D9AA8}
.st-val{font-family:var(--font-display);font-weight:900;font-size:3.6cqw;color:#fff;font-variant-numeric:tabular-nums}
/* stat values likewise set via countUp() (JS) */
.st-track{height:.7cqw;background:#1B222C;overflow:hidden}
.st-fill{height:100%;transform-origin:left center;transform:scaleX(0);background:linear-gradient(90deg,var(--b1),var(--b2))}

/* ===================== PLAYER CARD ===================== */
.player{inset:0;display:grid;place-items:center}
.pl-card{width:90cqw;height:82cqh;display:grid;grid-template-columns:42% 58%;overflow:hidden;
  border-radius:.5cqw;box-shadow:0 2cqh 7cqh rgba(0,0,0,.6)}
/* isolate: the grade overlay blends against the portrait only, never the card. */
.pl-photo{position:relative;overflow:hidden;isolation:isolate;display:grid;place-items:center;
  background:linear-gradient(160deg,color-mix(in srgb,var(--panel) 30%,#000) 0%,#0b0805 100%)}
.pl-img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0}
.player[data-photo] .pl-img{opacity:1}
.pl-ph{position:relative;color:#fff;opacity:.8;text-align:center;line-height:1;font-size:3.6cqw;
  text-transform:uppercase;letter-spacing:.02em}
.player[data-photo] .pl-ph{display:none}

/* ---- photo grade -------------------------------------------------------
   One look per event (back office → Player card → Photo effect). The overlay
   is a real element so it blends against the portrait only, and every grade
   scales with --fx-a (Photo intensity, 0-1) — 0 leaves the raw photo.
   The push-in and light sweep are animated from JS so they scrub. ---- */
.pl-fx{position:absolute;inset:0;pointer-events:none;display:none;z-index:2}
/* Show the grade overlay whenever an effect is set — even on the placeholder —
   so the operator can preview the look before dropping in a photo. */
.player[data-fx]:not([data-fx="none"]) .pl-fx{display:block}
.pl-photo .shine{z-index:3}

/* Brand duotone — the house look: mono portrait re-tinted primary → accent. */
.player[data-fx="duotone"][data-photo] .pl-img{filter:grayscale(var(--fx-a,1)) contrast(1.18) brightness(.94)}
.player[data-fx="duotone"] .pl-fx{background:linear-gradient(150deg,var(--b1) 0%,var(--b2) 100%);
  mix-blend-mode:color;opacity:calc(.92 * var(--fx-a,1))}

/* Spotlight — burns the edges down so the face carries the frame. */
.player[data-fx="spotlight"][data-photo] .pl-img{filter:contrast(1.08) saturate(1.06)}
.player[data-fx="spotlight"] .pl-fx{opacity:var(--fx-a,1);
  background:radial-gradient(56% 50% at 50% 38%,rgba(5,7,10,0) 0%,rgba(5,7,10,.45) 62%,rgba(5,7,10,.92) 100%)}

/* Halftone — print-style dot screen, reads well on a big LED wall. */
.player[data-fx="halftone"][data-photo] .pl-img{filter:grayscale(calc(.75 * var(--fx-a,1))) contrast(1.22)}
.player[data-fx="halftone"] .pl-fx{mix-blend-mode:overlay;opacity:calc(.6 * var(--fx-a,1));
  background:radial-gradient(circle at 50% 50%,rgba(0,0,0,.85) 34%,rgba(0,0,0,0) 36%);
  background-size:1.1cqw 1.1cqw}

/* Broadcast scanlines — CRT feed, with an accent wash off the top. */
.player[data-fx="scan"] .pl-fx{mix-blend-mode:multiply;opacity:calc(.85 * var(--fx-a,1));
  background:repeating-linear-gradient(0deg,rgba(0,0,0,.55) 0 .35cqh,rgba(0,0,0,0) .35cqh .8cqh),
             linear-gradient(180deg,color-mix(in srgb,var(--b2) 30%,transparent),transparent 42%)}

/* Film grain — warms the plate and breaks up flat jersey colour. */
.player[data-fx="grain"][data-photo] .pl-img{filter:contrast(1.1) saturate(.92) sepia(calc(.18 * var(--fx-a,1)))}
.player[data-fx="grain"] .pl-fx{mix-blend-mode:overlay;opacity:calc(.75 * var(--fx-a,1));
  background:repeating-linear-gradient(37deg,rgba(255,255,255,.16) 0 1px,rgba(0,0,0,.14) 1px 2px),
             repeating-linear-gradient(-53deg,rgba(255,255,255,.10) 0 1px,rgba(0,0,0,.10) 1px 3px)}

/* Frosted edge — sharp on the face, blurred towards the card border. */
.player[data-fx="frost"] .pl-fx{opacity:var(--fx-a,1);
  backdrop-filter:blur(.8cqw) saturate(1.08);-webkit-backdrop-filter:blur(.8cqw) saturate(1.08);
  -webkit-mask-image:radial-gradient(72% 66% at 50% 42%,transparent 45%,#000 100%);
          mask-image:radial-gradient(72% 66% at 50% 42%,transparent 45%,#000 100%)}
/* ---- photo shape (frame mask) — back office → Player card → Frame shape.
   circle/rounded/ring use border-radius (no clash with clip-path reveals);
   hexagon/angled use clip-path (a clip reveal clears its inline path on
   finish, so the CSS shape re-asserts). ------------------------------------ */
.pl-photo[data-shape="circle"]{border-radius:50%}
.pl-photo[data-shape="rounded"]{border-radius:2.4cqw}
.pl-photo[data-shape="ring"]{border-radius:50%}
.pl-photo[data-shape="ring"]::before{content:'';position:absolute;inset:0;z-index:4;pointer-events:none;
  border-radius:50%;border:.5cqw solid var(--b2);box-shadow:0 0 2cqh rgba(0,0,0,.45) inset}
.pl-photo[data-shape="hexagon"]{clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%)}
.pl-photo[data-shape="angled"]{clip-path:polygon(0 0,100% 0,88% 100%,0 100%)}
/* ---- sheen idle: a gloss highlight sweeping across the portrait on a loop. */
.pl-photo[data-idle="sheen"]::after{content:'';position:absolute;inset:-20% -40%;z-index:3;pointer-events:none;
  background:linear-gradient(105deg,transparent 42%,rgba(255,255,255,.34) 50%,transparent 58%);
  transform:translateX(-120%);animation:plSheen 3.6s ease-in-out infinite}
@keyframes plSheen{0%,15%{transform:translateX(-120%)}55%,100%{transform:translateX(120%)}}
.pl-info{position:relative;overflow:hidden;background:var(--panel);color:var(--secondary-color);
  padding:4.5cqh 3.6cqw;display:flex;flex-direction:column}
.pl-kicker{font-family:'JetBrains Mono',monospace;font-size:1.35cqw;letter-spacing:.32em;
  text-transform:uppercase;opacity:.85;margin-bottom:1.2cqh}
.pl-name{font-size:5.8cqw;line-height:.86;font-weight:900;text-transform:uppercase}
.pl-name .w{display:inline-block;overflow:hidden;vertical-align:bottom}
.pl-name .w i{display:inline-block;font-style:normal}
.pl-pos{font-family:'JetBrains Mono',monospace;font-size:1.7cqw;letter-spacing:.22em;
  text-transform:uppercase;opacity:.9;margin-top:.9cqh}
.pl-num{flex:1;display:grid;place-items:center;font-size:44cqh;line-height:.8;font-weight:900;
  font-variant-numeric:tabular-nums;opacity:.98}
.pl-team{display:flex;align-items:center;gap:1.6cqw;min-height:6cqh}
.pl-logo{height:6cqh;width:auto;max-width:14cqw;object-fit:contain;display:none}
.pl-teamname{font-size:2.6cqw;font-weight:900;letter-spacing:.04em;text-transform:uppercase}

/* ============================================================
   MATCHUP - two players head to head ("baller battle").

   The data used to live in the same grid columns as the portraits, so every
   value was written across a face. The cost of that was visible in the CSS:
   a text-shadow on every number and a full-frame radial darkener whose only
   job was making the middle legible. Both are gone. The middle third is now a
   column that OWNS the data; the portraits flank it and are never written on,
   and each stat row carries a split bar - the magnitude the old graphic never
   showed, when colour alone said who but never by how much.
   ============================================================ */
.matchup{inset:0}
/* Brand wedges: a diagonal colour field per side, low enough to read as depth
   rather than a panel. They are what the portraits stand on, so the two halves
   of the frame belong to opposing teams before a single stat is read. */
.mu-wedge{position:absolute;top:0;bottom:0;width:46cqw;z-index:0;opacity:0;
  clip-path:polygon(0 0,100% 0,82% 100%,0 100%)}
.mu-wedge[data-side="a"]{left:0;
  background:linear-gradient(100deg,color-mix(in srgb,var(--b1) 46%,transparent) 0%,transparent 82%)}
.mu-wedge[data-side="b"]{right:0;transform:scaleX(-1);
  background:linear-gradient(100deg,color-mix(in srgb,var(--b2) 46%,transparent) 0%,transparent 82%)}
/* The title sits at the head of the DATA column, where the team row used to be.
   Teams belong to the players now, and moving the title down frees the whole top
   band of the frame for the session's header logo - which had nowhere to go. */
.mu-title{position:relative;text-align:center;font-size:2.6cqw;color:var(--main,#fff);
  margin-bottom:2.2cqh;flex:none;
  /* One line, always. Wrapping to two pushed the column up into the band the
     header logo sits in — the title taking the logo's room is the opposite of
     what moving it down here was for. It may run a little wider than the
     scrim; the frame either side of the column is empty. */
  white-space:nowrap}
.mu-title .ch{display:inline-block;white-space:pre}
/* Short accent tick above the title - the only chrome the header gets. A real
   element, not a pseudo, so it scrubs on the master clock like everything else. */
.mu-tick{position:absolute;top:-1.6cqh;left:50%;margin-left:-4.5cqw;
  width:9cqw;height:.3cqw;background:linear-gradient(90deg,var(--b1),var(--b2));transform-origin:center}
/* Top band: the header logo, with room to be a real logo rather than a strip. */
.mu-logo{position:absolute;top:3cqh;left:50%;transform:translateX(-50%);z-index:5;
  height:9cqh;max-width:30cqw;object-fit:contain;display:none}
.matchup[data-logo] .mu-logo{display:block}
/* Portraits: cut-out PNGs, bottom-anchored, bleeding off the lower edge the way
   the broadcast key art does. Narrower than before - they flank the data now
   rather than sitting under it. */
.mu-photo{position:absolute;bottom:0;height:88cqh;width:29cqw;z-index:1;
  display:grid;place-items:end center}
.mu-photo[data-side="a"]{left:1.5cqw}
.mu-photo[data-side="b"]{right:1.5cqw}
/* Oversized outlined jersey number behind the portrait. A SIBLING of the photo,
   not a child: inside a box with overflow:hidden it was cropped to the photo
   slot, which is the one thing this device must not be. */
.mu-ghost{position:absolute;bottom:30cqh;z-index:0;font-size:26cqh;line-height:.8;opacity:0;
  color:transparent;-webkit-text-stroke:.22cqw color-mix(in srgb,var(--main,#fff) 28%,transparent);letter-spacing:-.02em}
.mu-ghost[data-side="a"]{left:-1cqw}
.mu-ghost[data-side="b"]{right:-1cqw}
.mu-img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;opacity:0;z-index:1;
  filter:drop-shadow(0 1.2cqh 2.6cqh rgba(0,0,0,.55))}
.mu-photo[data-side="a"] .mu-img{object-position:bottom left}
.mu-photo[data-side="b"] .mu-img{object-position:bottom right}
.mu-photo[data-photo] .mu-img{opacity:1}
.mu-ph{position:relative;margin-bottom:24cqh;color:var(--main,#fff);opacity:.35;font-size:2.2cqw;
  text-transform:uppercase;letter-spacing:.02em}
.mu-photo[data-photo] .mu-ph{display:none}

/* Nameplates: under the portrait, on the wedge. They used to float over the
   chest, which is why they needed a shadow to survive the picture. */
.mu-id{position:absolute;bottom:3.2cqh;z-index:4;width:27cqw}
.mu-id[data-side="a"]{left:1.5cqw;text-align:left}
.mu-id[data-side="b"]{right:1.5cqw;text-align:right}
.mu-nm{display:flex;align-items:center;gap:.7cqw;font-size:1.75cqw;line-height:1}
.mu-id[data-side="b"] .mu-nm{justify-content:flex-end}
.mu-flag{font-size:1.6cqw;line-height:1}
.mu-first{color:var(--main,#fff);font-weight:900;text-transform:uppercase;opacity:.92}
/* Team on its own line under the player's numbers, in that side's own accent.
   A real 3x3 club is "Amsterdam RABOBANK", not a word — beside the first name
   it crowded the plate, and under the age it has the full width to itself.
   Two lines maximum: past that a name is a paragraph, and the plate has a
   portrait standing on it. */
.mu-team{font-family:var(--font-display);font-weight:900;text-transform:uppercase;
  font-size:1.7cqw;line-height:1.05;letter-spacing:.01em;margin-top:.7cqh;
  position:relative;padding-left:.9cqw;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.mu-team:empty{display:none}
.mu-team::before{content:'';position:absolute;left:0;top:.12em;bottom:.12em;width:.22cqw;opacity:.85}
.mu-id[data-side="a"] .mu-team{color:var(--b1)}
.mu-id[data-side="a"] .mu-team::before{background:var(--b1)}
/* Side B reads right to left, so its tick sits on the other edge. */
.mu-id[data-side="b"] .mu-team{color:var(--b2);padding-left:0;padding-right:.9cqw}
.mu-id[data-side="b"] .mu-team::before{background:var(--b2);left:auto;right:0}
.mu-last{font-size:3.4cqw;line-height:.94;color:var(--main,#fff);text-transform:uppercase}
.mu-id[data-len="l"] .mu-last{font-size:2.9cqw}
.mu-id[data-len="xl"] .mu-last{font-size:2.4cqw}
.mu-last .w{display:inline-block;overflow:hidden;vertical-align:bottom}
.mu-last .w i{display:inline-block;font-style:normal}
.mu-meta{font-family:'JetBrains Mono',monospace;font-size:1.05cqw;color:var(--main,#fff);
  letter-spacing:.1em;opacity:.66;margin-top:.4cqh}
/* The rule takes its own side's colour: the plate says whose half it is before
   the name is read. */
.mu-rule{height:.34cqw;margin-top:.7cqh;width:64%;opacity:.95}
.mu-id[data-side="a"] .mu-rule{background:var(--b1);transform-origin:left center}
.mu-id[data-side="b"] .mu-rule{background:var(--b2);margin-left:auto;transform-origin:right center}

/* The data column: 40cqw of the middle, on its own scrim, feathered at both
   edges so it sits IN the frame rather than on top of it. */
.mu-col{position:absolute;top:0;bottom:0;left:50%;transform:translateX(-50%);width:40cqw;z-index:3;
  display:flex;flex-direction:column;justify-content:center;padding:6cqh 1.6cqw 3cqh;pointer-events:none;
  background:linear-gradient(90deg,transparent,rgba(4,6,10,.80) 14%,rgba(4,6,10,.86) 86%,transparent)}
.matchup[data-logo] .mu-col{padding-top:15cqh}
.mu-rows{display:flex;flex-direction:column;gap:2.35cqh;flex:0 1 auto}
.mu-row{display:flex;flex-direction:column;gap:.75cqh}
.mu-row[hidden]{display:none}
/* Value, label, value on ONE line. They used to sit in outer-aligned columns
   two-fifths of the wall apart, with a player between a number and its name. */
.mu-line{display:grid;grid-template-columns:1fr auto 1fr;align-items:baseline;column-gap:1.2cqw}
.mu-va,.mu-vb{font-family:var(--font-display);font-weight:900;font-size:3.5cqw;line-height:1;
  color:var(--main,#fff);font-variant-numeric:tabular-nums;text-transform:uppercase;white-space:nowrap}
.mu-va{text-align:right}
.mu-vb{text-align:left}
.mu-lb{font-family:'JetBrains Mono',monospace;font-size:1.15cqw;font-weight:600;letter-spacing:.16em;
  text-transform:uppercase;color:var(--main,#fff);opacity:.72;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;max-width:16cqw}
/* Leader of a numeric row: the accent picks the winning side out at distance.
   Ties and text rows (TEAM NAME) carry no mark. */
.mu-va.win,.mu-vb.win{color:var(--b2)}
/* A chevron on the leader's own side, pointing outward at the player who owns
   the number - colour alone is not enough on a washed-out LED wall. */
.mu-va.win::after,.mu-vb.win::before{display:inline-block;opacity:.9;font-size:.55em;
  vertical-align:.22em;color:var(--b2)}
.mu-va.win::after{content:'\25C0';margin-left:.35em}
.mu-vb.win::before{content:'\25B6';margin-right:.35em}
/* The split bar: one track, two shares meeting at a moving midpoint, each in
   its own side's colour. This is the magnitude - 28-19 and 28-27 used to look
   identical because colour said WHO and nothing said BY HOW MUCH. */
.mu-bar{display:flex;height:.62cqh;border-radius:.4cqh;overflow:hidden;
  background:rgba(255,255,255,.10)}
.mu-bar b{display:block;height:100%;width:0}
.mu-bar .sa{background:var(--b1)}
.mu-bar .sb{background:var(--b2)}
/* A row that cannot be compared (TEAM NAME, a tie of two words) keeps its
   height so the column does not reflow, and shows no bar. */
.mu-row[data-nobar] .mu-bar{visibility:hidden}

/* ============================================================
   COUNTDOWN - a clock ticking down to the next moment (tip-off,
   doors, halftime show, a sponsor draw). One centred plate: kicker,
   headline, the digits, a sub line and an elapsed bar. The hours
   group is dropped below an hour (data-h), and the whole plate
   switches to an urgent read inside the last ten seconds.
   ============================================================ */
.countdown{inset:0;display:grid;place-items:center;z-index:5}
.cd-plate{min-width:56cqw;max-width:86cqw;padding:5cqh 6cqw 4cqh;text-align:center;
  box-shadow:0 2cqh 6cqh rgba(0,0,0,.5)}
.cd-kicker{font-family:'JetBrains Mono',monospace;font-size:1.5cqw;letter-spacing:.34em;
  text-transform:uppercase;color:var(--secondary-color);opacity:.8}
.cd-kicker:empty{display:none}
.cd-title{font-size:4.2cqw;color:var(--main,#fff);margin-top:1.2cqh}
.cd-title:empty{display:none}
/* Digits: one grid per unit so the colons never shift as values change. */
.cd-clock{display:flex;align-items:flex-start;justify-content:center;gap:1.6cqw;margin-top:2.4cqh}
.cd-grp{display:flex;flex-direction:column;align-items:center;gap:.8cqh}
.cd-num{font-size:20cqh;line-height:.8;color:var(--main,#fff);
  text-shadow:0 .4cqw 2cqw rgba(0,0,0,.55)}
.cd-unit{font-family:'JetBrains Mono',monospace;font-size:1.2cqw;letter-spacing:.3em;
  text-transform:uppercase;color:var(--secondary-color);opacity:.7}
.cd-unit:empty{display:none}
.cd-colon{font-family:var(--font-display);font-weight:900;font-size:14cqh;line-height:1.05;
  color:var(--b2);font-style:normal}
/* How many numbers are on the wall follows the unit labels (data-slots): one
   label is one number, two is mm:ss, three is the full clock. And under an hour
   the full clock drops its hours group too - a wall reading "00 : 07 : 42" for
   a seven-minute break wastes the biggest digits it has. */
.countdown[data-slots="1"] .cd-grp[data-grp="h"],
.countdown[data-slots="1"] .cd-grp[data-grp="m"],
.countdown[data-slots="1"] .cd-colon{display:none}
.countdown[data-slots="2"] .cd-grp[data-grp="h"],
.countdown[data-slots="2"] .cd-colon[data-grp="h"]{display:none}
.countdown:not([data-h]) .cd-grp[data-grp="h"],
.countdown:not([data-h]) .cd-colon[data-grp="h"]{display:none}
/* A lone number carries the whole graphic, so it gets the room the three-group
   clock spends on colons and neighbours. */
.countdown[data-slots="1"] .cd-num{font-size:30cqh}
/* Last ten seconds: brand accent on the digits and a tightening frame. The
   colour change is the signal - it reads from the back of a stand where a
   size change does not. */
.countdown[data-urgent] .cd-num{color:var(--b2)}
.countdown[data-urgent] .cd-plate{box-shadow:0 0 0 .4cqw var(--b2),0 2cqh 6cqh rgba(0,0,0,.5)}
/* Zero: the digits step aside for the payoff word (LET'S GO / DOORS OPEN). */
.cd-zero{display:none;font-size:9cqw;color:var(--b2);line-height:.86;margin-top:1.6cqh}
.countdown[data-zero] .cd-clock{display:none}
.countdown[data-zero] .cd-zero{display:block}
.cd-sub{font-family:'JetBrains Mono',monospace;font-size:1.4cqw;letter-spacing:.24em;
  text-transform:uppercase;color:var(--secondary-color);opacity:.75;margin-top:2.4cqh}
.cd-sub:empty{display:none}
/* Elapsed bar - how far through the wait we are, without reading the number. */
.cd-bar{position:relative;height:.55cqh;margin-top:2.6cqh;background:rgba(255,255,255,.14);overflow:hidden}
.cd-fill{position:absolute;left:0;top:0;bottom:0;width:100%;transform:scaleX(0);transform-origin:left;
  background:linear-gradient(90deg,var(--b1),var(--b2))}

/* ============================================================
   IMPACT FRAME — every backdrop is its own element, so a
   toggle removes something you can actually see.
   ============================================================ */
.impact{position:absolute;inset:0;display:grid;place-items:center;opacity:0;z-index:4;overflow:hidden}
.bd{position:absolute;opacity:0;pointer-events:none}

.bd-field{inset:0;z-index:1;
  background:radial-gradient(70% 70% at 50% 50%,color-mix(in srgb,var(--field) 85%,#fff) 0%,var(--field) 38%,#05070A 100%)}
.bd-ticker{left:0;top:50%;translate:0 -50%;white-space:nowrap;z-index:2;
  font-family:var(--font-display);font-weight:900;font-size:27cqh;color:#fff;line-height:1}
.bd-rays{width:160cqh;height:160cqh;border-radius:50%;z-index:3;
  background:repeating-conic-gradient(from 0deg,transparent 0 2.4deg,rgba(255,255,255,.16) 2.4deg 3.3deg);
  -webkit-mask-image:radial-gradient(closest-side,transparent 20%,#000 44%,transparent 76%);
          mask-image:radial-gradient(closest-side,transparent 20%,#000 44%,transparent 76%)}
.bd-grid{inset:-30%;z-index:3;
  background:repeating-linear-gradient(0deg,transparent 0 3.4cqh,var(--b2) 3.4cqh calc(3.4cqh + 2px)),
             repeating-linear-gradient(90deg,transparent 0 3.4cqh,var(--b2) 3.4cqh calc(3.4cqh + 2px));
  -webkit-mask-image:radial-gradient(closest-side,#000 10%,transparent 62%);
          mask-image:radial-gradient(closest-side,#000 10%,transparent 62%)}
.bd-spot{inset:-40%;z-index:3;
  background:conic-gradient(from 0deg,transparent 0 62%,rgba(255,255,255,.30) 74%,transparent 86%)}
.bd-rings{inset:0;z-index:4;display:grid;place-items:center;opacity:1}
.bd-rings i{position:absolute;width:22cqh;height:22cqh;border-radius:50%;border:.55cqh solid var(--b2);opacity:0;transform:scale(.1)}
.bd-bars{inset:0;z-index:4;opacity:1}
.bd-bars i{position:absolute;left:-60%;width:220%;height:7cqh;opacity:0;transform:translateX(-120%) skewY(-4deg)}
.bd-bars i:nth-child(1){top:18%;background:var(--b1)}
.bd-bars i:nth-child(2){top:37%;background:var(--b2);height:3cqh}
.bd-bars i:nth-child(3){top:62%;background:#fff;height:2cqh}
.bd-bars i:nth-child(4){top:76%;background:var(--b1);height:5cqh}
.bd-glitch{inset:0;z-index:9;opacity:1;mix-blend-mode:overlay}
.bd-glitch i{position:absolute;left:0;width:100%;background:var(--b2);opacity:0}
.bd-glitch i:nth-child(1){top:22%;height:6cqh}
.bd-glitch i:nth-child(2){top:48%;height:3cqh}
.bd-glitch i:nth-child(3){top:71%;height:9cqh}
.bd-scan{inset:0;z-index:9;mix-blend-mode:overlay;
  background:repeating-linear-gradient(0deg,rgba(255,255,255,.16) 0 2px,transparent 2px 6px)}
.bd-vig{inset:0;z-index:9;background:radial-gradient(60% 60% at 50% 50%,transparent 30%,#000 100%)}
/* DOM confetti (not a <canvas>): an accelerated 2D canvas rasterises its
   backing store as opaque white on some GPU drivers, whiting out the whole
   stage. Positioned <i> elements have no backing store, so they're safe
   everywhere. Pieces burst from stage centre. */
.bd-particles{inset:0;z-index:8;opacity:1;overflow:hidden}
.bd-particles i{position:absolute;top:50%;left:50%;border-radius:1px;opacity:0}
.bd-fireworks,.bd-sparks,.bd-streamers,.bd-snow,.bd-glitter,.bd-beams{inset:0;z-index:8;opacity:1;overflow:hidden}
.bd-fireworks i{position:absolute;width:.8cqh;height:.8cqh;border-radius:50%;opacity:0}
.bd-sparks i{position:absolute;bottom:0;width:.7cqh;height:.7cqh;border-radius:50%;opacity:0}
.bd-streamers i{position:absolute;top:-8%;width:.5cqh;border-radius:2px;opacity:0}
.bd-snow i{position:absolute;top:-4%;border-radius:50%;background:#fff;opacity:0}
.bd-glitter i{position:absolute;width:.6cqh;height:.6cqh;border-radius:50%;opacity:0}
.bd-beams i{position:absolute;top:-20%;left:50%;width:16cqw;height:140%;opacity:0;mix-blend-mode:screen;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.4),transparent)}
.bd-flash{inset:0;z-index:12;background:#fff;mix-blend-mode:screen}
/* Screen pulse fired once per chant beat — an inward brand-colour vignette
   flash that frames the word without washing it out. */
.chant-pulse{position:absolute;inset:0;z-index:11;pointer-events:none;opacity:0;
  background:radial-gradient(circle at 50% 50%,transparent 30%,var(--b2) 108%)}
.chant-pulse[data-style="flash"]{background:radial-gradient(circle at 50% 50%,
  rgba(255,255,255,.95) 0%,rgba(255,255,255,.6) 52%,rgba(255,255,255,.18) 100%)}
/* Distinct beat pulses — each also gets its own motion in js (pulse kf). */
.chant-pulse[data-style="bars"]{background:linear-gradient(180deg,var(--b2) 0 14%,transparent 14% 86%,var(--b2) 86% 100%)}
.chant-pulse[data-style="sides"]{background:linear-gradient(90deg,var(--b2) 0 10%,transparent 10% 90%,var(--b2) 90% 100%)}
.chant-pulse[data-style="ring"]{background:radial-gradient(circle at 50% 50%,transparent 30%,var(--b2) 37% 45%,transparent 52%)}
.chant-pulse[data-style="scan"]{background:repeating-linear-gradient(0deg,var(--b2) 0 3px,transparent 3px 9px)}

/* the type */
.imp-word{position:relative;display:flex;z-index:6;line-height:.82;color:var(--main,#fff);white-space:pre;
  font-family:var(--font-display);font-weight:900;text-transform:uppercase}
.imp-word span{display:inline-block;transform-style:preserve-3d;
  filter:drop-shadow(0 .8cqh 2.4cqh rgba(0,0,0,.55))}
.imp-word .syl{display:inline-flex;filter:none}        /* syllable group (Chant beats these) */
.imp-word .syl-gap{filter:none;width:.34em}            /* gap between syllables */
/* Sliced-repeat engine: the word tiled vertically, each row offset horizontally
   so it reads as one word cut into sliding bands. */
.imp-slices{position:absolute;inset:0;z-index:6;display:flex;flex-direction:column;justify-content:center;
  align-items:center;overflow:hidden;pointer-events:none;opacity:0}
.imp-slices .sl-row{white-space:pre;font-family:var(--font-display);font-weight:900;text-transform:uppercase;
  color:var(--main,#fff);line-height:.66;margin:-.4cqh 0;will-change:transform;filter:drop-shadow(0 .3cqh 1.4cqh rgba(0,0,0,.5))}
.imp-ghost{position:absolute;z-index:5;opacity:0;color:var(--main,#fff);white-space:pre;
  font-family:var(--font-display);font-weight:900;text-transform:uppercase;line-height:.82}
.imp-sweep{position:absolute;z-index:7;inset:0;opacity:0;mix-blend-mode:overlay;pointer-events:none;
  background:linear-gradient(100deg,transparent 40%,rgba(255,255,255,.9) 50%,transparent 60%)}
.imp-sub{position:absolute;bottom:15cqh;z-index:10;display:flex;align-items:center;gap:1.4cqw;
  padding:.9cqh 2.4cqw;background:rgba(6,9,14,.86);opacity:0;border-left:.5cqw solid var(--b2)}
/* Scorer photo shown alongside the name when a call carries a picked player. */
.imp-sub-photo{display:none;width:calc(6cqh*var(--sub-scale,1));height:calc(6cqh*var(--sub-scale,1));
  border-radius:50%;object-fit:cover;background:#0c1017;margin-left:-1cqw}
.imp-sub-photo[src]{display:block}
.imp-sub b{font-family:var(--font-display);font-weight:900;font-size:calc(4cqh*var(--sub-scale,1));color:#fff}
.imp-sub em{font-style:normal;font-family:'JetBrains Mono',monospace;font-size:calc(1.5cqh*var(--sub-scale,1));letter-spacing:.22em;color:#9FB0C0}

/* ===================== CONSOLE ===================== */
/* ===== FLOATING CONSOLE PANEL ===== */
.panel{position:absolute;z-index:1000;top:14px;right:14px;width:min(430px,calc(100vw - 28px));
  background:rgba(10,13,18,.78);backdrop-filter:blur(20px) saturate(150%);
  -webkit-backdrop-filter:blur(20px) saturate(150%);
  border:1px solid rgba(255,255,255,.10);border-radius:10px;
  box-shadow:0 26px 80px rgba(0,0,0,.7),0 0 0 1px rgba(0,0,0,.4);
  display:flex;flex-direction:column;overflow:hidden}
.panel-head{display:flex;align-items:center;gap:8px;padding:9px 10px 9px 12px;cursor:grab;
  border-bottom:1px solid rgba(255,255,255,.08);user-select:none;touch-action:none}
.panel-head:active{cursor:grabbing}
.panel-head .ico{background:transparent;border:0;color:#7C8896;padding:4px 7px;font-size:13px;line-height:1}
.panel-head .ico:hover{color:#fff;background:rgba(255,255,255,.08)}
.panel-body{padding:11px 12px 13px;display:flex;flex-direction:column;gap:9px;
  max-height:min(70vh,720px);overflow-y:auto;overscroll-behavior:contain}
.panel[data-collapsed="true"] .panel-body{display:none}
.fab{position:absolute;z-index:1000;top:14px;right:14px;display:none;
  background:rgba(10,13,18,.85);backdrop-filter:blur(14px);border:1px solid rgba(255,255,255,.14)}
body[data-panel="hidden"] .panel{display:none}
/* The console is operator-only: keep the front clean (no ⚙ Console button).
   Press H to reveal the panel when debugging. */
body[data-panel="hidden"] .fab{display:none}
body[data-panel="hidden"] .hud{opacity:0}
/* One-time audio-unlock pill on the venue screen (?live=1). Small, bottom-left,
   dismissed on the first gesture — see the ?live branch in the JS. */
.snd-unlock{position:absolute;z-index:1001;left:14px;bottom:14px;padding:8px 14px;border-radius:999px;
  font:600 13px/1 system-ui,sans-serif;color:#fff;cursor:pointer;
  background:rgba(10,13,18,.82);backdrop-filter:blur(14px);border:1px solid rgba(255,255,255,.18)}
.snd-unlock[hidden]{display:none}
.grp{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.grp>.lbl{font-family:'JetBrains Mono',monospace;font-size:9px;letter-spacing:.16em;color:#66727F;width:66px;flex:none}
button{font-family:'Saira',sans-serif;font-weight:600;font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;
  background:#171D26;color:#C7D1DC;border:1px solid #2B3542;border-radius:2px;padding:7px 11px;cursor:pointer;
  transition:background .12s,border-color .12s,color .12s}
button:hover{background:#1E2531;border-color:#3B4757;color:#fff}
button[aria-pressed="true"]{background:#E6EBF1;color:#0B0D11;border-color:#E6EBF1}
button.hero{border-left:2px solid #FF3B2F}
button.roll{background:#FFB020;color:#0B0D11;border-color:#FFB020;font-weight:800}
button:focus-visible{outline:2px solid #FFB020;outline-offset:2px}
.tempo-out{font-family:'JetBrains Mono',monospace;font-size:10px;color:#8D9AA8;letter-spacing:.08em;
  min-width:52px;text-align:right;font-variant-numeric:tabular-nums;flex:none}
input[type=text]{flex:1;min-width:104px;font-family:'Saira',sans-serif;font-size:11px;font-weight:600;
  letter-spacing:.06em;background:#0F141B;color:#E6EBF1;border:1px solid #2B3542;border-radius:2px;padding:7px 9px}
input[type=text]:focus{outline:none;border-color:#FFB020;background:#12181F}
input[type=text]::placeholder{color:#5C6874;text-transform:uppercase;letter-spacing:.1em;font-weight:400}
input[type=range]{-webkit-appearance:none;appearance:none;flex:1;height:4px;background:#232B35;border-radius:2px;cursor:pointer}
input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:12px;height:20px;background:#FFB020;border-radius:1px}
input[type=range]::-moz-range-thumb{width:12px;height:20px;background:#FFB020;border:0;border-radius:1px}
.hint{font-family:'JetBrains Mono',monospace;font-size:10px;color:#5C6874;line-height:1.7;
  border-top:1px solid #1A212B;padding-top:9px;margin:0}
.hint b{color:#8D9AA8;font-weight:400}
@media (max-width:700px){
  .panel{left:8px;right:8px;top:auto;bottom:8px;width:auto}
  .panel-body{max-height:46vh}
  .grp>.lbl{width:100%}
  .hud{top:10px;left:12px}
}
@media (prefers-reduced-motion:reduce){.shine,.bd-rays,.bd-particles{display:none}}
