/* ===========================================================
   MOKAH — Sistema visual
   Dominante oscura. Brutalismo en la estructura, Art Déco en el
   detalle (arco + doble línea), fotografía y vídeo como narrativa.

   ÍNDICE
    1 Tokens · 2 Reset · 3 Tipografía · 3b Textura
    4 Doble línea · 5 Botones · 6 Media
    7 Header · 8 Menú fullscreen
    9 Hero
   10 Escenarios fijados: piezas comunes y orden de apilado
   11 Masa de tierra y manifiesto · 12 Tres pilares
   13 Cada ritual (revelado) · 14 Rituales partidos
   15 Refugio · 16 Esencia · 17 Art Déco
   18 Reseñas · 19 Reserva · 20 Footer · 21 Movimiento: reveal y rise
   =========================================================== */

/* ---------- 1. Tokens ---------- */
:root{
  /* Paleta bruta */
  --carbon:        #2F2B27;
  --carbon-deep:   #221F1C;
  --carbon-raised: #3A352F;
  --terracota:     #973E16;
  /* Naranja del logotipo. Sustituye a la arcilla #BB6A32 del brief: son
     el mismo valor tonal (3,5:1 sobre carbón), así que ninguna medida
     cambia, y una paleta con dos naranjas indistinguibles es un error. */
  --marca:         #C76223;
  --arcilla:       var(--marca);
  --arcilla-alta:  #CF8A4E;  /* arcilla elevada en valor: 4,95:1 sobre carbón */
  --arena:         #C9AB8F;
  --musgo:         #545B46;
  --hueso:         #EFE7DD;
  --carbon-soft:   #655F58;  /* derivado: carbón 72% + hueso 28% */

  /* Roles — tema oscuro por defecto */
  --bg:         var(--carbon);
  --bg-deep:    var(--carbon-deep);
  --surface:    var(--carbon-raised);
  --ink:        var(--hueso);
  --ink-muted:  var(--arena);      /* 6,5:1 sobre carbón */
  /* --accent es para TEXTO: tiene que pasar 4,5:1 aunque sea pequeño.
     Arcilla pura (3,5:1) queda solo para grafismo y display grande. */
  --accent:     var(--arcilla-alta); /* 5,0:1 sobre carbón · 5,8:1 sobre profundo */
  --fill:       var(--terracota);  /* solo relleno, nunca tinta sobre oscuro */
  --line:       rgb(239 231 221 / .18);
  --line-strong:rgb(239 231 221 / .34);

  /* Tipografía */
  /* Amiri es la display que usa Bucuti & Tara en sus titulares grandes.
     OFL, libre para uso comercial. Extensores largos y altura de x
     pequeña: pide interlineado algo más suelto que una didone. */
  --serif: "Amiri", Georgia, "Times New Roman", serif;
  --sans:  "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;

  /* Ritmo */
  --gut:   clamp(1.25rem, 4vw, 3.5rem);
  --bay:   clamp(5rem, 12vw, 11rem);   /* separación entre capítulos */
  --maxw:  1440px;

  /* Art Déco — arco */
  --arch: 50% 50% 0 0 / 42% 42% 0 0;

  /* Movimiento */
  --ease: cubic-bezier(.22,.61,.36,1);
  /* Salida exponencial, sin rebote: es la curva del revelado por máscara.
     Arranca rápido y se posa; nada vuelve atrás. */
  --ease-rise: cubic-bezier(.16,1,.3,1);
  --slow: 1.1s;
  --rise-t: 1.05s;

  /* El velo de los escenarios de imagen. Un solo color en todo el sitio,
     el mismo del carbón profundo, para que ninguna capa tiña. */
  --veil: 34 31 28;
}

/* Capítulo claro — el único del sitio */
.chapter--bone{
  --bg:        var(--hueso);
  --bg-deep:   var(--hueso);
  --surface:   #E4D9CB;
  --ink:       var(--carbon);
  --ink-muted: var(--carbon-soft);   /* 5,0:1 sobre hueso */
  --accent:    var(--terracota);     /* 5,7:1 sobre hueso */
  --line:      rgb(47 43 39 / .18);
  --line-strong:rgb(47 43 39 / .34);
}

/* ---------- 2. Reset ---------- */
*,*::before,*::after{ box-sizing:border-box }
html{ scroll-behavior:smooth; -webkit-text-size-adjust:100% }
body{
  margin:0;
  background:var(--carbon);
  color:var(--hueso);
  font:300 clamp(.95rem,.35vw + .85rem,1.0625rem)/1.65 var(--sans);
  overflow-x:clip;
  -webkit-font-smoothing:antialiased;
}
img,video,svg{ display:block; max-width:100% }
h1,h2,h3,p,dl,dd,figure,blockquote{ margin:0 }
ul,ol{ margin:0; padding:0; list-style:none }
a{ color:inherit; text-decoration:none }
button{ font:inherit; color:inherit; background:none; border:0; padding:0; cursor:pointer }

.wrap{ width:100%; max-width:var(--maxw); margin-inline:auto; padding-inline:var(--gut) }
.vh{ position:absolute!important; width:1px; height:1px; overflow:hidden; clip-path:inset(50%) }
.skip{
  position:absolute; left:var(--gut); top:-4rem; z-index:200;
  background:var(--hueso); color:var(--carbon); padding:.6rem 1rem;
  font-size:.8rem; letter-spacing:.06em; transition:top .2s;
}
.skip:focus{ top:1rem }
:focus-visible{ outline:1px solid var(--arena); outline-offset:4px }

/* Superficies del navegador. Selección, barra y caret vienen con los
   colores del sistema y no pertenecen a ningún sistema de diseño. */
::selection{ background:var(--terracota); color:var(--hueso) }
.chapter--bone ::selection{ background:var(--arena); color:var(--carbon) }
html{ scrollbar-color:var(--carbon-raised) var(--carbon-deep); scrollbar-width:thin }
::-webkit-scrollbar{ width:10px; height:10px }
::-webkit-scrollbar-track{ background:var(--carbon-deep) }
::-webkit-scrollbar-thumb{ background:var(--carbon-raised); border:2px solid var(--carbon-deep) }
::-webkit-scrollbar-thumb:hover{ background:#4A443C }
body{ caret-color:var(--arena) }

/* ---------- 3. Tipografía ---------- */
h1,h2,h3,.manifesto,.quote p,.deco__line,.hdr__mark,.ftr__mark{
  font-family:var(--serif); font-weight:400; letter-spacing:-.005em;
}
/* Interlineado ajustado a los extensores de Amiri: por debajo de 1,04 en
   H1 la "q" de "queda" choca con la línea siguiente. */
h1{ font-size:clamp(3.1rem,11vw,9rem); line-height:1.04 }
h2{ font-size:clamp(2rem,5.4vw,4.25rem); line-height:1.1 }
h3{ font-size:clamp(1.4rem,2.4vw,2.1rem); line-height:1.18 }

/* Las cejas y la numeración de sección salieron del sitio: el titular
   carga su propio peso y una etiqueta en versalitas encima no aportaba
   nada que el propio titular no dijera. */
.lead{
  max-width:46ch; color:var(--ink-muted);
  font-size:clamp(1rem,.4vw + .9rem,1.15rem); line-height:1.7;
}
.note{
  margin-top:2.5rem; font-size:.78rem; letter-spacing:.04em;
  color:var(--ink-muted); opacity:.75;
}
.note a{ border-bottom:1px solid var(--line-strong); padding-bottom:1px }

/* ---------- 3b. Textura de material ---------- */
/* La fuente venía como SVG de 5,26 MB con un JPEG de 3780px embebido en
   base64. Extraída y reescalada a 1100px WebP (78 KB, −98%).
   Capa fija a cover: no se repite, así que no hay costuras ni el patrón
   simétrico que delataría un mosaico. soft-light al 13% enriquece sin
   mover apenas la luminancia — verificado sobre el titular del hero. */
:root{ --grain: url("../media/textura.webp") }
.grain{
  /* inset negativo: la deriva no debe destapar el borde del mosaico. */
  position:fixed; inset:-6%; z-index:6; pointer-events:none;
  background:var(--grain) 0 0/300px repeat;
  opacity:.13; mix-blend-mode:soft-light;
}
/* Sobre el capítulo hueso la textura oscurece en vez de aclarar, así que
   se afloja para no ensuciar el único fondo claro del sitio. */
.chapter--bone{ position:relative; isolation:isolate }
.chapter--bone::after{
  content:""; position:absolute; inset:0; z-index:1; pointer-events:none;
  background:var(--grain) 0 0/300px repeat;
  opacity:.07; mix-blend-mode:multiply;
}
.chapter--bone > *{ position:relative; z-index:2 }

@media (prefers-reduced-motion:no-preference){
  /* Deriva imperceptible: 90 s por ciclo. Da vida al material sin que
     nada se mueva a la vista. */
  .grain{ animation:grano 90s var(--ease) infinite alternate }
}
@keyframes grano{
  from{ transform:scale(1.04) translate3d(-1%,-1%,0) }
  to{   transform:scale(1.04) translate3d(1%,1.5%,0) }
}

/* ---------- 4. Art Déco: doble línea ---------- */
.rule--double{ height:5px; position:relative }
.rule--double::before,.rule--double::after{
  content:""; position:absolute; inset-inline:0; height:1px; background:var(--line-strong);
}
.rule--double::before{ top:0 }
.rule--double::after{ top:4px }

/* ---------- 5. Botones ---------- */
.btn{
  display:inline-block; font-family:var(--sans); font-size:.74rem; font-weight:500;
  letter-spacing:.18em; text-transform:uppercase; border-radius:0;
  transition:color .4s var(--ease), background-color .4s var(--ease), border-color .4s var(--ease);
}
.btn--line{
  padding:.9rem 0 .55rem; border-bottom:1px solid var(--line-strong); color:var(--ink);
}
.btn--line:hover{ color:var(--accent); border-color:var(--accent) }
.btn--solid{
  padding:1.25rem 2.6rem; background:var(--fill); color:var(--hueso);
  border:1px solid var(--fill);
}
.btn--solid:hover{ background:transparent; color:var(--arena); border-color:var(--arena) }

/* ---------- 6. Media: placeholder + arco ---------- */
/* El texto de data-shot es la lista de tomas. Al llegar la fotografía
   real se sustituye el div por <img>/<video> y se conserva la clase. */
.media{
  position:relative; width:100%; aspect-ratio:4/5; overflow:clip;
  background:
    radial-gradient(120% 90% at 30% 12%, rgb(187 106 50 / .30), transparent 62%),
    radial-gradient(140% 110% at 82% 88%, rgb(84 91 70 / .34), transparent 58%),
    linear-gradient(168deg, #423A32 0%, #2A2622 58%, #201D1A 100%);
}
.media::before{
  content:""; position:absolute; inset:0; opacity:.5; mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
}
.media::after{
  content:attr(data-shot);
  position:absolute; inset:auto 8% 8%;
  font-family:var(--sans); font-size:.66rem; font-weight:400;
  letter-spacing:.1em; line-height:1.6; text-transform:uppercase;
  color:rgb(239 231 221 / .82);   /* 8:1 sobre el placeholder: legible como lista de tomas */
}
/* Cuando el hueco ya tiene fotografía, la etiqueta de rodaje no se pinta,
   pero el atributo se conserva en el marcado: es la fuente de la lista de
   tomas de assets/media/README.md y este material sigue siendo provisional.
   Borrar el data-shot al poner una foto provisional habría borrado también
   la instrucción de qué hay que rodar en su lugar. */
.media:has(img)::after,
.media:has(video)::after{ content:none }

.media--arch{ border-radius:var(--arch) }
.media img,.media video{ width:100%; height:100%; object-fit:cover }

/* ---------- 7. Header ---------- */
.hdr{
  position:fixed; inset:0 0 auto; z-index:100;
  display:flex; align-items:center; justify-content:space-between;
  padding:1.5rem var(--gut);
  /* Solo color: animar el padding de un elemento fijo provoca layout en
     cada frame del scroll. La compactación no vale ese coste. */
  transition:background-color .5s var(--ease), backdrop-filter .5s var(--ease);
}
.hdr.is-stuck{ background:rgb(34 31 28 / .92); backdrop-filter:blur(14px) }

/* Sobre los capítulos de imagen el header renuncia a su banda.
   No es una concesión: la banda de cabecera del velo de cada escenario
   —near-opaca en el 8,5% superior y disuelta al 19%— sostiene los mismos
   contrastes que la barra, pero se lee como el oscurecimiento natural de
   una fotografía en vez de como cromo de interfaz. Medido en DESIGN.md §6:
   marca 3,5:1 · «ESCRÍBENOS» 9,9:1 sobre el peor fotograma de las tres
   imágenes en cuatro proporciones de pantalla. */
.hdr.is-clear.is-stuck{ background:transparent; backdrop-filter:none }

/* Con el menú abierto el header pierde su fondo: la superficie del menú
   ya hace de fondo y una banda propia lo partiría en dos.
   El fondo se va con 0,75 s de retardo, no de golpe: la masa entra por
   la esquina superior derecha y el extremo del logotipo es lo último que
   cubre, sobre el segundo 0,85. Quitarlo antes dejaría «MENÚ» y
   «ESCRÍBENOS» sin respaldo sobre la página aún visible. */
.menu-abierto .hdr.is-stuck{
  background:transparent;
  backdrop-filter:none;
  transition:background-color .35s linear .75s;
}
/* Wordmark e isotipo, ambos en el naranja del logotipo original.
   Caja de tamaño fijo con los dos marcas apiladas: el relevo es un cruce
   de transform y opacidad, así que el header no recompone nada. La
   anchura la fija el wordmark, que es el más ancho. */
.hdr__mark{
  position:relative; display:block;
  width:clamp(108px,11vw,148px); height:42px;
}
.mark,
.iso{
  position:absolute; left:0; top:50%;
  fill:var(--marca);
  transition:opacity .5s var(--ease), transform .5s var(--ease);
}
.mark{ width:100%; height:auto; transform:translateY(-50%) }
.iso{ width:auto; height:38px; transform:translateY(-50%) translateY(14px); opacity:0 }

/* Al despegar del hero, el wordmark sube y sale; entra el isotipo. */
.hdr.is-stuck .mark{ opacity:0; transform:translateY(-50%) translateY(-14px) }
.hdr.is-stuck .iso{ opacity:1; transform:translateY(-50%) }

.hdr__mark:hover .mark,
.hdr__mark:hover .iso{ fill:var(--arcilla-alta) }

/* Con movimiento reducido el relevo sigue ocurriendo, pero sin
   desplazamiento: solo el cambio de opacidad, que es el que informa. */
@media (prefers-reduced-motion:reduce){
  .iso{ transform:translateY(-50%) }
  .hdr.is-stuck .mark{ transform:translateY(-50%) }
}
.hdr__right{ display:flex; align-items:center; gap:clamp(.35rem,1.2vw,1.1rem) }

/* ---- Iconos ---- */
/* Un solo tamaño: 17px. currentColor en todos, así el color lo pone el
   contexto y no el archivo. */
.ico{ display:block; width:17px; height:17px; fill:currentColor }

.social{ display:flex; align-items:center }
.social a{
  display:grid; place-items:center; padding:.72rem;
  color:var(--ink);
  transition:color .35s var(--ease), opacity .35s var(--ease);
}
.social a:hover{ color:var(--arcilla-alta) }
/* Filete de separación: las redes salen del sitio, el menú y la reserva
   se quedan dentro. Son dos funciones distintas y conviene marcarlo. */
.social::after{
  content:""; width:1px; height:15px; margin-inline:.5rem .15rem;
  background:var(--line-strong);
}

/* ---- Botón de menú ---- */
/* Área de pulsación de 44px con el icono de 22: el mínimo cómodo en
   táctil. */
.hdr__menu{
  position:relative; display:grid; place-items:center;
  width:44px; height:44px; color:var(--ink);
  transition:color .35s var(--ease);
}
.hdr__menu:hover{ color:var(--arcilla-alta) }

/* Las tres barras se transforman en la cruz: la de arriba baja y gira
   +45°, la de abajo sube y gira −45°, la del medio se contrae a cero.
   Conserva la geometría escalonada del icono original —11px, 16,5px,
   11px sobre una caja de 22— porque esa es su firma.
   Todas comparten anchura base de 22px y la diferencia la hace scaleX:
   así no se animan anchuras, solo transforms. */
.burger{ position:relative; display:block; width:22px; height:22px }
.burger i{
  position:absolute; left:0; width:22px; height:2px;
  background:currentColor; border-radius:0;
  /* Ease-out exponencial, no rebote: el rebote en un control de 22px se
     lee como un temblor, no como energía. */
  transition:transform .45s var(--ease-rise), opacity .2s linear;
}
.burger i:nth-child(1){ top:3.6px;  transform:translateX(25%) scaleX(.5) }
.burger i:nth-child(2){ top:10px;   transform:translateX(12.5%) scaleX(.75) }
.burger i:nth-child(3){ top:16.4px; transform:translateX(25%) scaleX(.5) }

/* Cruz: las diagonales de un cuadro de 12,8px miden 18,1 → scaleX(.82) */
.hdr__menu[aria-expanded="true"] .burger i:nth-child(1){
  transform:translateY(6.4px) rotate(45deg) scaleX(.82);
}
.hdr__menu[aria-expanded="true"] .burger i:nth-child(2){
  transform:scaleX(0); opacity:0;
}
.hdr__menu[aria-expanded="true"] .burger i:nth-child(3){
  transform:translateY(-6.4px) rotate(-45deg) scaleX(.82);
}

/* Con movimiento reducido las barras llegan a la cruz sin recorrido. */
@media (prefers-reduced-motion:reduce){
  .burger i{ transition:opacity .15s linear }
}

/* Sin filete inferior: en una franja de 44px el subrayado competía con el
   que separa las redes y metía una segunda línea horizontal. El cambio de
   color en hover ya informa de que es pulsable, y el área de pulsación se
   mantiene con el padding. */
.hdr__cta{
  padding-block:.6rem .5rem; color:var(--ink);
  transition:color .35s var(--ease);
}
.hdr__cta:hover{ color:var(--accent) }

/* En móvil las redes salen del header: no caben junto al logotipo, el
   menú y el CTA. Viven en el pie del menú fullscreen. */
@media (max-width:760px){
  .social{ display:none }
}

/* ---------- 8. Menú fullscreen ---------- */
:root{
  --curtain: cubic-bezier(.16,1,.3,1);
  /* Medido en el vídeo de referencia: la masa tarda ~630 ms en cubrir de
     esquina a esquina, y el cierre es un fundido uniforme de ~670 ms.
     Más lento y más largo a propósito: el cliente pidió que la llegada
     fuera elegante, no rápida. 1,15 s deja ver el frente desenfocado
     recorrer la pantalla en lugar de solo registrar el cambio. */
  --sweep:   cubic-bezier(.24,.68,.20,1);
  --sweep-t: 1.15s;
  --fade-out:.5s;
  /* Tamaño del lóbulo. El caso peor es un viewport cuadrado, donde la
     diagonal mide 141,4vmax: con 320vmax de lado y el núcleo opaco al
     96%, sobran 122px incluso ahí. Con 260vmax faltaban 231px. */
  --lobe: 320vmax;
  /* Superficie del menú. La referencia mide #0B0B0B con saturación 0;
     esta mantiene un resto cálido (R>G>B) para no salirse de la marca,
     pero está igual de cerca del negro. 15,2:1 con tinta hueso. */
  --menu-bg:#241F1A;
}

.nav{
  position:fixed; inset:0; z-index:90; background:transparent;
  display:flex; flex-direction:column; justify-content:center;
  padding:6rem var(--gut);
}
.nav[hidden]{ display:none }
/* Mientras no está abierto no debe interceptar clics: el telón está
   fuera de pantalla pero el <nav> sigue cubriendo el viewport. */
.nav:not(.is-open){ pointer-events:none }

/* La masa que inunda. Tres lóbulos circulares con el centro clavado
   junto a la esquina superior derecha, que crecen por scale desde 0.
   Se usa scale y no mask-size porque el transform lo compone la GPU: un
   mask-size animado repinta un mapa a pantalla completa cada frame.
   Sin `opacity` aquí, a propósito. Un ancestro con opacity < 1 crea un
   backdrop root y aislaría el backdrop-filter de los lóbulos: el
   desenfoque no vería la página, solo el interior del telón. El fundido
   de cierre lo hacen los hijos, uno a uno. */
.nav__curtain{
  position:absolute; inset:0; z-index:-1; overflow:clip;
}

/* El borde de cada lóbulo es un degradado ANCHO —el 26% exterior del
   radio, unos 480px— no un canto. Un arco de círculo nítido delata la
   geometría; una zona de desvanecimiento de ese tamaño se lee como una
   mancha que se extiende.
   Los tres arrancan a la vez y se diferencian por origen y escala final.
   Escalonarlos no servía: a mitad de recorrido los retrasados quedaban
   dentro del primero y no aportaban ningún lóbulo al frente. */
.nav__curtain i{
  position:absolute; width:var(--lobe); height:var(--lobe);
  border-radius:50%;
  background:radial-gradient(circle, var(--menu-bg) 0 74%, rgb(36 31 26 / 0) 100%);
  transform:scale(0); opacity:0;
  /* Cerrado: se funde, y el scale se resetea de golpe pero DESPUÉS del
     fundido, así no se ve rebobinar. */
  transition:opacity var(--fade-out) linear,
             transform 0s linear var(--fade-out);
}
.nav__curtain i:nth-child(1){ top:calc(var(--lobe) / -2);             right:calc(var(--lobe) / -2) }
.nav__curtain i:nth-child(2){ top:calc(var(--lobe) / -2 - 16vmax);    right:calc(var(--lobe) / -2 + 22vmax) }
.nav__curtain i:nth-child(3){ top:calc(var(--lobe) / -2 + 19vmax);    right:calc(var(--lobe) / -2 - 13vmax) }

/* El desenfoque. backdrop-filter sobre el lóbulo mayor: el 26% exterior
   de su fondo es translúcido, así que en esa corona se ve la página
   DESENFOCADA justo antes de que la oscuridad la cubra. Como este lóbulo
   es el que llega más lejos, el frente de desenfoque va por delante del
   frente de color. Solo en uno de los tres: a este tamaño es lo más caro
   de la página y tres serían un derroche. */
.nav__curtain i:nth-child(1){
  -webkit-backdrop-filter:blur(26px) saturate(.75);
  backdrop-filter:blur(26px) saturate(.75);
}
.nav.is-open .nav__curtain i{
  opacity:1;
  transition:opacity .1s linear, transform var(--sweep-t) var(--sweep);
  will-change:transform;   /* solo mientras el menú está abierto */
}
.nav.is-open .nav__curtain i:nth-child(1){ transform:scale(1) }
.nav.is-open .nav__curtain i:nth-child(2){ transform:scale(.90) }
.nav.is-open .nav__curtain i:nth-child(3){ transform:scale(.84) }

/* Capa plana de cierre. Los lóbulos aportan la llegada orgánica; esta
   garantiza que al final no queda ni un píxel del degradado sin cubrir,
   en cualquier proporción de pantalla. Entra cuando el frente ya ha
   pasado, así que su fundido no se percibe. */
.nav__curtain::before{
  content:""; position:absolute; inset:0;
  background:var(--menu-bg);
  opacity:0; transition:opacity var(--fade-out) linear;
}
.nav.is-open .nav__curtain::before{
  opacity:1; transition:opacity .40s linear .62s;
}

/* La textura del menú, a pantalla completa.
   `soft-light` es casi inerte sobre un fondo casi negro —ni al 90% pasa
   de desvest 1,5, y la referencia tiene 3,9—; la mezcla correcta aquí es
   `screen`, que suma luz. Y la textura general es un óxido de tono medio
   que al sumarla teñía de naranja: esta variante va desaturada al 18% y
   con el contraste subido a 1,42, así que aporta moteado neutro. */
.nav__curtain::after{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:url("../media/textura-menu.webp") 0 0/440px repeat;
  opacity:0; mix-blend-mode:screen;
  transition:opacity var(--fade-out) linear;
}
.nav.is-open .nav__curtain::after{ opacity:.17; transition:opacity .5s linear .5s }

/* Sin movimiento: la masa no barre, el menú simplemente aparece. */
@media (prefers-reduced-motion:reduce){
  .nav__curtain i{ transform:scale(1) }
}

/* Una columna, centrada y con medida acotada: los cinco destinos son el
   único contenido del menú. */
.nav__inner{
  width:100%; max-width:min(var(--maxw), 44rem); margin-inline:auto;
  opacity:0; transform:translateY(12px);
  transition:opacity .42s linear, transform .5s var(--curtain);
}
/* Los enlaces entran casi con la superficie, no después: en la
   referencia ya están puestos en el primer fotograma. */
.nav.is-open .nav__inner{
  opacity:1; transform:none;
  transition-delay:.55s;   /* la masa ya ha pasado por el centro */
}
.nav__list li{ opacity:0; transition:opacity .42s linear }
.nav.is-open .nav__list li{ opacity:1; transition-delay:.62s }
/* Sin numeración: el enlace ES el texto. Centrado y con la tipografía
   display, que es lo único que queda en el menú. */
.nav__list a{
  position:relative; display:block; text-align:center;
  padding:clamp(.85rem,1.9vw,1.5rem) 0;
  font-family:var(--serif); font-size:clamp(1.45rem,3.2vw,2.4rem);
  line-height:1.16; letter-spacing:-.005em;
  transition:color .4s var(--ease);
}
.nav__list a:hover,
.nav__list a:focus-visible{ color:var(--accent) }

/* El filete aparece solo en hover, y aparece DIBUJÁNDOSE: doble línea
   Art Déco que se abre desde el centro hacia los extremos.
   opacity:0 además de scaleX(0): con solo el scale, el navegador pinta
   un hairline residual por redondeo de subpíxel. */
.nav__list a::before,
.nav__list a::after{
  content:""; position:absolute; inset-inline:0; height:1px;
  background:currentColor; opacity:0;
  transform:scaleX(0); transform-origin:center;
  transition:transform .6s var(--ease), opacity .2s linear .1s;
}
.nav__list a::before{ bottom:0 }
.nav__list a::after{ bottom:4px }
.nav__list a:hover::before,
.nav__list a:focus-visible::before{ transform:scaleX(1); opacity:.6; transition-delay:0s }
.nav__list a:hover::after,
.nav__list a:focus-visible::after{ transform:scaleX(1); opacity:.6; transition-delay:.09s }

/* Con movimiento reducido el filete aparece, pero sin trazarse. */
@media (prefers-reduced-motion:reduce){
  .nav__list a::before,
  .nav__list a::after{ transition:opacity .2s linear; transform:scaleX(1); opacity:0 }
  .nav__list a:hover::before,
  .nav__list a:hover::after,
  .nav__list a:focus-visible::before,
  .nav__list a:focus-visible::after{ opacity:.6 }
}

/* Anclado abajo, no empujado por la lista. */
.nav__foot{
  position:absolute; left:0; right:0;
  bottom:clamp(1.75rem,4vh,3rem);
  padding-inline:var(--gut);
  width:100%; max-width:min(var(--maxw), 44rem); margin-inline:auto;
  text-align:center;
  opacity:0; transition:opacity .42s linear;
}
.nav.is-open .nav__foot{ opacity:1; transition-delay:.74s }
.nav__where{
  margin-top:1.1rem; font-size:.85rem; font-style:normal;
  letter-spacing:.04em; color:var(--arena);
}
/* El teléfono en display, no en versalitas: es el dato que se busca. */
.nav__tel{ margin-top:.5rem }
.nav__tel a{
  font-family:var(--serif); font-size:clamp(1.15rem,2.1vw,1.5rem);
  letter-spacing:.02em; color:var(--ink);
  transition:color .35s var(--ease);
}
.nav__tel a:hover{ color:var(--accent) }

@media (max-width:900px){
  .nav{ justify-content:flex-start; overflow-y:auto }
}

/* ---------- 9. Hero ---------- */
/* padding-top reserva la altura del header: el H1 nunca lo pisa,
   ni en viewports cortos (portátiles de 13", móvil en horizontal). */
.hero{
  position:relative; min-height:100svh; padding-top:5.5rem;
  display:flex; align-items:flex-end; overflow:clip;
}
.hero__media{ position:absolute; inset:-8% 0; will-change:transform }

/* --- Vídeo --- */
/* Opacidad 0 hasta que el JS confirma que hay material real (poster
   cargado o vídeo reproduciendo): así un archivo ausente o un autoplay
   bloqueado nunca deja un hueco negro, se sigue viendo la atmósfera.
   Los tres clips van apilados en el mismo hueco. Solo cambia la opacidad,
   nunca display ni z-index: el relevo es un fundido real. */
:root{ --reel-fade:.55s }
.hero__reel{ position:absolute; inset:0 }
.hero__video{
  position:absolute; inset:0; width:100%; height:100%;
  object-fit:cover; opacity:0;
  transition:opacity var(--reel-fade) linear;
}
.hero__video.is-visible{ opacity:1 }

/* --- Atmósfera de respaldo (CSS, 0 KB) --- */
.hero__atmos{
  position:absolute; inset:0; overflow:clip;
  background:linear-gradient(168deg,#443B33 0%,#2A2622 56%,#1E1B18 100%);
}
/* Haz de luz que respira muy despacio */
.hero__atmos::before{
  content:""; position:absolute; inset:-25%;
  background:linear-gradient(102deg,
    transparent 32%,
    rgb(207 138 78 / .20) 44%,
    rgb(239 231 221 / .09) 50%,
    rgb(187 106 50 / .12) 56%,
    transparent 68%);
  animation:haz 46s var(--ease) infinite alternate;
}
/* Grano, para que no se lea como un degradado limpio de CSS */
.hero__atmos::after{
  content:""; position:absolute; inset:0; opacity:.38; mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
}
/* Vapor: tres masas difusas con derivas distintas */
.hero__vapor{ position:absolute; inset:-30%; filter:blur(56px) }
.hero__vapor i{
  position:absolute; border-radius:50%;
  background:radial-gradient(circle, rgb(201 171 143 / .26), transparent 66%);
}
.hero__vapor i:nth-child(1){ width:62%; aspect-ratio:1; left:4%;  top:22%; animation:vapor1 58s linear infinite }
.hero__vapor i:nth-child(2){ width:48%; aspect-ratio:1; left:48%; top:8%;  animation:vapor2 74s linear infinite; opacity:.7 }
.hero__vapor i:nth-child(3){ width:70%; aspect-ratio:1; left:24%; top:46%; animation:vapor3 92s linear infinite; opacity:.5 }

@keyframes haz{ from{ transform:translate3d(-6%,0,0) } to{ transform:translate3d(6%,2%,0) } }
@keyframes vapor1{ 0%,100%{ transform:translate3d(0,0,0) scale(1) } 50%{ transform:translate3d(9%,-6%,0) scale(1.14) } }
@keyframes vapor2{ 0%,100%{ transform:translate3d(0,0,0) scale(1.08) } 50%{ transform:translate3d(-11%,7%,0) scale(1) } }
@keyframes vapor3{ 0%,100%{ transform:translate3d(0,0,0) scale(1) } 50%{ transform:translate3d(6%,-9%,0) scale(1.2) } }

/* --- Velo del hero ---
   Aligerado un 30% sobre la versión anterior: la elipse baja de .95/.86/.40
   a .67/.60/.28 y la base plana de .18 a .13. Se puede porque el hero solo
   lleva el H1 —texto de 108px, mínimo 3:1, no 4,5:1— y porque el margen
   medido era de sobra.
   Lo que NO se toca es la banda superior: es la única capa que sostiene el
   wordmark, y el wordmark va en naranja de marca, cuyo techo absoluto
   sobre carbón es 4,06:1. Ahí no hay margen que ceder.
   Y sigue sin haber rampa vertical larga: elipse anclada abajo a la
   izquierda + base plana + cierre corto de 36px. Una rampa larga deja una
   banda visible en el canto y ensucia el paso a la sección siguiente. */
.hero__scrim{
  position:absolute; inset:0;
  background:
    /* Banda del header. Misma fuerza que antes en el 7,5% superior —ahí
       no se puede ceder nada— pero con la caída repartida en cuatro topes
       hasta el 29%. Sobre un vídeo ya aclarado, una caída lineal corta se
       lee como una franja con borde. */
    linear-gradient(to bottom,
      var(--carbon) 0%,
      var(--carbon) 7.5%,
      rgb(34 31 28 / .72) 11%,
      rgb(34 31 28 / .42) 16%,
      rgb(34 31 28 / .18) 22%,
      rgb(34 31 28 / 0) 29%),
    /* Mancha elíptica anclada abajo a la izquierda: protege solo la zona
       del titular, y al ser elipse no genera ninguna línea horizontal. */
    radial-gradient(140% 92% at 5% 98%,
      rgb(34 31 28 / .67) 0%,
      rgb(34 31 28 / .60) 50%,
      rgb(34 31 28 / .28) 82%,
      rgb(34 31 28 / 0) 100%),
    /* Cierre del canto inferior: 36px, no 270. Sin él, el vídeo llega al
       borde con velo y contra el carbón plano de la sección siguiente se
       nota un escalón. Con 36px se lee como el canto de un bloque. */
    linear-gradient(to top,
      var(--carbon) 0%,
      var(--carbon) 1.5%,
      rgb(34 31 28 / 0) 4%),
    /* Base plana */
    linear-gradient(rgb(34 31 28 / .13), rgb(34 31 28 / .13));
}
/* En móvil el titular ocupa todo el ancho, así que la elipse se centra y
   se ensancha en lugar de apoyarse en la esquina izquierda. */
@media (max-width:760px){
  .hero__scrim{
    background:
      linear-gradient(to bottom,
        rgb(34 31 28 / .92) 0%,
        rgb(34 31 28 / .88) 7%,
        rgb(34 31 28 / .62) 11%,
        rgb(34 31 28 / .34) 16%,
        rgb(34 31 28 / .14) 22%,
        rgb(34 31 28 / 0) 29%),
      radial-gradient(155% 88% at 50% 100%,
        rgb(34 31 28 / .66) 0%,
        rgb(34 31 28 / .59) 52%,
        rgb(34 31 28 / .29) 84%,
        rgb(34 31 28 / 0) 100%),
      linear-gradient(to top,
        var(--carbon) 0%,
        var(--carbon) 1.5%,
        rgb(34 31 28 / 0) 4%),
      linear-gradient(rgb(34 31 28 / .15), rgb(34 31 28 / .15));
  }
}
.hero__body{
  position:relative; width:100%; max-width:var(--maxw); margin-inline:auto;
  padding:0 var(--gut) clamp(4.5rem,10vh,8rem);
}
.hero__h1{ margin:0; max-width:16ch }

/* Viewport corto: el hero deja de ser a pantalla completa y el H1 baja
   de escala, en lugar de desbordarse por arriba. */
@media (max-height:620px){
  .nav{ justify-content:flex-start; overflow-y:auto; padding-block:5rem 2rem }
  .nav__foot{ position:static; margin-top:2rem }
  .hero{ min-height:auto; padding-block:7rem 3.5rem }
  .hero__h1{ font-size:clamp(2.4rem,7vw,3.75rem) }
}

/* ---------- 10. Escenarios fijados: piezas comunes ----------
   Patrón: la <section> mide varias pantallas y dentro lleva un escenario
   `sticky` de 100svh. El escenario queda clavado mientras la sección pasa
   por debajo, y el JS escribe el progreso 0→1. Nada captura el scroll:
   es `position:sticky`, no un manejador de eventos. */
.reel__stage{
  position:sticky; top:0; height:100svh;
  overflow:clip; isolation:isolate;
  display:grid; place-items:center;
}

/* Orden de apilado dentro de un escenario. Explícito y en un solo sitio:
   con `z-index` repartido por las reglas de cada pieza, la masa de tierra
   quedaba por DEBAJO del texto de los pilares —que lleva z-index:2— y el
   manifiesto compartía pantalla con un titular que aún no tocaba. */
.reel__soft      { z-index:0 }
.reel__imgs      { z-index:0 }
.stage__scrim    { z-index:1 }
.reel__plate     { z-index:2 }
.reel__txt       { z-index:3 }
.reel__dots      { z-index:3 }
.reel__curtain   { z-index:4 }
.reel__manifiesto{ z-index:5 }
.stage__exit     { z-index:6 }

/* Velo común de los escenarios de imagen: banda de cabecera + base
   mínima. Nada más. Todo el resto del cuadro queda a la vista.
   La banda va al 98% en el 8,5% superior —hasta ahí llega el contenido
   del header— y a partir de ahí cae hasta cero en el 30%.
   La caída lleva cuatro topes y no uno. Con un solo tramo lineal corto,
   sobre una imagen ya clara la banda se leía como una FRANJA con borde:
   el ojo detecta la terminación de un degradado lineal. Repartida en
   .72 → .42 → .18 → 0 sobre 190px, la pendiente decrece y no hay ningún
   punto donde el degradado «acabe». */
.stage__scrim{
  position:absolute; inset:0; pointer-events:none;
  background:
    linear-gradient(to bottom,
      rgb(var(--veil) / .98) 0%,
      rgb(var(--veil) / .98) 8.5%,
      rgb(var(--veil) / .72) 12%,
      rgb(var(--veil) / .42) 17%,
      rgb(var(--veil) / .18) 23%,
      rgb(var(--veil) / 0) 30%),
    linear-gradient(rgb(var(--veil) / .14), rgb(var(--veil) / .14));
}

/* Marea de cierre. Sin esto, el borde inferior del escenario fijado se
   encuentra con el carbón plano de la sección siguiente y deja una línea
   horizontal recta a media pantalla — el defecto que se veía entre los
   pilares y «Cada ritual», y otra vez entre «Cada ritual» y los bloques.
   La tierra sube desde el pie con un canto difuso de 22vh, así que la
   entrega ocurre sin ningún borde.
   Los topes van en calc para que a --e:0 el canto quede EN 0% y no
   aparezca ninguna banda oscura permanente en el pie. */
.stage__exit{
  position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(to top,
    var(--carbon) 0%,
    var(--carbon) calc(var(--e, 0) * 122% - 22%),
    rgb(47 43 39 / 0) calc(var(--e, 0) * 122%));
}

/* ---------- 11. La masa de tierra y el manifiesto ----------
   Viven DENTRO del escenario de los pilares, no en una sección propia.
   La pantalla se queda quieta y la masa sube descubriendo la primera
   imagen. El texto viaja con ella y se apaga antes de que el frente lo
   alcance. */

/* Copia desenfocada de la primera imagen, debajo de todo. El blur es un
   filtro ESTÁTICO: el navegador la rasteriza una vez y la cachea. La capa
   nítida se cruza por encima con la opacidad que escribe el JS. */
.reel__soft{
  position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
  filter:blur(30px) saturate(.9); transform:scale(1.08);
}

/* La masa. Su canto inferior es un degradado del 28% de su propia altura
   —unos 39vh— así que el frente que recorre la pantalla es una zona de
   disolución, no una línea. */
.reel__curtain{
  position:absolute; left:0; right:0; top:0; height:140%;
  background:linear-gradient(to bottom,
    var(--carbon) 0%,
    var(--carbon) 72%,
    rgb(47 43 39 / 0) 100%);
  transform:translate3d(0, calc(var(--m, 0) * -142%), 0);
  will-change:transform;
}
/* Banda de desenfoque que viaja por delante del frente de color: la
   imagen se difumina primero y se descubre después. Mismo mecanismo que
   el lóbulo mayor del menú. Es un solo backdrop-filter y ocupa un tercio
   de la altura, no la pantalla entera. */
.reel__curtain::after{
  content:""; position:absolute; left:0; right:0; top:66%; height:38%;
  -webkit-backdrop-filter:blur(22px) saturate(.9);
  backdrop-filter:blur(22px) saturate(.9);
  -webkit-mask-image:linear-gradient(to bottom, rgb(0 0 0 / 0) 0%, #000 26%, rgb(0 0 0 / 0) 100%);
  mask-image:linear-gradient(to bottom, rgb(0 0 0 / 0) 0%, #000 26%, rgb(0 0 0 / 0) 100%);
}

.reel__manifiesto{
  position:relative;
  width:100%; max-width:var(--maxw); margin-inline:auto;
  padding-inline:var(--gut);
  transform:translate3d(0, calc(var(--m, 0) * -24vh), 0);
  /* Se apaga en el primer 40% del recorrido: para cuando el frente
     desenfocado llega a su altura, el texto ya no está. */
  opacity:calc(1 - var(--m, 0) * 2.5);
}
/* Fuera del flujo en cuanto se ha ido: si no, su caja sigue ocupando la
   celda central del grid y el bloque de los pilares queda descentrado. */
.reel__manifiesto{ grid-area:1 / 1; align-self:center }
.reel__txt{ grid-area:1 / 1 }
/* Medida más ancha al bajar el cuerpo: a 26ch y este tamaño el párrafo
   quedaba en una columna estrecha y alta. */
.manifesto{
  max-width:36ch; margin-inline:auto; text-align:center;
  font-size:clamp(1.15rem,2.3vw,1.8rem); line-height:1.42;
}

/* ---------- 12. Tres pilares ----------
   520vh en total: el 26% inicial lo consume el barrido de la masa de
   tierra (~109vh) y el resto se reparte entre los tres pilares, ~104vh
   cada uno. Es lo que permite que el cruce entre imágenes dure y que
   dentro de cada tercio quepa la secuencia imagen → titular → texto sin
   atropellarse. */
.reel{ position:relative; height:520vh; background:var(--carbon) }
.reel__imgs{ position:absolute; inset:0 }
.reel__img{
  position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
  opacity:0;
  /* El JS pone la opacidad; la transición cubre el salto entre frames de
     scroll y suaviza el relevo sin necesidad de interpolar a mano. */
  transition:opacity .5s linear;
}
/* La primera imagen ya está puesta: viene encendida desde el manifiesto,
   que la descubre a pantalla completa. Sin esto, el capítulo arrancaría
   apagando lo que el anterior acaba de revelar. */
.reel__img[data-layer="0"]{ opacity:1 }

/* Placa local bajo el bloque de texto. Es la ÚNICA zona velada de verdad
   y solo existe mientras hay texto encima: cuando el panel se va, la
   imagen se queda limpia.
   Sustituye al velo global anterior, que cubría la foto entera al 76% de
   media para sostener un párrafo de 17px. Medido sobre las tres imágenes
   en cuatro proporciones: titular 5,7:1 (mínimo 3), cuerpo 6,1:1 (mínimo
   4,5), y el velo medio de la mitad derecha baja de 0,71 a 0,25. */
.reel__plate{
  position:absolute; inset:0; pointer-events:none;
  opacity:0; transition:opacity .8s var(--ease);
  background:radial-gradient(40% 46% at 22% 50%,
    rgb(var(--veil) / .72) 0%,
    rgb(var(--veil) / .68) 42%,
    rgb(var(--veil) / .29) 78%,
    rgb(var(--veil) / 0) 100%);
}
.reel__plate.is-on{ opacity:1 }
@media (max-width:860px){
  /* En pantallas estrechas el bloque de texto ocupa casi todo el ancho,
     así que la placa se ensancha y se centra. */
  .reel__plate{
    background:radial-gradient(92% 42% at 46% 52%,
      rgb(var(--veil) / .78) 0%,
      rgb(var(--veil) / .72) 44%,
      rgb(var(--veil) / .32) 80%,
      rgb(var(--veil) / 0) 100%);
  }
}

/* El z-index lo pone el bloque de apilado de §10, no aquí: repetirlo en
   cada componente es como la masa de tierra acabó por debajo del texto. */
.reel__txt{
  position:relative;
  width:100%; max-width:var(--maxw); margin-inline:auto;
  padding-inline:var(--gut);
  display:grid;
}
/* Los paneles comparten celda. No se apilan traslúcidos —dos textos
   superpuestos son ilegibles—: el saliente se apaga y el entrante entra
   con el revelado por máscara. */
.reel__panel{
  grid-area:1 / 1; max-width:34rem;
  opacity:0; pointer-events:none;
  transition:opacity .55s linear;
}
.reel__panel.is-on{ opacity:1 }
.reel__panel h2{ margin-bottom:.9rem }
/* Dentro del escenario la frase va en hueso, no en arena: sobre imagen,
   arena (L 0,435) no pasa de 3:1 sin ahogar la foto en velo. */
.pillar__line{ color:var(--ink); max-width:28ch; font-size:clamp(1rem,.4vw + .9rem,1.15rem) }
.pillar__body{
  margin-top:.9rem; max-width:34ch; color:var(--ink);
  font-size:clamp(.92rem,.3vw + .85rem,1.02rem); line-height:1.72;
}

/* Numeración de posición, no de sección: informa de en qué plano estás
   dentro de la secuencia, que es algo que el lector sí necesita. */
.reel__dots{
  position:absolute; right:var(--gut); top:50%;
  transform:translateY(-50%); display:grid; gap:.9rem;
}
/* scaleY y no height: animar la altura provoca layout en cada frame. */
.reel__dots li{
  width:1px; height:40px; background:var(--line-strong);
  transform:scaleY(.65); transform-origin:center;
  transition:background-color .4s linear, transform .4s var(--ease);
}
.reel__dots li.is-on{ background:var(--marca); transform:scaleY(1) }
@media (max-width:860px){ .reel__dots{ display:none } }

/* ---------- 13. Rituales: la imagen aparece detrás del titular ---------- */
.reveal-stage{ position:relative; height:260vh; background:var(--carbon) }
.reveal-stage__img{
  position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
  opacity:0;
}
/* Aquí la banda de cabecera va DENTRO del velo que se enciende con la
   imagen. Si fuera una capa constante, sobre el carbón plano del arranque
   se leería como una barra oscura en el borde superior. */
.reveal-stage__scrim{
  position:absolute; inset:0; opacity:0;
  background:
    linear-gradient(to bottom,
      rgb(var(--veil) / .98) 0%,
      rgb(var(--veil) / .98) 8.5%,
      rgb(var(--veil) / .72) 12%,
      rgb(var(--veil) / .42) 17%,
      rgb(var(--veil) / .18) 23%,
      rgb(var(--veil) / 0) 30%),
    linear-gradient(rgb(var(--veil) / .34), rgb(var(--veil) / .34));
}
.reveal-stage__h{
  position:relative; z-index:2; text-align:center;
  padding-inline:var(--gut); max-width:22ch;
}

/* ---------- 14. Rituales, bloques partidos ----------
   Los tres van SEPARADOS por tierra, no encadenados con un filete.
   Pegados y con una línea entre medias se leían como las tres filas de una
   tabla; son tres objetos distintos entre los que hay que poder elegir, y
   la separación es lo que permite mirarlos de uno en uno.
   El filete desaparece además por una segunda razón: justo encima está la
   marea de cierre del escenario anterior, y una línea horizontal ahí
   volvía a marcar la costura que la marea existe para borrar. */
.rituals{
  background:var(--carbon);
  padding-block:clamp(4rem,9vw,8rem) 0;
  display:grid; gap:clamp(4rem,10vw,9rem);
}
.rite{
  display:grid; grid-template-columns:1fr 1fr; align-items:center;
  min-height:min(74svh, 660px);
}
.rite__media{ position:relative; align-self:stretch }
.rite__media .media{ position:absolute; inset:0; aspect-ratio:auto; height:100% }
.rite__body{ padding:clamp(2.5rem,6vw,5rem) var(--gut) }
/* Alterna el lado. El cuerpo se reordena junto a la imagen para que el
   texto quede siempre del lado contrario. */
.rite--flip .rite__media{ order:2 }
.rite h3{ margin-bottom:.9rem; font-size:clamp(1.8rem,3.4vw,2.8rem) }
.ritual__line{ color:var(--ink-muted); max-width:32ch; line-height:1.6 }
.ritual__meta{
  margin:1.25rem 0 1.5rem; font-size:.72rem; letter-spacing:.2em;
  text-transform:uppercase; color:var(--accent);
}
.rituals .note{ display:block; padding-block:0 clamp(3rem,7vw,5rem); margin-top:0 }
@media (max-width:860px){
  .rite{ grid-template-columns:1fr; min-height:0 }
  .rite--flip .rite__media{ order:0 }
  .rite__media{ aspect-ratio:4/3 }
  .rite__media .media{ position:absolute }
}

/* --- Sin movimiento: las secuencias dejan de ser secuencias ---
   Se apilan como bloques normales, con todo visible y a su altura. */
@media (prefers-reduced-motion:reduce){
  .reel, .reveal-stage{ height:auto }
  .reel__stage{ position:static; height:auto; padding-block:var(--bay) }
  .stage__exit, .reel__curtain, .reel__soft{ display:none }
  .reel__img{ opacity:0 }
  .reel__img[data-layer="0"]{ opacity:1 }
  .reel__plate{ opacity:1 }
  .reveal-stage__img, .reveal-stage__scrim{ opacity:1 }
  /* Sin secuencia, el escenario se lee como una pila: primero el
     manifiesto y debajo los tres pilares, todos visibles y a su altura. */
  .reel__stage{ display:block }
  .reel__manifiesto{
    transform:none; opacity:1;
    margin-bottom:clamp(3rem,8vw,6rem);
  }
  .reel__txt{ display:grid; gap:clamp(3rem,8vw,6rem) }
  .reel__panel{ grid-area:auto; opacity:1 }
  /* El manifiesto queda sobre la imagen sin la masa que lo respaldaba, así
     que se le da una placa propia: la alternativa sin movimiento no puede
     ser peor en contraste que el original. */
  .reel__manifiesto::before{
    content:""; position:absolute; inset:-8vh -2rem;
    background:radial-gradient(62% 62% at 50% 50%,
      rgb(var(--veil) / .92) 0%, rgb(var(--veil) / .78) 60%, rgb(var(--veil) / 0) 100%);
    z-index:-1;
  }
  /* El pie deja de fijarse y el wordmark se queda a su tamaño: sin la
     altura extra no hay 80vh de scroll que no llevan a ninguna parte. */
  .ftr{ height:auto }
  .ftr__stage{ position:static; height:auto; overflow:visible }
  .ftr__mark{ transform:none }
  .ftr__nav, .ftr__meta, .ftr__legal{ opacity:1; transform:none }
}

/* ---------- 15. El refugio ---------- */
.refuge{ background:var(--carbon-deep); padding-block:var(--bay) }
.refuge__grid{ display:grid; grid-template-columns:.85fr 1.15fr; gap:clamp(2rem,7vw,7rem) }
.refuge__stick{ position:sticky; top:clamp(6rem,18vh,11rem); align-self:start }
.refuge__stick h2{ margin-bottom:1.5rem }
.refuge__stick .btn{ margin-top:2rem }
.refuge__steps{ display:grid; gap:clamp(4rem,9vw,8rem) }
.step .media{ margin:1.5rem 0 1.75rem; aspect-ratio:16/11 }
/* Asimetría controlada: width:auto para que el margen reste anchura
   en lugar de empujar el bloque fuera del contenedor. */
.step:nth-child(even) .media{ margin-left:clamp(0rem,8vw,6rem); width:auto }
@media (max-width:900px){
  .refuge__grid{ grid-template-columns:1fr; gap:3.5rem }
  .refuge__stick{ position:static }
  .step:nth-child(even) .media{ margin-left:0 }
}

/* ---------- 16. Nuestra esencia (capítulo hueso) ---------- */
.chapter{ background:var(--bg); color:var(--ink); padding-block:var(--bay) }
.sec-head{ margin-bottom:clamp(3rem,7vw,6rem) }
.essence{ display:grid; grid-template-columns:repeat(2,1fr); gap:clamp(2.5rem,6vw,5rem) }
.essence h3{
  margin-bottom:1.25rem; padding-bottom:1.25rem;
  border-bottom:1px solid var(--line);
}
.essence p{ color:var(--ink-muted); max-width:44ch; line-height:1.75 }
@media (max-width:760px){ .essence{ grid-template-columns:1fr } }

/* ---------- 17. Transición Art Déco ---------- */
.deco{
  background:var(--carbon); padding-block:clamp(4.5rem,10vw,8rem);
  display:grid; place-items:center; gap:2.5rem; text-align:center;
}
.deco__svg{ width:min(400px,72vw); height:auto; overflow:visible }
.deco__p{
  fill:none; stroke:var(--arcilla); stroke-width:1;
  stroke-dasharray:600;
  transition:stroke-dashoffset 2s var(--ease);
}
.deco.is-in .deco__p{ stroke-dashoffset:0 }
.deco.is-in .deco__p:nth-child(2){ transition-delay:.18s }
.deco.is-in .deco__p:nth-child(3){ transition-delay:.36s }
.deco__line{
  font-size:clamp(1.1rem,2.4vw,1.7rem); font-style:italic;
  color:var(--arena); max-width:26ch; padding-inline:var(--gut);
}

/* ---------- 18. Reseñas ---------- */
.reviews{ background:var(--carbon); padding-block:var(--bay) }
.quote{ margin-top:clamp(2.5rem,5vw,4rem); max-width:34ch }
.quote:nth-of-type(2){ margin-left:auto; text-align:right }
.quote p{ font-size:clamp(1.35rem,3vw,2.25rem); line-height:1.22 }
.quote footer{
  margin-top:1.5rem; font-size:.72rem; letter-spacing:.16em;
  text-transform:uppercase; color:var(--arena);
}
.quote cite{ font-style:normal }
.quote footer span{ opacity:.6 }

/* ---------- 19. Reserva ----------
   Centrado, a diferencia del resto del sitio, que va alineado a la
   izquierda. Es deliberado: es el único capítulo cuyo trabajo es que
   pulses algo. Centrar el titular, la frase y el botón los pone en el
   mismo eje y deja el CTA justo debajo de la mirada, en lugar de a la
   izquierda con media pantalla vacía a la derecha. */
.book{ background:var(--carbon-deep); padding-block:var(--bay); text-align:center }
.book__h{ margin:clamp(2.5rem,5vw,4rem) 0 1.75rem }
/* .lead trae max-width:46ch y alineación a la izquierda por defecto; aquí
   necesita centrarse como bloque, no solo su texto. */
.book .lead{ margin-inline:auto }
.book .btn--solid{ margin-top:2.75rem }
.book__meta{
  margin-top:clamp(4rem,8vw,7rem); display:grid;
  grid-template-columns:repeat(3,1fr); gap:2rem;
  border-top:1px solid var(--line); padding-top:2.5rem;
}
/* El bloque de datos se queda centrado columna a columna: tres celdas
   alineadas a la izquierda debajo de un titular centrado se leerían como
   dos maquetaciones distintas pegadas. */
.book__meta address{ font-style:normal }
.book__meta dt{
  font-size:.72rem; letter-spacing:.2em; text-transform:uppercase;
  color:var(--accent); margin-bottom:.6rem;
}
.book__meta dd{ color:var(--arena); font-size:.95rem }
@media (max-width:700px){ .book__meta{ grid-template-columns:1fr; gap:1.75rem } }

/* ---------- 20. Footer ----------
   El cierre es un escenario fijado más. El wordmark llega a pantalla
   completa y se encoge hasta su esquina mientras los datos aparecen
   detrás de él.

   La interpolación vive aquí; las TRES constantes que la gobiernan las
   mide el JS una sola vez sobre el layout real:
     --k0  cuánto hay que agrandar el wordmark para llenar la pantalla
     --dx  --dy  a dónde hay que moverlo para que quede centrado
   Se miden en lugar de escribirse a mano porque el tamaño final del
   wordmark es un clamp() y su posición depende del grid: cualquier valor
   fijo dejaría el aterrizaje descuadrado en algún ancho.
   --fq va de 1 (gigante) a 0 (en su sitio). Sin JS se queda en 0, que es
   exactamente el pie de toda la vida. */
.ftr{
  background:var(--carbon); border-top:1px solid var(--line);
  position:relative; height:180vh;
}
.ftr__stage{
  position:sticky; top:0; height:100svh;
  display:grid; align-content:center;
  overflow:clip;                     /* el wordmark gigante no debe sacar barra */
  padding-block:clamp(3.5rem,7vw,5.5rem) 2.5rem;
}
.ftr__grid{ display:grid; grid-template-columns:1.2fr 1fr 1fr; gap:2.5rem clamp(2rem,5vw,4rem) }

.ftr__mark{
  display:block; width:clamp(140px,16vw,208px);
  /* `align-self:start` no es cosmético. Sin él, el enlace es un ítem de
     grid y se estira hasta la altura de la fila —157px frente a los 51 del
     wordmark—, así que tanto la escala como el centrado se calculaban
     sobre una caja que sobra por abajo: el logotipo llegaba al centro
     medido, pero el que se ve quedaba alto y a un tercio de su tamaño. */
  align-self:start;
  /* origen arriba-izquierda: es lo que hace que la medida de --dx/--dy sea
     una resta directa entre dos rectángulos, sin corregir por el centro. */
  transform-origin:left top;
  transform:
    translate3d(calc(var(--fq, 0) * var(--dx, 0px)), calc(var(--fq, 0) * var(--dy, 0px)), 0)
    scale(calc(1 + var(--fq, 0) * (var(--k0, 1) - 1)));
  transition:opacity .4s var(--ease);
}
.ftr__mark img{ width:100%; height:auto }
.ftr__mark:hover{ opacity:.82 }

/* Los datos entran después de que el wordmark haya recorrido la mayor
   parte del camino: primero se resuelve la firma, después aparece la
   letra pequeña. A --fq 0,62 todavía no se ven; a 0,23 ya están del todo. */
.ftr__nav,
.ftr__meta,
.ftr__legal{
  opacity:calc((1 - var(--fq, 0)) * 2.6 - 1);
  transform:translate3d(0, calc(var(--fq, 0) * 26px), 0);
}

.ftr__nav{ display:grid; gap:.7rem; font-size:.85rem; color:var(--arena) }
.ftr__nav a:hover{ color:var(--accent) }
.ftr__meta{ font-size:.85rem; line-height:1.9; color:var(--arena) }
.ftr__meta address{ font-style:normal }
.ftr__meta a{ border-bottom:1px solid rgb(201 171 143 / .35) }
.ftr__meta a:hover{ color:var(--accent); border-color:var(--accent) }
.ftr__legal{
  grid-column:1/-1; display:flex; flex-wrap:wrap; gap:1.5rem; align-items:center;
  margin-top:1.5rem; padding-top:1.75rem; border-top:1px solid var(--line);
  font-size:.72rem; letter-spacing:.04em; color:var(--arena);
}
.ftr__legal a:hover{ color:var(--accent) }
.ftr__legal p{ margin-left:auto }

/* Por debajo de 861px el pie apilado no cabe en una pantalla, así que no
   se fija: vuelve a ser un bloque normal y el wordmark se queda a su
   tamaño. Un escenario sticky con contenido que desborda es una trampa. */
@media (max-width:860px){
  .ftr{ height:auto }
  .ftr__stage{ position:static; height:auto; overflow:visible }
  .ftr__grid{ grid-template-columns:1fr }
  .ftr__mark{ transform:none }
  .ftr__nav, .ftr__meta, .ftr__legal{ opacity:1; transform:none }
  .ftr__legal p{ margin-left:0 }
}

/* ---------- 21. Movimiento ----------
   Dos mecanismos y no más:
     .reveal  bloques de contenido — sube y se enciende
     [data-rise] texto de display — revelado por máscara, línea a línea
   Todo el estado oculto vive bajo .js: si el script falla o tarda, la
   página se ve completa en lugar de quedarse en negro. */
.js .reveal{ opacity:0; transform:translateY(28px); transition:opacity var(--slow) var(--ease), transform var(--slow) var(--ease) }
.js .reveal.is-in{ opacity:1; transform:none }
.js .reveal .media{ clip-path:inset(0 0 100% 0); transition:clip-path 1.5s var(--ease) .1s }
.js .reveal.is-in .media{ clip-path:inset(0 0 0 0) }
.js .deco__p{ stroke-dashoffset:600 }
.no-js .deco__p{ stroke-dashoffset:0 }

/* --- Revelado por máscara ---
   El texto de display espera oculto a que el JS lo parta en líneas: si se
   viera antes, al montar las máscaras desaparecería y volvería a subir, y
   eso es un parpadeo, no una entrada.
   La animación de 0 s a los 3 s es el seguro: si el script no llega a
   ejecutarse —error, bloqueo de red— el texto aparece igual. Ninguna
   frase del sitio puede quedar invisible por culpa de un fallo de JS. */
.js [data-rise]{ opacity:0; animation:rise-seguro 0s linear 3s forwards }
.js [data-rise].rise{ opacity:1; animation:none }
@keyframes rise-seguro{ to{ opacity:1 } }

/* Cada línea vive en una caja que recorta y el texto entra desde debajo
   de su propio borde. El JS parte el elemento en líneas reales medidas
   sobre el layout, no por <br>: así funciona igual con un titular de dos
   líneas que con un párrafo que envuelve en cuatro.
   El padding compensa los descendentes de Amiri. Sin él la «g» de
   «Refugio» se cortaba contra el borde de la máscara. */
.rise__l{
  display:block; overflow:hidden; overflow:clip;
  padding-bottom:.18em; margin-bottom:-.18em;
}
.js .rise__l > span{
  display:block;
  transform:translateY(108%);
  transition:transform var(--rise-t) var(--ease-rise);
}
.js .rise.is-in .rise__l > span{ transform:none }
/* Escalonado entre líneas del mismo bloque: 70 ms. Suficiente para que se
   lea como un movimiento encadenado y no como cuatro líneas a la vez. */
.js .rise__l:nth-child(2) > span{ transition-delay:.07s }
.js .rise__l:nth-child(3) > span{ transition-delay:.14s }
.js .rise__l:nth-child(4) > span{ transition-delay:.21s }
.js .rise__l:nth-child(5) > span{ transition-delay:.28s }
.js .rise__l:nth-child(n+6) > span{ transition-delay:.35s }

/* El hero espera a que la página se asiente antes de levantar el titular. */
.js .hero__h1 .rise__l > span{ transition-delay:.28s }
.js .hero__h1 .rise__l:nth-child(2) > span{ transition-delay:.35s }

/* Dentro de un pilar el orden es imagen → titular → texto. El titular
   entra en cuanto el panel se enciende; la frase 220 ms después; el
   cuerpo, 340 ms.
   Aquí el disparador NO es la visibilidad sino el progreso de la
   secuencia, así que cuelga de .is-on del panel y no de .is-in. Efecto
   buscado: al volver a subir, el pilar se vuelve a escribir. */
.js .reel__panel.is-on .rise .rise__l > span{ transform:none }
.js .reel__panel .pillar__line .rise__l > span{ transition-delay:.22s }
.js .reel__panel .pillar__line .rise__l:nth-child(2) > span{ transition-delay:.29s }
.js .reel__panel .pillar__body .rise__l > span{ transition-delay:.34s }
.js .reel__panel .pillar__body .rise__l:nth-child(2) > span{ transition-delay:.41s }
.js .reel__panel .pillar__body .rise__l:nth-child(3) > span{ transition-delay:.48s }
.js .reel__panel .pillar__body .rise__l:nth-child(n+4) > span{ transition-delay:.55s }

@media (prefers-reduced-motion:reduce){
  html{ scroll-behavior:auto }
  *,*::before,*::after{ animation-duration:.01ms!important; transition-duration:.01ms!important }
  .reveal{ opacity:1; transform:none }
  .reveal .media{ clip-path:none }
  .hero__media{ transform:none!important }
  /* La máscara desaparece del todo: sin recorte y sin desplazamiento. */
  .rise__l{ overflow:visible; padding-bottom:0; margin-bottom:0 }
  .js .rise__l > span{ transform:none }
}
