/* ==========================================================================
   TRANSICIONES DE PAGINA — View Transitions API
   ==========================================================================

   Cero librerias y cero javascript propio: la transicion la hace el navegador.
   Todo el mecanismo son las ~20 lineas de reglas de este archivo, mas una
   linea de configuracion en navegacion.js para el caso de htmx.

   Que hace, en una frase: al cambiar de pagina, el contenido viejo se apaga y
   el nuevo entra subiendo dos pixeles menos de lo que estaba. El header, el
   pie, la barra lateral y los botones flotantes NO se mueven ni parpadean.

   Como llega a activarse. Son dos caminos que terminan en las mismas reglas:

     1. Navegacion de documento (el panel, el login, el generador, y el sitio
        publico si htmx no cargo). La pide la regla @view-transition de aca
        abajo. El navegador guarda una foto de la pagina que se va, carga la
        que viene y las cruza el solo.
     2. Navegacion sin recarga del sitio publico. Ahi no hay cambio de
        documento: htmx reemplaza el <main>. La pide navegacion.js con
        htmx.config.globalViewTransitions, que envuelve el reemplazo en
        document.startViewTransition().

   Que pasa en un navegador sin soporte: nada. La regla @view-transition se
   ignora, htmx reemplaza el contenido como venia haciendo y el sitio se ve
   exactamente como antes de este archivo. No hay polyfill ni fallback que
   mantener — esa es la razon de haberlo hecho asi y no con una libreria.

   Se carga en los cuatro layouts, despues de tokens.css (usa --duration-*,
   --ease-out y --space-2) y antes del global.css de cada capa (el del panel
   pisa --transicion-desplazamiento; ver mas abajo).
   ========================================================================== */


/* --- Activacion -----------------------------------------------------------
   Vale para las dos paginas de la navegacion, la que se va y la que viene: si
   una de las dos no la declara, no hay transicion. Como este archivo lo cargan
   los cuatro layouts, cualquier salto dentro del sitio la tiene. */
@view-transition {
  navigation: auto;
}


:root {
  /* Cuanto sube el contenido que entra. Es un escalon de la escala de
     espaciado (16px), no un numero elegido a ojo.

     Empezo en --space-2 (8px) y no alcanzaba: 8px es el 1% de la pantalla y
     la transicion corria entera sin que nadie la viera. Una transicion que no
     se percibe no es discreta, es codigo que no hace nada. 16px sigue siendo
     poco — un 2% —, pero es la diferencia entre notar el relevo y no.

     El panel lo pone en 0 (ver administracion/css/global.css): ahi el
     contenido cambia decenas de veces al dia y el movimiento, por chico que
     sea, se vuelve una demora que se nota. Le queda el cruce de opacidad. */
  --transicion-desplazamiento: var(--space-4);
}


/* --- La cascara: lo que no participa --------------------------------------
   Un view-transition-name saca al elemento del grupo "root" y lo hace viajar
   por su cuenta. Como estos son identicos en las dos paginas, el navegador los
   cruza consigo mismos: quedan quietos, sin parpadeo y sin acompañar el
   desplazamiento del contenido.

   Sin esto la foto del "root" es la pantalla entera, y al subir el contenido
   subirian tambien el header fijo y los botones flotantes. Es la diferencia
   entre una transicion de contenido y una pagina que da un salto.

   Para sumar un elemento nuevo: si esta fijo en pantalla o sobrevive al
   cambio de pagina, va en esta lista con las dos declaraciones — un nombre
   propio y la clase. El nombre tiene que ser unico en el documento: dos
   elementos con el mismo nombre a la vez no degradan la transicion, la
   cancelan entera. */

/* Sitio publico */
.global-navbar {
  view-transition-name: cascara-cabecera;
  view-transition-class: cascara;
}

.auth-footer {
  view-transition-name: cascara-pie;
  view-transition-class: cascara;
}

.floating-btn {
  view-transition-name: cascara-flotantes;
  view-transition-class: cascara;
}

.nav-progreso {
  view-transition-name: cascara-progreso;
  view-transition-class: cascara;
}

/* Aviso de cookies: vive en los dos layouts y es un dialogo por encima de
   todo. Si esta abierto mientras se navega, se queda donde esta. */
#aviso-navegacion-overlay {
  view-transition-name: cascara-cookies;
  view-transition-class: cascara;
}

/* Panel. body > header es el encabezado del panel y no existe en el sitio
   publico, que arma el suyo con <nav class="global-navbar">. */
body > header {
  view-transition-name: cascara-panel-cabecera;
  view-transition-class: cascara;
}

#panel-botones {
  view-transition-name: cascara-panel-menu;
  view-transition-class: cascara;
}

.panel-derechos {
  view-transition-name: cascara-panel-pie;
  view-transition-class: cascara;
}

/* Y que no se animen. El nombre solo los saca del grupo del contenido, pero
   el navegador igual les da su cruce de opacidad por defecto: 250ms de
   composicion por elemento para pasar de una imagen a otra identica.
   Invisible, pero no gratis, y deja de ser invisible el dia que uno de estos
   tenga fondo translucido — el modo de fusion del cruce (plus-lighter) suma
   las dos capas y ahi si se ve el destello.

   El selector es la clase, no cada nombre: asi sumar un elemento a la cascara
   son dos declaraciones y ninguna regla nueva. En un navegador que entienda
   view-transition-name pero no view-transition-class esto no engancha y se
   vuelve al cruce por defecto, que es lo que ya pasaba: invisible. */
::view-transition-group(.cascara),
::view-transition-old(.cascara),
::view-transition-new(.cascara) {
  animation: none;
}


/* --- El contenido ---------------------------------------------------------
   Lo que queda del "root" despues de apartar la cascara: el <main> del sitio,
   el <section> del panel.

   Las dos animaciones arrancan juntas, no una despues de la otra. Es a
   proposito: el navegador compone estas dos capas con mix-blend-mode
   plus-lighter, que es justamente el modo en el que dos opacidades
   complementarias suman 1 y el cruce no pasa por un gris intermedio. Encadenar
   una detras de otra alargaria la espera al doble para que se vea peor.

   La salida usa la duracion corta y la entrada la larga: lo viejo tiene que
   irse antes de que lo nuevo termine de llegar, o durante un instante se leen
   dos textos encima del otro. Con --ease-out el 80% del apagado ocurre en los
   primeros 60ms, asi que el solapamiento real es minimo.

   200ms de punta a punta. Una transicion de pagina que pasa de 300ms deja de
   sentirse como respuesta y empieza a sentirse como espera. */

/* El grupo del contenido no se anima: es el rectangulo que ocupa, y ese
   rectangulo es el area visible de la ventana, que no cambia entre una pagina
   y la otra. El navegador le da igual sus 250ms por si acaso, y mientras
   corren la pagina esta congelada — se pinta la foto de la transicion, no el
   documento. Apagarlo devuelve la pagina 50ms antes sin cambiar un pixel. */
::view-transition-group(root) {
  animation: none;
}

::view-transition-old(root) {
  animation: transicion-pagina-sale var(--duration-fast) var(--ease-out) both;
}

::view-transition-new(root) {
  animation: transicion-pagina-entra var(--duration-base) var(--ease-out) both;
}

@keyframes transicion-pagina-sale {
  to {
    opacity: 0;
  }
}

@keyframes transicion-pagina-entra {
  /* El primer tercio no hace nada: es el hueco en el que el contenido viejo
     termina de irse. Recien despues entra el nuevo.

     Sin ese hueco las dos capas se cruzaban a la vez y, como el navegador las
     compone con plus-lighter (dos opacidades complementarias que suman 1), el
     brillo de la pantalla no cambiaba en ningun momento del recorrido. Un
     cruce perfecto en el papel y, en la practica, imposible de percibir: no
     hay un solo fotograma donde el ojo pueda agarrarse de algo. */
  from,
  35% {
    opacity: 0;
    transform: translateY(var(--transicion-desplazamiento));
  }

  to {
    opacity: 1;
    transform: none;
  }
}


/* --- Menos movimiento -----------------------------------------------------
   No se apaga la transicion entera: quien pidio menos movimiento sigue
   necesitando ver que la pagina cambio, y un corte seco entre dos pantallas es
   mas brusco que un cruce de opacidad, no menos. Lo que se saca es lo unico
   que se mueve de sitio — el desplazamiento —, y queda el cruce.

   Va al final del archivo a proposito: pisa al :root de arriba por orden, sin
   necesidad de subir la especificidad. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --transicion-desplazamiento: 0px;
  }
}
