/* ============================================================================
   DESFILE — procesión diagonal de personajes ligada al scroll
   ----------------------------------------------------------------------------
   QUÉ HACE
   Los ocho personajes cruzan la pantalla en diagonal mientras se hace scroll.
   Entran pequeños y lejos, crecen al acercarse, se inclinan, giran, y salen por
   el otro lado. La explicación de cada uno aparece y desaparece sincronizada
   con SU paso, no con el de los demás.

   CÓMO, Y POR QUÉ ASÍ
   Todo sale de un único número: --scene, que js/scene.js escribe (0..1) en el
   contenedor de la escena una vez por frame. Cada actor deriva de ahí su propio
   progreso local --a con su ventana (--from, --span), y de --a salen posición,
   escala, giro y opacidad.

   Consecuencia, y es la razón de hacerlo así: si subes, la procesión retrocede.
   Si te paras a mitad, se queda a mitad. No es una animación que se dispara y
   corre sola — está cosida a la posición del scroll.

   Y no hay ni una línea de JavaScript por actor. Un solo valor escrito por
   frame mueve ocho personajes y ocho fichas de texto.

   COSTE
   Las propiedades translate / scale / rotate / opacity se resuelven en el
   compositor. Ocho capas con will-change, de las que solo dos o tres tienen
   opacidad distinta de cero en un momento dado. Sin filtros animados, sin
   repintados por frame.
   ========================================================================= */

.desfile {
  position: relative;
  height: var(--alto, 520vh);
  z-index: var(--z-content);
}

.desfile__fijo {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: clip;
}

.desfile__cabecera {
  position: absolute;
  inset: clamp(4.5rem, 9vh, 7rem) 0 auto;
  z-index: 6;
  display: grid;
  justify-items: center;
  gap: var(--space-2xs);
  text-align: center;
  pointer-events: none;
}

/* El titular necesita su propio velo: por debajo pasan personajes y cuñas, y
   el encabezado tiene que leerse en cualquier momento de la procesión. */
.desfile__cabecera::before {
  content: "";
  position: absolute;
  inset: -2rem -10% -1.5rem;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(
    62% 120% at 50% 46%,
    rgb(7 5 6 / 0.86) 0%,
    rgb(7 5 6 / 0.5) 52%,
    transparent 82%
  );
}

.desfile__pista {
  position: absolute;
  inset: 0;
}

.desfile__contador {
  position: absolute;
  inset: auto auto clamp(1.6rem, 5vh, 3rem) 50%;
  translate: -50% 0;
  z-index: 6;
  display: flex;
  gap: 0.55em;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.2em;
  color: var(--text-muted);
}

.desfile__contador i {
  display: block;
  width: 22px;
  height: 2px;
  background: var(--line);
  transition: background-color var(--dur-base) var(--ease-veil);
}

.desfile__contador i.activo {
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent);
}

/* ============================================================ EL ACTOR ====
   La ventana local de cada personaje dentro de la escena.
   ========================================================================= */

.js .testigo {
  --a: clamp(
    0,
    calc((var(--scene, 0) - var(--from, 0)) / var(--span, 0.22)),
    1
  );

  /* Aparición y despedida. Las dos rampas de 0.17 y el mínimo de las dos dan
     un valor que sube, se mantiene y baja — sin necesidad de abs() ni de
     ninguna función triangular. */
  --entra: clamp(0, calc(var(--a) / 0.17), 1);
  --sale: clamp(0, calc((1 - var(--a)) / 0.17), 1);
  --vida: min(var(--entra), var(--sale));

  /* La ficha tiene una ventana MÁS ESTRECHA que el actor, y descentrada: así
     nunca hay dos explicaciones en pantalla a la vez aunque los personajes se
     solapen al pasar. */
  --ficha-entra: clamp(0, calc((var(--a) - 0.28) / 0.14), 1);
  --ficha-sale: clamp(0, calc((0.72 - var(--a)) / 0.14), 1);
  --ficha-vida: min(var(--ficha-entra), var(--ficha-sale));
}

.desfile__pista .testigo {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.testigo__actor {
  position: absolute;
  left: 50%;
  top: 50%;
  width: clamp(174px, 20vw, 306px);
  aspect-ratio: 3 / 4;
  z-index: 2;

  /* El recorrido. --x0/--x1 y --y0/--y1 son números en vw y vh respecto al
     centro: interpolarlos es una multiplicación, y multiplicar un número
     suelto por 1vw da una longitud válida dentro de calc(). */
  translate: calc(
      -50% +
        (var(--x0, -32) + (var(--x1, 68) - var(--x0, -32)) * var(--a, 0)) * 1vw
    )
    calc(
      -50% +
        (var(--y0, 18) + (var(--y1, -22) - var(--y0, 18)) * var(--a, 0)) * 1vh
    );
  scale: calc(0.66 + var(--a, 0) * 0.86);
  rotate: calc((var(--a, 0) - 0.5) * var(--giro, 8) * 1deg);
  opacity: calc(var(--vida, 0) * 0.97);
  will-change: translate, scale, opacity;
}

/* La placa: apenas un cristal. El personaje flota dentro de un marco
   luminoso, no pegado a una tarjeta opaca. */
.testigo__marco {
  position: relative;
  width: 100%;
  height: 100%;
  display: grid;
  place-items: end center;
  background: linear-gradient(
    to bottom,
    color-mix(in oklab, var(--ink-800) 34%, transparent),
    color-mix(in oklab, var(--ink-900) 78%, transparent)
  );
  overflow: clip;
}

.testigo__marco img {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: bottom center;
  filter: drop-shadow(0 22px 30px rgb(0 0 0 / 0.8));
}

/* El aura de la placa, algo más contenida que en la rejilla: aquí hay ocho. */
.testigo__actor .figura__aura {
  inset: -16%;
  filter: blur(24px);
  opacity: calc(0.3 + var(--vida, 0) * 0.4);
}

/* ============================================================ LA FICHA ====
   La explicación. Anclada abajo a la izquierda, porque en la mitad del recorrido
   todos los personajes están a la derecha: la diagonal y el texto nunca se pisan.
   ========================================================================= */

.testigo__ficha {
  position: absolute;
  left: max(var(--space-s), calc((100vw - var(--shell)) / 2));
  bottom: clamp(3.2rem, 9vh, 6rem);
  z-index: 5;
  width: min(46ch, 44vw);
  opacity: var(--ficha-vida, 0);
  translate: calc((1 - var(--ficha-entra, 0)) * -30px) 0;
  pointer-events: none;
}

/* Velo propio: la ficha tiene que leerse sobre lo que sea que esté pasando
   detrás. Nunca dejes que un fondo en movimiento decida el contraste. */
.testigo__ficha::before {
  content: "";
  position: absolute;
  inset: -1.6rem -2.4rem;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(
    72% 82% at 26% 50%,
    rgb(7 5 6 / 0.9) 0%,
    rgb(7 5 6 / 0.6) 48%,
    transparent 78%
  );
}

.testigo__nombre {
  font-family: var(--font-display);
  /* Un escalón por debajo del titular de sección: el nombre del personaje
     compite con el personaje en movimiento, no con el encabezado. */
  font-size: var(--step-3);
  line-height: 1;
  text-transform: uppercase;
  color: var(--bone-100);
}

.testigo__rol {
  margin-block-start: 0.5em;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--c1, var(--accent));
}

.testigo__poder {
  margin-block-start: var(--space-xs);
  font-size: var(--step-0);
  color: var(--text-dim);
}

.testigo__poder em {
  font-style: normal;
  color: var(--bone-100);
}

/* El vínculo canónico. Está aquí porque el concurso va de contratos de alma, y
   no todos los personajes del reparto tienen la misma relación con uno: unos lo
   firmaron, otros lo cobran y otros lo redactan. Decirlo en la propia ficha
   evita que la lista parezca una elección arbitraria de personajes populares. */
.testigo__vinculo {
  margin-block-start: var(--space-xs);
  padding: 0.5em 0.8em;
  border: 1px solid color-mix(in oklab, var(--c1, var(--accent)) 45%, transparent);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: 0.04em;
  line-height: 1.6;
  color: var(--text-dim);
}

.testigo__reclamo {
  margin-block-start: var(--space-xs);
  padding-inline-start: var(--space-s);
  border-inline-start: 1px solid var(--c1, var(--accent));
  font-family: var(--font-deco);
  font-size: var(--step-1);
  line-height: 1.35;
  color: var(--bone-100);
}

/* ================================================== EL ESPACIO SE DISPUTA ==
   Cada personaje RECLAMA la pantalla mientras pasa: un baño de su color que
   inunda el fondo y dos derrames en los bordes laterales. Cuando dos se solapan
   —y se solapan a propósito— los dos tintes conviven y el espacio se ve
   disputado, que es exactamente lo que tiene que pasar en un concurso de
   contratos.

   Una sola capa por personaje, con los tres degradados dentro. Con opacidad 0
   el navegador ni la pinta, así que tener ocho no cuesta nada.
   ========================================================================= */

.testigo__ambiente {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: calc(var(--vida, 0) * 0.78);
  background:
    radial-gradient(
      66% 58% at 76% 44%,
      color-mix(in oklab, var(--c1) 62%, transparent) 0%,
      transparent 72%
    ),
    radial-gradient(
      48% 52% at 16% 62%,
      color-mix(in oklab, var(--c2) 40%, transparent) 0%,
      transparent 74%
    ),
    linear-gradient(
      to right,
      color-mix(in oklab, var(--c1) 78%, transparent) 0%,
      transparent 15%
    ),
    linear-gradient(
      to left,
      color-mix(in oklab, var(--c2) 78%, transparent) 0%,
      transparent 15%
    );
}

/* ================================================ LAS CUÑAS QUE IRRUMPEN ===
   Triángulos horizontales que se clavan desde los bordes en el instante en que
   el personaje entra en escena, y se retiran antes de que termine de cruzar.

   No acompañan al movimiento: lo INTERRUMPEN. Es la diferencia entre una
   procesión y una presentación de diapositivas. Y son horizontales a propósito
   —el personaje viaja en diagonal, las cuñas cortan en horizontal—, así que las
   dos direcciones se pelean en pantalla.

   Cada cuña tiene su propio desfase (--d), su altura (--sy) y su grosor (--sh),
   así que entran escalonadas y a distintas alturas. Las pares vienen del lado
   contrario y con la punta invertida.
   ========================================================================= */

.testigo__cuñas {
  position: absolute;
  inset: 0;
  z-index: 3;
  overflow: clip;
  pointer-events: none;
}

.testigo__cuñas i {
  --dd: calc(var(--a, 0) - var(--d, 0));
  --golpe: clamp(0, calc(var(--dd) / 0.055), 1);
  --retira: clamp(0, calc((var(--dd) - 0.12) / 0.09), 1);

  position: absolute;
  left: 0;
  top: calc(var(--sy, 26) * 1%);
  height: calc(var(--sh, 18) * 1%);
  width: 74vw;
  opacity: calc((var(--golpe) - var(--retira)) * var(--vida, 1) * 0.92);
  translate: calc((1 - var(--golpe)) * -78vw) 0;
  background: linear-gradient(
    to right,
    color-mix(in oklab, var(--c1) 95%, transparent) 0%,
    color-mix(in oklab, var(--c2) 58%, transparent) 44%,
    transparent 94%
  );
  clip-path: polygon(0 50%, 11% 0, 100% 0, 100% 100%, 11% 100%);
}

.testigo__cuñas i:nth-child(even) {
  left: auto;
  right: 0;
  translate: calc((1 - var(--golpe)) * 78vw) 0;
  clip-path: polygon(100% 50%, 89% 0, 0 0, 0 100%, 89% 100%);
  background: linear-gradient(
    to left,
    color-mix(in oklab, var(--c2) 95%, transparent) 0%,
    color-mix(in oklab, var(--c1) 58%, transparent) 44%,
    transparent 94%
  );
}

/* ==================================================== LA CADENA DEL DESFILE ==
   Enhebra los ocho personajes. Cada eslabón se enciende con SU color cuando le
   toca pasar y se apaga cuando ha pasado, así que la cadena se lee de un vistazo
   como el orden de la procesión.

   Se genera leyendo los actores del marcado (ver js/deco.js), así que no hay
   dos listas que puedan discrepar.
   ========================================================================= */

.desfile__cadena {
  position: absolute;
  left: clamp(0.4rem, 2.2vw, 2.2rem);
  top: 11vh;
  bottom: 11vh;
  width: 54px;
  z-index: 4;
  pointer-events: none;
}

.desfile__cadena svg {
  display: block;
  width: 100%;
  height: 100%;
}

/* Especificidad alta a propósito: la regla general de [data-deco] svg * fija
   stroke: currentColor y ganaría con un selector simple. */
.desfile__cadena svg .cadena__eslabon {
  --a: clamp(
    0,
    calc((var(--scene, 0) - var(--from, 0)) / var(--span, 0.22)),
    1
  );
  --w: min(
    clamp(0, calc(var(--a) / 0.16), 1),
    clamp(0, calc((1 - var(--a)) / 0.16), 1)
  );
  fill: none;
  stroke: var(--c1, var(--gold-700));
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
  opacity: calc(0.13 + var(--w) * 0.87);
}

/* ================================================== FUERA DE PANTALLA =====
   Donde la procesión no funciona. Una escena de 520vh con contenido fijo es
   una trampa en móvil, y con movimiento reducido es exactamente lo que hay que
   evitar. En los dos casos se convierte en una lista vertical de fichas con su
   personaje: se pierde el desfile, no el contenido.
   ========================================================================= */

.motion-off .desfile,
.motion-off .desfile__fijo {
  height: auto;
}

.motion-off .desfile__fijo {
  position: static;
  padding-block: var(--space-2xl);
  overflow: visible;
}

.motion-off .desfile__cabecera,
.motion-off .desfile__contador {
  position: static;
  margin-block-end: var(--space-l);
}

.motion-off .desfile__pista {
  position: static;
  display: grid;
  gap: var(--space-2xl);
}

.motion-off .desfile__pista .testigo {
  position: static;
  inset: auto;
  pointer-events: auto;
}

.motion-off .testigo__actor {
  position: relative;
  left: auto;
  top: auto;
  width: min(280px, 68vw);
  margin-inline: auto;
  opacity: 1;
  translate: none;
  scale: none;
  rotate: none;
  will-change: auto;
}

.motion-off .testigo__ficha {
  position: static;
  width: auto;
  margin-block-start: var(--space-s);
  opacity: 1;
  translate: none;
  text-align: center;
}

.motion-off .testigo__ficha::before,
.motion-off .desfile__contador {
  display: none;
}

@media (max-width: 900px), (prefers-reduced-motion: reduce) {
  .desfile,
  .desfile__fijo {
    height: auto;
  }

  .desfile__fijo {
    position: static;
    padding-block: var(--space-2xl);
    overflow: visible;
  }

  .desfile__cabecera {
    position: static;
    margin-block-end: var(--space-l);
  }

  .desfile__contador {
    display: none;
  }

  .desfile__pista {
    position: static;
    display: grid;
    gap: var(--space-2xl);
  }

  .desfile__pista .testigo {
    position: static;
    inset: auto;
    pointer-events: auto;
  }

  .testigo__actor {
    position: relative;
    left: auto;
    top: auto;
    width: min(280px, 68vw);
    margin-inline: auto;
    opacity: 1 !important;
    translate: none !important;
    scale: none !important;
    rotate: none !important;
    will-change: auto;
  }

  .testigo__ficha {
    position: static;
    width: auto;
    margin-block-start: var(--space-s);
    opacity: 1 !important;
    translate: none !important;
    text-align: center;
  }

  .testigo__ficha::before {
    display: none;
  }

  /* El ambiente y la cadena solo tienen sentido con una procesión en marcha.
     En la lista vertical serían manchas de color y una columna de eslabones
     sueltos. Se retiran. */
  .testigo__ambiente,
  .testigo__cuñas,
  .desfile__cadena {
    display: none;
  }
}
