/* Storyfeel — landing page.
   Tokens, fonts and the six themes come from legal/legal.css, which is already the shared
   palette for the public pages. This file only adds layout: the landing page is wider and
   more editorial than a legal document, so it cannot reuse .wrap (720px, built for prose).
   .brand and .langbar ARE reused, so the public pages look like one site. */

/* ⚑⚑ FONDO PLANO, sin el degradado rosa. La banda de nubes tiene que fundirse con la pagina
   justo en su borde, y un degradado hace eso imposible de garantizar: hay que reproducirlo dentro
   de la mascara EXACTAMENTE, y basta un will-change o un transform en el camino para que
   background-attachment:fixed se ancle al elemento en vez de a la ventana y aparezca el escalon.
   Con un color plano no hay nada que reproducir: el mismo token a los dos lados del borde. */
body{ background:var(--bg); }

/* ⚑⚑ EL CUERPO EDITORIAL SE DECLARA UNA VEZ. Lo usan los dos parrafos de la seccion 2 y la
   entradilla de «A rating out of five», y tienen que medir lo mismo. Escrito dos veces acabarian
   separandose el dia que alguien retoque uno: no es hipotetico, la entradilla ya iba por su cuenta
   en 16px mientras estos dos estaban en 24.3, y ese desnivel es lo que se veia mal. */
:root{ --paso-cuerpo: clamp(1.05rem, 1.9vw, 1.6rem); }

/* legal.css styles .doc as a document CARD (surface, border, padding) and paints every link
   inside it --rose-deep. Both are correct for a legal page and wrong here: this page is
   full-bleed sections, not a document. The link rule was not merely cosmetic — `.doc a` is
   (0,1,1) and silently beat `.cta` (0,1,0), so the primary button rendered its label in the
   same colour as its own background: a solid pill reading nothing at all. .doc has to stay,
   because legal.js toggles .doc[data-lang] to switch languages. */
.doc{ background:none; border:0; box-shadow:none; padding:0; border-radius:0; }
.doc a.cta{ color:var(--cta-ink); }
.doc a.cta.ghost{ color:var(--ink); }
.doc a.cta.ghost:hover{ color:var(--rose-deep); }

.lwrap{ max-width:1040px; margin:0 auto; padding:28px 22px 0; }
.lsection{ max-width:1040px; margin:0 auto; padding:0 22px; }

/* ---------- hero ---------- */
.hero{ text-align:center; padding:44px 0 0; }
/* Says what this IS, in three words, before the headline asks anything. A poetic opening buys
   attention and spends clarity: without this a first-time reader met a question, a paragraph
   about stories and a promise about a "companion" before learning it is an app for keeping a
   reading diary. Small and quiet on purpose — it informs, it does not compete. */
.hero .eyebrow{
  font-size:0.8rem; font-weight:700; letter-spacing:.14em; text-transform:uppercase;
  color:var(--rose-deep); margin:0 0 14px;
}
/* Names the reader by what they DO, not by a demographic. Two jobs, and the second matters as
   much: the right person recognises themselves, and the wrong person leaves.
   It sits ABOVE the buttons and carries the display face, because a line that decides whether
   somebody clicks cannot be a footnote underneath the thing they were deciding about. Italic and
   ink-weight so it reads as a statement closing the argument, not as small print. */
.hero .cta-who{
  font-family:var(--font-display); font-style:italic; font-weight:500;
  font-size:clamp(1.05rem, 2.2vw, 1.3rem); line-height:1.45; color:var(--ink);
  max-width:36ch; margin:52px auto 0; text-wrap:balance;
}
.hero h1{
  font-family:var(--font-display); font-weight:600; color:var(--ink);
  /* clamp rather than breakpoints: the line is the page's whole first impression and it must
     never break in a way that strands one word on its own line */
  /* Sized to hold the whole sentence on ONE line down to about 600px: 39 characters at ~0.47em
     each is ~18em, which fits the 1040px column at 3.05rem. Below that the vw term shrinks it,
     and on a small phone it is allowed to wrap rather than become unreadably small. */
  font-size:clamp(1.75rem, 5.4vw, 3.6rem); line-height:1.12; letter-spacing:-.02em;
  text-wrap:balance;
  margin:0 auto 16px; max-width:26ch;
}
.hero .lede{
  font-size:clamp(1rem, 2vw, 1.2rem); line-height:1.62; color:var(--ink-soft);
  max-width:62ch; margin:0 auto 18px; text-wrap:pretty;   /* widened with the headline */
}
.hero .lede:last-of-type{ margin-bottom:26px; }
.hero .lede strong{ color:var(--ink); font-weight:600; }

.cta-row{ display:flex; gap:12px; justify-content:center; align-items:center; flex-wrap:wrap; }

/* ⚑ Aire debajo de los botones de los planes, que son lo ultimo de la pagina antes del pie.
   Se cuelga de `.doc > .lsection:last-child` y no de una clase propia porque esa seccion no
   tiene ninguna: es una `.lsection` mas, y lo unico que la distingue es ser la ultima. Si algun
   dia se anade una seccion detras, el aire se ira con ella — que es lo que se querria, porque lo
   que se esta separando es el final del contenido del pie, no "los planes". */
.doc > .lsection:last-child{ padding-bottom:clamp(28px, 3.5vw, 60px); }

/* ⚑ El retrato entre la caja de privacidad y los planes. El aire va en su propio margen: asi no
   depende del relleno de las secciones vecinas, que son clases compartidas por media pagina.
   ⚑ `var(--radius)` y no un valor inventado: es el mismo redondeo que la caja de privacidad que
   tiene justo encima, que es con lo que se compara al mirarlo. */
/* ⚑ EL -15 px NO ES UN NUMERO SUELTO: es lo que se le quito al aire cuando la foto subio un 10%
   (554 px), para que los 30 px que ganaba de alto salieran de aqui y el bloque entero midiera lo
   mismo que antes. Esa cuenta valia para AQUELLA subida.
   ⚑⚑ LA DE +20% (665 px) NO SE HA COMPENSADO, y es a proposito: se pidio agrandar la imagen, no
   mantener el bloque. Asi que ahora el bloque SI crece — 66 px mas de foto, el mismo aire. Si en
   algun momento se quiere volver a cuadrarlo, el sitio es este y la cuenta es la misma: restar la
   mitad del alto ganado a cada lado.
   ⚑⚑ SIN `@media`, Y SE PROBO CON UNA. Restar el margen solo donde manda el tope en px parece lo
   fino, pero deja un ESCALON: en la franja donde la foto ya ha crecido —ahi manda el `vw`— y el
   margen todavia no ha cedido, el bloque va ganando hasta 29 px y los pierde de golpe al cruzar
   el umbral. Un salto asi al redimensionar se ve; 15 px menos de aire en movil no. Regla unica,
   sin costuras. */
.retrato{ margin:clamp(49px, calc(9vw - 15px), 125px) auto; padding:0; text-align:center; }
/* ⚑⚑ EL HUECO DE ABAJO NO ERA IGUAL AL DE ARRIBA, y no por el margen: por el RELLENO de la
   seccion siguiente. Medido a 1185: 108 px arriba y 172 abajo. Arriba, el margen de la figura
   COLAPSA con el de la caja de privacidad y gana el mayor (108 contra 60), asi que el hueco es
   108. Abajo no hay colapso posible, porque lo que sigue es un `padding-top` de 64 px de
   `.lsection` — y el relleno no colapsa NUNCA: se suma. 108 + 64 = 172.
   Se anula ese relleno solo cuando la seccion viene detras del retrato; asi los dos huecos son el
   margen de la figura y punto. */
.retrato + .lsection{ padding-top:0; }
/* ⚑ Tres subidas, y las tres con la misma pega. 420 -> 504 (+20%), -> 554 (+10%), -> 665 (+20%).
   El tope en `vw` subio una sola vez, de 76 a 86, y ahi se ha quedado: el 20% exacto de la
   primera habria sido 91,2vw, que a 375 px de ancho deja 17 px por lado y se come los margenes de
   la pagina, que son de 22. Las otras dos ni se intentaron — el 20% de ahora seria 103vw, o sea
   mas ancha que la ventana. En escritorio, que es donde manda el tope en px, las tres subidas
   estan enteras; en movil manda el ancho de la ventana y ahi no hay sitio que dar.
   ⚑⚑ Y por eso el umbral SE MUEVE cada vez: el tope en px solo manda por encima de 665/0,86 =
   773 px. Antes eran 644. Consecuencia concreta: una tableta de 768 px en vertical ya cae del
   lado del `vw` y se queda en 660 px — cinco menos que el tope, no se nota, pero la proxima
   subida la dejaria fuera del todo. */
/* ⚑ SIN `border-radius` NI `box-shadow`, y no por gusto: la imagen es un recorte sobre
   transparencia, y una sombra dibuja el RECTANGULO de la caja — es decir, un marco flotando
   alrededor de una figura que no lo llena. Las dos lineas vuelven el dia que vuelva una foto
   rectangular. */
.retrato img{ display:block; width:min(665px, 86vw); height:auto; margin-inline:auto; }
.cta{
  display:inline-flex; align-items:center; justify-content:center;
  /* --cta-bg/--cta-ink en vez de --rose-deep/#fff: el acento es el color de los ENLACES y en
     varios temas no da 4.5:1 con blanco encima. legal.css los define. */
  background:var(--cta-bg); color:var(--cta-ink); border:1px solid var(--cta-bg);
  font-family:var(--font-body); font-weight:700; font-size:1rem;
  padding:14px 30px; border-radius:999px; text-decoration:none;
  box-shadow:var(--card-shadow); transition:filter .15s ease, transform .15s ease;
}
.cta:hover{ filter:brightness(.95); transform:translateY(-1px); }
.cta.ghost{
  background:transparent; color:var(--ink); border-color:var(--line);
  font-weight:600; box-shadow:none;
}
.cta.ghost:hover{ border-color:var(--rose-deep); color:var(--rose-deep); filter:none; }
/* ⚑ Dos escalones arriba en una escala de 1.125: 0.85 x 1.125^2 = 1.076rem -> 1.08rem
   (17.3px en escritorio, antes 13.6). No hay escala tipografica declarada en este fichero, asi que
   "un escalon" se toma como el 1.125 de siempre; si se quiere mas o menos, es el tope del clamp.
   ⚑⚑ Y va en clamp, no en un valor fijo. Fijo en 1.08rem se veia bien en escritorio pero en
   movil quedaba en 17.3px mientras el cuerpo baja a 16.8: la LETRA PEQUENIA acababa siendo mas
   grande que el texto normal, con la jerarquia del reves justo donde menos sitio hay. El minimo
   de 0.95rem la deja por debajo del cuerpo en todo el rango. */
.cta-note{ font-size:clamp(0.95rem, 1.35vw, 1.08rem); color:var(--ink-faint); margin:16px 0 0; }

/* Decorative shelf: pure CSS, no images. It suggests the product without pretending to BE a
   screenshot of it — a fake screenshot would misrepresent what someone is signing up for. */
.shelf{ display:flex; gap:7px; justify-content:center; align-items:flex-end; margin:22px 0 26px; height:64px; }
.shelf i{
  display:block; width:26px; border-radius:3px 3px 1px 1px; background:var(--rose);
  opacity:.55; box-shadow:var(--card-shadow);
}
.shelf i:nth-child(odd){ background:var(--rose-deep); opacity:.42; }
.shelf i:nth-child(1){ height:58px; } .shelf i:nth-child(2){ height:72px; }
.shelf i:nth-child(3){ height:48px; } .shelf i:nth-child(4){ height:66px; }
.shelf i:nth-child(5){ height:76px; } .shelf i:nth-child(6){ height:54px; }
.shelf i:nth-child(7){ height:70px; } .shelf i:nth-child(8){ height:44px; }
.shelf i:nth-child(9){ height:62px; }
@media (prefers-reduced-motion: no-preference){
  .shelf i{ transition:height .3s ease; }
}

/* ---------- section rhythm ---------- */
.lsection{ padding-top:64px; }
/* The gap BELOW the block matches the gap above it (52px), so the hero closes as one unit —
   and stays deliberately smaller than the 64px between later sections, so it reads as the end of
   this block rather than a break from the page. */
.hero + .lsection{ padding-top:52px; }
/* ⚑ Titular y entradilla suben de tamanio. El motivo no es gusto: la entradilla estaba en
   16px justo debajo de la lede de la seccion 2, que mide 24.3px — o sea que el texto MENGUABA al
   bajar por la pagina, y por eso se leia pequenio. Ahora 33.6 -> 43.2px el titular y 16 -> 20.5px
   la entradilla, que la deja por debajo de la lede (sigue siendo secundaria) pero ya en la misma
   escala editorial.
   ⚑ Los `max-width` van en `ch`, no en px: al crecer la letra crece el limite con ella, asi que
   la longitud de linea en CARACTERES no se mueve y no hay que reajustarla a mano. */
/* ⚑⚑ EL `>` ES DELIBERADO Y HAY QUE RESPETARLO: deja fuera el <h2> que va dentro de
   `.quiet` (la seccion de privacidad), que tiene su propio estilo. Por eso no vale cambiarlo por un
   descendiente suelto.
   Y por eso hay que NOMBRAR el envoltorio: al meter el titular y la entradilla dentro de
   `.seccion-mosaico-in` dejaron de ser hijos directos de `.lsection` y perdieron el estilo entero
   —tipografia, centrado, tamanio— sin que nada fallara. Un envoltorio nuevo rompe todos los `>`
   que lo crucen; es la tercera vez que este fichero muerde por ahi. */
.lsection > h2,
.seccion-mosaico-in > h2{
  font-family:var(--font-display); font-weight:600; color:var(--ink);
  /* ⚑⚑ DOS LINEAS COMO MUCHO, EN LOS CUATRO IDIOMAS, Y HACEN FALTA LOS DOS NUMEROS.
     El titular mas largo es el espaniol del mosaico —"Un rating de cinco estrellas nunca fue el
     punto", 47 caracteres frente a 40 del ingles— y se partia en tres.
     ⚑ En escritorio manda `max-width`: 22ch dejaba la caja en 476 px y el espaniol no cabia;
     26ch la deja en 562 y entra en dos.
     ⚑⚑ En el movil `max-width` NO SIRVE PARA NADA, y esto cuesta verlo: `ch` escala CON la
     letra, asi que achicar la fuente achica la caja en la misma proporcion y la cuenta de
     caracteres por linea no se mueve. Medido: a 22, 24 y 26ch salian exactamente las mismas tres
     lineas, y bajando la letra de 29.6 a 22 px tampoco cambiaba nada. Lo que manda ahi es el
     ANCHO DEL CONTENEDOR (331 px en una pantalla de 375), y contra un ancho fijo la letra si
     decide: a 28 px son tres lineas y a 27 son dos. El minimo del clamp baja a 1.68rem (26.9 px)
     para quedar por debajo de ese umbral.
     ⚑ Los 26ch estan elegidos para que en el movil la caja pida ~349 px y por tanto la recorte
     el contenedor: si el `ch` volviera a ser el que manda alli, volveriamos a las tres lineas.
     ⚑ La regla la comparten TODOS los titulares de seccion, asi que en el movil todos bajan ese
     9%. Es a proposito: un titular con otro tamanio solo porque su texto es mas largo se nota mas
     que la escala entera un punto mas baja. De paso arregla el de planes en frances, que tambien
     salia en tres. */
  font-size:clamp(1.68rem, 4vw, 2.7rem); line-height:1.18; text-align:center;
  margin:0 auto 14px; max-width:26ch;
}
.lsection > .sub,
.seccion-mosaico-in > .sub{
  text-align:center; color:var(--ink-soft);
  font-size:var(--paso-cuerpo); line-height:1.55;
  max-width:56ch; margin:0 auto 38px;
}

/* ============================================================================
   MOSAICO DE PANTALLAZOS
   ----------------------------------------------------------------------------
   ⚑⚑ LAS COLUMNAS DE CADA FILA SON LAS PROPORCIONES DE SUS DOS IMAGENES, y eso no es
   decoracion: son capturas de una interfaz, y recortarlas para que encajen en una caja fija
   cortaria botones y texto. Si las dos columnas se reparten en proporcion a la relacion de aspecto
   de cada imagen, las dos salen EXACTAMENTE con el mismo alto y cada una llena la suya sin recorte.
   La cuenta: ancho util = W - hueco; columna_i = util * r_i/(r1+r2); alto_i = columna_i/r_i =
   util/(r1+r2), que no depende de i. Por eso quedan iguales, no por ajuste a ojo.
   ⚑ El zoom sale del CENTRO DE LA FILA, no del centro de cada tesela: a cada una se le calcula
   un transform-origin distinto que cae en el mismo punto (lo hace sky.js). Escalando cada una
   contra su propio centro, se verian dos zooms sueltos en vez de una fila que se abre. Es el mismo
   problema —y la misma solucion— que el bloque del hero.
   ⚑ `scale(0)` no cambia la MAQUETACION, asi que la fila ya ocupa su alto final antes de
   aparecer: no hay salto de contenido cuando entra.
   ============================================================================ */
/* ⚑⚑ EL MOSAICO SE SALE DE SU SECCION. Va dentro de una .lsection, que mide 1040px como
   mucho, y se pide que ocupe el 65% de la PAGINA. `width:65vw` a secas no bastaria: el bloque
   seguiria empezando donde empieza el contenido de la seccion y se iria hacia la derecha. El
   margen negativo `calc(50% - 32.5vw)` lo recentra — el 50% es del ancho del padre, asi que lleva el
   borde izquierdo al centro de la seccion y de ahi retrocede media anchura propia.
   ⚑ Los dos numeros van SIEMPRE emparejados: el margen es la mitad del ancho, con signo menos.
   Si un dia se cambia el 65, hay que cambiar el 32.5.
   ⚑ `vw` cuenta la barra de desplazamiento y el 50% no, asi que en un navegador con barra
   visible el centrado se desvia media barra (~7px sobre 1280). Medido y aceptado: es menos de lo
   que se nota, y las alternativas exactas obligan a partir la seccion en dos. */
/* ⚑ El aire con la entradilla se sube AQUI y no en el margen inferior de `.sub`: esa regla la
   comparte la otra seccion («It looks like you»), y tocarla separaria tambien su parrafo. Puesto en
   el mosaico, solo afecta al mosaico.
   ⚑ Son hermanos en un contenedor de bloque, asi que los dos margenes se funden en el mayor:
   el hueco que se ve es este numero, no la suma. De 38 a 72px en escritorio. */
/* ⚑⚑ EL AIRE DE ABAJO ES LO QUE DEJA LEER LA ULTIMA FILA, y por eso es tan grande. Este
   margen no separa el mosaico del final de su seccion: la arboleda sube con un margen NEGATIVO
   y los dos se funden, asi que el hueco real que queda es la RESTA. Con los 130px de antes menos
   los 115 que sube la arboleda quedaban 14 px — medido —, y con 14 px la ultima fila solo se veia
   entera en un unico punto del scroll, con su borde inferior a 885 en una ventana de 900 y la
   hierba entrando justo detras. La fila llegaba a abrirse del todo, si; lo que no habia era un
   momento en que se pudiera MIRAR abierta del todo.
   Subido a 17vw el hueco pasa de 14 a ~130 px a 1440, y la ventana en la que la fila se ve entera
   y despejada deja de ser un punto para ser un tramo.
   ⚑ Si se toca el margen negativo de `.arboleda`, hay que volver aqui: lo que importa no es
   ninguno de los dos numeros, es su diferencia. */
.mosaico{ display:grid; gap:clamp(10px, 1.1vw, 18px);
  margin:clamp(48px, 5.6vw, 76px) auto clamp(96px, 17vw, 260px);
/* ⚑⚑ EL 65vw LLEVA TOPE. El parrafo de encima mide `max-width:56ch` con la letra en un
     clamp, asi que DEJA DE CRECER: medido, se planta en 860 px y ahi se queda a 1600 y a 2560.
     El mosaico no se plantaba en nada, y por eso en una pantalla grande no es que fuera ancho
     —era que se iba separando del parrafo: 1.21 veces su ancho a 1585 px, 1.93 a 2545. Las dos
     piezas son la misma columna de lectura y tienen que guardar la proporcion.
     El tope sale de esa proporcion, no de un numero bonito: en la imagen de referencia el
     mosaico mide ~1.5 veces el parrafo, y 1.5 x 860 = 1290. La razon es invariante a la escala,
     asi que da igual que la referencia estuviera recortada o reducida.
     El tope entra a partir de 1985 px de ventana (65vw = 1290); por debajo no cambia una coma.
     ⚑ `min()` va TAMBIEN en el margen, y con la mitad justa: la caja se sale de `.lsection`
     (1040 px) con un margen negativo, y ese margen es lo que la centra. `50% - 32.5vw` solo
     centra mientras el ancho sea 65vw; en cuanto el ancho se topa hay que topar la mitad igual,
     o la caja se queda descentrada justo en las pantallas para las que es el arreglo. */
  width:min(65vw, 1290px); max-width:none;
  margin-inline:calc(50% - min(32.5vw, 645px)); }
.mosaico-fila{ position:relative; display:grid; gap:clamp(10px, 1.1vw, 18px); }
/* Las proporciones de cada pareja, en el orden en que van en el HTML. */
.mosaico-fila.f1{ grid-template-columns:1.714fr 0.775fr; }
.mosaico-fila.f2{ grid-template-columns:0.871fr 1.506fr; }
.mosaico-fila.f3{ grid-template-columns:1.314fr 1.252fr; }
/* ⚑⚑ LA FILA SE ESCALA COMO UN SOLO BLOQUE. De ahi sale, gratis, el zoom "desde el centro de
   la fila" que se pedia: una caja que se escala contra su propio centro ya crece hacia dentro. La
   version anterior escalaba las teselas UNA A UNA y le calculaba a cada una un transform-origin
   corrido para simular ese centro — cuentas que se desajustaban en cuanto algo movia la
   maquetacion. Esto es lo que hace `.tiles-row` en zainabkabira.com, copiado tal cual.
   ⚑ Arranca a la MITAD y a 0.35 de opacidad, no en cero: desde cero la fila aparece de la nada
   y da un golpe seco; desde la mitad se lee como que se acerca.
   ⚑⚑ EL VALOR POR DEFECTO ES 1, y es la unica diferencia deliberada con la referencia (alli es
   0). Si sky.js no llegara a correr, las seis capturas se ven ENTERAS Y QUIETAS, en vez de
   quedarse a media escala y medio transparentes para siempre. El JS solo puede empeorar una vista
   que ya es correcta, nunca dejar la seccion rota. Y no se ve ningun salto al cargar porque el
   mosaico nace fuera de pantalla: el primer fotograma lo coloca antes de que nadie mire. */
.mosaico-fila{
  --revelado:1;
  transform:scale(calc(0.5 + 0.5 * var(--revelado)));
  transform-origin:center center;
  opacity:calc(0.35 + 0.65 * var(--revelado));
  will-change:transform, opacity; }
.mosaico-tesela{
  position:relative; margin:0; overflow:hidden;
  border-radius:clamp(10px, 1vw, 16px); background:var(--surface); }

/* La ficha de cada captura: lo que antes eran las tarjetas de debajo, ahora dentro de su imagen.
   ⚑⚑ Solo con `@media (hover:hover)`. En una pantalla tactil no hay "pasar por encima": la
   ficha se quedaria escondida para siempre y con ella el texto, que ya no esta en ningun otro
   sitio de la pagina. Ahi se muestra fija, debajo de la imagen, y no encima.
   ⚑ `aria-hidden` NO se usa aqui: este texto ya no esta duplicado en ninguna tarjeta, asi que
   esconderlo del lector de pantalla seria perderlo. */
/* ⚑ Centrado en los dos ejes: `justify-content` reparte en vertical y `align-items` en
   horizontal. `text-align` solo centraria las LINEAS dentro de cada caja; sin `align-items`, las
   cajas seguirian ocupando todo el ancho y el parrafo, que lleva `max-width`, quedaria pegado a la
   izquierda con sus lineas centradas dentro — que se nota y queda peor que no centrar nada. */
.tesela-info{
  position:absolute; inset:0; display:flex; flex-direction:column;
  justify-content:center; align-items:center;
  padding:clamp(14px, 2.2vw, 34px); margin:0; text-align:center; }
/* ⚑ Dos escalones arriba en la escala de 1.125 (x1.2656), aplicados a los tres tamanios por
   igual para que la jerarquia interna de la ficha no cambie. */
.tesela-info .tag{
  display:inline-block; font-size:clamp(0.78rem, 0.91vw, 0.91rem); font-weight:700;
  letter-spacing:.09em; text-transform:uppercase; color:var(--rose-deep); margin:0 0 10px; }
.tesela-info h3{
  font-family:var(--font-display); font-weight:600; color:var(--ink);
  font-size:clamp(1.27rem, 1.9vw, 1.84rem); line-height:1.25; margin:0 0 10px; }
.tesela-info p{
  font-size:clamp(1.04rem, 1.27vw, 1.27rem); line-height:1.55; color:var(--ink-soft);
  margin:0 auto; max-width:44ch; }

@media (hover: hover){
  /* ⚑ `color-mix` en vez de un rgba a mano: el fondo tiene que ser el MISMO token de
     superficie en dia y en noche, y un rgba fijo obligaria a mantener dos. */
  .tesela-info{
    background:color-mix(in srgb, var(--surface) 66%, transparent);
    opacity:0; transition:opacity .3s ease; }
  /* ⚑⚑ EL DESENFOQUE SOLO MIENTRAS SE SEÑALA. Declarado en la regla de arriba, las SEIS
     fichas mantienen un `backdrop-filter` permanente aunque esten a opacidad 0: cada uno obliga a
     una capa compuesta y a releer el fondo que tiene detras, y es de las cosas mas caras que se
     pueden dejar encendidas. Medido: ocho elementos con backdrop-filter en reposo, seis de ellos
     invisibles. Aqui abajo solo existe el del que se esta senalando. */
  .mosaico-tesela:hover .tesela-info,
  .mosaico-tesela:focus-within .tesela-info{
    opacity:1;
    -webkit-backdrop-filter:blur(16px) saturate(1.15);
    backdrop-filter:blur(16px) saturate(1.15); }
}
@media (hover: none){
  /* Sin raton: la ficha va debajo de la imagen, siempre visible. */
  .mosaico-tesela{ display:flex; flex-direction:column; }
  .tesela-info{ position:static; padding:14px 16px 18px; }
  .mosaico-tesela img{ height:auto; }
}
/* ⚑⚑ EL JS SOLO ESCRIBE UN NUMERO, `--revelado`, y el CSS de arriba decide que significa. La
   escala sigue atada a la POSICION de la fila, que es lo que hace que subir sea la pelicula al
   reves: cada pixel de scroll devuelve la escala por donde vino, sin estado que pueda quedarse
   pegado ni direccion que adivinar. */
.mosaico-tesela img{ display:block; width:100%; height:100%; object-fit:cover; }

@media (max-width:640px){
  /* ⚑ En movil las dos de una fila no caben con dignidad: se apilan y cada una recupera su
     propia proporcion. */
  .mosaico-fila.f1, .mosaico-fila.f2, .mosaico-fila.f3{ grid-template-columns:1fr; }
  .mosaico-tesela img{ height:auto; }
  /* ⚑⚑ Y APILADAS, EL ZOOM SE MUDA A LA TESELA. Una fila apilada mide dos capturas de alto:
     escalarla entera significaria que la de abajo empieza a abrirse cuando todavia no ha asomado y
     termina cuando ya se esta yendo. Cada tesela se revela por su propio borde, una detras de
     otra. La referencia hace exactamente este mismo desdoble en su breakpoint de 640. */
  .mosaico-fila{ transform:none; opacity:1; will-change:auto; }
  .mosaico-tesela{
    --revelado:1;
    transform:scale(calc(0.5 + 0.5 * var(--revelado)));
    transform-origin:center center;
    opacity:calc(0.35 + 0.65 * var(--revelado));
    will-change:transform, opacity; }
}
@media (prefers-reduced-motion: reduce){
  /* ⚑ Quien pide menos movimiento ve el mosaico entero y quieto. La marca la lee tambien
     sky.js, que ni siquiera llega a escribir el numero; esto es el cinturon de seguridad. */
  .mosaico-fila, .mosaico-tesela{ --revelado:1 !important; transform:none !important; opacity:1 !important; }
}

/* ⚑ Aqui vivian las seis tarjetas `.benefit`. Su texto no se ha perdido: esta dentro de las
   capturas del mosaico (`.tesela-info`), que es donde se pidio ponerlo. Se quitan porque tenerlo
   en los dos sitios era decirlo dos veces en la misma pantalla. */

/* ---------- the privacy block: the one that carries the whole pitch ---------- */
/* ⚑ El aire de arriba y abajo va en el MARGEN de la caja, no en el relleno de la seccion:
   `.lsection` es una clase compartida por media pagina y tocarle el relleno movería secciones que
   no tienen nada que ver con esta. */
/* ⚑ Sin caja: el texto va directo sobre el fondo de la pagina. Fuera el `background`, el borde,
   el redondeo y la sombra — los cuatro eran la caja.
   ⚑⚑ Y FUERA TAMBIEN EL RELLENO VERTICAL, que era lo que separaba el texto del BORDE de la caja.
   Sin caja no separa de nada: se sumaba al margen y engordaba los dos huecos ~53 px cada uno.
   Medido a 1185 antes de quitarlo: 177 px de la arboleda al titular y 161 de las pastillas al
   retrato, de los cuales 52.8 eran este relleno. El horizontal SI se queda: ese sigue haciendo
   falta para que el texto no toque los bordes en pantallas estrechas. */
.quiet{
  padding:0 clamp(26px, 3vw, 44px);
  margin-block:clamp(34px, 5vw, 86px);
  /* ⚑⚑ LA CAJA SE SALE DE LOS 1040 DE `.lsection`, y no es capricho: con el parrafo al tamanio
     de cuerpo de la pagina, a partir de 1425 de ventana la fuente llega a su tope (1.6rem) mientras
     el interior de la caja se quedaba en ~910 px, y el parrafo se iba a CINCO lineas. Medido. Para
     que quepa en cuatro con la fuente ya al maximo hace falta cerca de 1020 px de texto, o sea unos
     1110 de caja. Misma tecnica que el mosaico y el carrusel: ancho propio y `margin-inline`
     negativo, que la deja centrada sin sacarla del flujo. */
  width:min(1160px, 94vw); max-width:none;
  margin-inline:calc(50% - min(580px, 47vw));
  text-align:center;
}
.quiet h2{
  font-family:var(--font-display); font-weight:600; color:var(--ink);
  font-size:clamp(1.6rem, 3.5vw, 2.35rem); line-height:1.22; margin:0 auto 18px; max-width:20ch;
}
/* ⚑ `--paso-cuerpo`, el mismo tamanio que los demas parrafos de la pagina: este iba en 1rem
   fijo y se leia mas pequenio que todo lo que tiene alrededor. El ancho se ajusta abajo. */
.quiet p{ color:var(--ink-soft); font-size:var(--paso-cuerpo); line-height:1.6;
  /* ⚑⚑ EN `ch` Y NO EN PIXELES, y es lo que sostiene las cuatro lineas. `ch` es el ancho del
     "0" de la fuente, asi que un ancho en `ch` guarda el mismo numero de CARACTERES por linea sea
     cual sea el tamanio: el recuento de lineas deja de depender del ancho de la ventana. A 66ch el
     parrafo cabe en cuatro de punta a punta del rango.
     ⚑ Lo probe antes con 78ch, dejando que mandara el interior de la caja, y salian TRES lineas
     en ventanas medianas: en pixeles el parrafo crece mas deprisa que la fuente y le caben mas
     palabras. La caja ancha esta para no RECORTAR estos 66ch cuando la fuente llega a su tope
     —a 1425 los 66ch piden 1016 px y el interior viejo daba 910, y ahi se iba a cinco—, no para
     que el parrafo la llene. */
  max-width:66ch; margin:0 auto; }
.quiet .nots{
  display:flex; gap:12px; justify-content:center; flex-wrap:wrap; margin:clamp(26px, 3vw, 40px) 0 0;
  list-style:none; padding:0;
}
/* ⚑⚑ LAS PASTILLAS PASAN A `--surface`. Iban rellenas de `--bg`, que es EL MISMO color que la
   pagina: dentro de la caja blanca eso las hacia resaltar, pero quitada la caja quedaban rellenas
   del color que tienen detras — o sea sin relleno, un contorno flotando. Con `--surface` vuelven a
   ser una forma.
   ⚑ Y de paso el texto gana: medido, `--ink-soft` sobre `--surface` da 5.09:1 de dia y 8.23:1 de
   noche, contra 4.54 y 9.25 que daba sobre `--bg`. */
.quiet .nots li{
  font-size:clamp(0.9rem, 1.15vw, 1.02rem); font-weight:600; color:var(--ink-soft);
  border:1px solid var(--line); border-radius:999px; padding:7px 15px; background:var(--surface);
}

/* ⚑ Aqui vivia la galeria `.shots` con las seis capturas. Se ha ido el 01-09: las mismas seis
   estan ahora en el mosaico, arriba, y tenerlas dos veces en la misma pagina no tenia sentido.
   Su problema —capturas de 0.78 a 1.71 de proporcion en una rejilla de columnas iguales, que
   obligaba a renunciar al recorte y salia irregular— lo resuelve el mosaico de otra forma: las
   columnas SON las proporciones, asi que encajan sin recortar y sin descuadrarse. */

/* ---------- plans teaser ---------- */
.plans-teaser{
  display:grid; grid-template-columns:repeat(auto-fit, minmax(min(100%, 210px), 1fr)); gap:14px;
  margin-bottom:26px;
}
.pt{
  background:var(--surface); border:1px solid var(--line); border-radius:var(--radius);
  padding:20px 18px; text-align:center; box-shadow:var(--card-shadow);
}
.pt.featured{ border-color:var(--rose-deep); }
.pt h3{ font-family:var(--font-display); font-weight:600; font-size:1.05rem; color:var(--ink); margin:0 0 6px; }
.pt .amount{ font-family:var(--font-display); font-size:1.75rem; font-weight:600; color:var(--ink); }
.pt .period{ font-size:0.82rem; color:var(--ink-faint); }
.pt p{ font-size:0.85rem; line-height:1.5; color:var(--ink-soft); margin:8px 0 0; }
.pt .badge{
  display:inline-block; font-size:0.66rem; font-weight:700; letter-spacing:.08em;
  text-transform:uppercase; color:var(--cta-ink); background:var(--cta-bg);
  border-radius:999px; padding:3px 10px; margin:0 0 8px;
}

/* ---------- footer ---------- */
/* ⚑⚑ EL PIE SE MUDO A `footer.css`. Lo llevan TODAS las paginas publicas —portada, contacto,
   los cuatro legales y la baja de correo— y esta hoja no: cargar `landing.css` entera en un
   documento legal le cambiaria la tipografia y la maquetacion, porque comparten clases (`.doc`,
   `.lsection`, `h2`...). El pie vive ahora en su propia hoja, que es lo unico que necesitan. */


@media (max-width:560px){
  .hero{ padding-top:26px; }
  .lsection{ padding-top:48px; }
  /* ⚑ Solo el relleno HORIZONTAL, como en la regla base: el vertical se quito al quitar la
     caja, y este atajo lo resucitaba —28 px— solo en pantallas estrechas. Segunda vez hoy que un
     `padding` completo dentro de una media query deshace lo que la regla base decidio. */
  .quiet{ padding:0 20px; }
  .shelf{ height:60px; } .shelf i{ width:20px; }
}

/* ===== EL HERO, A PANTALLA COMPLETA =====
   ⚑ La foto va en <img srcset> y no en background-image: asi el navegador elige el ancho de ESA
   pantalla y un movil no se descarga la de 2560. No es un detalle — el cielo nocturno original
   pesa 7,5 MB y aqui son 262 KB. */
/* ⚑⚑ EL HERO SE CLAVA CON `sticky`, NO ANIMANDO UN DESPLAZAMIENTO. Antes se clavaba
   sumandole `translate3d(0, scrollY)` con la linea de tiempo de scroll: una CANCELACION de dos
   numeros grandes que tiene que salir exacta en cada fotograma. Medido en el navegador (bloqueando
   el hilo principal a proposito y mirando el hero): esa animacion NO iba por el compositor, asi
   que la cancelacion llegaba tarde y el error se veia entero como saltos verticales. Un fotograma
   tarde en una ESCALA es un error de tamanio de menos de un pixel; un fotograma tarde en una
   POSICION es todo el desplazamiento de ese fotograma.
   `sticky` no es una animacion: es maquetacion, la resuelve el compositor con el mismo
   desplazamiento que acaba de aplicar, y no hay nada que pueda retrasarse. Es lo que hace
   zainabkabira.com, que fue la referencia desde el principio: `.hero{position:sticky;top:0}` y lo
   siguiente le pasa por encima. Lo unico que sigue animandose con el scroll es la escala y la
   opacidad, que es justo lo que la referencia anima. */
/* ⚑⚑ `z-index:0` NO SOBRA: es lo que hace que el envoltorio CREE UN CONTEXTO DE APILADO. Con
   `z-index:auto` no lo crea, y entonces el `z-index:1` del hueco de dentro no se queda dentro —
   compite en el nivel de arriba, le gana a `.seccion-mosaico` (que es z-index 0) y le tapa el
   titular. Se veia justo eso: el hueco pintando crema por encima de "A rating out of five".
   Con el contexto creado, ese 1 solo ordena a los hermanos de dentro (hero < hueco < banda) y el
   envoltorio entero se coloca como un bloque en z 0, por debajo de todo lo que viene despues:
   `.seccion-mosaico` (z 0 pero posterior en el documento), la arboleda (1) y `.sf-story` (4).
   ⚑ Y sigue tapando los bordes, que era el motivo de que el hueco pinte: por los lados, donde
   `.seccion-mosaico` no llega por su `max-width`, lo que se ve es el hueco — que esta por encima
   del hero, aunque el grupo entero este por debajo de la seccion. */
.hero-fijador{ position:relative; z-index:0; }
/* ⚑⚑ EN FLUJO, NO COMO RELLENO DEL ENVOLTORIO. `sticky` recorre la CAJA DE CONTENIDO de su
   contenedor y el relleno esta fuera de ella: con `padding-bottom` el hero tenia recorrido CERO y
   no se clavaba nada —comprobado, se movia 1:1 con la pagina—. Un hermano con alto de verdad si
   agranda esa caja. */
/* ⚑⚑ Y ADEMAS TAPA, porque es lo unico de ese tramo que ocupa TODO EL ANCHO. El hero, una vez
   suelto, se sigue pintando hasta el final del envoltorio; si algo de ahi abajo no lo cubre, asoma
   el cielo. Lo intente pintando las secciones siguientes y se veia el cielo por los DOS BORDES:
   `.seccion-mosaico` es una `.lsection`, o sea `max-width:1040px; margin:0 auto`, asi que su fondo
   solo tapa la columna central. Este hueco no tiene max-width y cubre exactamente el tramo que
   sobra, de punta a punta.
   ⚑ `z-index:1` para pintar POR ENCIMA del hero, que es `sticky` y por tanto crea su contexto en
   z auto. Se queda por debajo de la banda (z 3), asi que el recorte de nubes sigue dejando ver el
   cielo, y por debajo de `.sf-story` (z 4). No tapa nada que se tuviera que ver: todo lo que cubre
   ya lo cubria `.sf-story`, salvo justo la cola que se escapaba. */
.hero-trecho{ height:var(--hero-fijado, 0px); pointer-events:none;
  position:relative; z-index:1; background-color:var(--bg); }
.hero-sky{ position:sticky; top:0; min-height:100svh; display:flex; flex-direction:column;
  align-items:center; justify-content:center; overflow:hidden; isolation:isolate;
  padding:182px 24px 88px; text-align:center; }
/* ⚑⚑ El relleno de abajo lo marca LA BANDA DE NUBES, no el gusto. La banda mide ancho/3.06, o
   sea 32.7vw, y el contenido va centrado en lo que queda por encima: sin esto las nubes le comian
   253px al titular — medido — porque centrar en el hero entero ignora que el tercio de abajo ya
   esta ocupado. 26vw deja al titular rozando la primera nube, que es como se apoya en el original. */
/* ⚑⚑ El bloque baja 50px SIN que el hero crezca: +50 arriba y -50 abajo. Si solo se sumara
   arriba, el hero —que mide por su contenido, no por la ventana— crecería 50px y se llevaria
   consigo la banda de nubes y la seccion 2, o sea que bajaria todo en vez del bloque.
   ⚑ Los 50 caben: en reposo habia 86px entre el pie del titular y el borde de las nubes
   (medido), asi que quedan 36. Menos margen que este ya empezaria a rozar.
   ⚑ Esto NO toca el movil: el bloque de ≤900px vuelve a poner el padding entero con la forma
   corta, asi que alli manda aquel y la version movil se queda como estaba. */
.hero-sky{ padding-bottom:calc(max(96px, 33vw) - 50px); }
/* ⚑ La capa se hace mas grande que el hero (-6% por cada lado) para que la deriva no llegue
   nunca a ensenar el borde de la foto. */
/* ⚑⚑ SIN `will-change` EN LAS DOS CAPAS GRANDES DEL CIELO, y es contraintuitivo. Cada una
   mide 1.16 megapixeles, o sea 2.32 de los 2.47 que la pagina mantenia promovidos a capa
   permanente. Esas son justo las capas del hero: las que el navegador tira cuando te alejas mucho
   —el sintoma aparecia al llegar abajo del todo, y al alargar la pagina se adelanto a la seccion
   de planes— y las que tiene que reconstruir al volver, que es cuando se ven los saltos.
   `will-change` no las protege: es una PROMESA, y cuando se pide mas de lo que cabe el navegador
   deja de hacer caso a todas. Quitandola no hay capa permanente que tirar: la del scroll se
   promueve sola mientras la animacion corre (que es solo en los primeros 775px de scroll) y la de
   la deriva mientras esta a la vista. Fuera de ahi no hace falta ninguna.
   ⚑ La deriva es una animacion infinita de CSS: se promueve sola mientras corre, asi que el
   `will-change` era redundante ademas de caro. */
/* ⚑⚑ `will-change` VUELVE, y manda la traza. Lo quite razonando que menos area promovida era
   mejor; el perfil dice lo contrario para ESTOS elementos. Con el hilo principal ya limpio (scroll
   de 3.39 a 0.13 ms de media) lo que domina es el proceso de GPU —6553 ms— y con el una cifra que
   lo explica: 105 CAPAS CREADAS y 47 destruidas en una sola sesion de scroll, a rafagas (25 en un
   segundo). Eso es promocion BAJO DEMANDA: cada vez que la animacion entra en su tramo se crea la
   capa y se rasteriza, y al salir se tira. Crear una capa de 1.16 megapixeles una y otra vez sale
   mas caro que mantenerla.
   ⚑ La pregunta no era "cuanta area hay promovida" sino "cuantas veces se promueve". Va en lo
   que SE ANIMA con el scroll; en lo que no se anima —las dos imagenes de la arboleda— sigue sin
   ponerse, y ahi si sobraba. */
.sky-photo{ position:absolute; top:0; bottom:0; left:-6%; right:-6%; z-index:-2;
  animation:skyDrift 30s ease-in-out infinite alternate; will-change:transform; }
/* ⚑ Ya no pide capa: `heroCielo` ha desaparecido. La foto se quedaba quieta con su propio
   desplazamiento animado —y de ahi salia el hueco crema, porque se deslizaba dentro de la caja que
   la recorta— y ahora se queda quieta porque el hero ENTERO se queda quieto. Un `will-change` sin
   animacion detras es una capa permanente a cambio de nada. */
.hero-sky .sky-img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
/* ⚑ De derecha a izquierda: empieza desplazada a la derecha y termina a la izquierda, asi que
   lo que se ve es el cielo cruzando hacia la izquierda. `alternate` la devuelve en vez de cortar,
   que en 30 segundos no se lee como vaiven sino como respiracion. */
@keyframes skyDrift{
  from{ transform:translate3d(2.2%,0,0); }
  to  { transform:translate3d(-2.2%,0,0); }
}
:root:not([data-sky="night"]) .sky-night{ display:none; }
:root[data-sky="night"] .sky-day{ display:none; }

/* ⚑ El velo esta por el TEXTO, no por estetica: sobre una foto el contraste no se puede
   garantizar —cada pixel es distinto— y este velo es el unico suelo que hay. De paso disimula el
   bandeado que el WebP deja en los degradados del cielo nocturno. */
.hero-sky::after{ content:""; position:absolute; inset:0; z-index:-1; pointer-events:none; }
:root:not([data-sky="night"]) .hero-sky::after{
  background:linear-gradient(180deg, rgba(255,255,255,.30) 0%, rgba(255,255,255,.06) 42%, rgba(255,255,255,.46) 100%); }
:root[data-sky="night"] .hero-sky::after{
  background:linear-gradient(180deg, rgba(6,9,20,.60) 0%, rgba(6,9,20,.30) 42%, rgba(6,9,20,.72) 100%); }

/* La tinta del hero la manda EL CIELO, no el tema: sobre la foto de dia hace falta tinta oscura
   aunque el tema sea claro, y al reves de noche. Por eso no usa --ink. */

/* ===== la linea de arriba ===== */
/* ⚑⚑ .hero-sky DELANTE, y no por gusto: legal.css trae `.doc p` y `.doc h1`, que son (0,1,1)
   y le ganan a un `.sky-h1` de (0,1,0). El titular salia a 1.9rem —el tamanio de un titulo de
   documento legal— en vez de su clamp(), y la tinta la ponia --ink en vez de --sky-ink. Es EL
   MISMO mecanismo que LANDING.md ya tenia anotado para `.doc a` contra `.cta`; la leccion no era
   sobre los enlaces, era sobre `.doc`: cualquier cosa que se meta dentro de ese div compite con
   selectores de (0,1,1). */
.hero-sky .sky-eyebrow{ display:flex; align-items:center; justify-content:center; gap:9px;
  font-family:var(--font-body); font-size:0.75rem; font-weight:700; letter-spacing:.16em;
  text-transform:uppercase; color:var(--sky-ink); margin:0 0 6px; }
.sky-eyebrow::before{ content:""; width:8px; height:8px; border-radius:50%; background:var(--rose-deep); flex-shrink:0; }

/* ===== el titular =====
   ⚑ clamp() y no media queries: lo que rompe un titular tan largo no son tres anchos concretos,
   son todos los de en medio. */
/* ⚑⚑ DOS lineas y solo dos: cada una es una frase entera y no se parte. El max-width:15ch de
   antes (693px medidos) troceaba "Your Private Diary" en dos y "Companion to Remember" en otras
   dos — tres y pico en total. Con nowrap manda el ancho REAL de la frase mas larga, y el tamanio
   se elige para que quepa: 6.2vw deja "Companion to Remember" en unos 830px dentro de los ~1190
   utiles de una pantalla de 1280.
   ⚑ En movil se deja partir. Con nowrap a la fuerza, la frase larga se saldria de la pantalla
   por mucho que se encoja la letra, y una portada con scroll lateral es peor que un titular en
   tres lineas. */
.hero-sky .sky-h1{ font-family:var(--font-display); font-weight:600; color:var(--sky-ink);
  font-size:clamp(1.15rem, 5.6vw, 5.4rem); line-height:1.04; letter-spacing:-.02em;
  margin:0; max-width:none; }
.sky-h1 .l1, .sky-h1 .l2{ display:block; white-space:nowrap; }
/* ⚑⚑ La SEGUNDA linea no cuenta para el ancho del bloque: width:0 con overflow visible dibuja
   el texto entero pero aporta cero al ancho del padre. Asi el envoltorio se ajusta a "Your Private
   Diary" y es ESA frase la que queda centrada en la seccion, mientras "Companion to Remember" se
   derrama hacia la derecha — que es justo lo pedido.
   Sin esto mandaba la linea larga (818px contra 622) y la primera quedaba 98px a la izquierda del
   centro: el bloque estaba centrado, pero la frase que se lee primero no lo estaba.
   ⚑ El lema cuelga del borde del envoltorio con right:100%, asi que se mueve con el y sigue
   pegado a la primera linea sin tocar nada mas. */
.sky-h1 .l2{ width:0; overflow:visible; }
/* ⚑⚑ ALINEADO A LA IZQUIERDA, y el hueco de la palabra reservado con la MAS LARGA.
   Centrado, cada cambio de palabra cambiaba el ancho de la linea (Read 622px, Feel 592, Remember
   819) y con el bloque centrado eso mueve el titular ENTERO a izquierda y derecha tres veces por
   vuelta — y con el, el lema vertical que cuelga de su borde. Alinear a la izquierda hace que la
   palabra crezca hacia la derecha, que es hacia donde sobra sitio.
   ⚑ El ::after invisible con la palabra mas larga fija el ancho del hueco: sin el, la linea
   seguiria encogiendo con "Feel" y el bloque volveria a bailar, solo que menos. height:0 y
   overflow:hidden para que reserve ANCHO sin ocupar alto. */
.hero-sky .sky-h1{ text-align:left; }
/* ⚑⚑ El molde va EN FLUJO y la palabra encima, no al reves. Antes el ::after era un bloque de
   alto cero con overflow:hidden dentro de un inline-block, y eso le cambia la linea base a la caja
   entera: la palabra quedaba descuadrada respecto a "Companion to". Con el molde como texto en
   linea normal (solo invisible) la linea base la calcula el navegador como con cualquier palabra, y
   la de verdad se superpone en absoluto sin tocar la maquetacion. */
.sky-rot{ display:inline-block; position:relative; }
.sky-rot::after{ content:attr(data-longest); visibility:hidden; pointer-events:none; }
.sky-rot > span{ position:absolute; left:0; top:0; white-space:nowrap; }
/* ⚑⚑ DEBAJO DE 760 EL LEMA VUELVE A HORIZONTAL, encima del titular.
   Antes se escondia con display:none a partir de 900px — de ahi que "se perdiera" al estrechar la
   ventana. Aquella regla es de la primera version, cuando el rail colgaba del borde de la pantalla
   y de verdad no cabia; desde que se ancla al titular, cabe de sobra hasta 760 (medido: a 880 el
   rail entra entero, izquierda en 184 de 880). Esconder algo es la solucion cuando no cabe, no
   cuando ha dejado de no caber.
   ⚑⚑ Y AQUI SE CENTRA EL TITULAR. .sky-titlewrap pasa a display:block, o sea a ocupar todo el
   ancho, y entonces el text-align:left que en pantalla grande sirve para centrar la PRIMERA linea
   —porque el envoltorio se ajusta a ella— aqui la pega al margen izquierdo. Con el envoltorio
   ancho, centrar hay que decirlo. */
/* ⚑⚑ NADA CAMBIA EN MOVIL: ni el centrado ni el ancho. La composicion es "primera linea
   centrada con el logotipo, segunda alineada a su izquierda", y eso solo se sostiene si la segunda
   NO cuenta para el ancho (width:0) y NO se parte (nowrap) — exactamente igual que en pantalla
   ancha. Centrar las dos, como estaba, rompe la alineacion entre ellas; dejar que la segunda mande
   el ancho rompe el eje de la primera con el logotipo. Las dos cosas se arreglan sola si la
   segunda linea CABE, y de eso se encarga el tamanio.
   ⚑ Por eso el suelo del clamp baja a 1.15rem: en un movil la frase larga tiene que caber
   entera desde la izquierda de la primera hasta el margen derecho. Es un titular pequenio, si; la
   alternativa era partir la frase, y entonces ya no hay alineacion que mantener. */
.sky-rot > span{ display:inline-block; transition:opacity .32s ease, transform .32s ease; }
.sky-rot.out > span{ opacity:0; transform:translateY(-.16em); }

/* ===== el logotipo, donde el original pone el reproductor ===== */
/* ⚑ `will-change` aqui y en el titular por la MISMA razon que en las nubes: son los otros
   dos elementos a los que el scroll les reescribe el transform en cada evento, y eran los
   unicos del bloque sin promover a su propia capa.
   ⚑ Sin cifra que lo respalde: se midio el coste del manejador con y sin esto y la medida no
   los distingue (0.78 y 0.51 ms en la MISMA condicion), asi que el banco de pruebas es ruido.
   Se deja por coherencia con las nubes, no por una mejora demostrada. */
.sky-logo{ width:min(420px, 62vw); height:auto; display:block; margin:-.10em auto -.04em;
  position:relative; z-index:2; filter:drop-shadow(0 6px 26px rgba(0,0,0,.18));
  will-change:transform, opacity; }
:root[data-sky="night"] .sky-logo{ filter:drop-shadow(0 6px 26px rgba(0,0,0,.55)); }

/* ===== el rail vertical de la izquierda ===== */
/* ⚑⚑ El rail se centra con top:0/bottom:0 + justify-content y NO con translateY(-50%). El
   paralaje escribe `transform` en este mismo elemento, asi que un transform de maquetacion aqui
   seria pisado en el primer scroll y el rail saltaria media pantalla. Centrar sin transform deja
   el transform libre para lo que se mueve. */
/* ⚑⚑ El rail se ancla AL TITULAR, no al borde de la ventana. Colgado del borde quedaba a 227px
   de la frase en una pantalla de 1280 — medido — y a mas ancho, mas lejos: el lema dejaba de leerse
   como parte del titular y pasaba a ser un adorno del margen. `right:100%` sobre un envoltorio que
   abraza al titular lo deja siempre pegado a su izquierda, mida lo que mida la frase. */
.sky-titlewrap{ position:relative; display:inline-block; will-change:transform, opacity; }
.sky-rail{ position:absolute; right:100%; top:0; bottom:0; margin-right:calc(clamp(14px, 2vw, 30px) + 30px);
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:16px;
  z-index:3; }
.sky-rail-txt{ writing-mode:vertical-rl; text-orientation:mixed; transform:rotate(180deg);
  font-family:var(--font-body); font-size:0.6875rem; font-weight:700; letter-spacing:.34em;
  text-transform:uppercase; color:var(--sky-soft); white-space:nowrap; }
/* La linea va DEBAJO del lema (segundo hijo de la columna), o sea a su base.
   ⚑ En BLANCO, no en --sky-rule. Ese token es tinta oscura al 28% y sobre una foto no se ve; y
   ademas el lema de al lado ya es blanco con sombra, asi que la linea era el unico trazo oscuro
   de la columna. Lleva la misma sombra para que se sostenga sobre cualquier pixel del cielo. */
.sky-rail-line{ width:1px; height:64px; flex-shrink:0;
  background:rgba(255,255,255,.85); box-shadow:0 0 6px rgba(12,26,48,.35); }
/* ⚑ Aqui vivia el icono del libro y la regla que lo escondia al bajar. Las dos se han ido: el
   libro ahora sale de debajo de las nubes y recorre el hilo de puntos, y del desvanecido del rail
   se encarga el paralaje. Dos mecanismos para lo mismo era uno de mas. */

/* ===== las dos nubes de arriba a la izquierda =====
   ⚑ z-index 0 y no -1: a -1 quedarian POR DEBAJO del velo, que arriba es donde mas oscurece
   (0.30), y se verian apagadas justo en la esquina donde viven. A 0 pintan por encima del velo.
   Ahi arriba no hay texto con el que competir — el titular esta centrado y mas abajo, y la barra
   va a z-index 60 — asi que no tapan nada.
   ⚑ De noche NO. Son nubes de dia: sobre un campo de estrellas parecerian una mancha.
   ⚑ Las dos derivan, pero con duraciones distintas y una con retardo negativo. Con el mismo
   ciclo se moverian como una sola pieza y se notaria que son la misma imagen repetida. */
/* ⚑⚑ Cada nube va en un envoltorio porque hay DOS transforms que aplicarle: su deriva propia
   (CSS, en la imagen) y el zoom del bloque (JS, en el envoltorio). En el mismo elemento, el
   segundo que se escribe borra al primero. Es el tercer sitio de esta pagina donde pasa lo mismo:
   la rotacion del lema, la deriva del cielo, y ahora esto. */
.sky-cloud-wrap{ position:absolute; z-index:0; pointer-events:none; display:block;
  will-change:transform, opacity; }
/* ⚑ Mas transparentes, NO desenfocadas: un blur les deshace el contorno y deja de leerse como
   una nube dibujada. Aqui solo baja la opacidad. El SVG ya trae la suya (0.5 en el path), asi que
   este 0.6 se MULTIPLICA por aquella: el resultado real es un 30%. */
.sky-cloud{ display:block; width:100%; height:auto; will-change:transform; opacity:.6; }
/* ⚑⚑ DE NOCHE SE OSCURECEN, y hay que hacerlo con un filtro y no con la opacidad. El dibujo
   es un relleno CREMA (#FFF9E9): bajarle la opacidad lo unico que hace es acercarlo al cielo hasta
   borrarlo — mas palido, nunca mas oscuro. brightness() si mueve el color, asi que la crema se
   convierte en un gris de noche y las nubes pasan a TAPAR estrellas en vez de brillar sobre ellas,
   que es lo que hace una nube de verdad a esas horas.
   ⚑ Y por eso la opacidad SUBE al oscurecerlas: una forma oscura al 60% desaparece, mientras
   que al 78% se lee como sombra. Bajar las dos cosas a la vez habria sido borrarlas. */
:root[data-sky="night"] .sky-cloud{ filter:brightness(.34) saturate(.7); opacity:.78; }
/* ⚑ Tambien de noche, mismo tamanio y mismo sitio. Estuvieron ocultas por precaucion — unas
   nubes claras sobre un campo de estrellas podian quedar como una mancha — pero al 30% real de
   opacidad se leen como jirones altos, que es lo que hay en un cielo nocturno de verdad. */
/* ⚑ 50px mas arriba con calc() sobre el porcentaje: el % mantiene la proporcion en cualquier
   alto de pantalla y el calc le resta una cantidad fija encima. */
/* El sol. Se coloca por su ESQUINA (left/top) y no centrandolo con un transform: ese
   transform lo escribe el zoom del scroll y borraria el de colocacion. Los numeros dejan su
   centro cerca del 27%/25% del hero, que es donde estaba el sol en el cuadro original.
   ⚑ `-50px` igual que las nubes: subieron 50px en su dia y el sol tiene que acompaniarlas o el
   grupo se descuadra. */
/* ⚑ Los 100px van DENTRO del calc y no en un transform: el transform de este elemento lo
   escribe el zoom del scroll y se llevaria por delante cualquier desplazamiento de colocacion.
   ⚑ El ancho es el anterior x0.9 en los tres numeros del clamp (220/32/470 -> 198/28.8/423), asi
   que encoge igual en todo el rango y los dos puntos de corte (687px y 1469px) no se mueven — por
   eso el `sizes` del HTML sigue teniendo los mismos breakpoints. */
/* ⚑⚑ EL ENVOLTORIO DEL ASTRO SE ANIMA CON EL SCROLL COMO SUS TRES HERMANOS, Y ERA EL UNICO
   SIN `will-change`. `heroAleja` mueve a la vez el logotipo, el titular, las nubes y esto; los tres
   primeros pedian capa y este no, asi que era el unico candidato a quedarse en el hilo principal
   mientras los otros iban por el compositor. Un grupo que deberia moverse como una pieza, con un
   miembro yendo por otro camino, es una receta de tirones: el sol se queda medio fotograma detras
   de las nubes justo cuando el hilo principal esta ocupado — y esta seccion tiene debajo el
   mosaico y la arboleda dandole trabajo.
   ⚑ `opacity` tambien, porque `heroAleja` la anima igual que el transform y una pista a medias
   solo cubre la mitad. Por eso se le anade tambien a `.sky-cloud-wrap`, que declaraba unicamente
   el transform. */
.sky-orb-wrap{ position:absolute; left:calc(11% - 100px); top:calc(25% - 50px - 16%);
  width:clamp(198px, 28.8vw, 423px); z-index:0; pointer-events:none; display:block;
  will-change:transform, opacity; }
.sky-sun, .sky-moon{ display:block; width:100%; height:auto; }
/* ⚑ Sol de dia, luna de noche, en el MISMO envoltorio: el sitio no se copia, se comparte, asi
   que no puede quedar uno movido respecto al otro. Se conmuta el <img>, nunca el contenedor.
   ⚑ La luna llena su recuadro entero (radio 100% del ancho) y el sol solo el 82%, porque el
   sprite del sol es sobre todo halo. Con la misma anchura de envoltorio el cuerpo de la luna se ve
   1.21x mas grande que el del sol. Es a proposito: se pidio el mismo SITIO, no el mismo tamanio
   aparente; si se quisiera igualar, es multiplicar los tres numeros del clamp por 0.83. */
:root[data-sky="night"] .sky-sun{ display:none; }
:root:not([data-sky="night"]) .sky-moon{ display:none; }
/* ⚑⚑ La luna se encoge con `transform: scale()` y NO tocando su `width`. Dos razones:
   con scale el origen por defecto es el centro, asi que mengua EN EL SITIO sin tener que compensar
   con margenes (y un margen en % se resolveria contra el ANCHO del envoltorio, que solo coincide
   con el alto por casualidad, porque esta luna es cuadrada); y ademas el transform no cambia la
   maquetacion, asi que el envoltorio conserva su caja y el sol no se entera de nada.
   ⚑ Este transform es del <img> y el del zoom del scroll es del ENVOLTORIO: son elementos
   distintos, se componen y no se pisan. Es la misma separacion que ya obliga a que las nubes lleven
   envoltorio propio. */
.sky-moon{ transform:scale(.65); filter:brightness(.9); }

/* ⚑ Bajar 50px cancela EXACTAMENTE el `- 50px` con el que subieron en su dia, asi que en vez
   de dejar un `calc(17% - 50px + 50px)` que no dice nada, se quedan los porcentajes limpios. El
   sol conserva el suyo: se ha pedido mover las nubes, no el grupo entero. */
/* ⚑ c1 empieza fuera del hero por la izquierda (3% de 1265 son 38px, menos 50 = -12) y se
   corta contra el borde. Es a proposito: una nube cortada por el canto lee como que sigue mas alla
   del encuadre, que es justo lo que hace el resto del cuadro. */
.sky-cloud-wrap.c1{ left:calc(3% - 50px);  top:17%; width:clamp(150px, 22vw, 340px); }
.sky-cloud-wrap.c2{ left:16%; top:30%; width:clamp(88px, 13vw, 200px); }
.sky-cloud-wrap.c1 .sky-cloud{ animation:cloudDrift 44s ease-in-out infinite alternate; }
.sky-cloud-wrap.c2 .sky-cloud{ animation:cloudDrift 61s ease-in-out infinite alternate; animation-delay:-14s; }
@keyframes cloudDrift{
  from{ transform:translate3d(-2%,0,0); }
  to  { transform:translate3d(5%,0,0); }
}

/* ===== la estrella fugaz, solo de noche =====
   ⚑ Vive en el hero y no en el body: una animacion infinita sobre toda la pagina sigue costando
   pintado cuando ya no se ve. */
.sky-star{ display:none; }
:root[data-sky="night"] .sky-star{ display:block; position:absolute; z-index:-1; pointer-events:none;
  /* ⚑⚑ Estos numeros estan MEDIDOS, no calculados. Lo que se ve del cometa no es todo su
     recorrido: el transform va del 0% al 34% de la animacion pero la opacidad solo vale 1 entre el
     6% y el 26%, asi que el trozo visible es ese. Y la animacion es `ease-in`, o sea que en el 16%
     —la mitad de lo que se ve— NO lleva recorrido el 16% del camino, sino bastante menos.
     Intente calcularlo suponiendo avance lineal y el punto medio salio 190px desviado. Lo que
     funciona es pausar la animacion, ponerla en el 16%, medir donde esta y corregir la diferencia.
     Antes empezaba en -10%/-10% y lo visible pasaba por la esquina de arriba a la izquierda. */
  top:22.2%; left:27.3%; width:170px; height:2px; border-radius:2px;
  background:linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba(255,255,255,.85) 78%, #fff 100%);
  filter:drop-shadow(0 0 6px rgba(255,255,255,.75));
  transform:rotate(28deg); opacity:0; animation:skyShoot 9s ease-in infinite; }
/* ⚑ El segundo va por una paralela un poco por encima y por delante, no por la misma linea:
   dos cometas calcando la misma trayectoria se leen como un fallo de repeticion. */
/* ⚑ El segundo pasa 5% por encima y a la izquierda del primero: los dos cruzan cerca del
   centro pero por lineas distintas, que dos cometas calcando la misma trayectoria se leen como un
   fallo de repeticion. ⚑ Ojo al medirlo: lleva 4.4s de retraso, asi que hay que sumarlo al
   `currentTime` o se mide siempre el fotograma cero y parece que no se mueve. */
:root[data-sky="night"] .sky-star.s2{ top:17.2%; left:24.3%; width:120px; animation-delay:4.4s; animation-duration:11s; }
@keyframes skyShoot{
  0%   { opacity:0; transform:rotate(28deg) translate3d(0,0,0); }
  6%   { opacity:1; }
  26%  { opacity:1; }
  34%  { opacity:0; transform:rotate(28deg) translate3d(78vw, 46vh, 0); }
  100% { opacity:0; transform:rotate(28deg) translate3d(78vw, 46vh, 0); }
}

/* ============================================================================
   EL ALEJAMIENTO DEL HERO, EN EL HILO DEL COMPOSITOR
   ----------------------------------------------------------------------------
   ⚑⚑ ESTO ESTABA EN JAVASCRIPT Y POR ESO SE VEIA POR PASOS. El navegador desplaza la pagina
   en el hilo del compositor, o sea inmediatamente; un manejador de `scroll` corre en el hilo
   principal y llega uno o mas fotogramas despues. El resultado es que al mover la rueda el bloque
   se iba PRIMERO con la pagina (su transform todavia era el del fotograma anterior) y volvia a su
   sitio cuando por fin corria el manejador. Eso es exactamente lo que se describe como
   "scroll -> se mueve -> zoom, en ese orden": no son tres efectos, es uno que llega tarde.
   ⚑ Un requestAnimationFrame NO lo arregla: sigue siendo el hilo principal y sigue yendo un
   fotograma por detras. Lo unico que lo quita es que la animacion la lleve el compositor, que es
   lo que hace `animation-timeline: scroll()` — el avance lo marca el propio desplazamiento, asi
   que no puede desincronizarse de el.
   ⚑ La cuenta: el recorrido es lineal sobre [0, R], luego a un scroll `y` el desplazamiento vale
   y*(R/R) = y, que se anula contra el scroll y deja el bloque quieto en pantalla. La escala va de
   1 a 0.75 y la opacidad de 1 a 0 sobre EL MISMO tramo, asi que terminan juntas por construccion.
   R lo mide sky.js (0.95 del alto del hero) y lo escribe COMO NUMERO dentro de los fotogramas y
   del `animation-range`, al cargar y al cambiar la ventana; no se toca al desplazar. Hubo una
   variable `--hero-recorrido` con ese numero y se ha quitado: no la leia nadie, y cada vez que se
   escribia una propiedad personalizada en :root invalidaba el estilo del documento entero.
   ⚑ Y la foto se desplaza AHORA LO MISMO que el bloque (antes iba al 0.82 y se deslizaba 147 px
   por detras). Ese deslizamiento era el otro movimiento que se veia. Ahora lo unico que ocurre al
   bajar es que la pagina pasa y el bloque se aleja: scroll -> zoom, nada mas.
   ============================================================================ */
/* ⚑⚑ LOS FOTOGRAMAS DE ESTAS TRES ANIMACIONES LOS ESCRIBE sky.js, NO ESTE FICHERO, y el
   motivo es de peso: llevaban `var()` dentro del `transform`, y una animacion cuyos valores salen
   de una propiedad personalizada NO SE PUEDE COMPONER — el compositor necesita numeros concretos,
   asi que Chrome la atiende en el hilo principal en cada fotograma. Es lo que salia en la traza
   como `serviceScriptedAnimations`, 6.2 ms por fotograma largo, y la razon de que el hero nunca
   llegara a ir de verdad por el compositor por mucho que se aligeraran las capas.
   ⚑ Comprobar que la linea de tiempo esta viva NO es comprobar que la animacion se compone:
   eso es lo que yo daba por bueno y no lo era.
   Los valores dependen de medidas (el alto del hero, el de la arboleda), asi que se generan con
   numeros reales y se reescriben al cambiar la ventana. Ver `escribirAnimaciones()` en sky.js. */


/* ===== responsive ===== */
@media (max-width:900px){
  .hero-sky{ padding:112px 20px 72px; }
  .sky-logo{ width:min(320px, 74vw); }
}

/* ⚑ Nada de esto es informacion: si alguien pide menos movimiento, se para. La estrella fugaz
   DESAPARECE en vez de quedarse quieta — una raya blanca fija sobre el cielo parece un fallo. */
@media (prefers-reduced-motion: reduce){
  .sky-photo{ animation:none; }
  .sky-cloud{ animation:none; }
  /* ⚑ El alejamiento tambien se para. Antes bastaba con que sky.js se rindiera al entrar; ahora
     que lo lleva el CSS, hay que apagarlo aqui o seguiria corriendo sin preguntar. */
  :root.hilo-scroll .sky-logo,
  :root.hilo-scroll .sky-titlewrap,
  :root.hilo-scroll .sky-orb-wrap,
  :root.hilo-scroll .sky-cloud-wrap{ animation:none; }
  /* ⚑⚑ Y EL HERO DEJA DE CLAVARSE. Antes, con menos movimiento, el hero se iba con la pagina
     como cualquier seccion: la animacion que lo clavaba estaba apagada aqui arriba. Ahora lo clava
     `position:sticky`, que no es una animacion y no se apaga sola, asi que hay que apagarla a
     mano o quien pide menos movimiento veria justo el efecto que ha pedido no ver.
     ⚑ El hueco y los margenes se quedan como estan: se anulan entre si, asi que la pagina mide
     lo mismo y todo cae donde caia. Lo unico que cambia es quien se queda quieto — nadie. */
  .hero-sky{ position:relative; }
  .sky-cloud-wrap, .sky-orb-wrap{ transform:none !important; }
  :root[data-sky="night"] .sky-star{ display:none; }
  .sky-rot > span{ transition:none; }
  .sky-rail{ transition:none; }
}

/* ===== las dos versiones de cada dibujo =====
   Laura entrega el logotipo y el icono en dos tintas, negra y blanca. No se recolorean por CSS
   —son dibujos, no una mascara de una sola tinta como el wordmark de la app— asi que van los dos
   en el HTML y se ensena el que toca. El que no se ve no cuesta descarga: son SVG de 15 KB. */
/* ⚑ El logotipo es el BLANCO en los dos cielos. Sobre la foto de dia el titular ya va en blanco
   con sombra, asi que un logotipo negro al lado era el unico elemento oscuro de todo el bloque.
   La version negra sigue en brand/ para donde haga falta fondo claro de verdad. */

/* ===== la barra de arriba, CLAVADA (solo aqui) =====
   ⚑⚑ Esta es la UNICA regla de la barra que se queda en landing.css, y es la unica que tiene
   que quedarse: el resto —la rejilla de tres columnas, las pastillas, el panel del telefono—
   vive en `public.css` y lo llevan las siete paginas publicas. Lo que cambia SOLO aqui es que
   flota: el hero mide una pantalla entera y una barra en flujo le robaria ese alto. En las
   demas paginas no hay foto detras, la barra va en el flujo donde estaba la vieja `.pubnav`, y
   `public.css` la deja en `position:relative` — que ademas es lo que ancla el panel del movil.
   ⚑ Por eso `public.css` se carga ANTES que esta hoja en la portada: las dos reglas son
   `.skybar` a secas, misma especificidad, y gana la ultima. Si algun dia se invierte el orden
   de los <link>, la barra de la portada deja de flotar y se lleva el hero por delante. */
.skybar{ position:fixed; inset:0 0 auto 0; z-index:60;
  /* ⚑⚑ Y CON TOPE, POR LO MISMO QUE EL MOSAICO. La barra va de borde a borde de la ventana
     y reparte sus tres columnas en `1fr auto 1fr`, asi que el menu queda centrado pero las redes
     y el dia/noche se van a las esquinas: en una pantalla de 2560 acaban a mas de un palmo de
     todo lo demas, solos en dos rincones. El menu no se movia porque esta centrado; los otros dos
     si, porque estan anclados a los bordes.
     El tope los devuelve al ancho de la pagina. `1290px` es lo que mide el mosaico, que es la
     pieza mas ancha que hay; sumandole el relleno propio de la barra (24 por lado) los bordes de
     las pastillas caen JUSTO sobre los bordes del mosaico, asi que las dos cosas comparten
     columna en vez de parecerse. 1290 + 48 = 1338.
     ⚑ `margin-inline:auto` centra de verdad aqui: en una caja fija con `left` y `right` puestos
     —eso son los ceros de `inset`— los margenes automaticos reparten el sobrante a partes
     iguales. Sin ellos la caja se quedaria pegada a la izquierda al ponerle el `max-width`.
     ⚑ EL MOVIL NO SE ENTERA: 1338px no llega a topar en ninguna pantalla de telefono, asi que
     el tramo de 640 —barra en `flex`, boton a la izquierda, redes pegadas al dia/noche— se queda
     exactamente como estaba. */
  max-width:1338px; margin-inline:auto; }

/* ============================================================================
   SEGUNDA PASADA DEL HERO — tinta blanca, letras que giran, punto-cursor y nubes
   ============================================================================ */

/* ⚑ La tinta del titular pasa a BLANCA en los dos cielos. Sobre una foto el contraste no se puede
   calcular —cada pixel es distinto— asi que lo que lo sostiene es la sombra: una dura y pegada que
   dibuja el borde, y una blanda y ancha que separa la letra del cielo. Sin la segunda, el blanco
   sobre las nubes claras de la foto de dia desaparece.
   ⚑ Y por eso el velo del dia deja de ACLARAR la foto: aclarar el fondo de un texto blanco es
   trabajar en contra. Ahora oscurece un poco, como el de la noche pero mucho mas suave. */
.hero-sky .sky-h1, .hero-sky .sky-kicker{
  color:#FFFFFF;
  text-shadow:
    0 1px 0 rgba(12,26,48,.34),
    0 2px 3px rgba(12,26,48,.28),
    0 10px 34px rgba(12,26,48,.42);
}
:root:not([data-sky="night"]) .hero-sky::after{
  background:linear-gradient(180deg, rgba(10,22,44,.30) 0%, rgba(10,22,44,.12) 38%, rgba(10,22,44,.05) 62%, rgba(10,22,44,0) 100%); }
:root[data-sky="night"] .hero-sky::after{
  background:linear-gradient(180deg, rgba(6,9,20,.58) 0%, rgba(6,9,20,.28) 38%, rgba(6,9,20,.18) 62%, rgba(6,9,20,0) 100%); }

/* El lema, vertical y a la izquierda del titular.
   ⚑ writing-mode lo pone en columna y rotate(180deg) lo hace leer de abajo arriba, que es como
   va en el original. Sin la rotacion se lee de arriba abajo y el ojo lo toma por otra cosa. */
.hero-sky .sky-kicker{
  font-family:var(--font-body); font-size:0.6875rem; font-weight:700; letter-spacing:.3em;
  text-transform:uppercase; margin:0; white-space:nowrap;
  writing-mode:vertical-rl; text-orientation:mixed; transform:rotate(180deg); }

/* ⚑ El logotipo sube por encima del titular y crece: ya no compite con la palabra que rota, que
   es lo que pasaba cuando iba entre las dos lineas. */
.sky-logo{ width:min(300px, 54vw); margin:0 auto 22px; }

/* ===== las letras giran al pasar por encima =====
   ⚑ display:inline-block es obligatorio: transform NO hace nada sobre una caja en linea, asi que
   sin esto el giro simplemente no ocurre.
   ⚑ El giro es a la IZQUIERDA (negativo) y de 34 grados, dentro de los 30-40 que se pidieron.
   ⚑ transform-origin al 50% 60%: pivotando en el centro exacto la letra se sale de debajo del
   cursor y el hover parpadea; bajando el eje, la letra bascula y se queda donde estaba. */
/* ⚑ El eje NO va en el centro. Girando por el centro la letra bascula como una aguja y se
   despega de sus vecinas por los dos lados a la vez; con el eje abajo y a la izquierda, el pie de
   la letra se queda donde estaba y lo que se mueve es la parte de arriba — que es lo que se ve en
   la referencia. Tambien ayuda a que la letra no se salga de debajo del cursor. */
.hero-sky .sky-h1 .ltr{
  display:inline-block; transform-origin:22% 82%;
  transition:transform .34s cubic-bezier(.22,.9,.24,1), color .2s ease, text-shadow .2s ease; }
.hero-sky .sky-h1 .ltr:hover{
  /* ⚑ 15% del INTERLINEADO, no del alto de la letra. La linea va a 1.04, asi que 15% de 1.04em
     son 0.156em — en em porque translateY en % se mide contra la caja de la propia letra, que es
     distinta para una "i" que para una "R", y el salto tiene que ser el mismo para todas.
     ⚑ El orden importa: translate primero, rotate despues. Al reves, la letra se desplazaria
     siguiendo su propio eje ya girado y las de arriba saldrian ademas hacia un lado. */
  transform:translateY(-0.156em) rotate(-20deg); color:#F5C518;
  text-shadow:0 2px 4px rgba(12,26,48,.30), 0 12px 30px rgba(12,26,48,.30); }

/* ===== el punto que hace de cursor =====
   ⚑ mix-blend-mode:difference es lo que hace que "cambie de contraste con el fondo": no cambia
   de color por JS, es el navegador restando el pixel de debajo. Sobre cielo claro sale oscuro y
   sobre cielo de noche sale claro, sin una sola linea de logica.
   ⚑⚑ Lo quite el 01-09 pensando que era la causa de los saltos —un elemento fijo que mezcla
   obliga a componer la pagina que tiene detras— y NO lo era: los saltos siguieron igual y el punto
   se quedo en una bolita blanca. Vuelve. Si algun dia hay que quitarlo por rendimiento, que sea con
   una medida que lo demuestre, no con una sospecha.
   ⚑ Solo donde hay un puntero DE VERDAD. En una pantalla tactil no hay cursor que sustituir. */
.sky-dot{ display:none; }
@media (pointer:fine){
  .sky-dot{ display:block; position:fixed; top:0; left:0; width:11px; height:11px; border-radius:50%;
    background:#fff; mix-blend-mode:difference; pointer-events:none; z-index:9999;
    transform:translate3d(-50px,-50px,0); margin:-5.5px 0 0 -5.5px;
    transition:width .18s ease, height .18s ease, margin .18s ease; }
  .sky-dot.on-link{ width:34px; height:34px; margin:-17px 0 0 -17px; }
  :root.has-dot, :root.has-dot *{ cursor:none; }
  /* menos los campos de texto: ahi la barra vertical dice donde se va a escribir */
  :root.has-dot input, :root.has-dot textarea, :root.has-dot select{ cursor:auto; }
  /* ⚑⚑ CON UN <dialog> ABIERTO VUELVE EL CURSOR DE VERDAD. Un modal se pinta en la CAPA
     SUPERIOR, que esta por encima de cualquier z-index — tambien del 9999 del punto. O sea que el
     punto, que es el unico cursor que hay porque `cursor:none` esconde el del sistema, queda por
     DEBAJO del modal: dentro de el no se ve donde se apunta y no hay forma de acertarle a la X.
     Se resuelve en CSS y no en JS a proposito: `[open]` lo pone y lo quita el navegador solo, asi
     que no puede quedarse desincronizado — y menos aun sabiendo que el evento `close` del
     <dialog> no llega (medido). */
  :root.has-dot:has(dialog[open]), :root.has-dot:has(dialog[open]) *{ cursor:auto; }
  :root.has-dot:has(dialog[open]) .sky-dot{ display:none; }
}
@media (prefers-reduced-motion: reduce){
  .sky-dot{ display:none; }
  :root.has-dot, :root.has-dot *{ cursor:auto; }
  .hero-sky .sky-h1 .ltr{ transition:color .2s ease; }
  .hero-sky .sky-h1 .ltr:hover{ transform:none; }
}

/* ===== las nubes que cierran el hero =====
   ⚑ Es una MASCARA, no un adorno: va rellena de var(--bg), asi que el cielo parece terminar en
   nubes y la pagina sigue debajo sin costura. Al cambiar de dia a noche cambia sola, porque el
   relleno es el token del fondo.
   ⚑ preserveAspectRatio="none" aqui SI vale: es una silueta rellena, no un trazo, y estirarla no
   deja ningun grosor irregular a la vista. */
/* ⚑ La proporcion la marca el fichero (1440x471): con aspect-ratio el alto sale del ancho y las
   nubes no se deforman nunca. Estirar la mascara a un alto fijo las aplastaria en pantallas anchas.
   ⚑⚑ SIN max-height. Al ponerle un tope, la caja dejaba de respetar aspect-ratio y la mascara,
   que va a 100% 100%, aplastaba las nubes: medido, 3.44 de proporcion contra el 3.06 del fichero,
   un 11% de achatamiento. Si la banda resulta demasiado alta, lo que hay que mover es mask-size
   (que recorta por los lados) y NUNCA el alto de la caja. */
/* ⚑⚑ LA BANDA BAJA 9vw. Lo que se ve como "hueco" entre las dos secciones no es el relleno de
   la seccion 2: es la propia banda. Mide 32.7vw de alto y solo su parte de ARRIBA es silueta de
   nube — el resto es macizo, y como esta pintado del color de la pagina, se lee como espacio
   vacio. Recortar ese macizo por abajo (sale del hero, que tiene overflow:hidden) sube el borde de
   las nubes hacia el texto sin tocar ni la forma ni la proporcion.
   ⚑ De regalo, la fila transparente del pie del SVG queda fuera del hero, asi que el sellado
   de la segunda capa de mascara pasa a ser cinturon ademas de tirantes. */
/* ⚑⚑ SE COLOCA CONTRA EL ENVOLTORIO, y por eso el `bottom` lleva el trecho de clavado. El
   envoltorio mide el hero MAS `--hero-fijado`; restandole ese trecho, la banda queda otra vez
   6vw por debajo del pie del hero, exactamente donde estaba cuando vivia dentro de el. Asi el
   dibujo en reposo no cambia ni un pixel: lo unico que cambia es QUIEN se queda quieto. */
.sky-clouds{ position:absolute; left:0; right:0; width:100%;
  bottom:calc(var(--hero-fijado, 0px) - 6vw);
  aspect-ratio:1440 / 471;
  /* ⚑⚑ DELANTE del texto. Estuvo detras un rato, para que un bulto de nube no se comiera
     letras, y estaba mal: el paralaje CONSISTE en que la banda se coma el titular al bajar, y
     detras no puede comerse nada. Lo que resuelve el miedo original no es el orden de pintado
     sino el relleno del hero, que en reposo deja el titular por encima del borde de las nubes.
     El unico cruce que queda es el del scroll, y ese se busca. */
  /* ⚑⚑ LA BANDA ENSENIA EL FONDO DE LA PAGINA, no una imitacion suya. Estaba rellena de
     var(--bg), que es el color plano, mientras que el body lleva --app-gradient: un degradado. Dos
     cosas distintas nunca casan, y por eso se veia la juntura justo donde la mascara existe para
     que NO se vea.
     El truco es background-attachment:fixed. Con eso el degradado se coloca respecto a la VENTANA
     y no respecto a la caja, asi que la banda pinta exactamente los mismos pixeles que el body
     pintaria ahi detras: no es que se parezcan, es que son el mismo fondo. */
  /* ⚑ El mismo token que el body, y sin will-change: esta banda no se transforma nunca, y un
     will-change:transform aqui era ademas lo que rompia el anclaje del fondo. */
  background:var(--bg);
  z-index:3; pointer-events:none;
  /* ⚑⚑ DOS CAPAS DE MASCARA, y la segunda no es adorno. La ultima fila de pixeles de
     sky-band.svg es TRANSPARENTE — medido rasterizando el fichero: a 131px de alto, la fila 129 da
     100% de opacidad y la 130 da 0% — y estirada a una banda de 414px eso son ~3px por los que se
     veia la foto del cielo, una raya azul entre la crema de arriba y la de abajo.
     La segunda capa es un rectangulo solido pegado al pie: las capas de mascara se SUMAN, asi que
     sella ese borde sin tocar la silueta. Se pone al 6% — muy por encima de los 3px — porque ahi
     abajo la forma ya es maciza y taparla de mas no cambia nada. */
  -webkit-mask:url("images/sky-band.svg") center bottom / 100% 100% no-repeat,
               linear-gradient(#000,#000) center bottom / 100% 6% no-repeat;
          mask:url("images/sky-band.svg") center bottom / 100% 100% no-repeat,
               linear-gradient(#000,#000) center bottom / 100% 6% no-repeat; }

/* ===== el hilo de puntos y el libro que lo recorre =====
   ⚑ El trazado se DIBUJA EN JS con las medidas reales de la caja. Un viewBox fijo estirado con
   preserveAspectRatio="none" deformaria los puntos —serian ovalos— y ademas getPointAtLength
   devolveria coordenadas del sistema del viewBox y no pixeles, que es lo que hace falta para
   colocar el libro encima. */
/* ⚑⚑ LA BANDA SUBE Y LA SECCION 2 SUBE CON ELLA. El borde de las nubes y la distancia al
   texto estan ATADOS: la banda solo es silueta en su parte de arriba y por debajo hay una cola
   maciza, asi que subir las nubes mete esa cola dentro del hero y el hueco crece otra vez. Bajarla
   —lo de antes— cerraba el hueco pero se llevaba el dibujo hacia abajo.
   Se rompe el nudo moviendo las dos cosas a la vez: la banda sube 6vw y la seccion 2 sube los
   mismos 6vw con un margen negativo. La distancia entre nubes y texto no cambia, y el conjunto
   queda mas arriba.
   ⚑ El z-index es lo que lo hace posible: el hero se aisla (isolation:isolate) y pinta como
   una sola pieza opaca, asi que sin esto el texto de la seccion 2 se meteria DEBAJO de el y
   desapareceria. Con z-index:4 pasa por encima de la cola maciza — que es del color de la pagina,
   asi que no se nota que hay algo debajo. */
/* ⚑⚑ SUBE TAMBIEN EL TRECHO DE CLAVADO. El envoltorio anadio `--hero-fijado` de alto para
   que el hero tenga donde quedarse quieto; si no se descontara aqui, la pagina creceria ese mismo
   trecho y todo lo de abajo llegaria mas tarde. Descontandolo, el alto total del documento y la
   posicion de TODAS las secciones siguientes quedan idénticos a como estaban. */
.sf-story{ position:relative; z-index:4; margin-top:calc(-6vw - var(--hero-fijado, 0px)); }
/* ⚑⚑ TODO LO QUE VA DESPUES DEL HERO TAPA, no solo la primera seccion. Lo puse primero solo en
   `.sf-story` y quedaba una franja de cielo: el envoltorio del hero llega hasta
   `alto del hero + --hero-fijado`, y el hero, ya suelto, se sigue pintando hasta ese final. Si
   `.sf-story` termina ANTES que el envoltorio, por ese hueco se ve el cielo a traves de
   `.seccion-mosaico`, que era transparente. Aqui, de pura casualidad, `.sf-story` acababa 6 px
   despues del envoltorio y no se notaba; en una ventana mas alta el hero crece, `--hero-fijado`
   crece con el, el envoltorio se alarga y el texto de `.sf-story` no — y aparece la franja.
   ⚑ Depender de que una seccion sea "lo bastante alta" no es una solucion, es una coincidencia.
   Tapan todas las hermanas posteriores, y las que se anadan maniana tambien.
   ⚑ `background-color` y no el atajo `background`: el atajo borraria cualquier imagen o
   degradado que una de ellas traiga. Y va con el MISMO token que pinta el body —medido:
   rgb(241,236,227) plano de dia, rgb(10,14,26) de noche— asi que no puede aparecer juntura. */
.hero-fijador ~ *{ background-color:var(--bg); }
/* ⚑⚑ Y TIENE QUE TAPAR, que es lo que se le pedia de mas al clavar el hero con `sticky`.
   Mientras el hero se iba con la pagina daba igual que esto fuera transparente: detras no quedaba
   nada. Ahora el hero SE QUEDA los 775 px del clavado, asi que por un `.sf-story` transparente se
   le veia el cielo —y el fantasma del titular— por detras del texto de la seccion 2.
   ⚑ Se pinta con `var(--bg)`, que es EXACTAMENTE lo que pinta el body: medido en el navegador,
   los dos dan rgb(241,236,227) plano, sin degradado y sin `background-attachment`. No es que se
   parezcan, es el mismo token, asi que no puede aparecer juntura. Y por eso tampoco molesta que
   cubra los ultimos 154 px de la banda, que son de ese mismo color macizo.
   ⚑ Lo que queda por encima —el recorte de nubes de la banda— sigue siendo transparente donde la
   mascara lo es, que es por donde se ve el cielo del hero. El efecto se conserva entero: lo unico
   que cambia es que por debajo del borde de nubes ya no se ve nada. */
/* ⚑ Aqui vivian el hilo de puntos y el libro que lo recorria. Se han quitado enteros el
   01-09 para rehacerlos mas adelante; estan en el historial (`git log -- landing.css`) si hace
   falta recuperar el trazado o la curva. El z-index de abajo se queda: ya no hay hilo del que
   despegar el contenido, pero .sf-story se solapa con la cola del hero y el apilado sigue
   haciendo falta. */
.sf-story > .lsection{ position:relative; z-index:1; }

@media (max-width:900px){
  .sky-logo{ width:min(230px, 62vw); }
}

/* ============================================================================
   SECCION 2 — el texto que ya existia, ahora a escala editorial
   ----------------------------------------------------------------------------
   Ni una palabra cambia: son las mismas ledes, el mismo "para quien", la misma estanteria y los
   mismos botones. Lo que cambia es el aire.
   ⚑ El aire de aqui NACIO siendo funcional: marcaba la duracion del viaje del libro por el hilo
   de puntos (con la seccion en 516px el libro llegaba al final a los 900px de scroll y ahi se
   quedaba). Quitado el hilo el 01-09, estos margenes ya solo son ritmo de lectura. Se dejan como
   estan porque asi se ve bien, pero que nadie los defienda con un motivo que ya no existe.
   ⚑ Los selectores llevan .sf-story delante para ganarle a `.doc p` (0,1,1) de legal.css, que es
   la trampa que ya ha mordido dos veces en esta pagina.
   ============================================================================ */
/* ⚑ El aire de arriba lo marca la banda, que ya trae su propio remate: 18vh dejaban un vacio
   de casi dos dedos entre las nubes y la primera frase. 2vh es lo justo para que el texto no
   arranque pegado.
   ⚑⚑ El de ABAJO ya no es 22vh sueltos. El cierre —la frase, la estanteria, los botones y la
   letra pequenia— tiene que leerse como UN bloque, y para eso el aire de encima y el de debajo
   tienen que medir lo mismo: 17vh. Estaba en 77px arriba contra 306 abajo, o sea cuatro veces mas
   por un lado que por el otro, y por eso el grupo se caia hacia el final de la pagina.
   ⚑ El `- 64px` es la parte que ya pone la seccion siguiente con su propio padding-top: lo que
   se ve entre la letra pequenia y el titular es la SUMA de los dos, asi que hay que descontarlo o
   se pasa. Y el `max(...)` evita que en una ventana muy baja el calculo salga negativo. */
.sf-story .hero-copy{
  /* ⚑ El hueco de ABAJO de este bloque no es solo este relleno: la seccion siguiente aporta sus
     propios 64 px de `padding-top`, y por eso aqui se le restan — asi el hueco de abajo acaba
     valiendo lo mismo que el de arriba (el margen de `.cta-who`) y el bloque se lee como una
     seccion suelta. Los dos se han partido por la mitad: 17vh -> 8.5vh. */
  padding:2vh 24px max(0px, calc(8.5vh - 64px)); text-align:center; max-width:none; }
.sf-story .hero-copy .lede{
  font-family:var(--font-body); font-weight:400;
  font-size:var(--paso-cuerpo); line-height:1.55; color:var(--ink);
  /* ⚑ El hueco entre parrafos lo pone el margen inferior de .lede, asi que este numero manda
     los DOS: primero-segundo y segundo-"para quien". De 16vh a 7vh. */
  max-width:min(920px, 88vw); margin:0 auto 7vh; }
.sf-story .hero-copy .lede strong{ font-weight:700; }
/* ⚑⚑ El aire de ARRIBA del bloque se pone aqui, con un margen superior, y NO subiendo el
   margen inferior de .lede: ese numero manda tambien el hueco ENTRE los dos parrafos, y tocarlo
   los separaria a los dos por igual. Puesto aqui, los margenes contiguos se funden en el mayor
   (17vh gana a 7vh), asi que el hueco entre parrafos se queda como estaba. */
.sf-story .hero-copy .cta-who{
  font-family:var(--font-display); font-weight:600; font-style:italic;
  font-size:clamp(1.2rem, 2.3vw, 2rem); line-height:1.35; color:var(--ink);
  max-width:min(820px, 88vw); margin:8.5vh auto 10vh; }
.sf-story .hero-copy .shelf{ margin:0 auto 8vh; }
.sf-story .hero-copy .cta-row{ justify-content:center; margin-bottom:14px; }
.sf-story .hero-copy .cta-note{ color:var(--ink-faint); }

@media (max-width:900px){
  /* ⚑ El relleno de ARRIBA no se toca aqui: lo manda la regla general (2vh), que es lo que
     pega el texto a las nubes. Este bloque solo acorta el de abajo, que es recorrido del hilo. */
  /* ⚑ Misma cuenta que la regla base —8.5vh menos lo que aporta la seccion siguiente— y no un
     `8vh` a secas: con el valor suelto el hueco de abajo salia 120 px contra 60 arriba, porque los
     64 px de `padding-top` de `.lsection` se sumaban sin descontarse. Aqui solo cambia el relleno
     lateral. */
  .sf-story .hero-copy{ padding:2vh 20px max(0px, calc(8.5vh - 64px)); }
  .sf-story .hero-copy .lede{ margin-bottom:6vh; }
}
/* ⚑⚑ ESTE TRAMO VA DESPUES DEL DE 900 A PROPOSITO. Por debajo de 560 `.lsection` baja su
   `padding-top` de 64 a 48, asi que lo que hay que descontar del hueco de abajo cambia — pero las
   dos media queries casan a la vez en un movil y tienen la MISMA especificidad, o sea que gana la
   que este mas abajo en el fichero. Lo puse arriba, junto a las otras reglas de 560, y no servia
   de nada: seguia restando 64 y el bloque quedaba descuadrado 16 px. Tercera vez hoy que el orden
   decide una regla que parecia decidida por la media query. */
@media (max-width:560px){
  .sf-story .hero-copy{ padding-bottom:max(0px, calc(8.5vh - 48px)); }
}


/* ============================================================================
   ⚑⚑ ESTO VA AL FINAL A PROPOSITO. Las reglas del lema vertical viven en el bloque de la
   segunda pasada, mas abajo en este mismo fichero, y tienen la MISMA especificidad que estas
   (.hero-sky .sky-kicker, 0-2-0). A igualdad de especificidad gana la ultima, asi que escritas
   arriba no hacian nada: el lema seguia vertical a 740px y a 375px. Un media query no sube de
   rango por serlo — sigue compitiendo por orden.
   ============================================================================ */
/* ⚑⚑ LA DISTRIBUCION NO CAMBIA AL ESTRECHAR. Habia montado aqui un plan B que ponia el lema
   en horizontal encima del titular, y eso era rehacer la composicion en vez de encogerla: el lema
   vertical a la izquierda ES la composicion. Lo unico que se ajusta son los numeros — el
   envoltorio sigue siendo inline-block (si pasa a block ocupa todo el ancho y el rail, que cuelga
   de su borde con right:100%, se sale por la izquierda), y el lema se pega mas al titular y se
   encoge para que quepan los dos. */
@media (max-width:760px){
  .sky-rail{ margin-right:12px; gap:10px; }
  .hero-sky .sky-kicker{ font-size:0.5625rem; letter-spacing:.24em; }
  .sky-rail-line{ height:44px; }
  /* el hero deja sitio a la izquierda para la columna del lema */
  .hero-sky{ padding-left:52px; padding-right:16px; }
  /* ⚑⚑ Y AQUI EL TITULAR SE CENTRA. En pantalla ancha la primera linea queda centrada sin
     decirlo, porque la segunda no cuenta para el ancho (width:0) y el envoltorio se ajusta a la
     primera. Aqui la segunda vuelve a contar — tiene que partirse — asi que el envoltorio se
     ajusta a ELLA, y la primera, alineada a la izquierda, se pegaba a su borde y perdia el eje con
     el logotipo. Con text-align:center vuelve a compartirlo.
     ⚑ Y no vuelve el baile de antes: el molde invisible de .sky-rot sigue reservando el hueco
     de la palabra mas larga, asi que el ancho del envoltorio no cambia al rotar. */
  .hero-sky .sky-h1{ text-align:center; }
}


/* ============================================================================
   SECCION 3 — LA ARBOLEDA
   ----------------------------------------------------------------------------
   ⚑⚑ ES EL HERO AL REVES. Alli la crema de la pagina se comia el cielo por abajo con una
   mascara de nubes; aqui esta seccion se come la crema por arriba con una mascara de hierba. La
   diferencia esta en DONDE vive la mascara: alli en una banda aparte rellena del color de la
   pagina, y aqui en la SECCION misma. Asi el borde de hierba es literalmente donde empieza a verse
   el cuadro, y no hay dos colores que tengan que casar — que es lo que dio guerra con las nubes.
   ⚑ `grass-cream.png` mide 2880x395: transparente arriba, macizo abajo. De mascara, eso deja
   la seccion oculta en su primer tramo y visible desde las puntas de hierba hacia abajo. No hace
   falta darle la vuelta.
   ⚑⚑ DOS CAPAS DE MASCARA, y la segunda es obligatoria: la primera solo cubre los 395px del
   PNG (13.72% del ancho, porque 395/2880 = 0.1372). Sin un rectangulo macizo para el resto, todo
   lo que quedara por debajo de esa franja se ocultaria. Las capas de mascara se SUMAN.
   ⚑ El margen superior negativo es lo que la monta sobre la seccion 2. Sin el, la hierba
   recortaria contra su propio hueco vacio en vez de contra el final del mosaico. */
/* ⚑⚑ LA MASCARA VA EN UNA BANDA PEQUENIA, NO EN LA SECCION ENTERA. Estuvo sobre la seccion
   —870 px de alto por todo el ancho— y eso obliga al navegador a pintar la seccion completa en una
   textura y aplicarle la mascara CADA VEZ que algo cambia ahi dentro, que durante el sosten es en
   cada fotograma. En la traza el coste se habia mudado a Rendering (1316 ms) y Painting (575 ms)
   con el Scripting ya en 303. Asi lo hace el hero desde el principio: una banda de 176 px, no toda
   la seccion. Es la misma silueta con una quinta parte del area.
   ⚑ La banda se rellena con el color de la PAGINA y se recorta con la hierba invertida
   (`grass-cream-inv.png`: la misma silueta con el alfa al reves, generada del original). Asi tapa
   por ARRIBA y deja ver el cuadro por debajo del borde de hierba. Invertir el PNG y no usar
   `mask-composite` es a proposito: un fichero se ve, se abre y se comprueba; `mask-composite` es
   una regla que hay que tener en la cabeza y que ademas no se comporta igual en todas partes. */
/* ⚑⚑ ESTE APILADO LO BORRE SIN QUERER al reemplazar el bloque de la mascara, y hay que
   declararlo: la arboleda tiene que PINTARSE ENCIMA de la seccion 2 para montarsele al subir. Con
   contextos de apilado de por medio (isolation, transforms) el orden del documento no basta.
   ⚑ Y `.seccion-mosaico-in` lleva `will-change` por lo mismo que el cielo: se anima durante un
   alto de ventana y se queda quieta el resto, asi que sin el su capa —1.47 megapixeles— se crea y
   se tira en cada pasada. */
.seccion-mosaico{ position:relative; z-index:0; }
.seccion-mosaico-in{ will-change:transform; }

/* ⚑⚑ AQUI SE DECLARA LA LINEA DE TIEMPO `--arboleda`, Y SIN ESTAS DOS REGLAS NO EXISTE. El JS
   escribe `animation-timeline:--arboleda` sobre `.seccion-mosaico-in`, pero el nombre no estaba
   creado en ninguna parte del proyecto: se referenciaba y nunca se definia. Un nombre que no
   resuelve deja la animacion SIN linea de tiempo, `vivaLaLinea()` decia que no —correctamente— y
   el sosten caia SIEMPRE en la reserva de JS. O sea que el camino del compositor, que es el que
   esta escrito y comentado como el bueno, no se habia ejecutado nunca ni una vez, en ningun
   navegador. Los saltos verticales de la seccion 2 mientras la arboleda se le monta encima eran
   eso: un `transform` escrito a mano en cada scroll, que llega un fotograma tarde, sobre un bloque
   con las seis capturas dentro.
   ⚑⚑ HACEN FALTA LAS DOS. `view-timeline-name` la crea en la arboleda; `timeline-scope` es lo
   que la hace visible fuera de su subarbol. `.seccion-mosaico-in` es HERMANA de `.arboleda`, no
   descendiente, y sin el scope el nombre no le llega — se quedaria igual de muerto que antes.
   ⚑ El tramo `entry` mide exactamente el alto de la arboleda, que es el numero que el JS pone
   en los fotogramas (`S = arb.offsetHeight`). Por eso desplazar la seccion 2 ese mismo alto la
   deja clavada: si los dos numeros dejaran de ser el mismo, la seccion 2 derivaria durante el
   solape en vez de quedarse quieta. */
:root{ timeline-scope:--arboleda; }
.arboleda{ view-timeline-name:--arboleda; view-timeline-axis:block; }
/* ⚑ Aqui habia una copia ENTERA de `.arboleda` sin la mascara, sobrante de cuando la
   restaure: declaraba las mismas nueve propiedades que la de abajo y no aportaba nada. Dos reglas
   iguales para el mismo selector son una invitacion a editar la que no manda. */
/* ⚑⚑ LA MASCARA VUELVE A LA SECCION. La mudé a una banda con la mascara invertida por
   rendimiento; no arreglo los saltos y descuadro el borde. Esta es la version que funcionaba: la
   silueta original recorta la seccion entera, asi que el cuadro se ve DESDE la linea de hierba
   hacia abajo y la hierba se dibuja con el propio cuadro, no con crema encima.
   ⚑ Dos capas de mascara: la hierba arriba y un rectangulo macizo para todo lo que queda por
   debajo. Se suman. El macizo arranca en 8vw, dentro de la zona donde el PNG ya es 100% opaco
   (medido: lo es desde el 51.9% de su alto, o sea 7.12vw), asi que no puede quedar hueco entre las
   dos aunque el redondeo se mueva un pixel. */
.arboleda{
  position:relative; z-index:1; isolation:isolate; overflow:hidden;
  min-height:clamp(560px, 68vw, 1000px);
  /* ⚑⚑ `flex-end` Y NO `center`: cuando el `min-height` es mayor que el contenido sobra sitio,
     y centrado ese sobrante se reparte arriba y abajo — el carrusel se quedaba a 11 px del borde
     del cuadro a 1600 de ancho (a 1024 no, porque ahi manda el contenido y no hay sobrante). Al
     pie, el sobrante se va todo arriba y el carrusel toca el borde a cualquier ancho. El texto
     baja lo que sobre, que en las medidas hechas son 22 px como mucho. */
  display:flex; align-items:flex-end;
  margin-top:calc(-1 * clamp(60px, 8vw, 120px));
  /* ⚑ Sin relleno abajo: lo ultimo de la seccion es el carrusel, y asi su pie coincide con el
     borde inferior del cuadro en vez de dejar una banda de arboles vacia debajo. */
  padding:clamp(110px, 15vw, 220px) 22px 0;
  -webkit-mask:url("images/grass-cream.png") top center / 100% 13.72vw no-repeat,
               linear-gradient(#000,#000) bottom center / 100% calc(100% - 8vw) no-repeat;
          mask:url("images/grass-cream.png") top center / 100% 13.72vw no-repeat,
               linear-gradient(#000,#000) bottom center / 100% calc(100% - 8vw) no-repeat; }
/* ⚑ La capa se hace mas alta que la seccion (140%) y se sube un 20%: eso deja un 20% de
   margen por arriba y otro por abajo para desplazarla sin que asome el borde. Estaba en 120% y el
   paralaje solo tenia 10% de recorrido — 48px — que es la razon de que no se notara. */
.arboleda-fondo{ position:absolute; left:0; right:0; top:-20%; height:140%; z-index:-1; }
/* ⚑⚑ SIN `will-change`. Lo llevaba de cuando la imagen tenia paralaje propio; ese paralaje
   se quito y la promesa se quedo. Medido: 1.54 megapixeles de capa compuesta permanente por cada
   una de las dos imagenes, para algo que ya no se mueve. Eso es exactamente lo que hace que el
   navegador tire otras capas —las del hero— y devuelva los saltos al volver del pie de pagina. */
.arboleda-img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
  display:block; }
/* ⚑ Mismo conmutador que el cielo del hero: se ensenia una y se esconde la otra segun
   `data-sky`. Las dos van en `position:absolute` una sobre otra para que ocultar una no cambie la
   altura de la capa. */
:root:not([data-sky="night"]) .arboleda-noche{ display:none; }
:root[data-sky="night"] .arboleda-dia{ display:none; }

/* ⚑⚑ EL VELO NO ES DECORACION: SIN EL, LA MITAD DEL TEXTO NO SE LEE. Medido sobre los
   pixeles reales del cuadro, con la tinta oscura de la pagina, solo el 49.8% del area del bloque
   llegaba a 4.5:1 — el resto cae sobre troncos y sombras, con lo peor en 1.17. No es un pixel
   suelto, es casi la mitad.
   El 55% es el numero que sale de barrer opacidades y quedarse con la primera que aprueba entera:

     opacidad   0     0.30    0.45    0.55    0.65
     area >=4.5:1  49.8%  91.9%   100%    100%    100%
     peor pixel   1.17   2.85    4.38    5.68    7.23

   0.45 ya da 100% pero deja el peor en 4.38, por debajo del listón; 0.55 lo sube a 5.68 y todavia
   deja pasar el 45% del cuadro. Por eso 0.55 y no "lo que parecia bien".
   ⚑ Sin `backdrop-filter`: seria una capa compuesta permanente, que es justo lo que se acaba
   de quitar del mosaico por los saltos del hero. Un color translucido cuesta cero. */
/* ⚑⚑ SIN NADA DETRAS DEL TEXTO, Y ES UNA DECISION TOMADA CON LOS NUMEROS DELANTE. Medido
   sobre el cuadro, en la zona exacta que ocupa cada bloque: el titular aguanta solo (media 7.06:1
   de dia, 8.90:1 de noche) pero el parrafo con `--ink-soft` daba 1.81:1 de media y el 100% de su
   superficie por debajo de 4.5:1. Lo unico que se conserva de aquel arreglo es la TINTA: el
   parrafo va en `--ink` y no en `--ink-soft`, que es lo mejor que se puede hacer sin poner nada
   detras (con `--ink` el 45% de la superficie queda por debajo de 4.5:1; con `--ink-soft`, el
   100%). Se probo un panel y se probo un velo radial sin bordes; los dos se ven, y se ha preferido
   el cuadro limpio. Queda escrito para que nadie lo vuelva a "arreglar" sin saber lo que cuesta.
   ⚑ El envoltorio `.arboleda-texto` se queda aunque ya no lleve velo: los selectores de hijo
   directo del titular y el parrafo cuelgan de el, y moverlos otra vez es la clase de cambio que ya
   ha roto el formato de esta seccion tres veces. */
/* ⚑⚑ ESTA REGLA LA BORRE SIN QUERER al quitar el velo, y de ahi que el bloque se fuera a la
   izquierda: `.arboleda-in` es un ITEM FLEX (la arboleda es `display:flex`), asi que sin ancho ni
   margenes se encoge a su contenido y se pega al principio de la linea. Con `width:100%` y los
   margenes automaticos vuelve a medir lo que debe y a quedarse centrado. */
.arboleda-in{
  /* ⚑ 1000 y no 920: medido, el parrafo estaba tocando el ancho de esta caja (834 px) y por eso
     `max-width:56ch` en el propio parrafo no hacia NADA — mandaba el contenedor. A partir de
     980 px aqui, el parrafo pasa de cuatro lineas a tres y "Sunday." deja de quedarse solo. */
  width:100%; max-width:min(1000px, 92%); margin-inline:auto; position:relative;
  /* ⚑⚑ LO QUE SUBE EL TEXTO ES ESTE RELLENO, no el hueco de abajo. Lo intente primero
     separando el parrafo del carrusel, y no movio nada: la seccion es de alto CONTENIDO, asi que
     al crecer el hueco crecia la seccion y el texto se quedaba a la misma distancia del borde de
     arriba. Medido: el texto empezaba a 265 px del techo de la seccion, que es exactamente la suma
     de los dos rellenos superiores (216 de la seccion + 49 de esta caja). Se recorta este, que es
     el que sobra; el de la seccion no se toca porque es el que despeja la franja de hierba de la
     mascara (13.72vw, unos 197 px a 1440) y el texto se le echaria encima. */
  /* ⚑ Tampoco lleva relleno abajo, por lo mismo que la seccion: lo ultimo que hay es el
     carrusel y se quiere que su pie llegue al borde del cuadro. Sin esto quedaban 35 px de
     arboles vacios — el relleno de esta caja, no el de la seccion, que ya estaba a cero. */
  /* ⚑⚑ EL `+ 20px` BAJA EL BLOQUE DE TEXTO, y va acompaniado de un `- 20px` en el hueco de
     debajo del parrafo. Hacen falta LOS DOS porque la seccion tiene dos regimenes y cada palanca
     solo funciona en uno:
       · manda el CONTENIDO (lo normal, medido a 885 y 1425): el bloque cuelga del techo, asi que
         lo que lo baja es este relleno; recortar el hueco de abajo no lo mueve, solo encoge la
         seccion.
       · manda el `min-height` (ventanas donde 68vw es grande): el bloque esta pegado al pie y el
         sobrante se va arriba, asi que lo que lo baja es ADELGAZAR el contenido — o sea el hueco;
         y este relleno no lo mueve, porque lo que baja el texto lo sube el bloque entero.
     Con las dos a la vez el texto baja 20 px exactos en cualquiera de los dos casos. */
  padding:calc(clamp(10px, 1.4vw, 20px) + 20px) clamp(20px, 3vw, 46px) 0; }
/* ⚑⚑ ESTE BLOQUE NO SIGUE AL TEMA, Y ES LA EXCEPCION DE LA PAGINA. Todo lo demas invierte la
   polaridad con `data-sky`: tinta oscura sobre halo claro de dia, clara sobre oscuro de noche.
   Aqui no, y el motivo es el fondo. Estas tres reglas caen sobre un CUADRO —dos, en realidad,
   porque la arboleda de dia y la de noche son imagenes distintas—, y sobre pintura lo que despega
   la letra no es el contraste medio del fondo sino la SOMBRA PROYECTADA. Una tinta clara con halo
   oscuro funciona igual sobre el verde palido del dia que sobre el azul de la noche; la que se
   daba la vuelta perdia la sombra justo donde mas falta hacia. Comprobado en la pagina antes de
   fijarlo.
   ⚑ Los dos colores son LITERALMENTE los de la noche (`public.css`, `:root[data-sky="night"]`):
   `--ink:#EEF1F8` y `--bg:#0A0E1A`. Copiados y no referenciados a proposito — un `var(--ink)`
   aqui volveria a seguir al tema, que es justo lo que se quiere evitar. Si la paleta de la noche
   cambia, este es el sitio al que hay que volver.
   ⚑ Un solo sitio donde viven las tres, porque las usan tres reglas —el titular, el parrafo y el
   nombre de cada tema en el carrusel— y tienen que moverse juntas. */
.arboleda{
  --ink-cuadro:#EEF1F8;
  --halo:color-mix(in srgb, #0A0E1A 35%, transparent);
  --halo-ancho:color-mix(in srgb, #0A0E1A 22%, transparent); }
.arboleda-texto{ position:relative; }
.arboleda-texto > h2{
  /* ⚑ Sombra PROYECTADA, no contorno: las dos capas macizas salen a (-1,1) y (-2,2) y la ancha
     a (-3,3), como si la luz viniera de arriba a la derecha. El halo va al 35% y la capa ancha al
     22%: apenas se notan y aun asi despegan el trazo del cuadro.
     ⚑ La capa de 2 px se queda SIN desplazar a proposito. Corrida del todo, el flanco de arriba
     a la derecha de cada letra se queda sin halo, y ahi es justo donde peor se lee sobre el
     cuadro; esa capa centrada es la que lo cubre. Los colores viven arriba, en `.arboleda`. */
  text-shadow:
    -1px 1px 0 var(--halo), -2px 2px 0 var(--halo),
    0 0 2px var(--halo),
    -3px 3px 10px var(--halo-ancho);
  font-family:var(--font-display); font-weight:600; color:var(--ink-cuadro);
  font-size:clamp(1.85rem, 4vw, 2.7rem); line-height:1.18; text-align:center;
  margin:0 auto 14px; max-width:22ch; }
/* ⚑ Aqui hubo un velo y una discusion sobre `--ink` contra `--ink-soft`: con la tinta que
   seguia al tema, la suave (#706A62 de dia) fallaba en el 100% del parrafo hasta con el velo al
   80% — gris medio sobre crema, sin alfa que lo salvara. Se quedo la fuerte. Ya no aplica: la
   tinta es `--ink-cuadro`, clavada en la clara, y quien la despega del cuadro es la sombra. */
.arboleda-texto > .sub{
  /* ⚑ Sombra PROYECTADA, no contorno: las dos capas macizas salen a (-1,1) y (-2,2) y la ancha
     a (-3,3), como si la luz viniera de arriba a la derecha. El halo va al 35% y la capa ancha al
     22%: apenas se notan y aun asi despegan el trazo del cuadro.
     ⚑ La capa de 2 px se queda SIN desplazar a proposito. Corrida del todo, el flanco de arriba
     a la derecha de cada letra se queda sin halo, y ahi es justo donde peor se lee sobre el
     cuadro; esa capa centrada es la que lo cubre. Los colores viven arriba, en `.arboleda`. */
  text-shadow:
    -1px 1px 0 var(--halo), -2px 2px 0 var(--halo),
    0 0 2px var(--halo),
    -3px 3px 10px var(--halo-ancho);
  text-align:center; color:var(--ink-cuadro);
  font-size:var(--paso-cuerpo); line-height:1.55;
  /* ⚑⚑ ESTE HUECO ES EL QUE SUBE EL TEXTO, y cuesta ver por que. La seccion se queda con el
     mayor de dos altos: su `min-height` (68vw) o el de su contenido. Cuando manda el `min-height`
     sobra sitio, y con `align-items:flex-end` ese sobrante se va ENTERO arriba — o sea que cuanto
     MAS ALTO sea el contenido, mas arriba empieza. Separar el parrafo del carrusel engorda el
     contenido y sube el bloque. (Yo probe justo lo contrario primero, recortar rellenos, y el
     texto BAJO 30 px: menos contenido, mas sobrante, mas empujon desde arriba.)
     ⚑ Pasado cierto punto el contenido supera al `min-height` y manda el, y entonces el texto se
     queda a `relleno de la seccion + relleno de la caja` del techo y ya no sube mas. Ahi esta el
     suelo, y es a proposito: por debajo se metería en la franja de hierba de la mascara. */
  max-width:56ch; margin:0 auto max(0px, calc(clamp(56px, 7vw, 120px) - 20px)); }

/* ---- carrusel de temas ----
   ⚑ Con `scroll-snap` y desbordamiento horizontal: un carrusel de verdad, sin JS. Cuando
   lleguen las capturas basta con meter los <figure> dentro de .temas-pista.
   ⚑ `overflow-x:auto` en un contenedor que se sale del ancho de la pagina se lleva la barra
   de scroll de la VENTANA por delante si no se le pone un ancho: por eso la pista va dentro de una
   caja que sí lo tiene. */
/* ⚑⚑ LA GEOMETRIA, QUE ES TODO EL TRUCO. Las tarjetas no estan en fila: estan clavadas
   sobre una CIRCUNFERENCIA enorme, y lo que se mueve es la rueda entera. La de arriba queda de
   frente y las vecinas se inclinan solas — la inclinacion no se escribe, sale de estar puestas
   sobre el circulo.
   ⚑ `.temas-rueda` es un PUNTO (0x0): el centro del circulo. Asi la cuenta de cada tarjeta es
   directa y no hay que compensar el tamanio de ninguna caja. Leyendo su transform de derecha a
   izquierda: se coloca con el pie en el centro, sube el radio, y se gira su angulo alrededor del
   centro. `transform-origin:0 0` es lo que hace que ese giro sea alrededor del centro del circulo
   y no del centro de la tarjeta.
   ⚑ El radio sale de que las quince quepan sin tocarse: perimetro = ancho x 15, luego
   radio = ancho x 15 / 2pi = ancho x 2.3873.
   ⚑⚑ Y el centro del circulo se pone MAS ABAJO que la caja visible, a `radio + alto`, para que
   lo que asome sea solo la cresta: la de frente entera y las vecinas cayendo por los lados. */
.temas{
  --tema-w:clamp(170px, 22vw, 300px);   /* mas grandes: ya no viven en la columna de texto */
  --tema-h:calc(var(--tema-w) * 720 / 554);   /* la proporcion exacta de las capturas */
  --tema-paso:24deg;                          /* 360 / 15 */
  --tema-radio:calc(var(--tema-w) * 2.3873);
  /* ⚑⚑ AIRE POR ARRIBA. La tarjeta de frente esta a 0 grados y su borde superior caia
     EXACTAMENTE en el borde de la caja, que recorta: cualquier redondeo a subpixel durante el giro
     se comia una fila de pixeles, y eso es el recorte que se ve pasar. Bajando el centro del
     circulo este mismo valor, la de frente queda despegada del borde y ya no hay nada que rozar.
     ⚑ Se suma tambien al alto de la caja, para no comerse el hueco del pie. */
  /* ⚑ Despega la tarjeta del borde de arriba Y aloja el nombre, que ahora va encima. El suelo
     de 54 y no 46: medido a 765 px de ventana, con 46 el nombre quedaba a 10 px del borde — no se
     recorta, pero es un margen que se come cualquier cambio de tipografia o de interlineado. */
  --tema-aire:clamp(54px, 4.4vw, 66px);
  /* ⚑⚑ Y HUECO POR ABAJO. Sin el, la tarjeta de frente terminaba EXACTAMENTE en el borde
     inferior del cuadro: el pie de la caja ya coincidia con el de la seccion, que era lo pedido,
     pero la tarjeta quedaba sin respirar y se leia como cortada. Este valor se suma al alto de la
     caja y NO mueve el centro del circulo, asi que lo unico que cambia es que sobra sitio por
     debajo de la de frente; el pie de la caja sigue cayendo en el borde del cuadro. */
  --tema-aire-abajo:clamp(40px, 3.6vw, 64px);
  /* ⚑⚑ SE SALE DE LA CAJA DEL TEXTO. `.arboleda-in` mide 920 como mucho, y ahi dentro la rueda
     solo dejaba ver ENTERA la de frente: las dos vecinas quedaban cortadas por el `overflow`. La
     cuenta de lo que hace falta: la vecina esta a `radio*sin(24°)` del centro y su caja girada
     mide `(ancho*cos24 + alto*sin24)/2` de medio ancho, asi que para tres enteras hacen falta unos
     694 px a 1024 de ventana. Con esto hay de sobra y en pantallas anchas entran cinco.
     ⚑ Misma tecnica que el mosaico: ancho propio y `margin-inline` negativo para escaparse del
     contenedor sin sacarlo del flujo. */
  /* ⚑⚑ A TODO EL ANCHO. `100vw` cuenta la barra de scroll, asi que sobresale unos 7 px por
     cada lado — simetricos, y los recorta el `overflow:hidden` de la arboleda. Sale centrado
     porque `.arboleda-in` esta centrado: el margen negativo se mide desde su mitad. */
  position:relative; overflow:hidden;
  width:100vw; max-width:none;
  margin-inline:calc(50% - 50vw);
  /* ⚑ Sin la cola de 3.4rem: la reservaba el nombre cuando iba DEBAJO. Ahora lo de mas abajo
     es el borde de la captura, que es justo lo que se queria pegado al pie del cuadro. */
  height:calc(var(--tema-h) + var(--tema-aire) + var(--tema-aire-abajo)); }

/* ⚑ La transicion es lo que hace que un fotograma tarde no se note: el JS solo dice a que
   tarjeta hay que ir —un valor a saltos, no continuo— y el giro lo hace esta transicion. Es la
   leccion del hero: lo que se mueve con el scroll, fotograma a fotograma, tiembla. */
.temas-rueda{
  position:absolute; left:50%; top:calc(var(--tema-radio) + var(--tema-h) + var(--tema-aire));
  width:0; height:0;
  transform:rotate(var(--tema-giro, 0deg));
  transition:transform 420ms cubic-bezier(.4,0,.2,1); }

.tema{
  --d:0;                                      /* distancia en pasos a la de frente; lo pone el JS */
  position:absolute; left:0; top:0; margin:0; width:var(--tema-w);
  transform-origin:0 0;
  transform:rotate(calc(var(--i) * var(--tema-paso)))
            translateY(calc(-1 * var(--tema-radio)))
            translate(-50%, -100%);
  /* ⚑ Lejos: desenfocada y sin color, como en la referencia. El tope de 2 pasos evita que las
     de mas alla sigan pagando desenfoque, que es caro y ademas no se ven. */
  filter:blur(calc(min(var(--d), 3) * 2.6px)) grayscale(clamp(0, var(--d), 1));
  opacity:clamp(0, calc(1.22 - var(--d) * 0.26), 1);
  transition:filter 420ms ease, opacity 420ms ease; }

/* ⚑ La de frente va por delante de sus vecinas: si no, la inclinada de al lado le pisa una
   esquina y se nota que hay algo detras. */
.tema[data-frente]{ z-index:2; }

.tema-abrir{
  display:block; width:100%; padding:0; border:0; background:none; cursor:zoom-in;
  border-radius:clamp(10px, 1vw, 14px); overflow:hidden; line-height:0;
  box-shadow:0 10px 30px rgba(0,0,0,.16);
  transition:transform 220ms ease, box-shadow 220ms ease; }
.tema-abrir img{ display:block; width:100%; height:auto; border-radius:inherit; }
/* ⚑ El realce solo en la de frente: las demas estan desenfocadas y levantarlas no se lee como
   "puedes pulsar", se lee como un fallo de pintado. */
.tema[data-frente] .tema-abrir:hover,
.tema[data-frente] .tema-abrir:focus-visible{
  transform:translateY(-6px); box-shadow:0 18px 42px rgba(0,0,0,.24); }

/* ⚑ El pie solo existe para la de frente. Va DENTRO de la tarjeta, asi que hereda su giro — y
   como la de frente esta a 0 grados, sale derecho sin tener que corregir nada. */
/* ⚑ Encima de la captura, no debajo. El hueco que necesita sale de `--tema-aire`, que es el
   mismo que ya despegaba la tarjeta del borde de arriba: ahora ademas la aloja. */
.tema figcaption{
  position:absolute; bottom:100%; left:0; right:0; margin-bottom:.6rem; text-align:center;
  /* ⚑ Sombra PROYECTADA, no contorno: las dos capas macizas salen a (-1,1) y (-2,2) y la ancha
     a (-3,3), como si la luz viniera de arriba a la derecha. El halo va al 35% y la capa ancha al
     22%: apenas se notan y aun asi despegan el trazo del cuadro.
     ⚑ La capa de 2 px se queda SIN desplazar a proposito. Corrida del todo, el flanco de arriba
     a la derecha de cada letra se queda sin halo, y ahi es justo donde peor se lee sobre el
     cuadro; esa capa centrada es la que lo cubre. Los colores viven arriba, en `.arboleda`. */
  text-shadow:
    -1px 1px 0 var(--halo), -2px 2px 0 var(--halo),
    0 0 2px var(--halo),
    -3px 3px 10px var(--halo-ancho);
  font-family:var(--font-display); color:var(--ink-cuadro);
  font-size:clamp(1rem, 1.5vw, 1.2rem);
  opacity:calc(1 - min(var(--d), 1));
  transition:opacity 320ms ease; }

/* ---- la lupa ---- */
.tema-lupa{
  border:0; padding:0; background:var(--surface); color:var(--ink);
  border-radius:clamp(12px, 1.4vw, 18px); overflow:visible;
  max-width:min(92vw, 720px); max-height:92vh; box-shadow:0 30px 90px rgba(0,0,0,.35); }
.tema-lupa::backdrop{ background:rgba(0,0,0,.62); }
/* ⚑⚑ LA IMAGEN SE LIMITA POR EL ALTO, NO POR EL ANCHO, y esto no es un ajuste fino: iba a
   `width:100%` y su alto salia de ahi, asi que imagen + nombre pasaban de los 92vh del dialogo y el
   nombre se salia por debajo. Medido con la lupa abierta a 1200x900: el nombre acababa 95 px POR
   DEBAJO del borde inferior del dialogo, o sea fuera de la pantalla — no es que estuviera pegado
   al borde, es que no estaba dentro. Limitandola por el alto, el dialogo se estrecha solo hasta
   que todo cabe y el nombre siempre queda dentro.
   ⚑ Los 4.5rem que se restan son el hueco del nombre: su alto de linea mas sus dos margenes. */
/* ⚑ ARRIBA REDONDEADA, ABAJO A ESCUADRA. Las esquinas de ARRIBA de la imagen coinciden con las
   del dialogo, asi que ahi `inherit` es justo lo que hace falta: sin el, los picos cuadrados de la
   foto asomarian por fuera de la curva del dialogo. Las de ABAJO no coinciden con nada — debajo
   viene el nombre del tema, todavia dentro del dialogo — asi que redondearlas dibujaba una segunda
   curva en mitad de la caja, a un dedo de la curva de verdad. Se dejan rectas y solo redondea el
   dialogo, que es el unico que tiene un borde ahi abajo.
   Los longhand no son un capricho: `border-radius:inherit` es la abreviada y no se puede heredar
   solo la mitad; `border-top-left-radius:inherit` hereda ESA esquina del padre y ya esta. */
.tema-lupa img{ display:block; margin-inline:auto;
  border-top-left-radius:inherit; border-top-right-radius:inherit;
  border-bottom-left-radius:0; border-bottom-right-radius:0;
  max-width:100%; max-height:calc(92vh - 4.5rem); width:auto; height:auto; }
/* ⚑ El nombre queda casi pegado al borde de abajo del dialogo. Se le iguala el aire: el mismo
   por arriba que por abajo, y algo mas generoso que los .9rem que tenia. */
.tema-lupa-pie{ margin:1.1rem 0; text-align:center; color:var(--ink-soft);
  font-family:var(--font-display); font-size:clamp(1rem, 1.5vw, 1.2rem); }
.tema-cerrar{
  position:absolute; top:-14px; right:-14px; width:38px; height:38px; border-radius:50%;
  /* ⚑⚑ `!important` porque la regla que devuelve el cursor sobre el modal es
     `:root.has-dot:has(dialog[open]) *{ cursor:auto }`, y `auto` sobre el TEXTO de un boton se
     resuelve como barra de escribir: sobre la X salia el cursor de texto. Ese `*` le gana por
     especificidad a un `.tema-cerrar` normal. */
  border:0; cursor:pointer !important; font-size:22px; line-height:1;
  background:var(--surface); color:var(--ink); box-shadow:0 6px 18px rgba(0,0,0,.3); }

@media (prefers-reduced-motion: reduce){
  /* ⚑⚑ Quien pide menos movimiento no quiere una rueda girando. Se deshace el circulo y
     quedan en una fila que se desplaza a mano, con su ajuste por tarjeta: el mismo contenido, sin
     nada que se mueva solo. Todas nitidas y a color — el estado degradado NUNCA esconde. */
  .temas{ height:auto; overflow-x:auto; overscroll-behavior-x:contain;
    scroll-snap-type:x mandatory; scrollbar-width:none; }
  .temas::-webkit-scrollbar{ display:none; }
  .temas-rueda{ position:static; width:auto; height:auto; display:flex;
    gap:clamp(12px, 1.4vw, 22px); padding:4px 0 10px; transform:none; }
  .tema{ position:static; transform:none; filter:none; opacity:1;
    flex:0 0 auto; scroll-snap-align:center; }
  .tema figcaption{ position:static; opacity:1; }
  .tema-abrir, .tema-lupa img{ transition:none; }
}

@media (max-width:640px){
  /* ⚑⚑ EL RELLENO DE ABAJO TIENE QUE SER 0 AQUI TAMBIEN. La regla base ya lo pone a cero para
     que el pie del carrusel caiga justo en el borde inferior del cuadro; esta de aqui repetia el
     atajo `padding` entero con un 70 al final y lo deshacia — pero SOLO por debajo de 640, que es
     por lo que el desajuste se veia unicamente en movil. Un atajo que se reescribe entero en una
     media query se lleva por delante lo que la regla base habia decidido en los otros lados. */
  .arboleda{ margin-top:calc(-1 * clamp(40px, 9vw, 70px));
    padding:clamp(70px, 22vw, 150px) 20px 0; }
}
