/* =========================================================
   2048 — estilos · TEMA PIXEL
   Estética retro: tipografía Press Start 2P, esquinas
   cuadradas, colores planos (sin degradados ni glows).
   Color de las fichas = rampa plana por valor, idéntica en
   ambos temas. El "chrome" (fondo, tablero, texto) cambia
   según el tema (sistema o elección del usuario).
   ========================================================= */

:root {
  /* Chrome — TEMA OSCURO (por defecto) */
  --bg:        #131722;
  --bg-2:      #171b29;
  --board:     #1b2130;
  --cell:      #252c3e;
  --ink:       #f2f5fb;
  --ink-dim:   #8a93a8;
  --line:      #2a3145;
  --overlay-bg: rgba(19, 23, 34, 0.86);

  --accent:      #f2b03c;   /* dorado: marca 2048 y botón primario */
  --accent-ink:  #1a1c2a;   /* tinta sobre dorado (siempre oscura) */
  --marca-sombra: #55310b;  /* sombra dura del logo "2048" */
  --sombra-dura: rgba(0, 0, 0, 0.4);

  --radius:    0px;
  /* Doble tipografía pixel: Press Start 2P SOLO como display (logo y
     números de ficha, no tiene minúsculas); Silkscreen para todo el
     texto de la interfaz, mucho más legible en cuerpo y tamaño pequeño. */
  --fuente: "Press Start 2P", system-ui, sans-serif;
  --fuente-texto: "Silkscreen", system-ui, sans-serif;
}

/* Tema claro si lo pide el SISTEMA y el usuario no ha forzado nada */
@media (prefers-color-scheme: light) {
  :root:not([data-theme]) {
    --bg:        #f1f2f6;
    --bg-2:      #eaecf2;
    --board:     #dde1ea;
    --cell:      #cbd1de;
    --ink:       #1f2740;
    --ink-dim:   #6a7387;
    --line:      #c6ccda;
    --overlay-bg: rgba(241, 242, 246, 0.88);
    --marca-sombra: #b98a22;
    --sombra-dura: rgba(31, 39, 64, 0.25);
  }
}

/* Tema claro FORZADO por el usuario */
:root[data-theme="light"] {
  --bg:        #f1f2f6;
  --bg-2:      #eaecf2;
  --board:     #dde1ea;
  --cell:      #cbd1de;
  --ink:       #1f2740;
  --ink-dim:   #6a7387;
  --line:      #c6ccda;
  --overlay-bg: rgba(241, 242, 246, 0.88);
  --marca-sombra: #b98a22;
  --sombra-dura: rgba(31, 39, 64, 0.25);
}

/* Tema oscuro forzado: no hace falta bloque explícito. `:root` YA es el tema
   oscuro por defecto, y las ramas de arriba solo aplican sin data-theme o con
   data-theme="light". Los valores serían idénticos: se eliminó la duplicación. */

* { box-sizing: border-box; margin: 0; padding: 0; }

/* Altura REAL visible (dvh), no la falsa 100vh. Sin scroll ni rebote. */
html, body {
  height: 100dvh;
  overflow: hidden;
  overscroll-behavior: none;
}

body {
  display: grid;
  place-items: center;                 /* centra el juego en la pantalla */
  padding: 12px;
  font-family: var(--fuente-texto);
  color: var(--ink);
  background: var(--bg);               /* plano: sin glow, este es un juego pixel */
  font-variant-numeric: tabular-nums;
}

/* El ancho del juego se limita por: ancho de pantalla, un máximo fijo, y la
   ALTURA disponible. El tercer límite (62dvh) hace que en pantallas bajas el
   tablero encoja y todo siga cabiendo sin scroll. */
.app { width: min(94vw, 460px, 62dvh); }

/* ---- Cabecera ---- */
/* El logo ocupa la altura de la fila de marcadores: centrado vertical
   y a tamaño display (cap 2.9rem = 4 dígitos de ~46px caben junto al
   panel en 460px; 8.5vw lo escala en pantallas estrechas). */
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 16px;
}

/* Logo "2048": color plano + sombra dura desplazada (estilo pixel).
   Display: Press Start 2P. */
h1 {
  font-family: var(--fuente);
  font-size: clamp(2rem, 8.5vw, 2.9rem);
  font-weight: 400;
  line-height: 1.22;
  white-space: nowrap;
  color: var(--accent);
  text-shadow: 3px 3px 0 var(--marca-sombra);
}

.panel { display: flex; gap: 8px; align-items: center; }

.score-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 88px;
  padding: 9px 10px;
  background: var(--board);
  border: 2px solid var(--line);
  border-radius: var(--radius);
}

.score-label {
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--ink-dim);
}

.score-value {
  font-size: 1.1rem;
  font-weight: 400;
  margin-top: 6px;
}

/* Con logo a tamaño display, en pantallas estrechas el panel se compacta
   para que siga cabiendo al lado. */
@media (max-width: 360px) {
  .score-box { min-width: 70px; padding: 7px 8px; }
  .score-value { font-size: 0.9rem; }
  .panel { gap: 6px; }
}

/* ---- Acciones ---- */
.actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

/* Botón pixel: color plano + sombra dura que "se hunde" al pulsar.
   Fuente: Silkscreen (la de texto); Press Start 2P queda reservado para
   logo y fichas. */
.btn {
  font-family: inherit;
  font-size: 0.8rem;
  font-weight: 400;
  color: var(--accent-ink);
  background: var(--accent);
  border: none;
  border-radius: var(--radius);
  padding: 11px 16px;
  cursor: pointer;
  box-shadow: 3px 3px 0 var(--sombra-dura);
  transition: transform 0.12s ease, filter 0.12s ease, background 0.15s ease, color 0.15s ease, box-shadow 0.12s ease;
}
.btn:hover { filter: brightness(1.08); }
.btn:active {
  transform: translate(2px, 2px);
  box-shadow: 1px 1px 0 var(--sombra-dura);
}
.btn.ghost {
  background: transparent;
  color: var(--ink);
  border: 2px solid var(--line);
}
.btn:disabled { opacity: 0.4; cursor: not-allowed; filter: none; box-shadow: 3px 3px 0 var(--sombra-dura); }

/* Barra inferior (instalar, reto diario, ver jugada, compartir): debajo del
   tablero, con icono + texto. Cuadrícula: los botones visibles se reparten una
   fila (Instalar solo aparece en navegadores instalables y Ver jugada está
   oculto de momento); con los 4 visibles pasa a 2x2 en móvil. */
.actions-bottom {
  display: grid;
  grid-auto-flow: column;      /* los botones visibles se reparten UNA fila */
  grid-auto-columns: 1fr;
  gap: 6px;
  margin-top: 14px;
  margin-bottom: 0;
}
/* Con los 4 visibles no caben en una fila en móvil: 2x2. */
.actions-bottom:has(#install:not([hidden])):has(#replay:not([hidden])) {
  grid-auto-flow: row;
  grid-template-columns: repeat(2, 1fr);
}
@media (min-width: 520px) {
  .actions-bottom:has(#install:not([hidden])):has(#replay:not([hidden])) {
    grid-template-columns: repeat(4, 1fr);
  }
}
.actions-bottom .icon-btn {
  justify-content: center;
  padding: 10px 8px;
  gap: 7px;
  font-size: 0.7rem;
  white-space: nowrap;
}
.actions-bottom .icon-btn svg { flex: none; }
.actions-bottom .icon-btn svg,
.icon-btn svg { transform: scale(0.85); } /* iconos de 18px caben junto a letra pixel ancha */

/* Botones con icono SVG + contador */
.icon-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 10px 13px;
}
.icon-btn svg { display: block; }
.icon-btn .count { font-size: 0.8rem; font-weight: 400; min-width: 1ch; text-align: center; }
.icon-btn.armed { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.icon-btn.theme-toggle { padding: 10px 11px; }

/* [hidden] debe GANAR a display:inline-flex de .icon-btn (el [hidden] de la
   UA pierde por especificidad): si no, #install se vería siempre.
   Mismo patrón que .overlay[hidden] y .aviso-file[hidden]. */
.icon-btn[hidden] { display: none; }

/* Objetivo táctil >= 44 px (WCAG 2.5.5) para los botones NUEVOS
   (#install y #share): solo ellos, sin agravar la altura de #undo/#bomb. */
.tap-44 { min-height: 44px; min-width: 44px; }

/* Panel "Ver jugada" (sub-bloque 2d): NO modal, vive entre el tablero y la
   barra inferior y se abre con #replay (aria-controls). [hidden] gana a display. */
#replay-panel {
  display: grid;
  gap: 8px;
  margin-top: 14px;
  padding: 12px;
  background: var(--board);
  border: 2px solid var(--line);
  border-radius: var(--radius);
}
#replay-panel[hidden] { display: none; }
#replay-panel label {
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--ink-dim);
  line-height: 1.8;
}
#replay-input {
  width: 100%;
  resize: vertical;
  font-family: var(--fuente-texto);
  font-size: 0.75rem;
  line-height: 1.8;
  color: var(--ink);
  background: var(--cell);
  border: 2px solid var(--line);
  border-radius: var(--radius);
  padding: 9px 10px;
}
.replay-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* Reto diario activo (D5c): aria-pressed lo escribe game.js al arrancar un
   reto. Mismo tratamiento visual que .icon-btn.armed. Los colores salen de
   las variables del tema (--accent / --accent-ink), así que UNA regla sirve
   para el tema claro y el oscuro (R8) sin duplicar bloques. */
#daily[aria-pressed="true"] {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: var(--accent);
}

/* Interruptor de feedback (sonido + háptica): objetivo táctil >= 44 px
   (WCAG 2.5.5) y estado visible del switch, que role="switch" no pinta
   por sí solo. aria-checked lo gestiona game.js. */
.fx-toggle {
  min-height: 44px;
  min-width: 44px;
  display: inline-flex;
  align-items: center;
  gap: 7px;
}
.fx-toggle[aria-checked="false"] { opacity: 0.6; }

/* ---- Tablero ---- */
.board-wrap { position: relative; }

.board {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-template-rows: repeat(4, minmax(0, 1fr));
  gap: 10px;
  padding: 10px;
  background: var(--board);
  border: 2px solid var(--line);
  border-radius: var(--radius);
  aspect-ratio: 1;
}

/* Celda pixel: cuadrada, sin radios. Los números van en Press Start 2P
   (ocupa ~1em por dígito: los tamaños escalan con la longitud mediante
   las classes len3/len4). */
.cell {
  display: grid;
  place-items: center;
  border-radius: var(--radius);
  background: var(--cell);
  font-family: var(--fuente);
  font-weight: 400;
  font-size: clamp(1rem, 4.6vw, 1.55rem);
  color: var(--ink);
  user-select: none;
}
.cell.len3 { font-size: clamp(0.7rem, 3.2vw, 1.1rem); }
.cell.len4 { font-size: clamp(0.52rem, 2.6vw, 0.85rem); }

/* Ficha persistente dentro de cada .cell (identidad de nodos). Hereda el
   aspecto de su slot: la rampa data-value sigue EN .cell, así que cero
   selectores migrados y el número se pinta sobre el mismo color. */
.tile {
  background: inherit;
  color: inherit;
  border-radius: inherit;
}

/* ---- Rampa plana por valor (igual en ambos temas) ----
   Colores planos saturados, estilo de la referencia pixel: fríos y
   oscuros en los bajos (texto claro), brillantes en los medios (texto
   oscuro) y oscuros de nuevo en los extremos (+4096). SIN degradados.
   RAMPA de js/game-share.js replica ESTAS REGLAS literalmente
   (test anti-deriva de share.test.js). */
.cell[data-value="2"]    { background: #3d4b6e; color: #eaf0f9; }
.cell[data-value="4"]    { background: #2c6ca8; color: #eaf0f9; }
.cell[data-value="8"]    { background: #1e9e63; color: #103324; }
.cell[data-value="16"]   { background: #3bb44a; color: #0f2e17; }
.cell[data-value="32"]   { background: #8fbe2e; color: #18260a; }
.cell[data-value="64"]   { background: #c2c22e; color: #252503; }
.cell[data-value="128"]  { background: #e9b92e; color: #251a03; }
.cell[data-value="256"]  { background: #ee8a31; color: #261102; }
.cell[data-value="512"]  { background: #e85d3a; color: #2a0f05; }
.cell[data-value="1024"] { background: #e9538b; color: #2a0a16; }
.cell[data-value="2048"] { background: #f0b429; color: #241a02; }
.cell[data-value="4096"],
.cell[data-value="8192"] { background: #7a3e8f; color: #f2f5fb; }

/* ---- Animación: ficha recién aparecida ---- */
@keyframes aparece {
  from { transform: scale(0.4); opacity: 0; }
  to   { transform: scale(1);   opacity: 1; }
}
.cell.nueva { animation: aparece 0.16s ease-out; }

/* ---- Capa de efectos visuales (slide, fantasmas, flotantes) ----
   Fuera de #board y ANTES que #overlay en el DOM: los overlays siguen
   pintando encima por orden de capa. Sin z-index (decisión del plan) y sin
   eventos: #board.children sigue siendo exactamente 16 .cell. */
#fx-layer {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  border-radius: var(--radius);
}

/* Fantasma de fusión: una .cell clonada, ya posicionada con su rect por JS
   (left/top/width/height inline). No es interactiva.
   position:absolute es OBLIGATORIO: sin él left/top inline no hacen nada y
   los fantasmas se apilarían en la esquina de #fx-layer. #fx-layer es
   position:absolute (ver arriba), así que ÉL es el containing block de esos
   left/top, exactamente lo que resta game-fx.js (rect − rectCapa). */
.cell.fx-fantasma {
  position: absolute;
  pointer-events: none;
}

/* ---- Pop de fusión: la celda destino late DESPUÉS del slide ----
   El animation-delay cae con DURACION_SLIDE_MS (120 ms) de game-fx.js. */
@keyframes fusiona {
  0%   { transform: scale(1); }
  50%  { transform: scale(1.16); }
  100% { transform: scale(1); }
}
.cell.fusionando {
  animation: fusiona 0.18s ease-out 0.12s;
}

/* ---- Puntos flotantes +N (sobre la celda fusionada) ----
   Centrados con translate(-50%,-50%) sobre el left/top que calcula JS;
   suben y se desvanecen en 0.7 s (game-fx.js los retira con setTimeout).
   El overflow:hidden de #fx-layer los mantiene dentro del tablero. */
@keyframes flotante-sube {
  from { transform: translate(-50%, -50%); opacity: 1; }
  to   { transform: translate(-50%, calc(-50% - 1.6em)); opacity: 0; }
}
@keyframes flotante-desvanece {
  from { opacity: 1; }
  to   { opacity: 0; }
}
.fx-flotante {
  position: absolute;
  transform: translate(-50%, -50%);
  font-family: var(--fuente);          /* display: +N en pixel coqueto */
  font-weight: 400;
  font-size: clamp(0.9rem, 5vw, 1.4rem);
  color: var(--accent);
  text-shadow: 2px 2px 0 var(--sombra-dura);
  pointer-events: none;
  animation: flotante-sube 0.7s ease-out forwards;
}
/* prefers-reduced-motion: solo desvanece (la clase la pone el JS y la rama
   de style.css de abajo lo refuerza). */
.fx-flotante.fx-reducido { animation-name: flotante-desvanece; }

/* ---- Modo bomba ---- */
.board.modo-bomba { outline: 2px solid var(--accent); outline-offset: 4px; }
.board.modo-bomba .cell { cursor: crosshair; }

/* ---- Overlays fin / victoria ---- */
.overlay {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: var(--overlay-bg);
  backdrop-filter: blur(3px);
  border-radius: var(--radius);
}
.overlay[hidden] { display: none; }

.overlay-card { text-align: center; padding: 24px; }
.overlay-title {
  font-family: var(--fuente);
  font-size: 1.25rem;
  font-weight: 400;
  margin-bottom: 14px;
  line-height: 1.6;
}
.overlay-text { color: var(--ink); font-size: 0.8rem; line-height: 1.7; margin-bottom: 18px; }
.overlay-actions { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }

/* ---- Bienvenida ---- */
.welcome-card {
  background: var(--board);
  border: 2px solid var(--line);
  border-radius: var(--radius);
  max-width: 340px;
  width: 90%;
  padding: 26px 24px;
  text-align: center;
  box-shadow: 8px 8px 0 var(--sombra-dura);
  animation: popIn 0.28s cubic-bezier(0.2, 0.9, 0.3, 1.25);
  /* La lista de novedades creció (Bloque 1): en pantallas bajas la tarjeta
     no puede desbordar el tablero (body tiene overflow:hidden y se recortaría). */
  max-height: 100%;
  overflow-y: auto;
}
.welcome-overlay.cerrando .welcome-card { animation: popOut 0.18s ease-in forwards; }
.welcome-title {
  font-family: var(--fuente);
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.7;
  margin-bottom: 16px;
  color: var(--accent);
  text-shadow: 2px 2px 0 var(--marca-sombra);
}
.welcome-text {
  color: var(--ink);
  font-size: 0.72rem;
  line-height: 1.7;
  margin-bottom: 16px;
}
.welcome-nota { color: var(--ink-dim); font-size: 0.85em; }
.welcome-novedades {
  text-align: left;
  background: var(--cell);
  border: 2px solid var(--line);
  border-radius: var(--radius);
  padding: 12px 14px;
  margin-bottom: 20px;
}
.welcome-novedades-titulo {
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--ink-dim);
  margin-bottom: 10px;
}
.welcome-novedades ul { list-style: none; margin: 0; padding: 0; font-size: 0.68rem; line-height: 1.7; }
.welcome-novedades li { margin-bottom: 8px; }
.welcome-novedades li:last-child { margin-bottom: 0; }
.nov-icono { display: inline-block; width: 1.4em; }

@keyframes popIn {
  from { transform: scale(0.82); opacity: 0; }
  to   { transform: scale(1);    opacity: 1; }
}
@keyframes popOut {
  from { transform: scale(1);    opacity: 1; }
  to   { transform: scale(0.82); opacity: 0; }
}

/* =========================================================
   HORIZONTAL en móviles (pantalla baja):
   los controles pasan a un lado del tablero, no encima, para
   que el tablero cuadrado pueda usar toda la altura disponible.
   ========================================================= */
@media (orientation: landscape) and (max-height: 600px) {
  body { padding: 8px; }

  /* flex-column + wrap: cabecera y botones caen en una columna;
     el tablero (más alto) se pasa solo a la columna de al lado. */
  .app {
    width: auto;
    max-height: 100dvh;
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;
    align-content: center;
    justify-content: center;
    gap: 10px 22px;
  }

  .topbar { margin-bottom: 0; flex-direction: column; gap: 10px; }
  .actions { margin-bottom: 0; }
  .actions-bottom { margin-top: 0; }

  /* El tablero se dimensiona por la ALTURA (para caber a lo alto) sin pasarse
     de ancho (para dejar sitio a los controles al lado). */
  .board { width: min(84dvh, 56vw); }
}

/* ---- Accesibilidad: menos movimiento ---- */
@media (prefers-reduced-motion: reduce) {
  .cell.nueva { animation: none; }
  .cell.fusionando { animation: none; } /* el JS tampoco añade la clase */
  .fx-flotante { animation: flotante-desvanece 0.7s linear forwards; } /* solo desvanece */
  .btn { transition: none; }
  .toast { transition: none; } /* el toast solo usa opacidad, nunca transform */
  .welcome-card,
  .welcome-overlay.cerrando .welcome-card { animation: none; }
}

/* ---- Aviso: abierto como file:// (sin servidor) ---- */
.aviso-file {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  place-items: center;
  padding: 20px;
  background: var(--bg);
}
.aviso-file[hidden] { display: none; }
.aviso-card {
  max-width: 440px;
  text-align: center;
  background: var(--board);
  border: 2px solid var(--line);
  border-radius: var(--radius);
  padding: 26px 24px;
}
.aviso-card h2 {
  font-family: var(--fuente);
  font-size: 0.9rem; line-height: 1.7; margin-bottom: 14px;
}
.aviso-card p { color: var(--ink-dim); font-size: 0.72rem; line-height: 1.7; margin-bottom: 10px; }
.aviso-card code, .aviso-card pre {
  font-family: var(--fuente-texto);
  background: var(--cell);
  border-radius: var(--radius);
  padding: 2px 6px;
}
.aviso-card pre { padding: 10px; margin-bottom: 10px; }
.aviso-alternativa { font-size: 0.65rem; }

/* ---- Toast de feedback (#status · role="status") ----
   Vive como hijo de <main class="app">, FUERA de .board-wrap: no añade
   nodos a #board ni a #fx-layer. Sin foco ni tercer diálogo. Se anima
   SOLO con opacidad (prefers-reduced-motion gobierna transformaciones);
   las variables del tema evitan duplicar la rama clara. */
.toast {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%);   /* centrado fijo: no se anima */
  max-width: min(92vw, 480px);
  padding: 12px 16px;
  background: var(--bg-2);
  color: var(--ink);
  border: 2px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 4px 4px 0 var(--sombra-dura);
  font-size: 0.7rem;
  line-height: 1.7;
  text-align: center;
  opacity: 1;
  transition: opacity 0.18s ease;
  z-index: 60;
}
.toast[hidden] { display: none; }
