/* ====================================================================
   Mahjong Jujuy Legends — sistema visual "Cerro de Siete Colores"
   Paleta directa de la Quebrada de Humahuaca al amanecer.
   Tipografía: Fraunces (display, serif con carácter) + IBM Plex Sans (cuerpo).
   ==================================================================== */

/* v2.48 — las fonts cargan desde index.html (<link> en paralelo + display=optional),
   no por @import acá: el @import era fetch EN SERIE → demoraba el primer pintado y
   reacomodaba el texto al llegar la font ("saltos de pantalla al principio"). */

:root {
  /* paleta — extraída de la quebrada al sol bajo */
  --bg:        #1a0820;     /* noche puneña */
  --bg-elev:   #2a1538;     /* sombra de adobe */
  --bg-elev-2: #3d2350;     /* piedra ceremonial */
  --ink:       #f6efe1;     /* lana cruda */
  --ink-dim:   #b8a98f;     /* tela teñida con nogal */
  --gold:      #f2b84b;     /* oro de carnaval */
  --teal:      #6fe3c1;     /* turquesa de los andes */
  --rose:      #ff6b6b;     /* terracota de hornocal */
  --violet:    #b07ed6;     /* coca en flor */
  --siena:     #c46a2a;     /* tierra ferrugiona */
  --ochre:     #8b6a3b;     /* madera de algarrobo */
  --ok: var(--teal);
  --warn: var(--gold);
  --bad: var(--rose);

  /* ── §19 COLOR FUNCIONAL — alias exacto de valores vivos (PR-V12-26).
     Detalle/fuente por token: data/color_tokens_v12.json. Identidad
     (Fable): halos dorados, no relleno plano. live_wins. */
  --halo-free-inner: #ffd76a; /* halo libre, interior (game.js) */
  --halo-free-outer: #f2b84b; /* halo libre, exterior (game.js) */
  --state-free: var(--halo-free-outer); /* señal=halo, no la cara */
  --state-blocked: #6f6256; /* sin color propio (señal=geometría) */
  --state-selected: rgba(242, 184, 75, 0.55); /* fallback --w-accent */
  --state-hint: #f2b84b; /* halo pista, externo */
  --state-hint-inner: #ffd76a; /* halo pista, interno */
  --state-error: #e25a5a; /* mismatch-shake; no aliasado inline */

  --special-golden:    #f6c84f; /* ya coincide con rgba() vivo */
  --special-frozen:    #82d9ff;
  --special-bomb:      #ff684d;
  --special-locked:    #8d7aa8;
  --special-lightning: #7adcff;
  --special-eye:       #64dcc8;
  --boss-accent:       #ff5ea8; /* no encontrado en CSS activo */

  --shadow-sm: 0 2px 6px rgba(0,0,0,0.35);
  --shadow:    0 6px 22px rgba(0,0,0,0.45);
  --shadow-lg: 0 18px 48px rgba(0,0,0,0.55);

  /* v2.59 — FAMILIAS EN PALETA CUD (Okabe-Ito, Color Universal Design):
     distinguibles con daltonismo Y con visión envejecida (evita amarillo puro
     sobre crema y el par azul↔violeta). Redundante con emoji + label (WCAG 1.4.1).
     Compartida por clásico (.tile .band), Triple (.tt-tile::before) y galería. */
  --fam-paisajes: #56B4E9; /* celeste cielo   (Okabe-Ito sky blue) */
  --fam-carnaval: #CC79A7; /* púrpura rojizo  (Okabe-Ito reddish purple) */
  --fam-musica:   #E69F00; /* naranja bronce  (Okabe-Ito orange) */
  --fam-fauna:    #0072B2; /* azul profundo   (Okabe-Ito blue) */
  --fam-cultivos: #009E73; /* verde azulado   (Okabe-Ito bluish green) */
  --fam-historia: #D55E00; /* bermellón adobe (Okabe-Ito vermillion) */

  --r-sm: 10px;
  --r:    16px;
  --r-lg: 24px;

  --safe-top:    env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);

  --font-display: 'Fraunces', 'Cormorant Garamond', 'Times New Roman', serif;
  --font-body:    'IBM Plex Sans', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body {
  margin: 0; padding: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.45;
  overscroll-behavior: none;
  /* Evita el "arrastrar = seleccionar texto" (como en Word) que rompía la
     jugabilidad al clickear fuera de las fichas. */
  user-select: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  -webkit-touch-callout: none;
}
/* Inputs/áreas de texto SÍ seleccionables (por si hay formularios). */
input, textarea, [contenteditable] { user-select: text; -webkit-user-select: text; }
body {
  min-height: 100vh; min-height: 100dvh;
  /* atmósfera: gradiente cálido bajo + frío arriba, como horizonte puneño */
  background:
    radial-gradient(ellipse at 50% 110%, #5a2a44 0%, transparent 60%),
    radial-gradient(ellipse at 50% -10%, #1d3a5a 0%, transparent 55%),
    var(--bg);
  position: relative;
}
/* Detalle VIVO en el fondo: bruma andina que deriva/respira lento detrás de
   TODO. Sutil (opacidad baja) y coherente con el gradiente del mundo —
   se tiñe con los colores cálidos/fríos del horizonte. */
body::before {
  content: ''; position: fixed; inset: -25%; z-index: 0; pointer-events: none;
  background:
    radial-gradient(38% 30% at 24% 28%, rgba(242,184,75,0.12), transparent 70%),
    radial-gradient(34% 26% at 80% 68%, rgba(109,140,90,0.11), transparent 70%),
    radial-gradient(30% 22% at 60% 12%, rgba(196,106,42,0.10), transparent 72%);
  animation: bg-drift 28s ease-in-out infinite alternate;
  will-change: transform;
}
@keyframes bg-drift {
  0%   { transform: translate3d(-2%, -1.5%, 0) scale(1.0); }
  100% { transform: translate3d(3%, 2%, 0) scale(1.09); }
}
body.reduce-motion::before { animation: none; }

.app { display: grid; grid-template-rows: auto 1fr auto; min-height: 100vh; min-height: 100dvh; position: relative; z-index: 1; }

h1, h2, h3 { font-family: var(--font-display); letter-spacing: -0.01em; }
h1 { font-weight: 900; }
h2 { font-weight: 700; }
h3 { font-weight: 700; }

/* ────────────── topbar ────────────── */
.topbar {
  display: flex; align-items: center; justify-content: space-between;
  padding: calc(6px + var(--safe-top)) 14px 6px;   /* v4.2.5 — chrome más fino: el dueño pidió "todo muy grande" */
  background: linear-gradient(180deg, rgba(42,21,56,0.97), rgba(26,8,32,0.95));
  border-bottom: 1px solid rgba(242,184,75,0.15);
  position: sticky; top: 0; z-index: 10;
}
.logo { display: flex; align-items: center; gap: 10px; font-family: var(--font-display); font-weight: 900; font-size: 18px; letter-spacing: -0.01em; }
/* Botón de sonido siempre visible en el topbar. */
.topbar-btn {
  background: rgba(255,255,255,0.06); border: 1px solid rgba(242,184,75,0.28);
  color: var(--ink); border-radius: 10px; font-size: 16px; line-height: 1;
  min-width: 38px; height: 34px; cursor: pointer; display: grid; place-items: center;
  -webkit-tap-highlight-color: transparent; transition: background .15s, opacity .15s;
}
.topbar-btn:hover { background: rgba(255,255,255,0.13); }
.topbar-btn:active { transform: scale(0.94); }
.topbar-btn.muted { opacity: 0.55; }
.logo img { border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.4); }
.wallet { display: flex; gap: 8px; }
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px; border-radius: 999px;
  background: var(--bg-elev);
  font-family: var(--font-body); font-weight: 700; font-size: 13px;
  border: 1px solid rgba(255,255,255,0.06);
}
.chip.coins {
  background: linear-gradient(135deg, #5a3d12, #3a2812);
  color: var(--gold);
  border-color: rgba(242,184,75,0.35);
  text-shadow: 0 1px 2px rgba(0,0,0,0.4);
}
.chip.gems {
  background: linear-gradient(135deg, #1f4a4a, #143030);
  color: var(--teal);
  border-color: rgba(111,227,193,0.35);
}

/* ────────────── navbar inferior ────────────── */
.navbar {
  display: grid; grid-template-columns: repeat(5,1fr);
  background: rgba(42,21,56,0.95);
  border-top: 1px solid rgba(255,255,255,0.06);
  padding-bottom: var(--safe-bottom);
  position: sticky; bottom: 0; z-index: 10;
}
.nav-btn {
  background: none; border: 0;
  color: var(--ink-dim);
  padding: 12px 4px 10px;
  display: grid; gap: 3px; align-items: center; justify-items: center;
  cursor: pointer; font-size: 20px; font-family: inherit;
  transition: color .15s, transform .08s;
}
.nav-btn small { font-size: 12px; opacity: 0.9; font-family: var(--font-body); font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; }
.nav-btn:active { transform: scale(0.94); }
.nav-btn[aria-current="page"] { color: var(--gold); }
.nav-btn[aria-current="page"] small { color: var(--gold); }

/* ────────────── screens ────────────── */
.screen { padding: 16px 14px 28px; overflow-x: hidden; }
.screen h1 { margin: 6px 0 12px; font-size: 26px; line-height: 1.1; }
.screen h2 { margin: 20px 0 10px; font-size: 14px; color: var(--ink-dim); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; font-family: var(--font-body); }

/* ────────────── home hero ────────────── */
.hero {
  position: relative; isolation: isolate;
  padding: 28px 22px 24px;
  border-radius: var(--r-lg);
  box-shadow: var(--shadow);
  overflow: hidden;
  min-height: 240px;
  background: linear-gradient(180deg, #2a1538 0%, #5a2548 60%, #c46a2a 100%);
  border: 1px solid rgba(242,184,75,0.3);
}
.hero-scene {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.95;
}
.hero-scene svg { width: 100%; height: 100%; display: block; }
/* Sol con halo pulsante */
@keyframes sun-pulse {
  0%, 100% { opacity: 0.9; transform: scale(1); }
  50% { opacity: 1; transform: scale(1.05); }
}
.hero-scene .sun { animation: sun-pulse 4s ease-in-out infinite; transform-origin: center; transform-box: fill-box; }
@keyframes star-twinkle {
  0%, 100% { opacity: 0.4; }
  50% { opacity: 1; }
}
.hero-scene .star { animation: star-twinkle 3s ease-in-out infinite; }
.hero-scene .star:nth-child(odd) { animation-delay: 1.5s; }

/* ── Board ambient (in-game) ────────────────────────────────────────────── */
/* v4.2.x — doctrina "tablero QUIETO en idle": el sol/luna y las estrellas del
   tablero quedan ESTÁTICOS (antes respiraban/titilaban en loop infinito → repaint
   sostenido en celular). Las del home (.hero-scene .sun/.star, sun-pulse/star-twinkle)
   NO se tocan — siguen animando ahí. */
.board-svg .board-sun { transform-origin: center; transform-box: fill-box; }
.board-svg .board-star { transform-origin: center; transform-box: fill-box; }

/* Cóndor y serpentina: eran FX de movimiento CONTINUO (un cóndor cruzando el cielo,
   confeti de carnaval cayendo). v4.2.x — al quitarles la animación quedaban congelados
   en su posición base de forma rara (el cóndor centrado en x=0 → medio recortado en el
   borde sup-izq; las 3 serpentinas colgando estáticas del borde superior). Se ocultan
   con display:none (adorno trabado se ve peor que ausente, y refuerza el tablero en
   calma). @keyframes condor-fly / serpentina-float eliminados (quedaban huérfanos). */
.board-svg .ambient-condor { display: none; }
.board-svg .ambient-serpentina { display: none; }

/* Viento de altura (§15.5): 4 líneas blancas diagonales cruzando el board
   solo durante peek_active. DOM overlay encima del board SVG. */
.wind-fx {
  position: absolute; inset: 0;
  pointer-events: none;
  overflow: hidden;
  z-index: 6;
}
.wind-fx .wind-line {
  position: absolute;
  height: 1.5px;
  background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.55) 30%, rgba(255,255,255,0.85) 50%, rgba(255,255,255,0.55) 70%, transparent 100%);
  width: 60%;
  left: -65%;
  border-radius: 2px;
  filter: blur(0.4px);
  animation: windSweep 1.8s cubic-bezier(0.34, 0.8, 0.5, 1) forwards;
}
.wind-fx .wind-line:nth-child(1) { top: 22%; animation-delay: 0s;    transform: rotate(-6deg); }
.wind-fx .wind-line:nth-child(2) { top: 38%; animation-delay: 0.18s; transform: rotate(-4deg); width: 55%; }
.wind-fx .wind-line:nth-child(3) { top: 56%; animation-delay: 0.32s; transform: rotate(-5deg); width: 65%; }
.wind-fx .wind-line:nth-child(4) { top: 72%; animation-delay: 0.48s; transform: rotate(-3deg); width: 50%; }
@keyframes windSweep {
  0%   { transform: translateX(-160%); opacity: 0; }
  20%  { opacity: 1; }
  85%  { opacity: 1; }
  100% { transform: translateX(160%); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .board-svg .board-sun,
  .board-svg .board-star,
  .board-svg .ambient-condor,
  .board-svg .ambient-serpentina,
  .wind-fx .wind-line { animation: none !important; }
  .wind-fx { display: none !important; }
}
.hero h1 {
  position: relative; z-index: 2;
  margin: 0 0 6px;
  font-family: "Fraunces", ui-serif, Georgia, serif;
  font-size: 32px;
  font-weight: 900;
  letter-spacing: 0.3px;
  color: #fef7e3;
  text-shadow: 0 2px 8px rgba(0,0,0,0.5), 0 0 20px rgba(242,184,75,0.4);
}
.hero p, .hero .hero-sub {
  position: relative; z-index: 2;
  margin: 0 0 16px;
  color: rgba(255,255,255,0.85);
  font-size: 14px;
  max-width: 28ch;
  text-shadow: 0 1px 3px rgba(0,0,0,0.6);
}
.hero .row {
  position: relative; z-index: 2;
  display: flex; gap: 10px;
}

/* ────────────── buttons ────────────── */
.btn {
  background: linear-gradient(180deg, var(--gold), #c8881d);
  color: #2a1804;
  border: 0;
  padding: 13px 20px;
  border-radius: 999px;
  font-family: var(--font-body);
  font-weight: 800;
  font-size: 15px;
  letter-spacing: 0.01em;
  cursor: pointer;
  box-shadow: 0 6px 18px rgba(242,184,75,0.35), inset 0 1px 0 rgba(255,255,255,0.35);
  transition: transform .08s, box-shadow .15s, opacity .15s;
  min-height: 46px;
}
.btn:active { transform: scale(0.97); box-shadow: 0 2px 8px rgba(242,184,75,0.3); }
.btn[disabled] { opacity: 0.5; cursor: default; }
.btn.ghost {
  background: transparent;
  color: var(--ink);
  border: 1px solid rgba(255,255,255,0.18);
  box-shadow: none;
}
.btn.small { padding: 8px 14px; font-size: 13px; min-height: 36px; }
.btn.success {
  background: linear-gradient(180deg, var(--teal), #4a9d85);
  color: #0e3030;
  box-shadow: 0 6px 18px rgba(111,227,193,0.35);
}
.btn.danger {
  background: linear-gradient(180deg, var(--rose), #c44141);
  color: #fff;
}

/* ────────────── cards ────────────── */
.cards { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 14px; }
.card {
  background: var(--bg-elev);
  padding: 14px 16px;
  border-radius: var(--r);
  display: grid; gap: 4px;
  border: 1px solid rgba(255,255,255,0.05);
  box-shadow: var(--shadow-sm);
}
.card .k { font-size: 12px; color: var(--ink-dim); text-transform: uppercase; letter-spacing: 0.1em; font-weight: 600; }
.card .v { font-size: 22px; font-weight: 800; font-family: var(--font-display); }

/* ────────────── world map ────────────── */
.world {
  background: var(--bg-elev);
  border-radius: var(--r);
  padding: 16px;
  margin-bottom: 12px;
  border: 1px solid rgba(255,255,255,0.05);
  box-shadow: var(--shadow-sm);
}
.world header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.world h3 { margin: 0; font-size: 18px; }
/* v2.20 — auto-enfoque del sendero */
.world.current-world { scroll-margin-top: 16px; border-color: var(--gold); box-shadow: 0 0 0 1px var(--gold), var(--shadow-sm); }
.world.world-collapsed { padding: 12px 16px; opacity: 0.82; }
.world.world-collapsed .world-scene { display: none; }
.world-done-check { color: #6fe3c1; font-weight: 900; }
.here-badge {
  display: inline-block; font-size: 12px; font-weight: 800; color: #0e0418;
  background: var(--gold); border-radius: 999px; padding: 2px 9px; margin-left: 8px;
  vertical-align: middle; animation: hereBob 1.6s ease-in-out infinite;
}
@keyframes hereBob { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }
body.reduce-motion .here-badge { animation: none; }
.world .meta { font-size: 12px; color: var(--ink-dim); font-weight: 500; }
.world .levels { display: grid; grid-template-columns: repeat(5, 1fr); gap: 7px; }
.lvl {
  aspect-ratio: 1/1;
  display: grid; place-items: center;
  background: linear-gradient(160deg, var(--bg-elev-2), #2c1840);
  border-radius: var(--r-sm);
  font-family: var(--font-display);
  font-weight: 800; font-size: 15px;
  cursor: pointer; border: 0; color: var(--ink);
  position: relative;
  transition: transform .08s, box-shadow .15s;
  font-family: inherit;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.05), 0 2px 6px rgba(0,0,0,0.3);
}
.lvl:active { transform: scale(0.93); }
.lvl.locked { opacity: 0.3; cursor: default; filter: saturate(0.4); }
.lvl.done {
  background: linear-gradient(160deg, #6fe3c1, #3a8a72);
  color: #0e3030;
  box-shadow: 0 4px 12px rgba(111,227,193,0.25);
}
.lvl.current {
  background: linear-gradient(160deg, var(--gold), #b07015);
  color: #2a1804;
  box-shadow: 0 0 0 2px var(--gold), 0 6px 18px rgba(242,184,75,0.5);
  animation: pulsecurr 1.8s ease-in-out infinite;
}
@keyframes pulsecurr {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.04); }
}
.lvl .stars { position: absolute; bottom: 2px; right: 4px; font-size: 9px; }

/* ────────────── gameplay overlay ────────────── */
.gameboard-wrap {
  position: fixed; inset: 0; z-index: 50;
  /* v2.39 — FLEX column en vez de grid de 4 tracks fijos. El grid `auto auto 1fr auto`
     daba el 1fr a la fila de OBJETIVO (3er hijo) y el BOARD (5º hijo, con capítulo+
     objetivo+layout presentes) caía en una fila implícita → board mal dimensionado y
     contenido desbordado en celular. Con flex, el board toma TODO el espacio sobrante
     sin importar cuántas filas opcionales haya arriba → pantalla fija y bien armada. */
  display: flex; flex-direction: column;
  height: 100dvh; /* viewport dinámico (respeta barra del navegador en celular) */
  overflow: hidden; /* nada de scroll de página: la pantalla queda fija */
  background:
    radial-gradient(ellipse at 50% -10%, #2d1a4a 0%, transparent 50%),
    radial-gradient(ellipse at 50% 110%, #4a2030 0%, transparent 55%),
    var(--bg);
}
/* El tablero ocupa el resto; los demás bloques toman su altura natural. */
.gameboard-wrap > .hud,
.gameboard-wrap > .chapter-row,
.gameboard-wrap > .objective-row,
.gameboard-wrap > .layout-row,
.gameboard-wrap > .dock { flex: 0 0 auto; }
.gameboard-wrap > .board { flex: 1 1 auto; min-height: 0; }
.gameboard-wrap .hud {
  display: flex; align-items: center; gap: 6px;
  padding: 4px 10px;   /* v4.2.5 — sin var(--safe-top): el HUD va DEBAJO del topbar (que ya despeja el notch) → sumarlo duplicaba hasta 44px de aire muerto en celus con muesca */
  background: rgba(0,0,0,0.5);
  border-bottom: 1px solid rgba(255,255,255,0.05);
  font-size: 12px;
}
.gameboard-wrap .hud-stat {
  display: flex; flex-direction: column; align-items: center;
  min-width: 44px; flex: 0 1 auto;
  padding: 2px 4px;
}
.gameboard-wrap .hud-stat .k { font-size: 12px; color: var(--ink-dim); text-transform: uppercase; letter-spacing: 0.05em; font-weight: 600; }
.gameboard-wrap .hud-stat .v { font-size: 15px; font-weight: 800; font-family: var(--font-display); line-height: 1.1; }
.gameboard-wrap .hud .btn.small { padding: 7px 11px; font-size: 12px; }
.gameboard-wrap .hud .btn.icon-only { padding: 5px 9px; font-size: 18px; min-width: 40px; }  /* v4.2.5 — sonido/pausa más grandes: el dueño pidió silenciar MÁS FÁCIL en partida */
/* F9 — botones chicos del HUD (<44px visuales): área táctil invisible vía
   ::after (inset negativo) sin agrandar el botón. Necesitan position:relative
   para que el inset del ::after se ancle a ELLOS, no a un ancestro. */
.gameboard-wrap .hud .btn.small,
.gameboard-wrap .hud .btn.icon-only {
  position: relative;
}
.gameboard-wrap .hud .btn.small::after,
.gameboard-wrap .hud .btn.icon-only::after {
  content: '';
  position: absolute;
  inset: -6px;
}

/* Badge de layout más fino, no tape */
.layout-row {
  padding: 3px 6px;
  background: rgba(0,0,0,0.15);
  display: flex; justify-content: center;
  border-bottom: 1px solid rgba(255,255,255,0.04);
}
.layout-row .layout-badge {
  padding: 3px 11px; font-size: 12px;
  background: rgba(242,184,75,0.10);
  border: 1px solid rgba(242,184,75,0.25);
  border-radius: 10px;
  color: var(--gold); letter-spacing: 0.4px;
}

.board {
  position: relative; touch-action: manipulation;
  display: grid; place-items: center;
  padding: 6px; overflow: hidden;   /* v4.2.5: respiro más fino (era 14px) → más área para fichas grandes */
  min-height: 0;
  perspective: none;   /* v4.1.7 — tilt 3D quitado: rasterizaba el SVG a textura GPU borrosa. Plano = nitido. */
}
.board svg { width: 100%; height: 100%; max-width: 100%; max-height: 100%; }
/* Despegar el tablero del fondo: sombra de elevación para que "flote".
   v2.26 PERF: antes era `filter: drop-shadow` SOBRE el <svg> vivo → se
   re-rasterizaba CADA FRAME mientras las fichas animan el match (jank). Ahora es
   un box-shadow del contenedor .board (no re-rasteriza el contenido del SVG; el
   overflow:hidden propio NO recorta el box-shadow del propio elemento). Las
   fichas ya tienen su sombra 3D dibujada, así que la profundidad se mantiene. */
.board { box-shadow: 0 14px 30px rgba(0,0,0,0.55); }
/* v4.2.2 FIX PARPADEO MÓVIL — SIN transición de `filter`: tras cada match,
   patchBoard reclasifica free↔blocked y cada ficha que cambiaba ANIMABA su
   drop-shadow 120ms (re-raster SVG por frame × N fichas = el parpadeo del
   clásico en celular, de siempre). El cambio de sombra ahora es instantáneo
   (a 120ms el fade era imperceptible; el costo no). */
.tile { cursor: pointer; transition: transform .1s, opacity .35s ease; }
/* Por defecto TODAS las fichas se ven iguales — misma sombra, mismo color.
   La diferencia visible entre libre/bloqueada SÓLO aparece cuando se activa
   el poder Visión (body.vision-active). Sin Visión, el jugador "lee" el
   tablero por la geometría (las que están arriba se ven arriba), no por
   un truco visual de iluminación. */
/* v4.1.2 — sombra ALIVIANADA: la doble sombra profunda de v3.8 (0 5px 9px .42)
   leía como "bulto/peso" y hacía ver la ficha gorda y lenta. Ahora contacto corto
   + ambiente más corto y translúcido → ficha más fina y liviana (menos pintado).
   Sigue siendo estático (no anima filtro) → no rompe perf. */
.tile.blocked { cursor: default; }

/* PODER VISIÓN — durante 10s las bloqueadas se ven UN POCO MÁS OSCURAS
   y con MÁS SOMBRA, no transparentes. Las libres mantienen su brillo. */
body.vision-active .board-svg .tile.blocked {
  filter: brightness(0.74) saturate(0.7)
          drop-shadow(0 5px 9px rgba(0,0,0,0.7)) !important;
  /* sin opacity — el usuario las quiere visibles, sólo más oscuras */
}
body.vision-active .board-svg .tile.free {
  filter: drop-shadow(0 4px 8px rgba(0,0,0,0.55))
          drop-shadow(0 0 12px rgba(255,215,106,0.55)) !important;
}

/* Cuenta regresiva del poder Visión — píldora con ojo + barrita que se
   agota. Sin números: el ancho del fill comunica el tiempo restante. */
.vision-countdown {
  position: fixed;
  top: 14px;
  right: 14px;
  z-index: 9000;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px;
  background: rgba(20, 12, 30, 0.92);
  border: 1px solid rgba(122, 220, 255, 0.55);
  border-radius: 24px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.5), 0 0 14px rgba(122,220,255,0.4);
  animation: visionCountdownIn 0.25s ease-out;
}
@keyframes visionCountdownIn {
  from { transform: translateY(-30px) scale(0.7); opacity: 0; }
  to   { transform: translateY(0) scale(1); opacity: 1; }
}
.vision-countdown .vc-eye {
  font-size: 20px;
  filter: drop-shadow(0 0 4px rgba(122,220,255,0.7));
}
.vision-countdown .vc-bar {
  width: 140px;
  height: 9px;
  background: rgba(0,0,0,0.45);
  border-radius: 5px;
  overflow: hidden;
  box-shadow: inset 0 1px 2px rgba(0,0,0,0.5);
}
.vision-countdown .vc-fill {
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, #7adcff 0%, #46b4dc 60%, #1f7fa8 100%);
  border-radius: 5px;
  box-shadow: 0 0 8px rgba(122,220,255,0.6);
  /* La transición de width la setea el JS al activar la visión. */
}
@media (max-width: 380px) {
  .vision-countdown .vc-bar { width: 100px; }
}

/* Tutorial de boosters — manito 👇 ANCLADA al botón (es hija del botón del
   dock). Vive ARRIBA del botón apuntando hacia ABAJO hacia él. Sigue al
   botón con cualquier reflow/resize del dock. Reusable para los 6 boosters
   (Visión, Cóndor, Viento, Pachamama, Cardón, Comodín). */
.booster-tutorial-pointer,
.vision-tutorial-pointer {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 9001;
  pointer-events: none;
  text-align: center;
  white-space: nowrap;
}
.booster-tutorial-pointer .btp-hand,
.vision-tutorial-pointer .vt-hand {
  display: block;
  font-size: 38px;
  line-height: 1;
  filter: drop-shadow(0 3px 5px rgba(0,0,0,0.55));
  animation: btpHandBob 1.1s ease-in-out infinite;
}
.booster-tutorial-pointer .btp-msg,
.vision-tutorial-pointer .vt-msg {
  display: inline-block;
  margin-top: 2px;
  background: rgba(26,8,32,0.96);
  color: #f6efe1;
  font-size: 12px;
  font-weight: 700;
  padding: 5px 10px;
  border-radius: 12px;
  border: 1px solid rgba(255,215,106,0.6);
  box-shadow: 0 4px 12px rgba(0,0,0,0.5);
  max-width: 150px;
  white-space: normal;
  line-height: 1.25;
}
/* La manito 👇 "cabecea" hacia el botón (baja), reforzando que apunta abajo. */
@keyframes btpHandBob {
  0%, 100% { transform: translateY(-3px); }
  50%      { transform: translateY(4px); }
}
@keyframes vtHandBob { /* legacy alias */
  0%, 100% { transform: translateY(-3px); }
  50%      { transform: translateY(4px); }
}
/* El botón con tip activo late para llamar la atención. */
.booster.booster-tip-pulse,
body.vision-tutorial-active #bVision {
  animation: bVisionPulse 1.1s ease-in-out infinite;
  box-shadow: 0 0 0 3px rgba(122,220,255,0.6), 0 0 18px rgba(122,220,255,0.55);
  z-index: 10;
  position: relative;
}
@keyframes bVisionPulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.06); }
}
.tile.selected {
  filter: drop-shadow(0 0 14px #f2b84b) drop-shadow(0 0 5px #f2b84b) brightness(1.10);
}
.tile.hint { animation: hintpulse 0.9s ease-in-out 3; }
@keyframes hintpulse {
  0%, 100% { filter: brightness(1) drop-shadow(0 3px 6px rgba(0,0,0,0.5)); }
  50%      { filter: brightness(1.30) drop-shadow(0 0 14px #f2b84b); }
}

.dock {
  display: flex; gap: 6px;
  padding: 6px 10px calc(7px + var(--safe-bottom));   /* v4.2.5 — chrome más fino */
  background: rgba(0,0,0,0.6);
  justify-content: space-around;
  border-top: 1px solid rgba(255,255,255,0.05);
}
.booster {
  background: var(--bg-elev);
  border: 1px solid rgba(255,255,255,0.07);
  color: var(--ink);
  padding: 6px 8px;
  border-radius: var(--r);
  display: grid; gap: 1px; place-items: center;
  font-family: inherit; cursor: pointer;
  min-width: 56px; min-height: 52px;
  position: relative;
  transition: transform .08s, background .15s;
  box-shadow: 0 2px 6px rgba(0,0,0,0.3);
}
.booster:active:not(:disabled) { transform: scale(0.94); }
.booster .ico { font-size: 20px; line-height: 1; }
.booster .lbl { font-size: 12px; opacity: 0.85; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; }
.booster .count {
  position: absolute; top: -5px; right: -5px;
  background: var(--gold); color: #2a1804;
  font-size: 12px; font-weight: 800;
  border-radius: 999px;
  min-width: 20px; height: 20px;
  display: grid; place-items: center;
  padding: 0 5px;
  border: 2px solid var(--bg-elev);
}
.booster:disabled { opacity: 0.35; }
/* v2.31 — poder que NO tenés (count 0) DESAPARECE del dock (no queda gris). El
   dock muestra solo lo usable. Pachamama sin jugada queda visible-gris (la tenés). */
.booster.unavailable { display: none !important; }

/* ════════ v2.32 — íconos de premio SVG + barrido de luz + dock que invita ════════ */
/* Íconos de moneda/gema (premium, escalan con el font del chip) */
.ico-coin, .ico-gem { width: 1.15em; height: 1.15em; vertical-align: -0.22em; display: inline-block; }
.win-rewards .ico-coin, .win-rewards .ico-gem { width: 20px; height: 20px; vertical-align: -5px; }
.surprise-bonus .ico-coin { width: 16px; height: 16px; vertical-align: -3px; }
.coin-fly .ico-coin { width: 26px; height: 26px; display: block; filter: drop-shadow(0 2px 3px rgba(120,80,10,0.5)); }

/* Barrido de luz que cruza el tablero. v4.2.x — doctrina "tablero QUIETO en idle":
   se quitó la animation boardSheen (barrido continuo cada 9s → repaint sostenido en
   celular). El gradiente queda estático (opacity:0 base = invisible; el tablero no
   anima nada en reposo). @keyframes boardSheen eliminado (huérfano). */
.board-sheen {
  position: absolute; top: 0; bottom: 0; left: 0; width: 55%;
  pointer-events: none; z-index: 5; opacity: 0;
  background: linear-gradient(105deg, transparent 38%, rgba(255,246,220,0.22) 50%, transparent 62%);
}

/* Dock que INVITA: los poderes disponibles laten con un glow dorado suave
   (escalonado) para que llamen a usarlos. Solo opacity/box-shadow, lentos. */
@media (prefers-reduced-motion: no-preference) {
  .dock .booster:not(.unavailable):not(:disabled) { animation: boosterReady 2.8s ease-in-out infinite; }
  .dock .booster:not(.unavailable):not(:disabled):nth-child(2n) { animation-delay: 0.5s; }
  .dock .booster:not(.unavailable):not(:disabled):nth-child(3n) { animation-delay: 1s; }
  .dock .booster-power:not(.unavailable):not(:disabled) { animation-duration: 2.4s; }
}
@keyframes boosterReady {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.04); }
}
@media (prefers-reduced-motion: reduce) {
  .board-sheen { display: none; }
  .dock .booster { animation: none !important; }
}

/* ✨ Comodín — la carta mágica. Acento dorado-violeta + pulso constante */
.booster.booster-magic {
  background: linear-gradient(135deg, #5a2548 0%, #7a3878 50%, #c46a2a 100%);
  border: 1px solid rgba(242,184,75,0.45);
  box-shadow: 0 2px 8px rgba(0,0,0,0.4), 0 0 12px rgba(200,154,242,0.25);
  animation: magicPulse 2.4s ease-in-out infinite;
}
.booster.booster-magic .ico { animation: magicSpin 4s linear infinite; }
@keyframes magicPulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.04); }
}
@keyframes magicSpin {
  0%, 100% { transform: rotate(0) scale(1); }
  50%       { transform: rotate(8deg) scale(1.08); }
}
/* Cuando 5to slot está visible, dock se reorganiza */
.dock.dock-5 { gap: 6px; overflow-x: auto; }
.dock.dock-5 .booster { min-width: 56px; padding: 6px 8px; }
.dock.dock-5 .booster .lbl { font-size: 12px; }
/* Con Visión + Comodín hay 6 boosters — apretar un poco más */
.dock.dock-6 { gap: 6px; overflow-x: auto; }
.dock.dock-6 .booster { min-width: 56px; padding: 6px 8px; }
.dock.dock-6 .booster .lbl { font-size: 12px; }
.dock.dock-6 .booster .ico { font-size: 18px; }

/* v2.19 — dock con scroll horizontal: hasta 11 poderes desbloqueados sin
   apretarlos hasta romper el tap target. Snap suave + sin scrollbar visible. */
.dock.dock-scroll {
  display: flex; gap: 6px;
  overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
  padding: 4px 8px calc(4px + var(--safe-bottom));
  scrollbar-width: none;
}
.dock.dock-scroll::-webkit-scrollbar { display: none; }
.dock.dock-scroll .booster { flex: 0 0 auto; scroll-snap-align: center; }

/* PR-V12-24 — dock foco_v2 (flag off por default, ver hud_policy.js). Drawer
   <details> nativo: sin JS de toggle. Reusa .booster tal cual, solo agrega el
   panel flotante + el texto de razón cuando está deshabilitado. */
.dock-v2 { position: relative; }
.dock-v2 .drawer-wrap summary { list-style: none; cursor: pointer; }
.dock-v2 .drawer-wrap summary::-webkit-details-marker { display: none; }
.dock-v2 .drawer-wrap .drawer {
  position: absolute; left: 0; right: 0; bottom: 100%;
  display: flex; flex-wrap: wrap; gap: 6px; padding: 8px;
  background: rgba(0,0,0,0.88); border-top: 1px solid rgba(255,255,255,0.08);
}
.dock-v2 .booster .reason { grid-column: 1/-1; font-size: 12px; opacity: 0.75; }
/* v2.57 SEO — contenido indexable bajo el juego (Home). Discreto, tema oscuro. */
.seo-info {
  position: relative; z-index: 1;
  max-width: 720px; margin: 0 auto; padding: 26px 18px 40px;
  color: rgba(254,247,227,0.78); font-size: 14px; line-height: 1.65;
}
.seo-info h1 { font-family: Fraunces, serif; font-size: 22px; color: #fef7e3; margin: 0 0 10px; }
.seo-info h2 { font-family: Fraunces, serif; font-size: 17px; color: #f2b84b; margin: 20px 0 6px; }
.seo-info a { color: #6fe3c1; }
.seo-info ul { margin: 6px 0; padding-left: 20px; }
.seo-info .seo-foot { opacity: 0.6; font-size: 12px; margin-top: 22px; }
/* En pantalla de juego (overlay fijo) ocultarlo por prolijidad */
body:has(.gameboard-wrap) .seo-info, body:has(.tt-wrap) .seo-info { display: none; }

/* v2.58.3 — mini-fichas de las mode-cards del Home: el CTA principal muestra
   FICHAS DEL JUEGO (par 🦅🦅 / trío 🌵🌵🌵), no un emoji abstracto. */
.mode-tiles { display: flex; justify-content: center; margin-bottom: 6px; }
.mode-tiles .mt {
  width: 38px; height: 44px; display: grid; place-items: center;
  font-size: 21px; border-radius: 7px;
  background: linear-gradient(160deg, #fdf6e3 0%, #f0e3c4 70%, #d9c49a 100%);
  border: 1px solid #b9977a; box-shadow: 0 3px 6px rgba(0,0,0,0.4);
}
.mode-tiles .mt + .mt { margin-left: -12px; }
.mode-tiles .mt:nth-child(1) { transform: rotate(-7deg); }
.mode-tiles .mt:nth-child(2) { transform: rotate(3deg) translateY(-3px); }
.mode-tiles .mt:nth-child(3) { transform: rotate(9deg); }
.mode-card:hover .mt:nth-child(1), .mode-card:active .mt:nth-child(1) { transform: rotate(-10deg) translateY(-2px); }
.mode-card:hover .mt:nth-child(2), .mode-card:active .mt:nth-child(2) { transform: rotate(0deg) translateY(-6px); }
.mode-card:hover .mt:nth-child(3), .mode-card:active .mt:nth-child(3) { transform: rotate(12deg) translateY(-2px); }
.mode-tiles .mt { transition: transform .18s cubic-bezier(0.34,1.4,0.5,1); }

/* v2.58.2 (T2.4) — calendario mensual del Desafío Diario */
.daily-cal { margin-top: 10px; }
.dc-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
.dc-day {
  aspect-ratio: 1; display: grid; place-items: center;
  font-size: 12px; font-weight: 700; border-radius: 7px;
  background: rgba(255,255,255,0.06); color: rgba(254,247,227,0.55);
}
.dc-day.done { background: linear-gradient(135deg,#2f7a6e,#3fd9c0); color: #08251f; }
.dc-day.today { outline: 2px solid #f2b84b; color: #f2b84b; }
.dc-day.fut { opacity: 0.35; }
.dc-progress { margin-top: 8px; font-size: 12.5px; opacity: 0.85; }
.dc-progress b { color: #f2b84b; }

/* v2.58.1 (T2.6) — pinch-zoom: pan de 1 dedo para el browser, pinch de 2 para
   nosotros (Pointer Events en game.js). Sin esto el pinch zoomearía la página. */
.board, .board-svg, .board-svg .tile { touch-action: pan-x pan-y; }

/* v2.57 — MODO FICHAS GRANDES (accesibilidad integral): botones y textos del
   nivel más grandes; el tamaño de ficha lo sube fitBoard (game.js, min 58px). */
body.big-tiles .dock .booster { min-width: 74px; min-height: 64px; }
body.big-tiles .dock .booster .ico { font-size: 27px; }
body.big-tiles .dock .booster .lbl { font-size: 12px; }
body.big-tiles .dock .booster .count { font-size: 15px; }
body.big-tiles .hud { font-size: 1.12em; }
body.big-tiles .toast { font-size: 17px; }

/* v2.56.6 — indicio de "hay más poderes a la derecha": fade en el borde mientras
   quede contenido por scrollear (clase dock-more la maneja game.js al scrollear). */
.dock.dock-scroll.dock-more {
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 34px), transparent);
  mask-image: linear-gradient(90deg, #000 calc(100% - 34px), transparent);
}
/* Poderes nuevos: acento turquesa para diferenciarlos de los 6 base. */
.booster.booster-power {
  background: linear-gradient(135deg, #1f5a52 0%, #2f7a6e 55%, #c4922a 100%);
  border: 1px solid rgba(111,227,193,0.4);
  box-shadow: 0 2px 8px rgba(0,0,0,0.4), 0 0 10px rgba(111,227,193,0.18);
}

/* Modal "¡Nuevo poder!" */
.power-unlock-overlay {
  position: fixed; inset: 0; z-index: 90;
  background: rgba(0,0,0,0.72); backdrop-filter: blur(6px);
  display: grid; place-items: center; padding: 24px;
}
.power-unlock-dialog {
  background: linear-gradient(160deg, #2a1a3a, #1a1228);
  border: 2px solid var(--gold); border-radius: var(--r-lg, 24px);
  box-shadow: 0 18px 50px rgba(0,0,0,0.6), 0 0 40px rgba(242,184,75,0.3);
  padding: 26px 22px; text-align: center; max-width: 340px;
  animation: winPop .5s cubic-bezier(0.34,1.56,0.55,1);
}
.power-unlock-dialog .pu-kicker { font-size: 12px; font-weight: 800; letter-spacing: 2px; color: #6fe3c1; }
.power-unlock-dialog .pu-icon { font-size: 64px; margin: 10px 0 4px; animation: char-portrait-bob 2.4s ease-in-out infinite; }
.power-unlock-dialog .pu-name { font-family: var(--font-display); color: var(--gold); margin: 4px 0; font-size: 24px; }
.power-unlock-dialog .pu-desc { color: var(--ink); font-size: 14px; margin: 6px 0 4px; line-height: 1.4; }
.power-unlock-dialog .pu-free { color: #6fe3c1; font-size: 12px; font-weight: 700; margin: 6px 0 16px; }
.reduce-motion .power-unlock-dialog,
.reduce-motion .power-unlock-dialog .pu-icon { animation: none; }

/* Cuando Comodín activo, halo en el board para feedback visual */
body.comodin-mode .board {
  box-shadow: inset 0 0 60px rgba(200,154,242,0.35), inset 0 0 30px rgba(242,184,75,0.25);
  animation: comodinFlow 3s ease-in-out infinite;
}
body.comodin-mode .board-svg .tile.free {
  filter: drop-shadow(0 0 8px rgba(200,154,242,0.5)) drop-shadow(0 3px 6px rgba(0,0,0,0.55)) !important;
}
@keyframes comodinFlow {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.04); }
}

/* ────────────── result overlay ────────────── */
.overlay {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.72); backdrop-filter: blur(6px);
  display: grid; place-items: center; z-index: 100;
  padding: 20px;
  animation: fadein .2s ease-out;
}
@keyframes fadein { from { opacity: 0; } }
.dialog {
  background: linear-gradient(180deg, #3a2354, #2a1538);
  border-radius: var(--r-lg);
  padding: 28px 24px;
  max-width: 380px; width: 100%;
  text-align: center;
  box-shadow: var(--shadow-lg);
  border: 1px solid rgba(242,184,75,0.25);
  animation: dialogin .25s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes dialogin {
  from { transform: translateY(20px) scale(0.96); opacity: 0; }
  to   { transform: translateY(0) scale(1); opacity: 1; }
}
.dialog h2 { margin: 0 0 6px; font-size: 26px; font-family: var(--font-display); font-weight: 900; }
.dialog p { color: var(--ink-dim); margin: 0 0 16px; font-size: 14px; }
.dialog .stars-big {
  font-size: 44px;
  letter-spacing: 10px;
  color: var(--gold);
  margin: 12px 0 16px;
  text-shadow: 0 0 24px rgba(242,184,75,0.45);
}
.dialog .row { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }
.dialog .rewards { display: flex; gap: 12px; justify-content: center; margin: 10px 0 14px; flex-wrap: wrap; }
.dialog .rewards .chip { padding: 8px 14px; font-size: 14px; }

/* ────────────── pase ────────────── */
.pass-track { display: grid; gap: 8px; }
.pass-tier {
  background: var(--bg-elev);
  border-radius: var(--r);
  padding: 14px 16px;
  display: grid; grid-template-columns: auto 1fr 1fr; gap: 14px;
  align-items: center;
  border: 1px solid rgba(255,255,255,0.05);
}
.pass-tier .num { font-size: 22px; font-weight: 900; color: var(--gold); min-width: 32px; font-family: var(--font-display); }
.pass-tier .reward { font-size: 13px; }
.pass-tier .reward .lbl { font-size: 12px; color: var(--ink-dim); text-transform: uppercase; letter-spacing: 0.08em; display: block; margin-bottom: 1px; }
.pass-tier.claimed { opacity: 0.55; }
.pass-progress {
  background: var(--bg-elev);
  padding: 12px 16px;
  border-radius: var(--r);
  margin-bottom: 12px;
  border: 1px solid rgba(255,255,255,0.05);
}
.bar {
  background: rgba(0,0,0,0.35);
  height: 10px;
  border-radius: 999px;
  overflow: hidden;
  margin-top: 8px;
  box-shadow: inset 0 1px 2px rgba(0,0,0,0.4);
}
.bar .fill {
  background: linear-gradient(90deg, var(--gold), var(--teal));
  height: 100%;
  transition: width .35s ease-out;
  box-shadow: 0 0 12px rgba(242,184,75,0.4);
}

/* ────────────── eventos ────────────── */
.event {
  background: var(--bg-elev);
  border-radius: var(--r);
  padding: 14px 16px;
  margin-bottom: 10px;
  display: grid; gap: 4px;
  border-left: 3px solid var(--violet);
  box-shadow: var(--shadow-sm);
}
.event h3 { margin: 0; font-size: 16px; font-family: var(--font-display); font-weight: 700; }
.event .meta { font-size: 12px; color: var(--ink-dim); }
.event .reward { font-size: 12px; color: var(--gold); font-weight: 600; }

/* ────────────── toast ────────────── */
.toast {
  position: fixed; bottom: 96px; left: 50%; transform: translateX(-50%);
  background: var(--ink); color: var(--bg);
  padding: 10px 20px; border-radius: 999px;
  font-weight: 700; font-size: 13px;
  z-index: 200; box-shadow: var(--shadow-lg, var(--shadow)), 0 0 0 1px rgba(0,0,0,0.25);
  border: 1px solid rgba(255,255,255,0.18);
  animation: toastin .25s ease-out;
  max-width: calc(100% - 32px);
}
@keyframes toastin { from { opacity: 0; transform: translateX(-50%) translateY(10px); } }

/* ────────────── settings ────────────── */
.setting {
  background: var(--bg-elev);
  padding: 14px 16px;
  border-radius: var(--r);
  margin-bottom: 8px;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  border: 1px solid rgba(255,255,255,0.05);
}
.setting label { font-size: 14px; font-weight: 600; }
.setting .desc { font-size: 12px; color: var(--ink-dim); margin-top: 2px; }
.toggle {
  width: 46px; height: 26px;
  background: var(--bg-elev-2);
  border-radius: 999px;
  position: relative; cursor: pointer; border: 0; padding: 0;
  transition: background .15s;
}
.toggle .knob {
  position: absolute; top: 2px; left: 2px;
  width: 22px; height: 22px;
  background: var(--ink);
  border-radius: 50%;
  transition: left .15s, background .15s;
  box-shadow: 0 2px 4px rgba(0,0,0,0.4);
}
.toggle[aria-pressed="true"] { background: var(--teal); }
.toggle[aria-pressed="true"] .knob { left: 22px; background: #0e3030; }

/* ────────────── tile interaction (v∞ — animaciones "nivel dios") ──────────
   IMPORTANTE: el <g class="tile-slot"> SOLO posiciona (transform attr SVG).
   Todas las animaciones (hover, selected, match, hint, mismatch) operan
   sobre el <g class="tile"> interno con transform-box: fill-box, así CSS
   transform no destruye la posición absoluta del slot.

   Stack de animaciones por estado (cada uno aislado, no compite):
     - .tile-entering        → caída del cielo + squash + settle
     - .tile.free:hover      → lift suave con drop-shadow dinámica
     - .tile.selected        → float + idle breathing pulse infinito
     - .tile.match-burst     → anticipación pull-back + explosión rotada
     - .tile.mismatch-shake  → vibración + flash rojo + glow
     - .tile.hint            → pulso con halo dorado dramático
*/
.board-svg .tile-slot {
  /* nunca animar ni transitar el slot — sus coords son la posición real */
}
.board-svg .tile {
  /* transform-origin se inyecta por tile via inline style en game.js:
     "transform-origin: Xpx Ypx" donde X=px+TILE_W/2, Y=py+TILE_H/2
     (coordenadas SVG del centro de la cara frontal del tile).
     Motivo: transform-box:fill-box falla en Chrome para <g> — el browser
     calcula el fill-box en coords del viewport entero, no en coords locales,
     haciendo que transform-origin:center caiga en el centro del SVG completo.
     Con eso, scale(1.045) arrastra la ficha decenas de px hacia ese centro lejano.
     La solución es pasar la coordenada exacta como inline style, que gana
     sobre cualquier regla CSS y evita toda ambigüedad de coordinate space. */
  /* TRANSICIÓN BASE + DEBOUNCE (90ms):
     CRÍTICO: el delay aplica a TRANSFORM y FILTER. Si solo se debounceara
     transform, el filter (glow del drop-shadow) seguiría parpadeando cada
     vez que el browser pierde+recupera hover por sub-pixel jitter en el
     borde. 90ms cubre el jitter típico del cursor (~20-40ms) con margen.
     hover-IN debe ser 0ms (definido dentro del bloque :hover) para que
     la respuesta al pasar el mouse sea inmediata. */
  /* v4.2.x PERF móvil — se quitó `filter .20s` de la transición base: ninguna ficha
     transiciona filter (el glow de selección/pista pasa a ser un ring sólido, no
     drop-shadow). Solo transform transiciona. */
  transition:
    transform .15s cubic-bezier(0.22, 0.7, 0.32, 1) 90ms;
  /* v2.25 PERF: sin promoción GPU global en la ficha base. Antes se promovía CADA
     ficha (hasta 142) a su propia capa de composición → explosión de memoria GPU
     y jank. Ahora la promoción GPU vive sola en los estados que de verdad animan
     (.selected / .match-burst). El resto del tablero queda estático. */
}

/* ─── HOVER ─── SOLO escala, NO cambio de filter.
   Aprendido a la mala: cambiar filter en hover causa flickering visible en
   los bordes entre fichas (el glow se enciende/apaga rápido por sub-pixel
   jitter del cursor). El drop-shadow de free queda fijo en .tile.free.
   Solo el scale 1.03 da feedback de hover — y con el 90ms debounce de
   transform en el estado base, no parpadea ni en el borde más fino.

   CRÍTICO — `prefers-reduced-motion: no-preference`:
   Windows/macOS pueden tener "Reduce motion" activado a nivel sistema.
   Eso dispara una regla global `*  { transition-duration: 0.01ms !important }`
   que ANULA mi debounce de 90ms — la transition se vuelve instantánea,
   y en el borde sub-pixel donde el hover toggla rápido el scale salta
   INSTANTÁNEAMENTE entre 1.0 y 1.03 (la carta "se vuelve loca").
   Solución: el hover scale SOLO aplica cuando el sistema NO pide reduce-motion.
   Para usuarios con reduce-motion, la ficha NO escala — cero animación,
   cero flicker. El feedback queda en el cursor:pointer + drop-shadow extra. */
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .board-svg .tile.free:hover {
    transform: scale(1.03);
    /* hover-IN sin delay — respuesta inmediata al entrar */
    transition: transform .13s cubic-bezier(0.22, 0.7, 0.32, 1) 0ms;
  }
}
/* Para reduce-motion: CERO cambios en hover. Ningún transform, ningún filter.
   El cursor:pointer + el ring de selección al hacer click son feedback suficiente.
   Cualquier cambio visual con transition-duration 0.01ms (forzado por la regla
   global de reduce-motion) genera flicker al toggle. La única solución 100%
   estable es no cambiar nada. */

/* ─── SELECTED ─── overshoot + idle breath
   Doble animación: la primera deja la ficha alzada, la segunda respira para siempre.
   Si el usuario hace match o deselecciona, la clase se quita y todo vuelve a 0. */
.board-svg .tile.selected {
  /* v2.58.5 — RESPUESTA INSTANTÁNEA: .17s (era .34s + un WAAPI de 260ms que la
     pisaba) y transición de filter SIN el delay anti-jitter de 90ms del estado
     base: el glow dorado enciende YA, no ~290ms tarde. */
  animation:
    tileSelected .17s cubic-bezier(0.25, 1.5, 0.45, 1) forwards,
    tile-breath  2.4s ease-in-out .17s infinite;
  transition: transform .12s cubic-bezier(0.22, 0.7, 0.32, 1) 0ms;
  /* v4.2.x PERF móvil — se quitó el filter drop-shadow (re-raster del SVG en celular
     cada vez que se seleccionaba/deseleccionaba). La señal de selección ahora es el
     ring sólido .select-ring (siempre presente, revelado por esta clase; ver abajo).
     Queda el lift+breath (solo transform). */
  will-change: transform;   /* v2.25: promover SOLO la ficha activa */
}
@keyframes tileSelected {
  /* v2.58.5 — pop + elevación en UNA animación corta: overshoot con mini-giro
     (reemplaza al WAAPI eliminado) y asienta elevada. Feedback en el 1er frame. */
  0%   { transform: translateY(-2px) scale(1.02); }
  55%  { transform: translateY(-8px) scale(1.07) rotate(-1.5deg); }
  100% { transform: translateY(-5px) scale(1.03); }
}
@keyframes tile-breath {
  /* Pulso muy sutil — apenas perceptible. */
  0%, 100% { transform: translateY(-5px) scale(1.03); }
  50%      { transform: translateY(-6px) scale(1.035); }
}

/* CRÍTICO — reduce-motion: las animaciones de selected NO pueden correr.
   La regla global `*  { animation-duration: 0.01ms !important }` hace que
   `tile-breath ... infinite` corra ~100000 veces por segundo → la ficha
   "salta" sin parar al ser seleccionada. Para reduce-motion users, NO usar
   animation, sino aplicar el estado final directamente con transform.
   También deshabilitamos los rings infinite (select-ring-pulse, free-ring-pulse,
   hintPulse) que tienen el mismo problema. */
@media (prefers-reduced-motion: reduce) {
  .board-svg .tile.selected {
    animation: none !important;
    /* Elevación más sutil: 4px (antes 9px) y scale 3% (antes 5%).
       Suficiente para que se vea seleccionada sin sentir que "salta lejos". */
    transform: translateY(-4px) scale(1.03) !important;
    filter: drop-shadow(0 5px 9px rgba(0, 0, 0, 0.55))
            drop-shadow(0 0 12px rgba(242, 184, 75, 0.45)) !important;
  }
  .board-svg .tile.hint { animation: none !important; }
  .board-svg .select-ring,
  .board-svg .free-ring { animation: none !important; }
}

/* ─── REALCE DE FICHAS LIBRES (v2.19) ───
   Telegrafía qué se puede tocar AHORA (clave en juegos top). Es un glow dorado
   que respira — SOLO filter, NUNCA transform (el transform en libres reintroduce
   el flicker sub-pixel en bordes que tanto costó eliminar). El delay lo inyecta
   game.js por ficha (animation-delay inline, derivado de x/y → estable entre
   re-renders, escalonado para que el pulso no sea uniforme = se ve "vivo").
   La ficha seleccionada/hover/match tiene sus propias reglas que ganan. */
/* v2.25 PERF: el telegrafiado de fichas libres ya NO anima `filter` por ficha
   (drop-shadow repintaba cada frame × N fichas = causa #1 del trabe en celular).
   Ahora es un halo dorado <g class="free-glow"> que game.js dibuja dentro de cada
   ficha libre, cuya OPACIDAD pulsa — la opacidad se compone en GPU, no repinta →
   escala a 100+ fichas sin trabarse. El delay escalonado lo inyecta game.js. */
.board-svg .free-glow { opacity: 0; }
/* v4.1.6 PERF — halo FIJO en todos los tableros (antes pulsaba en <=80 fichas y
   animaba ~36 drop-shadows por frame -> tablero a 42fps). Estatico = misma
   telegrafia de "libre", tablero quieto = 60fps. */
.board-svg .tile.free:not(.selected):not(.match-burst) .free-glow { opacity: 0.42; }
/* reduce-motion: halo fijo tenue (telegrafía sin movimiento). */
@media (prefers-reduced-motion: reduce) {
  .board-svg .free-glow { opacity: 0.42; animation: none !important; }
}
/* v2.56.6 PERF — en tableros GRANDES (>80 fichas, clase big-board que pone game.js)
   30-50 halos SVG pulsando opacidad a la vez re-rasterizan el gradient cada frame
   (en SVG la opacidad de un <g> con paint-server NO compone gratis en GPU como en
   HTML) → micro-stutter sostenido en gama media/baja. Halo FIJO tenue: misma
   telegrafía de "libre", tablero quieto = relax de verdad. */
.board-svg.big-board .tile.free:not(.selected):not(.match-burst) .free-glow {
  opacity: 0.42; animation: none !important;
}

/* ─── MATCH BURST ─── anticipación + explosión + fade rotando
   Esta es la regla activa (sobreescribe la de la sección v2.6.2 más abajo
   por orden de cascada — ver match-flash). */
.board-svg .tile.match-burst {
  animation: matchBurst .58s cubic-bezier(0.32, 0, 0.18, 1) forwards;
  pointer-events: none;
  z-index: 10;
  will-change: transform;   /* v2.25: solo la ficha que explota se promueve */
}

/* match-leaving — clase nueva que NO tiene animation propia.
   La animación la maneja Web Animations API (vía el.animate() en game.js),
   que funciona INDEPENDIENTE del CSS reduce-motion global.
   Esta clase solo aporta los efectos estáticos: no clickable, encima de otras fichas. */
.board-svg .tile.match-leaving {
  pointer-events: none;
  z-index: 10;
}
/* v4.2.x PERF móvil — coreografía de transform/opacity SIN filter (brightness/
   saturate/drop-shadow re-rasterizaban el SVG por frame en celular durante el burst).
   El brillo del match lo aportan las partículas/juice DOM, no el filtro por ficha. */
@keyframes matchBurst {
  0%   { transform: scale(1) rotate(0deg); opacity: 1; }
  15%  { transform: scale(0.92) rotate(-3deg); opacity: 1; }
  38%  { transform: scale(1.42) rotate(2deg); opacity: 1; }
  64%  { transform: scale(1.18) rotate(10deg) translateY(2px); opacity: 0.7; }
  100% { transform: scale(0.32) rotate(28deg) translateY(10px); opacity: 0; }
}

/* ─── HINT ─── pulso con halo dorado dramático.
   v4.2.2 FIX PARPADEO MÓVIL: el halo/brillo pasa a ser ESTÁTICO en la clase y
   el pulso anima SOLO transform (composición GPU) — antes el keyframe animaba
   brightness+saturate+2×drop-shadow por frame, infinito, mientras había pista
   (misma familia del fix v4.1.6). Mismo look dramático, cero re-raster. */
.board-svg .tile.hint {
  animation: hintPulse 1.05s ease-in-out infinite;
  /* v4.2.x PERF móvil — se quitó el filter (brightness/saturate/2×drop-shadow):
     re-rasterizaba el SVG por frame en celular. El realce de pista ahora es el ring
     sólido .tile.hint .select-ring (ver abajo) + el hintPulse solo-transform.
     El SVG #hint-glow que game.js aplica inline se mantiene (on-demand, 2 fichas 2.8s). */
}
@keyframes hintPulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.075); }
}

.match-particle {
  position: fixed;
  width: 10px; height: 10px;
  border-radius: 50%;
  background: radial-gradient(circle, #f2b84b, #c46a2a);
  pointer-events: none;
  z-index: 200;
  animation: particleFly .6s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards;
}
@keyframes particleFly {
  0% {
    transform: translate(-50%, -50%) scale(0.6);
    opacity: 1;
  }
  100% {
    transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(0);
    opacity: 0;
  }
}

/* ────────────── floating score & combo ────────────── */
.match-float-score {
  position: fixed;
  transform: translate(-50%, -50%);
  pointer-events: none;
  z-index: 220;
  font-family: 'Fraunces', ui-serif, Georgia, serif;
  font-weight: 900;
  font-size: 32px;
  color: #f2b84b;
  text-shadow:
    0 0 8px rgba(242, 184, 75, 0.8),
    0 2px 4px rgba(0, 0, 0, 0.6),
    -1px -1px 0 #5a2548;
  letter-spacing: 0.5px;
  animation: floatScore 1.1s cubic-bezier(0.215, 0.61, 0.355, 1) forwards;
}
.match-float-score.combo {
  font-size: 28px;
  color: #6fe3c1;
  text-shadow:
    0 0 12px rgba(111, 227, 193, 0.95),
    0 2px 4px rgba(0, 0, 0, 0.7),
    -1px -1px 0 #1a4a35;
}
@keyframes floatScore {
  0%   { transform: translate(-50%, -50%) scale(0.6); opacity: 0; }
  20%  { transform: translate(-50%, -55%) scale(1.15); opacity: 1; }
  60%  { transform: translate(-50%, -85%) scale(1); opacity: 1; }
  100% { transform: translate(-50%, -115%) scale(0.85); opacity: 0; }
}

/* Screen shake en combos altos */
.shake {
  animation: shake 0.3s cubic-bezier(.36,.07,.19,.97) both;
}
/* v2.56 — amplitud ESCALABLE por evento vía --shake-amp (default 3px = el valor
   histórico). Se setea desde JS (magnitudeFx): combo alto / win / jefe sacuden
   más. Sólo transform → no rompe animation_perf_audit. reduce-motion lo apaga abajo. */
@keyframes shake {
  10%, 90% { transform: translate3d(calc(var(--shake-amp, 3px) * -0.34), 0, 0); }
  20%, 80% { transform: translate3d(calc(var(--shake-amp, 3px) * 0.67), 0, 0); }
  30%, 50%, 70% { transform: translate3d(calc(var(--shake-amp, 3px) * -1), 0, 0); }
  40%, 60% { transform: translate3d(calc(var(--shake-amp, 3px) * 1), 0, 0); }
}

/* ────────────── win overlay celebration ────────────── */
.win-overlay {
  position: fixed; inset: 0;
  background: rgba(14, 4, 24, 0.85);
  backdrop-filter: blur(6px);
  display: flex; align-items: center; justify-content: center;
  z-index: 100;
  animation: fadeIn 0.3s ease-out;
}
@keyframes fadeIn {
  from { opacity: 0; } to { opacity: 1; }
}

.win-dialog {
  position: relative;
  background: linear-gradient(160deg, #2d1840 0%, #5a2548 60%, #3a1f5a 100%);
  border: 2px solid #f2b84b;
  border-radius: 20px;
  padding: 32px 40px;
  max-width: 360px;
  text-align: center;
  box-shadow:
    0 0 60px rgba(242, 184, 75, 0.4),
    0 20px 40px rgba(0, 0, 0, 0.5),
    inset 0 0 0 1px rgba(255, 255, 255, 0.1);
  animation: winPop 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
  overflow: hidden;
}
@keyframes winPop {
  0%   { transform: scale(0.7) translateY(40px); opacity: 0; }
  60%  { transform: scale(1.05) translateY(-5px); opacity: 1; }
  100% { transform: scale(1) translateY(0); opacity: 1; }
}

/* Rayos detrás del título */
.win-rays {
  position: absolute;
  top: -50%; left: 50%;
  width: 600px; height: 600px;
  transform: translateX(-50%);
  background:
    conic-gradient(
      from 0deg,
      rgba(242, 184, 75, 0.2) 0deg,
      transparent 30deg,
      rgba(242, 184, 75, 0.15) 60deg,
      transparent 90deg,
      rgba(242, 184, 75, 0.2) 120deg,
      transparent 150deg,
      rgba(242, 184, 75, 0.18) 180deg,
      transparent 210deg,
      rgba(242, 184, 75, 0.2) 240deg,
      transparent 270deg,
      rgba(242, 184, 75, 0.15) 300deg,
      transparent 330deg,
      rgba(242, 184, 75, 0.2) 360deg
    );
  animation: rayRotate 12s linear infinite;
  pointer-events: none;
  opacity: 0.6;
}
@keyframes rayRotate {
  to { transform: translateX(-50%) rotate(360deg); }
}

.win-title {
  position: relative;
  margin: 0 0 4px;
  font-family: 'Fraunces', ui-serif, Georgia, serif;
  font-weight: 900;
  font-size: 26px;
  color: #f2b84b;
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
  letter-spacing: 0.5px;
}
.win-sub {
  position: relative;
  margin: 0 0 18px;
  font-size: 13px;
  color: #dfd8c4;
  opacity: 0.85;
}

.stars-big {
  position: relative;
  font-size: 56px;
  letter-spacing: 8px;
  margin: 18px 0 14px;
  line-height: 1;
}
.star-slot {
  display: inline-block;
  color: rgba(255, 255, 255, 0.2);
  transition: color 0.2s;
}
.star-slot.star-pop {
  color: #f2b84b;
  text-shadow: 0 0 14px #f2b84b, 0 0 28px rgba(242, 184, 75, 0.6);
  animation: starPop 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes starPop {
  0%   { transform: scale(0.3) rotate(-30deg); }
  60%  { transform: scale(1.3) rotate(8deg); }
  100% { transform: scale(1) rotate(0); }
}

.win-rewards {
  position: relative;
  display: flex; gap: 10px; justify-content: center;
  margin: 14px 0;
}
.win-rewards .chip {
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid rgba(242, 184, 75, 0.4);
  padding: 8px 14px;
  border-radius: 20px;
  font-weight: 700;
  font-size: 14px;
  color: #f2b84b;
}
/* v2.30 — BONUS SORPRESA (recompensa variable) */
.surprise-bonus {
  margin: -4px auto 10px; text-align: center; font-weight: 800; font-size: 14px;
  color: #fff; padding: 7px 16px; border-radius: 999px; display: inline-block;
  background: linear-gradient(100deg, #c41e5a, #f2b84b);
  box-shadow: 0 4px 16px rgba(242,184,75,0.5);
  animation: surpriseIn .5s cubic-bezier(0.34,1.56,0.64,1) .9s both;
}
.surprise-bonus b { color: #fff8e0; }
@keyframes surpriseIn { 0% { transform: scale(0) rotate(-8deg); opacity: 0; } 100% { transform: scale(1) rotate(0); opacity: 1; } }
/* v2.30 — "estás por llegar a algo": teaser de próxima meta con barra de progreso */
.win-next-goal {
  margin: 4px auto 14px; max-width: 320px; text-align: center;
  background: rgba(0,0,0,0.28); border: 1px solid rgba(255,255,255,0.12);
  border-radius: 14px; padding: 10px 14px;
}
.win-next-goal.big { border-color: rgba(242,184,75,0.55); box-shadow: 0 0 18px rgba(242,184,75,0.25); }
.wng-text { font-size: 13px; color: var(--ink); margin-bottom: 8px; }
.wng-text b { color: #f2b84b; }
.wng-icon { font-size: 16px; }
.wng-bar { height: 8px; border-radius: 999px; background: rgba(255,255,255,0.12); overflow: hidden; }
.wng-fill {
  height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, #f2b84b, #ffd76a);
  box-shadow: 0 0 8px rgba(242,184,75,0.6);
  animation: wngGrow .9s cubic-bezier(0.3,0.8,0.4,1) 1.1s both;
  transform-origin: left;
}
@keyframes wngGrow { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* v2.33 — COHERENCIA DE PUNTOS: el puntaje del HUD se convierte en monedas y se ve. */
.win-score { color: #ffd76a; font-weight: 800; }
.score-convert {
  margin: 2px auto 10px; display: inline-flex; align-items: center; gap: 7px;
  font-size: 13px; font-weight: 700; color: #e8dcc0;
  background: rgba(0,0,0,0.26); border: 1px solid rgba(255,255,255,0.12);
  padding: 5px 13px; border-radius: 999px;
  animation: scoreConvIn .5s cubic-bezier(0.34,1.56,0.64,1) 1.0s both;
}
.score-convert .sc-pts { color: #cbbfe6; }
.score-convert .sc-arrow { color: #f2b84b; font-weight: 900; }
.score-convert b { color: #ffd76a; display: inline-flex; align-items: center; gap: 3px; }
.score-convert .ico-coin { width: 15px; height: 15px; vertical-align: -2px; }
@keyframes scoreConvIn { 0% { transform: translateY(8px); opacity: 0; } 100% { transform: translateY(0); opacity: 1; } }

/* v2.33 — CELEBRACIÓN ESCALADA: 3★ enciende rayos y borde dorados; 2★ intermedio. */
.win-dialog.win-perfect { border-color: #ffd76a; box-shadow: 0 0 80px rgba(255,215,106,0.55), 0 20px 40px rgba(0,0,0,0.5), inset 0 0 0 1px rgba(255,255,255,0.14); }
.win-dialog.win-perfect .win-rays { opacity: 0.95; animation-duration: 8s; }
.win-dialog.win-perfect .win-title { color: #ffe39a; text-shadow: 0 0 18px rgba(255,215,106,0.7), 0 2px 4px rgba(0,0,0,0.5); animation: perfectThrob 1.6s ease-in-out infinite; }
.win-dialog.win-great .win-rays { opacity: 0.75; }
@keyframes perfectThrob { 0%,100% { transform: scale(1); } 50% { transform: scale(1.05); } }
/* v3.9 — MEGA WIN (Tarea 1): variante más grande, ~12% de las veces + 1ª victoria/jefe. */
.win-dialog.win-mega { border-color: #ffe39a; box-shadow: 0 0 110px rgba(255,227,154,0.7), 0 20px 40px rgba(0,0,0,0.5), inset 0 0 0 1px rgba(255,255,255,0.2); }
.win-dialog.win-mega .win-rays { opacity: 1; animation-duration: 6s; }

/* v2.33 — conteo "tragamonedas": el chip late mientras suma y da un pop al aterrizar. */
/* v2.34 (#36) — ciclo COMPLETO (1→1.07→1) sin `alternate`: cada vuelta termina en
   scale(1), así al quitar la clase `.counting` (fin del conteo) no hay micro-salto. */
.win-rewards .chip.coins.counting { animation: coinCount .3s ease-in-out infinite; }
.win-rewards .chip.coins.coin-landed { animation: coinLand .5s cubic-bezier(0.34,1.56,0.64,1); }
@keyframes coinCount { 0% { transform: scale(1); } 50% { transform: scale(1.07); } 100% { transform: scale(1); } }
@keyframes coinLand {
  0% { transform: scale(1.18);  }
  100% { transform: scale(1);  }
}

/* v2.34 — COFRE DE HITO (cada 10 niveles, recompensa REAL). Mismo lenguaje visual
   que el bonus sorpresa pero en clave "cofre" (verde→oro). */
.milestone-bonus {
  margin: -2px auto 10px; text-align: center; font-weight: 800; font-size: 14px;
  color: #fff; padding: 7px 16px; border-radius: 999px; display: inline-block;
  background: linear-gradient(100deg, #1f8a5a, #f2b84b);
  box-shadow: 0 4px 16px rgba(31,138,90,0.45);
  animation: surpriseIn .5s cubic-bezier(0.34,1.56,0.64,1) both;
}
.milestone-bonus b { color: #fff8e0; }
.milestone-bonus .ico-coin { width: 16px; height: 16px; vertical-align: -3px; }

/* v2.35 — RACHA DE SESIÓN (niveles ganados seguidos). Clave "fuego". */
.streak-bonus {
  margin: -2px auto 10px; text-align: center; font-weight: 800; font-size: 14px;
  color: #fff; padding: 7px 16px; border-radius: 999px; display: inline-block;
  background: linear-gradient(100deg, #d23b1e, #f2b84b);
  box-shadow: 0 4px 16px rgba(210,59,30,0.45);
  animation: surpriseIn .5s cubic-bezier(0.34,1.56,0.64,1) both;
}
.streak-bonus b { color: #fff8e0; }
.streak-bonus .ico-coin { width: 16px; height: 16px; vertical-align: -3px; }

/* v2.36 — día-HITO de la escalera de racha (cofre del 3er día, etc.): resalta. */
.streak-day.milestone {
  background: linear-gradient(160deg, rgba(242,184,75,0.25), rgba(31,138,90,0.18));
  border: 1px solid rgba(242,184,75,0.6);
  box-shadow: 0 0 12px rgba(242,184,75,0.25);
}
.streak-day.milestone .streak-reward { font-size: 17px; }

/* v2.36 — puntaje en el HUD del Triple (paridad con el clásico). */
.tt-hud-score {
  display: inline-block; margin-left: 8px; padding: 1px 8px; border-radius: 999px;
  background: rgba(0,0,0,0.28); color: #ffd76a; font-weight: 800; font-size: 12px;
  vertical-align: middle;
}

/* v2.36 — MARCOS cosméticos del tablero (sink de monedas). Borde del board según el
   marco equipado (body[data-marco]). Solo box-shadow → barato, sin reflow. */
/* v4.1.1 — los marcos aplican TAMBIÉN al Triple (#ttBoard): antes solo #board (clásico)
   y el marco equipado desaparecía al entrar al Triple — disociación visual entre modos. */
body[data-marco="marco_inti"]     #board, body[data-marco="marco_inti"]     #ttBoard { box-shadow: 0 0 0 3px #f2b84b inset, 0 0 22px rgba(242,184,75,0.45); border-radius: 14px; }
body[data-marco="marco_quebrada"] #board, body[data-marco="marco_quebrada"] #ttBoard { box-shadow: 0 0 0 3px #6fe3c1 inset, 0 0 22px rgba(111,227,193,0.40); border-radius: 14px; }
body[data-marco="marco_carnaval"] #board, body[data-marco="marco_carnaval"] #ttBoard { box-shadow: 0 0 0 3px #f2569b inset, 0 0 22px rgba(242,86,155,0.40);  border-radius: 14px; }
body[data-marco="marco_condor"]   #board, body[data-marco="marco_condor"]   #ttBoard { box-shadow: 0 0 0 3px #c89af2 inset, 0 0 26px rgba(200,154,242,0.50); border-radius: 14px; }

/* v2.37 — RAREZA de cofres: cada cofre se distingue por color (borde + etiqueta) y los
   listos brillan. Antes todos se veían iguales (🎁/🔒) y no se sabía cuál abrir-ya. */
.chest-slot { border: 1.5px solid var(--chest-col, rgba(242,184,75,0.45)) !important; position: relative; }
.chest-slot.ready { box-shadow: 0 0 14px var(--chest-col, #f2b84b); }
.chest-slot .chest-ico { position: relative; display: inline-block; }
.chest-slot .chest-lock { position: absolute; right: -7px; bottom: -5px; font-size: 0.48em; opacity: 0.85; }
.chest-rarity { font-size: 12px; font-weight: 800; color: var(--chest-col, #f2b84b); opacity: 0.95; margin: 1px 0 2px; text-transform: uppercase; letter-spacing: 0.4px; }

/* v2.34 — SALIDA COHERENTE: "lo que entra animado, se va animado". Estas clases las
   agrega dismissEl()/toast.js justo antes de eliminar el nodo (sólo si NO hay
   reduce-motion → el JS quita al instante en ese caso). Todo transform/opacity (GPU). */
.overlay-out { animation: overlayFadeOut .26s ease-in forwards !important; }
@keyframes overlayFadeOut { to { opacity: 0; } }
.overlay-out .dialog,
.overlay-out [class*="-dialog"] { animation: dialogScaleOut .26s ease-in forwards !important; }
@keyframes dialogScaleOut { to { transform: scale(0.92) translateY(16px); opacity: 0; } }
.stuck-bar.stuck-bar-out { animation: stuckBarOut .24s ease-in forwards !important; }
@keyframes stuckBarOut { to { transform: translateY(110%); opacity: 0; } }
.vision-countdown.vision-countdown-out { animation: visionCdOut .22s ease-in forwards !important; }
@keyframes visionCdOut { to { transform: translateY(-12px) scale(0.85); opacity: 0; } }
.booster-armed-badge.armed-badge-out { animation: armedBadgeOut .2s ease-in forwards !important; }
@keyframes armedBadgeOut { to { transform: translateY(10px); opacity: 0; } }
.toast.toast-out { animation: toastOut .2s ease-in forwards !important; }
@keyframes toastOut { to { transform: translateY(-10px); opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  .surprise-bonus, .wng-fill, .score-convert, .milestone-bonus, .streak-bonus,
  .win-dialog.win-perfect .win-title,
  .win-rewards .chip.coins.counting, .win-rewards .chip.coins.coin-landed { animation: none !important; }
}

.win-dialog .row {
  position: relative;
  display: flex; gap: 10px; margin-top: 16px;
}
.win-dialog .row .btn {
  flex: 1;
}

/* Confetti */
.confetti-layer {
  position: fixed; inset: 0;
  pointer-events: none;
  z-index: 101;
  overflow: hidden;
}
.confetti {
  position: absolute;
  top: -20px;
  width: 11px; height: 18px;
  border-radius: 2px;
  animation: confettiFall ease-out forwards;
  --drift: 0px;
}
@keyframes confettiFall {
  0%   { transform: translateY(0) translateX(0) rotate(0deg); opacity: 1; }
  100% { transform: translateY(110vh) translateX(var(--drift)) rotate(720deg); opacity: 0; }
}

/* Score chip en HUD */
.hud-stat.score .v {
  color: #f2b84b;
  font-weight: 900;
  text-shadow: 0 0 8px rgba(242, 184, 75, 0.4);
}

/* ────────────── splash screen ────────────── */
.splash {
  position: fixed;
  inset: 0;
  background: radial-gradient(ellipse at center, #3a1f5a 0%, #1a0820 60%, #0e0418 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9999;
  transition: opacity 0.6s ease-out, transform 0.6s ease-out;
}
.splash.splash-hide {
  opacity: 0;
  transform: scale(1.05);
  pointer-events: none;
}
.splash-inner {
  text-align: center;
  animation: splashFadeIn 0.8s ease-out;
}
@keyframes splashFadeIn {
  0%   { opacity: 0; transform: translateY(20px); }
  100% { opacity: 1; transform: translateY(0); }
}
.splash-logo {
  width: 140px;
  height: 140px;
  filter: drop-shadow(0 8px 24px rgba(242, 184, 75, 0.4));
  animation: splashLogoFloat 2.4s ease-in-out infinite;
}
@keyframes splashLogoFloat {
  0%, 100% { transform: translateY(0) rotate(-2deg); }
  50%      { transform: translateY(-6px) rotate(2deg); }
}
.splash-title {
  margin: 16px 0 4px;
  font-family: 'Fraunces', ui-serif, Georgia, serif;
  font-weight: 900;
  font-size: 36px;
  color: #f2b84b;
  letter-spacing: 1px;
  text-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
}
.splash-subtitle {
  margin: 0 0 24px;
  font-family: 'Fraunces', ui-serif, Georgia, serif;
  font-weight: 400;
  font-style: italic;
  font-size: 22px;
  color: #dfd8c4;
  letter-spacing: 4px;
  opacity: 0.85;
}
.splash-loader {
  width: 180px;
  height: 4px;
  margin: 0 auto;
  background: rgba(242, 184, 75, 0.2);
  border-radius: 2px;
  overflow: hidden;
}
.splash-loader-bar {
  height: 100%;
  background: linear-gradient(90deg, transparent, #f2b84b, transparent);
  animation: loaderSweep 1.4s ease-in-out infinite;
}
@keyframes loaderSweep {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(280%); }
}

/* ────────────── page transitions ────────────── */
.page-fade-out {
  opacity: 0;
  transform: translateY(-8px);
  transition: opacity 0.12s ease-out, transform 0.12s ease-out;
}
.page-fade-in {
  animation: pageIn 0.28s ease-out;
}
@keyframes pageIn {
  0%   { opacity: 0; transform: translateY(12px); }
  100% { opacity: 1; transform: translateY(0); }
}

/* ────────────── navbar SVG icons ────────────── */
.navbar .nav-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  color: var(--ink-dim, #a89568);
  transition: color 0.2s, transform 0.15s;
}
.navbar .nav-btn svg {
  stroke: currentColor;
}
.navbar .nav-btn[aria-current="page"] {
  color: #f2b84b;
  transform: translateY(-2px);
}
.navbar .nav-btn[aria-current="page"] svg {
  filter: drop-shadow(0 0 8px rgba(242, 184, 75, 0.5));
}
.navbar .nav-btn small {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.3px;
}

/* ────────────── hero ────────────── */
.hero {
  position: relative;
  padding: 24px 20px 22px;
  border-radius: 18px;
  background: linear-gradient(135deg, #2d1840 0%, #5a2548 60%, #3a1f5a 100%);
  border: 2px solid rgba(242, 184, 75, 0.3);
  overflow: hidden;
  margin-bottom: 16px;
}
.hero::before {
  content: '';
  position: absolute;
  top: -40%;
  right: -20%;
  width: 200px;
  height: 200px;
  background: radial-gradient(circle, rgba(242, 184, 75, 0.25) 0%, transparent 70%);
  pointer-events: none;
}
.hero h1 {
  position: relative;
  margin: 0 0 4px;
  font-family: 'Fraunces', ui-serif, Georgia, serif;
  font-weight: 900;
  font-size: 28px;
  color: #f2b84b;
}
.hero-sub {
  position: relative;
  margin: 0 0 14px;
  font-size: 13px;
  color: #dfd8c4;
  opacity: 0.85;
}
.hero .row {
  position: relative;
}

/* ────────────── home stat cards ────────────── */
.stat-card {
  display: flex;
  flex-direction: column;
  background: rgba(36, 17, 73, 0.6);
  border: 1px solid rgba(242, 184, 75, 0.15);
  padding: 12px 14px;
  border-radius: 12px;
  transition: transform 0.2s, border-color 0.2s;
}
.stat-card:hover {
  border-color: rgba(242, 184, 75, 0.4);
  transform: translateY(-2px);
}
.stat-card .k {
  font-size: 12px;
  color: var(--ink-dim, #a89568);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin-bottom: 4px;
}
.stat-card .v {
  font-family: 'Fraunces', ui-serif, Georgia, serif;
  font-size: 24px;
  font-weight: 900;
  color: #fef7e3;
}
.stat-card .frac {
  font-size: 14px;
  color: var(--ink-dim, #a89568);
  font-weight: 600;
}

/* ────────────── daily challenge section ────────────── */
.daily-section {
  margin-top: 18px;
}
.daily-section .section-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
}
.daily-section h2 {
  font-family: 'Fraunces', ui-serif, Georgia, serif;
  font-weight: 700;
  font-size: 19px;
  color: #f2b84b;
  margin: 0;
}
.section-sub {
  font-size: 12px;
  color: var(--ink-dim, #a89568);
  margin: 0 0 10px;
}
.timer {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 13px;
  color: #6fe3c1;
  background: rgba(111, 227, 193, 0.1);
  padding: 4px 10px;
  border-radius: 8px;
  font-variant-numeric: tabular-nums;
}

.daily-card {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 12px;
  background: linear-gradient(135deg, #2d1840, #3a1f5a);
  border: 1px solid rgba(242, 184, 75, 0.25);
  padding: 14px 16px;
  border-radius: 12px;
  transition: border-color 0.2s, transform 0.2s;
}
/* v2.19 — fila de cofres temporizados */
.chest-row { display: flex; gap: 10px; overflow-x: auto; padding: 2px; scrollbar-width: none; }
.chest-row::-webkit-scrollbar { display: none; }
.chest-slot {
  flex: 0 0 auto; width: 96px; text-align: center;
  background: linear-gradient(160deg, #2d1840, #1a1228);
  border: 1px solid rgba(242,184,75,0.25); border-radius: var(--r);
  padding: 12px 8px; display: grid; gap: 6px; justify-items: center;
}
.chest-slot.ready { border-color: var(--gold); box-shadow: 0 0 14px rgba(242,184,75,0.35); animation: chestReadyPulse 1.8s ease-in-out infinite; }
.chest-slot .chest-ico { font-size: 34px; line-height: 1; }
.chest-slot.ready .chest-ico { animation: char-portrait-bob 1.6s ease-in-out infinite; }
.chest-slot .chest-state { font-size: 12px; color: var(--ink-dim); font-weight: 700; }
.chest-slot.ready .chest-state { color: var(--gold); }
@keyframes chestReadyPulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.04); }
}
.reduce-motion .chest-slot.ready,
.reduce-motion .chest-slot.ready .chest-ico { animation: none; }
.daily-card:hover {
  border-color: rgba(242, 184, 75, 0.5);
  transform: translateY(-2px);
}
.daily-card.done {
  opacity: 0.65;
}
.daily-info strong {
  color: #fef7e3;
  font-weight: 700;
  font-size: 15px;
  display: block;
}
.daily-info .daily-meta {
  font-size: 12px;
  color: var(--ink-dim, #a89568);
  margin-top: 2px;
}

.btn.gold {
  background: linear-gradient(135deg, #f2b84b, #c46a2a);
  color: #0e0418;
  font-weight: 800;
  border: none;
  box-shadow: 0 4px 14px rgba(242, 184, 75, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.3);
}
.btn.gold:hover {
  filter: brightness(1.08);
}

/* ────────────── streak ladder ────────────── */
.streak-ladder {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 6px;
}
.streak-day {
  background: rgba(36, 17, 73, 0.5);
  border: 1px solid rgba(255, 255, 255, 0.05);
  border-radius: 10px;
  padding: 8px 4px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  transition: all 0.2s;
}
.streak-day .streak-num {
  font-family: 'Fraunces', serif;
  font-weight: 700;
  font-size: 18px;
  color: var(--ink-dim, #a89568);
}
.streak-day .streak-reward {
  font-size: 12px;
  color: var(--ink-dim, #a89568);
  font-weight: 600;
}
.streak-day.reached {
  background: linear-gradient(135deg, rgba(111, 227, 193, 0.18), rgba(111, 227, 193, 0.05));
  border-color: rgba(111, 227, 193, 0.45);
}
.streak-day.reached .streak-num {
  color: #6fe3c1;
}
.streak-day.today {
  background: linear-gradient(135deg, rgba(242, 184, 75, 0.25), rgba(242, 184, 75, 0.08));
  border-color: #f2b84b;
  animation: streakTodayPulse 2s ease-in-out infinite;
}
.streak-day.today .streak-num {
  color: #f2b84b;
  text-shadow: 0 0 8px rgba(242, 184, 75, 0.6);
}
@keyframes streakTodayPulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.04); }
}

/* ────────────── trail (sendero) en mapa ────────────── */
.world-header {
  margin-bottom: 12px;
}
.world-title {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 8px;
}
.world-icon {
  font-size: 32px;
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.4));
}
.world-title h3 {
  margin: 0;
  font-family: 'Fraunces', serif;
  font-size: 19px;
  color: #f2b84b;
}
.world-role {
  margin: 2px 0 0;
  font-size: 12px;
  color: var(--ink-dim, #a89568);
}
.world-progress {
  background: rgba(0, 0, 0, 0.25);
  padding: 8px 12px;
  border-radius: 8px;
}
.world-progress.locked {
  text-align: center;
  padding: 12px;
}
.lock-badge {
  color: var(--ink-dim, #a89568);
  font-size: 12px;
  font-style: italic;
}
.progress-bar {
  height: 6px;
  background: rgba(255, 255, 255, 0.08);
  border-radius: 3px;
  overflow: hidden;
}
.progress-fill {
  height: 100%;
  background: linear-gradient(90deg, #6fe3c1, #f2b84b);
  border-radius: 3px;
  transition: width 0.4s ease-out;
}
.progress-meta {
  display: flex;
  justify-content: space-between;
  margin-top: 4px;
  font-size: 12px;
  color: var(--ink-dim, #a89568);
}

.trail-container {
  background: linear-gradient(180deg, rgba(36, 17, 73, 0.35), rgba(36, 17, 73, 0.15));
  border-radius: 14px;
  padding: 10px;
  margin-top: 10px;
  overflow-x: auto;
}
/* v2.54 — píldoras de ventana del mapa: el mundo actual muestra tu nivel + pocas
   etapas; estas píldoras resumen lo de antes/después y dejan ver todo el mundo. */
.trail-window-pill {
  display: block; width: 100%; box-sizing: border-box;
  text-align: center; font-family: 'Sora','Inter',system-ui,sans-serif;
  font-size: 13px; font-weight: 800; letter-spacing: 0.3px;
  padding: 11px 14px; margin: 12px 0 0; border-radius: 13px;
  border: 1px solid rgba(242,184,75,0.28); color: var(--ink-dim);
  background: linear-gradient(180deg, rgba(58,30,90,0.55), rgba(36,17,73,0.42));
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.06), 0 4px 14px rgba(0,0,0,0.28);
}
.trail-window-pill.behind { color: rgba(143,235,209,0.95); border-color: rgba(111,227,193,0.3); margin: 0 0 8px; }
.trail-window-pill.ahead, .trail-window-pill.collapse {
  cursor: pointer; color: #2a1608; border: none;
  background: linear-gradient(180deg, #ffd76a, #e7a23a);
  box-shadow: 0 4px 0 #9a5d12, 0 9px 18px rgba(0,0,0,0.38);
  text-shadow: 0 1px 0 rgba(255,255,255,0.35); transition: transform .1s, box-shadow .1s;
}
.trail-window-pill.ahead:active, .trail-window-pill.collapse:active { transform: translateY(2px); box-shadow: 0 2px 0 #9a5d12, 0 4px 10px rgba(0,0,0,0.32); }
.trail-window-pill.collapse { margin: 0 0 10px; color: #fff; background: linear-gradient(180deg, #8a7bb5, #5a4888); box-shadow: 0 4px 0 #3a2c66, 0 9px 18px rgba(0,0,0,0.34); text-shadow: 0 1px 0 rgba(0,0,0,0.25); }

/* v2.54 — SOFT-STOP: cierre de sesión amable tras 3 niveles seguidos. */
.soft-stop-overlay {
  position: fixed; inset: 0; z-index: 9700;
  display: flex; align-items: center; justify-content: center;
  background: rgba(10, 4, 24, 0.72); backdrop-filter: blur(4px);
  animation: chapter-fade-in 0.3s ease-out;
}
.soft-stop-overlay.overlay-out { animation: chapter-fade-out 0.22s ease-in forwards; }
.soft-stop-card {
  max-width: 320px; width: 86%; text-align: center;
  background: linear-gradient(180deg, #2a1850, #1a0e34);
  border: 1px solid rgba(242,184,75,0.35); border-radius: 18px;
  padding: 22px 20px; box-shadow: 0 18px 48px rgba(0,0,0,0.6);
}
.soft-stop-card .ss-moon { font-size: 40px; margin-bottom: 6px; }
.soft-stop-card h2 { font-family: 'Fraunces', ui-serif, Georgia, serif; font-size: 20px; margin: 0 0 8px; color: var(--ink); }
.soft-stop-card p { font-size: 14px; color: var(--ink-dim); margin: 0 0 16px; line-height: 1.45; }
.soft-stop-card .ss-actions { display: flex; flex-direction: column; gap: 8px; }
.trail-svg {
  display: block;
  margin: 0 auto;
  max-width: 100%;
}
.trail-node {
  transition: transform 0.2s;
}
.trail-node:not(.locked):hover {
  transform: scale(1.08);
  transform-origin: center;
}
/* v2.55 — el glow del nodo actual ahora es un <circle> propio en el SVG (sin filter pesado). */
/* v2.29 — CÁMARA del sendero: foco en tu zona + mini-metas (cofres) + avatar */
.trail-node.far { opacity: 0.82; transition: opacity .35s ease; }   /* v2.55 — lejanos APENAS atenuados (no borrados) */
.milestone-marker { transform-box: fill-box; transform-origin: center; }
.milestone-marker.next { animation: msNextPulse 1.3s ease-in-out infinite; }
@keyframes msNextPulse { 0%,100% { opacity: 1; } 50% { opacity: 0.45; } }
.milestone-marker.done { opacity: 0.85; }
.map-avatar { animation: mapAvatarBob 1.8s ease-in-out infinite; }
@keyframes mapAvatarBob { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-4px); } }
@media (prefers-reduced-motion: reduce) {
  .milestone-marker.next, .map-avatar { animation: none !important; }
}

.world {
  background: linear-gradient(180deg, rgba(36, 17, 73, 0.4), rgba(36, 17, 73, 0.2));
  border: 1px solid rgba(242, 184, 75, 0.15);
  border-radius: 14px;
  padding: 14px;
  margin-bottom: 16px;
}

/* ────────────── galería ────────────── */
.gallery-progress {
  margin: 10px 0 6px;
}
.gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(98px, 1fr));
  gap: 10px;
  background: rgba(14, 4, 24, 0.4);
  padding: 12px;
  border-radius: 12px;
}
.gallery-item {
  background: rgba(36, 17, 73, 0.5);
  border: 1px solid rgba(255, 255, 255, 0.05);
  border-radius: 10px;
  padding: 8px;
  text-align: center;
  position: relative;
  transition: transform 0.2s, border-color 0.2s;
}
.gallery-item.unlocked {
  border-color: rgba(242, 184, 75, 0.3);
}
.gallery-item.unlocked:hover {
  transform: translateY(-3px) scale(1.03);
  border-color: #f2b84b;
}
.gallery-item.locked {
  opacity: 0.5;
  filter: grayscale(1) brightness(0.7);   /* v2.19: bloqueada = apagada, no solo translúcida */
}
.gallery-item.unlocked { transition: transform .12s ease, box-shadow .15s ease; }
.gallery-item.unlocked:hover { transform: translateY(-3px) scale(1.03); box-shadow: 0 6px 16px rgba(0,0,0,0.4), 0 0 0 1px var(--gold); }
.reduce-motion .gallery-item.unlocked:hover { transform: none; }
.gallery-item img {
  width: 80px;
  height: 100px;
  display: block;
  margin: 0 auto 4px;
}
.gallery-item .gallery-locked {
  width: 80px;
  height: 100px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 36px;
  color: rgba(255, 255, 255, 0.2);
  margin: 0 auto 4px;
}
/* v20 — Museo: ícono grande de la reliquia (reusa la grilla de galería). */
.museum-item .relic-icon {
  width: 80px;
  height: 100px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 46px;
  margin: 0 auto 4px;
  filter: drop-shadow(0 3px 6px rgba(0, 0, 0, 0.45));
}
.gallery-label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  color: #fef7e3;
}
.gallery-rarity {
  display: inline-block;
  margin-top: 4px;
  padding: 1px 6px;
  border-radius: 4px;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.rarity-common    { background: rgba(168, 149, 104, 0.3); color: #d4b878; }
.rarity-rare      { background: rgba(111, 227, 193, 0.25); color: #6fe3c1; }
.rarity-epic      { background: rgba(200, 154, 242, 0.25); color: #c89af2; }
.rarity-legendary { background: rgba(242, 184, 75, 0.25); color: #f2b84b; }

/* ────────────── home quick links ────────────── */
.quick-links {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}
.quick-link {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 14px 8px;
  background: linear-gradient(135deg, #2d1840, #3a1f5a);
  border: 1px solid rgba(242, 184, 75, 0.2);
  border-radius: 12px;
  color: #fef7e3;
  cursor: pointer;
  transition: all 0.2s;
}
.quick-link:hover {
  border-color: #f2b84b;
  transform: translateY(-2px);
}
.quick-link .ql-icon { font-size: 26px; }
.quick-link .ql-label {
  font-weight: 700;
  font-size: 13px;
  color: #fef7e3;
}
.quick-link .ql-meta {
  font-size: 12px;
  color: var(--ink-dim, #a89568);
  font-weight: 600;
}
.quick-link .ql-meta.live-dot {
  color: #6fe3c1;
  animation: livePulse 1.8s ease-in-out infinite;
}
@keyframes livePulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}

/* PR-V12-23 — Home foco_v2 (flag off por default, ver home_orchestrator.js).
   "Más" es <details> nativo: sin JS de toggle, cero costo. Contenido interno
   reusa .daily-section/.quick-links tal cual (mismas reglas de arriba). */
.home-v2 .more-toggle summary { list-style: none; cursor: pointer; }
.home-v2 .more-toggle summary::-webkit-details-marker { display: none; }

/* ────────────── pase andino visual ────────────── */
.pass-header { margin-bottom: 12px; }
.section-h2 {
  font-family: 'Fraunces', ui-serif, Georgia, serif;
  font-weight: 700;
  font-size: 19px;
  color: #f2b84b;
  margin: 22px 0 12px;
}
.pass-progress-card {
  background: linear-gradient(135deg, #2d1840, #3a1f5a);
  border: 2px solid rgba(242, 184, 75, 0.3);
  border-radius: 14px;
  padding: 14px 16px;
  margin-bottom: 14px;
}
.pass-progress-info {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  margin-bottom: 10px;
}
.pass-tier-current {
  font-family: 'Fraunces', serif;
  font-weight: 900;
  font-size: 28px;
  color: #f2b84b;
}
.pass-xp {
  font-size: 12px;
  color: var(--ink-dim, #a89568);
  margin-top: -4px;
}
.pass-next {
  font-size: 12px;
  color: #6fe3c1;
}
.pass-bar {
  height: 10px;
  background: rgba(0, 0, 0, 0.4);
  border-radius: 5px;
  overflow: hidden;
}
.pass-fill {
  height: 100%;
  background: linear-gradient(90deg, #f2b84b, #c46a2a);
  border-radius: 5px;
  transition: width 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

.pass-premium-cta {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 12px;
  align-items: center;
  background: linear-gradient(135deg, #5a2548, #3a1f5a);
  border: 2px solid #f2b84b;
  border-radius: 14px;
  padding: 14px 16px;
  margin-bottom: 16px;
  box-shadow: 0 0 20px rgba(242, 184, 75, 0.2);
}
.pass-premium-cta .cta-content strong {
  display: block;
  color: #f2b84b;
  font-size: 16px;
  margin-bottom: 4px;
}
.pass-premium-cta .cta-content p {
  margin: 0;
  font-size: 12px;
  color: var(--ink-dim, #a89568);
}
.pass-premium-active {
  background: linear-gradient(135deg, rgba(242, 184, 75, 0.15), rgba(200, 154, 242, 0.15));
  border: 1px solid #f2b84b;
  border-radius: 10px;
  padding: 10px 14px;
  text-align: center;
  font-size: 13px;
  color: #f2b84b;
  margin-bottom: 14px;
}

.pass-track-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.pass-tier-card {
  display: grid;
  grid-template-columns: 50px 1fr 1fr;
  gap: 10px;
  align-items: center;
  background: rgba(36, 17, 73, 0.5);
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 10px;
  padding: 10px 12px;
  transition: border-color 0.2s, background 0.2s;
}
.pass-tier-card.earned {
  border-color: rgba(111, 227, 193, 0.45);
  background: linear-gradient(135deg, rgba(111, 227, 193, 0.05), rgba(36, 17, 73, 0.5));
}
.pass-tier-card.current {
  border-color: #f2b84b;
  background: linear-gradient(135deg, rgba(242, 184, 75, 0.1), rgba(36, 17, 73, 0.5));
}
.pass-tier-card.claimed {
  opacity: 0.6;
}
.pass-tier-num {
  text-align: center;
  font-family: 'Fraunces', serif;
  font-size: 22px;
  font-weight: 900;
  color: #f2b84b;
}
.pass-tier-reward {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  position: relative;
}
.pass-tier-reward.locked .tier-value { opacity: 0.4; }
.pass-tier-reward .tier-label {
  display: block;
  font-size: 12px;
  color: var(--ink-dim, #a89568);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  font-weight: 700;
}
.pass-tier-reward .tier-value {
  color: #fef7e3;
  font-weight: 600;
}
.btn-pico {
  background: linear-gradient(135deg, #f2b84b, #c46a2a);
  color: #0e0418;
  border: none;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  font-weight: 900;
  font-size: 14px;
  cursor: pointer;
  margin-left: 4px;
}
.claimed-mark {
  color: #6fe3c1;
  font-weight: 900;
  font-size: 14px;
  margin-left: 4px;
}

/* ────────────── events redesign ────────────── */
.events-header { margin-bottom: 16px; }
.event-card-v2 {
  background: linear-gradient(135deg, #2d1840, #3a1f5a);
  border: 1px solid rgba(255, 255, 255, 0.05);
  border-left: 4px solid #c46a2a;
  border-radius: 14px;
  padding: 14px 16px;
  margin-bottom: 14px;
  transition: transform 0.2s;
}
.event-card-v2:hover { transform: translateX(2px); }
.event-card-header {
  display: flex;
  gap: 12px;
  align-items: center;
  margin-bottom: 10px;
}
.event-icon-big {
  width: 48px;
  height: 48px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 28px;
  border: 2px solid;
}
.event-card-title h3 {
  margin: 0 0 4px;
  font-family: 'Fraunces', serif;
  font-size: 17px;
  color: #fef7e3;
}
.event-badge {
  display: inline-block;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.5px;
  padding: 2px 8px;
  border-radius: 4px;
}
.event-badge.live {
  background: linear-gradient(135deg, #c41e3a, #8b3a4a);
  color: #fef7e3;
  animation: livePulse 1.8s ease-in-out infinite;
}
.event-badge.soon { background: rgba(242, 184, 75, 0.25); color: #f2b84b; }
.event-badge.upcoming { background: rgba(168, 149, 104, 0.25); color: #a89568; }
.event-narrative {
  margin: 0 0 10px;
  font-size: 13px;
  color: #dfd8c4;
  font-style: italic;
  line-height: 1.5;
}
.event-meta-row {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 10px;
  font-size: 12px;
}
.event-timer { color: #6fe3c1; font-family: 'IBM Plex Mono', monospace; }
.event-participants { color: var(--ink-dim, #a89568); }
.event-rewards {
  margin: 10px 0;
}
.event-rewards-label {
  font-size: 12px;
  color: var(--ink-dim, #a89568);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin-bottom: 4px;
}
.event-reward-chip {
  display: inline-block;
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid rgba(242, 184, 75, 0.3);
  padding: 4px 10px;
  border-radius: 12px;
  font-size: 12px;
  margin: 0 4px 4px 0;
  color: #f2b84b;
}
.event-action { width: 100%; margin-top: 6px; }
.events-footer { margin-top: 14px; }

/* ────────────── shop ────────────── */
.shop-balance-card {
  display: flex;
  gap: 16px;
  justify-content: center;
  background: linear-gradient(135deg, #2d1840, #3a1f5a);
  border: 1px solid rgba(242, 184, 75, 0.3);
  border-radius: 14px;
  padding: 14px;
  margin-bottom: 14px;
}
.balance-item {
  display: flex;
  align-items: center;
  gap: 6px;
}
.balance-icon { font-size: 22px; }
.balance-val {
  font-family: 'Fraunces', serif;
  font-weight: 900;
  font-size: 22px;
  color: #f2b84b;
}
.balance-label {
  font-size: 12px;
  color: var(--ink-dim, #a89568);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.shop-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 12px;
}
.shop-bundle {
  position: relative;
  background: linear-gradient(180deg, #2d1840, #1a0820);
  border: 1px solid rgba(242, 184, 75, 0.25);
  border-radius: 14px;
  padding: 14px 12px 12px;
  text-align: center;
  transition: transform 0.2s, border-color 0.2s;
  overflow: hidden;
}
.shop-bundle:hover {
  transform: translateY(-3px);
  border-color: #f2b84b;
}
.shop-bundle.featured {
  border: 2px solid #f2b84b;
  background: linear-gradient(180deg, #5a3878, #3a1f5a);
  box-shadow: 0 0 20px rgba(242, 184, 75, 0.25);
}
.bundle-tag {
  position: absolute;
  top: 6px;
  left: 6px;
  font-size: 12px;
  font-weight: 800;
  padding: 2px 8px;
  border-radius: 4px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
}
.bundle-discount {
  position: absolute;
  top: 6px;
  right: 6px;
  background: linear-gradient(135deg, #c41e3a, #8b3a4a);
  color: #fef7e3;
  font-size: 12px;
  font-weight: 800;
  padding: 2px 8px;
  border-radius: 4px;
}
.bundle-items {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px;
  margin: 18px 0 8px;
  min-height: 50px;
}
.bundle-item {
  display: flex;
  align-items: center;
  gap: 2px;
  font-size: 13px;
  font-weight: 700;
  color: #fef7e3;
}
.bundle-icon { font-size: 22px; }
.bundle-amount { font-size: 12px; opacity: 0.85; }
.bundle-name {
  font-size: 12px;
  color: var(--ink-dim, #a89568);
  margin-bottom: 8px;
  min-height: 28px;
}
.bundle-buy { width: 100%; padding: 8px; font-size: 14px; }

.ad-card {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 10px;
  align-items: center;
  background: rgba(36, 17, 73, 0.5);
  border: 1px solid rgba(111, 227, 193, 0.3);
  border-radius: 12px;
  padding: 14px 16px;
  margin-top: 8px;
}
.ad-card strong { color: #6fe3c1; display: block; font-size: 14px; }
.ad-meta { font-size: 12px; color: var(--ink-dim, #a89568); margin-top: 2px; }

/* ────────────── achievements ────────────── */
.achievements-header { margin-bottom: 14px; }
.ach-progress-card {
  background: linear-gradient(135deg, #2d1840, #3a1f5a);
  border: 1px solid rgba(242, 184, 75, 0.3);
  border-radius: 12px;
  padding: 12px 14px;
  margin-bottom: 18px;
}
.ach-progress-card .progress-bar { height: 8px; }
.ach-section-title {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 22px 0 10px;
}
.ach-section-title .cat-icon { font-size: 22px; }
.ach-section-title .cat-count {
  font-family: system-ui, sans-serif;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-dim, #a89568);
  margin-left: auto;
  background: rgba(0, 0, 0, 0.25);
  padding: 2px 8px;
  border-radius: 8px;
}

.ach-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.ach-row {
  display: grid;
  grid-template-columns: 48px 1fr auto;
  gap: 12px;
  align-items: center;
  background: rgba(36, 17, 73, 0.5);
  border: 1px solid rgba(255, 255, 255, 0.05);
  border-radius: 12px;
  padding: 10px 12px;
  transition: border-color 0.2s, background 0.2s;
}
.ach-row.unlocked {
  border-color: rgba(111, 227, 193, 0.45);
  background: linear-gradient(135deg, rgba(111, 227, 193, 0.05), rgba(36, 17, 73, 0.5));
}
.ach-row.claimed {
  opacity: 0.6;
}
.ach-row.locked { opacity: 0.7; }
.ach-row.ach-tier-5.unlocked {
  border-color: #f2b84b;
  background: linear-gradient(135deg, rgba(242, 184, 75, 0.15), rgba(36, 17, 73, 0.5));
  box-shadow: 0 0 12px rgba(242, 184, 75, 0.25);
}
.ach-row-icon {
  font-size: 32px;
  text-align: center;
  background: rgba(0, 0, 0, 0.3);
  border-radius: 50%;
  width: 48px;
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.ach-row.locked .ach-row-icon { filter: grayscale(1) brightness(0.7); }
.ach-row-title {
  font-weight: 700;
  font-size: 14px;
  color: #fef7e3;
}
.ach-row-desc {
  font-size: 12px;
  color: var(--ink-dim, #a89568);
  margin-top: 2px;
}
.ach-row-progress {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 6px;
}
.ach-row-bar {
  flex: 1;
  height: 4px;
  background: rgba(255, 255, 255, 0.08);
  border-radius: 2px;
  overflow: hidden;
}
.ach-row-fill {
  height: 100%;
  background: linear-gradient(90deg, #6fe3c1, #f2b84b);
  border-radius: 2px;
}
.ach-row-frac {
  font-size: 12px;
  color: var(--ink-dim, #a89568);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.ach-claimed-mark {
  color: #6fe3c1;
  font-weight: 900;
  font-size: 20px;
}
.ach-locked-reward {
  font-size: 12px;
  color: var(--ink-dim, #a89568);
  white-space: nowrap;
}

/* Achievement unlock toast (top-right) */
.achievement-unlock-toast {
  position: fixed;
  top: 20px;
  right: 20px;
  background: linear-gradient(135deg, #2d1840, #5a2548);
  border: 2px solid #f2b84b;
  border-radius: 14px;
  padding: 14px 18px;
  display: flex;
  gap: 12px;
  align-items: center;
  z-index: 300;
  box-shadow: 0 8px 32px rgba(242, 184, 75, 0.35), 0 0 0 0 rgba(242, 184, 75, 0.5);
  transform: translateX(120%);
  transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
  max-width: 320px;
}
.achievement-unlock-toast.show {
  transform: translateX(0);
  animation: achGlow 1.6s ease-out;
}
@keyframes achGlow {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.04); }
}
.achievement-unlock-toast .ach-icon {
  font-size: 36px;
  flex-shrink: 0;
}
.achievement-unlock-toast .ach-label {
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.5px;
  color: #f2b84b;
  text-transform: uppercase;
}
.achievement-unlock-toast .ach-name {
  font-family: 'Fraunces', serif;
  font-weight: 700;
  font-size: 15px;
  color: #fef7e3;
  margin: 2px 0;
}
.achievement-unlock-toast .ach-reward {
  font-size: 12px;
  color: #6fe3c1;
}

/* ────────────── high contrast mode ────────────── */
body.high-contrast .ach-row,
body.high-contrast .pass-tier-card,
body.high-contrast .event-card-v2,
body.high-contrast .shop-bundle,
body.high-contrast .stat-card,
body.high-contrast .daily-card,
body.high-contrast .quick-link {
  border-width: 2px !important;
  background: #0e0418 !important;
}
body.high-contrast .ach-row.unlocked,
body.high-contrast .pass-tier-card.earned {
  border-color: #6fe3c1 !important;
}
body.high-contrast .ach-row.ach-tier-5.unlocked,
body.high-contrast .pass-tier-card.current,
body.high-contrast .quick-link:hover {
  border-color: #ffffff !important;
}
body.high-contrast {
  --ink-dim: #ffffff !important;
}
body.high-contrast h1, body.high-contrast h2, body.high-contrast h3 {
  color: #ffeb6b !important;
}
body.high-contrast .btn {
  border: 2px solid #ffffff !important;
}

/* ────────────── consent flow ────────────── */
.consent-overlay {
  position: fixed; inset: 0; z-index: 300;
  background: linear-gradient(180deg, rgba(26,8,32,0.96), rgba(42,21,56,0.96));
  backdrop-filter: blur(8px);
  display: grid; place-items: center;
  padding: 16px;
  animation: fadein .2s ease-out;
  overflow-y: auto;
}
.consent-card {
  background: var(--bg-elev);
  border-radius: var(--r-lg);
  padding: 24px;
  max-width: 440px; width: 100%;
  box-shadow: var(--shadow-lg);
  border: 1px solid rgba(242,184,75,0.2);
  animation: dialogin .25s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.consent-header {
  margin-bottom: 14px;
  border-bottom: 1px solid rgba(255,255,255,0.06);
  padding-bottom: 10px;
}
.consent-step {
  font-family: var(--font-body);
  font-size: 12px;
  color: var(--ink-dim);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-weight: 600;
}
.consent-card h2 {
  margin: 6px 0 0;
  font-size: 22px;
  font-family: var(--font-display);
  font-weight: 800;
  line-height: 1.15;
}
.consent-body { margin: 14px 0; }
.consent-body p { font-size: 14px; line-height: 1.55; margin: 0 0 10px; }
.consent-note { font-size: 12px; color: var(--ink-dim); font-style: italic; }
.consent-list { padding-left: 0; list-style: none; }
.consent-list li {
  font-size: 13px;
  line-height: 1.5;
  padding: 8px 12px;
  border-left: 3px solid var(--gold);
  background: rgba(0,0,0,0.18);
  border-radius: 0 6px 6px 0;
  margin-bottom: 6px;
}
.consent-options { display: grid; gap: 8px; margin: 14px 0; }
.consent-actions {
  display: flex; gap: 10px; justify-content: flex-end;
  margin-top: 16px; padding-top: 14px;
  border-top: 1px solid rgba(255,255,255,0.06);
  flex-wrap: wrap;
}

/* ────────────── tutorial bubble ────────────── */
.tutorial-bubble {
  position: fixed;
  z-index: 150;
  background: linear-gradient(180deg, var(--bg-elev), var(--bg-elev-2));
  color: var(--ink);
  padding: 14px 18px;
  border-radius: var(--r);
  box-shadow: var(--shadow-lg);
  border: 1px solid rgba(242,184,75,0.4);
  max-width: 320px;
  width: calc(100% - 40px);
  animation: bubbleIn .3s cubic-bezier(0.34, 1.56, 0.64, 1);
  /* v2.43 — FIX TRABA EN CELULAR: el cartel NO debe interceptar taps del tablero.
     Antes, centrado sobre el board y con pointer-events activos, tapaba las fichas
     del medio y no se podían tocar (se sentia "trabado"). Ahora los taps pasan a
     traves del cartel; solo los botones (Ok / Saltar / A jugar) reciben el toque. */
  pointer-events: none;
}
.tutorial-bubble .tutorial-actions,
.tutorial-bubble button {
  pointer-events: auto;
}
@keyframes bubbleIn {
  from { transform: translateY(20px) scale(0.92); opacity: 0; }
  to { transform: translateY(0) scale(1); opacity: 1; }
}
.tutorial-bubble .tutorial-step {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--gold);
  font-weight: 700;
  margin-bottom: 4px;
}
.tutorial-bubble h3 {
  margin: 0 0 6px;
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 800;
}
.tutorial-bubble p {
  margin: 0 0 12px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--ink-dim);
}
.tutorial-actions {
  display: flex; gap: 6px;
  justify-content: flex-end;
  flex-wrap: wrap;
}
.tutorial-anchor-board {
  /* v2.43 — arriba, no en el centro: deja ver y tocar las fichas del medio. */
  top: 18%; left: 50%; transform: translate(-50%, -50%);
}
.tutorial-anchor-dock {
  bottom: 110px; left: 50%; transform: translateX(-50%);
}
.tutorial-anchor-center {
  top: 50%; left: 50%; transform: translate(-50%, -50%);
}

/* v2.43 — toggles de audio "a mano" en la barra del juego (música / efectos).
   El estado apagado se ve atenuado + tachado en rojo. */
.snd-toggle { position: relative; }
.snd-toggle.snd-off { opacity: 0.5; }
.snd-toggle.snd-off::after {
  content: "";
  position: absolute;
  left: 50%; top: 50%;
  width: 128%; height: 3px;   /* v4.2.5 — barra de "apagado" más gruesa = estado claro */
  background: #e0563b;
  transform: translate(-50%, -50%) rotate(-45deg);
  border-radius: 2px;
  pointer-events: none;
}

/* skip link de accesibilidad */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 8px;
  background: var(--gold);
  color: #2a1804;
  padding: 8px 14px;
  border-radius: 8px;
  z-index: 1000;
  font-weight: 700;
}
.skip-link:focus { left: 8px; }

/* ────────────── accessibility ────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}
/* Toggle in-app "Reducir movimiento" (body.reduce-motion): mismo kill-switch que
   la media query del SO, para los casos en que la preferencia del SO no está activa. */
body.reduce-motion *,
body.reduce-motion *::before,
body.reduce-motion *::after {
  animation-duration: 0.01ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.01ms !important;
  scroll-behavior: auto !important;
}

/* ────────────── responsive ────────────── */
@media (min-width: 600px) {
  .app { max-width: 540px; margin: 0 auto; box-shadow: 0 0 60px rgba(0,0,0,0.6); }
  /* gameboard-wrap mantiene full-screen (background cubre todo el viewport)
     pero los hijos directos se centran a 540px — así no ves la home detrás. */
  .gameboard-wrap {
    inset: 0; left: 0; right: 0;
    max-width: none;
    transform: none;
  }
  .gameboard-wrap > .hud,
  .gameboard-wrap > .objective-row,
  .gameboard-wrap > .layout-row,
  .gameboard-wrap > .board,
  .gameboard-wrap > .dock {
    max-width: 540px;
    margin-left: auto;
    margin-right: auto;
    width: 100%;
  }
}

/* §20 LEGIBILIDAD MÓVIL — breakpoints responsive para los tamaños
   objetivo del plan §20.2 (360×640, 390×844, 412×915, 768×1024). */

/* Teléfono chico (≤380px, ej. 360×640): compactar paddings y tipografía
   sin bajar de los mínimos §20.1 (tap 44px, emoji 26px, label 9px). */
@media (max-width: 380px) {
  html, body { font-size: 14px; }
  .hud { padding-left: 8px; padding-right: 8px; }
  .hud-stat { gap: 2px; }
  .dock { gap: 6px; }
  .booster { min-width: 52px; }   /* sigue >44px tap target */
  .objective-row, .layout-row { padding-left: 8px; padding-right: 8px; }
}

/* Teléfono grande (381–767px): tamaño base pleno, layout fluido. */
@media (min-width: 381px) and (max-width: 767px) {
  html, body { font-size: 15px; }
}

/* Tablet grande / desktop (≥900px): el .app ya queda centrado a 540px
   por el breakpoint de 600px; acá sólo se refuerza el encuadre. */
@media (min-width: 900px) {
  .app { box-shadow: 0 0 80px rgba(0,0,0,0.7); }
}

/* ════════════════════════════════════════════
   POLISH v2.6 — Error states + Loading states
   ════════════════════════════════════════════ */

/* ────────────── Skeleton loaders ────────────── */
@keyframes skeleton-pulse {
  0%, 100% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
}
.skeleton {
  background: linear-gradient(90deg,
    rgba(168, 149, 104, 0.08) 0%,
    rgba(242, 184, 75, 0.18) 50%,
    rgba(168, 149, 104, 0.08) 100%);
  background-size: 200% 100%;
  animation: skeleton-pulse 1.4s ease-in-out infinite;
  border-radius: 6px;
}
.skeleton-text { height: 14px; margin: 8px 0; }
.skeleton-text.short { width: 60%; }
.skeleton-text.medium { width: 85%; }
.skeleton-card {
  height: 96px;
  margin: 12px 0;
  border-radius: 10px;
}
.skeleton-tile {
  aspect-ratio: 220 / 280;
  border-radius: 10px;
}

/* ────────────── Route loader (full screen) ────────────── */
.route-loader {
  position: fixed;
  inset: 0;
  background: linear-gradient(180deg, #1a0820 0%, #3a1f08 100%);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 24px;
  z-index: 9000;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease-out;
}
.route-loader.active {
  opacity: 1;
  pointer-events: all;
}
.route-loader .spinner-andean {
  width: 64px;
  height: 64px;
  position: relative;
}
.route-loader .spinner-andean::before,
.route-loader .spinner-andean::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 4px solid transparent;
  border-top-color: #f2b84b;
  animation: spinner-rotate 1.2s cubic-bezier(0.6, 0.2, 0.4, 0.8) infinite;
}
.route-loader .spinner-andean::after {
  border-top-color: #c46a2a;
  animation-delay: -0.6s;
  animation-duration: 1.8s;
}
@keyframes spinner-rotate {
  to { transform: rotate(360deg); }
}
.route-loader .loader-text {
  color: #f2b84b;
  font-family: "Fraunces", ui-serif, Georgia, serif;
  font-size: 14px;
  letter-spacing: 1.4px;
  opacity: 0.85;
  text-transform: uppercase;
}

/* ────────────── Board loader (mientras carga nivel) ────────────── */
.board-loader {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 40px 20px;
  min-height: 220px;
  color: #d8c9a8;
}
.board-loader .dots {
  display: flex;
  gap: 8px;
}
.board-loader .dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #f2b84b;
  animation: dot-bounce 1.2s ease-in-out infinite;
}
.board-loader .dot:nth-child(2) { animation-delay: 0.15s; background: #c46a2a; }
.board-loader .dot:nth-child(3) { animation-delay: 0.30s; background: #8b3a4a; }
@keyframes dot-bounce {
  0%, 80%, 100% { transform: translateY(0); opacity: 0.6; }
  40% { transform: translateY(-10px); opacity: 1; }
}

/* ────────────── Error states ────────────── */
.error-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 48px 24px;
  text-align: center;
  gap: 16px;
  min-height: 320px;
}
.error-state .icon-glyph {
  width: 96px;
  height: 96px;
  border-radius: 50%;
  background: linear-gradient(135deg, #5a2548 0%, #c46a2a 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 40px;
  color: #f2b84b;
  box-shadow: 0 8px 24px rgba(0,0,0,0.4),
              inset 0 -3px 0 rgba(0,0,0,0.3),
              inset 0 2px 0 rgba(255,255,255,0.15);
}
.error-state h2 {
  color: #f2b84b;
  font-family: "Fraunces", ui-serif, serif;
  font-size: 22px;
  font-weight: 700;
  margin: 0;
  letter-spacing: 0.3px;
}
.error-state p {
  color: #d8c9a8;
  font-size: 15px;
  line-height: 1.55;
  max-width: 320px;
  margin: 0;
  opacity: 0.85;
}
.error-state .actions {
  display: flex;
  gap: 12px;
  margin-top: 12px;
  flex-wrap: wrap;
  justify-content: center;
}
.error-state .btn-retry {
  background: linear-gradient(180deg, #f2b84b 0%, #c46a2a 100%);
  color: #1a0820;
  border: none;
  padding: 12px 24px;
  border-radius: 8px;
  font-family: "Fraunces", ui-serif, serif;
  font-weight: 700;
  font-size: 14px;
  letter-spacing: 0.5px;
  cursor: pointer;
  text-transform: uppercase;
  box-shadow: 0 4px 0 rgba(0,0,0,0.35), inset 0 1px 0 rgba(255,255,255,0.3);
  transition: transform 0.1s, box-shadow 0.1s;
}
.error-state .btn-retry:active {
  transform: translateY(2px);
  box-shadow: 0 2px 0 rgba(0,0,0,0.35);
}
.error-state .btn-secondary {
  background: transparent;
  color: #d8c9a8;
  border: 1.5px solid #5a3a18;
  padding: 12px 20px;
  border-radius: 8px;
  font-size: 14px;
  cursor: pointer;
}

/* ────────────── Network/offline overlay ────────────── */
.network-banner {
  position: fixed;
  top: -60px;
  left: 0;
  right: 0;
  background: #8b3a4a;
  color: #fef7e3;
  padding: 14px 20px;
  text-align: center;
  font-size: 14px;
  font-weight: 600;
  z-index: 8000;
  transition: top 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  box-shadow: 0 4px 16px rgba(0,0,0,0.3);
}
.network-banner.visible { top: 0; }
.network-banner.success { background: #1c3a25; }

/* ────────────── Toast con icono ────────────── */
.toast.with-icon {
  display: flex;
  align-items: center;
  gap: 12px;
}
.toast.with-icon .toast-icon {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: rgba(242, 184, 75, 0.18);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-size: 16px;
}
.toast.toast-success .toast-icon { background: rgba(111, 227, 193, 0.2); color: #6fe3c1; }
.toast.toast-error .toast-icon { background: rgba(196, 30, 58, 0.2); color: #ff8b9c; }
.toast.toast-info .toast-icon { background: rgba(74, 144, 226, 0.2); color: #6fa8d4; }

/* ────────────── Button focus rings ────────────── */
button:focus-visible,
a:focus-visible,
[role="button"]:focus-visible {
  outline: 2.5px solid #f2b84b;
  outline-offset: 3px;
  border-radius: 4px;
}

/* ────────────── Button hover feedback (no haptics) ────────────── */
@media (hover: hover) {
  button:not(:disabled):hover,
  [role="button"]:not(:disabled):hover {
    filter: brightness(1.08);
  }
}

/* ────────────── Card lift on tap ────────────── */
.tappable {
  transition: transform 0.15s cubic-bezier(0.4, 0, 0.2, 1),
              box-shadow 0.15s cubic-bezier(0.4, 0, 0.2, 1);
  cursor: pointer;
}
.tappable:active {
  transform: scale(0.97);
}

/* ────────────── Empty state ────────────── */
.empty-state {
  text-align: center;
  padding: 56px 24px;
  color: #a89568;
}
.empty-state .glyph {
  font-size: 56px;
  opacity: 0.4;
  margin-bottom: 16px;
}
.empty-state h3 {
  color: #d8c9a8;
  font-family: "Fraunces", ui-serif, serif;
  font-size: 18px;
  margin: 0 0 8px 0;
}
.empty-state p {
  font-size: 14px;
  line-height: 1.5;
  margin: 0;
  max-width: 280px;
  margin: 0 auto;
  opacity: 0.8;
}

/* ────────────── Page transitions ────────────── */
.view-enter {
  opacity: 0;
  transform: translateX(20px);
}
.view-enter-active {
  opacity: 1;
  transform: translateX(0);
  transition: opacity 0.3s ease-out, transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

/* ────────────── Pull to refresh hint ────────────── */
.pull-hint {
  text-align: center;
  font-size: 12px;
  color: #a89568;
  padding: 8px 0;
  opacity: 0.6;
}

/* ════════════════════════════════════════════
   v2.6.2 — Tablero 3D mejorado
   ════════════════════════════════════════════ */

/* MISMATCH: vibración + flash rojo + glow caliente; refuerzo dramático
   sobre el sutil shake anterior. Filter en cada keyframe da el "neón" rojo. */
@keyframes mismatch-shake {
  0%, 100% { transform: translateX(0) rotate(0); filter: brightness(1); }
  12%      { transform: translateX(-7px) rotate(-2.2deg) scale(1.025);
             filter: brightness(1.2) saturate(1.4)
                     drop-shadow(0 0 14px rgba(226, 90, 90, 0.85)); }
  28%      { transform: translateX(7px) rotate(2.2deg) scale(1.025);
             filter: brightness(1.18) saturate(1.4)
                     drop-shadow(0 0 12px rgba(226, 90, 90, 0.8)); }
  44%      { transform: translateX(-5px) rotate(-1.6deg);
             filter: brightness(1.1) drop-shadow(0 0 9px rgba(226, 90, 90, 0.6)); }
  60%      { transform: translateX(5px) rotate(1.6deg);
             filter: brightness(1.05) drop-shadow(0 0 6px rgba(226, 90, 90, 0.4)); }
  76%      { transform: translateX(-2px) rotate(-0.4deg); filter: brightness(1.02); }
}
.board-svg .tile.mismatch-shake {
  animation: mismatch-shake 0.52s cubic-bezier(0.36, 0.07, 0.19, 0.97);
}

/* Match flash verde sobre el tile antes de removerlo */
@keyframes match-flash {
  0% { filter: brightness(1) saturate(1); }
  30% { filter: brightness(1.4) saturate(1.5) hue-rotate(80deg); }
  60% { filter: brightness(1.6) saturate(1.8) drop-shadow(0 0 12px #6fe3c1); }
  100% { filter: brightness(1) opacity(0); transform: scale(0.85); }
}
.tile.match-burst {
  animation: match-flash 0.55s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}

/* Nuevo destello dorado brillante sobre la ficha al matchear */
.match-tile-flash {
  position: fixed;
  pointer-events: none;
  z-index: 9200;
  border-radius: 8px;
  background: radial-gradient(circle, #fef7e3 0%, rgba(242,184,75,0.8) 40%, transparent 80%);
  box-shadow: 0 0 30px #f2b84b;
  transform: translate(-50%, -50%);
  animation: tile-flash-anim 0.6s cubic-bezier(0.2, 0.6, 0.3, 1) forwards;
}
@keyframes tile-flash-anim {
  0% { transform: translate(-50%, -50%) scale(0.8); opacity: 0; }
  30% { transform: translate(-50%, -50%) scale(1.1); opacity: 1; filter: brightness(1.5); }
  100% { transform: translate(-50%, -50%) scale(0.6); opacity: 0; filter: brightness(1); }
}

/* Ring de estado (selección/pista). v4.2.x — el <rect class="select-ring"> ahora se
   emite en TODAS las fichas (como .free-glow) y está OCULTO por defecto; la clase de
   estado del <g> padre lo revela. Reemplaza el drop-shadow de .selected/.hint (que
   re-rasterizaba el SVG en móvil). El pulso anima SOLO opacity (GPU, no re-layout — la
   animación de stroke-width se quitó) y corre SOLO en la ficha activa → cero anims en
   idle. */
@keyframes select-ring-pulse {
  0%, 100% { opacity: 0.85; }
  50%      { opacity: 1; }
}
.board-svg .select-ring { opacity: 0; }
.board-svg .tile.selected .select-ring {
  opacity: 1;
  stroke: var(--w-accent, var(--state-selected));
  animation: select-ring-pulse 1.2s ease-in-out infinite;
}
.board-svg .tile.hint .select-ring {
  opacity: 1;
  stroke: var(--state-hint-inner);
}

/* Tiles de capa más alta: ligeramente más brillantes (cerca de la luz).
   Apuntamos al <use> de la ilustración, no a <image>. */
.tile.layer-1 use { filter: brightness(1.05); }
.tile.layer-2 use { filter: brightness(1.10); }
.tile.layer-3 use { filter: brightness(1.15); }
.tile.layer-4 use { filter: brightness(1.20); }
.tile.layer-5 use { filter: brightness(1.25); }

/* Hover/selected ya cubiertos en el bloque "tile interaction" arriba,
   con transform-box: fill-box que evita el bug del slot. No duplicar aquí. */

/* Floating combo score animación */
@keyframes float-up-fade {
  0% { opacity: 0; transform: translate(-50%, 0) scale(0.7); }
  20% { opacity: 1; transform: translate(-50%, -10px) scale(1.1); }
  100% { opacity: 0; transform: translate(-50%, -55px) scale(1); }
}
.match-float-score {
  position: fixed;
  pointer-events: none;
  z-index: 9500;
  color: #f2b84b;
  font-family: "Fraunces", ui-serif, Georgia, serif;
  font-weight: 900;
  font-size: 20px;
  letter-spacing: 0.5px;
  text-shadow: 0 2px 6px rgba(0,0,0,0.6), 0 0 12px rgba(242,184,75,0.6);
  animation: float-up-fade 1s cubic-bezier(0.2, 0.6, 0.3, 1) forwards;
  transform: translate(-50%, 0);
}
.match-float-score.combo {
  color: #6fe3c1;
  font-size: 22px;
  text-shadow: 0 2px 8px rgba(0,0,0,0.7), 0 0 16px rgba(111,227,193,0.8);
}

/* Match particles */
.match-particle {
  position: fixed;
  pointer-events: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: radial-gradient(circle, #f2b84b 0%, #c46a2a 100%);
  z-index: 9400;
  animation: particle-fly 0.6s cubic-bezier(0.2, 0.6, 0.3, 1) forwards;
}
@keyframes particle-fly {
  0% { transform: translate(-50%, -50%) scale(1); opacity: 1; }
  100% { transform: translate(calc(-50% + var(--dx, 0px)), calc(-50% + var(--dy, 0px))) scale(0); opacity: 0; }
}

/* Screen shake en combos altos */
/* v2.56 — amplitud ESCALABLE vía --shake-amp (default 2px = histórico). */
@keyframes board-shake {
  0%, 100% { transform: translate(0, 0); }
  25% { transform: translate(calc(var(--shake-amp, 2px) * -1), calc(var(--shake-amp, 2px) * 0.5)); }
  50% { transform: translate(calc(var(--shake-amp, 2px) * 1), calc(var(--shake-amp, 2px) * -0.5)); }
  75% { transform: translate(calc(var(--shake-amp, 2px) * -0.5), calc(var(--shake-amp, 2px) * 1)); }
}
.board.shake {
  animation: board-shake 0.3s ease-in-out;
}

/* v2.56 — desglose "cuántas quedan de cada tipo" durante el peek (eye/Viento).
   Sólo visible mientras dura el peek → no aplana la info-oculta deliberada. */
.peek-typecount {
  position: absolute; top: 6px; left: 50%; transform: translateX(-50%);
  display: flex; flex-wrap: wrap; gap: 6px; justify-content: center;
  max-width: 92%; padding: 5px 8px; border-radius: 12px;
  background: rgba(14, 4, 24, 0.78); backdrop-filter: blur(3px);
  z-index: 40; pointer-events: none; animation: ptcIn .25s ease-out;
}
.peek-typecount .ptc-item { font-size: 14px; display: inline-flex; align-items: center; gap: 2px; color: #fef7e3; }
.peek-typecount .ptc-item b { font-size: 12px; color: #ffd76a; }
@keyframes ptcIn { from { opacity: 0; transform: translateX(-50%) translateY(-6px); } to { opacity: 1; transform: translateX(-50%) translateY(0); } }
.reduce-motion .peek-typecount { animation: none; }
@media (prefers-reduced-motion: reduce) { .peek-typecount { animation: none; } }

/* Board container con perspectiva y borde temático */
.board {
  border-radius: 14px;
  overflow: hidden;
  box-shadow:
    0 12px 36px rgba(0,0,0,0.55),
    inset 0 1px 0 rgba(255,255,255,0.08),
    inset 0 -2px 0 rgba(0,0,0,0.3);
  position: relative;
}

/* Layout name badge en HUD */
.layout-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  background: rgba(242, 184, 75, 0.12);
  border: 1px solid rgba(242, 184, 75, 0.35);
  border-radius: 12px;
  font-size: 12px;
  font-family: "Fraunces", ui-serif, serif;
  color: #f2b84b;
  letter-spacing: 0.4px;
  text-transform: capitalize;
}
.layout-badge::before {
  content: "◆";
  font-size: 9px;
  opacity: 0.7;
}
/* v3.5 — "nivel duro": umbral solver_difficulty ≥ 0.7 = el ~10% más difícil de la
   campaña (61/600 al calibrarlo). Si la regen cambia la distribución, recalibrar. */
.layout-badge.hard-badge {
  background: rgba(200, 74, 58, 0.16);
  border-color: rgba(224, 98, 74, 0.5);
  color: #ff9a76;
  text-transform: none;
}
.layout-badge.hard-badge::before { content: "⛰"; font-size: 10px; }

/* Layout row entre HUD y board */
.layout-row {
  display: flex;
  justify-content: center;
  padding: 6px 0 2px;
}

/* ════════════════════════════════════════════
   v2.6.3 — Splash con paisaje + logo chakana
   ════════════════════════════════════════════ */
.splash-scene {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
}
.splash-scene svg {
  width: 100%; height: 100%;
  display: block;
}
.splash-inner {
  position: relative;
  z-index: 2;
  background: radial-gradient(ellipse at center, rgba(14,4,24,0.55) 0%, rgba(14,4,24,0.85) 70%, rgba(14,4,24,0.95) 100%);
  padding: 38px 48px 28px;
  border-radius: 18px;
  backdrop-filter: blur(2px);
}
.splash-logo-mark {
  width: 90px; height: 90px;
  filter: drop-shadow(0 4px 16px rgba(242, 184, 75, 0.7));
  animation: splashLogoFloat 2.4s ease-in-out infinite;
}
.splash-title {
  margin: 14px 0 2px;
  font-family: "Fraunces", ui-serif, Georgia, serif;
  font-size: 26px;
  font-weight: 900;
  color: #fef7e3;
  letter-spacing: 1px;
  text-shadow: 0 2px 12px rgba(0,0,0,0.6), 0 0 24px rgba(242,184,75,0.4);
}
.splash-subtitle {
  margin: 0 0 18px;
  font-family: "Fraunces", ui-serif, Georgia, serif;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 6px;
  color: #f2b84b;
  text-transform: uppercase;
  opacity: 0.85;
}
.splash-loader {
  width: 140px; height: 4px;
  margin: 0 auto;
  background: rgba(242, 184, 75, 0.18);
  border-radius: 2px;
  overflow: hidden;
}
.splash-loader-bar {
  width: 30%; height: 100%;
  background: linear-gradient(90deg, transparent, #f2b84b 50%, transparent);
  animation: splashLoaderSlide 1.4s ease-in-out infinite;
}
@keyframes splashLoaderSlide {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(420%); }
}

/* ════════════════════════════════════════════
   v2.6.3 — Win/Lose escenas cinematográficas
   ════════════════════════════════════════════ */

/* Escena de fondo en win overlay */
.win-overlay { position: fixed; inset: 0; z-index: 200; display: flex; align-items: center; justify-content: center; }
.win-scene {
  position: absolute; inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  animation: scene-zoom-in 1.4s cubic-bezier(0.2, 0.6, 0.3, 1) backwards;
}
.win-scene svg { width: 100%; height: 100%; display: block; }
@keyframes scene-zoom-in {
  0% { opacity: 0; transform: scale(1.18); }
  100% { opacity: 1; transform: scale(1); }
}
.win-scene .win-rays-svg {
  transform-origin: 200px 200px;
  animation: rays-rotate 30s linear infinite;
}
@keyframes rays-rotate {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

.win-dialog {
  position: relative;
  z-index: 2;
  background: linear-gradient(180deg, rgba(58, 31, 90, 0.92) 0%, rgba(14, 4, 24, 0.96) 100%);
  backdrop-filter: blur(8px);
  border: 1.5px solid rgba(242, 184, 75, 0.45);
  box-shadow:
    0 0 40px rgba(242, 184, 75, 0.3),
    0 16px 48px rgba(0, 0, 0, 0.7),
    inset 0 1px 0 rgba(255, 255, 255, 0.1);
}

/* Stuck/Lose overlay */
.stuck-overlay {
  position: fixed; inset: 0; z-index: 200;
  display: flex; align-items: center; justify-content: center;
}
.lose-scene {
  position: absolute; inset: 0; z-index: 0; overflow: hidden;
  pointer-events: none;
  animation: scene-zoom-in 1.2s cubic-bezier(0.2, 0.6, 0.3, 1) backwards;
}
.lose-scene svg { width: 100%; height: 100%; display: block; }
.lose-dialog {
  position: relative;
  z-index: 2;
  background: linear-gradient(180deg, rgba(26, 8, 32, 0.94) 0%, rgba(14, 4, 24, 0.97) 100%);
  backdrop-filter: blur(10px);
  padding: 28px 26px;
  border-radius: 16px;
  border: 1.5px solid rgba(139, 58, 74, 0.5);
  box-shadow:
    0 0 40px rgba(139, 58, 74, 0.25),
    0 16px 48px rgba(0, 0, 0, 0.7),
    inset 0 1px 0 rgba(255, 255, 255, 0.08);
  max-width: 360px;
  text-align: center;
  animation: dialog-slide-up 0.4s cubic-bezier(0.2, 0.6, 0.3, 1) 0.3s backwards;
}
@keyframes dialog-slide-up {
  0% { opacity: 0; transform: translateY(30px) scale(0.96); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}
.lose-icon {
  font-size: 56px;
  margin-bottom: 12px;
  filter: drop-shadow(0 4px 12px rgba(139, 58, 74, 0.6));
  animation: lose-icon-float 3s ease-in-out infinite;
}
@keyframes lose-icon-float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-8px); }
}
.lose-dialog h2 {
  font-family: "Fraunces", ui-serif, Georgia, serif;
  font-size: 22px;
  font-weight: 800;
  margin: 0 0 10px;
  color: #fef7e3;
}
.lose-dialog p {
  font-size: 14px;
  line-height: 1.55;
  color: #d8c9a8;
  margin: 0 0 20px;
  opacity: 0.85;
}
.lose-dialog .row {
  display: flex; gap: 10px;
  flex-wrap: wrap; justify-content: center;
}

/* v2.23 — flujo "trabado": cartel para MIRAR + barra de opciones (no tapan el tablero) */
.stuck-hint {
  position: fixed; top: 70px; left: 50%; transform: translateX(-50%);
  background: rgba(26,18,40,0.92); color: var(--ink); border: 1px solid var(--gold);
  border-radius: 999px; padding: 10px 20px; font-size: 14px; font-weight: 700;
  z-index: 60; box-shadow: 0 6px 20px rgba(0,0,0,0.5); cursor: pointer;
  animation: stuckHintIn .3s ease-out;
}
@keyframes stuckHintIn { from { opacity: 0; transform: translateX(-50%) translateY(-12px); } }
.stuck-bar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  background: linear-gradient(180deg, rgba(26,18,40,0.6), rgba(14,4,24,0.96));
  backdrop-filter: blur(6px); padding: 14px 16px calc(16px + var(--safe-bottom));
  border-top: 1px solid rgba(242,184,75,0.4);
  animation: stuckBarIn .3s cubic-bezier(0.3,0.8,0.4,1);
}
@keyframes stuckBarIn { from { transform: translateY(100%); } }
.stuck-bar-title { text-align: center; font-size: 13px; color: var(--ink-dim); margin-bottom: 10px; }
.stuck-bar-row { display: flex; gap: 8px; justify-content: center; align-items: stretch; max-width: 460px; margin: 0 auto; }
.stuck-bar-row .btn { flex: 1; }
.stuck-bar-row .btn.small { flex: 0 0 auto; min-width: 48px; }
.stuck-bar-row .btn small { opacity: 0.85; font-weight: 800; }
/* resalto de las últimas fichas jugadas para "ver dónde te trabaste" */
/* v2.55.16 — PERF: era `infinite` → un filter drop-shadow re-rasterizado en GPU
   cada frame, para SIEMPRE, durante todo el juego = lag continuo en celu. Ahora
   pulsa 3 veces para llamar la atención y queda con un halo ESTÁTICO (sin animar). */
.board-svg .tile.last-played { filter: drop-shadow(0 3px 6px rgba(0,0,0,0.55)) drop-shadow(0 0 8px rgba(111,227,193,0.7)); animation: lastPlayedPulse 1.2s ease-in-out 3; }
@keyframes lastPlayedPulse {
  0%, 100% { filter: drop-shadow(0 3px 6px rgba(0,0,0,0.55)); }
  50% { filter: drop-shadow(0 3px 6px rgba(0,0,0,0.55)) drop-shadow(0 0 10px rgba(111,227,193,0.9)); }
}
body.reduce-motion .stuck-hint, body.reduce-motion .stuck-bar { animation: none; }
body.reduce-motion .board-svg .tile.last-played { animation: none; filter: drop-shadow(0 0 6px rgba(111,227,193,0.8)); }

/* Fondos escénicos por mundo en el mapa */
.world {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
.world-scene {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 140px;
  z-index: 0;
  pointer-events: none;
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  overflow: hidden;
  opacity: 0.85;
}
.world-scene svg { width: 100%; height: 100%; display: block; }
.world-scene::after {
  /* fade-out hacia abajo para que el contenido se lea */
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 40%, var(--bg-card, #2a1538) 100%);
}
.world-header {
  position: relative;
  z-index: 1;
  padding-top: 88px !important;
}
.world-title h3 {
  text-shadow: 0 2px 8px rgba(0,0,0,0.6);
  color: #fef7e3 !important;
}
.world-title .world-role {
  text-shadow: 0 1px 3px rgba(0,0,0,0.7);
}

/* ════════════════════════════════════════════
   v2.6.4 — Pause, Stats, Free-ring, Splash proverb
   ════════════════════════════════════════════ */

/* Pause overlay (similar a lose pero con icono propio) */
.pause-overlay { position: fixed; inset: 0; z-index: 200; display: flex; align-items: center; justify-content: center; }
.pause-scene { position: absolute; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
.pause-scene svg { width: 100%; height: 100%; display: block; }
.pause-dialog {
  position: relative; z-index: 2;
  background: linear-gradient(180deg, rgba(26,8,32,0.92) 0%, rgba(14,4,24,0.97) 100%);
  backdrop-filter: blur(8px);
  padding: 28px 26px;
  border-radius: 16px;
  border: 1.5px solid rgba(242,184,75,0.45);
  max-width: 320px;
  text-align: center;
  box-shadow: 0 16px 48px rgba(0,0,0,0.7);
}
.pause-icon { font-size: 56px; margin-bottom: 12px; color: #f2b84b; }
.pause-dialog h2 {
  font-family: "Fraunces", ui-serif, Georgia, serif;
  font-size: 22px; margin: 0 0 10px; color: #fef7e3;
}
.pause-dialog p { font-size: 14px; line-height: 1.55; color: #d8c9a8; margin: 0 0 20px; }
.pause-dialog .row { display: flex; gap: 10px; justify-content: center; }

/* HUD button icon-only (pause) */
.hud .btn.icon-only {
  min-width: 36px;
  width: 36px;
  padding: 0;
  font-size: 16px;
}

/* Free-ring pulsante en tiles libres */
@keyframes free-ring-pulse {
  0%, 100% { opacity: 0.5; }
  50% { opacity: 0.85; }
}
.free-ring {
  animation: free-ring-pulse 2.2s ease-in-out infinite;
}

/* Splash proverb */
.splash-proverb {
  margin: 16px 0 0;
  font-family: "Fraunces", ui-serif, Georgia, serif;
  font-style: italic;
  font-size: 13px;
  color: #d8c9a8;
  opacity: 0.85;
  letter-spacing: 0.3px;
  max-width: 260px;
  margin-left: auto;
  margin-right: auto;
  line-height: 1.5;
}

/* ════════════════════════════════════════════
   Stats Screen
   ════════════════════════════════════════════ */
.stats-hero {
  position: relative;
  border-radius: 14px;
  overflow: hidden;
  min-height: 160px;
  margin-bottom: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: var(--shadow);
  isolation: isolate;
}
.stats-hero-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.stats-hero-bg svg { width: 100%; height: 100%; display: block; }
.stats-hero-bg::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(14,4,24,0.2) 0%, rgba(14,4,24,0.6) 100%);
}
.stats-hero-content {
  position: relative;
  z-index: 1;
  text-align: center;
  padding: 24px;
}
.big-number {
  font-family: "Fraunces", ui-serif, Georgia, serif;
  font-size: 64px;
  font-weight: 900;
  color: #fef7e3;
  line-height: 1;
  text-shadow: 0 2px 12px rgba(0,0,0,0.7), 0 0 24px rgba(242,184,75,0.4);
}
.big-number .frac {
  font-size: 28px;
  opacity: 0.55;
  font-weight: 700;
}
.big-label {
  color: #f2b84b;
  font-size: 13px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  margin-top: 6px;
  text-shadow: 0 1px 4px rgba(0,0,0,0.6);
}

.stats-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
  margin-bottom: 22px;
}
.stat-tile {
  background: linear-gradient(180deg, rgba(58,31,90,0.4) 0%, rgba(26,8,32,0.6) 100%);
  border: 1px solid rgba(242,184,75,0.18);
  padding: 14px 12px;
  border-radius: 12px;
  text-align: center;
}
.stat-tile .stat-icon {
  font-size: 22px;
  margin-bottom: 6px;
  filter: drop-shadow(0 2px 4px rgba(0,0,0,0.4));
}
.stat-tile .stat-val {
  font-family: "Fraunces", ui-serif, Georgia, serif;
  font-size: 22px;
  font-weight: 900;
  color: #fef7e3;
  line-height: 1.1;
}
.stat-tile .stat-val .frac {
  font-size: 12px;
  opacity: 0.6;
  font-weight: 600;
}
.stat-tile .stat-key {
  font-size: 12px;
  color: #a89568;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  margin-top: 4px;
}

.stats-section {
  margin-bottom: 22px;
}
.stats-section h2 {
  font-family: "Fraunces", ui-serif, Georgia, serif;
  color: #f2b84b;
  font-size: 18px;
  font-weight: 700;
  margin: 0 0 10px;
  padding-bottom: 6px;
  border-bottom: 1px solid rgba(242,184,75,0.18);
}

.world-progress-row {
  display: grid;
  grid-template-columns: 32px 1fr 50px;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: rgba(58,31,90,0.25);
  border-radius: 10px;
  margin-bottom: 6px;
}
.world-progress-row .wp-icon {
  font-size: 20px;
  text-align: center;
}
.world-progress-row .wp-name {
  font-size: 13px;
  color: #fef7e3;
  margin-bottom: 4px;
  font-weight: 600;
}
.world-progress-row .wp-count {
  text-align: right;
  font-family: "Fraunces", serif;
  font-size: 13px;
  color: #f2b84b;
  font-weight: 700;
}

.booster-stats .bs-row,
.info-rows .info-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 14px;
  background: rgba(58,31,90,0.2);
  border-radius: 8px;
  margin-bottom: 4px;
  font-size: 13px;
}
.booster-stats .bs-row strong,
.info-rows .info-row strong {
  color: #f2b84b;
  font-family: "Fraunces", serif;
  font-size: 14px;
}

/* Modo Zen badge en HUD */
.hud-stat.zen-badge .v {
  color: #6fe3c1;
  text-shadow: 0 0 8px rgba(111, 227, 193, 0.5);
  font-weight: 800;
}
.hud.zen {
  background: linear-gradient(180deg, rgba(58, 31, 90, 0.4), rgba(26, 8, 32, 0.6));
}

/* Quick-link styling consistente para stats */
.quick-link {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 12px 8px;
}

/* Botones full-width en settings */
.btn.full-width {
  width: 100%;
  margin-bottom: 8px;
}
.btn.danger {
  background: linear-gradient(180deg, #8b3a4a, #5a1f2a);
  color: #fef7e3;
}

/* ════════════════════════════════════════════
   v2.6.5 — Gameplay polish: cascade-in, match dramático, combo banner
   ════════════════════════════════════════════ */

/* Touch responsiveness — eliminar 300ms delay en mobile.
   v2.58.1: .board/.tile salen de acá — usan pan-x pan-y (pinch-zoom propio),
   que también elimina el delay. */
.booster, .btn, .hud-stat {
  touch-action: manipulation;
}
.tile { -webkit-tap-highlight-color: transparent; }

/* CASCADE-IN: la ficha CAE DEL CIELO desde lejos arriba, se aplasta al
   aterrizar (squash horizontal/vertical), rebota una vez y se asienta.
   Stagger por distancia al centro lo decide el JS via animationDelay. */
@keyframes tile-cascade-in {
  0%   { opacity: 0;
         transform: translateY(-72px) scale(0.45) rotate(-9deg);
         filter: brightness(1.45) blur(1.2px); }
  35%  { opacity: 1;
         transform: translateY(-18px) scale(0.85, 0.92) rotate(-2deg);
         filter: brightness(1.25) blur(0.4px); }
  55%  { opacity: 1;
         transform: translateY(4px) scale(1.12, 0.82) rotate(0.6deg);
         filter: brightness(1.18) blur(0); }
  72%  { transform: translateY(-3px) scale(0.96, 1.06) rotate(-0.3deg);
         filter: brightness(1.08); }
  88%  { transform: translateY(1px) scale(1.02, 0.98) rotate(0.15deg);
         filter: brightness(1.03); }
  100% { opacity: 1;
         transform: translateY(0) scale(1) rotate(0deg);
         filter: brightness(1); }
}
.tile.tile-entering {
  animation: tile-cascade-in 0.62s cubic-bezier(0.28, 1.0, 0.42, 1) backwards;
  transform-origin: center;
  transform-box: fill-box;
}

/* NOTA: la animación activa de match-burst está en el bloque "tile
   interaction" arriba (matchBurst). Esta regla queda como fallback no-svg. */
.tile.match-burst:not(.board-svg .tile) {
  transform-origin: center;
}

/* Shockwave doble: oro afuera + verde adentro, en stagger.
   El JS sigue creando UN solo .match-shockwave; el ::before le agrega
   el segundo anillo verde sin necesidad de cambiar la lógica de spawn. */
.match-shockwave {
  position: fixed;
  pointer-events: none;
  /* v20 perf — el anillo crece por transform:scale (compositor), no por width/height
     (repaint). Base = tamaño FINAL (200px). El centrado va por MÁRGENES fijos
     (-100px): con translate(-50%) el centro se corría mientras escalaba. */
  width: 200px;
  height: 200px;
  margin-left: -100px;
  margin-top: -100px;
  border: 3px solid #ffd76a;
  border-radius: 50%;
  transform: scale(0.12);
  z-index: 9300;
  box-shadow: 0 0 24px rgba(255, 215, 106, 0.6),
              inset 0 0 18px rgba(255, 215, 106, 0.35);
  animation: shockwave-expand 0.72s cubic-bezier(0.16, 0.7, 0.3, 1) forwards;
}
.match-shockwave::before {
  content: "";
  position: absolute;
  inset: 4px;
  border: 2px solid #6fe3c1;
  border-radius: 50%;
  opacity: 0;
  box-shadow: 0 0 14px rgba(111, 227, 193, 0.7);
  animation: shockwave-inner 0.72s cubic-bezier(0.16, 0.7, 0.3, 1) 0.06s forwards;
}
@keyframes shockwave-expand {
  0%   { transform: scale(0.12); opacity: 1;   border-width: 3.5px; }
  60%  { opacity: 0.55; border-width: 2px; }
  100% { transform: scale(1); opacity: 0;   border-width: 0.5px; }
}
@keyframes shockwave-inner {
  0%   { inset: 8px;   opacity: 1;   border-width: 2.5px; }
  100% { inset: -60px; opacity: 0;   border-width: 0.5px; }
}

/* Combo banner cinematográfico */
@keyframes combo-banner-in {
  0% {
    opacity: 0;
    transform: translate(-50%, -50%) scale(0.3) rotate(-8deg);
  }
  60% {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1.15) rotate(2deg);
  }
  100% {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1) rotate(0deg);
  }
}
@keyframes combo-banner-out {
  0% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -180%) scale(0.9); }
}
.combo-banner {
  position: fixed;
  left: 50%;
  /* v2.58.5 — 13% (era 38%): el festejo tapaba EL CENTRO DEL TABLERO, justo
     donde el jugador está mirando/jugando. Arriba celebra sin estorbar. */
  top: 13%;
  transform: translate(-50%, -50%);
  z-index: 9600;
  pointer-events: none;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 22px;
  border-radius: 14px;
  /* v2.54 — el banner de combo adopta el COLOR DEL MUNDO (--w-pop): en Carnaval
     es cian/magenta, en Quebrada naranja, etc. Antes era siempre el mismo marrón. */
  background: linear-gradient(135deg, rgba(36, 17, 73, 0.92) 0%, var(--w-pop, rgba(196, 106, 42, 0.95)) 100%);
  border: 2px solid var(--w-accent, #f2b84b);
  box-shadow:
    0 0 40px rgba(242, 184, 75, 0.6),
    0 8px 32px rgba(0, 0, 0, 0.6),
    inset 0 1px 0 rgba(255, 255, 255, 0.2);
  animation: combo-banner-in 0.35s cubic-bezier(0.34, 1.56, 0.64, 1) backwards;
}
.combo-banner.combo-banner-out {
  animation: combo-banner-out 0.4s cubic-bezier(0.5, 0, 0.75, 0) forwards;
}
.combo-banner .combo-x {
  font-family: "Fraunces", ui-serif, Georgia, serif;
  font-size: 38px;
  font-weight: 900;
  color: #fef7e3;
  text-shadow: 0 2px 8px rgba(0, 0, 0, 0.6), 0 0 18px rgba(242, 184, 75, 0.8);
  line-height: 1;
}
.combo-banner .combo-text {
  font-family: "Fraunces", ui-serif, Georgia, serif;
  font-size: 22px;
  font-weight: 700;
  color: #f2b84b;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  text-shadow: 0 2px 6px rgba(0, 0, 0, 0.7);
}

/* Floating score MEJORADO — más visible */
.match-float-score {
  font-size: 26px;
  text-shadow:
    0 2px 8px rgba(0, 0, 0, 0.8),
    0 0 16px rgba(242, 184, 75, 0.7),
    0 0 4px rgba(254, 247, 227, 0.9);
}
.match-float-score.combo {
  font-size: 32px;
  letter-spacing: 1px;
  text-shadow:
    0 2px 10px rgba(0, 0, 0, 0.9),
    0 0 20px rgba(111, 227, 193, 0.9),
    0 0 6px rgba(254, 247, 227, 1);
}

/* Match particles — escala mejorada */
.match-particle {
  border-radius: 50%;
  z-index: 9400;
  transform: translate(-50%, -50%);
  filter: drop-shadow(0 0 4px currentColor);
}

/* Win flash — flash blanco corto cuando se gana */
@keyframes win-flash {
  0% { background: transparent; }
  /* v2.34 (#27) — pico adelantado (12% en vez de 20%): el destello pega y se disipa
     antes de que la card de victoria termine de entrar, sin taparla. */
  12% { background: rgba(254, 247, 227, 0.6); }
  100% { background: transparent; }
}
.win-flash-overlay {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 9700;
  animation: win-flash 0.5s ease-out forwards;
}

/* v2.40 — BLOQUE STALE ELIMINADO. Acá vivía un `.gameboard-wrap { min-height:100vh }`
   + `.board`/`.board-svg` de la era del layout fijo que PISABA el fix v2.39 (línea ~415):
   su `min-height:100vh` ganaba sobre `height:100dvh` → en celular el contenedor se forzaba
   a 100vh (más alto que el viewport con barra del navegador) y el DOCK se RECORTABA por
   overflow:hidden. Era justo la queja del celular. Las reglas canónicas (415 .gameboard-wrap
   flex+100dvh, 469 .board grid, 475 .board svg) + fitBoard ya cubren todo. */

/* Respeto a reduce-motion (extendido para nuevas anims) */
.reduce-motion .tile.tile-entering { animation: none !important; opacity: 1; transform: none; }
.reduce-motion .tile.match-burst { animation: match-flash-reduced 0.3s ease-out forwards; }
@keyframes match-flash-reduced {
  0% { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(0.7); }
}
.reduce-motion .combo-banner { animation: none !important; }
.reduce-motion .match-shockwave { display: none; }
.reduce-motion .match-particle { display: none; }
.reduce-motion .board.shake { animation: none !important; }
@media (prefers-reduced-motion: reduce) {
  .tile.tile-entering { animation: none !important; opacity: 1; transform: none; }
  .combo-banner { animation: none !important; }
  .match-shockwave { display: none; }
  .match-particle { display: none; }
  .board.shake { animation: none !important; }
}

/* ════════════════════════════════════════════
   v2.6.7 — Objectives, preload, performance
   ════════════════════════════════════════════ */

/* Tile preload overlay (al primer nivel de la sesión) */
.tile-preload-overlay {
  position: fixed; inset: 0;
  background: rgba(14,4,24,0.92);
  display: flex; align-items: center; justify-content: center; flex-direction: column;
  gap: 14px;
  z-index: 9000;
  color: #f2b84b;
  font-family: "Fraunces", ui-serif, Georgia, serif;
  font-size: 14px;
  letter-spacing: 1px;
}
.tile-preload-overlay .dots { display: flex; gap: 6px; }
.tile-preload-overlay .dot {
  width: 10px; height: 10px;
  background: #f2b84b;
  border-radius: 50%;
  animation: dot-pulse 1.2s ease-in-out infinite;
}
.tile-preload-overlay .dot:nth-child(2) { animation-delay: 0.2s; }
.tile-preload-overlay .dot:nth-child(3) { animation-delay: 0.4s; }
@keyframes dot-pulse {
  0%, 100% { opacity: 0.3; transform: scale(0.7); }
  50% { opacity: 1; transform: scale(1); }
}

/* Objective badge en HUD */
.objective-row {
  display: flex; justify-content: center;
  padding: 4px 8px;
  background: rgba(0,0,0,0.18);
  border-bottom: 1px solid rgba(255,255,255,0.04);
}
.objective-badge {
  padding: 3px 12px;
  border-radius: 12px;
  font-size: 12px;
  font-family: "Fraunces", serif;
  font-weight: 600;
  letter-spacing: 0.4px;
  border: 1px solid;
}
.objective-clear_all { background: rgba(111,227,193,0.10); border-color: rgba(111,227,193,0.35); color: #6fe3c1; }
.objective-no_hints { background: rgba(242,184,75,0.10); border-color: rgba(242,184,75,0.45); color: #f2b84b; }
.objective-combo    { background: rgba(196,30,90,0.12); border-color: rgba(196,30,90,0.45); color: #ff7aa3; }
.objective-find_rare{ background: rgba(176,126,214,0.12); border-color: rgba(176,126,214,0.4); color: #c89af2; }
.objective-speed    { background: rgba(74,144,226,0.12); border-color: rgba(74,144,226,0.4); color: #6fb6e6; }
.objective-boss {
  background: linear-gradient(90deg, rgba(242,184,75,0.2), rgba(196,30,90,0.2));
  border-color: #f2b84b;
  color: #fef7e3;
  font-weight: 800;
  animation: boss-pulse 2s ease-in-out infinite;
}
@keyframes boss-pulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.04); }
}

/* Objective complete / missed en win overlay */
.objective-complete {
  background: linear-gradient(90deg, rgba(111,227,193,0.18), rgba(242,184,75,0.18));
  border: 1px solid #6fe3c1;
  border-radius: 10px;
  padding: 8px 14px;
  margin: 10px 0;
  color: #fef7e3;
  font-family: "Fraunces", serif;
  font-size: 14px;
  font-weight: 700;
  text-align: center;
}
.objective-complete .bonus {
  color: #f2b84b;
  font-weight: 900;
  margin-left: 6px;
}
.objective-missed {
  padding: 6px 14px;
  margin: 10px 0;
  color: #a89568;
  font-size: 12px;
  text-align: center;
  font-style: italic;
}
/* v2.42 — badge de maestría del jefe en el overlay de victoria. */
.boss-mastery {
  border-radius: 10px;
  padding: 8px 14px;
  margin: 10px 0;
  text-align: center;
  font-family: "Fraunces", serif;
  font-size: 13px;
  font-weight: 700;
}
.boss-mastery.mastered {
  background: linear-gradient(90deg, rgba(242,184,75,0.22), rgba(255,215,120,0.22));
  border: 1px solid #f2b84b;
  color: #fef7e3;
  box-shadow: 0 0 16px rgba(242,184,75,0.35);
}
.boss-mastery.pending {
  background: rgba(168,149,104,0.12);
  border: 1px dashed #a89568;
  color: #d8c9a0;
  font-weight: 600;
}

/* ════════════════════════════════════════════
   v2.6.9 — Reveal screen + Level name HUD
   ════════════════════════════════════════════ */

.level-reveal-overlay {
  position: fixed; inset: 0;
  z-index: 800;
  background: radial-gradient(ellipse at center, rgba(58,31,90,0.92) 0%, rgba(14,4,24,0.97) 100%);
  display: flex; align-items: center; justify-content: center;
  backdrop-filter: blur(8px);
  animation: reveal-fade-in 0.35s cubic-bezier(0.4, 0, 0.2, 1);
  pointer-events: auto;
}
.level-reveal-overlay.reveal-out {
  animation: reveal-fade-out 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}
@keyframes reveal-fade-in {
  0% { opacity: 0; }
  100% { opacity: 1; }
}
@keyframes reveal-fade-out {
  0% { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(1.08); }
}
.reveal-inner {
  text-align: center;
  padding: 40px 32px;
  max-width: 90%;
  animation: reveal-slide-up 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) 0.05s backwards;
}
@keyframes reveal-slide-up {
  0% { opacity: 0; transform: translateY(40px) scale(0.85); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}
/* v2.22 — los BOSS se anuncian con aura roja/dorada */
.reveal-inner.reveal-boss {
  border-radius: 20px;
  box-shadow: 0 0 0 2px var(--gold), 0 0 60px rgba(196,30,58,0.5), 0 0 30px rgba(242,184,75,0.4);
  background: radial-gradient(ellipse at 50% 0%, rgba(196,30,58,0.25), transparent 70%);
}
.reveal-boss-tag {
  display: inline-block; font-family: var(--font-display, serif); font-weight: 900;
  font-size: 13px; letter-spacing: 3px; color: #2a1804;
  background: linear-gradient(90deg, var(--gold), #ffe98a, var(--gold));
  padding: 4px 16px; border-radius: 999px; margin-bottom: 10px;
  animation: bossTagPulse 1.4s ease-in-out infinite;
}
@keyframes bossTagPulse { 0%,100% { transform: scale(1); } 50% { transform: scale(1.06); } }
.reveal-boss .reveal-title { color: #ff9d6a; text-shadow: 0 0 20px rgba(196,30,58,0.6); }
.reduce-motion .reveal-boss-tag { animation: none; }
/* chip de gema ganada en el win */
.chip.gemwin { color: #6fe3c1; }
.reveal-eyebrow {
  font-family: "Fraunces", ui-serif, Georgia, serif;
  color: #f2b84b;
  font-size: 12px;
  letter-spacing: 4px;
  font-weight: 600;
  margin-bottom: 14px;
  text-transform: uppercase;
  opacity: 0.85;
}
.reveal-title {
  font-family: "Fraunces", ui-serif, Georgia, serif;
  color: #fef7e3;
  font-size: 42px;
  font-weight: 900;
  line-height: 1.1;
  letter-spacing: 0.5px;
  text-shadow:
    0 2px 12px rgba(0,0,0,0.7),
    0 0 32px rgba(242,184,75,0.4),
    0 0 8px rgba(254,247,227,0.3);
  margin-bottom: 18px;
}
.reveal-objective {
  font-family: "Fraunces", ui-serif, Georgia, serif;
  color: #d8c9a8;
  font-size: 14px;
  font-style: italic;
  opacity: 0.85;
  letter-spacing: 0.5px;
}
.reveal-star-hints {
  display: flex;
  gap: 12px;
  justify-content: center;
  margin-top: 14px;
}
.rsh {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.3px;
  padding: 3px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.1);
}
.rsh-3 { color: #f2b84b; border: 1px solid rgba(242,184,75,0.4); }
.rsh-2 { color: #b8c8ff; border: 1px solid rgba(184,200,255,0.3); }

/* HUD: indicador compacto de fichas libres */
.hud-free {
  font-size: 0.72em;
  opacity: 0.72;
  font-weight: 500;
  letter-spacing: 0;
}

/* HUD: level name visible */
.gameboard-wrap .hud-stat.level-name-stat {
  flex: 1;
  min-width: 0;
  align-items: flex-start;
  padding-left: 4px;
}
.gameboard-wrap .hud-stat.level-name-stat .k {
  color: #f2b84b;
  font-size: 12px;
}
.gameboard-wrap .hud-stat.level-name-stat .level-name {
  font-size: 13px;
  font-family: "Fraunces", serif;
  font-weight: 700;
  color: #fef7e3;
  letter-spacing: 0.2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  /* Antes: max-width:130px fijo. En viewports angostos (≤380px) la columna
     flex queda ~85px y el nombre (max 130px) desbordaba sobre la stat "Pares"
     ("Plaza Belgranb4"). Con 100% se trunca con ellipsis dentro de su columna. */
  max-width: 100%;
}

@media (prefers-reduced-motion: reduce) {
  .level-reveal-overlay,
  .reveal-inner { animation: none !important; }
}
.reduce-motion .level-reveal-overlay,
.reduce-motion .reveal-inner { animation: none !important; }

/* ════════════════════════════════════════════
   v2.6.9 — Chapter intro + Match word + Coya
   ════════════════════════════════════════════ */

/* Chapter intro overlay narrativa */
.chapter-intro-overlay {
  position: fixed; inset: 0; z-index: 8000;
  display: flex; align-items: center; justify-content: center;
  animation: chapter-fade-in 0.5s ease-out;
  background: #1a0820;
  cursor: pointer;   /* v2.51 — todo el cartel es "tocá para continuar" */
}
/* v2.51 — pista flotante: que se vea que tocando en cualquier lado se avanza. */
.story-tap-hint {
  position: absolute; left: 50%; bottom: 14px; transform: translateX(-50%);
  font-size: 12px; font-weight: 700; letter-spacing: 0.3px;
  color: rgba(255,247,227,0.78); background: rgba(0,0,0,0.32);
  padding: 5px 12px; border-radius: 999px; pointer-events: none;
  font-family: 'Sora','Inter',system-ui,sans-serif;
  animation: tapHintPulse 1.6s ease-in-out infinite;
}
@keyframes tapHintPulse { 0%,100% { opacity: 0.55; } 50% { opacity: 1; } }
.reduce-motion .story-tap-hint { animation: none; opacity: 0.8; }
.chapter-intro-overlay.chapter-fade-out {
  animation: chapter-fade-out 0.35s ease-in forwards;
}
@keyframes chapter-fade-in {
  0% { opacity: 0; } 100% { opacity: 1; }
}
@keyframes chapter-fade-out {
  0% { opacity: 1; } 100% { opacity: 0; }
}
.chapter-scene { position: absolute; inset: 0; z-index: 0; }
.chapter-scene svg { width: 100%; height: 100%; }
.chapter-content {
  position: relative; z-index: 2;
  background: linear-gradient(180deg, rgba(26,8,32,0.85) 0%, rgba(14,4,24,0.92) 100%);
  backdrop-filter: blur(6px);
  padding: 32px 28px;
  max-width: 440px;
  margin: 20px;
  border-radius: 16px;
  border: 1.5px solid rgba(242,184,75,0.4);
  text-align: center;
  box-shadow: 0 0 60px rgba(242,184,75,0.25);
  animation: chapter-content-up 0.7s cubic-bezier(0.2, 0.7, 0.3, 1) backwards;
}
@keyframes chapter-content-up {
  0% { opacity: 0; transform: translateY(40px) scale(0.95); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}
.chapter-subtitle {
  font-family: "Fraunces", serif;
  color: #f2b84b;
  font-size: 12px;
  letter-spacing: 5px;
  text-transform: uppercase;
  font-weight: 600;
  margin-bottom: 14px;
}
.chapter-icon {
  font-size: 56px;
  margin: 6px 0 12px;
  filter: drop-shadow(0 4px 12px rgba(242,184,75,0.6));
  animation: chapter-icon-float 2.5s ease-in-out infinite;
}
@keyframes chapter-icon-float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-6px); }
}
.chapter-title {
  font-family: "Fraunces", serif;
  font-size: 30px;
  font-weight: 900;
  color: #fef7e3;
  margin: 0 0 14px;
  letter-spacing: 0.3px;
  text-shadow: 0 2px 8px rgba(0,0,0,0.5), 0 0 24px rgba(242,184,75,0.3);
}
.chapter-intro-text {
  font-family: "Fraunces", serif;
  font-style: italic;
  color: #d8c9a8;
  font-size: 16px;
  line-height: 1.55;
  margin: 0 0 24px;
  letter-spacing: 0.2px;
}
.chapter-btn {
  font-size: 14px;
  padding: 12px 28px;
}

/* Match word "¡EXCELENTE!" floating */
.match-word {
  position: fixed;
  pointer-events: none;
  z-index: 9550;
  font-family: "Fraunces", ui-serif, Georgia, serif;
  font-weight: 900;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  transform: translate(-50%, 0);
  animation: word-pop 0.85s cubic-bezier(0.2, 0.7, 0.3, 1) forwards;
}
@keyframes word-pop {
  0% { opacity: 0; transform: translate(-50%, 8px) scale(0.5) rotate(-3deg); }
  25% { opacity: 1; transform: translate(-50%, -8px) scale(1.18) rotate(2deg); }
  50% { transform: translate(-50%, -18px) scale(1.0) rotate(0deg); }
  100% { opacity: 0; transform: translate(-50%, -42px) scale(0.9) rotate(0deg); }
}
.match-word.combo-1 { font-size: 22px; color: #fef7e3; text-shadow: 0 2px 6px rgba(0,0,0,0.7), 0 0 12px rgba(242,184,75,0.5); }
.match-word.combo-2 { font-size: 26px; color: #f2b84b; text-shadow: 0 2px 8px rgba(0,0,0,0.8), 0 0 16px rgba(242,184,75,0.7); }
.match-word.combo-3 { font-size: 30px; color: #6fe3c1; text-shadow: 0 2px 10px rgba(0,0,0,0.9), 0 0 18px rgba(111,227,193,0.8); }
.match-word.combo-4 { font-size: 32px; color: #ff7aa3; text-shadow: 0 2px 10px rgba(0,0,0,0.9), 0 0 20px rgba(255,122,163,0.8); }
.match-word.combo-5 { font-size: 34px; color: #c89af2; text-shadow: 0 2px 10px rgba(0,0,0,0.9), 0 0 22px rgba(200,154,242,0.9); }
.match-word.combo-6 { font-size: 36px; color: #f8dc3d; text-shadow: 0 2px 12px rgba(0,0,0,1), 0 0 24px rgba(248,220,61,1); }
.match-word.combo-7 { font-size: 38px; color: #fef7e3; text-shadow: 0 2px 12px rgba(0,0,0,1), 0 0 30px #f2b84b, 0 0 6px #fef7e3; }
.match-word.combo-8 {
  font-size: 42px;
  background: linear-gradient(90deg, #f2b84b, #6fe3c1, #c89af2, #f2b84b);
  background-size: 200% auto;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  text-shadow: 0 2px 12px rgba(0,0,0,1);
  filter: drop-shadow(0 0 16px #f2b84b);
  animation: word-pop 0.85s cubic-bezier(0.2, 0.7, 0.3, 1) forwards,
             rainbow-text 1s linear infinite;
}
@keyframes rainbow-text {
  0% { background-position: 0% 50%; }
  100% { background-position: 200% 50%; }
}

/* ─── NEAR-WIN BANNER ─────────────────────────────────────────
   Aparece cuando quedan 1-2 pares libres en el nivel. Empuja la
   sensación de "último esfuerzo" — momento más adictivo del juego. */
.near-win-banner {
  position: fixed;
  top: 12%;   /* v2.58.5 — fuera del centro del tablero (era 24%) */
  left: 50%;
  transform: translate(-50%, -50%) scale(0.6) rotate(-3deg);
  z-index: 9550;
  pointer-events: none;
  padding: 14px 32px;
  border-radius: 16px;
  background: linear-gradient(135deg, #ff4d6d 0%, #f2b84b 50%, #ffd76a 100%);
  border: 3px solid #1a0a02;
  box-shadow:
    0 0 32px rgba(255, 215, 106, 0.7),
    0 12px 28px rgba(0, 0, 0, 0.55),
    inset 0 2px 0 rgba(255, 255, 255, 0.4);
  display: flex; align-items: center; gap: 12px;
  animation: near-win-in 0.42s cubic-bezier(0.34, 1.6, 0.5, 1) forwards;
}
.near-win-banner.near-win-out {
  animation: near-win-out 0.4s cubic-bezier(0.5, 0, 0.75, 0) forwards;
}
.near-win-text {
  font-family: 'Fraunces', ui-serif, Georgia, serif;
  font-size: 28px;
  font-weight: 900;
  color: #1a0a02;
  letter-spacing: 0.4px;
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
  position: relative;
  z-index: 2;
}
.near-win-glow {
  position: absolute;
  inset: -20px;
  background: radial-gradient(ellipse, rgba(255, 215, 106, 0.5) 0%, transparent 60%);
  z-index: 0;
  pointer-events: none;
  animation: near-win-pulse 1.4s ease-in-out infinite;
}
@keyframes near-win-in {
  0%   { opacity: 0; transform: translate(-50%, -80%) scale(0.6) rotate(-8deg); }
  60%  { opacity: 1; transform: translate(-50%, -50%) scale(1.12) rotate(2deg); }
  100% { opacity: 1; transform: translate(-50%, -50%) scale(1) rotate(0); }
}
@keyframes near-win-out {
  0%   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -150%) scale(0.85); }
}
@keyframes near-win-pulse {
  0%, 100% { opacity: 0.6; transform: scale(1); }
  50%      { opacity: 1;   transform: scale(1.08); }
}

/* Match pulse del board (cada match): zoom + saturation kick */
@keyframes match-pulse-kf {
  0%   { transform: scale(1);     filter: saturate(1) brightness(1); }
  35%  { transform: scale(1.012); filter: saturate(1.25) brightness(1.06); }
  100% { transform: scale(1);     filter: saturate(1) brightness(1); }
}
.board.match-pulse {
  animation: match-pulse-kf 0.28s cubic-bezier(0.34, 1.56, 0.64, 1);
  transform-origin: center center;
}

/* Debris: partículas grandes con animación más larga y rotación
   (la partícula sigue una parábola: --dx,--dy ya incluye gravedad) */
.match-particle.match-debris {
  width: 11px;
  height: 11px;
  border-radius: 2px;
  animation: debris-fly 1.1s cubic-bezier(0.18, 0.5, 0.4, 1) forwards;
}
@keyframes debris-fly {
  0%   { transform: translate(-50%, -50%) scale(1) rotate(0); opacity: 1; }
  60%  { opacity: 1; }
  100% { transform: translate(calc(-50% + var(--dx, 0px)), calc(-50% + var(--dy, 0px))) scale(0.4) rotate(380deg); opacity: 0; }
}


/* ════════════════════════════════════════════
   v2.6.10 — Characters dialog + Quest cards
   ════════════════════════════════════════════ */

/* Character dialog bubble */
.char-dialog {
  /* v2.58.3 — 92px: despeja la navbar (home) y el dock de boosters (nivel);
     antes con 20px el globo tapaba los botones de abajo. */
  position: fixed; bottom: calc(92px + var(--safe-bottom)); left: 16px;
  z-index: 9700;
  display: flex; gap: 10px; align-items: flex-end;
  max-width: min(380px, 88vw);
  animation: char-rise-in 0.6s cubic-bezier(0.18, 0.9, 0.28, 1) backwards;
  pointer-events: auto; cursor: pointer;
}
.char-dialog-out { animation: char-slide-out 0.4s ease-in forwards; }
/* Retrato grande y con presencia. v2.38 — MOVIMIENTO 3D CALMO casi-real (el dueño
   pidió "que dejen de temblar"): el temblor venía del bob mecánico animando translateY
   con `filter: drop-shadow` SIN capa GPU → re-rasterizado por frame = shimmer. Fix:
   (1) promoción a capa propia (capa GPU + translateZ + backface-hidden) → render
   estable; (2) bob reemplazado por una RESPIRACIÓN/BALANCEO lento (7s) con pivote desde
   la base y un giro 3D sutil → se siente vivo y tranquilo, no mecánico. */
.char-portrait {
  width: clamp(110px, 28vw, 140px); flex-shrink: 0;
  filter: drop-shadow(0 8px 18px rgba(0,0,0,0.6));
  transform-origin: 50% 92%;            /* pivota desde los pies, como una persona parada */
  backface-visibility: hidden;
  transform: translateZ(0);             /* capa GPU propia → render estable */
  /* v2.55 — el dueño reportó TEMBLOR ("Parkinson") otra vez: en GPUs de celular
     el balanceo 3D (rotateY+perspective) sobre un elemento con filter:drop-shadow
     re-rasteriza el filtro CADA frame = shimmer. Se ELIMINA el idle infinito; el
     retrato queda quieto (solo la entrada grácil char-rise-in). Cero temblor. */
}
.char-portrait svg { width: 100%; height: auto; }
.char-bubble {
  background: rgba(14,4,24,0.96);
  backdrop-filter: blur(8px);
  padding: 12px 16px;
  border-radius: 16px 16px 16px 4px;
  border: 2px solid;
  box-shadow: 0 10px 28px rgba(0,0,0,0.55);
}
.char-name { font-family: Fraunces, serif; font-weight: 800; font-size: 14px; margin-bottom: 5px; letter-spacing: 0.4px; }
.char-msg { color: #fef7e3; font-size: 16px; line-height: 1.45; font-family: Fraunces, serif; font-style: italic; }
/* Entrada grácil: sube + escala desde 0.85 (antes era un slide-X de 0.4s, brusco). */
@keyframes char-rise-in {
  0%   { opacity: 0; transform: translateY(22px) scale(0.85); }
  60%  { opacity: 1; transform: translateY(-3px) scale(1.02); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes char-portrait-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-5px); }
}
/* v2.38 — RESPIRACIÓN 3D del personaje: lenta, orgánica, casi real. Combina respirar
   (translateY + scale leves) con un balanceo suave (rotateZ ±0.5°) y un giro 3D sutil
   (rotateY ±2° con perspective). 7s + ease-in-out → calmo, no mecánico. */
@keyframes char-breathe {
  0%   { transform: perspective(600px) translateZ(0) translateY(0)    rotateZ(0deg)    rotateY(0deg)  scale(1); }
  25%  { transform: perspective(600px) translateZ(0) translateY(-2px) rotateZ(0.5deg)  rotateY(2deg)  scale(1.008); }
  50%  { transform: perspective(600px) translateZ(0) translateY(-3px) rotateZ(0deg)    rotateY(0deg)  scale(1.014); }
  75%  { transform: perspective(600px) translateZ(0) translateY(-2px) rotateZ(-0.5deg) rotateY(-2deg) scale(1.008); }
  100% { transform: perspective(600px) translateZ(0) translateY(0)    rotateZ(0deg)    rotateY(0deg)  scale(1); }
}
@keyframes char-slide-out {
  0% { opacity: 1; }
  100% { opacity: 0; transform: translateY(12px) scale(0.92); }
}
/* Respeta "reducir movimiento": sin bob ni rise exagerado. */
.reduce-motion .char-portrait { animation: none; }
.reduce-motion .char-dialog { animation: char-rise-in 0.3s ease-out backwards; }

/* Confetti reutilizable (juice.js) — celebraciones de win en cualquier modo. */
.juice-confetti-layer { position: fixed; inset: 0; z-index: 9600; pointer-events: none; overflow: hidden; }
.juice-confetti {
  position: absolute; top: -12px; width: 13px; height: 18px; border-radius: 2px;
  opacity: 0.95; animation: juice-confetti-fall linear forwards;
}
@keyframes juice-confetti-fall {
  0%   { transform: translateY(-20px) rotate(0deg); opacity: 1; }
  100% { transform: translateY(118vh) rotate(540deg); opacity: 0; }
}

/* Chip de capítulo en el HUD del nivel (narrativa presente · Fase 4). */
.chapter-row { display: flex; justify-content: center; margin: 1px 0 3px; }
.chapter-chip {
  font-family: Fraunces, serif; font-size: 12px; color: #c8b8d8;
  background: rgba(58,31,90,0.40); border: 1px solid rgba(242,184,75,0.28);
  padding: 3px 12px; border-radius: 999px; letter-spacing: 0.2px;
  max-width: 92vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chapter-chip b { color: #f2b84b; font-weight: 700; }

/* Card de progreso de historia en Home (Fase 4b). */
.story-card {
  background: linear-gradient(135deg, rgba(58,31,90,0.45), rgba(139,58,74,0.30));
  border: 1px solid rgba(242,184,75,0.28); border-radius: 14px;
  padding: 12px 14px; margin: 0 0 14px;
}
.story-head { display: flex; align-items: center; gap: 12px; }
.story-icon { font-size: 30px; flex-shrink: 0; }
.story-kicker { font-size: 12px; letter-spacing: 0.6px; text-transform: uppercase; color: #f2b84b; font-weight: 700; }
.story-title { font-family: Fraunces, serif; font-size: 17px; color: #fef7e3; line-height: 1.2; margin-top: 2px; }
.story-bar { height: 6px; border-radius: 999px; background: rgba(0,0,0,0.35); margin-top: 10px; overflow: hidden; }
.story-bar-fill { height: 100%; border-radius: 999px; background: linear-gradient(90deg, #c46a2a, #f2b84b); transition: width 0.5s ease; }

/* Modal de subida de tier del Pase (Fase 5a). */
.pass-tierup-overlay {
  position: fixed; inset: 0; z-index: 9750; display: flex; align-items: center; justify-content: center;
  background: rgba(10,4,20,0.72); backdrop-filter: blur(4px); animation: char-rise-in 0.35s ease-out backwards;
}
.pass-tierup-card {
  background: linear-gradient(160deg, #3a1f5a, #1a0820); border: 2px solid #f2b84b;
  border-radius: 20px; padding: 26px 28px; text-align: center; max-width: 86vw; width: 340px;
  box-shadow: 0 18px 50px rgba(0,0,0,0.6);
}
.ptu-icon { font-size: 46px; }
.ptu-kicker { color: #f2b84b; font-weight: 800; letter-spacing: 1.5px; font-size: 12px; margin-top: 4px; }
.pass-tierup-card h2 { font-family: Fraunces, serif; color: #fef7e3; margin: 6px 0 4px; font-size: 30px; }
.pass-tierup-card p { color: #c8b8d8; font-size: 14px; margin: 0 0 16px; }
.pass-tierup-card .row { display: flex; gap: 10px; justify-content: center; }

/* Rescate del modo Triple (Pilar 2b). */
.tt-rescue-actions { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.tt-rescue-actions .btn small { opacity: 0.85; font-weight: 600; margin-left: 4px; }

/* Daily Quest cards */
.quests-section {
  background: rgba(58,31,90,0.18);
  padding: 12px;
  border-radius: 10px;
  border: 1px solid rgba(242,184,75,0.15);
}
.quest-card {
  display: grid;
  grid-template-columns: 32px 1fr auto;
  gap: 10px; align-items: center;
  padding: 8px 10px;
  background: rgba(14,4,24,0.4);
  border-radius: 8px;
  margin-bottom: 6px;
}
.quest-card.done {
  background: rgba(111,227,193,0.12);
  border: 1px solid rgba(111,227,193,0.4);
}
.quest-card.claimed { opacity: 0.5; }
.q-icon { font-size: 22px; text-align: center; }
.q-info { min-width: 0; }
.q-label { font-size: 13px; color: #fef7e3; font-weight: 600; margin-bottom: 4px; }
.q-progress-bar { background: rgba(255,255,255,0.08); height: 5px; border-radius: 3px; overflow: hidden; }
.q-progress-fill { background: linear-gradient(90deg, #f2b84b, #6fe3c1); height: 100%; transition: width 0.4s; }
.q-progress-text { font-size: 12px; color: #a89568; margin-top: 2px; letter-spacing: 0.4px; }

/* ════════════════════════════════════════════
   v2.6.11 — Fix flicker + Reward celebration
   ════════════════════════════════════════════ */

/* Anti-flicker GPU acceleration — SOLO los 3 contenedores del tablero (barato).
   v2.25: se quitó la regla `.tile { promoción-GPU }` que promovía CADA ficha (hasta
   142 capas GPU = jank). Las fichas que animan reciben promoción GPU en su estado
   (.selected / .match-burst); el resto del tablero queda estático. */
.board-svg, .gameboard-wrap, .board {
  will-change: transform;
  transform: translateZ(0);
  backface-visibility: hidden;
}


/* ════════════════════════════════════════════
   Reward Celebration: cofre + tarjeta + partículas
   ════════════════════════════════════════════ */
.reward-celebration {
  position: fixed; inset: 0;
  z-index: 9800;
  display: flex; align-items: center; justify-content: center;
  pointer-events: auto;
}
.reward-celebration.rc-fade-out { animation: rc-fade-out 0.4s ease-in forwards; }
@keyframes rc-fade-out { to { opacity: 0; } }

.rc-backdrop {
  position: absolute; inset: 0;
  background: radial-gradient(ellipse at center, rgba(58,31,90,0.85) 0%, rgba(14,4,24,0.95) 100%);
  backdrop-filter: blur(6px);
  animation: rc-backdrop-in 0.4s ease-out;
}
@keyframes rc-backdrop-in {
  from { opacity: 0; backdrop-filter: blur(0); }
  to { opacity: 1; }
}

/* Rayos de luz radiales detrás del cofre */
.rc-rays {
  position: absolute; top: 35%; left: 50%;
  width: 600px; height: 600px;
  margin-left: -300px; margin-top: -300px;
  background: conic-gradient(from 0deg,
    rgba(248,220,61,0.0) 0deg, rgba(248,220,61,0.4) 15deg, rgba(248,220,61,0) 30deg,
    rgba(248,220,61,0) 60deg, rgba(248,220,61,0.4) 75deg, rgba(248,220,61,0) 90deg,
    rgba(248,220,61,0) 120deg, rgba(248,220,61,0.4) 135deg, rgba(248,220,61,0) 150deg,
    rgba(248,220,61,0) 180deg, rgba(248,220,61,0.4) 195deg, rgba(248,220,61,0) 210deg,
    rgba(248,220,61,0) 240deg, rgba(248,220,61,0.4) 255deg, rgba(248,220,61,0) 270deg,
    rgba(248,220,61,0) 300deg, rgba(248,220,61,0.4) 315deg, rgba(248,220,61,0) 330deg,
    rgba(248,220,61,0) 360deg);
  animation: rc-rays-rotate 12s linear infinite, rc-rays-in 0.8s ease-out;
  pointer-events: none;
  opacity: 0;
}
.reward-celebration.rc-chest-show .rc-rays { opacity: 1; }
@keyframes rc-rays-rotate {
  from { transform: rotate(0); } to { transform: rotate(360deg); }
}
@keyframes rc-rays-in { from { opacity: 0; transform: scale(0.5); } to { opacity: 1; transform: scale(1); } }

.rc-content {
  position: relative; z-index: 2;
  text-align: center;
  padding: 32px 24px;
  max-width: 380px;
}

.rc-title {
  font-family: Fraunces, serif;
  font-size: 32px;
  font-weight: 900;
  color: #fef7e3;
  text-shadow: 0 4px 16px rgba(0,0,0,0.6), 0 0 24px rgba(248,220,61,0.7);
  margin-bottom: 18px;
  letter-spacing: 0.5px;
  animation: rc-title-pop 0.6s cubic-bezier(0.2, 1.4, 0.4, 1) backwards;
}
@keyframes rc-title-pop {
  0% { opacity: 0; transform: scale(0.5) translateY(-20px); }
  60% { opacity: 1; transform: scale(1.1); }
  100% { transform: scale(1) translateY(0); }
}

/* Cofre */
.rc-chest {
  width: 200px; height: 180px;
  margin: 0 auto;
  opacity: 0;
  transform: scale(0.4) translateY(40px);
  transition: opacity 0.4s, transform 0.5s cubic-bezier(0.2, 1.2, 0.4, 1);
  filter: drop-shadow(0 12px 30px rgba(0,0,0,0.8)) drop-shadow(0 0 20px rgba(248,220,61,0.4));
}
.reward-celebration.rc-chest-show .rc-chest {
  opacity: 1;
  transform: scale(1) translateY(0);
  animation: rc-chest-shake 0.4s ease-out 0.3s;
}
@keyframes rc-chest-shake {
  0%, 100% { transform: rotate(0); }
  20% { transform: rotate(-4deg); }
  40% { transform: rotate(4deg); }
  60% { transform: rotate(-3deg); }
  80% { transform: rotate(2deg); }
}

/* Tapa del cofre se abre */
.rc-lid {
  transform-origin: 100px 88px;
  transition: transform 0.6s cubic-bezier(0.34, 1.4, 0.5, 1);
}
.reward-celebration.rc-chest-open .rc-lid {
  transform: perspective(300px) rotateX(-118deg);
}
.rc-inner-glow {
  transition: opacity 0.4s 0.2s;
}
.reward-celebration.rc-chest-open .rc-inner-glow {
  opacity: 1;
  animation: rc-inner-pulse 1.6s ease-in-out infinite 0.6s;
}
@keyframes rc-inner-pulse {
  0%, 100% { opacity: 0.6; }
  50% { opacity: 1; }
}
/* v2.21 — halo de luz que ESTALLA al abrir */
.rc-burst { transform-origin: 100px 92px; }
.reward-celebration.rc-chest-open .rc-burst {
  animation: rc-burst-pop 0.7s ease-out forwards;
}
@keyframes rc-burst-pop {
  0% { opacity: 0; transform: scale(0.3); }
  35% { opacity: 0.95; transform: scale(1.15); }
  100% { opacity: 0; transform: scale(1.5); }
}
/* v2.21 — el tesoro (monedas+gema) asoma del cofre al abrir */
.rc-treasure { transform-origin: 100px 100px; }
.reward-celebration.rc-chest-open .rc-treasure {
  animation: rc-treasure-rise 0.6s cubic-bezier(0.2,1.3,0.4,1) forwards 0.18s;
}
@keyframes rc-treasure-rise {
  0% { opacity: 0; transform: translateY(14px) scale(0.7); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}
/* candado salta y cae al abrir */
.rc-lock { transform-origin: 100px 114px; }
.reward-celebration.rc-chest-open .rc-lock {
  animation: rc-lock-burst 0.5s ease-in forwards;
}
@keyframes rc-lock-burst {
  0% { opacity: 1; transform: translateY(0) rotate(0); }
  30% { transform: translateY(-22px) rotate(-15deg); }
  100% { opacity: 0; transform: translateY(60px) rotate(40deg); }
}
/* gema con destello (brillo continuo tras abrir) */
.reward-celebration.rc-chest-open .rc-treasure { will-change: transform; }
body.reduce-motion .rc-burst,
body.reduce-motion .rc-treasure,
body.reduce-motion .rc-lock { animation: none !important; opacity: 1; }
body.reduce-motion .rc-lock { display: none; }

/* Tarjeta del premio */
.rc-card {
  margin: -20px auto 20px;
  background: linear-gradient(180deg, rgba(248,220,61,0.18), rgba(242,184,75,0.12));
  border: 2px solid #f2b84b;
  border-radius: 14px;
  padding: 18px 24px;
  min-width: 200px;
  box-shadow:
    0 0 0 3px rgba(248,220,61,0.2),
    0 8px 24px rgba(0,0,0,0.5),
    inset 0 1px 0 rgba(255,255,255,0.2);
  opacity: 0;
  transform: scale(0.7) translateY(40px);
  transition: opacity 0.5s, transform 0.5s cubic-bezier(0.2, 1.3, 0.4, 1);
}
.reward-celebration.rc-card-show .rc-card {
  opacity: 1;
  transform: scale(1) translateY(0);
  animation: rc-card-float 3s ease-in-out infinite 0.6s;
}
@keyframes rc-card-float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-4px); }
}
.rc-card-icon {
  font-size: 44px;
  margin-bottom: 8px;
  filter: drop-shadow(0 4px 10px rgba(248,220,61,0.6));
  animation: rc-icon-spin 4s ease-in-out infinite;
}
@keyframes rc-icon-spin {
  0%, 100% { transform: rotate(0); }
  50% { transform: rotate(8deg); }
}
.rc-card-coins {
  font-family: Fraunces, serif;
  font-size: 30px;
  font-weight: 900;
  color: #f8dc3d;
  text-shadow: 0 2px 8px rgba(0,0,0,0.6), 0 0 16px rgba(248,220,61,0.6);
  letter-spacing: 1px;
}
.rc-card-item {
  font-family: Fraunces, serif;
  font-size: 16px;
  color: #fef7e3;
  margin-top: 6px;
  letter-spacing: 0.5px;
}
.rc-card-msg {
  font-family: Fraunces, serif;
  font-style: italic;
  font-size: 13px;
  color: #d8c9a8;
  margin-top: 10px;
  line-height: 1.4;
}

.rc-btn {
  background: linear-gradient(180deg, #f2b84b, #c8881d);
  border: none;
  color: #2a1804;
  padding: 12px 36px;
  border-radius: 10px;
  font-family: Fraunces, serif;
  font-weight: 800;
  font-size: 15px;
  letter-spacing: 0.5px;
  cursor: pointer;
  margin-top: 18px;
  box-shadow: 0 6px 16px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.3);
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.4s 1.2s, transform 0.4s 1.2s;
}
.rc-btn:hover { transform: translateY(-2px); box-shadow: 0 8px 20px rgba(0,0,0,0.6); }
.rc-btn:active { transform: translateY(0); }
.reward-celebration.rc-card-show .rc-btn {
  opacity: 1;
  transform: translateY(0);
}

/* Partículas doradas */
.rc-particles {
  position: absolute; top: 35%; left: 50%;
  width: 0; height: 0;
  pointer-events: none;
}
.rc-particle {
  position: absolute;
  width: 8px; height: 8px;
  border-radius: 50%;
  top: 0; left: 0;
  box-shadow: 0 0 8px currentColor;
  animation: rc-particle-fly 1.4s cubic-bezier(0.1, 0.6, 0.3, 1) forwards;
}
@keyframes rc-particle-fly {
  0% { opacity: 1; transform: translate(0, 0) scale(0); }
  20% { opacity: 1; transform: translate(calc(var(--dx) * 0.3), calc(var(--dy) * 0.3 - 20px)) scale(1.4); }
  100% { opacity: 0; transform: translate(var(--dx), var(--dy)) scale(0.4); }
}

/* ====================================================================
   Tendencias modernas: progress bar · shuffle · climax · urgencia · diario
   ==================================================================== */

/* HUD progress bar — barra delgada pegada al fondo del HUD */
.hud { position: relative; }
.hud-progress {
  position: absolute; bottom: 0; left: 0; right: 0;
  height: 3px;
  background: rgba(0,0,0,0.3);
  overflow: hidden;
  border-radius: 0 0 var(--r-sm) var(--r-sm);
}
.hud-progress-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--siena) 0%, var(--gold) 55%, var(--teal) 100%);
  transition: width 0.4s cubic-bezier(0.22, 0.7, 0.32, 1);
  box-shadow: 0 0 8px rgba(242, 184, 75, 0.6);
  will-change: width;
}

/* Board climax: cuando quedan ≤10 fichas, las fichas escalan despacio
   (5 segundos) para dar foco al endgame. EL FRAME (cuadro dorado) NUNCA
   se toca — solo el grupo <g class="board-tiles-layer"> dentro del SVG.
   El transform-origin viene inline del game.js (w/2, h/2 del viewBox).
   `!important` aquí es necesario porque reduce-motion global aplica
   `transition-duration: 0.01ms !important` con `*` selector — sin override
   no habría animación, sería un salto instantáneo. */
.board.board-climax .board-svg .board-tiles-layer {
  transform: scale(1.05) !important;
  transition: transform 5s cubic-bezier(0.22, 0.7, 0.32, 1) !important;
}
.board:not(.board-climax) .board-svg .board-tiles-layer {
  transform: scale(1) !important;
  transition: transform 5s cubic-bezier(0.22, 0.7, 0.32, 1) !important;
}

/* Shuffle out — fade de las fichas antes del remix */
.board-svg .tile.tile-shuffle-out {
  animation: tileShuffleOut 0.32s ease-in forwards !important;
}
@keyframes tileShuffleOut {
  0%   { opacity: 1; }
  60%  { opacity: 0.3; }
  100% { opacity: 0; }
}

/* Timer urgency — cambia de color cuando se acercan las estrellas */
#timer.timer-alert {
  color: var(--gold);
  font-weight: 700;
  transition: color 0.4s;
}
#timer.timer-warn {
  color: var(--rose);
  font-weight: 700;
  animation: timerUrgency 0.8s ease-in-out infinite;
}
@keyframes timerUrgency {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.55; }
}

/* ═══════════════════════════════════════════════════════════════
   A06: SPECIALS — golden / frozen / bomb / locked
   Mecánicas implementadas en game.js. Estos estilos los distinguen
   visualmente del resto para que el jugador identifique su rol.
   ═══════════════════════════════════════════════════════════════ */

/* SPECIALS — efectos LIGEROS para que el emoji original mande siempre.
   Antes había 3 capas de drop-shadow que tapaban la ficha; ahora una sola
   capa sutil + el color funcional vive en bordes/glow apenas perceptible.
   El jugador identifica el tipo por el TINTE de color, no por el chichón. */

/* Golden — tinte dorado leve, brillito chico al estar libre */
.board-svg .tile.special-golden {
  filter: drop-shadow(0 0 6px rgba(246, 200, 79, 0.55)) !important;
}
.board-svg .tile.special-golden.free {
  filter: drop-shadow(0 0 9px rgba(246, 200, 79, 0.80)) !important;
}

/* Bomb — tinte rojo/naranja sutil */
.board-svg .tile.special-bomb {
  filter: drop-shadow(0 0 7px rgba(255, 104, 77, 0.60)) !important;
}

/* Frozen — celeste leve, opacidad apenas reducida (se nota congelada) */
.board-svg .tile.special-frozen {
  filter: drop-shadow(0 0 6px rgba(130, 217, 255, 0.65)) !important;
  opacity: 0.92;
}

/* Locked — violeta tenue + cursor no-allowed */
.board-svg .tile.special-locked {
  filter: drop-shadow(0 0 6px rgba(141, 122, 168, 0.65)) !important;
  cursor: default !important;
}

/* Lightning — cian con un PULSO MUY SUAVE en la opacidad (no en filter,
   para no machacar el emoji) */
.board-svg .tile.special-lightning {
  filter: drop-shadow(0 0 7px rgba(122, 220, 255, 0.70)) !important;
  animation: lightningPulse 1.8s ease-in-out infinite;
}
@keyframes lightningPulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.86; }
}

/* Eye — turquesa, pulso lento e imperceptible */
.board-svg .tile.special-eye {
  filter: drop-shadow(0 0 6px rgba(100, 220, 200, 0.65)) !important;
  animation: eyePulse 3.2s ease-in-out infinite;
}
@keyframes eyePulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.88; }
}

/* Peek mode (eye) — ficha bloqueada revelada por 3s con tinte turquesa */
.board-svg .tile.peek-revealed {
  filter: drop-shadow(0 0 5px rgba(100, 220, 200, 0.45)) !important;
  opacity: 0.92;
}

@media (prefers-reduced-motion: reduce) {
  .board-svg .tile.special-lightning,
  .board-svg .tile.special-eye { animation: none !important; }
}

/* v4.0 — Tarea 4: badge de accesibilidad UNIVERSAL (glifo, no depende del
   color) para las 6 fichas especiales — el tinte de arriba (drop-shadow de
   color) es invisible para daltónicos. El <text> con el glifo lo agrega
   game.js en la esquina sup-derecha de cada ficha especial; acá solo le
   damos legibilidad sobre CUALQUIER color de cara (crema, tint dorado, bg
   personalizado del editor). drop-shadow doble ESTÁTICO (sin @keyframes,
   sin animación) — permitido por perf_budget, mismo patrón que la sombra de
   contacto de .tile.free/.blocked más arriba. No reemplaza el tinte de color
   (que se mantiene, es redundancia útil) — lo complementa (WCAG 1.4.1). */
.board-svg .tile-special-badge {
  font-size: 11px;
  filter: drop-shadow(0 0 1.1px rgba(0,0,0,0.9)) drop-shadow(0 0 1.7px rgba(0,0,0,0.75));
}

/* Daily challenge in-game badge */
.daily-level-badge {
  display: inline-flex;
  align-items: center;
  background: linear-gradient(135deg, #f2b84b, #c46a2a);
  color: #1a0820;
  font-size: 12px;
  font-weight: 800;
  padding: 2px 7px;
  border-radius: 999px;
  letter-spacing: 0.5px;
  animation: dailyBadgePulse 2s ease-in-out infinite;
  vertical-align: middle;
  margin-left: 5px;
  line-height: 1.4;
}
@keyframes dailyBadgePulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.04); }
}

/* ════════════════════════════════════════════════════════════════════
   FASE D — Polish visual estilo Supercell
   ════════════════════════════════════════════════════════════════════ */

/* D2 — Hit-flash full-screen (solo combo≥2). Destello dorado radial 160ms. */
.hit-flash-overlay {
  position: fixed; inset: 0;
  pointer-events: none;
  z-index: 60;
  background: radial-gradient(circle at 50% 55%, rgba(255,236,140,0.34) 0%, rgba(255,200,80,0.14) 38%, transparent 64%);
  animation: hitFlash 160ms ease-out forwards;
}
@keyframes hitFlash {
  0%   { opacity: 0; }
  30%  { opacity: 1; }
  100% { opacity: 0; }
}

/* ════════ v2.25 — Sensación "top": luz que respira + premio + ripple + crítico.
   TODO opacity/transform (compuesto en GPU, no repinta) → no traba el motor.
   Sutil a propósito para NO bajar el contraste del texto. reduce-motion off. ════════ */

/* Luz ambiental que sube y baja SIEMPRE — calidez de fondo "adictiva". Un solo
   elemento; concentrada arriba (donde está el cielo, lejos del texto del HUD). */
.ambient-breath {
  position: fixed; inset: 0; pointer-events: none; z-index: 1;
  background: radial-gradient(120% 70% at 50% 8%,
              rgba(255,214,106,0.085) 0%, rgba(242,184,75,0.04) 34%, transparent 60%);
  opacity: 0.4; mix-blend-mode: screen;
  animation: ambientBreath 7.5s ease-in-out infinite;
}
@keyframes ambientBreath { 0%,100% { opacity: 0.28; } 50% { opacity: 0.62; } }
.ambient-breath.flare { animation: ambientFlare 0.72s ease-out; }
@keyframes ambientFlare { 0% { opacity: 0.6; } 22% { opacity: 0.95; } 100% { opacity: 0.4; } }

/* Destello CÁLIDO en premios (match/combo/win/cofre) — "la luz cuando hay premio".
   Intensidad por variables que setea juice.js (combo grande = ilumina más). */
.reward-glow {
  position: fixed; inset: 0; pointer-events: none; z-index: 58;
  background: radial-gradient(circle at 50% 55%,
              hsla(var(--rg-hue, 44), 100%, 72%, 0.85) 0%,
              hsla(var(--rg-hue, 44), 95%, 60%, 0.30) 30%, transparent 60%);
  opacity: 0; transform: scale(var(--rg-scale, 1)); mix-blend-mode: screen;
  animation: rewardGlowPulse 0.7s ease-out forwards;
  will-change: opacity, transform;
}
@keyframes rewardGlowPulse {
  0%   { opacity: 0; transform: scale(0.7); }
  28%  { opacity: var(--rg-op, 0.6); transform: scale(var(--rg-scale, 1)); }
  100% { opacity: 0; transform: scale(calc(var(--rg-scale, 1) * 1.18)); }
}

/* Ripple al tocar una ficha — feedback inmediato (técnica de juegos top). */
.tap-ripple {
  position: fixed; pointer-events: none; z-index: 57;
  width: var(--ripple-size, 30px); height: var(--ripple-size, 30px);
  margin-left: calc(var(--ripple-size, 30px) / -2);
  margin-top: calc(var(--ripple-size, 30px) / -2);
  border-radius: 50%; border: 2px solid var(--ripple-color, rgba(255,215,106,0.95));
  opacity: 0.9; transform: scale(0.3);
  animation: tapRippleAnim 0.5s cubic-bezier(0.2,0.7,0.3,1) forwards;
  will-change: opacity, transform;
}
@keyframes tapRippleAnim { 0% { opacity: 0.9; transform: scale(0.3); } 100% { opacity: 0; transform: scale(2.6); } }

/* Flash crítico breve (combo ≥ 5) — pico visual de "golpe crítico". v2.27: cálido
   y suave (antes blanco 0.5 = se sentía duro/"semi-pro"); ahora un destello dorado
   tenue que se integra con la paleta. */
.crit-flash {
  position: fixed; inset: 0; pointer-events: none; z-index: 59;
  background: radial-gradient(circle at 50% 50%, rgba(255,236,180,0.42) 0%, rgba(255,214,106,0.16) 45%, transparent 70%);
  opacity: 0; mix-blend-mode: screen;
  animation: critFlashAnim 0.3s ease-out forwards;
}
@keyframes critFlashAnim { 0% { opacity: 0; } 22% { opacity: 0.9; } 100% { opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  .ambient-breath { animation: none !important; opacity: 0.28; }
  .reward-glow, .tap-ripple, .crit-flash { display: none !important; }
}

/* Shimmer: un brillo que cruza el botón principal cada tanto (atrae el ojo →
   técnica de retención). Solo transform/opacity en un ::after, barato. */
#btnPlay { position: relative; overflow: hidden; }
#btnPlay::after {
  content: ''; position: absolute; top: 0; left: -65%; width: 55%; height: 100%;
  background: linear-gradient(100deg, transparent, rgba(255,255,255,0.45), transparent);
  transform: skewX(-18deg); pointer-events: none;
  animation: shimmerSweep 4.5s ease-in-out infinite;
}
@keyframes shimmerSweep {
  0%, 68% { transform: translateX(-160%) skewX(-18deg); }
  100% { transform: translateX(200%) skewX(-18deg); }
}
.win-dialog .win-title, .reveal-title { position: relative; overflow: hidden; }
.win-dialog .win-title::after {
  content: ''; position: absolute; inset: 0; left: -65%; width: 55%;
  background: linear-gradient(100deg, transparent, rgba(255,255,255,0.5), transparent);
  transform: skewX(-18deg); pointer-events: none;
  animation: shimmerSweep 3.2s ease-in-out 0.4s infinite;
}
@media (prefers-reduced-motion: reduce) {
  #btnPlay::after, .win-dialog .win-title::after { display: none !important; }
}

/* D5 — Escalada de combo: glow del score en el HUD.
   v2.27 PERF: se QUITÓ el `filter: saturate/brightness` sobre TODO #screen — animar
   un filtro full-screen en cada combo hitcheaba el celular justo al encadenar
   (se sentía como un "salto"). La reacción de pantalla al combo ahora la da el
   reward-glow (juice.js, opacity → GPU), que escala con el combo sin repintar. */
body.combo-3 .gameboard-wrap .hud-stat.score .v { text-shadow: 0 0 10px rgba(242,184,75,0.7); }
body.combo-5 .gameboard-wrap .hud-stat.score .v {
  text-shadow: 0 0 16px rgba(242,184,75,0.9);
  animation: comboHudPulse 0.4s ease-out;
}
body.combo-7 .gameboard-wrap .hud-stat.score .v {
  text-shadow: 0 0 22px rgba(255,180,48,1), 0 0 6px #fff;
  animation: comboHudPulse 0.4s ease-out;
  color: #ffd76a;
}
@keyframes comboHudPulse {
  0% { transform: scale(1); }
  45% { transform: scale(1.28); }
  100% { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .hit-flash-overlay { display: none !important; }
}

/* D1 — Monedas que vuelan al contador (Supercell signature). Las anima WAAPI
   desde JS; acá solo el look del elemento volador. */
.coin-fly {
  position: fixed;
  z-index: 10000;
  font-size: 22px;
  line-height: 1;
  pointer-events: none;
  filter: drop-shadow(0 2px 4px rgba(180,120,20,0.6));
  will-change: transform, opacity;
}

/* D1b — Mini-contador de coins del win-overlay (destino de la coin-fly,
   porque el wallet del Home queda tapado por el overlay). */
.win-coin-target {
  display: inline-flex; align-items: center; gap: 6px;
  background: rgba(0,0,0,0.32);
  border: 1px solid rgba(242,184,75,0.5);
  border-radius: 999px;
  padding: 4px 12px;
  font-weight: 800; font-size: 16px;
  color: var(--gold);
}
.win-coin-target.coin-bump,
.coin-bump { animation: coinBump 0.3s ease-out; }   /* v2.19: genérico (chip topbar) */
@keyframes coinBump {
  0% { transform: scale(1); }
  50% { transform: scale(1.18); }
  100% { transform: scale(1); }
}
.reduce-motion .coin-bump { animation: none; }

/* v3.8 — "+N" del match que vuela al contador de score (mismo patrón WAAPI
   que .coin-fly, ver spawnScoreFly en game.js). Reusa .coin-bump al aterrizar. */
.score-fly {
  position: fixed; z-index: 9000; pointer-events: none;
  font-weight: 800; font-size: 20px; color: var(--gold, #f2b84b);
  text-shadow: 0 2px 6px rgba(0,0,0,0.6);
  will-change: transform, opacity;
}

/* v3.8 — "Aliento del Cerro" (src/live_comments.js): carteles que entran
   deslizando desde el borde derecho en momentos buenos (paridad de "feel"
   con el barrage/livecomments de Vita). z-index MENOR que los overlays de
   fin (win-overlay z:200, tt-end-overlay/tt-rescue-overlay z:80) — nunca los tapa. */
.cheer-banner {
  position: fixed; top: 38%; right: 0; z-index: 70;
  max-width: 76vw; padding: 10px 16px 10px 20px;
  border-radius: 999px 0 0 999px;
  background: linear-gradient(120deg,#f2b84b,#c46a2a);
  color: #fef3d8; font-weight: 700; font-size: 15px; white-space: nowrap;
  box-shadow: 0 4px 16px rgba(0,0,0,0.35);
  font-family: var(--font-display, serif);
  pointer-events: none;
  transform: translate(115%, var(--cy, 0px));
  animation: cheerIn 0.35s ease-out forwards;
}
.cheer-banner.cheer-out { animation: cheerOut 0.5s ease-in forwards; }
.cheer-banner.cheer-static { animation: none; opacity: 1; transform: translate(0, var(--cy, 0px)); }
@keyframes cheerIn {
  from { transform: translate(115%, var(--cy, 0px)); opacity: 0; }
  to   { transform: translate(0, var(--cy, 0px)); opacity: 1; }
}
@keyframes cheerOut {
  from { transform: translate(0, var(--cy, 0px)); opacity: 1; }
  to   { transform: translate(115%, var(--cy, 0px)); opacity: 0; }
}

/* D3 — Feedback de boosters armados (modo activo a la espera de target). */
.booster-armed-badge {
  position: fixed;
  left: 50%; transform: translateX(-50%);
  bottom: calc(86px + var(--safe-bottom));
  z-index: 9002;
  background: linear-gradient(135deg, #5a2548, #c46a2a);
  color: #fff; font-weight: 800; font-size: 13px;
  padding: 7px 16px; border-radius: 999px;
  border: 1px solid rgba(255,215,106,0.6);
  box-shadow: 0 6px 18px rgba(0,0,0,0.5);
  pointer-events: none; white-space: nowrap;
  animation: armedBadgeIn 0.3s cubic-bezier(0.34,1.56,0.64,1);
}
@keyframes armedBadgeIn {
  from { opacity: 0; transform: translateX(-50%) translateY(10px); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0); }
}
/* D3b — glow rojo pulsante cuando queda 1 uso del booster (urgencia). */
.booster .count.last-use {
  color: #ffd0d0;
  animation: lastUseBlink 1s ease-in-out infinite;
}
@keyframes lastUseBlink {
  0%, 100% { text-shadow: 0 0 0 transparent; }
  50%      { text-shadow: 0 0 8px rgba(255,80,80,0.95); color: #fff; }
}

/* D4 — Tema visual por mundo: tinta el HALO superior del fondo del juego con
   la paleta del mundo. El board mantiene su frame propio y el HUD su fondo
   oscuro → la legibilidad NO se ve afectada (verificado puna noche + carnaval).
   Solo cambia el color del aura superior, reforzando la identidad del mundo. */
body.world-san_salvador .gameboard-wrap, body.world-san_salvador_2 .gameboard-wrap {
  background:
    radial-gradient(ellipse at 50% -10%, #2d3a6a 0%, transparent 52%),
    radial-gradient(ellipse at 50% 110%, #5a3a28 0%, transparent 55%),
    var(--bg);
}
body.world-valles .gameboard-wrap, body.world-valles_2 .gameboard-wrap {
  background:
    radial-gradient(ellipse at 50% -10%, #2a5a3e 0%, transparent 52%),
    radial-gradient(ellipse at 50% 110%, #4a3a1e 0%, transparent 55%),
    var(--bg);
}
body.world-quebrada .gameboard-wrap, body.world-quebrada_2 .gameboard-wrap {
  background:
    radial-gradient(ellipse at 50% -10%, #7a3a1e 0%, transparent 52%),
    radial-gradient(ellipse at 50% 110%, #5a2520 0%, transparent 55%),
    var(--bg);
}
body.world-carnaval .gameboard-wrap, body.world-carnaval_2 .gameboard-wrap {
  background:
    radial-gradient(ellipse at 50% -10%, #6a1f5a 0%, transparent 52%),
    radial-gradient(ellipse at 50% 110%, #7a1f3a 0%, transparent 55%),
    var(--bg);
}
body.world-puna .gameboard-wrap, body.world-puna_2 .gameboard-wrap {
  background:
    radial-gradient(ellipse at 50% -10%, #1e2a52 0%, transparent 52%),
    radial-gradient(ellipse at 50% 110%, #2a2440 0%, transparent 55%),
    var(--bg);
}
body.world-cielo .gameboard-wrap, body.world-cielo_2 .gameboard-wrap {
  background:
    radial-gradient(ellipse at 50% -10%, #3a2a72 0%, transparent 52%),
    radial-gradient(ellipse at 50% 110%, #2a3a6a 0%, transparent 55%),
    var(--bg);
}

/* ════════════════════════════════════════════════════════════════════
   FASE B — Modo Triple Tile
   ════════════════════════════════════════════════════════════════════ */

/* Cards de selección de modo en Home */
.mode-cards {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
  margin-top: 12px;
}
.mode-card {
  position: relative;
  background: var(--bg-elev);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: var(--r);
  padding: 14px 10px;
  display: grid; gap: 3px; place-items: center;
  cursor: pointer; font-family: inherit; color: var(--ink);
  transition: transform .1s, border-color .15s, box-shadow .15s;
}
.mode-card:active { transform: scale(0.96); }
.mode-card .mode-emoji { font-size: 30px; line-height: 1; }
.mode-card .mode-name { font-weight: 800; font-size: 14px; }
.mode-card .mode-desc { font-size: 12px; color: var(--ink-dim); }
.mode-card.mode-triple {
  border-color: rgba(242,184,75,0.45);
  background: linear-gradient(160deg, #3a2354, #2a1538);
}
.mode-card.mode-triple:hover { box-shadow: 0 0 16px rgba(242,184,75,0.4); }
.mode-badge-new {
  position: absolute; top: -7px; right: 8px;
  background: linear-gradient(135deg, #6fe3c1, #3a8a72);
  color: #06231b; font-size: 12px; font-weight: 800;
  padding: 2px 7px; border-radius: 999px; letter-spacing: 0.5px;
  animation: dailyBadgePulse 2s ease-in-out infinite;
}

/* Menú de stages */
.tt-menu { padding: 12px 14px 80px; }
.tt-menu-hero { text-align: center; margin: 8px 0 18px; }
.tt-kicker {
  display: inline-block; font-size: 12px; font-weight: 800; letter-spacing: 1px;
  color: #6fe3c1; margin-bottom: 6px;
}
.tt-menu-title {
  font-family: var(--font-display); font-size: 30px; margin: 0 0 6px;
  color: var(--gold);
}
.tt-menu-sub { font-size: 13px; color: var(--ink-dim); margin: 0; }
.tt-stage-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));
  gap: 10px; margin-top: 14px;
}
.tt-stage-card {
  position: relative; aspect-ratio: 1;
  background: var(--bg-elev); border: 1px solid rgba(255,255,255,0.08);
  border-radius: 14px; cursor: pointer; font-family: inherit; color: var(--ink);
  display: grid; place-items: center; gap: 2px;
  transition: transform .1s, box-shadow .15s;
}
.tt-stage-card:active { transform: scale(0.94); }
.tt-stage-card.done { border-color: rgba(111,227,193,0.5); }
.tt-stage-card.locked { opacity: 0.5; cursor: default; }
.tt-stage-num { font-size: 24px; font-weight: 800; font-family: var(--font-display); }
.tt-stage-meta { font-size: 12px; color: var(--ink-dim); }
.tt-stage-world { font-size: 12px; color: var(--ink-dim); text-transform: uppercase; letter-spacing: 0.4px; }
.tt-stage-check { position: absolute; top: 5px; right: 7px; color: #6fe3c1; font-size: 13px; }
.tt-stage-lock { position: absolute; top: 5px; right: 7px; font-size: 13px; }
.tt-stage-best { position: absolute; bottom: 4px; left: 0; right: 0; font-size: 12px; color: var(--gold); }
.tt-menu-progress { font-size: 12px; color: var(--ink-dim); margin: 8px 0 0; }

/* Campaña por mundos (v2.17) — espejo del mapa clásico */
.tt-world-section { margin: 0 0 22px; }
.tt-world-section.world-locked { opacity: 0.6; }
.tt-world-header { display: flex; align-items: center; gap: 10px; margin: 6px 2px 9px; }
.tt-world-name { font-family: var(--font-display); font-size: 17px; color: var(--gold); white-space: nowrap; }
.tt-world-prog { flex: 1; height: 7px; border-radius: 99px; background: rgba(255,255,255,0.1); overflow: hidden; }
.tt-world-prog-fill { height: 100%; background: linear-gradient(90deg, #6fe3c1, #43c59e); border-radius: 99px; transition: width .3s; }
.tt-world-count { font-size: 12px; color: var(--ink-dim); white-space: nowrap; min-width: 42px; text-align: right; }
/* grilla densa para campañas de 100 niveles por mundo */
.tt-stage-grid.dense { grid-template-columns: repeat(auto-fill, minmax(50px, 1fr)); gap: 7px; margin-top: 0; }
.tt-stage-grid.dense .tt-stage-card { border-radius: 11px; }
.tt-stage-grid.dense .tt-stage-num { font-size: 16px; }
.tt-stage-stars { font-size: 12px; color: var(--gold); letter-spacing: -1px; line-height: 1; }

/* Tablero de juego (fullscreen, igual que gameboard-wrap) */
.tt-wrap {
  position: fixed; inset: 0; z-index: 50;
  display: grid; grid-template-rows: auto auto 1fr auto;
  background:
    radial-gradient(ellipse at 50% -10%, #3a2a72 0%, transparent 52%),
    radial-gradient(ellipse at 50% 110%, #2a2440 0%, transparent 55%),
    var(--bg);
}
.tt-hud {
  display: flex; align-items: center; gap: 8px;
  padding: calc(6px + var(--safe-top)) 12px 6px;
  background: rgba(0,0,0,0.25); backdrop-filter: blur(8px);
}
.tt-hud-title { font-weight: 800; font-size: 14px; flex: 1; }
.tt-hud-prog { width: 90px; height: 7px; background: rgba(0,0,0,0.4); border-radius: 5px; overflow: hidden; }
.tt-hud-prog-fill { height: 100%; background: linear-gradient(90deg, #6fe3c1, #3a8a72); transition: width .3s; }
/* F9 — mismo criterio que el HUD clásico: hit-area invisible para el botón
   chico de Salir (<44px visual), sin agrandarlo. */
.tt-hud .btn.small { position: relative; }
.tt-hud .btn.small::after { content: ''; position: absolute; inset: -6px; }

/* Bandeja de 7 slots — ARRIBA (la "línea" que pidió la usuaria) */
.tt-tray {
  display: flex; gap: 5px; justify-content: center;
  padding: 14px 14px; background: rgba(0,0,0,0.18);
  border-bottom: 1px solid rgba(255,255,255,0.06);
  box-shadow: 0 -4px 12px rgba(0,0,0,0.3);   /* v2.29: elevación, paridad con el clásico */
}
.tt-slot {
  width: 42px; height: 52px; border-radius: 8px;
  background: rgba(255,255,255,0.05);
  border: 1.5px dashed rgba(255,255,255,0.14);
  display: grid; place-items: center;
  transition: background .15s, transform .15s;
}
.tt-slot.filled {
  background: #f6efe1; border: 1px solid rgba(40,25,12,0.6);
  box-shadow: 0 3px 6px rgba(0,0,0,0.4);
  animation: ttSlotIn .2s cubic-bezier(0.34,1.56,0.64,1);
}
.tt-slot-emoji { font-size: 26px; line-height: 1; }
@keyframes ttSlotIn { from { transform: scale(0.5); opacity: 0; } to { transform: scale(1); opacity: 1; } }

/* Área de pilas */
/* Tablero Mahjong INTERCALADO (v2.16): fichas posicionadas absolutamente por
   (x,y,z) en geometría cruzada — mismas constantes que el clásico. */
.tt-board { overflow: auto; padding: min(24px, 5vh) 16px; display: flex; justify-content: center; align-items: flex-start; }   /* v2.29: margen seguro alrededor de las fichas del Triple */
.tt-board-inner { position: relative; margin: 0 auto; flex: none; }
.tt-tile {
  position: absolute;
  border-radius: 6px; background: #f6efe1;
  border: 1px solid rgba(40,25,12,0.45); /* v2.59 — mismo trazo liviano del clásico */
  display: grid; place-items: center;
  /* v2.47 — PARIDAD con la ficha del clásico: canto 3D de MARFIL (tonos cálidos
     escalonados que imitan el gradiente bone-side del SVG + línea oscura de
     cierre). v2.59 — aligerado igual que el clásico v2.58.5 (queja "pesadas"). */
  box-shadow:
    1px 1px 0 #e9d8ab,
    2px 2px 0 #d2ba85,
    3px 3px 0 #a78c5c,
    3.6px 3.6px 0 rgba(40,25,12,0.5),
    2px 6px 11px rgba(0,0,0,0.42);   /* v3.8 — ambiente más profundo: separa la pila con nitidez */
}
/* Banda de familia arriba — la misma de la cara del clásico. v3.8 — más sutil (.14): cara marfil limpia. */
.tt-tile::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 6px;
  background: rgba(244,180,48,0.14); border-radius: 6px 6px 0 0; pointer-events: none;
  z-index: -1; /* v4.1.1 — bajo emoji/label; el highlight (::after) pinta encima de la banda, como el clásico */
}
/* v4.1.1 — TALLADO v3.8 portado al Triple: top-highlight especular (46% superior,
   mismos stops que url(#top-highlight) del clásico) + rim light izquierdo. Vive en
   ::after con z:-1 (bajo emoji/label, sobre la cara) porque el render puede setear
   background INLINE (t.bg) en la ficha y pisaría un gradiente puesto ahí. sp-piedra
   queda afuera: su ::after es el 🪨 (y su look agrisado es distinto a propósito). */
.tt-tile:not(.sp-piedra):not(.sp-golden)::after {
  content: ''; position: absolute; inset: 0; z-index: -1;
  border-radius: 6px; pointer-events: none;
  background:
    linear-gradient(90deg, rgba(255,255,255,0.28), rgba(255,255,255,0) 6%) no-repeat,
    linear-gradient(180deg, rgba(255,255,255,0.40) 0%, rgba(255,255,255,0.12) 22%, rgba(255,255,255,0) 46%) no-repeat;
}
/* v2.59 — BANDA POR FAMILIA (paleta CUD) — un solo lenguaje de color para el
   clásico (SVG rect.band) y el Triple (::before). El color agrupa la familia;
   el emoji + nombre identifican la ficha (redundancia triple, WCAG 1.4.1). */
.board-svg .tile.fam-paisajes .band { fill: var(--fam-paisajes); }
.board-svg .tile.fam-carnaval .band { fill: var(--fam-carnaval); }
.board-svg .tile.fam-musica   .band { fill: var(--fam-musica); }
.board-svg .tile.fam-fauna    .band { fill: var(--fam-fauna); }
.board-svg .tile.fam-cultivos .band { fill: var(--fam-cultivos); }
.board-svg .tile.fam-historia .band { fill: var(--fam-historia); }
.tt-tile.fam-paisajes::before { background: var(--fam-paisajes); }
.tt-tile.fam-carnaval::before { background: var(--fam-carnaval); }
.tt-tile.fam-musica::before   { background: var(--fam-musica); }
.tt-tile.fam-fauna::before    { background: var(--fam-fauna); }
.tt-tile.fam-cultivos::before { background: var(--fam-cultivos); }
.tt-tile.fam-historia::before { background: var(--fam-historia); }
/* v2.48 — PARIDAD con el clásico: TODAS las fichas se ven (casi) iguales — la
   regla de oro del board clásico. El oscurecido fuerte de las tapadas las hacía
   ver "sucias/viejas". Queda un susurro de diferencia + el deny-shake al tocar. */
.tt-tile.covered { filter: brightness(0.72) saturate(0.78); }  /* v2.55 — claramente más opaca que las libres: se ve cuál es tocable */
.tt-tile.free { cursor: pointer; box-shadow:
    1px 1px 0 #e9d8ab,
    2px 2px 0 #d2ba85,
    3px 3px 0 #a78c5c,
    3.6px 3.6px 0 rgba(40,25,12,0.5),
    2px 9px 16px rgba(0,0,0,0.48);   /* v3.8 — libre "flota" más sobre el resto */
  transition: box-shadow .12s, filter .12s, transform .08s; }
.tt-tile.free:hover { box-shadow: 0 0 0 2px var(--gold),
    1px 1px 0 #e9d8ab,
    2px 2px 0 #d2ba85,
    3px 3px 0 #a78c5c,
    3.6px 3.6px 0 rgba(40,25,12,0.5),
    2px 10px 18px rgba(0,0,0,0.48);
  filter: brightness(1.07); }
.tt-tile.free:active { transform: scale(0.93); }
/* v2.17 animaciones gloriosas */
.tt-tile.tt-deny { animation: ttDeny 0.32s ease; }
@keyframes ttDeny {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-4px) rotate(-2deg); }
  60% { transform: translateX(4px) rotate(2deg); }
}
.tt-fly { pointer-events: none; border-radius: 6px; background: #f6efe1;
  border: 1px solid rgba(40,25,12,0.45); display: grid; place-items: center;
  box-shadow: 0 0 0 2px var(--gold),
    1px 1px 0 #e9d8ab, 2px 2px 0 #d2ba85, 3px 3px 0 #a78c5c,
    0 8px 20px rgba(0,0,0,0.6); }
.tt-tray.tt-collapse-flash { animation: ttTrayFlash 0.42s ease; }
@keyframes ttTrayFlash {
  0%, 100% { transform: scale(1); }
  35%      { transform: scale(1.11) rotate(-0.6deg); }
  70%      { transform: scale(1.05) rotate(0.4deg); }
}
body.reduce-motion .tt-tile.tt-deny,
body.reduce-motion .tt-tray.tt-collapse-flash { animation: none; }

/* Polvo de estrellas (v2.18) — compartido por el clásico y el Triple */
.star-dust {
  position: fixed; z-index: 96; pointer-events: none;
  color: #ffe79a; text-shadow: 0 0 6px #ffd76a, 0 0 13px #fff3c4;
  transform: translate(-50%, -50%); will-change: transform, opacity;
  animation: starDustFly 0.6s cubic-bezier(.2,.7,.3,1) forwards;
}
@keyframes starDustFly {
  0%   { transform: translate(-50%,-50%) translate(0,0) scale(.2) rotate(0); opacity: 0; }
  22%  { opacity: 1; transform: translate(-50%,-50%) translate(calc(var(--dx)*.3), calc(var(--dy)*.3)) scale(1.05) rotate(calc(var(--rot)*.3)); }
  100% { transform: translate(-50%,-50%) translate(var(--dx), var(--dy)) scale(.3) rotate(var(--rot)); opacity: 0; }
}
body.reduce-motion .star-dust { display: none; }
/* Triple pieces: large glyph, no painted words. */
.tt-tile-emoji { font-size: 38px; line-height: 1; pointer-events: none; margin-top: -8px; }  /* v4.2.5 — 34→38: ícono más grande, parejo con el clásico (misma cara entre modos) */

/* v3.2 F2 — especiales Triple */
.tt-tile.sp-golden { box-shadow: 0 0 0 2px #ffd76a, 0 0 14px 4px rgba(242,184,75,.65), 2px 2px 0 #d2ba85, 3px 3px 0 #a78c5c, 2px 8px 14px rgba(0,0,0,.4); }
/* v4.1.3 — daltonismo: badge ⭐ (glifo no-color) para la dorada; paridad con las otras
   especiales. ::after propio (golden queda fuera del highlight genérico); no toca el DOM. */
.tt-tile.sp-golden::after {
  content: '⭐'; position: absolute; top: 0; right: 2px; z-index: 1;
  font-size: 11px; line-height: 1; pointer-events: none;
  text-shadow: 0 1px 2px rgba(0,0,0,0.55);
}
/* v3.2.1 — piedra CONTUNDENTE: cara agrisada + 🪨 centrado grande (la esquina
   inferior-derecha la tapaba la ficha vecina del stack). Filtros ESTÁTICOS (no
   keyframes) → gate perf ok. Al rajarse recupera color y la piedra se desarma. */
.tt-tile.sp-piedra:not(.cracked) { filter: grayscale(.8) brightness(.92); }
.tt-tile.sp-piedra::after { content: '🪨'; position: absolute; inset: 0; display: grid; place-items: center; font-size: 22px; opacity: .85; pointer-events: none; text-shadow: 0 1px 3px rgba(0,0,0,.5); }
.tt-tile.sp-piedra.cracked::after { opacity: .25; transform: rotate(24deg) scale(.8); }
/* v3.2.1 — candado TRABADO se lee como "no disponible": oscurecido + badge legible. */
.tt-tile.sp-candado.locked { filter: brightness(.68) saturate(.55); }
.tt-lock-n { position: absolute; top: 1px; right: 1px; font-size: 12px; font-weight: 800; color: #ffd76a; background: rgba(20,10,0,.78); border-radius: 6px; padding: 0 4px; line-height: 1.4; pointer-events: none; }
.tt-tile.sp-mascara.sp-flip { animation: ttFlip .36s ease; }
@keyframes ttFlip { 0% { transform: rotateY(90deg); opacity: .2; } 100% { transform: rotateY(0deg); opacity: 1; } }
body.reduce-motion .tt-tile.sp-mascara.sp-flip { animation: none; }
/* v2.55.12 — barra inferior con texto + botón de PISTA (flex). */
.tt-hint { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: 12px; color: var(--ink-dim); padding: 8px calc(8px + var(--safe-bottom)); }
.tt-hint-txt { flex: 1; text-align: left; }
.tt-hint-btn {
  flex: 0 0 auto; font-size: 12px; font-weight: 700; color: #2a1606;
  background: linear-gradient(180deg, #ffd76a, #f2b84b); border: none;
  border-radius: 10px; padding: 7px 12px; cursor: pointer;
  box-shadow: 0 3px 0 #b9842c, 0 2px 6px rgba(0,0,0,0.3); transition: transform 0.08s ease;
}
.tt-hint-btn:active { transform: translateY(2px); box-shadow: 0 1px 0 #b9842c, 0 1px 3px rgba(0,0,0,0.3); }
.tt-hint-btn small { font-weight: 600; opacity: 0.85; }
/* Ficha resaltada por la pista: halo dorado pulsante (no usa filtros SVG). */
.tt-tile.hinted {
  outline: 3px solid #ffd76a; outline-offset: -1px;
  box-shadow: 0 0 0 3px rgba(255,215,106,0.55), 0 0 22px 6px rgba(242,184,75,0.8);
  z-index: 80 !important; animation: tt-hint-pulse 0.7s ease-in-out 4;
}
@keyframes tt-hint-pulse {
  0%, 100% { box-shadow: 0 0 0 3px rgba(255,215,106,0.5), 0 0 16px 4px rgba(242,184,75,0.65); }
  50% { box-shadow: 0 0 0 4px rgba(255,215,106,0.85), 0 0 28px 9px rgba(242,184,75,0.95); }
}
/* El TABLERO del Triple late en cada colapso (reusa el keyframe del clásico). */
.tt-board.match-pulse { animation: match-pulse-kf 0.28s cubic-bezier(0.34, 1.56, 0.64, 1); }
/* Escalada de combo: el puntaje del HUD del Triple brilla con la racha. */
body.combo-3 .tt-wrap .tt-hud-score { text-shadow: 0 0 10px rgba(242,184,75,0.7); }
body.combo-5 .tt-wrap .tt-hud-score { text-shadow: 0 0 16px rgba(242,184,75,0.9); animation: comboHudPulse 0.4s ease-out; }
body.combo-7 .tt-wrap .tt-hud-score { text-shadow: 0 0 22px rgba(255,180,48,1), 0 0 6px #fff; color: #ffd76a; animation: comboHudPulse 0.4s ease-out; }
.reduce-motion .tt-tile.hinted, .reduce-motion .tt-board.match-pulse { animation: none !important; }
@media (prefers-reduced-motion: reduce) {
  .tt-tile.hinted, .tt-board.match-pulse { animation: none !important; }
}

/* End overlay */
.tt-end-overlay {
  position: fixed; inset: 0; z-index: 80;
  background: rgba(0,0,0,0.72); backdrop-filter: blur(6px);
  display: grid; place-items: center;
  animation: fadein .2s ease-out;
}
.tt-end-dialog {
  background: linear-gradient(180deg, #3a2354, #2a1538);
  border: 1px solid rgba(242,184,75,0.3); border-radius: 20px;
  padding: 24px 22px; text-align: center; max-width: 320px;
  animation: dialogin .25s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.tt-end-dialog h2 { margin: 0 0 10px; font-family: var(--font-display); }
.tt-end-stars { font-size: 32px; color: var(--gold); margin: 8px 0; }
.tt-end-reward { font-size: 18px; font-weight: 800; color: var(--gold); }
.tt-end-sub { font-size: 13px; color: var(--ink-dim); }
.tt-end-dialog .row { margin-top: 16px; display: flex; gap: 10px; justify-content: center; }
/* v3.9 — MEGA WIN (Tarea 1): variante más grande del fin de stage (Triple). */
.tt-end-dialog.tt-end-mega { border-color: rgba(255,227,154,0.75); box-shadow: 0 0 60px rgba(255,227,154,0.5), 0 12px 40px rgba(0,0,0,0.5); }

/* v2.23 — overlay de RESCATE (bandeja llena): translúcido + diálogo abajo, para
   que el jugador VEA la bandeja y el tablero mientras decide. Nunca pierde acá. */
.tt-rescue-overlay {
  background: rgba(10,4,20,0.32); backdrop-filter: blur(2px);
  place-items: end center; padding-bottom: calc(18px + var(--safe-bottom));
}
.tt-rescue-overlay .tt-end-dialog {
  background: linear-gradient(180deg, rgba(58,35,84,0.97), rgba(42,21,56,0.99));
  box-shadow: 0 -8px 30px rgba(0,0,0,0.5); max-width: 360px; width: calc(100% - 28px);
}
.tt-rescue-overlay .btn[disabled] { opacity: 0.4; pointer-events: none; }
body.reduce-motion .tt-rescue-overlay, body.reduce-motion .tt-rescue-overlay .tt-end-dialog { animation: none; }

/* ───── Ligas / ranking (v2.19) ───── */
.league-loading { text-align: center; color: var(--ink-dim); padding: 30px 0; }
.league-banner {
  display: flex; justify-content: space-between; align-items: center;
  background: linear-gradient(135deg, #2d1840, #3a1f5a);
  border: 1px solid rgba(242,184,75,0.3); border-radius: var(--r);
  padding: 12px 16px; margin-bottom: 12px;
}
.league-banner .lg-mine { font-size: 14px; }
.league-banner .lg-mine strong { color: var(--gold); }
.league-banner .lg-mode { font-size: 12px; color: var(--ink-dim); }
.league-list { display: flex; flex-direction: column; gap: 5px; }
.league-row {
  display: grid; grid-template-columns: 46px 1fr auto; align-items: center; gap: 10px;
  background: var(--bg-elev); border: 1px solid rgba(255,255,255,0.06);
  border-radius: 12px; padding: 10px 14px;
}
.league-row.me { border-color: var(--gold); box-shadow: 0 0 0 1px var(--gold), 0 0 14px rgba(242,184,75,0.25); }
.league-row .lg-rank { font-weight: 800; font-size: 16px; text-align: center; }
.league-row .lg-name { font-size: 14px; font-weight: 600; }
.league-row .lg-score { font-size: 13px; color: var(--gold); font-weight: 700; }

/* ════ v2.46 — escena del mundo DE FONDO del tablero (doc 09 §8c) ════
   La misma escena del mapa, con velo oscuro, detrás de las fichas: el nivel
   se siente EN el mundo (Hornocal, carnaval, salar…). Un solo paint inicial,
   cero costo por frame (sin filtros, sin animación). Las fichas mandan. */
.board > .board-backdrop {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  border-radius: inherit; overflow: hidden; opacity: 0.55;
}
.board > .board-backdrop svg { width: 100%; height: 100%; display: block; }
.board > .board-svg { position: relative; z-index: 1; }
.board > .board-sheen { z-index: 2; }

/* v2.46 — Triple: la MISMA escena de mundo de fondo que el clásico (cohesión
   visual entre los dos modos). Absolute → no participa del grid del tt-wrap. */
.tt-wrap > .tt-backdrop {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  opacity: 0.42; overflow: hidden;
}
.tt-wrap > .tt-backdrop svg { width: 100%; height: 100%; display: block; }
.tt-wrap > .tt-hud, .tt-wrap > .tt-tray, .tt-wrap > .tt-board, .tt-wrap > .tt-hint {
  position: relative; z-index: 1;
}

/* v2.46 — anti "salto de pantalla" (desktop): la barra de scroll aparecía y
   desaparecía con overlays/banners y TODO el layout se corría unos px al
   medio de la partida. Reservar el gutter elimina ese brinco; en móvil no
   cambia nada (no hay scrollbar clásica). */
html { scrollbar-gutter: stable; }

/* ============================================================
   v3.0 — TENSIÓN REAL DEL TRIPLE: el peligro se ve venir.
   Bandeja en 5/7 = alerta ámbar; 6/7 = pulso rojo (reduce-motion lo apaga).
   Derrota: diálogo .lost con borde rojo (antes no existía perder). */
.tt-tray.tt-warn {
  box-shadow: 0 -4px 12px rgba(0,0,0,0.3), inset 0 0 0 2px rgba(242,184,75,0.5), 0 0 18px rgba(242,184,75,0.25);
}
.tt-tray.tt-danger {
  position: relative;
  box-shadow: 0 -4px 12px rgba(0,0,0,0.3), inset 0 0 0 2px rgba(226,74,74,0.75), 0 0 24px rgba(226,74,74,0.45);
}
/* pulso SOLO con opacity (GPU): la capa ::after trae el glow fuerte pre-pintado
   y respira encima del glow estático — cero re-paint por frame (perf budget §11). */
.tt-tray.tt-danger::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  box-shadow: inset 0 0 0 3px rgba(226,74,74,0.95), 0 0 34px rgba(226,74,74,0.65);
  opacity: 0;
  animation: ttDangerPulse 0.9s ease-in-out infinite;
  will-change: opacity;
}
@keyframes ttDangerPulse {
  0%, 100% { opacity: 0; }
  50%      { opacity: 1; }
}
.tt-hint-txt.danger { color: #ff7b6e; font-weight: 700; }
.tt-end-dialog.lost {
  border: 1px solid rgba(226,74,74,0.65);
  box-shadow: 0 0 30px rgba(226,74,74,0.35), 0 12px 40px rgba(0,0,0,0.5);
}
.tt-end-dialog.tt-danger-dialog { border: 1px solid rgba(242,184,75,0.5); }
@media (prefers-reduced-motion: reduce), (update: slow) {
  .tt-tray.tt-danger::after { animation: none; opacity: 0.6; }
}
body.reduce-motion .tt-tray.tt-danger::after { animation: none; opacity: 0.6; }

/* v3.1 — F1d récord de puntos (win overlay clásico + fin del Triple) y
   F1b derrota real del clásico (reusa la estética del diálogo de victoria). */
.new-record {
  margin: 6px auto 0; padding: 6px 12px; border-radius: 10px; width: fit-content;
  background: rgba(242, 184, 75, 0.14);
  border: 1px solid rgba(242, 184, 75, 0.55);
  color: #f2b84b; font-weight: 800; letter-spacing: 0.3px;
}
.tt-end-sub.new-record { display: block; }
.lose-dialog {
  border: 1px solid rgba(226, 74, 74, 0.65) !important;
  box-shadow: 0 0 30px rgba(226, 74, 74, 0.35), 0 12px 40px rgba(0, 0, 0, 0.5) !important;
}
.lose-dialog .win-title { color: #ff7b6e; }
