/* ──────────────────────────────────────────────────────────────────
   FYM Casino — Multiplayer Blackjack table & lobby
   Geometry: docs/blackjack-plan/GEOMETRY.md (measured, not eyeballed)

   THE HEIGHT BUDGET IS 695 px, NOT 874
   On a 402x874 phone in Telegram fullscreen the usable band is
   874 − 105 (Telegram's own ✕/⋯ pill row) − 40 (GameChrome's bar)
   − 34 (home indicator) = 695. game-chrome.css already computes that
   number as --gc-viewport-h; this file consumes it and never
   re-derives it. In particular there is no safe-area padding here:
   body already pads by --fym-safe-bottom on this screen, and the
   viewport variable already subtracts it. Doing both double-counts,
   which is how the previous table painted its controls under the
   home indicator.

   A FIXED 355x504 DESIGN BOX, SCALED AS ONE UNIT
   The table this replaces was a flex column of fixed bands with a
   340 px felt and three seats in a row. Five seats in a U is a
   geometry problem with an answer in a fixed coordinate space and a
   fight you lose in flexbox at 402 px. So the felt, the rail, the
   legend, the dealer station and all five pods live inside a
   355x504 box positioned in design units, and ONE transform —
   --bjt-tz-scale = min(1, slotW/355, slotH/504) — fits it to the
   phone. This is poker's mechanism (mp-poker.css:135-153,
   mp-poker-table.js:292-306) with an mpk- → bjt- rename.

   NOTHING INSIDE THE BOX MAY BE MEDIA-QUERIED. The box scales; a
   media query that changes a number inside it silently breaks every
   measured coordinate in GEOMETRY.md. The short-phone block at the
   foot of this file only touches the bands OUTSIDE the box.

   Poker's visual language, not poker's stylesheet: mp-poker.css is
   scoped to #mp-poker-table-screen in 303 places, so "reuse it by
   keeping the class names" was never true. The walnut rail, the felt
   body, the 240 px feTurbulence tile at 6 % in overlay blend, the
   inner vignette and the 2 px gold ring are lifted verbatim from
   mp-poker.css:156-204. Only the border-radius and the highlight's
   position and extent differ, because a blackjack table is a D — flat
   where the dealer stands, deeply rounded across the players' arc.
   ────────────────────────────────────────────────────────────────── */

#mp-bj-table-screen {
  --bjt-gold:   #c9a13b;
  --bjt-goldhi: #e8c86a;
  --bjt-ink:    #d8d2c6;
  --bjt-muted:  #8b8271;
  --bjt-plate:  #cfc8ba;
  --bjt-red:    #c04038;
  --bjt-blk:    #232a33;
  --bjt-win:    #5f9f7a;
  --bjt-loss:   #cf5f52;
  --bjt-felt-a: #2e6b4f;
  --bjt-felt-b: #10271d;

  /* The three bands outside the design box. The stage gets whatever
     is left, and the scale follows from that — so these three numbers
     are the whole layout budget.

     WAVE 5 SPENT THE 112. The wave-2 builder left the control band at
     112 px because the betting phase needed two rows — a chip rail and
     a CLEAR/BET row under it — and a band that is 112 in one phase has
     to be 112 in all of them (GEOMETRY §7 invariant 3). Moving the
     decision buttons into an overlay ABSOLUTELY POSITIONED INSIDE the
     band is what buys the 34 px back: whatever the overlay renders, the
     band is a fixed flex basis and the stage never resizes.

     34 + 96 + 78 = 208, so the stage is 695 − 208 = 487 and the box
     renders at 487/504 = 0.966 — which is the number GEOMETRY §7.3
     recorded from the mockup, and comfortably above the 0.9 floor where
     the legend drops its two small lines. */
  --bjt-head-h: 34px;
  --bjt-hero-h: 96px;
  --bjt-ctrl-h: 78px;

}

/* THE .active SCOPE IS NOT OPTIONAL, and leaving it off shipped a bug to
   production. `display: flex` on an #id selector has specificity 0,1,0,0
   and beats `.screen.active { display: block }` at 0,0,2,0 — so this
   screen was displayed whether or not it was the active one. The felt
   showed through underneath the games lobby, and tapping the multiplayer
   ROULETTE tile navigated correctly and then landed the player on a
   blackjack table, because the blackjack table had never left.
   mp-poker.css:19 does it right and its comment says why; this file
   copied poker's mechanism without copying the warning.

   The custom properties above stay unscoped on purpose: they cost
   nothing while hidden, and a variable that only exists on the active
   screen is a trap for anything that reads one during teardown. */
#mp-bj-table-screen.active {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  height: var(--gc-viewport-h, 100dvh);
  /* theme.css ships `.screen { min-height: calc(100vh − …) }`, which
     would stretch this past the measured height on a short webview */
  min-height: 0;
  /* …and `.screen { padding: 16px }`, which under the global
     border-box would take 32 px off the height budget and 32 off the
     width. The table this replaces never noticed because its root was
     position:absolute;inset:0 and resolved against the padding box; a
     flex root in normal flow does notice, and 32 px is the difference
     between the felt at 0.915 and at 0.85 with the legend degraded. */
  padding: 0;
  overflow: hidden;
  background:
    radial-gradient(150% 100% at 50% 0%, #18130e 0%, #0b0806 55%, #070503 100%);
  color: var(--bjt-ink);
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
  -webkit-user-select: none;
  user-select: none;
}

/* The escape hatch, poker's (mp-poker.css:42-46). Below the floor the
   scaled box is too small to read, so the layout is forced TALLER than
   the viewport and the page scrolls instead — the stage slot then gets
   its share of 470 rather than its share of 380. The JS toggles the
   class off the screen's own measured height. */
#mp-bj-table-screen.bjt-scroll { overflow-y: auto; }
#mp-bj-table-screen.bjt-scroll .bjt-root {
  flex: 1 0 auto;
  min-height: 470px;
}

/* The screen's own back control. GameChrome clicks this rather than
   navigating itself, so every teardown the button already ran still
   runs — which is why the class and the onclick both have to survive
   any rewrite of this file. CSS hides it; a hidden button still
   fires .click(). */
#mp-bj-table-screen .mpbj-header-btn {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  opacity: 0;
}

/* ── The four bands ──────────────────────────────────────────────── */

#mp-bj-table-screen .bjt-root {
  position: relative;
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  width: 100%;
  max-width: 402px;
  min-height: 0;
  overflow: hidden;
}

/* The elastic slot. min-height:0 is load-bearing: without it the flex
   item refuses to shrink below its content and the control band is
   pushed off screen. The 504 px child is position:absolute precisely
   so it can never do that pushing in the first place. */
#mp-bj-table-screen .bjt-stage {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
}
#mp-bj-table-screen .bjt-tzscale {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 355px;
  height: 504px;
  transform: translate(-50%, -50%) scale(var(--bjt-tz-scale, 1));
}
#mp-bj-table-screen .bjt-tz {
  position: relative;
  width: 355px;
  height: 504px;
}

/* ── Table head (34 px) ──────────────────────────────────────────── */

/* A FLEX BASIS IS NOT A HEIGHT UNTIL min-height SAYS SO.
   `flex: 0 0 34px` fixes the basis, but a column flex item's automatic
   minimum size is its CONTENT, so anything taller than 34 inside raises
   the band and the stage loses the difference. style.css:12876 ships an
   app-wide `button, .btn { min-height: 40px }` tap floor; .bjt-shoe-info
   is a <button>, so the head band rendered 40 px tall against a declared
   34 and the stage came out 481 instead of GEOMETRY §7.3's 487 — the
   table at 0.954 rather than 0.966, on every phone, since wave 2.
   Measured in a browser with the production cascade loaded; a harness
   that omits style.css sees 34 and reports the document's number back.

   These three lines are the whole layout budget (see --bjt-head-h et al
   above), so ALL THREE BANDS carry `min-height: 0` next to their own
   basis — head here, hero and control band at their own rules. Stated
   three times rather than once in a grouped selector on purpose: a band
   that cannot grow is the entire mechanism behind GEOMETRY §7
   invariant 3, and it belongs beside the number it protects. */
#mp-bj-table-screen .bjt-head {
  flex: 0 0 var(--bjt-head-h);
  min-height: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 14px;
  font-size: 11px;
  color: var(--bjt-muted);
}
#mp-bj-table-screen .bjt-tname {
  font-family: Georgia, serif;
  font-style: italic;
  font-size: 14px;
  font-weight: 600;
  color: var(--bjt-gold);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
#mp-bj-table-screen .bjt-decks {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
}

/* The shoe meter, shrunk from a band to a 34x5 pip. The cut card
   advances and the reshuffle ceremony fires when it is reached. The ⓘ
   is not decoration: each hand is dealt from its own committed
   shuffle, so the meter shows the RHYTHM of the table and not a
   running deck. A meter that implied a count it does not have would be
   a lie; disclosing it is what makes it a flourish. */
#mp-bj-table-screen .bjt-pip {
  position: relative;
  width: 34px;
  height: 5px;
  flex: 0 0 auto;
  border-radius: 3px;
  background: rgba(0, 0, 0, 0.5);
  box-shadow: inset 0 0 0 1px rgba(201, 161, 59, 0.22);
  overflow: hidden;
}
#mp-bj-table-screen .bjt-shoe-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0;
  background: linear-gradient(90deg, #3a6f55, #6fae87);
  transition: width 0.5s ease;
}
#mp-bj-table-screen .bjt-shoe-cut {
  position: absolute;
  top: -1px;
  bottom: -1px;
  width: 2px;
  background: var(--bjt-loss);
}
/* The Fair Play control. It opts OUT of style.css's 40 px tap floor —
   see the .bjt-head note above for what that floor cost — and gets the
   size back as a pseudo-element instead. A ::after costs no layout, so
   the target is 40x44 while the box the band has to hold is 17. It
   overhangs the band by 5 px top and bottom, onto the felt's dealer end,
   where nothing else is tappable. */
#mp-bj-table-screen .bjt-shoe-info {
  position: relative;
  min-height: 0;
  border: 0;
  background: none;
  color: var(--bjt-gold);
  font-size: 13px;
  padding: 0 2px;
  cursor: pointer;
}
#mp-bj-table-screen .bjt-shoe-info::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 40px;
  height: 44px;
  transform: translate(-50%, -50%);
}

/* ── Phase line ──────────────────────────────────────────────────
   Docked at the top of the control band rather than occupying a band
   of its own, so it costs the stage nothing. */

#mp-bj-table-screen .bjt-phase {
  position: absolute;
  left: 0;
  right: 0;
  top: 2px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-size: 10px;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--bjt-muted);
}
#mp-bj-table-screen .bjt-phase b {
  color: var(--bjt-goldhi);
  font-weight: 600;
}
#mp-bj-table-screen .bjt-clock {
  min-width: 24px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  padding: 1px 6px;
  border-radius: 7px;
  background: rgba(0, 0, 0, 0.4);
  box-shadow: inset 0 0 0 1px rgba(201, 161, 59, 0.25);
  color: var(--bjt-ink);
}
/* Untimed phases leave this empty, and an empty pill beside the phase
   name reads as a countdown that has broken. */
#mp-bj-table-screen .bjt-clock:empty { display: none; }

/* CLEAR lives on the phase line, not in the control row.
   78 px of band is one 44 px row and no more, and that row is spent on
   five chips plus a BET button carrying its own amount — 240 + 6 + 84 =
   330, which still fits the 340 a 360 px phone leaves. There is no
   seventh cell for an undo, so it goes in the strip above, which is
   otherwise dead space to the right of a centred phase label.

   It is 20 px tall, under the 44 px floor the tap targets elsewhere
   hold to. That is deliberate and it is the only control here that
   breaks it: clearing staged chips costs nothing and is itself the undo
   for a mis-tap, so the cost of missing it is one more tap. Every
   control that moves money — the chips, BET, and all four action
   pills — is 44. */
/* THE SAME 40 px FLOOR, ONE ROW DOWN. style.css:12876's
   `button { min-height: 40px }` beats a plain `height`, so this button
   declared 20 and rendered 40 — on a phase line that is 17 px tall,
   which put its box 23 px past the line and over the chip rail, under
   BET. Nothing broke, because .bjt-controls is later in the DOM and
   wins the hit test where the two meet, so the only symptom was a
   40 px-tall outline sitting across the rail. Measured: box 764..804
   against a phase line of 764..781.

   The 20 px is the design; the target is restored as a pseudo-element
   below, which costs no layout. */
#mp-bj-table-screen .bjt-clear {
  position: absolute;
  right: 12px;
  top: 0;
  min-height: 0;
  height: 20px;
  padding: 0 9px;
  border: 0;
  border-radius: 7px;
  font: inherit;
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 0.11em;
  color: var(--bjt-muted);
  background: rgba(0, 0, 0, 0.4);
  box-shadow: inset 0 0 0 1px rgba(201, 161, 59, 0.22);
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.16s ease;
}
/* 20 px of plate, 34 px of thumb. It reaches 7 px past the plate top
   and bottom; above is the hero strip's last few pixels and below is
   the chip rail, and .bjt-controls is later in the DOM so the rail wins
   the hit test wherever the two overlap. */
#mp-bj-table-screen .bjt-clear::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 34px;
  transform: translateY(-50%);
}
#mp-bj-table-screen .bjt-clear.bjt-on {
  opacity: 1;
  pointer-events: auto;
  color: var(--bjt-goldhi);
}
#mp-bj-table-screen .bjt-clock.bjt-urgent {
  color: #fff;
  background: var(--bjt-loss);
  animation: bjt-pulse 0.8s ease-in-out infinite;
}
@keyframes bjt-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.55; }
}

/* ── Rail, felt, beltline, notch ─────────────────────────────────
   GEOMETRY.md §2. The radii are the second version of these numbers:
   the first draft rounded the DEALER's end, which curves the cloth
   away from exactly the corner the chip tray and shoe occupy and
   leaves the whole station floating on the page background. The
   correction then over-shot — a 158/200 bottom arc left no straight
   side to hang seats 1, 2, 4 and 5 on. 116/138 is where both
   constraints hold, measured against the pods rather than eyeballed. */

#mp-bj-table-screen .bjt-rail {
  position: absolute;
  inset: 0;
  border-radius: 38px 38px 128px 128px / 32px 32px 152px 152px;
  background:
    radial-gradient(120% 60% at 35% 0%, rgba(255, 255, 255, 0.10), transparent 55%),
    linear-gradient(160deg, #5a3d28 0%, #46301f 45%, #3a2417 100%);
  box-shadow:
    0 10px 28px rgba(0, 0, 0, 0.65),
    0 2px 6px rgba(0, 0, 0, 0.5),
    inset 0 1px 0 rgba(255, 255, 255, 0.14),
    inset 0 -2px 4px rgba(0, 0, 0, 0.5);
}

#mp-bj-table-screen .bjt-felt {
  position: absolute;
  inset: 15px;
  border-radius: 28px 28px 116px 116px / 24px 24px 138px 138px;
  background:
    radial-gradient(ellipse 86% 46% at 50% 12%, rgba(255, 255, 255, 0.10), transparent 60%),
    radial-gradient(130% 95% at 50% 2%, var(--bjt-felt-a) 0%, #1d4a36 55%, var(--bjt-felt-b) 100%);
  box-shadow: 0 0 0 2px rgba(212, 175, 55, 0.45), 0 0 0 3px rgba(0, 0, 0, 0.4);
  /* the notch depends on this */
  overflow: hidden;
}
#mp-bj-table-screen .bjt-felt::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  mix-blend-mode: overlay;
  opacity: 0.06;
  pointer-events: none;
}
#mp-bj-table-screen .bjt-felt::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: inset 0 0 90px 30px rgba(0, 0, 0, 0.55),
              inset 0 2px 6px rgba(0, 0, 0, 0.6);
}

/* The dealer's cut-out. Clipped by the felt's overflow, so only its
   lower arc shows — the semicircle a dealer stands in, at a cost of
   zero playable felt. */
#mp-bj-table-screen .bjt-notch {
  position: absolute;
  left: 50%;
  top: -46px;
  transform: translateX(-50%);
  width: 186px;
  height: 96px;
  border-radius: 0 0 100px 100px / 0 0 62px 62px;
  border-bottom: 1.5px solid rgba(232, 217, 176, 0.13);
  background: radial-gradient(ellipse 100% 78% at 50% 0%,
              rgba(255, 255, 255, 0.05), transparent 70%);
  pointer-events: none;
}

#mp-bj-table-screen .bjt-beltline {
  position: absolute;
  inset: 32px;
  border-radius: 18px 18px 100px 100px / 16px 16px 118px 118px;
  border: 1px solid rgba(255, 255, 255, 0.05);
  pointer-events: none;
}

/* ── Felt legend ─────────────────────────────────────────────────
   GEOMETRY.md §5. Not full-width: the flanks belong to the seat ring
   and only the centre column x 92-263 is free — a full-width arc runs
   straight through seats 1 and 5. No spade ornaments either; they
   pushed line 1 five pixels past its own arc into seat 1's cards.

   Below scale 0.9 lines 2 and 3 land under 7 px, so they drop and only
   the line that states the actual contract survives. The full rules
   are one tap away in the fair-play sheet at a readable size. */

#mp-bj-table-screen .bjt-legend {
  position: absolute;
  left: 92px;
  top: 191px;
  width: 171px;
  height: 76px;
  pointer-events: none;
}
#mp-bj-table-screen .bjt-legend text {
  font-family: Georgia, serif;
  fill: rgba(232, 217, 176, 0.24);
  letter-spacing: 0.5px;
}
#mp-bj-table-screen .bjt-legend .bjt-l1 { font-size: 11px; font-weight: 700; letter-spacing: 0.35px; }
#mp-bj-table-screen .bjt-legend .bjt-l2 { font-size: 7.4px; font-style: italic; }
#mp-bj-table-screen .bjt-legend .bjt-l3 { font-size: 8px; }
#mp-bj-table-screen .bjt-terse .bjt-l2,
#mp-bj-table-screen .bjt-terse .bjt-l3 { display: none; }
/* Insurance is open: the line that prices it lights up. Same reflex
   help single-player gives. */
#mp-bj-table-screen .bjt-ins-open .bjt-l3 { fill: rgba(232, 200, 106, 0.5); }

/* ── Dealer station ──────────────────────────────────────────────
   GEOMETRY.md §4. The plaque is data, the tray is decoration, and the
   shoe is neither — it is the origin of every card's flight, which is
   its whole job. */

#mp-bj-table-screen .bjt-plaque {
  position: absolute;
  left: 24px;
  top: 30px;
  width: 72px;
  height: 40px;
  border-radius: 5px;
  background: linear-gradient(160deg, #d9ab54, #a8802c 55%, #7d5d1c);
  box-shadow: 0 3px 7px rgba(0, 0, 0, 0.55),
              inset 0 1px 0 rgba(255, 255, 255, 0.45),
              inset 0 -2px 3px rgba(0, 0, 0, 0.35);
  transform: perspective(280px) rotateX(26deg);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: 8px;
  line-height: 1.25;
  font-weight: 800;
  letter-spacing: 0.06em;
  color: #2a1d05;
  font-variant-numeric: tabular-nums;
}

#mp-bj-table-screen .bjt-tray {
  position: absolute;
  left: 118px;
  top: 22px;
  width: 120px;
  height: 38px;
  border-radius: 5px;
  transform: perspective(320px) rotateX(30deg);
  background: linear-gradient(180deg, #c69a3f, #8a6520);
  box-shadow: 0 4px 9px rgba(0, 0, 0, 0.55), inset 0 1px 0 rgba(255, 255, 255, 0.4);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 2px;
  padding: 0 5px 3px;
}
#mp-bj-table-screen .bjt-tray i {
  flex: 1;
  height: 26px;
  border-radius: 2px;
  display: block;
  background: repeating-linear-gradient(180deg,
              var(--bjt-c) 0 3px, rgba(255, 255, 255, 0.85) 3px 4px);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
}

/* left 252, not 262: at 262 the perspective-widened right edge sat
   flush against the felt boundary. 252 keeps ~9 px of clearance there
   and a 10 px gap from the tray. */
#mp-bj-table-screen .bjt-shoe {
  position: absolute;
  left: 252px;
  top: 18px;
  width: 74px;
  height: 58px;
  transform: perspective(340px) rotateX(24deg) rotateZ(-7deg);
}
#mp-bj-table-screen .bjt-shoe-body {
  position: absolute;
  inset: 0;
  border-radius: 4px 4px 3px 3px;
  background: linear-gradient(150deg, rgba(214, 232, 240, 0.42),
              rgba(150, 180, 196, 0.24) 55%, rgba(90, 120, 136, 0.34));
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.55),
              inset 0 1px 0 rgba(255, 255, 255, 0.55),
              inset 0 -2px 4px rgba(0, 0, 0, 0.3);
  border: 1px solid rgba(226, 242, 248, 0.5);
}
#mp-bj-table-screen .bjt-shoe-deck {
  position: absolute;
  left: 7px;
  right: 7px;
  top: 8px;
  height: 30px;
  border-radius: 2px;
  background: repeating-linear-gradient(45deg, #7a2f35 0 4px, #6a262c 4px 8px);
  box-shadow: inset 0 0 0 1.5px rgba(232, 217, 176, 0.35);
}
#mp-bj-table-screen .bjt-shoe-lip {
  position: absolute;
  left: 4px;
  right: 4px;
  bottom: 4px;
  height: 9px;
  border-radius: 2px;
  background: linear-gradient(180deg, #c69a3f, #8a6520);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
}

/* The shoe works. Cards are already SEEN to leave its mouth; what was
   missing is the object acknowledging it — a real shoe rocks a little
   as a card is pulled and the stack settles a pixel lower.

   The keyframe starts AND ends on the declared transform, byte for
   byte. Anything else snaps the moment the class comes off, which is
   the lesson the deal keyframe's 100 % already records. */
#mp-bj-table-screen .bjt-shoe.bjt-working {
  animation: bjt-shoe-pull 0.34s ease-out;
}
@keyframes bjt-shoe-pull {
  0%   { transform: perspective(340px) rotateX(24deg) rotateZ(-7deg); }
  38%  { transform: perspective(340px) rotateX(26.5deg) rotateZ(-8.6deg)
                    translate(-1.5px, 1px); }
  100% { transform: perspective(340px) rotateX(24deg) rotateZ(-7deg); }
}
/* …and the stack inside it drops as it empties. Bound to the same
   class so the two read as one gesture. */
#mp-bj-table-screen .bjt-shoe.bjt-working .bjt-shoe-deck {
  animation: bjt-shoe-settle 0.34s ease-out;
}
@keyframes bjt-shoe-settle {
  0%, 100% { transform: translateY(0); }
  45%      { transform: translateY(1.5px); }
}

/* ── Dealer hand ─────────────────────────────────────────────────── */

#mp-bj-table-screen .bjt-dealer {
  position: absolute;
  left: 0;
  right: 0;
  top: 86px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
}
#mp-bj-table-screen .bjt-dealer-name {
  font-family: Georgia, serif;
  font-style: italic;
  font-size: 10px;
  color: var(--bjt-gold);
  letter-spacing: 0.05em;
}
/* The dealer's hand is the one place with real depth. Seat pods get
   none, so their cards read as a flat rake — that asymmetry is
   deliberate in the reference rendering. */
#mp-bj-table-screen .bjt-dealer-cards {
  display: flex;
  gap: 3px;
  min-height: 56px;
  perspective: 640px;
}
/* The dealer's turn is the only stretch of the round where nobody can
   do anything, and an inert table for four seconds reads as a stall.
   One breathing line under the nameplate is enough to say the house is
   playing — no spinner, no text change. */
#mp-bj-table-screen .bjt-dealer-name {
  position: relative;
  transition: color 0.3s ease, text-shadow 0.3s ease;
}
#mp-bj-table-screen .bjt-playing .bjt-dealer-name {
  color: var(--bjt-goldhi);
  text-shadow: 0 0 12px rgba(232, 200, 106, 0.55);
}
#mp-bj-table-screen .bjt-playing .bjt-dealer-name::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -3px;
  width: 34px;
  height: 1px;
  transform: translateX(-50%);
  background: linear-gradient(90deg, transparent,
              rgba(232, 200, 106, 0.85), transparent);
  animation: bjt-dealer-breath 1.5s ease-in-out infinite;
}
@keyframes bjt-dealer-breath {
  0%, 100% { opacity: 0.25; width: 22px; }
  50%      { opacity: 1;    width: 46px; }
}

/* ── Seat pods ───────────────────────────────────────────────────
   GEOMETRY.md §3. 88 px wide, centred on the anchor. That width is
   what forces 13 %/87 % rather than poker's 9 %/91 %: at 9 % an
   88-wide pod starts at x = −12, outside the box. */

#mp-bj-table-screen .bjt-pod {
  position: absolute;
  width: 88px;
  transform: translate(-50%, -50%);
  text-align: center;
}
#mp-bj-table-screen .bjt-seat-hands {
  display: flex;
  gap: 3px;
  align-items: flex-end;
  justify-content: center;
  min-height: 34px;
}
#mp-bj-table-screen .bjt-hand {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 2px;
  border-radius: 6px;
  transition: box-shadow 0.2s, background 0.2s;
}
/* Everyone acts inside one shared window, so "still live" is true of
   four hands at once and four gold rings is noise, not a signal. The
   felt gets a hairline; the strong ring is reserved for YOUR seat and
   for the hero strip's active hand, which are the two places it
   actually means "you". */
#mp-bj-table-screen .bjt-hand.bjt-acting {
  box-shadow: inset 0 0 0 1px rgba(232, 200, 106, 0.28);
}
#mp-bj-table-screen .bjt-hand.bjt-acting.bjt-mine {
  background: rgba(232, 200, 106, 0.09);
  box-shadow: 0 0 0 1.5px var(--bjt-gold), 0 0 16px rgba(232, 200, 106, 0.4);
}
/* Your own seat carries the total only — the cards live in the hero
   strip. Given a bit more presence so the pod does not read as empty. */
#mp-bj-table-screen .bjt-hand.bjt-mine .bjt-total {
  min-width: 30px;
  padding: 2px 7px;
  font-size: 12px;
}
#mp-bj-table-screen .bjt-hand-cards {
  display: flex;
}
/* Fanned, not stacked: a split-to-four seat can show eleven cards and
   a row of them would be narrower than one card each. */
#mp-bj-table-screen .bjt-hand-cards > * + * { margin-left: -9px; }

#mp-bj-table-screen .bjt-total {
  display: inline-block;
  min-width: 22px;
  padding: 1px 5px;
  border-radius: 8px;
  font-size: 10px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  text-align: center;
  color: #0d1310;
  background: rgba(232, 217, 176, 0.92);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
}
#mp-bj-table-screen .bjt-total.bjt-bust { background: var(--bjt-loss); color: #fff; }
#mp-bj-table-screen .bjt-total.bjt-nat  { background: var(--bjt-goldhi); }
#mp-bj-table-screen .bjt-total.bjt-soft { background: rgba(180, 214, 196, 0.92); }

/* max-content, not 100 %: an empty seat's plate should be a small
   label centred under the anchor, not an 88 px slab of black. */
#mp-bj-table-screen .bjt-seat-plate {
  display: flex;
  align-items: center;
  gap: 4px;
  width: max-content;
  max-width: 88px;
  margin: 3px auto 0;
  padding: 2px 6px;
  border-radius: 10px;
  background: rgba(0, 0, 0, 0.46);
  box-shadow: inset 0 0 0 1px rgba(201, 161, 59, 0.22);
  font-size: 9px;
  color: var(--bjt-plate);
}
#mp-bj-table-screen .bjt-seat-plate.bjt-empty { opacity: 0.38; }

/* ── An empty chair you may take ─────────────────────────────────
   THE ONLY WAY INTO MULTI-SEAT PLAY. The server has allocated extra
   seats since wave 1 and nothing in the client ever asked for one:
   the lobby row sends a bodyless join, which is deliberately an
   idempotent rejoin, and an empty pod carried no control at all.

   0.38 opacity is the right weight for "nobody is sitting here" and
   exactly the wrong one for "tap this" — dimmed is the convention for
   unavailable everywhere else on this screen, including the chips the
   rail greys out. So a chair you can actually take comes back to full
   weight and takes the dashed gold ring, which is this table's own
   mark for a thing that is offered but not yet committed (the staged
   stake capsule uses it). At the cap the plate stays dim and keeps its
   listener — a tap there answers with the cap rather than with
   nothing, which is the difference between a rule and a dead pixel.

   The tap area is the plate's own box plus a ::after, for the reason
   every other control on this screen takes one: the plate is 15 px
   tall inside a scaled box and its own height must not grow. */
#mp-bj-table-screen .bjt-seat-plate.bjt-sit {
  position: relative;
  opacity: 1;
  cursor: pointer;
  color: var(--bjt-goldhi);
  background: rgba(0, 0, 0, 0.62);
  box-shadow: inset 0 0 0 1px rgba(201, 161, 59, 0.22);
  outline: 1px dashed rgba(232, 200, 106, 0.7);
  outline-offset: -1px;
  letter-spacing: 0.04em;
  font-weight: 700;
}
/* 44 REAL PIXELS, NOT 44 DESIGN UNITS. This is the only tap target on
   the screen that lives INSIDE the scaled box, so a flat 44 would be
   42.5 px on a 402 phone and 38 on a 360 one — the whole point of the
   pseudo-element is to hold the target at 44 wherever the table is
   drawn. Dividing by the box's own scale undoes it exactly. The plain
   declaration stays as the fallback: an engine that will not divide by
   a var() drops the second line and keeps a target that is merely
   slightly small, rather than one that is zero wide. */
#mp-bj-table-screen .bjt-seat-plate.bjt-sit::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 44px;
  height: 44px;
  width: calc(44px / var(--bjt-tz-scale, 1));
  height: calc(44px / var(--bjt-tz-scale, 1));
  transform: translate(-50%, -50%);
}
#mp-bj-table-screen .bjt-seat-plate.bjt-sit:active {
  background: rgba(201, 161, 59, 0.22);
}

/* A player may hold three seats, so three pods can carry the same
   face. The gold ring is what makes "these are mine" readable at a
   glance without reading the names. */
#mp-bj-table-screen .bjt-seat-plate.bjt-you {
  box-shadow: inset 0 0 0 1.4px var(--bjt-gold);
  color: var(--bjt-goldhi);
}
#mp-bj-table-screen .bjt-av {
  width: 15px;
  height: 15px;
  border-radius: 50%;
  object-fit: cover;
  background: linear-gradient(140deg, #5a4a2e, #2b2418);
  box-shadow: 0 0 0 1px rgba(201, 161, 59, 0.4);
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  /* 8, not 7. GEOMETRY §5 sets a 7 px floor for what the felt renders,
     and the box scale is 0.966 on a 402 px phone — so a 7 px monogram
     lands at 6.76 and is the only thing inside the box under the floor.
     Measured, not reasoned: 8 px reads 7.73 there, and 7.0 at the
     0.877 scale a 667 px webview produces. */
  font-size: 8px;
  font-weight: 800;
  line-height: 1;
  color: var(--bjt-goldhi);
}
#mp-bj-table-screen .bjt-nm {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 46px;
}

/* ── Win streak ──────────────────────────────────────────────────
   TWO OR MORE WINS, NEVER A LOSING RUN. That constraint is not a
   styling detail, it is the reason this element is allowed to exist at
   all: a counter that goes up when you win is a slot mechanic on a
   table game, and the plan says plainly (REDESIGN §8, §10.2) that it
   pushes toward chasing. Showing it only on a run of wins makes it a
   small celebration; showing it on a run of losses would make it a
   scoreboard telling a losing player how far down they are, which is
   the exact shape of the harm. There is deliberately no CSS here that
   could render a negative value.

   Gold at 2-3, amber at 4-5, and a slow pulse from 6 — the pulse is the
   only motion, it is 2.4 s, and prefers-reduced-motion drops it. */
#mp-bj-table-screen .bjt-streak {
  flex: 0 0 auto;
  margin-left: 1px;
  padding: 0 3px;
  border-radius: 5px;
  font-size: 7.5px;
  font-weight: 800;
  line-height: 1.5;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  color: #241a06;
  background: linear-gradient(180deg, #e8c86a, #c9a13b);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
}
#mp-bj-table-screen .bjt-streak.bjt-s-warm {
  background: linear-gradient(180deg, #f2b45c, #d97e2b);
}
#mp-bj-table-screen .bjt-streak.bjt-s-hot {
  background: linear-gradient(180deg, #f6c86a, #d8592f);
  color: #2a0f04;
  animation: bjt-streak-pulse 2.4s ease-in-out infinite;
}
@keyframes bjt-streak-pulse {
  0%, 100% { box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); }
  50%      { box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5),
                         0 0 9px rgba(232, 200, 106, 0.75); }
}
/* The plate is capped at 88 px and the badge costs about 18 of them, so
   the name yields rather than the plate growing past its pod. A class
   from paintSeats rather than :has(), which is newer than some of the
   webviews this ships into. */
#mp-bj-table-screen .bjt-seat-plate.bjt-has-streak .bjt-nm { max-width: 30px; }
#mp-bj-table-screen .bjt-seat-bal {
  font-size: 8px;
  color: var(--bjt-muted);
  margin-top: 1px;
  font-variant-numeric: tabular-nums;
  min-height: 10px;
}
/* AN EMPTY ROW IS STILL A ROW, and on four pods out of five this one is
   always empty: only your own bankroll is on the wire, so paintSeats
   writes '' here for every other player. It was still spending 11
   design units of pod height on exactly the pods that have none to
   spare.

   The 49 % and 71 % rows are 111 units apart and a pod grows
   symmetrically from its anchor, so a pod taller than 111 lands on its
   neighbour. Measured at 402x874 before this line: seats 4 and 5
   overlapped by 2.11 units whenever they held cards, and by 11.11 in
   the payout phase, where the outcome badge paints 9 units above the
   hand — which is how seat 4's PUSH ended up behind seat 5's stake
   chip, unreadable, in the one phase the badge exists for. */
#mp-bj-table-screen .bjt-seat-bal:empty { display: none; }

#mp-bj-table-screen .bjt-seat-stake {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 3px;
  min-height: 20px;
  margin-top: 2px;
}
/* Poker's chip recipe, not a new one: the same repeating-conic-gradient
   the chip rail already paints, at pod size. The centre disc is much
   darker than the rail's — at 20 px the conic edge segments run right
   under the digits and white-on-cream is unreadable. */
#mp-bj-table-screen .bjt-stake {
  width: 21px;
  height: 21px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 8px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  color: #f6f2e6;
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.8);
  background:
    radial-gradient(circle, rgba(8, 10, 9, 0.86) 0 60%, transparent 61%),
    repeating-conic-gradient(#f4f0e6 0 22deg, var(--bjt-c, #2f5d46) 22deg 60deg);
  box-shadow: 0 2px 0 rgba(0, 0, 0, 0.45), 0 3px 6px rgba(0, 0, 0, 0.45);
}
/* THE INSURANCE CHIP IS TYPE ON THE FELT, and GEOMETRY §5 puts the
   floor at 7 px of RENDERED type. This declared 6.5, which the table's
   own 0.966 scale turned into 6.28 on a 402 px phone and 3.6 on a
   360x640 one — the smallest thing on the table, in the one phase with
   the shortest clock, stating an amount of money.

   It was missed because nothing ever drew it: no harness scenario set
   `st.insurance`, and the geometry test had no assertion naming
   .bjt-stake at all. Both now exist.

   8 px is the same floor the monogram already sits on (7.73 rendered
   at 0.966, 7.0 at the 0.877 a 667 px webview produces), and the disc
   grows to 19 so three digits stay inside the dark centre instead of
   running onto the conic edge. 19 and not 21: it stays visibly
   subordinate to the stake chip beside it, and it stays under the
   20 px min-height of .bjt-seat-stake — so the row does not get taller
   and GEOMETRY §7c's 111-unit pod budget is untouched. Measured after
   the change at 402x874: pod ink unchanged, no neighbour overlap. */
#mp-bj-table-screen .bjt-stake.bjt-ins {
  width: 19px;
  height: 19px;
  font-size: 8px;
  --bjt-c: #3d6a8a;
}
/* Chips staged but not yet sent. A dashed ring is the casino's own
   convention for "not committed", and it matters here because the tray
   stays open across several seats: without it a three-seat player
   cannot tell which of their stacks the server has taken and which is
   still one tap from being cancelled. */
#mp-bj-table-screen .bjt-stake.bjt-pending {
  background: radial-gradient(circle, rgba(8, 10, 9, 0.7) 0 60%, transparent 61%);
  box-shadow: none;
  outline: 1.5px dashed rgba(232, 200, 106, 0.75);
  outline-offset: -1px;
  color: var(--bjt-goldhi);
}

/* ── The chip's flight ───────────────────────────────────────────
   A tapped chip travels from the rail to the seat it is going on. It is
   the same trick the cards use in reverse — a vector measured after
   layout, written as --cx/--cy — except that the rail is OUTSIDE the
   scaled box and the seat is inside it, so the vector is built in
   SCREEN pixels and the flying disc is a child of the screen, not of
   the design box. A design-px vector would be wrong by the scale
   factor, which is exactly the bug the hero strip's cards taught.

   Reuses single-player's chipDropIn easing (style.css:14338). */
#mp-bj-table-screen .bjt-chipfly {
  position: fixed;
  z-index: 6;
  width: 26px;
  height: 26px;
  margin: -13px 0 0 -13px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 8px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: #f6f2e6;
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.8);
  pointer-events: none;
  background:
    radial-gradient(circle, rgba(8, 10, 9, 0.86) 0 60%, transparent 61%),
    repeating-conic-gradient(#f4f0e6 0 22deg, var(--bjt-c, #2f5d46) 22deg 60deg);
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.55);
  animation: bjt-chipfly 0.42s cubic-bezier(0.2, 0.8, 0.3, 1.05) both;
}
@keyframes bjt-chipfly {
  0%   { transform: translate(0, 0) scale(1.15); opacity: 0; }
  12%  { opacity: 1; }
  100% { transform: translate(var(--cx, 0px), var(--cy, 0px)) scale(0.72);
         opacity: 0; }
}

#mp-bj-table-screen .bjt-outcome {
  position: absolute;
  left: 50%;
  top: -9px;
  z-index: 2;
  transform: translateX(-50%);
  padding: 1px 6px;
  border-radius: 7px;
  font-size: 8px;
  font-weight: 800;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  white-space: nowrap;
  color: #fff;
}
/* The pop is on a MODIFIER, not on the badge. paintSeats rewrites its
   innerHTML on every poll, so an animation declared on .bjt-outcome
   itself replayed once a second for the whole six-second payout — a
   badge that kept jumping long after it had been read. paint() adds
   .bjt-fresh on exactly one render per round. */
#mp-bj-table-screen .bjt-outcome.bjt-fresh {
  animation: bjt-pop 0.28s cubic-bezier(0.2, 1.4, 0.4, 1);
}
#mp-bj-table-screen .bjt-outcome.bjt-o-win { background: var(--bjt-win); }
/* A natural is the one outcome the table pays 3:2 for; it gets the
   gold rather than the same green as any other win. */
#mp-bj-table-screen .bjt-outcome.bjt-o-blackjack {
  background: linear-gradient(180deg, #e8c86a, #c9a13b);
  color: #231a07;
}
#mp-bj-table-screen .bjt-outcome.bjt-o-lose,
#mp-bj-table-screen .bjt-outcome.bjt-o-bust { background: var(--bjt-loss); }
#mp-bj-table-screen .bjt-outcome.bjt-o-push { background: #6b7280; }
@keyframes bjt-pop {
  from { transform: translateX(-50%) scale(0.6); opacity: 0; }
  to   { transform: translateX(-50%) scale(1);   opacity: 1; }
}

/* ── Win effects ─────────────────────────────────────────────────
   Five people read this felt at once, so a win has to be legible from
   across the table without turning the whole thing into a firework.
   One halo behind the winning hand, and a single gold sweep across its
   cards — 0.9 s, once, not a loop. A natural gets the warmer halo
   because it is the one outcome that pays 3:2.

   Deliberately NOT applied to the losing side. There is nothing to
   celebrate and nothing worth animating about it, and a table that
   flashes red at four seats while one wins reads as a fault. */
#mp-bj-table-screen .bjt-hand.bjt-won,
#mp-bj-table-screen .bjt-hh.bjt-won {
  animation: bjt-halo 1.5s ease-out both;
}
#mp-bj-table-screen .bjt-hand.bjt-won-bj,
#mp-bj-table-screen .bjt-hh.bjt-won-bj {
  animation: bjt-halo-bj 1.7s ease-out both;
}
@keyframes bjt-halo {
  0%   { box-shadow: 0 0 0 0 rgba(95, 159, 122, 0); }
  25%  { box-shadow: 0 0 18px 4px rgba(95, 159, 122, 0.55); }
  100% { box-shadow: 0 0 0 0 rgba(95, 159, 122, 0); }
}
@keyframes bjt-halo-bj {
  0%   { box-shadow: 0 0 0 0 rgba(232, 200, 106, 0); }
  22%  { box-shadow: 0 0 22px 6px rgba(232, 200, 106, 0.7); }
  100% { box-shadow: 0 0 0 0 rgba(232, 200, 106, 0); }
}
/* The sweep. A moving highlight across the card faces, clipped to the
   card, so it reads as light crossing the table rather than as a
   rectangle drawn over it. */
#mp-bj-table-screen .bjt-won .bjt-card::before,
#mp-bj-table-screen .bjt-won-bj .bjt-card::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  overflow: hidden;
  background: linear-gradient(105deg, transparent 38%,
              rgba(255, 240, 190, 0.85) 50%, transparent 62%);
  background-size: 260% 100%;
  animation: bjt-sweep 0.9s ease-out both;
  pointer-events: none;
}
@keyframes bjt-sweep {
  from { background-position: 160% 0; opacity: 0.95; }
  to   { background-position: -60% 0; opacity: 0; }
}

/* ── Cards ───────────────────────────────────────────────────────
   Three sizes off one base: 24x34 in a pod, 40x56 in the dealer's hand
   and the hero's active hand, 28x39 in the hero's idle hands. The
   paper, the five-layer shadow and the die-cut hairline are poker's
   (mp-poker.css:229-241) — a flat white rectangle over green reads as
   a tile, not as an object resting on cloth.

   transform-origin stays at its 50 % 50 % default. Single-player's
   `center bottom` (style.css:14240) raises the visual centre by
   ~0.128·h under the 42° rake, which is ~4 px of silent error per card
   in a measured flight vector. */

#mp-bj-table-screen .bjt-card {
  position: relative;
  width: 24px;
  height: 34px;
  border-radius: 2.5px;
  background: linear-gradient(160deg, #ffffff, #f4f1ea);
  /* Four layers, not three. The first two are the paper — a lit top
     edge and a die-cut hairline. The third is contact shadow, tight and
     dark, which is what says the card is TOUCHING the cloth. The fourth
     is the cast, long and soft and offset down-right to match the
     felt's own highlight at 50 % 12 %; without it a raked card floats,
     and with the cast alone it hovers. Both together is what the
     reference photograph has. */
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.65),
    0 0 0 0.5px rgba(0, 0, 0, 0.14),
    1px 2px 4px rgba(0, 0, 0, 0.45),
    3px 8px 14px -4px rgba(0, 0, 0, 0.55);
  font-family: Georgia, serif;
  font-weight: 700;
  color: var(--bjt-blk);
  flex: 0 0 auto;
  /* the table's rake. The deal keyframe MUST land on exactly this or
     the card snaps the moment the animation class is dropped. */
  transform: rotateX(42deg);
}
#mp-bj-table-screen .bjt-card.bjt-r { color: var(--bjt-red); }
#mp-bj-table-screen .bjt-card i {
  position: absolute;
  top: 1px;
  left: 2px;
  font-style: normal;
  font-size: 8px;
  line-height: 1;
}
#mp-bj-table-screen .bjt-card b {
  position: absolute;
  left: 50%;
  top: 56%;
  transform: translate(-50%, -50%);
  font-size: 11px;
  font-weight: 400;
}
#mp-bj-table-screen .bjt-card.bjt-down {
  background:
    repeating-linear-gradient(45deg, #7a2f35 0 4px, #6a262c 4px 8px);
  box-shadow:
    inset 0 0 0 2px rgba(232, 217, 176, 0.30),
    0 0 0 0.5px rgba(0, 0, 0, 0.2),
    1px 2px 4px rgba(0, 0, 0, 0.45),
    3px 8px 14px -4px rgba(0, 0, 0, 0.55);
}
#mp-bj-table-screen .bjt-card.bjt-down i,
#mp-bj-table-screen .bjt-card.bjt-down b { display: none; }
/* The FYM mark only where it fits. At 24x34 it is four illegible
   pixels; single-player's 13 px version is clipped outright. */
#mp-bj-table-screen .bjt-dealer-cards .bjt-card.bjt-down::after,
#mp-bj-table-screen .bjt-hero-hands .bjt-card.bjt-down::after {
  content: "FYM";
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: Georgia, serif;
  font-weight: 900;
  font-size: 9px;
  letter-spacing: 0.5px;
  color: rgba(255, 235, 180, 0.9);
}

#mp-bj-table-screen .bjt-dealer-cards .bjt-card { width: 40px; height: 56px; }
#mp-bj-table-screen .bjt-dealer-cards .bjt-card i { font-size: 13px; }
#mp-bj-table-screen .bjt-dealer-cards .bjt-card b { font-size: 19px; }

/* ── A seat that has split three or four ways ─────────────────────
   THE CARDS COME OFF. The pod shows totals, exactly as your own pods
   already do at every hand count, and for the same reason stated there:
   a split-to-four hand does not fit in 88 px, and it stops fitting at
   the moment it matters most.

   Wave 4 tried to shrink instead — an 18x26 card at -7 overlap. It is
   not enough, and the shortfall is not a matter of taste. Measured in a
   browser at 402x874, seat 5's painted extent with four hands was
   x 232.13..385.56: 153 design units of content in an 88 px pod,
   **30.56 units outside the 355-wide box**, and overlapping the legend's
   first line by 23.3 x 20.1 and its second by 22.5 x 15.9. Three hands
   overflowed too, by 6.34. Both of GEOMETRY §7's first two invariants,
   broken by any opponent who splits.

   The room is not there to be found. A pod on the 49 % row has the
   legend's right edge at x 263 on one side and the box edge at 355 on
   the other: about 91 units. Wrapping to 2x2 fits the width but needs
   ~101 units of height, and the 49 % and 71 % rows are 111 apart with
   ~56 units of pod already above and below the hands — so a wrapped pod
   lands on its own neighbour. Shrinking the total pill far enough to fit
   four soft displays ("10/20") puts the type under the 7 px floor
   GEOMETRY §5 sets. Totals only is what is left, and it is the reading
   anyone takes off another player's split anyway.

   Verified by measurement after the change, not by eye: seat 5 at four
   hands is 74.4 units wide, inside the box, clear of every glyph. */
#mp-bj-table-screen .bjt-pod[data-hands="3"] .bjt-hand-cards,
#mp-bj-table-screen .bjt-pod[data-hands="4"] .bjt-hand-cards { display: none; }

/* The pill carries the whole hand now, so it is tightened rather than
   shrunk: 9 px is 8.6 px on a 402 px phone, above the floor. The HARD
   total is what paintSeats writes here — see totalHTML's `compact`
   argument — because "10/20" is five characters and four of them do not
   fit in 91 units at any legible size. */
#mp-bj-table-screen .bjt-pod[data-hands="3"] .bjt-hand,
#mp-bj-table-screen .bjt-pod[data-hands="4"] .bjt-hand { padding: 1px; }
#mp-bj-table-screen .bjt-pod[data-hands="3"] .bjt-total,
#mp-bj-table-screen .bjt-pod[data-hands="4"] .bjt-total {
  min-width: 13px;
  padding: 1px 3px;
  font-size: 9px;
}
#mp-bj-table-screen .bjt-pod[data-hands="3"] .bjt-seat-hands,
#mp-bj-table-screen .bjt-pod[data-hands="4"] .bjt-seat-hands { gap: 2px; }

/* ── The flight out of the shoe ──────────────────────────────────
   GEOMETRY.md §6. --fx/--fy are the vector from the card's resting
   centre back to the shoe's mouth, in DESIGN px, measured per card
   after layout by flightPass(). They are never divided by the scale:
   the transform sits on an ancestor of the card, so a child's
   translate is already expressed inside the scaled subtree.

   The opacity ramp is load-bearing. `both` + animation-delay holds the
   0 % state through the delay, so a card that has not been dealt yet is
   invisible and parked at the shoe. That single mechanism replaces
   poker's whole visibility-hold apparatus (mpk-dh1/dh2/hold0/hold1). */

#mp-bj-table-screen .bjt-card.bjt-deal {
  animation: bjtDealIn 0.68s cubic-bezier(0.2, 0.85, 0.3, 1) both;
  animation-delay: var(--d, 0s);
}
@keyframes bjtDealIn {
  0% {
    transform: translate(var(--fx, 0px), var(--fy, 0px))
               rotate(var(--fr, -20deg)) scale(0.55) rotateX(0deg);
    opacity: 0;
  }
  12%  { opacity: 1; }
  62%  { transform: translate(6px, 5px) rotate(1.5deg) scale(1.04) rotateX(35deg); }
  100% { transform: translate(0, 0) rotate(0deg) scale(1) rotateX(42deg); }
}

/* The hole card turning over is the beat the whole hand waits on, so
   it is a real turn: the face-DOWN card rotates to edge-on, the
   element is swapped there, and the face rotates the rest of the way.
   Cross-fading a card that is already face-up (what this used to do)
   reads as a card flipping from face-up to face-up. */
#mp-bj-table-screen .bjt-card.bjt-flipout {
  animation: bjt-flipout 0.21s ease-in both;
}
#mp-bj-table-screen .bjt-card.bjt-flipin {
  animation: bjt-flipin 0.29s ease-out both;
}
@keyframes bjt-flipout {
  from { transform: rotateX(42deg) rotateY(0deg); }
  to   { transform: rotateX(42deg) rotateY(88deg) scale(1.04); }
}
@keyframes bjt-flipin {
  from { transform: rotateX(42deg) rotateY(-88deg) scale(1.06); }
  to   { transform: rotateX(42deg) rotateY(0deg)   scale(1); }
}

/* ── Hero strip ──────────────────────────────────────────────────
   OUTSIDE the design box, in real pixels, because the hero's cards and
   the controls are the two things that must not shrink with the felt.
   The flight vector for these is therefore built in SCREEN px — a
   design-px vector is meaningless here. */

/* min-height:0 is not decoration here. A flex item's automatic minimum
   size is its content, so without it `flex: 0 0 88px` is only a
   suggestion: the strip grew to 97 px, ate 9 px of stage, and dropped
   the scale under the legend's 0.9 threshold. */
#mp-bj-table-screen .bjt-hero {
  flex: 0 0 var(--bjt-hero-h);
  /* The band states its own height — see the .bjt-head note for what a
     column flex item's automatic minimum does to one that does not. */
  min-height: 0;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 0 12px;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
}
#mp-bj-table-screen .bjt-hero-hands {
  display: flex;
  align-items: center;
  gap: 9px;
  flex: 1 1 auto;
  min-width: 0;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
}
#mp-bj-table-screen .bjt-hero-hands::-webkit-scrollbar { display: none; }
/* With no hands the scroller still claimed its half of the strip and
   pushed "Take a seat to play" into the right margin. */
#mp-bj-table-screen .bjt-hero-hands:empty { flex: 0 0 0; }
/* 3 + 8 label + 2 + 56 card + 2 + 14 total + 3 = 88, inside the 96 px
   band the overlay's 34 px paid for. The band is overflow:hidden, so a
   strip that outgrows it loses its total badge rather than pushing the
   felt — the 8 px of slack is what stops that happening to a hand whose
   label wraps. */
#mp-bj-table-screen .bjt-hh {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 3px 7px;
  border-radius: 9px;
  opacity: 1;
  transition: opacity 0.18s ease, box-shadow 0.18s ease, background 0.18s ease;
}
/* DIM ONLY WHEN THERE IS SOMETHING TO DIM AGAINST. The half-opacity is
   there to make one hand stand out; with no hand being asked there is
   nothing to stand out FROM, and all it does is grey out your own cards
   at the moment you most want to read them — which is the payout, where
   this used to leave a winning 21 and a natural both at 50 %.
   paintHero sets .bjt-focus only while a hand of yours is on the clock. */
#mp-bj-table-screen .bjt-hero-hands.bjt-focus .bjt-hh { opacity: 0.5; }
#mp-bj-table-screen .bjt-hero-hands.bjt-focus .bjt-hh.bjt-on { opacity: 1; }
/* Waiting on a stake rather than on a decision: the seat is yours and
   it is in the strip, but there are no cards in it yet. Dimmer than an
   idle hand and with a dashed well where the cards will land, so the
   strip reads as «three seats, none dealt» rather than as three empty
   boxes that might be a rendering fault. */
#mp-bj-table-screen .bjt-hh.bjt-idle { opacity: 0.42; }
#mp-bj-table-screen .bjt-hh.bjt-idle .bjt-hand-cards {
  width: 40px;
  height: 39px;
  border-radius: 4px;
  border: 1px dashed rgba(232, 217, 176, 0.22);
}
/* The hand you are being asked about is the one that grows. A player
   holding five seats never hunts for what the clock is counting down
   on. */
#mp-bj-table-screen .bjt-hh.bjt-on {
  opacity: 1;
  background: rgba(232, 200, 106, 0.09);
  box-shadow: 0 0 0 1.4px var(--bjt-gold);
}
#mp-bj-table-screen .bjt-hh .bjt-lbl {
  font-size: 8px;
  line-height: 1;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--bjt-muted);
  white-space: nowrap;
}
#mp-bj-table-screen .bjt-hh .bjt-hand-cards { perspective: 600px; }
#mp-bj-table-screen .bjt-hero-hands .bjt-card { width: 28px; height: 39px; }
#mp-bj-table-screen .bjt-hero-hands .bjt-card i { font-size: 9px; }
#mp-bj-table-screen .bjt-hero-hands .bjt-card b { font-size: 13px; }
#mp-bj-table-screen .bjt-hero-hands .bjt-hand-cards > * + * { margin-left: -11px; }
#mp-bj-table-screen .bjt-hh.bjt-on .bjt-card { width: 40px; height: 56px; }
#mp-bj-table-screen .bjt-hh.bjt-on .bjt-card i { font-size: 13px; }
#mp-bj-table-screen .bjt-hh.bjt-on .bjt-card b { font-size: 19px; }
#mp-bj-table-screen .bjt-hh.bjt-on .bjt-hand-cards > * + * { margin-left: -15px; }
#mp-bj-table-screen .bjt-hero-msg {
  flex: 1;
  font-size: 12px;
  color: var(--bjt-muted);
  text-align: center;
}

/* ── Controls ────────────────────────────────────────────────────
   CONSTANT HEIGHT, every phase — GEOMETRY.md §7 invariant 3. The band
   is the stage's complement, so a band that grows when the action
   buttons appear recomputes --bjt-tz-scale and jumps the whole table
   the moment it becomes your turn. #bjt-controls is absolutely
   positioned inside the band for exactly that reason: whatever
   paintControls writes, the band is the same height.

   TWO LAYERS IN ONE BAND, and the split is the whole point of wave 5:

     #bjt-controls  the RESTING layer — what the band shows when you
                    are not being asked anything. The chip rail while
                    betting, the round's net while paying out, a phase
                    word otherwise. It persists.
     #bjt-overlay   the DECISION layer — hit/stand/double/split, or
                    insurance's yes/no. It appears when a hand of yours
                    needs an answer and it is gone the instant one is
                    given, which is single-player's pattern
                    (style.css:14424) and the one the owner named.

   Both are absolutely positioned in the same 78 px band, so neither can
   change its height. The overlay sits ON the resting layer rather than
   beside it: at bottom:14px it lands on the same row the chip rail
   occupies, which is why betting keeps its rail and the acting phases
   render no resting content to show through. */

#mp-bj-table-screen .bjt-ctrl-band {
  position: relative;
  flex: 0 0 var(--bjt-ctrl-h);
  min-height: 0;
}
#mp-bj-table-screen .bjt-controls {
  position: absolute;
  left: 10px;
  right: 10px;
  top: 16px;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

/* ── The action overlay ──────────────────────────────────────────
   Lifted from single-player's .bj-actions / .bj-action-btn
   (style.css:14424-14447): absolutely positioned, pill buttons,
   backdrop-filter blur, gold on rgba(20,16,8,.6), z-index above the
   felt. The one thing added is the container's pointer-events:none, so
   the transparent gaps between four pills do not swallow taps aimed at
   whatever is underneath.

   Illegal actions are DIMMED IN PLACE, never removed. A row that
   reflows under a thumb already in motion is how a player doubles when
   they meant to hit — and with four buttons in fixed order the muscle
   memory is worth more than the tidiness. */
#mp-bj-table-screen .bjt-overlay {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 14px;
  z-index: 7;
  display: flex;
  gap: 8px;
  justify-content: center;
  padding: 0 12px;
  pointer-events: none;
  opacity: 0;
  transform: translateY(7px);
  transition: opacity 0.16s ease, transform 0.2s cubic-bezier(0.2, 0.8, 0.3, 1);
}
#mp-bj-table-screen .bjt-overlay.bjt-on {
  opacity: 1;
  transform: none;
}
#mp-bj-table-screen .bjt-abtn {
  flex: 1 1 0;
  max-width: 92px;
  min-height: 44px;
  padding: 0 6px;
  /* Stated, not inherited. This file's header claims a "global
     border-box"; there is none — the page is content-box and the UA
     sheet is what makes a <button> border-box. So min-height:44px means
     44 on a button and 46 on a span, and the insurance row measured 46
     because a span sibling with the same declaration stretched it. Both
     of these say it now, so the tap floor is the tap floor. */
  box-sizing: border-box;
  border-radius: 999px;
  border: 1px solid rgba(201, 161, 59, 0.6);
  background: rgba(20, 16, 8, 0.62);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: #ffd97a;
  font: inherit;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.06em;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.5);
  cursor: pointer;
  pointer-events: auto;
  transition: transform 0.08s, opacity 0.15s;
}
#mp-bj-table-screen .bjt-abtn:active { transform: translateY(2px); }
#mp-bj-table-screen .bjt-abtn.bjt-a-hit {
  color: #8fe0b4;
  border-color: rgba(143, 224, 180, 0.55);
}
#mp-bj-table-screen .bjt-abtn.bjt-a-stand {
  color: #f0a49a;
  border-color: rgba(240, 164, 154, 0.55);
}
#mp-bj-table-screen .bjt-abtn[disabled] {
  opacity: 0.32;
  filter: grayscale(0.7);
  cursor: default;
  pointer-events: none;
}
/* The pills carry pointer-events:auto so the gaps between them stay
   transparent to taps — which means a faded-out overlay is still an
   invisible row of live buttons across the band. This is the line that
   makes "it disappears the moment you decide" true and not merely
   apparent, and it must survive any future tidy of the two rules
   above. */
#mp-bj-table-screen .bjt-overlay:not(.bjt-on) .bjt-abtn { pointer-events: none; }
/* Insurance answers two questions at once — take it, and how long is
   left — so its own countdown rides the same row as the answer rather
   than sending the player back up to the phase line. IN the row, not
   above it: the band is 78 px and the gap between the phase line and
   the pills is four of them. A caption stacked in that gap measured
   630-640 against a phase line at 619-633, which is a collision that
   only shows up on a real layout — the first version of this file had
   exactly that bug.
   The two answers are wider than an action pill because there are two
   of them and a clock rather than four. */
#mp-bj-table-screen .bjt-overlay.bjt-ins .bjt-abtn { max-width: 148px; }
#mp-bj-table-screen .bjt-ins-clock {
  flex: 0 0 auto;
  width: 44px;
  min-height: 44px;
  box-sizing: border-box;
  border-radius: 999px;
  border: 1px solid rgba(201, 161, 59, 0.35);
  background: rgba(20, 16, 8, 0.62);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--bjt-goldhi);
  pointer-events: none;
}
#mp-bj-table-screen .bjt-ins-clock.bjt-urgent {
  color: #fff;
  border-color: rgba(207, 95, 82, 0.8);
  background: rgba(120, 34, 28, 0.72);
}

#mp-bj-table-screen .bjt-btn {
  min-height: 44px;
  border: 0;
  border-radius: 10px;
  font-size: 13px;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #0d1310;
  background: linear-gradient(180deg, #e8c86a, #c9a13b);
  box-shadow: 0 3px 0 #8a6c22, 0 5px 10px rgba(0, 0, 0, 0.45);
  cursor: pointer;
  transition: transform 0.08s, filter 0.15s;
}
#mp-bj-table-screen .bjt-btn:active { transform: translateY(2px); box-shadow: 0 1px 0 #8a6c22; }
#mp-bj-table-screen .bjt-btn[disabled] {
  filter: grayscale(0.85) brightness(0.55);
  cursor: default;
  box-shadow: 0 3px 0 rgba(0, 0, 0, 0.4);
}
/* .bjt-b-hit and .bjt-b-stand are gone with the 2x2 grid: hit and stand
   are overlay pills now (.bjt-a-hit / .bjt-a-stand), and a solid green
   slab is the wrong object for a control that has to sit on top of the
   felt without hiding it. */
#mp-bj-table-screen .bjt-btn.bjt-b-ghost  { background: rgba(255,255,255,.07); color: var(--bjt-ink); box-shadow: inset 0 0 0 1px rgba(201,161,59,.35); }

/* ONE ROW, and the width is spent to the last pixel: five 44 px chips
   with 5 px gaps is 240, plus a 6 px gap and an 84 px minimum for BET
   is 330. A 360 px phone leaves 340 inside the band's 10 px insets, so
   this is the narrowest layout that still holds every denomination and
   a BET button carrying its own amount. On a 402 px phone BET grows to
   136 and reads «BET 250 · SEAT 3».

   flex-shrink is 0 on the rail and 1 on the button on purpose: below
   340 the button gives up label before any chip gives up its tap
   target. */
#mp-bj-table-screen .bjt-chips {
  display: flex;
  flex: 0 0 auto;
  gap: 5px;
  justify-content: center;
}
#mp-bj-table-screen .bjt-btn.bjt-b-bet {
  flex: 1 1 auto;
  min-width: 84px;
  max-width: 140px;
  font-size: 12px;
  letter-spacing: 0.06em;
  padding: 0 4px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
#mp-bj-table-screen .bjt-chip {
  width: 44px;
  height: 44px;
  flex: 0 0 auto;
  border: 0;
  border-radius: 50%;
  font-size: 11px;
  font-weight: 800;
  color: #f4f0e6;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.75);
  cursor: pointer;
  /* The centre disc is 0.72, not 0.28. At 0.28 the conic's cream wedges
     read straight through it and the digits are cream-on-cream wherever
     a wedge happens to land under one — "10" and "1K" were the worst
     because their strokes are narrow. The pod's own capsule already
     solved this at 21 px with 0.86 and says so in its comment; the rail
     had the same problem at 44 and a value that was never revisited. */
  background:
    radial-gradient(circle, rgba(8, 10, 9, 0.72) 0 56%, transparent 57%),
    repeating-conic-gradient(#f4f0e6 0 22deg, var(--bjt-c, #2f5d46) 22deg 60deg);
  box-shadow: 0 3px 0 rgba(0, 0, 0, 0.45), 0 5px 9px rgba(0, 0, 0, 0.45);
  transition: transform 0.08s;
}
#mp-bj-table-screen .bjt-chip:active { transform: translateY(2px); }
/* Unavailable, not broken. A chip the exposure ceiling cannot cover is
   greyed AND flattened — it loses the stacked-edge shadow that makes
   the live ones look pick-up-able, so the row reads as "these four" at
   a glance rather than as five chips one of which does nothing. */
#mp-bj-table-screen .bjt-chip[disabled] {
  filter: grayscale(0.85) brightness(0.5);
  opacity: 0.6;
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.4);
  cursor: default;
}
#mp-bj-table-screen .bjt-chip.bjt-c1 { --bjt-c: #2f5d46; }
#mp-bj-table-screen .bjt-chip.bjt-c2 { --bjt-c: #23262b; }
#mp-bj-table-screen .bjt-chip.bjt-c3 { --bjt-c: #7a2f35; }
/* No dark-ink exception for the gold chip any more: the centre disc is
   now dark on every denomination, so dark text there would be the
   unreadable one. */
#mp-bj-table-screen .bjt-chip.bjt-c4 { --bjt-c: #c9a13b; }
#mp-bj-table-screen .bjt-chip.bjt-c5 { --bjt-c: #3d6a8a; }

/* flex:1 is new: #bjt-controls became a centred flex row when the band
   dropped to 78 px, and without a basis the row collapses to its
   content and BACK TO LOBBY renders as a 130 px button in the middle of
   the band instead of spanning it. */
#mp-bj-table-screen .bjt-row {
  display: flex;
  flex: 1 1 auto;
  gap: 6px;
  align-items: center;
}
#mp-bj-table-screen .bjt-row .bjt-btn { flex: 1; }

/* ── Reactions ───────────────────────────────────────────────────── */

/* 38 x 38, and it takes the same min-height: 0 as the other two — the
   app-wide 40 px floor made this 38 x 40, which is an oval with
   border-radius 50 %, not the roundel it is lifted from. The target
   comes back as a 44 x 44 pseudo-element. */
#mp-bj-table-screen .bjt-react-btn {
  position: absolute;
  right: 8px;
  bottom: calc(var(--bjt-ctrl-h) + var(--bjt-hero-h) + 4px);
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0;
  width: 38px;
  height: 38px;
  border: 0;
  border-radius: 50%;
  font-size: 17px;
  color: var(--bjt-goldhi);
  background: rgba(0, 0, 0, 0.55);
  box-shadow: inset 0 0 0 1px rgba(201, 161, 59, 0.35);
  cursor: pointer;
  z-index: 4;
}
#mp-bj-table-screen .bjt-react-tray {
  position: absolute;
  right: 8px;
  bottom: calc(var(--bjt-ctrl-h) + var(--bjt-hero-h) + 48px);
  display: none;
  /* 40 px cells on a 44 px pitch. 34 on a 38 px pitch is what shipped,
     and it is the one control family on this screen that never got the
     house's own tap size — poker's palette cells are 56 x 40 with the
     same 4 px gutter (mp-poker.css:1587). At this pitch each cell's
     44 x 44 target tiles the grid exactly: no dead gap between two
     glyphs, and no target reaching over its neighbour's ink. */
  grid-template-columns: repeat(4, 40px);
  gap: 4px;
  padding: 6px;
  border-radius: 12px;
  background: rgba(8, 12, 10, 0.92);
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.6), inset 0 0 0 1px rgba(201, 161, 59, 0.3);
  z-index: 5;
}
#mp-bj-table-screen .bjt-react-tray.bjt-open { display: grid; }
/* THE SAME CASCADE COLLISION, TWELVE MORE TIMES. style.css:12876's
   app-wide `button, .btn { min-height: 40px }` beats a plain height, so
   these declared 34 x 34 and rendered 34 x 40 — a glyph off centre in a
   cell taller than the grid track it was laid out on.
   .bjt-shoe-info, .bjt-clear and .bjt-react-btn were each fixed the
   same way, and these twelve were missed because nothing had ever
   measured inside an open tray.

   min-height: 0 takes the floor off; the tap area comes back as a
   ::after, which costs no layout. z-index: -1 puts every target
   underneath every cell's own box — still above the tray's background,
   because the tray is its own stacking context — so a target can only
   ever claim empty space and never a neighbour's glyph. On this pitch
   it has nothing to claim, and that is the point: it is what keeps a
   later change to the gutter from quietly turning the targets into a
   theft. */
#mp-bj-table-screen .bjt-react-tray button {
  position: relative;
  min-height: 0;
  width: 40px;
  height: 40px;
  border: 0;
  border-radius: 9px;
  background: rgba(255, 255, 255, 0.05);
  font-size: 19px;
  line-height: 1;
  padding: 0;
  cursor: pointer;
}
#mp-bj-table-screen .bjt-react-tray button::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 44px;
  height: 44px;
  border-radius: 10px;
  transform: translate(-50%, -50%);
  z-index: -1;
}
#mp-bj-table-screen .bjt-react-tray button:active { background: rgba(255, 255, 255, 0.12); }
#mp-bj-table-screen .bjt-react-btn svg { display: block; }
#mp-bj-table-screen .bjt-react-btn::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  transform: translate(-50%, -50%);
}

/* The bubble a reaction arrives in is poker's, chrome and all
   (mp-poker.css:1618-1650): the dark plate, the gold hairline, the
   rotated-square tail, and the 240 ms overshoot pop. What blackjack
   adds is the drift — poker holds its chip on the pod for 2.5 s and
   fades it, but a blackjack pod is 88 px of felt with cards, a plate,
   a balance and a bet capsule already on it, and a chip parked there
   covers one of them. So it pops in poker's curve and then leaves. */
#mp-bj-table-screen .bjt-float {
  position: absolute;
  padding: 3px 8px 4px;
  border-radius: 11px;
  font-size: 17px;
  line-height: 1.15;
  background: rgba(16, 12, 8, 0.94);
  border: 1px solid rgba(232, 200, 106, 0.35);
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.5);
  pointer-events: none;
  animation: bjt-rise 1.7s cubic-bezier(0.2, 1.4, 0.4, 1) forwards;
  z-index: 6;
}
#mp-bj-table-screen .bjt-float::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -4.5px;
  width: 8px;
  height: 8px;
  transform: translateX(-50%) rotate(45deg);
  background: rgba(16, 12, 8, 0.94);
  border-right: 1px solid rgba(232, 200, 106, 0.35);
  border-bottom: 1px solid rgba(232, 200, 106, 0.35);
}
@keyframes bjt-rise {
  from { transform: translateY(0) scale(0.35); opacity: 0; }
  14%  { opacity: 1; transform: translateY(-8px) scale(1); }
  55%  { opacity: 1; transform: translateY(-20px) scale(1); }
  to   { transform: translateY(-64px) scale(0.85); opacity: 0; }
}

/* ── Result banner ───────────────────────────────────────────────
   Single-player's .bj-result (style.css:14448-14511), lifted: the dark
   glass plate, the 1.5 px gold rule, the clipped-gradient headline, the
   monospace amount, and both keyframes — a spring in, a soft fade out.

   Three things are deliberately different, and all three are because
   five people are reading this felt instead of one.

   1. It is SMALLER. Single-player's is 26 px of headline in a 220 px
      plate over a table nobody else is using. Here it has to state a
      result without hiding the four other seats' outcomes, which are
      the reason a multiplayer table is worth sitting at.
   2. It lives over the STAGE, bounded by the bands, rather than at the
      viewport's centre. The hero strip carries your cards through the
      payout and must not be covered by the summary of them.
   3. It leaves on its own after 1.8 s, well inside the payout window,
      so the table is clear again before the next betting phase opens.
      A banner the player has to dismiss is a banner that is still up
      when the next hand deals. */

#mp-bj-table-screen .bjt-result {
  position: absolute;
  left: 0;
  right: 0;
  top: var(--bjt-head-h);
  bottom: calc(var(--bjt-ctrl-h) + var(--bjt-hero-h));
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 8;
  pointer-events: none;
}
#mp-bj-table-screen .bjt-result.bjt-open { display: flex; }
#mp-bj-table-screen .bjt-result-plate {
  min-width: 168px;
  padding: 13px 26px;
  text-align: center;
  font-family: Georgia, serif;
  background: rgba(8, 5, 2, 0.88);
  border: 1.5px solid rgba(212, 168, 65, 0.5);
  border-radius: 16px;
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.7);
  animation: bjt-result-in 0.55s cubic-bezier(0.2, 1.3, 0.3, 1) both;
}
#mp-bj-table-screen .bjt-result.bjt-fade .bjt-result-plate {
  animation: bjt-result-out 0.45s ease-in forwards;
}
@keyframes bjt-result-in {
  from { opacity: 0; transform: scale(0.62); }
  to   { opacity: 1; transform: scale(1); }
}
@keyframes bjt-result-out {
  to { opacity: 0; transform: scale(0.93); }
}
#mp-bj-table-screen .bjt-result-head {
  font-size: 21px;
  font-weight: 900;
  letter-spacing: 3px;
  background: linear-gradient(180deg, #ffe8a0 0%, #f0c94c 50%, #b8860b 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.9));
}
#mp-bj-table-screen .bjt-result-amt {
  margin-top: 5px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 1.2px;
  color: #ffd97a;
}
/* A natural is the one hand the table pays 3:2 for; it gets the halo. */
#mp-bj-table-screen .bjt-result.bjt-r-blackjack .bjt-result-plate {
  border-color: rgba(255, 217, 122, 0.8);
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.7), 0 0 34px rgba(255, 217, 122, 0.3);
}
#mp-bj-table-screen .bjt-result.bjt-r-lose .bjt-result-plate {
  border-color: rgba(207, 95, 82, 0.6);
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.7), 0 0 22px rgba(207, 95, 82, 0.16);
}
#mp-bj-table-screen .bjt-result.bjt-r-lose .bjt-result-head {
  background: linear-gradient(180deg, #ffb0a8 0%, #cf5f52 50%, #6b1a14 100%);
  -webkit-background-clip: text;
  background-clip: text;
}
#mp-bj-table-screen .bjt-result.bjt-r-lose .bjt-result-amt { color: #ff8a7a; }
#mp-bj-table-screen .bjt-result.bjt-r-push .bjt-result-head {
  background: linear-gradient(180deg, #e4dccc 0%, #a9a091 50%, #6b6558 100%);
  -webkit-background-clip: text;
  background-clip: text;
}
#mp-bj-table-screen .bjt-result.bjt-r-push .bjt-result-amt { color: var(--bjt-plate); }

/* ── Reshuffle ceremony ──────────────────────────────────────────── */

#mp-bj-table-screen .bjt-reshuffle {
  position: absolute;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 10px;
  background: rgba(6, 10, 8, 0.82);
  z-index: 8;
  text-align: center;
}
#mp-bj-table-screen .bjt-reshuffle.bjt-open { display: flex; }
#mp-bj-table-screen .bjt-reshuffle h4 {
  margin: 0;
  font-family: Georgia, serif;
  font-style: italic;
  font-size: 20px;
  color: var(--bjt-goldhi);
}
#mp-bj-table-screen .bjt-reshuffle p {
  margin: 0;
  max-width: 260px;
  font-size: 11px;
  line-height: 1.5;
  color: var(--bjt-muted);
}
#mp-bj-table-screen .bjt-shuffle-deck {
  display: flex;
  gap: 3px;
}
#mp-bj-table-screen .bjt-shuffle-deck span {
  width: 26px;
  height: 37px;
  border-radius: 3px;
  background: repeating-linear-gradient(45deg, #7a2f35 0 4px, #6a262c 4px 8px);
  box-shadow: inset 0 0 0 1.5px rgba(232, 217, 176, 0.3);
  animation: bjt-riffle 0.9s ease-in-out infinite;
}
#mp-bj-table-screen .bjt-shuffle-deck span:nth-child(2) { animation-delay: 0.1s; }
#mp-bj-table-screen .bjt-shuffle-deck span:nth-child(3) { animation-delay: 0.2s; }
#mp-bj-table-screen .bjt-shuffle-deck span:nth-child(4) { animation-delay: 0.3s; }
#mp-bj-table-screen .bjt-shuffle-deck span:nth-child(5) { animation-delay: 0.4s; }
@keyframes bjt-riffle {
  0%, 100% { transform: translateY(0)    rotate(0deg); }
  50%      { transform: translateY(-9px) rotate(6deg); }
}

/* ── Fair-play sheet ─────────────────────────────────────────────── */

#mp-bj-table-screen .bjt-sheet {
  position: absolute;
  inset: 0;
  display: none;
  z-index: 9;
  background: rgba(6, 10, 8, 0.95);
  padding: calc(14px + var(--fym-safe-top, 0px)) 14px
           calc(14px + var(--fym-safe-bottom, 0px));
  overflow-y: auto;
}
#mp-bj-table-screen .bjt-sheet.bjt-open { display: block; }
#mp-bj-table-screen .bjt-sheet h4 {
  margin: 0 0 4px;
  font-family: Georgia, serif;
  font-style: italic;
  font-size: 17px;
  color: var(--bjt-goldhi);
}
#mp-bj-table-screen .bjt-sheet p { margin: 0 0 10px; font-size: 11.5px; line-height: 1.55; color: var(--bjt-ink); }
#mp-bj-table-screen .bjt-sheet dt { font-size: 9.5px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--bjt-muted); margin-top: 8px; }
#mp-bj-table-screen .bjt-sheet dd {
  margin: 2px 0 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10px;
  line-height: 1.45;
  word-break: break-all;
  color: var(--bjt-ink);
}
#mp-bj-table-screen .bjt-sheet .bjt-ok { color: var(--bjt-win); }
#mp-bj-table-screen .bjt-sheet .bjt-bad { color: var(--bjt-loss); }

/* ── Lobby ───────────────────────────────────────────────────────── */

#mp-bj-lobby-screen .bjt-lobby-head {
  margin: 4px 0 14px;
  text-align: center;
}
#mp-bj-lobby-screen .bjt-lobby-head h3 {
  margin: 0;
  font-family: Georgia, serif;
  font-style: italic;
  font-size: 21px;
  color: #e8c86a;
}
#mp-bj-lobby-screen .bjt-lobby-head p {
  margin: 4px 0 0;
  font-size: 11px;
  color: var(--muted);
}
#mp-bj-lobby-screen .bjt-table-row {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  margin-bottom: 8px;
  padding: 12px 14px;
  border: 0;
  border-radius: 12px;
  text-align: left;
  color: var(--text);
  background: linear-gradient(160deg, rgba(46, 107, 79, 0.35), rgba(16, 39, 29, 0.5));
  box-shadow: inset 0 0 0 1px rgba(201, 161, 59, 0.25);
  cursor: pointer;
}
#mp-bj-lobby-screen .bjt-table-row:active { transform: translateY(1px); }
#mp-bj-lobby-screen .bjt-table-row .bjt-t-name {
  flex: 1;
  font-family: Georgia, serif;
  font-style: italic;
  font-size: 15px;
  color: #e8c86a;
}
#mp-bj-lobby-screen .bjt-table-row .bjt-t-meta { font-size: 10.5px; color: var(--muted); }
#mp-bj-lobby-screen .bjt-mode-pill {
  padding: 2px 8px;
  border-radius: 8px;
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}
#mp-bj-lobby-screen .bjt-mode-pill.bjt-m-play { background: rgba(95, 159, 122, 0.25); color: #7fd0a2; }
#mp-bj-lobby-screen .bjt-mode-pill.bjt-m-real { background: rgba(201, 161, 59, 0.25); color: #e8c86a; }
#mp-bj-lobby-screen .bjt-rules-note {
  margin-top: 14px;
  padding: 10px 12px;
  border-radius: 10px;
  font-size: 10.5px;
  line-height: 1.55;
  color: var(--muted);
  background: rgba(255, 255, 255, 0.03);
  box-shadow: inset 0 0 0 1px var(--border);
}

/* ── Short phones ────────────────────────────────────────────────── */

/* ── Short phones ────────────────────────────────────────────────
   ONLY the bands outside the design box. The box scales as one unit,
   so a media query that changes a card, a pod or an anchor inside it
   breaks every measured coordinate in GEOMETRY.md — which is exactly
   what the block this replaces did (dealer min-height, .bjt-card
   34→30, dealer cards 44→38).

   Shrinking the bands rather than letting the stage collapse is what
   keeps a short webview scroll-free: 534 usable − 204 of bands leaves
   the stage 330 and the box at 0.65, where the whole table is still
   one glance. The scroll hatch below that is a last resort. */

@media (max-height: 700px) {
  #mp-bj-table-screen {
    --bjt-head-h: 30px;
    /* 3 + 11 label + 2 + 45 card + 2 + 14 total + 3 = 80, with 8 to
       spare. The band is `overflow: hidden`, so a strip that outgrows
       it does not push the felt — it silently loses the total badge. */
    --bjt-hero-h: 88px;
    --bjt-ctrl-h: 72px;
  }
  #mp-bj-table-screen .bjt-hero-hands .bjt-card { width: 24px; height: 34px; }
  #mp-bj-table-screen .bjt-hero-hands .bjt-card i { font-size: 8px; }
  #mp-bj-table-screen .bjt-hero-hands .bjt-card b { font-size: 11px; }
  #mp-bj-table-screen .bjt-hh.bjt-on .bjt-card { width: 32px; height: 45px; }
  #mp-bj-table-screen .bjt-hh.bjt-on .bjt-card i { font-size: 10px; }
  #mp-bj-table-screen .bjt-hh.bjt-on .bjt-card b { font-size: 15px; }
  #mp-bj-table-screen .bjt-hh.bjt-on .bjt-hand-cards > * + * { margin-left: -12px; }
  #mp-bj-table-screen .bjt-hh.bjt-idle .bjt-hand-cards { width: 34px; height: 34px; }
  #mp-bj-table-screen .bjt-btn { min-height: 42px; font-size: 12px; }
  #mp-bj-table-screen .bjt-chip { width: 40px; height: 40px; }
  /* 72 px of band: the phase line ends at 14 and a 44 px pill row from
     bottom:10 starts at 18, so the two still clear each other. */
  #mp-bj-table-screen .bjt-overlay { bottom: 10px; }
}

/* Narrow, not short. Five 44 px chips plus a labelled BET is 330 and a
   360 px phone leaves 340 — but a 320 px one leaves 300, and something
   has to give. The chip is what gives, exactly as it does on a short
   phone, because the alternative is dropping a denomination or letting
   the row scroll sideways, and nothing on this screen may do that. */
@media (max-width: 359px) {
  #mp-bj-table-screen .bjt-chip { width: 40px; height: 40px; }
  #mp-bj-table-screen .bjt-chips { gap: 4px; }
  #mp-bj-table-screen .bjt-btn.bjt-b-bet { min-width: 72px; font-size: 11px; }
  #mp-bj-table-screen .bjt-abtn { font-size: 11px; letter-spacing: 0.02em; }
}

@media (prefers-reduced-motion: reduce) {
  #mp-bj-table-screen .bjt-card.bjt-deal,
  #mp-bj-table-screen .bjt-card.bjt-flipout,
  #mp-bj-table-screen .bjt-card.bjt-flipin,
  #mp-bj-table-screen .bjt-outcome,
  #mp-bj-table-screen .bjt-shuffle-deck span,
  #mp-bj-table-screen .bjt-clock.bjt-urgent,
  /* wave 5-6 additions. The rule for all of them is the same: the
     INFORMATION each carries must survive its animation being removed.
     The streak badge is still there and still legible without the
     pulse; the win halo is a flourish over an outcome badge that
     already says WIN; the chip flight is confirmation of a tap that
     also lands as a capsule on the felt; the result banner still
     appears and still leaves, it just stops springing. */
  #mp-bj-table-screen .bjt-streak.bjt-s-hot,
  #mp-bj-table-screen .bjt-hand.bjt-won,
  #mp-bj-table-screen .bjt-hand.bjt-won-bj,
  #mp-bj-table-screen .bjt-hh.bjt-won,
  #mp-bj-table-screen .bjt-hh.bjt-won-bj,
  #mp-bj-table-screen .bjt-won .bjt-card::before,
  #mp-bj-table-screen .bjt-won-bj .bjt-card::before,
  #mp-bj-table-screen .bjt-shoe.bjt-working,
  #mp-bj-table-screen .bjt-shoe.bjt-working .bjt-shoe-deck,
  #mp-bj-table-screen .bjt-playing .bjt-dealer-name::after,
  #mp-bj-table-screen .bjt-float,
  #mp-bj-table-screen .bjt-result-plate,
  #mp-bj-table-screen .bjt-result.bjt-fade .bjt-result-plate { animation: none; }

  /* The sweep's ::before paints a bright band across the card face and
     is only invisible because it animates to opacity 0. With animation
     off it would sit there permanently, covering the rank — so it is
     removed outright rather than merely stilled. */
  #mp-bj-table-screen .bjt-won .bjt-card::before,
  #mp-bj-table-screen .bjt-won-bj .bjt-card::before { content: none; }

  /* Same trap: the float's keyframe starts at opacity 0 and the plate's
     at scale 0.62. Stilling them would leave an invisible bubble and a
     shrunken banner. Both are pinned to their finished state instead. */
  #mp-bj-table-screen .bjt-float { opacity: 1; }
  #mp-bj-table-screen .bjt-result-plate { opacity: 1; transform: none; }
  #mp-bj-table-screen .bjt-result.bjt-fade .bjt-result-plate { opacity: 0; }

  #mp-bj-table-screen .bjt-overlay,
  #mp-bj-table-screen .bjt-hh,
  #mp-bj-table-screen .bjt-clear,
  #mp-bj-table-screen .bjt-dealer-name { transition: none; }

  /* flyChip already refuses to build one of these, so this is a second
     lock on the same door — a disc whose whole existence is a 0.42 s
     translate has no still frame worth showing. */
  #mp-bj-table-screen .bjt-chipfly { display: none; }
}

/* A full table has to LOOK full. The row was visually identical to a
   joinable one and simply did nothing when tapped, which reads as a
   broken button rather than a busy table. */
#mp-bj-lobby-screen .bjt-table-row.bjt-full {
  opacity: 0.45;
  cursor: default;
}
#mp-bj-lobby-screen .bjt-table-row.bjt-full .bjt-t-meta {
  color: var(--loss);
  font-weight: 700;
}
