/* ==========================================================================
   EXIT RIDDLES — portada (site/)
   --------------------------------------------------------------------------
   Página estática, sin build y sin dependencias: lo que hay en `site/` es
   exactamente lo que rsync sube al hosting (docs/deployment.md).

   La paleta y las tres voces tipográficas NO se inventan aquí: son las de
   `packages/web/src/styles/theme.css`, copiadas a mano porque este archivo
   no pasa por el bundler y no puede importarlas. Si allí cambia el latón,
   cambia aquí — es el precio de no tener build, y es barato comparado con
   tener dos marcas distintas.

   Índice
     0 · tipografía autoalojada     7 · bandas y titulares
     1 · tokens                     8 · pilares
     2 · base y utilidades          9 · salas
     3 · barra y progreso          10 · cooperativo
     4 · hero (capas y parallax)   11 · pasos · puerta · pie
     5 · lockup y wordmark         12 · zonas táctiles
     6 · botones                   13 · movimiento reducido
   ========================================================================== */

/* ==========================================================================
   0 · TIPOGRAFÍA AUTOALOJADA — docs/art-direction.md §3
   --------------------------------------------------------------------------
   Dos subconjuntos por familia. El `latin-ext` no es opcional: el filtro de
   la dirección de arte es el polaco, y sin él `ą ę ł ń ś ź ż` se rompen. El
   navegador elige el archivo por `unicode-range`, así que un lector español
   nunca llega a descargar el segundo.
   ========================================================================== */
@font-face {
  font-family: "Cinzel";
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url("/assets/fonts/cinzel-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Cinzel";
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url("/assets/fonts/cinzel-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
    U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Cormorant Garamond";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/fonts/cormorant-garamond-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Cormorant Garamond";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/fonts/cormorant-garamond-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
    U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* --------------------------------------------------------------------------
   CIRÍLICO — para el ruso
   --------------------------------------------------------------------------
   Cinzel no tiene cirílico: solo `latin` y `latin-ext`. Con el ruso activo,
   el nombre y los titulares caían a la fuente de reserva del sistema y la
   página dejaba de parecerse a sí misma.

   Forum es la sustituta: la misma capital romana de inscripción que Cinzel,
   pero con cirílico. Se carga también su corte latino porque el wordmark
   «Exit Riddles» sigue estando en latín dentro de una página en ruso, y sin
   él saltaría de tipografía a media marca.

   Nada de esto lo descarga quien no lee ruso: los archivos cirílicos van por
   `unicode-range`, y Forum solo entra en `--font-display` bajo `:lang(ru)`.
   -------------------------------------------------------------------------- */
@font-face {
  font-family: "Cormorant Garamond";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/fonts/cormorant-garamond-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: "Forum";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/forum-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: "Forum";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/forum-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}

/* ==========================================================================
   1 · TOKENS — los mismos nombres y los mismos valores que theme.css
   ========================================================================== */
:root {
  /* metal */
  --brass-hi: #f0d49a;
  --brass: #b8934e;
  --brass-mid: #8f6f37;
  --brass-dk: #5c451f;
  --copper: #8c5a2b;
  --patina: #4e8578;

  /* piedra */
  --stone-dk: #14100e;
  --stone: #221c18;
  --stone-lt: #372e28;

  /* luz */
  --ember: #ffb547;
  --crystal: #7fd8ff;
  --ink: #efe3cb;
  --ink-dim: #a2917a;

  --font-display: "Cinzel", Georgia, serif;
  --font-prose: "Cormorant Garamond", Georgia, serif;

  --r: 3px;
  --bevel: inset 0 1px 0 rgb(255 225 170 / 0.45), inset 0 -2px 3px rgb(0 0 0 / 0.55);
  --touch-min: 44px;
  --wrap: 1180px;

  /*
   * Variables que escribe el JS. Se declaran aquí con su valor neutro para
   * que la página se vea entera aunque el script no llegue a ejecutarse:
   * sin esto, un `calc()` con una variable vacía invalida la propiedad y la
   * maqueta se desmonta.
   */
  --mx: 50%;   /* ratón, en % del viewport */
  --my: 40%;
  --px: 0;     /* desplazamiento de parallax, -1..1 */
  --py: 0;
  --scroll: 0; /* progreso del documento, 0..1 */
}

/*
 * Titulares en ruso: Forum en lugar de Cinzel, que no tiene cirílico.
 * `--font-prose` no cambia porque Cormorant Garamond sí lo trae. El JS
 * mantiene `<html lang>` al día al cambiar de idioma, así que esto se
 * enciende y se apaga solo.
 */
:root:lang(ru) {
  --font-display: "Forum", "Cinzel", Georgia, serif;
}

/* ==========================================================================
   2 · BASE Y UTILIDADES
   ========================================================================== */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  /* El ancla no puede quedar debajo de la barra fija. */
  scroll-padding-top: 5rem;
}

body {
  margin: 0;
  background: var(--stone-dk);
  color: var(--ink);
  font-family: var(--font-prose);
  font-size: clamp(1.05rem, 0.98rem + 0.35vw, 1.25rem);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img {
  max-width: 100%;
  height: auto;
  display: block;
}

a {
  color: var(--ember);
  text-decoration-color: rgb(255 181 71 / 0.4);
  text-underline-offset: 3px;
}

/* El foco es FRÍO (cristal) y el hover CÁLIDO (latón): así no se confunden
   nunca, que es justo lo que pide theme.css. */
:focus-visible {
  outline: 2px solid var(--crystal);
  outline-offset: 3px;
  border-radius: var(--r);
}

.wrap {
  width: min(100% - 2.5rem, var(--wrap));
  margin-inline: auto;
}

.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip {
  position: absolute;
  top: -100px;
  left: 1rem;
  z-index: 100;
  padding: 0.7rem 1.1rem;
  background: var(--stone-lt);
  color: var(--ink);
  border: 1px solid var(--brass-mid);
  border-radius: var(--r);
  text-decoration: none;
}
.skip:focus {
  top: 1rem;
}

/* Grano compartido: ruido procedural, cero bytes de descarga. */
.grain::after,
.hero__art::after,
.door::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
  opacity: 0.16;
  mix-blend-mode: overlay;
  z-index: 5;
}

/* Aparición al entrar en pantalla. El estado inicial solo se aplica si el
   JS ha marcado el documento (`.js`): sin script, todo se ve desde el
   principio en vez de quedarse invisible para siempre. */
.js .reveal {
  opacity: 0;
  transform: translateY(22px);
  transition:
    opacity 0.7s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}
.js .reveal.is-in {
  opacity: 1;
  transform: none;
}

/* ==========================================================================
   3 · BARRA Y PROGRESO
   ========================================================================== */
.bar {
  position: fixed;
  inset: 0 0 auto;
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 1.5rem;
  padding: 0.55rem clamp(0.9rem, 3vw, 1.6rem);
  /* Arranca invisible sobre el hero y se materializa al bajar (lo conmuta el
     JS con `.is-stuck`). */
  background: rgb(20 16 14 / 0);
  backdrop-filter: blur(0px);
  border-bottom: 1px solid transparent;
  transition:
    background 0.35s ease,
    backdrop-filter 0.35s ease,
    border-color 0.35s ease;
}
.bar.is-stuck {
  background: rgb(20 16 14 / 0.82);
  backdrop-filter: blur(14px) saturate(1.2);
  border-bottom-color: rgb(184 147 78 / 0.28);
}

.bar__brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  color: var(--ink);
  text-decoration: none;
  font-family: var(--font-display);
  font-size: 0.92rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  white-space: nowrap;
}
.bar__brand img {
  width: 34px;
  height: auto;
  filter: drop-shadow(0 0 10px rgb(127 216 255 / 0.28));
}
/* En móvil el emblema basta: el nombre entero deja sin sitio al selector. */
@media (max-width: 720px) {
  .bar__brand span {
    display: none;
  }
}

.bar__nav {
  display: flex;
  gap: 1.4rem;
  margin-inline-start: auto;
}
.bar__nav a {
  color: var(--ink-dim);
  text-decoration: none;
  font-family: var(--font-display);
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  transition: color 0.2s;
}
.bar__nav a:hover {
  color: var(--brass-hi);
}
@media (max-width: 900px) {
  .bar__nav {
    display: none;
  }
}

.bar__right {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-inline-start: auto;
}
.bar__nav + .bar__right {
  margin-inline-start: 0;
}

.lang select {
  min-height: var(--touch-min);
  padding: 0 0.6rem;
  background: rgb(34 28 24 / 0.92);
  color: var(--ink);
  border: 1px solid rgb(184 147 78 / 0.35);
  border-radius: var(--r);
  font-family: var(--font-display);
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  cursor: pointer;
  /* Sin esto, Chrome pinta el desplegable con su propio gris claro y en la
     barra oscura aparece un rectángulo blanco enorme. */
  color-scheme: dark;
  max-width: 8.5rem;
}
/* En móvil manda el botón de jugar: el idioma se queda en el ancho justo
   para su texto más largo (`Français`) y deja de comerse la barra. */
@media (max-width: 560px) {
  .lang select {
    max-width: 6.2rem;
    padding: 0 0.35rem;
    font-size: 0.68rem;
  }
  .bar {
    gap: 0.5rem;
  }
}

.progress {
  position: fixed;
  inset: 0 0 auto;
  z-index: 61;
  height: 2px;
  pointer-events: none;
}
.progress i {
  display: block;
  height: 100%;
  width: calc(var(--scroll) * 100%);
  background: linear-gradient(90deg, var(--brass-dk), var(--brass-hi) 55%, var(--crystal));
  box-shadow: 0 0 12px rgb(127 216 255 / 0.55);
}

/* ==========================================================================
   4 · HERO
   --------------------------------------------------------------------------
   Cuatro capas que se mueven a velocidades distintas. Ninguna lleva texto:
   el nombre y los botones van encima, en HTML.
   ========================================================================== */
.hero {
  position: relative;
  min-height: 100svh;
  display: grid;
  place-items: center;
  padding: clamp(5rem, 12vh, 8rem) 1.25rem clamp(4rem, 10vh, 6rem);
  overflow: hidden;
  isolation: isolate;
}

.hero__art {
  position: absolute;
  inset: 0;
  z-index: -1;
  /* Piedra procedural: es el fondo REAL mientras el arte carga, y el que se
     ve entero si el AVIF no existiera. La página nunca aparece en blanco. */
  background:
    radial-gradient(80% 60% at 50% 8%, rgb(55 46 40 / 0.85), transparent 70%),
    radial-gradient(50% 40% at 12% 55%, rgb(255 181 71 / 0.13), transparent 70%),
    radial-gradient(50% 40% at 88% 55%, rgb(255 181 71 / 0.11), transparent 70%),
    radial-gradient(60% 50% at 50% 100%, rgb(127 216 255 / 0.06), transparent 70%),
    linear-gradient(180deg, #0b0908, var(--stone-dk) 45%, #0a0807);
}

.layer {
  position: absolute;
  inset: -6%; /* margen extra: el parallax mueve la capa y no debe verse el borde */
  will-change: transform;
}

.layer--bg {
  background-image: image-set(
    url("/assets/img/hero-1920.avif") type("image/avif"),
    url("/assets/img/hero-1920.webp") type("image/webp")
  );
  background-size: cover;
  background-position: center 42%;
  /* El arte se apoya en la piedra procedural de debajo en vez de taparla del
     todo: si el archivo faltara, la caída es invisible. */
  opacity: 0.92;
  transform: translate3d(calc(var(--px) * 14px), calc(var(--py) * 14px), 0) scale(1.06);
}
/* En pantallas estrechas se sirve la copia de 960: bajar 1920 px a un móvil
   es el asesino silencioso de la conversión (art-direction.md §5). */
@media (max-width: 800px) {
  .layer--bg {
    background-image: image-set(
      url("/assets/img/hero-960.avif") type("image/avif"),
      url("/assets/img/hero-960.webp") type("image/webp")
    );
  }
}

/* Neblina volumétrica: dos manchas cálidas que respiran muy despacio. Es
   luz, no movimiento — que es lo que pide art-direction.md §7. */
.layer--haze {
  background:
    radial-gradient(38% 50% at 14% 46%, rgb(255 181 71 / 0.22), transparent 68%),
    radial-gradient(38% 50% at 86% 46%, rgb(255 181 71 / 0.18), transparent 68%),
    radial-gradient(45% 38% at 50% 78%, rgb(127 216 255 / 0.1), transparent 72%);
  mix-blend-mode: screen;
  animation: breathe 9s ease-in-out infinite;
  transform: translate3d(calc(var(--px) * 26px), calc(var(--py) * 26px), 0);
}
@keyframes breathe {
  0%,
  100% {
    opacity: 0.75;
  }
  50% {
    opacity: 1;
  }
}

.layer--embers {
  inset: 0;
  width: 100%;
  height: 100%;
  mix-blend-mode: screen;
  opacity: 0.85;
}

/* Primer plano: la mesa con el cofre y las llaves. Es la capa que más se
   mueve —está «más cerca»— y por eso es la que hace que la escena tenga
   profundidad de verdad y no parezca un cartel. */
.layer--fore {
  background-image: image-set(
    url("/assets/img/hero-fore-1600.avif") type("image/avif"),
    url("/assets/img/hero-fore-1600.webp") type("image/webp")
  );
  background-size: cover;
  background-position: center bottom;
  transform: translate3d(calc(var(--px) * 46px), calc(var(--py) * 22px), 0);
}
@media (max-width: 800px) {
  .layer--fore {
    background-image: image-set(
      url("/assets/img/hero-fore-900.avif") type("image/avif"),
      url("/assets/img/hero-fore-900.webp") type("image/webp")
    );
  }
}

/* Viñeta + suelo oscuro: es lo que hace legible el texto encima del arte.
   art-direction.md §8 pide fondo sólido bajo el texto; en un hero el
   equivalente honesto es un velo que garantice el contraste, y este deja el
   centro por debajo de #191411 (medido: 12.4:1 contra `--ink`). */
.layer--vignette {
  inset: 0;
  background:
    /* El corazón: donde caen el emblema y el nombre. Sin este velo el fondo
       tiene tanto detalle (engranajes, piedra, lámparas) que compite con el
       texto y no gana ninguno de los dos. */
    radial-gradient(46% 44% at 50% 44%, rgb(8 6 5 / 0.9), rgb(8 6 5 / 0.55) 55%, transparent 80%),
    radial-gradient(58% 52% at 50% 46%, rgb(10 8 7 / 0.6), rgb(10 8 7 / 0.28) 62%, transparent 82%),
    linear-gradient(180deg, rgb(10 8 7 / 0.6) 0%, transparent 24%, transparent 60%, var(--stone-dk) 99%);
}

/* Linterna: el halo que sigue al ratón. `screen` sobre la escena da luz de
   verdad en vez de una mancha clara pegada encima. */
.lantern {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(
    260px 260px at var(--mx) var(--my),
    rgb(255 181 71 / 0.16),
    rgb(255 181 71 / 0.05) 42%,
    transparent 70%
  );
  mix-blend-mode: screen;
  opacity: 0;
  transition: opacity 0.5s ease;
}
.has-pointer .lantern {
  opacity: 1;
}

.hero__content {
  position: relative;
  z-index: 2;
  text-align: center;
  max-width: 46rem;
}

.eyebrow {
  margin: 0 0 1.6rem;
  font-family: var(--font-display);
  font-size: clamp(0.66rem, 0.6rem + 0.3vw, 0.8rem);
  letter-spacing: 0.42em;
  text-transform: uppercase;
  color: var(--brass);
  text-indent: 0.42em; /* compensa el tracking para que siga centrado */
}

/* ==========================================================================
   5 · LOCKUP Y WORDMARK
   --------------------------------------------------------------------------
   El emblema es arte; el nombre es tipografía real (Cinzel) con relleno
   metálico. No es capricho: un nombre dentro de un PNG no se traduce, no
   escala y puede estar mal escrito — el primer logotipo del proyecto ponía
   «RIDDOES» (docs/art-direction.md §2).
   ========================================================================== */
.lockup {
  position: relative;
  display: grid;
  place-items: center;
  margin-bottom: 1.4rem;
}

/*
 * Dos medidas aprendidas al quitarle el damero al emblema:
 *
 * 1. El tamaño. Con el damero, el archivo era apaisado (640×349) y ocupaba
 *    180 px de alto; recortado al círculo es cuadrado (640×646) y con el
 *    ancho de antes se comía 330 px, empujando los botones fuera de la
 *    primera pantalla en un portátil de 900 px.
 * 2. El halo. El emblema es un círculo de engranajes de latón y el fondo del
 *    hero es… un arco de engranajes de latón: sin el damero blanco que lo
 *    recortaba de mentira, se camuflaba con la pared. La sombra proyectada y
 *    el halo frío no son adorno, son lo que lo despega del fondo.
 */
.lockup__emblem {
  width: clamp(140px, 20vw, 230px);
  filter:
    drop-shadow(0 0 26px rgb(0 0 0 / 0.95))
    drop-shadow(0 0 60px rgb(127 216 255 / 0.3))
    drop-shadow(0 14px 34px rgb(0 0 0 / 0.85));
  animation: hover 7s ease-in-out infinite;
}
@keyframes hover {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-10px);
  }
}

.wordmark {
  margin: -0.12em 0 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0 0.32em;
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(2.6rem, 11vw, 6.6rem);
  line-height: 0.94;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.wordmark__word {
  position: relative;
  /* Relleno metálico: el degradado se recorta contra la letra. El
     `color: transparent` va con `-webkit-` porque sigue siendo el prefijo
     que entienden todos los motores para `background-clip: text`. */
  background: linear-gradient(
    176deg,
    #fff6e2 4%,
    var(--brass-hi) 26%,
    var(--brass) 48%,
    var(--brass-mid) 62%,
    var(--brass-hi) 78%,
    var(--brass-dk) 100%
  );
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  /* La sombra no puede ir en el mismo elemento (el texto es transparente y
     `text-shadow` pintaría por encima del recorte): se dibuja con una copia
     detrás, vía `data-text`. */
}
.wordmark__word::before {
  content: attr(data-text);
  position: absolute;
  inset: 0;
  z-index: -1;
  color: #120d09;
  text-shadow:
    0 2px 0 rgb(0 0 0 / 0.6),
    0 0 34px rgb(255 181 71 / 0.42),
    0 0 70px rgb(255 181 71 / 0.2);
}
/* Reflejo que cruza el metal. Lento y muy tenue: comunica «esto es metal»,
   no reclama atención (art-direction.md §7). */
.wordmark__word::after {
  content: attr(data-text);
  position: absolute;
  inset: 0;
  background: linear-gradient(
    100deg,
    transparent 38%,
    rgb(255 255 255 / 0.85) 48%,
    transparent 58%
  );
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  background-size: 260% 100%;
  animation: sheen 7s ease-in-out 1.2s infinite;
}
@keyframes sheen {
  0%,
  62% {
    background-position: 170% 0;
  }
  92%,
  100% {
    background-position: -70% 0;
  }
}

.claim {
  margin: 0.7rem 0 0;
  font-family: var(--font-display);
  font-size: clamp(0.66rem, 0.55rem + 0.4vw, 0.9rem);
  letter-spacing: 0.46em;
  text-indent: 0.46em;
  text-transform: uppercase;
  color: var(--brass);
  /* Filete de latón a los lados, como en la placa del logotipo. */
  display: flex;
  align-items: center;
  gap: 1rem;
  white-space: nowrap;
}
.claim::before,
.claim::after {
  content: "";
  height: 1px;
  width: clamp(1.5rem, 8vw, 4.5rem);
  background: linear-gradient(90deg, transparent, var(--brass-mid), transparent);
}

.hero__sub {
  margin: 0 auto 2.2rem;
  max-width: 30rem;
  font-size: clamp(1.15rem, 1rem + 0.7vw, 1.5rem);
  color: var(--ink);
  text-shadow: 0 2px 12px rgb(0 0 0 / 0.85);
}

.cta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
  justify-content: center;
}

.hero__note {
  margin: 1.8rem 0 0;
  font-family: var(--font-display);
  font-size: 0.7rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.scrollcue {
  position: absolute;
  bottom: 1.6rem;
  left: 50%;
  translate: -50% 0;
  display: grid;
  justify-items: center;
  gap: 0.55rem;
  color: var(--ink-dim);
  text-decoration: none;
  font-family: var(--font-display);
  font-size: 0.62rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  text-indent: 0.32em;
  transition: color 0.2s;
}
.scrollcue:hover {
  color: var(--brass-hi);
}
.scrollcue__rail {
  position: relative;
  display: block;
  width: 1px;
  height: 46px;
  background: linear-gradient(180deg, transparent, rgb(184 147 78 / 0.5));
  overflow: hidden;
}
.scrollcue__rail i {
  position: absolute;
  inset-inline: -1px;
  height: 14px;
  background: linear-gradient(180deg, transparent, var(--crystal));
  animation: drip 2.4s ease-in-out infinite;
}
@keyframes drip {
  0% {
    top: -14px;
    opacity: 0;
  }
  35% {
    opacity: 1;
  }
  100% {
    top: 46px;
    opacity: 0;
  }
}

/* ==========================================================================
   6 · BOTONES — el latón de theme.css, no un latón nuevo
   ========================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--touch-min);
  padding: 0.75rem 1.6rem;
  border: 1px solid transparent;
  border-radius: var(--r);
  font-family: var(--font-display);
  font-size: 0.82rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition:
    transform 0.12s ease,
    box-shadow 0.25s ease,
    filter 0.25s ease;
}
.btn:active {
  transform: translateY(1px);
}

.btn--primary {
  background: linear-gradient(
    180deg,
    var(--brass-hi) 0%,
    var(--brass) 58%,
    var(--brass-mid) 84%,
    var(--brass-dk) 100%
  );
  /* #3a2a10 sobre el tramo medio del degradado (`--brass`): 4.82:1 medido, y
     sube según se aclara hacia arriba. El texto de un botón es informativo,
     así que tiene que pasar el 4.5:1 de art-direction.md §8 en su punto peor,
     no de media. */
  color: #3a2a10;
  box-shadow:
    var(--bevel),
    0 8px 22px rgb(0 0 0 / 0.55);
  text-shadow: 0 1px 0 rgb(255 232 190 / 0.5);
}
.btn--primary:hover {
  filter: brightness(1.08);
  box-shadow:
    var(--bevel),
    0 10px 28px rgb(0 0 0 / 0.6),
    0 0 28px rgb(255 181 71 / 0.4);
}

.btn--ghost {
  background: rgb(34 28 24 / 0.6);
  color: var(--ink);
  border-color: rgb(184 147 78 / 0.45);
  backdrop-filter: blur(6px);
}
.btn--ghost:hover {
  border-color: var(--brass-hi);
  color: var(--brass-hi);
  background: rgb(55 46 40 / 0.7);
}

.btn--sm {
  min-height: 38px;
  padding: 0.45rem 0.95rem;
  font-size: 0.72rem;
}
.btn--lg {
  padding: 1rem 2.4rem;
  font-size: 0.92rem;
}

/* ==========================================================================
   7 · BANDAS Y TITULARES
   ========================================================================== */
.band {
  position: relative;
  padding: clamp(5rem, 14vh, 9rem) 0;
}
.band--rooms {
  background:
    radial-gradient(70% 50% at 50% 0%, rgb(55 46 40 / 0.55), transparent 70%),
    var(--stone-dk);
}
.band--coop {
  background: linear-gradient(180deg, var(--stone-dk), #0a0d10 50%, var(--stone-dk));
}

.kicker {
  margin: 0 0 0.9rem;
  font-family: var(--font-display);
  font-size: 0.7rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--brass);
}

.h2 {
  margin: 0 0 1.1rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.9rem, 1.2rem + 3vw, 3.4rem);
  line-height: 1.08;
  letter-spacing: 0.01em;
  color: var(--ink);
}
.h2--xl {
  font-size: clamp(2.2rem, 1.2rem + 4.5vw, 4.4rem);
}

.lead {
  margin: 0 0 2.6rem;
  max-width: 44ch;
  font-size: clamp(1.15rem, 1rem + 0.6vw, 1.45rem);
  color: var(--ink);
}

/* ==========================================================================
   8 · PILARES
   ========================================================================== */
.pillars {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  gap: clamp(1.5rem, 4vw, 3rem);
  margin: 0;
  padding: 0;
  list-style: none;
}
/* El retardo por posición hace que entren en cascada, no en bloque. */
.pillar:nth-child(2) {
  transition-delay: 0.09s;
}
.pillar:nth-child(3) {
  transition-delay: 0.18s;
}

.pillar__icon {
  display: grid;
  place-items: center;
  width: 58px;
  height: 58px;
  margin-bottom: 1.1rem;
  border: 1px solid rgb(184 147 78 / 0.4);
  border-radius: 50%;
  color: var(--brass-hi);
  background: radial-gradient(circle at 40% 30%, rgb(55 46 40 / 0.9), rgb(20 16 14 / 0.9));
  box-shadow:
    inset 0 1px 0 rgb(255 225 170 / 0.2),
    0 0 22px rgb(255 181 71 / 0.12);
}
.pillar__icon svg {
  width: 28px;
  height: 28px;
}

.pillar__t {
  margin: 0 0 0.5rem;
  font-family: var(--font-display);
  font-size: 1.12rem;
  letter-spacing: 0.06em;
  color: var(--ink);
}
.pillar__d {
  margin: 0;
  color: var(--ink-dim);
}

/* ==========================================================================
   9 · SALAS
   ========================================================================== */
.rooms {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 19rem), 1fr));
  gap: clamp(1.2rem, 3vw, 2rem);
  margin-top: 2.5rem;
}

.room {
  position: relative;
  overflow: hidden;
  border: 1px solid rgb(184 147 78 / 0.28);
  border-radius: var(--r);
  background: linear-gradient(180deg, var(--stone), #191411);
  box-shadow: 0 18px 40px rgb(0 0 0 / 0.5);
  /* El tilt: el JS escribe --rx/--ry en grados. `perspective` va en el propio
     elemento para que cada tarjeta gire sobre su centro. */
  transform: perspective(900px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
  transition:
    transform 0.35s cubic-bezier(0.22, 1, 0.36, 1),
    border-color 0.3s ease,
    box-shadow 0.3s ease;
  transform-style: preserve-3d;
}
.room:hover {
  border-color: rgb(240 212 154 / 0.6);
  box-shadow:
    0 22px 50px rgb(0 0 0 / 0.6),
    0 0 34px rgb(255 181 71 / 0.14);
}
.room:nth-child(2) {
  transition-delay: 0.08s;
}
.room:nth-child(3) {
  transition-delay: 0.16s;
}

.room__art {
  position: relative;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  background: linear-gradient(160deg, var(--stone-lt), #100c0a);
}
.room__art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}
.room:hover .room__art img {
  transform: scale(1.06);
}
/* Degradado bajo la imagen: el título de debajo nunca compite con el arte. */
.room__art::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 45%, rgb(25 20 17 / 0.95));
}

.room__art--locked {
  display: grid;
  place-items: center;
}
.room__lock {
  color: rgb(162 145 122 / 0.55);
}
.room__lock svg {
  width: 46px;
  height: 46px;
}

.room__badge {
  position: absolute;
  z-index: 2;
  top: 0.8rem;
  left: 0.8rem;
  padding: 0.28rem 0.7rem;
  border-radius: 999px;
  background: rgb(78 133 120 / 0.9);
  color: #06110e;
  font-family: var(--font-display);
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

.room__body {
  padding: 1.3rem 1.4rem 1.6rem;
}
.room__t {
  margin: 0 0 0.5rem;
  font-family: var(--font-display);
  font-size: 1.3rem;
  color: var(--ink);
}
.room__d {
  margin: 0 0 1rem;
  color: var(--ink-dim);
  font-size: 1.02rem;
}
.room__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
  margin: 0 0 1.2rem;
  font-family: var(--font-display);
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--brass);
}

.room--locked {
  opacity: 0.72;
}
.room--locked .room__t {
  color: var(--ink-dim);
}

/* ==========================================================================
   10 · COOPERATIVO
   ========================================================================== */
.coop {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr));
  gap: clamp(2rem, 6vw, 4.5rem);
  align-items: center;
}

.ticks {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 0.75rem;
}
.ticks li {
  position: relative;
  padding-inline-start: 1.9rem;
  color: var(--ink-dim);
}
.ticks li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: 0.62em;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--brass);
  box-shadow: 0 0 12px rgb(255 181 71 / 0.6);
}

/* Los dos paneles se separan al entrar en pantalla: el gesto cuenta la
   mecánica —dos mitades de la misma sala— más rápido que el párrafo. */
.coop__art {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 3px;
  aspect-ratio: 4 / 3;
  border: 1px solid rgb(184 147 78 / 0.3);
  border-radius: var(--r);
  overflow: hidden;
  background: #0a0807;
}
.pane {
  position: relative;
  display: grid;
  place-items: center;
  transition: transform 0.9s cubic-bezier(0.22, 1, 0.36, 1);
}
/* Las dos celdas son las dos mitades de una misma imagen generada: la
   izquierda con lámpara de aceite, la derecha con cristal frío. Que sean el
   mismo sitio con dos luces distintas es exactamente lo que cuenta la
   sección. */
.pane--a {
  background-color: #100c0a;
  background-image:
    linear-gradient(0deg, rgb(16 12 10 / 0.45), rgb(16 12 10 / 0.45)),
    image-set(
      url("/assets/img/coop-a-700.avif") type("image/avif"),
      url("/assets/img/coop-a-700.webp") type("image/webp")
    );
  background-size: cover;
  background-position: center;
}
.pane--b {
  background-color: #080b0d;
  background-image:
    linear-gradient(0deg, rgb(8 11 13 / 0.45), rgb(8 11 13 / 0.45)),
    image-set(
      url("/assets/img/coop-b-700.avif") type("image/avif"),
      url("/assets/img/coop-b-700.webp") type("image/webp")
    );
  background-size: cover;
  background-position: center;
}
.js .coop__art .pane--a {
  transform: translateX(-14%);
}
.js .coop__art .pane--b {
  transform: translateX(14%);
}
.js .coop__art.is-in .pane--a,
.js .coop__art.is-in .pane--b {
  transform: none;
}

/* El «ojo» de cada panel: un iris que mira hacia el cursor. Es el emblema
   traducido a CSS, y da vida sin cargar nada. */
.pane__eye {
  width: clamp(48px, 9vw, 84px);
  aspect-ratio: 1;
  border-radius: 50%;
  border: 2px solid rgb(184 147 78 / 0.7);
  background:
    radial-gradient(circle at 50% 50%, #0a0807 0 22%, transparent 23%),
    radial-gradient(circle at 50% 50%, currentColor 0 44%, transparent 45%);
  box-shadow: 0 0 26px rgb(0 0 0 / 0.6);
  transform: translate(calc(var(--px) * 10px), calc(var(--py) * 10px));
  transition: transform 0.25s ease-out;
}
.pane--a .pane__eye {
  color: rgb(255 181 71 / 0.75);
}
.pane--b .pane__eye {
  color: rgb(127 216 255 / 0.75);
}

.pane__seam {
  position: absolute;
  inset-block: 0;
  left: 50%;
  width: 1px;
  translate: -50% 0;
  background: linear-gradient(180deg, transparent, rgb(127 216 255 / 0.5), transparent);
}

/* ==========================================================================
   11 · PASOS · PUERTA · PIE
   ========================================================================== */
.steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  gap: clamp(1.5rem, 4vw, 3rem);
  margin: 2.5rem 0 0;
  padding: 0;
  list-style: none;
  counter-reset: paso;
}
.step {
  position: relative;
  padding-top: 1.5rem;
  border-top: 1px solid rgb(184 147 78 / 0.25);
}
.step:nth-child(2) {
  transition-delay: 0.09s;
}
.step:nth-child(3) {
  transition-delay: 0.18s;
}
.step__n {
  position: absolute;
  top: -0.9rem;
  left: 0;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--stone-dk);
  border: 1px solid rgb(184 147 78 / 0.5);
  font-family: var(--font-display);
  font-size: 0.8rem;
  color: var(--brass-hi);
}
.step__t {
  margin: 1.4rem 0 0.4rem;
  font-family: var(--font-display);
  font-size: 1.15rem;
  color: var(--ink);
}
.step__d {
  margin: 0;
  color: var(--ink-dim);
}

/* --- La puerta: dos hojas que se abren con el scroll ---------------------- */
.door {
  position: relative;
  min-height: 100svh;
  display: grid;
  place-items: center;
  padding: 6rem 1.25rem;
  overflow: hidden;
  isolation: isolate;
  background: radial-gradient(60% 60% at 50% 50%, #1a2226, #060809 72%);
}

.door__leaves {
  position: absolute;
  inset: 0;
  z-index: -1;
  display: grid;
  grid-template-columns: 1fr 1fr;
}
/* Cada hoja es media imagen: la puerta se generó con la junta en el eje
   exacto y `scripts/portada-assets.mjs` la parte en dos. El degradado de
   debajo es el respaldo si el archivo faltara. */
.door__leaf {
  background:
    linear-gradient(90deg, rgb(0 0 0 / 0.5), transparent 22%, transparent 78%, rgb(0 0 0 / 0.5)),
    linear-gradient(160deg, var(--stone-lt), #120e0c);
  background-size: cover;
  background-position: center;
  box-shadow: 0 0 60px rgb(0 0 0 / 0.7) inset;
  /* `--open` va de 0 (cerrada) a 1 (abierta) y lo escribe el JS según lo
     cerca que esté la sección del centro de la pantalla. */
  transition: transform 0.15s linear;
}
.door__leaf--l {
  border-right: 1px solid rgb(184 147 78 / 0.35);
  background-image:
    linear-gradient(90deg, rgb(0 0 0 / 0.5), transparent 22%),
    image-set(
      url("/assets/img/puerta-izq-960.avif") type("image/avif"),
      url("/assets/img/puerta-izq-960.webp") type("image/webp")
    );
  background-position: right center;
  transform: translateX(calc(var(--open, 0) * -62%));
}
.door__leaf--r {
  border-left: 1px solid rgb(184 147 78 / 0.35);
  background-image:
    linear-gradient(270deg, rgb(0 0 0 / 0.5), transparent 22%),
    image-set(
      url("/assets/img/puerta-der-960.avif") type("image/avif"),
      url("/assets/img/puerta-der-960.webp") type("image/webp")
    );
  background-position: left center;
  transform: translateX(calc(var(--open, 0) * 62%));
}
/* La rendija de luz fría por la que se escapa lo que hay detrás. */
.door__seam {
  position: absolute;
  inset-block: 0;
  left: 50%;
  width: clamp(2px, calc(var(--open, 0) * 40vw), 40vw);
  translate: -50% 0;
  background: linear-gradient(
    90deg,
    transparent,
    rgb(127 216 255 / 0.5),
    rgb(127 216 255 / 0.14) 40%,
    transparent
  );
  filter: blur(calc(6px + var(--open, 0) * 30px));
  opacity: calc(1 - var(--open, 0) * 0.45);
}

.door__content {
  position: relative;
  z-index: 2;
  text-align: center;
  max-width: 40rem;
  padding: 2rem 1.5rem;
  /* Aparece cuando la puerta ya está entreabierta. */
  opacity: clamp(0, calc(var(--open, 0) * 2 - 0.5), 1);
  transform: translateY(calc((1 - var(--open, 0)) * 26px));
  transition:
    opacity 0.2s linear,
    transform 0.2s linear;
}
/* Velo bajo el texto. Lo que hay detrás es la rendija de luz fría, y el
   titular caía justo encima: sin este velo el contraste medido bajaba a
   3.1:1 —por debajo del 4.5:1 que exige art-direction.md §8—. Con él sube a
   11.8:1 y la luz se sigue viendo alrededor. */
.door__content::before {
  content: "";
  position: absolute;
  inset: -1rem -2rem;
  z-index: -1;
  background: radial-gradient(60% 55% at 50% 50%, rgb(6 8 9 / 0.88), rgb(6 8 9 / 0.55) 62%, transparent 82%);
}

.door__content .lead {
  margin-inline: auto;
}

.waitlist {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  justify-content: center;
  margin-top: 2.4rem;
}
.waitlist input {
  flex: 1 1 15rem;
  max-width: 20rem;
  min-height: var(--touch-min);
  padding: 0 0.9rem;
  background: rgb(10 8 7 / 0.7);
  border: 1px solid rgb(184 147 78 / 0.4);
  border-radius: var(--r);
  color: var(--ink);
  font-family: var(--font-prose);
  font-size: 1rem;
}
.waitlist input::placeholder {
  color: rgb(162 145 122 / 0.7);
}
.waitlist input:focus-visible {
  border-color: var(--crystal);
}
.waitlist__msg {
  flex-basis: 100%;
  margin: 0.4rem 0 0;
  min-height: 1.4em;
  font-size: 0.95rem;
  color: var(--brass-hi);
}
.waitlist__msg[data-state="error"] {
  color: #ef6a4e;
}

/* Para qué se pide el correo, dicho junto al campo (ver el comentario del
   HTML). Tiene que leerse sin esfuerzo pero sin competir con el botón. */
.waitlist__legal {
  flex-basis: 100%;
  margin: 0.2rem 0 0;
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--ink-dim);
}
.waitlist__legal a {
  color: var(--ink-dim);
  text-decoration-color: rgb(162 145 122 / 0.5);
  text-underline-offset: 3px;
}
.waitlist__legal a:hover,
.waitlist__legal a:focus-visible {
  color: var(--brass-hi);
}

.foot {
  padding: 2.5rem 0;
  border-top: 1px solid rgb(184 147 78 / 0.2);
  background: #0a0807;
}
.foot__in {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 1.6rem;
}
.foot__brand {
  margin: 0;
  font-family: var(--font-display);
  font-size: 0.95rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--brass);
}
.foot__c {
  margin: 0;
  color: var(--ink-dim);
  font-size: 0.9rem;
}
/*
 * Fila legal del pie. Va ARRIBA del bloque de marca, no debajo: quien busca
 * «reembolsos» o «privacidad» baja hasta el final de la página y lee de
 * arriba abajo — el copyright y los idiomas ya estaban al final y no hacía
 * falta enterrar los enlaces todavía más.
 */
.foot__legal {
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem 1.5rem;
  margin-bottom: 0.6rem;
}
.foot__legal a {
  padding: 0.35rem 0;
  color: var(--ink-dim);
  font-family: var(--font-display);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  transition: color 0.2s;
}
.foot__legal a:hover,
.foot__legal a:focus-visible {
  color: var(--brass-hi);
}

.foot__mor {
  margin: 0 0 1.4rem;
  max-width: 46ch;
  color: var(--ink-dim);
  font-size: 0.85rem;
}

.foot__langs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin-inline-start: auto;
}
.foot__langs button {
  min-height: 38px;
  padding: 0.4rem 0.8rem;
  background: none;
  border: 1px solid transparent;
  border-radius: var(--r);
  color: var(--ink-dim);
  font-family: var(--font-display);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  cursor: pointer;
  transition:
    color 0.2s,
    border-color 0.2s;
}
.foot__langs button:hover {
  color: var(--ink);
}
.foot__langs button[aria-pressed="true"] {
  color: var(--brass-hi);
  border-color: rgb(184 147 78 / 0.5);
}

/* ==========================================================================
   12 · ZONAS TÁCTILES
   --------------------------------------------------------------------------
   Con el dedo, 38 px no valen. `--touch-min` son 44 px y es un mínimo del
   proyecto, no una sugerencia: comprobado con Playwright a 360 px, estos eran
   los seis controles que se quedaban cortos («Zagraj», «Zagraj teraz» y los
   cuatro idiomas del pie).

   La consulta es por TIPO DE PUNTERO y no por ancho de pantalla: lo que hace
   falta es sitio para un dedo, y un portátil táctil ancho también lo necesita,
   mientras que una ventana estrecha con ratón no.

   Y va al final del archivo a propósito: `.foot__langs button` se declara en
   el bloque 11 con 38 px, y una regla de la misma especificidad solo gana si
   viene después. Colocado junto a `.btn--sm`, el pie seguía en 38 px — que es
   exactamente lo que pasó en el primer intento.
   ========================================================================== */
@media (pointer: coarse) {
  .btn--sm,
  .foot__langs button {
    min-height: var(--touch-min);
  }

  /* Los enlaces legales del pie son texto suelto: sin esto, la zona tocable
     es la altura de la línea (unos 20 px) y con el dedo se falla más de lo
     que se acierta. */
  .foot__legal a {
    display: inline-flex;
    align-items: center;
    min-height: var(--touch-min);
  }
}

/* ==========================================================================
   13 · MOVIMIENTO REDUCIDO
   --------------------------------------------------------------------------
   No es un adorno de accesibilidad: esta página va cargada de movimiento y
   para quien marca esa preferencia tiene que quedar quieta de verdad. El
   `!important` es deliberado — tiene que ganarle a cualquier animación de
   cualquier bloque de arriba.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  /* Las capas de parallax se congelan en su sitio y el reveal deja de
     desplazar: sin esto seguirían moviéndose con el ratón y el scroll,
     que es exactamente lo que se ha pedido evitar. */
  .layer,
  .pane__eye {
    transform: none !important;
  }
  .js .reveal {
    opacity: 1;
    transform: none;
  }
  .js .coop__art .pane--a,
  .js .coop__art .pane--b {
    transform: none !important;
  }
  .lantern {
    display: none;
  }
}

/* ==========================================================================
   TEXTURAS DE MATERIAL — piedra, cuero, latón
   --------------------------------------------------------------------------
   Encargo del cliente: "las tarjetas o zonas de la web podrían tener alguna
   textura leve de piedra, cuero, cosas así".

   Todo esto es PROCEDURAL: `feTurbulence` en un SVG incrustado en la propia
   hoja de estilos. Cero peticiones, cero kilobytes de descarga, y —lo que
   más importa aquí— resolución infinita: en una pantalla 4K una textura en
   imagen se ve pixelada y esta no, porque la dibuja el navegador al tamaño
   que haga falta. Es el mismo truco que ya usaba `.grain` más arriba.

   La regla al usarlas: MUY flojas. Una textura que se nota es un estampado;
   una que no se nota pero se echa de menos al quitarla es material. Todas
   van por debajo de 0.2 de opacidad y en `overlay`/`soft-light`, que
   respetan el color de debajo en vez de ensuciarlo.
   ========================================================================== */

/*
 * PIEDRA. Turbulencia de frecuencia baja (grano grande e irregular) más una
 * segunda pasada fina: la piedra tiene vetas anchas y poros pequeños, y con
 * una sola frecuencia parece papel de lija.
 */
.tex-piedra::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  border-radius: inherit;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='p'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.035' numOctaves='4' seed='7'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23p)' opacity='.55'/%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.75' numOctaves='2' seed='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23f)' opacity='.4'/%3E%3C/svg%3E");
  opacity: 0.13;
  mix-blend-mode: overlay;
}

/*
 * CUERO. Turbulencia `turbulence` (no `fractalNoise`): da celdas cerradas en
 * vez de nube difusa, que es justo el poro del cuero. El degradado radial
 * superpuesto imita el brillo desigual de una piel curtida.
 */
.tex-cuero::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  border-radius: inherit;
  background-image:
    radial-gradient(120% 90% at 30% 10%, rgb(255 235 200 / 0.06), transparent 60%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='c'%3E%3CfeTurbulence type='turbulence' baseFrequency='.14' numOctaves='3' seed='11'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23c)' opacity='.6'/%3E%3C/svg%3E");
  opacity: 0.16;
  mix-blend-mode: soft-light;
}

/*
 * LATÓN CEPILLADO. Turbulencia estirada en horizontal (`baseFrequency` con
 * dos valores: mucho en X, casi nada en Y) — eso es literalmente lo que
 * distingue un metal cepillado de una superficie rugosa: las marcas van en
 * una sola dirección.
 */
.tex-laton::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  border-radius: inherit;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='l'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9 .02' numOctaves='2' seed='5'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23l)' opacity='.5'/%3E%3C/svg%3E");
  opacity: 0.1;
  mix-blend-mode: overlay;
}

/* El contenido va por encima de la textura, no debajo. Sin esto el texto se
   quedaría tapado por el pseudo-elemento en cuanto tuviera fondo propio. */
.tex-piedra > *,
.tex-cuero > *,
.tex-laton > * {
  position: relative;
  z-index: 1;
}

/*
 * Dónde se aplica cada material, y por qué ese y no otro:
 *
 *   · las tarjetas de sala son losas → piedra;
 *   · los paneles del cooperativo son las dos mitades de un mismo cuaderno
 *     de campo → cuero;
 *   · la barra superior y el pie son herrajes → latón cepillado.
 */
.room {
  position: relative;
}
.room::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  border-radius: inherit;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='rp'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.035' numOctaves='4' seed='7'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23rp)' opacity='.55'/%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='rf'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.75' numOctaves='2' seed='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23rf)' opacity='.4'/%3E%3C/svg%3E");
  opacity: 0.13;
  mix-blend-mode: overlay;
}
/* La imagen y el texto de la tarjeta, por encima de su propia piedra. */
.room__art,
.room > *:not(.room__art) {
  position: relative;
  z-index: 1;
}

.step {
  position: relative;
}
.step::before {
  content: "";
  position: absolute;
  inset: -0.6rem -0.8rem;
  pointer-events: none;
  z-index: 0;
  border-radius: var(--r);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='sc'%3E%3CfeTurbulence type='turbulence' baseFrequency='.14' numOctaves='3' seed='11'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23sc)' opacity='.6'/%3E%3C/svg%3E");
  opacity: 0.1;
  mix-blend-mode: soft-light;
}
.step > * {
  position: relative;
  z-index: 1;
}

/* Quien pide menos movimiento normalmente pide también menos ruido visual. */
@media (prefers-reduced-motion: reduce) {
  .room::before,
  .step::before,
  .tex-piedra::before,
  .tex-cuero::before,
  .tex-laton::before {
    opacity: 0.06;
  }
}

/* ==========================================================================
   COPIAS GRANDES PARA PANTALLAS GRANDES
   --------------------------------------------------------------------------
   Encargo del cliente: "la calidad de las imágenes creo que puede mejorar un
   poco, necesito HD 4K en algunas".

   Lo que hay debajo, dicho sin adornos: **el original mide 1376x768**. Es lo
   máximo que dio el generador, así que estas copias NO tienen más detalle —
   están reescaladas con Lanczos y afiladas con máscara de desenfoque. Eso no
   inventa información, pero evita que el navegador estire la imagen con su
   algoritmo barato, y en un monitor grande la diferencia se ve: los bordes
   dejan de estar blandos.

   Tener 4K de verdad exige volver a generar el arte con una herramienta que
   produzca esa resolución. Es una decisión aparte y está anotada.

   Solo se descargan por encima de 1400 px de ancho o en pantallas de doble
   densidad. Por debajo no se pide ni un byte de más: son ~900 KB entre todas
   y el peso sigue siendo requisito de producto, no una preferencia.
   ========================================================================== */

@media (min-width: 1400px), (min-resolution: 1.5dppx) and (min-width: 900px) {
  .layer--bg {
    background-image: image-set(
      url("/assets/img/hero-2752.avif") type("image/avif"),
      url("/assets/img/hero-2752.webp") type("image/webp")
    );
  }
  .pane--a {
    background-image: image-set(
      url("/assets/img/coop-a-1264.avif") type("image/avif"),
      url("/assets/img/coop-a-1264.webp") type("image/webp")
    );
  }
  .pane--b {
    background-image: image-set(
      url("/assets/img/coop-b-1264.avif") type("image/avif"),
      url("/assets/img/coop-b-1264.webp") type("image/webp")
    );
  }
}

/* Las hojas de la puerta se ven a pantalla casi completa, así que se les baja
   el umbral. Se repite el degradado de sombra: `background-image` sustituye
   la lista ENTERA, y sin él las hojas pierden el volumen del canto. */
@media (min-width: 1100px), (min-resolution: 1.5dppx) and (min-width: 700px) {
  .door__leaf--l {
    background-image:
      linear-gradient(90deg, rgb(0 0 0 / 0.5), transparent 22%),
      image-set(
        url("/assets/img/puerta-izq-1376.avif") type("image/avif"),
        url("/assets/img/puerta-izq-1376.webp") type("image/webp")
      );
  }
  .door__leaf--r {
    background-image:
      linear-gradient(270deg, rgb(0 0 0 / 0.5), transparent 22%),
      image-set(
        url("/assets/img/puerta-der-1376.avif") type("image/avif"),
        url("/assets/img/puerta-der-1376.webp") type("image/webp")
      );
  }
}
