/* ---------- tipografías ---------- */
/* Autoalojadas: el repo exige hosting propio, y así el peso de la página deja
 * de tener una parte invisible servida por un tercero. Son los mismos archivos
 * subseteados a latin que servía Google. Ambas son variables: un archivo por
 * familia cubre todos los pesos, sin negritas sintetizadas.
 */

@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('../fonts/space-grotesk-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: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('../fonts/inter-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;
}

/* ============================================================
   Black&WhiteIA — sitio público
   Bloques blancos sobre una placa de circuito, vidrio naranja
   iluminando desde abajo, y superficies de vidrio líquido
   encima. El CSS vive aquí y no dentro del HTML: la versión
   anterior tenía 637 líneas de estilos inline repetidos, que es
   la causa mecánica de que se sintiera desordenada.
   ============================================================ */

:root {
  /* El sitio es blanco entero. El fondo es el mismo tono que el suelo de la
     escena de bloques, a propósito: si el canvas no carga, no se nota dónde
     tendría que haber estado. */
  --bg: #f4f1ed;
  --bg-warm: #faf7f3;

  /* Los dos grises están calculados contra el peor fondo real, no contra
     `--bg`: el peor sitio donde cae una letra no es el papel, es una traza
     naranja encendida de la escena vista a través del vidrio. Medido pixel a
     pixel, ese peor punto es #f7b585. Sobre él, el gris de antes (#6b625a)
     daba 3.26:1 en texto de 12 px, o sea que ya no pasaba AA antes de tocar
     nada. Contra ese fondo el párrafo da 5.6:1 y la letra pequeña 4.8:1.
     El escalón entre los dos es corto porque no hay sitio para tres grises
     sobre este fondo: la jerarquía la llevan el tamaño y el grosor. */
  --text: #17130f;
  --muted: #443c35;   /* cuerpo de texto */
  --dim: #483f38;     /* pies de tarjeta, metadatos, 12 px */

  --accent: #ff5f0a;
  --accent-soft: #ff8a3d;
  --accent-glow: rgba(255, 95, 10, 0.38);

  /* El naranja va en tres, porque sobre blanco no sirve el mismo para todo.
     `--accent` es el de los rellenos —botones, viñetas, selección—, donde el
     contraste lo pone el texto de encima; como letra daría 2.6:1 sobre el
     fondo y no llega ni de lejos a AA.
     Los otros dos son de letra, y están separados por tamaño: sobre la traza
     naranja encendida vista a través del vidrio, el vivo se queda en 3.4:1,
     que basta para un titular —texto grande, umbral 3:1— y no para un número
     de 12 px, que necesita 4.5. Ese va en el oscuro. */
  --accent-text: #a63800;        /* titulares, texto grande. 5.85:1 sobre --bg */
  --accent-text-small: #7d2a00;  /* números y etiquetas de 12-13 px */

  /* Vidrio líquido: el borde claro arriba y el oscuro abajo son lo que da la
     sensación de un canto biselado captando luz, no un rectángulo
     translúcido. La luz llega de un mundo blanco, así que el reflejo de
     arriba es casi blanco sólido y la sombra lleva el naranja del vidrio que
     ilumina la escena desde abajo. */
     El relleno baja otro 30% y el desenfoque sube en la misma proporción: es
     el cambio que mantiene el vidrio legible mientras se vuelve más
     transparente. Lo que difumina no es la letra —esa va encima del filtro—
     sino la escena, así que quitarle relleno al vidrio y dárselo al
     desenfoque deja pasar más movimiento y menos contraste de fondo. */
  --glass-bg: linear-gradient(150deg, rgba(255, 255, 255, 0.41) 0%, rgba(255, 255, 255, 0.24) 55%, rgba(255, 170, 110, 0.10) 100%);
  --glass-border: rgba(255, 255, 255, 0.88);
  /* El `saturate` va bajo a propósito, y es el ajuste menos evidente de toda
     la hoja. Subirlo da un vidrio más vistoso, pero lo que satura es el fondo
     que se ve a través: con 165% la misma traza naranja pasaba de #f7b585 a
     #db7d36 y el texto pequeño se desplomaba de 4.8:1 a 2.0:1. O sea que el
     precio de un vidrio más lucido lo pagaba la letra. A 115% el vidrio
     transparente contrasta mejor que el opaco de ayer. */
  --glass-blur: blur(28px) saturate(115%);
  /* Los paneles difuminan menos que el vidrio grande: son muchos y cada uno
     paga su propio filtro. El token existe para que el móvil pueda bajarlo. */
  --panel-blur: blur(19px) saturate(112%);
  --glass-shadow:
    0 1px 0 0 rgba(255, 255, 255, 0.95) inset,
    0 -1px 0 0 rgba(120, 70, 30, 0.1) inset,
    0 26px 60px -26px rgba(110, 45, 0, 0.38);

  --display: 'Space Grotesk', system-ui, sans-serif;
  --body: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;

  --gutter: clamp(18px, 5vw, 64px);
  --maxw: 1200px;
  --radius: 20px;

  color-scheme: light;
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* Chrome Android reajusta el tamaño de fuente por su cuenta ("text
   autosizing") cuando el alto del viewport cambia -p.ej. al esconderse la
   barra de direcciones- y recalcula todo el texto de golpe, logo y botones
   incluidos: eso es el salto que se veía en el hero, no nuestro JS. Con
   text-size-adjust en 100% el texto queda siempre al tamaño que el CSS pide,
   sin que el navegador lo toque. */
html { scroll-behavior: smooth; scroll-padding-top: 88px; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--body);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;

  /* `clip` y no `hidden`. Con `hidden` en un eje, el otro pasa de `visible` a
     `auto` y el body se vuelve contenedor de scroll; el `position: sticky` del
     hero se engancha entonces a él y no al viewport, que es la causa corriente
     de que el sticky falle en el móvil. `clip` recorta igual y no crea
     contenedor. Mismo criterio que .section y .contact más abajo. */
  overflow-x: clip;
}

/* ---------- la escena de fondo ----------
 *
 * Lienzo fijo detrás de todo el documento, visible desde el primer píxel.
 *
 * z-index negativo para que quede debajo del contenido sin tener que numerar
 * cada sección; el velo va entre el lienzo y el texto.
 */
.bloques {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: -2;
  /* Entra desvanecida para que el primer cuadro no aparezca de golpe sobre el
     fondo plano mientras el shader termina de compilar. */
  opacity: 0;
  transition: opacity .6s ease;
}
.bloques.is-visible { opacity: 1; }
/* Sin WebGL2 queda `--bg`, que es el mismo tono del suelo de la escena: se
   pierde el movimiento, no la página. */
.bloques.is-lost { opacity: 0; }

/* Viñeta que cierra los bordes y despeja el centro para el texto. Sin ella
   los bloques del borde compiten con los titulares. */
.bloques__velo {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(120% 95% at 50% 45%, transparent 52%, rgba(244, 241, 237, 0.62) 100%);
}

img, video, canvas, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
::selection { background: var(--accent); color: #150600; }
button, input, textarea { font: inherit; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 6px; }

/* Enlace de salto. Está siempre en el DOM y solo se ve cuando alguien que
   navega con teclado lo enfoca. Sin él hay que pasar por los seis enlaces de
   la barra antes de llegar al contenido, en cada carga. */
.saltar {
  position: absolute;
  top: 0;
  left: 50%;
  z-index: 100;
  transform: translate(-50%, -120%);
  padding: 10px 18px;
  border-radius: 0 0 10px 10px;
  background: var(--accent);
  color: #150600;
  font-weight: 600;
  transition: transform .18s ease;
}
.saltar:focus { transform: translate(-50%, 0); }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ---------- utilidad de vidrio ---------- */

/* Dos niveles a propósito.
 *
 * .glass lleva backdrop-filter con el desenfoque fuerte: el panel del titular
 * sobre la escena, la barra de navegación y los botones.
 *
 * .panel se ve casi igual y difumina menos. La distinción nació cuando las
 * tarjetas se apoyaban en fondo quieto y el desenfoque no aportaba nada;
 * desde que la escena está detrás de toda la página sí aporta, y el
 * desenfoque más suave va más abajo, en la sección «sobre la escena». Sigue
 * importando no pasarse: cada capa obliga al navegador a releer lo que hay
 * detrás, y todas compiten con el canvas por la misma GPU. La versión
 * anterior tenía 24 capas difuminando a la vez. */

.glass, .panel {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  box-shadow: var(--glass-shadow);
  border-radius: var(--radius);
}

.glass {
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
}

/* Reflejo especular que recorre el borde superior. Es el detalle que separa
   "vidrio" de "caja semitransparente". */
.glass, .panel { position: relative; isolation: isolate; }
.glass::after, .panel::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  /* `overlay` sobre claro empuja a blanco puro y borra el canto; `soft-light`
     lo conserva. */
  background: linear-gradient(160deg, rgba(255, 255, 255, 0.55) 0%, transparent 42%);
  mix-blend-mode: soft-light;
}

/* Sin soporte de backdrop-filter, se compensa opacando el fondo: sin esto el
   texto quedaría directamente sobre la escena, ilegible. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .glass,
  .panel { background: rgba(250, 248, 245, 0.93); }
}

/* ---------- acercamiento de las tarjetas ----------
 *
 * La tarjeta se levanta y crece un punto al pasar por encima, como si se
 * despegara del fondo hacia la luz. La curva es la de salida rápida y frenada
 * larga: un `ease` normal se siente elástico a esta escala.
 *
 * Solo con ratón: en táctil el hover se queda pegado después de tocar, y la
 * tarjeta se quedaría agrandada sin motivo. Con movimiento reducido, el
 * `transition-duration` global de .01ms lo deja instantáneo. */
@media (hover: hover) and (pointer: fine) {
  .card,
  .stat {
    transition:
      transform .38s cubic-bezier(.22, .61, .36, 1),
      border-color .25s ease,
      box-shadow .38s ease;
    will-change: transform;
  }
  /* El contenedor está en el selector por un motivo concreto, no por estilo:
     todas las tarjetas llevan `data-reveal`, y la regla que las deja quietas
     al aparecer —`[data-reveal].is-in { transform: none }`— tiene la misma
     especificidad que `.card:hover` y va después en la hoja. Ganaba ella: el
     acercamiento no se veía y solo cambiaba el borde. Con el contenedor
     delante son tres clases y manda esta. */
  .cards .card:hover,
  .stats .stat:hover {
    transform: translateY(-6px) scale(1.045);
    border-color: rgba(255, 138, 61, .42);
    /* La sombra se alarga con el levantamiento. Sin esto la tarjeta crece pero
       se queda pegada al fondo, y el acercamiento se lee como un fallo. */
    box-shadow:
      0 1px 0 0 rgba(255, 255, 255, 0.95) inset,
      0 -1px 0 0 rgba(120, 70, 30, 0.1) inset,
      0 36px 74px -28px rgba(110, 45, 0, 0.46);
  }
}

/* ---------- tipografía ---------- */

h1, h2, h3 { font-family: var(--display); letter-spacing: -0.035em; line-height: 1.05; }
.lead { color: var(--muted); font-size: clamp(15.5px, 1.9vw, 18.5px); line-height: 1.7; }
strong { font-weight: 600; color: var(--text); }

/* ---------- marca ---------- */

.logo {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--display);
  font-weight: 700;
  letter-spacing: -0.035em;
  white-space: nowrap;
  line-height: 1;
}

.logo__text { color: #17130f; }

.logo__badge {
  display: inline-grid;
  place-items: center;
  background: linear-gradient(150deg, var(--accent-soft), var(--accent));
  color: #140800;
  border-radius: 0.28em;
  padding: 0.16em 0.26em 0.2em;
  font-weight: 700;
  letter-spacing: -0.02em;
  box-shadow: 0 0 22px -4px var(--accent-glow);
}

.logo--nav { font-size: 17px; }
.logo--footer { font-size: 15px; opacity: .85; }

/* ---------- navegación ---------- */

.nav {
  /* Fija, no pegajosa. Una barra pegajosa ocupa su sitio en el flujo y empuja
     el hero hacia abajo; el contenedor pegajoso del hero no se engancharía
     hasta haber recorrido esa altura, y la página "subía" antes de que la
     animación arrancara. Fija no ocupa flujo: el hero empieza en cero. */
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 14px var(--gutter);
  background: linear-gradient(to bottom, rgba(244, 241, 237, 0.88), rgba(244, 241, 237, 0));
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

.nav__links { display: none; gap: 26px; }
.nav__links a { color: var(--muted); font-size: 14px; transition: color .2s; }
.nav__links a:hover { color: var(--text); }

/* ---------- botones ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 13px 24px;
  border-radius: 999px;
  font-size: 14.5px;
  font-weight: 600;
  cursor: pointer;
  text-align: center;
  transition: transform .22s, box-shadow .22s, border-color .22s, background .22s;

  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  box-shadow: var(--glass-shadow);
}

.btn:hover { transform: translateY(-2px); border-color: rgba(255, 138, 61, .55); }

.btn--primary {
  background: linear-gradient(150deg, var(--accent-soft), var(--accent));
  border-color: rgba(255, 180, 120, .5);
  color: #170700;
  box-shadow:
    0 1px 0 0 rgba(255, 255, 255, .3) inset,
    0 14px 38px -14px var(--accent-glow);
}
.btn--primary:hover { box-shadow: 0 1px 0 0 rgba(255,255,255,.35) inset, 0 20px 46px -14px var(--accent-glow); }

.btn--sm { padding: 9px 17px; font-size: 13px; }
.btn--lg { padding: 16px 30px; font-size: 15.5px; }

/* ---------- hero ---------- */

/* El hero ocupa más de una pantalla de alto. Ese excedente es la distancia de
   scroll que alimenta la inmersión: no se secuestra la rueda ni el dedo, solo
   se mide cuánto ha avanzado el usuario dentro de la sección. 150svh de alto
   menos la pantalla fija = 50svh de recorrido. Se bajó desde 130vh y luego
   85vh: en ambos casos se hacía largo antes de llegar.

   `svh` y no `vh`: en el móvil `vh` se resuelve contra el viewport grande —el
   de la barra de direcciones escondida— mientras que la pantalla fija de acá
   abajo mide `100svh`, el chico. Mezclarlos hacía que el recorrido real no
   fuera el de la cuenta. Con las dos en `svh` la resta vuelve a dar 50, y
   ninguna de las dos se mueve cuando la barra aparece o se va. */
.hero { position: relative; height: 150svh; }

.hero__sticky {
  position: sticky;
  top: 0;
  height: 100svh;
  display: grid;
  place-items: center;
  padding: 92px var(--gutter) 84px;
  /* Transparente: detrás está la escena, y es lo que tiene que verse. */
}

/* Fondo estático: se ve solo si WebGL2 no está o el canvas pierde el contexto.
   Nunca queda un hueco negro sin explicación. */
.hero__sticky::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(55% 48% at 50% 48%, rgba(255, 95, 10, 0.13), transparent 72%);
}

/* El panel de vidrio flotando sobre la escena: la luz pasa por detrás y
   alrededor, no por encima. */
.hero__panel {
  position: relative;
  z-index: 1;
  width: min(100%, 760px);
  padding: clamp(28px, 5vw, 52px) clamp(22px, 4.5vw, 54px);
  text-align: center;

  /* Al entrar en el campo, el panel se acerca y se desvanece: lo atraviesas,
     no desaparece. Las dos variables las escribe el scroll desde main.js. */
  transform: scale(var(--panel-scale, 1));
  opacity: var(--panel-opacity, 1);
  will-change: transform, opacity;
}

/* Ya invisible, no debe seguir capturando clics de los botones. */
.hero__panel.is-through { pointer-events: none; }

.hero__title {
  font-size: clamp(31px, 6.4vw, 68px);
  font-weight: 700;
  margin-bottom: 20px;
  /* Reparte las líneas por peso en vez de llenar cada una hasta el borde.
     Sin esto, "tú." quedaba solo en la última línea. */
  text-wrap: balance;
}
/* El naranja de letra, no el de relleno: #ff5f0a sobre el vidrio claro da
   2.63:1 y no pasa ni el umbral de texto grande. Y sin resplandor — el halo
   servía para separar la palabra del negro; sobre blanco solo la ensucia. */
.hero__title em { font-style: normal; color: var(--accent-text); }

.hero__lead {
  max-width: 520px;
  margin: 0 auto 32px;
  color: var(--muted);
  font-size: clamp(15px, 2vw, 18px);
  line-height: 1.65;
}

.hero__actions { display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; }

/* Sin mouse la instrucción no tiene sentido; en táctil se reemplaza por una
   que sí se puede seguir (ver el @media al final del bloque). */
.hero__hint {
  opacity: var(--hint-opacity, 1);
  position: absolute;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 1;
  color: var(--dim);
  font-size: 10.5px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* ---------- secciones ---------- */

.section { max-width: var(--maxw); margin: 0 auto; padding: clamp(64px, 10vw, 140px) var(--gutter); }
.section__head { max-width: 700px; margin-bottom: clamp(34px, 5.5vw, 62px); }
.section__title { font-size: clamp(27px, 5.2vw, 52px); font-weight: 700; margin-bottom: 18px; text-wrap: balance; }

/* ---------- métricas ---------- */

.stats { display: grid; grid-template-columns: 1fr; gap: 12px; list-style: none; }

.stat { display: flex; flex-direction: column; gap: 6px; padding: 24px 22px; }
.stat__value {
  font-family: var(--display);
  font-size: clamp(25px, 3.4vw, 36px);
  font-weight: 700;
  line-height: 1;
  /* La cifra es grande: le vale el naranja vivo, umbral 3:1. */
  color: var(--accent-text);
  /* Sin resplandor: sobre blanco el halo naranja emborrona la cifra. */
}
.stat__label { font-size: 13.5px; font-weight: 600; }
.stat__detail { font-size: 12.5px; color: var(--dim); line-height: 1.5; }

/* ---------- tarjetas ---------- */

.cards { display: grid; grid-template-columns: 1fr; gap: 14px; }

.card { display: flex; flex-direction: column; gap: 11px; padding: 26px; }
.card__n { font-family: var(--display); font-size: 12.5px; font-weight: 700; color: var(--accent-text-small); letter-spacing: .1em; }
.card__name { font-size: 19px; font-weight: 700; }
.card__body { color: var(--muted); font-size: 14.5px; line-height: 1.65; flex: 1; }
.card__fit { padding-top: 12px; border-top: 1px solid rgba(255,255,255,.09); color: var(--dim); font-size: 12px; }

/* ---------- proceso ---------- */

.steps { list-style: none; display: grid; gap: 12px; }
.step { display: grid; gap: 8px; padding: 24px; }
.step__n { font-family: var(--display); font-size: 13px; font-weight: 700; color: var(--accent-text-small); }
.step__title { font-size: 18px; font-weight: 700; margin-bottom: 6px; }
.step__body { color: var(--muted); font-size: 14.5px; line-height: 1.7; max-width: 620px; }

/* ---------- alcance ---------- */

.scope { display: grid; grid-template-columns: 1fr; gap: 14px; }
.scope__col { padding: 26px; }
.scope__col--in { background: linear-gradient(150deg, rgba(255,95,10,.14) 0%, rgba(255,255,255,.02) 60%); }
.scope__title { font-size: 12px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--dim); margin-bottom: 16px; }
.scope__col--in .scope__title { color: var(--accent-text-small); }
.scope__list { list-style: none; display: grid; gap: 11px; }
.scope__list li { position: relative; padding-left: 23px; font-size: 14.5px; line-height: 1.55; }
.scope__col--out .scope__list li { color: var(--muted); }
.scope__list li::before {
  content: ''; position: absolute; left: 0; top: 8px;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--accent); box-shadow: 0 0 10px var(--accent-glow);
}
.scope__col--out .scope__list li::before { background: transparent; border: 1px solid var(--dim); box-shadow: none; }

.note { margin-top: 14px; padding: 24px; border-left: 2px solid var(--accent); }
.note__title { font-size: 15px; font-weight: 700; margin-bottom: 8px; }
.note p { color: var(--muted); font-size: 14px; line-height: 1.7; }

/* ---------- loopa ---------- */

.soon { max-width: var(--maxw); margin: 0 auto; padding: clamp(28px, 5vw, 56px) var(--gutter); }

.soon__box {
  display: grid;
  gap: 22px;
  padding: clamp(26px, 4vw, 38px);
  align-items: center;
}

.soon__logo { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.soon__logo svg { width: 30px; height: 30px; flex: none; }
.soon__logo span {
  font-family: var(--display);
  font-size: 21px;
  font-weight: 700;
  letter-spacing: .04em;
  color: #fff;
}
.soon__logo span i { color: var(--accent-text); font-style: normal; }

.soon__tag {
  display: inline-block;
  padding: 4px 11px;
  border: 1px solid rgba(255,255,255,.2);
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--dim);
  margin-bottom: 14px;
}

.soon__body { color: var(--muted); font-size: 14.5px; line-height: 1.65; max-width: 520px; }
.soon__box .btn { justify-self: start; }

/* ---------- contacto ---------- */

.contact { text-align: center; }
.contact__title { font-size: clamp(27px, 5.2vw, 54px); font-weight: 700; margin-bottom: 16px; text-wrap: balance; }
.contact__lead { max-width: 520px; margin: 0 auto 30px; color: var(--muted); font-size: 15.5px; line-height: 1.7; }
.contact__actions { display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; }

/* ---------- pie ---------- */

.footer {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 32px var(--gutter) 48px;
  border-top: 1px solid rgba(255,255,255,.08);
  display: grid;
  gap: 12px;
  justify-items: center;
  text-align: center;
  color: var(--dim);
  font-size: 12.5px;
}

/* ---------- aparición al hacer scroll ---------- */

[data-reveal] {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity .7s cubic-bezier(.22,1,.36,1), transform .7s cubic-bezier(.22,1,.36,1);
}
[data-reveal].is-in { opacity: 1; transform: none; }

/* Sin JS o con movimiento reducido, el contenido se ve igual. Nunca se
   esconde información detrás de una animación. */
.no-js [data-reveal] { opacity: 1; transform: none; }
/* Sin JS nadie enciende la escena ni desvanece el panel, así que el recorrido
   del hero sería medio scroll mirando un titular quieto. Se acorta a una
   pantalla. */
.no-js .hero { height: auto; }
.no-js .hero__sticky { position: static; min-height: 100svh; height: auto; }
.no-js .hero__hint { display: none; }
@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1; transform: none; }

  /* Sin inmersión no hace falta el recorrido de scroll, y obligar a bajar dos
     pantallas para llegar al contenido sería un castigo. */
  .hero { height: auto; }
  .hero__sticky { position: static; min-height: 100svh; height: auto; }
  .hero__panel { transform: none !important; opacity: 1 !important; }
}

/* Sin WebGL no hay escena que recorrer: el hero se comporta igual que con
   movimiento reducido, y la pista deja de invitar a algo que no va a pasar.
   La marca la pone main.js cuando la escena no arranca. */
.no-bloques .hero { height: auto; }
.no-bloques .hero__sticky { position: static; min-height: 100svh; height: auto; }
.no-bloques .hero__panel { transform: none; opacity: 1; }
.no-bloques .hero__hint { display: none; }

/* ============================================================
   SOBRE LA ESCENA
   Reglas que existen porque detrás de todo el documento hay un
   canvas moviéndose, no un fondo quieto.
   ============================================================ */

/* Los paneles SÍ difuminan, al contrario de lo que dice la regla de `.panel`
   más arriba. Esa regla decía «sin desenfoque, porque se apoyan en fondo
   quieto», y dejó de ser cierto el día que la escena pasó a estar detrás de
   toda la página. Es justo el caso que la propia regla reserva para `.glass`.
   Y es lo que permite que el vidrio sea más transparente sin perder el texto:
   el desenfoque funde las pistas naranjas en un tono plano, o sea que le
   quita contraste al fondo en vez de quitárselo a la letra. */
.panel {
  backdrop-filter: var(--panel-blur);
  -webkit-backdrop-filter: var(--panel-blur);
}

/* Los separadores eran blancos translúcidos, de cuando el fondo era negro.
   Sobre blanco desaparecían. */
.card__fit,
.footer { border-top-color: rgba(90, 60, 30, 0.16); }

/* La columna «lo que sí entra» se apoyaba en un blanco al 2%. */
.scope__col--in {
  background: linear-gradient(150deg, rgba(255, 95, 10, 0.12) 0%, rgba(255, 255, 255, 0.5) 60%);
}

/* RED DE SEGURIDAD.
   La página no tiene fondo propio más allá de `--bg`, y el blanco vivo lo
   pone el lienzo. Si el lienzo se apaga —sin WebGL2, sin JavaScript, o si el
   navegador tira el contexto— queda el `--bg`, que es el mismo tono del suelo
   de la escena. Se pierde el movimiento; no se pierde la página.
   Esto solo apaga del todo el velo, que sin escena detrás no tiene nada que
   cerrar. */
.no-bloques .bloques__velo,
.no-js .bloques__velo { display: none; }

/* Los titulares de sección van desnudos sobre la escena. Sobre bloques
   blancos y pistas naranjas encendidas, el párrafo gris pierde la pelea.
   Un charco de luz detrás los devuelve al primer plano sin tapar la escena:
   opaco donde está el texto y disuelto en los bordes, así que no se lee como
   una caja. Degradado y no `backdrop-filter` a propósito — un desenfoque más
   a pantalla completa sí competiría con el canvas por la GPU. */
.section__head,
.contact { position: relative; isolation: isolate; }

/* El charco se sale 130 px por cada lado, y eso ensanchaba el documento: en un
   teléfono de 390 px la página medía 520 y se arrastraba de lado. No se ve como
   un desbordamiento, se ve como una página mal hecha.
   `clip` y no `hidden` a propósito: `hidden` convierte la sección en contenedor
   de scroll —con su ancla de desplazamiento y su efecto sobre lo pegajoso—,
   mientras que `clip` solo recorta. Recortar en la sección y no en el cuerpo
   deja que el charco siga extendiéndose todo lo que quepa en pantalla ancha y
   lo corta justo en el borde cuando no cabe. */
.section,
.contact { overflow-x: clip; }

.section__head::before,
.contact::before {
  content: '';
  position: absolute;
  /* La caja se estira bastante más allá del texto para que el degradado tenga
     sitio donde apagarse. */
  inset: -74px -130px;
  z-index: -1;
  pointer-events: none;
  /* `closest-side` es lo que quita el canto: la elipse termina justo en cada
     borde de la caja, así que llega a transparente exactamente ahí. Con un
     tamaño en porcentaje quedaba medio opaca al llegar al borde y se veía el
     rectángulo, que era justo lo que había que evitar. */
  background: radial-gradient(closest-side,
    rgba(247, 245, 242, 0.95) 0%,
    rgba(247, 245, 242, 0.78) 46%,
    rgba(247, 245, 242, 0) 100%);
}

/* ============================================================
   RESPONSIVE
   Se escribe de móvil hacia arriba: arriba quedó la versión
   angosta, y cada corte solo añade lo que el ancho permite.
   ============================================================ */

/* ---- Tablet en vertical ---- */
@media (min-width: 620px) {
  .stats { grid-template-columns: repeat(2, 1fr); }
  .cards { grid-template-columns: repeat(2, 1fr); }
  .scope { grid-template-columns: repeat(2, 1fr); }
  .footer { grid-template-columns: 1fr auto; justify-items: stretch; text-align: left; }
  .footer > :last-child { text-align: right; }
}

/* ---- Tablet en horizontal ---- */
@media (min-width: 860px) {
  .nav__links { display: flex; }
  .step { grid-template-columns: 76px 1fr; gap: 24px; align-items: start; padding: 26px 28px; }
  .step__n { padding-top: 3px; }
  .soon__box { grid-template-columns: 1fr auto; gap: 32px; }
  .soon__box .btn { justify-self: end; }
}

/* ---- Escritorio ---- */
@media (min-width: 1100px) {
  .stats { grid-template-columns: repeat(4, 1fr); }
  .cards { grid-template-columns: repeat(4, 1fr); }
}

/* ---- Pantallas muy bajas (móvil apaisado): el hero a 100svh dejaría el
       titular sin aire, así que se libera la altura mínima. ---- */
@media (max-height: 560px) and (orientation: landscape) {
  .hero { min-height: auto; padding-block: 76px 56px; }
  .hero__hint { display: none; }
}

/* ---- Pantallas táctiles: no hay puntero que mover ---- */
@media (pointer: coarse) {
  .hero__hint__mouse { display: none; }
}
@media (pointer: fine) {
  .hero__hint__touch { display: none; }
}

/* ---- El desenfoque de fondo es caro en equipos modestos. En pantallas
       pequeñas se reduce el radio: se mantiene la lectura de vidrio sin
       pagar el costo completo en cada panel.
       Y como el radio baja, el relleno sube: el desenfoque es lo que corre en
       GPU —lo único que el acelerador de CPU no puede medir, o sea lo que no
       se ha podido comprobar en un teléfono de verdad—, mientras que el
       relleno no cuesta nada. En el móvil la legibilidad la paga el relleno y
       no el desenfoque. ---- */
@media (max-width: 619px) {
  :root {
    --glass-blur: blur(15px) saturate(112%);
    --panel-blur: blur(13px) saturate(110%);
    --glass-bg: linear-gradient(150deg, rgba(255, 255, 255, 0.52) 0%, rgba(255, 255, 255, 0.32) 55%, rgba(255, 170, 110, 0.12) 100%);
  }
}
