/* ==========================================================================
   FUNDACIÓN PUNTO 37 — capa de movimiento
   --------------------------------------------------------------------------
   REESCRITA DESDE CERO tras un fallo en producción que dejó 28 de 29 elementos
   invisibles. La causa quedó identificada y condiciona todo este archivo:

   la versión anterior revelaba con TRANSICIONES. Cada transición se reiniciaba
   sola en cada recálculo de estilo, así que nunca terminaba y se quedaba
   colgada en su fase de retardo con fill:backwards, que fija el valor INICIAL.
   Y en la cascada las transiciones están por encima de todo, incluso de
   !important: por eso ninguna regla de rescate lograba volver visible el
   contenido.

   Aquí NO se revela con transiciones. Se revela con @keyframes de una sola
   pasada y animation-fill-mode:forwards, que al terminar deja el estado final
   clavado y no se puede reiniciar solo. Las transiciones quedan sólo para
   respuestas al puntero, donde son inofensivas porque el estado de reposo del
   elemento ya es visible.

   Además todo el estado escondido cuelga de html.anim, que pone el script. Sin
   JavaScript la clase no existe, ninguna regla de reposo aplica y la página se
   ve entera. Y el propio script retira html.anim si detecta que algo quedó
   oculto: el contenido siempre gana.

   --------------------------------------------------------------------------
   MAPA DE GESTOS. Son pocos a propósito: si todo se mueve, nada destaca.

     rv / rv-izq / rv-der / rv-zoom   entradas neutras de bloque
     rv-baldosa   tiles de color: fichas macizas que alguien pone en la mesa
     rv-nube      TODO lo recortado con máscara de nube (fotos del damero,
                  chips de cifras, marcos de onda, píldoras del cierre)
     rv-rotulo    renglones en versalitas: se despliegan
     rv-mano      las cinco palabras en Goodkids: llegan a mano
     rv-linea     no esconde nada; sólo dibuja el canto inferior del elemento

   Y dos movimientos de reposo, ambos perpetuos y ambos muy contenidos:
   el latido de las fotos en nube y la respiración horizontal de los festones.
   ========================================================================== */

/* --- 1. REVELADO AL ENTRAR EN PANTALLA ----------------------------------- */
html.anim .rv{ opacity:0 }
html.anim .rv-on{
  animation:rv-entra .68s cubic-bezier(.22,.68,0,1) forwards;
  animation-delay:var(--rv-d,0s);
}
@keyframes rv-entra{
  from{ opacity:0; transform:translate3d(0,24px,0) }
  to  { opacity:1; transform:none }
}
/* Variantes por dirección, para que una rejilla no entre toda igual */
html.anim .rv-izq.rv-on{ animation-name:rv-izq }
html.anim .rv-der.rv-on{ animation-name:rv-der }
html.anim .rv-zoom.rv-on{ animation-name:rv-zoom }
@keyframes rv-izq { from{opacity:0;transform:translate3d(-26px,0,0)} to{opacity:1;transform:none} }
@keyframes rv-der { from{opacity:0;transform:translate3d( 26px,0,0)} to{opacity:1;transform:none} }
@keyframes rv-zoom{ from{opacity:0;transform:scale(.9)}            to{opacity:1;transform:none} }

/* --- 1b. DEL REVELADO AL REPOSO ------------------------------------------
   El script retira .rv y .rv-on en cuanto la animación TERMINA, y deja
   .rv-listo. No es cosmético, es la única forma de recuperar el hover:

   una animación acabada con fill:forwards NO desaparece; se queda ocupando el
   origen "animación" de la cascada, que pesa más que cualquier declaración
   normal de autor. Mientras estuviera ahí, ".tile:hover{transform:...}" no
   movía nada. Medido en el propio sitio: con la animación puesta el hover
   devuelve la matriz identidad; al quitarla, los -4px de siempre.

   Como el fotograma final de TODOS los @keyframes de entrada es exactamente el
   estado natural del elemento (opacity:1, transform:none), soltar las clases
   no se ve. Y no puede esconder nada: lo que se retira es el escondite.

   Por eso aquí no hay ninguna regla ".rv-listo{...}" que fije valores: el
   elemento se queda en su estado de siempre. .rv-listo sólo sirve de gancho
   para lo que empieza DESPUÉS de la entrada. */

/* --- 2. HERO: EL NIÑO Y EL GATO ------------------------------------------
   Son dos capas recortadas con la MISMA caja, así que superpuestas al 100%
   reconstruyen la figura original. Se mueven con periodos distintos y
   desfasadas: si ambas subieran y bajaran igual, el conjunto parecería una
   calcomanía sacudiéndose. Con el desfase el gato se lee más rápido que el
   niño, y eso es lo que da sensación de profundidad. */
.hero-capas{ position:relative }
.hero-capas img{ display:block; width:100% }
.hero-capas .capa-nino{ position:absolute; inset:0 }
html.anim .hero-capas .capa-gato{ animation:flota-gato 3.9s ease-in-out infinite }
html.anim .hero-capas .capa-nino{ animation:flota-nino 5.2s ease-in-out infinite; animation-delay:-1.4s }
@keyframes flota-gato{ 0%,100%{transform:translate3d(0,0,0) rotate(0deg)} 50%{transform:translate3d(0,-9px,0) rotate(-.7deg)} }
@keyframes flota-nino{ 0%,100%{transform:translate3d(0,0,0)}            50%{transform:translate3d(0,-4px,0)} }

/* --- 2.b LA RUEDA CORTADA ------------------------------------------------
   El cliente: "mover animación del niño del primer hero un poco más abajo para
   que la rueda que se está cortando no se note demasiado el corte de imagen".

   DE DÓNDE VIENE EL CORTE. No es del contenedor ni del final de la sección: el
   recorte está DENTRO DEL ARCHIVO. Medido sobre los dos .webp, que son de
   1000x972 los dos:

     · img/hero-nino.webp — la última fila de píxeles (y=971) tiene 150 píxeles
       opacos seguidos, de x=567 a x=716, y esa banda viene ENSANCHÁNDOSE fila
       a fila: 132px en y=892, 138 en 912, 144 en 932, 150 en 971. Una
       circunferencia que sigue creciendo en la última fila es una
       circunferencia cuyo ecuador quedó fuera del lienzo. La rueda delantera
       no está completa en el archivo.
     · img/hero-gato.webp — igual: 526 píxeles opacos en su última fila. Ahí lo
       que se corta es la nube blanca sobre la que va la moto.

   Así que no hay rueda que reconstruir, y no se intenta. Lo que se corrige es
   dónde cae esa recta.

   EN ESCRITORIO (901px para arriba) SE VA DE LA VISTA. Ahí la figura es la
   última pieza de la banda y debajo le quedan los 96px de relleno inferior de
   .hero-inicio. Bajándola 124px, el canto del archivo pasa 28px por DEBAJO del
   borde de la banda roja, y .hero-inicio ya recorta con overflow:hidden. La
   moto deja de terminar en una recta suspendida en mitad del rojo y pasa a
   salirse de la banda, que es composición y no defecto.

   LOS CUATRO EXTREMOS DEL CICLO DE FLOTACIÓN, que es donde esto se podía
   deshacer solo. Las dos capas suben y bajan con periodos distintos, así que
   el canto del archivo viaja con ellas. Medidos los cuatro:

     capa-gato en reposo   → 28px por debajo del borde   (oculto)
     capa-gato arriba del todo (-9px) → 19px por debajo  (oculto)
     capa-nino en reposo   → 28px por debajo             (oculto)
     capa-nino arriba del todo (-4px) → 24px por debajo  (oculto)

   El peor momento del ciclo deja 19px de margen. Ni en ése asoma el corte.

   El desplazamiento va en .hero-capas y NO en las dos <img> por dos motivos:
   las imágenes tienen su transform ocupado por el vaivén, y con movimiento
   reducido §10 les pone transform:none !important, que se llevaría por delante
   cualquier bajada escrita ahí. Puesto en el contenedor, el corte sigue fuera
   de la vista también para quien pide menos movimiento.

   Y va con transform y no con margen ni con position:relative+top a propósito:
   un transform no reflota la maqueta. La rejilla del hero, la altura de la
   sección y todo lo que hay debajo se quedan exactamente donde estaban, así
   que esta bajada no puede abrir un desbordamiento vertical ni empujar una
   barra horizontal. */
@media (min-width:901px){
  .hero-capas{ transform:translate3d(0,124px,0) }
}

/* DE 900px PARA ABAJO NO HAY DÓNDE ESCONDER EL CORTE. La maqueta cambia: la
   figura deja de ser lo último de la banda. En tablet pasa a la fila de arriba
   con las tres cifras debajo (su canto queda a 345px del borde de la banda), y
   en el teléfono se va al principio del todo, con el titular a 8px por debajo.
   Bajarla ahí no esconde el corte: lo mete dentro del texto.

   Así que en esas dos pantallas la recta no se esconde, se DISUELVE: los
   últimos píxeles de la capa se desvanecen con una máscara y el neumático y la
   nube se apagan contra el rojo en vez de terminar en una regla. La máscara
   sólo quita píxeles, no dibuja ninguno: no se inventa la rueda que falta en
   el archivo, se deja de fingir que estaba entera.

   Se declara con -webkit-mask-image además de mask-image porque es como el
   resto del sitio pide sus máscaras (ver .cifra en estilo.css), y porque el
   prefijo es el que atienden los WebKit antiguos.

   Los 22px de desvanecido son el 7% de los 299px de figura que quedan en una
   pantalla de 375: suficiente para que no se lea un canto y poco para que no
   se lea una neblina. Y no dependen del ciclo de flotación, porque la máscara
   viaja con el elemento enmascarado: sube y baja con él y tapa el mismo canto
   en los cuatro extremos.

   La máscara va en las dos <img> y no en .hero-capas porque el contenedor no
   se mueve y las capas sí: enmascarando el contenedor, el canto del niño se
   saldría de la zona difuminada en el punto más alto de su vaivén. */
@media (max-width:900px){
  .hero-capas img{
    -webkit-mask-image:linear-gradient(to top, rgba(0,0,0,0) 0, #000 22px);
            mask-image:linear-gradient(to top, rgba(0,0,0,0) 0, #000 22px);
  }
}

/* En tablet sí cabe además el "un poco más abajo" que pidió el cliente: medido
   en 768, entre el canto de la figura y la fila de cifras hay 58px libres, así
   que bajarla 10px no le quita aire a nada.

   Por debajo de 600 NO se baja ni un píxel, y esto se midió: ahí el titular
   arranca 8px por debajo de la figura, y cualquier bajada mete la nube blanca
   del dibujo dentro de "Llegamos hasta donde". El corte ya lo resuelve el
   desvanecido de arriba; empujar la figura contra el texto no arreglaría nada
   y estropearía el titular, que es lo primero que se lee en esa pantalla. */
@media (min-width:601px) and (max-width:900px){
  .hero-capas{ transform:translate3d(0,10px,0) }
}

/* --- 3. NUBES DE ESQUINA Y FESTONES --------------------------------------
   Respiración sólo horizontal en los festones: cualquier movimiento vertical
   abriría una costura del color de la banda de abajo en el canto. */
html.anim .nube-esquina{ animation:deriva 17s ease-in-out infinite }
html.anim .nube-esquina.ne-der{ animation-duration:21s; animation-delay:-6s }
@keyframes deriva{ 0%,100%{transform:translate3d(0,0,0)} 50%{transform:translate3d(10px,-6px,0)} }

/* El festón ya respiraba ensanchándose. Ahora además deriva de lado, que es lo
   que hace que se lea como nubes pasando y no como una goma que se estira.

   La deriva es la parte delicada. El festón está montado con left:-2px y
   width:calc(100% + 4px), así que sólo sobra un canto de 2px por lado; lo que
   de verdad da margen es el propio scaleX. Por eso ensanche y deriva viajan en
   el MISMO fotograma: cuando la pieza no está ensanchada tampoco está corrida,
   y en cualquier punto intermedio el sobrante del scaleX (1,75% del ancho por
   lado en el pico) es casi cuatro veces la deriva (0,45%). Y por eso la deriva
   va en % de la propia caja y no en píxeles: la proporción se mantiene igual
   en una pantalla de 375 que en una de 1440. */
html.anim .nube{ animation:respira var(--nube-t,24s) ease-in-out infinite }
@keyframes respira{
  0%,100%{ transform:scaleX(1)     translateX(0)     }
  50%    { transform:scaleX(1.035) translateX(.45%)  }
}
@keyframes respira-inv{
  0%,100%{ transform:scaleX(1)     translateX(0)     }
  50%    { transform:scaleX(1.035) translateX(-.45%) }
}
/* Los dos cantos de una misma banda no pueden respirar a la vez ni hacia el
   mismo lado: se leería como si la banda entera se hinchara. El de abajo va al
   revés y más lento, y el del pie más lento todavía. */
html.anim .nube-abajo{ animation-name:respira-inv; --nube-t:29s }
html.anim .pie .nube{ --nube-t:33s }

/* --- 4. BOTONES ----------------------------------------------------------
   En reposo se mueve SÓLO el botón Dona, y sólo su corazón. Animar todos los
   botones pone la página nerviosa: cuando todo se mueve, nada destaca. El
   corazón ya está ahí y late, así que el gesto es el natural y no desplaza
   nada a su alrededor. Ciclo largo con pausa, para acompañar sin insistir. */
html.anim .btn-dona svg{ animation:latido 3.4s ease-in-out infinite; transform-origin:50% 50% }
@keyframes latido{
  0%,86%,100%{ transform:scale(1) }
  89%{ transform:scale(1.22) }
  92%{ transform:scale(1) }
  95%{ transform:scale(1.13) }
}

/* El hover SÓLO donde hay puntero de verdad. En una pantalla táctil el
   navegador aplica :hover al tocar y se queda pegado hasta que tocas en otro
   lado: el botón parece trabado. Con esta consulta eso no puede pasar. */
@media (hover:hover) and (pointer:fine){
  .btn{ transition:transform .16s ease, box-shadow .16s ease }
  .btn-dona:hover{ transform:translateY(-3px) }
  html.anim .btn-dona:hover svg{ animation-duration:1.1s }
  .btn-hueco:hover{ transform:translateY(-3px) }
  .menu a{ transition:color .16s ease }
  .persona .retrato{ transition:transform .25s ease }
  .persona:hover .retrato{ transform:scale(1.04) }
}

/* Respuesta al dedo: el botón se hunde. Va fuera de la consulta anterior
   porque :active sí existe en táctil y es la única señal inmediata que recibe
   quien toca. */
.btn:active{ transform:translateY(2px) }
.btn-dona:active{ box-shadow:0 1px 0 var(--rojo-hondo) }

/* --- 5. CONTADOR DE CIFRAS ----------------------------------------------- */
.cifra b{ font-variant-numeric:tabular-nums }

/* ==========================================================================
   6. QUÉ HACEMOS — EL DAMERO
   --------------------------------------------------------------------------
   Nueve piezas, dos naturalezas. Las tiles son bloques de color plano con el
   título dentro; las fotos son imágenes recortadas con máscara de nube. Antes
   entraban las nueve con el mismo zoom y se quedaban quietas, que es
   exactamente "nueve cosas iguales". Ahora:

     · el compás lo marca la COLUMNA, medida sobre el DOM por el script, así
       que el barrido se lee de izquierda a derecha por renglón y en móvil
       —una sola columna— nadie espera a nadie;
     · dentro de un renglón la tile llega primero y la foto la sigue;
     · cada naturaleza tiene su gesto;
     · las fotos, ya colocadas, laten. La máscara de nube aguanta eso: es una
       silueta blanda, y un 1,4% de escala se lee como respiración y no como
       un salto. Nada se mueve de sitio.
   ========================================================================== */

/* Tile: una ficha maciza que alguien pone sobre la mesa. Sube, se pasa un pelo
   de largo y se asienta. El rebote va DENTRO de los keyframes, no en la curva
   de tiempo, para poder medirlo. */
html.anim .rv-baldosa.rv-on{
  animation-name:rv-baldosa;
  animation-duration:.74s;
  animation-timing-function:cubic-bezier(.34,.72,.28,1);
}
@keyframes rv-baldosa{
  from{ opacity:0; transform:translate3d(0,30px,0) scale(.93)  }
  58% { opacity:1; transform:translate3d(0,-6px,0) scale(1.014) }
  to  { opacity:1; transform:none }
}

/* Nube: la máscara perdona el giro y el crecimiento, así que la pieza puede
   llegar torcida, como una calcomanía que se pega y se endereza. Es el mismo
   gesto para todo lo recortado en nube del sitio, no sólo para el damero. */
html.anim .rv-nube.rv-on{
  animation-name:rv-nube;
  animation-duration:.8s;
  animation-timing-function:cubic-bezier(.3,.74,.28,1);
}
@keyframes rv-nube{
  from{ opacity:0; transform:scale(.78) rotate(-3deg)   }
  55% { opacity:1; transform:scale(1.04) rotate(1.1deg) }
  to  { opacity:1; transform:none }
}

/* Latido de reposo de las fotos. Arranca cuando la entrada TERMINA (de ahí que
   cuelgue de .rv-listo y no de .rv-on): así nunca hay dos animaciones peleando
   por el transform del mismo elemento.

   El desfase entre las cuatro se hace cambiando la DURACIÓN y no el retardo. Un
   retardo negativo, que es la forma corta de desfasar, arrancaría el latido en
   el fotograma cero de la página y se comería el revelado. */
html.anim .tablero .foto-nube.rv-listo{
  animation:latido-nube var(--lat-t,7.4s) ease-in-out infinite;
}
html.anim .tablero .foto-nube:nth-child(2){ --lat-t:6.4s }
html.anim .tablero .foto-nube:nth-child(4){ --lat-t:7.7s }
html.anim .tablero .foto-nube:nth-child(6){ --lat-t:6.9s }
html.anim .tablero .foto-nube:nth-child(8){ --lat-t:8.3s }
@keyframes latido-nube{
  0%,100%{ transform:scale(1) }
  50%    { transform:scale(1.014) }
}

/* --- 6b. RESPUESTA AL PUNTERO EN EL DAMERO -------------------------------
   "Algo más que un desplazamiento": la tile sube, se ladea un pelo y su
   contenido sube MENOS que ella, que es lo que da el relieve.

   La sombra crece con ella. Va en DOS tonos —una corta y oscura de contacto y
   otra larga y clara de proyección— porque es el mismo lenguaje de sombra
   sólida desplazada que usa el reposo de las tiles; una sola sombra plana
   rompería la lectura. Nunca difuminada: el brandbook no tiene ni una.

   La sombra es lo único que se anima fuera de transform y opacity, y es una
   transición de puntero, no un revelado: el mismo caso que la sombra del .btn
   de más arriba, que ya estaba así desde el principio.

   Estas reglas volvieron a funcionar el día que el script pasó a soltar la
   animación terminada (§1b). Antes las pisaba el origen "animación". */
@media (hover:hover) and (pointer:fine){
  .tile{ transition:transform .22s cubic-bezier(.3,.7,.3,1), box-shadow .22s ease }
  .tile > div{ transition:transform .22s cubic-bezier(.3,.7,.3,1) }
  .tile:hover{
    transform:translate3d(0,-6px,0) rotate(-.55deg);
    box-shadow:0 5px 0 rgba(0,0,0,.16), 0 16px 0 rgba(0,0,0,.07);
  }
  .tile:hover > div{ transform:translate3d(0,-3px,0) }
  .tile:active{
    transform:translate3d(0,-1px,0);
    box-shadow:0 2px 0 rgba(0,0,0,.16), 0 6px 0 rgba(0,0,0,.07);
  }

  /* En la foto se mueve la IMAGEN, no la nube: el contorno se queda quieto y
     la escena se acerca dentro de él. Además así el latido de la nube y la
     respuesta al puntero no se disputan el mismo transform. */
  .foto-nube img{ transition:transform .32s cubic-bezier(.3,.7,.3,1) }
  .foto-nube:hover img{ transform:scale(1.06) }
}

/* --- 6c. EL PANEL "VER MÁS" ----------------------------------------------
   <details> aparece de golpe porque el navegador pasa el contenido de
   display:none a visible. No se puede animar esa transición, pero sí lo que ya
   está dentro una vez abierto, y eso basta para que se lea como que el panel
   se despliega.

   Los renglones NO cambian de opacidad: sólo se corren. Es a propósito. Un
   escalonado clásico necesitaría animation-delay con fill:backwards, y
   backwards fija el fotograma INICIAL durante la espera; si esa animación se
   quedara colgada, el renglón se quedaría invisible. Que es justo el fallo que
   costó la reescritura de este archivo. Aquí el abanico se consigue con
   DURACIONES distintas y arranque simultáneo: no hay fase de espera que se
   pueda quedar pegada, y en el peor caso el renglón está en su sitio y legible
   desde el primer fotograma. */
html.anim .detalle[open] > ul{
  animation:abre-lista .34s cubic-bezier(.22,.68,0,1) forwards;
}
@keyframes abre-lista{
  from{ opacity:0; transform:translate3d(0,-9px,0) }
  to  { opacity:1; transform:none }
}
html.anim .detalle[open] li{
  animation:abre-renglon var(--it,.34s) cubic-bezier(.22,.68,0,1) forwards;
}
@keyframes abre-renglon{
  from{ transform:translate3d(-12px,0,0) }
  to  { transform:none }
}
html.anim .detalle[open] li:nth-child(1){ --it:.26s }
html.anim .detalle[open] li:nth-child(2){ --it:.34s }
html.anim .detalle[open] li:nth-child(3){ --it:.42s }
html.anim .detalle[open] li:nth-child(4){ --it:.50s }
html.anim .detalle[open] li:nth-child(5){ --it:.58s }

/* El signo del resumen. Cambia de "+" a "–" por contenido, así que girarlo
   sobre sí mismo no diría nada: lo que se anima es la llegada del signo nuevo. */
html.anim .detalle[open] summary::after{
  animation:marca-abre .3s cubic-bezier(.22,.68,0,1) forwards;
}
@keyframes marca-abre{
  from{ opacity:0; transform:rotate(-100deg) scale(.5) }
  to  { opacity:1; transform:none }
}
@media (hover:hover) and (pointer:fine){
  .detalle summary{ transition:transform .16s ease }
  .detalle summary:hover{ transform:translateX(3px) }
}

/* ==========================================================================
   7. RÓTULOS EN VERSALITAS
   --------------------------------------------------------------------------
   Son los renglones cortos, en mayúsculas y muy espaciados, que titulan cosas:
   el cargo de cada persona, "DIRECTIVOS", el lugar de un evento, el mes, la
   etiqueta de cada sede.

   Lo natural sería animar el letter-spacing, pero aquí sólo se animan transform
   y opacity. Comprimir el renglón en X y soltarlo da exactamente la misma
   lectura —el rótulo se despliega— y va por compositor, sin recalcular texto.
   ========================================================================== */
html.anim .rv-rotulo{ transform-origin:0 50% }
html.anim .rv-rotulo.rv-on{
  animation-name:rv-rotulo;
  animation-duration:.58s;
}
@keyframes rv-rotulo{
  from{ opacity:0; transform:translate3d(0,8px,0) scaleX(.82) }
  52% { opacity:1 }
  to  { opacity:1; transform:none }
}
/* Donde la columna va centrada, el rótulo tiene que desplegarse desde el
   centro; con el origen a la izquierda parecería empujado hacia un lado. */
html.anim .persona .rv-rotulo{ transform-origin:50% 50% }
@media (max-width:600px){
  /* En móvil el pie se centra entero (estilo.css §móvil), rótulos incluidos. */
  html.anim .pie .rv-rotulo{ transform-origin:50% 50% }
}

/* ==========================================================================
   8. LAS PALABRAS ESCRITAS A MANO
   --------------------------------------------------------------------------
   Goodkids aparece en cinco sitios contados de todo el arte. Son remates, no
   titulares, y por eso llegan DESPUÉS del bloque que las contiene y con un
   gesto que las demás palabras no tienen: entran torcidas y se enderezan, como
   algo puesto a mano. El origen va cerca del arranque de la palabra y por
   debajo de su eje, que es donde pivota un trazo escrito.
   ========================================================================== */
html.anim .rv-mano{ transform-origin:8% 68% }
html.anim .rv-mano.rv-on{
  animation-name:rv-mano;
  animation-duration:.78s;
  animation-timing-function:cubic-bezier(.3,.74,.28,1);
}
@keyframes rv-mano{
  from{ opacity:0; transform:translate3d(0,14px,0) rotate(-3.2deg) scale(.9)  }
  56% { opacity:1; transform:translate3d(0,-2px,0) rotate(1.2deg)  scale(1.03) }
  to  { opacity:1; transform:none }
}

/* Vaivén continuo del texto del hero de Nosotros tras la entrada. Cuelga de
   .rv-listo y no de .rv-on, mismo motivo que .tablero .foto-nube.rv-listo más
   abajo: si colgara de .rv-on pelearía con rv-mano por el transform del mismo
   elemento. Isaías pidió más "wow" después de ver la entrada sola — un
   vaivén suave con un toque de giro, como un trazo que respira, nunca oculta
   nada (sólo transform, igual que .adorno--flota). */
html.anim .hero-nos-texto.rv-listo{
  animation: flota-texto-nos 4.6s ease-in-out infinite;
}
@keyframes flota-texto-nos{
  0%,100%{ transform:translate3d(0,0,0) rotate(0deg) }
  50%    { transform:translate3d(0,-8px,0) rotate(-.6deg) }
}

/* La chispa que remata "compromiso" ya estaba en el marcado, quieta. Titila con
   ciclo largo y pausa larga, como el corazón del botón Dona: un guiño cada
   tantos segundos, no un parpadeo. Vuelve siempre a giro cero, así que no da
   tirones al cerrar el ciclo, y la opacidad no baja de .78: nunca desaparece. */
html.anim .chispa svg{
  animation:destella 6.8s ease-in-out infinite;
  transform-origin:50% 50%;
}
@keyframes destella{
  0%,58%,100%{ transform:scale(1)    rotate(0deg)   ; opacity:1   }
  67%        { transform:scale(1.45) rotate(24deg)  ; opacity:1   }
  76%        { transform:scale(.88)  rotate(-14deg) ; opacity:.78 }
  86%        { transform:scale(1.16) rotate(7deg)   ; opacity:1   }
}

/* ==========================================================================
   9. CANTOS QUE SE DIBUJAN
   --------------------------------------------------------------------------
   Dos piezas del sitio se sostienen sobre una raya: la liga "Conoce nuestra
   historia" y el rótulo de cada columna del pie. Esa raya puede dibujarse de
   izquierda a derecha al entrar, y es un gesto que se lee muy bien porque el
   ojo ya sabe hacia dónde va.

   Cómo: se apaga el borde real y lo suple un ::after que crece de scaleX(0) a
   scaleX(1). Todo cuelga de html.anim, así que sin script —o si el vigía
   desmonta la capa— vuelve el borde de siempre y no falta nada.

   Estos elementos NO se esconden: lo que se revela es la raya, no el texto. Por
   eso el script los arma con .rv-linea, que anula el opacity:0 del reposo.
   ========================================================================== */
html.anim .rv.rv-linea{ opacity:1 }
html.anim .rv-linea.rv-on{ animation:none }

html.anim .gesto .liga,
html.anim .pie-titulo{ position:relative; border-bottom-color:transparent }
html.anim .gesto .liga::after,
html.anim .pie-titulo::after{
  content:""; position:absolute; left:0; right:0;
  transform:scaleX(0); transform-origin:0 50%;
}
/* Cada raya se repone con su propio grosor y su propio color: la de la liga es
   de 1,5px y hereda el color del texto; la del pie es de 1px y va en el gris
   oscuro del borde original, que NO es el color del rótulo. */
html.anim .gesto .liga::after{ bottom:-1.5px; height:1.5px; background:currentColor }
html.anim .pie-titulo::after { bottom:-1px;   height:1px;   background:#2c2c2c }

/* Se nombran los dos estados —.rv-on mientras entra y .rv-listo cuando el
   script suelta la animación— con EXACTAMENTE los mismos valores. Al ser los
   mismos, el navegador no reinicia nada en el relevo: la raya sigue
   dibujándose sin cortarse. */
html.anim .gesto .liga.rv-on::after,
html.anim .gesto .liga.rv-listo::after,
html.anim .pie-titulo.rv-on::after,
html.anim .pie-titulo.rv-listo::after{
  animation:traza-canto .52s cubic-bezier(.22,.68,0,1) forwards;
  animation-delay:calc(var(--rv-d,0s) + .24s);
}
@keyframes traza-canto{ from{transform:scaleX(0)} to{transform:scaleX(1)} }

/* --- 10. MOVIMIENTO REDUCIDO ---------------------------------------------
   Quien lo pide ve la página quieta y COMPLETA. Nada puede quedar en cero.
   Se nombran también los estados nuevos: .rv-listo, las rayas dibujadas, el
   latido de las nubes y la chispa. */
@media (prefers-reduced-motion:reduce){
  html.anim .rv,
  html.anim .rv-on,
  html.anim .rv-listo{ opacity:1 !important; transform:none !important; animation:none !important }
  html.anim .hero-capas img,
  html.anim .nube-esquina,
  html.anim .nube,
  html.anim .tablero .foto-nube,
  html.anim .chispa svg,
  html.anim .btn-dona svg{ animation:none !important; transform:none !important }
  html.anim .detalle[open] > ul,
  html.anim .detalle[open] li,
  html.anim .detalle[open] summary::after{ opacity:1 !important; transform:none !important; animation:none !important }
  /* La raya se queda dibujada entera, que es su estado final. */
  html.anim .gesto .liga::after,
  html.anim .pie-titulo::after{ transform:none !important; animation:none !important }
  .btn,.tile,.tile > div,.foto-nube img,.persona .retrato,.detalle summary{ transition:none !important }
}
