/* ═══ LA CAPA VIAJA CON LA HOJA ════════════════════════════════════════════════
   Esta hoja declara su @layer acá adentro, así es inmune a cómo se la cargue:
   por <link> sin capa, lo no-capado le ganaría a todo lo capado. Por eso el
   <head> puede usar <link> (paralelo, y un fallo se ve en Network) en vez de
   @import (serial, bloquea el render y si falla se pierde en silencio).
   ═════════════════════════════════════════════════════════════════════════ */
@layer lib {
/* ═══════════════════════════════════════════════════════════════════════════════════════════════
 * mx-effects.css — el contrato de efectos del kit.
 *
 * El vocabulario fx-*, elev-* y motion-* CANÓNICO, SHIPPEADO con el kit (viaja en _content/MxLite.Framework.UI.Cx/) y cargado
 * en @layer lib → disponible en TODO preview/app, con o SIN skin. Antes vivía fragmentado en 3 lugares
 * (0-core/MxLite.Core/css/effects.css que NO viaja, aurora/skin.css que solo existe con ese skin, y un fx-sheen
 * duplicado) → una clase como fx-lift/fx-glass DESAPARECÍA en silencio fuera del skin aurora. Ahora es contrato.
 *
 * REGLA: las utilidades leen tokens con FALLBACK brand-aware (color-mix sobre --mx-color-primary) → se re-tiñen
 * con el brand activo. Los SKINS pueden PISAR esos tokens (--mx-glow-primary, --mx-glass-bg, --mx-elevation-*),
 * NO redefinir las clases. Los @keyframes (fx-aurora-spin, fx-comal-rise, cx-marquee) viven en Az/components.css.
 * ═══════════════════════════════════════════════════════════════════════════════════════════════ */

/* Esta hoja no define tokens de efecto, sólo clases.
   Los valores de --mx-glow-*, --mx-glass-*, --mx-elevation-* y --mx-grain-opacity viven en UNA casa:
   color/theme-recipes.css (los emite ColorEngine.EmitRichTokens por tema, brand-aware). Acá había una
   copia con VALORES DIVERGENTES (glow 45%↔35%, blur 10px↔8px) que ganaba o perdía según la cascada —
   diseñar contra un dado. ContratosSsotTests fija que esta hoja no vuelva a declarar esos tokens. */

/* ── ELEVACIÓN (opt-in por clase; mapea a las sombras reales del tema) ─────────────────────────── */
.elev-0{box-shadow:var(--mx-elevation-0)}
.elev-1{box-shadow:var(--mx-elevation-1)}
.elev-2{box-shadow:var(--mx-elevation-2)}
.elev-3{box-shadow:var(--mx-elevation-3)}
.elev-4{box-shadow:var(--mx-elevation-4)}
.elev-5{box-shadow:var(--mx-elevation-5)}

/* ── GLOW (halo del rol) ───────────────────────────────────────────────────────────────────────── */
.fx-glow{box-shadow:var(--mx-glow-primary)}
.fx-glow-success{box-shadow:var(--mx-glow-success)}
.fx-glow-danger{box-shadow:var(--mx-glow-danger)}
.fx-glow-info{box-shadow:var(--mx-glow-info)}

/* ── GRADIENTES / MESH / AURORA (superficies) ──────────────────────────────────────────────────── */
.fx-gradient{background:var(--mx-gradient-primary)}
.fx-gradient-2{background:var(--mx-gradient-secondary, var(--mx-gradient-primary))}
.fx-gradient-text{background:var(--mx-gradient-primary);-webkit-background-clip:text;background-clip:text;color:transparent}
.fx-mesh{background:var(--mx-gradient-mesh, var(--mx-gradient-primary))}
.fx-aurora{background:var(--mx-gradient-aurora, var(--mx-gradient-primary))}
.fx-aurora-live{animation:fx-aurora-spin 34s linear infinite}

/* ── GLASS (vidrio esmerilado, brand-aware) ────────────────────────────────────────────────────── */
.fx-glass{
  background:var(--mx-glass-bg);
  backdrop-filter:var(--mx-glass-blur);-webkit-backdrop-filter:var(--mx-glass-blur);
  border:var(--mx-glass-border);
  box-shadow:var(--mx-glass-shadow);
}

/* ── SHEEN (velo superior sutil) + GRAIN (textura fractal) ─────────────────────────────────────── */
.fx-sheen{position:relative;background-image:var(--mx-color-surface-grad,linear-gradient(180deg,rgba(255,255,255,.12),transparent 45%))}
.fx-grain{position:relative}
.fx-grain::after{content:'';position:absolute;inset:0;pointer-events:none;opacity:var(--mx-grain-opacity);mix-blend-mode:overlay;
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")}

/* ── MOVIMIENTO (hover-lift premium + pop al click) ────────────────────────────────────────────── */
.fx-lift{transition:transform var(--mx-dur-2,.18s) var(--mx-ease-emphasized,cubic-bezier(.2,.8,.2,1)),
  box-shadow var(--mx-dur-2,.18s) var(--mx-ease-emphasized,ease)}
.fx-lift:hover{transform:translateY(-6px);box-shadow:var(--mx-elevation-5),var(--mx-glow-primary)}
.motion-pop{transition:transform var(--mx-dur-1,120ms) ease}
.motion-pop:active{transform:scale(.97)}

/* PARALLAX al scroll (scroll-driven, sin JS) — @keyframes en Az/components.css */
@supports (animation-timeline: scroll()){
  .fx-parallax-slow{animation:fx-comal-rise linear both;animation-timeline:scroll(root block);animation-range:0 130vh;will-change:transform}
  .fx-parallax-mid{animation:fx-comal-rise-mid linear both;animation-timeline:scroll(root block);animation-range:0 130vh;will-change:transform}
}

/* accesibilidad: sin movimiento si el usuario lo pidió */
@media (prefers-reduced-motion: reduce){
  .fx-aurora-live,.fx-parallax-slow,.fx-parallax-mid{animation:none}
  .fx-lift,.motion-pop{transition:none}
}

/* ── FONDOS VIVOS · animación de fondo declarativa, gateada por Temperamento ─────────────────────────
 * La intención viaja como class="mxa mxa-{efecto}" + custom-props --mxa-* en el SVG inline de .mx-bg-decor
 * (los emite PatronRender); la física vive acá, una vez. El dial Temperamento escala duración ×
 * --mx-anim-dur-mult y amplitud × --mx-anim-amp. Sólo transform/opacity (compositor). Por default quieto:
 * sin gating (Dials.Gating) un tema queda estático. */
:root{ --mx-anim-play:paused; --mx-anim-dur-mult:1; --mx-anim-amp:0 }
.mx-bg-decor .mxa{
  transform-box:fill-box; transform-origin:center;
  animation-play-state:var(--mx-anim-play);
  animation-duration:calc(var(--mxa-dur,20s) * var(--mx-anim-dur-mult));
  animation-delay:var(--mxa-delay,0s);
  animation-timing-function:ease-in-out;
  animation-iteration-count:infinite;
}
.mx-bg-decor .mxa-deriva  { animation-name:mxa-deriva }
.mx-bg-decor .mxa-pulso   { animation-name:mxa-pulso }
.mx-bg-decor .mxa-giro    { animation-name:mxa-giro; animation-timing-function:linear }
.mx-bg-decor .mxa-ola     { animation-name:mxa-ola }
.mx-bg-decor .mxa-parpadeo{ animation-name:mxa-parpadeo }
.mx-bg-decor .mxa-ascenso { animation-name:mxa-ascenso; animation-timing-function:linear }

/* amplitud efectiva = --mxa-amp (del motivo, por instancia) × --mx-anim-amp (del dial). En g0-2 el dial
 * pone --mx-anim-amp:0 y el transform computa a 0 (doble candado con play-state:paused). */
@keyframes mxa-deriva{
  0%,100%{ transform:translate(0,0) }
  33%{ transform:translate(calc(6% * var(--mxa-amp,1) * var(--mx-anim-amp)), calc(-5% * var(--mxa-amp,1) * var(--mx-anim-amp))) }
  66%{ transform:translate(calc(-5% * var(--mxa-amp,1) * var(--mx-anim-amp)), calc(4% * var(--mxa-amp,1) * var(--mx-anim-amp))) }
}
@keyframes mxa-pulso{
  0%,100%{ transform:scale(1) }
  50%{ transform:scale(calc(1 + .06 * var(--mxa-amp,1) * var(--mx-anim-amp))) }
}
@keyframes mxa-giro{ from{ transform:rotate(0) } to{ transform:rotate(360deg) } }
@keyframes mxa-ola{
  0%,100%{ transform:scaleY(1) }
  50%{ transform:scaleY(calc(1 + .08 * var(--mxa-amp,1) * var(--mx-anim-amp))) }
}
/* parpadeo: piso de opacidad (sutil siempre): nunca sube a 1, y frecuencia ≤ 0.5 Hz por la dur del motivo */
@keyframes mxa-parpadeo{
  0%,100%{ opacity:.06 }
  50%{ opacity:calc(.06 + .05 * var(--mxa-amp,1) * var(--mx-anim-amp)) }
}
/* ascenso: la capa nace bajo el lienzo (cy>100, recortada por el viewBox) y sube en línea recta hasta salir por
 * arriba, fundiéndose en las puntas: el loop no tiene salto. La opacidad va horneada acá (animar opacity pisa el
 * atributo del elemento): crucero .12 × --mx-anim-amp. Doble candado: play-state paused + amp 0 → opacity 0,
 * aunque un retraso negativo lo pause en pleno vuelo. Con reduced-motion queda en su posición del yaml, fuera del
 * viewBox (invisible). Distancia -130 unidades × amplitud: toda burbuja cruza el lienzo entero. */
@keyframes mxa-ascenso{
  0%{ transform:translateY(0); opacity:0 }
  10%{ opacity:calc(.12 * var(--mx-anim-amp)) }
  90%{ opacity:calc(.12 * var(--mx-anim-amp)) }
  100%{ transform:translateY(calc(-130px * var(--mxa-amp,1))); opacity:0 }
}

/* LA LEY: reducir movimiento apaga todo el sistema de fondos vivos con una regla */
@media (prefers-reduced-motion: reduce){
  .mx-bg-decor .mxa{ animation:none !important }
}
}
