/* ============================================================
   MOVIMIENTO — tres costuras donde algo aparecía sin puente

   Va en un fichero propio y no en output.css a propósito. output.css es un
   build de Tailwind cuyo `content` en tailwind.config.js sigue apuntando al
   proyecto estático anterior (./*.php, ./js/**), no a app/Views de este. Si se
   recompilara para meter esto, Tailwind no vería las clases que usan las
   vistas de aquí y las borraría del CSS: el sitio se rompería entero. Arreglar
   esa configuración es un trabajo aparte; mientras tanto, cargar después es
   suficiente y no arriesga nada.

   Se carga en todas las páginas porque el botón del chat vive en tres.

   NO está aquí la entrada de los mensajes del chat: ya existe desde antes
   (@keyframes chat-msg-in, 250 ms) y funciona bien. Se comprobó midiendo una
   burbuja recién insertada. Duplicarla habría sido peor que no tocarla — una
   animación gana a una transición, así que la nueva no se habría visto y sólo
   habría dejado reglas muertas.

   Todo anima sólo `transform` y `opacity` — las dos propiedades que el
   compositor resuelve sin recalcular diseño ni repintar.
   ============================================================ */

/* ---------- 1. Mensaje de estado del formulario ----------
   setStatus() escribe textContent y el mensaje parpadeaba a la existencia. En
   un acuse de envío eso importa: un texto que aparece de golpe se lee como un
   error de validación aunque diga que todo salió bien.

   Se resuelve con :empty y sin tocar el JS. El <span> nace vacío, así que
   arranca oculto; en cuanto setStatus() le mete texto deja de coincidir con
   :empty y la transición corre sola. Y al revés: si algún día se limpia el
   estado, se desvanece en lugar de desaparecer.

   Baja desde arriba, que es de donde viene la acción — el botón de enviar está
   debajo y el estado se anuncia por encima de él. */

.form-status {
  transition:
    opacity 220ms var(--ease-out, cubic-bezier(.23, 1, .32, 1)),
    transform 220ms var(--ease-out, cubic-bezier(.23, 1, .32, 1));
}

.form-status:empty {
  opacity: 0;
  transform: translateY(-4px);
}

/* ---------- 2. Pulsación del botón de enviar del chat ----------
   No es una animación que faltara: .chat-send ya declaraba
   `transition: transform .25s var(--ease-lift)` y tenía :hover y :disabled,
   pero ninguna regla :active. Había una transición esperando un estado que
   nadie producía.

   El :hover ya escala a 1.06, así que el valor de pulsación se elige contra
   ese punto de partida y no contra 1: .96 se nota viniendo de cualquiera de
   los dos sin llegar a caricatura.

   250 ms para un acuse de pulsación llega cuando la mano ya soltó. Se separa
   el transform del resto. */

.chat-send {
  transition:
    transform 110ms cubic-bezier(.2, 0, 0, 1),
    opacity 250ms ease,
    background-color 250ms ease;
}

.chat-send:active:not(:disabled) {
  transform: scale(.96);
  transition-duration: 60ms;
}

/* ---------- 3. Escalonado de la rejilla bento ----------
   Las cinco tarjetas cruzan el umbral del observador a la vez y subían juntas,
   que se lee como un solo bloque moviéndose en vez de cinco piezas colocándose.

   60 ms entre cada una es suficiente para separarlas sin que la última se haga
   esperar. La duración baja de 750 a 500 ms sólo aquí: con el escalonado
   encima, 750 dejaría la quinta aterrizando pasado un segundo.

   El retardo es sólo de entrada y no bloquea nada: las tarjetas son pulsables
   desde el primer fotograma. */

.bento-card.reveal-up {
  transition-duration: 500ms;
}

.bento-card.reveal-up:nth-child(2) { transition-delay: 60ms; }
.bento-card.reveal-up:nth-child(3) { transition-delay: 120ms; }
.bento-card.reveal-up:nth-child(4) { transition-delay: 180ms; }
.bento-card.reveal-up:nth-child(5) { transition-delay: 240ms; }

/* ---------- Menos movimiento ----------
   No es "sin acuse": es el mismo mensaje sin desplazamiento. Se conserva el
   fundido, que comunica que algo apareció sin mover nada por la pantalla, y se
   quita el escalonado, que sólo existe para dar ritmo.

   El sitio ya neutraliza .reveal-up entero en este modo, así que aquí sólo hay
   que asegurarse de no reintroducir el retardo. */

@media (prefers-reduced-motion: reduce) {
  .form-status {
    transition: opacity 150ms ease;
    transform: none;
  }

  .form-status:empty {
    transform: none;
  }

  .chat-send:active:not(:disabled) {
    transform: none;
  }

  .bento-card.reveal-up {
    transition-delay: 0ms !important;
  }
}

/* ============================================================
   LO MISMO, EN LAS 12 PAGINAS INTERIORES

   Estas dos cosas se arreglaron en la portada y nunca llegaron al resto del
   sitio. No son hallazgos nuevos: son el mismo defecto donde tambien aplica.

   La auditoria de las interiores no encontro nada mas. Contraste, jerarquia de
   titulos, desbordamiento, nombres accesibles y tamano de objetivos se midieron
   en las doce, en los dos temas y a 1280 y 390 px: todo limpio.
   ============================================================ */

/* ---------- Respuesta al toque ----------
   El sitio anima transform en 250 ms, y ese mismo transform es el acuse de
   pulsacion (:active scale .97). Para un toque eso llega cuando la mano ya
   solto. Baja a 110 ms al pulsar y 60 al soltar; hover, color y sombra se
   quedan en 250, que ahi si es el ritmo correcto.

   La portada tiene su propia version de esta regla con mas especificidad
   (#paradox.hero-redesign), asi que alli sigue mandando aquella y esta no
   interfiere. */

.btn-primary,
.btn-ghost,
.chip,
.tilt-card,
.chat-send {
  transition:
    transform 110ms cubic-bezier(.2, 0, 0, 1),
    background-color 250ms ease,
    border-color 250ms ease,
    color 250ms ease,
    box-shadow 250ms ease,
    opacity 250ms ease;
}

.btn-primary:active,
.btn-ghost:active {
  transition-duration: 60ms;
}

/* ---------- Sin transparencia ----------
   Las interiores tienen 29 superficies con backdrop-filter y no habia una sola
   regla para prefers-reduced-transparency. Quien pide menos transparencia suele
   hacerlo porque el desenfoque le dificulta leer: la respuesta correcta es
   volver opacas las superficies, no quitar el blur y dejarlas translucidas.

   Se usan los tokens del sitio, que ya se invierten con el tema, en vez de
   fijar colores: asi esto funciona igual en claro y en oscuro. */

@media (prefers-reduced-transparency: reduce) {
  .glass-panel,
  .bento-card,
  .case-card,
  .tilt-card,
  .mobile-nav,
  body > header {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    background: var(--surface-container, #1f1f1f) !important;
  }

  .chip {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background: var(--surface-container-high, #2a2a2a);
  }
}

/* ---------- Mas contraste ----------
   Fondos solidos y bordes definidos, que es lo que pide la senal. */

@media (prefers-contrast: more) {
  .glass-panel,
  .bento-card,
  .case-card,
  .tilt-card,
  .chip {
    background: var(--surface-container-lowest, #0e0e0e);
    border-color: var(--on-surface, #e2e2e2);
  }

  .btn-ghost {
    border-color: var(--on-surface, #e2e2e2);
  }
}
