/* Supernova Poker — theme mirrors blackjack.html/roulette.html (self-contained,
   no build step). Accent --c = gold, matching the felt's own branding text. */
:root{
  --bg:#06070A; --surface:#0E1117; --surface-2:#141821; --border:#1E2330;
  --mint:#23F7DD; --amber:#F5B544; --coral:#FF6B9D; --blue:#5B8DEF; --lavender:#A78BFA; --yellow:#FFD23F; --green:#3DDC84;
  --text:#F4F6FA; --text-dim:#9BA3B4; --text-faint:#6B7385;
  --mono:'JetBrains Mono','SFMono-Regular',ui-monospace,Menlo,Consolas,monospace;
  --c:#FFD23F;
  --ease:cubic-bezier(.16,1,.3,1);
}
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}

/* ⚠️ ANIMAȚIILE NU AU VOIE SĂ MĂREASCĂ PAGINA.
   `dealIn` pornește de la `translate(50%,-160%)`, deci o carte împărțită la un
   scaun de lângă marginea din dreapta iese câțiva pixeli din ecran. Măsurat:
   **7px pe orizontală**. Consecința nu era 7px, ci o reacție în lanț — apărea
   bara orizontală, bara mânca 15px din înălțime, deci apărea și cea verticală,
   iar pagina sărea la fiecare mână împărțită.

   `clip`, nu `hidden`: `hidden` ar face din `html` un container de derulare, cu
   efectele lui secundare peste tot (elemente `fixed`, derulare pe iOS). `clip`
   doar taie ce iese, fără să schimbe nimic altceva.
   ⚠️ Numai pe orizontală — pe verticală pagina TREBUIE să poată fi derulată,
   sunt regulile și istoricul mâinilor dedesubt. */
html{overflow-x:clip;}
/* ⚠️⚠️ `visibility:visible` E AICI, NU ÎN JS. Pagina pornește ascunsă dintr-un
   `<style>` inline (vezi `index.html`), iar singurul lucru care o arată e chiar
   APLICAREA acestei foi — deci nu există nicio fereastră în care conținutul să fie
   vizibil nestilizat. [DECISIONS §10.123] */
/* ⚠️⚠️ MASA NU SE ARATĂ ÎNAINTE DE DECIZIE (Vlad, 2026-09-03). Poarta e ascunsă la
   pornire, deci fără asta ar exista o fereastră — scurtă, dar reală — în care se vede
   masa fără poartă, iar poarta cade peste ea o clipă mai târziu: exact saltul
   reclamat. Clasa se scoate în `showGate()` ȘI în `hideGate()`, adică la prima
   decizie, oricare ar fi ea.
   ⚠️ `visibility`, nu `display:none`: layout-ul rămâne așezat, deci nu sare nimic când
   apare. [DECISIONS §10.123] */
body.booting .scene{visibility:hidden}
/* ⚠️ ȘI ANTETUL (Vlad, 2026-10-02, la comutatorul Public/Private: „apare Casino Poker sus, Server Online și adresa, arată urât"). Titlul și bara cu
   starea serverului și adresa stau în afara `.scene`, deci la reîncărcare se vedeau câteva sute de ms înainte de poartă. Același lucru cu tot ce e sub masă: `Leave table` + stiva (`.below-table`), regulile și istoricul. Aceeași regulă, aceeași clasă:
   dispar la prima decizie, cu `visibility` (layout-ul rămâne așezat). `.lobby-back` rămâne vizibil: e ieșirea. */
body.booting .player-bar, body.booting .wrap > h1,
body.booting .below-table, body.booting .rules, body.booting .history{visibility:hidden}
body{
  visibility:visible;
  font-family:system-ui,-apple-system,'Segoe UI',sans-serif; color:var(--text); min-height:100vh;
  background:
    radial-gradient(120% 80% at 50% -10%, rgba(255,210,63,0.10), transparent 55%),
    radial-gradient(90% 70% at 50% 120%, rgba(167,139,250,0.08), transparent 60%),
    var(--bg);
  -webkit-tap-highlight-color:transparent; user-select:none; -webkit-user-select:none;
}
.wrap{max-width:1000px; margin:0 auto; padding:16px 22px calc(34px + env(safe-area-inset-bottom));}

/* same gold pill design as every other game's lobby button / identity pill */
.lobby-back{position:fixed; top:14px; left:16px; font-family:'Roboto', sans-serif; font-size:11px; letter-spacing:.06em;
  text-transform:uppercase; color:#FFE55C; text-decoration:none; padding:7px 12px; border:2px solid rgba(255,215,0,0.3);
  border-radius:10px; background:linear-gradient(145deg, rgba(26,26,46,0.95) 0%, rgba(22,33,62,0.95) 100%);
  backdrop-filter:blur(10px); transition:.15s; z-index:500;}
.lobby-back:hover{color:#FFD700; border-color:rgba(255,215,0,0.6);}
@media (max-width:700px){.lobby-back{position:static; display:inline-block; margin-bottom:10px;}}

h1{text-align:center; font-size:48px; font-weight:800; letter-spacing:-0.02em; margin:0 0 10px;}
h1 .x{color:var(--c);}

.player-bar{position:fixed; top:14px; right:16px; z-index:40; display:flex; align-items:center; gap:8px;}
@media (max-width:700px){.player-bar{position:static; justify-content:flex-end; margin-bottom:10px;}}
.player-id{font-family:var(--mono); font-size:13px; color:#FFE55C; letter-spacing:.04em;
  border:2px solid rgba(255,215,0,0.3); border-radius:10px; padding:7px 14px;
  background:linear-gradient(145deg, rgba(26,26,46,0.95) 0%, rgba(22,33,62,0.95) 100%);
  backdrop-filter:blur(10px);}
.player-id .badge{display:inline-block; width:8px; height:8px; border-radius:50%; background:var(--text-faint); margin-right:6px; vertical-align:middle;}
.player-id.wallet-connected .badge{background:var(--mint);}
.player-id.wallet-connected{color:#FFE55C;}

.credits-pill{font-family:var(--mono); font-size:13px; color:var(--text-faint); letter-spacing:.04em;
  border:1px solid var(--border); border-radius:10px; padding:7px 14px; background:linear-gradient(180deg,#0c1016,#080b10);}
.credits-pill b{color:var(--text); font-weight:800; font-variant-numeric:tabular-nums; margin-left:5px;}
.credits-pill b.flash{animation:pop .4s var(--ease); display:inline-block;}
@keyframes pop{0%{transform:scale(1);}40%{transform:scale(1.22);}100%{transform:scale(1);}}

/* ⚠️ Server online/offline — verde cât timp masa e la zi cu serverul (connected
   sau seated), roșu în orice altă stare (connecting/reconnecting/error). Cerut
   de Vlad, 2026-08-21: nu mai era decât text neutru, fără nicio culoare. Clasele
   se pun din setNetStatus(). */
#net-status.net-online{color:var(--green); border-color:color-mix(in srgb,var(--green) 45%,var(--border));}
#net-status.net-online b{color:var(--green);}
#net-status.net-offline{color:var(--coral); border-color:color-mix(in srgb,var(--coral) 45%,var(--border));}
#net-status.net-offline b{color:var(--coral);}

/* ⚠️ Stiva jucătorului la masă — SCOASĂ din .player-bar (2026-08-21, cerut de
   Vlad) fiindcă pariul era deja arătat de două ori (aici și pe pâslă). Mutată
   sub butoanele de acțiune, în .below-row (vezi acolo) — pe masă nu poate sta:
   cărțile și tot ce e pe pâslă rămân neatinse. Același design auriu ca
   .seat-pill de la Blackjack xEGLD (nu .credits-pill — acela e neutru). */
/* ⚠️ MĂRITĂ CU 50% pe 2026-08-23, la cererea lui Vlad — e singurul loc în care îți
   vezi stiva cât joci, iar la 12px se citea greu de la distanța de la care privești
   masa. Scalate proporțional: 12→18px, 7/14→11/21px, colțul 10→15px, bordura 2→3px.
   ⚠️ `gap`, `.seat-pill-cap` și `.seat-pill-cur` sunt în `em`, deci urmează singure —
   nu le converti în px, altfel o viitoare rescalare le lasă în urmă.
   ⚠️ `.seat-pill` are un SINGUR consumator, `#stack-pill` din `.below-row`. Dacă apare
   al doilea, verifică-l: mărimea de aici nu mai e neutră. */
.seat-pill{display:inline-flex; align-items:baseline; gap:.42em; white-space:nowrap;
  font-family:var(--mono); font-size:18px; letter-spacing:.05em; color:#FFE55C;
  padding:11px 21px; border-radius:15px; border:3px solid rgba(255,215,0,0.3);
  background:linear-gradient(145deg, rgba(26,26,46,0.95) 0%, rgba(22,33,62,0.95) 100%);
  backdrop-filter:blur(10px);}
.seat-pill-cap{opacity:.72; font-size:.85em;}
.seat-pill .amt{font-weight:800; font-variant-numeric:tabular-nums;}
.seat-pill-cur{opacity:.68; font-size:.85em;}

/* ============================================================
   THE TABLE — Masa_Poker.webp as background, everything else laid
   out as % positions (computed from the actual render camera, see
   Dev_3D_Poker_Table.md) over it, scaling with container units.
   NOTE: the asset is 3012x1146 since 2026-08-13 (re-rendered 3x so it stops
   being upscaled past the 1750px cap). 1004/382 below is the SAME ratio and
   is left as-is on purpose — not a stale value. */
.scene{position:relative; left:50%; transform:translateX(-50%); z-index:1;
  width:min(1750px, 98vw, calc(82vh * 2.6283)); margin:5vh auto 0; aspect-ratio:1004 / 382;
  container-type:size; --cw:11.26cqh;}
.scene::before{content:""; position:absolute; inset:0; z-index:-1; pointer-events:none;
  border-radius:16px;
  background:url("images/Masa_Poker.webp?v=2") center/cover no-repeat;
  -webkit-mask-image:
    radial-gradient(40% 40% at 0% 100%, transparent 0%, #000 70%),
    radial-gradient(40% 40% at 100% 100%, transparent 0%, #000 70%),
    radial-gradient(42% 42% at 0% 0%, transparent 0%, #000 70%),
    radial-gradient(42% 42% at 100% 0%, transparent 0%, #000 70%),
    linear-gradient(to bottom, transparent 0%, #000 6%),
    linear-gradient(to right, transparent 0%, #000 4%),
    linear-gradient(to left, transparent 0%, #000 4%);
  -webkit-mask-composite: source-in, source-in, source-in, source-in, source-in, source-in, source-in;
          mask-image:
    radial-gradient(40% 40% at 0% 100%, transparent 0%, #000 70%),
    radial-gradient(40% 40% at 100% 100%, transparent 0%, #000 70%),
    radial-gradient(42% 42% at 0% 0%, transparent 0%, #000 70%),
    radial-gradient(42% 42% at 100% 0%, transparent 0%, #000 70%),
    linear-gradient(to bottom, transparent 0%, #000 6%),
    linear-gradient(to right, transparent 0%, #000 4%),
    linear-gradient(to left, transparent 0%, #000 4%);
          mask-composite: intersect;
  filter:drop-shadow(0 0 70px rgba(255,210,63,.12));}

/* ---- community cards + pot, centered over the felt branding ---- */
/* the dealer's board cards get their OWN --cw instead of inheriting .scene's
   11.26cqh — Vlad wanted them bigger (2026-08-12). Set to 14.72cqh, i.e. the
   same size as the hero's own cards (.seat.hero), so the board reads as the
   main thing on the felt rather than the smallest cards on the table. */
/* 45.1% — the anchor projected from the felt centre, and the only correct value:
   it is what keeps the board clear of the dealer's chip tray. Measured by
   projecting the tray through the current camera into this crop, it occupies
   21.63%..34.50%; at 45.1% the board's top edge lands at 34.79%, just under it.
   Both attempts to raise the board to give the pot more room (42.6%, then 39%)
   put the cards ON the tray — at 39% they climbed 5.8% into it (Vlad: "nu se
   suiau nici odata peste caseta de jetoane"). DO NOT raise this.
   The board's bottom edge (55.4%) does reach the pot pile, and that is fine —
   the cards cover it via z-index:7 below, the same call blackjack makes with
   .hand-spot(7) over .bet-spot(5). Size and position are both fixed: solve any
   overlap with z-order, or by moving the POT, never by moving these. */
.community{position:absolute; left:50%; top:45.1%; transform:translate(-50%,-50%);
  display:flex; gap:1.21cqw; z-index:7; --cw:14.72cqh;}
/* 64.3% was the projected anchor; moved down 3.1% together with .pot-chips —
   see the comment there. Bottom lands at 70.02%, still clear of the hero's
   cards (71.69%). */
.pot{position:absolute; left:50%; top:67.4%; transform:translate(-50%,-50%); z-index:4;
  font-family:var(--mono); font-size:calc(var(--cw)*0.24); font-weight:800; color:var(--c);
  background:rgba(5,7,13,.82); border:1px solid color-mix(in srgb,var(--c) 45%,var(--border)); border-radius:999px;
  padding:.35em 1em; white-space:nowrap; box-shadow:0 4px 12px rgba(0,0,0,.55); text-shadow:0 0 10px color-mix(in srgb,var(--c) 50%,transparent);}

/* ---- chip piles: any amount (a live bet in front of a player, or the pot)
   becomes a cluster of little "turnulete" (towers), one per denomination
   present, biggest denomination first. Multiple towers no longer line up in
   a row — chipPileHTML() (poker.js) positions each one via inline left/top
   using CHIP_CLUSTER_LAYOUTS (2 side by side, 3 triangle, 4 grid, 5/6 hex
   rows), so .chip-pile itself just needs to be a plain positioning root (its
   own position:absolute, already set per context below, is enough — towers
   are placed at left/top:50% of THIS box, then offset). --cw is inherited
   from the surrounding seat (hero/bot) or set explicitly per context so every
   pile on the table reads at the same size (see .pot-chips/.bot-bet-chips/
   .hero-row .bet-chips). */
/* pot pile: 20% smaller than the .scene base (13cqh) it would otherwise
   inherit — Vlad found the pot chips too big relative to the players'. */
/* 55.6% was the anchor projected from the felt; the pot moves down 3.1% from it
   (2026-08-12). The board cards had to stay at 45.1% to clear the dealer's chip
   tray, and once they were enlarged their bottom edge reached 55.4% — which put
   even a flat 3-tower row 2.05% behind them. The board cannot move, so the pot
   does: at 58.7% a flat row starts at 56.45%, i.e. 1.05% of clear air under the
   cards, while a tall tower still slides up behind them (by design — z-order
   covers it). Budget checked: only 4.77% existed between the old badge bottom
   and the hero's cards, so 3.1% is most of it; POT_POS in poker.js must be kept
   in step with this value. */
.pot-chips{position:absolute; left:50%; top:58.7%; transform:translate(-50%,-50%); z-index:4; pointer-events:none; --cw:9.01cqh;}
/* sized so a chip's diameter is close to a card's width (real chip ⌀ 23.5cm vs
   a poker card's 6.35cm width scaled the same way, see Dev_3D_Poker_Table.md
   "Jetoanele mărite") — was 0.34cw, "ridicol de mici" per Vlad. Positioned via
   inline left/top (set in poker.js, see CHIP_CLUSTER_LAYOUTS) rather than
   flex — position:absolute here is what makes that positioning read relative
   to the pile's own center instead of the page. */
.chip-tower{position:absolute; transform:translate(-50%,-50%); width:calc(var(--cw)*0.85); height:calc(var(--cw)*1.2);}
/* Discs stacked with a slight vertical offset so each one peeks out above the
   one below it, like a real chip stack. Offset kept very tight (0.11cw, ~13%
   of a disc's own height) — 0.33 and even 0.18 still looked "lăbărțat"
   (loose/sprawled) per Vlad; a real stack shows just a thin sliver of each
   chip underneath.
   ---- 2026-08-13: the FACE is now blackjack's, not a Blender sprite ----
   Vlad asked for the same design and colour as the blackjack table, so this
   is a straight port of blackjack.html's `.chip`: a colour disc with a dashed
   white edge, an inner highlight ring, and the denomination printed on it.
   Was six rendered webps (images/chips/chip_<colour>.webp, still on disk).
   ⚠️ The SIZE did not change and must not: the tower box and the disc were
   already byte-identical between the two games (--cw*0.85 wide, --cw*1.2 tall,
   discs at --i*--cw*0.11), and `*{box-sizing:border-box}` keeps the dashed
   border INSIDE the disc — so this occupies exactly what the sprites did.
   Denomination→colour was already the same mapping in both games, so nothing
   changed there either — it just lives here now instead of in a JS lookup. */
.chip-disc{position:absolute; left:0; bottom:calc(var(--i) * var(--cw) * 0.11); width:100%;
  height:calc(var(--cw)*0.85);}
/* the chip face itself — shared by the stacked discs and the single chip that
   flies to the pot, so both read as the same physical object. */
.chip-disc, .chip-fly{border-radius:50%; display:grid; place-items:center;
  font-family:var(--mono); font-weight:800; font-size:calc(var(--cw)*0.26); color:#fff;
  border:calc(var(--cw)*0.09) dashed rgba(255,255,255,.85);
  box-shadow:0 4px 8px rgba(0,0,0,.5), inset 0 3px 6px rgba(255,255,255,.25), inset 0 -3px 6px rgba(0,0,0,.3);
  text-shadow:0 1px 2px rgba(0,0,0,.5);}
.chip-disc::before, .chip-fly::before{content:""; position:absolute; inset:20%; border-radius:50%;
  background:radial-gradient(circle at 50% 38%, rgba(255,255,255,.28), rgba(255,255,255,.06));
  box-shadow:inset 0 0 0 2px rgba(0,0,0,.18);}
.chip-disc span, .chip-fly span{position:relative; z-index:1;}
/* exact colours from blackjack.html — do not drift, the two tables are meant
   to show the same chips. */
.chip-disc.c1  , .chip-fly.c1  {background:radial-gradient(circle at 50% 35%, #c3cbd6, #8f98a8);}
.chip-disc.c5  , .chip-fly.c5  {background:radial-gradient(circle at 50% 35%, #f0616d, #b3212e);}
.chip-disc.c10 , .chip-fly.c10 {background:radial-gradient(circle at 50% 35%, #6f9bf2, #3457b8);}
.chip-disc.c25 , .chip-fly.c25 {background:radial-gradient(circle at 50% 35%, #52e394, #1d9c58);}
.chip-disc.c50 , .chip-fly.c50 {background:radial-gradient(circle at 50% 35%, #55555e, #232328);}
.chip-disc.c100, .chip-fly.c100{background:radial-gradient(circle at 50% 35%, #b98bd6, #6b3f8c);}
.chip-count{position:absolute; left:50%; bottom:100%; transform:translateX(-50%); margin-bottom:calc(var(--cw)*0.06);
  font-family:var(--mono); font-weight:800; color:#fff; font-size:calc(var(--cw)*0.15); line-height:1;
  background:rgba(0,0,0,.72); border-radius:999px; padding:.2em .5em; white-space:nowrap;}
.chip-pop{animation:chipPop .28s var(--ease) backwards;}
@keyframes chipPop{from{transform:scale(.35); opacity:0;} to{transform:scale(1); opacity:1;}}
/* a single chip that flies from a player's seat to the pot (or pot to winner),
   pure visual feedback — position is animated left/top in %, same coordinate
   space as .seat/.pot (both live directly inside #table/.scene). */
/* z-index 6: above the static piles (4) — a chip in flight lands ON the pile —
   but below every card (7), so a chip crossing the felt passes UNDER the board
   instead of over it. Was 8, i.e. over everything. */
/* --cw here is LOCAL and exists only so the shared chip-face rule above (border
   width, font size — both expressed in --cw) scales to this box instead of
   inheriting .scene's 11.26cqh, which would draw a border thicker than the
   chip. 2.77/0.85 makes --cw*0.85 come out at exactly 2.77cqh, i.e. the size
   this chip already was. The width/height below are left spelled out as
   2.77cqh so that stays obvious.
   This chip carries no printed value on purpose — at ~14px the digits land at
   ~4px. See flyChip() in poker.js. */
.chip-fly{position:absolute; --cw:calc(2.77cqh / 0.85);
  width:2.77cqh; height:2.77cqh; min-width:14px; min-height:14px; z-index:6;
  pointer-events:none; transform:translate(-50%,-50%);
  transition:left .65s cubic-bezier(.3,.6,.3,1), top .65s cubic-bezier(.3,.6,.3,1), opacity .65s ease-in .05s;}

/* the whole pot flying home to whoever won it (flyPotChips in poker.js): a
   clone of the felt pile, same towers, same --cw as .pot-chips, so what leaves
   looks like what was sitting there. Zero-size anchor box exactly like
   .pot-chips — the .chip-tower children position themselves off its centre.
   z-index 8 is deliberate and applies ONLY to this direction: the pot going
   out passes OVER the board (7), while a bet swept the other way stays at
   .chip-fly's 6 and slides under it. Shrinks as it goes, so it reads as being
   absorbed into the winner's stack rather than dropped on top of it. */
.pot-fly{position:absolute; z-index:8; pointer-events:none; --cw:9.01cqh;
  transform:translate(-50%,-50%);
  transition:left .9s cubic-bezier(.34,.62,.28,1), top .9s cubic-bezier(.34,.62,.28,1),
             transform .9s cubic-bezier(.34,.62,.28,1), opacity .9s ease-in .38s;}

/* ---- seat pods: one per player, positioned by JS from real camera-projected
   cupholder coordinates (see Dev_3D_Poker_Table.md). Hero's pod is bigger and
   sits lower (own cards face-up, larger); bot pods are compact, cards down. */
/* z-index 5: players' cards sit above the chip piles (4) too, per the same rule.
   NOT raised to the board's 7 on purpose — the hero's hand overlaps
   .rail-controls (cards 70..94%, buttons 91..103%), and those buttons must stay
   clickable and on top. */
.seat{position:absolute; transform:translate(-50%,-50%); z-index:5; display:flex; flex-direction:column; align-items:center; gap:.31cqw;
  transition:filter .2s;}
.seat.folded{opacity:.4; filter:saturate(.4);}
.seat.acting .name-tag{color:var(--c); border-color:var(--c); box-shadow:0 0 14px color-mix(in srgb,var(--c) 55%,transparent);}
.seat .hand{display:flex;}
.seat .card3d + .card3d{margin-left:calc(var(--cw)*-0.55);}
.seat.hero{--cw:14.72cqh;}
.seat.bot{--cw:10.39cqh;}
/* hero's cards + chip pile side by side ("jetoanele... in dreapta cartilor,
   pe masa pregatite" — Vlad) instead of stacked, chips to the right since
   .bet-chips comes after .hand in the DOM. */
/* .hero-row's OWN box must stay exactly hand-sized — .seat.hero is centered
   on HERO_FELT_POS via translate(-50%,-50%), so if the row's flow height grew
   to match the (taller) chip pile, that translate would push the bottom edge
   down into the rail buttons (measured: -0.5px overlap with align-items:center
   AND :flex-end — flex alignment doesn't change the container's own height,
   only where children sit within it). The pile is positioned OUT of flow
   instead (absolute, anchored to the hand's right edge), so it can be taller
   than the hand without growing the box translate(-50%,-50%) centers. */
.hero-row{position:relative; display:flex;}
/* --cw:10.4cqh — same scale as .pot-chips/.bot-bet-chips (see below): Vlad
   wants every chip pile on the table the same size, pot included, not just
   hero matching bots.
   top:50% (not bottom:0) + a much bigger margin-left: with bottom:0 the pile
   sat at the hand's BOTTOM edge, which — verified by sampling the actual
   background pixels at that point (canvas + RGB channel test, same technique
   as BOT_CHIP_POS) — is already past the felt, onto the wood rail, no matter
   the x. The felt only reaches to about x:62% at the cards' own height
   (y:73.5%, the hand's vertical CENTER); top:50% keeps the pile at that
   height instead of the hand's bottom, and margin-left:1.3cw (was 0.18 —
   scaled for the OLD tight-beside-the-cards look) pushes it far enough right
   to clear the hand without crossing back onto the rail. Checked at the
   widest cluster (6 towers): every tower center still samples as felt.
   ---- 2026-08-13: lifted half a chip (0.425cw) ----
   Vlad: "la playerul care joaca, jetoanele se suprapun putin cu masa, trebuie
   mutate mai in sus pe verticala cu jumatate de jeton." He was right to the
   pixel — measured on the real discs, the felt ends at y:86.6% under this pile
   while its bottom edge reached y:90.64%, i.e. 0.45cw of chip hanging over the
   wooden rail. (Note the tower CENTRES were all still on felt, which is why the
   older centre-only check above never caught it — a disc is drawn 0.425cw below
   its own centre.)
   ⚠️ The lift lives on `top`, NOT on `transform`. It was on the transform first
   and Vlad caught the result immediately: "prima data cand apare jetonul apare la
   pozitia vechie, dupa care sare imediat la pozitia noua". The .chip-pop entry
   animation's keyframes set `transform:scale(...)`, which REPLACES the whole
   transform — so for the 0.28s it ran the lift vanished, the pile sat back over
   the rail, then snapped up. Anything chipPop animates must stay out of
   `transform`. (Bots never showed this: theirs is translate(-50%,-50%) on a
   zero-size box, so losing it changes nothing visible.)
   ⚠️ HERO ONLY — the bots' piles are placed from BOT_CHIP_POS in poker.js and
   are not affected; do not "fix" them to match. */
.hero-row .bet-chips{position:absolute; left:100%; top:calc(50% - var(--cw) * 0.425);
  transform:translateY(-50%); margin-left:calc(var(--cw)*1.3); --cw:9.01cqh;}
.name-tag{font-family:var(--mono); font-size:calc(var(--cw)*0.19); font-weight:700; color:var(--text-dim);
  background:rgba(5,7,13,.82); border:1px solid var(--border); border-radius:999px; padding:.3em .85em;
  white-space:nowrap; box-shadow:0 4px 10px rgba(0,0,0,.5);}
.name-tag .stack{color:var(--text); font-weight:800; margin-left:.5em;}
.bet-chips{position:relative;}
/* bots' pile is its own absolutely-positioned layer (BOT_CHIP_POS in
   poker.js) — on the green felt, forward of the cupholder, not nested in
   .seat.bot anymore, so it needs its own explicit --cw (would otherwise fall
   back to .scene's 13cqh and collide between adjacent seats, found via
   getBoundingClientRect on seats 0/1). Same 10.4cqh as .pot-chips/hero's own
   pile — every chip pile on the table reads at one consistent size now. */
.bot-bet-chips{position:absolute; transform:translate(-50%,-50%); --cw:9.01cqh; z-index:4; pointer-events:none;}
/* the amount badge floats ABOVE the pile (toward the pot/open felt) instead
   of adding a row below it — for hero that avoids the rail buttons, for bots
   it avoids crowding their cards. */
.pile-amt{position:absolute; left:50%; bottom:100%; transform:translateX(-50%); margin-bottom:calc(var(--cw)*0.1);
  /* ⚠️ 0.1811 → 0.2083 = încă +15% (Vlad, 2026-09-03: „să se vadă mai bine betul").
     Istoricul mărimii: +15%, apoi +5% (2026-08-27), acum +15%. */
  font-family:var(--mono); font-weight:800; color:#06130b; font-size:calc(var(--cw)*0.2083); line-height:1;
  /* ⚠️⚠️ PADDING-UL ORIZONTAL SCADE, ca pastila să NU se lățească (cerut explicit:
     „mai înaltă, dar mai lată nu"). Padding-ul e în `em`, deci ar fi crescut cu fontul
     — 0.8em×1.15 pe fiecare parte, plus textul mai lat, ar fi dat o pastilă cu ~15%
     mai lată. ⚠️ 0.5em e MĂSURAT în browser, nu ales: la o sumă obișnuită („0.040")
     lățimea iese EXACT 0% diferență față de înainte. Cu 0.62em creștea încă cu 6%.
     ⚠️ ÎNĂLȚIMEA crește cu fontul, cum s-a cerut: `line-height:1` plus 0.3em sus și
     jos înseamnă 1.6em, deci +15% odată cu litera.
     ⚠️ La sume LUNGI pastila tot se lățește — și e corect: „doar dacă dă textul pe
     afară o mărești și pe lățime". `white-space:nowrap` garantează că textul nu se
     rupe niciodată pe două rânduri. */
  background:linear-gradient(180deg,#ffe27a,var(--c)); border-radius:999px; padding:.3em .5em; white-space:nowrap;
  box-shadow:0 3px 8px rgba(0,0,0,.4);}
.status-tag{font-family:var(--mono); font-size:calc(var(--cw)*0.16); font-weight:700; letter-spacing:.06em; text-transform:uppercase;
  color:var(--coral); padding:.15em .6em;}
.status-tag.win{color:var(--c);}
/* ⚠️ SB / BB — pastilele de blind, sub butonul D, în același spațiu de
   coordonate (vezi renderBlindTags în poker.js). Deliberat mai mici și mai
   discrete decât D: spun cine pune jumătate și cine întreg, fără să concureze
   cu butonul care spune cine împarte. `pointer-events:none` fiindcă nu sunt
   controale — nu au ce să intercepteze. */
.blind-tag{position:absolute; padding:.18cqw .5cqw; border-radius:.6cqw;
  font-family:var(--mono); font-weight:800; font-size:1.05cqw; line-height:1.15;
  letter-spacing:.04em; display:grid; place-items:center; white-space:nowrap;
  z-index:5; transform:translate(-50%,-50%); pointer-events:none;
  box-shadow:0 2px 6px rgba(0,0,0,.45);}
.blind-tag.sb{background:rgba(20,22,34,.92); color:var(--text-dim); border:1px solid rgba(255,255,255,.28);}
.blind-tag.bb{background:rgba(20,22,34,.92); color:var(--c); border:1px solid color-mix(in srgb,var(--c) 55%,transparent);}

.dealer-btn{position:absolute; width:2.63cqw; height:2.63cqw; min-width:20px; min-height:20px; border-radius:50%;
  background:linear-gradient(180deg,#fff,#ddd); color:#111; font-family:var(--mono); font-weight:800; font-size:1.42cqw;
  display:grid; place-items:center; box-shadow:0 3px 8px rgba(0,0,0,.5); border:2px solid #999; z-index:5;
  transform:translate(-50%,-50%);}

/* ---- sound control: mute + volume, ported from roulette.html's own
   sound-ctl (same open/close-panel behaviour, same master-gain engine in
   poker.js) — just rescaled from roulette's raw cqw units to poker's --cw
   (cqh-based, see .scene) so it sits at the same relative size as every
   other on-table element here. Corner of the felt, top-right — clear of
   every seat (closest is seat 8 at x:75.4/y:11.4, well left/below this).
   Anchored by LEFT, not right: roulette's version anchored the pill by its
   right edge, so opening it (padding-right + slider width growing) pushed
   the whole box — speaker included — to the left, since flexbox lays the
   button out from the box's (moving) left edge. Vlad wants the opposite:
   speaker stays put, the volume bar grows out to its right. Anchoring by a
   fixed `left` instead means the box only grows on its right side, so the
   first flex child (the button) never moves. `left` is pulled in from the
   true corner by more than the panel's open-state growth (padding-right
   0.2cw + slider 1.7cw + slider's own margin 0.15cw ≈ 2.05cw), so the fully
   open pill's right edge still lands short of the table's right edge. */
/* ⚠️⚠️ O SINGURĂ PASTILĂ pentru tot sunetul: efecte + microfon (2026-09-02).
   ⚠️ COLOANĂ, nu rând: [DECISIONS §6.7] — ancorată pe `left` tocmai ca difuzorul
   să NU se miște la deschidere. Cu `align-items:flex-start`, butonul rămâne în
   colțul din stânga-sus indiferent cât crește panoul.
   ⚠️ Și creșterea e ÎN JOS: marginea din dreapta a pastilei deschise avea deja
   doar ~9px până la marginea mesei (măsurat la §6.7), deci un rând mai lat ar fi
   scos-o de pe masă. Rândul 2 e ținut sub lățimea rândului 1 — vezi `.voice-row`. */
.sound-ctl{position:absolute; z-index:6; top:4.31cqh; left:calc(100% - (var(--cw)*3.2));
  display:flex; flex-direction:column; align-items:flex-start;
  gap:0; padding:calc(var(--cw)*0.09);
  border-radius:999px; border:1px solid var(--border); background:rgba(6,7,13,.72);
  backdrop-filter:blur(4px);
  transition:padding .28s var(--ease), background .2s var(--ease),
             border-color .2s var(--ease), border-radius .28s var(--ease), gap .28s var(--ease);}
.snd-row, .voice-row, .tick-row{display:flex; align-items:center; gap:0;}
.sound-ctl.open{padding-right:calc(var(--cw)*0.2); border-radius:calc(var(--cw)*0.34);}
/* Rândul de voce EXISTĂ doar cu panoul deschis: închis, pastila rămâne exact
   butonul rotund de dinainte. */
.voice-row, .tick-row{display:none;}
.sound-ctl.open .voice-row:not([hidden]),
.sound-ctl.open .tick-row:not([hidden]){display:flex; margin-top:calc(var(--cw)*0.1);}
.voice-row[hidden], .tick-row[hidden]{display:none !important;}
.sound-ctl:hover, .sound-ctl:focus-within{background:rgba(6,7,13,.92);
  border-color:color-mix(in srgb,var(--c) 45%,transparent);}
.mute-btn{width:calc(var(--cw)*0.62); height:calc(var(--cw)*0.62); min-width:26px; min-height:26px; flex:none;
  border-radius:999px; border:0; background:transparent;
  color:var(--text); font-size:calc(var(--cw)*0.32); line-height:1; cursor:pointer; display:flex;
  align-items:center; justify-content:center; transition:.2s var(--ease);}
.mute-btn:hover{color:var(--c);}
.mute-btn.muted{color:var(--text-faint);}
/* --pct is written by renderSound() in poker.js; paints the filled track */
.vol{-webkit-appearance:none; appearance:none; flex:none; height:calc(var(--cw)*0.12);
  border-radius:999px; cursor:pointer; outline:none;
  width:0; opacity:0; margin-left:0; pointer-events:none;
  transition:width .28s var(--ease), margin-left .28s var(--ease), opacity .2s var(--ease);
  background:linear-gradient(to right,
    var(--c) 0 var(--pct,100%), rgba(255,255,255,.20) var(--pct,100%) 100%);}
.sound-ctl.open .vol{width:calc(var(--cw)*1.7); opacity:1; margin-left:calc(var(--cw)*0.15); pointer-events:auto;}
.sound-ctl.open .vol.muted{opacity:.35;}
.vol:focus-visible{box-shadow:0 0 0 calc(var(--cw)*0.04) color-mix(in srgb,var(--c) 40%,transparent);}
.vol::-webkit-slider-thumb{-webkit-appearance:none; width:calc(var(--cw)*0.28); height:calc(var(--cw)*0.28);
  min-width:12px; min-height:12px; border:0; border-radius:50%; background:#fff; cursor:pointer;
  box-shadow:0 0 calc(var(--cw)*0.08) color-mix(in srgb,var(--c) 75%,transparent);}
.vol::-moz-range-thumb{width:calc(var(--cw)*0.28); height:calc(var(--cw)*0.28); min-width:12px; min-height:12px; border:0;
  border-radius:50%; background:#fff; cursor:pointer;
  box-shadow:0 0 calc(var(--cw)*0.08) color-mix(in srgb,var(--c) 75%,transparent);}

/* ---- two-faced cards: FAȚA e un SVG vectorial, SPATELE rămâne desenat aici ----
   ⚠️ Cartea nu mai e desenată din CSS. Fișierele sunt în `/casino-cards/` (52,
   `viewBox="0 0 744 1039.24"`), COMUNE celor TREI jocuri cu cărți — cele două mese
   de poker și blackjack — ca `/casino-gate.css` și `/casino-wallet.js`.
   ⚠️ Ce era înainte (`.face .corner`, `.pips`, `.pip`, `.ace`, `.court`,
   `.face.front.red`) e salvat în
   `Carti_Poker_SVG/back_up_carti_2026-09-01_16-57/`.
   ⚠️ NU redesena colțurile aici: SVG-ul le poartă deja (rang + simbol, sus-stânga
   și rotit jos-dreapta), deci s-ar suprapune peste cele din fișier.
   ⚠️ Raportul SVG e 744/1039.24 = 0.7159, al cărții 1/1.4 = 0.7143 — 0,2%, adică
   sub o zecime de pixel la mărimile de pe masă. De-aia imaginea umple caseta
   (`width/height:100%`) în loc de `object-fit:contain`, care ar lăsa o dungă. */
.ghost{width:var(--cw); height:calc(var(--cw)*1.4); border-radius:10%; border:2px dashed rgba(255,255,255,.18);}
.card3d{width:var(--cw); height:calc(var(--cw)*1.4); position:relative; flex:0 0 auto;
  transform:rotate(var(--rot,0deg)); transform-style:preserve-3d;}
.card3d.new{animation:dealIn .4s var(--ease) backwards;}
@keyframes dealIn{from{transform:translate(50%,-160%) rotate(10deg); opacity:0;} to{transform:translate(0,0) rotate(var(--rot,0deg)); opacity:1;}}
.cf{position:absolute; inset:0; transform-style:preserve-3d; transition:transform .4s var(--ease);}
.card3d.down .cf{transform:rotateY(180deg);}
.card3d.reveal .cf{animation:holeFlip .55s var(--ease) forwards;}
@keyframes holeFlip{from{transform:rotateY(180deg);}to{transform:rotateY(0deg);}}
.face{position:absolute; inset:0; backface-visibility:hidden; -webkit-backface-visibility:hidden; border-radius:calc(var(--cw)*0.12);}
/* fundal alb plin, nu gradient: cartonul e desenat acum ÎN fișier, iar un gradient
   sub el s-ar vedea doar pe marginea de câțiva px lăsată de viewBox. */
.face.front{background:#fdfdf8; color:#16161d; overflow:hidden;
  box-shadow:0 10px 22px rgba(0,0,0,.55), inset 0 1px 0 rgba(255,255,255,.9), inset 0 0 0 1px rgba(0,0,0,.06);}
.face.front img{width:100%; height:100%; display:block; border-radius:inherit;
  user-select:none; -webkit-user-select:none; -webkit-user-drag:none; pointer-events:none;}
.face.back{transform:rotateY(180deg);
  background:
    repeating-linear-gradient(45deg, rgba(255,210,63,.16) 0 8px, transparent 8px 16px),
    linear-gradient(160deg,#241b06,#120d02);
  border:6px solid #e7e7dd; box-shadow:0 10px 22px rgba(0,0,0,.55);}
.face.back::after{content:"♠"; position:absolute; inset:0; display:grid; place-items:center;
  font-size:calc(var(--cw)*0.3); color:rgba(255,210,63,.5); text-shadow:0 0 16px rgba(255,210,63,.4);}

/* result banner floating over the felt */
.banner{display:none; position:absolute; left:50%; top:40%; transform:translate(-50%,-50%); z-index:9;
  font-family:var(--mono); font-weight:800; font-size:clamp(14px,2.6cqw,26px); letter-spacing:.03em; text-align:center;
  /* ⚠️ `pre-line`, NU `nowrap`: din 2026-09-01 bannerul poartă o linie per parte
     câștigătoare (vezi finishHandUI), deci `\n` trebuie să rupă rândul. Cu
     `nowrap` cele două poturi s-ar fi lipit într-o singură bandă care iese de pe
     masă. `max-width` e plasa: o linie lungă se rupe în loc să curgă în afară. */
  white-space:pre-line; max-width:86cqw; line-height:1.35;
  color:var(--text); background:rgba(5,7,13,.9); border:1px solid var(--border); border-radius:.6em;
  padding:.5em .9em; backdrop-filter:blur(5px); pointer-events:none;}
.banner.gold{color:var(--yellow); border-color:color-mix(in srgb,var(--yellow) 55%,transparent); text-shadow:0 0 26px color-mix(in srgb,var(--yellow) 70%,transparent);}
/* was 2.8s (2200ms next-hand delay), then 4.5s (4500ms) — scaled up along
   with scheduleNextHandOrRebuy() (poker.js) so it fades right as the next
   hand starts, not long before it. */
.banner.go{animation:bannerPop 6.5s var(--ease) forwards;}
@keyframes bannerPop{0%{opacity:0; transform:translate(-50%,-50%) scale(.7);} 12%{opacity:1; transform:translate(-50%,-50%) scale(1.05);}
  20%{transform:translate(-50%,-50%) scale(1);} 82%{opacity:1;} 100%{opacity:0; transform:translate(-50%,-50%) scale(.96);}}

/* ---- rail controls: small round buttons sitting ON the table's own wood
   rail (bordura), where the hero's cards used to sit — freed up by moving the
   hero's cards onto the felt instead (see .seat.hero / HERO_FELT_POS in
   poker.js). Positioned at the real projected mid-point of the front rail's
   wood band, see Dev_3D_Poker_Table.md. ---- */
.rail-controls{position:absolute; left:50%; top:96.9%; transform:translate(-50%,-50%);
  display:flex; gap:3.95cqw; z-index:6;}
/* ---- round action buttons: layered gradient + bevel for a real "casino
   button" feel instead of a flat tinted circle, one accent colour per action
   via --rbtn-accent so the glow/border/icon tint all stay in sync. 30%
   bigger than the original (9.5cqh/34px -> 12.35cqh/44px), per Vlad. The
   check/call button doubles as "Start Hand" before the first deal — see
   renderControls() in poker.js, which swaps its icon/title/class to "start"
   while G.phase==="idle" — so its accent (green) reads as "go" either way. */
.rbtn{appearance:none; cursor:pointer; font:inherit; width:12.35cqh; height:12.35cqh; min-width:44px; min-height:44px;
  border-radius:50%; display:grid; place-items:center; position:relative; transition:.15s var(--ease);
  --rbtn-accent:var(--text-faint);
  background:
    radial-gradient(circle at 50% 28%, rgba(255,255,255,.14), transparent 52%),
    radial-gradient(circle at 50% 100%, color-mix(in srgb,var(--rbtn-accent) 20%,transparent), transparent 65%),
    linear-gradient(160deg,#1d2230,#0a0c12 68%);
  border:2.5px solid color-mix(in srgb,var(--rbtn-accent) 65%,transparent);
  box-shadow:
    0 7px 16px -2px rgba(0,0,0,.6),
    inset 0 1.5px 0 rgba(255,255,255,.14),
    inset 0 -4px 8px rgba(0,0,0,.5),
    0 0 0 1px color-mix(in srgb,var(--rbtn-accent) 16%,transparent);}
.rbtn .ico{font-size:4.7cqh; line-height:1;
  color:color-mix(in srgb,var(--rbtn-accent) 30%,var(--text));
  filter:drop-shadow(0 1px 3px rgba(0,0,0,.55));}
.rbtn:disabled{opacity:.35; cursor:not-allowed; filter:saturate(.4);}
.rbtn:hover:not(:disabled){transform:translateY(-2px);
  box-shadow:
    0 9px 18px -2px rgba(0,0,0,.6),
    inset 0 1.5px 0 rgba(255,255,255,.16),
    inset 0 -4px 8px rgba(0,0,0,.5),
    0 0 20px color-mix(in srgb,var(--rbtn-accent) 60%,transparent);}
.rbtn:active:not(:disabled){transform:translateY(1px);}
.rbtn.fold{--rbtn-accent:var(--coral);}
.rbtn.check{--rbtn-accent:var(--green);}
.rbtn.raise{--rbtn-accent:var(--c);}

/* ---- CLEPSIDRA DE TUR ---------------------------------------------------
   ⚠️ NUMAI la masa PvP. Se pune pe BUTONUL CARE SE VA APĂSA SINGUR — fold dacă
   ai de plătit, check dacă nu (`timeoutAction()` din engine.js) — deci inelul nu
   spune doar „mai ai puțin", ci și CE pierzi dacă taci. Pe celelalte două butoane
   nu apare: n-ar fi adevărat, acolo nu se întâmplă nimic la zero.

   Trei trepte, armate din `armTurnClock()`: inel la 10s (tăcut), tic la 6s,
   puls la 3s. Cifrele vin de la SERVER, nu de aici.

   ⚠️ INELUL EXISTĂ TOT TIMPUL, doar că e transparent. Nu se adaugă și nu se
   scoate niciun element la armare: un `::after` creat pe loc ar începe animația
   într-un cadru în care așezarea încă se recalculează.

   ⚠️ CÂND CEASUL PORNEȘTE, BORDURA PROPRIE A BUTONULUI SE STINGE. Nu e un efect
   secundar, e semnalul: saltul de la inel verde întreg la inel gol e ce sare în
   ochi la T-10s, într-un buton pe care altfel nu se schimbă nimic. S-a încercat
   și varianta în care bordura RĂMÂNE și e chiar pista ceasului (deci nimic nu
   sare) — mai elegantă pe hârtie, dar Vlad a comparat cele două rulând și a ales
   asta: „se vede cum se umple clepsidra mai bine si iti sare in ochi ca ceva se
   intampla". La 10 secunde saltul e un indiciu, nu o panică; obiecția inițială
   era calibrată pe o fereastră de 6s, unde vine prea târziu ca să mai ajute.
   [DECISIONS §10.111](../../DECISIONS.md). */
@property --p{syntax:'<number>'; inherits:true; initial-value:0;}
/* ⚠️ Culoarea e o proprietate ÎNREGISTRATĂ, animată în aceleași keyframes — NU
   derivată din --p cu `color-mix`: acolo substituția nu se reface la fiecare
   cadru, deci inelul se umplea corect dar rămânea verde până la capăt. */
@property --col{syntax:'<color>'; inherits:true; initial-value:#3DDC84;}

.rbtn.turnclock::after{content:""; position:absolute; inset:-2.5px; border-radius:50%;
  pointer-events:none; opacity:0; transition:opacity .18s var(--ease);
  -webkit-mask:radial-gradient(farthest-side, transparent calc(100% - 2.5px), #000 calc(100% - 2.5px));
          mask:radial-gradient(farthest-side, transparent calc(100% - 2.5px), #000 calc(100% - 2.5px));
  /* de la BAZĂ, simetric în ambele direcții, se închide exact sus la zero */
  background:conic-gradient(
    rgba(255,255,255,.05) 0 calc(180deg - var(--p)*180deg),
    var(--col)            0 calc(180deg + var(--p)*180deg),
    rgba(255,255,255,.05) 0);
  filter:drop-shadow(0 0 calc(var(--p)*11px) var(--col));}

.rbtn.turnclock.armed{border-color:transparent;}
.rbtn.turnclock.armed::after{opacity:1;
  animation:turnDrain var(--turn-dur,10s) linear forwards;
  animation-delay:var(--turn-delay,0s);}
@keyframes turnDrain{
  0%  {--p:0;   --col:#3DDC84;}   /* verde */
  45% {--col:#F5B544;}            /* portocaliu */
  /* ⚠️ #e14352 e mijlocul gradientului lui `.chip-disc.c5` — roșul care există
     deja pe masă. NU `--coral`: acela e ROZ, și a fost respins exact pentru asta
     (2026-08-23, butonul CANCEL). */
  100%{--p:1;   --col:#e14352;}
}

/* ⚠️ PULSUL NU E O CLASĂ CSS, e `Element.animate()` din `pulseTurnClock()`.
   `animation` e un shorthand: o a doua regulă cu `animation:puls` ar ȘTERGE
   `turnDrain` de pe același element, iar inelul ar îngheța verde exact la primul
   tic. Costă o oră de căutat, fiindcă arată ca o problemă de culoare. */

/* ---- pauza dintre mâini: ACELAȘI inel, ALT registru --------------------
   ⚠️ Aurul mesei (`--c`), de la un capăt la altul: nicio rampă spre roșu. Roșul
   înseamnă „pierzi mâna" la ceasul de tur, iar la pauză nu pierzi nimic — doar
   începe mâna următoare. Folosit în ambele locuri, ar striga „pericol" la un lucru
   normal, iar a doua oară n-ar mai fi crezut nici acolo unde chiar e.
   ⚠️ Și e mai subțire (fără glow): trebuie să se vadă, nu să se impună — apare la
   FIECARE mână, deci un inel insistent ar obosi în zece minute. */
.rbtn.turnclock.gap.armed::after{
  animation-name:gapDrain;
  filter:none;}
@keyframes gapDrain{
  0%  {--p:0; --col:#FFD23F;}
  100%{--p:1; --col:#FFD23F;}
}

@media (prefers-reduced-motion:reduce){
  /* fără pâlpâire, dar ceasul RĂMÂNE: e informație, nu decor */
  .rbtn.turnclock.armed::after{filter:none;}
}

/* ---- bet sizing: a small popover that floats just above the rail buttons
   instead of a permanent panel below the table ---- */
/* ⚠️ PANOUL DE PARIU — 2026-08-23. Ce lipsea când a fost reclamat („momentan e
   confuz"): potul nu se vedea NICĂIERI (iar panoul stă chiar PESTE potul de pe
   pâslă), butoanele nu spuneau ce sumă produc, iar singura cifră nu spunea dacă e
   „ridic LA" sau „mă costă".
   ⚠️ Estetica rămâne A PANOULUI (mono, `--surface`, accent `--c`) — NU se importă
   clasele `.gate-amount`, care sunt Cinzel 22px auriu pe mov, pentru overlay-ul de
   conectare. „Copiază, nu inventa" înseamnă vecinul potrivit, nu orice vecin.

   ⚠️⚠️ BUGETUL DE ÎNĂLȚIME E ~190px, și e o MĂSURĂTOARE: atât încape între cărțile
   comunitare (jos la 55,4% din scenă) și butoanele de acțiune (sus la 90,7%), la
   1440×900. Forma s-a schimbat de două ori — coloană simplă (255px, ACOPEREA
   board-ul, respinsă), bandă lată de 720px (118px, dar „prea alungită pe
   orizontală", respinsă de Vlad) — bugetul nu. Dacă adaugi un rând, RE-MĂSOARĂ. */
/* ⚠️ `bottom:12%`, nu 13%: panoul se așază CENTRAT în banda liberă. Măsurat la
   1440×900: banda dintre cărțile comunitare și butoanele de acțiune e 190px, panoul
   are 159px, deci rămân ~15px de fiecare parte. La 13% rămâneau 4px SUS — adică o
   singură literă în plus într-o explicație și era iar peste board. */
.bet-popover{display:none; position:absolute; left:50%; bottom:10.3%; transform:translateX(-50%); z-index:8;
  width:min(440px, 94%); flex-direction:column; gap:5px;
  background:rgba(8,10,15,.94); border:1px solid var(--border); border-radius:16px;
  padding:9px 11px; backdrop-filter:blur(6px); box-shadow:0 14px 34px -12px rgba(0,0,0,.7);}
.bet-popover.show{display:flex;}

/* stânga: potul + suma de scris. dreapta: cele patru sume + confirmarea. */
.bet-cols{display:flex; gap:9px; align-items:stretch;}
.bet-col{display:flex; flex-direction:column; gap:4px; min-width:0;}
.bet-col:first-child{flex:1 1 0;}
.bet-col-actions{flex:0 0 186px; justify-content:space-between; gap:5px;}

/* ⚠️ A RĂMAS DOAR POTUL. „TO CALL" și „STACK" erau dublură (Vlad, 2026-08-23) —
   stiva o scrie pastila de sub masă, call-ul linia de stare. Potul NU se poate
   scoate: panoul îl acoperă pe cel de pe pâslă. */
.bet-context{display:flex;}
/* ⚠️ POTUL SE CITEȘTE DE LA DISTANȚĂ. Era 12px pe cenușiu — „trebuie să mă chiorăsc
   să văd" (Vlad, 2026-08-23). E numărul după care se judecă toată decizia, deci e cel
   mai mare text din panou, nu cel mai mic. */
.bet-context span{flex:1; display:flex; align-items:baseline; justify-content:center; gap:7px;
  background:var(--surface); border:1px solid var(--border); border-radius:9px; padding:6px 8px;}
/* ⚠️⚠️ ETICHETELE SE CITESC (ales de Vlad, 2026-09-03: „griul ăla spălăcit nu-l
   vezi"). Gri LUMINOS, nu o culoare — fiindcă în panoul ăsta fiecare culoare are
   deja un înțeles: auriu = potul, câmpul de sumă și ALL-IN · verde = CONFIRM ·
   roșu = anulare · albastru = „e în discuție", la voce.
   ⚠️⚠️ S-au randat și verdele și albastrul, și s-au RESPINS uitându-ne la ele:
   pe 3 din 4 butoane, o etichetă colorată FURĂ exact semnalul lui ALL-IN, cerut
   cu două minute înainte. O culoare care înseamnă două lucruri în același ecran
   e o datorie, nu o claritate. */
.bet-context i{font-style:normal; font-family:var(--mono); font-size:9.5px; letter-spacing:.06em; color:#aebccb;}
.bet-context b{font-family:var(--mono); font-size:19px; font-weight:800; color:var(--text); line-height:1.05;}
.bet-context .lead{border-color:color-mix(in srgb,var(--c) 40%,var(--border));}
.bet-context .lead b{color:var(--c);}

.bet-label{font-family:var(--mono); font-size:8px; letter-spacing:.08em; color:#aebccb;
  white-space:nowrap; flex-shrink:0;}
/* ⚠️ CÂMP DE SCRIS, nu doar cursor (cerut explicit). Plafonul de sus e TARE — vezi
   setBetTarget() în poker.js: nu se poate scrie mai mult decât ai LA MASĂ. */
.bet-amt-row{display:flex; align-items:center; gap:6px; background:rgba(0,0,0,.34);
  border:1px solid color-mix(in srgb,var(--c) 38%,transparent); border-radius:10px; padding:5px 9px;}
.bet-amt-row:focus-within{border-color:var(--c);}
/* ⚠️⚠️ `min-width` NU MAI E 0 (reparat 2026-09-03, raportat de Vlad: „cifra 4 se
   vede doar pe jumătate"). Cu `flex:1; min-width:0`, câmpul cedează PRIMUL când
   rândul se strâmtorează — deși e numărul pe care se ia decizia. Măsurat: la un
   panou de 414px conținutul de 57px avea 44px vizibili; la 376px, **6px**.
   ⚠️ 3.7em la 19px ≈ 70px, adică exact cât ocupă cea mai lungă sumă plauzibilă
   („12.345"). Sub atât nu se coboară; cine cedează acum e eticheta și unitatea. */
.bet-input{flex:1 1 auto; min-width:3.7em; background:none; border:none; outline:none; padding:0;
  font-family:var(--mono); font-size:19px; font-weight:800; color:var(--c); text-align:left;}
.bet-input::placeholder{color:#5c6270;}
.bet-unit{font-family:var(--mono); font-size:10px; color:#aebccb; white-space:nowrap;}
/* MAX, ca la restul câmpurilor de sumă din site (`.amt-max` din casino-gate.css) */
.bet-max{flex-shrink:0; appearance:none; cursor:pointer; padding:3px 8px; border-radius:999px;
  border:1px solid color-mix(in srgb,var(--c) 45%,transparent); background:transparent; color:var(--c);
  font:inherit; font-size:9.5px; font-weight:700; transition:background .15s ease;}
.bet-max:hover{background:color-mix(in srgb,var(--c) 14%,transparent);}

.bet-derived,.bet-why,.bet-err{font-family:var(--mono); font-size:10px; line-height:1.3;}
.bet-derived{color:var(--text-dim); margin-top:1px;}
/* ⚠️ EXPLICAȚIA E MAI MARE ȘI MAI LUMINOASĂ decât restul liniilor mici (Vlad,
   2026-08-23: „fă-o mai clară, puțin mai mare"). Era 10px pe `--text-faint`, adică
   cel mai șters text din panou — deși e singurul care spune DE UNDE vine suma.
   ⚠️ Cifrele sunt AURII (`--c`), aceeași culoare ca suma din câmp: ochiul urmărește
   aritmetica, nu fraza. Vlad a propus roșu; roșul e luat în panou de eroare
   (`.bet-err`) și de butonul de anulare, iar o explicație normală colorată la fel
   ar citi „ceva e greșit". Auriu = „valoare", ceea ce chiar sunt. */
.bet-lines{min-height:16px;}
.bet-why{color:var(--text-dim); font-size:12px;}
.bet-why b{color:var(--c); font-weight:800;}
.bet-derived:empty,.bet-why:empty{display:none;}
.bet-err{color:var(--coral);}
.bet-err[hidden]{display:none;}

.bet-panel-row{display:flex; align-items:center;}
.bet-popover input[type=range]{flex:1; min-width:0; accent-color:var(--c);}

/* ⚠️ GRILĂ 2×2, nu un rând de patru: pe un panou de 440px patru butoane în linie
   ar avea ~44px fiecare, adică exact cât să-și rupă eticheta („ALL-" + „IN") și să
   crească rândul în înălțime — direcția în care panoul ajunge iar peste board. */
.bet-quick{display:grid; grid-template-columns:1fr 1fr; gap:4px;}
/* ⚠️ Mărite 2026-08-23 („butoanele de pot sunt prea mici"). Spațiul vine din faptul
   că panoul urcă acum până lângă cărți — potul de pe pâslă e oricum sub el. */
/* ⚠️⚠️ PE DOUĂ RÂNDURI, ȘI TOATE SPUN „RAISE TO" (ales de Vlad, 2026-09-03).
   Butoanele scriau numele sizing-ului lângă sumă — `POT 0.060` — la 3 cm sub
   `POT 0.030`, potul REAL de pe masă. Același cuvânt, două înțelesuri: te aștepți
   ca al doilea număr să fie primul. Vlad a raportat-o exact așa.
   ⚠️ Numele (MIN · ½ POT · POT · ALL-IN) au DISPĂRUT de pe buton, deliberat, și e
   un cost asumat: două butoane pot arăta aceeași sumă (pe poturi mici ½ POT cade
   peste MIN). Informația nu s-a pierdut — după apăsare, `betWhy` spune care e
   („the smallest raise allowed", „½ of the pot after your call"), iar `title` o
   spune la hover, fără să coste niciun pixel.
   ⚠️ S-au respins, MĂSURATE: toate patru pe un rând cu „RAISE TO" lângă sumă
   (butoane care nu se mai deosebesc între ele), un titlu comun peste grup
   (+19px), și „RAISE TO" peste nume pe trei rânduri (+22px) — panoul are ~190px
   până la cărțile comunitare, deja consumați. [DECISIONS §10.87] */
/* ⚠️⚠️ ÎNĂLȚIMEA E CEA A RÂNDULUI DE SUMĂ, MĂSURATĂ, NU GHICITĂ (2026-09-03).
   Cu padding-ul inițial (5px, moștenit de la varianta pe UN rând), butonul pe
   DOUĂ rânduri ieșea la 31px — vizibil mai înalt decât POT (22px) și decât
   rândul RAISE TO/cifra (25px), și mai înalt decât CONFIRM (24px). Raportat de
   Vlad: „nu mai sunt la aceeași mărime cu butoanele rise".
   ⚠️ Comparat cu producția LA ACEEAȘI SCENĂ înainte de schimbare: acolo butonul
   (pe un rând) era 22px — deci ținta e ~22-25px, nu orice. */
.bet-quick button{appearance:none; cursor:pointer; font:inherit; font-weight:700; letter-spacing:.02em;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:1px;
  line-height:1; white-space:nowrap;
  padding:3px 4px; border-radius:9px; background:var(--surface); border:1px solid var(--border); color:var(--text-dim);}
.bet-quick button i{font-style:normal; font-size:9px; letter-spacing:.1em; opacity:1; color:#aebccb;}
/* ⚠️⚠️ ALL-IN ÎȘI PĂSTREAZĂ NUMELE, ȘI E AURIU (cerut de Vlad, 2026-09-03).
   Celelalte trei sunt fracții de pot — se deosebesc prin sumă, deci pot să spună
   toate „RAISE TO". All-in NU e o fracție: e altă acțiune, singura care îți pune
   toată stiva pe masă, și singura de pe care nu te mai poți întoarce. O etichetă
   care l-ar ascunde printre celelalte trei ar fi exact greșeala scumpă.
   ⚠️ Auriul e `--c`, cel deja folosit pentru pot și pentru câmpul RAISE TO — nu o
   culoare nouă. */
.bet-quick button[data-q="allin"] i{color:var(--c); opacity:1; font-weight:800;}
.bet-quick button b{font-family:var(--mono); font-size:12.5px; font-weight:800; color:var(--text); line-height:1.1;}
.bet-quick button:hover{color:var(--text); border-color:var(--c);}
/* Butonul stins: se vede că e acolo, dar nu invită. Vezi renderBetPanel(). */
.bet-quick button.dead{opacity:.32; cursor:default;}
.bet-quick button.dead:hover{color:var(--text-dim); border-color:var(--border);}
/* pastila apăsată rămâne marcată, ca să se vadă DE UNDE vine suma din câmp */
.bet-quick button.on{border-color:var(--c); color:var(--text);}
.bet-quick button.on b{color:var(--c);}

/* ⚠️ VERDE = mergi, ROȘU = renunți. Verdele e cel de pe rail (`.rbtn` check/call).
   ⚠️⚠️ ROȘUL E AL JETONULUI DE 5, nu coralul mesei: `#f0616d → #b3212e`, exact
   gradientul din `.chip-disc.c5`. Coralul (`--coral`, #FF6B9D) e ROZ, iar Vlad l-a
   respins tocmai pentru asta (2026-08-23) — „roșul ca jetonul, nu roz". Culoarea
   există deja pe masă, deci nu e un roșu inventat.
   ⚠️ PĂTRAT, cu „✕": `aspect-ratio:1` + `align-self:stretch`, deci latura urmează
   singură înălțimea rândului — nu se scrie nicio dimensiune de mână, care s-ar
   desincroniza la prima schimbare de padding a lui CONFIRM. */
.bet-confirm-row{display:flex; gap:6px; align-items:stretch;}
.bet-confirm-row button{appearance:none; cursor:pointer; font:inherit; font-weight:800; font-size:11.5px;
  letter-spacing:.04em; padding:9px 6px; border-radius:10px; border:none;}
.bet-confirm-row .go{flex:1 1 auto; min-width:0; background:linear-gradient(180deg,#6BEFA8,var(--green)); color:#04170c;}
.bet-confirm-row .go:disabled{background:var(--surface-2); color:var(--text-faint); cursor:not-allowed;}
.bet-confirm-row .cancel{flex:0 0 auto; align-self:stretch; aspect-ratio:1; padding:0;
  display:grid; place-items:center; font-size:15px; line-height:1; letter-spacing:0;
  background:linear-gradient(180deg,#f0616d,#b3212e); color:#fff;}

/* ⚠️⚠️ MASA MICĂ: panoul se STRÂNGE, altfel ajunge peste cărțile comunitare.
   Banda liberă e ~35% din ÎNĂLȚIMEA SCENEI (între board la 55,4% și butoane la
   90,7%), iar scena se micșorează cu fereastra — panoul, fiind în px, nu. Măsurat:
   la 1440×900 banda are 190px și panoul de 159px încape; la 1024×700 banda scade la
   ~135px și NU mai încape.
   ⚠️ `@container`, nu `@media`: contează cât e de mare MASA, nu fereastra — cele
   două nu variază la fel, fiindcă scena e `min(1750px, 98vw, 82vh × 2.6283)`.
   ⚠️ Sub ~335px înălțime de scenă nu încape nicio formă; acolo panoul chiar acoperă
   board-ul, ca și cel dinaintea lui. Limită cunoscută, nu ascunsă. */
/* ⚠️⚠️ MASA MICĂ: panoul se STRÂNGE, dar PĂSTREAZĂ forma compactă pe două coloane.
   Banda liberă e ~35% din ÎNĂLȚIMEA SCENEI (între board la 55,4% și butoane la
   90,7%), iar scena se micșorează cu fereastra — panoul, fiind în px, nu. Măsurat:
   la 1440×900 banda are 190px, la 1024×700 doar ~135px.
   ⚠️ `@container`, nu `@media`: contează cât e de mare MASA, nu fereastra — scena e
   `min(1750px, 98vw, 82vh × 2.6283)`, deci cele două nu variază la fel.
   ⚠️ NU se trece pe o bandă lată aici. A fost încercat și respins de Vlad
   (2026-08-23): forma alungită pe orizontală era exact ce nu voia, iar la 1280×800
   ar fi primit-o înapoi fără să ceară nimeni. Se strâng fonturile și spațiile.
   ⚠️ Sub ~330px înălțime de scenă nu încape nicio formă; acolo panoul chiar acoperă
   board-ul, ca și cel dinaintea lui. Limită cunoscută, nu ascunsă. */
@container (max-height: 500px){
  /* ⚠️ și `bottom` se recentrează: pe masa mică slack-ul e de ordinul a 10px, deci
     poziția moștenită ar lăsa aproape zero de o parte. */
  .bet-popover{width:min(430px, 96%); padding:5px 8px; gap:2px; bottom:11.4%;}
  .bet-cols{gap:6px;}
  .bet-col{gap:2px;}
  .bet-col-actions{flex:0 0 176px;}
  /* ⚠️ potul rămâne CEL MAI MARE text și aici — pe o masă mică e cu atât mai
     greu de citit, deci e ultimul lucru din care se taie. */
  .bet-context span{padding:2px 5px;}
  .bet-context b{font-size:15px;}
  .bet-context i{font-size:8.5px;}
  .bet-amt-row{padding:2px 7px; gap:4px;}
  /* ⚠️ La 16px, 3.7em ≈ 59px — tot cât cea mai lungă sumă, la fontul mai mic. */
  .bet-input{font-size:16px;}
  .bet-derived,.bet-err{font-size:9px; line-height:1.2;}
  .bet-why{font-size:10.5px; line-height:1.2;}
  .bet-lines{min-height:13px;}
  .bet-popover input[type=range]{height:11px;}
  .bet-quick{gap:3px;}
  /* ⚠️ ACEEAȘI ȚINTĂ ca la scenă mare — vezi regula din regula de bază: butonul
     pe DOUĂ rânduri nu are voie să depășească înălțimea rândului de sumă. */
  .bet-quick button{padding:1px 2px; gap:0;}
  .bet-quick button b{font-size:10px;}
  .bet-quick button i{font-size:8px;}
  .bet-confirm-row{gap:4px;}
  .bet-confirm-row button{padding:6px; font-size:10.5px;}
  .bet-confirm-row .cancel{padding:0; font-size:13px;}
}
/* ⚠️⚠️ ORDINEA CONTEAZĂ: blocul de mai jos e pentru scene NARROW, ridicat
   DUPĂ cel de „masă mică" (bazat pe înălțime) — vezi de ce, imediat mai jos.
   ⚠️⚠️ De ce e mutat aici, și n-a fost dintru-nceput (2026-09-03): `.scene` are
   `aspect-ratio:1004/382` FIX, deci lățime și înălțime nu variază independent —
   o scenă sub 468px lățime are AUTOMAT sub ~178px înălțime, adică e ÎNTOTDEAUNA
   și în regimul de „masă mică" de mai sus (prag 500px înălțime = ~1314px
   lățime). Cele două seturi de reguli se suprapun mereu la scene mici, nu doar
   uneori.
   ⚠️ Poziționate ÎNAINTE de blocul de „masă mică", regulile astea PIERDEAU:
   `.bet-input{font-size:16px}` din blocul de mai sus (deja în producție din
   2026-08-23, neatins) venea ULTIMUL în sursă și bătea orice font mai mic scris
   aici — măsurat: la scenă 380px, `.bet-input` rămânea la 16px cu `min-width`
   calculat pentru 14.5px, deci conținutul ("12.345") era mai lat decât caseta.
   Mutate DUPĂ, regulile astea sunt cele mai specifice pentru îngustare extremă
   și câștigă, cum trebuie. */
/* ⚠️⚠️ `xEGLD` NU SE ASCUNDE NICIODATĂ (cerut explicit de Vlad, 2026-09-03: „xEGLD
   trebuie să fie mereu"). Prima variantă îl ascundea sub 468px de scenă — greșit
   de două ori: strâmtorarea era pe lățime (era scrisă pe `max-height`, deci nici
   nu se declanșa unde trebuia), și oricum ascunderea unei unități pe o masă de
   BANI nu e o soluție acceptabilă, oricât de rar s-ar declanșa.
   ⚠️ Pe lățime mică, rândul se STRÂNGE (fonturi + spații mai mici), nu se golește
   de conținut. Ordinea rămâne: eticheta cedează cel mai mult, cifra rămâne mereu
   cea mai mare literă din rând. Pragurile sunt pe SCENĂ, nu pe panou — panoul e
   `min(440px, 94%)`, deci scade sub 440 abia când scena trece sub ~468px. */
@container (max-width: 468px){
  .bet-amt-row{gap:4px; padding:4px 7px;}
  .bet-label{font-size:7px;}
  .bet-input{font-size:16px; min-width:3.3em;}
  .bet-unit{font-size:8.5px;}
  .bet-max{padding:2px 6px; font-size:8.5px;}
}
@container (max-width: 400px){
  .bet-label{font-size:6.5px; letter-spacing:.04em;}
  .bet-input{font-size:14.5px; min-width:3.1em;}
  .bet-unit{font-size:7.5px;}
  .bet-max{padding:2px 5px; font-size:8px;}
}
/* ⚠️⚠️ SUB ~390PX DE SCENĂ, VINOVATUL NU MAI E RÂNDUL — E COLOANA DE BUTOANE.
   `.bet-col-actions` are lățime FIXĂ (186px, sau 176px pe masă scundă) și nu
   cedează nimic; la un panou strâns asta lasă coloanei din stânga (POT + suma)
   mai puțin loc decât are nevoie chiar și micșorată la maximum de mai sus.
   ⚠️ Măsurat: la scenă 380px, coloana din stânga rămânea cu ~140px — sub cât
   ocupă „RAISE TO" + „12.345" + „xEGLD" + MAX chiar la fonturile mici. */
@container (max-width: 390px){
  .bet-popover{padding:7px 8px;}
  .bet-cols{gap:5px;}
  .bet-col-actions{flex-basis:150px;}
  .bet-quick{gap:2px;}
  .bet-quick button{padding:3px 2px;}
  .bet-quick button b{font-size:10px;}
  .bet-quick button i{font-size:7px;}
  .bet-confirm-row{gap:3px;}
  .bet-confirm-row button{padding:5px; font-size:9.5px;}
}
@container (max-width: 340px){
  .bet-col-actions{flex-basis:128px;}
  .bet-label{font-size:5.5px;}
  .bet-input{font-size:13px; min-width:2.9em;}
  .bet-unit{font-size:6.5px;}
  .bet-max{padding:1px 4px; font-size:7px;}
}
/* ⚠️ Sub ~330px de scenă panoul nu mai încape curat (măsurat: la 300px cifra se
   taie, chiar și la fonturile minime de mai sus) — mai îngust decât orice telefon
   real la 98vw (cel mai mic ecran obișnuit dă ~353px). Limită CUNOSCUTĂ, ca cea de
   ~330px înălțime de la board mai sus, nu ascunsă: n-are sens micșorat mai mult,
   fontul ar deveni ilizibil înainte să rezolve o lățime pe care niciun telefon n-o
   are. Verificat curat, măsurat, la fiecare prag: 1750 → 320px. */


/* ---- thin strip below the table: status message + secondary links (no more
   boxed console — the real controls now live on the table itself) ---- */
.below-table{margin:34px 0 0;}
.msg{text-align:center; min-height:24px; font-size:16px; font-weight:600; color:var(--text-dim);}
.msg.good{color:var(--c);}
.msg.bad{color:var(--coral);}

/* ⚠️ GRID, nu flex + space-between: „Leave table" și #handnum au lățimi diferite
   (handnum azi e gol), deci space-between n-ar centra pastila de stack pe
   mijlocul RÂNDULUI, doar pe mijlocul spațiului rămas între ele — cele două
   coloane 1fr sunt garantat egale, indiferent de conținutul lor. */
.below-row{display:grid; grid-template-columns:1fr auto 1fr; align-items:center; margin-top:14px; font-size:12px; color:var(--text-faint); gap:10px;}
.below-row .leave-btn{justify-self:start;}
/* ⚠️ „Invite players" e OGLINDA lui „Leave table": aceeași celulă ca `#handnum`
   (coloana din dreapta), aceeași mărime, ca rândul să fie simetric în jurul stivei. */
.below-row #btn-invite{grid-column:3; justify-self:end;}
/* ⚠️ SIMETRIE PE LĂȚIME: „Leave table" și „Invite players" au texte de lungimi
   diferite, deci fără o lățime minimă comună rândul ar arăta strâmb. `ch` e legat de
   fontul mono al butoanelor, deci ține și dacă se schimbă mărimea literei. */
/* ⚠️ 23.3ch = fix cât ocupă „Invite players", cel mai lung dintre cele două —
   MĂSURAT în browser (1ch = 6.623px la fontul mono de 11px), nu ghicit. Primele
   încercări (15.5ch, 18.5ch) erau SUB lățimea naturală, deci regula nu făcea
   nimic și butoanele rămâneau 127 vs 149.
   ⚠️ A crescut de la 22.5 la 23.3 când plicul a devenit DESEN: caseta desenului e
   mai lată decât cerneala glifei ✉, deci lățimea naturală a butonului a urcat cu
   5px. Se mută AMÂNDOUĂ, altfel simetria se pierde exact ca s-o repari. */
.below-row .leave-btn{min-width:23.3ch; justify-content:center;}
.below-row #handnum{grid-column:3;}
.below-row .seat-pill{justify-self:center;}
.below-row #handnum{justify-self:end;}
@media (max-width:560px){.below-row{grid-template-columns:1fr; justify-items:center; gap:10px;}
  .below-row .leave-btn, .below-row .seat-pill, .below-row #handnum,
  .below-row #btn-invite{justify-self:center; grid-column:auto;}}

/* same gold pill design as .lobby-back / the Casino Lobby button */
.leave-btn{appearance:none; cursor:pointer; font-family:var(--mono); font-size:11px; font-weight:700; letter-spacing:.08em;
  text-transform:uppercase; display:inline-flex; align-items:center; gap:7px; color:#FFE55C; padding:7px 12px;
  border:2px solid rgba(255,215,0,0.3); border-radius:10px;
  background:linear-gradient(145deg, rgba(26,26,46,0.95) 0%, rgba(22,33,62,0.95) 100%);
  backdrop-filter:blur(10px); transition:.15s;}
/* ⚠️ Caseta pictogramei e aceeași fie că înăuntru e o glifă, fie un desen — altfel
   cele două butoane ar avea textul pornit de la x-uri diferite. */
.leave-btn .ico{font-size:14px; line-height:1; display:inline-flex; align-items:center;
  justify-content:center; width:14px; height:14px;}
.leave-btn .ico svg{display:block;}
.leave-btn:hover:not(:disabled){color:#FFD700; border-color:rgba(255,215,0,0.6);}
.leave-btn:active:not(:disabled){transform:translateY(1px);}
.leave-btn:disabled{color:var(--text-faint); background:var(--surface); border-color:var(--border); opacity:.55; cursor:not-allowed; box-shadow:none; transform:none;}

.rules{margin-top:32px; background:linear-gradient(180deg,#0c1016,#080b10); border:1px solid var(--border); border-radius:14px; padding:0 14px;}
.rules-head{display:flex; align-items:center; justify-content:space-between; padding:13px 0; font-size:11px; letter-spacing:.12em; text-transform:uppercase; font-weight:600; color:var(--text-faint);}
.rules-head button{appearance:none; background:none; border:none; color:var(--text-faint); font:inherit; font-size:10px; cursor:pointer; padding:2px 6px; border-radius:4px;}
.rules-head button:hover{color:var(--text-dim);}
.pt{padding:9px 0; border-top:1px solid var(--border); font-size:13px; color:var(--text-dim); line-height:1.5;}

.history{margin-top:28px; background:linear-gradient(180deg,#0c1016,#080b10); border:1px solid var(--border); border-radius:14px; overflow:hidden;}
.history-head{display:flex; align-items:center; justify-content:space-between; padding:12px 14px; font-size:11px; letter-spacing:.12em; text-transform:uppercase; font-weight:600; color:var(--text-faint);}
.history-head button{appearance:none; background:none; border:none; color:var(--text-faint); font:inherit; font-size:10px; cursor:pointer; padding:2px 6px; border-radius:4px;}
.history-head button:hover{color:var(--text-dim);}
.history-list{max-height:200px; overflow-y:auto;}
.history-list::-webkit-scrollbar{width:4px;}
.history-list::-webkit-scrollbar-track{background:transparent;}
.history-list::-webkit-scrollbar-thumb{background:var(--border); border-radius:2px;}
/* the fade belongs to a row that JUST appeared, not to every row: renderHistory()
   rebuilds the list only when its content changed and tags only the new rows
   `.h-new`. On `.h-row` it replayed for the whole log on every repaint. */
.h-row{padding:7px 14px; border-top:1px solid var(--border); font-size:12px; color:var(--text-dim);}
.h-row.h-new{animation:hfade .25s ease;}
@keyframes hfade{from{opacity:0;transform:translateY(-4px);}to{opacity:1;transform:none;}}
.h-empty{padding:16px 14px; font-size:12px; color:var(--text-faint); font-family:var(--mono); text-align:center; border-top:1px solid var(--border);}
/* the winning hand's actual 5 cards, right in the log line — small rank+suit
   badges, not scaled-down table cards (see miniCardHTML in poker.js). */
.hcards{display:inline-flex; gap:3px; margin-left:6px; vertical-align:middle;}
.hcard{display:inline-block; padding:1px 4px; border-radius:4px; background:var(--surface-2);
  border:1px solid var(--border); font-family:var(--mono); font-size:10.5px; font-weight:700; color:var(--text);}
.hcard.red{color:var(--coral);}


/* ---- buy-in modal: a single drag-to-pick slider (like the table's own
   volume control) instead of a 2x2 grid of preset amounts — smaller and
   quieter than the old grid, one control instead of four buttons. ---- */
.modal-overlay{position:fixed; inset:0; background:rgba(2,3,6,.82); backdrop-filter:blur(4px); z-index:60;
  display:flex; align-items:center; justify-content:center; padding:20px;}
.modal{position:relative; width:100%; max-width:320px; background:linear-gradient(180deg,#0f131b,#0a0d12); border:1px solid var(--border);
  border-radius:18px; padding:22px 20px 18px; box-shadow:0 30px 60px -20px rgba(0,0,0,.7);}
/* ⚠️ AL DOILEA DRUM spre aceeași ieșire, nu un al doilea buton (cerut de Vlad,
   2026-08-19): apasă exact `cashOutAndLeave`, funcția lui `.lobby-back` — pusă
   aici fiindcă acest modal (z-index:60) acoperă colțul din stânga-sus cât
   timp e deschis, chiar dacă `.lobby-back` are acum z-index:500. */
.modal-close{position:absolute; top:10px; right:12px; width:28px; height:28px; border-radius:50%;
  border:1px solid var(--border); background:rgba(255,255,255,.04); color:var(--text-dim);
  font:inherit; font-size:16px; line-height:1; cursor:pointer; display:flex; align-items:center;
  justify-content:center; transition:.15s;}
.modal-close:hover{background:rgba(255,255,255,.1); color:#fff; border-color:var(--text-faint);}
.modal h2{margin:0 0 4px; font-size:18px; text-align:center;}
.modal p{color:var(--text-dim); font-size:12px; text-align:center; margin:0 0 14px;}

.buyin-amt{text-align:center; font-family:var(--mono); font-weight:800; font-size:30px; color:var(--c);
  text-shadow:0 0 22px color-mix(in srgb,var(--c) 35%,transparent); margin-bottom:10px;}
/* --pct written by updateBuyinAmt() in poker.js, same technique as .vol */
.buyin-slider{-webkit-appearance:none; appearance:none; display:block; width:100%; height:7px;
  border-radius:999px; cursor:pointer; outline:none; border:1px solid var(--border);
  background:linear-gradient(to right, var(--c) 0 var(--pct,50%), var(--surface-2) var(--pct,50%) 100%);}
.buyin-slider::-webkit-slider-thumb{-webkit-appearance:none; width:20px; height:20px; border-radius:50%;
  background:#fff; cursor:pointer; margin-top:-1px;
  box-shadow:0 2px 6px rgba(0,0,0,.5), 0 0 0 4px color-mix(in srgb,var(--c) 55%,transparent);}
.buyin-slider::-moz-range-thumb{width:20px; height:20px; border:0; border-radius:50%; background:#fff; cursor:pointer;
  box-shadow:0 2px 6px rgba(0,0,0,.5), 0 0 0 4px color-mix(in srgb,var(--c) 55%,transparent);}
.buyin-slider:disabled{opacity:.4; cursor:not-allowed;}
.buyin-range-labels{display:flex; justify-content:space-between; font-family:var(--mono); font-size:10px;
  color:var(--text-faint); margin:6px 1px 16px;}
.buyin-go{display:block; width:100%; appearance:none; cursor:pointer; font:inherit; font-weight:800; font-size:14px;
  padding:12px; border-radius:12px; border:none; background:linear-gradient(180deg,#ffe27a,var(--c)); color:#06130b;}
.buyin-go:hover:not(:disabled){filter:brightness(1.06);}
.buyin-go:disabled{opacity:.4; cursor:not-allowed; background:var(--surface); color:var(--text-faint);}
/* quiet secondary action under the modal's primary button — same ghost
   treatment as .confirm-leave (outline only, no fill) so it never competes
   with Sit Down / Add Chips for attention. */
.modal-back{display:block; width:100%; margin-top:8px; appearance:none; cursor:pointer; font:inherit;
  font-weight:700; font-size:12.5px; padding:10px; border-radius:12px; background:transparent;
  color:var(--text-faint); border:1px solid var(--border); transition:.15s;}
.modal-back:hover{color:var(--text-dim); border-color:var(--text-faint);}
.modal .avail{text-align:center; font-family:var(--mono); font-size:12px; color:var(--text-faint); margin-top:14px;}

/* ---- buy-in FIELD: a typed amount instead of the slider above, for "sit" and
   "deposit" (2026-08-15, same recipe as the lobby's deposit/withdraw screen and
   Slot xEGLD's buy-in — see renderWalletModal()). The slider stays in the
   markup and in CSS above: openRebuyModal()/setupBuyinModal() (test-only, see
   CLAUDE.md — never wired to a real button) still use it. ---- */
.buyin-field{margin-bottom:10px;}
.buyin-field[hidden]{display:none;}
.buyin-input-row{display:flex; align-items:center; gap:8px; background:var(--surface);
  border:1px solid var(--border); border-radius:11px; padding:9px 11px; transition:.13s var(--ease);}
.buyin-input-row:focus-within{border-color:var(--c);}
.buyin-input{flex:1; min-width:0; appearance:none; background:none; border:none; outline:none;
  color:var(--c); font-family:var(--mono); font-size:18px; font-weight:700; letter-spacing:.02em; padding:0;}
/* ⚠️ CENUȘIU (`--text-faint`), NU AURIU ESTOMPAT — aceeași regulă ca la lobby:
   placeholder-ul trebuie să fie clar altă culoare decât textul chiar tastat, nu
   doar o nuanță mai palidă a aceluiași auriu, altfel poate trece drept „o sumă
   deja scrisă acolo". */
.buyin-input::placeholder{color:var(--text-faint);}
.buyin-unit{font-family:var(--mono); font-size:11px; color:var(--text-faint); flex-shrink:0;}
.buyin-max{appearance:none; cursor:pointer; font:inherit; font-family:var(--mono); font-size:10px;
  font-weight:700; letter-spacing:.09em; padding:5px 9px; border-radius:7px; flex-shrink:0;
  color:var(--c); background:color-mix(in srgb,var(--c) 12%,transparent);
  border:1px solid color-mix(in srgb,var(--c) 45%,transparent); transition:.12s;}
.buyin-max:hover{background:color-mix(in srgb,var(--c) 22%,transparent);}
.buyin-max[hidden]{display:none;}
.buyin-hint{font-size:12px; color:var(--text-dim); line-height:1.45; margin:8px 1px 16px; text-align:center;}
.buyin-hint[hidden]{display:none;}
.buyin-err{font-size:12px; color:var(--coral); line-height:1.45; margin:8px 1px 16px; text-align:center;}
.buyin-err[hidden]{display:none;}

/* ---- leave-mid-hand confirm (replaces the native confirm() popup) ----
   "stay" is the safe/recommended choice, so it gets the same prominent gold
   treatment as .buyin-go; "leave" is the one that forfeits money, so it's
   deliberately quieter and coral-outlined (same warning color as .msg.bad),
   not a second gold button competing for attention. ---- */
.modal.leave-confirm p{margin-bottom:18px;}
.confirm-row{display:flex; flex-direction:column; gap:8px;}
.confirm-row button{appearance:none; cursor:pointer; font:inherit; font-weight:800; font-size:13px;
  padding:12px; border-radius:12px; transition:.15s;}
.confirm-stay{border:none; background:linear-gradient(180deg,#ffe27a,var(--c)); color:#06130b;}
.confirm-stay:hover{filter:brightness(1.06);}
.confirm-leave{background:var(--surface); color:var(--coral); border:1.5px solid color-mix(in srgb,var(--coral) 55%,transparent);}
.confirm-leave:hover{background:color-mix(in srgb,var(--coral) 16%,var(--surface)); border-color:var(--coral);}

@media (max-width:640px){
  h1{font-size:36px;}
}

/* ---- cine e la scaunul ăsta (2026-09-02) --------------------------------
   ⚠️ Se deschide la CLICK/TAP, nu la hover: hover nu există pe telefon.
   ⚠️ `z-index` peste scaune, dar sub modalele de conectare — e o lămurire, nu o
   întrerupere. */
.seat-card{position:absolute; transform:translate(-50%,-118%); z-index:9;
  min-width:12cqw; max-width:32cqw; padding:.55em .7em; text-align:left;
  font-family:var(--mono); font-size:clamp(9px,1.05cqw,13px); line-height:1.45;
  color:var(--text); background:rgba(5,7,13,.96); border:1px solid var(--border);
  border-radius:.5em; backdrop-filter:blur(6px); box-shadow:0 6px 24px rgba(0,0,0,.5);}
.seat-card.mine{border-color:color-mix(in srgb,var(--yellow) 45%,transparent);}
.seat-card .sc-name{font-weight:800; margin-bottom:.25em;}
/* ⚠️ `break-all`: o adresă bech32 n-are spații, deci fără asta iese din fereastră. */
.seat-card .sc-addr{opacity:.8; word-break:break-all;}
.seat-card .sc-none{opacity:.6; font-style:italic;}
.seat-card .sc-note{margin-top:.4em; opacity:.55; font-size:.86em;}
.seat-card .sc-copy{margin-top:.5em; width:100%; cursor:pointer;
  font-family:inherit; font-size:inherit; padding:.35em .5em; border-radius:.4em;
  color:var(--text); background:rgba(255,255,255,.06);
  border:1px solid color-mix(in srgb,var(--yellow) 40%,transparent);}
.seat-card .sc-copy:hover{background:rgba(255,255,255,.12);}

/* ============================================================================
   VOCEA DE LA MASĂ — rândul din pastila de sunet, starea scaunelor, mutul
   ⚠️ Nu mai există o a doua pastilă: totul stă în meniul difuzorului.
   ============================================================================ */
.mic-btn{position:relative; overflow:hidden;
  width:calc(var(--cw)*0.62); height:calc(var(--cw)*0.62); min-width:26px; min-height:26px; flex:none;
  border-radius:999px; border:0; background:transparent;
  color:var(--text-faint); font-size:calc(var(--cw)*0.28); line-height:1; cursor:pointer;
  display:flex; align-items:center; justify-content:center; transition:.2s var(--ease);}
.mic-btn:hover{color:var(--text);}
/* ⚠️ TREI stări, nu două. „Microfon pornit" și „chiar se aude acum" sunt lucruri
   diferite: cu microfonul deschis, tăcerea e normală, iar fără starea a treia
   nimeni n-ar ști dacă masa îl aude. Verde = pleacă sunet ACUM. */
.voice-row.on .mic-btn{color:var(--text);}
.voice-row.live .mic-btn{color:#3DDC84;
  text-shadow:0 0 calc(var(--cw)*0.16) rgba(61,220,132,.85);}
.voice-row.denied .mic-btn, .voice-row.nomic .mic-btn{color:#FF6B6B;}
/* ⚠️⚠️ MICROFONUL ÎNCHIS SE VEDE TĂIAT — aceeași limbă vizuală ca la scaune
   (cerut de Vlad, 2026-09-03: „momentan nu îți transmite nimic").
   ⚠️ Cele trei stări de deasupra sunt scrise cu `color`, iar `color` NU tinge o
   glifă emoji color ([§10.115](DECISIONS.md)) — deci butonul arăta IDENTIC
   pornit și oprit, iar „trei stări, nu două" era adevărat despre CSS și fals
   despre ecran.
   ⚠️⚠️ ROȘIE MEREU, nu `currentColor` (corectat de Vlad, 2026-09-03: „acea linie
   gri nu se vede bine"). Prima versiune o lăsa să moștenească starea — cenușie
   când e doar închis, roșie la eroare — o nuanță frumoasă care costa exact
   lucrul pentru care există linia: să se VADĂ. Roșu e și convenția pe care o are
   deja oricine a folosit Zoom, Meet sau Teams. Culoarea nu mai poartă nicio
   informație aici; starea o poartă prezența liniei.
   ⚠️ Stă ÎN buton (78% lățime): `.mic-btn` are `overflow:hidden` pentru bara de
   nivel, deci orice depășire ar fi retezată exact la capete, unde se vede. */
.voice-row:not(.on) .mic-btn::after{content:""; position:absolute;
  left:11%; top:50%; width:78%; height:max(1.5px, .1em);
  background:#FF6B6B; border-radius:2px;
  transform:translateY(-50%) rotate(-45deg);
  /* Contur întunecat, ca linia să se citească peste pixelii glifei. */
  box-shadow:0 0 0 1px rgba(6,7,13,.92);}

/* ⚠️⚠️ PUNCT VERDE ÎN COLȚ CÂND MICROFONUL E DESCHIS (ales de Vlad dintre trei
   variante, 2026-09-03). Răspunde la întrebarea care contează — „sunt deschis?",
   adică *mă poate auzi masa* — nu la „se aude acum": cu microfonul deschis,
   tăcerea e normală, deci un indicator care dispare când taci ar înceta să spună
   exact ce trebuie.
   ⚠️ ACELAȘI înțeles ca punctul de pe difuzor (`.sound-ctl.mic-live`), care se
   vede cu meniul închis. Două puncte, un singur mesaj — dacă vreodată le dai
   înțelesuri diferite, ai două limbaje în aceeași pastilă.
   ⚠️ `::before`, fiindcă `::after` e deja linia roșie de „închis" — și cele două
   nu apar niciodată împreună.
   ⚠️ Stă la 14% de colț, nu în vârf: butonul e rotund ȘI are `overflow:hidden`,
   deci un punct pus în colțul dreptunghiului ar fi retezat de rotunjire. */
.voice-row.on .mic-btn::before{content:""; position:absolute; right:14%; top:14%;
  width:.30em; height:.30em; border-radius:999px; background:#3DDC84;
  box-shadow:0 0 0 1.5px rgba(6,7,13,.92), 0 0 5px rgba(61,220,132,.85);}

/* ⚠️ Cu panoul ÎNCHIS microfonul nu se vede, deci starea lui trebuie spusă pe
   butonul care rămâne: un punct verde pe difuzor. Fără el, „am microfonul
   deschis?" ar cere deschiderea meniului ca să afli — adică exact întrebarea pe
   care o comandă de sunet n-are voie s-o lase fără răspuns. */
.sound-ctl.mic-live .mute-btn::after{content:""; position:absolute;
  right:calc(var(--cw)*0.04); top:calc(var(--cw)*0.04);
  width:calc(var(--cw)*0.15); height:calc(var(--cw)*0.15); min-width:6px; min-height:6px;
  border-radius:999px; background:#3DDC84;
  box-shadow:0 0 calc(var(--cw)*0.12) rgba(61,220,132,.9);}
.mute-btn{position:relative;}

.vvol{-webkit-appearance:none; appearance:none; flex:none; height:calc(var(--cw)*0.12);
  /* ⚠️ 1.00cw, nu mai mult: rândul 2 trebuie să rămână SUB lățimea rândului 1.
     Socoteala, în `cw`: rândul 1 deschis = 0.62 (buton) + 0.15 (margine) + 1.70
     (slider) = 2.47. Rândul 2 = 0.62 + 0.13 + 1.00 + 0.13 + 0.56 = 2.44.
     ⚠️ Dacă rândul 2 l-ar depăși, ar lăți TOATĂ pastila — iar la §6.7 s-a măsurat
     că marginea dreaptă a pastilei deschise are doar ~9px până la marginea mesei. */
  width:calc(var(--cw)*1.00); margin-left:calc(var(--cw)*0.13);
  border-radius:999px; cursor:pointer; outline:none;
  background:linear-gradient(to right,
    var(--c) 0 var(--vpct,90%), rgba(255,255,255,.20) var(--vpct,90%) 100%);}
.vvol::-webkit-slider-thumb{-webkit-appearance:none; width:calc(var(--cw)*0.28); height:calc(var(--cw)*0.28);
  min-width:12px; min-height:12px; border:0; border-radius:50%; background:#fff; cursor:pointer;}
.vvol::-moz-range-thumb{width:calc(var(--cw)*0.28); height:calc(var(--cw)*0.28); min-width:12px; min-height:12px;
  border:0; border-radius:50%; background:#fff; cursor:pointer;}

.ptt-btn{flex:none; margin-left:calc(var(--cw)*0.13); padding:0;
  width:calc(var(--cw)*0.56); height:calc(var(--cw)*0.34);
  border:0; border-radius:999px; background:rgba(255,255,255,.10); color:var(--text-faint);
  font-family:'Roboto',sans-serif; font-size:calc(var(--cw)*0.13); letter-spacing:.04em;
  cursor:pointer; transition:.2s var(--ease);}
.ptt-btn:hover{color:var(--text);}
.ptt-btn[aria-pressed="true"]{background:color-mix(in srgb,var(--c) 40%,transparent); color:#fff;}

/* ---- rândul 3: ticul ceasului de tur, pe mut separat ---------------------
   ⚠️ Socoteala lățimii, în `cw` — aceeași regulă ca la `.vvol`, și e obligatorie:
   rândul 1 deschis = 0.62 + 0.15 + 1.70 = 2.47. Rândul 2 = 2.44.
   Rândul 3 = 0.62 (buton) + 0.13 + 1.00 (etichetă) + 0.13 + 0.56 (comutator) = 2.44
   — identic cu rândul 2, deci comutatorul se aliniază cu PTT.
   ⚠️ Eticheta are lățime FIXĂ și `overflow:hidden`: un text mai lung ar lăți toată
   pastila, iar la §6.7 s-a măsurat că marginea ei dreaptă are ~9px până la marginea
   mesei. Textul cedează, geometria nu. */
.tick-btn{width:calc(var(--cw)*0.62); height:calc(var(--cw)*0.62); min-width:26px; min-height:26px; flex:none;
  border-radius:999px; border:0; background:transparent; color:var(--text-dim);
  font-size:calc(var(--cw)*0.26); line-height:1; cursor:pointer;
  display:flex; align-items:center; justify-content:center; transition:.2s var(--ease);}
.tick-btn:hover{color:var(--c);}
.tick-row.off .tick-btn{color:var(--text-faint);}
.tick-lab{flex:none; width:calc(var(--cw)*1.00); margin-left:calc(var(--cw)*0.13);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  font-family:'Roboto',sans-serif; font-size:calc(var(--cw)*0.13); letter-spacing:.06em;
  color:var(--text-faint); user-select:none;}
.tick-toggle{flex:none; margin-left:calc(var(--cw)*0.13); padding:0;
  width:calc(var(--cw)*0.56); height:calc(var(--cw)*0.34);
  border:0; border-radius:999px; background:rgba(255,255,255,.10); color:var(--text-faint);
  font-family:'Roboto',sans-serif; font-size:calc(var(--cw)*0.13); letter-spacing:.04em;
  cursor:pointer; transition:.2s var(--ease);}
.tick-toggle:hover{color:var(--text);}
.tick-toggle[aria-pressed="true"]{background:color-mix(in srgb,var(--c) 40%,transparent); color:#fff;}
/* ⚠️ Cât masa e pe mut, rândul e stins — dar NU ascuns și NU inert, ca rândul de
   voce: apăsarea comută mai departe alegerea ta pentru ticuri, ca s-o poți lăsa
   pusă înainte să dai sonorul înapoi. Mutul mesei taie tot; ăsta taie doar ticul. */
.sound-ctl .tick-row.silenced{opacity:.45;}

/* ⚠️ Panoul DESCHIS coboară până pe la 21% din înălțimea mesei, adică peste zona
   scaunului 8 (y 19.8%). E acceptat, și de-aia: apare doar cât ține meniul
   deschis (îl deschide omul, se închide singur în 3s), iar `z-index:6` îl pune
   PESTE scaune (`z-index:5`), deci nu dispare sub ele. Varianta veche, cu a doua
   pastilă, stătea acolo PERMANENT. */

/* ⚠️ Mutul mesei e ABSOLUT: cât e pornit, microfonul nu se poate deschide, iar
   rândul o arată — stins, dar NU ascuns și NU inert. Apăsarea spune de ce (vezi
   handlerul lui `mic-btn`); un control dezactivat care tace e exact ce evită
   restul paginii. */
.voice-row.silenced{opacity:.45;}
.voice-row.silenced .mic-btn{color:var(--text-faint); text-shadow:none;}

/* ---- starea scaunelor -------------------------------------------------- */
/* ⚠️ Inelul de „vorbește acum" stă pe eticheta de nume, NU pe `.seat`: scaunul
   poartă deja starea de rând (`.acting`), iar două inele pe același element ar
   face imposibil de citit al cui e rândul. */
/* ⚠️ TREI pictograme, o singură vizibilă. Care anume spune ce face omul ACUM:
   🎙 stins = e în discuție și tace · 🔊 verde = vorbește · 🎙 tăiat roșu = l-ai
   pus TU pe mut. Cerut de Vlad, 2026-09-03.
   ⚠️ MĂRIME 1.23em, nu .82em (+50%, cerut explicit: „e infim"). Pictograma nu mai
   e un indicator pasiv de când se apasă — o ȚINTĂ de 13px lângă un nume nu se
   nimerește, mai ales pe tactil. */
.seat .name-tag .vmic, .seat .name-tag .vspk, .seat .name-tag .vmute{display:none;
  margin-left:.35em; font-size:1.23em; line-height:0; vertical-align:-.2em;}
/* ⚠️ Pictograma e DESENATĂ (vezi `VICO_*` din poker.js): arcele difuzorului
   trebuie să fie verzi, iar pe un emoji arcele nu se pot colora — §10.115.
   ⚠️ `1em` aici înseamnă 1.23em din eticheta de nume, prin `font-size` de sus. */
.seat .name-tag svg.vico{width:1em; height:1em; display:block;}
.seat .name-tag .v-body{fill:currentColor;}
.seat .name-tag .v-line{stroke:currentColor; stroke-width:2; fill:none; stroke-linecap:round;}
/* ⚠️⚠️ ARCELE SUNT VERZI EXPLICIT, nu `currentColor`: ele SUNT semnalul „vorbește
   acum", iar corpul difuzorului rămâne neutru ca ele să iasă în față. */
.seat .name-tag .v-wave{stroke:#3DDC84; stroke-width:2; fill:none; stroke-linecap:round;}
.seat .name-tag .v-slash{stroke:#FF6B6B; stroke-width:2.2; stroke-linecap:round; fill:none;}

/* ---- în voce, dar tace: microfon stins ---------------------------------- */
/* ⚠️ Vizibilă și când tace, altfel ținta pe care o apeși ca să-l muți apare doar
   cât vorbește și fuge de sub deget. Stinsă, ca să nu concureze cu „vorbește";
   se aprinde la hover, fiindcă ATUNCI e un buton. */
/* ⚠️⚠️ ALBASTRU, nu gri (ales de Vlad dintre alb / albastru / verde, 2026-09-03,
   comparate în browser). Gri stins la 50% se pierdea pe pâsla verde, iar de când
   pictograma se APASĂ nu mai e un indicator pasiv — o țintă trebuie să se vadă.
   ⚠️⚠️ ȘI DE CE NU VERDE, deși a fost pe masă: verdele înseamnă deja „vorbește
   acum". Un microfon verde care TACE lângă un difuzor verde care VORBEȘTE lasă
   doar forma să facă diferența, iar la 16px forma se citește mai greu decât
   culoarea — adică exact semnalul cerut acum două runde s-ar fi tocit.
   ⚠️ Albastrul nu se ciocnește de nimic: masa e verde/auriu/coral, iar verdele și
   roșul sunt luate de „vorbește" și „pe mut". */
.seat.voice-on .name-tag .vmic{display:inline-block; color:#4EA8FF; opacity:1;
  cursor:pointer; transition:.18s var(--ease);}
.seat.voice-on .name-tag .vmic:hover{filter:brightness(1.3);}

/* ---- vorbește acum: MICROFONUL DEVINE DIFUZOR CARE EMITE ---------------- */
/* ⚠️⚠️ Schimbarea de OBIECT e semnalul, nu culoarea (cerut de Vlad, 2026-09-03).
   Motivul e §10.115: `color` NU tinge o glifă emoji color, deci „microfon verde"
   nu există pe ecran — dar „microfon → difuzor" se vede din prima privire, la
   orice culoare, pe orice platformă. Haloul e în plus, nu în locul ei. */
.seat.voice-on.talking .name-tag .vmic{display:none;}
/* ⚠️⚠️ CORPUL E ALBASTRU CA MICROFONUL, ARCELE VERZI (cerut de Vlad, 2026-09-03).
   Cele două culori spun două lucruri diferite, și de-aia nu se contopesc:
   ALBASTRU = „e în discuție" (același obiect, tace sau vorbește), VERDE = „iese
   sunet ACUM". Corpul vopsit verde ar face pictograma să strige un singur lucru
   și ar tăia legătura cu microfonul din care s-a transformat. */
.seat.voice-on.talking .name-tag .vspk{display:inline-block; color:#4EA8FF; opacity:1;
  cursor:pointer;
  filter:drop-shadow(0 0 calc(var(--cw)*0.03) rgba(61,220,132,.9));}
.seat.talking .name-tag{box-shadow:0 0 0 1px rgba(61,220,132,.55),
  0 0 calc(var(--cw)*0.22) rgba(61,220,132,.45);}

/* ---- pus pe mut: RĂMÂNE MICROFON TĂIAT, orice ar face el ---------------- */
/* ⚠️⚠️ Mutul BATE „vorbește": cine e pe mut nu se transformă niciodată în difuzor
   (cerut de Vlad, 2026-09-03). Un difuzor care „emite" lângă cineva pe care
   tocmai l-ai tăiat ar spune exact contrariul adevărului — tu NU-l auzi.
   ⚠️ De-aia dispare și inelul verde de pe etichetă.
   ⚠️ Microfon TĂIAT, nu difuzor barat: ce apeși e un microfon, iar difuzorul e
   deja pastila ta de volum. Linia e DESENATĂ — nu există emoji „microfon barat"
   care să se randeze la fel peste tot, iar combinatorul U+0338 cade diferit pe
   fiecare platformă. */
.seat.vmuted .name-tag .vmic, .seat.vmuted .name-tag .vspk{display:none !important;}
.seat.vmuted .name-tag .vmute{display:inline-block; color:#FF6B6B; opacity:1;
  cursor:pointer;}
.seat.vmuted .name-tag .vmute:hover{opacity:.75;}
.seat.vmuted.talking .name-tag{box-shadow:none;}

/* ---- indiciul de o singură dată: unde e microfonul ---------------------- */
/* ⚠️⚠️ `position:absolute` E OBLIGATORIU, nu o alegere de stil: în fluxul
   pastilei ar lăți-o peste rândul 1 (2.47cw), iar pastila are ~9px până la
   marginea mesei ([DECISIONS §6.7], regula #1sexdecies). Din același motiv
   crește spre STÂNGA — `right:100%`, niciodată `left`. */
/* ⚠️⚠️ ANCORATĂ PE CENTRUL PASTILEI, nu pe vârful ei — și nu e o alegere de gust:
   bula spune „microfonul e aici", iar aliniată sus săgeata arăta spre DIFUZOR
   (rândul 1). Centrul pastilei cu trei rânduri CADE pe rândul 2, adică fix pe
   microfon. ⚠️ Nu se poate calcula în `cw`: `.mute-btn`/`.mic-btn` au
   `min-height:26px`, deci pe mese mici pixelii bat multiplicatorul și un offset
   scris în `cw` ar rata rândul exact acolo unde e mai înghesuit.
   ⚠️ Găsit deschizând pagina, nu de teste — [DECISIONS §1.8]. */
.mic-hint{position:absolute; right:calc(100% + 10px); top:50%;
  transform:translateY(-50%); z-index:2;
  width:max-content; max-width:calc(var(--cw)*4.2);
  display:flex; flex-direction:column; gap:.25em;
  padding:calc(var(--cw)*0.14) calc(var(--cw)*0.2);
  border-radius:10px; border:1px solid color-mix(in srgb,#3DDC84 45%,transparent);
  background:rgba(6,7,13,.94); backdrop-filter:blur(4px);
  box-shadow:0 6px 18px rgba(0,0,0,.55);
  font-family:'Roboto',sans-serif; text-align:left; pointer-events:none;
  animation:micHintIn .28s var(--ease) both;}
.mic-hint[hidden]{display:none;}
.mic-hint b{color:#3DDC84; font-size:calc(var(--cw)*0.17); letter-spacing:.04em;
  text-transform:uppercase;}
.mic-hint span{color:var(--text-dim); font-size:calc(var(--cw)*0.155); line-height:1.35;}
/* Vârful spre pastilă — desenat, nu un caracter, ca să stea exact pe difuzor. */
.mic-hint::after{content:""; position:absolute; left:100%; top:calc(50% - 6px);
  border:6px solid transparent; border-left-color:color-mix(in srgb,#3DDC84 45%,transparent);}
/* ⚠️ `transform` e o singură proprietate: animată ca `translateX`, ar ȘTERGE
   `translateY(-50%)` de mai sus și bula ar sări cu jumătate din înălțime. */
@keyframes micHintIn{from{opacity:0; transform:translate(6px,-50%);}
                     to{opacity:1; transform:translateY(-50%);}}

/* ---- butonul de mut din cartela scaunului ------------------------------ */
.seat-card .sc-mute{margin-top:.5em; width:100%; cursor:pointer;
  border:1px solid var(--border); border-radius:8px; background:rgba(255,255,255,.06);
  color:var(--text); font-family:'Roboto',sans-serif; font-size:11px; letter-spacing:.05em;
  text-transform:uppercase; padding:6px 8px; transition:.18s var(--ease);}
.seat-card .sc-mute:hover{border-color:color-mix(in srgb,var(--c) 55%,transparent);}
.seat-card .sc-mute.on{background:rgba(255,107,107,.16); border-color:rgba(255,107,107,.55); color:#FFC9C9;}
.seat-card .sc-hint{margin-top:.4em; font-size:10px; line-height:1.35; color:var(--text-faint);}

/* ============================================================================
   MESE PRIVATE (2026-09-04) — lista de invitați din poartă.
   ⚠️ Nimic nou pe MASĂ: butonul „Invite" refolosește `.leave-btn`, iar câmpul de
   nume refolosește `.amt-row`/`.amt-input` (regula 1decies: estetica se COPIAZĂ
   din ce există, nu se inventează). Aici sunt doar lista și butonul ei de scos.
   ========================================================================== */
.priv-list { list-style: none; margin: 10px 0 0; padding: 0; max-height: 148px; overflow-y: auto; }
.priv-list li { display: flex; align-items: center; justify-content: space-between;
  gap: 8px; padding: 5px 8px; border-radius: 8px; font-size: 13px;
  background: rgba(255,255,255,.04); margin-bottom: 4px; }
.priv-list li.empty { justify-content: flex-start; opacity: .55; background: none; }
.gate-x { background: none; border: 0; color: #FF6B6B; cursor: pointer;
  font-size: 13px; line-height: 1; padding: 2px 4px; opacity: .7; }
.gate-x:hover { opacity: 1; }
.priv-err { color: #FF6B6B; font-size: 12px; margin-top: 6px; }
.priv-cap { margin-top: 12px; font-size: 11px; letter-spacing: .08em;
  text-transform: uppercase; opacity: .55; }
.gate-host { background: none; border: 1px solid color-mix(in srgb, var(--yellow) 45%, transparent);
  color: var(--yellow); cursor: pointer; font-size: 11px; line-height: 1;
  padding: 4px 8px; border-radius: 7px; opacity: .85; }
.gate-host:hover { opacity: 1; }

/* ============================================================================
   COMUTATORUL DE MASĂ (2026-09-04, cerut de Vlad: „un dongle elegant, gen Apple").
   ⚠️ Două poziții, un singur lucru de înțeles. Bila alunecă — mișcarea E confirmarea
   că apăsarea a contat, înainte ca serverul să răspundă.
   ⚠️ `prefers-reduced-motion`: bila sare, nu alunecă. Nu dispare — poziția ei e chiar
   informația.
   ========================================================================== */
.tbl-switch {
  position: relative; display: grid; grid-template-columns: 1fr 1fr;
  width: 100%; max-width: 260px; margin: 16px auto 0; padding: 3px;
  border-radius: 999px; background: rgba(0, 0, 0, .34);
  border: 1px solid rgba(255, 214, 102, .22);
}
.tsw-thumb {
  position: absolute; top: 3px; left: 3px; z-index: 0;
  width: calc(50% - 3px); height: calc(100% - 6px); border-radius: 999px;
  background: linear-gradient(180deg, #ffd666, #e0a92c);
  box-shadow: 0 1px 6px rgba(0, 0, 0, .35);
  transition: transform .3s cubic-bezier(.32, .72, 0, 1);
}
.tbl-switch.is-private .tsw-thumb { transform: translateX(100%); }
.tsw-opt {
  position: relative; z-index: 1; background: none; border: 0; padding: 8px 0;
  border-radius: 999px; font: inherit; font-size: 13.5px; font-weight: 600;
  color: #efe7d4; opacity: .62; cursor: pointer;
  transition: color .22s ease, opacity .22s ease;
}
.tsw-opt.is-on { color: #241a02; opacity: 1; }
.tsw-opt:hover:not(.is-on) { opacity: .85; }
/* ⚠️ Propoziția are înălțime REZERVATĂ: fără ea, comutarea între un text de un rând și
   unul de două ar face butonul de dedesubt să sară sub deget. */
.tbl-what { margin-top: 9px; font-size: 12.5px; opacity: .72; min-height: 2.6em; }
.tbl-ok-slot { margin-top: 10px; min-height: 40px; }   /* ⚠️ înălțime fixă: confirmarea vine și pleacă fără să miște poarta */
.tbl-ok {
  margin-top: 0; padding: 8px 11px; border-radius: 10px; font-size: 12.5px;
  border: 1px solid rgba(61, 220, 132, .42); background: rgba(61, 220, 132, .10);
  color: #bff5d8;
}
/* ⚠️⚠️ INVITAȚIA E ALBASTRĂ, și e singurul lucru albastru din poartă (cerut de Vlad,
   2026-09-04: „să sară în ochi"). Limbajul de culoare al porții: AURIU = acțiunea TA
   (te așezi), VERDE = s-a întâmplat ceva (confirmare), ROȘU = ceva n-a mers.
   Invitația nu e niciuna din trei — e ceva ce a făcut ALTCINEVA pentru tine, deci
   primește a patra culoare. ⚠️ Albastrul de la VOCE (#4EA8FF) e pe MASĂ, nu în poartă,
   deci cele două nu se pot vedea niciodată în același ecran.
   ⚠️ Pulsul rulează de DOUĂ ori și se oprește: atrage privirea o dată, apoi tace.
   O animație perpetuă într-un ecran în care trebuie să decizi ceva e zgomot. */
.tbl-invite {
  display: flex; align-items: center; gap: 10px; justify-content: space-between;
  margin-top: 11px; padding: 10px 12px; border-radius: 12px;
  font-size: 13px; line-height: 1.4; text-align: left; color: #dbe9ff;
  background: linear-gradient(180deg, rgba(91, 141, 239, .17), rgba(91, 141, 239, .07));
  border: 1px solid rgba(91, 141, 239, .55);
  animation: inviteNudge 1.6s ease-in-out 2;
}
.tbl-invite b { color: #9dc0ff; font-weight: 700; }
.tbl-invite .env { color: #7aa7ff; font-size: 15px; flex: 0 0 auto; }
.tbl-more { margin-top: 6px; font-size: 12px; opacity: .55; }
.tbl-join {
  flex: 0 0 auto; cursor: pointer; font: inherit; font-size: 12.5px; font-weight: 700;
  padding: 7px 15px; border-radius: 9px; color: #fff;
  background: linear-gradient(180deg, #6f9dff, #3f6fd8);
  border: 1px solid rgba(157, 192, 255, .65);
  box-shadow: 0 2px 10px rgba(63, 111, 216, .4);
  transition: filter .15s ease, transform .1s ease;
}
.tbl-join:hover { filter: brightness(1.1); }
.tbl-join:active { transform: translateY(1px); }
/* ⚠️ Pulsul se vede ÎN interiorul rândului (fundal + contur), nu doar ca strălucire în afară: Vlad nu-l vedea
   (2026-10-02, D3) — o umbră care iese din rând e ușor de tăiat de cardul porții și de privit pe lângă. */
@keyframes inviteNudge {
  0%, 100% { box-shadow: 0 0 0 rgba(91, 141, 239, 0);
             border-color: rgba(91, 141, 239, .55);
             background: linear-gradient(180deg, rgba(91, 141, 239, .17), rgba(91, 141, 239, .07)); }
  50%      { box-shadow: 0 0 22px rgba(91, 141, 239, .7);
             border-color: rgba(157, 192, 255, 1);
             background: linear-gradient(180deg, rgba(91, 141, 239, .52), rgba(91, 141, 239, .30)); }
}
/* ⚠️ Cine a cerut mai puțină mișcare primește rândul, nu pulsul — culoarea și
   conturul rămân, deci invitația se vede la fel de bine. */
@media (prefers-reduced-motion: reduce) { .tbl-invite { animation: none; } }
@media (prefers-reduced-motion: reduce) { .tsw-thumb { transition: none; } }
.priv-cap2 { margin-top: 9px; font-size: 12px; opacity: .58; }
/* ⚠️ Linia care desparte cele DOUĂ întrebări ale ecranului: „unde joc" (sus) de „cât
   aduc" (jos). Fără ea, comutatorul și câmpul de sumă par un singur formular. */
.gate-sep { height: 1px; margin: 16px -26px 15px; background: #24203a; }
/* ⚠️ Sus, comutatorul n-are nevoie de spațiul de dinainte — titlul i-l dă deja. */
.gate-body > .tbl-switch:first-child { margin-top: 4px; }
/* ⚠️ Butonul gazdei — ALBASTRU ca invitațiile primite (același subiect), și în zona de
   SUS, lângă comutator: e lucrul pentru care ai apăsat „Private". Jos, sub butonul
   auriu, era în zona „cât aduc" și nu-l găsea nimeni. */
/* ⚠️ Propoziția care spune ce urmează, în ecranul de așezare: aici NU se invită
   (regula e în `tableSwitchHtml`). Discretă — e o indicație, nu o acțiune. */
.tbl-next {
  display: block; margin-top: 8px; font-size: 12px; color: #7FB5E8;
  letter-spacing: .02em; min-height: 1.5em;   /* ⚠️ rând fix: Public și Private au aceeași înălțime */
}
.tbl-next.is-empty { visibility: hidden; }
.tbl-invite .exp { display: block; font-style: normal; font-size: 11px; opacity: .6; margin-top: 2px; }
.tbl-decline {
  flex: 0 0 auto; background: none; border: 0; color: #9dc0ff; opacity: .55;
  cursor: pointer; font: inherit; font-size: 14px; line-height: 1; padding: 4px 2px 4px 6px;
}
.tbl-decline:hover { opacity: 1; color: #ff9db0; }

/* ============================================================================
   INVITAREA, INLINE (2026-09-04) — cerut de Vlad: „nu este cazul de 100 de modale".
   ⚠️ Lista crește ÎN JOS, câmpul de adăugare stă mereu SUB ea. Nimic nu se deschide
   peste altceva.
   ========================================================================== */
.inv-box { margin-top: 11px; text-align: left; }
.inv-list { list-style: none; margin: 0 0 8px; padding: 0; max-height: 132px; overflow-y: auto; }
.inv-list li { display: flex; align-items: center; gap: 8px; padding: 6px 9px; border-radius: 9px;
  background: rgba(91, 141, 239, .10); border: 1px solid rgba(91, 141, 239, .30);
  margin-bottom: 5px; font-size: 13px; }
.inv-list li.sent { background: rgba(255, 255, 255, .04); border-color: #24203a; }
.inv-list .who { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.inv-list i { font-style: normal; font-size: 11px; opacity: .5; }
.priv-x { background: none; border: 0; color: #9dc0ff; opacity: .6; cursor: pointer;
  font: inherit; font-size: 13px; line-height: 1; padding: 2px 4px; }
.priv-x:hover { opacity: 1; color: #ff9db0; }
.inv-add { display: flex; gap: 7px; align-items: stretch; }
.inv-input { flex: 1; min-width: 0; padding: 9px 11px; border-radius: 10px;
  border: 1px solid rgba(91, 141, 239, .40); background: rgba(0, 0, 0, .30);
  color: #efe7d4; font: inherit; font-size: 13px; }
.inv-input::placeholder { color: rgba(239, 231, 212, .38); }
.inv-input:focus { outline: none; border-color: rgba(157, 192, 255, .75); }
/* ⚠️ „+" e PĂTRAT și de aceeași înălțime cu câmpul: un buton mai scund ar face rândul
   să pară nealiniat la fiecare randare a listei. */
.inv-plus { flex: 0 0 auto; width: 40px; border-radius: 10px; cursor: pointer;
  color: #fff; font: inherit; font-size: 19px; font-weight: 700; line-height: 1;
  background: linear-gradient(180deg, #6f9dff, #3f6fd8);
  border: 1px solid rgba(157, 192, 255, .65); }
.inv-plus:hover { filter: brightness(1.1); }
.inv-err { color: #FF6B6B; font-size: 12px; margin-top: 7px; }
.inv-cap { margin-top: 8px; font-size: 11.5px; opacity: .55; }
.inv-cap .n, .inv-cap b { color: #9dc0ff; font-weight: 600; }
.inv-cap2 { margin-top: 12px; margin-bottom: 6px; font-size: 11px; letter-spacing: .08em;
  text-transform: uppercase; opacity: .5; }
/* ⚠️ Încuiat ≠ ascuns: comutatorul rămâne indicatorul care spune unde ești, dar se
   vede că nu se poate mișca acum. */
.tbl-switch.is-locked { opacity: .55; }
.tbl-switch.is-locked .tsw-opt { cursor: not-allowed; }

/* ⚠️ NOTA DE ASTEPTARE a reconectarii (2026-10-02, cerut de Vlad: „nimeni nu vede" — era gri deschis, 12,5px, 62% opacitate).
   Rosie, ingrosata, in chenar, ca sa nu poata fi ratata. Doar ea: `.hint` ramane gri la restul ecranelor porții. */
.gate-body .hint.wait {
  opacity: 1; font-size: 14.5px; font-weight: 700; line-height: 1.45; color: #FF6B6B;
  margin-top: 12px; padding: 10px 14px; border-radius: 10px;
  border: 1px solid rgba(255, 107, 107, .55); background: rgba(255, 107, 107, .10);
}

/* ⚠️ Fereastra fantomă de la comutator (vezi `saveGateGhost`): doar de privit, nimic nu se apasă până vine poarta adevărată. */
/* ⚠️ Clasa se numește `gate-ghost`, NU `ghost`: `.ghost` există deja mai sus (cartea-marcaj goală de pe masă, cu chenar punctat gri) și l-ar fi moștenit pe toată pagina. */
.gate.gate-ghost, .gate.gate-ghost * { pointer-events: none; }
/* ⚠️ FUNDAL OPAC cât fantoma e pe ecran: acoperă TOATĂ pagina, colțurile incluse (nimic din spate nu mai clipește prin transparență). Aceleași culori ca poarta
   adevărată, fără transparență și fără blur — pagina din spate e oricum ascunsă (`body.booting`). */
.gate.gate-ghost { background: radial-gradient(ellipse at center, rgb(18, 10, 40), rgb(4, 2, 12)); backdrop-filter: none; }
