/* Sistema de movimiento.
 *
 * Tres reglas que gobiernan todo lo de acá:
 *
 *   1. El movimiento **aclara**, nunca decora. Cada animación explica de
 *      dónde viene un elemento o confirma que algo pasó. Si no hace ninguna
 *      de las dos cosas, sobra.
 *   2. Solo se animan `transform`, `opacity` y `filter`. Animar `width` o
 *      `top` obliga al navegador a rehacer el diseño en cada fotograma, y en
 *      el equipo modesto de una caja eso se ve como tirones.
 *   3. **Se apaga entero** con `prefers-reduced-motion`. Para quien tiene
 *      sensibilidad vestibular, el movimiento no es un adorno prescindible:
 *      es un síntoma. El bloque final no deja ni una excepción.
 */

/* ------------------------------------------------------- entradas al ver -- */
/* Los elementos aparecen al entrar en pantalla. El desplazamiento es corto
 * (14px) a propósito: lo justo para que se perciba dirección, no un viaje. */
.revelar {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 520ms cubic-bezier(0.16, 1, 0.3, 1),
              transform 520ms cubic-bezier(0.16, 1, 0.3, 1);
  will-change: opacity, transform;
}
.revelar--visible {
  opacity: 1;
  transform: none;
  /* Se retira en cuanto termina: `will-change` permanente reserva memoria de
     vídeo por cada elemento, y una página con cincuenta lo paga caro. */
  will-change: auto;
}

/* Escalonado dentro de un grupo: las tarjetas de una rejilla entran una tras
 * otra, lo que ayuda a leerlas como serie en vez de como bloque. */
.revelar--1 { transition-delay: 60ms; }
.revelar--2 { transition-delay: 120ms; }
.revelar--3 { transition-delay: 180ms; }
.revelar--4 { transition-delay: 240ms; }
.revelar--5 { transition-delay: 300ms; }
.revelar--6 { transition-delay: 360ms; }

/* --------------------------------------------------------- realimentación -- */
/* Confirmación de que una acción se registró. Un pulso corto sobre la propia
 * pieza tocada: no hace falta un cartel para decir «listo». */
@keyframes pulso-acuse {
  0%   { transform: scale(1); }
  38%  { transform: scale(1.045); }
  100% { transform: scale(1); }
}
.acuse { animation: pulso-acuse 320ms cubic-bezier(0.16, 1, 0.3, 1); }

/* Rechazo: una sacudida lateral breve. Es la convención que todo el mundo
 * entiende sin explicación, y no depende del color, así que también funciona
 * para quien no distingue el rojo. */
@keyframes sacudida-rechazo {
  0%, 100% { transform: translateX(0); }
  20%      { transform: translateX(-5px); }
  40%      { transform: translateX(5px); }
  60%      { transform: translateX(-3px); }
  80%      { transform: translateX(3px); }
}
.rechazo { animation: sacudida-rechazo 340ms ease-in-out; }

/* Cifra que cambia: destello del fondo, no del número. Cambiar el color del
 * texto lo vuelve ilegible justo en el instante en que se quiere leer. */
@keyframes destello-cifra {
  from { background-color: var(--turquesa-100); }
  to   { background-color: transparent; }
}
.cifra-cambia {
  animation: destello-cifra 700ms ease-out;
  border-radius: var(--radio-sm);
}

/* -------------------------------------------------------------- circuito -- */
/* La señal que recorre el bus. Se detiene por completo con movimiento
 * reducido: es lo único animado de forma continua en la página. */
@media (prefers-reduced-motion: reduce) {
  .circuito__señal { display: none; }
}

/* Latido muy lento de los nodos. La amplitud es mínima —de 0,75 a 1— porque
 * un parpadeo marcado en el fondo compite con el texto que está encima. */
@keyframes latido-nodo {
  0%, 100% { opacity: 0.75; }
  50%      { opacity: 1; }
}
.circuito__luces { animation: latido-nodo 4.5s ease-in-out infinite; }

/* --------------------------------------------------------------- barrido -- */
/* Barra de carga indeterminada, para esperas sin porcentaje conocido. */
@keyframes barrido-carga {
  from { transform: translateX(-100%); }
  to   { transform: translateX(300%); }
}
.barra-carga {
  position: relative;
  overflow: hidden;
  height: 3px;
  background: var(--borde);
  border-radius: 999px;
}
.barra-carga::after {
  content: "";
  position: absolute;
  inset-block: 0;
  width: 33%;
  background: var(--turquesa);
  border-radius: inherit;
  animation: barrido-carga 1.15s cubic-bezier(0.65, 0, 0.35, 1) infinite;
}

/* ----------------------------------------------------- movimiento reducido */
/* Sin excepciones. Todo lo de arriba queda inerte, y el contenido sigue
 * siendo legible porque ningún elemento depende de su animación para
 * mostrarse: `.revelar--visible` fija el estado final igualmente. */
@media (prefers-reduced-motion: reduce) {
  .revelar,
  .revelar--visible {
    opacity: 1;
    transform: none;
    transition: none;
    will-change: auto;
  }
  .acuse,
  .rechazo,
  .cifra-cambia,
  .circuito__luces,
  .barra-carga::after {
    animation: none;
  }
}

/* ---------------------------------------------------- control de sonido -- */
/* Lo dibuja el guion solo si el navegador puede reproducir audio: un control
 * que no hace nada es peor que no tenerlo. */
.sonido-btn {
  width: 2.25rem;
  height: 2.25rem;
  display: grid;
  place-items: center;
  padding: 0;
  color: var(--marino-300);
  background: transparent;
  border: 1px solid var(--linea-sobre-oscuro);
  border-radius: var(--radio-sm);
  cursor: pointer;
  transition: color var(--transicion), border-color var(--transicion),
              background var(--transicion);
}
.sonido-btn svg { width: 1.15rem; height: 1.15rem; }

.sonido-btn:hover {
  color: var(--turquesa-400);
  border-color: var(--turquesa);
}
.sonido-btn:focus-visible {
  outline: 2px solid var(--turquesa);
  outline-offset: 2px;
}

/* Encendido: se distingue por color Y por el icono, nunca solo por color.
 * Quien no separa el turquesa del gris sigue viendo las aspas del icono. */
.sonido-btn--activo {
  color: var(--turquesa-400);
  border-color: var(--turquesa);
  background: var(--superficie-velada);
}
