/* ── Componente Aura ─────────────────────────────────────────────────────────
   Animaciones de entrada al hacer scroll. El JS solo decide CUÁNDO (pone
   `.is-show`); el QUÉ vive aquí.

   Cómo funciona
   -------------
   Cada animación es un par de estados sobre las mismas cuatro propiedades:

     estado inicial   .upaep__aura:not(.is-show)   → --upaep-aura-from-*
     estado final     .upaep__aura.is-show         → --upaep-aura-to-*  (neutro)

   Un modificador `.__<animación>` no escribe propiedades: solo redefine
   `--upaep-aura-from-transform` (y sus compañeras). Por eso una animación nueva
   son tres líneas de CSS y cero líneas de JS.

   Propiedades que ocupa Aura
   --------------------------
   `transform`, `opacity`, `filter` y `clip-path`. NO usa `translate:`, `scale:`
   ni `rotate:` — esas quedan libres a propósito, para los hover del consumidor y
   para que Mirage (paralaje) pueda actuar sobre el MISMO nodo sin pelearse:

     <img src="foto.webp" alt="" data-aura="zoom-in" data-mirage>   ← entra Y hace paralaje

   Para componer la transición con las tuyas, reutiliza la variable en vez de
   pisar el shorthand:

     transition: var(--upaep-aura-transition), border-color .25s ease;

   Variables configurables del componente (fallback a tokens globales):
--------------------------------------------------------------------------- */
.upaep__aura,
[data-aura] {
    /* tiempos */
    --upaep-aura-duration: 600ms;
    --upaep-aura-delay: 0ms;
    --upaep-aura-easing: cubic-bezier(.22, .75, .2, 1);

    /* magnitudes de las animaciones del catálogo */
    --upaep-aura-distance: 1.75rem;   /* recorrido de fade/slide */
    --upaep-aura-scale: .94;          /* escala inicial de zoom-in */
    --upaep-aura-scale-out: 1.06;     /* escala inicial de zoom-out */
    --upaep-aura-rotate: 12deg;       /* ángulo inicial de flip/rotate */
    --upaep-aura-blur: 8px;           /* desenfoque inicial de los blur */
    --upaep-aura-perspective: 1200px; /* profundidad de los flip */
    --upaep-aura-origin: 50% 50%;

    /* estado inicial (lo redefine cada modificador `.__*`) */
    --upaep-aura-from-opacity: 0;
    --upaep-aura-from-transform: none;
    --upaep-aura-from-filter: none;
    --upaep-aura-from-clip: none;

    /* estado final — neutro salvo que se pida otra cosa */
    --upaep-aura-to-opacity: 1;
    --upaep-aura-to-transform: none;
    --upaep-aura-to-filter: none;
    --upaep-aura-to-clip: none;

    /* transición componible: úsala, no la pises */
    --upaep-aura-transition:
        opacity var(--upaep-aura-duration) var(--upaep-aura-easing) var(--upaep-aura-delay),
        transform var(--upaep-aura-duration) var(--upaep-aura-easing) var(--upaep-aura-delay),
        filter var(--upaep-aura-duration) var(--upaep-aura-easing) var(--upaep-aura-delay),
        clip-path var(--upaep-aura-duration) var(--upaep-aura-easing) var(--upaep-aura-delay);
}

/*? Estado inicial. Se aplica al atributo declarativo Y a la clase que pone el
    JS: así el elemento ya nace oculto y no hay destello antes de que corra
    aura.js. Sin JS, el bloque de `prefers-reduced-motion` y el fragmento
    `<noscript>` de la documentación devuelven todo a la vista. */
.upaep__aura:not(.is-show),
[data-aura]:not(.is-show) {
    opacity: var(--upaep-aura-from-opacity);
    transform: var(--upaep-aura-from-transform);
    filter: var(--upaep-aura-from-filter);
    clip-path: var(--upaep-aura-from-clip);

    /*? Solo mientras está pendiente: sostener la capa de composición de 80
        elementos ya revelados sí se nota. */
    will-change: opacity, transform;
}

/*? La transición y el origen viven en el BLOQUE, no en el estado: la transición
    para que también se anime el repliegue (`once: false` / `mirror`), y el
    origen porque no es interpolable — si cambiara al poner `.is-show`, los
    `rotate-in` girarían alrededor del punto equivocado. */
.upaep__aura {
    transform-origin: var(--upaep-aura-origin);
    transition: var(--upaep-aura-transition);
}

.upaep__aura.is-show {
    opacity: var(--upaep-aura-to-opacity);
    transform: var(--upaep-aura-to-transform);
    filter: var(--upaep-aura-to-filter);
    clip-path: var(--upaep-aura-to-clip);
}

/*? Revelado sin animar (elementos que quedaron arriba del viewport al recargar,
    o `reveal(el, false)` desde la API). Lo pone y lo quita el JS en un frame.
    El segundo selector es para el nodo que además lleva Mirage: ahí compite con
    la regla combinada de mirage.css y necesita más especificidad. */
.upaep__aura.__no-transition,
.upaep__aura.__no-transition.upaep__mirage-media,
.upaep__aura.__no-transition.upaep__mirage {
    transition: none;
}

/*? Instancia apagada (`disable`, o el breakpoint de `disable: 'mobile'`). */
.upaep__aura.is-disabled {
    transition: none;
}

/* ── Catálogo · fade ─────────────────────────────────────────────────────────
   Desplazamiento + opacidad. El más usado y el más barato. */
.upaep__aura.__fade,
[data-aura="fade"] {
    --upaep-aura-from-transform: none;
}

.upaep__aura.__fade-up,
[data-aura="fade-up"] {
    --upaep-aura-from-transform: translate3d(0, var(--upaep-aura-distance), 0);
}

.upaep__aura.__fade-down,
[data-aura="fade-down"] {
    --upaep-aura-from-transform: translate3d(0, calc(var(--upaep-aura-distance) * -1), 0);
}

.upaep__aura.__fade-left,
[data-aura="fade-left"] {
    --upaep-aura-from-transform: translate3d(calc(var(--upaep-aura-distance) * -1), 0, 0);
}

.upaep__aura.__fade-right,
[data-aura="fade-right"] {
    --upaep-aura-from-transform: translate3d(var(--upaep-aura-distance), 0, 0);
}

.upaep__aura.__fade-up-left,
[data-aura="fade-up-left"] {
    --upaep-aura-from-transform: translate3d(calc(var(--upaep-aura-distance) * -1), var(--upaep-aura-distance), 0);
}

.upaep__aura.__fade-up-right,
[data-aura="fade-up-right"] {
    --upaep-aura-from-transform: translate3d(var(--upaep-aura-distance), var(--upaep-aura-distance), 0);
}

.upaep__aura.__fade-down-left,
[data-aura="fade-down-left"] {
    --upaep-aura-from-transform: translate3d(calc(var(--upaep-aura-distance) * -1), calc(var(--upaep-aura-distance) * -1), 0);
}

.upaep__aura.__fade-down-right,
[data-aura="fade-down-right"] {
    --upaep-aura-from-transform: translate3d(var(--upaep-aura-distance), calc(var(--upaep-aura-distance) * -1), 0);
}

/* ── Catálogo · zoom ─────────────────────────────────────────────────────────
   Escala + opacidad. Para imágenes y tarjetas con foto. */
.upaep__aura.__zoom-in,
[data-aura="zoom-in"] {
    --upaep-aura-from-transform: scale(var(--upaep-aura-scale));
}

.upaep__aura.__zoom-in-up,
[data-aura="zoom-in-up"] {
    --upaep-aura-from-transform: translate3d(0, var(--upaep-aura-distance), 0) scale(var(--upaep-aura-scale));
}

.upaep__aura.__zoom-in-down,
[data-aura="zoom-in-down"] {
    --upaep-aura-from-transform: translate3d(0, calc(var(--upaep-aura-distance) * -1), 0) scale(var(--upaep-aura-scale));
}

.upaep__aura.__zoom-out,
[data-aura="zoom-out"] {
    --upaep-aura-from-transform: scale(var(--upaep-aura-scale-out));
}

.upaep__aura.__zoom-out-up,
[data-aura="zoom-out-up"] {
    --upaep-aura-from-transform: translate3d(0, var(--upaep-aura-distance), 0) scale(var(--upaep-aura-scale-out));
}

.upaep__aura.__zoom-out-down,
[data-aura="zoom-out-down"] {
    --upaep-aura-from-transform: translate3d(0, calc(var(--upaep-aura-distance) * -1), 0) scale(var(--upaep-aura-scale-out));
}

/* ── Catálogo · slide ────────────────────────────────────────────────────────
   Solo desplazamiento, SIN opacidad, y con recorrido en % del propio elemento:
   entra "empujando" desde fuera de su caja. Pide un padre con overflow oculto. */
.upaep__aura.__slide-up,
.upaep__aura.__slide-down,
.upaep__aura.__slide-left,
.upaep__aura.__slide-right,
[data-aura="slide-up"],
[data-aura="slide-down"],
[data-aura="slide-left"],
[data-aura="slide-right"] {
    --upaep-aura-from-opacity: 1;
    --upaep-aura-slide-distance: 100%;
}

.upaep__aura.__slide-up,
[data-aura="slide-up"] {
    --upaep-aura-from-transform: translate3d(0, var(--upaep-aura-slide-distance), 0);
}

.upaep__aura.__slide-down,
[data-aura="slide-down"] {
    --upaep-aura-from-transform: translate3d(0, calc(var(--upaep-aura-slide-distance) * -1), 0);
}

.upaep__aura.__slide-left,
[data-aura="slide-left"] {
    --upaep-aura-from-transform: translate3d(calc(var(--upaep-aura-slide-distance) * -1), 0, 0);
}

.upaep__aura.__slide-right,
[data-aura="slide-right"] {
    --upaep-aura-from-transform: translate3d(var(--upaep-aura-slide-distance), 0, 0);
}

/* ── Catálogo · flip ─────────────────────────────────────────────────────────
   Giro 3D. Es el único grupo que necesita `perspective()` dentro del transform
   (la propiedad `perspective` afecta a los HIJOS, no al propio elemento). */
.upaep__aura.__flip-up,
[data-aura="flip-up"] {
    --upaep-aura-from-transform: perspective(var(--upaep-aura-perspective)) rotateX(var(--upaep-aura-rotate));
}

.upaep__aura.__flip-down,
[data-aura="flip-down"] {
    --upaep-aura-from-transform: perspective(var(--upaep-aura-perspective)) rotateX(calc(var(--upaep-aura-rotate) * -1));
}

.upaep__aura.__flip-left,
[data-aura="flip-left"] {
    --upaep-aura-from-transform: perspective(var(--upaep-aura-perspective)) rotateY(calc(var(--upaep-aura-rotate) * -1));
}

.upaep__aura.__flip-right,
[data-aura="flip-right"] {
    --upaep-aura-from-transform: perspective(var(--upaep-aura-perspective)) rotateY(var(--upaep-aura-rotate));
}

/* ── Catálogo · rotate ───────────────────────────────────────────────────────
   Giro plano con un pellizco de escala; el origen decide de dónde "cuelga". */
.upaep__aura.__rotate-in,
[data-aura="rotate-in"] {
    --upaep-aura-from-transform: rotate(var(--upaep-aura-rotate)) scale(var(--upaep-aura-scale));
}

.upaep__aura.__rotate-in-left,
[data-aura="rotate-in-left"] {
    --upaep-aura-origin: 0% 100%;
    --upaep-aura-from-transform: rotate(calc(var(--upaep-aura-rotate) * -1)) translate3d(calc(var(--upaep-aura-distance) * -1), 0, 0);
}

.upaep__aura.__rotate-in-right,
[data-aura="rotate-in-right"] {
    --upaep-aura-origin: 100% 100%;
    --upaep-aura-from-transform: rotate(var(--upaep-aura-rotate)) translate3d(var(--upaep-aura-distance), 0, 0);
}

/* ── Catálogo · blur ─────────────────────────────────────────────────────────
   `filter` no compone en la GPU tan bien como transform: úsalo en pocos
   elementos grandes (un título, una foto), no en una rejilla de 40 tarjetas. */
.upaep__aura.__blur-in,
[data-aura="blur-in"] {
    --upaep-aura-from-filter: blur(var(--upaep-aura-blur));
}

.upaep__aura.__blur-up,
[data-aura="blur-up"] {
    --upaep-aura-from-filter: blur(var(--upaep-aura-blur));
    --upaep-aura-from-transform: translate3d(0, var(--upaep-aura-distance), 0);
}

/* ── Catálogo · clip ─────────────────────────────────────────────────────────
   Cortinilla: el elemento no se mueve, se descubre. `clip-path` NO interpola
   contra `none`, así que estas variantes también fijan su estado final. */
.upaep__aura.__clip-up,
.upaep__aura.__clip-down,
.upaep__aura.__clip-left,
.upaep__aura.__clip-right,
[data-aura="clip-up"],
[data-aura="clip-down"],
[data-aura="clip-left"],
[data-aura="clip-right"] {
    --upaep-aura-from-opacity: 1;
    --upaep-aura-to-clip: inset(0 0 0 0);
}

.upaep__aura.__clip-up,
[data-aura="clip-up"] {
    --upaep-aura-from-clip: inset(100% 0 0 0);
}

.upaep__aura.__clip-down,
[data-aura="clip-down"] {
    --upaep-aura-from-clip: inset(0 0 100% 0);
}

.upaep__aura.__clip-left,
[data-aura="clip-left"] {
    --upaep-aura-from-clip: inset(0 0 0 100%);
}

.upaep__aura.__clip-right,
[data-aura="clip-right"] {
    --upaep-aura-from-clip: inset(0 100% 0 0);
}

/* ── Catálogo · none ─────────────────────────────────────────────────────────
   `none` cablea el elemento (eventos, `is-show`) pero no lo mueve ni lo atenúa:
   sirve para reaccionar a la entrada sin animar nada. Para apagar Aura de verdad
   está `disable`. */
.upaep__aura.__none,
[data-aura="none"] {
    --upaep-aura-from-opacity: 1;
    --upaep-aura-from-transform: none;
    --upaep-aura-from-filter: none;
    --upaep-aura-from-clip: none;
}

/* ── Utilidades de composición ───────────────────────────────────────────────
   Ajustes de tiempo sin pasar por el JS. Funcionan porque las opciones
   `duration`/`delay`/`easing` valen `null` por defecto: el JS solo escribe la
   variable inline si se la pides, y entonces gana ella (es lo correcto: lo
   explícito manda). Van con las dos formas del selector para que también
   apliquen al markup declarativo antes de que corra el JS. */
.upaep__aura.__delay-1, [data-aura].__delay-1 { --upaep-aura-delay: 90ms; }
.upaep__aura.__delay-2, [data-aura].__delay-2 { --upaep-aura-delay: 180ms; }
.upaep__aura.__delay-3, [data-aura].__delay-3 { --upaep-aura-delay: 270ms; }
.upaep__aura.__delay-4, [data-aura].__delay-4 { --upaep-aura-delay: 360ms; }

.upaep__aura.__fast, [data-aura].__fast { --upaep-aura-duration: 350ms; }
.upaep__aura.__slow, [data-aura].__slow { --upaep-aura-duration: 900ms; }

/*? Recorrido corto: para elementos pequeños (chips, iconos), donde 1.75rem se
    ve exagerado. */
.upaep__aura.__short, [data-aura].__short { --upaep-aura-distance: .75rem; }
.upaep__aura.__long, [data-aura].__long { --upaep-aura-distance: 3.5rem; }

/* ── Movimiento reducido ─────────────────────────────────────────────────────
   Doble red de seguridad: el JS ni observa ni esconde, y el CSS deja el estado
   final por si el elemento se marcó antes de que corriera el JS (o si el JS no
   llega a correr). El contenido NUNCA se queda invisible. */
@media (prefers-reduced-motion: reduce) {

    .upaep__aura,
    [data-aura] {
        transition: none;
    }

    .upaep__aura:not(.is-show),
    [data-aura]:not(.is-show) {
        opacity: 1;
        transform: none;
        filter: none;
        clip-path: none;
        will-change: auto;
    }
}

/* ── Responsive ──────────────────────────────────────────────────────────────
   En pantallas chicas el recorrido se acorta: el mismo desplazamiento que en
   escritorio se lee como un salto. Para apagar Aura del todo en móvil usa
   `data-aura-disable="mobile"` (o `disable: 'mobile'` desde el JS). */
@media (max-width: 768px) {

    .upaep__aura,
    [data-aura] {
        --upaep-aura-distance: 1rem;
        --upaep-aura-blur: 5px;
    }
}
