/* ─── Capa de efectos ────────────────────────────────────────────────────────
   Todo lo de aquí se anima con transform y opacity. Ni una animación toca
   width, height, top ni left: eso obligaría al navegador a recalcular la
   maquetación en cada frame, que es la forma más rápida de perder los 60 fps
   en un móvil. */

.boards { position: relative; }

/* El canvas va por encima pero no recibe eventos: debajo siguen los botones del
   tablero, con su foco y su teclado intactos. */
.fx-canvas {
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 5;
}

/* ─── Textos de recompensa ─────────────────────────────────────────────────── */
.float {
    position: absolute;
    transform: translate(-50%, -50%);
    pointer-events: none;
    z-index: 6;
    font-weight: 800;
    font-size: clamp(.95rem, 3vw, 1.4rem);
    letter-spacing: .04em;
    text-shadow: 0 2px 8px rgb(0 0 0 / .6);
    white-space: nowrap;
    animation: float-up 1s cubic-bezier(.2, .8, .3, 1) forwards;
}
.float-hit { color: #ffd166; }
.float-sunk { color: #ff6b6b; font-size: clamp(1.2rem, 4vw, 1.9rem); }
.float-miss { color: #9fc4d4; font-size: .95rem; font-weight: 600; }
.float-sonar { color: #4fd6ff; }

@keyframes float-up {
    0%   { opacity: 0; transform: translate(-50%, -50%) scale(.5); }
    18%  { opacity: 1; transform: translate(-50%, -60%) scale(1.15); }
    32%  { transform: translate(-50%, -62%) scale(1); }
    100% { opacity: 0; transform: translate(-50%, -160%) scale(.95); }
}

/* ─── Contador de racha ────────────────────────────────────────────────────── */
.streak {
    position: absolute;
    top: var(--space-3);
    left: 50%;
    transform: translateX(-50%);
    z-index: 6;
    pointer-events: none;
    font-weight: 800;
    font-size: clamp(1rem, 3.4vw, 1.5rem);
    letter-spacing: .06em;
    padding: var(--space-1) var(--space-4);
    border-radius: 999px;
    background: color-mix(in srgb, var(--bg-deep) 82%, transparent);
    border: 2px solid currentColor;
    color: #ffd166;
}
.streak[data-level="3"] { color: #ff9f45; }
.streak[data-level="4"] { color: #ff6b6b; }
.streak[data-level="5"] { color: #ff3ea5; }
.streak.is-bumped { animation: streak-bump .38s cubic-bezier(.2, 1.6, .4, 1); }

@keyframes streak-bump {
    0%   { transform: translateX(-50%) scale(1); }
    45%  { transform: translateX(-50%) scale(1.28) rotate(-2deg); }
    100% { transform: translateX(-50%) scale(1); }
}

/* ─── Carteles ─────────────────────────────────────────────────────────────── */
.banner {
    position: absolute;
    top: 42%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 7;
    pointer-events: none;
    font-weight: 900;
    font-size: clamp(1.3rem, 5vw, 2.4rem);
    letter-spacing: .05em;
    text-align: center;
    text-shadow: 0 4px 18px rgb(0 0 0 / .75);
    animation: banner-in 1.5s cubic-bezier(.2, .9, .3, 1) forwards;
}
.banner-sunk { color: #ff6b6b; }
.banner-sonar { color: #4fd6ff; }
.banner-streak { color: #ffd166; }
.banner-lost { color: #9fc4d4; font-size: clamp(1rem, 3.4vw, 1.5rem); }
.banner-salvo { color: #ff9f45; }
.banner-intel { color: #7cf7c0; }

@keyframes banner-in {
    0%   { opacity: 0; transform: translate(-50%, -50%) scale(.6); }
    14%  { opacity: 1; transform: translate(-50%, -50%) scale(1.12); }
    26%  { transform: translate(-50%, -50%) scale(1); }
    72%  { opacity: 1; }
    100% { opacity: 0; transform: translate(-50%, -68%) scale(.98); }
}

/* ─── Cargas de sonar ──────────────────────────────────────────────────────── */
.sonar-panel {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    background: color-mix(in srgb, var(--accent-2) 12%, transparent);
    border: 1px solid color-mix(in srgb, var(--accent-2) 45%, transparent);
    border-radius: 999px;
    padding: var(--space-2) var(--space-3);
}
.sonar-title { font-size: .7rem; text-transform: uppercase; letter-spacing: .08em; color: var(--text-dim); }
@media (max-width: 40rem) { .sonar-title { display: none; } }
.sonar-charges { display: flex; gap: var(--space-2); }
.sonar-charge {
    width: 1.1rem; height: 1.1rem; border-radius: 50%;
    border: 2px solid var(--accent-2);
    opacity: .3;
}
.sonar-charge[data-full="true"] {
    opacity: 1;
    background: var(--accent-2);
    box-shadow: 0 0 10px color-mix(in srgb, var(--accent-2) 70%, transparent);
    animation: charge-in .4s cubic-bezier(.2, 1.6, .4, 1);
}
@keyframes charge-in { from { transform: scale(.3); } }

[data-action="use-sonar"][data-aiming="true"] { background: var(--accent-2); }
[data-action="use-salvo"][data-aiming="true"] { background: #ff9f45; }

/* ─── Salvas de artillería ─────────────────────────────────────────────────── */
/* Naranja frente al azul del sonar: dos recompensas distintas, dos colores. */
.salvo-panel {
    background: color-mix(in srgb, #ff9f45 12%, transparent);
    border-color: color-mix(in srgb, #ff9f45 45%, transparent);
}
.salvo-charge { border-color: #ff9f45; }
.salvo-charge[data-full="true"] {
    background: #ff9f45;
    box-shadow: 0 0 10px rgb(255 159 69 / .7);
}

/* Vista previa: dónde caería la salva si soltases aquí.
   El :hover va incluido a propósito: sin él la casilla bajo el ratón se queda con su
   resalte de siempre y la línea de tres se ve rota justo por donde apuntas. */
.cell[data-salvo-aim="ok"],
.cell[data-salvo-aim="ok"]:hover {
    box-shadow: inset 0 0 0 2px #ff9f45, 0 0 12px rgb(255 159 69 / .45);
    background: rgb(255 159 69 / .18);
}
.cell[data-salvo-aim="bad"],
.cell[data-salvo-aim="bad"]:hover {
    box-shadow: inset 0 0 0 2px #ff6b6b;
    background: rgb(255 107 107 / .16);
}

/* ─── Racha del bando ──────────────────────────────────────────────────────── */
/* La barra que engancha: se ve subir con cada acierto y hace que el siguiente
   disparo importe más que el anterior. */
.streak-bar {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 8rem;
}
.streak-label { font-size: .68rem; text-transform: uppercase; letter-spacing: .06em; color: var(--text-dim); white-space: nowrap; }
@media (max-width: 40rem) { .streak-label { display: none; } }
.streak-track {
    flex: 1;
    height: .45rem;
    min-width: 4rem;
    border-radius: 999px;
    background: color-mix(in srgb, var(--text-dim) 25%, transparent);
    overflow: hidden;
}
.streak-fill {
    display: block;
    height: 100%;
    width: 0;
    border-radius: inherit;
    background: linear-gradient(90deg, var(--accent-2), #ffd166);
    transition: width .35s cubic-bezier(.2, .9, .3, 1);
}
.streak-bar[data-hot="true"] .streak-fill {
    background: linear-gradient(90deg, #ffd166, #ff6b6b);
    animation: streak-glow .9s ease-in-out infinite alternate;
}
@keyframes streak-glow { to { box-shadow: 0 0 12px rgb(255 159 69 / .9); } }

/* ─── Flotas restantes ─────────────────────────────────────────────────────── */
.fleet-progress {
    display: grid;
    gap: var(--space-1);
    margin-bottom: var(--space-2);
}
.fleet-progress-row { display: flex; align-items: center; gap: var(--space-2); font-size: .72rem; }
.fleet-progress-name { color: var(--text-dim); min-width: 5.5rem; }
.fleet-progress-track {
    flex: 1;
    height: .4rem;
    border-radius: 999px;
    background: color-mix(in srgb, var(--text-dim) 22%, transparent);
    overflow: hidden;
}
.fleet-progress-fill {
    display: block; height: 100%; width: 100%;
    border-radius: inherit;
    transition: width .5s cubic-bezier(.2, .9, .3, 1);
}
.fleet-progress-fill.is-enemy { background: linear-gradient(90deg, #ff6b6b, #ff9f45); }
.fleet-progress-fill.is-own { background: linear-gradient(90deg, var(--accent-2), #7cf7c0); }
.fleet-progress-count { font-variant-numeric: tabular-nums; color: var(--text-dim); min-width: 2.2rem; text-align: right; }
.fleet-progress-track[data-critical="true"] { animation: critical-pulse 1.1s ease-in-out infinite; }
@keyframes critical-pulse { 50% { box-shadow: 0 0 10px rgb(255 107 107 / .8); } }

/* ─── Turno propio ─────────────────────────────────────────────────────────── */
/* El tablero rival late despacio mientras te toca. Nada de parpadeos: un halo que
   respira, que se nota sin robar la atención. */
.boards[data-your-turn="true"] [data-board-panel="enemy"] {
    animation: turn-breathe 2.4s ease-in-out infinite;
    border-radius: var(--radius-2, 10px);
}
@keyframes turn-breathe {
    0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 0%, transparent); }
    50%      { box-shadow: 0 0 22px 2px color-mix(in srgb, var(--accent) 35%, transparent); }
}

/* ─── Casilla recién revelada ──────────────────────────────────────────────── */
/* Un golpe seco de escala. Solo `transform`, que es lo único que no cuesta reflow. */
.cell.is-revealed { animation: cell-pop .32s cubic-bezier(.2, 1.7, .4, 1); z-index: 2; }
@keyframes cell-pop {
    0%   { transform: scale(.55); }
    60%  { transform: scale(1.22); }
    100% { transform: scale(1); }
}

/* ─── Casillas delatadas por un chivatazo ──────────────────────────────────── */
.cell[data-intel="true"] {
    box-shadow: inset 0 0 0 2px #7cf7c0;
    background: rgb(124 247 192 / .14);
}

/* ─── Daño recibido ────────────────────────────────────────────────────────── */
/* Un destello rojo en los bordes cuando el golpe cae en TU tablero. Sin mover nada
   de sitio: solo un pseudoelemento encima, que no provoca reflow. */
.boards { position: relative; }
.boards[data-damage="true"]::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 6;
    border-radius: var(--radius-lg, 12px);
    box-shadow: inset 0 0 60px rgb(255 60 60 / .55);
    animation: damage-flash .42s ease-out forwards;
}
@keyframes damage-flash { from { opacity: 1; } to { opacity: 0; } }

/* ─── Placas de logro ──────────────────────────────────────────────────────── */
/* Entran por la izquierda y se van solas. Van arriba y a un lado para no tapar el
   cartel grande del centro: se pueden ver los dos a la vez. */
.achievement-stack {
    position: absolute;
    top: var(--space-3);
    left: var(--space-3);
    z-index: 8;
    display: grid;
    gap: var(--space-2);
    justify-items: start;
    pointer-events: none;
}
.achievement {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    max-width: 18rem;
    padding: var(--space-2) var(--space-3);
    border-radius: 999px;
    pointer-events: none;
    background: color-mix(in srgb, var(--bg-elev, #0b1b24) 88%, transparent);
    border: 1px solid color-mix(in srgb, #ffd166 55%, transparent);
    box-shadow: 0 8px 26px rgb(0 0 0 / .45);
    animation: achievement-in 2.6s cubic-bezier(.2, .9, .3, 1) forwards;
}
.achievement-icon { color: #ffd166; font-size: 1.1rem; }
.achievement-text { display: grid; line-height: 1.15; }
.achievement-text strong { font-size: .82rem; letter-spacing: .03em; }
.achievement-text small { font-size: .68rem; color: var(--text-dim); }

@keyframes achievement-in {
    0%   { opacity: 0; transform: translateX(-120%); }
    9%   { opacity: 1; transform: translateX(6%); }
    14%  { transform: translateX(0); }
    82%  { opacity: 1; transform: translateX(0); }
    100% { opacity: 0; transform: translateX(-120%); }
}

/* Zonas ya escaneadas: frío es «ahí no hay nada», caliente es «algo hay». */
.cell[data-scan="cold"] { box-shadow: inset 0 0 0 1px rgb(120 160 180 / .35); }
.cell[data-scan="hot"] { box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--accent-2) 55%, transparent); }
.cell[data-scan-value]::after {
    content: attr(data-scan-value);
    position: absolute; inset: auto auto 1px 2px;
    font-size: .55rem; font-weight: 700; color: var(--accent-2); opacity: .9;
}

/* ─── Cortinilla entre fases ───────────────────────────────────────────────── */
.curtain {
    position: fixed; inset: 0; z-index: 60;
    display: grid; place-items: center;
    background: color-mix(in srgb, var(--bg-deep) 88%, transparent);
    pointer-events: none;
    opacity: 0;
}
.curtain.is-running { animation: curtain-fade 1.5s ease-out forwards; }
.curtain-sweep {
    position: absolute; inset: 0;
    background: linear-gradient(100deg, transparent 35%, color-mix(in srgb, var(--accent) 35%, transparent) 50%, transparent 65%);
    transform: translateX(-100%);
}
.curtain.is-running .curtain-sweep { animation: curtain-sweep 1.5s cubic-bezier(.4, 0, .2, 1) forwards; }
.curtain-text {
    position: relative;
    font-size: clamp(1.4rem, 6vw, 3rem);
    font-weight: 900;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--accent);
    text-shadow: 0 0 30px color-mix(in srgb, var(--accent) 55%, transparent);
}

@keyframes curtain-fade { 0% { opacity: 0; } 18% { opacity: 1; } 78% { opacity: 1; } 100% { opacity: 0; } }
@keyframes curtain-sweep { to { transform: translateX(100%); } }

/* ─── Luces de colores ─────────────────────────────────────────────────────────
 *
 * Aquí había «agua»: dos manchas azul verdosas moviéndose despacio, y antes de eso una
 * cuadrícula de papel milimetrado. Las dos cosas eran de cuando la plataforma era un juego
 * de hundir barcos, y lo que decían era «hoja de cálculo».
 *
 * Ahora son los cuatro colores de la baraja, muy suaves y muy despacio. Es lo que se busca:
 * la mesa del salón de casa un domingo por la tarde. Se mueven tan lento —minuto y medio la
 * vuelta— que no se ve moverse; lo que se nota es que el fondo no está quieto del todo.
 *
 * Dos capas a velocidades distintas, porque una sola se repite y se le ve el ciclo. Se
 * mueven con `transform`, así que las lleva la GPU y no cuestan ni un recálculo de
 * maquetación: encima de esto hay texto que se lee.
 */
body::before,
body::after {
    content: "";
    position: fixed;
    /*
     * Se sale un cuarto de pantalla por cada lado, para que al moverse no asome el borde.
     *
     * Ojo con los porcentajes de dentro: se miden sobre ESTA caja, que es una vez y media
     * la pantalla, no sobre la pantalla. Puestos a ojo como si fueran de pantalla, las
     * cuatro luces caían fuera y el fondo se quedaba en un tinte de nada. La equivalencia
     * es `caja = (pantalla + 25) / 1.5`: el 12 % de pantalla es el 25 % de aquí.
     */
    inset: -25%;
    pointer-events: none;
    z-index: -1;
    animation: luces 90s ease-in-out infinite alternate;
}

body::before {
    background:
        radial-gradient(38vmax 38vmax at 25% 29%, color-mix(in srgb, var(--oros) 78%, transparent), transparent 64%),
        radial-gradient(34vmax 34vmax at 75% 25%, color-mix(in srgb, var(--copas) 72%, transparent), transparent 64%);
    opacity: .55;
}

body::after {
    background:
        radial-gradient(40vmax 40vmax at 69% 74%, color-mix(in srgb, var(--espadas) 68%, transparent), transparent 64%),
        radial-gradient(32vmax 32vmax at 29% 73%, color-mix(in srgb, var(--bastos) 72%, transparent), transparent 64%);
    opacity: .5;
    animation-duration: 124s;
    animation-direction: alternate-reverse;
}

/* En oscuro se bajan: la misma mancha sobre fondo oscuro se lee como una nube gris. */
:root[data-theme="oscuro"] body::before { opacity: .34; }
:root[data-theme="oscuro"] body::after  { opacity: .3; }

@keyframes luces {
    from { transform: translate3d(-3%, -2%, 0) scale(1); }
    50%  { transform: translate3d(3%, 2%, 0) scale(1.08); }
    to   { transform: translate3d(-2%, 3%, 0) scale(1.03); }
}

/* ─── Ajustes ──────────────────────────────────────────────────────────────── */
.settings { position: relative; }
.icon { display: grid; place-items: center; padding: var(--space-2); }
.icon svg { width: 1.3rem; height: 1.3rem; }
[data-action="settings"] .cross { display: none; }
[data-action="settings"][data-muted="true"] .waves { display: none; }
[data-action="settings"][data-muted="true"] .cross { display: block; }

.settings-panel {
    position: absolute; right: 0; top: calc(100% + var(--space-2));
    width: min(19rem, calc(100vw - 2rem));
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--radius-2); box-shadow: var(--shadow-2);
    padding: var(--space-4); z-index: 40;
    display: grid; gap: var(--space-3);
}
.settings-panel h2 { font-size: .78rem; margin: 0; }
.settings-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); font-size: .9rem; }
.settings-row input[type="range"] { width: 8rem; }
.settings-help { font-size: .78rem; color: var(--text-dim); margin: 0; }

/* ─── Menos movimiento ─────────────────────────────────────────────────────── */
/* Con prefers-reduced-motion o en modo de bajo rendimiento: nada se mueve solo.
   Los efectos del canvas ya se apagan desde JavaScript. */
@media (prefers-reduced-motion: reduce) {
    body::before, body::after { animation: none; }
    .float, .banner, .streak.is-bumped, .curtain.is-running,
    .curtain.is-running .curtain-sweep, .sonar-charge[data-full="true"],
    .achievement, .streak-bar[data-hot="true"] .streak-fill,
    .fleet-progress-track[data-critical="true"], .boards[data-damage="true"]::after,
    .boards[data-your-turn="true"] [data-board-panel="enemy"], .cell.is-revealed { animation: none; }
    .float, .banner, .achievement { opacity: 1; }
    /* Las barras siguen contando, pero de golpe: el dato importa, el viaje no. */
    .streak-fill, .fleet-progress-fill { transition: none; }
    .boards[data-damage="true"]::after { display: none; }
}
:root[data-low-perf="true"] body::before,
:root[data-low-perf="true"] body::after { animation: none; }

/* Cara del votante sobre su casilla. Pequeña, en la esquina, sin tapar el estado. */
.vote-avatar {
    position: absolute;
    inset: 1px 1px auto auto;
    width: 45%;
    height: 45%;
    border-radius: 50%;
    border: 1px solid var(--accent);
    object-fit: cover;
    pointer-events: none;
    animation: vote-pop .28s cubic-bezier(.2, 1.6, .4, 1);
}
@keyframes vote-pop { from { transform: scale(.2); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .vote-avatar { animation: none; } }
