/* carrusel.css — último de la cascada, aislado a propósito.
   Ningún valor suelto: todo sale de tokens.css.

   DOS MOTORES, mejora progresiva:
   · Sin JS  → la ventana es un scroll horizontal nativo con scroll-snap. Se
               desliza con el dedo, se navega con teclado y se ve terminado.
   · Con JS  → js/ui/carrusel.js añade .carrusel--js: se apaga el scroll nativo
               y manda un solo translate3d sobre la pista, más el efecto de
               profundidad de las tarjetas vecinas.
   Los controles (flechas y puntos) solo existen bajo .carrusel--js: sin JS no
   harían nada y un control muerto es peor que ningún control. */

/* ------------------------------------------------------------------ Armazón */

.carrusel {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--e-4) var(--e-2);
  margin-top: var(--e-8);
}

.carrusel__ventana {
  /* Sangrado: la tarjeta arranca alineada con el texto, pero la siguiente se
     asoma hasta el filo de la pantalla. El ancho extra se lo come el padding,
     así el contenido de la pista mide EXACTAMENTE lo que el contenedor y
     --ancho-tarjeta sigue cuadrando en 2 y en 3 columnas. */
  flex: 0 0 calc(100% + var(--canal));
  margin-inline: calc(var(--canal) / -2);
  padding-inline: calc(var(--canal) / 2);
  padding-block: var(--e-3) var(--e-6);
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}

.carrusel__ventana::-webkit-scrollbar {
  display: none;
}

.carrusel__pista {
  display: flex;
  gap: var(--gap-carrusel);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* ---------------------------------------------------------- Motor con JS */

.carrusel--js .carrusel__ventana {
  overflow: hidden;
  scroll-snap-type: none;

  /* El punto de fuga del mazo. Va aquí, en la ventana, y no en la pista: la
     pista se desplaza en X, y si llevara ella la perspectiva el punto de fuga
     viajaría con las tarjetas y el efecto se rompería al deslizar. */
  perspective: var(--perspectiva);
  perspective-origin: 50% 50%;
}

.carrusel--js .carrusel__pista {
  /* pan-y deja el scroll vertical de la página en manos del navegador; el
     horizontal lo toma el gesto. Sin JS NO se pone: mataría el scroll nativo. */
  touch-action: pan-y;
  transition: transform var(--dur-media) var(--ease);

  /* Sin esto, el translateZ de las tarjetas se aplana y no hay 3D: la pista
     tiene su propio transform y crearía un contexto 2D para sus hijas. */
  transform-style: preserve-3d;
}

.carrusel__pista--arrastrando {
  transition: none;
  will-change: transform;
  cursor: grabbing;
  user-select: none;
}

/* Durante el arrastre las tarjetas siguen al dedo cuadro a cuadro: una
   transición aquí las dejaría persiguiendo al puntero con retraso. */
.carrusel__pista--arrastrando .tarjeta-linea {
  transition: none;
  will-change: transform, opacity;
}

/* ------------------------------------------------------- Tarjeta de línea */

.tarjeta-linea {
  display: flex;
  flex: 0 0 var(--ancho-tarjeta);
  flex-direction: column;
  scroll-snap-align: center;
  background: var(--blanco);
  border: var(--borde);
  border-radius: var(--radio-tarjeta);
  overflow: hidden;
}

/* Profundidad 3D tipo ApeChain: mazo de tarjetas. La del centro viene al frente
   y plana; las vecinas se hunden en Z y giran sobre Y para "mirar" al centro.

   Estas reglas son solo el REPOSO y el respaldo si el JS no arranca: en marcha,
   js/ui/carrusel.js escribe el transform inline de cada tarjeta cuadro a cuadro
   a partir de su distancia continua al centro (por eso el giro sigue al dedo).
   Los valores salen de los tokens --z-vecina / --giro-vecina / --escala-vecina.

   Solo transform y opacity: las dos que el compositor mueve sin repintar. */
.carrusel--js .tarjeta-linea {
  transform: translate3d(0, 0, calc(var(--z-vecina) * -1)) scale(var(--escala-vecina));
  opacity: var(--opacidad-vecina);
  transition:
    transform var(--dur-media) var(--ease),
    opacity var(--dur-media) var(--ease);
}

.carrusel--js .tarjeta-linea[data-activa] {
  transform: none;
  opacity: 1;
}

/* La sombra la lleva SOLO la del centro del mazo: con 3 tarjetas a la vista,
   "activa" son las tres, pero al frente hay una. */
.carrusel--js .tarjeta-linea[data-centro] {
  box-shadow: var(--sombra-flotante);
}

.tarjeta-linea__figura {
  display: block;
  margin: 0;
  aspect-ratio: 4 / 3;
  background: var(--hueso-hondo);
  overflow: hidden;
}

.tarjeta-linea__imagen {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.tarjeta-linea__cuerpo {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: var(--e-3);
  padding: var(--e-4) var(--e-4) var(--e-6);
}

/* El texto va en --tinta-suave (6.7:1 sobre blanco, medido), no en --acento: el verde sobre la
   tarjeta blanca da 2.34:1 y reprueba AA, justo lo que advierte tokens.css.
   El acento verde se conserva, pero como elemento gráfico: la barra de antes. */
.tarjeta-linea__etiqueta {
  display: flex;
  align-items: center;
  gap: var(--e-2);
  margin: 0;
  font-family: var(--fuente-utilidad);
  font-size: var(--txt-xs);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--tinta-suave);
}

.tarjeta-linea__etiqueta::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--acento);
}

.tarjeta-linea__numero {
  margin-right: var(--e-1);
  color: var(--tinta-suave);
}

.tarjeta-linea__titulo {
  margin: 0;
  font-family: var(--fuente-display);
  font-size: var(--txt-xl);
  font-weight: 400;
  line-height: var(--alto-display);
  letter-spacing: -0.01em;
  text-transform: uppercase;
  color: var(--tinta);
}

.tarjeta-linea__descripcion {
  margin: 0;
  font-size: var(--txt-sm);
  line-height: var(--alto-cuerpo);
  color: var(--tinta-suave);
}

.tarjeta-linea__lista {
  display: grid;
  gap: var(--e-1);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--txt-sm);
}

.tarjeta-linea__item {
  position: relative;
  padding-left: var(--e-4);
  color: var(--tinta);
}

.tarjeta-linea__item::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.6em;
  width: var(--e-2);
  height: var(--e-2);
  border-radius: var(--radio-btn);
  background: var(--acento);
}

.tarjeta-linea__cta {
  align-self: flex-start;
  margin-top: auto;
  padding-top: var(--e-2);
  font-size: var(--txt-sm);
  font-weight: 600;
  color: var(--tinta);
  text-decoration: none;
  border-bottom: var(--borde);
  border-bottom-color: var(--acento-hondo);
}

.tarjeta-linea__cta:hover,
.tarjeta-linea__cta:focus-visible {
  color: var(--acento-fuerte);
}

/* ---------------------------------------------------------- Controles */

.carrusel__puntos,
.carrusel__flecha {
  display: none; /* sin JS no navegan: no se muestran */
}

.carrusel--js .carrusel__puntos {
  display: flex;
  flex: 1 0 100%;
  justify-content: center;
  gap: var(--e-1);
  order: 1;
}

.carrusel__punto {
  display: grid;
  place-items: center;
  width: var(--e-6);
  height: var(--e-6);
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.carrusel__punto[hidden] {
  display: none;
}

/* La pastilla activa se estira con transform, no con width: animar el ancho
   obliga al navegador a recalcular layout en cada cuadro. */
.carrusel__punto::before {
  content: "";
  display: block;
  width: var(--e-2);
  height: var(--e-2);
  border-radius: var(--radio-btn);
  background: var(--hueso-hondo);
  transition:
    transform var(--dur-rapida) var(--ease),
    background-color var(--dur-rapida) var(--ease);
}

.carrusel__punto[aria-selected="true"]::before {
  transform: scaleX(2.6);
  background: var(--acento);
}

.carrusel__flecha {
  place-items: center;
  width: var(--e-12);
  height: var(--e-12);
  padding: 0;
  border: var(--borde);
  border-radius: var(--radio-btn);
  background: transparent;
  color: var(--tinta);
  cursor: pointer;
  transition:
    border-color var(--dur-rapida) var(--ease),
    background-color var(--dur-rapida) var(--ease);
}

.carrusel__flecha--anterior {
  order: 2;
  margin-left: auto;
}

.carrusel__flecha--siguiente {
  order: 3;
}

.carrusel__flecha:hover {
  border-color: var(--acento);
  background: var(--blanco);
}

.carrusel__flecha[aria-disabled="true"] {
  opacity: var(--opacidad-vecina);
  cursor: default;
}

.carrusel__flecha[aria-disabled="true"]:hover {
  border-color: var(--hueso-hondo);
  background: transparent;
}

/* Foco visible propio: el carrusel es lo primero que se toca con teclado. */
.carrusel:focus-visible,
.carrusel__flecha:focus-visible,
.carrusel__punto:focus-visible,
.tarjeta-linea__cta:focus-visible {
  outline: var(--grosor-foco) solid var(--acento);
  outline-offset: var(--offset-foco);
}

/* ------------------------------------------------------------ Breakpoints */

@media (min-width: 768px) {
  .carrusel--js .carrusel__puntos {
    flex: 0 1 auto;
    justify-content: flex-start;
  }

  .carrusel--js .carrusel__flecha {
    display: grid;
  }
}

/* --------------------------------------------------- Movimiento reducido */

@media (prefers-reduced-motion: reduce) {
  .carrusel--js .carrusel__pista {
    transition: none;
  }

  /* Sin perspectiva ni giro: el 3D es justo el tipo de movimiento que marea a
     quien pide movimiento reducido. Salto directo y tarjetas planas.
     El JS lo acompaña: deja de escribir el transform inline y borra el que hubiera. */
  .carrusel--js .carrusel__ventana {
    perspective: none;
  }

  .carrusel--js .carrusel__pista {
    transform-style: flat;
  }

  .carrusel--js .tarjeta-linea,
  .carrusel--js .tarjeta-linea[data-activa] {
    transform: none;
    opacity: 1;
    transition: none;
  }

  .carrusel__punto::before,
  .carrusel__flecha {
    transition: none;
  }
}

/* ============================================================ MODO ANILLO

   Las 6 tarjetas se reparten en un círculo y el aro gira sobre su eje Y. Van
   VACÍAS a propósito: son formas, no contenido. El texto de la línea que está
   al frente se lee en el panel de al lado, y cambia al girar.

   El contenido de cada tarjeta NO se borra del DOM: se oculta con la técnica de
   clip. Así el texto de las 6 líneas sigue en la página para los buscadores,
   mientras que los lectores de pantalla leen el panel (el aro va aria-hidden,
   para no oír el mismo texto dos veces).

   Solo se activa con JS y sin `prefers-reduced-motion`: un aro girando es
   justo el tipo de movimiento que hay que poder apagar. Sin él, manda el
   fallback plano de arriba. */

/* Se reutiliza el flex-wrap que ya tenía .carrusel: los puntos llevan order 1 y
   las flechas order 2 y 3, así que caen solos en una fila debajo del aro. */
.carrusel--anillo {
  gap: var(--e-6) var(--e-2);
}

.carrusel--anillo .carrusel__ventana {
  /* A sangre: el aro ocupa el ancho de la pantalla y las tarjetas de los lados
     se salen por los bordes, en vez de quedar encajadas en el contenedor. */
  flex: 1 1 100%;
  width: 100vw;
  margin-inline: calc(50% - 50vw);
  order: -2;
  height: var(--altura-escena-anillo);
  margin: 0;
  padding: 0;
  display: grid;
  place-items: center;
  /* `clip` y no `hidden`: recorta lo que sobresale del aro sin crear un
     contenedor de scroll —con `hidden` el aro empujaba la página a scroll
     horizontal en móvil— y sin aplanar el 3D de las tarjetas, que cuelga de
     preserve-3d en la pista, no de aquí. */

  /* VISIBLE a propósito: las tarjetas no se recortan en la caja de la escena.
     El único recorte legítimo es el borde de la pantalla, y ese lo pone
     .seccion--lineas con overflow-x: clip. En vertical las tarjetas pueden
     sobresalir hacia la sección siguiente — la referencia hace exactamente
     eso: la banda se sale de su franja por abajo. */
  overflow: visible;
  perspective: var(--perspectiva-anillo);
}

.carrusel--anillo .carrusel__pista {
  position: relative;
  display: block;
  width: var(--ancho-tarjeta-anillo);
  height: var(--alto-tarjeta-anillo);
  gap: 0;
  transform-style: preserve-3d;
  transition: transform var(--dur-lenta) var(--ease);
}

/* La TARJETA es la imagen, y va horizontal. El texto NO va dentro: flota
   debajo, suelto sobre el fondo de planta, sin caja ni borde.

   Por eso el <li> deja de tener fondo y sombra —los lleva la figura— y solo
   hace de columna: imagen arriba, texto flotando abajo, separados por hueco. */
.carrusel--anillo .tarjeta-linea {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  gap: var(--hueco-texto-anillo);
  width: 100%;
  height: 100%;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  overflow: visible;

  /* La tarjeta es un OBJETO 3D: sin esto, sus rebanadas se proyectan
     aplanadas sobre el plano de la tarjeta y el combado pierde profundidad. */
  transform-style: preserve-3d;

  /* SIEMPRE opaca: pisa la opacidad de vecina del modo mazo (.carrusel--js).
     En el aro la distancia se marca con brillo, nunca con transparencia. */
  opacity: 1;

  /* La tarjeta SÍ se ve por detrás: al girar el aro se alcanza a ver el dorso
     de las de atrás, que es parte del efecto. Lo que no puede verse es su
     contenido en espejo — eso se apaga abajo, en la figura y en el texto. */
  backface-visibility: visible;
}

/* Sin dorso: la tarjeta que mira al otro lado del aro no pinta nada. */

/* La caja blanca es solo la imagen.

   La curvatura ya NO es un truco de silueta: js/ui/carrusel.js parte la
   imagen en rebanadas verticales y gira cada una unos grados — la tarjeta se
   comba de verdad y la perspectiva arquea sola los bordes. La figura queda
   como caja de la imagen del fallback (que se oculta cuando hay rebanadas). */
.carrusel--anillo .tarjeta-linea__figura {
  flex: none;
  aspect-ratio: var(--proporcion-tarjeta);
  background: var(--blanco);
  border: 0;
  border-radius: var(--radio-img);
  overflow: hidden;
  backface-visibility: hidden;

  /* Realismo: tres sombras en vez de una.
     1) contacto — corta y densa, pega la tarjeta al espacio;
     2) cuerpo   — la sombra proyectada de verdad;
     3) canto    — un filo claro de 1px que simula el borde del material
                   recogiendo luz. Sin él la tarjeta parece un recorte. */
  box-shadow:
    0 2px 6px -2px rgb(0 0 0 / 0.45),
    0 26px 54px -22px rgb(0 0 0 / 0.62),
    inset 0 1px 0 rgb(255 255 255 / 0.42),
    inset 0 -1px 0 rgb(0 0 0 / 0.22);
}

/* Reflejo especular: una banda diagonal muy tenue sobre la cara. Se mueve con
   el aro porque va dentro de la tarjeta, así que el brillo cambia según hacia
   dónde mire — que es lo que hace que se lea como superficie y no como papel. */
.carrusel--anillo .tarjeta-linea__lonjas::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(
    104deg,
    rgb(255 255 255 / 0) 34%,
    rgb(255 255 255 / 0.13) 47%,
    rgb(255 255 255 / 0.03) 55%,
    rgb(255 255 255 / 0) 68%
  );
}

.carrusel--anillo .tarjeta-linea__figura {
  position: relative;
  background: var(--blanco);
}

/* (El sombreado cilíndrico vive dentro de las rebanadas: ver curvarTarjeta.) */

/* Sin desenfoque: `filter` en la tarjeta obligaría al navegador a aplanar su
   3D interno (las rebanadas), y la lejanía ya se comunica oscureciendo. */

/* El texto YA NO viaja con la tarjeta: vive fuera del aro, en primer plano
   (.carrusel__texto, más abajo). Dentro de la tarjeta solo queda la imagen.
   El contenido sigue en el DOM para el SEO y para el fallback sin JS. */
.carrusel--anillo .tarjeta-linea__cuerpo {
  display: none;
}

.carrusel--anillo .tarjeta-linea__etiqueta {
  justify-content: center;
}

/* La línea del acento sobra cuando la etiqueta va centrada y suelta. */
.carrusel--anillo .tarjeta-linea__etiqueta::after {
  content: none;
}

.carrusel--anillo .tarjeta-linea__titulo {
  font-size: var(--txt-lg);
}

.carrusel--anillo .tarjeta-linea__descripcion {
  font-size: var(--txt-xs);
}

.carrusel--anillo .tarjeta-linea__cta {
  align-self: center;
  margin-top: var(--e-2);
}

/* Los bullets no caben sin apretar la tarjeta: el detalle técnico se lee en la
   sección de capacidades. Se ocultan solo en el aro, no en el fallback. */
.carrusel--anillo .tarjeta-linea__lista {
  display: none;
}

.carrusel--anillo .tarjeta-linea[data-centro],
.carrusel--anillo .tarjeta-linea[data-activa] {
  transform: none;            /* el modo mazo no manda aquí */
  box-shadow: none;
}

/* La del frente se marca solo con el acento, sin rellenos. */
.carrusel--anillo .tarjeta-linea[data-frente] {
  border-color: var(--acento);
  border-width: 2px;
}


@media (min-width: 768px) {
}

/* --------------------------------------- Fondo de color por tarjeta */

/* La sección toma el color de la línea que está al frente y lo cruza con una
   transición larga, así el cambio se lee como parte del giro y no como un
   parpadeo. El color lo pone js/ui/carrusel.js en --fondo-lineas leyendo el
   token --color-linea-<id> de cada tarjeta.

   Ya no hay foto de planta ni velo blanco encima: era el velo lo que dejaba
   toda la sección lavada. Con color plano, el contraste es una cuenta fija en
   vez de depender del píxel de la foto que quede debajo. */
.seccion--lineas {
  position: relative;
  isolation: isolate;
  background-color: var(--fondo-lineas);
  transition: background-color var(--dur-lenta) var(--ease);

  /* La animación es lo primero que se ve y tiene que verse SOLA: sin esto la
     sección medía 76% de la pantalla en celular y 84% en escritorio, y
     asomaba el hero blanco de abajo (el "pedazo en blanco").
     `dvh` y no `vh` porque en móvil la barra del navegador se recoge y `vh`
     mide la pantalla sin barra: dejaba un salto al hacer scroll. */
  display: grid;
  align-content: center;
  min-height: 100svh;
  min-height: 100dvh;

  /* PEGAJOSA: el aro se queda quieto y el resto de la página pasa por encima.
     Es lo que hace la referencia, y sale gratis con `sticky` — sin JS y sin
     scroll-jacking, así que la rueda del ratón y el teclado siguen siendo los
     del navegador. Las secciones de después necesitan fondo propio (lo tienen)
     y quedar por delante en la pila: eso lo da el orden del documento. */
  position: sticky;
  top: 0;

  /* El aro va a sangre con width: 100vw, y 100vw INCLUYE la barra de scroll
     vertical: sin este recorte, la pagina desborda ~12px en horizontal.
     `clip` y no `hidden` para no crear un contenedor de scroll. */
  overflow-x: clip;
}

/* Degradado y ondas de contorno.

   Las ondas son `repeating-radial-gradient`: anillos concéntricos de 1px con
   el centro fuera de cuadro, que a este tamaño se leen como curvas de nivel.
   Se hace así y no con una imagen porque pesa cero y se tiñe sola con el color
   de la línea, sin tener que generar seis fondos distintos. */
.seccion--lineas::before {
  content: "";
  position: absolute;
  inset: -3%;      /* holgura: el fondo se desplaza y no debe descubrir borde */
  z-index: -2;
  pointer-events: none;

  /* CUATRO capas, todas SEMITRANSPARENTES a propósito, de arriba a abajo:

     1) grano — ruido finísimo. Es lo que mata el `banding`: un degradado de
        dos tonos casi iguales estirado sobre 100dvh se rompe en franjas
        visibles, y el ruido las disuelve. Pesa ~400 bytes y no se anima.
     2) viñeta — oscurece los bordes para que el aro se despegue del fondo.
     3) foco — la luz que cae tras el aro.
     4) telón — la nave real, desenfocada y casi gris. Da textura de sitio
        real, que un degradado plano no puede fingir.

     Ninguna depende de `--fondo-lineas`: el color de la línea lo pinta el
     `background-color` de la sección, que se ve POR DEBAJO de estas cuatro.
     Antes las capas se armaban con `color-mix(var(--fondo-lineas))` y se
     intentaba animarlas con `transition: background-image`, que NO es
     animable: al girar el aro, el color de la sección cruzaba suave mientras
     el degradado conmutaba de golpe. Ese era el parpadeo del fondo.

     La foto viene YA desenfocada y con su transparencia horneada (15 KB): un
     `filter: blur()` a pantalla completa es de lo más caro que se le puede
     pedir al navegador, y aquí ni se anima ni cambia. */
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23g)' opacity='0.055'/%3E%3C/svg%3E"),
    radial-gradient(
      ellipse 82% 70% at 50% 44%,
      transparent 0%,
      transparent 54%,
      rgb(0 0 0 / var(--vineta-fondo)) 100%
    ),
    radial-gradient(
      ellipse 62% 52% at 42% 32%,
      rgb(255 255 255 / var(--brillo-fondo)) 0%,
      rgb(255 255 255 / 0) 68%
    ),
    image-set(
      url("../assets/img/planta/telon-aro.webp") type("image/webp"),
      url("../assets/img/planta/telon-aro.jpg") type("image/jpeg")
    );
  background-size: 180px 180px, cover, cover, cover;
  background-repeat: repeat, no-repeat, no-repeat, no-repeat;
  background-position: center;
  transition: transform 620ms var(--ease);
  transform: translate3d(calc(var(--raton-x, 0) * -10px), calc(var(--raton-y, 0) * -7px), 0);
}

/* Las curvas de nivel, en su propia capa: se mueven despacio y en bucle, y al
   ir en `transform` no cuestan repintado. Es lo que le quita al fondo el aire
   de imagen fija.

   Las líneas se dibujan con un degradado de cuatro paradas y no con un corte
   duro: un `repeating-radial-gradient` de 1.5px sin antialiasing producía
   moiré — las rayas rotas que se veían en las esquinas. Con las paradas
   suavizadas, la misma curva se lee limpia y además cuesta lo mismo. */
.seccion--lineas .fondo-ondas {
  position: absolute;
  inset: -18%;
  z-index: -1;
  pointer-events: none;
  background-image:
    repeating-radial-gradient(
      ellipse 120% 80% at 12% -10%,
      transparent 0 calc(var(--paso-onda) - var(--grosor-onda) * 2),
      rgb(255 255 255 / calc(var(--trama-fondo) * 0.55))
        calc(var(--paso-onda) - var(--grosor-onda)) calc(var(--paso-onda) - var(--grosor-onda) * 0.5),
      transparent var(--paso-onda)
    ),
    repeating-radial-gradient(
      ellipse 140% 90% at 88% 110%,
      transparent 0 calc(var(--paso-onda) * 1.45 - var(--grosor-onda) * 2),
      rgb(255 255 255 / calc(var(--trama-fondo) * 0.38))
        calc(var(--paso-onda) * 1.45 - var(--grosor-onda))
        calc(var(--paso-onda) * 1.45 - var(--grosor-onda) * 0.5),
      transparent calc(var(--paso-onda) * 1.45)
    );
  animation: deriva-ondas var(--deriva-ondas) ease-in-out infinite alternate;
  will-change: transform;
}

@keyframes deriva-ondas {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(3.2%, -2.4%, 0) scale(1.06); }
}

@media (prefers-reduced-motion: reduce) {
  .seccion--lineas .fondo-ondas {
    animation: none;
  }
}

/* Sobre fondo oscuro, el texto de la sección se pasa a claro. */
.seccion--lineas .seccion__titulo,
.seccion--lineas .carrusel__texto-titulo {
  color: var(--hueso);
}

.seccion--lineas .seccion__subtitulo,
.seccion--lineas .carrusel__texto-descripcion,
.seccion--lineas .carrusel__texto-etiqueta {
  color: var(--hueso-hondo);
}

.seccion--lineas .carrusel__texto-cta {
  color: var(--hueso);
}

.seccion--lineas .carrusel__flecha {
  border-color: rgb(255 255 255 / 0.35);
  color: var(--hueso);
}

.seccion--lineas .carrusel__flecha:hover {
  border-color: var(--acento);
  background: rgb(255 255 255 / 0.1);
}

.seccion--lineas .carrusel__punto::before {
  background: rgb(255 255 255 / 0.35);
}

.seccion--lineas .carrusel__punto[aria-selected="true"]::before {
  background: var(--acento);
}

@media (prefers-reduced-motion: reduce) {
  .seccion--lineas {
    transition: none;
  }
}

/* --------------------------------------------- Texto en primer plano */

/* Vive FUERA del aro: no gira, no se inclina, no se aleja. Se queda quieto
   debajo mientras el aro rueda por detrás, y al cambiar de línea sale hacia el
   mismo lado al que está girando el aro y entra por el contrario. Ese detalle
   —que la dirección de salida coincida con la del giro— es lo que hace que se
   lea como una sola pieza y no como dos animaciones sueltas. */
.carrusel__texto {
  flex: 1 0 100%;
  order: -1;                 /* justo debajo del aro, encima de los controles */
  display: grid;
  gap: var(--e-2);
  justify-items: center;
  min-height: clamp(8.5rem, 24vh, 11rem);   /* reserva el alto: cambiar de línea no salta */
  align-content: start;
  text-align: center;
  transform: translateX(0);
  opacity: 1;
  transition:
    transform var(--dur-media) var(--ease),
    opacity var(--dur-media) var(--ease);
}

/* Durante el salto al lado contrario no debe haber transición: si no, el texto
   se ve cruzar la pantalla de vuelta en vez de aparecer donde toca. */
.carrusel__texto--quieto {
  transition: none;
}

.carrusel__texto--sale-izq {
  transform: translateX(calc(var(--e-8) * -1));
  opacity: 0;
}

.carrusel__texto--sale-der {
  transform: translateX(var(--e-8));
  opacity: 0;
}

.carrusel__texto-etiqueta {
  margin: 0;
  font-family: var(--fuente-utilidad);
  font-size: var(--txt-xs);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--tinta-suave);
}

.carrusel__texto-titulo {
  margin: 0;
  font-family: var(--fuente-display);
  font-size: var(--txt-2xl);
  font-weight: 400;
  line-height: var(--alto-display);
  letter-spacing: -0.01em;
  text-transform: uppercase;
  color: var(--tinta);
}

.carrusel__texto-descripcion {
  margin: 0;
  max-width: 48ch;
  color: var(--tinta-suave);
}

.carrusel__texto-cta {
  display: inline-flex;
  align-items: center;
  min-height: var(--target-tactil);
  font-weight: 600;
  color: var(--tinta);
  text-decoration: none;
  border-bottom: 1px solid var(--acento);
}

.carrusel__texto-cta:hover,
.carrusel__texto-cta:focus-visible {
  color: var(--acento-fuerte);
}

@media (prefers-reduced-motion: reduce) {
  .carrusel__texto {
    transition: none;
    transform: none;
  }
}

/* El encabezado de la seccion no se muestra: chocaria con el navbar
   transparente que flota encima, y en la referencia el hero no lleva titulo
   propio. Clip y no display:none: el H2 sigue en la jerarquia para lectores
   de pantalla y buscadores. */
.seccion--lineas > .contenedor > .seccion__encabezado {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Franja oscura arriba de la seccion: hace legible el navbar transparente
   sobre las fotos. Pinta ENCIMA de las tarjetas, como en la referencia. */
.seccion--lineas::after {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 7rem;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(to bottom, rgb(0 0 0 / 0.38), rgb(0 0 0 / 0.12) 62%, rgb(0 0 0 / 0));
}

/* Rebanadas de la curvatura real. Sin overflow y sin clip: cualquiera de los
   dos aplanaría el preserve-3d y las rebanadas volverían a ser un plano. */
.carrusel--anillo .tarjeta-linea__lonjas {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  aspect-ratio: var(--proporcion-tarjeta);
  transform-style: preserve-3d;
  pointer-events: none;
}

.carrusel--anillo .tarjeta-linea__lonja {
  position: absolute;
  top: 0;
  left: 50%;
  height: 100%;
  background-repeat: no-repeat;

  /* El apagado por distancia va en brightness ESCALONADO (el JS lo cambia por
     niveles, no por cuadro) y la transición lo alisa. La tarjeta nunca es
     transparente: solo más oscura cuanto más atrás. */
  transition: filter var(--dur-media) var(--ease);

  /* La cara trasera SE VE: al otro lado del aro se sigue viendo la imagen,
     apagada por el brightness de distancia. Es el efecto de la referencia,
     sin el panel del dorso. */
  backface-visibility: visible;
}

/* Con rebanadas puestas, la figura plana entera se apaga: su caja blanca y
   su sombra son un rectángulo PLANO, y asomaban como picos por las esquinas
   de la tarjeta combada. La curva la pintan solo las rebanadas. */
.carrusel--anillo .tarjeta-linea--curvada .tarjeta-linea__imagen {
  visibility: hidden;
}

.carrusel--anillo .tarjeta-linea--curvada .tarjeta-linea__figura {
  background: none;
  border: 0;
  box-shadow: none;
}

/* -------------------------------- Fondo de vida (planta/ADN interactivo) */

/* Trazo blanco tenue con forma de tallo-hélice: lee como planta y como ADN a
   la vez, que es la doble lectura de la marca. Sigue al puntero desplazándose
   y girando apenas; la transición amortigua para que se sienta líquido. */
.seccion--lineas .fondo-vida {
  position: absolute;
  top: -4%;
  right: 4%;
  height: 108%;
  width: auto;
  z-index: -1;
  color: rgb(255 255 255 / 0.085);   /* al 14% el trazo competía con el aro */
  pointer-events: none;
  transform:
    translate3d(calc(var(--raton-x, 0) * 26px), calc(var(--raton-y, 0) * 16px), 0)
    rotate(calc(var(--raton-x, 0) * 2.5deg));
  transition: transform 480ms var(--ease);
}

@media (prefers-reduced-motion: reduce) {
  .seccion--lineas .fondo-vida {
    transition: none;
    transform: none;
  }
}

/* ------------------------------------ Miniaturas (previews) del anillo */

/* En móvil TAMBIÉN van: sin ellos el aro no tenía ninguna señal de que se
   puede pasar de línea (las flechas solo salen desde 768px), y el usuario
   tenía que adivinar el arrastre. Van más pequeñas, pero con los 44px de
   alto tocable que pide el dedo. */
.carrusel--anillo .carrusel__puntos {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  min-height: var(--target-tactil);
  align-items: center;
}

/* Los puntos del aro son miniaturas de cada línea, como la esquina inferior
   de la referencia. La activa va a todo color con su BARRA DE PROGRESO: el
   ancho lo pone --progreso, que el JS actualiza durante el ciclo de deriva. */
.carrusel--anillo .carrusel__puntos {
  gap: var(--e-2);
}

/* La miniatura SE VE de 30px de alto, pero se TOCA de 44: el relleno vertical
   agranda el botón y `content-box` deja la foto donde estaba. Un dedo no
   acierta en 30px, y son seis pegadas. */
.carrusel__punto--miniatura {
  --cinta-miniatura: 0.4375rem;   /* 7px: lo que le falta a 30 para llegar a 44 */
  width: 2.75rem;
  height: var(--target-tactil);
  padding: var(--cinta-miniatura) 0;
  border-radius: 6px;
  overflow: hidden;
  position: relative;
  background-clip: content-box;
  background-size: cover;
  background-position: center;
  filter: brightness(0.55);
  transition: filter var(--dur-rapida) var(--ease);
}

.carrusel__punto--miniatura::before {
  content: none;   /* fuera la pastilla: la miniatura ES el control */
}

.carrusel__punto--miniatura:hover {
  filter: brightness(0.8);
}

.carrusel__punto--miniatura[aria-selected="true"] {
  filter: none;
  /* el offset negativo trae el marco hasta el borde de la FOTO, no al del
     área tocable, que sobresale 7px por arriba y por abajo */
  outline: 2px solid var(--acento);
  outline-offset: calc(var(--cinta-miniatura) * -1);
}

.carrusel__punto--miniatura[aria-selected="true"]::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: var(--cinta-miniatura);
  height: 3px;
  width: calc(var(--progreso, 0) * 100%);
  background: var(--acento);
}

@media (min-width: 768px) {
  .carrusel__punto--miniatura {
    --cinta-miniatura: 0.375rem;
    width: 3rem;
    height: 2.75rem;
  }
}

@media (min-width: 1024px) {
  .carrusel__punto--miniatura {
    --cinta-miniatura: 0.25rem;
    width: 4rem;
    height: 3rem;
  }
}

/* ------------------------------------------- Escritorio: modo hero */

/* En pantallas grandes la referencia cambia de composición: la tarjeta del
   frente es casi un hero y el TEXTO SE MONTA sobre ella, abajo a la izquierda.
   Las flechas se apilan en vertical a la derecha y los puntos bajan a la
   esquina. En móvil nada de esto aplica: allí el texto sigue debajo. */
@media (min-width: 1024px) {

  /* El fondo sigue a pantalla completa; lo que baja es el ARO: el hueco de
     arriba deja ver la parte alta de las tarjetas, que antes quedaba metida
     debajo del navbar. */
  .seccion--lineas {
    padding-block: var(--e-24) var(--e-12);
  }

  .seccion--lineas .seccion__encabezado {
    margin-bottom: var(--e-2);
  }

  .carrusel--anillo {
    position: relative;
    margin-top: var(--e-4);
  }

  /* Manto local bajo el texto: encima de la tarjeta el blanco caía sobre acero
     pulido y el contraste dependía del fotograma. Es un degradado, no un
     `backdrop-filter`: cualquier filtro aquí aplanaría el 3D de al lado. */
  .carrusel--anillo .carrusel__texto::before {
    content: "";
    position: absolute;
    z-index: -1;
    inset: -12% -18% -30% -22%;
    background: radial-gradient(
      ellipse 68% 62% at 32% 62%,
      rgb(0 20 28 / 0.72) 0%,
      rgb(0 20 28 / 0.45) 46%,
      rgb(0 20 28 / 0) 78%
    );
  }

  .carrusel--anillo .carrusel__texto {
    position: absolute;
    z-index: 2;
    inset-inline-start: clamp(var(--e-8), 9vw, 9rem);
    inset-block-end: clamp(var(--e-8), 9vh, 6rem);
    order: initial;
    flex: none;
    width: min(44ch, 34vw);
    min-height: 0;
    justify-items: start;
    text-align: left;
  }

  .carrusel--anillo .carrusel__flecha {
    position: absolute;
    z-index: 2;
    inset-inline-end: clamp(var(--e-6), 4vw, 4rem);
    top: 50%;
    margin: 0;
  }

  .carrusel--anillo .carrusel__flecha--anterior {
    transform: translateY(-120%);
  }

  .carrusel--anillo .carrusel__flecha--siguiente {
    transform: translateY(20%);
  }

  .carrusel--anillo .carrusel__puntos {
    position: absolute;
    z-index: 2;
    inset-inline-end: clamp(var(--e-6), 4vw, 4rem);
    inset-block-end: clamp(var(--e-6), 6vh, 4rem);
    flex: none;
    order: initial;
  }
}
