/* ============================================================================
   COMPONENTES — piezas propias de Vínculos de Alma
   ----------------------------------------------------------------------------
     .paso      despliegue progresivo ligado al scroll
     .figura    tarjeta de personaje con borde luminoso giratorio
     .match     muestra del perfil combinado que hay que entregar
     .criterio  barra de puntuación que se llena al revelarse
     .cadena    eslabón dibujado por progreso de scroll
   ========================================================================= */

/* ============================================================== 1. EL PASO ==
   La pieza que hace que la información "se despliegue gradualmente con el
   scroll". No es un reveal por aparición: es un valor LIGADO al scroll.

   js/scene.js escribe --scene (0..1) en el contenedor de la escena una vez por
   frame. Cada .paso calcula su propio progreso con --from y --span, y de ahí
   salen opacidad y desplazamiento.

   Consecuencia, y es lo importante: si subes, vuelve a esconderse. El contenido
   está cosido a la posición del scroll, no disparado por ella. Eso es lo que
   convierte una sección en una escena y no en una lista con fundidos.
   ========================================================================= */

.js .paso {
  --t: clamp(
    0,
    calc((var(--scene, 0) - var(--from, 0)) / var(--span, 0.16)),
    1
  );
  opacity: var(--t);
  translate: 0 calc((1 - var(--t)) * 32px);
}

/* Un paso puede pedir máscara en lugar de desplazamiento: el contenido no
   aparece, se descubre. Más elegante para bloques de texto. */
.js .paso--maska {
  translate: none;
  clip-path: inset(0 0 calc((1 - var(--t)) * 100%) 0);
  opacity: clamp(0.15, calc(var(--t) * 2), 1);
}

.js .paso--izq {
  translate: calc((1 - var(--t)) * -34px) 0;
}

/* ============================================================ 2. LA FIGURA ==
   Tarjeta de personaje con borde luminoso.

   CÓMO SE HACE LA LUZ, Y POR QUÉ ASÍ
   Son dos capas con costes muy distintos:

   .figura__aura  Un cono de color desenfocado que GIRA con transform. Como
                  transform se resuelve en el compositor, no repinta ni un
                  píxel por frame. Es gratis.
   .figura__aro   Un borde de 1 px hecho con un gradiente cónico y una máscara
                  que recorta el relleno. Este SÍ repinta, porque un gradiente
                  no se puede componer. Por eso solo anima el ángulo (--ring,
                  declarado con @property) y no el color ni la posición.

   Si el navegador no soporta @property, --ring se queda en su valor inicial y
   el borde queda FIJO, que sigue siendo bonito. Degradación sin código extra.
   ========================================================================= */

@property --ring {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

.figura {
  --c1: var(--accent);
  --c2: var(--accent-hot);
  position: relative;
  display: grid;
  isolation: isolate;
}

.figura__aura {
  position: absolute;
  inset: -13%;
  z-index: 0;
  pointer-events: none;
  background: conic-gradient(
    from 0deg,
    transparent 0 16%,
    var(--c1) 30%,
    var(--c2) 38%,
    transparent 50% 66%,
    var(--c1) 80%,
    transparent 94%
  );
  filter: blur(28px);
  opacity: 0.42;
  animation: spin 12s linear infinite;
  transition: opacity var(--dur-slow) var(--ease-veil);
}

.figura:hover .figura__aura,
.figura:focus-within .figura__aura {
  opacity: 0.95;
}

.figura__cuerpo {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-rows: 1fr auto;
  background: linear-gradient(
    to bottom,
    color-mix(in oklab, var(--ink-800) 94%, transparent),
    color-mix(in oklab, var(--ink-900) 97%, transparent)
  );
  backdrop-filter: blur(6px);
  overflow: clip;
}

/* Borde luminoso: gradiente cónico recortado a 1 px con doble máscara. */
.figura__aro {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  padding: 1px;
  background: conic-gradient(
    from var(--ring),
    transparent 0deg,
    var(--c1) 42deg,
    var(--c2) 74deg,
    transparent 132deg,
    transparent 214deg,
    var(--c1) 258deg,
    transparent 320deg
  );
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  mask-composite: exclude;
  animation: aro-gira 7s linear infinite;
}

@keyframes aro-gira {
  to {
    --ring: 360deg;
  }
}

/* Una segunda pasada del aro, más lenta y en sentido contrario, para que el
   borde nunca se lea como un patrón repetido. */
.figura__aro--rev {
  animation-direction: reverse;
  animation-duration: 11.5s;
  opacity: 0.6;
}

@media (prefers-reduced-motion: reduce) {
  .figura__aro,
  .figura__aura {
    animation: none;
  }
}

/* ------------------------------------------------------------ el retrato -- */

.figura__arte {
  position: relative;
  display: grid;
  place-items: end center;
  min-height: clamp(240px, 34vw, 340px);
  padding: var(--space-s) var(--space-s) 0;
}

.figura__arte img {
  width: 100%;
  max-height: clamp(230px, 32vw, 330px);
  object-fit: contain;
  /* Las imágenes se alinean por abajo: si una trae aire por debajo de los
     pies, parecerá más pequeña que las demás. Ver assets/personajes/LEEME.md */
  object-position: bottom center;
  filter: drop-shadow(0 18px 26px rgb(0 0 0 / 0.75));
  transition:
    transform var(--dur-slow) var(--ease-deco),
    filter var(--dur-base) var(--ease-veil);
}

.figura:hover .figura__arte img,
.figura:focus-within .figura__arte img {
  transform: translateY(-9px) scale(1.035);
  filter: drop-shadow(0 22px 34px rgb(0 0 0 / 0.8))
    drop-shadow(0 0 22px color-mix(in oklab, var(--c1) 55%, transparent));
}

/* ------------------------------------------------- respaldo sin imagen ----
   Mientras el PNG no exista, la tarjeta NO se rompe: muestra el sello, el
   nombre del personaje y el nombre exacto del archivo que falta. La página se
   puede publicar con tres imágenes y añadir el resto después. */

.figura__respaldo {
  display: none;
}

/* Selectores por atributo/clase genérica, no por .figura: el mismo componente
   de respaldo se usa en la rejilla y dentro de la procesión del desfile. */
.sin-arte img {
  display: none;
}

.sin-arte .figura__respaldo {
  display: grid;
  place-items: center;
  gap: var(--space-s);
  align-self: stretch;
  padding: var(--space-m) var(--space-s);
  text-align: center;
}

.figura__sello {
  width: clamp(84px, 12vw, 116px);
  aspect-ratio: 1;
  color: var(--c1);
  opacity: 0.55;
}

.figura__pista {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.18em;
  line-height: 1.9;
  text-transform: uppercase;
  color: var(--text-muted);
}

.figura__pista code {
  display: block;
  margin-block-start: 0.4em;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: none;
  color: var(--accent);
}

/* -------------------------------------------------------------- los datos -- */

.figura__datos {
  position: relative;
  z-index: 2;
  display: grid;
  gap: 0.35em;
  padding: var(--space-s);
  border-top: 1px solid var(--line);
}

.figura__nombre {
  font-family: var(--font-display);
  font-size: var(--step-2);
  line-height: 1;
  text-transform: uppercase;
  color: var(--bone-100);
}

.figura__rol {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--c1);
}

.figura__poder {
  margin-block-start: 0.35em;
  font-size: var(--step--1);
  color: var(--text-dim);
}

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

.figura__reclamo {
  margin-block-start: 0.5em;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* ------------------------------------------------------------ el crédito --
   La línea de autoría la construye js/main.js a partir de los atributos
   data-artista / data-enlace / data-licencia de cada tarjeta. No está escrita a
   mano en el HTML a propósito: así no se puede olvidar ni descolocar, y el
   crédito viaja siempre pegado a la obra. */

.figura__credito {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5em;
  margin-block-start: 0.8em;
  padding-block-start: 0.8em;
  border-top: 1px dashed color-mix(in oklab, var(--accent) 24%, transparent);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  line-height: 1.6;
  color: var(--text-muted);
}

.figura__credito a {
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid color-mix(in oklab, var(--accent) 45%, transparent);
  transition: color var(--dur-fast) var(--ease-veil);
}

.figura__credito a:hover {
  color: var(--accent-bright);
  border-bottom-color: var(--accent-bright);
}

.credito__licencia {
  padding: 0.28em 0.65em;
  border: 1px solid var(--line);
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-dim);
}

/* Verde solo para lo que tiene permiso explícito o licencia libre. El arte
   oficial se queda en gris: es la convención del fandom, no una autorización. */
.credito__licencia[data-tipo="seguro"] {
  border-color: color-mix(in oklab, #4ea86b 60%, transparent);
  color: #86d9a1;
}

.credito__licencia[data-tipo="oficial"] {
  border-color: var(--line);
  color: var(--text-muted);
}

/* --------------------------------------------------- crédito pendiente ----
   Un hueco que no se ve es un hueco que se queda. Este marcador aparece
   mientras una tarjeta no tenga autor declarado, y desaparece solo cuando lo
   tenga. Es la diferencia entre "acordarse" y "no poder olvidarse". */

.credito--pendiente {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  padding: 0.28em 0.65em;
  border: 1px dashed color-mix(in oklab, var(--accent-hot) 60%, transparent);
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-hot);
}

.credito--pendiente::before {
  content: "○";
  font-size: 11px;
  line-height: 1;
}

/* ======================================================= 7. PIE DE CRÉDITOS ==
   La lista agregada del pie. La rellena el mismo módulo, así que la sección de
   testigos y el pie no pueden discrepar.
   ========================================================================= */

.pie__creditos {
  display: grid;
  gap: var(--space-2xs);
  list-style: none;
  font-size: var(--step--2);
}

.pie__creditos a {
  color: var(--accent);
}

.pie__creditos li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.5em;
  align-items: baseline;
}

.pie__creditos li::before {
  content: "◆";
  font-size: 0.6em;
  color: var(--gold-700);
}

.pie__creditos .pendiente {
  color: var(--text-muted);
}

.pie__creditos .pendiente::before {
  color: var(--blood-700);
}

/* ============================================================= 3. EL MATCH ==
   Muestra de lo que hay que entregar: perfil combinado. Es un mock, no un
   componente funcional; sirve para que nadie tenga que adivinar el formato.
   ========================================================================= */

.match {
  position: relative;
  display: grid;
  background: var(--bg-raised);
  border: 1px solid var(--line);
  overflow: clip;
}

.match__portada {
  position: relative;
  aspect-ratio: 3 / 1;
  display: grid;
  place-items: center;
  background:
    repeating-linear-gradient(
      115deg,
      transparent 0 17px,
      color-mix(in oklab, var(--accent) 7%, transparent) 17px 18px
    ),
    radial-gradient(
      75% 130% at 18% 130%,
      color-mix(in oklab, var(--blood-700) 62%, transparent),
      transparent 72%
    ),
    radial-gradient(
      60% 120% at 88% -20%,
      color-mix(in oklab, var(--gold-700) 40%, transparent),
      transparent 70%
    ),
    linear-gradient(to bottom, var(--ink-700), var(--ink-900));
}

.match__portada span {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.match__cuerpo {
  display: grid;
  gap: var(--space-s);
  padding: var(--space-m);
}

.match__pareja {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-s);
  margin-block-start: -58px;
}

.match__avatar {
  width: clamp(72px, 10vw, 96px);
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  border: 2px solid var(--line);
  border-radius: 50%;
  background: radial-gradient(
    circle at 38% 28%,
    var(--ink-600),
    var(--ink-900) 72%
  );
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.12em;
  text-align: center;
  text-transform: uppercase;
  color: var(--text-muted);
}

.match__nudo {
  width: clamp(46px, 6vw, 58px);
  aspect-ratio: 1;
  flex: none;
  color: var(--accent);
}

.match__nombres {
  text-align: center;
  font-family: var(--font-display);
  font-size: var(--step-2);
  line-height: 1.1;
  text-transform: uppercase;
  color: var(--bone-100);
}

.match__nombres b {
  color: var(--accent-hot);
  font-weight: 400;
}

.match__bio {
  max-width: var(--measure);
  margin-inline: auto;
  text-align: center;
  color: var(--text-dim);
}

.match__nota {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-s);
  padding-block-start: var(--space-s);
  border-top: 1px solid var(--line-soft);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* ========================================================= 4. EL CRITERIO ==
   Barra de puntuación. Se llena con el mismo --t del paso que la contiene, así
   que la barra crece A MEDIDA que el criterio se revela. No hay animación
   aparte ni temporizador: es la misma señal.
   ========================================================================= */

.criterio {
  display: grid;
  gap: var(--space-3xs);
}

.criterio__cabeza {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-s);
}

.criterio__nombre {
  font-size: var(--step-0);
  color: var(--bone-100);
}

.criterio__peso {
  font-family: var(--font-display);
  font-size: var(--step-1);
  color: var(--accent);
}

.criterio__via {
  height: 3px;
  background: var(--line-soft);
  overflow: clip;
}

.criterio__relleno {
  height: 100%;
  background: linear-gradient(to right, var(--blood-700), var(--accent));
  transform: scaleX(calc(var(--peso, 0) * var(--t, 1)));
  transform-origin: left center;
}

.criterio__pie {
  font-size: var(--step--1);
  color: var(--text-muted);
}

/* ============================================================= 5. EL SELLO ==
   Marca de lacre. Se usa como separador, como nudo entre los dos roles y como
   marca de agua del respaldo de personaje.
   ========================================================================= */

.sello {
  display: grid;
  place-items: center;
}

.sello svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.sello [pathLength] {
  fill: none;
  stroke: currentColor;
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

.sello--lacre {
  color: var(--blood-500);
  filter: drop-shadow(0 0 18px color-mix(in oklab, var(--blood-500) 55%, transparent));
}
