/* ==========================================================================
   Biblioteca de efectos — CSS base. Se copia a la web y se adapta con variables.
   No define colores ni fuentes de marca: usa las variables de la web
   (--c-fondo, --c-tinta, --c-marca, --c-acento, --f-display, --f-texto) con valores de respaldo.
   Catálogo y cuándo usar cada uno: references/efectos.md
   ========================================================================== */

/* ---------- Apariciones ligadas al scroll (CSS nativo; sin soporte -> efectos.js añade .sin-sdt + IO) ---------- */
@supports (animation-timeline: view()) {
  .revela        { animation: ef-sube linear both;    animation-timeline: view(); animation-range: entry 5% cover 28%; }
  .revela-izq    { animation: ef-izq linear both;     animation-timeline: view(); animation-range: entry 5% cover 30%; }
  .revela-escala { animation: ef-escala linear both;  animation-timeline: view(); animation-range: entry 0% cover 35%; }
  .revela-clip > img, .revela-clip > picture, .revela-clip > video {
    animation: ef-desclip linear both; animation-timeline: view(); animation-range: entry 0% cover 45%;
  }
  .revela-cortina { animation: ef-cortina linear both; animation-timeline: view(); animation-range: entry 10% cover 40%; }
}
@keyframes ef-sube    { from { opacity: 0; translate: 0 50px; } }
@keyframes ef-izq     { from { opacity: 0; translate: -60px 0; } }
@keyframes ef-escala  { from { opacity: 0; scale: .85; } }
@keyframes ef-desclip { from { clip-path: inset(14% 10% 14% 10% round 60px); scale: 1.12; } to { clip-path: inset(0 round var(--r, 0px)); scale: 1; } }
@keyframes ef-cortina { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }

.sin-sdt .revela, .sin-sdt .revela-izq, .sin-sdt .revela-escala {
  opacity: 0; transition: opacity .8s, translate .9s cubic-bezier(.2, .9, .2, 1), scale .9s cubic-bezier(.2, .9, .2, 1);
}
.sin-sdt .revela { translate: 0 40px; }
.sin-sdt .revela-izq { translate: -50px 0; }
.sin-sdt .revela-escala { scale: .88; }
.sin-sdt .vista.revela, .sin-sdt .vista.revela-izq, .sin-sdt .vista.revela-escala { opacity: 1; translate: 0 0; scale: 1; }
.sin-sdt .revela-clip > img, .sin-sdt .revela-clip > picture { clip-path: inset(10% 8% 10% 8% round 60px); transition: clip-path 1.1s cubic-bezier(.6, 0, .2, 1); }
.sin-sdt .revela-clip.vista > img, .sin-sdt .revela-clip.vista > picture { clip-path: inset(0 round var(--r, 0px)); }
.sin-sdt .revela-cortina { clip-path: inset(0 100% 0 0); transition: clip-path 1s cubic-bezier(.7, 0, .2, 1); }
.sin-sdt .revela-cortina.vista { clip-path: inset(0 0 0 0); }

/* ---------- Escena fija con progreso (--p 0..1 lo pone efectos.js) ----------
   <section class="escena" data-escena style="--alto:300vh"><div class="escena__fija">…</div></section>
   Dentro, cualquier cosa puede usar calc(var(--p) * …). Tramos útiles: --t1 = primer 30 %, etc. */
.escena { --p: 0; position: relative; height: var(--alto, 300vh); }
.escena__fija { position: sticky; top: 0; height: 100vh; height: 100svh; overflow: hidden; }
.escena {
  --t1: clamp(0, var(--p) / .3, 1);
  --t2: clamp(0, (var(--p) - .3) / .35, 1);
  --t3: clamp(0, (var(--p) - .65) / .35, 1);
}

/* ---------- Cinta con inercia (data-cinta) ---------- */
.cinta { overflow: hidden; white-space: nowrap; }
.cinta__pista { display: flex; width: max-content; will-change: transform; }
.cinta__pista > * { flex: none; }

/* ---------- Texto partido (data-texto="lineas|palabras|letras") ---------- */
[data-texto] .ef-u { display: inline-block; }
[data-texto] .ef-m { display: inline-block; overflow: hidden; vertical-align: top; padding-bottom: .06em; margin-bottom: -.06em; }
[data-texto] .ef-u { translate: 0 110%; rotate: 4deg; transition: translate .9s cubic-bezier(.2, .9, .2, 1), rotate .9s cubic-bezier(.2, .9, .2, 1); transition-delay: calc(var(--i, 0) * var(--paso, 40ms)); }
[data-texto].vista .ef-u { translate: 0 0; rotate: 0deg; }
[data-texto="letras"] { --paso: 22ms; }
[data-texto="lineas"] { --paso: 90ms; }

/* ---------- Botón con relleno que sube (clase .ef-relleno) ---------- */
.ef-relleno { position: relative; overflow: hidden; isolation: isolate; transition: color .35s; }
.ef-relleno::before {
  content: ""; position: absolute; inset: 0; z-index: -1; background: var(--relleno, var(--c-acento, #ffd23f));
  clip-path: circle(0% at 50% 120%); transition: clip-path .5s cubic-bezier(.6, 0, .2, 1);
}
.ef-relleno:hover::before, .ef-relleno:focus-visible::before { clip-path: circle(150% at 50% 120%); }

/* ---------- Foco que sigue al puntero (data-foco pone --mx/--my) ---------- */
.ef-foco { position: relative; isolation: isolate; }
.ef-foco::after {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none; border-radius: inherit; opacity: 0; transition: opacity .3s;
  background: radial-gradient(380px circle at var(--mx, 50%) var(--my, 50%), var(--foco, rgba(255, 255, 255, .18)), transparent 60%);
}
.ef-foco:hover::after { opacity: 1; }

/* ---------- Máscara que revela una segunda imagen bajo el puntero (data-mascara) ---------- */
.ef-mascara { position: relative; overflow: hidden; }
.ef-mascara > :last-child {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  -webkit-mask-image: radial-gradient(circle var(--radio, 0px) at var(--mx, 50%) var(--my, 50%), #000 98%, transparent 100%);
  mask-image: radial-gradient(circle var(--radio, 0px) at var(--mx, 50%) var(--my, 50%), #000 98%, transparent 100%);
}

/* ---------- Galería horizontal fija (data-horizontal) ---------- */
.ef-horizontal { position: relative; }
.ef-horizontal__fija { position: sticky; top: 0; height: 100vh; height: 100svh; overflow: hidden; display: flex; align-items: center; }
.ef-horizontal__pista { display: flex; gap: var(--hueco, 24px); padding-inline: var(--marge, 24px); will-change: transform; }
.ef-horizontal__pista > * { flex: none; }
@media (max-width: 760px) { /* en móvil: carrusel nativo con dedo, sin fijar */
  .ef-horizontal { height: auto !important; }
  .ef-horizontal__fija { position: static; height: auto; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; }
  .ef-horizontal__pista { transform: none !important; }
  .ef-horizontal__pista > * { scroll-snap-align: center; }
}

/* ---------- Trazo SVG que se dibuja (data-trazo; efectos.js pone --largo y --t) ---------- */
[data-trazo] path, [data-trazo] line, [data-trazo] polyline, [data-trazo] circle, [data-trazo] rect {
  stroke-dasharray: var(--largo, 1000); stroke-dashoffset: calc(var(--largo, 1000) * (1 - var(--t, 0)));
}

/* ---------- Transición circular entre estados (Efectos.transicionCircular) ---------- */
::view-transition-old(root) { animation: none; }
::view-transition-new(root) { animation: ef-circulo .85s cubic-bezier(.7, 0, .2, 1); }
@keyframes ef-circulo {
  from { clip-path: circle(0 at var(--vt-x, 50%) var(--vt-y, 50%)); }
  to   { clip-path: circle(150vmax at var(--vt-x, 50%) var(--vt-y, 50%)); }
}

/* ---------- Grano de papel / película (clase en <body>: .ef-grano) ---------- */
.ef-grano::after {
  content: ""; position: fixed; inset: 0; z-index: 90; pointer-events: none; opacity: var(--grano, .07); mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---------- Cursor propio (cursor.js; solo con ratón) ---------- */
.ef-cursor { position: fixed; left: 0; top: 0; z-index: 999; pointer-events: none; width: 14px; height: 14px; margin: -7px 0 0 -7px; border-radius: 50%;
  background: var(--cursor, #fff); mix-blend-mode: difference; transition: width .3s, height .3s, margin .3s; display: grid; place-items: center; }
.ef-cursor span { font: 600 12px/1 var(--f-texto, system-ui); color: #000; opacity: 0; transition: opacity .2s; white-space: nowrap; }
.ef-cursor.grande { width: 84px; height: 84px; margin: -42px 0 0 -42px; }
.ef-cursor.grande span { opacity: 1; }
@media (hover: none), (pointer: coarse) { .ef-cursor { display: none; } }

/* ---------- Fondo WebGL (fondo-gl.js): respaldo si no hay WebGL ---------- */
.ef-fondo-gl { position: absolute; inset: 0; z-index: -1; overflow: hidden;
  background: radial-gradient(60% 80% at 20% 30%, var(--gl-1, #6d5dfc), transparent), radial-gradient(60% 80% at 80% 70%, var(--gl-2, #ff7a59), transparent), var(--gl-3, #111); }
.ef-fondo-gl canvas { width: 100%; height: 100%; display: block; }

/* ---------- Movimiento reducido: todo quieto y visible ---------- */
@media (prefers-reduced-motion: reduce) {
  .revela, .revela-izq, .revela-escala, .revela-cortina, .revela-clip > * { animation: none !important; opacity: 1 !important; translate: none !important; scale: none !important; clip-path: none !important; }
  [data-texto] .ef-u { translate: 0 0 !important; rotate: 0deg !important; transition: none !important; }
  [data-trazo] * { stroke-dashoffset: 0 !important; }
  ::view-transition-new(root) { animation: none; }
}
