.player-channel-page {
  width: min(1400px, calc(100% - 32px));
  margin: 0 auto;
  padding: 32px 0 56px;
}

.player-channel-hero {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(320px, 1fr);
  gap: 24px;
  align-items: start;
}

.player-channel-stream {
  background: #05070b;
  border-radius: 18px;
  overflow: hidden;
  box-shadow: 0 18px 48px rgba(0, 0, 0, 0.35);
}

/* Feeds are stacked and cross-faded rather than swapped, so switching to the
   other player is instant instead of tearing down and re-buffering a stream. */
.pc-stage {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  background: #05070b;
}

.pc-feed {
  position: absolute;
  inset: 0;
  opacity: 0;
  visibility: hidden;
  transition: opacity 220ms ease;
}

.pc-feed.is-active {
  opacity: 1;
  visibility: visible;
}

.pc-feed iframe,
.player-channel-stream > iframe {
  display: block;
  width: 100%;
  height: 100%;
  aspect-ratio: 16 / 9;
  border: 0;
}

/* Player feeds used to be flipped here: the app broadcast from the phone's
   selfie camera, which reaches Kick already mirrored, so a right-handed
   player appeared to shoot left-handed. The app now publishes the back
   (table-facing) camera, which is not mirrored, so the flip is gone -- it
   would be the thing putting the cue arm on the wrong side. The app can
   still flip to the selfie camera mid-turn, but it never tells anyone it
   did, so there is nothing to condition on; re-introducing the flip means
   publishing the camera facing with the stream state first. */
.pc-stage[data-mode="players"] .pc-feed iframe {
  /* Kick has no "hide controls" embed parameter -- their player raises its
     chrome on pointer activity, so the only way to keep it down is to make
     sure the iframe never sees a pointer. Costs nothing here: player feeds
     are muted by design and there is nothing in them worth clicking, and it
     also stops a viewer unmuting the feed they AREN'T watching (both are
     mounted at once). The caster feed is deliberately left interactive so
     viewers can unmute the commentary. */
  pointer-events: none;
}

/* Which player's camera you're looking at. */
.pc-feed-tag {
  position: absolute;
  left: 12px;
  bottom: 12px;
  padding: 5px 12px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 700;
  color: #fff;
  background: rgba(5, 7, 11, 0.72);
  border: 1px solid rgba(255, 255, 255, 0.16);
  backdrop-filter: blur(6px);
  pointer-events: none;
}

.pc-shooting {
  position: absolute;
  right: 12px;
  top: 12px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 800;
  color: #052b12;
  background: #2eff73;
  box-shadow: 0 6px 20px rgba(46, 255, 115, 0.35);
  pointer-events: none;
}

.pc-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #052b12;
  animation: pc-pulse 1.4s ease-in-out infinite;
}

@keyframes pc-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

@media (prefers-reduced-motion: reduce) {
  .pc-feed { transition: none; }
  .pc-dot { animation: none; }
}

.pc-coverage {
  color: rgba(255, 255, 255, 0.68);
  margin: 6px 0 14px;
}

.pc-round {
  display: inline-block;
  padding: 5px 12px;
  margin-bottom: 12px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.75);
  background: rgba(255, 255, 255, 0.08);
}

.pc-score {
  display: grid;
  gap: 8px;
  margin-bottom: 18px;
}

.pc-score-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 14px;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid transparent;
}

.pc-score-row.is-shooting {
  border-color: rgba(46, 255, 115, 0.55);
  background: rgba(46, 255, 115, 0.1);
}

.pc-score-name {
  font-weight: 700;
  color: #fff;
}

.pc-score-value {
  font-size: 22px;
  font-weight: 900;
  font-variant-numeric: tabular-nums;
  color: #2eff73;
}

.player-channel-no-stream {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 16 / 9;
  color: rgba(255, 255, 255, 0.6);
}

.player-channel-panel {
  background: rgba(8, 13, 20, 0.9);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 18px;
  padding: 22px;
}

.player-channel-empty,
.player-channel-error {
  padding: 48px 24px;
  text-align: center;
  background: rgba(8, 13, 20, 0.9);
  border-radius: 18px;
}
.player-channel-card {
  max-width: 520px;
  margin: 0 auto;
  padding: 32px;
  border-radius: 22px;
  background: linear-gradient(
    145deg,
    rgba(13, 20, 32, 0.96),
    rgba(20, 36, 52, 0.92)
  );
  border: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow: 0 22px 60px rgba(0, 0, 0, 0.38);
}

.player-channel-card h2 {
  margin: 0 0 10px;
  font-size: 34px;
}

.player-channel-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  margin-top: 24px;
}

.player-channel-stats div {
  padding: 16px;
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.07);
}

.player-channel-status {
  margin: 12px 0 18px;
  padding: 14px 18px;
  border-radius: 12px;
  font-size: 18px;
  font-weight: 600;
  text-align: center;
  color: #ffffff;
  background: linear-gradient(90deg, #ef5c23, #ff7a3d);
  box-shadow: 0 8px 24px rgba(239, 92, 35, 0.35);
}

@media (max-width: 900px) {
  .player-channel-hero {
    grid-template-columns: 1fr;
  }
}

/* ------------------------------------------------------------------------- */
/* Shell                                                                      */
/* ------------------------------------------------------------------------- */

/* Emitted by the JS on first paint and on every idle card. Both went unstyled. */
.player-channel-root {
  color: rgba(255, 255, 255, 0.86);
}

.pc-muted {
  color: rgba(255, 255, 255, 0.62);
  margin: 10px 0 0;
}

.pc-subhead {
  margin: 18px 0 10px;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
}

/* ------------------------------------------------------------------------- */
/* Is there anything to watch?                                                */
/* ------------------------------------------------------------------------- */

.pc-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 800;
  letter-spacing: 0.4px;
}

.pc-badge.is-live {
  color: #04150a;
  background: #2eff73;
}

/* The live dot pulses; this one must not, or "offline" reads as activity. */
.pc-badge.is-live .pc-dot {
  background: #04150a;
}

.pc-badge.is-offline {
  color: rgba(255, 255, 255, 0.72);
  background: rgba(255, 255, 255, 0.1);
}

/* Kick could not be reached. Deliberately NOT styled as offline: the server
   does not know, and the colour should not claim otherwise. */
.pc-badge.is-unknown {
  color: rgba(255, 255, 255, 0.62);
  background: rgba(255, 255, 255, 0.06);
  border: 1px dashed rgba(255, 255, 255, 0.25);
}

.pc-countdown {
  margin-top: 14px;
  font-size: 26px;
  font-weight: 900;
  font-variant-numeric: tabular-nums;
  color: #ffb066;
}

/* ------------------------------------------------------------------------- */
/* Balls                                                                      */
/* ------------------------------------------------------------------------- */

/* Geometry matched to casual-overlay.css so a pocketed ball is the same object
   on both public pages. The `ov-` prefix is the shared renderer's, not a stray:
   ball-rail.js emits this markup for the overlay and for this page alike. */
.ov-balls {
  display: flex;
  align-items: center;
  gap: 0.15em;
  flex-wrap: nowrap;
  overflow: hidden;
  font-size: 15px;
}

.ov-ball {
  display: block;
  width: 1.55em;
  height: 1.55em;
  flex: none;
}

.ov-ball svg {
  width: 100%;
  height: 100%;
  display: block;
}

/* Out of rotation with no 11 down yet: worth something only if the 11 follows. */
.ov-ball.is-pending {
  opacity: 0.55;
  outline: 1px dashed rgba(242, 194, 48, 0.8);
  outline-offset: 1px;
  border-radius: 50%;
}

/* The turn ended without the 11, so those points are gone. */
.ov-ball.is-lost {
  opacity: 0.38;
  outline: 1px dashed rgba(255, 255, 255, 0.35);
  outline-offset: 1px;
  border-radius: 50%;
}

.ov-ball--slop,
.ov-ball--scratch,
.ov-ball--badbreak {
  opacity: 0.75;
}

/* The panel is ~400px wide, so a rail on the same line as a name and a score
   was handed almost no room and then clipped itself. On its own line it has the
   full width and wraps instead of disappearing. */
.pc-score-balls .ov-balls,
.pc-round-balls .ov-balls {
  flex-wrap: wrap;
  overflow: visible;
  row-gap: 0.2em;
}

/* ------------------------------------------------------------------------- */
/* The matchup header                                                         */
/* ------------------------------------------------------------------------- */

/* Three columns, so the two sides stay side by side and the "vs" can never end
   up alone on its own line. Each side's name and meta stack instead of running
   together into a sentence that wraps mid-player. */
.pc-matchup {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 10px;
  margin: 0 0 4px;
}

.pc-side {
  min-width: 0;
}

.pc-side:last-child {
  text-align: right;
}

.pc-side-name {
  font-size: 19px;
  font-weight: 800;
  line-height: 1.25;
  /* A long display name truncates rather than reflowing the whole header. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pc-side-name a {
  color: #fff;
  text-decoration: none;
}

.pc-side-name a:hover {
  text-decoration: underline;
}

.pc-side-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 4px;
  font-size: 13px;
  color: rgba(255, 255, 255, 0.62);
}

.pc-side:last-child .pc-side-meta {
  justify-content: flex-end;
}

.pc-versus {
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.42);
}

.pc-elo-value {
  font-variant-numeric: tabular-nums;
}

.pc-rank {
  flex: none;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: #ffd479;
  background: rgba(242, 194, 48, 0.16);
}

/* ------------------------------------------------------------------------- */
/* Live scoreboard                                                            */
/* ------------------------------------------------------------------------- */

/* The row is now two lines: the header line, then the rail. */
.pc-score-row {
  display: block;
}

.pc-score-head {
  display: flex;
  align-items: center;
  gap: 8px;
}

.pc-score-balls {
  margin-top: 8px;
}

.pc-turn-points {
  margin-left: auto;
  font-size: 13px;
  font-weight: 800;
  color: #f2c230;
  white-space: nowrap;
}

/* Without the turn-points chip there is nothing to push the total right. */
.pc-score-head .pc-score-value {
  margin-left: auto;
}

.pc-score-head .pc-turn-points ~ .pc-score-value {
  margin-left: 0;
}

.pc-score-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ------------------------------------------------------------------------- */
/* What the turn is worth, and why                                            */
/* ------------------------------------------------------------------------- */

.pc-notes {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}

.pc-note {
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.3px;
  white-space: nowrap;
}

.pc-note.is-great {
  color: #04150a;
  background: #2eff73;
}

/* Provisional: pocketed out of rotation, worth nothing until the 11 drops. */
.pc-note.is-pending {
  color: #f2c230;
  background: rgba(242, 194, 48, 0.16);
}

.pc-note.is-bad {
  color: #ff9d9d;
  background: rgba(255, 107, 107, 0.16);
}

/* ------------------------------------------------------------------------- */
/* Round by round                                                             */
/* ------------------------------------------------------------------------- */

.pc-rounds {
  margin-bottom: 18px;
}

.pc-round-row {
  padding: 7px 10px;
  border-radius: 10px;
}

.pc-round-row:nth-child(odd) {
  background: rgba(255, 255, 255, 0.04);
}

.pc-round-head {
  display: flex;
  align-items: center;
  gap: 10px;
}

.pc-round-balls {
  margin-top: 6px;
}

.pc-round-label {
  flex: none;
  width: 34px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.6px;
  color: rgba(255, 255, 255, 0.5);
}

.pc-round-player {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 700;
}

.pc-round-points {
  flex: none;
  font-weight: 900;
  font-variant-numeric: tabular-nums;
  color: #2eff73;
}

/* ------------------------------------------------------------------------- */
/* Result                                                                     */
/* ------------------------------------------------------------------------- */

.pc-results {
  margin-top: 4px;
  padding: 16px;
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.pc-result-headline {
  font-size: 20px;
  font-weight: 900;
  margin-bottom: 12px;
}

.pc-result-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 0;
}

.pc-result-row.is-winner .pc-score-name {
  color: #2eff73;
}

/* The tiebreaker score, beside the regulation one it decided. */
.pc-result-sd {
  flex: none;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: #ffb066;
  background: rgba(255, 176, 102, 0.16);
}

.pc-result-row .pc-score-value {
  margin-left: auto;
}

.pc-result-reason {
  margin-top: 10px;
  font-size: 13px;
  color: rgba(255, 255, 255, 0.6);
}

.pc-elo {
  font-size: 13px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

.pc-elo.is-up {
  color: #2eff73;
}

.pc-elo.is-down {
  color: #ff6b6b;
}

/* ------------------------------------------------------------------------- */
/* Our own head count                                                         */
/* ------------------------------------------------------------------------- */

/* Deliberately NOT styled like .pc-badge.is-live. That badge is Kick's number
   and this one is ours, and two counts dressed identically read as one number
   contradicting itself. This is quieter, and it says where it came from. */
.pc-site-viewers {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 8px 0 2px;
  padding: 5px 12px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.3px;
  color: rgba(255, 255, 255, 0.82);
  background: rgba(239, 92, 35, 0.16);
  border: 1px solid rgba(239, 92, 35, 0.42);
}

/* ---------------------------------------------------------------------------
   "Your opponent messaged you."

   SIZED FOR A TELEVISION ON A WALL, not for the laptop this was written on.
   The reader is standing at a pool table several feet away, glancing up
   between shots, and the usual polite 13px toast in a corner is invisible from
   there. Hence the size, the weight, and the fact that it sits over the feed
   rather than beside it: for fourteen seconds, this is more important than the
   picture behind it.

   Fixed to the viewport because the page rewrites its own root on every layout
   change -- see showMessageFlash.
   --------------------------------------------------------------------------- */
.pc-message-flash {
  position: fixed;
  left: 50%;
  bottom: clamp(16px, 4vh, 48px);
  transform: translateX(-50%);
  z-index: 60;

  width: min(720px, calc(100vw - 32px));
  padding: clamp(14px, 2vw, 22px) clamp(18px, 2.4vw, 28px);

  border-radius: 18px;
  border: 2px solid rgba(56, 189, 248, 0.65);
  background: rgba(6, 10, 16, 0.96);
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.55);

  cursor: pointer;
  animation: pc-message-flash-in 260ms ease-out;
}

.pc-message-flash-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 6px;
}

.pc-message-flash-icon {
  font-size: clamp(18px, 2vw, 24px);
  line-height: 1;
}

.pc-message-flash-name {
  color: #7dd3fc;
  font-size: clamp(13px, 1.4vw, 17px);
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* The message itself carries the size. Everything else on this card is a
   label; this is the sentence somebody is squinting at. */
.pc-message-flash-body {
  margin: 0;
  color: #fff;
  font-size: clamp(20px, 2.8vw, 34px);
  line-height: 1.25;
  font-weight: 700;
  overflow-wrap: anywhere;
}

.pc-message-flash-hint {
  margin: 10px 0 0;
  color: rgba(255, 255, 255, 0.5);
  font-size: clamp(12px, 1.2vw, 15px);
  font-weight: 600;
  letter-spacing: 0.04em;
}

@keyframes pc-message-flash-in {
  from {
    opacity: 0;
    transform: translate(-50%, 14px);
  }
  to {
    opacity: 1;
    transform: translate(-50%, 0);
  }
}

/* The card still appears, at once, and still leaves on its own -- it is
   information, not decoration, and suppressing it would be suppressing the
   message. Only the movement goes. */
@media (prefers-reduced-motion: reduce) {
  .pc-message-flash {
    animation: none;
  }
}
