/*
 * Estilos de la landing.
 *
 * La paleta y las tipografías son las de la aplicación de verdad
 * (`src/app/globals.css` y `src/brand/tokens.css`), copiadas aquí a mano y a
 * propósito: esta página se publica en un dominio y no puede depender del build
 * del producto. Si la marca cambia, se cambia en los dos sitios — son dos
 * copias, y aquí sí es lo correcto, porque la alternativa es acoplar una página
 * estática a una aplicación de escritorio.
 *
 * Oscuro por defecto, como el estudio. Claro si el visitante lo pide.
 */

:root {
  --fondo: #161619;
  --fondo-alto: #1d1d21;
  --panel: #212126;
  --borde: #32323a;
  --texto: #e9e9ee;
  --texto-tenue: #a0a0ac;
  --acento: #5457ee;
  --acento-hover: #4649e0;
  --acento-fuerte: #8f92ff;
  /* La caja donde vive un trozo de interfaz: un escalón por encima del panel,
     para que se lea como «esto es una ilustración» y no como parte de la web. */
  --ilustra: #26262c;
  /* La negativa de la ficha técnica. Rosa y no rojo de alarma: informa, no
     asusta — es un requisito que no se cumple, no un error. */
  --no: #ff8099;

  --titulo: "Poppins", system-ui, sans-serif;
  --cuerpo: "Montserrat", system-ui, sans-serif;

  --ancho: 1120px;
  --radio: 14px;
}

@media (prefers-color-scheme: light) {
  :root {
    --fondo: #f3f3f5;
    --fondo-alto: #ffffff;
    --panel: #ffffff;
    --borde: #dedee4;
    --texto: #1e1e26;
    --texto-tenue: #5d5d69;
    --acento: #4649e0;
    --acento-hover: #393cd1;
    --acento-fuerte: #4245d6;
    --ilustra: #eceaf0;
    --no: #b0304a;
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--fondo);
  color: var(--texto);
  font-family: var(--cuerpo);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { font-family: var(--titulo); line-height: 1.15; margin: 0 0 .5em; }
h1 { font-size: clamp(2.2rem, 5vw, 3.6rem); letter-spacing: -.02em; }
h2 { font-size: clamp(1.6rem, 3vw, 2.3rem); }
h3 { font-size: 1.15rem; }
p  { margin: 0 0 1em; }
a  { color: inherit; }

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

/* ── Barra ── */
.barra {
  display: flex; align-items: center; justify-content: space-between;
  gap: 24px; padding: 20px 28px;
  max-width: var(--ancho); margin: 0 auto;
}
.barra__nav { display: flex; align-items: center; gap: 22px; font-size: .95rem; }
.barra__nav a { text-decoration: none; color: var(--texto-tenue); }
.barra__nav a:hover { color: var(--texto); }

/* ── Secciones ── */

/*
 * EL RECORTE QUE MATA LA BARRA HORIZONTAL.
 *
 * `.campo` mide `100vw` para sangrar de lado a lado, y `100vw` INCLUYE la barra
 * de desplazamiento vertical mientras que el ancho útil de la página no. Con una
 * barra clásica de 15 px el campo mide 15 más que la ventana y, al ir centrado,
 * asoma 7 px por cada lado: eso son ocho píxeles de barra horizontal en toda la
 * página —medido a 1024, 1200, 1280, 1366, 1440, 1512, 1600 y 1920—.
 *
 * No se veía en las pruebas porque el navegador sin ventana oculta las barras y
 * ahí `100vw` coincide con el ancho útil. Hubo que ejecutarlas quitando ese
 * argumento para que apareciera.
 *
 * Se recorta aquí, en `main`, y no en `body`:
 *   · `clip` y no `hidden` porque `hidden` convertiría esto en un contenedor de
 *     desplazamiento, y entonces los enlaces internos desplazarían DENTRO de
 *     `main` en vez de la página; `clip` recorta sin crear ese contenedor;
 *   · en `main` y no en `body` porque la barra pegajosa y la barra de acción
 *     flotante viven FUERA de `main`, así que ningún recorte puede alcanzarlas.
 * Los 7 px que se pierden por lado nunca se vieron: quedaban fuera de la ventana.
 */
main {
  overflow-x: clip;
}

main > section {
  max-width: var(--ancho);
  margin: 0 auto;
  padding: 72px 28px;
}

.sobretitulo {
  font-family: var(--titulo); font-size: .8rem; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--acento-fuerte);
  margin-bottom: 14px;
}
.entradilla { font-size: 1.2rem; color: var(--texto-tenue); max-width: 60ch; }
.letra-chica { font-size: .85rem; color: var(--texto-tenue); }

/* ── Portada ── */
.portada { text-align: center; padding-top: 56px; }
.portada .entradilla { margin-inline: auto; }
.portada__acciones { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin: 28px 0 12px; }
/* ── El campo de piezas flotantes ───────────────────────────────────────────
   Es el FONDO de la portada entera, no una banda debajo. Así las piezas pueden
   subir por los carriles de los lados —el centro se deja libre para el titular—
   y el conjunto deja de estar cortado a sangre justo debajo del pliegue.

   Se sale del carril del contenido para ocupar el ancho de la ventana. Sin
   `overflow: hidden` las piezas de los bordes crearían barra de desplazamiento
   horizontal, que es el fallo clásico de un fondo a sangre. */
.portada {
  position: relative;
  /* Sitio DENTRO de la portada para la banda de abajo. Antes el campo se salía
     120 px por debajo y se comía el título de la sección siguiente: la solución
     no es que el fondo invada al vecino, es que la portada mida lo que ocupa. */
  padding-bottom: 360px;
}

.campo {
  position: absolute;
  left: 50%;
  top: 0;
  translate: -50% 0;
  width: 100vw;
  height: 100%;
  overflow: hidden;
  /* Detrás del texto. No es solo estética: el titular tiene que poder leerse
     aunque una pieza se acerque más de la cuenta en una ventana rara. */
  z-index: 0;
  /* Un velo cortísimo abajo, solo para que el borde no sea un tajo. Nada de
     apagar las piezas: eso se pidió expresamente que no. */
  mask-image: linear-gradient(to bottom, #000 0%, #000 94%, transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 94%, transparent 100%);
}

/* El texto, por delante del campo y sin fondo: las piezas no llegan al centro
   por colocación, no por taparlas. */
.portada > :not(.campo) {
  position: relative;
  z-index: 1;
}

/*
 * La profundidad, gobernada por un solo número.
 *
 * `--z` va de 0 (delante) a 1 (al fondo) y de ahí salen tamaño, desenfoque,
 * sombra y velocidad de parallax —esta última la aplica el script—. Con cuatro
 * valores sueltos por pieza, cambiar la sensación de profundidad obligaría a
 * tocar cuarenta y ocho números y el conjunto dejaría de ser coherente al
 * primer retoque.
 *
 * La opacidad NO está en esa lista: ninguna pieza vive a medio pintar. Entran
 * apareciendo y se quedan opacas. Una imagen semitransparente permanente no se
 * lee como lejana, se lee como que algo va mal.
 */
.pieza {
  position: absolute;
  left: calc(var(--x) * 1%);
  top: calc(var(--y) * 1%);
  width: var(--w);
  /* `translate` y no `transform`: así el anclaje no pelea con el `y` que anima
     GSAP, que sí va en `transform`. Son propiedades distintas y se componen. */
  translate: -50% -50%;
  /* El orden de pintado sale de la PROFUNDIDAD y no del orden del HTML, que
     está puesto por otra cosa: qué seis piezas se ven en móvil. */
  z-index: calc((1 - var(--z)) * 100);
  will-change: transform;
}

/*
 * DOS ANCLAJES, y no es un capricho.
 *
 * `.pieza--lado` no tiene regla propia a propósito: usa el anclaje por el
 * centro, que es el de `.pieza`. Está en el HTML como marca de lectura —al ver
 * la lista se sabe cuál va al carril y cuál a la banda— y no como gancho de
 * estilo. Una regla vacía para "completar" sería CSS muerto.
 *
 * Las de los lados se anclan por su CENTRO: caben en el carril y da igual lo
 * altas que sean. Las de abajo se anclan por su BORDE SUPERIOR, porque
 * centradas suben la mitad de su altura y las más altas se metían debajo del
 * titular — medido: una pieza de 440 px centrada en el 90 % de un campo de 662
 * llega hasta el 63 %, y el texto baja hasta el 69 %.
 *
 * Con el anclaje por arriba, `--y` es una promesa: por debajo de ese número no
 * hay texto, así que la pieza no puede pisarlo por mucho que crezca.
 */
.pieza--abajo {
  /*
   * EL AIRE entre la última línea de texto y el borde de arriba de la banda.
   *
   * Una sola perilla y en píxeles: lo que hay que respirar es una distancia
   * concreta —la que separa la llamada a la acción de lo que hay debajo—, no una
   * proporción que cambia con lo alto que sea el titular en cada ventana. Con
   * los 39 px que salían de los porcentajes, la banda se leía pegada a los
   * botones.
   */
  --aire: 78px;
  translate: -50% 0;
  top: calc(var(--y) * 1% + var(--aire));
}

.pieza__cuerpo {
  scale: calc(1 - var(--z) * 0.28);
  /*
   * Desenfoque SOLO en el tercio del fondo y suave: hasta 3,6 px.
   * Difuminar todo lo que está detrás imita una apertura enorme y el conjunto
   * pasa de «hay profundidad» a «esto está desenfocado», que es otra cosa y
   * además cansa. El `max()` deja limpio todo lo que esté por delante de 0,55.
   */
  filter: blur(calc(max(0px, var(--z) - 0.55) * 8px));
  border-radius: 14px;
  overflow: hidden;
  /* La sombra crece con la cercanía: sin la opacidad en juego, es —con la
     escala— lo que dice qué está delante de qué. */
  box-shadow: 0 calc((1 - var(--z)) * 30px) calc((1 - var(--z)) * 60px)
    rgba(0, 0, 0, calc(0.12 + (1 - var(--z)) * 0.38));
}

.pieza__cuerpo img { display: block; width: 100%; height: auto; }

/* ── El campo en pantalla estrecha ───────────────────────────────────────────
 *
 * DEJA DE SER UN ESPACIO Y PASA A SER UN MONTÓN.
 *
 * En escritorio el campo es el fondo de la portada entera: doce piezas
 * colocadas por coordenadas, a distintas profundidades y con parallax. Nada de
 * eso funciona en 390 px y no es cuestión de afinar los números:
 *
 *   · las coordenadas van en porcentaje de un campo pensado para 1440, así que
 *     lo que en escritorio asoma por el carril lateral, aquí sale de la ventana
 *     y crea desplazamiento horizontal —medido: 612 px de ancho en una ventana
 *     de 390—;
 *   · el parallax necesita recorrido, y en una columna estrecha las piezas se
 *     iban dejando un vacío de 350 px antes de la sección siguiente;
 *   · la profundidad no se lee: tres cuartas partes de cada pieza quedan
 *     tapadas por la de al lado.
 *
 * Así que en móvil el campo sale del posicionamiento absoluto y se convierte en
 * una fila en el flujo, con tres piezas solapadas y giradas. Misma estética
 * —piezas reales, esquinas redondeadas, sombra de elevación, giros distintos—
 * sin nada que dependa de tener sitio ni de poder pasar el ratón.
 */
@media (max-width: 860px) {
  /* El hueco reservado abajo era para el campo absoluto. Sin él sobra, y lo que
     sobra se ve como una sección que no acaba nunca. */
  .portada { padding-bottom: 44px; }

  .campo {
    position: static;
    width: auto;
    height: auto;
    translate: none;
    overflow: visible;
    /* El velo de abajo tapaba el corte del campo a sangre. Ya no hay corte. */
    mask-image: none;
    -webkit-mask-image: none;

    display: flex;
    justify-content: center;
    align-items: flex-end;
    margin-top: 40px;
  }

  /* Tres, y no seis: en 350 px de ancho útil, la cuarta ya no se distingue de la
     tercera. Las tres primeras del HTML son las que llevan más peso. */
  .pieza:nth-child(n + 4) { display: none; }

  /*
   * UNA SOLA PERILLA: el ancho de pieza, y el solape sale de él.
   *
   * En píxeles fijos el abanico mide lo mismo en un iPhone SE que en un Plus, y
   * a 360 px se salía por los dos lados —medido: de -2 a 361 en una ventana de
   * 360—. Con `min()` la pieza cede ancho cuando la ventana es estrecha, y como
   * el solape es una fracción de la pieza, el conjunto encoge entero en vez de
   * descuadrarse. El giro añade un pico de unos 10 px por lado que también
   * encoge con ella.
   */
  .campo { --pieza: min(130px, 30vw); }

  .pieza {
    position: static;
    width: var(--pieza);
    flex: 0 0 auto;
    translate: none;
    /* Nada se mueve aquí: anunciar una capa de composición por pieza es pedirle
       memoria al teléfono para nada. */
    will-change: auto;
  }

  /*
   * El solape y los giros van a mano, pieza a pieza.
   *
   * Tres imágenes en fila y separadas se leen como una galería. Solapadas y
   * torcidas se leen como un montón encima de una mesa, que es lo mismo que
   * dice la portada en grande. Los 22 px negativos son los que dejan ver la
   * franja de marca de la de debajo sin comerse su titular.
   */
  .pieza:nth-child(1) { rotate: -7deg; margin-right: calc(var(--pieza) * -0.19); z-index: 1; }
  .pieza:nth-child(2) { rotate: 3deg; z-index: 3; }
  .pieza:nth-child(3) { rotate: 8deg; margin-left: calc(var(--pieza) * -0.19); z-index: 2; }

  /* En fila, la profundidad la dan el solape y el giro. El desenfoque y la
     escala del `--z` solo restarían definición a imágenes ya pequeñas. */
  .campo .pieza__cuerpo {
    scale: 1;
    filter: none;
    box-shadow: 0 2px 4px rgb(0 0 0 / .10), 0 12px 28px rgb(0 0 0 / .34);
  }
}

/* ── Botones ── */
.boton {
  display: inline-block; text-decoration: none; font-family: var(--titulo);
  font-weight: 600; font-size: .95rem; padding: 12px 22px;
  border-radius: 10px; border: 1px solid transparent; transition: background .15s, border-color .15s;
}
.boton--principal { background: var(--acento); color: #fff; }
.boton--principal:hover { background: var(--acento-hover); }
.boton--fantasma { border-color: var(--borde); color: var(--texto); }
.boton--fantasma:hover { border-color: var(--texto-tenue); }
.boton--grande { font-size: 1.05rem; padding: 15px 30px; }

/* ── Rejillas y tarjetas ── */
.rejilla, .requisitos__cajas {
  display: grid; gap: 18px; padding: 0; margin: 0; list-style: none;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}

.tarjeta {
  background: var(--fondo-alto);
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  padding: 22px;
}

.tarjeta p { color: var(--texto-tenue); margin: 0; }

/* ── Capacidades: tres tarjetas con su trozo de interfaz ────────────────────
   Más anchas que el resto del carril: son el bloque que hay que mirar, no que
   leer en columna estrecha. */
.capacidades {
  max-width: 1320px;
  text-align: center;
}

.capacidades .apoyo {
  color: var(--texto-tenue);
  max-width: 46ch;
  margin: 0 auto 44px;
}

.capacidades .rejilla {
  gap: 20px;
  text-align: left;
}

/*
 * La tarjeta, en tres pisos: icono y texto arriba, y el fragmento de interfaz
 * abajo empujado por `margin-top: auto` para que las tres terminen a la misma
 * altura aunque su texto no mida lo mismo.
 */
.capacidades .tarjeta {
  display: flex;
  flex-direction: column;
  /* Sin relleno propio: lo pone cada parte. El texto quiere más aire que la
     ilustración, y con un relleno único había que elegir cuál de los dos
     quedaba mal. */
  padding: 0;
  border-radius: 20px;
  overflow: hidden;
}

/* El bloque de icono, título, párrafo y lista, con su propio aire.
   El relleno de abajo es el HUECO MÍNIMO hasta la ilustración: vez y media el
   margen que la ilustración tiene con la tarjeta (26 px), porque un contenido y
   una imagen separados por lo mismo que la imagen del borde se leen pegados. */
.tarjeta__texto {
  padding: 32px 32px 40px;
}

/* La ilustración conserva el espacio que tenía —26 px a los tres lados— y sigue
   empujada al fondo para que las tres tarjetas terminen a la misma altura. */
.capacidades .ilustra {
  margin: 26px;
  margin-top: auto;
}

/*
 * Los iconos, sin caja y dibujados a mano.
 *
 * Fuera la pastilla con su tinte: el número de los pasos ya se escribe a mano y
 * la casilla de aquí lo contradecía —una sección con la letra suelta y la otra
 * con todo encajado—. Sin fondo, el icono se lee como un apunte al margen.
 *
 * Y son de trazo irregular a propósito: esquinas que no rematan, arcos que no
 * llegan a tocarse, óvalos que se dejan abiertos. Es el mismo lenguaje del
 * garabato que subraya los números.
 */
.tarjeta__icono {
  display: block;
  margin-bottom: 18px;
  color: var(--acento-fuerte);
}

/* Un cincuenta por ciento más grandes que los de la pastilla: sin fondo que los
   sostenga, a 21 px se quedaban en una mota. */
.tarjeta__icono svg { width: 32px; height: 32px; }

.capacidades .tarjeta h3 {
  font-size: 1.22rem;
  letter-spacing: -.01em;
  margin-bottom: 10px;
}

.capacidades .tarjeta p {
  font-size: .92rem;
  line-height: 1.55;
  color: var(--texto-tenue);
  margin: 0 0 10px;
}

/* El dato concreto, en otro registro: se lee de un vistazo sin competir con la
   frase de arriba, que es la que explica. */
/*
 * El dato va al color tenue ENTERO y no diluido.
 *
 * Con la mezcla al 78 % el contraste se quedaba en 3,88:1 sobre el fondo de la
 * tarjeta en tema claro —medido—, por debajo del 4,5:1 que pide la norma para
 * texto pequeño. La diferencia de registro ya la marca el tamaño, que es .8rem:
 * no hacía falta pagarla también en legibilidad. Sin diluir da 4,83:1 en claro y
 * 5,74:1 en oscuro.
 */
.tarjeta__dato {
  font-size: .8rem !important;
  line-height: 1.5 !important;
  color: var(--texto-tenue) !important;
}

/*
 * El fragmento de las CAPACIDADES sangra por la derecha y por abajo.
 *
 * Ahí funciona: la tarjeta es ancha, el trozo se ve a buen tamaño y el corte se
 * lee como una ventana a algo más grande. En las filas de los pasos, con la
 * columna más estrecha, el mismo recurso dejaba la interfaz diminuta y cortada
 * a lo tonto: por eso allí se usa la caja de abajo y no esto.
 */
.tarjeta__ui {
  margin: 22px -26px 0 0;
  margin-top: auto;
  padding-top: 22px;
  overflow: hidden;
}

.tarjeta__ui picture { display: block; }

.tarjeta__ui img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 12px 0 0 0;
  border: 1px solid var(--borde);
  border-right: 0;
  border-bottom: 0;
}

/* ── Pasos: filas alternas ──────────────────────────────────────────────────
   El mismo ancho que las capacidades, y el mismo par de título y apoyo. */
.pasos {
  max-width: 1320px;
  text-align: center;
}

.pasos .apoyo {
  color: var(--texto-tenue);
  max-width: 46ch;
  margin: 0 auto 56px;
}

.pasos__lista {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 20px;
  text-align: left;
}

.paso {
  display: grid;
  grid-template-columns: minmax(0, 38fr) minmax(0, 62fr);
  align-items: center;
  gap: 40px;
  background: var(--fondo-alto);
  border: 1px solid var(--borde);
  border-radius: 20px;
  padding: 40px;
}

/*
 * El vaivén: los pares llevan el texto a la derecha y la ilustración a la
 * izquierda. `direction` y no reordenar el HTML — el orden del documento es el
 * de los pasos y con lector de pantalla se recorre así, uno, dos y tres.
 */
.paso:nth-child(even) {
  direction: rtl;
}

.paso:nth-child(even) > * {
  direction: ltr;
}

.paso__texto {
  max-width: 46ch;
}

/*
 * El número, a mano.
 *
 * Deja de ser la pastilla que iguala a `.tarjeta__icono` en las capacidades, y
 * es a propósito: las tarjetas de arriba son tres cosas en paralelo y los pasos
 * son una secuencia. Que la numeración se escriba a mano —y no se encaje en una
 * casilla— es lo que las separa de un vistazo.
 *
 * Dos grados de inclinación: un rotulador nunca cae a plomo, y a cero se lee
 * como una tipografía manuscrita puesta recta, que es peor que no ponerla.
 */
.paso__numero {
  display: inline-grid;
  justify-items: start;
  gap: 2px;
  margin-bottom: 14px;
  color: var(--acento-fuerte);
  line-height: 1;
}

.paso__cifra {
  font-family: "Caveat", ui-rounded, cursive;
  font-weight: 700;
  font-size: 2.6rem;
  transform: rotate(-2deg);
  transform-origin: left bottom;
}

/* El subrayado va en el acento y no en el color de la cifra: así se lee como una
   marca hecha ENCIMA del número, que es lo que es, y no como parte del trazo. */
.paso__raya {
  display: block;
  width: 72px;
  height: 14px;
  color: var(--acento);
}

.paso__raya path {
  fill: none;
  stroke: currentColor;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.paso h3 {
  font-size: 1.32rem;
  letter-spacing: -.01em;
  margin-bottom: 10px;
}

.paso p {
  font-size: .95rem;
  line-height: 1.6;
  color: var(--texto-tenue);
  margin: 0 0 10px;
}

/*
 * LA CAJA ILUSTRATIVA.
 *
 * Un bloque entero de la aplicación, con aire alrededor, sobre un fondo propio y
 * con su borde. La caja es lo que dice «esto ilustra lo de al lado»; sin ella,
 * un trozo de interfaz suelto flota sobre el fondo y se lee como un pantallazo
 * mal recortado.
 *
 * ENTERO es la palabra: aquí no se recorta nada. Por eso las capturas se toman
 * en una ventana estrecha —el bloque mide lo que la caja puede enseñar— en vez
 * de cortar una pantalla de mil y pico píxeles.
 *
 * `--px` sale de `recursos/ui/medidas.json`, que escribe `traer.mjs`: es la
 * mitad del ancho capturado, porque se captura a densidad 2. Así las tres salen
 * al mismo aumento en toda la página.
 */
.ilustra {
  margin: 0;
  /*
   * EL AIRE DE LA CAJA, EN UNA PERILLA.
   *
   * No es adorno: cada variante expresa su relleno EN FUNCIÓN de este número
   * —la mitad, cero, cero solo a la derecha— y en móvil lo único que se cambia
   * es el número. Cuando esto era un `padding: 24px` suelto, la regla móvil
   * `.ilustra { padding: 18px }` lo pisaba entero y se llevaba por delante la
   * intención de tres variantes a la vez: la de página perdía su sangrado por
   * abajo, la del corte perdía el suyo por la derecha y la desnuda ganaba un
   * relleno que no debía tener nunca. Se veía en la página y no en la hoja.
   */
  --aire: 24px;
  padding: var(--aire);
  border-radius: 16px;
  background: var(--ilustra);
  border: 1px solid var(--borde);
  display: grid;
  place-items: center;
  min-width: 0;
  /* Recorta lo que se salga. Sin esto, la ilustración que sangra por la derecha
     se desbordaba por encima del borde de su propia caja, y en móvil —donde la
     columna es más estrecha que la imagen— se veía a la legua. */
  overflow: hidden;
}

.ilustra picture { display: block; }

.ilustra img {
  display: block;
  /* `--px` es el tamaño REAL en píxeles de aplicación —la mitad de la captura,
     que va a densidad 2—. `--zoom` es la desviación deliberada de ese 1:1, y por
     defecto no hay ninguna: se declara sola donde se aplica, para que quede a la
     vista que esa ilustración no está al mismo aumento que las demás. */
  width: calc(var(--px) * var(--zoom, 1) * 1px);
  /* El tope es red de seguridad para ventanas estrechas, no el modo normal: si
     se activara siempre, cada ilustración saldría a un zoom distinto. */
  max-width: 100%;
  height: auto;
  border-radius: 10px;
}

/* ── Lista de la tarjeta ────────────────────────────────────────────────────
   Un filete entre líneas y no viñetas: separa sin añadir un signo que hay que
   leer. Y el icono en el color del texto, macizo y sin fondo, para que sea una
   marca de lectura y no un botón. */
.lista {
  list-style: none;
  margin: 4px 0 0;
  padding: 0;
}

.lista li {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 0;
  /* Más pequeña que el párrafo de arriba: es una enumeración, no lectura. Con
     el mismo cuerpo competía con la frase que la explica. */
  font-size: .78rem;
  line-height: 1.4;
  color: var(--texto-tenue);
  border-top: 1px solid var(--borde);
}

/* El primero no lleva filete: separa entre elementos, no los encierra. */
.lista li:first-child {
  border-top: 0;
}

.lista svg {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  /* `currentColor` en el trazado y el color heredado aquí: si mañana cambia el
     tono del texto, el icono lo sigue sin tocar nada. */
  color: inherit;
}

/*
 * La ilustración que trae el FONDO DE PÁGINA de la aplicación.
 *
 * Es una tarjeta con las esquinas redondeadas, así que en la captura se ve por
 * las esquinas lo que había detrás: el fondo de la aplicación. Medido en el
 * fichero, `rgb(243,243,245)` — que es exactamente el `--fondo` de esta página,
 * porque la paleta se copió de allí. Con el gris de la caja ilustrativa quedaban
 * dos grises casi iguales que no casaban, y esa es la clase de desajuste que se
 * nota sin saber por qué.
 *
 * Y sangra por abajo: el corte cae dentro de un campo, así que la tarjeta tiene
 * que salirse de la caja para que se lea «esto sigue» y no «esto se acabó».
 */
.ilustra--pagina {
  background: var(--fondo);
  /* La mitad de relleno que las demás: la ilustración ya es ancha de por sí y
     con los 24 de rigor la caja crecía sin que se viera más. Y CERO abajo, que
     es lo que la deja a sangre por el pie. */
  padding: calc(var(--aire) / 2) calc(var(--aire) / 2) 0;
  place-items: end center;
  position: relative;
}

/* El mismo velo que en el paso 2, y por el mismo motivo: cubre la caja entera
   para que no se vea dónde acaba la imagen y empieza el contenedor. */
.ilustra--pagina::after {
  content: "";
  position: absolute;
  inset: 50% 0 0;
  border-radius: 0 0 15px 15px;
  background: linear-gradient(to bottom, rgb(0 0 0 / 0), rgb(0 0 0 / 0.10));
  pointer-events: none;
}

/*
 * La que NO sangra.
 *
 * `--pagina` trae el sangrado porque su captura está cortada a media pieza y
 * tiene que leerse como que la pantalla sigue. Ésta no: es un bloque completo,
 * con su principio y su final, así que se queda dentro de la caja con su aire
 * por los cuatro lados.
 */
.ilustra--pagina.ilustra--entera {
  padding: calc(var(--aire) / 2);
  place-items: center;
}

.ilustra--pagina.ilustra--entera img {
  border-radius: 10px;
}

.ilustra--pagina.ilustra--entera::after {
  content: none;
}

/* Las esquinas de abajo se van con el sangrado: la tarjeta continúa. */
.ilustra--pagina img {
  border-radius: 10px 10px 0 0;
}

/*
 * La que se corta por la DERECHA.
 *
 * El selector de formatos llega con el blanco de la aplicación dentro, así que
 * la caja toma ese mismo blanco: recortado sobre un gris se leía como una
 * pegatina.
 *
 * Y sale por el borde derecho en vez de caber justo. Es un control que en la
 * aplicación continúa —hay más formatos y más campos a su derecha— y cortarlo
 * ahí lo dice sin tener que escribirlo. El aire de los otros tres lados se
 * queda como estaba: la pieza no es grande y encajonarla más la ahogaría.
 */
.ilustra--corte-derecha {
  background: var(--fondo-alto);
  padding-right: 0;
  /* Anclada por la IZQUIERDA para que lo que sobre se vaya por la derecha; con
     `overflow: hidden` en la caja, eso es el corte. */
  place-items: center start;
  position: relative;
}

.ilustra--corte-derecha img {
  /* Sin tope: si se dejara encoger, no habría corte, habría una imagen pequeña. */
  max-width: none;
  /* Y sin redondeo: la imagen va directamente sobre el blanco de la caja, así
     que el radio no recorta un canto, muerde la interfaz — se le comía la
     esquina de abajo a la izquierda. */
  border-radius: 0;
}

/* El velo entra por el canto cortado y muere hacia el centro: es lo que hace que
   el corte se lea como profundidad y no como un tajo. */
.ilustra--corte-derecha::after {
  content: "";
  position: absolute;
  inset: 0 0 0 70%;
  border-radius: 0 15px 15px 0;
  background: linear-gradient(to right, rgb(0 0 0 / 0), rgb(0 0 0 / 0.10));
  pointer-events: none;
}

/*
 * La ilustración cuyo fondo YA ES el de la caja.
 *
 * El campo del encargo llega con el blanco de la aplicación dentro, así que la
 * caja gris le ponía un gris alrededor de un blanco: dos tonos para una sola
 * pieza. Aquí la caja toma el mismo color que la imagen y lo que la separa de la
 * tarjeta es el borde, no el fondo.
 *
 * Y un velo desde abajo —negro del 10 % al 0 % en la mitad inferior— que le da
 * el poco de hondura que el fondo plano le quitaba.
 *
 * El velo cubre LA CAJA ENTERA, de borde a borde, no solo la imagen. Es todo el
 * sentido de haber igualado los dos blancos: si el degradado se parara en el
 * canto de la imagen, el blanco de la caja y el de la imagen volverían a leerse
 * como dos superficies distintas y no habríamos ganado nada.
 *
 * Va en el `inset` y no en un hijo: al ser absoluto sobre un elemento con borde,
 * se posiciona contra la caja de relleno, así que llega hasta el borde sin
 * pintarlo por encima.
 */
.ilustra--plana {
  background: var(--fondo-alto);
  position: relative;
}

.ilustra--plana::after {
  content: "";
  position: absolute;
  inset: 50% 0 0;
  border-radius: 0 0 15px 15px;
  background: linear-gradient(to bottom, rgb(0 0 0 / 0), rgb(0 0 0 / 0.10));
  pointer-events: none;
}

/*
 * La ilustración que YA TRAE su fondo.
 *
 * El encuadre de exportación es un trozo del lienzo, así que llega con el gris
 * de la aplicación dentro. Meterlo en la caja gris es poner un gris sobre otro:
 * dos marcos para una sola imagen. Aquí el borde va sobre la imagen misma y no
 * hace falta caja.
 *
 * Alineada a la derecha y no centrada: es una esquina de pantalla, y una esquina
 * pegada al borde se lee como que la ventana sigue más allá; centrada, se lee
 * como un recorte flotando.
 */
.ilustra--desnuda {
  padding: 0;
  background: none;
  border: 0;
  place-items: center end;
}

.ilustra--desnuda img {
  border: 1px solid var(--borde);
  border-radius: 12px;
}

/*
 * A vez y media su tamaño real.
 *
 * Rompe a propósito el 1:1 que comparten las otras cinco ilustraciones: la
 * interfaz de la aplicación usa cuerpos de 11 a 14 px y, al lado del texto de
 * esta página, a tamaño real se lee pequeña. Aquí lo que importa es que se lean
 * «Guardado» y «Sin problemas de validación», que es lo que demuestra el paso.
 *
 * La captura va a densidad 2, así que a 1,5× siguen tocando 1,33 píxeles de
 * imagen por píxel de pantalla en una retina: se ve nítida igual.
 */
.ilustra--desnuda {
  --zoom: 1.5;
}

@media (max-width: 860px) {
  /*
   * UN SOLO NÚMERO PARA EL RELLENO DE TODAS LAS TARJETAS.
   *
   * En escritorio las dos familias respiran distinto a propósito: la fila de un
   * paso tiene 40 px y el bloque de texto de una capacidad, 32 con 40 abajo,
   * porque son composiciones distintas —una fila a dos columnas y una columna
   * con ilustración al pie—. En una sola columna esa diferencia deja de
   * justificarse y solo se ve como descuadre: dos tarjetas iguales, una con más
   * margen que la otra.
   *
   * Puesto en una variable y no repetido en cada regla: es una IGUALDAD que
   * tiene que seguir siendo cierta, y dos cifras sueltas se separan al primer
   * retoque.
   */
  :root { --pad-tarjeta: 20px; }

  .paso,
  .paso:nth-child(even) {
    grid-template-columns: 1fr;
    gap: 22px;
    padding: var(--pad-tarjeta);
    direction: ltr;
  }

  /* El texto de la capacidad, al mismo relleno que la fila del paso. Abajo,
     vez y media: es el hueco mínimo hasta la ilustración, y con el mismo valor
     que los lados el contenido y la imagen se leen pegados. */
  .tarjeta__texto {
    padding: var(--pad-tarjeta) var(--pad-tarjeta) calc(var(--pad-tarjeta) * 1.5);
  }

  /* Y la ilustración se separa del borde de su tarjeta lo mismo que el texto:
     así el marco de la tarjeta es uno solo y no dos anchos distintos. */
  .capacidades .ilustra {
    margin: var(--pad-tarjeta);
    margin-top: auto;
  }

  .paso__numero {
    margin-bottom: 10px;
  }

  /* El número a mano aguanta menos reducción que el texto —es un trazo, y por
     debajo de 28 px deja de leerse como rotulador—, así que baja menos que los
     títulos. La raya lo acompaña. */
  .paso__cifra {
    font-size: 1.85rem;
  }

  .paso__raya {
    width: 46px;
  }

  /* Solo se gira la perilla: cada variante recalcula su relleno a partir de
     ella y conserva lo suyo. */
  .ilustra { --aire: 18px; }

  /*
   * EL SANGRADO POR LA DERECHA, GARANTIZADO.
   *
   * La caja conserva su aire por arriba, por la izquierda y por abajo —eso lo
   * pone `--aire`— y cero a la derecha, que es de donde se sale la imagen.
   *
   * Lo que no vale aquí es el ancho fijo de las demás ilustraciones. `--px` son
   * 326 px, y en una columna sola ese número se cruza con el ancho de la
   * tarjeta: a 360 de ventana sobra imagen y sangra; a 390 coincide al píxel y
   * queda a ras, sin sangrar; y de 414 en adelante FALTA imagen y se abre un
   * hueco a la derecha, con el degradado pintando sobre el fondo vacío. Tres
   * comportamientos distintos según el teléfono, y ninguno pedido.
   *
   * Puesto como «el ancho de la caja MÁS 48», el sangrado es siempre el mismo y
   * la interfaz crece con la tarjeta en vez de quedarse en su tamaño de
   * escritorio. El fichero está a densidad 2 (652 px reales), así que hay margen
   * de sobra para estirarlo hasta donde llega una columna de teléfono.
   */
  .ilustra--corte-derecha img { width: calc(100% + 48px); }
}

/* ── Requisitos: ficha técnica en tres carriles ─────────────────────────────
   Sin tarjetas y a todo el ancho. Aquí no hay tres cosas que elegir, hay una
   ficha con tres apartados, así que se separan con un filete y no con una caja. */
.requisitos {
  max-width: 1320px;
  text-align: center;
}

.requisitos .apoyo {
  color: var(--texto-tenue);
  max-width: 46ch;
  margin: 0 auto 48px;
}

.carriles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  border-top: 1px solid var(--borde);
  text-align: left;
}

.carril {
  padding: 26px 30px 4px;
  border-left: 1px solid var(--borde);
}

/* El primero no lleva filete: separa entre carriles, no los encierra. */
.carril:first-child {
  border-left: 0;
  padding-left: 0;
}

.carril h3 {
  font-size: 1.06rem;
  margin-bottom: 16px;
}

.carril ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.carril li {
  display: grid;
  gap: 5px;
  padding: 14px 0;
  border-top: 1px solid var(--borde);
  font-size: .92rem;
  line-height: 1.5;
}

.carril li:first-child {
  border-top: 0;
}

/* La línea principal. Existe para que los chips sean texto EN LÍNEA y no hijos
   de la rejilla del <li>: sueltos, cada uno se comía su propio renglón. */
.carril__linea {
  margin: 0;
  font-size: .92rem;
  line-height: 1.55;
}

/* La aclaración, en otro registro: se lee si hace falta y no estorba si no. */
.carril li span {
  color: var(--texto-tenue);
  font-size: .8rem;
  line-height: 1.5;
}

/*
 * EL CHIP DEL DATO.
 *
 * Solo para lo que se consulta —cuánto ocupa, qué versión, qué procesador—, que
 * es lo que alguien busca en esta sección sin leer la frase entera. Puesto en
 * todo se convertiría en decoración y dejaría de señalar nada.
 *
 * `font-weight: inherit` a propósito: el chip ya destaca por su fondo, y con
 * negrita encima el renglón se llena de bultos.
 *
 * Se llama `chip-dato` y no `pieza` porque `.pieza` YA es la publicación
 * flotante de la portada. Al reutilizar el nombre, las doce piezas del campo se
 * llevaron el fondo y el borde de este chip — y no lo cazó ninguna comprobación,
 * porque técnicamente la página seguía funcionando.
 */
.chip-dato {
  display: inline-block;
  padding: 2px 8px;
  margin: 0 1px;
  border-radius: 7px;
  /* Gris macizo y SIN borde. Con fondo de panel y filete quedaban cajas, no
     chips: el borde los separaba del renglón en vez de asentarlos en él.
     El gris sale del color del texto y no de un valor suelto, así que funciona
     igual en los dos temas sin declararlo dos veces. */
  background: color-mix(in srgb, var(--texto) 9%, transparent);
  border: 0;
  font-weight: inherit;
  font-size: .86em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/*
 * Cuando al chip le sigue una coma, el signo queda a NUEVE píxeles del texto —los
 * 8 de relleno más 1 de margen— y se lee «chip Apple , M1»: el hueco de la
 * pastilla parece un espacio escrito. Se recupera casi todo y la coma vuelve a
 * pegarse a la palabra sin montarse sobre el gris.
 */
.chip-dato--con-coma {
  margin-right: -7px;
}

/* El «no» va teñido: es la única parte de la ficha donde el dato es una negativa
   y conviene que se vea sin leer. */
.chip-dato--no {
  background: color-mix(in srgb, var(--no) 14%, transparent);
  color: var(--no);
  font-weight: 600;
}

@media (max-width: 860px) {
  .requisitos {
    max-width: none;
  }

  .requisitos .apoyo {
    margin-bottom: 28px;
    font-size: .95rem;
  }

  .carril {
    padding: 22px 0 4px;
    border-left: 0;
    border-top: 1px solid var(--borde);
  }

  .carril:first-child {
    border-top: 0;
    padding-top: 0;
  }

  .carril li {
    font-size: .88rem;
  }
}

/* ── Compra: el recibo sobre la mesa ────────────────────────────────────────
   La página abre con las piezas flotando y cierra con ellas amontonadas. Es el
   mismo material al principio y al final, y lo último que se ve antes de pagar
   es lo que sale del programa. */
.comprar { text-align: center; }

.comprar .apoyo {
  color: var(--texto-tenue);
  max-width: 44ch;
  margin: 0 auto 44px;
}

.mesa {
  position: relative;
  /*
   * SU PROPIO CONTEXTO DE APILAMIENTO.
   *
   * El recibo lleva `z-index: 10` para ganarle a las fotos y al lienzo de
   * destellos. Pero `.mesa` era `position: relative` con `z-index: auto`, o sea
   * NO creaba contexto, así que ese 10 competía en la raíz contra el 10 de la
   * barra pegajosa —y a igualdad gana el que va después en el documento—: al
   * llegar al final de la página el recibo se pintaba ENCIMA de la barra y le
   * partía el menú por la mitad.
   *
   * `isolation` y no un z-index: el número del recibo solo tiene que ordenar lo
   * de dentro de la mesa, y encerrándolo aquí deja de tener opinión sobre lo que
   * pasa fuera.
   */
  isolation: isolate;
  display: grid;
  place-items: center;
  /* Sitio para que las polaroids asomen por los cuatro lados del recibo. */
  padding: 40px 0 56px;
}

/* ── Las piezas sobre la mesa ────────────────────────────────────────────── */
.mesa__fotos {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/*
 * Cada una en su sitio, girada y a su profundidad.
 *
 * `--z` va de 1 (al fondo) a 3 (más cerca del recibo) y de ahí salen el tamaño,
 * la sombra y cuánto se aparta del ratón: un número, tres consecuencias, igual
 * que en el campo de la portada.
 *
 * El desplazamiento va en PÍXELES y en los márgenes, no en el `translate`: ahí
 * un porcentaje se mide sobre la propia foto y no sobre la mesa, y las cinco
 * salían a setenta píxeles del centro, escondidas detrás del recibo.
 */
.pieza-mesa {
  position: absolute;
  left: 50%;
  top: 50%;
  margin: 0;
  margin-left: var(--x);
  margin-top: var(--y);
  width: calc(152px + var(--z) * 16px);
  border-radius: 14px;
  overflow: hidden;
  /* El centrado y el giro aparte, para que el `transform` quede libre para el
     ratón y no peleen. */
  translate: -50% -50%;
  rotate: var(--giro);
  z-index: var(--z);
  will-change: transform;
  /* Dos sombras: una corta que la pega a la mesa y una larga que la levanta. Con
     una sola, o flota sin apoyo o se queda plana. */
  box-shadow:
    0 2px 4px rgb(0 0 0 / .07),
    0 calc(var(--z) * 7px) calc(var(--z) * 18px) rgb(0 0 0 / .16);
  transition: box-shadow .35s ease;
}

/* Cerca del ratón se levanta: sombra más larga y más suave, que es lo que hace
   una cosa al separarse de la mesa. El desplazamiento lo pone el script. */
.pieza-mesa--cerca {
  box-shadow:
    0 3px 6px rgb(0 0 0 / .06),
    0 calc(var(--z) * 13px) calc(var(--z) * 30px) rgb(0 0 0 / .22);
}

.pieza-mesa img {
  display: block;
  width: 100%;
  height: auto;
}

/* ── Los destellos ───────────────────────────────────────────────────────── */
/*
 * El lienzo va POR ENCIMA de las fotos (que están en 1–3) y POR DEBAJO del
 * recibo (que está en 10): los destellos acompañan a las piezas, pero nunca
 * cruzan por delante del precio ni del botón.
 *
 * Lo crea y lo pinta el script. Si no llega, aquí no hay nada que se vea a
 * medias: simplemente no existe el elemento.
 */
.mesa__chispas {
  position: absolute;
  inset: 0;
  /*
   * El tamaño va EXPLÍCITO, y no es redundante con `inset: 0`.
   *
   * `canvas` es un elemento reemplazado: con `width: auto` toma su tamaño
   * intrínseco —los atributos `width`/`height`, que el script multiplica por la
   * densidad de pantalla— y, al quedar sobredeterminado, descarta el `right`. En
   * un Mac a 2x eso lo dejaba midiendo el doble que la mesa, con los destellos
   * cayendo al doble de distancia de donde tocaba. Solo se veía midiendo la caja
   * del lienzo: a 1x cuadra por casualidad.
   */
  width: 100%;
  height: 100%;
  z-index: 5;
  pointer-events: none;
}

/* ── El recibo ───────────────────────────────────────────────────────────── */
.recibo {
  position: relative;
  z-index: 10;
  width: min(560px, 100%);
  text-align: left;
  background: var(--fondo-alto);
  border: 1px solid var(--borde);
  border-radius: 20px 20px 3px 3px;
  padding: 34px 34px 30px;
  display: grid;
  gap: 2px;
  box-shadow: 0 24px 60px rgb(0 0 0 / .14);
}

/* El borde dentado: remata la metáfora sin tener que escribirla. */
.recibo::after {
  content: "";
  position: absolute;
  left: -1px;
  right: -1px;
  bottom: -11px;
  height: 12px;
  background: repeating-linear-gradient(135deg, var(--fondo) 0 8px, transparent 8px 16px);
}

.rotulo-recibo {
  font-family: var(--titulo);
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--texto-tenue);
  margin: 0 0 10px;
}

.recibo__linea {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 18px;
  padding: 11px 0;
  border-top: 1px solid var(--borde);
  font-size: .9rem;
}

.recibo__linea:first-of-type { border-top: 0; }

.recibo__cosa { display: flex; align-items: center; gap: 10px; min-width: 0; }

/* Un icono por concepto, del que se reconoce: la imagen de disco, la ventana, el
   documento. Al color del texto y sin fondo, como los de las capacidades. */
.recibo__icono { width: 19px; height: 19px; flex-shrink: 0; color: var(--acento-fuerte); }

.recibo__dato { color: var(--texto-tenue); text-align: right; font-size: .84rem; white-space: nowrap; }

.recibo__total {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 18px;
  margin-top: 8px;
  padding: 16px 0 6px;
  /* Filete grueso y del color del texto: es la línea del total de cualquier
     recibo, y ese es exactamente el gesto que se está tomando prestado. */
  border-top: 2px solid var(--texto);
  font-family: var(--titulo);
  font-weight: 700;
  font-size: 1.7rem;
}

.recibo__cifra { display: flex; align-items: center; gap: 12px; }

/* La flecha señala el TOTAL y no el botón: el botón ya se ve solo. */
.flecha-total { color: var(--acento); flex-shrink: 0; }
.flecha-total path { fill: none; stroke: currentColor; stroke-width: 2.1; stroke-linecap: round; stroke-linejoin: round; }

.recibo__pie { display: grid; gap: 12px; justify-items: center; padding-top: 20px; text-align: center; }
.recibo__pie .letra-chica { margin: 0; max-width: 44ch; }

/* ── La mesa en pantalla estrecha ────────────────────────────────────────────
 *
 * Mismo problema que el campo y misma solución.
 *
 * Las cinco piezas están colocadas a ±352 px del centro para asomar por los
 * lados de un recibo de 560. En 390 px de ventana eso las manda fuera de la
 * pantalla: no se ven, y aun así estiran el documento hasta 612 px de ancho.
 * Además el imán y los destellos son de ratón, y en un teléfono no hay ratón:
 * lo único que hacen es trabajo que nadie percibe.
 *
 * Aquí las tres primeras se apilan ENCIMA del recibo, en el flujo y solapadas,
 * y el recibo sube a taparlas por abajo. La lectura es la misma que en
 * escritorio —el papel encima de las fotos— con la baraja recolocada.
 */
@media (max-width: 860px) {
  .mesa {
    /* De rejilla centrada a bloque: ya no hay nada superpuesto que centrar. */
    display: block;
    padding: 0 0 8px;
  }

  .mesa__fotos {
    position: static;
    display: flex;
    justify-content: center;
    align-items: flex-end;
    /* El recibo monta 30 px sobre las fotos. Es lo que las convierte en «lo que
       hay debajo del papel» en vez de en una cabecera ilustrada. */
    margin-bottom: -30px;
  }

  .pieza-mesa:nth-child(n + 4) { display: none; }

  .mesa__fotos { --pieza: min(112px, 28vw); }

  .pieza-mesa {
    position: static;
    width: var(--pieza);
    flex: 0 0 auto;
    /* Los `--x`/`--y` viajan en márgenes; en fila hay que devolverlos a cero
       antes de repartir el solape. */
    margin: 0;
    translate: none;
    border-radius: 10px;
    will-change: auto;
    /* Sin ratón no hay «cerca»: una sola sombra, la de reposo. */
    box-shadow: 0 2px 4px rgb(0 0 0 / .08), 0 10px 22px rgb(0 0 0 / .20);
    transition: none;
  }

  .pieza-mesa:nth-child(1) { rotate: -8deg; margin-right: calc(var(--pieza) * -0.18); z-index: 1; }
  .pieza-mesa:nth-child(2) { rotate: 4deg; z-index: 3; }
  .pieza-mesa:nth-child(3) { rotate: -3deg; margin-left: calc(var(--pieza) * -0.18); z-index: 2; }

  .recibo { padding: 24px 20px 22px; }
  .recibo__total { font-size: 1.45rem; }

  /*
   * La línea del recibo se parte en dos alturas.
   *
   * En escritorio va concepto a la izquierda y dato a la derecha, como en un
   * recibo de papel. En 350 px las dos columnas se pelean por el ancho y las
   * dos parten: «PostCreator 1.0 para / Mac» contra «.dmg · 339 / MB», tres
   * líneas para decir dos cosas. Apilado se lee de un vistazo y el dato sigue
   * siendo el renglón secundario, ahora por tamaño y color en vez de por lado.
   */
  .recibo__linea {
    display: grid;
    gap: 3px;
    padding: 12px 0;
  }

  .recibo__dato {
    text-align: left;
    white-space: normal;
    /* A la altura del texto, no del icono: el icono ya marca dónde empieza el
       concepto y repetir esa sangría dejaría el dato flotando. */
    padding-left: 29px;
    font-size: .8rem;
  }
}

/* ── Pie ── */
.pie {
  border-top: 1px solid var(--borde); margin-top: 40px;
  padding: 32px 28px; text-align: center; color: var(--texto-tenue); font-size: .9rem;
}
.pie p { margin: 0 0 6px; }

/* ── Las tarjetas se salen del carril ────────────────────────────────────────
 *
 * En una columna, el relleno de la sección y el de la tarjeta se SUMAN: 20 px de
 * carril más 20 de tarjeta son 40 px de margen a cada lado antes de la primera
 * letra, sobre 390 de pantalla. Eso es una quinta parte del ancho gastada en
 * aire duplicado, y se nota en cada línea que parte antes de tiempo.
 *
 * La tarjeta ya trae su propio aire, así que aquí se sale del carril y se queda
 * a 3 px del borde. El texto sigue teniendo su margen —el de la tarjeta— y gana
 * 34 px de ancho de lectura.
 *
 * El tirón se calcula CONTRA el carril y no se escribe a mano: si mañana el
 * carril cambia, los 3 px del borde siguen siendo 3.
 */
@media (max-width: 640px) {
  main > section {
    --carril: 20px;
    padding: 48px var(--carril);
  }

  .capacidades .rejilla,
  .pasos__lista,
  .mesa {
    margin-inline: calc(3px - var(--carril));
  }
}

/* Conmutador de idioma. Discreto: no compite con la acción de compra, pero
   tiene que verse sin buscarlo — la mitad del público de Gumroad lee en inglés. */
.idioma {
  font-family: var(--titulo); font-size: .8rem; font-weight: 600;
  letter-spacing: .06em; text-decoration: none; color: var(--texto-tenue);
  border: 1px solid var(--borde); border-radius: 8px; padding: 6px 10px;
}
.idioma:hover { color: var(--texto); border-color: var(--texto-tenue); }

/* El logotipo de la barra. Bloque, no en línea: como enlace en línea la imagen
   arrastra el hueco de la línea base y la barra queda descuadrada abajo. */
.marca {
  display: flex;
  align-items: center;
  flex-shrink: 0;
}

/* ── Lo que necesita la animación ────────────────────────────────────────────
   Aquí NO va ningún estado inicial: nada de opacidad cero ni desplazamientos.
   Eso lo pone `animacion.js`, para que si el script no llega la página se vea
   entera y quieta en vez de en blanco con el texto invisible. */

.barra {
  position: sticky;
  top: 0;
  z-index: 10;
  background: transparent;
  transition: background-color .25s ease, border-color .25s ease;
  border-bottom: 1px solid transparent;
  /* La barra pegajosa se sale del carril del contenido para poder pintar su
     fondo de lado a lado; el relleno la devuelve al carril.
     El cálculo va sobre `100%` y no sobre `100vw` por el mismo motivo que el
     recorte de `main`: `100vw` cuenta la barra de desplazamiento y las secciones
     de abajo se centran sin ella, así que el logotipo quedaba 7,5 px a la
     derecha de todo lo demás. Con `100%` —el ancho real del cuerpo— las dos
     cuentas dan el mismo número. */
  max-width: none;
  padding-inline: max(28px, calc((100% - var(--ancho)) / 2 + 28px));
}

.barra--posada {
  background: color-mix(in srgb, var(--fondo) 88%, transparent);
  backdrop-filter: saturate(180%) blur(10px);
  border-bottom-color: var(--borde);
}

/*
 * El titular se parte en palabras para escalonarlas al entrar.
 *
 * Dos tramos: el de fuera recorta y el de dentro se mueve. Con uno solo, la
 * palabra al subir asoma por encima de la línea anterior.
 *
 * El relleno de abajo compensado con el margen negativo NO es un apaño: sin él,
 * `overflow: hidden` corta las colas de las g, las j y las p, y solo se nota en
 * los titulares que las llevan.
 */
.palabra {
  display: inline-block;
  overflow: hidden;
  padding-bottom: .14em;
  margin-bottom: -.14em;
  vertical-align: bottom;
}

.palabra__cuerpo {
  display: inline-block;
}

/* Quien pide menos movimiento no ve ninguno: el script se sale antes de tocar
   nada, y aquí se apaga también lo poco que anima el CSS. */
@media (prefers-reduced-motion: reduce) {
  .barra {
    transition: none;
  }
}

/* ── Ir a otra sección ───────────────────────────────────────────────────────
 *
 * Dos cosas hacen falta para que un enlace interno se lea como un movimiento y
 * no como un corte, y las dos van aquí porque son la misma decisión.
 *
 * UNA: el salto se anima. Sin esto la página aparece de golpe en otro sitio y
 * hay que releer la pantalla para saber dónde has caído; con el recorrido a la
 * vista, se sabe que has bajado y cuánto. Va en `prefers-reduced-motion:
 * no-preference` porque a quien pide menos movimiento un desplazamiento largo
 * le sienta peor que el corte, y porque así el valor por defecto —si la consulta
 * no casa— es el salto seco de siempre.
 *
 * Y DOS: la barra es pegajosa, así que el destino quedaría DEBAJO de ella. El
 * título al que saltas queda tapado y parece que el enlace no ha ido a ningún
 * sitio.
 *
 * Los 116 px SON MEDIDOS y no estimados, que es de donde venía el fallo: aquí
 * ponía 88 «que son los 64 de la barra más aire», y la barra no mide 64. Mide 91
 * de 430 px de ancho en adelante y 86 en los teléfonos estrechos, donde el botón
 * lleva menos relleno. Con 88 el título aterrizaba TRES píxeles por debajo del
 * borde de la barra, y en móvil, con 72, diecinueve por debajo: el enlace parecía
 * no haber ido a ningún sitio, que es exactamente lo que esta regla existe para
 * evitar. 116 son los 91 del caso peor más 25 de aire, y valen para los dos
 * tamaños porque entre uno y otro la barra solo cambia cinco píxeles.
 */
@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

main > section[id] {
  scroll-margin-top: 116px;
}

/* ── La escala tipográfica en pantalla estrecha ──────────────────────────────
 *
 * LOS `clamp()` DE LA HOJA NO LLEGAN A BAJAR AQUÍ.
 *
 * Su término central va en `vw`, y a 390 px de ventana 5vw son 19,5 px: muy por
 * debajo del suelo, así que el titular se queda CLAVADO en su mínimo de 35,2 px
 * y el `clamp` no hace nada. Eso son unos 20 caracteres por línea —medido—, y un
 * titular de siete palabras se parte en cinco renglones. Lo mismo con el h2 en
 * su suelo de 25,6.
 *
 * Lo que sigue no es «más pequeño porque sí»: cada recta está calculada para
 * PASAR POR EL VALOR QUE LA PÁGINA YA TENÍA A 860 px. Así el corte no se nota
 * —a 861 el titular mide 43,0 px y a 860 mide 43,1— y lo único que cambia es que
 * ahora sí sigue bajando de ahí.
 */
@media (max-width: 860px) {
  /* Un punto menos de cuerpo base. Arrastra consigo todo lo que va en `em`,
     como los chips de la ficha técnica, y por eso se toca aquí y no pieza a
     pieza. */
  body { font-size: 16px; }

  /* 28,5 px a 390 · 43,1 a 860. */
  h1 { font-size: clamp(1.6rem, 1.03rem + 3.09vw, 2.7rem); }

  /* 21,0 px a 390 · 25,8 a 860. */
  h2 { font-size: clamp(1.2rem, 1.06rem + 1.02vw, 1.62rem); }

  h3 { font-size: 1.06rem; }

  /* 17,0 px a 390, y recupera sus 19,2 antes de llegar al corte. */
  .entradilla { font-size: clamp(1rem, .925rem + .55vw, 1.2rem); }

  /* El apoyo iba al mismo cuerpo que el texto corrido y competía con él: bajo un
     título más pequeño, el subtítulo tiene que ceder también. */
  .apoyo { font-size: .95rem; }

  .capacidades .tarjeta h3 { font-size: 1.06rem; }
  .paso h3 { font-size: 1.14rem; }
  .carril h3 { font-size: 1rem; }
}

/* ── La barra en pantallas muy estrechas ─────────────────────────────────────
 *
 * A 360 px no cabe: logotipo de 150, botón de compra y conmutador de idioma
 * suman más que el ancho útil, y el conjunto estiraba el documento a 380 px
 * —medido—. Se apretan las tres cosas un punto en vez de esconder ninguna: lo
 * que vive en la barra es comprar y cambiar de idioma, y las dos tienen que
 * seguir ahí en el teléfono más estrecho que se venda.
 */
@media (max-width: 400px) {
  .barra { padding-inline: 16px; gap: 12px; }

  .barra__nav { gap: 10px; }
  .barra__nav .boton { padding: 10px 14px; font-size: .88rem; }
  .marca img { width: 122px; height: auto; }
  .idioma { padding: 6px 8px; }
}

@media (max-width: 640px) {
  /*
   * A 390 px los dos enlaces de texto se parten en tres líneas cada uno y la
   * cabecera se convierte en un acordeón de 260 px de alto — medido en captura.
   * Se van: la página es una sola columna y se recorre bajando. Lo que no se va
   * es lo único que hay que poder hacer siempre, comprar y cambiar de idioma.
   */
  .barra__nav a:not(.boton):not(.idioma) {
    display: none;
  }

  .barra {
    flex-wrap: nowrap;
  }

  .portada {
    padding-top: 32px;
  }

  /* El de escritorio ya sirve: la barra apenas encoge en el teléfono. Un segundo
     número aquí solo era una oportunidad más de que se quedara desfasado. */
}

/* ── La barra de acción del teléfono ─────────────────────────────────────────
 *
 * Los dos botones de la portada, flotando abajo durante el recorrido y solo en
 * pantalla de teléfono: en escritorio la barra de arriba ya lleva el suyo y se
 * ve siempre.
 *
 * Flota con aire alrededor y no pegada al filo: pegada se lee como parte del
 * navegador —la misma zona donde el sistema pinta sus propios controles— y
 * separada se lee como algo de la página. El aire de abajo suma el hueco del
 * indicador del iPhone, que si no se le monta encima.
 */
.cta-flotante {
  position: fixed;
  /* Por encima de la barra pegajosa (10) y del lienzo de destellos (5): es lo
     último que se pinta y nada debe taparlo. */
  z-index: 20;
  left: 12px;
  right: 12px;
  bottom: calc(12px + env(safe-area-inset-bottom, 0px));

  /* En escritorio no existe. */
  display: none;

  gap: 8px;
  padding: 8px;
  border-radius: 16px;
  background: color-mix(in srgb, var(--fondo-alto) 88%, transparent);
  border: 1px solid var(--borde);
  /* El desenfoque de detrás es lo que la separa del contenido sin taparlo del
     todo. Donde no exista, el 88 % de fondo sigue siendo legible. */
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  box-shadow: 0 2px 6px rgb(0 0 0 / .10), 0 16px 36px rgb(0 0 0 / .30);
}

/* Mitad y mitad: son dos acciones del mismo peso —una compra y una duda— y
   repartir el ancho a partes iguales es lo que dice que las dos valen. */
.cta-flotante .boton {
  flex: 1 1 0;
  text-align: center;
  padding: 13px 12px;
  font-size: .9rem;
  white-space: nowrap;
}

.cta-flotante .boton--fantasma {
  background: color-mix(in srgb, var(--fondo) 55%, transparent);
}

@media (max-width: 640px) {
  /*
   * OJO: aquí el estado de partida SÍ vive en el CSS, al revés que en todo lo
   * demás de esta página.
   *
   * La regla general es que lo que se oculta lo oculte el script, para que un
   * fallo al cargarlo no deje la página en blanco. Aquí es al contrario y a
   * propósito: lo que se esconde es un ATAJO, no contenido. Si el script no
   * llega, falta un botón de más; si se hiciera al revés, la barra se quedaría
   * fija tapando el pie de página para siempre.
   */
  .cta-flotante {
    display: flex;
    visibility: hidden;
    opacity: 0;
    translate: 0 130%;
    /* Al esconderse, `visibility` espera a que termine el fundido; al aparecer,
       cambia en el acto. Sin ese retardo, la barra desaparecería de golpe en el
       primer fotograma y no habría fundido que ver. */
    transition: opacity .2s ease, translate .2s ease-in, visibility 0s linear .2s;
  }

  /* Entra más despacio de lo que sale: aparecer es una oferta y conviene que se
     note; irse es quitarse de en medio, y ahí lo que se agradece es que sea
     rápido. */
  .cta-flotante--dentro {
    visibility: visible;
    opacity: 1;
    translate: 0 0;
    transition: opacity .28s ease, translate .34s cubic-bezier(.22, 1, .36, 1), visibility 0s;
  }
}

/* Quien pide menos movimiento la ve aparecer y desaparecer sin deslizamiento.
   Lo que NO se toca es que aparezca: es el botón de comprar, no un adorno. */
@media (prefers-reduced-motion: reduce) {
  .cta-flotante {
    translate: 0 0;
    /* El retardo de `visibility` sigue haciendo falta también aquí, o el
       fundido no se llega a ver al esconderse. */
    transition: opacity .15s linear, visibility 0s linear .15s;
  }

  .cta-flotante--dentro {
    translate: 0 0;
    transition: opacity .15s linear, visibility 0s;
  }
}

/* ── El botón con la manzana ─────────────────────────────────────────────────
 *
 * La manzana dice «esto es una aplicación para Mac» sin gastar una palabra del
 * botón, que es donde menos sitio hay. Va en los dos botones de «Comprar por
 * 39 €» de la portada, y solo ahí. En la barra flotante NO va: medido, los dos
 * botones ya iban justos en esa barra —a 320 px se salían de la pantalla— y los
 * 25 px de la manzana los echaban fuera también a 360. La portada ya ha dicho
 * que esto es para Mac; la barra de abajo es un recordatorio, no una primera
 * impresión. El del recibo tampoco la lleva: ahí la línea de arriba ya dice
 * «PostCreator 1.0 para Mac».
 */
.boton--con-icono {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
}

.icono-apple {
  width: 1.05em;
  height: 1.05em;
  flex-shrink: 0;
  /* La manzana tiene el rabo arriba y el peso abajo: centrada por su caja se ve
     caída. Ocho milésimas de eme la suben a donde el ojo la espera. */
  margin-top: -.08em;
}

/*
 * La barra flotante en pantallas muy estrechas.
 *
 * «Comprar por 39 €» y «Antes de comprar» son dieciséis caracteres cada uno, y a
 * 320 px no caben dos veces en los 280 de ancho útil: el botón fantasma llegaba
 * a 343 en una ventana de 320 —medido—. Con un punto menos de cuerpo y menos
 * relleno entran los dos con holgura.
 *
 * Va AQUÍ, al final, y no junto al resto de reglas de 400 px: allí queda antes
 * que el bloque base de `.cta-flotante` en el fichero y, a igual especificidad,
 * pierde. Se comprobó midiendo, porque en la hoja parecía correcto.
 */
@media (max-width: 400px) {
  .cta-flotante {
    left: 10px;
    right: 10px;
    padding: 6px;
    gap: 6px;
  }

  .cta-flotante .boton {
    padding: 12px 10px;
    font-size: .8rem;
  }
}

/* ── Imprimir o guardar en PDF ───────────────────────────────────────────────
 *
 * Sin esto salen HOJAS EN BLANCO. El estado de partida de los revelados lo pone
 * el script —`opacity: 0` y un desplazamiento— y solo lo deshace ScrollTrigger
 * cuando la sección asoma por la ventana. Al imprimir, el navegador compone el
 * documento entero de una vez y todo lo que nunca llegó a asomar sale invisible.
 *
 * La red va aquí y no en el script a propósito: tiene que funcionar tanto si el
 * script corrió como si no. Es el único sitio de esta hoja donde `!important`
 * está justificado, porque lo que hay que ganar son estilos EN LÍNEA escritos
 * por GSAP, y a esos no se les gana con especificidad.
 */
@media print {
  *,
  *::before,
  *::after {
    opacity: 1 !important;
    transform: none !important;
    translate: none !important;
    filter: none !important;
    animation: none !important;
    transition: none !important;
  }

  /* Pegajosa en papel no significa nada, y repetida en cada hoja, menos. */
  .barra {
    position: static;
  }

  /* Un botón flotante impreso es una mancha: lo que hace ya está en el recibo. */
  .cta-flotante,
  .mesa__chispas {
    display: none !important;
  }

  /* El campo de piezas se apoya en posiciones absolutas sobre una portada que en
     papel ya no mide lo mismo. Fuera: el argumento va en el texto. */
  .campo {
    display: none;
  }

  main {
    overflow-x: visible;
  }
}

/* ── Tres columnas o una, nunca dos ──────────────────────────────────────────
 *
 * La rejilla es `repeat(auto-fit, minmax(260px, 1fr))` y con tres tarjetas eso
 * da tres, dos o una según el ancho. Dos es la mala: la tercera se queda sola en
 * la segunda fila, a media anchura, con un hueco del mismo tamaño al lado. Y no
 * era un caso raro de un ancho suelto: pasaba desde 546 px hasta 875, que es
 * media tableta y todo el teléfono en horizontal.
 *
 * El corte son 875 porque a 876 caben las tres justas: 876 menos los 56 del
 * carril son 820, menos dos huecos de 20 son 780, entre tres son los 260 exactos
 * que pide el `minmax`. Por debajo, una sola columna.
 */
@media (max-width: 875px) {
  .capacidades .rejilla {
    grid-template-columns: 1fr;
  }
}

/* ── El recibo acompaña a las tarjetas ───────────────────────────────────────
 *
 * `.recibo` tiene un tope de 560 px porque un recibo tiene una medida y no debe
 * estirarse sin fin. Pero por debajo de 640 la página es una columna de teléfono
 * y ese tope lo dejaba centrado con hasta 40 px de aire a cada lado mientras las
 * tarjetas de arriba iban pegadas a 3 —medido a 640—. Leídas seguidas, la última
 * sección parecía de otra página.
 */
@media (max-width: 640px) {
  /* El tope va en `width: min(560px, 100%)`, no en `max-width`: la primera
     versión de esta regla anulaba un `max-width` que no existía y no hacía
     absolutamente nada. Solo se vio midiendo la caja. */
  .recibo {
    width: 100%;
  }
}
