/* Hold'em Broadcast HUD -- widget styles.
 *
 * Four widgets, mirroring the UMG build one-for-one:
 *   .card        two sizes (hole / board), face-up or face-down
 *   .seat        hole cards + name + model + win% + stack + action + D/SB/BB
 *   .pot         the pot plate
 *   .street      the community cards, revealed street by street
 *
 * Geometry is literal px at the 1920x1080 design canvas -- `.hud-stage` is
 * scaled as a whole, so nothing in here needs to be responsive.
 */

/* ------------------------------------------------------------------ stage */

.hud-root {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;   /* the 3D scene underneath keeps the mouse */
  font-family: var(--sans);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
}

/* The whole overlay is authored at 1920x1080 and scaled to fit, exactly like
 * UE's DPI curve. scale.js owns --hud-scale / --hud-x / --hud-y. */
.hud-stage {
  position: absolute;
  top: 0;
  left: 0;
  width: 1920px;
  height: 1080px;
  transform: translate(var(--hud-x, 0px), var(--hud-y, 0px)) scale(var(--hud-scale, 1));
  transform-origin: top left;
}

/* Two rails: the table furniture top-left, the field of play down the right. */
.hud-left {
  position: absolute;
  left: 22px;
  top: 22px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 18px;
}

/* --rail-scale is set by Hud._fitRail: a full table is taller than the canvas,
 * so the rail shrinks to fit rather than running off the bottom -- and it now
 * also folds in a fixed 25% shrink (see RAIL_SHRINK) to keep the panels off the
 * characters on the right of the frame.
 *
 * `right: 222px` -- pulled 200px in from the edge for the same reason: it frees
 * a strip on the right where the far-side players sit. The scale origin is
 * top-right, so this inner edge is what the shrink anchors to. */
.hud-right {
  position: absolute;
  right: 222px;
  top: 25px;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 14px;
  transform: scale(var(--rail-scale, 1));
  transform-origin: top right;
}

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

.card {
  --w: 72px;
  --h: 100px;
  position: relative;
  width: var(--w);
  height: var(--h);
  flex: 0 0 auto;
  border-radius: 10px;
  background: linear-gradient(160deg, var(--paper-top), var(--paper) 55%, var(--paper-edge));
  box-shadow: 0 3px 7px -2px rgba(0, 0, 0, 0.55), inset 0 0 0 1px rgba(0, 0, 0, 0.06);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(var(--h) * 0.02);
  line-height: 1;
  user-select: none;
}

.card--board {
  --w: 96px;
  --h: 134px;
}

.card__rank {
  font-family: var(--sans);
  font-weight: 800;
  font-size: calc(var(--h) * 0.40);
  letter-spacing: -0.02em;
  color: var(--ink);
}

/* White PNG + tint, the same model as the UMG brush: one asset per suit, the
 * colour applied at runtime. A CSS mask is how the web does "tint".
 *
 * The handoff specifies 0.40H for both rank and suit, but that is a *font
 * size* against an *image box*: a glyph fills roughly two thirds of its em,
 * a PNG fills its box entirely. Matching the number makes the pip tower over
 * the rank, so the suit is sized to match the rank optically instead. */
.card__suit {
  width: calc(var(--h) * 0.28);
  height: calc(var(--h) * 0.28);
  background-color: var(--ink);
  -webkit-mask: var(--suit-src) center / contain no-repeat;
  mask: var(--suit-src) center / contain no-repeat;
}

.card--s { --suit-src: url("../assets/art/suit-spade.png"); }
.card--h { --suit-src: url("../assets/art/suit-heart.png"); }
.card--d { --suit-src: url("../assets/art/suit-diamond.png"); }
.card--c { --suit-src: url("../assets/art/suit-club.png"); }

.card--red .card__rank { color: var(--red); }
.card--red .card__suit { background-color: var(--red); }

.card--back {
  background: #16222a url("../assets/art/card-back.png") center / cover no-repeat;
  box-shadow: 0 2px 5px -2px rgba(0, 0, 0, 0.6), inset 0 0 0 1px rgba(255, 255, 255, 0.06);
}

/* An undealt board position. Pure CSS -- it is a rectangle, not art. Filled
 * rather than dashed: the board should read as five places that exist, one of
 * which is empty, not as a dotted diagram of a board yet to come. */
.card--slot {
  background: rgba(255, 255, 255, 0.035);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.05);
}

/* Deal-in: only ever applied to cards revealed on THIS street. */
@keyframes card-deal-in {
  from { opacity: 0; transform: translateY(-10px) scale(0.9) rotate(-4deg); }
  to   { opacity: 1; transform: none; }
}
.card--reveal { animation: card-deal-in 0.34s cubic-bezier(0.2, 0.8, 0.25, 1) both; }

/* --------------------------------------------------------- glass panelling */

.panel {
  border-radius: 18px;
  padding: 13px;
  background: linear-gradient(180deg, var(--panel-top), var(--panel-bottom));
  box-shadow: var(--panel-shadow), inset 0 0 0 1px var(--panel-stroke);
  backdrop-filter: blur(3px);
}

/* --------------------------------------------------------------- the seat */

.seat {
  position: relative;
  width: 460px;
  /* Eased, and to the same 0.18s as the panel's ring below: when `.seat--acting`
   * toggles, the slide-in and the ring arrive together and, more importantly,
   * leave together the moment the turn passes. Transform is post-layout, so
   * sliding one seat never nudges the others. Opacity is slower, for the gentle
   * fade of the non-winners when the hand is decided (see .seat--muted). */
  transition: transform 0.18s ease, opacity 0.4s ease;
}

/* The hand is over: every seat but the winner fades back so the eye lands on who
 * took it. Applied to the whole seat, so its ring and badges fade with it; the
 * winner keeps full opacity and its gold ring. Clears on the next hand. */
.seat--muted {
  opacity: var(--muted-opacity);
}

/* Busted out of the table for good (railbird), distinct from folding one hand.
 * Fades and desaturates the whole panel so an out seat reads as done, and does
 * not compete with the seats still contesting the table. */
.seat--out {
  opacity: 0.38;
  filter: grayscale(0.65);
}

/* The acting seat steps 50px toward the table, alongside its ring, to call
 * attention to whose decision it is. Returns to the flush position when the
 * class clears. The WINNER seat borrows the same step once the hand is over --
 * the reason to look has moved from "who acts" to "who took it". */
.seat--acting,
.seat--winner {
  transform: translateX(-50px);
}

.seat__panel {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 8px;
  transition: box-shadow 0.18s ease;   /* the ring, in step with the slide above */
}

/* To act. Non-acting live seats get no ring -- the gold means "we are waiting
 * on this seat", so it must never be ambient. */
.seat--acting .seat__panel {
  box-shadow: var(--panel-shadow), inset 0 0 0 2px var(--acting-ring);
}

/* Won the hand: a fuller, brighter gold ring than the acting one, so the winner
 * reads as a result rather than a seat still on the clock. */
.seat--winner .seat__panel {
  box-shadow:
    var(--panel-shadow),
    inset 0 0 0 2px var(--gold),
    0 0 24px -6px rgba(232, 182, 74, 0.55);
}

.seat--folded .seat__head,
.seat--folded .seat__body {
  opacity: var(--folded-opacity);
  filter: saturate(var(--folded-saturate));
}

/* head row: name .......... model chip .. win% */

.seat__head {
  display: flex;
  align-items: center;
  gap: 12px;
}

.seat__name {
  flex: 1;
  min-width: 0;
  font-weight: 800;
  font-size: 25px;
  letter-spacing: 0.02em;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Always present, even when empty. The odds change every street and vanish
 * when a seat folds; without a reserved column the model chip beside them
 * would slide around, and a broadcast overlay must not twitch. */
.seat__win {
  flex: 0 0 auto;
  min-width: 76px;
  text-align: right;
  font-family: var(--mono);
  font-weight: 700;
  font-size: 30px;
  letter-spacing: -0.01em;
  color: var(--gold);
  font-variant-numeric: tabular-nums;
}

/* body row: two hole cards | stack over action chip */

.seat__body {
  display: flex;
  align-items: center;
  gap: 15px;
}

.seat__hole {
  display: flex;
  gap: 8px;
  flex: 0 0 auto;
}

.seat__info {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}

.seat__stack {
  position: relative;              /* anchors the floating delta */
  font-family: var(--mono);
  font-weight: 700;
  font-size: 21px;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

/* Stack-change feedback. The number is count-rolled in JS (hud.js
 * _renderStack); these classes carry the colour flash and the scale pop that
 * ride on top. A gain pops harder than a loss on purpose -- winning a pot
 * should feel bigger than posting a blind. The classes are added to the freshly
 * built span each render, so the animation fires from its start every time. */
.seat__stack.is-gain {
  animation: stack-gain 620ms ease-out;
}
.seat__stack.is-loss {
  animation: stack-loss 520ms ease-out;
}

@keyframes stack-gain {
  0%   { color: var(--stack-gain); transform: scale(1); }
  28%  { transform: scale(1.14); }
  100% { color: var(--text); transform: scale(1); }
}
@keyframes stack-loss {
  0%   { color: var(--stack-loss); transform: scale(1); }
  30%  { transform: scale(1.06); }
  100% { color: var(--text); transform: scale(1); }
}

/* The floating delta ("+320" / "-20"). Reserved for the SILENT moments -- a
 * posted blind and a won pot -- where nothing on the felt is moving; ordinary
 * bets already animate chips and a character, so they get only the flash above.
 * Rises a little and fades, anchored to the right of the stack number. */
.seat__delta {
  position: absolute;
  left: calc(100% + 10px);
  top: 50%;
  white-space: nowrap;
  font-family: var(--mono);
  font-weight: 800;
  font-size: 16px;
  pointer-events: none;
  animation: stack-delta 1100ms ease-out forwards;
}
.seat__delta--gain { color: var(--stack-gain); }
.seat__delta--loss { color: var(--stack-loss); }

@keyframes stack-delta {
  0%   { opacity: 0; transform: translateY(-30%); }
  18%  { opacity: 1; transform: translateY(-60%); }
  100% { opacity: 0; transform: translateY(-140%); }
}

/* Motion is decoration here: the colour still reads without it. Drop the scale
 * pop and the drift for anyone who asks for reduced motion, keep a plain fade. */
@media (prefers-reduced-motion: reduce) {
  .seat__stack.is-gain,
  .seat__stack.is-loss {
    animation: none;
  }
  .seat__delta {
    animation: stack-delta-still 900ms ease-out forwards;
  }
  @keyframes stack-delta-still {
    0%, 70% { opacity: 1; transform: translateY(-60%); }
    100%    { opacity: 0; transform: translateY(-60%); }
  }
}

/* ------------------------------------------------------------ model chip */

.chip-model {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex: 0 0 auto;
  padding: 4px 13px;
  border-radius: 999px;
  background: var(--model-bg);
  color: var(--model);
  font-weight: 800;
  font-size: 15px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  /* Models are named by whoever claimed the seat, so the length is not ours to
   * control. Truncate rather than let a long id push the win % off the panel. */
  max-width: 190px;
  white-space: nowrap;
  overflow: hidden;
}

.chip-model > span:last-child {
  overflow: hidden;
  text-overflow: ellipsis;
}

.chip-model__dot {
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--model-dot);
}

/* ----------------------------------------------------------- winner badge
 * Sits in the odds slot of the winning seat once the hand is decided. Gold like
 * the POT tab and the BB button, so a win reads as the pot coming this way. */

.chip-winner {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  flex: 0 0 auto;
  padding: 5px 13px;
  border-radius: 999px;
  background: linear-gradient(180deg, var(--gold), var(--gold-deep));
  color: #14161a;
  font-weight: 800;
  font-size: 15px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  white-space: nowrap;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.2),
              0 4px 14px -4px rgba(232, 182, 74, 0.6);
}

.chip-winner__amt {
  font-family: var(--mono);
  font-weight: 700;
  letter-spacing: 0;
}

/* ----------------------------------------------------------- action chip */

.chip-action {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 5px 15px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.06);
  color: var(--text);
  font-weight: 800;
  font-size: 17px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}

.chip-action__dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--dot, var(--act-check));
}

.chip-action__amt {
  font-family: var(--mono);
  font-weight: 700;
  letter-spacing: 0;
}

.chip-action[data-action="CHECK"] { --dot: var(--act-check); }
.chip-action[data-action="CALL"]  { --dot: var(--act-call); color: #bcd6f5; }
.chip-action[data-action="BET"],
.chip-action[data-action="RAISE"] {
  --dot: var(--act-raise);
  color: #f4d9a6;
  background: rgba(224, 147, 46, 0.14);
}
.chip-action[data-action="ALL_IN"] {
  --dot: var(--act-allin);
  color: #f6b5ae;
  background: rgba(212, 59, 48, 0.16);
}
.chip-action[data-action="FOLD"] { --dot: var(--act-fold); color: var(--text-faint); }

/* -------------------------------------------------- position badge (D/SB/BB)
 * Anchored on the seat's inner edge and centred on the CARD row, not on the
 * panel -- so it lines up across seats whose head rows differ in height.
 * Deliberately a sibling of the dimmed content: position is a fact about the
 * table, so a folded dealer still shows a full-strength button.
 */

.seat__badge {
  position: absolute;
  right: 0;
  /* Vertically centred on the 100px card row: panel padding + half the gap the
   *  badge leaves in it. Keep the badge height here in sync with `height`. */
  bottom: calc(13px + (100px - 45px) / 2);
  transform: translateX(40%);
  z-index: 2;
  width: 45px;
  height: 45px;
  border-radius: 999px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-size: 20px;
  letter-spacing: 0.01em;
  box-shadow: 0 3px 8px -2px rgba(0, 0, 0, 0.75), inset 0 0 0 1px rgba(0, 0, 0, 0.3);
}

/* Two characters need to step down a size to stay inside the circle. */
.seat__badge--sb,
.seat__badge--bb { font-size: 16px; }

.seat__badge--d {
  background: radial-gradient(circle at 40% 32%, #fff, #c7ccd1);
  color: #14161a;
}
.seat__badge--sb {
  background: radial-gradient(circle at 40% 32%, #363c44, #1c2127);
  color: var(--text);
  box-shadow: 0 3px 8px -2px rgba(0, 0, 0, 0.75), inset 0 0 0 2px rgba(232, 182, 74, 0.55);
}
.seat__badge--bb {
  background: radial-gradient(circle at 40% 32%, var(--gold), var(--gold-deep));
  color: #161311;
}

/* ---------------------------------------------------------------- the pot */

.pot {
  display: inline-flex;
  align-items: stretch;
  border-radius: 10px;
  overflow: hidden;
  background: var(--pot-plate);
  box-shadow: 0 8px 22px -8px rgba(0, 0, 0, 0.8), inset 0 0 0 1px rgba(232, 182, 74, 0.28);
}

.pot__label {
  display: flex;
  align-items: center;
  padding: 0 18px;
  font-weight: 800;
  font-size: 18px;
  letter-spacing: 0.18em;
  text-indent: 0.18em;   /* trailing letter-space would otherwise skew the tab */
  color: #0c0f12;
  background: linear-gradient(180deg, var(--gold), var(--gold-deep));
}

.pot__amount {
  display: flex;
  align-items: center;
  padding: 8px 16px;
  font-family: var(--mono);
  font-weight: 700;
  font-size: 31px;
  color: var(--gold);
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------- the street */

.street__cards {
  display: flex;
  gap: 15px;
}

/* The street name as its own plate, under the board. */
.street-label {
  display: inline-flex;
  align-items: center;
  padding: 8px 20px;
  border-radius: 10px;
  background: linear-gradient(180deg, var(--panel-top), var(--panel-bottom));
  box-shadow: var(--panel-shadow), inset 0 0 0 1px var(--panel-stroke);
  font-weight: 800;
  font-size: 26px;
  letter-spacing: 0.18em;
  text-indent: 0.18em;
  color: var(--text);
}

/* A hidden widget must not leave a gap in the flex column. */
.is-hidden { display: none !important; }
