/* ===========================================================================
   /watch/<Name> DURING A MATCH: the board around the video.

   Drawn by js/player-channel/live-board.js. Three pieces:

     .pc-bug    the scoreboard across the top -- flags, names, Rating, rank and
                the two scores, the side at the table lit up in the app's green
     .pc-tray   the ball return under the video: the turn at the table, each
                ball rolling in as it is marked
     .pc-card   round by round, as a fixed grid of rounds by players

   BUILT FOR A MONITOR BESIDE THE TABLE. That is where this page is mostly
   watched -- full screen, from across a room, by people holding cues -- so the
   numbers are big, the colours mean one thing each, and nothing ever needs a
   scroll. In a browser window it is the same board, smaller.

   ONE UNIT. Every size here is a multiple of --u, so the television rules at
   the bottom only have to change what --u is (and where the stage stops) for
   the whole board to scale with the screen.

   THE COLOURS, AND WHAT THEY MEAN:
     green  #2eff73   at the table, live, points scored (the app's own green)
     amber  #ffb020   riding on the 11: pocketed, not yet worth anything
     gold   #ffd166   the bonuses -- a full sequence, the 11 on the break
     red    #ff5a5a   scratches, bad breaks, sudden death
   ========================================================================= */

.pc-live {
  --u: clamp(5px, 0.58vw, 8.5px);
  --pc-green: #2eff73;
  --pc-green-deep: #052b12;
  --pc-amber: #ffb020;
  --pc-gold: #ffd166;
  --pc-red: #ff5a5a;
  --pc-ink: #f4f7f6;
  --pc-ink-soft: rgba(244, 247, 246, 0.66);
  --pc-glass: rgba(10, 15, 22, 0.92);
  --pc-line: rgba(255, 255, 255, 0.09);
  --pc-display: "Barlow Condensed", "Josefin Sans", "Arial Narrow", sans-serif;
  --pc-gap: calc(var(--u) * 1.6);

  display: flex;
  flex-direction: column;
  gap: var(--pc-gap);
  color: var(--pc-ink);
}

.pc-live-main {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(calc(var(--u) * 46), 31%);
  gap: var(--pc-gap);
  align-items: stretch;
}

.pc-live-stage {
  display: flex;
  flex-direction: column;
  gap: var(--pc-gap);
  min-width: 0;
}

/* ===========================================================================
   The bug
   ========================================================================= */

.pc-bug {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: stretch;
  min-height: calc(var(--u) * 13);
  border-radius: calc(var(--u) * 2);
  overflow: hidden;
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0) 55%),
    linear-gradient(90deg, #0c131c 0%, #0a0f16 50%, #0c131c 100%);
  border: 1px solid var(--pc-line);
  box-shadow: 0 calc(var(--u) * 2) calc(var(--u) * 6) rgba(0, 0, 0, 0.45);
}

.pc-bug-side {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  grid-template-areas: "flag id score";
  align-items: center;
  column-gap: calc(var(--u) * 1.8);
  padding: calc(var(--u) * 1.4) calc(var(--u) * 2.4);
  min-width: 0;
  transition: opacity 400ms ease;
}

.pc-bug-side.is-right {
  grid-template-columns: auto minmax(0, 1fr) auto;
  grid-template-areas: "score id flag";
  text-align: right;
}

.pc-bug-flag { grid-area: flag; }
.pc-bug-id { grid-area: id; min-width: 0; }
.pc-bug-score { grid-area: score; }

/* The flag, presented: a real piece of the scoreboard, not an icon. */
.pc-bug-flag .flag-img {
  display: block;
  width: calc(var(--u) * 8);
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  margin: 0;
  border-radius: calc(var(--u) * 0.8);
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, 0.18),
    0 calc(var(--u) * 0.6) calc(var(--u) * 1.6) rgba(0, 0, 0, 0.5);
}

.pc-bug-name {
  font-family: var(--pc-display);
  font-size: calc(var(--u) * 4.6);
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  color: var(--pc-ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pc-bug-meta {
  display: flex;
  align-items: center;
  gap: calc(var(--u) * 1);
  margin-top: calc(var(--u) * 0.9);
  font-size: calc(var(--u) * 1.75);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--pc-ink-soft);
  white-space: nowrap;
}

.pc-bug-side.is-right .pc-bug-meta {
  justify-content: flex-end;
}

/* `display` beats the browser's own [hidden]; a missing rank must leave no pill. */
.pc-bug-meta [hidden] {
  display: none !important;
}

.pc-bug-rating b {
  font-family: var(--pc-display);
  font-size: calc(var(--u) * 2.5);
  font-weight: 700;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--pc-ink);
}

.pc-bug-rank {
  padding: calc(var(--u) * 0.25) calc(var(--u) * 0.9);
  border-radius: 999px;
  font-family: var(--pc-display);
  font-size: calc(var(--u) * 2.1);
  font-weight: 700;
  letter-spacing: 0.02em;
  color: #1c1405;
  background: linear-gradient(180deg, #ffe08a, #f2b630);
}

.pc-bug-up {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--u) * 0.7);
  padding: calc(var(--u) * 0.35) calc(var(--u) * 1.1);
  border-radius: 999px;
  font-size: calc(var(--u) * 1.55);
  font-weight: 800;
  color: var(--pc-green-deep);
  background: var(--pc-green);
}

.pc-bug-up-dot {
  width: calc(var(--u) * 0.9);
  height: calc(var(--u) * 0.9);
  border-radius: 50%;
  background: var(--pc-green-deep);
  animation: pc-board-blink 1.2s ease-in-out infinite;
}

.pc-bug-score {
  min-width: 1.4em;
  font-family: var(--pc-display);
  font-size: calc(var(--u) * 10.5);
  font-weight: 800;
  line-height: 0.9;
  text-align: center;
  font-variant-numeric: tabular-nums;
  color: #fff;
  text-shadow: 0 calc(var(--u) * 0.4) calc(var(--u) * 1.6) rgba(0, 0, 0, 0.55);
}

/* --- At the table --------------------------------------------------------- */

.pc-bug-glow {
  position: absolute;
  inset: 0;
  opacity: 0;
  pointer-events: none;
  transition: opacity 400ms ease;
}

.pc-bug-side.is-left .pc-bug-glow {
  background: linear-gradient(90deg, rgba(46, 255, 115, 0.2), rgba(46, 255, 115, 0.02) 75%);
}

.pc-bug-side.is-right .pc-bug-glow {
  background: linear-gradient(270deg, rgba(46, 255, 115, 0.2), rgba(46, 255, 115, 0.02) 75%);
}

/* The bar along the bottom of the side at the table. */
.pc-bug-glow::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: calc(var(--u) * 0.55);
  background: var(--pc-green);
  box-shadow: 0 0 calc(var(--u) * 2) rgba(46, 255, 115, 0.8);
}

.pc-bug-side.is-shooting .pc-bug-glow {
  opacity: 1;
}

.pc-bug-side.is-shooting .pc-bug-score {
  color: var(--pc-green);
  text-shadow: 0 0 calc(var(--u) * 3) rgba(46, 255, 115, 0.45);
}

/* The player waiting their turn is still on the board -- just not lit. */
.pc-bug-side.is-waiting {
  opacity: 0.78;
}

.pc-bug-side > :not(.pc-bug-glow) {
  position: relative;
}

/* --- A score that just moved ---------------------------------------------- */

.pc-bug-score.is-up {
  animation: pc-score-up 900ms cubic-bezier(0.2, 0.9, 0.3, 1.2);
}

.pc-bug-score.is-down {
  animation: pc-score-down 900ms ease-out;
}

@keyframes pc-score-up {
  0% { transform: scale(1); }
  25% { transform: scale(1.32); color: #fff; text-shadow: 0 0 calc(var(--u) * 5) rgba(46, 255, 115, 1); }
  100% { transform: scale(1); }
}

@keyframes pc-score-down {
  0%, 100% { transform: none; }
  15% { transform: translateX(-4%); color: var(--pc-red); }
  30% { transform: translateX(4%); color: var(--pc-red); }
  45% { transform: translateX(-2%); }
  60% { transform: translateX(2%); }
}

/* --- The middle ----------------------------------------------------------- */

.pc-bug-center {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(var(--u) * 0.8);
  min-width: calc(var(--u) * 17);
  padding: calc(var(--u) * 1.2) calc(var(--u) * 2.4);
  background: rgba(255, 255, 255, 0.04);
  border-left: 1px solid var(--pc-line);
  border-right: 1px solid var(--pc-line);
}

.pc-bug-round {
  display: flex;
  flex-direction: column;
  align-items: center;
  line-height: 1;
}

.pc-bug-round-k {
  font-size: calc(var(--u) * 1.5);
  font-weight: 800;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--pc-ink-soft);
}

.pc-bug-round-n {
  margin-top: calc(var(--u) * 0.4);
  font-family: var(--pc-display);
  font-size: calc(var(--u) * 5.4);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

.pc-bug-round-n small {
  font-size: 0.5em;
  font-weight: 700;
  color: var(--pc-ink-soft);
}

.pc-bug-lead {
  padding: calc(var(--u) * 0.3) calc(var(--u) * 1.2);
  border-radius: 999px;
  font-size: calc(var(--u) * 1.5);
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--pc-ink-soft);
  background: rgba(255, 255, 255, 0.06);
}

.pc-bug-lead b {
  color: var(--pc-ink);
}

.pc-bug-lead-arrow {
  margin: 0 calc(var(--u) * 0.5);
  font-size: 0.85em;
  color: var(--pc-green);
}

.pc-bug-lead:empty {
  display: none;
}

/* Sudden death: the middle of the board turns red, as the splash did. */
.pc-bug.is-sudden .pc-bug-center {
  background: linear-gradient(180deg, rgba(255, 90, 90, 0.28), rgba(255, 90, 90, 0.1));
}

.pc-bug.is-sudden .pc-bug-round-k {
  color: #ffd0d0;
}

.pc-bug.is-sudden .pc-bug-round-n {
  color: #fff;
}

/* ===========================================================================
   The stage, inside the board
   ========================================================================= */

.pc-live .player-channel-stream {
  border-radius: calc(var(--u) * 2);
  border: 1px solid var(--pc-line);
}

.pc-live .pc-feed-tag {
  font-size: calc(var(--u) * 1.7);
  padding: calc(var(--u) * 0.6) calc(var(--u) * 1.6);
}

/* ===========================================================================
   The tray
   ========================================================================= */

.pc-tray {
  --ball: calc(var(--u) * 7.6);

  position: relative;
  display: flex;
  flex-direction: column;
  gap: calc(var(--u) * 1);
  padding: calc(var(--u) * 1.3) calc(var(--u) * 1.8) calc(var(--u) * 1.5);
  border-radius: calc(var(--u) * 2);
  background: var(--pc-glass);
  border: 1px solid var(--pc-line);
  overflow: hidden;
}

.pc-tray-head {
  display: flex;
  align-items: center;
  gap: calc(var(--u) * 1.4);
  min-height: calc(var(--u) * 4);
}

.pc-tray-who {
  display: flex;
  align-items: center;
  gap: calc(var(--u) * 1);
  min-width: 0;
}

.pc-tray-who .flag-img {
  width: calc(var(--u) * 3.4);
  height: auto;
  margin: 0;
  border-radius: calc(var(--u) * 0.4);
}

.pc-tray-name {
  font-family: var(--pc-display);
  font-size: calc(var(--u) * 3);
  font-weight: 700;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.pc-tray-tag {
  flex: none;
  font-size: calc(var(--u) * 1.5);
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--pc-green);
}

.pc-tray-notes {
  display: flex;
  gap: calc(var(--u) * 0.8);
}

.pc-chip {
  padding: calc(var(--u) * 0.4) calc(var(--u) * 1.1);
  border-radius: 999px;
  font-size: calc(var(--u) * 1.5);
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}

.pc-chip.is-bad {
  color: #ffd6d6;
  background: rgba(255, 90, 90, 0.22);
  border: 1px solid rgba(255, 90, 90, 0.5);
}

.pc-tray-points {
  display: flex;
  align-items: baseline;
  gap: calc(var(--u) * 0.8);
  margin-left: auto;
  white-space: nowrap;
}

.pc-tray-points-n {
  font-family: var(--pc-display);
  font-size: calc(var(--u) * 4.4);
  font-weight: 800;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--pc-green);
}

.pc-tray-points-k {
  font-size: calc(var(--u) * 1.5);
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--pc-ink-soft);
}

.pc-tray-pending {
  align-self: center;
  margin-left: calc(var(--u) * 0.6);
  padding: calc(var(--u) * 0.4) calc(var(--u) * 1.1);
  border-radius: 999px;
  font-size: calc(var(--u) * 1.6);
  font-weight: 800;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #241600;
  background: var(--pc-amber);
  animation: pc-board-breathe 1.6s ease-in-out infinite;
}

/* --- The rail ------------------------------------------------------------- */

/* A ball return: a dark trough with a wooden lip, the way the balls come back
   down under a coin-op table. */
.pc-tray-rail {
  position: relative;
  padding: calc(var(--u) * 0.9);
  border-radius: 999px;
  background:
    linear-gradient(180deg, #05080c 0%, #0d131b 55%, #05080c 100%);
  box-shadow:
    inset 0 calc(var(--u) * 0.6) calc(var(--u) * 1.4) rgba(0, 0, 0, 0.85),
    inset 0 calc(var(--u) * -0.2) 0 rgba(255, 255, 255, 0.05),
    0 0 0 calc(var(--u) * 0.45) #3a2616,
    0 0 0 calc(var(--u) * 0.6) #5c3d22;
}

.pc-tray-track {
  position: relative;
  display: flex;
  align-items: center;
  gap: calc(var(--u) * 0.7);
  min-height: var(--ball);
}

/* Room for a long turn: scratches and slop push past nine balls. */
.pc-tray-track.is-long {
  --ball: calc(var(--u) * 6);
}

/* Full size where there is room, and shrinking together where there is not --
   a phone's width, or a turn long enough with scratches and slop to run past
   nine. Square either way. */
.pc-tray-slot,
.pc-tray-ball {
  position: relative;
  flex: 0 1 var(--ball);
  min-width: 0;
  aspect-ratio: 1;
}

.pc-tray-slot {
  border-radius: 50%;
  background: radial-gradient(circle at 50% 40%, rgba(255, 255, 255, 0.035), rgba(0, 0, 0, 0.4) 70%);
  box-shadow: inset 0 calc(var(--u) * 0.3) calc(var(--u) * 0.8) rgba(0, 0, 0, 0.7);
}

/* --- The break ------------------------------------------------------------ */

/* Whatever went down on the break, in a pill of its own at the head of the
   rail with a tab that says so. Silver, not a colour that already means
   something: green is scoring, amber is the 11, gold is a bonus. */
.pc-tray-break {
  position: relative;
  display: flex;
  align-items: center;
  gap: inherit;
  flex: 0 1 auto;
  min-width: 0;
  margin: calc(var(--u) * -0.5) calc(var(--u) * 0.4) calc(var(--u) * -0.5) calc(var(--u) * -0.5);
  padding: calc(var(--u) * 0.5);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.07);
  box-shadow: inset 0 0 0 calc(var(--u) * 0.25) rgba(225, 232, 240, 0.55);
}

.pc-tray-break-tag {
  position: absolute;
  left: 50%;
  top: calc(var(--u) * -1.3);
  z-index: 3;
  transform: translateX(-50%);
  padding: calc(var(--u) * 0.15) calc(var(--u) * 0.9);
  border-radius: 999px;
  font-size: calc(var(--u) * 1.2);
  font-weight: 800;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  white-space: nowrap;
  color: #0b1016;
  background: #e1e8f0;
}

/* The same group in the score feed: the outline without the tab, which the
   tray has already explained. */
.pc-pbp-balls .ov-break-group {
  display: inline-flex;
  align-items: center;
  gap: inherit;
  padding: calc(var(--u) * 0.3);
  margin: calc(var(--u) * -0.3) calc(var(--u) * 0.3) calc(var(--u) * -0.3) calc(var(--u) * -0.3);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.07);
  box-shadow: inset 0 0 0 calc(var(--u) * 0.18) rgba(225, 232, 240, 0.5);
}

.pc-tray-ball .ov-ball {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  filter: drop-shadow(0 calc(var(--u) * 0.5) calc(var(--u) * 0.6) rgba(0, 0, 0, 0.6));
}

/* The base rail rules dim these for a small row of balls. In the tray they are
   the subject; their meaning is carried by the ring and the pop instead. */
.pc-tray-ball .ov-ball.is-pending,
.pc-tray-ball .ov-ball--slop,
.pc-tray-ball .ov-ball--scratch {
  opacity: 1;
  outline: none;
}

/* Riding on the 11: an amber ring that breathes until the 11 drops. */
.pc-tray-ball.is-pending::after {
  content: "";
  position: absolute;
  inset: calc(var(--u) * -0.45);
  border-radius: 50%;
  border: calc(var(--u) * 0.35) dashed var(--pc-amber);
  animation: pc-board-breathe 1.6s ease-in-out infinite;
  pointer-events: none;
}

.pc-tray-ball:has(.ov-ball--slop) .ov-ball {
  filter: grayscale(0.6) brightness(0.75);
}

/* --- Rolling in ----------------------------------------------------------- */

/* Two animations, one each on the wrapper and the ball, so the ball can turn
   as it travels while the "+1" riding with it stays upright. --roll-from and
   --roll-turn are measured per ball by live-board.js; --delay carries a roll
   on from where it was when the tray is redrawn mid-roll. */
.pc-tray-ball.is-rolling {
  animation: pc-roll-move 1100ms cubic-bezier(0.25, 0.75, 0.3, 1) both;
  animation-delay: var(--delay, 0ms);
}

.pc-tray-ball.is-rolling .ov-ball {
  animation: pc-roll-spin 1100ms cubic-bezier(0.25, 0.75, 0.3, 1) both;
  animation-delay: var(--delay, 0ms);
}

@keyframes pc-roll-move {
  0% { transform: translate(var(--roll-from, 0px), -130%); opacity: 0; }
  10% { transform: translate(calc(var(--roll-from, 0px) * 0.97), 0); opacity: 1; }
  14% { transform: translate(calc(var(--roll-from, 0px) * 0.95), -14%); }
  19% { transform: translate(calc(var(--roll-from, 0px) * 0.92), 0); }
  84% { transform: translate(-7%, 0); }
  92% { transform: translate(2.5%, 0); }
  100% { transform: none; opacity: 1; }
}

@keyframes pc-roll-spin {
  0% { transform: rotate(var(--roll-turn, 0deg)); }
  10% { transform: rotate(calc(var(--roll-turn, 0deg) * 0.97)); }
  84% { transform: rotate(-12deg); }
  92% { transform: rotate(4deg); }
  100% { transform: none; }
}

/* What that ball was worth, rising off it once it settles. */
.pc-tray-pop {
  position: absolute;
  left: 50%;
  bottom: 70%;
  z-index: 2;
  padding: calc(var(--u) * 0.25) calc(var(--u) * 0.9);
  border-radius: 999px;
  font-family: var(--pc-display);
  font-size: calc(var(--u) * 2.4);
  font-weight: 800;
  line-height: 1.1;
  white-space: nowrap;
  text-transform: uppercase;
  transform: translateX(-50%);
  opacity: 0;
  pointer-events: none;
  animation: pc-pop 1400ms ease-out both;
  animation-delay: calc(var(--delay, 0ms) + 820ms);
}

.is-promoted > .pc-tray-pop {
  animation-delay: calc(var(--pdelay, 0ms) + 150ms);
}

.pc-tray-pop.is-good { color: var(--pc-green-deep); background: var(--pc-green); }
.pc-tray-pop.is-pending { color: #241600; background: var(--pc-amber); font-size: calc(var(--u) * 1.8); }
.pc-tray-pop.is-bad { color: #fff; background: var(--pc-red); }
.pc-tray-pop.is-flat { color: var(--pc-ink); background: rgba(255, 255, 255, 0.18); font-size: calc(var(--u) * 1.8); }

@keyframes pc-pop {
  0% { opacity: 0; transform: translate(-50%, 30%) scale(0.6); }
  18% { opacity: 1; transform: translate(-50%, -10%) scale(1.12); }
  30% { transform: translate(-50%, -20%) scale(1); }
  75% { opacity: 1; transform: translate(-50%, -55%); }
  100% { opacity: 0; transform: translate(-50%, -90%); }
}

/* The 11 dropped: every ball that was riding on it lights up and counts. */
.pc-tray-ball.is-promoted .ov-ball {
  animation: pc-promote 1300ms ease-out both;
  animation-delay: var(--pdelay, 0ms);
}

@keyframes pc-promote {
  0% { transform: scale(1); filter: drop-shadow(0 0 0 rgba(46, 255, 115, 0)); }
  30% { transform: scale(1.22); filter: drop-shadow(0 0 calc(var(--u) * 2) rgba(46, 255, 115, 1)); }
  100% { transform: scale(1); filter: drop-shadow(0 calc(var(--u) * 0.5) calc(var(--u) * 0.6) rgba(0, 0, 0, 0.6)); }
}

/* --- The good news -------------------------------------------------------- */

.pc-tray-banner {
  display: inline-flex;
  align-items: baseline;
  gap: calc(var(--u) * 1);
  padding: calc(var(--u) * 0.5) calc(var(--u) * 1.6);
  border-radius: 999px;
  white-space: nowrap;
  position: relative;
  overflow: hidden;
}

.pc-tray-banner[hidden] {
  display: none;
}

.pc-tray-banner.is-gold {
  color: #2a1a00;
  background: linear-gradient(180deg, #ffe7a3, var(--pc-gold) 55%, #e9a91f);
  box-shadow: 0 0 calc(var(--u) * 2.4) rgba(255, 209, 102, 0.55);
}

.pc-tray-banner.is-green {
  color: var(--pc-green-deep);
  background: var(--pc-green);
  box-shadow: 0 0 calc(var(--u) * 2.4) rgba(46, 255, 115, 0.5);
}

.pc-tray-banner-text {
  font-family: var(--pc-display);
  font-size: calc(var(--u) * 2.6);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.pc-tray-banner-sub {
  font-size: calc(var(--u) * 1.5);
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* A sheen that crosses it every few seconds while it is up. */
.pc-tray-banner::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: 40%;
  left: -50%;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, 0.65), transparent);
  animation: pc-sheen 3.2s ease-in-out infinite;
}

.pc-tray-banner.is-in {
  animation: pc-banner-in 700ms cubic-bezier(0.2, 0.9, 0.3, 1.3);
}

@keyframes pc-banner-in {
  0% { transform: scale(2.2); opacity: 0; }
  60% { transform: scale(0.94); opacity: 1; }
  100% { transform: scale(1); }
}

@keyframes pc-sheen {
  0%, 55% { left: -50%; }
  100% { left: 130%; }
}

/* The whole tray flares gold for a bonus. */
.pc-tray.is-celebrate {
  animation: pc-tray-celebrate 1600ms ease-out;
}

@keyframes pc-tray-celebrate {
  0% { box-shadow: 0 0 0 0 rgba(255, 209, 102, 0); }
  20% { box-shadow: 0 0 0 calc(var(--u) * 0.5) rgba(255, 209, 102, 0.9), 0 0 calc(var(--u) * 8) rgba(255, 209, 102, 0.55); }
  100% { box-shadow: 0 0 0 0 rgba(255, 209, 102, 0); }
}

/* ===========================================================================
   The card: the score line, then play by play
   ========================================================================= */

.pc-card {
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding: calc(var(--u) * 1.8) calc(var(--u) * 2);
  border-radius: calc(var(--u) * 2);
  background: var(--pc-glass);
  border: 1px solid var(--pc-line);
}

/* --- The line ------------------------------------------------------------- */

/* A scoreline, not a table of boxes: names down the left, a narrow column per
   round, the total set apart on the right. Rows are told apart by a hairline
   and nothing else. */
.pc-line {
  --cols: 3;

  display: grid;
  grid-template-columns:
    minmax(0, 1fr)
    repeat(var(--cols), calc(var(--u) * 5.4))
    calc(var(--u) * 7.4);
  align-items: center;
  column-gap: calc(var(--u) * 0.4);
}

.pc-line-corner {
  display: block;
}

.pc-line-h {
  padding-bottom: calc(var(--u) * 0.8);
  font-size: calc(var(--u) * 1.4);
  font-weight: 800;
  letter-spacing: 0.14em;
  text-align: center;
  text-transform: uppercase;
  color: var(--pc-ink-soft);
}

.pc-line-h.is-current {
  color: var(--pc-green);
}

.pc-line-h.is-sudden {
  color: #ff9d9d;
}

.pc-line-h.is-total {
  color: var(--pc-ink);
}

.pc-line-who,
.pc-line-c {
  height: calc(var(--u) * 5.6);
  border-top: 1px solid var(--pc-line);
}

.pc-line-who {
  display: flex;
  align-items: center;
  gap: calc(var(--u) * 1);
  min-width: 0;
  padding-left: calc(var(--u) * 1);
  border-left: calc(var(--u) * 0.4) solid transparent;
}

.pc-line-who.is-shooting {
  border-left-color: var(--pc-green);
  background: linear-gradient(90deg, rgba(46, 255, 115, 0.1), transparent 70%);
}

.pc-line-who .flag-img {
  flex: none;
  width: calc(var(--u) * 3.2);
  height: auto;
  margin: 0;
  border-radius: calc(var(--u) * 0.35);
}

.pc-line-name {
  min-width: 0;
  font-family: var(--pc-display);
  font-size: calc(var(--u) * 2.6);
  font-weight: 700;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.pc-line-c {
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--pc-display);
  font-size: calc(var(--u) * 3);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--pc-ink);
}

/* A round not played yet: a faint dot, so the line shows what is left. */
.pc-line-c i {
  width: calc(var(--u) * 0.7);
  height: calc(var(--u) * 0.7);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.16);
}

.pc-line-c.is-max {
  color: var(--pc-gold);
}

.pc-line-c.is-negative {
  color: var(--pc-red);
}

.pc-line-c.is-live {
  color: var(--pc-green);
}

.pc-line-c.is-live i {
  width: calc(var(--u) * 1);
  height: calc(var(--u) * 1);
  background: var(--pc-green);
  box-shadow: 0 0 calc(var(--u) * 1) var(--pc-green);
  animation: pc-board-blink 1.2s ease-in-out infinite;
}

.pc-line-c.is-total {
  margin-left: calc(var(--u) * 0.6);
  font-size: calc(var(--u) * 3.6);
  font-weight: 800;
  background: rgba(255, 255, 255, 0.05);
}

/* --- Play by play --------------------------------------------------------- */

.pc-pbp-head {
  margin: calc(var(--u) * 2.4) 0 calc(var(--u) * 0.6);
  font-size: calc(var(--u) * 1.4);
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--pc-ink-soft);
}

.pc-pbp {
  flex: 1 1 auto;
  min-height: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* One turn: who and what it was worth on the first line, the balls beneath. */
.pc-pbp-item {
  display: grid;
  grid-template-columns: calc(var(--u) * 6) minmax(0, 1fr) auto;
  grid-template-areas:
    "tag who points"
    ".   balls points";
  align-items: center;
  column-gap: calc(var(--u) * 1);
  row-gap: calc(var(--u) * 0.6);
  padding: calc(var(--u) * 1.1) calc(var(--u) * 0.6) calc(var(--u) * 1.1) 0;
  border-top: 1px solid var(--pc-line);
}

.pc-pbp-tag {
  grid-area: tag;
  display: inline-flex;
  align-items: center;
  gap: calc(var(--u) * 0.5);
  font-size: calc(var(--u) * 1.4);
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--pc-ink-soft);
}

.pc-pbp-who {
  grid-area: who;
  display: flex;
  align-items: center;
  gap: calc(var(--u) * 0.8);
  min-width: 0;
}

.pc-pbp-who .flag-img {
  flex: none;
  width: calc(var(--u) * 2.4);
  height: auto;
  margin: 0;
  border-radius: calc(var(--u) * 0.25);
}

.pc-pbp-name {
  min-width: 0;
  font-family: var(--pc-display);
  font-size: calc(var(--u) * 2.2);
  font-weight: 700;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.pc-pbp-points {
  grid-area: points;
  min-width: calc(var(--u) * 4);
  font-family: var(--pc-display);
  font-size: calc(var(--u) * 4.2);
  font-weight: 800;
  line-height: 1;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.pc-pbp-points.is-max { color: var(--pc-gold); }
.pc-pbp-points.is-negative { color: var(--pc-red); }

.pc-pbp-balls {
  grid-area: balls;
  min-width: 0;
  min-height: calc(var(--u) * 3);
}

.pc-pbp-balls .ov-balls {
  flex-wrap: wrap;
  overflow: visible;
  gap: calc(var(--u) * 0.35);
  font-size: inherit;
}

.pc-pbp-balls .ov-ball {
  width: calc(var(--u) * 3.4);
  height: calc(var(--u) * 3.4);
}

.pc-pbp-wait {
  font-size: calc(var(--u) * 1.5);
  font-weight: 700;
  color: var(--pc-ink-soft);
}

/* The turn at the table. */
.pc-pbp-item.is-live {
  margin: 0 calc(var(--u) * -1);
  padding-left: calc(var(--u) * 1);
  padding-right: calc(var(--u) * 1.6);
  border-top-color: transparent;
  border-radius: calc(var(--u) * 1.2);
  background: linear-gradient(90deg, rgba(46, 255, 115, 0.14), rgba(46, 255, 115, 0.03));
  box-shadow: inset calc(var(--u) * 0.4) 0 0 var(--pc-green);
}

.pc-pbp-item.is-live .pc-pbp-tag,
.pc-pbp-item.is-live .pc-pbp-points {
  color: var(--pc-green);
}

.pc-pbp-item.is-live + .pc-pbp-item {
  border-top-color: transparent;
}

.pc-pbp-dot {
  width: calc(var(--u) * 0.9);
  height: calc(var(--u) * 0.9);
  border-radius: 50%;
  background: var(--pc-green);
  box-shadow: 0 0 calc(var(--u) * 1) var(--pc-green);
  animation: pc-board-blink 1.2s ease-in-out infinite;
}

.pc-pbp-item.is-sudden:not(.is-live) .pc-pbp-tag {
  color: #ff9d9d;
}

/* A turn that has just been written in slides down into the feed. */
.pc-pbp-item.is-new {
  animation: pc-pbp-in 900ms cubic-bezier(0.2, 0.8, 0.3, 1);
}

@keyframes pc-pbp-in {
  0% { opacity: 0; transform: translateY(-40%); background: rgba(46, 255, 115, 0.25); }
  40% { opacity: 1; }
  100% { transform: none; background: transparent; }
}

.pc-pbp-empty {
  padding: calc(var(--u) * 2) 0;
  font-size: calc(var(--u) * 1.8);
  color: var(--pc-ink-soft);
  border-top: 1px solid var(--pc-line);
}

/* --- Under the card ------------------------------------------------------- */

.pc-card-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: calc(var(--u) * 0.8) calc(var(--u) * 1.6);
  font-size: calc(var(--u) * 1.6);
  color: var(--pc-ink-soft);
}

.pc-card-foot:empty {
  display: none;
}

.pc-card-foot .pc-site-viewers {
  margin: 0;
}

.pc-card-credit a,
.pc-card-foot .player-channel-links a {
  color: var(--pc-ink);
}

.pc-card-foot .player-channel-links {
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--u) * 0.4) calc(var(--u) * 1.6);
  width: 100%;
}

/* ===========================================================================
   Shared motion
   ========================================================================= */

@keyframes pc-board-blink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.3; }
}

@keyframes pc-board-breathe {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.55; }
}

/* The balls still arrive and the numbers still change -- only the movement
   goes. Nothing here is decoration that carries information on its own. */
@media (prefers-reduced-motion: reduce) {
  /* Not the shot moments, which carry their own reduced version: much of
     what they say is only visible at the end of an animation. */
  .pc-live *:not(.pc-mo, .pc-mo *, .pc-mo-toast, .pc-mo-toast *),
  .pc-live *:not(.pc-mo, .pc-mo *, .pc-mo-toast, .pc-mo-toast *)::before,
  .pc-live *:not(.pc-mo, .pc-mo *, .pc-mo-toast, .pc-mo-toast *)::after {
    animation: none !important;
    transition: none !important;
  }

  .pc-tray-pop {
    display: none;
  }
}

/* ===========================================================================
   Narrower windows
   ========================================================================= */

@media (max-width: 900px) {
  .pc-live {
    --u: clamp(4.4px, 1.15vw, 8px);
  }

  .pc-live-main {
    grid-template-columns: minmax(0, 1fr);
  }

}

@media (max-width: 600px) {
  .pc-live {
    --u: clamp(4px, 1.5vw, 7px);
  }

  .pc-bug-side {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "flag score" "id id";
    row-gap: calc(var(--u) * 1);
    padding: calc(var(--u) * 1.4);
  }

  .pc-bug-side.is-right {
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas: "score flag" "id id";
  }

  .pc-bug-side.is-right .pc-bug-flag {
    justify-self: end;
  }

  .pc-bug-center {
    min-width: 0;
    padding: calc(var(--u) * 1);
  }

  .pc-bug-lead {
    display: none;
  }

  .pc-tray-head {
    flex-wrap: wrap;
  }

  /* Two lines of name beats an ellipsis through the middle of it. */
  .pc-bug-name {
    white-space: normal;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    font-size: calc(var(--u) * 3.8);
  }
}

/* ===========================================================================
   Full screen, on the monitor beside the table
   ===========================================================================
   Sized off the screen's HEIGHT (vh), because that is the axis the board is
   fighting for: a scoreboard, a 16:9 picture and a tray stacked between the
   top and bottom of a screen nobody is going to scroll. min() with the width
   keeps a 16:10 or 4:3 screen from running off the side instead.

   The picture is as big as what is left allows and no bigger, and the card
   takes every pixel of width the picture does not. */

@media (min-width: 901px) {
  html.is-tv .pc-live {
    --u: min(1vh, 0.5625vw);
    --pc-gap: calc(var(--u) * 1.3);
    --pc-bug-h: calc(var(--u) * 13.5);
    --pc-tray-h: calc(var(--u) * 16.5);
    --pc-card-min: calc(var(--u) * 52);
    --pc-stream-w: min(
      calc(100vw - var(--pc-tv-pad, 0px) * 2 - var(--pc-gap) - var(--pc-card-min)),
      calc(
        (100dvh - var(--pc-tv-pad, 0px) * 2 - var(--pc-bug-h) - var(--pc-tray-h) - var(--pc-gap) * 3) * 16 / 9
      )
    );

    height: 100%;
    min-height: 0;
  }

  html.is-tv .pc-bug {
    height: var(--pc-bug-h);
    min-height: 0;
    flex: none;
  }

  html.is-tv .pc-live-main {
    flex: 1 1 auto;
    min-height: 0;
    grid-template-columns: var(--pc-stream-w) minmax(0, 1fr);
  }

  html.is-tv .pc-live-stage {
    min-height: 0;
  }

  html.is-tv .pc-live .player-channel-stream {
    width: 100%;
    flex: none;
    margin: 0;
    align-self: stretch;
  }

  html.is-tv .pc-tray {
    --ball: calc(var(--u) * 9.4);
    flex: 1 1 auto;
    min-height: var(--pc-tray-h);
    justify-content: center;
  }

  html.is-tv .pc-card {
    min-height: 0;
    overflow: hidden;
  }

  html.is-tv .pc-tray-track.is-long {
    --ball: calc(var(--u) * 7.4);
  }

  /* The feed never scrolls. Newest is on top, so whatever runs off the bottom
     is the oldest turn of the match -- faded out rather than cut through. */
  html.is-tv .pc-pbp {
    overflow: hidden;
    -webkit-mask-image: linear-gradient(180deg, #000 calc(100% - var(--u) * 6), transparent);
    mask-image: linear-gradient(180deg, #000 calc(100% - var(--u) * 6), transparent);
  }

  /* Links are for clicking. Nobody clicks a television. */
  html.is-tv .pc-card-foot .player-channel-links {
    display: none;
  }
}
