/* ============================================================================
   THE TEEPEE · capa de movimiento
   ----------------------------------------------------------------------------
   Tokens y mecanismos de las secciones. Se carga DESPUÉS del CSS del sitio:
   no redefine color ni tipografía, solo movimiento.

   Los valores no son de gusto: salen de siete webs medidas en vivo el
   27-08-2026 (Vero Studio, Léo Parpeix, Longbow, Veo, Emons, Graham McDonnell,
   Cooldock). Doctrina y origen de cada número:
   COACH/_SISTEMAS/BIBLIA-DISENO/capitulos/12-gramatica-del-movimiento.md
   ========================================================================= */

:root{
  /* --- duración. Máximo 4 valores por proyecto (12.3) --- */
  --mo-fast:   125ms;   /* hover, foco */
  --mo-base:   250ms;   /* reveals, cards */
  --mo-menu:   300ms;   /* menús, paneles */
  --mo-page:   450ms;   /* transición mayor */

  /* --- curvas. Las dos primeras son la firma medida del lote de referencias --- */
  --mo-ref:    cubic-bezier(.16, 1, .3, 1);      /* Longbow */
  --mo-ref-2:  cubic-bezier(.165, .84, .44, 1);  /* Veo y Emons */
  --mo-enter:  cubic-bezier(.05, .7, .1, 1);     /* Material 3 emphasized decelerate */
  --mo-exit:   cubic-bezier(.3, 0, .8, .15);

  /* --- distancias de revelado. Medidas: 10-30 px, NUNCA 40+ (12.x) --- */
  --mo-reveal-corto: 10px;   /* Longbow */
  --mo-reveal-medio: 24px;   /* Veo */
  --mo-reveal-largo: 30px;   /* Cooldock, el tope */

  /* --- el bronce que sí pasa AA sobre crema (5.8:1). El dorado da 1.6-2.4:1 --- */
  --acento-legible: #6F520F;
}

/* ===========================================================================
   1 · REVELADO AL ENTRAR EN PANTALLA
   El estado oculto lo pone .js, que añade un <script> síncrono en el <head>.
   Sin JS no hay .js y el contenido se ve entero: degradación segura, no
   página en blanco. Y al ir en el head llega antes del primer pintado, así
   que tampoco parpadea. (BIBLIA-DISENO 20.14 / 20.18)
   ======================================================================== */
.js [data-rev]{
  opacity: 0;
  transform: translateY(var(--mo-reveal-medio));
}
[data-rev]{
  /* La opacidad va POR DELANTE del desplazamiento: cuando el elemento está a
     mitad de camino ya se ve al 75-90%. Llega visible y luego se coloca.
     Medido en Veo y Longbow. Por eso la opacidad dura menos que el transform. */
  transition:
    opacity   calc(var(--mo-base) * .7) var(--mo-ref),
    transform var(--mo-base)            var(--mo-ref);
}
[data-rev].dentro{ opacity: 1; transform: none; }

/* Stagger: 40 ms por elemento con tope de 400 ms, porque el bucle del CMS
   puede devolver 6 tarjetas o 40 y nadie lo probó con 40. (12.9) */
[data-rev]{ transition-delay: min(calc(var(--i, 0) * 40ms), 400ms); }

/* ===========================================================================
   2 · EL HERO QUE RESPIRA — Longbow
   1,5% de zoom y 11 px de deriva a lo largo de TODO el scroll. Imperceptible
   de un vistazo, constante al mirarlo. Es la diferencia entre una foto pegada
   y una foto viva, y no le roba el sitio al texto.
   ======================================================================== */
.respira{
  --p: 0;                                   /* 0 → 1, lo escribe el JS */
  transform: scale(calc(1.0435 + var(--p) * .0152))
             translateX(calc(-12.26px + var(--p) * 11.25px));
  transform-origin: 50% 45%;
  will-change: transform;                   /* solo mientras es visible, lo quita el JS */
}

/* ===========================================================================
   3 · APERTURA DE ENCUADRE — Vero Studio
   La imagen crece Y su recorte se abre a la vez. El recorte de partida NO está
   centrado: va de 55% a 95% en vertical, pegado abajo, así que al abrirse la
   foto PARECE SUBIR. Un inset() simétrico da la misma geometría y no produce
   esa sensación. Ese matiz es todo el mecanismo.
   ======================================================================== */
.encuadre{
  --p: 0;
  transform: scale(calc(.5 + var(--p) * .5));
  clip-path: polygon(
    calc(30% - var(--p) * 30%) calc(55% - var(--p) * 55%),
    calc(70% + var(--p) * 30%) calc(55% - var(--p) * 55%),
    calc(70% + var(--p) * 30%) calc(95% + var(--p) * 5%),
    calc(30% - var(--p) * 30%) calc(95% + var(--p) * 5%)
  );
  will-change: transform, clip-path;
}

/* ===========================================================================
   4 · PILA STICKY A PANTALLA COMPLETA — Vero
   "así en pequeño no me gusta": ocupa la pantalla entera.
   El aterrizaje divide por ~12 en cada paso: ease-out exponencial, sin rebote.
   ======================================================================== */
.pila{ position: relative; }
.pila__item{
  position: sticky;
  top: 0;
  height: 100dvh;
  overflow: hidden;
}

/* ===========================================================================
   5 · MARQUESINAS ENFRENTADAS — Veo
   Dos filas en sentidos opuestos y a velocidades DISTINTAS (~62 y ~55 px/paso).
   Que no vayan a la misma velocidad es la mitad del efecto.
   Con control de pausa: WCAG 2.2.2 exige poder parar todo bucle de más de 5 s.
   ======================================================================== */
.tira{ overflow: hidden; -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); }
.tira__pista{ display: flex; gap: 1rem; width: max-content; animation: correr var(--dur, 60s) linear infinite; }
.tira--vuelta .tira__pista{ animation-direction: reverse; }
.tira:hover .tira__pista,
.tira:focus-within .tira__pista,
.tira[data-parada="si"] .tira__pista{ animation-play-state: paused; }
@keyframes correr{ to{ transform: translateX(-50%); } }

/* ===========================================================================
   6 · EL BOTÓN CON TRES DURACIONES — Longbow
   Fondo .5s, borde .35s, texto .3s. El texto cambia ANTES que el fondo, y eso
   es lo que hace que el botón se sienta sólido y no plano.
   ======================================================================== */
.boton-solido{
  background-image: linear-gradient(90deg, var(--acento-legible) 50%, transparent 50%);
  background-size: 200% 100%;
  background-position: 100% 0;
  transition:
    background-position .5s  var(--mo-ref),
    border-color        .35s var(--mo-ref),
    color               .3s  var(--mo-ref);
}
.boton-solido:hover,
.boton-solido:focus-visible{ background-position: 0 0; color: var(--crema, #F5EFE3); }
.boton-solido:active{ transform: scale(.97); }  /* anticipación (12.7) */

/* ===========================================================================
   7 · HOVER DESENFOCADO — Graham McDonnell
   La palabra ENTRA desde scale(1.1), -20 px y blur(4px), y aterriza nítida.
   El desenfoque es lo que hace que parezca LLEGAR en vez de encenderse.
   Y la otra mitad, que casi nadie copia: los no señalados viven al 80%.
   El contraste lo hace el conjunto, no el elemento.
   ======================================================================== */
.menu-vivo:hover .menu-vivo__enlace{ opacity: .8; }
.menu-vivo__enlace{ position: relative; opacity: 1; transition: opacity var(--mo-fast) var(--mo-ref); }
.menu-vivo:hover .menu-vivo__enlace:hover{ opacity: 1; }
.menu-vivo__eco{
  position: absolute; inset: 0; pointer-events: none;
  opacity: 0; filter: blur(4px);
  transform: translateX(-20px) scale(1.1);
  transition: opacity var(--mo-menu) var(--mo-ref), filter var(--mo-menu) var(--mo-ref), transform var(--mo-menu) var(--mo-ref);
}
.menu-vivo__enlace:hover .menu-vivo__eco,
.menu-vivo__enlace:focus-visible .menu-vivo__eco{ opacity: .8; filter: blur(0); transform: none; }

/* ===========================================================================
   8 · ENTRAR GIRADO Y AL DOBLE — Emons
   scale 1.93 + rotación 15°, aterriza recto. Escala y rotación se resuelven a
   la vez: es ACOPLAMIENTO. Un translateY suelto es el gesto que se rechazó
   once veces de once, y resulta ser el revelado por defecto de Framer.
   ======================================================================== */
.js [data-gira]{ opacity: 0; transform: scale(1.93) rotate(15deg); }
[data-gira]{ transition: opacity var(--mo-page) var(--mo-ref-2), transform var(--mo-page) var(--mo-ref-2); }
[data-gira].dentro{ opacity: 1; transform: none; }

/* ===========================================================================
   9 · CUE DE SCROLL SINUSOIDAL — Longbow
   ±4 px y opacidad de 0.35 a 1, en bucle. Un translateY seco no da esto.
   ======================================================================== */
.cue{ animation: respirar 2.8s ease-in-out infinite; }
@keyframes respirar{
  0%, 100%{ transform: translateY(4px);  opacity: .35; }
  50%     { transform: translateY(-4px); opacity: 1;   }
}

/* ===========================================================================
   ACCESIBILIDAD
   No se apaga todo a martillazos: se conserva la aparición (comunica de dónde
   sale cada cosa) y se elimina el recorrido, el zoom y los bucles, que son los
   que disparan el malestar vestibular. (BIBLIA-DISENO cap. 21)
   ======================================================================== */
@media (prefers-reduced-motion: reduce){
  .js [data-rev],
  .js [data-gira]{ transform: none; }
  [data-rev], [data-gira]{ transition: opacity 150ms linear; transition-delay: 0ms; }
  .respira, .encuadre{ transform: none; clip-path: none; }
  .tira__pista{ animation: none; }
  .cue{ animation: none; opacity: .8; }
  .boton-solido{ transition-duration: 120ms; }
}
