/* ============================================================
   ui.css — librería de componentes animados (vanilla, sin deps)
   Pareja de js/ui.js. Cada componente es independiente:
   podés copiar sólo su bloque CSS + su función de ui.js.
   ============================================================ */

/* ---------- 1. ScrollReveal ----------
   Uso: <div data-ui-reveal>            (por defecto: sube 24px)
        <div data-ui-reveal="left" data-ui-delay="200" data-ui-duration="900">
   Las reglas cuelgan de .ui-js (que agrega ui.js al cargar), así que
   si el JS no corre, el contenido queda visible en vez de invisible. */
.ui-js [data-ui-reveal] {
  opacity: 0;
  transform: translate3d(var(--ui-reveal-x, 0px), var(--ui-reveal-y, var(--ui-reveal-dist, 24px)), 0);
  transition:
    opacity var(--ui-reveal-dur, .8s) var(--ui-ease, cubic-bezier(.22, .61, .36, 1)) var(--ui-reveal-delay, 0ms),
    transform var(--ui-reveal-dur, .8s) var(--ui-ease, cubic-bezier(.22, .61, .36, 1)) var(--ui-reveal-delay, 0ms);
  will-change: opacity, transform;
}
.ui-js [data-ui-reveal].is-visible {
  opacity: 1;
  transform: none;
  will-change: auto;
}
/* Al terminar la entrada, ui.js quita el atributo data-ui-reveal y estas
   reglas dejan de aplicar: el elemento queda sin transform ni transition
   propias, listo para que otro componente (p. ej. HoverCard) lo use.
   La clase .is-visible se conserva por si el sitio la usa para estilar. */
/* dirección = hacia dónde viaja el elemento al aparecer */
.ui-js [data-ui-reveal="down"]  { --ui-reveal-y: calc(var(--ui-reveal-dist, 24px) * -1); }
.ui-js [data-ui-reveal="left"]  { --ui-reveal-y: 0px; --ui-reveal-x: var(--ui-reveal-dist, 24px); }
.ui-js [data-ui-reveal="right"] { --ui-reveal-y: 0px; --ui-reveal-x: calc(var(--ui-reveal-dist, 24px) * -1); }
.ui-js [data-ui-reveal="fade"]  { --ui-reveal-y: 0px; }

/* ---------- 2. CountUp ----------
   Uso: <span data-ui-countup="28" data-ui-prefix="+"></span>
   Sin estilos propios; esta clase es sólo una ayuda tipográfica opcional. */
.ui-countup {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
}

/* ---------- 3. ProgressBar ----------
   Uso: <div class="ui-progress" data-ui-progress="72"></div>
   ui.js crea el relleno interno si no existe. */
.ui-progress {
  position: relative;
  height: var(--ui-progress-h, 10px);
  border-radius: 999px;
  background: var(--ui-progress-track, rgba(0, 0, 0, .08));
  overflow: hidden;
}
.ui-progress-fill {
  display: block;
  height: 100%;
  width: 100%;
  border-radius: inherit;
  background: var(--ui-progress-fill-bg, currentColor);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--ui-progress-dur, 1s) cubic-bezier(.22, .61, .36, 1) var(--ui-progress-delay, 0ms);
}
.ui-progress.is-visible .ui-progress-fill {
  transform: scaleX(var(--ui-progress-value, 0));
}
.ui-progress-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 6px;
  font-size: .95rem;
}

/* ---------- 4. HoverCard ----------
   100% CSS. Uso: class="ui-hover-card" en cualquier tarjeta. */
.ui-hover-card {
  transition:
    transform var(--ui-hover-dur, .22s) ease-out,
    box-shadow var(--ui-hover-dur, .22s) ease-out;
}
.ui-hover-card:hover,
.ui-hover-card:focus-within {
  transform: translateY(var(--ui-hover-lift, -6px));
  box-shadow: var(--ui-hover-shadow, 0 12px 28px rgba(0, 0, 0, .14));
}

/* ---------- 5. LogoMarquee ----------
   Uso: <div class="ui-marquee" data-ui-marquee data-ui-speed="30">
          <div class="ui-marquee-track"> ...items... </div>
        </div>
   ui.js duplica el track para que el loop no corte. */
.ui-marquee {
  --ui-marquee-gap: 40px;
  overflow: hidden;
  position: relative;
  /* difuminado en los bordes para que entren y salgan sin cortar */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.ui-marquee-track {
  display: flex;
  align-items: center;
  gap: var(--ui-marquee-gap);
  width: max-content;
  padding-right: var(--ui-marquee-gap);
  will-change: transform;
}
.ui-marquee.is-running .ui-marquee-track {
  animation: ui-marquee-scroll var(--ui-marquee-dur, 30s) linear infinite;
}
.ui-marquee.is-reverse .ui-marquee-track { animation-direction: reverse; }
.ui-marquee:hover .ui-marquee-track,
.ui-marquee:focus-within .ui-marquee-track { animation-play-state: paused; }
@keyframes ui-marquee-scroll {
  from { transform: translate3d(0, 0, 0); }
  /* -50% del track duplicado, menos medio gap: sin salto al reiniciar */
  to   { transform: translate3d(calc(-50% - var(--ui-marquee-gap) / 2), 0, 0); }
}

/* ---------- 6. BackToTop ----------
   ui.js crea el botón solo, o realza uno existente con [data-ui-backtotop]. */
.ui-backtotop {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 50;
  width: 48px;
  height: 48px;
  display: grid;
  place-items: center;
  border: none;
  border-radius: 50%;
  cursor: pointer;
  font-size: 1.2rem;
  line-height: 1;
  background: var(--ui-backtotop-bg, #1b1b1b);
  color: var(--ui-backtotop-fg, #fff);
  box-shadow: 0 6px 18px rgba(0, 0, 0, .22);
  opacity: 0;
  transform: translateY(16px) scale(.9);
  pointer-events: none;
  transition: opacity .3s ease, transform .3s ease;
}
.ui-backtotop.is-visible {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}
.ui-backtotop:hover { transform: translateY(-2px); }

/* ---------- 7. StickyHeader ----------
   Uso: <header data-ui-sticky-header data-ui-threshold="30">
   Sólo agrega .is-stuck; los colores los pone cada sitio. */
[data-ui-sticky-header] {
  position: sticky;
  top: 0;
  z-index: 40;
  transition: background-color .3s ease, box-shadow .3s ease, padding .3s ease;
}
[data-ui-sticky-header].is-stuck {
  box-shadow: var(--ui-header-shadow, 0 4px 16px rgba(0, 0, 0, .1));
}


/* ---------- 8. HoverGlow ----------
   Foco de luz que sigue al cursor dentro de la tarjeta.
   Uso: class="ui-glow-card" (se combina con .ui-hover-card en el mismo nodo).
   ui.js actualiza --ui-glow-x / --ui-glow-y; el resto es CSS. */
.ui-glow-card { position: relative; }
.ui-glow-card::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  z-index: 1;
  opacity: 0;
  transition: opacity var(--ui-glow-fade, .3s) ease;
  background: radial-gradient(
    var(--ui-glow-size, 240px) circle at var(--ui-glow-x, 50%) var(--ui-glow-y, 50%),
    var(--ui-glow-color, rgba(255, 255, 255, .5)),
    transparent 68%);
}
.ui-glow-card:hover::before,
.ui-glow-card:focus-within::before { opacity: 1; }

/* ---------- 9. CategoryTransition ----------
   Envoltorio de View Transitions. El CSS sólo ajusta tiempos; los nombres
   (view-transition-name) los pone cada sitio en los elementos que quiere
   que se muevan de una vista a la otra. */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: var(--ui-vt-dur, .4s);
  animation-timing-function: cubic-bezier(.22, .61, .36, 1);
}
/* Las tarjetas nombradas se desplazan a su nueva posición en vez de
   simplemente fundirse. */
html.ui-vt-running .ui-vt-item { will-change: transform; }

/* ---------- 10. ResultConfetti ----------
   El canvas lo crea y lo borra ui.js; sólo necesita quedar por encima
   de todo y no robar clicks. */
.ui-confetti {
  position: fixed;
  inset: 0;
  z-index: 60;
  pointer-events: none;
}


/* ---------- 11. Carousel ----------
   La librería sólo se ocupa de mostrar una slide por vez y de los controles;
   la grilla interna de cada slide la define cada sitio. */
[data-ui-carousel] {
  position: relative;
  /* Clave para que el deslizar funcione en celular: le decimos al navegador
     que el eje vertical es suyo (scrollea la página como siempre) y el
     horizontal es nuestro. Sin esto se queda el gesto entero y nos manda
     un pointercancel apenas empieza el movimiento. */
  touch-action: pan-y;
}
/* Obligatorio: cualquier display que el sitio le ponga a la slide (grid,
   flex) le gana al [hidden] del navegador y se verían todas a la vez. */
.ui-slide[hidden] { display: none !important; }
.ui-slide { animation: ui-slide-in var(--ui-slide-dur, .5s) ease both; }
@keyframes ui-slide-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

.ui-carousel-btn {
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--ui-btn-border, rgba(0, 0, 0, .12));
  background: var(--ui-btn-bg, #fff);
  color: inherit;
  cursor: pointer;
  font-size: 1.1rem;
  line-height: 1;
  transition: transform .2s ease, border-color .2s ease, box-shadow .2s ease;
}
.ui-carousel-btn:hover {
  transform: scale(1.08);
  box-shadow: 0 4px 14px rgba(0, 0, 0, .12);
}

[data-ui-dots] { display: flex; gap: 7px; justify-content: center; }
.ui-dot {
  width: 8px;
  height: 8px;
  padding: 0;
  border: none;
  border-radius: 50%;
  cursor: pointer;
  background: var(--ui-dot-bg, rgba(0, 0, 0, .18));
  transition: background .25s ease, transform .25s ease;
}
.ui-dot.is-active {
  background: var(--ui-dot-active, currentColor);
  transform: scale(1.35);
}

/* ---------- 12. Glitch ----------
   Uso: UI.glitch(elemento) para un disparo, o UI.glitch(el, { duracion: 600 }).
   Sacude el elemento en diagonal, le separa los colores y le pasa lineas
   finas horizontales por encima, como una pantalla con interferencia.

   Se aplica al elemento que se quiere romper, no a su contenedor: sirve
   tanto para una frase suelta como para una tarjeta o un titulo.

   Variables: --ui-glitch-dur (duracion), --ui-glitch-linea (color de
   las lineas), --ui-glitch-hueco (separacion entre lineas) y
   --ui-glitch-grosor. */
:where(.ui-glitch) { position: relative; }

.ui-glitch.is-glitching {
  animation: ui-glitch-sacudida var(--ui-glitch-dur, 460ms) steps(1, end);
  /* Separacion de color: sin esto, sobre un fondo claro la sacudida sola
     casi no se lee. */
  text-shadow:
     3px 0 rgba(214, 40, 90, .55),
    -3px 0 rgba(0, 168, 214, .55);
}

/* Modo solo lineas: la interferencia sin la sacudida. Sirve para pasarla
   por encima de un area grande (un fondo, una seccion entera) mientras
   otra cosa se sacude.

   VA DESPUES de la regla de arriba a proposito: las dos tienen la misma
   especificidad (dos clases), asi que la que gana es la ultima. Puesta
   antes no anulaba nada y el area entera se sacudia igual. */
.ui-glitch--lineas.is-glitching {
  animation: none;
  text-shadow: none;
}

/* Las lineas finas. Van en un ::after encima del elemento y bajan despacio,
   asi la interferencia se mueve en vez de quedar como una textura pegada. */
.ui-glitch.is-glitching::after {
  content: "";
  position: absolute;
  inset: -3px -6px;
  pointer-events: none;
  background: repeating-linear-gradient(
    to bottom,
    transparent 0 var(--ui-glitch-hueco, 3px),
    var(--ui-glitch-linea, rgba(20, 30, 40, .45))
      var(--ui-glitch-hueco, 3px)
      calc(var(--ui-glitch-hueco, 3px) + var(--ui-glitch-grosor, 1px))
  );
  animation: ui-glitch-lineas var(--ui-glitch-dur, 460ms) linear;
}

/* Saltos bruscos a proposito: con steps(1, end) salta de posicion en
   posicion en vez de deslizarse, que es lo que lo hace leer como una
   falla y no como una animacion. */
@keyframes ui-glitch-sacudida {
  0%   { transform: translate(0, 0) skewX(0); }
  10%  { transform: translate(-13px, -7px) skewX(-12deg); }
  22%  { transform: translate(10px,   6px) skewX(9deg); }
  33%  { transform: translate(-7px,   9px) skewX(-5deg); }
  45%  { transform: translate(16px, -10px) skewX(14deg); }
  57%  { transform: translate(-11px,  5px) skewX(-8deg); }
  68%  { transform: translate(6px,   -8px) skewX(6deg); }
  79%  { transform: translate(-9px,   3px) skewX(-4deg); }
  90%  { transform: translate(4px,    4px) skewX(2deg); }
  100% { transform: translate(0, 0) skewX(0); }
}

/* Bloques: rectangulos finos sueltos, repartidos al azar por todo el area.
   Las lineas finas son textura; estos son el golpe. Los crea ui.js porque
   cada uno necesita posicion, ancho y tiempo propios. */
.ui-glitch-bloques {
  position: absolute;
  inset: 0;
  overflow: hidden;      /* que ninguno se escape del area */
  pointer-events: none;
}
.ui-glitch-bloque {
  position: absolute;
  background: var(--ui-glitch-bloque, currentColor);
  animation: ui-glitch-bloque var(--ui-glitch-dur, 460ms) steps(1, end);
  opacity: 0;
}

@keyframes ui-glitch-bloque {
  0%   { opacity: 0;   transform: translateX(0); }
  18%  { opacity: .85; transform: translateX(-18px); }
  40%  { opacity: .45; transform: translateX(12px); }
  62%  { opacity: .8;  transform: translateX(-8px); }
  84%  { opacity: .3;  transform: translateX(5px); }
  100% { opacity: 0;   transform: translateX(0); }
}

/* Las lineas bajan y ademas parpadean: quedan mas presentes al principio,
   que es cuando la sacudida es mas fuerte. */
@keyframes ui-glitch-lineas {
  0%   { transform: translateY(-3px); opacity: .95; }
  50%  { transform: translateY(2px);  opacity: .6; }
  100% { transform: translateY(6px);  opacity: 0; }
}

/* ---------- Accesibilidad: sin movimiento ---------- */
@media (prefers-reduced-motion: reduce) {
  .ui-js [data-ui-reveal] {
    opacity: 1;
    transform: none;
    transition: none;
  }
  .ui-progress-fill {
    transition: none;
    transform: scaleX(var(--ui-progress-value, 0));
  }
  .ui-hover-card { transition: none; }
  .ui-marquee.is-running .ui-marquee-track { animation: none; }
  .ui-backtotop { transition: none; }
  [data-ui-sticky-header] { transition: none; }
  /* Sin foco de luz, sin transición entre vistas y sin confeti:
     ui.js además ni engancha los listeners ni dibuja el canvas. */
  .ui-glow-card::before { display: none; }
  /* El carrusel no rota solo (lo decide ui.js) y las slides no entran animadas. */
  .ui-slide { animation: none; }
  .ui-carousel-btn, .ui-dot { transition: none; }
  /* El glitch no se sacude ni le pasan las lineas (ui.js ademas ni siquiera
     le pone la clase). */
  .ui-glitch.is-glitching { animation: none; text-shadow: none; }
  .ui-glitch.is-glitching::after { display: none; }
  .ui-glitch-bloques { display: none; }
  ::view-transition-old(root),
  ::view-transition-new(root) { animation: none; }
}
