/* Front de juego v2.1 (SPEC-FRONT-V2.md + lote cosmetico). MOBILE-FIRST.
   REGLA MAESTRA: la pantalla de mesa entra COMPLETA en 100dvh sin scroll de
   pagina; los unicos scrolls son internos al chat/log (y a login/lobby).
   La mesa es un SVG PROPIO (rail + paño degradado); los asientos se montan
   sobre el rail. La barra de accion mantiene sus 4 slots inmutables. */

/* el selector #app[v-cloak] es OBLIGATORIO: la regla #app{display:flex}
   de abajo (especificidad 1,0,0) le ganaba al [v-cloak] pelado (0,1,0) y
   el template CRUDO se pintaba un instante antes del mount (medido
   2026-08-15: hasta ~500 ms en red lenta) */
[v-cloak], #app[v-cloak] { display: none; }
* { box-sizing: border-box; }
:root {
  --panel: #131a24;
  --borde: #2a3547;
  --oro: #d8c56f;
  --verde: #6fc26f;
  --azul: #9db7d8;
  --alto-barra: 56px;   /* mobile; desktop lo sube la media query */
  --alto-tabs: 32px;
  /* Paleta DE LA MESA (v2.3, colores nuestros): rail plomo/grafito con
     franja especular arriba y paño azul marino. Son variables POR MESA:
     el SVG las consume via stop-color, y a futuro cada mesa podra traer
     las suyas desde tables_config (se setean en el style del .mesa-wrap);
     estos valores son el default. */
  /* v2.11: la paleta aprobada en mobile (v2.8) pasa a GLOBAL: rail
     oscuro casi negro tipo goma pulida y paño azul saturado. */
  --rim-1: #4a4a4a;  /* especular sutil superior */
  --rim-2: #2a2a2a;
  --rim-3: #1f1f1f;
  --rim-4: #0d0d0d;
  --felt-1: #3a86e0; /* centro del paño: azul vivo */
  --felt-2: #0d3a75; /* borde del paño: azul profundo */
  /* Tonos casino del tema de paño (lote 2026-08-15): centro vivo + borde
     profundo, mismas luminancias que el azul default para que cartas,
     dorsos (1B.svg blanco/negro) y placas (fondo propio oscuro) contrasten
     igual en los tres. */
  --felt-verde-1: #2f9e57;
  --felt-verde-2: #0c4a26;
  --felt-rojo-1: #b13a3a;
  --felt-rojo-2: #4d1015;
  --celeste: #2fd0f2;
  --stack-verde: #4fd68a;
  /* v2.7 (bug 3): el reloj de accion tiene color PROPIO, inconfundible con
     el saldo (oro) y el stack (verde): ambar, y rojo al agotarse */
  --timer: #ffb020;
  --timer-critico: #ff4d4d;
}
/* Tema del paño por agent (branding.tableTheme, lista CERRADA): la clase
   la pone cargarBranding() POR JS sobre <html> (documentElement) y SOLO
   pisa las vars del paño que consume el SVG de la mesa. 'azul' no lleva
   clase (es el default). Nada de --brand-*: los colores de marca no
   tocan el paño. Van DESPUES de :root a proposito: misma especificidad,
   gana el orden. */
.tema-pano-verde { --felt-1: var(--felt-verde-1); --felt-2: var(--felt-verde-2); }
.tema-pano-rojo { --felt-1: var(--felt-rojo-1); --felt-2: var(--felt-rojo-2); }
html, body { height: 100%; }
body { font-family: system-ui, sans-serif; margin: 0; background: #0b0f14; color: #e8e8e8; overflow: hidden; }
#app { display: flex; flex-direction: column; height: 100dvh; }
header { display: flex; align-items: center; gap: .7rem; padding: .3rem .8rem; background: var(--panel); flex-wrap: nowrap; min-height: 34px; }
h1 { font-size: .95rem; margin: 0; color: var(--verde); }
h2 { font-size: 1rem; }
.saldos { font-size: .8rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.saldos b { margin-right: .6rem; font-variant-numeric: tabular-nums; color: var(--oro); }
.idiomas { margin-left: auto; font-size: .8rem; white-space: nowrap; display: flex; align-items: center; gap: .4rem; }
.idiomas a { cursor: pointer; color: var(--azul); }
/* Selector de idioma con bandera: mismo componente que el backoffice
   (admin/style.css), adaptado a la paleta del juego. SVG en data-URI:
   emoji de banderas no renderiza en muchos Linux/tablets. */
.idioma-selector { position: relative; }
.idioma-boton {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  background: transparent;
  border: 1px solid var(--borde);
  border-radius: 6px;
  color: #e8e8e8;
  font-size: .8rem;
  padding: .15rem .45rem;
  cursor: pointer;
}
.idioma-lista {
  position: absolute;
  right: 0;
  top: calc(100% + .3rem);
  z-index: 300; /* por encima de mesa y cromo flotante del header */
  display: flex;
  flex-direction: column;
  min-width: 10rem;
  background: var(--panel);
  border: 1px solid var(--borde);
  border-radius: 8px;
  padding: .3rem;
  box-shadow: 0 8px 24px rgba(0, 0, 0, .45);
}
.idioma-lista a {
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: .55rem;
  padding: .5rem .6rem;
  min-height: 44px;
  border-radius: 6px;
  color: #e8e8e8;
  font-size: .9rem;
}
.idioma-lista a:hover { background: rgba(255, 255, 255, .07); }
.idioma-lista a.on { color: var(--verde); font-weight: 600; }
.bandera {
  width: 20px;
  height: 14px;
  border-radius: 2px;
  background-size: cover;
  background-position: center;
  flex: none;
  outline: 1px solid rgba(255, 255, 255, .15);
}
.bandera-es { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 40'%3E%3Crect width='60' height='40' fill='%23c60b1e'/%3E%3Crect y='10' width='60' height='20' fill='%23ffc400'/%3E%3C/svg%3E"); }
.bandera-en { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 40'%3E%3Crect width='60' height='40' fill='%23012169'/%3E%3Cpath d='M0 0 60 40M60 0 0 40' stroke='%23fff' stroke-width='8'/%3E%3Cpath d='M0 0 60 40M60 0 0 40' stroke='%23C8102E' stroke-width='4'/%3E%3Crect x='25' width='10' height='40' fill='%23fff'/%3E%3Crect y='15' width='60' height='10' fill='%23fff'/%3E%3Crect x='27' width='6' height='40' fill='%23C8102E'/%3E%3Crect y='17' width='60' height='6' fill='%23C8102E'/%3E%3C/svg%3E"); }
.bandera-pt { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 40'%3E%3Crect width='60' height='40' fill='%23009739'/%3E%3Cpath d='M30 5 55 20 30 35 5 20Z' fill='%23FEDD00'/%3E%3Ccircle cx='30' cy='20' r='8.5' fill='%23012169'/%3E%3C/svg%3E"); }
/* Menu de USUARIO del header (avatar_elegido 2026-08-11): mismo patron
   que el selector de idioma (boton + lista absoluta). En el landscape
   compacto hereda el pointer-events:auto de .idiomas (header fixed). */
.usuario-menu { position: relative; }
.usuario-boton {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  background: transparent;
  border: 1px solid var(--borde);
  border-radius: 6px;
  color: var(--azul);
  font-size: .8rem;
  padding: .15rem .45rem;
  cursor: pointer;
}
.usuario-nombre { max-width: 6.5rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.usuario-avatar { width: 20px; height: 20px; border-radius: 50%; object-fit: cover; object-position: center 27%; flex: none; background: #223; }
.usuario-lista {
  position: absolute;
  right: 0;
  top: calc(100% + .3rem);
  z-index: 300; /* mismo plano que .idioma-lista */
  display: flex;
  flex-direction: column;
  min-width: 11rem;
  background: var(--panel);
  border: 1px solid var(--borde);
  border-radius: 8px;
  padding: .3rem;
  box-shadow: 0 8px 24px rgba(0, 0, 0, .45);
}
.usuario-lista a { cursor: pointer; display: flex; align-items: center; gap: .55rem; padding: .5rem .6rem; min-height: 44px; border-radius: 6px; color: #e8e8e8; font-size: .9rem; }
.usuario-lista a:hover { background: rgba(255, 255, 255, .07); }
/* grilla del selector de caras (17 del set 3D) */
.avatar-caja { max-width: 21rem; }
.avatar-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: .55rem; overflow-y: auto; }
.avatar-opcion { padding: 0; border: 2px solid transparent; border-radius: 50%; overflow: hidden; aspect-ratio: 1 / 1; background: #223; cursor: pointer; }
.avatar-opcion.on { border-color: var(--oro); }
.avatar-opcion img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* el avatar propio en la placa abre el selector */
.avatar.elegible { cursor: pointer; }
/* perfil v1: la placa de un rival abre su ficha */
.placa-click { cursor: pointer; }
/* --- perfil propio (modal) --- */
.perfil-caja { max-width: 23rem; }
.perfil-cab { display: flex; align-items: center; gap: .9rem; }
.perfil-avatar {
  position: relative;
  width: 84px;
  height: 84px;
  padding: 0;
  border: 2px solid var(--borde);
  border-radius: 50%;
  overflow: visible;
  background: #223;
  cursor: pointer;
  flex: none;
}
.perfil-avatar img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; display: block; }
.perfil-avatar-lapiz {
  position: absolute;
  right: -2px;
  bottom: -2px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--panel);
  border: 1px solid var(--borde);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: .8rem;
}
.perfil-datos { min-width: 0; }
.perfil-nombre { font-size: 1.15rem; font-weight: 700; overflow: hidden; text-overflow: ellipsis; }
.perfil-saldo { color: var(--azul); font-size: .9rem; }
.perfil-saldo b { color: var(--oro); font-variant-numeric: tabular-nums; }
.perfil-campo { font-size: .9em; }
.perfil-nota { margin: 0; font-size: .78rem; opacity: .65; }
.perfil-msg { margin: 0; font-size: .85rem; color: var(--verde); }
.perfil-msg.perfil-err { color: #e66; }
/* el idioma del perfil es un DROPDOWN (reusa .idioma-selector del header):
   con mas idiomas las banderas en linea no entraban */
.perfil-idioma { display: flex; justify-content: space-between; align-items: center; gap: .8em; }
.perfil-pass summary { cursor: pointer; font-size: .9em; padding: .2rem 0; }
.perfil-pass label { margin-top: .45rem; }
/* --- ficha de rival: SOLO nick y avatar --- */
.ficha-caja { max-width: 15rem; align-items: center; text-align: center; }
.ficha-avatar {
  width: 110px;
  height: 110px;
  border-radius: 50%;
  overflow: hidden;
  border: 2px solid var(--borde);
  background: #223;
}
.ficha-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ficha-nombre { font-size: 1.2rem; font-weight: 700; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
.ficha-caja .modal-acciones { justify-content: center; }
section { padding: 1rem; overflow-y: auto; flex: 1; min-height: 0; }
.chica { max-width: 22rem; margin: 0 auto; width: 100%; flex: none; padding-top: 3rem; }
form { display: flex; flex-direction: column; gap: .6rem; }
label { display: flex; flex-direction: column; gap: .2rem; font-size: .85rem; }
input, select, button { padding: .4rem .6rem; background: #0d1117; color: #e8e8e8; border: 1px solid var(--borde); border-radius: 4px; font-size: .9rem; }
button { cursor: pointer; background: #24405c; }
button:hover { background: #2e5a86; }
button:disabled { opacity: .4; cursor: default; }
button:disabled:hover { background: #24405c; }
/* avisos como toast flotante: no empujan el layout (fit-to-screen) */
/* Contenedor UNICO de los dos canales (error + aviso): columna centrada
   con gap, asi nunca se pisan (recon 2026-08-10: el aviso persistente de
   sesion tapaba "Credenciales invalidas"). El fixed vive SOLO aca. */
.avisos-flotantes { position: fixed; top: 2.4rem; left: 50%; transform: translateX(-50%); z-index: 90; display: flex; flex-direction: column; align-items: center; gap: .4rem; max-width: 92vw; pointer-events: none; }
.error, .aviso { margin: 0; padding: .35rem .9rem; border-radius: 6px; background: rgba(10, 15, 20, .95); border: 1px solid var(--borde); font-size: .85rem; max-width: 92vw; }
.error { color: #ff7b7b; border-color: #7b2f2f; }
.aviso { color: var(--oro); border-color: #6b5e2f; }

.mesas { display: flex; gap: 1rem; flex-wrap: wrap; }
.tarjeta { border: 1px solid var(--borde); border-radius: 8px; padding: 1rem; min-width: 14rem; background: var(--panel); }
.tarjeta h3 { margin: 0 0 .4rem; color: var(--verde); }
.tarjeta p { margin: .2rem 0; font-size: .9rem; }

/* ===== lobby v1 (mobile-first: se usa mas desde el celular) ===== */
.lobby { padding: .6rem .8rem; }
.lobby-nav { display: flex; gap: .4rem; flex-wrap: wrap; margin-bottom: .6rem; }
.lobby-nav button { font-size: .85rem; padding: .5rem .9rem; border-radius: 999px; }
.lobby-nav button.on { background: var(--verde); color: #0b1016; font-weight: 700; }
.lobby-nav button:disabled { opacity: .45; cursor: not-allowed; }
.lobby-barra { display: flex; gap: .6rem 1rem; flex-wrap: wrap; align-items: center; justify-content: space-between; margin-bottom: .7rem; }
.lobby-contadores { display: flex; gap: 1rem; font-size: .9rem; }
/* grupos por tipo de dinero (punto 5): titulo chico arriba de cada tabla */
.lobby-grupo { margin-bottom: 1.1rem; }
.lobby-grupo-titulo {
  margin: 0 0 .4rem;
  font-size: .78rem;
  text-transform: uppercase;
  letter-spacing: .12em;
  color: var(--texto-suave, #9fb0c3);
}
.lobby-grupo-vacio { font-size: .85rem; color: var(--texto-suave, #9fb0c3); font-style: italic; }

/* franjas tipo tabla: grid compartido entre encabezado y filas; en
   angosto scrollea .lobby-scroll (la pagina nunca scrollea a lo ancho) */
.lobby-scroll { overflow-x: auto; border: 1px solid var(--borde); border-radius: 8px; }
.lobby-tabla { min-width: 640px; }
.lobby-cab, .lobby-fila {
  display: grid;
  grid-template-columns: minmax(8rem, 1.4fr) 5rem 4.5rem minmax(8rem, 1.2fr) minmax(7rem, 1fr) 4.5rem 6.5rem;
  gap: .5rem;
  align-items: center;
  padding: .5rem .8rem;
}
.lobby-cab { border-bottom: 1px solid var(--borde); background: rgba(255, 255, 255, .03); }
/* Tinte SUTIL por grupo (Raul 2026-08-10): mismo tono que el chip del
   bloque (azul alcance-global / verde alcance-fun), alpha bajo para que
   solo se note comparando los dos bloques. El texto no cambia. */
.lobby-grupo-real .lobby-cab { background: rgba(77, 163, 255, .07); }
.lobby-grupo-practica .lobby-cab { background: rgba(126, 196, 111, .07); }
.lobby-cab button, .lobby-cab span {
  background: none; border: 0; padding: 0; text-align: left;
  font-size: .72rem; text-transform: uppercase; letter-spacing: .08em;
  color: var(--texto-suave, #9fb0c3); cursor: default; min-height: 32px;
  display: inline-flex; align-items: center;
}
.lobby-cab button { cursor: pointer; }
.lobby-cab button.on { color: var(--verde); font-weight: 700; }
.lobby-fila { border-bottom: 1px solid var(--borde); font-size: .9rem; }
.lobby-fila:last-child { border-bottom: 0; }
.lobby-fila:hover { background: rgba(255, 255, 255, .03); }
.lf-nombre { font-weight: 600; color: var(--verde); }
/* Chip de ALCANCE de la mesa (recon 2026-08-10): texto + color por scope,
   nunca color solo. scope lo deriva el server en filaLobby. */
.alcance-chip { display: inline-block; margin-left: .35rem; padding: 0 .45rem; border: 1px solid; border-radius: 999px; font-size: .68rem; font-weight: 600; vertical-align: middle; white-space: nowrap; }
.alcance-global { color: #4da3ff; border-color: #2b5c8f; }
.alcance-agent { color: #c792ea; border-color: #6d4f80; }
.alcance-fun { color: #7ec46f; border-color: #3f6d38; }
.lf-moneda { font-weight: 700; }
.lobby-fila .ficha-leyenda { display: block; font-size: .72rem; }
.lobby-fila .ocupacion { font-weight: 700; color: var(--verde); }
.lobby-fila .ocupacion.llena { color: #ff7b7b; }
.lf-entrar { text-align: right; }
.lf-entrar button { min-height: 44px; width: 100%; }

/* ===== pantalla de mesa (base = mobile portrait, todo en un viewport) ===== */
.juego { flex: 1; min-height: 0; display: flex; flex-direction: column; padding: 0; overflow: hidden; position: relative; }

/* controles de mesa: zona separada de la barra de accion */
.mesa-top { display: flex; align-items: center; gap: .6rem; padding: .2rem .6rem; min-height: 32px; }
.mesa-id { color: var(--verde); font-weight: bold; font-size: .85rem; }
/* Titulo de la mesa + leyendas EN la banda (fix portrait 2026-08-13): el
   nombre, la marca de bots corta y el valor de la ficha. Envuelve en
   portrait si no entra a 390 (crece la banda, el ovalo recentra) en vez
   de flotar sobre las cartas de arriba. */
.mesa-titulo { display: flex; align-items: baseline; flex-wrap: wrap; gap: .1rem .5rem; min-width: 0; }
.mesa-marca { font-size: .72rem; white-space: nowrap; }
.bots-marca { color: #d4af37; font-weight: 600; }
.ficha-marca { color: var(--texto-suave, #9fb0c3); }
.menu-btn { font-size: .95rem; padding: .15rem .6rem; min-height: 30px; }
.controles-mesa { display: none; }
.controles-mesa.abierto { display: flex; flex-direction: column; gap: .9rem; position: fixed; inset: 0; z-index: 60; background: rgba(5, 8, 12, .96); padding: 4rem 2rem; }
.controles-mesa.abierto button { min-height: 48px; font-size: 1rem; }
.controles-mesa .solo-movil { font-size: 1.05rem; color: var(--azul); }
/* solo-land: entradas del menu que existen SOLO en el celu apaisado
   (hoy: Historial / Chat, porque ahi el ☰ dejo de abrir el chat) */
.solo-land { display: none; }
/* volumen (lote audio 2026-08-05): fila compacta dentro del menu ☰ /
   de la barra de controles de desktop */
.controles-mesa .volumen { display: flex; align-items: center; gap: .5rem; font-size: .8rem; color: var(--azul); }
.controles-mesa .volumen input[type=range] { flex: 1; min-width: 6rem; max-width: 12rem; margin: 0; }
/* sonda de audio (diagnostico iPhone): linea chica informativa */
.controles-mesa .sonda-audio { font-size: .72rem; color: var(--azul); opacity: .8; }
.cerrar-menu { margin-top: auto; background: #1d2a3a; }

/* zona de mesa: el wrap tiene el aspecto EXACTO del viewBox del SVG por
   CSS (sin JS): asientos y fichas en % del wrap SON coordenadas del
   dibujo. Mobile v2.10 (punto medio estilo
   PPPoker/PokerBros): rectangulo vertical 710x1000 con esquinas al 30%
   del ancho, 87vw x 64dvh: margen oscuro chico pero visible. */
.mesa-zona { flex: 1; min-height: 0; position: relative; display: flex; align-items: center; justify-content: center; padding: .3rem; }
/* LOTE cqw: el wrap es container (inline-size); todo lo interno se mide
   en cqw = % del ANCHO REAL del wrap (incluidos los topes 1200px/dvh),
   ya no en vw del viewport. Factores de conversion: mobile x1.1494
   (1cqw=0.87vw), desktop x1.3514 (1cqw=0.74vw). Topes rem eliminados:
   cqw ya sigue al wrap capeado. */
/* redistrib 2026-08-04: ovalo mobile ANGOSTO (66vw): con la placa
   legible de 8.3rem el anillo alrededor recibe las placas sin recortes
   a 360 (Raul: "achica el ovalo y ubica las placas en el anillo libre").
   Los tamaños internos en cqw se recalibraron para compensar (~x1.2). */
.mesa-wrap { position: relative; aspect-ratio: 710 / 1000; width: min(66vw, 45.4dvh); container-type: inline-size; }
.mesa-svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

/* asiento v2.4: PLACA horizontal sobre el rail (avatar izquierda, nombre
   arriba, stack en verde), cartas en abanico ARRIBA saliendo por detras */
.asiento { position: absolute; transform: translate(-50%, -50%); text-align: center; font-size: .6rem; z-index: 5; display: flex; flex-direction: column; align-items: center; width: auto; }
/* Con el abanico ENCIMA de la placa, la placa de un asiento debe pisar
   las cartas del asiento de ABAJO. El translate(-50%,-50%) hace de cada
   asiento un contexto de apilamiento (z1/z2 internos no cruzan), asi que
   el orden se resuelve POR FILA: mas arriba en la mesa => z mayor. La
   fila sale del ancla top de posAsiento() via selector de atributo.
   Filas actuales: mobile 96(heroe)/86/66/22/4 (game.js MOVIL, lote
   mesa-grande 2026-08-05) y desktop 97(heroe)/89/59/25/4.5 (DESKTOP
   v3); z5 es la fila del heroe. El landscape compacto suma 79 y 16
   (bloque de abajo). ATENCION: si esos top:% cambian en game.js, estos
   selectores hay que actualizarlos A LA PAR o el orden de pintado entre
   filas se rompe en silencio. */
.asiento[style*="top: 86%"], .asiento[style*="top: 89%"] { z-index: 6; }
.asiento[style*="top: 66%"], .asiento[style*="top: 59%"] { z-index: 7; }
.asiento[style*="top: 22%"], .asiento[style*="top: 25%"] { z-index: 8; }
.asiento[style*="top: 4%"], .asiento[style*="top: 4.5%"] { z-index: 9; }
.placa { position: relative; z-index: 2; display: flex; align-items: stretch; background: linear-gradient(180deg, #2c2f34, #0b0d10); border: 1.5px solid #4a4e55; border-radius: 8px; box-shadow: inset 0 1px 1px rgba(255, 255, 255, .25), 0 5px 10px rgba(0, 0, 0, .7); overflow: hidden; width: 8.7rem; height: 2.6rem; }
/* redistrib mobile 2026-08-04: placa LEGIBLE 8.3rem (restriccion de
   Raul: nombre completo sin truncar; medido en canvas + DOM: "cuarto-jugador"
   bold 10px = 84px + avatar 41.6 + padding). Desktop la pisa en cqw. */
.asiento.mio .placa { border-color: var(--verde); }
.asiento.turno .placa { border-color: var(--timer); box-shadow: 0 0 10px rgba(255, 176, 32, .55), inset 0 1px 1px rgba(255, 255, 255, .25); }
.asiento.ganador .placa { border-color: var(--oro); box-shadow: 0 0 11px #d8c56f99, inset 0 1px 1px rgba(255, 255, 255, .25); }
/* avatar DENTRO de la placa, a la izquierda; el borde es el anillo por
   hash que desempata colisiones */
/* v2.16: slot SIEMPRE cuadrado (aspect-ratio 1:1) en los dos layouts y
   object-position hacia arriba: la cara del set 3D no se corta ni se
   deforma; el ancho sale del alto de la placa */
.avatar { height: 100%; aspect-ratio: 1 / 1; width: auto; flex: none; display: flex; align-items: center; justify-content: center; color: #f4f4f4; position: relative; border-right: 1px solid rgba(0, 0, 0, .55); border-left: 3px solid #888; }
.av-img { width: 100%; height: 100%; object-fit: cover; object-position: center 27%; display: block; }
.placa-info { flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: center; padding: 0 .25rem; background: linear-gradient(180deg, transparent, rgba(0, 0, 0, .35)); }
.asiento .nombre { font-size: 10px; font-weight: bold; color: #fff; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-shadow: 0 1px 2px rgba(0, 0, 0, .8); }
.asiento .stack { font-size: 11px; color: var(--stack-verde); font-weight: 800; font-variant-numeric: tabular-nums; text-shadow: 0 1px 2px rgba(0, 0, 0, .8); }
/* v2.12: TIMER PERIMETRAL: el anillo de progreso recorre el borde de la
   placa del jugador en turno (dentro del contorno: la placa clipea con
   overflow hidden), ambar -> rojo critico; los segundos en pildora sobre
   la ESQUINA inferior derecha de la placa. */
.timer-borde { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 5; pointer-events: none; }
.timer-borde rect { fill: none; stroke-width: 3; vector-effect: non-scaling-stroke; }
.timer-borde .tb-base { stroke: rgba(0, 0, 0, .55); }
.timer-borde .tb-prog { stroke: var(--timer); }
.timer-borde .tb-prog.critico { stroke: var(--timer-critico); }
.reloj-pill { position: absolute; bottom: -.5rem; right: -.35rem; z-index: 8; background: rgba(8, 12, 17, .92); border: 1px solid var(--timer); color: var(--timer); border-radius: 999px; padding: 0 .38rem; font-size: .66rem; font-weight: 800; font-variant-numeric: tabular-nums; line-height: 1.05rem; white-space: nowrap; }
.reloj-pill.critico { color: var(--timer-critico); border-color: var(--timer-critico); }
/* cartas del asiento (TODOS los asientos, ambos layouts): abanico
   centrado ENCIMA de la placa, solapando el 50% del alto de la carta por
   detras (la placa, z2, pisa a las cartas, z1: queda visible la mitad
   superior); abanico -7/+7 con origen abajo-centro y separacion
   horizontal del 55% del ancho. El ancho vive en --carta-w (cada
   layout/asiento lo redefine) para que el solape del abanico (45%)
   siempre acompañe al tamaño real. */
.asiento { --carta-w: 12.4cqw; }
.asiento.mio { --carta-w: 17.5cqw; }
.asiento .cartas { position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%) translateY(50%); z-index: 1; display: flex; align-items: flex-end; }
/* reveal PE (2026-08-05, su .opponent-reveal: z-index 999 + drop-shadow
   sobre el player-plaque-wrapper z50): en SHOWDOWN las cartas saltan
   POR ENCIMA de la placa (dentro del asiento: z3 > placa z2) y se ven
   superpuestas a ella, en LOS TRES layouts. */
.mesa-wrap.showdown .asiento .cartas { z-index: 3; filter: drop-shadow(0 6px 12px rgba(0, 0, 0, .5)); }
/* fuera de la mano (PE .seat.folded, su players.css): placa y cartas
   TRANSPARENTES en gris — foldeado o sentado esperando la proxima
   mano. Los tres layouts (regla base). */
.asiento.fuera .placa, .asiento.fuera .cartas { opacity: .5; filter: grayscale(100%); }
.asiento .cartas .carta { margin: 0; }
/* rotacion del abanico via --rot-fin: dealCard termina EXACTO en la
   rotacion de reposo (sin salto al soltar .carta-animada) */
.asiento .cartas .carta:first-child { --rot-fin: -7deg; transform: rotate(var(--rot-fin)); transform-origin: bottom center; }
.asiento .cartas .carta:last-child:not(:first-child) { --rot-fin: 7deg; transform: rotate(var(--rot-fin)); transform-origin: bottom center; margin-left: calc(var(--carta-w) * -.45); }
/* abanico con CARAS a la vista (heroe siempre; villano revelado en el
   showdown): tamaño de heroe y solape menor (30% del alto) para que el
   indice de esquina quede legible; los DORSOS conservan 9vw/2.4rem con
   solape 50%. El --carta-w seteado en .cartas pisa al del .asiento
   para todo el abanico (incluido el margen del 55%). */
.asiento .cartas:has(.cara) { --carta-w: 17.5cqw; transform: translateX(-50%) translateY(30%); }
/* laterales (solo mobile): caras con tope menor; a 12.5vw el abanico
   rotado (~83px) no entra en los ~38px que hay del ancla (x 3.66% /
   96.34%) al borde de pantalla y se recorta */
.asiento.lateral .cartas:has(.cara) { --carta-w: 11.494cqw; }
/* premio y estado de los asientos norte: en flujo DEBAJO de la placa,
   como el resto (la zona de arriba ahora la ocupan las cartas) */
.asiento .premio { color: var(--oro); font-weight: bold; background: rgba(8, 12, 17, .9); border: 1px solid var(--oro); border-radius: 999px; padding: 0 .4rem; margin-top: .15rem; font-variant-numeric: tabular-nums; z-index: 3; }
/* v2.8 (solo mobile): placa VERTICAL compacta de los asientos laterales
   del estadio (avatar arriba, nombre/stack debajo): no invade el paño.
   Satelites en posiciones reservadas: dealer y reloj como ESQUINAS de la
   placa (whitelisteados: pisan su propia placa, nada mas), premio/estado
   arriba, abanico HACIA el paño (abajo), con "ver" envuelto debajo. */
.asiento.lateral .placa { flex-direction: column; width: 3.4rem; height: auto; }
.asiento.lateral .avatar { width: 100%; height: auto; aspect-ratio: 1 / 1; border-left: none; border-top: 3px solid #888; border-right: none; border-bottom: 1px solid rgba(0, 0, 0, .55); }
.asiento.lateral .placa-info { padding: .1rem .15rem .15rem; text-align: center; }
.asiento.lateral .nombre { font-size: .5rem; }
.asiento.lateral .stack { font-size: .56rem; }
/* los laterales estan a 14% uno del otro: sin banda libre arriba ni
   abajo. Las cartas usan el ancla GLOBAL (encima de la placa, mitad
   visible); premio / estado / segundos siguen como BADGES sobre la
   propia placa (solapan su placa y nada mas). */
.asiento.lateral .premio { position: absolute; bottom: -.3rem; left: 50%; transform: translateX(-50%); margin-top: 0; white-space: nowrap; z-index: 4; }
.asiento.lateral .estado { position: absolute; bottom: .1rem; left: 50%; transform: translateX(-50%); margin-top: 0; white-space: nowrap; z-index: 4; font-size: .52rem; background: rgba(8, 12, 17, .75); border-radius: 999px; padding: 0 .25rem; }
.asiento.lateral .dealer, .asiento.lateral .dealer.izq, .asiento.lateral .dealer.der { top: -.3rem; right: -.05rem; left: auto; transform: none; }
/* tope-centro (solo mesas cortas / heads-up): satelites a los costados,
   arriba no hay lugar (borde del viewport) */
.asiento.tc .premio, .asiento.tc .estado { position: absolute; right: calc(100% + .25rem); left: auto; margin-top: 0; white-space: nowrap; }
.asiento.tc .estado { top: .15rem; }
.asiento.tc .premio { top: 1.35rem; }
.asiento .estado { color: #bbb; font-style: italic; margin-top: .1rem; text-shadow: 0 1px 2px rgba(0, 0, 0, .8); }
/* asiento vacio v2.4: circulo con borde PUNTEADO tenue y dos lineas */
.asiento .libre, .asiento .vacio { width: 2.7rem; height: 2.7rem; min-height: 0; padding: 0; border-radius: 50%; background: rgba(8, 12, 17, .35); border: 1.5px dotted rgba(255, 255, 255, .3); color: var(--azul); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .05rem; line-height: 1.1; }
.asiento .libre:hover { border-color: rgba(255, 255, 255, .6); background: rgba(8, 12, 17, .55); }
.libre-n { font-size: .56rem; color: rgba(255, 255, 255, .55); white-space: nowrap; }
.libre-s { font-size: .6rem; font-weight: bold; color: var(--azul); }
.asiento .vacio { opacity: .7; }
/* circulo libre cubierto por una placa: sin click mientras este tapado
   (fleco del fix heads-up: la placa del rival en tc pisa los circulos) */
.asiento .libre.tapado { pointer-events: none; }
/* "ver" del muck: hijo del asiento (NO del abanico), en flujo debajo de
   la placa: no pisa nombre/stack ni queda detras de la placa */
.asiento .ver { cursor: pointer; color: var(--azul); font-size: .62rem; text-decoration: underline; margin-top: .1rem; background: rgba(8, 12, 17, .85); border-radius: 999px; padding: 0 .3rem; white-space: nowrap; }
.dealer { display: inline-block; background: #e8e8e8; color: #10141c; border-radius: 50%; width: 1rem; height: 1rem; line-height: 1rem; font-size: .62rem; font-weight: bold; text-align: center; }
/* v2.7 (bug 4): el boton dealer vive JUNTO a la placa, del lado del paño
   (izq/der segun el costado de la mesa), a la altura del centro de la
   placa: posicion reservada que no colisiona con cartas ni fichas */
.asiento .dealer { position: absolute; top: 2.3rem; transform: translateY(-50%); z-index: 8; box-shadow: 0 1px 3px rgba(0, 0, 0, .6); }
.asiento .dealer.der { left: calc(100% + .25rem); }
.asiento .dealer.izq { right: calc(100% + .25rem); }

/* apuesta: ficha CSS + monto, entre el asiento y el centro. ARTE unico
   para los DOS layouts (lote medidas-PE): inlay claro 44% + anillo 2px
   oscuro + conic 30/30 con 6 marcas claras del propio color
   (color-mix) + denominacion dentro; colores por umbral en
   ui-rules.colorFicha (--ficha-base/-oscuro/-num). Mobile a 1.5rem,
   desktop 3.04cqw. */
/* z 12 (fichas PE 2026-08-05): la ficha pinta ENCIMA de las cartas de
   todas las filas (asientos z 5-9; su pucks-container es z 25) y por
   debajo del panel de ganador (20). Los clones del barrido van a z 19
   inline (game.js barrerFichasAlPote). */
.ficha-apuesta { position: absolute; transform: translate(-50%, -50%); display: flex; align-items: center; gap: .18rem; background: rgba(8, 12, 17, .78); border-radius: 999px; padding: .05rem .32rem .05rem .18rem; color: var(--oro); font-size: 11px; font-variant-numeric: tabular-nums; z-index: 12; }
/* Arte de ficha v2 (Raul 2026-08-05, leido de PE chips.css y adaptado
   a NUESTRA identidad): el disco de PE es conic de wedges color/blanco
   + inlay blanco 40% — el nuestro invertia igual de mal (cuerpo mitad
   claro). Ahora: CUERPO al color de la denominacion (40-71%), 6 marcas
   de 30 grados en tono claro SOLO en el aro exterior (71-100%; PE usa
   9 de 20 grados: diferencia deliberada), inlay MAS CHICO (36%, antes
   44%) apenas mas claro que el cuerpo con anillo claro fino, y cifra
   en --ficha-numc legible sobre el color. */
/* PILA REAL por apuesta (Raul 2026-08-05, todos los layouts): el
   ::before de ficha unica se reemplaza por stacks de .pila-chip (la
   MISMA pieza que la pila del pote: arte v2 identico en desktop,
   portrait y apaisado). El tamaño por layout entra por --pila-chip-d
   (portrait 1.25rem aca; desktop y compacto lo pisan mas abajo). */
.ficha-pila { display: flex; align-items: flex-end; gap: 2px; flex: none; }
.ficha-apuesta .pila-chip { --pila-chip-d: 1.5rem; } /* portrait, lote board-max 2026-08-05: 1.6 rozaba dorsos a 360 */

/* cartas: proporcion de naipe; dorso == carta (el reveal no mueve nada) */
.carta { display: inline-flex; align-items: center; justify-content: center; background: #f4f4f0; border-radius: 3px; margin: 0 .06rem; font-weight: bold; width: 1.5rem; aspect-ratio: 5 / 7; font-size: .66rem; box-shadow: 0 1px 2px rgba(0, 0, 0, .5); }
/* cara = SVG del mazo CC0 (el arte trae su propio blanco y borde) */
/* caras como BACKGROUND-IMAGE (tecnica PokerEngine, recon 2026-08-04 de
   styles/cards.css: div + background-size contain + fondo transparente +
   drop-shadow): mientras el SVG carga no hay placeholder blanco — no se
   pinta nada — y el naipe aparece entero. El dorso sigue siendo CSS. */
.carta.cara { background-color: transparent; background-size: contain; background-repeat: no-repeat; background-position: center; padding: 0; box-shadow: none; filter: drop-shadow(2px 2px 3px rgba(0, 0, 0, .4)); }
/* reparto estilo PokerEngine (players.js/cards.css del recon): la carta
   NUEVA vuela desde el centro de la mesa (--startX/--startY los setea la
   directiva v-reparto de game.js), girando desde -180 y escalando desde
   0, escalonada por indice; opacity 0 hasta que arranca su animacion. */
@keyframes dealCard {
  0% { opacity: 0; transform: translate(var(--startX, 0px), var(--startY, 0px)) scale(0) rotate(-180deg); }
  100% { opacity: 1; transform: translate(0, 0) scale(1) rotate(var(--rot-fin, 0deg)); }
}
.carta-animada { opacity: 0; animation: dealCard .5s ease-out forwards; }
.board { display: flex; justify-content: center; gap: .5747cqw; }
.board .carta { width: 13.2cqw; border-radius: 4px; margin: 0; }
.asiento .carta { width: var(--carta-w); }
.asiento.mio .carta { border-radius: 5px; }
.carta.rojo { color: #c0392b; }
.carta.negro { color: #1a1a2a; }
/* dorso: 1B.svg del MISMO set CC0 que las caras (antes era un
   placeholder propio en rayas CSS). Mismo tratamiento que .cara
   (contain, sin fondo ni sombra propia) para que el naipe entre entero
   y el reveal no mueva nada. */
.carta.dorso { background-color: transparent; background-image: url('/cartas/1B.svg?v=2'); background-size: contain; background-repeat: no-repeat; background-position: center; color: transparent; padding: 0; box-shadow: none; filter: drop-shadow(2px 2px 3px rgba(0, 0, 0, .4)); }
.carta.gana { outline: 2px solid var(--oro); box-shadow: 0 0 8px #d8c56faa; }

/* el asiento propio usa la MISMA placa; solo sus cartas van boca arriba
   (mas grandes) en el abanico de arriba */

/* marca de agua sobre el paño: mismo tono apenas mas oscuro, tipografia
   gruesa, detras del contenido del centro */
.marca-agua { position: absolute; left: 50%; top: 56%; transform: translate(-50%, -50%); z-index: 3; font-weight: 800; font-size: 1.7rem; letter-spacing: .06em; color: rgba(0, 0, 0, .22); pointer-events: none; user-select: none; white-space: nowrap; }

/* pila del POTE (fichas PE 2026-08-05: su chips.css .chip-stack +
   socket.js updateTable, arte de ficha NUESTRO): stacks column-reverse
   con solape (las de arriba pisan a las de abajo), centrados debajo
   del board. Sin numero adentro: a este tamaño el color es la
   denominacion. */
.pot-pila { display: flex; justify-content: center; align-items: flex-end; gap: .5cqw; margin-top: .5cqw; pointer-events: none; }
.pila-stack { display: flex; flex-direction: column-reverse; }
/* .pila-chip: LA pieza de ficha unica del sistema (arte v2). La usan la
   pila del pote y las pilas de apuesta; el diametro sale de
   --pila-chip-d (default 2.3cqw = pote) y el solape vertical es 70%
   del diametro (como el margin-top -22 sobre 28px de PE). La cifra va
   en ::after, proporcional al diametro y encogida por digitos. */
.pila-chip { position: relative; width: var(--pila-chip-d, 2.3cqw); height: var(--pila-chip-d, 2.3cqw); border-radius: 50%; margin-top: calc(var(--pila-chip-d, 2.3cqw) * -0.7); flex: none; --ficha-inlay: color-mix(in srgb, var(--ficha-base, #b03a3a) 72%, #fff); background: radial-gradient(circle closest-side at center, var(--ficha-inlay) calc(36% - 1.5px), var(--ficha-claro, #eee) calc(36% - 1.5px) 40%, var(--ficha-base, #b03a3a) 40% 71%, transparent 71%), repeating-conic-gradient(var(--ficha-claro, #eee) 0deg 30deg, var(--ficha-base, #b03a3a) 30deg 60deg); box-shadow: 0 2px 3px rgba(0, 0, 0, .55), inset 0 1px 2px rgba(255, 255, 255, .35); }
.pila-chip::after { content: var(--ficha-num, ''); position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: calc(var(--pila-chip-d, 2.3cqw) * .36 * var(--ficha-num-k, 1)); color: var(--ficha-numc, #fff); }
.pila-stack .pila-chip:first-child { margin-top: 0; }
/* v2.7: en portrait el centro se ancla por su borde SUPERIOR (bajo el
   arco de rivales): el resultado del showdown crece HACIA ABAJO, hacia la
   banda libre que queda antes del abanico propio. El desktop vuelve al
   centrado clasico. */
.centro { position: absolute; left: 50%; top: 34.5%; transform: translateX(-50%); text-align: center; width: 88%; z-index: 6; }
/* pot: pastilla oscura redondeada arriba del board, monto en verde */
.pot { display: inline-block; background: rgba(6, 10, 16, .72); border: 1px solid rgba(255, 255, 255, .12); border-radius: 999px; padding: .12rem .75rem; color: var(--stack-verde); font-weight: 700; font-variant-numeric: tabular-nums; margin-bottom: .3rem; font-size: .74rem; }
/* panel de GANADOR (estilo PokerEngine, reemplaza al viejo .resultado):
   overlay centrado sobre el paño, por DEBAJO de la capa de asientos
   (z4 < asientos z5..z9): nunca tapa una placa; desaparece con el reset
   de la mano nueva (mismo ciclo de vida que tenia .resultado) */
/* z-index 20: el panel pinta ENCIMA de los asientos (z 5-9) y fichas
   (z 6) — en mobile 9-max las placas laterales y55 con sus cartas
   tapaban al ganador (reporte de Raul 2026-08-04) — y debajo del chrome
   fijo (tab-cuerpo 25, panel-lateral 30, overlay 70). El padding 1.9rem
   sigue conteniendo las 5 cartas (237px <= 241px a 390) */
.panel-ganador { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: 89.6532cqw; z-index: 20; background: rgba(10, 15, 20, .94); border: 1px solid var(--oro); border-radius: 10px; padding: .45rem 1.9rem; display: flex; flex-direction: column; gap: .4rem; box-shadow: 0 8px 24px rgba(0, 0, 0, .6); }
.pg-bloque { display: flex; flex-direction: column; gap: .25rem; }
.pg-bloque + .pg-bloque { border-top: 1px solid var(--borde); padding-top: .4rem; }
.pg-cab { display: flex; align-items: center; gap: .45rem; }
.pg-avatar { width: 2.1rem; height: 2.1rem; border-radius: 50%; overflow: hidden; flex: none; border: 2px solid #888; }
.pg-info { min-width: 0; text-align: left; }
.pg-nombre { font-weight: bold; font-size: .78rem; color: #fff; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pg-mano { color: var(--oro); font-size: .7rem; }
.pg-botes { color: var(--azul); font-size: .6rem; }
.pg-monto { margin-left: auto; color: var(--stack-verde); font-weight: 800; font-variant-numeric: tabular-nums; font-size: .85rem; white-space: nowrap; }
.pg-cartas { display: flex; justify-content: center; gap: .2rem; }
.pg-cartas .carta { width: 2.8rem; border-radius: 4px; margin: 0; }
.panel-ganador .rake { color: #888; font-size: .64rem; margin: 0; text-align: center; }
/* countdown en el pie del panel: mas chico que el del centro (gana en
   especificidad a la regla desktop de .countdown) */
.panel-ganador .countdown { font-size: .85rem; margin-top: 0; align-self: center; }
/* countdown entre manos: grande, amarillo con glow suave */
.countdown { display: inline-block; color: #ffd95e; font-size: .85rem; font-weight: 800; text-transform: uppercase; letter-spacing: .04em; margin-top: .35rem; font-variant-numeric: tabular-nums; text-shadow: 0 0 12px rgba(255, 217, 94, .55), 0 1px 2px rgba(0, 0, 0, .8); }
.estado-mesa { display: inline-block; color: var(--azul); font-size: .74rem; margin-top: .3rem; }
/* Los textos del centro reservan su lugar toda la pausa (mesa quieta
   2026-08-05): se apagan por visibility, nunca por v-if, para que el
   board no se recoloque cuando aparecen (el centro de landscape y
   desktop esta anclado al medio). display:block: en linea, el espacio
   reservado colapsaria al esconder el de al lado. */
.centro .countdown, .centro .estado-mesa { display: block; }
.centro .countdown.oculto, .centro .estado-mesa.oculto { visibility: hidden; }

/* chat + log: pestañas en flujo (32px); el cuerpo se DESPLIEGA POR ENCIMA
   de la mesa (absolute) sin empujar el layout; scroll SOLO interno */
.zona-inferior { flex: none; }
.panel-lateral { background: var(--panel); border-top: 1px solid var(--borde); }
.tabs { display: flex; gap: 1.1rem; padding: 0 .8rem; height: var(--alto-tabs); align-items: center; }
.tabs a { cursor: pointer; color: var(--azul); display: flex; align-items: center; gap: .3rem; font-size: .82rem; height: 100%; }
.tabs a.on { color: var(--verde); font-weight: bold; box-shadow: inset 0 -2px 0 var(--verde); }
.badge { background: #b03a3a; color: #fff; border-radius: 999px; min-width: 1.05rem; height: 1.05rem; line-height: 1.05rem; font-size: .62rem; text-align: center; padding: 0 .2rem; font-weight: bold; }
.tab-cuerpo { position: absolute; left: .3rem; right: .3rem; bottom: calc(var(--alto-tabs) + var(--alto-barra) + env(safe-area-inset-bottom) + .2rem); z-index: 25; background: rgba(15, 21, 30, .97); border: 1px solid var(--borde); border-radius: 8px; display: flex; flex-direction: column; height: 38dvh; overflow: hidden; }
.log, .chat-msgs { overflow-y: auto; padding: .25rem .7rem; font-size: .75rem; flex: 1; min-height: 0; }
.log p, .chat-msgs p { margin: .16rem 0; overflow-wrap: anywhere; }
.chat { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.chat-envio { display: flex; flex-direction: row; gap: .4rem; padding: .35rem .7rem; }
.chat-envio input { flex: 1; min-width: 0; }
.chat-nota { color: #888; font-size: .75rem; padding: .3rem .7rem; margin: 0; }

/* barra de ACCION compacta (v2.1): misma regla de slots inmutables y
   siempre-montada; altura de barra, botones tocables >= 44px */
.barra-accion { flex: none; display: grid; grid-template-columns: 1fr 1.3fr 2fr 1fr; gap: .3rem; align-items: stretch; height: calc(var(--alto-barra) + env(safe-area-inset-bottom)); padding: .3rem .35rem calc(.3rem + env(safe-area-inset-bottom)); background: var(--panel); border-top: 2px solid var(--oro); }
.barra-accion .slot { min-height: 44px; font-size: .82rem; padding: .2rem .3rem; }
.barra-accion .subir { display: flex; flex-direction: row; align-items: center; gap: .35rem; border: none; background: none; padding: 0; }
.barra-accion .subir input[type=range] { flex: 1; min-width: 2.5rem; margin: 0; padding: 0; }
.barra-accion .subir button { flex: none; min-height: 44px; font-size: .78rem; padding: .2rem .4rem; max-width: 60%; }
.barra-accion .subir.off { opacity: .4; }

/* barra de PRE-ACCION (lote pre-acciones, diseño PE): mismos slots que la
   barra de accion; el radio va oculto y el label ES el boton (PE
   actions.css). Colores activos de PE: fold rojo, check/fold verde,
   call any azul. La clase activa gana al hover por especificidad. */
.pre-acciones .slot { display: flex; align-items: center; justify-content: center; text-align: center; background: #24405c; border: 1px solid var(--borde); border-radius: 4px; color: #e8e8e8; cursor: pointer; user-select: none; -webkit-user-select: none; }
.pre-acciones label.slot:hover { background: #2e5a86; }
.pre-acciones input[type=radio] { display: none; }
.pre-acciones .slot.pre-on-fold { background: linear-gradient(to bottom, #d32f2f, #9a0007); font-weight: 700; }
.pre-acciones .slot.pre-on-check { background: linear-gradient(to bottom, #388e3c, #1b5e20); font-weight: 700; }
.pre-acciones .slot.pre-on-call { background: linear-gradient(to bottom, #1976d2, #0d47a1); font-weight: 700; }

/* buy-in como modal centrado */
.overlay { position: fixed; inset: 0; z-index: 70; background: rgba(5, 8, 12, .72); display: flex; align-items: center; justify-content: center; padding: 1rem; }
.modal { background: var(--panel); border: 1px solid var(--borde); border-radius: 10px; padding: 1rem; display: flex; flex-direction: column; gap: .7rem; width: 100%; max-width: 22rem; }
.modal span { font-variant-numeric: tabular-nums; text-align: center; color: var(--oro); }
.modal button { min-height: 46px; }
/* prompt de recarga (lote rebuy-ux): saldo informativo arriba, countdown
   de la reserva bien visible; hereda todo lo demas de .modal */
.modal-rebuy .rebuy-saldo { margin: 0; text-align: center; color: var(--azul); font-size: .9rem; }
.modal-rebuy .rebuy-tiempo { margin: 0; text-align: center; color: var(--oro); font-size: 1.05rem; font-variant-numeric: tabular-nums; }

/* ===== desktop / landscape: mesa central mas chica con aire, chat/log
   abajo-izquierda de altura fija junto a la barra compacta (~72px) ===== */
/* LAYOUT POR ORIENTACION (lote landscape 2026-08-04): portrait ->
   vertical, landscape -> horizontal, sin condicion de ancho. El espejo
   JS es MEDIA_MOVIL en game.js: SIEMPRE a la par de esta condicion. */
@media (orientation: landscape) {
  :root { --alto-barra: 72px; }
  /* 85rem CALCULADO: wrap tope 1200px + 2x65px de voladizo de los
     flancos (x2%/98%, mitad afuera del rail: media caja de caras
     reveladas rotadas 89px - 24px que el ancla esta adentro) + margen.
     Con 76rem las cartas/placas laterales recortaban a 1920. */
  .juego { max-width: 85rem; width: 100%; margin: 0 auto; }
  h1 { font-size: 1.05rem; }
  .menu-btn { display: none; }
  .solo-movil { display: none; }
  .mesa-top { padding: .2rem .5rem; }
  .controles-mesa { display: flex; position: static; flex-direction: row; gap: .5rem; background: none; padding: 0; margin-left: auto; }
  .controles-mesa button { min-height: 0; font-size: .8rem; padding: .25rem .6rem; }

  /* mesa a las MEDIDAS DE POKERENGINE: min(75vw, 1100px) + alto
     disponible como tercer tope. Sin el 105dvh viejo (achicaba la mesa
     7% a 1200 y 14% a 1440 vs la referencia). --alto-disp = 100dvh
     menos el chrome MEDIDO en el DOM a 1200x800: header 34 + mesa-top
     32 + zona-inferior 148 + margenes 11.2 + padding mesa-zona 9.6 =
     234.8px (redondeado 235). Objetivo: 900x480 a 1200x800 (PE exacto)
     y 1080x576 a 1440x900 (PE da 1080x550 porque capea el alto aparte
     y deforma el ovalo; nuestro aspecto es fijo 1.875). */
  .juego { --alto-disp: calc(100dvh - 235px); }
  /* top 46.5px: centra la mesa en el VIEWPORT como PokerEngine (medido
     2026-08-04: PE deja 160/160 a 1200x800 y 175/175 a 1440x900, mesa
     siempre centrada). El offset es CONSTANTE porque la zona ya resta
     los 235px de chrome: (234.8/2) - (zona_top 66 + padding 4.8). Si el
     chrome cambia, recalcular. Reemplaza al top:8px del lote medidas-PE. */
  .mesa-wrap { aspect-ratio: 900 / 480; width: min(75vw, 1100px, calc(var(--alto-disp) * 1.875)); top: 46.5px; }
  .asiento { font-size: .68rem; }
  /* placa desktop ~17.5% del ancho de la mesa (proporcion del recon
     179x69 sobre 1024) con el avatar ocupando el alto a la izquierda */
  /* LOTE 2: placa en cqw (18.4 x 7.06, misma proporcion que 8.6x3.3rem):
     escala con la mesa y mata el degradado 821-999. El avatar mantiene
     su proporcion (height:100% + aspect-ratio en la regla base). Stack
     MAS GRANDE que el nombre (jerarquia del recon PE: 16 vs 13). */
  .placa { width: 19.4cqw; height: 7.48cqw; }
  /* el avatar queda en ~7.0cqw solo (height:100% de la placa menos
     bordes), la proporcion PE; nombre/stack en px FIJOS como PE */
  .asiento .nombre { font-size: 13px; }
  .asiento .stack { font-size: 16px; }
  .avatar { border-left-width: 3px; }
  .asiento .dealer { top: 3rem; }
  .reloj-pill { font-size: .72rem; }
  .asiento .libre, .asiento .vacio { width: 3.6rem; height: 3.6rem; }
  .libre-n { font-size: .6rem; }
  .libre-s { font-size: .66rem; }
  .marca-agua { font-size: 3rem; top: 63%; }
  /* countdown chico tambien en desktop (Raul 2026-08-05: "texto chico
     bajo el board"; era 1.6rem) */
  .countdown { font-size: .85rem; }
  .pot { font-size: .85rem; }
  /* cartas desktop en vw CON TOPE rem (mismo tamaño exacto a 1200px:
     7.3vw=87.6, 6.4vw=76.8=4.8rem, 3.2vw=38.4=2.4rem): por debajo de
     1200 escalan con la mesa (a 821-1000px el rem fijo dejaba el board
     al 78-86%% del paño y todo solapado); el tope rem manda de ~1620px
     para arriba. */
  .board { gap: 1.1cqw; }
  .board .carta { width: 7.55cqw; }
  /* mismas anclas de cartas que mobile; solo cambia el ancho (dorsos) */
  /* LOTE 2: villano con dorso y cara del MISMO tamaño (6.44cqw) y MISMO
     solape (45% -> 55% visible, el valor del recon PE): desaparecen el
     cambio de tamaño por :has(.cara), la regla de 35% de la fila tope y
     el tamaño especial de caras. La regla :has de abajo NEUTRALIZA la
     herencia del base mobile (14.3675cqw / 30%), que no se toca. */
  .asiento { --carta-w: 6.53cqw; }
  .asiento .cartas, .asiento .cartas:has(.cara) { transform: translateX(-50%) translateY(45%); }
  .asiento .cartas:has(.cara) { --carta-w: 6.53cqw; }
  /* HEROE: misma medida y solape que los villanos (correccion de Raul,
     lote medidas-PE): hereda 6.53cqw / 45% de las reglas genericas */
  .asiento.mio { max-width: 22rem; }
  .ficha-apuesta { font-size: 1.3514cqw; padding: .08em .53em .08em .3em; gap: .3em; }
  /* pila real 2026-08-05: el arte vive en .pila-chip (base); desktop
     solo pisa el diametro */
  .ficha-apuesta .pila-chip { --pila-chip-d: 3.04cqw; }
  .centro { width: 52%; top: 50%; transform: translate(-50%, -50%); }
  /* LOTE 2: panel en cqw (38cqw = los 320px de hoy a 1200, pero escala)
     con avatar al doble y tipografia con pisos en px */
  .panel-ganador { width: 44cqw; padding: .45rem .7rem; }
  .pg-avatar { width: 8.65cqw; height: 8.65cqw; }
  .pg-nombre { font-size: 22px; }
  .pg-mano { font-size: 20px; }
  .pg-botes { font-size: 13px; }
  .pg-monto { font-size: 16px; }
  .pg-cartas .carta { width: 5.43cqw; }
  /* panel con MAS de un bloque: bbox acotado al 90% del paño reduciendo
     proporcionalmente los tamaños internos (scale del panel ENTERO, no
     por bloque). Factores MEDIDOS con bote partido de 2 bloques:
     a 821 daba 314px de alto vs 248 permitidos (hace falta <=0.789) y
     a 900, 280 vs 272 (<=0.970). Solo desktop (este bloque @media). */
  @container (max-width: 620px) {
    .panel-ganador:has(.pg-bloque + .pg-bloque) { transform: translate(-50%, -50%) scale(.70); }
  }
  @container (min-width: 620.01px) and (max-width: 700px) {
    .panel-ganador:has(.pg-bloque + .pg-bloque) { transform: translate(-50%, -50%) scale(.82); }
  }
  @container (min-width: 700.01px) and (max-width: 780px) {
    .panel-ganador:has(.pg-bloque + .pg-bloque) { transform: translate(-50%, -50%) scale(.82); }
  }
  .pot { font-size: .82rem; }

  /* grid inferior: chat/log (altura FIJA, scroll interno) + barra abajo */
  .zona-inferior { display: grid; grid-template-columns: 21rem 1fr; gap: .5rem; margin: .25rem .5rem .45rem; align-items: end; height: 148px; }
  /* chat PEGADO al borde como PokerEngine (medido 2026-08-04: su chat es
     un panel fixed anclado al borde de la pantalla, no un bloque del
     flujo). Va al rincon inferior-izquierdo (a la derecha vive la barra
     de accion), mismo tamaño que hoy: 21rem x 148px, que a mesa centrada
     nunca pisa el wrap (gap minimo 12px a 1200x800). La columna 21rem
     del grid queda vacia y conserva la posicion de la barra. z-30: sobre
     la mesa, bajo menu (60) / modal (70) / avisos (90). */
  .panel-lateral { position: fixed; left: 0; bottom: 0; z-index: 30; width: 21rem; height: 148px; border: 1px solid var(--borde); border-left: none; border-bottom: none; border-radius: 0 8px 0 0; display: flex; flex-direction: column; overflow: hidden; }
  .tab-cuerpo { position: static; height: auto; flex: 1; min-height: 0; border: none; border-radius: 0; background: none; }
  .log { flex: 1; }
  .chat-msgs { flex: 1; }
  /* grid-column 2: con el chat fixed (fuera del flujo) la barra es el
     primer item del grid y caeria en la columna de 21rem */
  .barra-accion { grid-column: 2; height: var(--alto-barra); border: 1px solid var(--oro); border-radius: 8px; padding: .3rem .4rem; align-self: end; }
  .barra-accion .subir button { max-width: none; }
}

/* ===== LANDSCAPE COMPACTO (celular apaisado, alto <=500px) = COPIA
   del modo mobile-horizontal de PokerEngine A MEDIDAS RENDERIZADAS
   (lote pe-px 2026-08-04): se midio su mesa REAL (bots brooklyn-loft)
   a 932x430 y 844x390 y TODO px de este bloque se multiplica por
   --pe-escala = min(1, 100dvh/430) — el espejo exacto de su
   applyMobileViewportScale() de main.js (escala el body por vh/430).
   La setea actualizarLayout() en game.js. Medidas base (escala 1,
   932x430, verificadas contra su DOM): mesa 752x376 margenes 90/14.1,
   placa 144x54 avatar 50 nombre 11 stack 13, board 70x100 gap 6,
   heroe 82x115 abanico +-5deg solape -45, dorsos 42x59 a -32 abanico
   +-10deg, reveladas 55x77 a -45, chip 22 pastilla 12px, panel
   350-450x~170 (specs de su notifications.css). A 844x390 todo rinde
   x0.907 (609.5x304.7 etc): igualado exacto. Componentes nuestros,
   arte nuestro (salvo el dorado del panel, pedido explicito).
   DIFERENCIA DELIBERADA: botones de accion a LOS LADOS (columnas
   fixed en las esquinas libres del estadio), sin escalar (no son de
   PE). Fila top y16 (PE y13 recortaba dorsos; decision de Raul). */
@media (orientation: landscape) and (max-height: 500px) {
  /* cromo flotante: header transparente fixed (saldo izq, idiomas der);
     nada empuja el layout */
  header { position: fixed; top: 0; left: 0; right: 0; z-index: 40; background: none; min-height: 0; padding: .25rem .6rem; pointer-events: none; }
  header a, header .idiomas { pointer-events: auto; }
  .saldos { max-width: 20vw; }
  /* columnas laterales (Raul 2026-08-05, DISEÑO PROPIO, no PE — su fila
     top recorta las cartas de arriba y ese defecto se evita adrede):
     chat/historial a la IZQUIERDA (☰ + mesa-id, panel overlay debajo)
     y controles de mesa (Rebuy/Levantarse/Volver) en COLUMNA VERTICAL
     a la DERECHA, en la esquina libre ARRIBA de la placa 92%/36% (con
     la mesa a escala PE completa esa franja mide ~75px a 932x430:
     botones compactos y sin mesa-id en esa columna). El tope del ovalo
     queda libre: nada fixed pisa el estadio. */
  .mesa-top { position: fixed; top: 36px; left: 8px; right: auto; transform: none; z-index: 45; min-height: 0; height: auto; padding: 0; background: none; display: flex; flex-direction: column; align-items: flex-start; gap: .2rem; }
  /* Lote menu-land (Raul 2026-08-05): los controles de mesa DENTRO del
     menu ☰ (el MISMO de portrait; sueltos quedaban con texto enano en
     la franja derecha). El ☰ crece a 44x44 (pulgar) y vive en el margen
     oscuro izquierdo, sin pisar estadio ni placas. El overlay achica su
     padding: 5 botones de 48px no entraban en 390 de alto con el 4rem
     de portrait. solo-movil (titulo y Cancelar) vuelve a verse: el
     landscape generico lo esconde para el desktop. */
  .mesa-top .menu-btn { display: block; min-width: 44px; min-height: 44px; font-size: 1.15rem; }
  .controles-mesa { display: none; }
  .controles-mesa.abierto { display: flex; padding: 1.2rem 2rem; gap: .5rem; overflow-y: auto; }
  .controles-mesa.abierto .solo-movil, .controles-mesa.abierto .solo-land { display: block; }
  /* mesa PE: estadio 2:1 al 47% del viewport, ESCALADA como la suya
     (su formula usa vh reales y el body se escala despues: por eso a
     844x390 su mesa rinde 609.5, no 672) */
  .juego { --alto-disp: calc(100dvh - 54px); }
  .mesa-wrap { aspect-ratio: 2 / 1; width: calc(min(92vw, var(--alto-disp) * 2) * var(--pe-escala, 1)); position: absolute; left: 50%; top: 47%; transform: translate(-50%, -50%); }
  .zona-inferior { position: fixed; left: 0; right: 0; bottom: 0; height: auto; margin: 0; display: block; z-index: 35; pointer-events: none; }
  /* chat/historial como PANEL DESPLEGABLE sobre el paño: cerrado no
     existe (el :has detecta el v-show del cuerpo), abierto flota bajo
     el ☰ sin tapar ni el boton ni los slots de accion de la izquierda
     (Fold/Check arrancan en bottom 8+58: el panel corta en 108) */
  .panel-lateral { pointer-events: auto; display: flex; flex-direction: column; position: fixed; left: 8px; top: 92px; bottom: 108px; width: min(21rem, 60vw); height: auto; z-index: 55; background: rgba(15, 21, 30, .97); border: 1px solid var(--borde); border-radius: 8px; overflow: hidden; }
  .panel-lateral:has(.tab-cuerpo[style*="display: none"]) { display: none; }
  .tab-cuerpo { position: static; height: auto; flex: 1; min-height: 0; border: none; border-radius: 0; background: none; }
  /* DIFERENCIA DELIBERADA: botones a LOS LADOS, fuera del estadio */
  .barra-accion { display: contents; }
  .barra-accion .slot, .barra-accion .subir, .barra-accion .subir input[type=range] { pointer-events: auto; }
  .barra-accion .slot { position: fixed; z-index: 36; width: 110px; min-height: 0; height: 44px; box-shadow: 0 4px 10px rgba(0, 0, 0, .8); }
  .barra-accion .slot:nth-child(1) { left: 8px; bottom: 8px; }
  .barra-accion .slot:nth-child(2) { left: 8px; bottom: 58px; }
  .barra-accion .subir { position: fixed; right: 8px; bottom: 52px; z-index: 36; width: 104px; height: auto; display: flex; flex-direction: column; gap: 4px; }
  .barra-accion .subir input[type=range] { width: 100%; margin: 0; min-width: 0; filter: drop-shadow(0 3px 5px rgba(0, 0, 0, .9)); }
  .barra-accion .subir button { min-height: 0; height: 40px; max-width: none; }
  .barra-accion .slot:nth-child(4) { right: 8px; bottom: 8px; width: 104px; }
  /* pre-accion en landscape: espejo exacto de las ranuras de accion (PE:
     check/fold en la ranura del call). Auto Fold y Check/Fold heredan
     nth-child(1)/(2) a la izquierda y Clear el (4) a la derecha; solo el
     tercer slot (Call Any) necesita coordenadas propias, donde va .subir. */
  .pre-acciones .slot:nth-child(3) { right: 8px; bottom: 58px; width: 104px; }
  /* placa PE RENDERIZADA: 144x54 (la nuestra 144x~50+borde, nunca mas
     grande), avatar 50x50, nombre 11px acotado, stack 13px/900 */
  .placa { width: calc(144px * var(--pe-escala, 1)); height: calc(50px * var(--pe-escala, 1)); }
  .placa-info { min-width: calc(90px * var(--pe-escala, 1)); padding: 0 calc(10px * var(--pe-escala, 1)); }
  .asiento .nombre { font-size: calc(11px * var(--pe-escala, 1)); max-width: calc(70px * var(--pe-escala, 1)); margin-bottom: calc(2px * var(--pe-escala, 1)); }
  .asiento .stack { font-size: calc(13px * var(--pe-escala, 1)); font-weight: 900; }
  /* board PE RENDERIZADO: 70x100 gap 6 (su bloque tardio pisa el 53x74
     temprano); pot al 12% (su #pot-display). Centro BAJADO de 38% a
     41.5% (Raul 2026-08-05): con la fila top bajada, la carta del
     jugador de arriba tocaba el board (gap -0.1px a 844x390 medido);
     ahora quedan 10-17px. La pila del pote fluye DEBAJO del board y
     baja con el. */
  /* centro BAJADO 41.5% -> 56% (Raul 2026-08-05): el conjunto pot+board+
     pila queda centrado vertical en el paño (antes sobraba fieltro
     abajo). El 14.5% equivale a 44/54/49px a 844/932/915 y escala
     parejo porque todo el bloque va en pe-escala. Tope: el heroe a
     844x390 (la pila queda a ~3.5px de su carta en river con 9). OJO:
     top ancla el CENTRO del bloque (translate -50% heredado del
     desktop), no su borde. */
  .centro { top: 56%; }
  .centro .pot { position: absolute; left: 50%; top: calc(50% - 13cqw); transform: translate(-50%, -50%); margin: 0; font-size: calc(12px * var(--pe-escala, 1)); }
  .board { gap: calc(6px * var(--pe-escala, 1)); }
  .board .carta { width: calc(70px * var(--pe-escala, 1)); }
  /* heroe ANCLADO SOBRE SU PLACA como los villanos (lote heroe-land
     2026-08-06): el display flotante de PE (bottom -4cqw+17px) colgaba
     las cartas por debajo de la placa, fuera de la mesa — PE usa un
     heroe aparte que nosotros no tenemos. Mismo criterio que el reveal
     de villano (top = -45/55 del ancho de carta), escalado al 82 del
     heroe y con +6 por el bbox del abanico rotado (+-5deg agranda el
     alto ~6px medidos): -73px. El abanico +-5/-45 de PE se conserva. */
  .asiento.mio .cartas { top: calc(-73px * var(--pe-escala, 1)); bottom: auto; transform: translateX(-50%); --carta-w: calc(82px * var(--pe-escala, 1)); }
  .asiento.mio .cartas .carta, .asiento.mio .cartas .carta:first-child { transform: rotate(-5deg) translateY(calc(5px * var(--pe-escala, 1))); margin-right: calc(-45px * var(--pe-escala, 1)); margin-left: 0; }
  .asiento.mio .cartas .carta:last-child:not(:first-child) { transform: rotate(5deg) translateY(calc(5px * var(--pe-escala, 1))); margin-right: 0; margin-left: 0; }
  /* villanos PE: dorsos 42px a -32, abanico +-10 solape -16; reveladas
     55px a -45 */
  .asiento:not(.mio) .cartas { bottom: auto; top: calc(-32px * var(--pe-escala, 1)); transform: translateX(-50%); --carta-w: calc(42px * var(--pe-escala, 1)); }
  .asiento:not(.mio) .cartas .carta:first-child { transform: rotate(-10deg) translateY(calc(5px * var(--pe-escala, 1))); margin-right: calc(-16px * var(--pe-escala, 1)); }
  .asiento:not(.mio) .cartas .carta:last-child:not(:first-child) { transform: rotate(10deg) translateY(calc(5px * var(--pe-escala, 1))); margin-left: 0; }
  .asiento:not(.mio) .cartas:has(.cara) { --carta-w: calc(55px * var(--pe-escala, 1)); top: calc(-45px * var(--pe-escala, 1)); transform: translateX(-50%); }
  /* fichas PE: chip 22 (rinde 20 a 844, como el suyo), cifra 8px,
     pastilla 12px; apilado sugerido con sombras del disco */
  .ficha-apuesta { font-size: calc(12px * var(--pe-escala, 1)); padding: calc(2px * var(--pe-escala, 1)) calc(8px * var(--pe-escala, 1)) calc(2px * var(--pe-escala, 1)) calc(2px * var(--pe-escala, 1)); gap: calc(3px * var(--pe-escala, 1)); }
  /* pila real 2026-08-05: fuera el apilado FALSO por box-shadow (0 -3px
     / 0 -6px): ahora la pila es de fichas reales (.pila-chip) */
  .ficha-apuesta .pila-chip { --pila-chip-d: calc(22px * var(--pe-escala, 1)); }
  /* panel de ganador = su #winner-pop-up EXACTO (notifications.css):
     350-450, padding 20, borde 2px dorado, radio 12, glow 25; nombre
     22, mano 20, botes 13, total/descripcion 16, avatar 80 con borde
     3px dorado, cartas 50x70 gap 8; centrado en la PANTALLA (el wrap
     esta al 47%: +3dvh lo lleva al 50% del viewport) */
  .panel-ganador { left: 50%; top: calc(50% + 3dvh); width: auto; min-width: calc(350px * var(--pe-escala, 1)); max-width: calc(450px * var(--pe-escala, 1)); padding: calc(20px * var(--pe-escala, 1)); border: 2px solid #d4af37; border-radius: 12px; box-shadow: 0 0 calc(25px * var(--pe-escala, 1)) rgba(212, 175, 55, .5); }
  .pg-avatar { width: calc(80px * var(--pe-escala, 1)); height: calc(80px * var(--pe-escala, 1)); border: 3px solid #d4af37; }
  .pg-nombre { font-size: calc(22px * var(--pe-escala, 1)); }
  .pg-mano { font-size: calc(20px * var(--pe-escala, 1)); }
  .pg-botes { font-size: calc(13px * var(--pe-escala, 1)); }
  .pg-monto { font-size: calc(16px * var(--pe-escala, 1)); }
  .pg-info { font-size: calc(16px * var(--pe-escala, 1)); }
  .panel-ganador .rake { font-size: calc(13px * var(--pe-escala, 1)); }
  .pg-cartas { gap: calc(8px * var(--pe-escala, 1)); }
  .pg-cartas .carta { width: calc(50px * var(--pe-escala, 1)); }
  /* SHOWDOWN PAGADO (Raul 2026-08-05, fix "no se ven las cartas de
     todos" en apaisado): el abanico del HEROE (82px, solape -45) vivia
     con el centro TAPADO por su propia placa y el borde bajo el filo
     de pantalla con el panel + premio (medido a 932x430). Con la mano
     completa (.mesa-wrap.showdown, clase del template) el heroe pasa
     al MISMO formato que los villanos revelados: 55px SOBRE la placa,
     abanico +-10. Solo apaisado; desktop y portrait ya se veian. */
  .mesa-wrap.showdown .asiento.mio .cartas { --carta-w: calc(55px * var(--pe-escala, 1)); top: calc(-45px * var(--pe-escala, 1)); bottom: auto; }
  .mesa-wrap.showdown .asiento.mio .cartas .carta, .mesa-wrap.showdown .asiento.mio .cartas .carta:first-child { transform: rotate(-10deg) translateY(calc(5px * var(--pe-escala, 1))); margin-right: calc(-16px * var(--pe-escala, 1)); margin-left: 0; }
  .mesa-wrap.showdown .asiento.mio .cartas .carta:last-child:not(:first-child) { transform: rotate(10deg) translateY(calc(5px * var(--pe-escala, 1))); margin-right: 0; margin-left: 0; }
  /* filas del anillo PE (game.js COMPACTO): mas arriba => z mayor */
  .asiento[style*="top: 88%"] { z-index: 6; }
  .asiento[style*="top: 66%"] { z-index: 7; }
  .asiento[style*="top: 36%"] { z-index: 8; }
  .asiento[style*="top: 16%"] { z-index: 9; }
  /* NUDGES de PE (su mobile.css visual-N, en px: escalan como todo).
     Lote asientos-al-borde (Raul 2026-08-05): laterales ya clavados al
     borde por ancla (x0/100, game.js) — sus nudges horizontales mueren,
     el vertical -10 de la fila 36 queda. Esquinas 88: +14 -> +17 (aire
     >=8px cartas-vs-pila a 844). Tops 16: -3px vertical (mas arriba;
     tope: reveal a 2.6px del filo a 932x430). Heroe: +18 mas un termino
     SOLO en dvh corto (430-100dvh)*.15 — a 844x390 el aire pila-heroe
     era 3.3px y el filo de pantalla a 932 no deja bajarlo parejo. */
  /* heroe +18 -> +30 (lote heroe-land): las cartas ya no cuelgan bajo la
     placa, asi que el asiento baja el hueco liberado y el abanico
     anclado arriba no toca la pila del pote (aire medido con 9 en mano
     en river: 3.7 / 7.1 / 4.1 px a 844x390 / 932x430 / 915x412). */
  .asiento.mio { transform: translate(-50%, calc(-50% + 30px * var(--pe-escala, 1) + max(0px, (430px - 100dvh) * .15))); }
  .asiento[style*="left: 28%"][style*="top: 88%"] { transform: translate(calc(-50% - 16px * var(--pe-escala, 1)), calc(-50% + 17px * var(--pe-escala, 1))); }
  .asiento[style*="left: 0%"][style*="top: 36%"] { transform: translate(-50%, calc(-50% - 10px * var(--pe-escala, 1))); }
  .asiento[style*="left: 31%"][style*="top: 16%"] { transform: translate(calc(-50% - 8px * var(--pe-escala, 1)), calc(-50% - 3px * var(--pe-escala, 1))); }
  .asiento[style*="left: 69%"][style*="top: 16%"] { transform: translate(calc(-50% + 8px * var(--pe-escala, 1)), calc(-50% - 3px * var(--pe-escala, 1))); }
  .asiento[style*="left: 100%"][style*="top: 36%"] { transform: translate(-50%, calc(-50% - 10px * var(--pe-escala, 1))); }
  .asiento[style*="left: 72%"][style*="top: 88%"] { transform: translate(calc(-50% + 16px * var(--pe-escala, 1)), calc(-50% + 17px * var(--pe-escala, 1))); }
}

/* ===== PORTRAIT v3 (2026-08-04): mesa grande con el estilo nuevo. La
   zona inferior (tabs + barra) flota sobre el paño (misma compactacion
   que hizo viable el landscape) y el ovalo pasa de 66vw a ancho
   COMPLETO, con tope de alto para que el rail del heroe (y96 + media
   placa) quede sobre la zona flotante en pantallas cortas. Cartas y
   board conservan su tamaño EN PIXELES de la mesa 66vw (cqw x0.66):
   lo que crece es el paño y el aire entre placas — la placa 8.7rem
   LEGIBLE no se toca. Anclas nuevas en game.js (MOVIL portrait-v3). */
@media (orientation: portrait) {
  .zona-inferior { position: fixed; left: 0; right: 0; bottom: 0; z-index: 35; }
  .tabs { background: rgba(15, 21, 30, .92); }
  /* lote portrait-aire (Raul 2026-08-05): mesa MAS CHICA (94vw*.67, era
     100vw*.71) con asientos hacia los bordes (anclas en game.js MOVIL):
     margen oscuro visible y aire entre placas. Cartas/fichas un toque
     mas grandes EN PIXELES (el cqw se recalibro sobre la mesa menor). */
  /* lote mesa-grande (Raul 2026-08-05): wrap ANCLADO ARRIBA (el centrado
     regalaba ~84px sobre el ovalo en dvh cortos) y factor .67 -> .815:
     el maximo medido con 9 en mano a 390x664 (Safari iOS con barra:
     100dvh real, NO el 844 de DevTools). El margen 23px recibe el
     abanico de la fila top (y4) sin tocar .mesa-top. */
  .mesa-zona { align-items: flex-start; }
  /* margen superior: 23px mientras el alto manda (dvh <= 714, wrap
     limitado por (dvh-255)*.815); cuando el 96vw capea el ancho y sobra
     alto, crece hasta 88px para re-centrar el ovalo (medido: a 844 deja
     ~65px de aire arriba y abajo en vez de 130 abajo). */
  .mesa-wrap { width: min(96vw, calc((100dvh - 255px) * .815)); margin-top: clamp(23px, calc(100dvh * .5 - 334px), 88px); }
  /* esquinas inferiores CLAVADAS al borde de pantalla (placa a 2px), no
     al % del wrap: con dvh corto el wrap se angosta y el % las apretaba
     contra el abanico del heroe (50vw - 50cqw = margen lateral del wrap
     centrado). Lote bordes 2026-08-06 (Raul): las filas del MEDIO (22 y
     66) tambien van clavadas al borde — con el % del wrap quedaban mas
     adentro que las filas de arriba y abajo. El resto sigue en %. */
  .asiento[style*="top: 86%"][style*="left: 19.7%"],
  .asiento[style*="top: 66%"][style*="left: 19.7%"],
  .asiento[style*="top: 22%"][style*="left: 19.7%"] { left: calc(74px - 50vw + 50cqw) !important; }
  .asiento[style*="top: 86%"][style*="left: 80.3%"],
  .asiento[style*="top: 66%"][style*="left: 80.3%"],
  .asiento[style*="top: 22%"][style*="left: 80.3%"] { left: calc(50cqw + 50vw - 74px) !important; }
  /* placa +4.8px SOLO portrait: "jugador-numero" (14 chars) quedaba a
     1px de entrar y el ellipsis se comia ~3 letras (medido) */
  .placa { width: 9rem; }
  .asiento { --carta-w: 9cqw; }
  .asiento.mio { --carta-w: 12cqw; }
  .asiento .cartas:has(.cara) { --carta-w: 12cqw; }
  /* lote board-max 2026-08-05: filas del medio abiertas del todo
     (22 / 66) y board casi de borde a borde del paño (~86% de ancho:
     5x17cqw + gaps), pila 5.5cqw y apuesta 1.6rem — MAXIMO medido sin
     pisadas con mesa llena en mano y showdown (fixture 390/360) */
  .centro { top: 27%; }
  /* board al TECHO de 90% del paño (Raul 2026-08-05): gap .38 -> .15
     y carta 17 -> 17.85cqw (5x17.85 + 4x.15 = 89.85cqw); el alto extra
     salio de bajar la fila inferior 66 -> 67 (sin achicar cartas de
     jugadores: no hizo falta, medido) */
  .board { gap: .15cqw; }
  .board .carta { width: 17.85cqw; }
  /* fichas del POTE mas grandes solo portrait (el default 2.3cqw sobre
     una mesa de ~340-367px quedaba de 8px) */
  .pot-pila .pila-chip { --pila-chip-d: 5.5cqw; }
}
/* lote mesa-grande: a 360 (Android) la carta REVELADA de 12cqw no entra
   entre las placas fijas de 9rem (144*2 + abanico > 360px) y el reveal
   de la fila 22 rozaba las placas del tope. Solo ahi baja a 11cqw; el
   iPhone 390 conserva 12cqw (medido con 9 en mano, river y showdown). */
@media (orientation: portrait) and (max-width: 379px) {
  .asiento.mio { --carta-w: 11cqw; }
  .asiento .cartas:has(.cara) { --carta-w: 11cqw; }
}

/* --- OMAHA: 4 cartas con las medidas de PE y rotacion CERO ---
   (lote abanico-4c, 2026-08-06; reemplaza al reparto compacto de v412)
   Los parametros del abanico (+-7 grados, solape 45%) son de 2 cartas.
   Con 4: rotacion CERO (Raul) y el ANCHO DEL CONJUNTO atado al asiento,
   que mide lo mismo que la placa en desktop y portrait (medido:
   asientoW == placaW) y 128 de los 144 de la placa en mobile-landscape
   (89%: el equivalente proporcional). El reparto sale de la formula
   (100% - 4*carta) / 3, asi cada contexto (dorso/cara, heroe/villano,
   los tres layouts) queda EXACTO sin duplicar anchos por breakpoint.
   Referencia PE (leida de su cards.css): villano Omaha 69x98 con avance
   de 30px sobre carta de 69 = 43% visible, conjunto ~100% de su placa.
   Solo con 4 cartas (:nth-last-child(4)): Hold'em queda intacto. */
.asiento .cartas:has(.carta:first-child:nth-last-child(4)) { width: 100%; justify-content: center; }
.asiento .cartas .carta:first-child:nth-last-child(4) { --rot-fin: 0deg; transform: rotate(var(--rot-fin)); }
.asiento .cartas .carta:first-child:nth-last-child(4) ~ .carta {
  --rot-fin: 0deg;
  margin-left: calc((100% - 4 * var(--carta-w)) / 3);
  transform: rotate(var(--rot-fin));
  transform-origin: bottom center;
}
/* PORTRAIT al 66% de la placa: es el UNICO entorno donde el ancho de
   placa no entra — los asientos contiguos estan mas cerca que la placa
   y a 100% las cartas invadian la placa vecina 23px POR LADO (medido).
   PE usa 65% en mobile, misma conclusion. */
@media (orientation: portrait) {
  .asiento .cartas:has(.carta:first-child:nth-last-child(4)) { width: 66%; }
}
/* DESKTOP: carta de villano (dorsos) a los 69px de PE. El bloque
   desktop usa --carta-w: 6.53cqw = 58.8px (1cqw = 9px, el mismo
   contenedor que la placa de 19.4cqw = 174.6): 69px son 7.67cqw.
   Solo desktop (landscape con alto real): mobile-landscape tiene su
   propio bloque y conserva su tamaño. */
@media (orientation: landscape) and (min-height: 501px) {
  .asiento:not(.mio) .cartas:not(:has(.cara)):has(.carta:first-child:nth-last-child(4)) { --carta-w: 7.67cqw; }
}
/* LANDSCAPE (lote indice-omaha-land, 2026-08-07; cierra el PENDIENTE):
   con el conjunto atado al asiento (128px < placa 144px) el avance
   quedaba en 24-29% del ancho y el indice se cortaba (medido: heroe
   29.7%). Solo FASE DE JUEGO (:not(.showdown); las reveladas de 55px
   del showdown ya se ven bien) y solo con 4 cartas: avance FIJO del 40%
   del ancho de carta — el indice de esquina entra completo en las 4 —
   y se anulan los margenes PE de 2 cartas (-45 heroe / -16 villano) que
   se colaban en el reparto. El conjunto del heroe se ENSANCHA (82px se
   conserva; 82+3*33=181px centrados sobre la placa, con aire a las
   placas de las esquinas medido con 9 en mano) y el de villanos queda
   en 42+3*17=93px, mas angosto que los 128 de antes. Verificado a
   932x430, 844x390 y 915x412: visible=[0.4,1] en mano, cero solapes/
   recortes; el showdown queda intacto. */
@media (orientation: landscape) and (max-height: 500px) {
  /* flex: none — sin el, el conjunto que excede el contenedor (heroe:
     181 > 144) encoge las cartas por flex-shrink en vez de desbordar
     centrado (medido: 82 -> 72.75) */
  .mesa-wrap:not(.showdown) .asiento.mio .cartas .carta:first-child:nth-last-child(4) { margin-right: 0; margin-left: 0; flex: none; }
  .mesa-wrap:not(.showdown) .asiento.mio .cartas .carta:first-child:nth-last-child(4) ~ .carta { margin-right: 0; margin-left: calc(-49px * var(--pe-escala, 1)); flex: none; } /* avance 33px = 40% de 82 */
  .mesa-wrap:not(.showdown) .asiento:not(.mio) .cartas:not(:has(.cara)) .carta:first-child:nth-last-child(4) { margin-right: 0; margin-left: 0; flex: none; }
  .mesa-wrap:not(.showdown) .asiento:not(.mio) .cartas:not(:has(.cara)) .carta:first-child:nth-last-child(4) ~ .carta { margin-right: 0; margin-left: calc(-25px * var(--pe-escala, 1)); flex: none; } /* avance 17px = 40% de 42 */
}

/* --- CROMO fuera del alcance de los abanicos (lote cromo, 2026-08-06;
   acotado a DESKTOP el mismo dia)
   Los 3 botones de mesa (rebuy / levantarse / volver al lobby) pasan a
   ICONOS en columna vertical, sin texto, al costado derecho del ovalo.
   La posicion NO es inventada: se sondeo un rectangulo de 44x140
   contra todas las cartas, placas y el board con 9 jugadores en OMAHA
   (el abanico mas ancho), en mano y en showdown: en desktop la columna
   queda libre en centro-der. SOLO desktop: en mobile (portrait y
   landscape) estos 3 botones ya vivian en el menu hamburguesa
   (.controles-mesa, entradas .solo-movil) y ahi se quedan; la columna
   se oculta. */
.acciones-mesa { position: fixed; right: 6px; top: 50%; transform: translateY(-50%); z-index: 46; display: flex; flex-direction: column; gap: .3rem; }
.acciones-mesa button {
  width: 44px; height: 44px; min-height: 44px; padding: 0; margin: 0;
  font-size: 1.25rem; line-height: 1; border-radius: 10px;
  background: rgba(8, 12, 17, .88); border: 1px solid rgba(255, 255, 255, .18);
  color: var(--azul); box-shadow: 0 2px 6px rgba(0, 0, 0, .5);
}
.acciones-mesa button:hover { border-color: var(--oro); color: var(--oro); }
@media (orientation: portrait) {
  /* mobile: los 3 botones viven en el menu hamburguesa, como antes */
  .acciones-mesa { display: none; }
}
@media (orientation: landscape) and (max-height: 500px) {
  /* mobile: los 3 botones viven en el menu hamburguesa, como antes */
  .acciones-mesa { display: none; }
  /* Lote header-land (2026-08-07): a top:2px el ☰ pisaba el texto del
     header fixed ("Poker Saldo:..." quedaba cortado). Orden VERTICAL:
     header arriba (termina en y24), ☰ debajo (y27-71) y el titulo al
     COSTADO del ☰ — absolute para que el bbox del contenedor quede del
     ancho del boton (el rect muerto ☰+titulo tocaba 2px la carta
     revelada del lateral nudgeado a 844x390, medido) y nowrap porque
     hereda los 44px del contenedor y quebraba en dos lineas. Titulo en
     y27-43: la carta mas cercana arranca en y68 (con nudge -10). */
  .mesa-top { top: 27px; left: 4px; }
  /* landscape: el titulo COMPLETO (nombre + leyendas) a la derecha del ☰,
     apilado en el margen oscuro; ya no solo el mesa-id. */
  .mesa-top .mesa-titulo { position: absolute; left: 52px; top: 0; flex-direction: column; align-items: flex-start; gap: 0; }
  .mesa-top .mesa-id { white-space: nowrap; }
}

/* Leyenda de bots (SPEC-BOTS.md Fase 2). Aviso visible de que la mesa
   tiene bots, en el lobby (tarjeta) y en la mesa (banner superior). */
.bots-aviso {
  /* leyenda VISIBLE en la tarjeta (antes solo emoji + title): linea
     propia bajo el nombre, mismo patron que .ficha-leyenda */
  display: block;
  color: #d4af37;
  font-weight: 600;
  font-size: 0.72rem;
}
/* Contenedor de las leyendas flotantes de la mesa (bots + valor de la
   ficha): columna centrada en top:44 — debajo de .mesa-top (~36px en
   flujo; a 390x844 la banda y0-36 del section es del nombre de mesa) y
   sin pelearse entre si cuando estan las dos (mesas FUN de bots). */
.leyendas-mesa {
  position: absolute;
  top: 44px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 30;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  pointer-events: none;
}
.bots-leyenda {
  background: rgba(0, 0, 0, 0.65);
  color: #d4af37;
  border: 1px solid #d4af37;
  border-radius: 999px;
  padding: 2px 12px;
  font-size: 0.8em;
  font-weight: 600;
  white-space: nowrap;
}
/* Valor de la ficha, SIEMPRE visible (tambien 1:1). Neutra a proposito:
   el dorado es de la leyenda de bots. */
.ficha-leyenda-mesa {
  background: rgba(0, 0, 0, 0.65);
  color: var(--texto-suave, #9fb0c3);
  border: 1px solid var(--borde);
  border-radius: 999px;
  padding: 1px 10px;
  font-size: 0.75em;
  white-space: nowrap;
}

/* Leyenda de fichas (PLAN-RUTA.md 2): "1 ficha = X MONEDA" en la fila
   del lobby. SIEMPRE visible (2026-08-10), tambien 1:1; en la mesa vive
   .ficha-leyenda-mesa dentro de .leyendas-mesa. */
.ficha-leyenda {
  color: #d4af37;
  font-size: 0.8em;
  font-weight: 600;
  white-space: nowrap;
}
/* ----- lobby v2: branding por agent + estado vacio con salida ----- */
:root { --brand-primary: var(--verde); --brand-accent: var(--azul); }
.marca-logo { height: 1.3em; vertical-align: -0.25em; margin-right: .4em; border-radius: 4px; }
header h1 { color: var(--brand-primary); }
.lobby-cta { display: inline-block; margin-left: .8em; padding: .35em .9em; border: none; border-radius: 8px; background: var(--brand-accent); color: #fff; font-weight: 700; cursor: pointer; }
.lobby-cta:hover { filter: brightness(1.1); }
.lobby-grupo.resaltado { outline: 2px solid var(--brand-accent); border-radius: 8px; transition: outline .3s; }

/* ----- privadas de player (2026-08-10): modales crear / mis privadas ----- */
.lobby-privadas { display: flex; gap: .5em; }
.lobby-privadas button { padding: .3em .8em; border: none; border-radius: 8px; background: var(--brand-accent); color: #10141a; font-weight: 700; cursor: pointer; }
.modal-fondo { position: fixed; inset: 0; z-index: 60; background: rgba(0, 0, 0, .55); display: flex; align-items: center; justify-content: center; padding: 1em; }
.modal-caja { background: var(--panel, #141b24); border: 1px solid rgba(255,255,255,.14); border-radius: 12px; padding: 1em 1.2em; max-width: 26em; width: 100%; max-height: 90vh; overflow-y: auto; display: flex; flex-direction: column; gap: .55em; }
.modal-caja h3 { margin: 0 0 .2em; }
.modal-caja label { display: flex; justify-content: space-between; align-items: center; gap: .8em; font-size: .9em; }
.modal-caja input, .modal-caja select { width: 11em; padding: .35em .5em; background: var(--fondo, #0b0f14); color: inherit; border: 1px solid rgba(255,255,255,.18); border-radius: 6px; }
.modal-acciones { display: flex; gap: .5em; justify-content: end; margin-top: .3em; }
.modal-acciones .primario { background: var(--brand-accent); color: #10141a; font-weight: 700; border: none; }
.modal-acciones button { padding: .4em .9em; border-radius: 8px; border: 1px solid rgba(255,255,255,.2); background: none; color: inherit; cursor: pointer; }
.priv-item { border-top: 1px solid rgba(255,255,255,.1); padding-top: .5em; margin-top: .3em; }
/* .priv-link/.priv-qr/.priv-sin retiradas 2026-08-18: la UI de
   invitacion por token se fue (la entrada es por clave) */
.priv-error { color: #f87171; margin: 0; }

/* ---------- Torneos S&G (lote 6) ---------- */
/* tarjetas de la pestaña Sit & Go del lobby: una por torneo, apiladas */
.sng-lista { display: flex; flex-direction: column; gap: .7rem; }
.sng-card {
  background: var(--panel, #141b26);
  border: 1px solid var(--borde, #2a3648);
  border-radius: 10px;
  padding: .8rem .9rem;
}
.sng-head { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin-bottom: .45rem; }
.estado-sng {
  font-size: .72rem; text-transform: uppercase; letter-spacing: .08em;
  border-radius: 999px; padding: 2px 10px; border: 1px solid var(--borde, #2a3648);
}
.estado-sng.sng-registering { color: #22c55e; border-color: #22c55e; }
.estado-sng.sng-running { color: #d4af37; border-color: #d4af37; }
.sng-datos { display: flex; gap: .4rem 1.2rem; flex-wrap: wrap; font-size: .85rem; color: var(--texto-suave, #9fb0c3); margin-bottom: .55rem; }
.sng-datos strong { color: var(--texto, #e8eef6); }
.sng-acciones { display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; }
.sng-alta { background: var(--verde); color: #0b1016; font-weight: 700; }
.sng-alta:disabled { opacity: .45; cursor: not-allowed; }
.sng-baja { border-color: #b0413e; color: #e08886; }
.sng-ok { color: #22c55e; font-size: .85rem; font-weight: 600; }

/* banner de estado del torneo en la mesa (junto a las otras leyendas) */
.torneo-banner {
  background: rgba(0, 0, 0, 0.65);
  color: #d4af37;
  border: 1px solid #d4af37;
  border-radius: 999px;
  padding: 2px 12px;
  font-size: 0.8em;
  font-weight: 600;
  white-space: nowrap;
}

/* ---- Loader pre-login con marca (entrada de master/launch) ---- */
.cargando { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1rem; padding: 1rem; }
.cargando-logo { max-width: min(60vw, 220px); max-height: 25vh; border-radius: 12px; }
.cargando-titulo { font-size: 1.5rem; margin: 0; color: var(--brand-primary); text-align: center; }
.cargando-texto { color: var(--azul); font-size: .85rem; margin: 0; }
.cargando-puntos { display: flex; gap: .45rem; }
.cargando-puntos span { width: 9px; height: 9px; border-radius: 50%; background: var(--brand-accent); animation: carga-pulso 1.2s infinite ease-in-out; }
.cargando-puntos span:nth-child(2) { animation-delay: .2s; }
.cargando-puntos span:nth-child(3) { animation-delay: .4s; }
@keyframes carga-pulso { 0%, 80%, 100% { opacity: .25; transform: scale(.8); } 40% { opacity: 1; transform: scale(1); } }

/* ---- Header en PORTRAIT (lote 2026-08-15): el SALDO se ve COMPLETO y
   todo lo demas cede espacio. SOLO portrait: desktop y landscape quedan
   exactamente como estaban. ---- */
@media (orientation: portrait) {
  /* identidad: CON logo (mide 20px fijos) el titulo de largo arbitrario
     se oculta; SIN logo el titulo queda (fallback obligatorio: nunca un
     header sin identidad) y se elipsa antes que empujar al saldo */
  header h1 { flex: 0 1 auto; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
  header h1.con-logo .titulo-texto { display: none; }
  /* saldo: sin la etiqueta Saldo/Balance y sin truncarse jamas */
  header .saldo-etiqueta { display: none; }
  header .saldos { flex: 0 0 auto; overflow: visible; }
  /* idioma: la bandera SIEMPRE, en las tres vistas, y sin el codigo al
     lado. Razon (Raul 2026-08-15): el selector no puede depender de
     entender la interfaz — el del perfil esta detras de un avatar sin
     etiqueta, y hay agents con default_locale 'en' que te dejan en un
     idioma que no elegiste. Emblema de ancho fijo: no cede. */
  header .idioma-codigo { display: none; }
  header .idioma-selector { flex: none; }
  /* PRIORIDAD DE ANCHO: 1) saldo completo siempre (flex none), 2)
     bandera fija, 3) el NICK cede primero — flex-shrink altisimo en su
     rama y cadena min-width:0 hasta el span: se recorta con elipsis y,
     si no entra ni recortado, colapsa hasta desaparecer. Recien despues
     cede el titulo (h1, shrink 1). */
  header .idiomas { min-width: 0; flex-shrink: 999; }
  header .usuario-menu { min-width: 0; }
  header .usuario-boton { min-width: 0; max-width: 100%; font-size: .68rem; }
  header .usuario-nombre { min-width: 0; }
}
