/* El arte viaja en AVIF con respaldo WebP, así que cada imagen va envuelta en
   un <picture>. Ese envoltorio no debe existir para la maquetación: sin esto,
   la imagen dejaría de ser hija directa de la tarjeta y perdería su hueco. */
picture { display: contents; }

:root {
  color-scheme: dark;
  --bg: #10131a;
  --panel: #171b24;
  --line: #262c39;
  --text: #e6e9ef;
  --muted: #8b93a5;
  --ok: #3ecf8e;
  --warn: #e5b567;
  --bad: #e5605e;
  --accent: #5b8def;
  --gold: #f2c14e;
}

* { box-sizing: border-box; }

/* Foco siempre visible: la sala se recorre entera con el teclado y sin anillo
   no se sabe dónde se está apostando. */
:focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 2px;
  border-radius: 4px;
}

/* El enlace de salto solo aparece al tabular, pero entonces debe verse. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 8px;
  z-index: 100;
  padding: 10px 14px;
  background: var(--gold);
  color: #1a1206;
  font-weight: 700;
  text-decoration: none;
  border-radius: 6px;
}

.skip-link:focus { left: 8px; }

.noscript {
  margin: 16px 20px;
  padding: 14px 16px;
  border: 1px solid var(--warn);
  border-radius: 8px;
  background: rgba(229, 181, 103, .12);
  color: var(--text);
  line-height: 1.6;
}

.noscript a { color: var(--gold); }

body {
  margin: 0;
  font: 14px/1.5 system-ui, -apple-system, "Segoe UI", sans-serif;
  background: var(--bg);
  color: var(--text);
}

header {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 20px;
  border-bottom: 1px solid var(--line);
  background: var(--panel);
}

header h1 { font-size: 17px; margin: 0; flex: 1; }

nav {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  padding: 10px 20px;
  border-bottom: 1px solid var(--line);
}

nav button {
  background: transparent;
  border: 1px solid transparent;
  color: var(--muted);
}

nav button.active { color: var(--text); border-color: var(--line); background: var(--panel); }

main { padding: 20px; max-width: 1200px; }

button {
  cursor: pointer;
  border-radius: 6px;
  border: 1px solid var(--line);
  background: var(--accent);
  /* Texto oscuro sobre el azul y el rojo: en blanco el contraste se queda en
     3,2:1 y el texto de los botones deja de leerse con luz ambiente. */
  color: #081226;
  padding: 7px 12px;
  font: inherit;
}

button.ghost { background: transparent; color: var(--muted); }
button.danger { background: var(--bad); color: #1f0505; }
button:disabled { opacity: .5; cursor: not-allowed; }

input, select, textarea {
  background: #0d1017;
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 7px 9px;
  font: inherit;
  width: 100%;
}

textarea { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; }

label { display: block; margin-bottom: 10px; color: var(--muted); }
label input, label select, label textarea { margin-top: 4px; color: var(--text); }

.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 16px;
  margin: 16px 0;
  max-width: 640px;
}

/* Sin esto, cualquier display explícito (por ejemplo .row) gana al atributo
   hidden y los controles ocultos siguen viéndose. */
[hidden] { display: none !important; }

.row { display: flex; gap: 8px; align-items: flex-end; flex-wrap: wrap; margin: 12px 0; }
.row label { margin: 0; }

.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(190px, 100%), 1fr)); gap: 10px; }

.metric {
  background: var(--panel);
  border: 1px solid var(--line);
  border-left: 3px solid var(--ok);
  border-radius: 8px;
  padding: 10px 12px;
}

.metric.warn { border-left-color: var(--warn); }
.metric.bad { border-left-color: var(--bad); }
.metric b { display: block; font-size: 22px; }
.metric span { color: var(--muted); font-size: 12px; }

table { width: 100%; border-collapse: collapse; margin: 10px 0; font-size: 13px; }
th, td { text-align: left; padding: 7px 9px; border-bottom: 1px solid var(--line); vertical-align: top; }
th { color: var(--muted); font-weight: 600; }
tr[data-clickable] { cursor: pointer; }
tr[data-clickable]:hover { background: var(--panel); }

.output {
  background: #0d1017;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 12px;
  overflow: auto;
  max-height: 380px;
  font-size: 12.5px;
  white-space: pre-wrap;
  word-break: break-word;
}

/* El aviso flota: si empujara el contenido, al desaparecer subiría el layout y
   un clic ya apuntado a un botón caería en vacío. */
.msg {
  position: fixed;
  top: 14px;
  right: 14px;
  z-index: 20;
  max-width: 380px;
  padding: 10px 12px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--panel);
  box-shadow: 0 6px 18px rgba(0, 0, 0, .45);
}
.msg.ok { border-color: var(--ok); color: var(--ok); }
.msg.err { border-color: var(--bad); color: var(--bad); }
.msg.warn { border-color: var(--warn); color: var(--warn); }

.muted { color: var(--muted); }
.pill { border: 1px solid var(--line); border-radius: 999px; padding: 1px 8px; font-size: 12px; }
.pill.ok { color: var(--ok); border-color: var(--ok); }
.pill.warn { color: var(--warn); border-color: var(--warn); }
.pill.bad { color: var(--bad); border-color: var(--bad); }

code { background: #0d1017; padding: 1px 5px; border-radius: 4px; }

/* ---------------------------------------------------------------------------
   Mesa de juego. El jugador no debería tener que leer JSON para saber si ha
   ganado: la rueda, los rodillos y las cartas son la interfaz, y el JSON queda
   detrás de <details> para quien quiera auditar la jugada.
   --------------------------------------------------------------------------- */

.bankroll {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 10px 14px;
  font-size: 15px;
}

.bankroll strong { font-size: 20px; }

/* El sprite vive en el documento (Chrome no resuelve <use> contra otro
   fichero) y no debe ocupar sitio ni leerse. */
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

.ico { width: 20px; height: 20px; vertical-align: -4px; }
.chip-icon { width: 30px; height: 30px; flex: none; filter: drop-shadow(0 2px 3px rgba(0, 0, 0, .5)); }

.game-tabs { padding: 10px 0; border: 0; }
.game-tabs button { font-size: 15px; padding: 8px 16px; display: inline-flex; align-items: center; gap: 8px; }
.game-tabs button .ico { vertical-align: 0; }

/* Carril de fichas: la pila del jugador, lo que hay en el tapete y cómo va la
   sesión, con fichas de verdad en vez de tres cifras sueltas. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.chip-rail {
  display: flex;
  gap: 10px;
  align-items: stretch;
  flex-wrap: wrap;
  margin: 0 0 12px;
  padding: 10px 14px;
  border: 1px solid #27402f;
  border-radius: 12px;
  background:
    radial-gradient(ellipse at 50% 120%, rgba(255, 233, 168, .10), transparent 60%),
    linear-gradient(180deg, #16321f, #11241a);
}

.rail-slot {
  display: grid;
  grid-template-rows: auto 1fr auto;
  justify-items: center;
  align-content: end;
  gap: 2px;
  min-width: 104px;
  flex: 1 1 104px;
}

.rail-slot b { font-size: 18px; }
.rail-slot b.up { color: var(--ok); }
.rail-slot b.down { color: var(--bad); }
.rail-label { font-size: 12px; color: var(--muted); text-align: center; }

.rail-bet {
  border-left: 1px dashed #2f5a3f;
  border-right: 1px dashed #2f5a3f;
}

.pile {
  position: relative;
  width: 60px;
  height: 104px;
  align-self: end;
}

/* El hueco de apuesta se ve aunque esté vacío: así el jugador sabe dónde
   aterrizan sus fichas antes de poner la primera. */
.rail-bet .pile::after {
  content: "";
  position: absolute;
  left: 8px;
  bottom: 0;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px dashed rgba(242, 193, 78, .45);
}

.chip {
  position: absolute;
  left: 14px;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  box-shadow: 0 2px 3px rgba(0, 0, 0, .5), inset 0 -4px 6px rgba(0, 0, 0, .35);
  background:
    radial-gradient(circle at 50% 42%, rgba(255, 255, 255, .22), transparent 42%),
    repeating-conic-gradient(rgba(255, 255, 255, .85) 0 12deg, transparent 12deg 45deg),
    radial-gradient(circle, #6b7280 0 58%, transparent 58%),
    #6b7280;
}

.chip.d1 { --tone: #dfe4ec; }
.chip.d5 { --tone: #c0392b; }
.chip.d10 { --tone: #2f6fd0; }
.chip.d25 { --tone: #1f9d55; }
.chip.d100 { --tone: #20242e; }

.chip.d1, .chip.d5, .chip.d10, .chip.d25, .chip.d100 {
  background:
    radial-gradient(circle at 50% 38%, rgba(255, 255, 255, .25), transparent 45%),
    repeating-conic-gradient(rgba(255, 255, 255, .9) 0 11deg, transparent 11deg 45deg),
    radial-gradient(circle, var(--tone) 0 60%, rgba(255, 255, 255, .9) 60%);
}

.chip.d100 {
  background:
    radial-gradient(circle at 50% 38%, rgba(255, 255, 255, .18), transparent 45%),
    repeating-conic-gradient(rgba(242, 193, 78, .95) 0 11deg, transparent 11deg 45deg),
    radial-gradient(circle, var(--tone) 0 60%, rgba(242, 193, 78, .95) 60%);
}

.chip.flying {
  position: fixed;
  z-index: 60;
  pointer-events: none;
  transition: transform .52s cubic-bezier(.2, .8, .3, 1);
}

.pile.swept .chip {
  transition: transform .4s ease-in, opacity .4s ease-in;
  transform: translateX(120px) rotate(28deg);
  opacity: 0;
}

@media (max-width: 420px) {
  .pile { height: 76px; width: 52px; }
  .chip { width: 26px; height: 26px; left: 13px; }
  .rail-slot { min-width: 86px; }
}

.stake-bar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 6px 0 14px; }
.stake-bar input { width: 110px; }
.chips { display: flex; gap: 6px; }

.chips button {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 40%, #2a3140, #1b2130);
  border: 2px dashed #3c4658;
  color: var(--text);
  padding: 0;
}

.chips button.active { border-color: #f2c14e; color: #f2c14e; }

.felt {
  display: flex;
  gap: 22px;
  flex-wrap: wrap;
  position: relative;
  overflow: hidden;
  background: radial-gradient(ellipse at 50% 0%, #1d4d38, #123424 70%);
  border: 1px solid #0d2419;
  border-radius: 14px;
  padding: 20px;
}

/* Foco de sala: una luz cálida barre el tapete muy despacio, lo justo para que
   la mesa parezca iluminada y no un rectángulo plano. */
.felt::before {
  content: "";
  position: absolute;
  inset: -40% -10%;
  pointer-events: none;
  background: radial-gradient(ellipse at 30% 0%, rgba(255, 233, 168, .16), transparent 55%);
  animation: felt-light 14s ease-in-out infinite alternate;
}

@keyframes felt-light {
  from { transform: translateX(-8%); opacity: .75; }
  to { transform: translateX(8%); opacity: 1; }
}

/* Atrezzo: las fichas viven en la esquina de la mesa, nunca sobre el juego ni
   bajo el dedo. Por debajo de 900 px no hay sitio y desaparecen. */
.felt-prop {
  position: absolute;
  right: 18px;
  bottom: -12px;
  width: auto;
  height: 230px;
  pointer-events: none;
  opacity: .92;
  filter: drop-shadow(0 18px 22px rgba(0, 0, 0, .55));
}

@media (max-width: 900px) { .felt-prop { display: none; } }

.felt .play { background: #f2c14e; color: #201a08; font-weight: 600; padding: 10px 18px; }
.verdict { font-size: 15px; margin: 12px 0; }
.verdict.win { color: var(--ok); font-weight: 600; }
.verdict.lose { color: var(--bad); }

/* El consejo de jugada no compite con el veredicto: va debajo, en tono
   apagado, y se puede apagar porque a un jugador experto le estorba. */
.advice {
  margin: 0 0 6px;
  padding: 8px 12px;
  border-left: 3px solid var(--gold, #e3c477);
  background: rgba(227, 196, 119, .10);
  border-radius: 0 8px 8px 0;
  font-size: 14px;
  line-height: 1.35;
}
.advice-toggle {
  display: inline-flex;
  gap: 6px;
  align-items: center;
  margin: 0 0 10px;
  font-size: 13px;
  opacity: .8;
  cursor: pointer;
}

/* Ruleta */

.wheel-box { position: relative; width: 232px; text-align: center; }

/* El plato se inclina dentro de un escenario con perspectiva: así la rueda
   tiene fondo y la bola corre por el aro en vez de resbalar sobre un disco. */
.wheel-stage {
  position: relative;
  width: 232px;
  height: 196px;
  perspective: 760px;
  perspective-origin: 50% 20%;
}

.wheel-tilt {
  position: absolute;
  inset: 0;
  height: 232px;
  transform: rotateX(54deg);
  transform-style: preserve-3d;
  margin-top: -14px;
}

/* El cuenco: pared interior del plato, visible gracias a la inclinación. */
.wheel-stage::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 24px;
  width: 236px;
  height: 150px;
  transform: translateX(-50%);
  border-radius: 50%;
  background: radial-gradient(ellipse at 50% 35%, rgba(0, 0, 0, .65), rgba(0, 0, 0, .12) 70%, transparent);
  filter: blur(2px);
}

.wheel {
  width: 220px;
  height: 220px;
  border-radius: 50%;
  /* El aro imita metal torneado: anillos claros y oscuros alrededor del borde
     y sombra proyectada para que la rueda se despegue del tapete. */
  border: 6px solid #a2803a;
  position: absolute;
  inset: 0;
  margin: auto;
  transition: transform 3.2s cubic-bezier(.15, .7, .12, 1);
  box-shadow:
    inset 0 0 30px rgba(0, 0, 0, .75),
    inset 0 0 0 2px rgba(0, 0, 0, .55),
    0 0 0 2px #f7e3b0,
    0 0 0 5px #6d511a,
    0 14px 30px rgba(0, 0, 0, .55);
}

.wheel::after {
  content: "";
  position: absolute;
  inset: 33%;
  border-radius: 50%;
  background:
    radial-gradient(circle at 38% 32%, #ffeab3, #b5892c 55%, #6d511a);
  border: 3px solid #4a380f;
  box-shadow: inset 0 2px 6px rgba(255, 255, 255, .35), 0 3px 8px rgba(0, 0, 0, .5);
}

.wheel span {
  position: absolute;
  left: calc(50% - 10px);
  top: calc(50% - 10px);
  width: 20px;
  height: 20px;
  line-height: 20px;
  text-align: center;
  font-size: 10px;
  font-weight: 600;
  color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .8);
}

.wheel-pointer {
  position: absolute;
  top: 2px;
  left: calc(50% - 8px);
  width: 0;
  height: 0;
  border-left: 8px solid transparent;
  border-right: 8px solid transparent;
  border-top: 16px solid #f2c14e;
  z-index: 2;
}

.wheel-result { margin-top: 12px; font-size: 15px; }
.wheel-result.win { color: var(--ok); font-weight: 600; }
.wheel-result.lose { color: var(--bad); }

/* El tapete no puede imponer un ancho mínimo: con 320 px de pantalla, 320 px
   de tablero más el relleno del felt sacaban 353 px de documento y recortaban
   la última columna. Que encoja y, si no cabe, que se desplace solo él. */
.board { flex: 1 1 260px; min-width: 0; overflow-x: auto; }
/* El tapete con su forma real: el cero a la izquierda y tres filas de doce
   columnas. Entre casilla y casilla hay una pista estrecha, la raya, donde se
   ponen las fichas a caballo, los cuadros, las calles y las líneas. */
.numbers {
  display: grid;
  grid-template-columns: 0 minmax(22px, 1.4fr) repeat(12, 7px minmax(0, 1fr)) 7px;
  grid-template-rows: 7px repeat(3, minmax(26px, 1fr) 7px);
  gap: 0;
  min-width: 300px;
}

.numbers button { grid-column: var(--c); grid-row: var(--r); }

/* En el móvil el tapete se pone de pie, como en las mesas de las apps: doce
   filas de tres, que es la única forma de que entre entero en 320 px sin
   esconder la última columna detrás de un scroll que no se ve. */
@media (max-width: 460px) {
  .numbers {
    grid-template-columns: 7px repeat(3, minmax(0, 1fr) 7px);
    grid-template-rows: 0 minmax(26px, auto) repeat(12, 7px minmax(22px, 1fr)) 7px;
    min-width: 0;
  }
  .numbers button { grid-column: var(--r); grid-row: var(--c); }
  /* Con el tapete de pie las exteriores también tienen que encoger: dejarlas
     en 260 px cortaba "3ª docena" y "Columna 3" por la derecha. */
  .board .outside { grid-template-columns: repeat(3, minmax(0, 1fr)); min-width: 0; }
}

.numbers button, .outside button {
  /* Las casillas son rojas, negras y verdes: el texto oscuro de los botones
     generales sobre negro daría 1,1:1. */
  color: #fff;
  padding: 6px 2px;
  font-size: 12px;
  border-radius: 4px;
  border: 1px solid transparent;
}

.numbers button.red, .outside button.red { background: #b0202a; }
.numbers button.black, .outside button.black { background: #1b1b1b; }
.numbers button.green { background: #1b7f4b; }

/* Zonas de la raya: un rombo pequeño que se ve donde de verdad se pondría la
   ficha, con área de toque mayor que el dibujo para que se pueda usar en el
   móvil sin apuntar al píxel. */
.numbers button.spot {
  position: relative;
  width: 100%;
  min-width: 0;
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: 0;
  z-index: 2;
}

.numbers button.spot::before {
  content: "";
  position: absolute;
  inset: -3px;
  border-radius: 4px;
}

/* El cuadro y la línea están en el cruce de dos rayas, rodeados de caballos y
   calles: si no manda el cruce, un clic en su centro pone otra apuesta. */
.numbers button.spot-corner, .numbers button.spot-line { z-index: 4; }
.numbers button.spot-corner::before, .numbers button.spot-line::before { inset: -6px; }
/* El área de toque no puede salirse del tapete: en el borde añadía scroll y
   recortaba la ficha del último cruce de cada fila. */
.numbers button.spot-edge::before { inset-inline-end: 0; inset-block-end: 0; }

.numbers button.spot::after {
  content: "";
  position: absolute;
  inset: 50% auto auto 50%;
  width: 7px;
  height: 7px;
  transform: translate(-50%, -50%) rotate(45deg);
  background: rgba(255, 255, 255, .22);
  border-radius: 1px;
}

.numbers button.spot:hover::after,
.numbers button.spot:focus-visible::after { background: #f2c14e; }
.numbers button.spot:focus-visible { outline: 2px solid #8fd3ff; outline-offset: 0; }

/* Con ficha puesta, el rombo se convierte en la ficha y dice cuánto lleva. */
.numbers button.spot.has-chip::after {
  width: 18px;
  height: 18px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #f6dd9a, #c8972f 70%, #8a6316);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .55);
}

.numbers button.spot.has-chip::before {
  content: attr(data-chips);
  inset: 50% auto auto 50%;
  transform: translate(-50%, -50%);
  width: 18px;
  height: 18px;
  display: grid;
  place-items: center;
  font-size: 9px;
  font-weight: 700;
  color: #2b1d04;
  z-index: 3;
}

/* Con el dedo no se apunta al píxel: de pie, cada zona de la raya crece hasta
   donde puede sin pisar a la de al lado (17 px las de dos rayas, 27 px los
   cruces). Las guías de interfaz del sector piden 44 px, pero con 37 casillas
   en pantalla no caben: pasado este punto la zona empieza a comerse la casilla
   del número, que es donde cae la mayoría de los toques. */
@media (max-width: 460px) {
  .numbers button.spot::before { inset: -5px; }
  .numbers button.spot-corner::before, .numbers button.spot-line::before { inset: -10px; }
  .numbers button.spot-edge::before { inset-inline-end: 0; inset-block-end: 0; }
}

/* La ficha del último cruce de cada fila se dibuja hacia dentro: centrada
   sobre el borde del tapete se veía por la mitad. */
@media (max-width: 460px) {
  .numbers button.spot-edge::after,
  .numbers button.spot-edge.has-chip::after,
  .numbers button.spot-edge.has-chip::before {
    inset-inline-start: auto;
    inset-inline-end: 0;
    transform: translate(0, -50%);
  }
}
.numbers button.selected, .outside button.selected { border-color: #f2c14e; box-shadow: 0 0 0 2px rgba(242, 193, 78, .4); }

/* Las apuestas de fuera llevan etiqueta larga ("2ª docena", "Columna 3"): con
   seis columnas fijas se cortaban en pantallas estrechas, así que caben las que
   quepan y el texto puede ocupar dos líneas. */
.outside { display: grid; grid-template-columns: repeat(auto-fit, minmax(76px, 1fr)); gap: 3px; margin-top: 6px; min-width: 260px; }
.outside button { background: #21402f; white-space: normal; line-height: 1.2; min-height: 2.2rem; }

/* Tragamonedas */

/* Escaparate de máquinas: la elegida se ve elegida sin depender solo del
   color, por el borde y el relieve. */
.machines { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; width: 100%; margin-bottom: 12px; }
.machine-card { display: flex; flex-direction: column; align-items: center; gap: 2px; width: 150px; padding: 8px; text-align: center; background: rgba(0, 0, 0, .28); border: 2px solid rgba(255, 255, 255, .12); border-radius: 12px; color: inherit; cursor: pointer; }
.machine-card img { width: 100%; height: auto; border-radius: 8px; }
.machine-card .title { font-weight: 700; }
.machine-card .small { line-height: 1.25; }
.machine-card.active { border-color: #e3c477; box-shadow: 0 0 0 2px rgba(227, 196, 119, .35), 0 6px 18px rgba(0, 0, 0, .45); }
.machine-card:focus-visible { outline: 3px solid #8fd3ff; outline-offset: 2px; }
@media (max-width: 420px) { .machine-card { width: 100%; flex-direction: row; flex-wrap: wrap; align-items: flex-start; text-align: left; } .machine-card img { flex: 0 0 72px; width: 72px; } .machine-card > :not(img) { flex: 1 1 calc(100% - 82px); min-width: 0; overflow-wrap: anywhere; } }

.machine { text-align: center; }
.reels { display: flex; gap: 10px; justify-content: center; }

.reel {
  position: relative;
  width: 84px;
  height: 104px;
  border-radius: 10px;
  /* La carcasa es el hueco por el que se ve el tambor: dentro gira un cilindro
     de verdad, con sus caras en el espacio. */
  background: linear-gradient(180deg, #05070b, #1a2030 18%, #222a3c 50%, #151b28 82%, #05070b);
  border: 3px solid #7a5c1e;
  box-shadow: inset 0 0 14px rgba(0, 0, 0, .8), 0 4px 10px rgba(0, 0, 0, .45);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 34px;
  overflow: hidden;
  perspective: 420px;
}

.cyl {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  transition: transform .62s cubic-bezier(.16, .84, .24, 1);
}

.cyl .face {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  backface-visibility: hidden;
}

.cyl.spinning { animation: cyl-roll .72s linear infinite; }

@keyframes cyl-roll {
  from { transform: rotateX(0deg); }
  to { transform: rotateX(360deg); }
}

/* Luz de la carcasa: el tambor se oscurece arriba y abajo, donde se curva. */
.reel::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  border-radius: 7px;
  background: linear-gradient(180deg, rgba(0, 0, 0, .85), transparent 28%, rgba(255, 255, 255, .06) 48%, transparent 70%, rgba(0, 0, 0, .85));
}

.reel .sym { width: 62px; height: 62px; object-fit: contain; filter: drop-shadow(0 4px 6px rgba(0, 0, 0, .65)); }
.reel.hit { border-color: #ffe9a8; box-shadow: inset 0 0 14px rgba(0, 0, 0, .8), 0 0 18px rgba(242, 193, 78, .55); }
.sym-text { font-size: 28px; font-weight: 700; color: var(--gold); }

.paytable { min-width: 220px; font-size: 13px; }
.paytable div { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 3px 0; border-bottom: 1px solid rgba(255, 255, 255, .08); }
.pay-line { display: inline-flex; align-items: center; gap: 4px; }
.pay-line .sym.small { width: 24px; height: 24px; object-fit: contain; }
.pay-line em { font-style: normal; color: var(--muted); margin-left: 6px; }
.sym-any { width: 24px; text-align: center; color: var(--muted); }

/* Blackjack */

.bj { flex: 1; }
.hand { margin-bottom: 14px; }
.hand-label { display: block; color: #cfe6d8; margin-bottom: 6px; }
.cards { display: flex; gap: 8px; min-height: 96px; }

/* La carta vive en el espacio: reverso y frente son dos caras opuestas del
   mismo naipe, y repartir es voltearlo. */
.card3d { width: 66px; height: 96px; perspective: 720px; flex: none; }

.card-inner {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transform: rotateY(180deg);
}

.card3d.down .card-inner { transform: rotateY(0deg); }
.card-inner > * { backface-visibility: hidden; }

.card-back {
  position: absolute;
  inset: 0;
  border-radius: 8px;
  background:
    repeating-linear-gradient(45deg, rgba(255, 255, 255, .07) 0 6px, transparent 6px 12px),
    radial-gradient(circle at 50% 50%, #3a4d84, #1b2545 70%);
  border: 1px solid #16203a;
  box-shadow: 0 4px 10px rgba(0, 0, 0, .45), inset 0 0 0 3px rgba(242, 193, 78, .35);
}

.card-face {
  position: absolute;
  inset: 0;
  transform: rotateY(180deg);
  width: 66px;
  height: 96px;
  border-radius: 8px;
  background: linear-gradient(150deg, #fffdf6, #ece7d8);
  color: #17181c;
  border: 1px solid #cdc9bb;
  font-family: Georgia, "Times New Roman", serif;
  box-shadow: 0 4px 10px rgba(0, 0, 0, .45), inset 0 0 0 3px rgba(255, 255, 255, .7);
}

/* La carta real lleva el valor en las dos esquinas y el palo grande al centro:
   así se lee en abanico, con solo una esquina visible. */
.card-face .corner {
  position: absolute;
  display: flex;
  flex-direction: column;
  align-items: center;
  line-height: 1;
  font-size: 15px;
  font-weight: 700;
}

.card-face .corner i { font-style: normal; font-size: 12px; }
.card-face .corner.tl { top: 6px; left: 6px; }
.card-face .corner.br { bottom: 6px; right: 6px; transform: rotate(180deg); }

.card-face .suit {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 34px;
}

.card-face.red { color: #b0202a; }

details.tech { margin-top: 18px; }
details.tech summary { cursor: pointer; color: var(--muted); padding: 8px 0; }

/* ---------------------------------------------------------------------------
   Presentación de sala. La mesa tiene que verse como un casino y no como un
   panel de monitorización: paleta cálida sobre fondo oscuro, cifras grandes y
   una celebración cuando el premio es grande. Nada de esto oculta el RTP, los
   límites ni el detalle técnico: llamar la atención no es lo mismo que engañar.
   --------------------------------------------------------------------------- */

.hero {
  background:
    radial-gradient(circle at 12% 20%, rgba(242, 193, 78, .18), transparent 45%),
    radial-gradient(circle at 88% 10%, rgba(176, 32, 42, .22), transparent 45%),
    linear-gradient(160deg, #1b2130, #10131a);
  border: 1px solid #2c3446;
  border-radius: 16px;
  padding: 26px 24px;
  margin: 16px 0;
  max-width: 900px;
}

.hero h2 { margin: 0 0 8px; font-size: 26px; letter-spacing: .2px; }
.hero p { margin: 0 0 14px; color: var(--muted); max-width: 62ch; }

.pulse { display: flex; gap: 18px; flex-wrap: wrap; }
.pulse div { min-width: 96px; }
.pulse b { display: block; font-size: 20px; color: var(--gold); }
.pulse span { font-size: 12px; color: var(--muted); }

.hud {
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
  background: linear-gradient(120deg, #1c2233, #151925 60%);
  border: 1px solid #333c52;
  border-radius: 14px;
  padding: 14px 18px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05);
}

.hud-label { display: block; font-size: 11px; letter-spacing: .8px; text-transform: uppercase; color: var(--muted); }
.hud-unit { color: var(--muted); font-size: 12px; }
.hud-balance { display: flex; align-items: center; gap: 10px; }
.hud-balance strong { font-size: 30px; color: var(--gold); font-variant-numeric: tabular-nums; }
.hud-balance strong.bump { animation: bump .5s ease-out; }

@keyframes bump {
  0% { transform: scale(1); }
  40% { transform: scale(1.18); color: var(--ok); }
  100% { transform: scale(1); }
}

.hud-level { min-width: 190px; }
.xp-bar { height: 8px; border-radius: 999px; background: #0d1017; border: 1px solid var(--line); overflow: hidden; margin: 5px 0 3px; }
.xp-bar i { display: block; height: 100%; background: linear-gradient(90deg, #f2c14e, #e5605e); transition: width .6s ease; }

.hud-streak { display: flex; align-items: center; gap: 8px; }
.hud-streak strong { font-size: 22px; }
.flame { width: 26px; height: 26px; flex: none; }

/* El récord es una marca contra uno mismo: se enseña al lado de la racha y se
   ilumina solo cuando el jugador está en su máximo, para que la medalla
   signifique algo y no sea un adorno permanente. */
.hud-record { display: flex; align-items: center; gap: 8px; }
.hud-record strong { font-size: 22px; }
.hud-record .record-note { display: block; }
.medal { width: 26px; height: 26px; flex: none; filter: grayscale(.7) opacity(.65); }
.hud-record.at-top .medal { filter: none; animation: medal-shine 2.4s ease-in-out infinite; }

@keyframes medal-shine {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.12); }
}

@media (prefers-reduced-motion: reduce) {
  .hud-record.at-top .medal { animation: none; }
}

/* El reto de hoy se distingue de las misiones fijas con una franja, no con
   otro bloque: sigue siendo la misma lista. */
.mission.today { background: rgba(242, 193, 78, .08); border-left: 3px solid var(--gold); padding-left: 8px; }

.bonus-btn {
  background: linear-gradient(160deg, #ffd977, #e0a52c);
  color: #241c05;
  font-weight: 700;
  padding: 10px 18px;
  border-color: #b5892c;
  box-shadow: 0 0 0 0 rgba(242, 193, 78, .55);
  animation: bonus-pulse 2.2s ease-out infinite;
}

@keyframes bonus-pulse {
  0% { box-shadow: 0 0 0 0 rgba(242, 193, 78, .55); }
  70% { box-shadow: 0 0 0 14px rgba(242, 193, 78, 0); }
  100% { box-shadow: 0 0 0 0 rgba(242, 193, 78, 0); }
}

.sound { margin-left: auto; line-height: 0; padding: 8px 10px; color: var(--muted); }
.sound[aria-pressed="true"] { color: var(--gold); }

/* minmax(300px, …) obliga a la columna a medir 300 px aunque la pantalla sea
   más estrecha, y entonces es la rejilla la que desborda el documento. */
.engage { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); gap: 14px; margin: 14px 0; }
.engage h3 { margin: 0 0 10px; font-size: 15px; }

.missions, .community, .club {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 14px 16px;
}

.mission { display: grid; grid-template-columns: 1fr auto; gap: 4px 12px; align-items: center; padding: 8px 0; border-bottom: 1px solid var(--line); }
.mission:last-child { border-bottom: 0; }
.mission .title { font-size: 13px; }
.mission .track { grid-column: 1; height: 7px; border-radius: 999px; background: #0d1017; border: 1px solid var(--line); overflow: hidden; }
.mission .track i { display: block; height: 100%; background: linear-gradient(90deg, #3ecf8e, #f2c14e); transition: width .5s ease; }
.mission .reward { grid-row: span 2; text-align: right; }
.mission .reward b { color: var(--gold); display: block; }
.mission.done .title { color: var(--ok); }

.club-pitch { margin: 0 0 10px; font-size: 13px; color: var(--muted); }
.club-track { display: block; height: 9px; border-radius: 999px; background: #0d1017; border: 1px solid var(--line); overflow: hidden; margin-bottom: 6px; }
.club-track i { display: block; height: 100%; background: linear-gradient(90deg, #4f8cff, #3ecf8e); transition: width .5s ease; }
.club-goal { margin-bottom: 10px; font-size: 12px; }
.club-members { list-style: none; margin: 0 0 12px; padding: 0; max-height: 170px; overflow: auto; }
.club-members li { display: flex; justify-content: space-between; gap: 10px; padding: 5px 0; border-bottom: 1px solid var(--line); font-size: 13px; }
.club-members li:last-child { border-bottom: 0; }
.club-members li.me { color: var(--gold); font-weight: 600; }
.club-actions { display: flex; flex-wrap: wrap; gap: 8px; }

.winners { list-style: none; margin: 0; padding: 0; max-height: 190px; overflow: auto; }
.winners li { display: flex; justify-content: space-between; gap: 10px; padding: 5px 0; border-bottom: 1px dashed var(--line); font-size: 13px; }
.winners li b { color: var(--gold); }
.winners li.big b { color: var(--ok); }
.winners .empty { color: var(--muted); }

.game-tabs button {
  background: linear-gradient(160deg, #232b3d, #171c28);
  border: 1px solid #333c52;
  color: var(--text);
  border-radius: 12px;
  padding: 12px 20px;
  font-size: 15px;
  font-weight: 600;
}

.game-tabs button span { font-size: 18px; margin-right: 6px; }
.game-tabs button.active { border-color: var(--gold); color: var(--gold); box-shadow: 0 0 14px rgba(242, 193, 78, .2); }

.felt { box-shadow: inset 0 0 60px rgba(0, 0, 0, .45), 0 8px 24px rgba(0, 0, 0, .35); }
.felt .play { box-shadow: 0 4px 0 #b5892c; }
.felt .play:active { transform: translateY(2px); box-shadow: 0 2px 0 #b5892c; }

/* Se asoma por abajo: arriba tapaba la fila de apuesta (Máx, Repetir, límites)
   y centrada taparía los rodillos o las cartas que acaban de premiar. */
.celebration {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding-bottom: 5vh;
  pointer-events: none;
  z-index: 30;
}

/* El velo deja pasar los clics, pero la tarjeta no: si no, el botón de
   comprobar la ronda sería inalcanzable con el ratón. */
.celebration-card {
  pointer-events: auto;
  text-align: center;
  padding: 22px 38px;
  border-radius: 18px;
  border: 2px solid var(--gold);
  background: rgba(20, 24, 34, .92);
  box-shadow: 0 0 60px rgba(242, 193, 78, .35);
  animation: pop .45s cubic-bezier(.2, 1.4, .4, 1);
}

.celebration-card span { display: block; letter-spacing: 1px; text-transform: uppercase; font-size: 13px; color: var(--muted); }
.celebration-card strong { display: block; font-size: 40px; color: var(--gold); font-variant-numeric: tabular-nums; }

@keyframes pop {
  from { transform: scale(.6); opacity: 0; }
  to { transform: scale(1); opacity: 1; }
}

/* Quien pide menos movimiento no debería recibir animaciones: la información
   sigue estando en el texto y en las cifras. */
@media (prefers-reduced-motion: reduce) {
  .wheel { transition: none; }
  .felt::before { animation: none; }
  .bonus-btn { animation: none; }
  .celebration-card { animation: none; }
  .hud-balance strong.bump { animation: none; }
  .xp-bar i, .mission .track i, .club-track i { transition: none; }
}

@media (max-width: 640px) {
  .hud { gap: 12px; padding: 12px; }
  .hud-balance strong { font-size: 24px; }
  .celebration-card strong { font-size: 34px; }
  main { padding: 12px; }
}

/* Las tablas de datos no caben en un móvil: que scrollee la tabla y no el
   documento entero, o el jugador acaba arrastrando la sala de lado. */
#rounds, #operations, #incidents, #approvals, #users, #audit, #rulesets-list {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

#rounds table { min-width: 560px; }
pre.output { overflow-x: auto; }

/* ---------------------------------------------------------------------------
   Lobby, bola de la ruleta, tira de resultados y ranking. Todo lo que se ve
   aquí sale de la API: el lobby publica el RTP y los límites reales, y la bola
   solo narra el número que ya devolvió el servidor.
   --------------------------------------------------------------------------- */

.lobby {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  gap: 14px;
  margin: 18px 0;
}

.game-card {
  position: relative;
  border: 1px solid #2c3446;
  border-radius: 14px;
  padding: 0 16px 16px;
  background: linear-gradient(165deg, #1c2230, #12151d);
  cursor: pointer;
  overflow: hidden;
  transition: transform .18s ease, border-color .18s ease, box-shadow .18s ease;
}

.game-card:hover, .game-card:focus-visible {
  transform: translateY(-3px);
  border-color: #f2c14e;
  box-shadow: 0 10px 26px rgba(0, 0, 0, .45);
}

.game-card.active { border-color: #f2c14e; box-shadow: inset 0 0 0 1px rgba(242, 193, 78, .5); }

/* La ilustración es el reclamo de la tarjeta: ocupa todo el ancho, se recorta
   como una foto y se funde con el panel por abajo para que el texto respire. */
.game-card .art {
  height: 118px;
  margin: 0 -16px 12px;
  overflow: hidden;
  position: relative;
}

.game-card .art img { display: block; width: 100%; height: 100%; object-fit: cover; }

.game-card .art::after {
  content: "";
  position: absolute;
  inset: auto 0 0;
  height: 46px;
  background: linear-gradient(transparent, rgba(18, 21, 29, .92));
  pointer-events: none;
}

.game-card:hover .art img, .game-card:focus-visible .art img { transform: scale(1.04); }
.game-card .art img { transition: transform .25s ease; }

.game-card h3 { margin: 0 0 6px; font-size: 17px; }
.game-card p { margin: 0 0 10px; color: var(--muted); font-size: 13px; }
.game-card footer { display: flex; gap: 8px; flex-wrap: wrap; }

.game-card .tag {
  font-size: 12px;
  padding: 3px 8px;
  border-radius: 999px;
  border: 1px solid #38415a;
  color: var(--muted);
}

.game-card.off { opacity: .45; cursor: not-allowed; }
.game-card.off::after {
  content: "mesa cerrada";
  position: absolute;
  top: 10px;
  right: 10px;
  font-size: 11px;
  background: var(--bad);
  color: #1f0505;
  padding: 2px 8px;
  border-radius: 999px;
}

/* Tira de resultados: la sesión del jugador de un vistazo. */
.streak-strip {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin: 10px 0 4px;
}

/* La tira crece con cada ronda: si no scrollea dentro de su caja, es ella la
   que desborda el documento en móvil. */
.strip {
  display: flex;
  gap: 6px;
  min-height: 24px;
  flex: 1 1 160px;
  min-width: 0;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  padding-bottom: 2px;
}

.strip .pip { flex: 0 0 auto; }

.pip {
  font-size: 12px;
  font-weight: 700;
  padding: 3px 8px;
  border-radius: 999px;
  border: 1px solid #38415a;
  animation: pip-in .25s ease-out;
}

.pip.up { color: #0f2a1d; background: var(--ok); border-color: #2ba874; }
.pip.down { color: #fff; background: rgba(229, 96, 94, .22); border-color: #7b3736; }
.pip.flat { color: var(--muted); }

@keyframes pip-in { from { transform: scale(.6); opacity: 0; } to { transform: scale(1); opacity: 1; } }

.turbo { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--muted); }
.keys { font-size: 12px; margin-top: 8px; }
.keys kbd {
  border: 1px solid #38415a;
  border-bottom-width: 2px;
  border-radius: 4px;
  padding: 1px 5px;
  font-size: 11px;
}

/* Atajos de apuesta */
.stake-ops { display: flex; gap: 6px; }
.stake-ops button { padding: 6px 10px; font-size: 13px; }

/* Bola: el aro gira y la bola viaja pegada a él, en sentido inverso a la rueda. */
.ball-track {
  position: absolute;
  inset: 0;
  pointer-events: none;
  transform-style: preserve-3d;
  transition: transform 3.2s cubic-bezier(.12, .72, .1, 1);
}

.ball {
  position: absolute;
  top: 10px;
  left: calc(50% - 6px);
  width: 12px;
  height: 12px;
  border-radius: 50%;
  /* La bola no es parte del plato: flota sobre él y proyecta su sombra. */
  transform: translateZ(14px);
  background: radial-gradient(circle at 32% 28%, #fff, #e6e6e6 45%, #9a9a9a);
  box-shadow: 0 0 8px rgba(255, 255, 255, .75), 0 10px 8px rgba(0, 0, 0, .55);
}

/* Rodillos: el que acaba de parar da un golpe y la línea premiada se enciende. */
.reel.landed { animation: reel-land .28s ease-out; }
.reel.hit { border-color: #f2c14e; box-shadow: 0 0 14px rgba(242, 193, 78, .55); }

@keyframes reel-land {
  0% { transform: translateY(-14px); }
  60% { transform: translateY(4px); }
  100% { transform: translateY(0); }
}

/* Cartas repartidas: llegan desde el mazo y se voltean sobre su eje. */
.card3d.dealt { animation: card-deal .3s ease-out both; }
.card3d.dealt .card-inner { animation: card-flip .42s cubic-bezier(.3, .9, .3, 1) both; animation-delay: inherit; }
.card3d.down.dealt .card-inner { animation: none; }

@keyframes card-deal {
  from { transform: translate(-34px, -26px) rotate(-14deg); opacity: 0; }
  to { transform: none; opacity: 1; }
}

@keyframes card-flip {
  from { transform: rotateY(0deg); }
  to { transform: rotateY(180deg); }
}

.cards { position: relative; flex-wrap: wrap; }

.cards[data-badge="bust"]::after,
.cards[data-badge="bj"]::after {
  position: absolute;
  left: 0;
  top: -14px;
  font-size: 11px;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: 999px;
}

.cards[data-badge="bust"]::after { content: "te pasaste"; background: var(--bad); color: #1f0505; }
.cards[data-badge="bj"]::after { content: "¡BLACKJACK!"; background: #f2c14e; color: #241c05; }

/* Ranking del día */
.leaders { list-style: none; margin: 6px 0 0; padding: 0; counter-reset: pos; }

.leaders li {
  counter-increment: pos;
  display: grid;
  grid-template-columns: 22px 1fr auto auto;
  gap: 8px;
  align-items: center;
  padding: 5px 0;
  border-bottom: 1px dashed #262d3c;
  font-size: 13px;
}

.leaders li::before { content: counter(pos) "."; color: var(--muted); }
.leaders li b { color: var(--ok); }
.leaders li:first-child b { color: #f2c14e; }
.leaders li.empty { grid-template-columns: 1fr; color: var(--muted); }
.leaders li.empty::before { content: ""; }

@media (prefers-reduced-motion: reduce) {
  .ball-track { transition: none; }
  .reel.landed, .card3d.dealt, .card3d.dealt .card-inner, .pip { animation: none; }
  .cyl, .cyl.spinning { animation: none; transition: none; }
  .game-card, .game-card .art img { transition: none; }
  .chip.flying, .pile.swept .chip { transition: none; }
}

@media (max-width: 640px) {
  .lobby { grid-template-columns: 1fr; }
  .game-card .art { height: 92px; }
}

/* Transparencia e historial de créditos */
.trust {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 12px;
  margin-top: 14px;
}

.trust-card h3 { margin: 0 0 6px; font-size: 14px; }
.trust-card .small { font-size: 12px; }

.trust-games { display: grid; gap: 6px; margin: 8px 0; }

/* Las cuatro cifras que un jugador pregunta: cuánto tiene, cuánto ganó,
   cuánto perdió y cómo va. */
.figures {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(118px, 1fr));
  gap: 8px;
  margin: 8px 0 10px;
}

.figure {
  display: grid;
  gap: 2px;
  padding: 8px 10px;
  border: 1px solid #262d3c;
  border-radius: 10px;
  background: #141a25;
}

.figure span { font-size: 12px; color: var(--muted); }
.figure b { font-size: 22px; line-height: 1.1; }
.figure b.up { color: var(--ok); }
.figure b.down { color: var(--bad); }
.figure small { font-size: 11px; color: var(--muted); }

.trust-detail summary { cursor: pointer; font-size: 13px; color: var(--muted); }

.trust-game {
  display: grid;
  gap: 2px;
  padding: 6px 8px;
  border: 1px solid #262d3c;
  border-radius: 8px;
  font-size: 13px;
}

.trust-game .title { font-weight: 600; text-transform: capitalize; }
.trust-game .nums b.up { color: var(--ok); }
.trust-game .nums b.down { color: var(--bad); }

.movements { list-style: none; margin: 0 0 6px; padding: 0; max-height: 260px; overflow-y: auto; }

.movements li {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 2px 10px;
  padding: 5px 0;
  border-bottom: 1px dashed #262d3c;
  font-size: 13px;
}

.movements li .muted { grid-column: 1 / -1; font-size: 11px; }
.movements li.up b { color: var(--ok); }
.movements li.down b { color: var(--bad); }
.movements li.empty { grid-template-columns: 1fr; color: var(--muted); }

.verify-now-row { flex-wrap: wrap; gap: 8px; align-items: center; }
.verify-now-row .msg { margin: 0; flex: 1 1 240px; }

/* Marcador de números salidos: memoria de la mesa, nunca un pronóstico. */
.scoreboard { margin: 10px 0 0; display: grid; gap: 6px; }
.numbers-strip { display: flex; flex-wrap: wrap; gap: 6px; }

.numbers-strip .num {
  display: grid;
  place-items: center;
  min-width: 30px;
  height: 30px;
  padding: 0 6px;
  border-radius: 50%;
  font-weight: 700;
  font-size: 13px;
  color: #fff;
  border: 1px solid rgba(255, 255, 255, .18);
}

.numbers-strip .num.red { background: #8e1f26; }
.numbers-strip .num.black { background: #1b1f27; }
.numbers-strip .num.green { background: #15603c; }

/* Autojuego: siempre con una condición de parada a la vista. */
.spin-row { gap: 8px; flex-wrap: wrap; align-items: center; }

.autoplay {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 12px;
  align-items: center;
  margin-top: 10px;
  padding: 10px 12px;
  border: 1px solid #27402f;
  border-radius: 12px;
  background: rgba(10, 24, 16, .55);
  font-size: 13px;
}

.autoplay label { display: inline-flex; gap: 6px; align-items: center; color: var(--muted); }
.autoplay input { width: 76px; }
.autoplay #auto-state { flex: 1 1 100%; margin: 0; }

/* Fichas sobre las casillas: el jugador ve dónde puso y cuánto, sin leer una
   lista aparte. */
.numbers button, .outside button { position: relative; }
.numbers button.has-chip::after, .outside button.has-chip::after {
  content: attr(data-chips);
  position: absolute; right: 2px; bottom: 2px;
  min-width: 1.4em; padding: 0 .25em;
  border-radius: 999px; border: 1px solid #0006;
  background: radial-gradient(circle at 35% 30%, #ffe9a8, #d9a629 60%, #9c7212);
  color: #2a1d00; font-size: .68rem; font-weight: 700; line-height: 1.5;
  box-shadow: 0 1px 2px #0008;
}
.board-ops { flex-wrap: wrap; gap: .4rem; margin-top: .4rem; }
.board-total { margin: .3rem 0 .5rem; font-weight: 600; }

/* La pista y las apuestas guardadas: plegadas para no competir con el tapete,
   pero a un clic de distancia para quien las usa cada ronda. */
.track, .favs { margin: .4rem 0; border-radius: .5rem; background: #ffffff08; padding: .4rem .6rem; }
.track summary, .favs summary { cursor: pointer; font-weight: 600; }
.track .row, .favs .row { flex-wrap: wrap; gap: .4rem; align-items: center; margin-top: .4rem; }
.track button small { display: block; font-weight: 400; opacity: .75; }
.fav-list { list-style: none; margin: .4rem 0 0; padding: 0; display: flex; flex-direction: column; gap: .3rem; }
.fav-list li { display: flex; gap: .4rem; align-items: center; }
.fav-list li > button:first-child { flex: 1; text-align: left; }

/* Historial de giros de la tragamonedas. */
.spin-log { display: flex; flex-direction: column; gap: .25rem; width: 100%; }
.spin-row-log {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  padding: .2rem .4rem; border-radius: .4rem; background: #ffffff08;
}
.spin-row-log .pay-line { display: inline-flex; gap: .15rem; }
.spin-row-log b.win { color: #7bdc8a; }

/* Manos divididas: dos apuestas vivas, cada una con sus fichas. */
.split-hands { display: flex; flex-wrap: wrap; gap: .75rem; margin: .5rem 0; }
.split-hand {
  display: flex; flex-direction: column; gap: .25rem;
  padding: .4rem .6rem; border-radius: .6rem;
  border: 1px solid #ffffff1f; background: #0003; min-width: 9rem;
}
.split-hand.playing { border-color: #e8c25a; box-shadow: 0 0 0 1px #e8c25a55; }

/* Confirmación de apuesta grande: avisa, no bloquea la sala. */
.big-bet {
  margin: .6rem 0; padding: .7rem .9rem;
  border: 1px solid #e8c25a66; border-radius: .6rem; background: #2a200c;
}
.big-bet .row { gap: .5rem; margin-top: .5rem; }

/* Reglas en lenguaje llano, plegadas: están a un clic y no estorban. */
.rules-plain { margin: .8rem 0; }
.rules-plain summary { cursor: pointer; font-weight: 600; }
.rules-plain p { margin: .5rem 0; max-width: 70ch; }

/* Guía de la mesa: el paso que toca, en grande y sin tecnicismos. Es un carril
   fijo encima del tapete, no un pop-up: nunca hay nada que cerrar para jugar. */
.coach {
  background: linear-gradient(180deg, #1b2434, #141b27);
  border: 1px solid #2d4258;
  border-left: 4px solid var(--gold);
  border-radius: 12px;
  padding: 14px 16px;
  margin: 6px 0 14px;
}

.coach-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.coach-head strong { font-size: 18px; }

.coach-step {
  background: rgba(242, 193, 78, .14);
  color: var(--gold);
  border-radius: 999px;
  padding: 3px 10px;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}

.coach-off { margin-left: auto; font-size: 12px; }
.coach-text { margin: 8px 0 12px; font-size: 15px; line-height: 1.5; }
.coach-actions { gap: 10px; flex-wrap: wrap; }

.coach-actions .play {
  background: #f2c14e;
  color: #201a08;
  font-weight: 700;
  font-size: 16px;
  padding: 12px 22px;
  box-shadow: 0 4px 0 #b5892c;
}

.coach-actions .play:active { transform: translateY(2px); box-shadow: 0 2px 0 #b5892c; }
.coach-on { margin: 0 0 12px; font-size: 13px; }

@media (max-width: 520px) {
  .coach-off { margin-left: 0; }
  .coach-actions { flex-direction: column; align-items: stretch; }
  .coach-actions button { width: 100%; }
}

/* Controles de sonido: efectos, música de sala y volumen, juntos y pequeños
   para que no compitan con la mesa. */
.audio-box { display: inline-flex; align-items: center; gap: 6px; }
.audio-box .volume { width: 84px; accent-color: var(--gold); }
.audio-box .sound.on { border-color: var(--gold); color: var(--gold); }
@media (max-width: 520px) { .audio-box .volume { width: 60px; } }

/* El premio grande sacude la mesa un instante. Quien pide menos movimiento no
   la nota: la regla vive dentro de la consulta. */
@media (prefers-reduced-motion: no-preference) {
  .shake { animation: shake .5s ease-in-out; }
  @keyframes shake {
    0%, 100% { transform: translate3d(0, 0, 0); }
    20% { transform: translate3d(-6px, 2px, 0) rotate(-.25deg); }
    40% { transform: translate3d(5px, -3px, 0) rotate(.25deg); }
    60% { transform: translate3d(-4px, 3px, 0); }
    80% { transform: translate3d(3px, -2px, 0); }
  }
}

/* ---------------------------------------------------------------------------
   Capa de efectos
   ---------------------------------------------------------------------------
   El lienzo de partículas vive por encima de la mesa y por debajo de la
   celebración, y no intercepta un solo clic: si alguna vez capturara el ratón,
   taparía el botón de jugar. */
.fx-layer {
  position: fixed;
  inset: 0;
  z-index: 28;
  pointer-events: none;
}

/* Un rodillo girando a 500 rpm no se ve nítido en ninguna máquina real: el
   desenfoque es lo que convierte seis caras rotando en movimiento creíble. */
.cyl.spinning { filter: blur(1.4px) brightness(1.08); }
.cyl.spinning .face { opacity: .92; }

/* Cambio de mesa: la nueva entra desde atrás, como un corte de cámara. Dura
   poco a propósito; una transición larga se vuelve un peaje. */
[data-pane].entra { animation: mesa-entra .42s cubic-bezier(.2, .8, .3, 1); }

@keyframes mesa-entra {
  from { opacity: 0; transform: translate3d(0, 14px, 0) scale(.985); }
  to { opacity: 1; transform: none; }
}

/* Premio grande: la tarjeta crece, respira y se envuelve en halo dorado. El
   texto no cambia de tamaño para que siga siendo legible. */
.celebration.grande .celebration-card {
  border-color: var(--gold);
  box-shadow: 0 0 0 1px rgba(242, 193, 78, .5), 0 18px 60px rgba(242, 193, 78, .28);
  animation: pop .25s ease-out, latido 1.1s ease-in-out .25s 2;
}

.celebration.grande .celebration-card strong { font-size: 52px; text-shadow: 0 0 22px rgba(242, 193, 78, .55); }
.celebration-card .ghost.small { margin-top: 8px; font-size: 13px; padding: 4px 10px; }

@keyframes latido {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.035); }
}

.fx-quality {
  background: var(--panel, #161b22);
  color: inherit;
  border: 1px solid var(--line, #2b323d);
  border-radius: 8px;
  padding: 4px 6px;
  font: inherit;
  font-size: 13px;
}

@media (prefers-reduced-motion: reduce) {
  .cyl.spinning { filter: none; }
  [data-pane].entra { animation: none; }
  .celebration.grande .celebration-card { animation: none; }
}

/* Tus últimas mesas: una fila para volver donde jugabas sin recorrer el
   escaparate entero. Se desplaza de lado en móvil. */
.recent { width: 100%; margin: 4px 0 10px; }
.recent h3 { margin: 0 0 6px; font-size: 1rem; }
.recent-row { display: flex; gap: 10px; overflow-x: auto; padding-bottom: 4px; scroll-snap-type: x proximity; }
.recent-card { flex: 0 0 auto; scroll-snap-align: start; display: flex; align-items: center; gap: 8px; max-width: 260px; padding: 6px 10px 6px 6px; text-align: left; background: rgba(0, 0, 0, .28); border: 2px solid rgba(255, 255, 255, .12); border-radius: 12px; color: inherit; cursor: pointer; min-height: 56px; }
.recent-card img { flex: 0 0 44px; width: 44px; height: 44px; border-radius: 8px; }
.recent-card .title { font-weight: 700; }
/* Nombre y cifra van en columna al lado de la miniatura; sueltos en la fila
   se repartían el ancho y el nombre se partía letra a letra. */
.recent-card .recent-text { display: flex; flex-direction: column; min-width: 0; overflow-wrap: anywhere; }
.recent-card:focus-visible { outline: 3px solid #8fd3ff; outline-offset: 2px; }

/* Barra al alcance del pulgar: en un móvil el botón de jugar se queda abajo,
   fijo, mientras el jugador mira la mesa. En pantalla grande no hace falta. */
.thumb-bar { display: none; }
@media (max-width: 760px), (max-height: 560px) {
  .thumb-bar {
    position: fixed; inset: auto 0 0 0; z-index: 40;
    display: flex; gap: 8px; align-items: center; justify-content: space-between;
    padding: 8px 10px calc(8px + env(safe-area-inset-bottom));
    background: rgba(9, 24, 17, .96); border-top: 2px solid rgba(227, 196, 119, .35);
    box-shadow: 0 -6px 18px rgba(0, 0, 0, .45);
  }
  .thumb-bar button { min-height: 48px; }
  .thumb-bar > button:not(.play) { display: flex; flex-direction: column; align-items: center; gap: 2px; flex: 0 0 auto; padding: 4px 10px; font-size: .8rem; background: transparent; border: 0; color: inherit; }
  .thumb-bar > button:not(.play) .ico { width: 20px; height: 20px; }
  .thumb-bar .play { flex: 1 1 auto; min-width: 0; }
  /* En pantallas de 320 px el rótulo del botón se partía en dos líneas y la
     barra crecía al doble: con menos relleno cabe en una. */
  @media (max-width: 340px) {
    .thumb-bar { gap: 4px; padding-left: 6px; padding-right: 6px; }
    .thumb-bar > button:not(.play) { padding: 4px 6px; font-size: .72rem; }
    .thumb-bar .play { padding: 10px 8px; font-size: .95rem; }
  }
  /* Que la barra no tape el final de la mesa: el hueco lo mide la propia
     barra, que en pantallas muy estrechas ocupa dos filas. */
  [data-view="mesa"] { padding-bottom: calc(var(--thumb-h, 76px) + 12px); }
}

/* Modo sin marco: el respaldo de pantalla completa cuando el navegador no da
   la API. No cambia nada del juego, solo esconde lo que no es mesa para que el
   tapete quepa entero en una pantalla corta. */
body.sin-marco > header,
body.sin-marco #lobby,
body.sin-marco .engage { display: none; }
body.sin-marco [data-view="mesa"] { padding-top: 8px; }

/* Academia: la sala enseña el oficio. Son fichas de lectura corta, no un curso
   en otra pantalla: se abren debajo y acaban mandando al tapete. */
.academy { width: 100%; margin: 6px 0 12px; padding: 12px 14px; background: rgba(0, 0, 0, .3); border: 2px solid rgba(227, 196, 119, .3); border-radius: 14px; }
.academy-head { display: flex; flex-wrap: wrap; gap: 10px 16px; align-items: center; justify-content: space-between; }
.academy-head h3 { margin: 0; font-size: 1.05rem; }
.academy-head p { margin: 2px 0 0; }
.academy-progress { display: flex; flex-direction: column; gap: 4px; min-width: 180px; }
.academy-track { display: block; height: 8px; border-radius: 999px; background: rgba(255, 255, 255, .12); overflow: hidden; }
.academy-track i { display: block; height: 100%; background: var(--gold); transition: width .3s ease; }
.academy-list { list-style: none; display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 8px; margin: 12px 0 0; padding: 0; }
.academy-link { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 56px; padding: 8px 10px; text-align: left; color: inherit; background: rgba(0, 0, 0, .28); border: 2px solid rgba(255, 255, 255, .12); border-radius: 12px; cursor: pointer; }
.academy-num { flex: 0 0 28px; display: grid; place-items: center; width: 28px; height: 28px; border-radius: 50%; background: rgba(255, 255, 255, .1); font-weight: 700; }
.academy-txt { display: flex; flex-direction: column; min-width: 0; overflow-wrap: anywhere; }
.academy-item.hecha .academy-link { border-color: rgba(62, 207, 142, .55); }
.academy-item.hecha .academy-num { background: var(--ok); color: #06240f; }
.academy-item.fallada .academy-link { border-color: rgba(227, 196, 119, .6); }
.academy-item.fallada .academy-num { background: var(--gold); color: #2a1d00; }
#academy-review { min-height: 44px; }
.academy-lesson { margin-top: 12px; padding: 12px 14px; background: rgba(0, 0, 0, .36); border: 2px solid rgba(255, 255, 255, .14); border-radius: 12px; }
.academy-lesson h4 { margin: 0 0 8px; font-size: 1rem; }
.academy-lesson p { margin: 0 0 8px; max-width: 70ch; }
.lesson-quiz { margin-top: 10px; padding-top: 10px; border-top: 1px solid rgba(255, 255, 255, .12); }
.lesson-q { font-weight: 700; }
.lesson-options { display: flex; flex-wrap: wrap; gap: 8px; }
.lesson-opt { min-height: 44px; }
.lesson-opt.bien { border-color: var(--ok); color: var(--ok); }
.lesson-opt.mal { border-color: var(--warn); color: var(--warn); }
.lesson-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.lesson-actions button { min-height: 44px; }
/* La corrección del ejercicio se lee donde está la pregunta: `.msg` es un aviso
   fijo en la esquina de la ventana y aquí eso hacía parecer que responder no
   hacía nada. */
.lesson-quiz .msg { position: static; max-width: 70ch; margin: 10px 0 0; box-shadow: none; }
