/* ============================================================================
   Espurna Studio · v2 — "La Espurna Viva"
   Sistema de diseño completo. Todo comentado por bloques para que cualquier
   programador pueda continuarlo. Orden: tokens → reset → capas de fondo (ascua,
   grano, viñeta) → cursor → preloader → HUD → hero → responsive → accesibilidad
   → el viaje (raíl, paneles, hoja móvil) → precios → contacto → footer.
   ========================================================================== */

/* ── Fuentes ─────────────────────────────────────────────────────────────── */
@font-face {
  font-family: "Fraunces";
  src: url("../../fonts/fraunces.woff2") format("woff2");
  font-weight: 100 900;            /* archivo variable: cubrimos todo el rango */
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("../../fonts/inter.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* ── Tokens de marca ─────────────────────────────────────────────────────── */
:root {
  /* Color — negro cálido de la marca + rampa de ascua */
  --bg:        #100c09;
  --bg-soft:   #171009;
  --ink:       #f4ece0;          /* blanco hueso */
  --ink-dim:   #b7a692;
  /* 7.2:1 sobre --bg. Antes era #9a8b78 = 5.88:1, que cumple AA sobre el fondo
     PLANO pero deja casi nada de margen: este color lo llevan textos que van
     directamente sobre el lienzo 3D (la nota de precios, el aviso de scroll, el
     © del pie), y ahí basta un resplandor del Sol de luminancia 0.055 para
     bajarlo de 4.5:1. Con 7.2:1 el margen aguanta el fondo real, no el teórico. */
  --ink-faint: #ab9b86;
  --ember:     #ff6a12;          /* naranja ascua */
  --ember-hot: #ffb457;          /* borde incandescente */
  --ember-deep:#c3360a;
  /* Final del degradado de los botones de acción. NO es --ember-deep: con
     #c3360a el texto #1a0d03 del botón da 3.49:1 y falla 1.4.3 AA a partir del
     ~82% del ancho del botón (medido). #e4530e da 5.03:1 y a ojo es el mismo
     naranja. --ember-deep se queda para decoración, donde no hay texto encima. */
  --ember-btn: #e4530e;

  /* Tipografía */
  --serif: "Fraunces", Georgia, "Times New Roman", serif;
  --sans:  "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  /* Ritmo / medidas */
  --pad: clamp(1.25rem, 4vw, 3.5rem);
  --maxw: 1320px;

  /* Curvas de animación reutilizables */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-io:  cubic-bezier(0.65, 0, 0.35, 1);
}

/* ── Reset esencial ──────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html { -webkit-text-size-adjust: 100%; }

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: clamp(1rem, 0.9rem + 0.4vw, 1.15rem);
  line-height: 1.6;
  overflow-x: hidden;
  /* El cursor propio sustituye al del sistema en dispositivos con puntero fino */
  min-height: 100svh;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

img, svg, canvas { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

::selection { background: var(--ember); color: #1a0d03; }

/* Solo para lectores de pantalla: oculto a la vista, presente en el árbol a11y */
.u-sr {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap; border: 0;
}

/* Foco de teclado visible y coherente en TODO lo interactivo (sobre tema oscuro
   el outline por defecto queda muy tenue). Solo con :focus-visible → no molesta
   al ratón. */
a:focus-visible,
button:focus-visible,
.btn:focus-visible,
[tabindex]:focus-visible,
summary:focus-visible {
  outline: 2px solid var(--ember-hot);
  outline-offset: 3px;
  border-radius: 4px;
}

/* Ocultamos el scrollbar visual pero mantenemos el scroll (estética inmersiva) */
html { scrollbar-width: none; }
html::-webkit-scrollbar { width: 0; height: 0; }

/* Salto al contenido — invisible hasta recibir el foco por teclado */
.skip {
  position: fixed;
  top: 0.6rem; left: 0.6rem;
  z-index: 200;
  transform: translateY(-160%);
  padding: 0.6rem 1rem;
  border-radius: 10px;
  background: var(--ember-hot); color: #1a0d03; font-weight: 700;
  transition: transform .2s var(--ease-out);
}
.skip:focus-visible { transform: translateY(0); outline-offset: 2px; }

/* ══════════════════════════════════════════════════════════════════════════
   CAPAS DE FONDO
   ══════════════════════════════════════════════════════════════════════════ */

/* Ascua WebGL — fija detrás de todo el contenido */
.ember {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
}

/* Rescoldo de reserva: sólo se ve si NO hay WebGL (clase .no-webgl en <html>) */
.ember-fallback {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  display: none;
  background:
    radial-gradient(60% 45% at 50% 78%, rgba(255,120,30,0.55), rgba(255,120,30,0) 70%),
    radial-gradient(28% 22% at 50% 74%, rgba(255,190,110,0.75), rgba(255,120,30,0) 70%),
    var(--bg);
}
.no-webgl .ember { display: none; }
.no-webgl .ember-fallback { display: block; }

/* Grano de película — textura muy sutil sobre todo el conjunto */
.grain {
  position: fixed;
  inset: 0;                 /* antes -50%: la capa ocupaba 4× el viewport en memoria */
  z-index: 1;
  pointer-events: none;
  opacity: 0.05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  mix-blend-mode: overlay;
}

/* Viñeta cinematográfica — oscurece las esquinas para enfocar la mirada en el
   centro de la escena 3D. Va SOBRE el ascua (z1) pero DEBAJO del contenido (z2),
   con mezcla "multiply": sólo tiñe el fondo 3D, nunca el texto ni las tarjetas. */
.vignette {
  position: fixed; inset: 0; z-index: 1; pointer-events: none;
  background: radial-gradient(120% 88% at 50% 42%, transparent 52%, rgba(6,4,2,0.62) 100%);
  mix-blend-mode: multiply;
}
.no-webgl .vignette { display: none; }

/* Todo el contenido navegable va por encima de las capas de fondo */
.hud, main { position: relative; z-index: 2; }

/* ══════════════════════════════════════════════════════════════════════════
   CURSOR PERSONALIZADO
   ══════════════════════════════════════════════════════════════════════════ */
.cursor { position: fixed; inset: 0; z-index: 90; pointer-events: none; }
.cursor__dot,
.cursor__ring {
  position: fixed;
  top: 0; left: 0;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  will-change: transform;
}
.cursor__dot {
  width: 6px; height: 6px;
  background: var(--ember-hot);
  box-shadow: 0 0 12px 2px rgba(255,140,40,0.9);
}
.cursor__ring {
  width: 42px; height: 42px;
  border: 1px solid rgba(255,140,50,0.5);
  transition: width .3s var(--ease-out), height .3s var(--ease-out),
              border-color .3s var(--ease-out), background-color .3s var(--ease-out);
}
/* Al pasar por algo interactivo, el anillo crece y se aviva */
.cursor.is-hot .cursor__ring {
  width: 68px; height: 68px;
  background: rgba(255,120,40,0.10);
  border-color: rgba(255,160,70,0.85);
}

/* El cursor propio sólo tiene sentido con puntero fino (ratón/trackpad) */
@media (hover: none), (pointer: coarse) {
  .cursor { display: none; }
  body { cursor: auto; }
}
/* ⚠️ `body:has(> .cursor)` y no `body` a secas. El `<div class="cursor">` que
   sustituye al puntero **solo existe en index.html**: las tres páginas legales y
   la 404 no lo tienen, pero sí ejecutan el script que pone `class="js"`. Con el
   selector antiguo, esas cuatro páginas se navegaban con ratón o trackpad
   SIN NINGÚN PUNTERO VISIBLE. Con `:has` la regla solo se activa donde hay
   sustituto de verdad.
   Y si el navegador no soporta `:has` (Firefox < 121), descarta la regla entera
   y sale el puntero del sistema — que es exactamente el fallo seguro. */
@media (hover: hover) and (pointer: fine) {
  .js body:has(> .cursor),
  .js body:has(> .cursor) a,
  .js body:has(> .cursor) button { cursor: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   PRELOADER — "encendido" de la marca
   ══════════════════════════════════════════════════════════════════════════ */
.loader {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  place-content: center;
  gap: 1.4rem;
  background: var(--bg);
}
.loader.is-done { pointer-events: none; }
/* Sin JS el preloader NO puede ocultarse solo (lo hace main.js): lo retiramos
   para que el contenido y el fallback apilado del viaje sean accesibles. */
.no-js .loader { display: none; }
.loader__mark {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}
.loader__word {
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(2rem, 7vw, 4rem);
  letter-spacing: -0.02em;
  color: var(--ink);
}
/* La chispa que "prende" sobre la marca */
.loader__spark {
  position: absolute;
  right: -14px; top: -6px;
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--ember-hot);
  box-shadow: 0 0 22px 6px rgba(255,150,50,0.9);
  opacity: 0;
  transform: scale(0.2);
}
.loader__bar {
  width: min(240px, 60vw);
  height: 2px;
  background: rgba(255,255,255,0.10);
  overflow: hidden;
  border-radius: 2px;
}
.loader__bar span {
  display: block;
  width: 0%;
  height: 100%;
  background: linear-gradient(90deg, var(--ember-deep), var(--ember-hot));
}

/* ══════════════════════════════════════════════════════════════════════════
   HUD superior
   ══════════════════════════════════════════════════════════════════════════ */
.hud {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: clamp(1rem, 2.5vw, 1.75rem) var(--pad);
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--serif);
  font-size: 1.15rem;
  letter-spacing: -0.01em;
}
.brand img { width: 24px; height: 24px; filter: drop-shadow(0 0 10px rgba(255,120,40,0.5)); }
.brand i { color: var(--ink-dim); font-style: normal; }
/* El HUD flota sobre el núcleo brillante del Sol: una sombra sólida garantiza
   el contraste del texto sea cual sea el brillo detrás (WCAG 1.4.3). */
.brand, .hudnav a { text-shadow: 0 1px 14px rgba(6,4,2,0.85), 0 0 2px rgba(6,4,2,0.7); }

/* ══════════════════════════════════════════════════════════════════════════
   HERO
   ══════════════════════════════════════════════════════════════════════════ */
.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 0 var(--pad);
}
.hero__inner {
  max-width: var(--maxw);
  margin: 0 auto;
  width: 100%;
  /* El texto vive en el tercio superior para respirar sobre el núcleo del ascua */
  transform: translateY(-6vh);
}
.hero__eyebrow {
  font-size: 0.8rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--ink-dim);
  margin-bottom: clamp(1rem, 2vw, 1.6rem);
  text-shadow: 0 1px 20px rgba(8, 4, 2, 0.6);
}
.hero__title {
  font-family: var(--serif);
  font-weight: 340;
  line-height: 0.98;
  letter-spacing: -0.035em;
  font-size: clamp(2.9rem, 11vw, 9.5rem);
  /* Seguridad: en pantallas muy estrechas una palabra larga nunca desborda */
  overflow-wrap: break-word;
}
.hero__title .line { display: block; }
/* Sombra sólo en la línea blanca (la de ascua ya lleva su propio resplandor) */
.hero__title .line:not(.line--ember) { text-shadow: 0 2px 46px rgba(8, 4, 2, 0.45); }
.hero__title .line--ember {
  font-style: italic;
  font-weight: 420;
  background: linear-gradient(92deg, var(--ember-hot), var(--ember) 45%, var(--ember-deep));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  /* leve resplandor para que "arda" */
  filter: drop-shadow(0 4px 34px rgba(255,110,30,0.35));
}
.hero__sub {
  margin-top: clamp(1.4rem, 3vw, 2.2rem);
  max-width: 42ch;
  color: var(--ink-dim);
  font-size: clamp(1rem, 0.95rem + 0.4vw, 1.25rem);
  text-shadow: 0 1px 22px rgba(8, 4, 2, 0.65);
}

/* Indicador de scroll */
.scrollcue {
  position: absolute;
  left: 50%;
  bottom: clamp(1.4rem, 4vh, 2.6rem);
  transform: translateX(-50%);
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 0.7rem;
  color: var(--ink-faint);
}
.scrollcue__label {
  font-size: 0.72rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  /* Puede caer sobre el Sol o sobre la nave: la sombra sólida le asegura el
     contraste haya lo que haya detrás. */
  text-shadow: 0 1px 14px rgba(6,4,2,0.95), 0 0 3px rgba(6,4,2,0.9);
}
.scrollcue__line {
  width: 1px; height: 46px;
  background: linear-gradient(var(--ember-hot), transparent);
  position: relative;
  overflow: hidden;
}
.scrollcue__line::after {
  content: "";
  position: absolute;
  top: -50%; left: 0;
  width: 100%; height: 50%;
  background: var(--ember-hot);
  animation: cueRun 1.8s var(--ease-io) infinite;
}
@keyframes cueRun {
  0%   { transform: translateY(-100%); }
  100% { transform: translateY(320%); }
}

/* ══════════════════════════════════════════════════════════════════════════
   UTILIDADES DE REVELADO
   El estado inicial (oculto) sólo se aplica si hay JS: así, sin JS, todo se ve.
   ══════════════════════════════════════════════════════════════════════════ */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(28px);
  /* sin will-change: el reveal ocurre una sola vez; GSAP no lo necesita y así
     no promocionamos ~20 elementos a capas permanentes de GPU. */
}

/* ══════════════════════════════════════════════════════════════════════════
   RESPONSIVE
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 760px) {
  /* En móvil el Sol llena la pantalla y el texto queda por encima: un velo
     oscuro sutil (sólo arriba) protege la legibilidad sin apagar el Sol. */
  .hero::before {
    content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
    background: linear-gradient(178deg, rgba(6,4,2,0.62) 0%, rgba(6,4,2,0.30) 40%, rgba(6,4,2,0) 66%);
  }
  /* El mensaje se ancla ARRIBA en vez de centrarse: así el tercio inferior
     queda libre para la escena y la nave, en vez de que el texto le pase por
     encima. Antes todo competía por el mismo espacio y se sentía saturado. */
  .hero { justify-content: flex-start; padding-top: clamp(5rem, 13vh, 7rem); }
  .hero__inner { transform: none; }
  .hero__eyebrow { margin-bottom: 0.9rem; }
  .hero__title { font-size: clamp(2.5rem, 12vw, 4.4rem); }
  .hero__sub { font-size: 1rem; margin-top: 1.1rem; max-width: 34ch; }
  .hero__cta { margin-top: 1.6rem; }
  /* El aviso deja de estar centrado: en vertical el centro de abajo es donde
     caen el Sol y la nave, y ahí no se leía. */
  .scrollcue {
    left: var(--pad); transform: none;
    align-items: flex-start;
    bottom: clamp(1rem, 2.5vh, 1.6rem);
    gap: 0.5rem;
  }
  /* 10rem = dos líneas justas; más estrecho se parte en cuatro y más ancho se
     mete debajo del Sol. */
  .scrollcue__label { font-size: 0.66rem; letter-spacing: 0.2em; max-width: 10rem; line-height: 1.5; }
  .scrollcue__line { height: 34px; }
}

/* ⚠️ Los bloques de PREFERS-REDUCED-MOTION y de POINTER:COARSE vivían aquí y se
   han movido al FINAL del fichero. Motivo: una media query NO añade
   especificidad, así que sus reglas perdían contra las reglas base de los
   componentes, que se declaran más abajo (.panel, .tier, .form). Cuatro
   declaraciones estaban muertas — entre ellas los tres `backdrop-filter: none`,
   o sea que en TODO dispositivo táctil seguían activos tres desenfoques a
   pantalla completa sobre el lienzo vivo, que es justo lo que ese bloque decía
   estar evitando. Al final del fichero sí ganan. NO devolverlos aquí. */

/* ══════════════════════════════════════════════════════════════════════════
   NAV del HUD + BOTONES
   ══════════════════════════════════════════════════════════════════════════ */
.hudnav {
  display: inline-flex;
  align-items: center;
  gap: clamp(0.8rem, 2vw, 1.6rem);
  font-family: var(--sans);
  font-size: 0.9rem;
}
/* padding-block para que el objetivo de pulsado llegue a 24px (WCAG 2.2 AA
   2.5.8): el texto solo daba 23px de alto. */
.hudnav a { color: var(--ink-dim); transition: color .25s var(--ease-out); padding-block: 4px; }
.hudnav a:hover { color: var(--ink); }
.hudnav__cta {
  color: var(--ink) !important;
  border: 1px solid rgba(255,140,50,0.5);
  border-radius: 999px;
  padding: 0.5rem 1rem;
  white-space: nowrap;
  background: rgba(255,106,18,0.08);
  transition: background .25s var(--ease-out), border-color .25s var(--ease-out);
}
.hudnav__cta:hover { background: rgba(255,106,18,0.18); border-color: var(--ember-hot); }
/* En móvil dejamos solo el CTA para no saturar el HUD */
@media (max-width: 640px) {
  .hudnav a:not(.hudnav__cta) { display: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   SELECTOR DE IDIOMA
   ──────────────────────────────────────────────────────────────────────────
   No es un traductor: son tres versiones reales de la web (/, /ca/, /en/),
   cada una con su URL indexable y su `hreflang`. Aparece dos veces —en el HUD
   y en el pie— porque quien baja hasta el final no va a subir a buscarlo.

   `margin-left: auto` no es decorativo: el `.hud` es un flex de tres hijos con
   `space-between`, así que sin él el selector se quedaba suelto en el centro
   de la cabecera. El margen automático se come todo el hueco libre antes de
   que `space-between` reparta, y el resultado es marca · [hueco] · idiomas nav.

   Los enlaces son de dos letras: el objetivo de pulsado de 24 px (WCAG 2.5.8)
   hay que construirlo con relleno, no sale del texto.
   ══════════════════════════════════════════════════════════════════════════ */
.langs {
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
  font-family: var(--sans);
  font-size: 0.78rem;
  letter-spacing: 0.06em;
}
.hud .langs { margin-left: auto; margin-right: clamp(0.8rem, 2vw, 1.6rem); }
.langs a {
  color: var(--ink-faint);
  padding: 6px 8px;
  border-radius: 7px;
  line-height: 1;
  transition: color .25s var(--ease-out), background .25s var(--ease-out);
  /* Misma sombra que el resto del HUD: flota sobre el núcleo del Sol. */
  text-shadow: 0 1px 14px rgba(6,4,2,0.85), 0 0 2px rgba(6,4,2,0.7);
}
.langs a:hover { color: var(--ink); }
/* El idioma activo lleva color Y fondo: el color por sí solo no puede ser el
   único indicador (WCAG 1.4.1). */
.langs a[aria-current] {
  color: var(--ink);
  background: rgba(255,106,18,0.14);
  box-shadow: inset 0 0 0 1px rgba(255,140,50,0.35);
}
.foot .langs { margin-top: 0.2rem; }

/* ── Cabida del HUD en móvil ───────────────────────────────────────────────
   Los cortes de aquí abajo NO son números redondos elegidos a ojo: salen de
   medir en el navegador lo que ocupa cada configuración del HUD. Meter un
   tercer elemento en una barra que ya iba justa desbordaba el CTA fuera de la
   pantalla, y el `overflow-x: hidden` lo escondía en silencio — que es la peor
   forma de romperse, porque no se ve.

     configuración                                 necesita   dónde se usa
     marca + 3 idiomas + nav completo (3 enlaces)   641,1 px    > 760
     marca + 3 idiomas compactos + nav completo     607   px   ≤ 760
     marca + 3 idiomas compactos + CTA solo         446   px   ≤ 640
     símbolo + 3 idiomas compactos + CTA solo       310   px   ≤ 520

   El punto crítico NO es el móvil: es 641 px, justo por encima del corte en el
   que el nav se queda solo con el CTA. Ahí conviven la marca larga, los tres
   idiomas y los tres enlaces del nav, y la suma daba 641,1 px sobre 641
   disponibles — cabía por 0,1 px. Por eso el selector se compacta ya desde
   760 px y no desde 640: el problema estaba en la tablet, no en el teléfono.

   Se reutilizan los cortes que ya tiene la hoja (760, 640 y 400) en vez de
   inventar tres nuevos.

   Qué se sacrifica: la palabra de la marca, que se queda en su símbolo — el
   enlace conserva su `aria-label`, así que para un lector de pantalla no cambia
   nada. El pie mantiene siempre los tres idiomas y el nombre completo.

   ⚠️ 2026-07-31 · EL IDIOMA ACTIVO YA NO SE ESCONDE. Se ocultaba por debajo de
   760 px «porque es un enlace a esta misma página», y el resultado era que en un
   móvil desaparecía justo el que dice DÓNDE ESTÁS: se veían dos siglas sueltas
   (CA EN) y ni se leía como un selector ni había forma de saber el idioma en
   curso. Un selector que no marca la selección no es un selector.
   Vuelto a medir con las tres siglas: no cuesta NADA, porque el hueco sale del
   `margin-left: auto` que ya había entre la marca y el grupo de la derecha.
   Medido con el idioma activo visible (borde derecho del CTA y holgura):
     320 px → CTA en 305, holgura 15,2 px, sin desbordamiento
     390 px → CTA en 372, holgura 18,0 px, sin desbordamiento
   Idénticos a los de antes: el CTA no se mueve ni un píxel. */
@media (max-width: 760px) {
  .hud .langs { font-size: 0.72rem; gap: 0; margin-right: 0.5rem; }
  /* 7px de relleno vertical sobre 11,5px de texto = 25,5px de alto: por encima
     del objetivo de 24px de WCAG 2.5.8. Con 6px se quedaba en 23,5. */
  .hud .langs a { padding: 7px 6px; }
  /* El activo, más compacto pero PRESENTE: sin subrayado de fondo ancho, solo
     el recuadro que ya lo distingue en escritorio. */
  .hud .langs a[aria-current] { padding-left: 5px; padding-right: 5px; }
}
/* ⚠️ El corte de la palabra de la marca sube de 400 a 480 px. Con el idioma
   activo otra vez visible, la suma medida a 401 px es:
     20 + 135,3 (marca con palabra) + 84,2 (tres idiomas) + 8 + 178,3 (CTA) + 20
     = 445,8 px  →  necesita 446 px, y con 401 el CTA se salía 24,8 px.
   Y salirse aquí no se ve: `overflow-x: hidden` lo esconde, que es justo la
   forma de romperse que este bloque existe para evitar.
   Se corta en 520 y no en 480: a 481 px cabe, pero deja solo 11,2 px entre la
   marca y los idiomas, y las métricas de fuente de Safari y Firefox no son las
   de Chrome. 520 deja 50 px, que es holgura de verdad. */
@media (max-width: 520px) {
  .hud .brand span { display: none; }
  /* A 320-520 px las siglas se juntan al máximo sin bajar de los 24 px de
     objetivo táctil: el alto lo pone el relleno vertical, que no se toca. */
  .hud .langs a { padding-left: 5px; padding-right: 5px; }
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  font-family: var(--sans);
  font-weight: 600;
  font-size: 0.98rem;
  letter-spacing: 0.01em;
  padding: 0.85rem 1.5rem;
  border-radius: 999px;
  transition: transform .25s var(--ease-out), box-shadow .3s var(--ease-out),
              background-color .25s var(--ease-out), border-color .25s var(--ease-out);
}
.btn:hover { transform: translateY(-2px); }
.btn--ember {
  color: #1a0d03;
  background: linear-gradient(95deg, var(--ember-hot), var(--ember) 55%, var(--ember-btn));
  box-shadow: 0 8px 30px -8px rgba(255,110,30,0.6);
}
.btn--ember:hover { box-shadow: 0 12px 40px -8px rgba(255,130,40,0.75); }
.btn--ghost {
  color: var(--ink);
  border: 1px solid rgba(255,255,255,0.22);
  background: rgba(255,255,255,0.02);
}
.btn--ghost:hover { border-color: var(--ember-hot); color: var(--ember-hot); }

.hero__cta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
  margin-top: clamp(1.8rem, 3.5vw, 2.6rem);
}
.hero__sub strong { color: var(--ink); font-weight: 600; }

/* ══════════════════════════════════════════════════════════════════════════
   EL VIAJE — carrusel orbital (scroll = giro del sistema)
   La sección es MUY alta y su escenario queda pinneado (sticky). El JS lee el
   progreso del scroll dentro de ella para girar el sistema y enfocar cada
   planeta; los paneles de texto los coloca/desvanece el JS. Sin JS (o con
   reduced-motion) los paneles se apilan y se leen con normalidad — el
   contenido nunca depende del efecto.
   ══════════════════════════════════════════════════════════════════════════ */
.journey {
  position: relative;
  /* Alto = espacio de scroll del viaje: un tramo por parada. Son SEIS paradas
     (5 planetas de la oferta + Saturno, el planeta de las maquetas), a ~150vh
     cada una para que el vuelo se lea con calma.
     Subió de 760vh el 2026-07-30 al meter el DESCANSO del 18% en cada parada
     (→ main.js): sin alargar el recorrido, ese 18% de scroll parado saldría del
     vuelo y la nave volaría un 22% más rápido — justo lo contrario de lo que se
     busca.

     Y subió otra vez el 2026-07-31 al traerse el ALEJAMIENTO dentro del viaje.
     La cuenta es la misma que la vez anterior y conviene dejarla escrita: las
     paradas ocupaban el 90% del recorrido y ahora ocupan el 75% (`J_PARADAS` en
     main.js), así que para que NO se acorten hay que dividir por 0,75/0,90 →
     900 × 1,20 = 1080vh. Si se toca `J_PARADAS`, hay que rehacer esta cuenta o
     el vuelo cambia de velocidad sin que nadie lo haya pedido.

     Y una tercera vez el 2026-07-31, por lo mismo: el ALEJAMIENTO pasó a ser un
     plano largo (6 s) y la ENTRADA muerta se recortó, así que `J_PARADAS` bajó
     de 0,75 a 0,72. Misma cuenta: 1080 × 0,75/0,72 = 1125vh. Las paradas
     conservan exactamente los píxeles que tenían. */
  height: 1125vh;
}
/* En móvil el mismo recorrido se hace a dedo y se hace largo antes: se acorta
   el tramo, no el descanso. 760 × 1,20 = 912, y × 0,75/0,72 = 950. */
@media (max-width: 920px) { .journey { height: 950vh; } }
/* Móvil APAISADO: el viaje se mide en vh, y con 390px de alto 760vh son solo
   2.317 px de recorrido útil para seis planetas — 386 px por parada. Ahí cada
   píxel de scroll movía casi tres veces más cámara que en escritorio y el vuelo
   salía disparado. Se compensa con el alto, que es lo que faltaba. */
@media (max-height: 520px) and (orientation: landscape) { .journey { height: 2000vh; } }
/* Ancla invisible del menú "Proyectos": cae en el punto de scroll exacto en el
   que la nave llega al planeta de las maquetas (última parada = 95% del viaje,
   que es donde el JS sitúa el final del recorrido útil). */
.journey__anchor {
  position: absolute;
  left: 0;
  width: 1px; height: 1px;
  top: calc((100% - 100svh) * 0.95);
  pointer-events: none;
}
.journey__stage {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
}
/* ── Raíl de progreso del viaje ────────────────────────────────────────────
   Seis marcas que dicen de un vistazo cuántas paradas hay y en cuál estamos —
   la duda de "¿cuánto queda?" es la que hace abandonar un scroll largo— y que
   además permiten saltar a cualquier planeta de un toque. Lo construye el JS
   (main.js · construirRail), así que sin JS simplemente no existe.

   Va en el borde DERECHO en escritorio (donde la tarjeta de texto ocupa la
   izquierda) y ARRIBA en móvil (donde la hoja de información ocupa el pie).
   Puesto en el centro chocaba con una cosa o con la otra. */
.rail {
  position: absolute;
  z-index: 4;
  display: flex;
  gap: 0.4rem;
  right: clamp(0.4rem, 1.4vw, 1.2rem);
  top: 50%;
  transform: translateY(-50%);
  flex-direction: column;
}
.rail__stop {
  display: grid;
  place-items: center;
  width: 44px; height: 34px;      /* objetivo táctil holgado (WCAG 2.5.8) */
  padding: 0;
}
.rail__bar {
  display: block;
  width: 3px; height: 26px;
  border-radius: 2px;
  /* 0.45 y no 0.28: compuesto sobre el fondo, 0.28 daba 2.40:1 y los indicadores
     de interfaz necesitan 3:1 (WCAG 1.4.11). Con 0.45 son 4.52:1. La marca
     ACTIVA se sigue distinguiendo de sobra: es ámbar y escala ×1.9. */
  background: rgba(255,255,255,0.45);
  /* Cerco oscuro: las marcas pasan por encima de planetas muy claros y sin él
     desaparecen justo cuando más falta hacen. */
  box-shadow: 0 0 0 1px rgba(6,4,2,0.55), 0 1px 6px rgba(6,4,2,0.7);
  transition: background .35s var(--ease-out), transform .35s var(--ease-out),
              box-shadow .35s var(--ease-out);
}
.rail__stop:hover .rail__bar { background: rgba(255,255,255,0.55); }
.rail__stop.is-on .rail__bar {
  background: var(--ember-hot);
  transform: scaleX(1.9);
  box-shadow: 0 0 0 1px rgba(6,4,2,0.55), 0 0 14px 2px rgba(255,140,50,0.7);
}
.rail__stop:focus-visible { border-radius: 8px; }
/* Sin escena 3D el viaje se apila: el raíl no tiene nada que indicar. */
.no-js .rail, .no-webgl .rail, .reduced .rail { display: none; }

/* Móvil y tableta: arriba, en horizontal, justo debajo del HUD. */
@media (max-width: 920px) {
  .rail {
    right: auto; left: 50%;
    top: clamp(4.4rem, 11vh, 6.5rem);
    transform: translateX(-50%);
    flex-direction: row;
    gap: 0.3rem;
  }
  .rail__stop { width: 36px; height: 44px; }
  .rail__bar { width: 26px; height: 3px; }
  .rail__stop.is-on .rail__bar { transform: scaleY(1.9); }
}
/* Móvil APAISADO: aquí la información vuelve a ser tarjeta a la izquierda, así
   que el raíl vuelve a su sitio de escritorio (vertical, a la derecha). Puesto
   arriba se cruzaba con el menú y con el planeta. */
@media (max-width: 920px) and (min-aspect-ratio: 1/1) and (max-height: 560px) {
  .rail {
    left: auto; right: clamp(0.4rem, 1.4vw, 1.2rem);
    top: 50%;
    transform: translateY(-50%);
    flex-direction: column;
    gap: 0.15rem;
  }
  .rail__stop { width: 40px; height: 28px; }
  .rail__bar { width: 3px; height: 20px; }
  .rail__stop.is-on .rail__bar { transform: scaleX(1.9); }
}
@media (max-width: 400px) {
  .rail { gap: 0.2rem; }
  .rail__stop { width: 32px; }
  .rail__bar { width: 22px; }
}

/* Panel de texto de cada planeta: tarjeta abajo-izquierda (desktop),
   abajo a lo ancho (móvil). El planeta enfocado queda en el centro, por
   encima de la tarjeta, así nunca se pisan. */
.panel {
  position: absolute;
  left: var(--pad);
  bottom: clamp(2rem, 7vh, 5rem);
  width: min(30rem, calc(100% - var(--pad) * 2));
  padding: clamp(1.4rem, 2.5vw, 2rem);
  border-radius: 20px;
  border: 1px solid rgba(255,255,255,0.09);
  /* ⚠️ SIN `backdrop-filter`, Y NO ES UN OLVIDO.
     Este panel flota sobre el <canvas> del viaje, que repinta en CADA fotograma.
     Un `backdrop-filter: blur(12px)` obliga al compositor a rehacer el desenfoque
     también en cada fotograma, y el coste arranca justo cuando el panel aparece
     — es decir, AL LLEGAR AL PLANETA. Eran los tirones que se notaban al llegar.
     No es un pico: es un impuesto sostenido mientras el panel esté en pantalla,
     que es casi todo el viaje.
     Ya estaba resuelto para pantallas táctiles (→ el bloque `pointer: coarse`);
     resulta que en escritorio dolía igual. Se compensa subiendo la opacidad del
     fondo, que es exactamente lo que hace la versión táctil: el texto se lee
     igual de bien y el desenfoque no lo echa de menos nadie sobre un cielo
     oscuro. */
  background: linear-gradient(180deg, rgba(22,16,10,0.90), rgba(13,9,6,0.86));
  box-shadow: 0 24px 70px -30px rgba(0,0,0,0.9);
  will-change: opacity, transform;
}
/* Estado inicial oculto SOLO con JS: sin JS, los paneles se ven (fallback). */
.js .panel { opacity: 0; }
.panel__index {
  display: inline-block;
  font-size: 0.76rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ember);
  margin-bottom: 0.8rem;
}
.panel__title {
  font-family: var(--serif);
  font-weight: 360;
  line-height: 1.06;
  letter-spacing: -0.03em;
  font-size: clamp(1.7rem, 3.4vw, 2.7rem);
  overflow-wrap: break-word;
}
.panel__title em { font-style: italic; color: var(--ember-hot); }
.panel__lead {
  margin-top: 0.9rem;
  color: var(--ink-dim);
  font-size: clamp(0.98rem, 0.94rem + 0.25vw, 1.12rem);
}
.panel__list {
  list-style: none;
  margin-top: 1.1rem;
  display: grid;
  gap: 0.6rem;
}
.panel__list li {
  position: relative;
  padding-left: 1.5rem;
  color: var(--ink-dim);
  font-size: 0.98rem;
}
.panel__list li strong { color: var(--ink); font-weight: 600; }
.panel__list li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.5em;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--ember);
  box-shadow: 0 0 12px 1px rgba(255,120,40,0.8);
}
.panel__cta {
  display: inline-block;
  margin-top: 1.3rem;
  font-weight: 600;
  color: var(--ember-hot);
  border-bottom: 1px solid rgba(255,140,50,0.4);
  padding-bottom: 3px;
  transition: color .25s var(--ease-out), border-color .25s var(--ease-out);
}
.panel__cta:hover { color: var(--ink); border-color: var(--ember-hot); }

/* ── Panel de la ÚLTIMA PARADA: el planeta de las maquetas ────────────────
   Es el mismo panel pero más ancho, con la lista de accesos a las demos. Cada
   fila es un enlace real (miniatura + nombre + flecha) que abre la maqueta en
   una pestaña nueva. */
.panel--demos { width: min(34rem, calc(100% - var(--pad) * 2)); }
.demos {
  list-style: none;
  margin-top: 1.1rem;
  display: grid;
  gap: 0.5rem;
}
.demo {
  display: grid;
  grid-template-columns: 4.4rem 1fr auto;
  align-items: center;
  gap: 0.85rem;
  padding: 0.45rem 0.6rem 0.45rem 0.45rem;
  border-radius: 12px;
  border: 1px solid rgba(255,255,255,0.07);
  background: rgba(255,255,255,0.03);
  transition: border-color .25s var(--ease-out), background .25s var(--ease-out), transform .25s var(--ease-out);
}
.demo:hover,
.demo:focus-visible {
  border-color: rgba(255,140,50,0.4);
  background: rgba(255,140,50,0.07);
  transform: translateX(3px);
}
.demo:focus-visible { outline: 2px solid var(--ember-hot); outline-offset: 2px; }
.demo__shot {
  width: 100%;
  /* `height: auto` es obligatorio: el atributo `height` del <img> (que está ahí
     para reservar espacio y evitar saltos de layout) le gana a `aspect-ratio` y
     dejaría la miniatura con su alto intrínseco (250px). */
  height: auto;
  aspect-ratio: 8 / 5;
  object-fit: cover;
  border-radius: 7px;
  display: block;
  border: 1px solid rgba(255,255,255,0.08);
}
.demo__body { display: flex; flex-direction: column; gap: 0.12rem; min-width: 0; }
.demo__body strong { font-weight: 600; font-size: 0.98rem; }
.demo__body em {
  font-style: normal;
  font-size: 0.78rem;
  color: var(--ink-faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.demo__go { color: var(--ember); font-size: 1.05rem; padding: 0 0.15rem; }

/* Desktop amplio: la tarjeta no ocupa toda la altura, centrada verticalmente
   a la izquierda para dejar el escenario respirar. */
@media (min-width: 920.02px) {
  .panel { top: 50%; bottom: auto; transform: translateY(-50%); }
  .js .panel { transform: translateY(calc(-50% + 26px)); }
}
/* Escritorio con poca altura: la ficha de maquetas suelta el párrafo de apoyo
   (los cinco accesos son lo que importa) y aprieta las filas. */
@media (min-width: 920.02px) and (max-height: 780px) {
  .panel--demos .panel__lead { display: none; }
  .demo { grid-template-columns: 3.4rem 1fr auto; gap: 0.65rem; padding: 0.3rem 0.5rem 0.3rem 0.3rem; }
  .demo__body strong { font-size: 0.9rem; }
  .demos { gap: 0.4rem; }
}

/* ══════════════════════════════════════════════════════════════════════════
   LA INFORMACIÓN DE CADA PLANETA · DOS FORMATOS, NO UNO ADAPTADO
   · Escritorio (≥921px): tarjeta flotante a la izquierda, siempre abierta.
     Hay sitio de sobra y leer sin tener que tocar nada es lo cómodo.
   · Móvil y tableta (≤920px): HOJA INFERIOR. Solo se ve la cabecera (número +
     titular) y el detalle se despliega a petición. La escena recupera dos
     tercios de la pantalla, el texto respira, el pulgar tiene un objetivo
     grande abajo y la nave conserva su franja — que main.js mide y le pasa al
     motor 3D, así que la garantía no depende de estos números.
   ══════════════════════════════════════════════════════════════════════════ */

/* Escritorio: ni botón ni plegado; el envoltorio es transparente al layout. */
.panel__toggle { display: none; }
.panel__more-in { display: contents; }

@media (max-width: 920px) {
  .panel {
    left: 0; right: 0; bottom: 0; top: auto;
    width: 100%;
    max-width: none;
    max-height: 62svh;   /* el resto de la pantalla es para la escena y la nave */
    padding: 1.15rem var(--pad) calc(1.15rem + env(safe-area-inset-bottom, 0px));
    border-radius: 20px 20px 0 0;
    border-left: 0; border-right: 0; border-bottom: 0;
    box-shadow: 0 -18px 60px -26px rgba(0,0,0,0.95);
    overflow: visible;
  }
  .panel__index { margin-bottom: 0.45rem; }
  .panel__title { font-size: clamp(1.45rem, 5.6vw, 2rem); line-height: 1.14; }

  /* El detalle crece con la técnica de grid 0fr → 1fr: una transición de altura
     de verdad, sin tener que saber de antemano cuánto mide el contenido. */
  .panel__more {
    display: grid;
    grid-template-rows: 0fr;
    opacity: 0;
    transition: grid-template-rows .45s var(--ease-out), opacity .28s var(--ease-out);
  }
  .panel__more-in { display: block; min-height: 0; overflow: hidden; }
  .panel.is-open .panel__more { grid-template-rows: 1fr; opacity: 1; }
  .panel.is-open .panel__more-in {
    overflow-y: auto;
    max-height: 40svh;
    overscroll-behavior: contain;
  }

  .panel__toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    width: 100%;
    min-height: 44px;
    margin-top: 0.9rem;
    padding: 0.5rem 0;
    color: var(--ember-hot);
    font-family: var(--sans);
    font-weight: 600;
    font-size: 0.92rem;
    border-top: 1px solid rgba(255,255,255,0.09);
  }
  .panel__toggle-icon {
    flex: 0 0 auto;
    width: 9px; height: 9px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(225deg);              /* apunta arriba: "despliégame" */
    transition: transform .35s var(--ease-out);
  }
  .panel.is-open .panel__toggle-icon { transform: rotate(45deg); }

  /* Aire. En móvil el texto necesita respirar MÁS que en escritorio, no menos:
     antes se apretaba todo para que cupiera y se leía como un prospecto. */
  .panel__lead { margin-top: 0.9rem; font-size: 1rem; line-height: 1.55; }
  .panel__list { margin-top: 1rem; gap: 0.75rem; }
  .panel__list li { font-size: 0.95rem; line-height: 1.5; padding-left: 1.4rem; }
  .panel__cta {
    margin-top: 1.2rem;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }
  .panel--demos { width: 100%; }
  .demos { gap: 0.55rem; margin-top: 1rem; }
  .demo {
    grid-template-columns: 3.6rem 1fr auto;
    gap: 0.8rem;
    min-height: 52px;
    padding: 0.45rem 0.6rem 0.45rem 0.45rem;
  }
}

/* Móviles PEQUEÑOS en vertical (≤700px de alto): la cabecera se aprieta y la
   hoja abierta se limita más. Si no, con el tope general (62svh) la escena se
   queda en una rendija y la nave hay que encogerla hasta que no se ve. */
@media (max-width: 920px) and (max-height: 700px) and (max-aspect-ratio: 1/1) {
  .panel { max-height: 56svh; padding-top: 0.85rem; }
  .panel__index { margin-bottom: 0.35rem; }
  .panel__title { font-size: clamp(1.25rem, 5.6vw, 1.55rem); }
  .panel__toggle { margin-top: 0.65rem; min-height: 42px; }
  .panel.is-open .panel__more-in { max-height: 34svh; }
}

/* Pantallas BAJAS y anchas (móvil apaisado): aquí sobra ancho y falta alto, así
   que la hoja puede ocupar más — pero solo porque enseguida se convierte en
   tarjeta lateral (regla siguiente). */
@media (max-width: 920px) and (max-height: 620px) and (min-aspect-ratio: 1/1) {
  .panel { max-height: 82svh; padding-top: 0.85rem; }
  .panel__title { font-size: clamp(1.25rem, 3.8vh, 1.6rem); }
  .panel.is-open .panel__more-in { max-height: 42svh; }
}

/* Móvil APAISADO (sobra ancho, falta alto): la hoja vuelve a ser tarjeta, a la
   izquierda, y las maquetas pasan a dos columnas. */
@media (max-width: 920px) and (min-aspect-ratio: 1/1) and (max-height: 560px) {
  .panel {
    left: var(--pad); right: auto; bottom: 0.9rem;
    width: min(26rem, 58%);
    border: 1px solid rgba(255,255,255,0.09);
    border-radius: 18px;
    padding: 0.9rem 1.1rem;
    max-height: calc(100svh - 1.8rem);
  }
  .panel--demos { width: min(30rem, 66%); }
  .demos { grid-template-columns: 1fr 1fr; gap: 0.4rem 0.5rem; }
  .demo { grid-template-columns: 2.8rem 1fr auto; gap: 0.5rem; min-height: 44px; }
  .demo__body em { display: none; }
  .panel__list li { font-size: 0.9rem; }
  .panel.is-open .panel__more-in { max-height: 46svh; }
}

/* ── Hero en móviles pequeños o cortos ─────────────────────────────────────
   Medido a 320×568: el bloque del mensaje acababa en 575px sobre un viewport de
   568 (desbordaba 7px) y el aviso de scroll caía ENCIMA de los botones. Aquí se
   comprime el ritmo tipográfico —sin quitar ni una palabra— para que el mensaje
   entero quepa en una pantalla y quede aire debajo para la escena. */
@media (max-width: 400px), (max-height: 660px) and (max-aspect-ratio: 1/1) {
  .hero { padding-top: clamp(4rem, 11vh, 5.4rem); }
  .hero__eyebrow {
    font-size: 0.66rem; letter-spacing: 0.16em;
    line-height: 1.35; margin-bottom: 0.55rem;
  }
  .hero__title { font-size: clamp(1.95rem, 11.5vw, 2.6rem); }
  .hero__sub { font-size: 0.93rem; line-height: 1.5; margin-top: 0.8rem; }
  .hero__cta { margin-top: 1.05rem; gap: 0.55rem; }
  .hero__cta .btn { padding: 0.7rem 1rem; font-size: 0.9rem; }
  /* El aviso pasa a UNA FILA (rótulo + pista) y baja de 74px a 22px de alto: en
     columna se metía por debajo de los botones aunque el mensaje ya cupiera. */
  .scrollcue {
    flex-direction: row;
    align-items: center;
    gap: 0.55rem;
    bottom: 0.85rem;
    /* Es un enlace real a #sistema: el objetivo de pulsado no puede bajar de
       24px (WCAG 2.5.8). En fila se quedaba en 22. */
    min-height: 26px;
  }
  .scrollcue__label { max-width: none; font-size: 0.62rem; letter-spacing: 0.16em; }
  .scrollcue__line { height: 22px; }
}

/* Móviles pequeños (≤400px): se aprieta la tipografía, nunca el contenido. */
@media (max-width: 400px) {
  .panel__title { font-size: clamp(1.35rem, 6.2vw, 1.7rem); }
  .panel__lead { font-size: 0.95rem; }
  .panel__list li { font-size: 0.92rem; padding-left: 1.25rem; }
  .panel__list li::before { width: 6px; height: 6px; }
  .demo { grid-template-columns: 3rem 1fr auto; gap: 0.6rem; }
  .demo__body strong { font-size: 0.9rem; }
  .demo__body em { font-size: 0.74rem; }
}

/* Fallback SIN JS / sin WebGL / reduced-motion: el viaje se convierte en
   secciones apiladas legibles y el contenido nunca se pierde. */
.no-js .journey,
.no-webgl .journey,
.reduced .journey { height: auto; }
.no-js .journey__stage,
.no-webgl .journey__stage,
.reduced .journey__stage { position: static; height: auto; overflow: visible; padding: 8vh 0; }
.no-js .panel,
.no-webgl .panel,
.reduced .panel {
  position: relative;
  left: auto; bottom: auto; top: auto;
  width: 100%;
  max-width: 52ch;
  max-height: none;
  overflow: visible;
  margin: 0 auto clamp(2rem, 6vw, 4rem);
  padding: clamp(1.4rem, 2.5vw, 2rem);
  border: 1px solid rgba(255,255,255,0.09);
  border-radius: 20px;
  box-shadow: 0 24px 70px -30px rgba(0,0,0,0.9);
  transform: none !important;
  opacity: 1 !important;
  pointer-events: auto !important;
}
/* Sin escena no hay nada que desplegar: el contenido va entero y a la vista. */
.no-js .panel__toggle,
.no-webgl .panel__toggle,
.reduced .panel__toggle { display: none; }
.no-js .panel__more,
.no-webgl .panel__more,
.reduced .panel__more { display: block; opacity: 1; }
.no-js .panel__more-in,
.no-webgl .panel__more-in,
.reduced .panel__more-in { display: block; overflow: visible; max-height: none; }

/* ══════════════════════════════════════════════════════════════════════════
   PRECIOS
   ══════════════════════════════════════════════════════════════════════════ */
.pricing {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 14vh var(--pad) 10vh;
}
.pricing__head { text-align: center; max-width: 60ch; margin: 0 auto clamp(2.5rem, 6vw, 4rem); }
.pricing__kicker, .contact__kicker {
  font-size: 0.8rem; letter-spacing: 0.28em; text-transform: uppercase; color: var(--ember);
}
.pricing__title, .contact__title {
  font-family: var(--serif); font-weight: 340; line-height: 1.05; letter-spacing: -0.03em;
  font-size: clamp(2.1rem, 6vw, 4.6rem); margin-top: 0.6rem;
}
.pricing__title em, .contact__title em { font-style: italic; color: var(--ember-hot); }
.pricing__sub { margin-top: 1.1rem; color: var(--ink-dim); font-size: 1.08rem; }

.tiers {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1rem, 2vw, 1.6rem);
  align-items: stretch;
}
.tier {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: clamp(1.6rem, 2.5vw, 2.2rem);
  border-radius: 20px;
  border: 1px solid rgba(255,255,255,0.09);
  background: linear-gradient(180deg, rgba(28,20,12,0.78), rgba(16,12,9,0.72));
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  transition: transform .3s var(--ease-out), border-color .3s var(--ease-out), box-shadow .3s var(--ease-out);
}
.tier:hover { transform: translateY(-4px); border-color: rgba(255,140,50,0.35); }
.tier--featured {
  border-color: rgba(255,140,50,0.55);
  box-shadow: 0 20px 60px -22px rgba(255,110,30,0.55);
}
/* ⚠️ `scale:` (propiedad independiente), NO `transform: scale()`. La tarjeta
   lleva `data-reveal`, y `.js [data-reveal]` (0,2,0) le gana en especificidad a
   `.tier--featured` (0,1,0) escribiendo `transform: translateY(28px)`; después
   GSAP deja además un `transform` EN LÍNEA, que gana a todo. Resultado: el
   realce de «La Llama» no ocurría en ningún navegador con JS, y el `translateY`
   del hover de las tres tarjetas tampoco. Las propiedades independientes
   (`scale`/`translate`/`rotate`) se componen con `transform` en vez de pelearse
   con él, así que conviven con GSAP. */
@media (min-width: 920.02px) {
  .tier--featured { scale: 1.045; }
}
.tier__badge {
  position: absolute;
  top: -0.8rem; left: 50%; transform: translateX(-50%);
  font-size: 0.72rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: #1a0d03; font-weight: 700;
  background: linear-gradient(95deg, var(--ember-hot), var(--ember));
  padding: 0.35rem 0.9rem; border-radius: 999px;
  white-space: nowrap;
}
.tier__name { font-family: var(--serif); font-size: 1.8rem; font-weight: 500; }
.tier__for { color: var(--ink-faint); font-size: 0.92rem; margin-top: 0.15rem; }
.tier__price {
  font-family: var(--serif); font-weight: 500;
  font-size: clamp(2.4rem, 4vw, 3.2rem); margin: 1rem 0 0.2rem;
  display: flex; align-items: baseline; gap: 0.3rem; flex-wrap: wrap;
}
.tier__from { font-family: var(--sans); font-size: 0.85rem; color: var(--ink-faint); letter-spacing: 0.1em; text-transform: uppercase; }
.tier__cur { font-size: 1.6rem; color: var(--ember-hot); }
/* «+ IVA» pegado al precio y no en la letra pequeña del final: la ley obliga a
   indicar si el importe lleva impuestos, pero el motivo de fondo es comercial —
   quien lee «desde 800 €» y recibe una factura de 968 € se siente engañado antes
   de empezar, y esa conversación se tiene siempre en el peor momento. */
.tier__vat {
  font-family: var(--sans); font-size: 0.78rem; color: var(--ink-faint);
  letter-spacing: 0.08em; text-transform: uppercase; align-self: center;
}
.tier__feats {
  list-style: none; margin: 1.4rem 0 1.8rem; display: grid; gap: 0.7rem; flex: 1;
}

/* ── Plegado de los planes en móvil ────────────────────────────────────────
   En escritorio los tres planes se comparan de un vistazo, en columnas: aquí no
   hay nada que plegar y el botón sobra. En móvil van apilados y medían 3,32
   pantallas juntos — un precio no se compara si hay que recordarlo tres
   pantallas más arriba.
   Es el CSS quien decide si esto existe, no el JavaScript: el botón se crea
   siempre y aquí se esconde. Así girar el móvil no obliga a reconstruir nada. */
.tier__toggle { display: none; }

@media (max-width: 920px) {
  .js .tier--plegable .tier__toggle {
    display: flex; align-items: center; justify-content: space-between;
    gap: 0.6rem; width: 100%;
    margin: 1.1rem 0 0;
    padding: 0.7rem 0.9rem;
    border: 1px solid rgba(255,255,255,0.14);
    border-radius: 12px;
    background: rgba(255,255,255,0.04);
    color: var(--ink-dim);
    font-family: var(--sans); font-size: 0.86rem; letter-spacing: 0.02em;
    transition: color .2s var(--ease-out), border-color .2s var(--ease-out);
  }
  .js .tier--plegable .tier__toggle:hover { color: var(--ink); border-color: rgba(255,140,50,0.4); }
  /* `display: none` y no `max-height: 0`: plegado de verdad es también fuera del
     árbol de accesibilidad. Con `max-height` el texto oculto sigue siendo
     tabulable y lo lee un lector de pantalla, que es peor que no plegarlo. */
  .js .tier--plegable .tier__feats { display: none; margin-top: 1.1rem; }
  .js .tier--plegable.is-open .tier__feats { display: grid; }
  /* Flecha que gira: es la única señal de que esto se abre y se cierra. */
  .tier__toggle-icon {
    width: 10px; height: 10px; flex: none;
    border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
    transform: rotate(45deg); transform-origin: 60% 60%;
    transition: transform .25s var(--ease-out);
  }
  .js .tier--plegable.is-open .tier__toggle-icon { transform: rotate(-135deg); }
}
.tier__feats li {
  position: relative; padding-left: 1.5rem; color: var(--ink-dim); font-size: 0.98rem;
}
.tier__feats li::before {
  content: "✦"; position: absolute; left: 0; top: 0; color: var(--ember); font-size: 0.85rem;
}
.tier__cta { width: 100%; }

.custom {
  margin-top: clamp(1.2rem, 2.5vw, 1.8rem);
  display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap;
  gap: 1.4rem;
  padding: clamp(1.5rem, 3vw, 2.2rem);
  border-radius: 20px;
  border: 1px dashed rgba(255,140,50,0.35);
  background: rgba(255,106,18,0.04);
}
.custom__text h3 { font-family: var(--serif); font-size: 1.5rem; font-weight: 500; }
.custom__text p { color: var(--ink-dim); margin-top: 0.4rem; max-width: 52ch; }
/* `max-width` en ch como el resto del fichero (.pricing__head 60ch,
   .custom__text p 52ch). Sin él era la ÚNICA caja de texto sin tope: medido,
   190 caracteres por línea a 1920px y 212 a 2560px, contra las ~75 que se leen
   de un vistazo. Y encima es la letra pequeña comercial, la que más importa que
   se lea entera. */
.pricing__note {
  text-align: center; color: var(--ink-faint); font-size: 0.9rem;
  margin: 2rem auto 0; max-width: 70ch;
}

/* ══════════════════════════════════════════════════════════════════════════
   CONTACTO — "Envía tu señal"
   ══════════════════════════════════════════════════════════════════════════ */
.contact {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 12vh var(--pad) 8vh;
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}
.contact__title { font-size: clamp(2.4rem, 6vw, 4.6rem); }
.contact__sub { margin-top: 1.2rem; color: var(--ink-dim); font-size: 1.1rem; max-width: 40ch; }
.contact__trust {
  list-style: none; margin-top: 1.8rem; display: grid; gap: 0.7rem;
}
.contact__trust li {
  position: relative; padding-left: 1.7rem; color: var(--ink-dim);
}
.contact__trust li::before {
  content: "✓"; position: absolute; left: 0; top: 0;
  color: var(--ember-hot); font-weight: 700;
}

.form {
  padding: clamp(1.6rem, 3vw, 2.4rem);
  border-radius: 22px;
  border: 1px solid rgba(255,255,255,0.09);
  background: linear-gradient(180deg, rgba(24,17,10,0.82), rgba(16,12,9,0.78));
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
}
.form__req { font-size: 0.82rem; color: var(--ink-faint); margin-bottom: 1rem; }
.form__req span { color: var(--ember-hot); }
.form__row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.field { display: flex; flex-direction: column; gap: 0.45rem; margin-bottom: 1.1rem; }
.field label { font-size: 0.86rem; color: var(--ink-dim); letter-spacing: 0.02em; }
.field .opt { color: var(--ink-faint); }
.field input,
.field textarea,
.field select {
  width: 100%;
  font-family: var(--sans);
  font-size: 1rem;
  color: var(--ink);
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.34);   /* ≈3:1 → borde percibido (WCAG 1.4.11) */
  border-radius: 11px;
  padding: 0.8rem 0.95rem;
  transition: border-color .2s var(--ease-out), box-shadow .2s var(--ease-out), background-color .2s var(--ease-out);
}
.field textarea { resize: vertical; min-height: 120px; }
.field select { cursor: pointer; appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%23b7a692' d='M6 8 0 0h12z'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 1rem center; padding-right: 2.4rem;
}
.field input::placeholder,
.field textarea::placeholder { color: var(--ink-faint); }
.field input:focus,
.field textarea:focus,
.field select:focus {
  outline: none;
  border-color: var(--ember);
  background: rgba(255,255,255,0.06);
  box-shadow: 0 0 0 3px rgba(255,106,18,0.16);
}
.field option { background: #1b130c; color: var(--ink); }

.consent {
  display: flex; gap: 0.7rem; align-items: flex-start;
  color: var(--ink-dim); font-size: 0.9rem; margin: 0.4rem 0 1.4rem;
  cursor: pointer;
}
/* 24x24 mínimo: es un control aislado, no un enlace dentro de una frase. */
.consent input { margin-top: 0.1rem; accent-color: var(--ember); width: 24px; height: 24px; flex: 0 0 auto; }
/* En prosa el enlace no puede distinguirse solo por color (WCAG 1.4.1): subrayado. */
.consent a { text-decoration: underline; text-underline-offset: 2px; }

.form__submit { width: 100%; padding: 1rem 1.5rem; font-size: 1.05rem; }
.form.is-sending .form__submit { opacity: 0.7; pointer-events: none; }
.form__status { margin-top: 1rem; font-size: 0.95rem; min-height: 1.2em; }
.form__status.is-ok { color: var(--ember-hot); }
.form__status.is-err { color: #ff7a5c; }

/* Honeypot: fuera de la vista pero accesible para bots */
.form__gotcha {
  position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden;
}

/* ══════════════════════════════════════════════════════════════════════════
   FOOTER
   ══════════════════════════════════════════════════════════════════════════ */
.foot {
  position: relative; z-index: 2;
  max-width: var(--maxw); margin: 0 auto;
  padding: 6vh var(--pad) 4vh;
  border-top: 1px solid rgba(255,255,255,0.08);
  text-align: center;
}
.foot__inner { display: flex; flex-direction: column; align-items: center; gap: 0.8rem; }
.foot__tag { font-family: var(--serif); font-style: italic; color: var(--ink-dim); font-size: 1.15rem; }
.foot__meta { color: var(--ink-faint); font-size: 0.9rem; }
/* El correo es el único canal de contacto directo de la web y estaba pintado
   igual que el texto que lo rodea: solo se revelaba al pasar el ratón, o sea
   nunca en móvil (1.4.1 — el color no puede ser el único indicador). Y el
   relleno vertical le da 24px de alto de zona pulsable sin alterar la línea:
   en un elemento en línea el padding vertical agranda el área activa pero no
   la caja de línea, así que no mueve nada. */
.foot__meta a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  padding: 6px 2px;
}
.foot__meta a:hover, .foot__meta a:focus-visible { color: var(--ember-hot); }
.foot__copy { color: var(--ink-faint); font-size: 0.82rem; margin-top: 1.6rem; }

/* ══════════════════════════════════════════════════════════════════════════
   RESPONSIVE — el viaje debe verse espectacular en cualquier pantalla
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 920px) {
  .contact { grid-template-columns: 1fr; }
  .tiers { grid-template-columns: 1fr; max-width: 460px; margin: 0 auto; }
  .tier--featured { order: -1; }
}
@media (max-width: 560px) {
  .form__row { grid-template-columns: 1fr; gap: 0; }
  .custom { flex-direction: column; align-items: flex-start; text-align: left; }
  .custom .btn { width: 100%; }
  .hero__cta { gap: 0.7rem; }
  .hero__cta .btn { flex: 1 1 auto; }
}

/* Móviles pequeños (~320–400px): apretamos paddings y tipos para que NADA se
   salga ni se amontone. */
@media (max-width: 400px) {
  :root { --pad: 1.1rem; }
  .brand { font-size: 1.02rem; }
  .brand img { width: 21px; height: 21px; }
  .hudnav__cta { padding: 0.45rem 0.8rem; font-size: 0.82rem; }
  .hero__title { font-size: clamp(2.4rem, 13.5vw, 3.3rem); }
  .hero__cta .btn { padding: 0.8rem 1rem; font-size: 0.92rem; }
  .tier { padding: 1.35rem; }
  .panel__list li { font-size: 0.92rem; }
}

/* Monitores muy grandes / ultrawide: subimos un punto el ancho útil y el hero,
   sin que el texto pierda densidad. */
@media (min-width: 1800px) {
  :root { --maxw: 1480px; }
  .hero__title { font-size: clamp(7rem, 8.5vw, 11rem); }
}

/* ══════════════════════════════════════════════════════════════════════════
   FORM · DESPLEGABLE A MEDIDA (custom select)
   El <select> nativo sigue en el DOM (se envía al PHP y funciona sin JS). Con JS
   se oculta y lo sustituye una lista con estética de marca cuya lista abierta SÍ
   podemos estilar. Accesible (role listbox/option, teclado, foco gestionado).
   ══════════════════════════════════════════════════════════════════════════ */
.selectbox { position: relative; }
/* Con JS activo el <select> nativo se oculta (sigue enviándose igual).
   Sin JS, se muestra como un campo normal (hereda el estilo de .field select). */
.selectbox.is-enhanced .selectbox__native { display: none; }

.selectbox__trigger {
  width: 100%;
  display: flex; align-items: center; gap: 0.75rem;
  font-family: var(--sans); font-size: 1rem; color: var(--ink); text-align: left;
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.13);
  border-radius: 11px;
  padding: 0.8rem 0.95rem;
  cursor: pointer;
  transition: border-color .2s var(--ease-out), box-shadow .2s var(--ease-out), background-color .2s var(--ease-out);
}
.selectbox__trigger:hover { border-color: rgba(255,140,50,0.4); }
.selectbox.is-open .selectbox__trigger,
.selectbox__trigger:focus-visible {
  outline: none; border-color: var(--ember);
  background: rgba(255,255,255,0.06);
  box-shadow: 0 0 0 3px rgba(255,106,18,0.16);
}
.selectbox__value { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.selectbox__value.is-placeholder { color: var(--ink-faint); }
.selectbox__caret {
  flex: 0 0 auto; width: 9px; height: 9px;
  border-right: 2px solid var(--ink-dim); border-bottom: 2px solid var(--ink-dim);
  transform: rotate(45deg) translate(-1px, -1px);
  transition: transform .25s var(--ease-out), border-color .25s var(--ease-out);
}
.selectbox.is-open .selectbox__caret { transform: rotate(225deg); border-color: var(--ember-hot); }

.selectbox__list {
  position: absolute; z-index: 30; left: 0; right: 0; top: calc(100% + 0.4rem);
  list-style: none; margin: 0; padding: 0.4rem;
  max-height: 15rem; overflow-y: auto;
  background: #16100a;                         /* opaco: legible sobre el fondo 3D */
  border: 1px solid rgba(255,140,50,0.25);
  border-radius: 14px;
  box-shadow: 0 24px 60px -24px rgba(0,0,0,0.92);
  animation: selectbox-in .18s var(--ease-out);
}
@keyframes selectbox-in { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
.selectbox__option {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.65rem 0.8rem; border-radius: 9px;
  color: var(--ink-dim); font-size: 0.98rem; cursor: pointer;
  transition: background-color .15s var(--ease-out), color .15s var(--ease-out);
}
.selectbox__option.is-placeholder { color: var(--ink-faint); }
.selectbox__option:hover,
.selectbox__option.is-active { background: rgba(255,140,50,0.14); color: var(--ink); }
.selectbox__option.is-selected { color: var(--ember-hot); font-weight: 600; }
.selectbox__option.is-selected::after { content: "✓"; margin-left: auto; color: var(--ember-hot); }

/* ── Enlaces legales del footer ─────────────────────────────────────────── */
.foot__legal {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 0.3rem 1.2rem; margin-top: 0.2rem; font-size: 0.85rem;
}
.foot__legal a { color: var(--ink-faint); transition: color .25s var(--ease-out); padding: 0.35rem 0; }
.foot__legal a:hover { color: var(--ember-hot); }

/* ══════════════════════════════════════════════════════════════════════════
   PÁGINAS LEGALES (aviso-legal, privacidad, cookies)
   Ligeras: sin WebGL ni librerías. Sólo el brillo cálido de la marca de fondo.
   ══════════════════════════════════════════════════════════════════════════ */
.legal-page {
  background:
    radial-gradient(85% 55% at 50% -12%, rgba(255,106,18,0.12), rgba(255,106,18,0) 60%),
    var(--bg);
  min-height: 100svh;
}
.legal {
  position: relative; z-index: 2;
  max-width: 760px; margin: 0 auto;
  padding: clamp(6rem, 16vh, 9rem) var(--pad) 12vh;
}
.legal__back {
  display: inline-flex; align-items: center; gap: 0.4rem;
  color: var(--ink-faint); font-size: 0.85rem; margin-bottom: 1.8rem;
  transition: color .25s var(--ease-out);
}
.legal__back:hover { color: var(--ember-hot); }
.legal h1 {
  font-family: var(--serif); font-weight: 360; line-height: 1.05;
  letter-spacing: -0.025em; font-size: clamp(2rem, 6vw, 3.4rem);
}
.legal__updated { color: var(--ink-faint); font-size: 0.85rem; margin-top: 0.7rem; }
.legal h2 {
  font-family: var(--serif); font-weight: 500; font-size: 1.5rem;
  margin: 2.6rem 0 0.2rem; color: var(--ink);
}
.legal p, .legal li { color: var(--ink-dim); line-height: 1.75; }
.legal p { margin-top: 0.9rem; }
.legal ul { padding-left: 1.2rem; margin-top: 0.7rem; }
.legal li { margin-top: 0.45rem; }
.legal a { color: var(--ember-hot); text-decoration: underline; text-underline-offset: 2px; }
.legal strong { color: var(--ink); }
.legal .todo {
  color: var(--ember-hot); font-weight: 600;
  background: rgba(255,106,18,0.08); border-radius: 4px; padding: 0 0.25rem;
}
.legal__foot {
  margin-top: 3.5rem; padding-top: 1.6rem;
  border-top: 1px solid rgba(255,255,255,0.08);
  color: var(--ink-faint); font-size: 0.85rem;
}

/* ══════════════════════════════════════════════════════════════════════════
   RESPONSIVE · ENDURECIDO — casos límite reales
   Bloque final que cubre lo que las media queries de arriba no atrapan:
   móvil apaisado / ventanas muy bajas, teléfonos diminutos (≤360px) y
   monitores 4K/ultrawide. Va al final para poder ajustar sin tocar la base.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Móvil pequeño de verdad (≤360px): que NADA desborde el HUD ni el hero ── */
@media (max-width: 360px) {
  :root { --pad: 0.95rem; }
  .brand { font-size: 0.95rem; gap: 0.45rem; }
  .brand img { width: 19px; height: 19px; }
  .hudnav__cta { padding: 0.42rem 0.7rem; font-size: 0.76rem; }
  .hero__title { font-size: clamp(2.15rem, 13vw, 2.9rem); }
  .hero__eyebrow { font-size: 0.72rem; letter-spacing: 0.2em; }
  .hero__sub { font-size: 0.96rem; }
  .panel__index { font-size: 0.7rem; margin-bottom: 0.55rem; }
  .tier__name { font-size: 1.55rem; }
  .foot__legal { gap: 0.3rem 0.9rem; }
}

/* ── Viewports BAJOS y anchos (móvil apaisado, ventana a media altura) ──────
   El hero base usa tipos enormes (hasta 9.5rem) que en 375px de alto no caben.
   Aquí lo comprimimos y recolocamos para que el mensaje se vea entero sin
   scroll y sin que la pista de scroll pise el texto. */
@media (max-height: 600px) and (min-aspect-ratio: 1/1) {
  .hero { justify-content: center; padding-top: 4.5rem; padding-bottom: 2.5rem; }
  .hero__inner { transform: none; }
  .hero__eyebrow { margin-bottom: 0.7rem; }
  .hero__title { font-size: clamp(1.9rem, 6.5vw, 3.4rem); }
  .hero__sub { font-size: 0.96rem; margin-top: 0.9rem; max-width: 52ch; }
  .hero__cta { margin-top: 1.2rem; }
  .scrollcue { display: none; }   /* no hay altura para la pista */
}

/* (La red de seguridad de altura del panel en móvil ya no hace falta: la hoja
   inferior nace acotada por `max-height` y su detalle tiene scroll propio.
   Ver «LA INFORMACIÓN DE CADA PLANETA».) */

/* ── Monitores 4K / ultrawide (≥2400px): más lienzo útil y hero mayúsculo,
   manteniendo la densidad de lectura con medidas en ch. */
@media (min-width: 2400px) {
  :root { --maxw: 1720px; --pad: clamp(3.5rem, 5vw, 6rem); }
  body { font-size: 1.22rem; }
  .hero__title { font-size: clamp(9rem, 8vw, 13rem); }
  .hero__sub { max-width: 46ch; }
  .pricing__title, .contact__title { font-size: clamp(3.6rem, 5vw, 5.4rem); }
}

/* ══════════════════════════════════════════════════════════════════════════
   PREFERENCIAS DEL USUARIO Y AJUSTES POR DISPOSITIVO
   ⚠️ ESTE BLOQUE VA EL ÚLTIMO, Y NO ES CAPRICHO. Las media queries no suman
   especificidad: si estas reglas se declaran antes que los componentes que
   quieren anular, PIERDEN por orden de origen y quedan muertas sin avisar.
   Ya pasó: estaban arriba y sus tres `backdrop-filter: none` no hacían nada.
   Cualquier regla nueva que anule un componente va aquí abajo.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Respetar a quien pide menos movimiento ─────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .js [data-reveal] { opacity: 1 !important; transform: none !important; }
  .scrollcue__line::after { animation: none; }
  .selectbox__list { animation: none; }
  /* El grano y la viñeta son puro adorno: fuera cuando piden menos movimiento
     (además de aligerar la composición). */
  .grain { display: none; }
  * { scroll-behavior: auto !important; }
  /* El cursor propio es un anillo de 68px persiguiendo al puntero con medio
     segundo de retraso: es exactamente el tipo de movimiento que esta
     preferencia pide quitar. Se devuelve el puntero del sistema. */
  .cursor { display: none; }
  /* ⚠️ Con `.js` delante, y no `body` a secas. `.js body` (0,1,1) le gana por
     ESPECIFICIDAD a `body` (0,0,1) por mucho que esta regla vaya después: sin
     el `.js` se ocultaba el cursor propio y NO se devolvía el del sistema, o
     sea que con «menos movimiento» activado te quedabas sin puntero. */
  .js body, .js body:has(> .cursor) { cursor: auto; }
  .js a, .js button, .js [data-cursor],
  .js body:has(> .cursor) a, .js body:has(> .cursor) button { cursor: pointer; }
}

/* ── Rendimiento en táctil: aligerar la composición (pointer grueso) ──────
   El canvas 3D repinta cada frame; cada blend a pantalla completa y cada
   backdrop-filter se recomponen encima. En gama baja eso es jank de scroll.
   Sobre una escena oscura el resultado visual es casi idéntico sin ellos. */
@media (pointer: coarse) {
  /* Fuera las dos capas de blend a pantalla completa sobre el canvas vivo */
  .grain { display: none; }
  .vignette { mix-blend-mode: normal; background: radial-gradient(120% 88% at 50% 42%, transparent 52%, rgba(6,4,2,0.55) 100%); }

  /* Sin backdrop-filter: subimos la opacidad del fondo de las tarjetas para
     mantener la legibilidad. Visualmente casi indistinguible, muchísimo más barato. */
  .panel {
    -webkit-backdrop-filter: none; backdrop-filter: none;
    background: linear-gradient(180deg, rgba(22,15,10,0.93), rgba(13,9,6,0.92));
  }
  .tier {
    -webkit-backdrop-filter: none; backdrop-filter: none;
    background: linear-gradient(180deg, rgba(26,18,11,0.96), rgba(15,11,8,0.95));
  }
  .form {
    -webkit-backdrop-filter: none; backdrop-filter: none;
    background: linear-gradient(180deg, rgba(22,15,9,0.96), rgba(15,11,8,0.96));
  }
}

/* ── Modo de alto contraste de Windows ────────────────────────────────────
   Ahí el sistema fuerza su propia paleta y descarta `box-shadow` y los colores
   de fondo. Los dos únicos `outline: none` del fichero (campos del formulario y
   disparador del desplegable) dependen de un box-shadow para marcar el foco, así
   que en alto contraste el foco DESAPARECÍA del todo. Se devuelve un contorno
   real con los colores del sistema. */
@media (forced-colors: active) {
  .field input, .field textarea, .selectbox__trigger, .rail__stop,
  a:focus-visible, button:focus-visible, input:focus-visible,
  textarea:focus-visible, select:focus-visible {
    outline: 2px solid Highlight;
    outline-offset: 2px;
  }
  .rail__stop.is-on .rail__bar { background: Highlight; forced-color-adjust: none; }
  .btn { border: 1px solid ButtonText; }
}
