/* =====================================================================
   fd-experiencia.css  —  Capa de Experiencia Full Dominoes
   ---------------------------------------------------------------------
   Se carga DESPUÉS de estilos.css. No reemplaza nada: solo agrega la
   capa de movimiento, profundidad y respuesta táctil que faltaba.

   Contiene:
     1. Tokens de movimiento (curvas, duraciones)
     2. Fondos VIVOS (aurora, luz que barre, grano, viñeta que respira)
     3. Botones: ondas al click, brillo que barre, presión física
     4. Entrada escalonada de tarjetas / paneles
     5. Tienda: tarjetas con volumen, tilt, destello de compra
     6. Sala: HUD con más jerarquía y feedback de turno
     7. prefers-reduced-motion / bajo rendimiento

   Todo respeta el lenguaje que ya existe: glass oscuro + turquesa (#06B6D4)
   + dorado (#FBBF24). No se introduce paleta nueva.
   ===================================================================== */

:root {
  /* Curvas: nada de 'ease' plano — eso es justo lo que hace que se sienta
     de plantilla. Estas tienen sobre-tiro controlado (rebote corto). */
  --fd-out: cubic-bezier(.22, 1, .36, 1);
  --fd-inout: cubic-bezier(.65, 0, .35, 1);
  --fd-rebote: cubic-bezier(.34, 1.56, .64, 1);

  --fd-t-rapido: .16s;
  --fd-t-medio: .32s;
  --fd-t-lento: .6s;

  --fd-turquesa-rgb: 6, 182, 212;
  --fd-dorado-rgb: 251, 191, 36;
}

/* =====================================================================
   1. FONDOS VIVOS
   ---------------------------------------------------------------------
   Problema actual: cada pantalla pone una foto fija con un degradado
   oscuro encima. Resultado: se ve OPACO y muerto, porque no hay ni un
   solo pixel que cambie en toda la pantalla.

   Solución en 3 capas (todas pointer-events:none, cero costo táctil):
     a) ::before  -> aurora: dos manchas de luz que se desplazan MUY
                     lento (18s y 26s). Es lo que le da "respiración".
     b) ::after   -> viñeta que late + grano fino (SVG inline, 0 requests).
     c) canvas    -> partículas y polvo de luz (fd-fondo-vivo.js).

   Se activa poniendo la clase .fd-vivo en el <body>. Ya viene aplicada
   automáticamente por fd-experiencia.js a los body que tienen fondo.
   ===================================================================== */

/* LOBBY EXCLUIDO: sin :not(.lobby-pro), estas capas con position:fixed
   crean un stacking context que tapa a .fd-confirm-ov (z-index:4000).
   El overlay se creaba pero era invisible: quedaba detrás de esta viñeta. */
body.fd-vivo:not(.lobby-pro)::before,
body.fd-vivo:not(.lobby-pro)::after {
  content: '';
  position: fixed;
  inset: -12%;
  pointer-events: none;
  z-index: 0;
}

/* (a) Aurora: luz turquesa y dorada que se pasea por el fondo.
   mix-blend-mode: screen hace que SUME luz sobre la foto en vez de
   taparla — por eso deja de verse opaca sin tener que aclarar la imagen. */
body.fd-vivo:not(.lobby-pro)::before {
  background:
    radial-gradient(38% 32% at 22% 28%, rgba(var(--fd-turquesa-rgb), .30) 0%, rgba(var(--fd-turquesa-rgb), 0) 68%),
    radial-gradient(34% 30% at 78% 72%, rgba(var(--fd-dorado-rgb), .20) 0%, rgba(var(--fd-dorado-rgb), 0) 66%),
    radial-gradient(46% 40% at 50% 4%, rgba(120, 200, 255, .16) 0%, rgba(120, 200, 255, 0) 70%);
  mix-blend-mode: screen;
  opacity: .9;
  animation: fdAurora 26s var(--fd-inout) infinite;
  will-change: transform, opacity;
}

@keyframes fdAurora {
  0%   { transform: translate3d(0, 0, 0) scale(1);      opacity: .75; }
  25%  { transform: translate3d(3%, -2%, 0) scale(1.08); opacity: 1;   }
  50%  { transform: translate3d(-2%, 3%, 0) scale(1.04); opacity: .82; }
  75%  { transform: translate3d(-3%, -3%, 0) scale(1.1); opacity: .95; }
  100% { transform: translate3d(0, 0, 0) scale(1);      opacity: .75; }
}

/* (b) Viñeta que respira + grano. El grano es clave: sin él, los
   degradados grandes muestran bandas (banding) en pantallas AMOLED. */
body.fd-vivo:not(.lobby-pro)::after {
  background:
    radial-gradient(120% 90% at 50% 50%, rgba(0, 0, 0, 0) 42%, rgba(3, 6, 14, .55) 100%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.4'/%3E%3C/svg%3E");
  background-size: cover, 140px 140px;
  opacity: .5;
  animation: fdRespirar 9s var(--fd-inout) infinite;
}

@keyframes fdRespirar {
  0%, 100% { opacity: .42; }
  50%      { opacity: .62; }
}

/* (c) Lienzo de partículas — lo inyecta fd-fondo-vivo.js */
#fd-lienzo-fondo {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: -1;
}

/* RETIRADA — la regla que decía:
     body.fd-vivo > *:not(#fd-lienzo-fondo):not(#fd-capa-ondas)
       { position: relative; z-index: 1 }

   Le pegaba a TODO hijo directo del <body>, incluidos los diálogos que el
   JS crea al vuelo (.fd-confirm-ov y compañía). Y les ganaba: los dos
   :not() llevan selectores de ID adentro, así que la regla vale (2,0,1)
   contra el (0,1,0) de una clase suelta. Les cambiaba el
   `position: fixed` por `position: relative` y el diálogo dejaba de ser
   una capa -- se quedaba al final del flujo, con altura cero, invisible.

   No hace falta subir el contenido: alcanza con bajar el lienzo a
   z-index:-1 (abajo). Ahí queda detrás de todo el contenido pero delante
   del fondo del <body>, sin tocarle nada a nadie. */

#fd-lienzo-fondo { z-index: -1; }

/* En la mesa de juego el fondo vivo va más discreto: ahí lo importante
   son las fichas, no el ambiente. */
body.fondo-mesa-juego.fd-vivo::before { opacity: .5; animation-duration: 34s; }
body.fondo-mesa-juego.fd-vivo::after  { opacity: .38; }
body.fondo-mesa-juego #fd-lienzo-fondo { opacity: .45; }


/* =====================================================================
   2. ONDAS AL PULSAR (lo que pediste)
   ---------------------------------------------------------------------
   Son DOS ondas distintas, y esa combinación es la que da la sensación
   de "algo pasó de verdad":

     · Onda interna  (.fd-onda)  -> nace en el punto exacto del dedo y se
       expande recortada dentro del botón. Es el "material" del botón
       reaccionando.
     · Anillo externo (.fd-anillo) -> se escapa del botón hacia afuera y
       se desvanece. Es la "energía". Va en una capa fija aparte
       (#fd-capa-ondas) para que ningún overflow:hidden lo corte.

   Ambas las dispara fd-experiencia.js con un solo listener global.
   ===================================================================== */

.fd-clip-ondas {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}

.fd-onda {
  position: absolute;
  border-radius: 50%;
  transform: translate(-50%, -50%) scale(0);
  background: radial-gradient(circle,
    rgba(255, 255, 255, .55) 0%,
    rgba(var(--fd-turquesa-rgb), .35) 45%,
    rgba(255, 255, 255, 0) 72%);
  animation: fdOnda .62s var(--fd-out) forwards;
  will-change: transform, opacity;
}

@keyframes fdOnda {
  0%   { transform: translate(-50%, -50%) scale(0);   opacity: .9; }
  60%  { opacity: .45; }
  100% { transform: translate(-50%, -50%) scale(1);   opacity: 0; }
}

/* Variante dorada para acciones de valor (comprar, jugar, cobrar) */
.fd-onda.fd-onda-oro {
  background: radial-gradient(circle,
    rgba(255, 245, 210, .65) 0%,
    rgba(var(--fd-dorado-rgb), .40) 45%,
    rgba(255, 255, 255, 0) 72%);
}

#fd-capa-ondas {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 99999;
}

.fd-anillo {
  position: absolute;
  border-radius: 50%;
  border: 2px solid rgba(var(--fd-turquesa-rgb), .75);
  box-shadow:
    0 0 18px rgba(var(--fd-turquesa-rgb), .55),
    inset 0 0 12px rgba(var(--fd-turquesa-rgb), .30);
  transform: translate(-50%, -50%) scale(.2);
  animation: fdAnillo .72s var(--fd-out) forwards;
  will-change: transform, opacity;
}

.fd-anillo.fd-anillo-oro {
  border-color: rgba(var(--fd-dorado-rgb), .8);
  box-shadow:
    0 0 18px rgba(var(--fd-dorado-rgb), .55),
    inset 0 0 12px rgba(var(--fd-dorado-rgb), .30);
}

@keyframes fdAnillo {
  0%   { transform: translate(-50%, -50%) scale(.2); opacity: .85; border-width: 3px; }
  100% { transform: translate(-50%, -50%) scale(1.9); opacity: 0;  border-width: 1px; }
}

/* Anillo TENUE: el que sale al tocar cualquier punto de la pantalla que no
   sea un botón. Más chico, más apagado y más rápido que el de un botón.
   Esa diferencia es intencional: el jugador aprende con el dedo qué zonas
   responden y cuáles son solo escenografía, sin que haya que decírselo. */
.fd-anillo.fd-anillo-tenue {
  border-color: rgba(255, 255, 255, .38);
  box-shadow:
    0 0 14px rgba(var(--fd-turquesa-rgb), .30),
    inset 0 0 8px rgba(255, 255, 255, .12);
  animation-duration: .55s;
}


/* =====================================================================
   3. BOTONES CON PESO FÍSICO
   ---------------------------------------------------------------------
   Un botón se siente estático cuando solo cambia de color. Se siente
   real cuando (1) se hunde, (2) la sombra se acorta al hundirse — como
   un objeto que baja hacia la superficie — y (3) tiene un brillo que lo
   recorre de vez en cuando, señalando que está vivo y esperando.
   ===================================================================== */

button, .boton-grande, [role="button"], .btn-articulo, .btn-h, .chip-config-mesa {
  position: relative;
  transition:
    transform var(--fd-t-rapido) var(--fd-out),
    box-shadow var(--fd-t-medio) var(--fd-out),
    filter var(--fd-t-rapido) linear;
}

button:active, .boton-grande:active, [role="button"]:active,
.btn-articulo:active, .btn-h:active, .chip-config-mesa:active {
  transform: translateY(2px) scale(.975);
  filter: brightness(1.12);
}

/* Botones principales: relieve + brillo que barre cada 5s.
   Se aplica automáticamente por JS a .boton-dorado / .boton-grande /
   .btn-articulo, o a mano con class="fd-btn-vivo". */
.fd-btn-vivo {
  overflow: hidden;
  box-shadow:
    0 6px 0 rgba(0, 0, 0, .28),
    0 10px 22px rgba(0, 0, 0, .40),
    inset 0 1px 0 rgba(255, 255, 255, .28);
}

.fd-btn-vivo:active {
  box-shadow:
    0 2px 0 rgba(0, 0, 0, .28),
    0 4px 10px rgba(0, 0, 0, .45),
    inset 0 1px 0 rgba(255, 255, 255, .18);
}

.fd-btn-vivo::after {
  content: '';
  position: absolute;
  top: -60%;
  left: -120%;
  width: 60%;
  height: 220%;
  background: linear-gradient(100deg,
    rgba(255, 255, 255, 0) 0%,
    rgba(255, 255, 255, .34) 50%,
    rgba(255, 255, 255, 0) 100%);
  transform: rotate(12deg);
  pointer-events: none;
  animation: fdBarrido 5.5s var(--fd-inout) infinite;
}

@keyframes fdBarrido {
  0%, 72%  { left: -120%; }
  92%, 100% { left: 190%; }
}

/* Botón de acción crítica (JUGAR AHORA, COMPRAR): latido lento del halo.
   Es la única cosa en pantalla que debería llamar así de fuerte. */
.fd-btn-latido {
  animation: fdLatido 2.6s var(--fd-inout) infinite;
}

@keyframes fdLatido {
  0%, 100% { box-shadow: 0 6px 0 rgba(0,0,0,.28), 0 10px 22px rgba(0,0,0,.4), 0 0 0 0 rgba(var(--fd-dorado-rgb), .45); }
  55%      { box-shadow: 0 6px 0 rgba(0,0,0,.28), 0 10px 26px rgba(0,0,0,.45), 0 0 0 14px rgba(var(--fd-dorado-rgb), 0); }
}

/* Estado ocupado: el botón se bloquea y muestra que está trabajando,
   en vez de quedarse mudo mientras el fetch va y viene. */
.fd-btn-cargando {
  pointer-events: none;
  color: transparent !important;
  position: relative;
}

.fd-btn-cargando::before {
  content: '';
  position: absolute;
  inset: 0;
  margin: auto;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .28);
  border-top-color: #fff;
  animation: fdGirar .7s linear infinite;
}

@keyframes fdGirar { to { transform: rotate(360deg); } }


/* =====================================================================
   4. ENTRADA ESCALONADA
   ---------------------------------------------------------------------
   Ahora todo aparece de golpe, y eso es exactamente lo que hace que una
   pantalla parezca "HTML suelto". Con 40ms de diferencia entre elementos
   el ojo lee una composición armada, no un volcado.
   ===================================================================== */

.fd-entra {
  opacity: 0;
  transform: translateY(14px) scale(.985);
  animation: fdEntra .5s var(--fd-out) forwards;
}

@keyframes fdEntra {
  to { opacity: 1; transform: translateY(0) scale(1); }
}

.fd-entra-1  { animation-delay: .04s; }
.fd-entra-2  { animation-delay: .08s; }
.fd-entra-3  { animation-delay: .12s; }
.fd-entra-4  { animation-delay: .16s; }
.fd-entra-5  { animation-delay: .20s; }
.fd-entra-6  { animation-delay: .24s; }
.fd-entra-7  { animation-delay: .28s; }
.fd-entra-8  { animation-delay: .32s; }
.fd-entra-9  { animation-delay: .36s; }
.fd-entra-10 { animation-delay: .40s; }


/* =====================================================================
   5. TIENDA CON VOLUMEN
   ---------------------------------------------------------------------
   El diagnóstico del "parece tienda HTML": las tarjetas son rectángulos
   planos con borde, todas al mismo nivel visual, y comprar no produce
   ninguna celebración. Se arregla con:
     · profundidad real (sombra proyectada + luz superior interna)
     · tilt 3D al tocar (lo aplica el JS midiendo el punto del dedo)
     · borde de luz que gira (conic-gradient) en el artículo destacado
     · destello + partículas al comprar
   ===================================================================== */

.fd-card-3d {
  position: relative;
  transform-style: preserve-3d;
  transition:
    transform var(--fd-t-medio) var(--fd-out),
    box-shadow var(--fd-t-medio) var(--fd-out);
  box-shadow:
    0 2px 4px rgba(0, 0, 0, .30),
    0 12px 28px rgba(0, 0, 0, .45),
    inset 0 1px 0 rgba(255, 255, 255, .10);
}

.fd-card-3d::after {
  /* Luz cenital: simula que hay una fuente arriba. Sin esto las
     tarjetas se leen como stickers pegados sobre el fondo. */
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(180deg,
    rgba(255, 255, 255, .12) 0%,
    rgba(255, 255, 255, .02) 22%,
    rgba(0, 0, 0, .10) 100%);
}

.fd-card-3d:active {
  box-shadow:
    0 1px 2px rgba(0, 0, 0, .35),
    0 6px 14px rgba(0, 0, 0, .5),
    inset 0 1px 0 rgba(255, 255, 255, .06);
}

/* Artículo destacado / equipado: aro de luz que rota alrededor */
.fd-card-destacada {
  position: relative;
  isolation: isolate;
}

.fd-card-destacada::before {
  content: '';
  position: absolute;
  inset: -2px;
  border-radius: inherit;
  padding: 2px;
  background: conic-gradient(
    from 0deg,
    rgba(var(--fd-dorado-rgb), 0) 0deg,
    rgba(var(--fd-dorado-rgb), .95) 60deg,
    rgba(var(--fd-turquesa-rgb), .95) 140deg,
    rgba(var(--fd-dorado-rgb), 0) 220deg,
    rgba(var(--fd-dorado-rgb), 0) 360deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  animation: fdGirarAro 3.6s linear infinite;
  z-index: -1;
}

@keyframes fdGirarAro { to { transform: rotate(360deg); } }

/* Compra exitosa: destello dorado que sale de la tarjeta */
.fd-comprado {
  animation: fdComprado .8s var(--fd-rebote);
}

@keyframes fdComprado {
  0%   { transform: scale(1); }
  22%  { transform: scale(1.07); filter: brightness(1.6) saturate(1.3); }
  55%  { transform: scale(.985); filter: brightness(1.05); }
  100% { transform: scale(1); filter: none; }
}

.fd-chispa {
  position: absolute;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: radial-gradient(circle, #fff 0%, rgba(var(--fd-dorado-rgb), .9) 45%, rgba(var(--fd-dorado-rgb), 0) 70%);
  pointer-events: none;
  animation: fdChispa .9s var(--fd-out) forwards;
}

@keyframes fdChispa {
  0%   { transform: translate(-50%, -50%) scale(1); opacity: 1; }
  100% { transform: translate(calc(-50% + var(--fx, 0px)), calc(-50% + var(--fy, 0px))) scale(.2); opacity: 0; }
}

/* Precio: micro-animación cuando el saldo cambia */
.fd-saldo-sube { animation: fdSaldoSube .55s var(--fd-rebote); }

@keyframes fdSaldoSube {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.22); color: #FBBF24; }
  100% { transform: scale(1); }
}

/* Skeleton mientras carga la tienda: mejor que un vacío blanco */
.fd-skeleton {
  background: linear-gradient(100deg,
    rgba(255,255,255,.04) 30%,
    rgba(255,255,255,.11) 50%,
    rgba(255,255,255,.04) 70%);
  background-size: 220% 100%;
  animation: fdSkeleton 1.3s linear infinite;
  border-radius: 12px;
}

@keyframes fdSkeleton {
  from { background-position: 180% 0; }
  to   { background-position: -80% 0; }
}


/* =====================================================================
   6. SALA DE JUEGO
   ---------------------------------------------------------------------
   Los tres problemas de lectura que tiene hoy la mesa:
     a) La barra superior compite con la mesa: mismo peso visual.
     b) No hay una señal INEQUÍVOCA de "es tu turno" — el anillo del
        avatar es sutil y está arriba, mientras tus fichas están abajo.
     c) Las zonas donde se puede soltar la ficha aparecen y desaparecen
        sin transición, así que se perciben como un glitch.
   ===================================================================== */

/* (a) La barra se hunde en el fondo cuando no la estás mirando */
body.fondo-mesa-juego .barra-sala {
  backdrop-filter: blur(14px) saturate(1.25);
  -webkit-backdrop-filter: blur(14px) saturate(1.25);
  background:
    linear-gradient(165deg, rgba(255,255,255,.07), transparent 50%),
    rgba(8, 13, 24, .62);
  border: 1px solid rgba(255, 255, 255, .10);
  box-shadow: 0 8px 24px rgba(0, 0, 0, .45);
  transition: opacity var(--fd-t-lento) var(--fd-out);
}

/* (b) Señal de turno propia: un borde de luz recorre TODA la pantalla.
   Es imposible no verlo, y no tapa nada porque vive en los bordes. */
body.fd-mi-turno::after {
  box-shadow:
    inset 0 0 0 2px rgba(var(--fd-turquesa-rgb), .5),
    inset 0 0 48px rgba(var(--fd-turquesa-rgb), .22),
    radial-gradient(120% 90% at 50% 50%, transparent 42%, rgba(3,6,14,.5) 100%);
  animation: fdBordeTurno 2.2s var(--fd-inout) infinite;
}

@keyframes fdBordeTurno {
  0%, 100% { opacity: .42; }
  50%      { opacity: .78; }
}

/* Tus fichas cuando es tu turno: se elevan un poco. Movimiento pequeño,
   mensaje grande. */
.mano-jugador.mi-turno-glow .ficha {
  animation: fdFichaLista 2.4s var(--fd-inout) infinite;
}

.mano-jugador.mi-turno-glow .ficha:nth-child(2n)  { animation-delay: .12s; }
.mano-jugador.mi-turno-glow .ficha:nth-child(3n)  { animation-delay: .24s; }

@keyframes fdFichaLista {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-3px); }
}

/* Ficha jugable: en vez del pulso plano, un halo que respira en el borde */
.ficha.jugable {
  box-shadow:
    0 0 0 2px rgba(var(--fd-turquesa-rgb), .55),
    0 0 16px rgba(var(--fd-turquesa-rgb), .40),
    0 6px 14px rgba(0, 0, 0, .45);
  transition: box-shadow var(--fd-t-medio) var(--fd-out), transform var(--fd-t-rapido) var(--fd-out);
}

.ficha.seleccionada {
  transform: translateY(-10px) scale(1.06);
  z-index: 5;
}

/* (c) Zonas de soltar: entran y salen suave, y "respiran" mientras
   arrastras. Ya no parpadean. */
.zona-drop {
  transition:
    opacity var(--fd-t-medio) var(--fd-out),
    transform var(--fd-t-medio) var(--fd-out),
    background-color var(--fd-t-medio) linear;
}

.zona-drop.posible {
  animation: fdZonaRespira 1.5s var(--fd-inout) infinite;
}

@keyframes fdZonaRespira {
  0%, 100% { box-shadow: 0 0 0 0 rgba(var(--fd-turquesa-rgb), .45); transform: scale(1); }
  50%      { box-shadow: 0 0 0 10px rgba(var(--fd-turquesa-rgb), 0);  transform: scale(1.05); }
}

/* Ficha que acaba de caer en la mesa: golpe seco, no aparición mágica */
.ficha-recien-colocada {
  animation: fdFichaCae .38s var(--fd-rebote);
}

@keyframes fdFichaCae {
  0%   { transform: translateY(-22px) scale(1.14) rotate(-3deg); opacity: 0; }
  55%  { transform: translateY(2px) scale(.97); opacity: 1; }
  100% { transform: translateY(0) scale(1) rotate(0); }
}

/* Marcador: el número cambia con impulso, así se nota que anotaste */
.marcador-valor { transition: transform var(--fd-t-medio) var(--fd-rebote); }
.marcador-valor.fd-anota { animation: fdAnota .6s var(--fd-rebote); }

@keyframes fdAnota {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.45); text-shadow: 0 0 18px currentColor; }
  100% { transform: scale(1); }
}


/* =====================================================================
   7. ACCESIBILIDAD / RENDIMIENTO
   ---------------------------------------------------------------------
   Si el usuario pidió menos movimiento (o el dispositivo va justo y el
   JS pone .fd-bajo-rendimiento), todo se apaga menos lo funcional.
   Esto NO es opcional: en Android gama baja el fondo animado a pantalla
   completa es lo primero que tira los FPS.
   ===================================================================== */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  body.fd-vivo::before, body.fd-vivo::after { animation: none; }
  #fd-lienzo-fondo { display: none; }
}

body.fd-bajo-rendimiento::before { animation: none; opacity: .55; }
body.fd-bajo-rendimiento::after  { animation: none; }
body.fd-bajo-rendimiento #fd-lienzo-fondo { display: none; }
body.fd-bajo-rendimiento .fd-btn-vivo::after { animation: none; display: none; }
body.fd-bajo-rendimiento .fd-card-destacada::before { animation: none; }


/* =====================================================================
   8. PROFUNDIDAD — SISTEMA DE CAPAS  (añadido en la v2)
   ---------------------------------------------------------------------
   "Se ve pegado" tiene una causa medible: hoy TODO está a la misma
   distancia del ojo. El fondo, el brillo y las tarjetas no se mueven
   nunca uno respecto al otro, así que el cerebro los interpreta como una
   sola lámina. Ninguna sombra arregla eso — la profundidad se percibe por
   PARALAJE (cosas que se mueven a distinta velocidad) y por OCLUSIÓN
   (cosas que tapan a otras con sombra de contacto).

   Aquí se implementan las dos. Las variables --fd-par-x/y las escribe
   fd-profundidad.js desde el giroscopio (o el puntero en escritorio).
   ===================================================================== */

:root {
  --fd-par-x: 0px;
  --fd-par-y: 0px;

  /* Escalera de elevación. Cada peldaño tiene DOS sombras: una corta y
     oscura (contacto con la superficie de abajo) y una larga y difusa
     (sombra proyectada). Usar una sola sombra es lo que hace que las
     tarjetas parezcan recortes de papel. */
  --fd-elev-1:
    0 1px 2px rgba(0, 0, 0, .30),
    0 4px 10px rgba(0, 0, 0, .28);
  --fd-elev-2:
    0 2px 4px rgba(0, 0, 0, .34),
    0 12px 26px rgba(0, 0, 0, .42);
  --fd-elev-3:
    0 3px 6px rgba(0, 0, 0, .38),
    0 22px 48px rgba(0, 0, 0, .52);
}

/* --- Paralaje aplicado a las capas de fondo --- */
/*
   RETIRADO: el paralaje sobre la FOTO del fondo.
   Movía `background-position` del <body>. Problema: varias pantallas
   apilan DOS capas de fondo (un degradado + la imagen), y
   `background-position` con un solo valor las mueve a las dos por igual.
   El degradado se desalineaba de la imagen y el borde donde terminaba se
   leía como un corte o como una segunda copia del fondo -- el desfase y
   la "duplicidad de la imagen" que se veían en la sala, sobre todo al
   recargar (que es cuando el valor arranca en 0 y salta al primero que
   entrega el sensor).
   La foto ahora se queda FIJA. La profundidad sigue funcionando igual de
   bien con las otras tres capas: la foto es el horizonte, y un horizonte
   real tampoco se mueve. */

/* La aurora está en un plano intermedio. */
body.fd-con-paralaje.fd-vivo::before {
  translate: calc(var(--fd-par-x) * 0.55) calc(var(--fd-par-y) * 0.55);
}

/* Las partículas son la capa más cercana al ojo: se mueven a full. */
body.fd-con-paralaje #fd-lienzo-fondo {
  translate: var(--fd-par-x) var(--fd-par-y);
}

/* El contenido se mueve AL REVÉS y poquito. Ese contramovimiento es lo
   que lo despega del fondo: si se moviera igual, seguiría pareciendo
   parte de la misma lámina. */
body.fd-con-paralaje .fd-plano-frontal {
  translate: calc(var(--fd-par-x) * -0.35) calc(var(--fd-par-y) * -0.35);
}

/* --- Panel de vidrio: el material base de toda la interfaz --- */
/* Un solo material, usado consistentemente, es lo que separa "app
   profesional" de "colección de pantallas". */
.fd-panel {
  position: relative;
  border-radius: 18px;
  background:
    linear-gradient(165deg, rgba(255, 255, 255, .09), rgba(255, 255, 255, .02) 42%),
    rgba(10, 16, 28, .58);
  border: 1px solid rgba(255, 255, 255, .10);
  backdrop-filter: blur(18px) saturate(1.3);
  -webkit-backdrop-filter: blur(18px) saturate(1.3);
  box-shadow: var(--fd-elev-2);
  overflow: hidden;
}

/* Filo de luz superior: una línea de 1px que simula el canto biselado del
   vidrio captando la luz. Es un detalle de 3 líneas que cambia por
   completo la lectura de material. */
.fd-panel::before {
  content: '';
  position: absolute;
  top: 0; left: 12%; right: 12%;
  height: 1px;
  background: linear-gradient(90deg,
    transparent,
    rgba(255, 255, 255, .55),
    transparent);
  pointer-events: none;
}

.fd-panel-alto { box-shadow: var(--fd-elev-3); }
.fd-panel-bajo { box-shadow: var(--fd-elev-1); border-radius: 14px; }

/* Acento de color en el borde superior, para paneles que representan un
   equipo, un tier de tienda o un estado. */
.fd-panel-acento-oro::after,
.fd-panel-acento-turquesa::after {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  pointer-events: none;
}
.fd-panel-acento-oro::after {
  background: linear-gradient(90deg, transparent, var(--color-dorado), transparent);
}
.fd-panel-acento-turquesa::after {
  background: linear-gradient(90deg, transparent, var(--color-turquesa), transparent);
}

/* --- Niebla de distancia --- */
/* Los objetos lejanos pierden contraste y se tiñen del color del aire.
   Aplicado a los elementos del fondo de la escena, hace que los del
   frente se adelanten sin tener que agrandarlos. */
.fd-lejano {
  filter: saturate(.75) brightness(.86) blur(.3px);
  opacity: .88;
}

/* --- Sombra de contacto --- */
/* Una elipse difusa DEBAJO del elemento. Es la señal más barata y más
   convincente de "esto está apoyado sobre algo", y es justo lo que le
   falta a los elementos flotantes de la tienda y el lobby. */
.fd-apoyado { position: relative; }
.fd-apoyado::after {
  content: '';
  position: absolute;
  left: 50%; bottom: -6px;
  width: 78%; height: 12px;
  transform: translateX(-50%);
  background: radial-gradient(ellipse at center,
    rgba(0, 0, 0, .55) 0%,
    rgba(0, 0, 0, 0) 72%);
  filter: blur(3px);
  pointer-events: none;
  z-index: -1;
}


/* =====================================================================
   9. SALA — JERARQUÍA DE LECTURA  (ampliado en la v2)
   ---------------------------------------------------------------------
   En la captura, los cuatro jugadores, el marcador y el título del turno
   compiten con el mismo peso visual, y la mesa (que es LO ÚNICO que
   importa) queda del mismo tamaño relativo que la escenografía. Un juego
   de mesa profesional resuelve esto igual que la TV resuelve un partido:
   el terreno de juego domina, los datos van en los bordes, y el que
   tiene el turno es inequívoco.
   ===================================================================== */

/* El jugador EN TURNO se adelanta; los demás retroceden. Esta es la
   señal principal, y funciona sin leer una sola palabra. */
body.fondo-mesa-juego .jugador-card {
  transition:
    transform var(--fd-t-medio) var(--fd-out),
    opacity var(--fd-t-medio) var(--fd-out),
    filter var(--fd-t-medio) var(--fd-out);
}

body.fondo-mesa-juego .jugador-card:has(.turno-activo) {
  transform: scale(1.06);
  filter: none;
  opacity: 1;
}

/* Navegadores del WebView sin :has() se quedan con el estado neutro, que
   sigue siendo legible -- no se rompe nada. */
body.fondo-mesa-juego .jugador-card:not(:has(.turno-activo)) {
  filter: saturate(.7) brightness(.82);
  opacity: .78;
}

/* Placa de nombre: pastilla de vidrio en vez de texto suelto sobre la
   escena. El texto suelto sobre una imagen con detalle nunca se lee bien
   y es una de las cosas que más delata un montaje improvisado. */
body.fondo-mesa-juego .etiqueta-flotante {
  background: rgba(6, 11, 20, .58);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid rgba(255, 255, 255, .10);
  border-radius: 999px;
  padding: 2px 9px;
  box-shadow: var(--fd-elev-1);
}

/* Contador de fichas: se pone en rojo cuando al rival le queda 1. Es la
   información más importante de la mesa y hoy pasa desapercibida. */
body.fondo-mesa-juego .contador-fichas-pill.fd-alerta {
  background: rgba(239, 68, 68, .22);
  border-color: rgba(239, 68, 68, .55);
  color: #FCA5A5;
  animation: fdAlertaFicha 1.1s var(--fd-inout) infinite;
}

@keyframes fdAlertaFicha {
  0%, 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, .45); }
  50%      { box-shadow: 0 0 0 7px rgba(239, 68, 68, 0); }
}

/* Marcador: los dos equipos se leen de un vistazo, con el que va ganando
   destacado. */
body.fondo-mesa-juego .marcador-tarjeta {
  background:
    linear-gradient(165deg, rgba(255, 255, 255, .08), transparent 50%),
    rgba(8, 13, 24, .66);
  border: 1px solid rgba(255, 255, 255, .10);
  border-radius: 12px;
  box-shadow: var(--fd-elev-2);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}

body.fondo-mesa-juego .marcador-fila.fd-lider .marcador-valor {
  color: #fff;
  text-shadow: 0 0 12px currentColor;
}

/* La mesa gana presencia: un halo cálido debajo del tablero que la separa
   del decorado de la sala espacial. Sin esto las fichas blancas flotan
   sobre el neón sin apoyarse en ninguna superficie. */
body.fondo-mesa-juego .puesto-tablero::before {
  content: '';
  position: absolute;
  left: 50%; top: 50%;
  width: 92%; height: 62%;
  transform: translate(-50%, -50%);
  background: radial-gradient(ellipse at center,
    rgba(255, 230, 190, .16) 0%,
    rgba(255, 200, 140, .06) 45%,
    rgba(0, 0, 0, 0) 72%);
  pointer-events: none;
  z-index: 0;
  animation: fdRespirarMesa 7s var(--fd-inout) infinite;
}

@keyframes fdRespirarMesa {
  0%, 100% { opacity: .72; }
  50%      { opacity: 1; }
}
