/* ==========================================================================
   ANDÉN — estudio de arquitectura y visualización 3D · Cusco
   CSS a mano, sin framework.

   Por qué no Tailwind por CDN, que el encargo permitía: son ~100 KB de JS que
   se ejecutan en el navegador del visitante y provocan un parpadeo de texto
   sin estilo antes de pintar. Con el objetivo de <1 MB y en un mercado 90 %
   móvil, escribirlo a mano sale más ligero, pinta a la primera y —lo que más
   importa aquí— no se parece a nada.

   ESCALA: pocos escalones a propósito. Una página con diez tamaños de titular
   y doce de cuerpo no tiene sistema, tiene decisiones sueltas, y se nota.
   ========================================================================== */

/* ---------------- Fuentes auto-alojadas ----------------
   Sin <link> a Google: es una ida y vuelta a otro servidor antes de poder
   pintar texto, y en móvil peruano eso se paga. `swap` para que nunca haya
   un hueco en blanco esperando la fuente. */
@font-face { font-family: Archivo; src: url(fuentes/archivo-latin-400-normal.woff2) format("woff2"); font-weight: 400; font-display: swap; }
@font-face { font-family: Archivo; src: url(fuentes/archivo-latin-500-normal.woff2) format("woff2"); font-weight: 500; font-display: swap; }
@font-face { font-family: Archivo; src: url(fuentes/archivo-latin-600-normal.woff2) format("woff2"); font-weight: 600; font-display: swap; }
@font-face { font-family: Fraunces; src: url(fuentes/fraunces-latin-400-normal.woff2) format("woff2"); font-weight: 400; font-display: swap; }
@font-face { font-family: Fraunces; src: url(fuentes/fraunces-latin-500-normal.woff2) format("woff2"); font-weight: 500; font-display: swap; }
@font-face { font-family: "Inter Tight"; src: url(fuentes/inter-tight-latin-400-normal.woff2) format("woff2"); font-weight: 400; font-display: swap; }
@font-face { font-family: "Inter Tight"; src: url(fuentes/inter-tight-latin-500-normal.woff2) format("woff2"); font-weight: 500; font-display: swap; }

:root {
  --hueso: #f6f4f0;
  --superficie: #ede9e2;
  --tinta: #16181a;
  --texto: #6e6b65;
  --tenue: #9a968e;
  --linea: #e1dbd2;
  --acento: #9a5b34;      /* cobre quemado. Un solo acento, como pide el encargo. */

  --display: Archivo, ui-sans-serif, system-ui, sans-serif;
  /* Titulares en serifa (5 ago 2026, pedido del cliente: «más premium pero
     amigable»). Fraunces SOLO en h1-h3; la marca y los rótulos siguen en
     Archivo — una serifa en versalita espaciada se lee disfrazada. */
  --titular: Fraunces, Georgia, serif;
  --cuerpo: "Inter Tight", ui-sans-serif, system-ui, sans-serif;

  --t-h1: clamp(2rem, 7.2vw, 3.7rem);
  --t-h2: clamp(1.55rem, 4.6vw, 2.6rem);
  --t-h3: 1.15rem;
  --t-cifra: clamp(2rem, 6vw, 3rem);

  --ancho: 68rem;
  --aire: clamp(4rem, 11vw, 8rem);   /* separación vertical entre secciones */
  /* Alto real del nav: 0,9rem de padding arriba y abajo + los 40 px del
     botón. Lo usan el hero (para meterse debajo) y `scroll-margin-top`. */
  --nav-alto: 4.3rem;
  --curva: cubic-bezier(0.22, 1, 0.36, 1);
}
:root.reduce { --dur: 0.001s; }
:root { --dur: 1s; }

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
:root.reduce { scroll-behavior: auto; }

body {
  margin: 0;
  background: var(--hueso);
  color: var(--tinta);
  font: 400 1rem/1.65 var(--cuerpo);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img, video { max-width: 100%; height: auto; display: block; }
a { color: inherit; }

.envoltorio { width: 100%; max-width: var(--ancho); margin-inline: auto; padding-inline: 1.25rem; }
@media (min-width: 48rem) { .envoltorio { padding-inline: 2.5rem; } }

section { padding-block: var(--aire); }

/* ---------------- Tipografía ---------------- */
h1, h2, h3 { font-family: var(--titular); font-weight: 500; margin: 0; text-wrap: balance; letter-spacing: -0.01em; }
h1 { font-size: var(--t-h1); line-height: 1.06; letter-spacing: -0.03em; }
h2 { font-size: var(--t-h2); line-height: 1.12; letter-spacing: -0.025em; }
h3 { font-size: var(--t-h3); line-height: 1.3; letter-spacing: -0.01em; }
p  { margin: 0; }
.plomo { font-size: 1.0625rem; line-height: 1.7; color: var(--texto); max-width: 34rem; }
.nota  { font-size: 0.8125rem; line-height: 1.6; color: var(--tenue); }

/* El rótulo en versalita. UN valor de tracking para todos: seis valores
   distintos haciendo lo mismo es lo que delata que no hay sistema. */
.rotulo {
  font-family: var(--display);
  font-size: 0.6875rem; font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.18em;
  color: var(--acento);
}

/* ---------------- Motion ----------------
   Las clases NO cambian de árbol con «reducir movimiento»: solo se les pone
   la duración a cero. El estado inicial es idéntico siempre. */
.sube, .asienta { opacity: 0; transition: opacity calc(var(--dur) * 0.5) var(--curva), transform calc(var(--dur) * 0.55) var(--curva); }
.sube { transform: translateY(10px); }
.asienta { transform: translateY(-12px); }
.sube.visto, .asienta.visto { opacity: 1; transform: none; }

/* El recorte va en el PADRE y el movimiento en el hijo. Al revés, el hijo se
   esconde a sí mismo del observador y no aparece nunca (regla 1 de motion.js). */
.mascara { overflow: hidden; display: block; }
.mascara > * { display: block; transform: translateY(110%); transition: transform calc(var(--dur) * 0.85) var(--curva); }
.mascara.visto > * { transform: none; }

.traza { height: 1px; background: var(--linea); transform: scaleX(0); transform-origin: left; transition: transform var(--dur) var(--curva); }
.traza.visto { transform: scaleX(1); }
.traza.acento { background: var(--acento); }

/* Cascada: un solo observador en el grupo y los hijos escalonados por CSS.
   Escalonar con `transition-delay` en vez de con temporizadores hace que
   nada dependa de que el JS siga vivo. */
.grupo > * { opacity: 0; transform: translateY(14px); transition: opacity calc(var(--dur) * 0.5) var(--curva), transform calc(var(--dur) * 0.55) var(--curva); }
.grupo.visto > * { opacity: 1; transform: none; }
.grupo.visto > :nth-child(2) { transition-delay: 0.07s; }
.grupo.visto > :nth-child(3) { transition-delay: 0.14s; }
.grupo.visto > :nth-child(4) { transition-delay: 0.21s; }
.grupo.visto > :nth-child(5) { transition-delay: 0.28s; }
.grupo.visto > :nth-child(6) { transition-delay: 0.35s; }
:root.reduce .grupo.visto > * { transition-delay: 0s; }

/* ---------------- Botones ---------------- */
.boton {
  display: inline-flex; align-items: center; gap: 0.6rem;
  padding: 0.95rem 1.5rem; border-radius: 999px;
  font: 500 0.9375rem/1 var(--cuerpo); text-decoration: none;
  background: var(--tinta); color: var(--hueso);
  transition: transform 0.15s var(--curva), background 0.2s;
  min-height: 48px;   /* área de toque: el 90 % del tráfico es móvil */
}
.boton:hover { background: #000; }
.boton:active { transform: scale(0.975); }
.boton.contorno { background: transparent; color: var(--tinta); border: 1px solid var(--linea); }
.boton.contorno:hover { border-color: var(--tinta); background: transparent; }
/* Invertido, para cuando el botón vive sobre el vídeo: un botón tinta sobre
   un velo oscuro no se recorta contra nada. */
.boton.claro { background: var(--hueso); color: var(--tinta); }
.boton.claro:hover { background: #fff; }
.boton .flecha { transition: transform 0.2s var(--curva); }
.boton:hover .flecha { transform: translateX(3px); }

/* ---------------- Nav ---------------- */
.nav {
  position: sticky; top: 0; z-index: 50;
  transition: background 0.3s, border-color 0.3s, backdrop-filter 0.3s, color 0.3s;
  border-bottom: 1px solid transparent;
}
.nav.compacto { background: color-mix(in srgb, var(--hueso) 88%, transparent); backdrop-filter: blur(10px); border-bottom-color: var(--linea); }

/* 🔴 MIENTRAS EL NAV ESTÁ SOBRE EL VÍDEO VA EN CLARO. Es tinta sobre hueso en
   toda la página, pero los primeros 40 px de scroll lo dejan encima de un
   plano oscuro: ahí el logotipo, los enlaces y el botón negro desaparecían.
   `compacto` ya distingue los dos estados —lo pone el JS al pasar de 40 px—,
   así que basta colgarse de él. */
.nav:not(.compacto) { color: var(--hueso); }
/* 🔴 Y LLEVA SU PROPIA SOMBRA, porque el color solo no bastaba: MEDIDO sobre
   los 18 segundos del clip, el peor fotograma dejaba los enlaces en 2,05:1
   —la calle y el edificio claro pasan justo por detrás—, y un enlace de
   14 px necesita 4,5:1. Se oscurece SOLO la banda del nav en vez de subir el
   velo de todo el hero: así el cielo del plano sigue viéndose. */
.nav:not(.compacto)::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 220%;
  background: linear-gradient(to bottom, rgb(12 13 14 / 0.94), rgb(12 13 14 / 0.54) 46%, rgb(12 13 14 / 0));
  pointer-events: none; z-index: -1;
}
.nav:not(.compacto) .enlaces { color: rgb(246 244 240 / 0.74); }
.nav:not(.compacto) .enlaces a:hover { color: #fff; }
.nav:not(.compacto) .marca span { color: #d2905f; }
.nav:not(.compacto) .boton { background: var(--hueso); color: var(--tinta); }
.nav:not(.compacto) .boton:hover { background: #fff; }
.nav .fila { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding-block: 0.9rem; }
.marca { font-family: var(--display); font-weight: 600; font-size: 0.95rem; letter-spacing: 0.22em; text-transform: uppercase; text-decoration: none; }
.marca span { color: var(--acento); }
.nav .enlaces { display: none; gap: 1.75rem; font-size: 0.875rem; color: var(--texto); }
.nav .enlaces a { text-decoration: none; }
.nav .enlaces a:hover { color: var(--tinta); }
@media (min-width: 56rem) { .nav .enlaces { display: flex; } }
.nav .boton { padding: 0.7rem 1.1rem; font-size: 0.8125rem; min-height: 40px; white-space: nowrap; }

/* 🔴 EL NAV SE COMÍA EL PRINCIPIO DE LA SECCIÓN A LA QUE SE SALTA. Con el nav
   pegajoso arriba (≈69 px), un ancla deja el destino pegado a y=0 y la barra
   se pinta encima: el rótulo quedaba medio tapado y las TILDES desaparecían
   —«LÁMINA» se leía «LAMINA»—, porque el fondo del nav es opaco al 88 % y
   solo dejaba pasar un fantasma del acento. Se vio zoomeando una captura; a
   tamaño real parece un rótulo sin tilde, no un solape.
   Afecta a los seis enlaces internos de la página. */
section[id] { scroll-margin-top: 5.5rem; }

/* ---------------- Hero con vídeo a sangre ----------------
   El brief pide «la fotografía manda y el texto acompaña». Aquí manda del
   todo: el clip ocupa la pantalla y el texto es lo mínimo para saber dónde
   estás y qué hacer.

   🔴 EL VÍDEO SE METE DEBAJO DEL NAV con un margen negativo de su altura. El
   nav es `sticky`, o sea que va EN FLUJO: sin esto, el vídeo empezaría por
   debajo de la barra y quedaría una franja hueso arriba. Es el mismo truco
   del hero de UMBRAL en el portafolio de Enlazu. */
.hero {
  position: relative;
  margin-top: calc(-1 * var(--nav-alto));
  padding: 0;
  min-height: 78vh;            /* respaldo para navegadores sin svh */
  min-height: min(88svh, 52rem);
  display: flex; align-items: flex-end;
  overflow: hidden;
  background: #0c0d0e;         /* mientras el vídeo no ha pintado nada */
  color: var(--hueso);
}
.hero-fondo { position: absolute; inset: 0; }
.hero-video {
  width: 100%; height: 100%; object-fit: cover; display: block;
  /* El plano interesante vive en el centro-alto del encuadre; al recortar en
     vertical, se prefiere perder suelo antes que cielo. */
  object-position: center 42%;
}

/* 🔴 EL VELO SON DOS CAPAS SEPARADAS, Y NO ES UN CAPRICHO DE CÓDIGO.
   Sobre los 555 fotogramas del clip, la franja de abajo es la única oscura de
   forma constante (media 63 de 255, mínimo 45, MÁXIMO 123) y la de arriba es
   mid-tone (85-154): ni admite tinta ni admite blanco por sí sola.

   · La de ARRIBA es fija y pequeña: solo existe para que el nav se lea, y
     MEDIDO no depende de la otra (el nav da 5,15:1 con ella y sin ella).
   · La de ABAJO existe SOLO para el texto — y el texto ahora llega al final.
     Así que empieza en 0 y entra con él. Durante los 17,8 s el plano se ve
     LIMPIO, a contraste completo. Mirando un recorte a 1:1 en pantalla retina
     se veía que buena parte de lo que se leía como «poca calidad» era este
     velo apagando los ladrillos, no el archivo. */
.hero-fondo::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to bottom, rgb(12 13 14 / 0.34) 0%, rgb(12 13 14 / 0) 16%);
}
.hero-velo {
  position: absolute; inset: 0;
  opacity: 0;
  background:
    linear-gradient(to top,
      rgb(12 13 14 / 0.92) 0%, rgb(12 13 14 / 0.86) 30%,
      rgb(12 13 14 / 0.62) 52%, rgb(12 13 14 / 0.18) 72%,
      rgb(12 13 14 / 0) 88%);
}

/* ═══ LA ENTRADA DEL TEXTO ══════════════════════════════════════════
   TODOS los retardos viven en variables, y los modos solo cambian VALORES,
   nunca declaraciones. Así no hay ni una carrera de especificidad ni de
   orden de fuente en todo el bloque: es el fallo que más caro sale aquí,
   porque la regla perdedora no rompe nada — simplemente no se aplica, y la
   página se sigue viendo bien. */
.hero {
  --paso: 1;              /* multiplicador global de retardos */
  --d-rotulo: 200ms;
  --d-l1: 320ms;
  --d-l2: 410ms;
  --d-l3: 500ms;
  --d-cta: 820ms;
  --d-nota: 940ms;
}

/* MODO CORTO — scroll o Tab: el visitante se está yendo, o está pidiendo el
   contenido. Los mismos siete gestos, en el mismo orden, sin escalonado y a
   0,42 de duración: aterriza en ~320 ms. Cambian los TIEMPOS, no el árbol. */
.hero.listo[data-modo="corto"] { --paso: 0; --dur: 0.42s; }

/* REDUCIR MOVIMIENTO — (0,5,0): gana por SELECTOR, no por orden de fuente.
   `revelar()` siempre escribe `data-modo`, así que el atributo existe
   siempre y esta regla gana siempre. */
:root.reduce .hero.listo[data-modo] { --paso: 0; --dur: 0.001s; }

/* EL VELO ES EL TRASPASO DE MANDO: la imagen se retira y la tipografía
   entra. Va con `--dur`, así que «reducir movimiento» lo apaga solo.
   🔴 EL 0,75 ESTÁ CALCULADO, NO ELEGIDO: con la curva del sitio la salida
   vale 0,92 cuando el tiempo va por el 40,4 %, o sea 303 ms. El rótulo
   arranca a 200 ms y cruza el 50 % de su opacidad a 450 ms, con el velo ya
   al 99 %. REGLA A MANTENER SI SE TOCA ALGO: ninguna tinta alcanza fuerza
   antes de que el suelo esté puesto — es lo que mantiene válidos los
   5,20:1 del rótulo, que se midieron con el velo al 100 %. */
.hero-velo { transition: opacity calc(var(--dur) * 0.75) var(--curva); }
.hero.listo .hero-velo { opacity: 1; }

/* Las tres piezas ligeras. `.sube` sin tocar. */
.hero.listo .hero-texto .sube { opacity: 1; transform: none; }
.hero.listo .hero-texto .rotulo   { transition-delay: calc(var(--d-rotulo) * var(--paso)); }
.hero.listo .hero-texto .acciones { transition-delay: calc(var(--d-cta)    * var(--paso)); }
.hero.listo .hero-texto .nota     { transition-delay: calc(var(--d-nota)   * var(--paso)); }

/* ── EL TITULAR, LÍNEA A LÍNEA ────────────────────────────────────
   Es el único gesto nuevo, y es oficio tipográfico, no decoración: los
   saltos están elegidos a mano, no los decide el navegador. 90 ms de
   escalón con 620 ms de duración solapan dos líneas consecutivas un 85 %,
   así que se lee UNA frase escribiéndose y no tres cosas apareciendo (por
   debajo de 60 ms vuelve a ser una losa; por encima de 120 ms es una
   lista). Y es el límite antes de la autocita: el portafolio hermano hace
   máscara palabra a palabra, así que línea a línea es lo más lejos que se
   puede llegar sin repetirse. */
.hero-titular { margin-top: 1.1rem; max-width: 18ch; }

.hero-titular .linea {
  display: block;
  overflow: hidden;
  /* 🔴 REGLA DE LA TINTA: se despeja la TINTA, no la caja. Medido a 1440,
     el titular tiene 8,38 px libres arriba (la tilde de «dónde», el «¿») y
     0,38 px abajo (la «p» de «empezar») — menos de medio píxel. `overflow`
     recorta en la caja de RELLENO, así que el padding agranda la zona
     visible y el margen negativo devuelve exactamente lo mismo al layout:
     la posición del bloque no cambia en ningún ancho.
     Y no es solo por Archivo: las fuentes van con `font-display: swap`, y
     la caja de la de respaldo es ~0,075em más alta por lado. O sea que en
     el PRIMER pintado, y en cualquier despliegue donde el woff2 falle, esos
     0,38 px ya no existen y la «p» se corta. 0,18em cubre los dos casos. */
  padding-block: 0.18em;
  margin-block: -0.18em;
}
.hero-titular .linea > span {
  display: block;
  /* 🔴 125 % Y NO 110 %: la caja de recorte es ahora 0,36em más alta que la
     de contenido, así que el 110 % de siempre dejaría asomar la línea por
     arriba dentro del padding. El mínimo exacto es (1,06 + 0,18)/1,06 =
     117 %, y no depende del cuerpo porque padding y line-height van los dos
     en em. 125 % deja holgura. */
  transform: translateY(125%);
  transition: transform calc(var(--dur) * 0.62) var(--curva);
}
.hero.listo .hero-titular .linea > span { transform: none; }
.hero.listo .hero-titular .linea:nth-child(1) > span { transition-delay: calc(var(--d-l1) * var(--paso)); }
.hero.listo .hero-titular .linea:nth-child(2) > span { transition-delay: calc(var(--d-l2) * var(--paso)); }
.hero.listo .hero-titular .linea:nth-child(3) > span { transition-delay: calc(var(--d-l3) * var(--paso)); }

/* 🔴 UN CTA INVISIBLE NO PUEDE SER PULSABLE. Durante la espera el enlace
   está a opacidad 0 pero su caja de 48 px sigue ahí y recibe toques: un
   toque a ciegas sobre el vídeo abriría WhatsApp. Esto no toca el orden de
   tabulación, así que la ruta `foco` del JS sigue funcionando. */
.hero:not(.listo) .hero-texto { pointer-events: none; }

.hero-texto { position: relative; z-index: 1; padding-bottom: clamp(2.75rem, 6vw, 4.5rem); padding-top: 8rem; }
.hero .rotulo { color: var(--hueso); }
.hero .nota { color: rgb(246 244 240 / 0.62); }
.hero .acciones { margin-top: 2rem; display: flex; flex-wrap: wrap; gap: 0.75rem; }

@media (max-width: 47.99rem) {
  /* 🔴 MÁS BAJO EN EL TELÉFONO, y no por estética: un 16:9 dentro de una
     pantalla vertical se recorta por los lados, y cuanto más alto es el
     hueco menos ancho del vídeo se ve — o sea más aumento sobre el archivo.
     A 88svh se veía el 31 % del ancho (2,9× de aumento); a 72svh se ve el
     43 % (1,9×). Se nota en la nitidez y no cuesta nada. */
  .hero { min-height: 68vh; min-height: 72svh; }
  .hero-texto { padding-top: 6rem; }
}

/* ---------------- La mesa de planos ----------------
   El centro visual. Cuatro láminas tumbadas en isométrica que se hojean de
   lado: render, estructura, planta y terreno. Se pasa arrastrando, con las
   flechas, con los puntos o con las teclas ← →.

   Antes esto era una vista explotada ligada al scroll vertical y se comía
   TRES pantallas de alto. Igual de visual y en una sola: la profundidad la
   da la perspectiva, no el recorrido.

   🔴 TODO SALE DE UN SOLO NÚMERO, `--activo`, que el JS deja en el contenedor
   y puede ser fraccionario mientras arrastras. Cada lámina calcula su sitio
   con `--d` (su distancia a la activa), así que los estados intermedios son
   correctos por construcción y no hay saltos al soltar.

   🔴 Y LAS LÁMINAS SE TUMBAN, EL TEXTO NO. Solo la hoja lleva el `rotateX`;
   el rótulo vive fuera de esa transformación y queda derecho. Un texto en
   isométrica no se lee: se descifra. */
.mesa-seccion { overflow: hidden; }
.mesa-cabecera { max-width: 46rem; }

/* 🔴 DOS GRUPOS EN LA MISMA SECCIÓN, con la línea como columna de rejilla de
   1 px. Ponerla como borde de una de las dos columnas la ataría a la altura
   de esa columna; como celda propia mide lo que mide la fila y se puede
   animar sin tocar el layout de nadie.
   Por debajo de 60rem se apila: dos abanicos isométricos de media pantalla no
   se leen en un teléfono, y el 90 % del tráfico es móvil. */
.mesa-doble { display: grid; gap: 2.5rem; margin-top: 2.75rem; }
.mesa-col { min-width: 0; }
.mesa-col-cabecera { display: flex; align-items: flex-end; justify-content: space-between; gap: 1rem; }
.mesa-col-cabecera .nota { margin-top: 0.35rem; }
.mesa-col .mesa { margin-top: 1.75rem; }
/* 🔴 EL PIE DE LA LÁMINA VA ABSOLUTO, así que NO ocupa sitio: los puntos no
   se enteran de que existe. Con un pie de una línea colaba; en cuanto uno cae
   en dos —«Cada ambiente con sus metros y sus cotas.»— la segunda línea y los
   puntos acababan en el mismo renglón. Se reserva el hueco de dos líneas a
   mano, que es lo que cuesta un elemento fuera de flujo. */
.mesa-col .mesa-puntos { margin-top: 5.5rem; }

/* La línea, en el eje que toque. Es la misma hairline de `.traza` girada:
   en móvil se traza de izquierda a derecha, en escritorio de arriba abajo. */
.mesa-linea { width: 100%; height: 1px; background: var(--linea); }
.traza-v { transform: scaleX(0); transform-origin: left; transition: transform var(--dur) var(--curva); }
.traza-v.visto { transform: scaleX(1); }

.mesa-pie { margin-top: 2.75rem; max-width: 40rem; }
.mesa-pie a { color: var(--tinta); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--linea); }
.mesa-pie a:hover { text-decoration-color: var(--acento); }

@media (min-width: 60rem) {
  .mesa-doble { grid-template-columns: minmax(0, 1fr) 1px minmax(0, 1fr); gap: 0 2.75rem; }
  .mesa-linea { width: 1px; height: auto; align-self: stretch; }
  .traza-v { transform: scaleY(0); transform-origin: top; }
  .traza-v.visto { transform: scaleY(1); }

  /* 🔴 EN MEDIA COLUMNA EL ABANICO NO CABE CON LOS VALORES DE ANTES. El paso
     y el ancho de lámina estaban calculados para la mesa a todo lo ancho: con
     ellos la lámina más lejana se salía de su columna y cruzaba la línea. Se
     bajan los dos, y la altura con ellos para que no quede aire muerto. */
  .mesa-doble .mesa { --paso: clamp(2.1rem, 3.4vw, 3.2rem); height: clamp(11rem, 17vw, 15rem); }
  .mesa-doble .lamina { width: min(18rem, 56%); }
  .mesa-doble .lamina .hoja { box-shadow: 0 18px 40px rgb(0 0 0 / 0.2); }
}

.mesa-mandos { display: flex; gap: 0.5rem; }
.redondo {
  width: 44px; height: 44px; border-radius: 999px; flex: none;
  border: 1px solid var(--linea); background: transparent; color: var(--tinta);
  display: grid; place-items: center; cursor: pointer;
  transition: border-color 0.2s, background 0.2s, transform 0.15s var(--curva);
}
.redondo:hover { border-color: var(--tinta); }
.redondo:active { transform: scale(0.94); }
.redondo[disabled] { opacity: 0.3; cursor: default; }

.mesa {
  --activo: 0;
  /* El paso del abanico, en una unidad compartida por las láminas y por el
     tablero. Con porcentajes no salía: el % de la lámina se mide sobre su
     propio ancho y el del tablero sobre el de la mesa, así que la
     compensación de centrado nunca cuadraba. */
  --paso: clamp(4.5rem, 9vw, 8.5rem);
  /* Cuánto se compensa el abanico para que su masa quede centrada. En un
     teléfono vale 0 — ver la nota del `.tablero`. */
  --centrado: 0.62;
  position: relative;
  margin-top: 2.5rem;
  height: clamp(19rem, 46vw, 27rem);
  perspective: 1600px;
  cursor: grab;
  /* Deja pasar el scroll vertical del dedo y solo se queda con el horizontal:
     sin esto, arrastrar la mesa en el móvil secuestra el scroll de la página. */
  touch-action: pan-y;
  outline: none;
}
.mesa.arrastrando { cursor: grabbing; }
.mesa:focus-visible { outline: 2px solid var(--acento); outline-offset: 6px; border-radius: 0.5rem; }
/* 🔴 EL TABLERO SE MUEVE AL REVÉS QUE EL ABANICO, para mantenerlo centrado.
   Con la primera lámina al frente todas las demás se abren hacia la derecha y
   la composición quedaba con un hueco muerto a la izquierda — se vio en
   captura, no en el código. Desplazando el tablero por el centro del abanico
   (con 4 láminas, el centro es 1,5) la masa se queda en el medio y aun así se
   nota el movimiento lateral al pasar. */
.tablero {
  position: absolute; inset: 0;
  transform-style: preserve-3d;
  transform: translateX(calc((var(--activo) - 1.5) * var(--paso) * var(--centrado)));
  transition: transform 0.55s var(--curva);
}
.mesa.arrastrando .tablero { transition: none; }
:root.reduce .tablero { transition: none; }

.lamina {
  --d: calc(var(--i) - var(--activo));
  /* `abs()` todavía no es fiable en todos los navegadores; con max() sale lo
     mismo y funciona en todos. */
  --ad: max(var(--d), calc(-1 * var(--d)));
  position: absolute; left: 50%; top: 50%; margin: 0;
  width: min(30rem, 62%);
  /* 🔴 El centrado va en la MISMA transformación que el desplazamiento. Si se
     mete en un hijo, la imagen se ve centrada pero la CAJA queda media lámina
     corrida y aparecen desbordes laterales (lección de la noria, §33). */
  transform:
    translate(-50%, -50%)
    translateX(calc(var(--d) * var(--paso)))
    translateZ(calc(var(--ad) * -110px));
  opacity: max(0.28, calc(1 - var(--ad) * 0.3));
  transition: transform 0.55s var(--curva), opacity 0.4s linear;
  will-change: transform;
}
/* Mientras el dedo está abajo no hay transición: la lámina tiene que ir
   pegada al dedo, no persiguiéndolo medio segundo por detrás. */
.mesa.arrastrando .lamina { transition: none; }
:root.reduce .lamina { transition: none; }

.lamina .hoja {
  display: block; border-radius: 0.5rem; overflow: hidden;
  transform: rotateX(26deg) rotateZ(-9deg);
  box-shadow: 0 26px 60px rgb(0 0 0 / 0.22);
  background: var(--superficie);
}
.lamina img { width: 100%; height: auto; display: block; }

/* El rótulo, derecho y solo en la lámina que está al frente. */
.lamina figcaption {
  position: absolute; left: 0; top: calc(100% + 1.1rem); width: 100%;
  opacity: max(0, calc(1 - var(--ad) * 2.5));
  transition: opacity 0.3s linear;
  pointer-events: none;
}
.lamina figcaption p { margin-top: 0.3rem; font-size: 0.875rem; line-height: 1.55; color: var(--texto); }

.mesa-puntos { display: flex; gap: 0.5rem; justify-content: center; margin-top: 1.5rem; }
.mesa-puntos button {
  width: 34px; height: 34px; border: 0; background: transparent; padding: 0;
  display: grid; place-items: center; cursor: pointer;   /* 34px de área de toque para un punto de 7 */
}
.mesa-puntos button::before {
  content: ""; width: 7px; height: 7px; border-radius: 999px;
  background: var(--linea); transition: background 0.25s, transform 0.25s var(--curva);
}
.mesa-puntos button[aria-selected="true"]::before { background: var(--acento); transform: scale(1.5); }

@media (max-width: 47.99rem) {
  /* 🔴 EN EL TELÉFONO NO SE COMPENSA EL ABANICO. Visto en captura, no medido:
     con la compensación de escritorio el tablero se corre 67 px a la
     izquierda, y como la lámina activa ocupa el 74 % del ancho, se salía por
     el borde y su rótulo se leía «ENDER» y «o que vas a ver…» — el texto
     empezaba fuera de la pantalla. Aquí el hueco muerto que la compensación
     evita (§5, fallo 2) no existe, porque las láminas vecinas se salen de la
     pantalla igual: lo único que importa es que la lámina de delante quede
     centrada. El desborde no lo cantaba ninguna métrica porque la sección
     lleva `overflow:hidden` y `scrollWidth` seguía valiendo 390. */
  .mesa { height: clamp(15rem, 62vw, 20rem); margin-top: 2rem; --centrado: 0; }
  .lamina { width: 74%; }
  .lamina figcaption { top: calc(100% + 0.8rem); }
}

/* ---------------- Comparador antes / después ----------------
   El corte se hace con `clip-path` sobre la capa de arriba: no re-maqueta
   nada, así que arrastrar no provoca reflow y va fluido en un teléfono. */
.comparador { position: relative; border-radius: 1rem; overflow: hidden; background: var(--superficie); aspect-ratio: 4 / 3; touch-action: pan-y; --corte: 50%; }
@media (min-width: 48rem) { .comparador { aspect-ratio: 16 / 9; } }
.comparador img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.comparador .despues { clip-path: inset(0 0 0 var(--corte)); }
.comparador .barra { position: absolute; top: 0; bottom: 0; left: var(--corte); width: 2px; background: var(--hueso); pointer-events: none; }
.comparador .tirador {
  position: absolute; top: 50%; left: var(--corte);
  width: 44px; height: 44px; margin: -22px 0 0 -22px; border-radius: 999px;
  background: var(--hueso); color: var(--tinta);
  display: grid; place-items: center; font-size: 0.8rem; pointer-events: none;
  box-shadow: 0 2px 10px rgb(0 0 0 / 0.18);
}
.comparador input[type=range] { position: absolute; inset: auto 0 1rem; width: calc(100% - 2rem); margin-inline: 1rem; opacity: 0; height: 44px; cursor: ew-resize; }
.comparador input[type=range]:focus-visible { opacity: 1; }
.comparador .etiqueta { position: absolute; bottom: 0.85rem; font-family: var(--display); font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.16em; color: var(--hueso); text-shadow: 0 1px 6px rgb(0 0 0 / 0.5); }
.comparador .etiqueta.izq { left: 1rem; }
.comparador .etiqueta.der { right: 1rem; }

/* ---------------- Rejillas ---------------- */
.rejilla { display: grid; gap: 1px; background: var(--linea); border: 1px solid var(--linea); border-radius: 0.75rem; overflow: hidden; }
.rejilla > * { background: var(--hueso); padding: 1.6rem; }
@media (min-width: 40rem) { .rejilla.dos { grid-template-columns: 1fr 1fr; } }
@media (min-width: 56rem) { .rejilla.tres { grid-template-columns: repeat(3, 1fr); } }

.lista-check { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.9rem; }
.lista-check li { display: flex; gap: 0.75rem; align-items: flex-start; font-size: 0.9375rem; line-height: 1.6; }
.lista-check .tic { flex: none; width: 1.15rem; height: 1.15rem; margin-top: 0.18rem; color: var(--acento); }

/* ---------------- Bloque oscuro (el sello legal) ---------------- */
.oscuro { background: var(--tinta); color: var(--hueso); }
.oscuro .plomo, .oscuro .nota { color: color-mix(in srgb, var(--hueso) 62%, transparent); }
.oscuro .rotulo { color: #d2905f; }
.oscuro .rejilla { background: rgb(255 255 255 / 0.12); border-color: rgb(255 255 255 / 0.12); }
.oscuro .rejilla > * { background: var(--tinta); }
.oscuro .traza { background: rgb(255 255 255 / 0.14); }

/* ---------------- Proyectos ---------------- */
.proyecto figure { margin: 0; }
.proyecto .foto { border-radius: 0.75rem; overflow: hidden; background: var(--superficie); aspect-ratio: 4 / 3; }
.proyecto .foto img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.9s var(--curva); }
.proyecto:hover .foto img { transform: scale(1.04); }
.proyecto figcaption { margin-top: 0.9rem; display: flex; justify-content: space-between; gap: 1rem; align-items: baseline; }

/* Carrusel en móvil: apilar seis tarjetas hace páginas de veinte pantallas. */
.carrusel { display: grid; gap: 1.25rem; }
@media (max-width: 47.99rem) {
  .carrusel { grid-auto-flow: column; grid-auto-columns: 82%; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; margin-inline: -1.25rem; padding-inline: 1.25rem; }
  .carrusel::-webkit-scrollbar { display: none; }
  .carrusel > * { scroll-snap-align: start; }
}
@media (min-width: 48rem) { .carrusel.tres { grid-template-columns: repeat(3, 1fr); } }

/* ---------------- Proceso ---------------- */
.paso { position: relative; padding-top: 1.4rem; }
.paso .n { font-family: var(--display); font-size: 0.75rem; font-weight: 600; letter-spacing: 0.1em; color: var(--acento); }
.paso h3 { margin-top: 0.6rem; }
.paso p { margin-top: 0.5rem; font-size: 0.9375rem; line-height: 1.65; color: var(--texto); }

/* ---------------- Cobertura ---------------- */
.distritos { display: flex; flex-wrap: wrap; gap: 0.5rem; list-style: none; padding: 0; margin: 0; }
.distritos li { border: 1px solid var(--linea); border-radius: 999px; padding: 0.5rem 0.95rem; font-size: 0.875rem; }

/* ---------------- Preguntas ---------------- */
.pregunta { border-top: 1px solid var(--linea); }
.pregunta:last-of-type { border-bottom: 1px solid var(--linea); }
.pregunta summary { list-style: none; cursor: pointer; padding-block: 1.15rem; display: flex; justify-content: space-between; gap: 1.5rem; align-items: baseline; font-family: var(--display); font-weight: 500; font-size: 1rem; }
.pregunta summary::-webkit-details-marker { display: none; }
.pregunta summary::after { content: "+"; color: var(--acento); font-size: 1.25rem; line-height: 1; flex: none; transition: transform 0.25s var(--curva); }
.pregunta[open] summary::after { transform: rotate(45deg); }
.pregunta .respuesta { height: 0; overflow: hidden; transition: height 0.3s var(--curva); }
.pregunta .respuesta p { padding-bottom: 1.3rem; max-width: 46rem; font-size: 0.9375rem; line-height: 1.7; color: var(--texto); }
:root.reduce .pregunta .respuesta { transition: none; }

/* ---------------- Cierre y pie ---------------- */
.cierre { text-align: center; }
.cierre h2 { max-width: 16ch; margin-inline: auto; }
.pie { border-top: 1px solid var(--linea); padding-block: 2.5rem; font-size: 0.8125rem; color: var(--tenue); }
.pie .fila { display: flex; flex-wrap: wrap; gap: 1rem; justify-content: space-between; align-items: center; }

/* ---------------- WhatsApp flotante ----------------
   Persistente en móvil, como pide el encargo. `env(safe-area-inset-bottom)`
   para que no quede debajo de la barra del iPhone. */
.flotante {
  position: fixed; right: 1rem; z-index: 60;
  bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
  display: inline-flex; align-items: center; gap: 0.55rem;
  padding: 0.85rem 1.2rem; border-radius: 999px;
  background: var(--tinta); color: var(--hueso);
  font: 500 0.875rem/1 var(--cuerpo); text-decoration: none;
  box-shadow: 0 6px 24px rgb(0 0 0 / 0.22);
}
@media (min-width: 56rem) { .flotante { display: none; } }

/* ---------------- Pasada de móvil (5 ago 2026) ----------------
   Medida con el barrido de 390×844 (ver-movil.mjs del proyecto de Enlazu):
   0 desbordes reales —el abanico recortado y el carrusel con asomo son
   diseño—, pero 15 rótulos a 11 px y los puntos de las mesas con 34 px de
   toque. Aquí solo se corrige eso: legibilidad y área táctil, sin tocar la
   composición. */
@media (max-width: 47.99rem) {
  .rotulo { font-size: 0.75rem; }
  .comparador .etiqueta { font-size: 0.75rem; }
  /* 44 px es el mínimo táctil; el punto dibujado sigue midiendo 7. */
  .mesa-puntos button { width: 44px; height: 44px; }
  .mesa-puntos { gap: 0.25rem; }
  /* El logo es un enlace de 25 px de alto: se le da masa táctil con
     padding compensado, sin mover el layout. */
  .nav .marca { padding: 0.6rem; margin: -0.6rem; }
}
