/* sitio.css — Gran Danés LM
   ─────────────────────────────────────────────────────────────────────────────
   El sitio vive en negro a propósito y no tiene tema claro: la pieza es una
   fotografía de las siete de la tarde disolviéndose en negro, y sobre blanco no
   existe. Por eso `color-scheme: dark` está declarado en el <head> y todos los
   colores se pintan explícitos — nada se hereda del navegador. */

:root{
  --negro:      #000;      /* el ground. La foto se disuelve EN él, no sobre él */
  --tinta:      #e8ddc8;   /* crema cálida: el mismo tono que la luz de la foto */
  /* DOS tokens, no uno: el texto y el filete pedían cosas opuestas. El tostado
     viejo (#5d5346) sobre negro da 2.79:1 — bajo el mínimo 4.5:1 de WCAG AA para
     texto normal, y aquí es el peor caso (cuerpo chico, versales, tracking alto).
     Subirlo a secas dejaba los filetes de 1 px como un subrayado grueso. Por eso
     se parten: --tenue pinta texto (5.11:1 contra negro, mismo matiz cálido);
     --filete conserva el susurro de 1 px. Medido, no a ojo. */
  --tenue:      #8a7b68;   /* texto: 5.11:1 contra --negro */
  --filete:     #5d5346;   /* trazo de 1 px: el tostado de siempre */
  --brasa:      #c8a06a;
}

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

/* EL RESPALDO DE `overflow-x:clip` PARA iOS 15.6 — el porqué, en la regla de
   abajo. Va antes para que `clip` lo pise donde `clip` se entiende. */
html{ overflow-x:hidden; }

html,body{
  min-height:100%;
  background:var(--negro);
  color:var(--tinta);
  /* `clip`, NO `hidden`, Y ES LA DIFERENCIA ENTRE QUE LA SECCIÓN DE CONCURSOS
     FUNCIONE O NO. `overflow-x:hidden` obliga a que `overflow-y` compute a
     `auto`, y eso convierte al <body> en un contenedor de scroll propio: un
     `position:sticky` de dentro deja de pegarse a la ventana y se va hacia
     arriba con la página. Medido: el top de la vista bajaba a −540, −1620,
     −2700… o sea que el relevo cambiaba de pieza mientras el usuario ya estaba
     mirando negro vacío.

     `clip` recorta igual y NO crea contenedor de scroll, así que el sticky
     vuelve a pegarse a la ventana.

     ── Y `clip` NO EXISTE ANTES DE SAFARI 16, o sea que en un iPhone con iOS
     15.6 —que está en el parque objetivo— esta declaración entera se cae y el
     `overflow-x` se queda en `visible`: la página se arrastra de lado. El
     respaldo va en la regla de ARRIBA y SÓLO SOBRE `html`, nunca sobre el
     <body>, y esa distinción es todo el arreglo: el overflow del ELEMENTO RAÍZ
     se propaga al viewport y el propio <html> computa a `visible`, así que no
     se convierte en contenedor de scroll y el sticky de concursos sigue
     pegándose. Al <body> no se le pone respaldo: con el viewport ya recortado
     no le queda nada que recortar.

     Y LA DISTINCIÓN ESTÁ MEDIDA, no razonada: con las cinco declaraciones que
     Safari 15.6 tira y el respaldo SÓLO en <html>, el top de `.concursos__vista`
     sale 0 en y=4000, 5000, 6000 y 7000 —pegada—. Añadiendo el mismo respaldo al
     <body>, los mismos cuatro puntos dan −3156, −4156, −5156 y −6156: la vista
     se va con la página. Son los mismos números negativos del párrafo de arriba,
     reproducidos.

     El orden es el que manda: respaldo primero, `clip` después. Donde `clip`
     existe gana por ser la última declaración y el dibujo es el de siempre. */
  overflow-x:clip;
}
body{ -webkit-font-smoothing:antialiased; }

/* ── EL REBOTE DE ARRIBA NO PUEDE ENSEÑAR NEGRO ───────────────────────────────
   VICTOR, EN EL IPHONE: «responde y rebota, la típica. No quiero que vean negro
   si scrollean hacia arriba.» Al tirar hacia abajo estando arriba del todo, el
   rebote elástico de iOS despega el contenido del canto y lo que asoma por
   encima es el fondo del ELEMENTO RAÍZ — que hasta hoy era el mismo negro plano
   del resto de la página. En un sitio cuyo hero es una fotografía a sangre, eso
   se lee como un hueco.

   NO SE MATA EL REBOTE, y esa era la otra salida. `overscroll-behavior-y:contain`
   lo quita, pero en la raíz quita TAMBIÉN el tirar-para-recargar del navegador,
   que es gesto de sistema y no nuestro. Lo que molesta no es que rebote: es lo
   que se ve detrás.

   ASÍ QUE EL FONDO DE LA RAÍZ DEJA DE SER NEGRO Y PASA A SER EL CANTO DE ARRIBA
   DE LA ESCENA QUE ESTÉ PUESTA. `hero.js` lo publica al pasar de lámina (§ el
   campo `canto` de ESCENAS), así que el rebote continúa la fotografía en vez de
   cortarla. Y NO PUEDE SER UN COLOR FIJO, que es lo primero que uno intenta:
   medido sobre el recorte vertical real de cada una a 390×844, el canto de
   arriba va de #0d0b0a (Piano) a #9e9387 (Cachorro) — un factor de diez. Un solo
   valor acertaría con una y fallaría con seis.

   EL VALOR ESCRITO AQUÍ ES EL DE SANTOS, y por la misma razón que su `--foco`
   vive en el CSS: Santos es la que abre y la única que se dibuja SIN JavaScript.
   Si `hero.js` no llega, el rebote sigue enseñando el canto correcto.

   `background-color` y no `background` para no pisar nada, y con la MISMA
   duración y curva del fundido de las láminas: si el color saltara de golpe
   mientras las fotografías se disuelven, el salto se vería justo en el borde.

   PENDIENTE DE CONFIRMAR EN EL APARATO DE VICTOR. El rebote elástico es un gesto
   táctil de iOS: no ocurre con el ratón y no se reproduce en este banco. Lo que
   sí está medido aquí son los siete colores y que el color viaja con la
   rotación. */
html{
  background-color:#3b2d20;
  transition:background-color var(--hero-fundido) var(--hero-curva);
}
@media (prefers-reduced-motion: reduce){ html{ transition:none; } }

/* ── EL HERO ─────────────────────────────────────────────────────────────────
   UNA FOTOGRAFÍA A PANTALLA COMPLETA Y UNA PORTADA DE REVISTA ENCIMA: membrete
   fino arriba, palabra enorme, la fotografía, palabra enorme. Antes esto era un
   tríptico de WebGL en un canvas y después una fotografía con el rótulo en una
   esquina; el porqué de los dos cambios está en `index.html`, sobre la propia
   sección, y las medidas de la portada en `.hero__portada`, más abajo.

   EL HERO SIGUE CLAVADO, y eso no es herencia perezosa: es lo que hace que la
   sección de concursos SUBA POR ENCIMA de la fotografía en vez de empujarla, que
   es el gesto del recorrido de este sitio. `.hero__riel` —hermano, en flujo
   normal— es lo único que le da altura al documento, y mide una pantalla.

   `100svh` Y NO `100vh`: en un teléfono `100vh` es la ventana GRANDE, con la
   barra del navegador escondida, así que la fotografía nacería más alta que la
   ventana de ahora y el `cover` recortaría por arriba y por abajo píxeles que no
   hacen falta. `svh` es la ventana pequeña, la que de verdad se ve.

   Y EL NEGRO ESTÁ DECLARADO DEBAJO, no heredado: mientras la lámina baja, lo que
   se ve es el ground del sitio y no el blanco del navegador. */
.hero{
  /* EL TOKEN SE DECLARA AQUÍ Y NO EN CADA RÓTULO, y no es ahorro de líneas: la
     marca y el pie son DOS nodos que tienen que dibujarse con la misma letra, y
     dos declaraciones del mismo token son exactamente como se separan. `--garalda`
     vive en `.concursos` —lo declara `concursos.css` junto a su `@font-face`— y
     fuera de ese árbol no resuelve, así que sin esta línea el hero sale en Times.
     Es la misma cuenta que hace el conmutador de idioma doscientas líneas abajo. */
  --garalda:"Cormorant Concursos", Garamond, "Hoefler Text", "Times New Roman", serif;
  position:fixed; inset:0; z-index:0;
  height:100vh; height:100svh;
  background:var(--negro);
  /* `hidden` PRIMERO Y `clip` DESPUÉS, y aquí el respaldo sí puede ser `hidden`
     sin pagar nada: el estropicio que `clip` evita en el <body> —volverse
     contenedor de scroll y despegar el sticky— no aplica a una caja `fixed` que
     no tiene dentro un solo `position:sticky`. En Safari 15.6 `clip` se cae, se
     queda `hidden` y el hero recorta igual; de 16 en adelante gana `clip` y el
     dibujo es el mismo píxel por píxel. */
  overflow:hidden;
  overflow:clip;
}
/* EL HERO SE GUARDA CUANDO SU RIEL SALE DE PANTALLA. El porqué entero está en el
   script del final del index (§ EL HERO SE GUARDA CUANDO NO LE TOCA): al ser
   `fixed` sigue pintado detrás de TODO el documento, así que cualquier píxel que
   no tape un elemento opaco lo enseña — y contra el rebote de iOS, que revela una
   zona que no pertenece al documento, no hay elemento que se pueda estirar.
   `visibility` y no `display`: no toca el layout. */
body.hero-guardado .hero{ visibility:hidden; }

/* ── EL RIEL ──────────────────────────────────────────────────────────────────
   El hero es `fixed` y no ocupa flujo, así que este `<div>` es lo único que le da
   altura al documento y por tanto quien decide DÓNDE empieza la sección de
   concursos y, con ella, si el `loading="lazy"` de sus láminas sirve de algo.

   MIDE UNA PANTALLA, EN TODAS LAS VENTANAS. Una fotografía quieta no tiene
   recorrido interno que agotar: está agotada desde el primer píxel, y por eso
   `HERO_FIN()` vale 0 y el salto a concursos se dispara con «tantito scroll».
   Es exactamente lo que medía el riel de la portada del bucle —la que mandaba
   por defecto—, así que el recorrido de concursos hacia abajo no se mueve un
   píxel respecto de lo que había.

   Y AHORA ESTÁ EN CSS Y NO EN UN JAVASCRIPT GENERADO. Este número lo escribía
   `medios.js` en el <head>, inyectando una etiqueta `<style>`, porque dependía
   del encuadre del tríptico —N pantallas en relevo, una en tríptico— y eso no se
   sabía sin leer las escenas. Con una sola forma no hay nada que calcular, y una
   regla estática está decidida antes del primer layout sin que corra una línea
   de JavaScript: el `lazy` de los concursos funciona incluso con el JS apagado.

   `svh` ANTES QUE `vh` por la misma razón que en `.hero`, y el `100vh` de
   delante es el respaldo para quien no conozca `svh`. */
.hero__riel{ height:100vh; height:100svh; pointer-events:none; }

/* ── LA LÁMINA · UN PUNTO FOCAL POR ESCENA ───────────────────────────────────
   `cover` para que la fotografía sangre por las cuatro orillas en cualquier
   ventana, y `object-position` MEDIDO —no `center`— porque un `cover` a ciegas
   corta cabezas.

   HASTA EL 16 DE SEPTIEMBRE DE 2026 EL NÚMERO ERA UNO SOLO PARA LAS SIETE, y ése
   era el defecto: Santos y Cachorro se compusieron PARA el hero, y Reloj, Cama,
   Piano, Plata Abrazo y Perlas eran piezas sueltas con el sujeto en otro sitio.
   Una regla global no puede servir a siete composiciones. Victor: «están como
   cortadas, o cortadas abajo o cortadas arriba, no respiran bien».

   AHORA CADA ESCENA TRAE SU PAR DE NÚMEROS, en `--foco`, y en apaisado y en
   vertical por separado. La tabla está abajo, con la caja del grupo de la que
   sale cada uno.

   ── CÓMO SE CALCULÓ, PARA QUE SE PUEDA REHACER ──────────────────────────────
   Con `cover`, la fracción VISIBLE de la lámina en cada eje sale de comparar la
   proporción de la ventana `ab` con la de la imagen `ai`:

     ab > ai  →  se ve todo el ancho y sólo `ai/ab` del alto   (recorte vertical)
     ab < ai  →  se ve todo el alto  y sólo `ab/ai` del ancho  (recorte horizontal)

   Y con una fracción visible `f`, un `object-position` de `p` deja a la vista el
   tramo `[p(1−f), p(1−f)+f]`. O sea que para que la caja del grupo `[b0,b1]` no
   se corte hacen falta las dos:  `p ≤ b0/(1−f)`  y  `p ≥ (b1−f)/(1−f)`.
   El valor elegido es el que MAXIMIZA EL MARGEN MÍNIMO sobre todas las ventanas
   donde el grupo cabe; donde no cabe, reparte la pérdida entre los dos cantos.

   Ventanas con las que se resolvió — apaisado `ab` 1.60 · 1.739 · 1.778 · 1.86 ·
   1.93 · 2.00, vertical `ab` 0.462 · 0.50 · 0.563 · 0.62 · 0.695 · 0.75. La
   apaisada llega a 2.00 y no se queda en 1.778 porque UN NAVEGADOR DE VERDAD ES
   MÁS BAJO QUE SU PANTALLA: en 1440×900 la ventana útil de Chrome ronda 1440×760,
   o sea `ab` 1.90, y ahí el recorte vertical ya vale 6.5 % del alto. Medir sólo a
   1440×900 exactos es medir la única ventana donde este número no hace nada.

   ── LAS SIETE CAJAS, EN FRACCIÓN DE SU LÁMINA ───────────────────────────────
   «el grupo» = ella y los perros, del pelo de la coronilla a la uña de la pata.

     escena          apaisado 16:9 (1672×941)     vertical 9:16 (941×1672)
     santos          x .365-.700  y .36-.97       x .12-.93  y .32-.88
     piano           x .310-.700  y .27-.93       x .00-.96  y .27-.85
     reloj           x .295-.625  y .30-.94       x .09-.94  y .27-.80   (930×1692)
     plata-abrazo    x .375-.630  y .045-.95      x .09-.88  y .09-.98
     cachorro        x .350-.780  y .06-.98       x .26-.94  y .30-.97
     perlas          x .375-.705  y .155-.99      x .15-.93  y .215-.89
     cama            x .245-.790  y .30-.95       x .00-.98  y .345-.79

   ── LA REGLA DEL AIRE · ARRIBA MANDA SOBRE ABAJO ───────────────────────────
   VICTOR, VIENDO LAS SIETE EN PANTALLA: «prefiero que escondas la parte de abajo,
   las patas; me importa menos la parte de abajo que la parte de arriba. Ella
   SIEMPRE tiene que tener aire en la parte de arriba.»

   Eso INVIERTE la prioridad con la que se resolvió la primera pasada, que sólo
   pedía que la cabeza y las patas entraran las dos. Cuando no caben las dos, la
   que entra es la cabeza y el recorte se lo come el SUELO.

   EL SUELO DE AIRE, MEDIBLE Y NO A OJO: el punto más alto del sujeto —la
   coronilla de ella, o la punta de la oreja del perro si está más arriba—
   conserva por encima al menos el 4 % del alto del viewport, y nunca menos de
   24 px. En `cover`, ese aire vale `(y0 − p(1−fv)) / fv` en fracción de la
   ventana, así que GANAR AIRE ES BAJAR `p` HACIA EL 0 %: se enseña más techo y se
   recorta más suelo.

   Y DE AHÍ SALE UNA SOLA REGLA PARA LAS SIETE, no dos parches:

     `p` = el MENOR valor que deja el fondo del grupo dentro —o sea el máximo
     aire arriba sin perder las patas—; y si ése no llega al suelo de aire en
     alguna ventana, se BAJA hasta el mayor que sí lo cumpla, y el suelo de la
     fotografía se pierde lo justo y nada más.

   Cuatro escenas cierran con «patas dentro» y tres pagan suelo: Plata Abrazo,
   Cachorro y Perlas en apaisado, y Plata Abrazo en vertical.

   ── LAS DOS QUE VICTOR SEÑALÓ, CON SU NÚMERO ───────────────────────────────
   · PLATA ABRAZO (apaisado), la peor: lo que se salía por arriba era el perro de
     pie, que es lo que esa fotografía viene a enseñar. Su oreja empieza en y
     .045 y el `47 %` de la pasada anterior dejaba 3.5 % de aire en una ventana de
     `ab` 1.90 — por debajo del suelo. Ahora `6 %`, que es el máximo que admite el
     maestro: 4.5 % en toda ventana de 16:9 o más estrecha y 4.0 % en la peor.
     A cambio pierde hasta un 4.6 % de abajo —la punta de las botas— a `ab` 1.98.
   · CACHORRO (apaisado), la que él llama la más importante: la coronilla de ella
     está en y .06 y con el `75 %` quedaba pegada al canto. Ahora `15 %`: 6.0 % de
     aire en las ventanas sin recorte y 4.8 % en la peor, pagando hasta un 6.7 %
     del suelo — las patas del perro de pie.

   ── EL TECHO DE CADA MAESTRO, QUE ES LO QUE NO SE PUEDE COMPRAR ────────────
   A 1440×900, 1920×1080 y 2000×1150 la lámina 16:9 NO SE RECORTA DE ALTO —la
   ventana es menos alargada que la imagen—, así que el aire de arriba vale
   exactamente `y0` y ningún `object-position` lo cambia. Ése es el techo:
   Plata Abrazo 4.5 %, Cachorro 6.0 %, Perlas 15.5 %, Piano 27 %, Reloj y Cama
   30 %, Santos 36 %. Las dos primeras están ahí por el encuadre del maestro, no
   por esta hoja de estilo; más aire que ése pide otro maestro.

   ── EL EJE HORIZONTAL SIGUE LA MISMA REGLA: SI NO CABEN LAS DOS, GANA LA CABEZA
   Tres verticales no caben de ancho —el sujeto mide más que la ventana— y una de
   ellas la nombró Victor probándola en el teléfono.

   · CAMA, y es la que él nombró: «no quiero que se le corte la cabeza al perro».
     El danés está echado A LO LARGO y el grupo mide el 98 % del ancho; a 390×844
     se ve el 82.1 %, o sea que faltan 15.9 puntos. La cabeza dormida es el sujeto
     de esa fotografía tanto como la coronilla de ella, y está pegada al canto
     IZQUIERDO: el hocico empieza en x .02 y la cabeza entera va de .02 a .23.
     REPARTIR LA PÉRDIDA POR LOS DOS LADOS —el 44 % de la primera pasada— metía la
     orilla visible en .079 y le cortaba el hocico. Con `0 %` la orilla izquierda
     caía en .000 y entraban la cabeza y las patas delanteras completas; lo que se
     va es el 17.9 % de la derecha, o sea los cuartos traseros y la cola. Mismo
     criterio que el aire de arriba, aplicado al eje de las x.
     HOY VA EN `8 %` Y ESE NÚMERO ES UN TOPE, NO UN GUSTO. Victor la quiso «un
     poquito a la izquierda», que en `cover` es subir la x; pero cada punto de x
     se come .179 puntos de la orilla izquierda, y el hocico empieza en .020. El
     último valor que no lo toca es el 11.2 %, así que el empujón se para en 8 y
     deja .006 de margen — un pelo de foto, pero medido. Más allá de ahí no es un
     encuadre más apretado: es la cabeza cortada que él prohibió por su nombre.
   · PIANO: el grupo mide el 96 % del ancho, faltan 13.9 puntos. Aquí sí se
     reparte (39 %) porque ninguna de las dos cabezas está en un canto: se va la
     pata delantera del perro izquierdo y la cola del derecho, ~7 % cada una.
   · RELOJ: 85 % contra 84.1 % —su maestro es 930×1692 y no 941×1672—. Faltan 0.9
     puntos, 4 px en un teléfono de 390. Se reparten.

   ── LOS CUATRO EMPUJONES DE VICTOR EN EL TELÉFONO, Y HACIA DÓNDE VAN ────────
   «Un poquito. No mucho», mirando las siete en vertical. En `cover` SUBIR LA x
   CORRE EL SUJETO HACIA LA IZQUIERDA —se enseña más del lado derecho de la
   fotografía—, y eso está comprobado mirando los abanicos de cuatro valores por
   escena, no aplicando la fórmula a ciegas:

     CAMA           0 % → 8 %    izquierda, y el 8 es el tope del hocico (arriba)
     RELOJ         67 % → 75 %   izquierda
     PLATA ABRAZO  42 % → 50 %   izquierda; a 66 ella empieza a tocar el canto
     PERLAS        72 % → 64 %   derecha; a 48 el danés izquierdo se corta

   CACHORRO NO SE TOCA: Victor la dio por buena por su nombre. Y el apaisado no
   se toca en ninguna de las siete: estos cuatro números son sólo del bloque
   vertical, que es el que él tiene delante en el teléfono.

   ── RELOJ BAJA DEL 25 % AL 0 % EN VERTICAL, Y NO ROMPE ESTA REGLA: LA ESTIRA ──
   Victor, en el iPhone y con el rótulo de tres alturas ya puesto: «la del reloj
   creo que la tenemos que hacer para abajo, bastante, especialmente si el título
   va a estar arriba». Bajar el SUJETO es exactamente lo mismo que ganar aire
   arriba —`GANAR AIRE ES BAJAR p HACIA EL 0 %`, cinco párrafos más arriba—, así
   que este empujón tira en la MISMA dirección que la regla y no contra ella: el
   0 % es el extremo de la escala, o sea el máximo aire que admite el maestro
   (su techo es 30 %) y el máximo suelo recortado. Lo que se pierde por abajo son
   las patas delanteras del danés echado, que es el precio que la regla ya tenía
   escrito. De las siete, ésta es la ÚNICA que se toca: Victor dice que muchas van
   a necesitar bajar con el título puesto, pero no puede juzgarlas hasta verlo.

   Y en apaisado, a partir de `ab` 2.00 —un monitor ancho con la ventana muy baja—
   PLATA ABRAZO (le faltan 1.7 puntos de alto) y CACHORRO (3.2) no caben enteras.
   Ahí manda la regla del aire: se pierde el suelo y la cabeza se queda.

   ── POR QUÉ LA TABLA VIVE EN EL CSS Y NO EN `ESCENAS` DE `hero.js` ──────────
   Porque el par de números CAMBIA CON LA ORIENTACIÓN, y quien conoce la
   orientación es el CSS. Metidos en el JavaScript harían falta un `matchMedia`,
   una escucha de giro de teléfono y un reescribir del estilo en línea a cada
   cambio — y sobre todo: LA PRIMERA LÁMINA NO PASA POR `hero.js`. Santos vive en
   el `<picture>` de `index.html` y se dibuja con el JavaScript apagado; su foco
   tiene que llegarle por la misma puerta que a las otras seis o serían dos
   verdades. Lo único que pone el JavaScript es la CLASE —`hero__foto--<nombre>`,
   que sale de `esc.nombre` y no se escribe dos veces—, y el `<img>` del index la
   trae puesta a mano. */
/* LA LÁMINA Y SU RECORTE COMPARTEN ESTE BLOQUE ENTERO, Y ESO ES LO QUE LOS DEJA
   ALINEADOS AL PÍXEL. El recorte (§ LA CUARTA CAPA, más abajo) es la MISMA
   fotografía con el alfa del sujeto: si los dos se dibujan con la misma caja, el
   mismo `cover` y el mismo `--foco`, caen uno sobre otro sin una sola coordenada
   que mantener de acuerdo. Dos reglas gemelas serían dos encuadres que alguien
   tendría que acordarse de mover a la vez, y el día que no lo haga el recorte se
   despega de su fotografía por unos píxeles — que es el fallo que menos se
   perdona aquí, porque se ve como un doble borde. */
.hero__foto,
.hero__recorte{
  /* `absolute` Y NO EL `block` DE ANTES, y con una sola lámina dibuja el mismo
     píxel: `.hero__laminas` es `absolute; inset:0` dentro de un `.hero` que es
     `fixed; inset:0`, así que la caja es la misma pantalla completa de siempre.
     Lo que compra es que las láminas se APILEN: dos fotografías en el flujo se
     pondrían una debajo de la otra y el hero mediría dos pantallas. */
  position:absolute; inset:0;
  display:block; width:100%; height:100%;
  object-fit:cover;
  /* EL RESPALDO ES EL DE ANTES —`50% 82%`— y no es decorativo: lo usa cualquier
     lámina que llegue sin clase de escena, que hoy no existe y mañana puede
     existir si alguien añade una fila a `ESCENAS` y olvida su fila de aquí. Una
     lámina sin foco se ve centrada, no rota. */
  object-position:var(--foco, 50% 82%);
  /* EL NÚMERO DEL FUNDIDO NO ESTÁ AQUÍ Y NO ES UN OLVIDO: lo escribe `hero.js`
     en `--hero-fundido` al arrancar, y es el ÚNICO sitio del sitio donde vive
     —`SEGUNDOS_DE_FUNDIDO`, arriba de ese archivo, junto a los segundos por
     lámina—. Un respaldo aquí sería la segunda copia del mismo número, y las dos
     copias se separan el día que Victor cambie una.
     Y SIN JAVASCRIPT LA VARIABLE NO EXISTE, con lo que esta `transition` entera
     es inválida y no hay transición. Es exactamente lo correcto: sin JavaScript
     tampoco hay rotación que fundir, y el hero es el hero quieto de siempre.

     LA CURVA VIENE POR LA MISMA PUERTA Y POR LA MISMA RAZÓN (`--hero-curva`,
     `CURVA_DEL_FUNDIDO` en `hero.js`). Era `linear` hasta el 16 de septiembre de
     2026; ahora es la cúbica in-out que `🔭 Estudio-Horoscopo` cronometró en el
     template que Victor quiso copiar, junto con los 1 178 ms. Una cúbica in-out
     no arranca: se queda quieta, cruza rápido por el medio y se posa, y eso es lo
     que hace que el cambio se lea como un pase de página. Es lo ÚNICO que se
     copió de aquella transición —el efecto era un shader de WebGL— y costó
     0 bytes. */
  transition:opacity var(--hero-fundido) var(--hero-curva);
}
/* ── EL ORDEN DE APILAMIENTO DEL HERO, EN UN SITIO Y CON SU PORQUÉ ────────────
   Cinco capas y cada número está obligado por la de al lado:

     0  `.hero__laminas`   las fotografías
        └ dentro, y sin poder asomar de ahí:
          · los `<img>` de lámina, cuyo z-index sube vuelta tras vuelta
          · `.hero__licua`  EL LIENZO DE LA LÁMINA · sólo durante el relevo
     1  —                  vacío; aquí vivía la lumbre, ver abajo
     2  `.hero::after`     la caída de luz que le da contraste al texto
     3  `.hero__portada` y `.hero__baja`  el texto y el indicador de scroll
     4  `.hero__recortes`  el sujeto recortado, que pasa por DELANTE del texto
        └ dentro, y por el mismo motivo encerrados:
          · los `<img>` de recorte, con el z-index de su lámina
          · `.hero__licua`  EL LIENZO DEL RECORTE · sólo durante el relevo,
            y siempre un peldaño por encima de los `<img>` de esta caja
     5  `.hero__lumbre`    el disco de luz del cursor, por encima de TODO

   LOS DOS LIENZOS SON EL MISMO DIBUJO PARTIDO POR EL TEXTO, y por eso están en
   dos filas de esta tabla y no en una. Durante el relevo el shader dibuja la
   fotografía licuada en el de la fila 0 y el sujeto licuado —la misma pasada con
   el alfa de la máscara— en el de la fila 4, así que el título queda EN MEDIO de
   las dos mitades de una sola imagen. Es la misma portada de revista que hacen
   los `<img>` en reposo, sostenida por las mismas dos cajas mientras dura el
   cruce. Ninguno de los dos tiene contexto WebGL: ver `.hero__licua`, abajo.

   LA LUMBRE SUBIÓ DE 1 A 5 EL DÍA QUE ENTRÓ LA CAPA 4, y es la segunda cosa que
   el recorte rompió sin tocarla. En 1 la luz bañaba la fotografía y NO al sujeto
   recortado, que está tres capas más arriba: el cursor pasaba por encima y la
   silueta se quedaba apagada dentro de un fondo iluminado, o sea PEGADA, que es
   exactamente lo que esta capa existe para evitar. Victor: «también con el mouse
   on hover se ve rarísimo».
   MEDIDO, con el cursor sobre la cabeza del perro de Plata Abrazo y un disco de
   90 px partido por el alfa del recorte: en 1 el sujeto recibía −0.51 RGB —cero,
   la luz le pasaba por debajo— mientras el fondo de al lado recibía +10.50. En 5
   el sujeto recibe +29.09 y el fondo +12.95; más él que el fondo porque `overlay`
   aclara lo claro y la cabeza está a media luz sobre follaje oscuro.
   Arriba del todo la luz baña las cuatro por igual, que es lo que hace una
   lámpara pasando sobre una portada impresa: también alumbra la tinta. Y NO SE
   COME EL TÍTULO — medido con el cursor sobre la R de CRIADERO, sobre los 10 391
   píxeles de tinta de la banda: media 214.2 → 224.2, p99 232 → 249, y CERO
   píxeles quemados a 255. El título se entibia; no pierde un canto.
   EL 1 SE QUEDA VACÍO A PROPÓSITO. La caída de luz podría bajar a ocuparlo —su
   único requisito es ir sobre las láminas y bajo el texto—, pero renumerarla
   sería mover un número que ya está bien por dejar la tabla bonita, y su propio
   comentario cuenta que subió a 2 POR la lumbre. El hueco es esa historia.

   LA CUARTA ES LA QUE HACE DE ESTO UNA PORTADA DE REVISTA. Una portada impresa
   pasa el título por DETRÁS de la cabeza y por DELANTE del fondo, y eso con una
   sola fotografía no se puede: o el texto está encima de todo o está debajo de
   todo. La capa 4 es la misma fotografía otra vez, recortada por el alfa del
   sujeto, y al ir por encima del texto lo tapa exactamente donde hay sujeto y en
   ningún otro sitio. El porqué de cada lámina y sus números están en
   `.hero__recortes`, abajo.

   LA LUMBRE OBLIGÓ A SUBIR LAS DOS DE ARRIBA, y no es cosmética: `mix-blend-mode`
   se funde con lo que hay debajo DENTRO DE SU CONTEXTO DE APILAMIENTO. Si la
   lumbre se quedara empatada con la caída de luz en 1, se fundiría CON ELLA y no
   con la fotografía, que es justo lo que no se quiere. Tiene que ir encima de las
   láminas y debajo de la caída, o sea que la caída sube a 2 y el texto a 3.
   Lo midió `🔭 Estudio-Horoscopo` y es la única trampa del efecto.

   LA CAJA DONDE SE BARAJAN. `z-index:0` —no `auto`— para que sea su propio
   contexto de apilamiento: dentro, `hero.js` sube el z-index de la lámina que
   entra vuelta tras vuelta sin techo, y nada de eso puede asomar por encima de
   las tres capas de arriba. El porqué del `z-index` que sube está en `hero.js`,
   sobre `pasaA()`. */
.hero__laminas{ position:absolute; inset:0; z-index:0; }
/* LA LÁMINA QUE ESPERA SU TURNO. La primera NO lleva esta clase —nace opaca y se
   ve sin una línea de JavaScript—; las demás las crea `hero.js` con ella puesta
   y se la quita al pasarles el turno. */
.hero__foto--espera{ opacity:0; }
/* ── EL FOCO DE CADA ESCENA · VERTICAL ARRIBA, APAISADO ABAJO ────────────────
   El orden de los dos bloques ES la regla: el vertical va primero y sin consulta
   —es el respaldo— y el apaisado lo pisa cuando la ventana es más ancha que alta.
   La frontera es `orientation`, letra por letra la misma que llevan los
   `<source>` del `<picture>` y la que reparte los encuadres en `hero.js`; si
   divergen, el navegador dibuja un encuadre con el foco del otro.
   Las cajas de las que salen estos catorce números están en el comentario
   grande de arriba, con la cuenta para rehacerlos. */
.hero__foto--santos      { --foco: 64% 52%; }
.hero__foto--piano       { --foco: 39% 40%; }   /* no cabe de ancho: reparte */
.hero__foto--reloj       { --foco: 75%  0%; }   /* los dos empujones de Victor; ver abajo */
/* PLATA ABRAZO YA NO ROTA EN VERTICAL —`soloApaisado` en su fila de `hero.js`,
   17-sep-2026, porque su cabeza pisaba el título en los tres teléfonos— así que
   este par NO LO PINTA NADIE HOY. Se queda escrito y no se borra: el encuadre
   vertical de esa escena existe, sus archivos se publican y el día que se la
   devuelva a la rotación este número es el que le toca. Está dicho aquí para que
   nadie pierda una tarde afinando un foco que no se ve. */
.hero__foto--plata-abrazo{ --foco: 50% 24%; }   /* suelo sacrificado · empujón */
.hero__foto--cachorro    { --foco:100% 88%; }
.hero__foto--perlas      { --foco: 64% 56%; }   /* empujón a la derecha */
.hero__foto--cama        { --foco:  8% 16%; }   /* el tope del hocico; ver abajo */
@media (orientation: landscape){
  .hero__foto--santos      { --foco: 83% 82%; }
  .hero__foto--piano       { --foco: 55% 58%; }
  .hero__foto--reloj       { --foco: 10% 64%; }
  .hero__foto--plata-abrazo{ --foco: 52%  6%; }   /* suelo sacrificado; ver arriba */
  .hero__foto--cachorro    { --foco:100% 15%; }   /* suelo sacrificado */
  .hero__foto--perlas      { --foco: 90% 72%; }   /* suelo sacrificado */
  .hero__foto--cama        { --foco: 68% 70%; }
}

/* ── LA CUARTA CAPA · EL SUJETO PASA POR DELANTE DEL TÍTULO ──────────────────
   Victor, señalando la escalinata y el perro plata: «está chocando la I y la A
   con ella… quiero que ella esté enfrente del texto y no detrás». El texto no se
   mueve y la fotografía tampoco: lo que entra es una tercera capa con la MISMA
   fotografía recortada por el alfa del sujeto, encima del texto (§ la tabla de
   apilamiento, arriba).

   ES HERMANA DE `.hero__laminas` Y NO HIJA, y ésa es toda la diferencia: dentro
   de `.hero__laminas` —que es `z-index:0` y su propio contexto de apilamiento—
   ningún número puede asomar por encima del texto, que es justo lo que esta capa
   tiene que hacer. Es la misma razón por la que el mármol SÍ vive ahí dentro,
   leída al revés.

   `pointer-events:none` Y `aria-hidden` EN EL HTML: es la escena que el `alt` de
   la lámina ya describe, dibujada por segunda vez. Ni es contenido nuevo para
   quien la oye, ni tapa el texto para quien lo selecciona — la portada se sigue
   copiando como texto, porque el ratón atraviesa esta capa entera.

   SIN JAVASCRIPT AQUÍ NO HAY NADA. La caja nace vacía en `index.html` y la llena
   `hero.js` con la lámina que esté puesta; si el script no corre, si un recorte
   no baja o si el navegador no entiende ninguno de los dos formatos, esta capa
   se queda vacía y la portada es EXACTAMENTE la de hoy. Es una capa que sólo
   puede añadir. */
.hero__recortes{ position:absolute; inset:0; z-index:4; pointer-events:none; }

/* ── Y EN VERTICAL ESTA CAPA NO EXISTE, POR PARTIDA DOBLE ────────────────────
   MEDIDO el 17-sep-2026 sobre los catorce encuadres: en 390×844 ninguna lámina
   vertical pone sujeto debajo de la tinta —los 9×16 dejan al sujeto en el centro
   del cuadro y las dos palabras caen sobre fondo—, así que en vertical no hay
   nada que tapar. Un teléfono de pie no baja un solo byte de recorte.

   LA MEDIDA NO ES LA GARANTÍA; ESTAS DOS LÍNEAS SÍ. El `media` de los `<source>`
   (§ `hero.js`, `recorte()`) hace que en vertical NO HAYA FUENTE QUE RESOLVER:
   ahí está el cero de bytes, y no depende de que los encuadres sigan sin chocar.
   Y esta regla tapa el otro agujero, que es de píxeles y no de bytes: quien gira
   el aparato DESPUÉS de haber bajado un recorte se queda con el nodo cargado en
   el árbol, y un recorte de 16×9 sobre una lámina de 9×16 cae desplazado —dos
   encuadres distintos, mismo `--foco`—. Con la capa apagada no hay nada que
   desplazar. Las dos hacen falta y ninguna sustituye a la otra. */
@media (orientation: portrait){ .hero__recortes{ display:none; } }

/* EL RECORTE HEREDA SU CAJA Y SU `--foco` DE LA LÁMINA Y NO LOS REPITE. La caja
   sale del bloque que comparte con `.hero__foto` (arriba); el foco, de llevar
   PEGADA la misma clase de escena —`.hero__foto--cachorro` y compañía—, que es
   donde vive el par de números. Por eso aquí abajo no hay ni un `object-position`
   ni una coordenada: si los hubiera serían la segunda copia, y el día que se
   afine un foco el recorte se quedaría en el viejo.

   ── LO QUE NO HEREDA ES EL TIEMPO, Y AHÍ ESTÁ TODO EL EFECTO ────────────────
   El recorte NO entra ni sale con su lámina: sale ANTES de que la fotografía se
   mueva y entra UN COMPÁS DESPUÉS de que se haya asentado. Las dos duraciones
   son suyas y el encadenado vive en `hero.js` (§ LOS TRES TIEMPOS DEL RECORTE),
   que es donde puede haber una PUERTA — el CSS sabe cuánto dura un fundido, pero
   no sabe esperar a que termine antes de dejar correr otra cosa.

   POR QUÉ SALE ANTES, QUE ES LO QUE NO SE PUEDE TOCAR: el relevo de las láminas
   lo dibuja un shader que LICÚA las dos fotografías. Un `<img>` no se licúa, así
   que un recorte que siguiera en pantalla durante la transición se quedaría
   nítido y opaco sobre un fondo derritiéndose. Victor: «durante la transición se
   ven los cutouts… sí, en todas, luego luego se ve».

   LAS DOS DURACIONES VAN EN DOS REGLAS Y NO EN UNA `transition` con dos valores,
   porque una transición se define en el ESTADO AL QUE SE VA: al poner la clase
   manda la duración de salida, al quitarla la de entrada. Escrito así, cada
   número está donde se usa.
   Y SIN JAVASCRIPT LAS VARIABLES NO EXISTEN, la `transition` es inválida y no hay
   transición — que aquí ni siquiera importa, porque sin JavaScript no hay
   recorte que transicionar. */
/* ── Y EL RECORTE NO ES UNA SEGUNDA FOTOGRAFÍA: ES LA MISMA, ENMASCARADA ─────
   El `<img>` de esta capa carga EL MISMO archivo que su lámina —`hero.js` le
   pone los mismos `<source>`— y lo que lo recorta es esta máscara. Antes era una
   copia en color con alfa y SE VEÍA: Victor, «se ve el cutout, como si el
   recorte tuviera otra iluminación». Dos codificaciones de los mismos píxeles no
   dan los mismos píxeles; una máscara sobre la misma fuente sí (el número medido
   está en `hero.js`, sobre `recorte()`).

   LA MÁSCARA TIENE QUE CAER EXACTAMENTE DONDE CAE LA FOTOGRAFÍA, y por eso estas
   tres líneas son el reflejo de las tres de arriba y no se pueden tocar por
   separado:

     object-fit:cover        ←→  mask-size:cover
     object-position:--foco  ←→  mask-position:--foco

   Funciona porque la máscara tiene la MISMA proporción que la lámina (1672×941):
   con la misma caja y la misma proporción, `cover` da la misma escala, y un
   porcentaje de posición significa lo mismo en las dos propiedades —alinear ese
   punto de la imagen con ese punto de la caja—. Si alguien publicara una máscara
   con otra proporción, esto se desalinearía sin avisar.
   `--foco` es el MISMO token que usa la fotografía, así que afinar un foco mueve
   las dos a la vez y no hay nada que mantener de acuerdo.

   EL RESPALDO DE `--alfa` ES UNA MÁSCARA VACÍA Y NO «sin máscara», que es la
   diferencia entre no verse y verse ENTERA. Si por lo que sea la variable no
   llegara, `mask-image` sin valor dejaría el `<img>` completo —la fotografía a
   pantalla partida por encima del título—; con un degradado transparente, no se
   dibuja nada y la portada se queda como si esta capa no existiera. Es el mismo
   trato que el resto del hero: lo que añade, se apaga solo. */
.hero__recorte{
  -webkit-mask-image:var(--alfa, linear-gradient(#0000, #0000));
          mask-image:var(--alfa, linear-gradient(#0000, #0000));
  -webkit-mask-size:cover;                    mask-size:cover;
  -webkit-mask-position:var(--foco, 50% 82%); mask-position:var(--foco, 50% 82%);
  -webkit-mask-repeat:no-repeat;              mask-repeat:no-repeat;
  transition:opacity var(--recorte-entra) var(--hero-curva);
}
.hero__recorte--espera{
  opacity:0;
  transition:opacity var(--recorte-sale) var(--hero-curva);
}

/* ── EL LIENZO DEL MÁRMOL ────────────────────────────────────────────────────
   El `<canvas>` donde `hero-shader.js` licúa las dos fotografías durante el
   cruce. No está en el HTML y no puede estarlo: existe sólo cuando hay
   JavaScript Y WebGL Y no se ha pedido menos movimiento, y `hero.js` lo crea
   dentro de `.hero__laminas` después del primer pintado.

   `display:none` DE ENTRADA Y VISIBLE UN SEGUNDO POR VUELTA. Entre lámina y
   lámina no dibuja nada, así que además de ocultarlo `hero.js` lo baja a 1×1
   para devolver el búfer — ver `duerme()`. Las dos cosas hacen falta: ocultarlo
   sin vaciarlo deja la memoria reservada, y vaciarlo sin ocultarlo enseñaría un
   píxel estirado a pantalla completa.

   VIVE DENTRO DE `.hero__laminas` Y NO SUELTO EN `.hero`, y eso es lo que deja
   la lumbre en su sitio: `.hero__laminas` es `z-index:0` y su propio contexto de
   apilamiento, así que el `z-index` que `hero.js` le sube al lienzo para ponerlo
   por encima de la lámina que entra NO PUEDE asomar por encima del disco de luz
   (1), la caída de luz (2) ni el texto (3). El mármol pasa por debajo de la lumbre,
   que es donde tiene que pasar.

   ── Y SON DOS LIENZOS CON ESTA MISMA CLASE, NO UNO ──────────────────────────
   Esta regla la comparten los dos y por eso está escrita una vez: el de la
   lámina, en `.hero__laminas` (z 0), y el del recorte, en `.hero__recortes`
   (z 4). La frase de arriba —que dentro de `.hero__laminas` nada puede asomar
   por encima del texto— es exactamente la razón de que el segundo esté en la
   otra caja: el recorte tiene que ir por DELANTE del título, y desde aquí dentro
   no se puede. Es la misma pareja de cajas que ya usan `.hero__foto` y
   `.hero__recorte`, y por el mismo motivo.

   NINGUNO DE LOS DOS TIENE CONTEXTO WebGL. Los dos son `bitmaprenderer`:
   enseñan el bitmap que les vuelca el ÚNICO contexto, que vive fuera de pantalla
   (§ `hero-shader.js`). Un segundo WebGL habría costado subir las mismas dos
   láminas otra vez —las texturas no cruzan de un contexto a otro— y un navegador
   sólo deja tener unos pocos contextos. Aquí hay uno y dos ventanas a él, y por
   eso las dos capas no pueden desincronizarse: salen del mismo `pinta()`.

   EL REBOTE DE ARRIBA LOS COGE A LOS DOS por llevar esta clase
   (`body.rebota-cima .hero__licua`, más abajo), que es lo que hay que querer: el
   recorte tiene que estirarse con su fotografía también cuando alguien empuja el
   canto de arriba. */
.hero__licua{
  position:absolute; inset:0;
  display:none;
  width:100%; height:100%;
}
.hero__licua.es-visible{ display:block; }
/* Y MIENTRAS EL MÁRMOL CORRE, LAS LÁMINAS NO SE FUNDEN. El canvas ya está
   tapando la pantalla con las dos fotografías dentro, así que la que entra se
   pone opaca de golpe y debajo: fundir además con CSS sería cruzar dos veces la
   misma pareja y el resultado se ve lavado en el medio. La clase la pone y la
   quita `pasaA()`, y sin ella —o sin JavaScript— la `transition` de siempre. */
.hero__laminas.es-licua .hero__foto{ transition:none; }
/* ── Y EL RECORTE TAMPOCO SE FUNDE MIENTRAS EL SHADER SE LO LLEVA ────────────
   Es la misma regla que la de arriba leída en la otra capa, y es la que convierte
   los dos fundidos del recorte en dos relevos de un cuadro. Con `es-licua`
   puesta, `hero.js` apaga el `<img>` en el mismo acto en que enciende el lienzo
   —y lo enciende en el mismo acto en que apaga el lienzo, al final— sin que
   ninguna de las dos `transition` llegue a arrancar.

   ÉSA ES LA FRASE DE VICTOR, EN UNA LÍNEA DE CSS: «quiero que la vieja ya esté
   ENFRENTE del texto cuando venga la imagen. No quiero que se haga al frente y
   hacia atrás.» Los 120 ms de salida y los 350 de entrada existían porque un
   `<img>` no se puede licuar y había que quitarlo de en medio antes de que la
   fotografía se derritiera. Ahora el recorte se licúa con ella, así que no hay
   nada de lo que apartarse y los dos fundidos sobran.

   NO SE BORRAN `--recorte-sale` NI `--recorte-entra`, y no es por nostalgia: sin
   `OffscreenCanvas` —Safari por debajo de 16.4— el shader no puede llevarse el
   recorte, esta clase no se pone y la coreografía de tres tiempos es la que
   corre, entera. Ver `llevaElShaderElRecorte()` en `hero.js`. */
.hero__recortes.es-licua .hero__recorte{ transition:none; }

/* ── LA LUMBRE · UN DISCO DE LUZ QUE SIGUE AL CURSOR ─────────────────────────
   El efecto que Victor mandó copiar del template del horóscopo, y el único de
   aquella página que se copia ENTERO: un degradado radial blanco fundido en
   `overlay`, que es el modo que aclara lo claro y respeta lo oscuro — o sea que
   sobre esta fotografía se lee como una linterna suave y no como un velo. Medido
   por `🔭 Estudio-Horoscopo`: +33.9 de RGB a 100 px del centro y +0.3 a 350, con
   lo que la caída muere dentro del disco y no ensucia el resto de la pantalla.

   CERO BYTES DE DESCARGA. El template gasta 4.8 KB comprimidos de `mousetrap.js`
   para esto; aquí el degradado y la fusión son CSS y del JavaScript sólo salen
   `--lx` y `--ly`, que es dónde está el cursor.

   NUEVE PARADAS Y NO LAS TREINTA Y UNA DEL ORIGINAL. Las suyas son una sinusoide
   muestreada por su editor; con nueve la caída no se escalona y son 300 B en vez
   de 1 100.

   `display:none` DE ENTRADA Y SE ENCIENDE POR CAPACIDAD DEL PUNTERO. En un
   teléfono este `<div>` no se dibuja NUNCA —ni una capa, ni un byte— y no hay
   sustituto táctil, que es deliberado: un efecto cuyo argumento es «dónde está el
   cursor» no tiene traducción en un dedo. El template lo deja en
   `visibility:hidden`, que es pagar el nodo para no verlo.

   Y CON `prefers-reduced-motion` DESAPARECE. El template NO lo respeta —está
   verificado en el informe—; aquí el `display:none` gana a la consulta de puntero
   por venir después, y `hero.js` además no escribe las variables. */
.hero__lumbre{
  display:none;                 /* ← sólo con puntero fino, dos reglas más abajo */
  position:absolute; inset:0; z-index:5;
  pointer-events:none;          /* no se toca: es luz, no un control */
  opacity:0;
  /* `overlay` SOBRE TODO EL HERO y no sólo sobre la lámina, y por eso z-index 5.
     `mix-blend-mode` se funde con lo que hay DEBAJO dentro de su contexto de
     apilamiento, así que el número decide a quién alumbra: en 1 alumbraba la
     fotografía y dejaba apagado al sujeto recortado (capa 4). El porqué completo
     y la medida sobre la tinta del título están en la tabla de apilamiento, sobre
     `.hero__laminas`. */
  mix-blend-mode:overlay;
  transition:opacity var(--lumbre-fundido) var(--lumbre-curva);
}
/* EL DISCO VA EN EL PSEUDOELEMENTO Y NO EN LA CAJA, y es lo que deja animar dos
   cosas por separado con la misma curva: la caja hace el `opacity` y el disco el
   `scale`. Sin el `scale` la lumbre no APARECE, se enciende — y esa mitad del
   gesto es la que se nota. */
.hero__lumbre::before{
  content:''; position:absolute;
  width:var(--lumbre-d); height:var(--lumbre-d);
  /* `--lx`/`--ly` las escribe `hero.js` en píxeles de ventana. El respaldo es el
     centro: si el script no corre, el `<div>` está en `opacity:0` y no se ve
     nada, pero un `left` sin valor sí sería un error de sintaxis que se llevaría
     por delante la regla entera. */
  left:var(--lx, 50%); top:var(--ly, 50%);
  transform:translate(-50%, -50%) scale(var(--lumbre-s, 0));
  transition:transform var(--lumbre-fundido) var(--lumbre-curva);
  border-radius:50%;
  background:radial-gradient(circle,
    rgba(255,255,255,.80) 0%,  rgba(255,255,255,.66) 17%, rgba(255,255,255,.44) 30%,
    rgba(255,255,255,.20) 43%, rgba(255,255,255,.08) 52%, rgba(255,255,255,0)  65%,
    rgba(255,255,255,0) 100%);
}
/* LOS TRES NÚMEROS DEL GESTO, JUNTOS Y CON SU PROCEDENCIA. El diámetro y el medio
   segundo salen del template medido; la curva es LA MISMA del fundido de las
   láminas, y que sean la misma es la decisión: la portada tiene un solo
   temperamento y no dos.

   AQUÍ SÍ SE ESCRIBE LA CURVA A MANO y en `.hero__foto` no. No es una
   incoherencia: aquél es el número que Victor cambia —vive arriba de `hero.js`,
   con los segundos por lámina— y éste es una constante del efecto. Un valor que
   sólo se toca aquí no gana nada por dar un rodeo por el JavaScript, y perdería
   lo único que importa: que la lumbre se vea igual con el script apagado... que
   es que no se vea, porque sin `--lx` no hay nada que encender. */
.hero__lumbre{
  --lumbre-d:700px;
  --lumbre-fundido:500ms;
  --lumbre-curva:cubic-bezier(.645, .045, .355, 1);
}
@media (hover: hover) and (pointer: fine){
  .hero__lumbre{ display:block; }
}
/* `.tiene-lumbre` LA PONE `hero.js` y sólo cuando va a poder mover el disco. Sin
   JavaScript el `:hover` no llega aquí y no se enciende nada — que es lo correcto:
   encendido y quieto en el centro de la pantalla se vería peor que apagado. */
.hero.tiene-lumbre:hover .hero__lumbre{ opacity:1; }
.hero.tiene-lumbre:hover .hero__lumbre::before{ --lumbre-s:1; }
@media (prefers-reduced-motion: reduce){
  .hero__lumbre{ display:none; }
}

/* ── EL CANTO DE ARRIBA · LA FOTOGRAFÍA ACUSA EL EMPUJÓN ──────────────────────
   Arriba del todo el único elemento agarrable es la lámina, así que el empujón
   contra el borde superior lo acusa ELLA, creciendo un pelo contra el dedo como
   una fotografía que se aprieta y no cede. Es el gesto de las cabeceras de foto
   de las aplicaciones, que es literalmente como lo pidió Victor.

   Y AQUÍ SIGUE LA REGLA DURA DE AQUELLA LANE, que ahora vale igual: EL MUELLE DE
   ARRIBA SÓLO PUEDE REBASAR HACIA ARRIBA. `--cima` está topado en 0 por el
   script, así que esta escala nunca baja de 1. Una escala de 0.99 sobre un
   elemento a pantalla completa dentro de un `fixed` ABRE UN MARCO en los cuatro
   cantos, y por ese marco se ve lo que haya debajo del hero — que es el agujero
   de dceb633 y de 1431d9e por una puerta nueva.

   VA COLGADO DE UNA CLASE Y NO COMO `transform:scale(1)` PERMANENTE: en reposo la
   lámina no lleva transform ninguno y no cuesta una capa mientras nadie empuja.
   Antes esto vivía sobre `.hero__lienzo`, el `<div>` que envolvía el canvas del
   tríptico; el elemento cambió de nombre y de naturaleza, el gesto no. */
body.rebota-cima .hero__foto,
body.rebota-cima .hero__licua{
  transform:scale(calc(1 + var(--cima, 0) * var(--lamina, .015)));
  transform-origin:50% 50%;
}

/* ── LA CAÍDA DE LUZ · LOS DOS CANTOS DE LA FOTOGRAFÍA, DE PUNTA A PUNTA ─────
   NO ES ATMÓSFERA: ES CONTRASTE, Y SALE DE UNA MEDIDA. El texto de la portada ya
   no vive en una esquina: son tres alturas CENTRADAS —membrete y marca pegados al
   canto de arriba, oficio pegado al de abajo—, y debajo de cada una puede caer
   cualquier cosa de siete fotografías distintas. Medido sobre las capturas, la
   crema de la casa (#e8ddc8, L 0.7303) pide un fondo de L ≤ 0.1234 para llegar a
   4.5:1, y el canto de arriba de CACHORRO es #9e9387 (L 0.2988): sobre él la
   palabra da 2.19:1 sin nada debajo. Ilegible, y no en un caso raro — es el borde
   entero de la lámina más clara de las siete.

   ── POR QUÉ ES UN DEGRADADO DE CANTO A CANTO Y NO UNA VIÑETA ────────────────
   Hasta hoy esto era una elipse anclada en `0% 100%`, la esquina de abajo a la
   izquierda, porque ahí y sólo ahí había texto. Con el texto centrado esa elipse
   no sirve para nada: cae fuera de las tres alturas nuevas y deja el membrete y
   las dos palabras grandes a la intemperie. Y una elipse CENTRADA tampoco vale,
   que fue el segundo intento y el que Victor vio y nombró: «lo horripilante que
   es la pinche mancha negra». Una elipse sobre un texto es una MANCHA — tiene
   forma, tiene centro y se ve —, y da igual que el contraste salga bien.

   LO QUE NO SE VE ES LA CAÍDA DE LUZ DE UNA PORTADA IMPRESA: los dos cantos
   horizontales oscurecidos ENTEROS, sin centro y sin forma, apagándose hacia el
   medio a lo largo de casi media pantalla. No hay canto que detectar porque no
   hay un sitio donde el degradado empiece: empieza en el borde del papel. Es
   exactamente lo que hace la fotografía de la referencia por sí sola —su borde
   superior es oscuro y por eso GRAN se lee sin una caja detrás—, y aquí se
   fabrica para las siete, incluidas las dos que no lo traen puesto.

   ── LAS CIFRAS ────────────────────────────────────────────────────────────
   `.64` en el canto y paradas hasta cero en el 52 %. El .64 sale de la peor
   medición: sobre #9e9387 un negro al 36 % ya cruza el 4.5:1, y de ahí al .64 hay
   el margen que se come el rebote de arriba —que enseña ese mismo canto— y la
   mancha de sol de RELOJ. Las paradas son lo que borra el escalonado: con tres,
   la caída se ve a bandas en un degradado tan largo. Y el 52 % es el punto en que
   las dos caídas se encuentran en cero, o sea que en el medio de la pantalla la
   fotografía está intacta.

   ── LA MITAD OSCURA SE MIDE CON LA PALABRA Y NO CON LA VENTANA ─────────────
   Y ÉSTE ES EL CAMBIO DEL 17 DE SEPTIEMBRE. Las paradas de la rampa estaban
   TODAS en porcentajes de la ventana —10, 20, 30, 40, 52— y eso era verdad
   mientras la palabra de arriba midiera siempre lo mismo. Desde que las dos
   palabras permutan con el idioma (§ index.html, EL SÁNDWICH) la de arriba mide
   cosas distintas: a 1440×900, CRIADERO son 207.4 px de cuerpo contra los 167.8
   de GRAN DANÉS, porque cruza el mismo 88 % del ancho con dos letras menos. Un
   24 % más alta.

   Y ESO SE PAGÓ EN EL CONTRASTE, MEDIDO: el pie de GRAN DANÉS caía en el 20.8 %
   del alto, donde la caída vale .43; el de CRIADERO cae en el 24.8 %, donde vale
   .35. Sobre el ventanal de Santos —el píxel más claro que hay bajo una letra en
   todo el sitio— eso es la diferencia entre 4.86:1 y 3.86:1. La palabra no se
   salía de la caída: se salía de la parte OSCURA de la caída.

   La cura es que la rampa deje de contar en porcentajes de ventana hasta el pie
   de la palabra: `--pie-arriba` y `--pie-abajo` (§ los tokens del cuerpo, arriba)
   dicen dónde acaba cada palabra, y hasta ahí la caída no baja de `.44` — el
   valor con el que la peor escena pasa con margen. De ahí al 52 % sigue la cola
   de siempre, con sus paradas repartidas por interpolación entre el pie y el
   final, así que el degradado acaba donde acababa, se apaga igual de largo y no
   aparece un canto en ningún sitio. LO ÚNICO que cambia es que el tramo oscuro
   se estira o se encoge con la palabra que tiene encima, en vez de describir una
   que ya no está.

   El día que alguien cambie una palabra, un idioma o el tope de `26svh`, esto se
   entera solo. No hay un porcentaje que volver a medir.

   `pointer-events:none` porque no hay nada que tocar aquí, y `z-index:2` para
   quedar entre la lumbre y el texto — la tabla del apilamiento está arriba,
   sobre `.hero__laminas`, y ahí se explica por qué este número era 1 hasta que
   entró la lumbre. */
.hero::after{
  content:''; position:absolute; inset:0; z-index:2; pointer-events:none;
  background:
    /* el canto de ARRIBA, oscuro hasta el pie de su palabra y luego la cola */
    linear-gradient(to bottom,
      rgba(0,0,0,.64) 0%,
      rgba(0,0,0,.56) calc(var(--pie-arriba) * .5),
      rgba(0,0,0,.44) var(--pie-arriba),
      rgba(0,0,0,.26) calc(var(--pie-arriba) + (52% - var(--pie-arriba)) * .38),
      rgba(0,0,0,.10) calc(var(--pie-arriba) + (52% - var(--pie-arriba)) * .70),
      rgba(0,0,0,0)   52%),
    /* y el de ABAJO, la misma cuenta contra la cabeza de la suya */
    linear-gradient(to top,
      rgba(0,0,0,.64) 0%,
      rgba(0,0,0,.56) calc(var(--pie-abajo) * .5),
      rgba(0,0,0,.44) var(--pie-abajo),
      rgba(0,0,0,.26) calc(var(--pie-abajo) + (52% - var(--pie-abajo)) * .38),
      rgba(0,0,0,.10) calc(var(--pie-abajo) + (52% - var(--pie-abajo)) * .70),
      rgba(0,0,0,0)   52%);
}

/* ══ LA PORTADA ══════════════════════════════════════════════════════════════
   Membrete, palabra grande, fotografía, palabra grande. El porqué de la
   composición está en `index.html`, sobre su marcado; aquí viven las medidas.

   UNA SOLA CAJA A SANGRE Y `space-between`, y eso es lo que hace el sándwich: la
   cabecera se planta contra el canto de arriba, el oficio contra el de abajo y el
   hueco de en medio —la fotografía— es lo que sobra. Con tres cajas posicionadas
   por su cuenta ese hueco sería la resta de tres números y cambiaría de signo en
   cuanto el cuerpo de una palabra creciera; aquí no hay resta que hacer.

   `--garalda` SE DECLARA AQUÍ y no se hereda, por lo mismo que en el conmutador
   de idioma: el token vive en `.concursos` —donde lo declara `concursos.css`— y
   fuera de ese árbol no resuelve. Sin esta línea la portada entera sale en Times.

   SE PUEDE SELECCIONAR, y por eso NO lleva `pointer-events:none`: es texto de
   verdad y se copia como texto de verdad. Que cubra el hero entero no le quita el
   hover a nadie —la lumbre escucha en `.hero`, y un evento sobre un hijo pasa por
   el padre— ni tapa ningún control, porque dentro del hero no hay ninguno. */
/* EL AIRE LO ABRE EL ÚLTIMO HIJO, Y ESA ES LA CURA DE UNA CAJA QUE SOBRABA.
   Aquí había `justify-content:space-between` sobre DOS hijos, y el segundo hijo
   era una caja `.hero__portada__cabeza` que existía sólo para que el membrete y
   la palabra de arriba contaran como uno: con tres hijos sueltos, el reparto
   abría hueco TAMBIÉN entre el membrete y su palabra, que es justo lo que no
   puede pasar.

   Esa caja se ha ido, y no por limpieza: **estorbaba.** Desde que las dos
   palabras grandes cambian de sitio con el idioma, la que está arriba no es
   siempre la misma —en español el oficio, en inglés la raza (§ index.html, EL
   SÁNDWICH)— y una caja que envuelve «la de arriba» obligaría a mover un nodo
   DENTRO y FUERA de ella en cada cambio de idioma. Con los tres hijos sueltos,
   el intercambio es lo que tiene que ser: dos hermanos que permutan.

   El reparto se hace sin contar hijos: todos se apilan arriba y el ÚLTIMO abre
   el hueco con `margin-top:auto`. El último es siempre la palabra de abajo, en
   los dos idiomas y con el JavaScript apagado, porque el intercambio es un
   `insertBefore` y no un `order`. El aire entre el membrete y su palabra lo pone
   el membrete con su propio `margin-bottom`, que es de quien era el `gap`. */
.hero__portada{
  position:absolute; inset:0; z-index:3;
  display:flex; flex-direction:column; justify-content:flex-start;
  align-items:center; text-align:center;
  padding:var(--portada-techo) clamp(.6rem, 2.5vw, 2rem) var(--portada-suelo);
  --garalda:"Cormorant Concursos", Garamond, "Hoefler Text", "Times New Roman", serif;
}
.hero__portada > :last-child{ margin-top:auto; }

/* LOS TOKENS DEL CUERPO CUELGAN DE `.hero` Y NO DE LA PORTADA, y no es un gusto:
   el indicador de scroll es HERMANO de la portada, no hijo, y una custom property
   viaja hacia abajo pero nunca de lado. Puesto en la portada, `.hero__baja` no
   podría leer el cuerpo de la palabra que tiene que esquivar y el número volvería
   a estar tecleado dos veces. El único ascendiente de los dos es `.hero`.

   ── EL CUERPO DE LAS DOS PALABRAS GRANDES, Y DE DÓNDE SALE ────────────────
     LA PALABRA CRUZA LA PANTALLA, así que su cuerpo no es un número elegido: es
     el que hace que ESA palabra mida el 88 % del ancho. Y eso depende de cuántos
     ems ocupa la palabra, que cambia con cada idioma — KENNEL son seis letras y
     CRIADERO ocho, y con un cuerpo común la inglesa se quedaría a un tercio del
     ancho de la española.

     `--em-*` ES EL ANCHO DE LA PALABRA EN EMS, MEDIDO Y NO CALCULADO. Se saca
     pintándola a 100 px con este mismo tracking y dividiendo el ancho por 100:

         GRAN DANÉS 7.55    GREAT DANE 7.44    CRIADERO 6.11    KENNEL 4.54

     Si mañana cambia una de las cuatro palabras, ESTE es el número que hay que
     volver a medir; el cuerpo sale solo. Y si alguien lo olvida, lo que se ve es
     una palabra corta o desbordada —un fallo que se ve—, no un silencio.

     EL TOPE ESTÁ EN `svh` Y NO EN PÍXELES porque lo que topa es el reparto de la
     pantalla, no el tamaño de la letra: en una ventana apaisada y baja —un iPhone
     tumbado, 844×390— el 88 % del ancho serían 122 px de cuerpo y la palabra de
     abajo se comería el 29 % del alto ella sola. Con el tope en 26svh las dos
     puntas juntas nunca pasan de la mitad de la pantalla y la fotografía conserva
     la otra mitad, que es la que trae los perros. */
.hero{
  /* el relleno de la portada vive aquí por lo mismo que el cuerpo: el indicador
     de scroll se aparta del canto de abajo con ESTE número y no con una copia */
  /* LA BANDA QUE EL CONMUTADOR DE IDIOMA SE RESERVA EN EL CANTO DE ARRIBA, y la
     razón de que sea un token y no una cuenta mental: el membrete está CENTRADO y
     el conmutador vive a la derecha, así que lo que impide que se pisen no es un
     hueco sino un ANCHO MÁXIMO —lo que sobra del centro hacia los dos lados—. Con
     la cuenta escrita en la cabeza el choque no se ve venir: a 320 px el membrete
     medía 225.9 px, la banda empieza en x=243 y «ESPAÑOL» caía encima de
     «KENNEL ·». Medido y fotografiado, no razonado.

     4.1rem = 65.6 px, y sale de medir el conmutador a la anchura en que aprieta:
     a 320 px su canto izquierdo cae en x=257.3, o sea que ocupa 62.7. El token
     lleva 2.9 px de más A PROPÓSITO: es el tope de un rótulo centrado, así que lo
     que garantiza es que ni creciendo hasta el tope entre en la banda. Si alguien
     le cambia a «ESPAÑOL» el cuerpo, el tracking o el relleno, ESTE es el número
     que hay que volver a medir — y se mide con `getBoundingClientRect`, no
     sumando. */
  --banda-idioma:4.1rem;
  /* ── EL RELLENO DE LA PORTADA, Y POR QUÉ DEJÓ DE SER UNA CIFRA FIJA ────────
     Victor, con la portada abierta en un teléfono: «el de arriba bajarlo un
     poquito y el de abajo subirlo un poquito, porque siento que queda sin
     espacio lo de English». Las dos mitades de la queja son la misma cuenta y
     las dos se ven en la medida, no en la opinión. MEDIDO a 390×844 con los
     números viejos —.95rem arriba y .35rem abajo, fijos a cualquier altura—:

         conmutador ENGLISH    5 → 32 px
         membrete             15 → 29 px     ← DENTRO del rango del conmutador
         CRIADERO empieza en  39 px
         GRAN DANÉS acaba en 838 de 844      ← 5.6 px de aire

     El de arriba no era un problema de aire sino de RENGLÓN: el membrete y el
     conmutador ocupaban la misma banda vertical, así que el ojo los leía como
     una sola línea apretada y «ENGLISH» parecía el final del membrete en vez de
     un control aparte. No se tocan —de eso se encarga `--banda-idioma`, que es
     un ancho— pero compartir altura basta para que se vean encima.

     Y el de abajo eran 5.6 px de aire bajo una palabra de 41 px de alto. En el
     iPhone sin botón eso lo salva `env(safe-area-inset-bottom)`, que suma 34;
     en cualquier Android sin barra de gesto, no lo salva nadie.

     LA CURA ES QUE LOS DOS RELLENOS MIDAN LA VENTANA y no un `rem` suelto, con
     un SUELO en el número viejo. A 390×844 el término en `svh` gana y da 35.4
     arriba y 21.9 abajo: el membrete arranca en 35 —tres píxeles por debajo de
     donde acaba el conmutador, o sea dos renglones de verdad— y la palabra de
     abajo se despega a 22. En apaisado —844×390, la ventana más baja del
     parque— el `svh` queda POR DEBAJO del suelo, así que ahí manda .95/.35 y esa
     composición no pierde un píxel de fotografía: es donde el aire escasea y es
     justo donde esto no cambia nada.

     Los topes de 2.3rem y 1.4rem son para que en una pantalla alta de verdad el
     relleno no siga creciendo y separe las dos puntas del sándwich.

     Y NO HAY QUE TOCAR NADA MÁS: la caída de luz (`--pie-arriba`, `--pie-abajo`)
     y el indicador de scroll cuelgan de estos dos tokens, así que se enteran
     solos. */
  --portada-techo:calc(clamp(.95rem, 4.2svh, 2.3rem) + env(safe-area-inset-top, 0px));
  --portada-suelo:calc(clamp(.35rem, 2.6svh, 1.4rem) + env(safe-area-inset-bottom, 0px));
  /* EL CUERPO DEL MEMBRETE Y EL AIRE QUE LO SEPARA DE SU PALABRA, COMO TOKENS Y
     NO COMO DOS CIFRAS TECLEADAS DOS VECES. Las dos las consume el membrete —una
     es su `font-size`, la otra su `margin-bottom`— y las dos las necesita además
     la caída de luz para saber dónde acaba la palabra de arriba (§ `--pie-arriba`).
     El cuerpo es EL MISMO `clamp` que `.cintillo` declara en `concursos.css`: se
     repite aquí porque desde ahí no se puede leer, y se declara como token para
     que no haya una TERCERA copia dentro del degradado. */
  --cuerpo-membrete:clamp(.62rem, .82vw, .78rem);
  --aire-membrete:clamp(.4rem, 1.2svh, .9rem);
  --em-marca:7.55;
  --em-oficio:6.11;
  /* ── EL TECHO BAJA DE 26svh A 16svh, Y ESTO SE LO COMÍA LA FOTOGRAFÍA ──────
     Victor, con la portada abierta en una ventana ancha: «el font está enorme,
     no te deja ver las putas fotos». Y la cuenta le da la razón — MEDIDO en su
     ventana, 2000×1000:

         CRIADERO    min(88vw/6.11 = 288.1,  26svh = 260.0)  →  260.0 px
         GRAN DANÉS  min(88vw/7.55 = 233.1,  26svh = 260.0)  →  233.1 px
         las dos                                                493 px de 1000

     O sea el 49 % de la pantalla en letras. Y no era un descuido: la nota de
     este bloque decía «las dos puntas juntas nunca pasan de la MITAD de la
     pantalla» como si fuese el límite seguro. Media pantalla ERA el problema.
     Una portada de revista pone el título sobre la fotografía; no la tapa.

     CON 16svh SON 320 px DE 1000 — el 32 %, y a la fotografía le quedan dos
     tercios. En 1440×900 pasa de 375 a 288 px por el mismo camino.

     Y SE TOCA EL TECHO, NO EL 88vw, QUE ES LA MITAD QUE IMPORTA. Los dos
     términos del `min` gobiernan en ventanas distintas: en un TELÉFONO manda el
     ancho (88vw/7.55 = 45.5 px, muy por debajo de cualquier svh) y en una
     ventana ANCHA manda el alto. Bajar el 88vw habría encogido la portada del
     teléfono, que es la que Victor ya había dado por buena; bajar el techo
     muerde exactamente donde la ventana es ancha y baja, que es donde la
     fotografía se estaba quedando sin sitio. El teléfono no cambia un píxel. */
  --cuerpo-marca: min(calc(88vw / var(--em-marca)),  16svh);
  --cuerpo-oficio:min(calc(88vw / var(--em-oficio)), 16svh);
  /* ── Y QUÉ CUERPO TIENE LA PALABRA DE ABAJO, QUE YA NO ES SIEMPRE LA MISMA ──
     Los cuatro tokens de arriba miden PALABRAS: cada uno cuelga de su texto y no
     se entera de dónde cae. Éste mide un SITIO —el renglón de abajo del hero— y
     por eso es el único que cambia de dueño con el idioma: en español abajo va la
     raza, en inglés el oficio (§ index.html, EL SÁNDWICH).

     EXISTE PORQUE ALGUIEN LO LEE DE FUERA. El indicador de scroll se planta justo
     encima de esa palabra y hasta hoy leía `--cuerpo-oficio` directamente, lo cual
     era verdad mientras el oficio estuviera siempre abajo. Desde que las dos
     palabras permutan, ese nombre habría descrito la palabra equivocada en
     español y el icono se habría plantado encima de GRAN DANÉS con la altura de
     CRIADERO — un choque que nadie vería venir leyendo el token. Separar las dos
     preguntas —«¿cuánto mide esta palabra?» y «¿qué palabra va abajo?»— es lo que
     impide que vuelva a pasar. */
  --cuerpo-arriba:var(--cuerpo-oficio);
  --cuerpo-abajo:var(--cuerpo-marca);
  /* ── Y HASTA DÓNDE BAJA CADA PALABRA, QUE ES LO QUE LA CAÍDA DE LUZ TIENE QUE
     CUBRIR ──────────────────────────────────────────────────────────────────
     El pie de la palabra de arriba y la cabeza de la de abajo, contados desde su
     canto: el relleno de la portada más la caja de la palabra, que es su cuerpo
     por el .92 de su interlínea.

     LOS DOS LADOS NO SON SIMÉTRICOS, Y ESO COSTÓ UNA MEDIDA. Abajo la palabra es
     lo último que hay antes del relleno, así que su cabeza es relleno + caja y
     se acabó — es la misma cuenta con la que el indicador de scroll se planta.
     ARRIBA hay DOS alturas por encima de la palabra: el membrete y el aire que
     lo separa de ella. Contando sólo relleno + caja, el pie salía 28.5 px alto a
     1440×900 y la caída se aclaraba ANTES de acabarse la palabra: medido, GREAT
     DANE sobre Cachorro caía de 4.26 a 4.08 en vez de subir. Las dos alturas que
     faltaban entran aquí por sus tokens, no por una cifra copiada. */
  --pie-arriba:calc(var(--portada-techo) + var(--cuerpo-membrete) * 1.5
                    + var(--aire-membrete) + var(--cuerpo-arriba) * .92);
  --pie-abajo: calc(var(--portada-suelo) + var(--cuerpo-abajo) * .92);
}
/* EL INGLÉS MIDE OTRA COSA, Y ADEMÁS LAS PONE AL REVÉS. `pon()` cambia el texto,
   intercambia los dos nodos y escribe `lang` en el <html> (index.html, al final),
   así que el CSS se entera del idioma sin que nadie le avise. Sin JavaScript el
   documento se queda en `lang="es"`, que es lo que trae escrito, y los números de
   arriba son los correctos. */
:root[lang="en"] .hero{
  --em-marca:7.44; --em-oficio:4.54;
  --cuerpo-arriba:var(--cuerpo-marca);   /* en inglés arriba va GREAT DANE */
  --cuerpo-abajo:var(--cuerpo-oficio);   /* y abajo KENNEL */
}



/* ── EL MEMBRETE ─────────────────────────────────────────────────────────────
   Una línea fina de versalitas en lo alto que dice qué es esto, dónde está y
   desde cuándo. Lleva `.cintillo` PEGADO en el HTML, así que el tracking, las
   mayúsculas, el cuerpo y el `wght` 600 le llegan de `concursos.css`; aquí sólo
   está lo que cambia respecto de un cintillo cualquiera.

   YA NO SE APARTA DEL CONMUTADOR DE IDIOMA, y esa es la mitad de lo que se
   simplifica al centrarlo: antes vivía anclado a la izquierda con un `max-width`
   calculado para dejarle libre la banda del conmutador. Centrado, el ancho que
   ocupa se reparte por los dos lados y en la ventana más ancha en que cabe de una
   pieza —701 px— su canto derecho queda a 42 px del conmutador. La cuenta se cae
   sola y no hay nada que esquivar.

   Y NO TRAE VIÑETA. Tuvo una —una elipse negra dibujada sobre una caja mayor que
   el texto— y era la segunda de las dos manchas que Victor mandó quitar. El
   contraste lo da ahora la caída de luz del canto de arriba, que es la misma para
   las tres alturas y no dibuja una forma detrás de ninguna. Las siete mediciones,
   en `Taller/Auditoria/Hero-Portada · Informe.md`.

   EL `text-indent` COMPENSA EL TRACKING: abre por la DERECHA de la última letra,
   así que una línea centrada se ve corrida media unidad hacia la izquierda. Se
   devuelve la MITAD, que es lo que sobra por ese lado. */
.hero__membrete.cintillo{
  /* EL AIRE BAJO EL MEMBRETE ES ESTE MARGEN, y era el `gap` de la caja
     `.hero__portada__cabeza` que se retiró al hacer que las dos palabras grandes
     permuten con el idioma (§ arriba, sobre `.hero__portada`). Mismo `clamp`, y
     va AQUÍ y no en una regla `.hero__membrete` suelta: el `margin:0` de esta
     misma declaración tiene dos clases y le ganaría, dejando las dos alturas
     pegadas sin que nada lo avise. Medido: el título subía 10.8 px a 1440×900 y
     se metía más dentro del ventanal de Santos, o sea que el descuido salía
     directamente en el contraste.

     Va en el membrete y no en la palabra porque el membrete es siempre el mismo
     nodo, y la palabra que tiene debajo cambia con el idioma. Sale de un token
     porque la caída de luz también tiene que sumarlo para saber dónde acaba la
     palabra de arriba. */
  margin:0 0 var(--aire-membrete);
  /* el mismo cuerpo que `.cintillo` declara, dicho por el token del que también
     tira `--pie-arriba`; ver arriba */
  font-size:var(--cuerpo-membrete);
  /* EL ANCHO MÁXIMO ES LO QUE LO APARTA DEL CONMUTADOR, y por eso se resta la
     banda DOS veces: el rótulo está centrado, así que lo que gana por un lado lo
     gana también por el otro. Restarla una sola vez dejaría el canto derecho
     justo encima de «ESPAÑOL». Y si algún día no cupiera, la línea caería en tres
     renglones —un fallo que se ve— en vez de solaparse en silencio.

     92 % Y NO UN `ch`: el `ch` mide la cifra CERO de la fuente y este rótulo va a
     .34em de tracking, o sea que cada carácter ocupa casi el doble de un `ch`.
     Un `max-width:60ch` partía en dos la línea a 1440 px, donde cabe de sobra. */
  max-width:min(92%, calc(100vw - 2 * var(--banda-idioma)));
  line-height:1.5;
  color:var(--tinta);
  text-shadow:0 0 .35em rgba(0,0,0,.72), 0 0 1.1em rgba(0,0,0,.62),
              0 .1em 2.2em rgba(0,0,0,.45);
  text-indent:.17em;
}
/* AQUÍ VIVÍA EL CORTE POR MEDIA QUERY —`.hero__membrete br{display:none}` y su
   `@media (max-width:700px)`— y se ha retirado con el `<br>` que escondía. El
   membrete perdió el oficio y la raza, cabe de una pieza hasta 320 px, y lo que
   decide si parte es ahora el hueco: los `&nbsp;` del texto dejan un único sitio
   partible, el que sigue al `·`. El porqué entero está sobre el marcado, en el
   index. Una anchura tecleada menos que mantener al día.

   EL TRACKING CEDE DONDE EL HUECO YA NO DA, y eso SÍ sigue en pie. A 320 px el
   ancho máximo son 188.8 px —320 menos las dos bandas del conmutador— y
   «PUEBLA, MÉXICO · DESDE 2012» mide 225.9 px con el .34em de un cintillo
   cualquiera. A .18em mide 186.6 en español, que es el largo de los dos, y entra
   con 1.1 px por lado: apretado, y por eso los `&nbsp;` dejan la salida abierta
   en vez de confiar en el margen. Medido en el sitio a 320, no calculado: el
   `.34em` estira una versal corta mucho más de lo que parece. Y el `100vw` del
   ancho máximo NO es un `100%`: el padre es una caja de anchura ajustada al
   contenido, así que un porcentaje ahí se muerde la cola y el tope salía 20 px
   corto. */
@media (max-width:560px){ .hero__membrete.cintillo{ letter-spacing:.18em; } }

/* ── LAS DOS PALABRAS GRANDES ────────────────────────────────────────────────
   Las dos son la MISMA regla porque son la misma pieza vista dos veces: el
   sándwich de la portada. Lo único que las distingue es el cuerpo, y el cuerpo
   sale de cuántos ems mide cada palabra (§ arriba, `--em-*`).

   MAYÚSCULAS CON TRACKING Y NI UNA VERSALITA, que es la regla de la casa desde
   que Victor vio el A/B: `text-transform:uppercase`, nunca `font-variant-caps`.

   `wght` 300 Y NO EL 500 DE ANTES, y no es un capricho: 500 era el peso de un
   rótulo de 40 px donde el asta fina todavía necesita ayuda. Aquí el cuerpo pasa
   de 200 px en una ventana de escritorio, y a ese tamaño el grueso de un 500
   tapa justo el contraste de asta que hace que una garalda sea una garalda. 300
   es el extremo ligero del eje real de Cormorant (§ `@font-face`, 300 700) y es
   el peso de una portada impresa.

   `letter-spacing:.14em` — tracking generoso, que es lo que separa un titular de
   una palabra grande. Cuesta ancho: a .14em GRAN DANÉS mide 7.55 em contra los
   6.15 que mediría sin tracking, o sea que la letra sale un 19 % más chica para
   ocupar el mismo sitio. Se paga porque una portada se lee por el aire entre
   letras, no por el tamaño.

   `line-height:.92` Y NO 1: a este cuerpo, la interlínea normal de la fuente deja
   por encima y por debajo de las versales un aire muerto de decenas de píxeles
   que separa la palabra de su canto y deshace el sándwich. .92 aprieta la caja
   contra las versales — no hay descendentes en ninguna de las cuatro palabras y
   los acentos de DANÉS caben dentro (medido: la Á sube 0.71 em sobre la base y la
   caja da 0.92).

   `white-space:nowrap` NO ES DECORACIÓN, ES EL REQUISITO 5: la palabra grande no
   se parte ni desborda a 320 px. Y no se parte POR CONSTRUCCIÓN y no por suerte:
   el cuerpo es una fracción del ancho de la ventana, así que a cualquier anchura
   la palabra mide el mismo 88 % de ella. El `nowrap` es el centinela de que la
   cuenta de ems sigue siendo verdad — si alguien cambia el texto y olvida el
   número, se ve desbordar.

   EL `margin-left` ES EL AJUSTE ÓPTICO DEL TRACKING, y aquí importa más que en el
   membrete porque el cuerpo es veinte veces mayor: la caja de la palabra incluye
   el hueco que abre la última letra por su derecha, así que centrarla deja los
   trazos .07 em corridos a la izquierda. Con la caja centrada por el flex, un
   margen izquierdo de .14 em se reparte a medias y devuelve exactamente eso.

   LA SOMBRA NO SUSTITUYE A LA CAÍDA DE LUZ y no está por eso: la caída es la que
   garantiza el 4.5:1 y esto es el medio píxel de asiento que separa la crema del
   grano de la fotografía. */
.hero__marca,
.hero__oficio{
  margin:0;
  font-family:var(--garalda);
  font-variation-settings:"wght" 300;
  line-height:.92;
  letter-spacing:.14em;
  margin-left:.14em;
  text-transform:uppercase;
  white-space:nowrap;
  color:var(--tinta);
  text-shadow:0 0 .06em rgba(0,0,0,.92), 0 0 .18em rgba(0,0,0,.86),
              0 0 .40em rgba(0,0,0,.66), 0 .02em .85em rgba(0,0,0,.45);
}
.hero__marca { font-size:var(--cuerpo-marca); }
.hero__oficio{ font-size:var(--cuerpo-oficio); }


/* ── EL INDICADOR DE SCROLL ───────────────────────────────────────────────────
   Un filete vertical por el que cae una gota de luz, y nada más. El porqué de
   que exista y de que viva en el HTML está sobre su marcado, en el index; aquí
   van las medidas.

   ── POR QUÉ YA NO ES UN RATÓN ──────────────────────────────────────────────
   Era una rueda de ratón dibujada a 25 px. Victor: «el símbolo de scroll no se
   ve tan bien, como que no da a entender correctamente qué podemos hacer». Y no
   lo daba a entender por dos razones que no se arreglan retocando el trazo:

     · EN UN TELÉFONO NO HAY RATÓN. La mayoría de quien abre un criadero lo abre
       con el pulgar, y el icono le nombraba un aparato que no tiene en la mano.
       Un cue que describe el gesto equivocado no es una pista, es ruido.
     · A ESE CUERPO LA SILUETA NO SOBREVIVE. Un rectángulo redondeado de 16×34
       con un trazo de 1.4 px sobre una fotografía se lee como una pastilla. El
       reconocimiento de un icono figurativo depende de píxeles que aquí no hay.

   Lo que sustituye es EL FILETE SOLO. La primera versión de este cambio traía
   además una palabra —DESLIZA / SCROLL, en el cintillo de la casa—, que es el
   patrón de portada editorial de manual. Victor, viéndola puesta: «sin palabra
   o muy pequeña». Y tiene razón por algo que sólo se ve montado: la palabra cae
   A DOS DEDOS de CRIADERO y de GRAN DANÉS, que son versales de la misma
   tipografía y del mismo color. Tres rótulos del mismo registro en la misma
   columna, y el más chico de los tres es el único que no dice nada de la casa:
   el ojo lo lee como una cuarta altura de la portada y la portada pierde su
   sándwich. Quitarla no le resta información al filete —la dirección la dice el
   recorrido de la gota, no una letra— y le devuelve a las dos palabras grandes
   su columna entera.

   El filete no depende del aparato ni del idioma: vale igual para una rueda que
   para un pulgar, y no hay nada que traducir. Si algún día se quiere la palabra
   de vuelta, el sitio es debajo del filete y no encima, y muy pequeña.

   ── EN MEDIO SE QUEDA, Y LO QUE HAY EN MEDIO ES UNA PALABRA ENORME ─────────
   Victor lo pidió «justamente en medio», y en medio y abajo vive la segunda
   mitad del sándwich de la portada: el oficio cruzando la pantalla. No es un
   vecino del que apartarse por el lado —ocupa el 88 % del ancho en TODA
   ventana— así que el indicador sube por encima de ÉL.

   El número sale de leer EL CUERPO de la palabra que esquiva —`--cuerpo-abajo`,
   el mismo token del que cuelga su `font-size`—, así que no hay dos verdades
   que mantener de acuerdo: cambie la palabra, el idioma o la ventana, el
   indicador se entera solo. La cuenta, de abajo arriba: el relleno de la
   portada, la caja de la palabra (su cuerpo por el .92 de su interlínea) y un
   dedo de aire.

   Y SE LEE `--cuerpo-abajo` Y NO `--cuerpo-oficio`: el indicador esquiva un
   SITIO, no una palabra. Con el nombre viejo, en español habría apartado el
   alto de CRIADERO teniendo debajo a GRAN DANÉS.

   ── `env(safe-area-inset-bottom)` SE SUMA, NO SE COME ──────────────────────
   En un iPhone sin botón, los últimos 34 px de la ventana son la barra del
   gesto. Ya viene sumado dentro de `--portada-suelo`, que es el mismo relleno
   con el que la palabra de abajo se aparta de ese borde — los dos se apartan de
   lo mismo y por el mismo número.

   ── EL VALOR DE REPOSO SUBE DE .62 A .82 ───────────────────────────────────
   Sigue siendo una pista que tiene que perder contra la portada, pero la tinta
   que hay ahora es MUCHO MENOS: un filete de 1 px contra el marco cerrado del
   ratón que había antes. El mismo .62, con esta materia, deja de leerse. Y el
   sitio donde cae es el peor de la fotografía para esto: el CENTRO, donde la
   caída de luz de los cantos ya vale cero y a 1440 lo que hay debajo es el
   bordado del jorongo —claro y lleno de detalle—. Por eso además lleva DOS
   sombras, anotadas en su regla.

   OJO CON LEER ESTE .82 COMO «CASI OPACO»: se multiplica por el .7 del propio
   filete y por el degradado que lo desvanece por las puntas, así que la tinta
   real de la línea no pasa de .70 ni en su tramo más fuerte. El número que se
   ve es ése, no éste. */
.hero__baja{
  /* z-index 3, al ras de la portada: los dos son la capa de texto del hero. Ver
     la tabla de apilamiento sobre `.hero__laminas`. */
  position:absolute; z-index:3; pointer-events:none;
  left:50%; transform:translateX(-50%);
  bottom:calc(var(--portada-suelo) + var(--cuerpo-abajo) * .92 + .9rem);
  display:flex; flex-direction:column; align-items:center; gap:.3rem;
  color:var(--tinta);
  opacity:.82;
  /* TRES SOMBRAS, Y LAS QUE IMPORTAN SON LAS DOS APRETADAS. Un trazo de 1 px
     de crema sobre el bordado del jorongo —que es lo que hay detrás a 1440, el
     trozo más claro y más ocupado de la fotografía— desaparece: no es falta de
     tinta, es falta de CANTO. Crema contra crema no contrasta por mucho que se
     suba la opacidad; lo que hace visible una línea fina sobre fondo claro es
     el borde oscuro pegado a ella, que es lo que hacen estas dos (1 px casi
     opaca, 2.5 px de transición). La tercera, ancha, es el halo que llevan las
     dos palabras grandes: sin ella el filete flota recortado encima de la
     fotografía en vez de asentarse en ella.

     Y VAN EN `filter` Y NO EN UN `box-shadow` DEL FILETE: `filter` sombrea la
     forma REAL —el degradado que se desvanece por las puntas incluido—, así que
     el canto oscuro se desvanece con ella. Un `box-shadow` sombrearía la caja
     rectangular entera y dejaría dos muñones oscuros donde la línea ya no está. */
  filter:drop-shadow(0 0 1px rgba(0,0,0,.95)) drop-shadow(0 0 2.5px rgba(0,0,0,.85))
         drop-shadow(0 1px 10px rgba(0,0,0,.55));
  /* la retirada al primer scroll: la clase la pone `hero.js` y el nodo se va del
     árbol al acabar este fundido */
  transition:opacity 600ms linear;
}
.hero__baja.es-ido{ opacity:0; }

/* ── EL INDICADOR, QUE AHORA ES UNO SOLO PARA LOS DOS APARATOS ────────────────
   El porqué de que sean dos chevrones y no una mano ni un ratón está sobre su
   marcado, en el index. Aquí sólo el tamaño y el latido.

   SE ACABARON LAS DOS PIEZAS. Hasta hoy convivían `.hero__baja__mano` (táctil) y
   `.hero__baja__raton` (cursor), cada una con su `clamp`, su animación y su rama
   de `prefers-reduced-motion`: seis reglas y tres keyframes para decir «baja».
   Con un glifo que no nombra aparato, la media query de `(hover:none)` sobra
   entera. Menos código y una sola cosa que mantener.

   EL TAMAÑO ES MENOR QUE EL DE LOS GLIFOS QUE SUSTITUYE —2.1rem contra los 3.45
   del ratón y los 3.7 de la mano— y no es una rebaja: es que estas dos flechas
   NO tienen que ser reconocidas, sólo leídas. Un ratón necesitaba cuerpo para
   que su silueta se distinguiera de un óvalo; cuatro trazos rectos se leen a
   cualquier cuerpo. Lo que sobra de tinta se lo devuelve a la fotografía. */
.hero__baja__flechas{
  display:block;
  width:auto; height:clamp(1.6rem, 3.6svh, 2.1rem);
  animation:hero-flechas 2.8s cubic-bezier(.4, 0, .5, 1) infinite;
}
/* CAE Y VUELVE, con más de la mitad del ciclo en reposo: es un latido, no un
   bucle. Mismo pulso que llevaban las cinco piezas anteriores — lo único que ha
   cambiado siempre es la forma, nunca el compás. Y no se apaga del todo: el
   suelo de .55 es el mismo criterio con el que la ruedita del ratón se quedó en
   .62 —una pieza que desaparece deja de ser un indicador la mitad del tiempo—,
   sólo que aquí hay más tinta y pide menos suelo. */
@keyframes hero-flechas{
  0%, 8%    { transform:translateY(0);   opacity:.55; }
  38%       { transform:translateY(5px); opacity:1; }
  72%, 100% { transform:translateY(0);   opacity:.55; }
}

/* EL FILETE SE DESVANECE POR LAS DOS PUNTAS y no acaba en corte: una línea con
   los dos cantos limpios es un objeto —un palo— y se lee como una regla de
   separación; una que se disuelve es un recorrido que sigue más allá de donde
   se ve, que es justo la frase. Por eso el degradado y no un `background` liso.

   1 px CLAVADO Y NO UN `rem`: un filete es un filete a cualquier cuerpo, y en
   pantalla de retina el navegador lo resuelve a medio píxel físico él solo.

   Y ES MÁS LARGO QUE CUANDO TENÍA UNA PALABRA ENCIMA —de 1.9…2.6rem a
   2.6…3.6rem—, porque ahora es TODO lo que hay. Lo que dice el filete no es su
   grosor sino su RECORRIDO: es la distancia que la gota tarda en cruzarlo la
   que se lee como «hay camino hacia abajo», y con 30 px de caída el viaje se
   acaba antes de haberse leído. El techo lo sigue poniendo el iPhone apaisado,
   donde la ventana mide 292 px de alto: 3.6rem son 57.6 px, un quinto de esa
   altura, y el `svh` de en medio lo baja solo antes de llegar ahí. */


/* LA GOTA ES LO ÚNICO QUE SE MUEVE. El filete está quieto: lo que se lee es la
   DIRECCIÓN, y para eso basta con que algo la recorra. Un indicador entero
   botando arriba y abajo es el adorno de cualquier plantilla y llama más
   atención que el <h1> que tiene al lado.

   `currentColor` y no blanco: la gota es la misma crema del resto, a plena
   opacidad contra el .85 del filete que la contiene. Ese contraste interno es
   lo que la hace visible sin subir de tamaño. */


/* 2.8 s POR VUELTA, que es lento de verdad, y con el 60 % del ciclo en reposo:
   la gota entra por arriba, cruza el filete, se va por abajo y luego no pasa
   nada durante un segundo y medio. Es un latido, no un bucle. Es el mismo ciclo
   que llevaba la rueda del ratón —lo que cambió es la forma, no el pulso.

   LOS PORCENTAJES SON DE SU PROPIO ALTO, que es el 30 % del filete: -100 % la
   deja entera por encima del canto de arriba y 333 % entera por debajo del de
   abajo (30 × 3.33 = 100). Si cambia el `height` de la gota, cambia el 333. */

/* ── EL CHEVRÓN ESTUVO AQUÍ Y SE RETIRÓ · 17-sep-2026 ────────────────────────
   `.hero__baja__pico` era un chevrón de dos trazos colgado debajo del ratón, con
   su propio `@keyframes hero-pico` medio ciclo por detrás. Existía porque el
   glifo `mouse` de Material Symbols tenía una proporción de 1.57 y a cualquier
   cuerpo que no compitiera con el <h1> se leía como un ANILLO —el mismo 1.58 de
   la rueda dibujada a mano que Victor tumbó, así que no era el dibujo: era la
   proporción—. La salida fue repartir el recado: el ratón decía CON QUÉ y el
   chevrón HACIA DÓNDE.

   El ratón de Lucide trae la ruedita DENTRO del cuerpo, y una ruedita en el
   tercio superior de un canto vertical ya dice las dos cosas. Victor lo eligió
   entre 33 candidatos montados a tamaño real sobre esta fotografía, y lo eligió
   SOLO. Dos recados compitiendo por el mismo medio segundo de atención son peor
   que uno claro.

   SU TRABAJO NO SE PERDIÓ, SE MUDÓ AL SUELO DE OPACIDAD DE LA RUEDITA. Lo que
   el chevrón tapaba de verdad era el hueco del latido: mientras la ruedita valía
   0 no había nada que identificase al ratón. Retirado el chevrón, ese hueco se
   cierra donde nace —la ruedita no baja de .62, medido— y no colgando una
   segunda pieza debajo. 👑, 17-sep-2026: «la ruedita dentro del cuerpo dice lo
   mismo y es lo que Victor eligió ver».

   NO SE DEVUELVE. Si alguien mide que la pieza perdió claridad, la palanca es el
   suelo de la ruedita, que está en su `@keyframes` con el barrido medido al
   lado; devolver el chevrón lo decide Victor y nadie más. */

/* ══ LA MANO · EL INDICADOR TÁCTIL, Y ES OTRA PIEZA, NO LA MISMA VOLTEADA ════
   Victor, 17-sep-2026: «pon una manita haciendo swipe, ya las he visto, es una
   manita con un dedo hacia arriba haciendo el gesto, para que se entienda. Y en
   computadora lo dejamos igual y ya». La lista de los cuatro intentos y por qué
   murió cada uno está en `index.html`, pegada al marcado.

   ── EL GESTO NO ES EL MISMO EN LOS DOS APARATOS ────────────────────────────
       rueda  → la empujas hacia ABAJO y la página baja      ↓
       dedo   → lo arrastras hacia ARRIBA y la página baja   ↑

   Son direcciones OPUESTAS para el mismo resultado. Por eso hay dos indicadores
   y no uno volteado: el de escritorio describe una rueda —filete, gota cayendo
   y chevrón hacia abajo, intacto— y el táctil describe un dedo.

   ── LA MANO SUSTITUYE AL FILETE, NO CONVIVE CON ÉL ─────────────────────────
   Montados juntos son dos recados compitiendo por el mismo medio segundo de
   atención: la mano YA dice el gesto entero —qué se toca, hacia dónde va— y el
   filete de debajo sólo añade una segunda cosa que mirar. El filete existía
   porque lo que había encima era insuficiente (la gota era una pista, el
   chevrón un símbolo sin contexto); un dibujo del gesto no necesita contexto,
   es el gesto. Por eso en `(hover:none)` el filete y el chevrón no se dibujan.

   ── EL TAMAÑO, QUE ES POR DONDE SE MURIÓ EL RATÓN ──────────────────────────
   Un icono figurativo a 25 px sobre una fotografía no se reconoce, y una mano
   tiene MÁS silueta que reconocer que un ratón. Si esta mano se dibuja a la
   medida de la pieza de escritorio, repite el fallo con otro glifo.

   No hace falta: aquel techo lo ponía el APAISADO, no el teléfono de pie. En
   vertical las dos palabras del hero ocupan el 11 % del alto (52 + 42 px de
   844) y esta columna está vacía. Medido con esta regla, dpr 1:

       390×844   mano 92.8 px de alto ·  70.8 px de ancho   (11.0 % de la ventana)
       430×932   mano 96 px           ·  73.2 px            (10.3 %)
       844×390   mano 72 px           ·  54.9 px            (18.5 % — el techo)

   `clamp(4.5rem, 11svh, 6rem)`: el 11svh es el que manda en un teléfono de pie,
   el suelo de 4.5rem es el que salva el apaisado —donde 11svh serían 43 px y la
   mano volvería a caer en la talla del ratón— y el techo de 6rem impide que en
   una tableta alta se coma la portada.

   EL APAISADO ES EL CASO QUE ACOTA, y el suelo está puesto CONTRA su límite. La
   ventana mide 390 px, el quinto que no se puede pasar son 78, y el indicador
   entero —que es sólo la mano— ocupa 72: quedan 6 px de holgura. Ahí es donde
   más falta hace el tamaño, porque es donde la mano cae encima del bordado del
   vestido, que es el trozo más ocupado de la fotografía. Si alguien vuelve a
   colgarle algo debajo, esos 72 px tienen que bajar para que quepan los dos. */


/* EL RATÓN · EL NÚMERO ESTÁ RE-MEDIDO CONTRA LA CAJA DE LUCIDE ───────────────
   Lo que hay que conservar es el CUERPO QUE SE VE, no el número viejo. El glifo
   `mouse` de Material medía 560 × 800 en su caja de 960 y con su trazo de 46 la
   tinta llegaba a 606 × 846, o sea el 88.1 % del alto de la caja. El de Lucide
   es un `rect` de 14 × 20 en una caja de 24 y con su trazo de 2 la tinta llega a
   16 × 22: el 91.7 %. Llena más, así que la caja baja en ese factor
   (0.881 / 0.917 = 0.961): 2.8 → 2.7rem, 6.4 → 6.15svh, 3.6 → 3.45rem.

   MEDIDO, dpr 1, sobre la fotografía viva:

       1440×900   caja 55.2 px · tinta 50.6 × 36.8 px   (5.6 % del alto)
        844×390   caja 43.2 px · tinta 39.6 × 28.8 px   (10.2 % — el techo)

   Y POR QUÉ NO CRECE MÁS, que es la parte que no cambia con el glifo: se montó a
   34 px sobre la fotografía y no se leía —encima del vestido bordado, el trozo
   más ocupado del cuadro, era una manchita ovalada—; a 46 px seguía siendo un
   anillo. Por encima de ~50 px de tinta el canto vertical del cuerpo por fin se
   distingue: DOS lados rectos y las esquinas redondas sólo arriba y abajo, que
   es lo que tiene un ratón y no tiene un huevo. Más allá deja de ser una pista y
   empieza a ser un adorno que compite con el <h1>, porque cae en el CENTRO de la
   portada, donde la caída de luz de los cantos ya vale cero. El `svh` de en
   medio lo encoge solo en una ventana baja, que es donde la fotografía no puede
   ceder ni un píxel. */


/* LA RUEDITA BAJA Y NADA MÁS SE MUEVE. El cuerpo está quieto: lo que se lee es
   el GESTO —el dedo empujando la rueda— y para eso basta con que se mueva la
   rueda. Un icono entero botando es el adorno de cualquier plantilla. 2.8 s por
   vuelta con más de la mitad del ciclo en reposo: es un latido, no un bucle, y
   es el mismo pulso que lleva la mano del teléfono. */
/* EL RECORRIDO VA EN UNIDADES DE LA CAJA DE 24, NO EN LAS DE 960. Aquí ponía
   105px, que eran píxeles de usuario del viewBox de Material: en una caja de 24
   eso son más de cuatro cajas y la ruedita se va de la pantalla. RE-CALCULADO
   sobre el glifo de Lucide: la ruedita es `M12 6v4` con trazo 2 de punta redonda,
   así que su tinta ocupa de y=5 a y=11, y el canto INTERIOR de abajo del cuerpo
   —`rect` y=2..22 con trazo 2— está en y=21. Con `translateY(8px)` el borde de
   abajo de la ruedita pasa de 11 a 19 y su punta redonda muere en y=20: cerca
   del canto, sin tocarlo, que es donde se acaba el gesto.

   ── LA RUEDITA NUNCA SE APAGA DEL TODO, Y ÉSA ES LA REGLA QUE IMPORTA ───────
   Aquí el reposo valía opacity 0 y la ruedita desaparecía más de la mitad del
   ciclo. Se podía cuando el cuerpo era el `mouse` de Material y llevaba un
   chevrón debajo diciendo la dirección; ahora el cuerpo es un `rect` de 14×20
   con `rx` 7 y LA RUEDITA ES LA ÚNICA PIEZA QUE LO IDENTIFICA. Sin ella el
   cuerpo solo es un anillo de proporción 1.37 — el mismo fallo que ya tumbó a
   la rueda dibujada a mano (1.58) y al `mouse` de Material (1.57). Un indicador
   que no se reconoce más de la mitad del tiempo no se reconoce: parpadea.

   EL SUELO ES .62 Y ESTÁ MEDIDO SOBRE ESTA FOTOGRAFÍA, no elegido de memoria.
   La ruedita cae en el CENTRO de la portada, encima del bordado del jorongo, que
   es el trozo más claro y más ocupado del cuadro: medido a 1440 y dpr 1, el
   fondo bajo ella tiene L media 47.7 y un vaivén propio de 52.7 L entre p05 y
   p95. Para ser FIGURA y no textura, la tinta de la ruedita tiene que despegarse
   de ese vaivén. Barrido de siete suelos, delta de luminancia contra el mismo
   fondo sin ruedita (p90 · máx):

       .35  45.3 ·  56.2   ← por debajo del vaivén del bordado: es textura
       .45  61.3 ·  72.9   ← 1.16×, se adivina
       .50  69.1 ·  81.4   ← 1.31×, el suelo que tenía el chevrón
       .62  88.6 · 102.2   ← 1.68×  ◀ ÉSTE
       .70 102.5 · 116.2   ← 2.07×, ya no late
      1.00 155.3 · 169.8   ← el latido desaparece

   Y NO VALE EL .50 DEL CHEVRÓN, que era la referencia de partida: aquél era una
   forma de dos trazos de 1.7 y 24 px de ancho, y esto es un segmento de 4.6 px
   de ancho por 14 de alto. MENOS TINTA PIDE MÁS SUELO, no el mismo. El .62 es
   además el suelo que ya lleva la mano del teléfono, y por la misma razón: allí
   la mano es TODO el indicador y su tinta real en reposo es .51 (.62 × el .82
   del contenedor); aquí la ruedita es la pieza que identifica al suyo y su tinta
   real medida es .508. Mismo trabajo, mismo número.

   EL CERO SÓLO VIVE EN EL SALTO DE VUELTA, tramo 42–48 %, igual que en la mano:
   la ruedita se desvanece en el canto de abajo, regresa arriba invisible y
   reaparece. Sin ese corte el retorno se leería como la ruedita SUBIENDO, que es
   el gesto contrario. Descontado el salto, el latido conserva el reposo que
   pedía: 52 % del ciclo quieta arriba (0–8 % y 56–100 %) y 6 % invisible. */

/* MISMO PULSO QUE LA GOTA —2.8 s, cubic-bezier igual, ~64 % del ciclo sin
   movimiento—: es un latido, no un bucle. Lo que cambia es que la mano NUNCA
   SE APAGA DEL TODO, y ésa es la diferencia que importa. La gota podía
   desaparecer entre latidos porque el filete se quedaba sosteniendo el sitio;
   aquí la mano es TODO el indicador, y un indicador que existe la mitad del
   tiempo no es un indicador. Por eso el reposo es .62 y no 0 — que multiplicado
   por el .82 del contenedor da .51 de tinta real en reposo y .82 en el golpe.

   El cero sólo aparece en el tramo 44–50 %, que es el salto de vuelta: la mano
   se desvanece arriba, regresa abajo invisible y reaparece. Sin ese corte el
   retorno se leería como la mano BAJANDO, que es exactamente el gesto contrario
   al que hay que enseñar.

   EL VIAJE ES ±16 % DE SU PROPIO ALTO —30 px en un teléfono de pie—, y es
   `translateY` sobre el glifo, no sobre la caja: el hueco que reserva el
   indicador no cambia con la animación. */

/* CON `prefers-reduced-motion` EL INDICADOR SE QUEDA QUIETO Y SIGUE AHÍ. No
   desaparece, y ésa es la distinción que suele fallarse: quien pide menos
   movimiento no está pidiendo menos información, y esto es información —es la
   única pista de que debajo de la fotografía hay un sitio entero—. La gota se
   para A DOS TERCIOS DEL FILETE, que es una posición que sigue diciendo «hacia
   abajo» —no está centrada ni pegada al canto, está VENIDA de arriba— y el
   filete sube de tinta para compensar lo que pierde al no latir. Sin palabra
   que lo respalde, esta parada es todo el recado que queda: por eso no se
   esconde la gota, se planta. */
@media (prefers-reduced-motion: reduce){
  /* con el movimiento apagado las flechas se plantan A MEDIO VIAJE —3 de los 5
     px del recorrido, o sea venidas de arriba, que sigue diciendo «hacia
     abajo»— y a plena tinta. El número es la mitad del `translateY` del
     keyframe: si cambia allí, cambia aquí. */
  .hero__baja__flechas{ animation:none; opacity:1; transform:translateY(3px); }
}

/* LA VIÑETA SE FUE, Y ESA ES LA MITAD DEL ENCARGO DE ESTA LANE.
   VICTOR, LITERAL: «te pedí que me quitaras lo horripilante que es la pinche
   mancha negra que está debajo del idioma, y lo que fuiste fue a ponerme otra
   mancha del lado izquierdo». Tenía razón en las dos. Aquí vivía una elipse negra
   —`.idioma::before`, `inset:-150% -80%`, núcleo al 52 %— dibujada sobre una caja
   mucho mayor que el rótulo para que ninguna letra se saliera del núcleo. Cumplía
   su medición: 14.7:1 en el núcleo y 7.5:1 sobre el píxel más claro del hero. Y
   se veía. Una elipse sobre una fotografía tiene forma, tiene centro y se lee
   como una mancha aunque el contraste sobre; el número no era el problema.

   LO QUE LA SUSTITUYE NO ES OTRO VELO: ES QUE YA NO HACE FALTA NINGUNO. El
   conmutador vive en el canto de ARRIBA, y desde que la portada es una portada el
   canto de arriba de la fotografía viene oscurecido de punta a punta por la caída
   de luz de `.hero::after` — que existe para el membrete y las dos palabras
   grandes y cubre esta esquina de paso, por geometría y no por casualidad. El
   mismo recurso, una sola vez, para las cuatro cosas que se leen sobre la
   fotografía. Las siete mediciones de esta esquina, en
   `Taller/Auditoria/Hero-Portada · Informe.md`.

   LO QUE SÍ SE QUEDA ES LA SOMBRA, Y SUBE UN PUNTO. Era `0 1px 3px rgba(0,0,0,.9)`
   —un asiento de un píxel pensado para vivir sobre un velo opaco— y ahora es el
   halo de la casa, el mismo de las dos palabras grandes: un desenfoque ancho y
   suave que separa la crema del grano sin dibujar un canto. Va en la regla de
   arriba, junto a la geometría.

   ── Y EL TERCER CHOQUE DE ESTE WIDGET SIGUE RESUELTO, POR OTRA PUERTA ──────
   La nota que este archivo llevaba aquí decía que el velo existía porque por
   debajo del conmutador pasa el documento ENTERO: el cintillo del hero, el título
   de concursos y su `border-top` de 1 px, que a 1280 cruzaba «ESPAÑOL» a 1.2 px
   del canto. Eso sigue siendo verdad y sigue sin poderse esquivar moviendo la
   caja. Lo que lo resuelve hoy es que el rótulo se lee por contraste propio sobre
   lo que haya: crema de la casa, halo ancho, y el canto de arriba oscurecido
   mientras se está sobre el hero. Un filete de 1 px cruzando una letra crema con
   halo no la borra — lo que la borraba era una fotografía clara detrás, y eso es
   lo que la caída de luz quita. */
.idioma__op.cintillo{
  background:none; border:0; padding:.2rem .1rem; cursor:pointer;
  font-size:.62rem; letter-spacing:.26em;
  /* ── EL REPOSO ES CREMA, Y ESO TIENE DOS FACTURAS DETRÁS ────────────────────
     `--filete` es el trazo de 1 px de la casa, no un color de TEXTO: 2.79:1
     sobre el negro con el cuerpo computado de 9.92 px, y la WCAG AA pide 4.5:1.
     `--tenue` lo subió a 5.11:1 y con eso cruzó el suelo… CONTRA EL NEGRO. Pero
     el conmutador no vive sobre negro: vive sobre la fotografía del hero, que
     desde `Hero-Siete` rota entre siete escenas con zonas claras. Sobre una de
     ellas `--tenue` mide 1.76:1. El umbral estaba bien calculado contra el fondo
     equivocado, y por eso Victor lo vio apagado antes que ninguna medición.
     `--tinta` es la crema de la marca —la misma de `.hero__marca`, que resuelve
     este problema exacto sobre la misma fotografía— y sobre la caída de luz del
     canto de arriba da 9.8:1 en la peor de las siete escenas.

     `--tenue` NO desaparece del sitio: sigue siendo el gris de texto sobre el
     negro de la página (§ `.cierre__puerta__txt`, que sí vive sobre negro). Lo
     que desaparece es usarlo encima de una fotografía. */
  color:var(--tinta);
  transition:color 180ms ease;
  /* sólo para colgar de aquí el campo de toque; no cambia el dibujo */
  position:relative;
}
/* ── EL CAMPO DE TOQUE, QUE NO ES LA LETRA ────────────────────────────────────
   «ESPAÑOL» a .62rem con .2rem de relleno es una caja de 54.7 × 16.3 px medida a
   390×844, y un pulgar necesita 44. Subir el relleno movería la caja del velo y
   volvería a apretar contra el cintillo de concursos, que es el choque que la
   sección de arriba acaba de resolver tres veces — así que el campo se agranda
   SIN TOCAR UN PÍXEL: una capa transparente centrada sobre el botón. No pinta,
   no ocupa flujo y no cambia dónde cae ninguna letra; lo único que cambia es
   dónde acierta el dedo. Los dos botones miden 54.7 de ancho y van separados por
   su `·`, así que ninguno de los dos campos pisa al otro.

   Y CRECE HACIA ABAJO, NO HACIA LOS DOS LADOS. Centrado sobre la letra, los 44
   px se salen por el canto de arriba de la pantalla —el conmutador vive a
   `.3rem` del borde— y quedan 41 px alcanzables: medido. Anclado al techo del
   botón, los 44 caen enteros dentro de la ventana, y lo que queda debajo es
   fotografía, que no recibe ni toque ni foco. */
.idioma__op.cintillo::after{
  content:"";
  position:absolute; left:50%; top:0;
  transform:translateX(-50%);
  width:100%; min-width:44px; height:44px;
}
/* El `aria-pressed` de abajo NO LO RECIBE NADIE HOY: el conmutador es de una sola
   opción —«English» en español y «Español» en inglés (index.html:92)—, así que
   esta regla es sólo el respaldo de un futuro conmutador de dos. La legibilidad
   del reposo NO cuelga de ella; la da `--tenue` de arriba. */
.idioma__op.cintillo[aria-pressed="true"]{ color:var(--tinta); }
/* ── LOS ESTADOS, AHORA QUE EL REPOSO YA ES CREMA ────────────────────────────
   Hasta hoy `:hover` y `:focus-visible` se distinguían subiendo el color de
   `--tenue` a `--tinta`. Con el reposo YA en `--tinta` esa diferencia es cero, y
   un estado que no se ve no existe: hay que devolverlo por otro sitio.

   EL HOVER SUBE A BLANCO, que es el único paso que queda por encima de la crema
   y el mismo recurso que usan las dos puertas del cierre (§ carrusel.css,
   `.cierre__puerta:hover`). No se subraya: a .26em de tracking un subrayado corre
   por debajo de las letras Y de sus huecos, y se lee como un filete.

   EL FOCO NO PUEDE COLGAR DEL COLOR y nunca debió: quien llega con el tabulador
   necesita ver DÓNDE está, no que algo cambió de tono. Un `outline` de brasa, el
   mismo de las puertas del cierre, y `outline-offset` para que no toque las
   letras. Así el foco se ve igual con el reposo que tenga el conmutador. */
.idioma__op.cintillo:hover{ color:#fff; }
.idioma__op.cintillo:focus-visible{
  color:#fff;
  outline:2px solid var(--brasa); outline-offset:3px;
}
.idioma__sep{ color:var(--filete); font-size:.62rem; line-height:1; }

/* En un teléfono se aparta del borde lo justo para no caer bajo el pulgar que
   sujeta el aparato, y crece hasta el objetivo táctil de 44 px que pide la WCAG
   — el mismo criterio que el menú del click derecho veinte líneas más arriba. */
/* EN TELÉFONO NO HAY ZONA LIBRE, Y ESO ES UN HECHO DE LA COMPOSICIÓN, no una
   pega que se pueda esquivar moviendo la caja. El cabezal del hero es un lockup
   a sangre: cintillo y palabra grande ARRIBA, palabra de la escena ABAJO, y el
   sujeto en medio. Se probaron las tres colocaciones y las tres chocan, medido:
   arriba a 11…47 se monta sobre el cintillo (empieza en ~30); a 70…106 sobre la
   T de GREAT; abajo a 792…828 sobre COMPANION, que es la más larga de las seis
   palabras y llega al 80 % del ancho; y en el medio del canto derecho cae sobre
   el vestido plateado de la escena 1 y desaparece por contraste.

   ASÍ QUE LO QUE CAMBIA NO ES EL SITIO SINO LA LEGIBILIDAD: un velo oscuro
   pequeño detrás, que es exactamente el recurso que esta hoja ya usa para el menú
   del click derecho —negro translúcido y un desenfoque de lo que hay detrás, sin
   borde, sin esquina redonda y sin sombra de sistema operativo—. No es cromo
   añadido: es el mismo idioma, y es lo único que hace que dos palabras de 11 px
   sobrevivan encima de una fotografía que cambia cada tres segundos.

   Se queda ARRIBA A LA DERECHA, que es donde se busca un conmutador de idioma, y
   con el velo ya no importa que el cintillo pase por debajo. */
@media (max-width:640px){
  .idioma{
    /* PEGADO AL CANTO Y LO MÁS PEQUEÑO QUE AGUANTA. La banda de arriba la pelean
       DOS cintillos —el del hero en la portada y el del título de concursos, que
       en español cae en dos renglones— y a 375 la caja del conmutador quedaba a
       UN píxel del segundo. Un píxel no es holgura: es que todavía no ha chocado.
       Con el velo detrás ya no tapa nada que no se lea, pero seguía apretando, así
       que se le recorta el relleno y se pega más a la esquina. */
    top:calc(.3rem + env(safe-area-inset-top, 0px)); bottom:auto;
    right:.35rem; transform:none;
    /* EL RELLENO LATERAL SE VA CASI ENTERO, Y ES LO QUE LE DEVUELVE EL RENGLÓN AL
       MEMBRETE. Los .5rem de cada lado existían para separar la letra del canto
       del VELO; sin velo no separan de nada y sólo engordan la banda que el
       membrete tiene que esquivar — 17 px de los 77 que medía a 320. El campo de
       toque no se entera: son 44 px colgados del `::after`, y la caja del botón ya
       mide 54.2, así que el campo sigue siendo el botón entero y no se sale por el
       canto de la pantalla. */
    padding:.34rem .12rem;
  }
  /* el `color:var(--tinta)` que vivía aquí se fue a la regla de arriba: era la
     única parte del teléfono que ya estaba bien, y hoy es la regla del sitio.
     Aquí sólo queda la GEOMETRÍA. */
  .idioma__op.cintillo{ padding:0; font-size:.6rem; letter-spacing:.2em; }
}

/* ══ EL RETRATO DE ESCALA ══════════════════════════════════════════════════════
   El tamaño del perro no se cuenta con una cifra: se cuenta CON EL SCROLL. Se
   entra y sólo se le ve la cara, se baja, y al salir sólo se ve el cachorro entre
   sus patas. SIN UNA LÍNEA DE JAVASCRIPT — ni `scroll`, ni `sticky`, ni
   `IntersectionObserver`: es un cajón más alto que la ventana con una imagen más
   alta que la ventana dentro, y la página lo recorre sola.

   TODO CUELGA DEL ALTO DEL CAJÓN, y ese alto no lleva UNA sola cifra tecleada.
   Sale de seis variables: cuatro que MIDE `Scripts/retrato.py` sobre el PNG y
   reimprime cada vez que se corre, y dos que son decisiones.

     --aspecto    ancho ÷ alto del PNG. LA PROPORCIÓN DEL ARCHIVO SE ESCRIBE AQUÍ
                  Y EN NINGÚN OTRO SITIO: la guarda, el tope y la caja de la
                  lámina salen de ella con una división.
     --perro      cuánto del lienzo ocupa EL PERRO, de las orejas a las patas del
                  cachorro. Hace que «dos pantallas» sea dos pantallas DE PERRO y
                  no de archivo. Sin él la pieza se rompe en silencio el día que
                  el PNG traiga negro añadido: medido con un lienzo de prueba 9:39
                  (862×3735), «dos pantallas» dejaban al perro en 0.83 pantallas
                  —cabe entero de una vez, el scroll ya no lo recorre— y con
                  `--perro` los dos lienzos rinden IDÉNTICO: 695 px de ancho
                  dibujado y 1.48 pantallas de perro a 390×844 con los dos.
     --holgura    medio lienzo ÷ media banda del perro con su aire. Es COMPOSICIÓN,
                  no archivo: no cambia con la resolución ni con el relleno negro.
     --nativo     el ancho en píxeles del PNG. Sólo alimenta el tope de nitidez.

     --pantallas  CUÁNTO MIDE LA PIEZA, en pantallas de perro. Es la única perilla
                  que se va a querer mover: a 200vh el perro ocupa el 32 % del
                  ancho de un 1440. En TELÉFONO subirla no hace nada y es correcto
                  —ahí manda la guarda, que es un tope—: medido a 2, 3 y 4, la
                  sección mide 1471 px y la banda vista 189…673 en las tres.
     --invento    cuánto puede el navegador estirar la lámina, en múltiplos del
                  ancho nativo. HOY ESTA PERILLA MUERDE A LA OTRA: con 862 px topa
                  la sección en 1825, que a 1440×900 son justo 2 pantallas de
                  perro, así que subir `--pantallas` no mueve un píxel mientras
                  `--invento` sea 1. La receta de las dos está en el mensaje del
                  commit. No es pega de la regla, es el archivo: el sitio ya sirve
                  esta lámina con 2.42× de invención en un teléfono a dpr 3, y con
                  el retrato a 2400 px el tope se va a 5081 y la perilla del alto
                  queda libre hasta 4 pantallas sin pagar nada.

   LA FÓRMULA. La imagen va a `height:100%`, o sea `alto × aspecto` de ancho, y de
   ella se ven los `100vw` centrales. Que el perro entre entero pide

       100vw ÷ (alto × aspecto) × (lienzo÷2)  ≥  media banda + aire

   y despejando sale `100vw × holgura ÷ aspecto`: LA GUARDA DE LAS PATAS, la única
   razón por la que la pieza no mide siempre dos pantallas. Lo primero que se
   pierde por los lados son las patas delanteras, que son lo que enmarca al
   cachorro. Hoy da 377vw; a 420vw —el número con el que llegó el encargo— se ven
   los 50.4 % centrales y las zarpas se cortan 18 px por lado. Mirado en
   `Capturas/Escala/`, no razonado. Los 6 px de aire que lleva dentro la holgura
   son también lo que absorbe que `100vw` incluya la barra de scroll y el redondeo
   del navegador al escalar.

   Y LO QUE NINGÚN ARCHIVO ARREGLA: el recorte no lo decide el lienzo, lo decide
   EL PERRO. Mide 470×1825 px —3.88 veces más alto que ancho— contra 2.16 de una
   pantalla de 390×844. Dibujar N pantallas de perro pide N×844×0.2575 px de
   ancho: N=1.79 pide 389 y N=2 pide 435. DOS PANTALLAS DE PERRO SIN CORTAR NO
   EXISTEN en un teléfono de 390, con este lienzo ni con ninguno. La guarda
   entrega 1.74 pantallas de lienzo, el 97 % de ese techo geométrico.

   `vh` Y NO `svh`, al revés que el riel del hero: aquel necesita no pasarse de la
   ventana de ahora, y éste necesita NO MOVERSE.

   EL PORQUÉ ESTABA MAL ESCRITO, Y ERA LA PISTA FALSA DEL BUG DEL SWIPE
   (17-sep-2026). Decía aquí que «`svh` cambia cuando la barra del navegador se
   esconde», y eso es FALSO: el que cambia con la barra es `dvh`. `svh` es el
   viewport PEQUEÑO —barras puestas— y es tan fijo como `vh`; está bien contado
   cien líneas más abajo, en el bloque del teléfono apaisado, y lo que estaba mal
   era este párrafo. La razón de verdad para `vh` aquí es la de la línea de
   arriba: el encuadre del cachorro se calculó contra la ventana grande y se
   quiere entero, no que la sección mida distinto según el aparato.

   Y LO QUE SÍ SE MIDIÓ, para que nadie vuelva a perseguirlo: con `vh` y `svh`
   congelados —que es lo que hace un teléfono de verdad cuando la barra se
   retrae— pasar `innerHeight` de 844 a 734 mueve el alto del documento 43 px de
   11 412, y mueve `.escala` CERO. El teletransporte del swipe rápido no nacía
   aquí ni en ninguna unidad de esta hoja; nacía en la red de seguridad del salto
   de `concursos.js`, y ahí está escrito (§«LA RED DE SEGURIDAD», §`REPOSO_MS`).

   `background` explícito: a 1440×900 la imagen se dibuja a 862 px centrados y a
   los lados hay negro de verdad, que tiene que ser el mismo de la fotografía.
   `z-index:1` como los concursos, o el hero `fixed` en z-index 0 la taparía. */
.escala{
  /* LAS CUATRO, MEDIDAS AHORA DE LOS 192 CUADROS DE `Assets/Video/escala-1440.mp4`.
     El video cambió de forma —era 1056×608 apaisado y ahora es 1440×2560 VERTICAL—
     y aun así estas cuatro casi no se mueven, que es la prueba de que llega la
     MISMA toma con más píxeles y no un encuadre nuevo: recortado al marco, el
     video viejo y el nuevo son la misma fotografía (`--perro` 0.8536 → 0.8527,
     una milésima). Lo que cambia de verdad es la RESOLUCIÓN, y eso vive en
     `--nativo` y en los dos encodes.

     `--aspecto` NO CAMBIA: es el aspecto del MARCO, no el del archivo. Lo que sí
     cambia es el ancho del fondo en marcos, y eso vive en `.escala__fondo`.

     `--perro` es la UNIÓN de los 192 cuadros y no la del último: de las orejas
     más altas que el adulto llega a levantar (y=108 del video, cuadros 179-192)
     a la LÍNEA DE CONTACTO con el suelo (y=2291). Las orejas se miden a
     luminancia > 20 dentro de la ventana del marco —están retroiluminadas—.
     LAS PATAS YA NO SE PUEDEN MEDIR CON EL UMBRAL 140 DEL VIDEO ANTERIOR, y esto
     es una trampa heredada que hay que dejar escrita: en aquel render el reflejo
     no pasaba de 121 y >140 separaba al perro de su espejo; en éste el piso
     refleja MUCHO más y >140 sigue dando positivo hasta y=2435, que son 144 px
     de REFLEJO contados como perro. La línea de contacto se saca por SIMETRÍA
     ESPECULAR —se correlaciona la banda de las patas por encima y por debajo de
     cada `y` candidata y se toma el máximo— y da 2291, confirmado por un segundo
     método independiente (fin de la primera racha brillante de cada columna,
     p90 = 2284, máx = 2289). En los 192 cuadros el contacto se mueve de 2293 a
     2290: TRES PÍXELES, y por eso el charco de aquí abajo puede ser fijo.

     `--holgura` sale de la banda de las patas EN REPOSO, igual que antes: medio
     marco ÷ (media banda + aire). La banda a la altura del contacto va de x=400
     a x=1050 del video, o sea 0.27293 marcos de semibanda contra los 0.28556 de
     la toma anterior —el perro nuevo pisa un pelo más estrecho—, más los mismos
     6 px sobre 862 de aire, EN RAZÓN y no en píxeles.
     LO QUE NO PROTEGE SIGUE SIENDO LA COLA: en los cuadros del meneo se abre
     hasta x=1439 —el canto del video, 0.5947 marcos de semiancho— y protegerla
     pediría --holgura 0.84, o sea dibujar la pieza MÁS GRANDE que la ventana.
     Se corta en teléfono y está dicho, igual que antes.

     `--nativo` VUELVE A QUERER DECIR CASI «no ampliar», y ése es el arreglo que
     Victor pidió. El marco mide 1210 px de ancho DENTRO del video (2560 ×
     --aspecto) donde antes medía 287, así que el mismo 862 px de tope pasa de
     ser un presupuesto de AMPLIACIÓN de 3.00× a uno de REDUCCIÓN de 0.71×
     (862 ÷ 1210). El valor no se toca —moverlo movería el aterrizaje, que es lo
     único que esta pieza no puede mover— pero su significado se dio la vuelta:
     en escritorio a dpr 1 el video se dibuja MÁS CHICO que su píxel nativo. */
  --aspecto:0.4723;      /* 862 ÷ 1825 — el MARCO, que no se mueve */
  --perro:0.8531;        /* orejas y=107 → contacto y=2291, unión de los 350 cuadros */
  --holgura:1.7863;      /* 0.5 ÷ (semibanda 0.27293 + aire 0.00696), en marcos */
  --nativo:862px;        /* presupuesto: 0.71× sobre los 1210 px nativos del marco */
  /* y las dos perillas de la decisión, una cifra cada una */
  --pantallas:2;
  --invento:1;

  position:relative; z-index:1;
  /* el alto va a una variable propia y no directo en `height` porque lo lee más
     de una regla, y repetir un `min()` de tres términos en dos sitios es
     exactamente como se separan. Lo leía el radio del halo, que ya no está; lo
     sigue leyendo quien tenga que escalar con la pieza y no con la ventana */
  --alto:min(calc(var(--pantallas) * 100vh / var(--perro)),
             calc(100vw * var(--holgura) / var(--aspecto)),
             calc(var(--nativo) * var(--invento) / var(--aspecto)));
  height:var(--alto);
  overflow:hidden;
  background:var(--negro);
}

/* AIRE DESPUÉS DE LA PIEZA, PARA PODER CENTRAR AL PERRO. Sin esto la sección es
   lo último del documento: al llegar al final del scroll el canto de abajo de la
   fotografía coincide con el canto de la ventana y el perro se queda anclado
   ABAJO, sin margen para subirlo. Con 12vh de aire el scroll llega un poco más
   lejos y la pieza sube: medido a 1440x900, el centro del cachorro pasa de y=497
   a y=389 en el último cuadro del recorrido, o sea de pegado al borde inferior a
   centrado alto. Sólo en escritorio: en un teléfono la pieza ya llena la ventana
   y el aire sólo añadiría negro que empujar. */
/* EL AIRE DE DESPUÉS lo da el bloque del rótulo, que vive fuera de la sección:
   ver `.escala__cta`. Su alto es lo único que decide DÓNDE queda el cachorro en
   el último cuadro, porque el scroll acaba en el canto de abajo del documento:
       y del cachorro = alto de ventana − alto del bloque − 403 px
   (los 403 son lo que el cachorro está por encima del canto de la fotografía).
   Con el bloque en ~180 px y una ventana de 900, el cachorro cae en y≈316: un
   pelo por encima del centro, que es exactamente lo pedido. */

/* EL ALTO DE ESCRITORIO, APARTE Y SIN DUPLICAR LA REGLA: aquí no se reescribe el
   `height`, sólo la variable de la que sale. 821 px es la MISMA frontera que ya
   usa el `sizes` de las láminas de concursos, así que no se inventa un punto de
   ruptura nuevo. Queda en 2 porque hoy subirlo no haría nada — ver `--invento`. */
@media (min-width:821px){
  .escala{ --pantallas:2; }
}

/* ── DOS CAPAS SOBRE UN SOLO MARCO, Y LAS DOS SON LA MISMA CAJA ───────────────
   Hasta hoy la fotografía llegaba en tres láminas con alfa —el estudio, el adulto
   y el cachorro— que se apilaban para poder tocar a cada uno por separado. Ya no:
   el video es UNA superficie y todo lo que hacía falta separar se murió con el
   recorte (el halo). Quedan dos capas y ocupan exactamente la misma caja: el
   `<img>` del último cuadro debajo y el `<video>` encima.

   EL MARCO NO SE MUEVE, y es lo que salva las medidas de las lanes anteriores: es
   el mismo lienzo 862×1825 de los sujetos, mismo alto, mismo `--aspecto`, mismo
   centro. Por eso la guarda de las patas, el aire de 6 px y las capturas siguen
   valiendo sin rehacerlas — lo que cambió es qué se dibuja dentro, no dónde.

   Y LA CAJA DEL FONDO ES LA QUE REGISTRA EL VIDEO CON EL MARCO: sale con `x`
   NEGATIVA y 3.68 marcos de ancho, así que el piso se derrama por los dos lados y
   en escritorio cubre de lado a lado. Como el video trae al perro centrado, esa
   caja es todo el encuadre que hace falta: no se reencuadra nada, se calibra.

   Sigue habiendo una tercera caja, `.escala__cachorro`, pero ya no lleva lámina:
   es la zona que se pica, medida del último cuadro. */
.escala__marco{
  position:absolute; top:0; left:50%; transform:translateX(-50%);
  height:100%; aspect-ratio:var(--aspecto);
  /* PROMOVIDO A SU PROPIA CAPA, Y EN ESTE ORDEN: primero se encogió el fondo (ver
     el bloque de abajo) y sólo DESPUÉS se promueve. Al revés habría sido peor —
     promover una capa de 2 614 px de ancho a dpr 3 es pedirle al compositor que
     sostenga 34 Mpx en memoria de textura—. Con el fondo ceñido al marco, la capa
     mide lo que la pieza y el scroll la TRASLADA en vez de re-rasterizar mosaicos
     según entran en la ventana, que es lo que se veía al bajar rápido.
     `translateZ(0)` y no sólo `will-change`: aquí ya hay un `translateX`, así que
     la promoción sale del mismo transform y no se paga dos veces. */
  transform:translateX(-50%) translateZ(0);
  will-change:transform;
}
.escala__capa{
  position:absolute;
  left:calc(var(--x) * 100%);  top:calc(var(--y) * 100%);
  width:calc(var(--w) * 100%); height:calc(var(--h) * 100%);
  max-width:none; display:block;
}
/* EL ANCHO DEL FONDO SALE DEL ARCHIVO, Y CON EL VIDEO VERTICAL SE DIO LA VUELTA:
   el video apaisado medía 1056×608 = 1.73684 y se derramaba 3.68 marcos a lo
   ancho; éste mide 1440×2560 = 0.5625 —9:16 clavado— y son 0.5625 ÷ 0.4723 =
   1.19098 marcos. La `x` es lo que hay que correrse a la izquierda para que el
   centro del video sea el del marco, y el píxel queda cuadrado.

   LO QUE SE PIERDE CON ESO VA DICHO SIN ADORNO: el piso YA NO LLEGA A LOS CANTOS
   DE LA VENTANA EN ESCRITORIO. A 1440×900 el fondo se dibuja a 1027 px CSS sobre
   una ventana de 1440 —antes eran 3243— así que sobran 207 px de negro de página
   por lado. No hay forma de arreglarlo con este archivo: el encuadre vertical no
   tiene más madera que enseñar, y estirarlo sería deformar al perro. Lo que sí
   hace falta es que el corte no se vea, y de eso se encarga el velo lateral de
   aquí abajo, que hasta hoy era una red que no se disparaba nunca y ahora
   trabaja de verdad. */
.escala__fondo   { --x:-0.09549; --y:0;       --w:1.19098; --h:1;       }

/* ── EL FONDO NO SE DERRAMA EN UN TELÉFONO, Y ESTO ES UN ARREGLO DE RASTER ────
   Victor: bajando rápido por el perro «se ven los bloques de la foto cargando,
   it makes it look cheap», y —lo que lo delata— PASA TAMBIÉN DESPUÉS DE CARGADA:
   subes, vuelves a bajar y los trozos se vuelven a pintar.

   LA CIFRA LO EXPLICA ENTERO. El derrame 16:9 hace que el fondo se dibuje a 3.76
   marcos de ancho. En un teléfono de 390 eso son 2 614 px CSS, y a dpr 3 la
   superficie que el navegador tiene que rasterizar y SOSTENER es de 34.6 Mpx
   (42.1 en un 430). No la sostiene: tira los mosaicos cuando sales y los vuelve a
   pintar cuando reapareces. Eso no es «cargando», es re-rasterizando — por eso
   pasa con la lámina ya descargada. En escritorio la misma regla son 5.9 Mpx y
   por eso ahí nunca se vio.

   Y LO QUE SE TIRA NO SE VE NUNCA: el derrame existe para que la madera llegue a
   los cantos en ESCRITORIO; en teléfono ya está medido que sobran de 1 069 a
   1 226 px por lado. Se está pagando raster por fotografía que cae fuera de la
   pantalla en todas las ventanas de teléfono.

   Debajo de 820 px el fondo se ciñe al marco y se recorta con `object-fit:cover`,
   que a este aspecto conserva EXACTAMENTE el encuadre vertical de siempre y
   recorta por los lados justo el ala que sobraba: la composición no se mueve un
   píxel y la superficie baja de 34.6 a 9.2 Mpx. El negro de los cantos, si
   sobrara, ya lo pone la sección — no hace falta una fotografía para pintarlo. */
/* CON VIDEO ESTO NO SE HEREDA, SE REHACE, y la cuenta que manda es otra: una
   lámina se rasteriza una vez y un video se decodifica 24 veces por segundo. Con
   el archivo VERTICAL el ala que sobra ya no son 2.68 marcos sino 0.19, así que
   el ahorro de ceñir el fondo cae de 25 Mpx de textura a casi nada — pero el
   recorte SIGUE VALIENDO LA PENA, y ahora por la razón contraria: no por lo que
   ahorra sino por lo que COMPRA. El archivo de teléfono viene recortado al marco
   de fábrica (1080×2284, § index.html), o sea que los 1080 px se gastan enteros
   dentro del marco en vez de repartirse en un 9:16 del que el marco sólo ve el
   84 %. Medido en la caja del cachorro a 390×844 dpr2 —energía de alta
   frecuencia, varianza del laplaciano normalizada por contraste—: el 9:16 sin
   recortar a 1080 da 0.0218 y el recorte a 1080 da 0.0249, con los MISMOS bytes.
   Y contra lo que había desplegado, 0.0011: veintidós veces menos.
   El `cover` se queda para los dos: el recorte mide 1080/2284 = 0.47285 contra el
   0.4723 del marco, y esos cinco diezmilésimos los absorbe él. */
@media (max-width:820px){
  .escala__fondo{
    --x:0; --w:1;
    object-fit:cover; object-position:50% 50%;
  }
  /* ── EL PERRO SE CORRE 20 px A LA DERECHA EN TELÉFONO ──────────────────────
     Victor, en el iPhone: «el perro como que se sale del display, la cara, cuando
     hace sus movimientos». Es cierto y sólo pasa en movimiento: a 430×932, hacia
     el segundo 4 de la intro, el danés gira la cabeza y el hocico, la lengua y la
     oreja izquierda quedan CORTADOS por el canto izquierdo. En el primer cuadro
     no se ve — por eso hay que mirarlo con el vídeo corriendo, no con una captura
     del principio.

     Y NO SE ARREGLA CON `object-position`, aunque sea lo primero que uno toca. El
     archivo de teléfono viene recortado al marco de fábrica (1080×2284) y el
     `cover` sobre esta caja deja 0.8 px de desbordamiento horizontal: medido. No
     hay nada que panear dentro del vídeo. Lo que SÍ recorta es el MARCO, que mide
     768.1 px en una ventana de 430 y va centrado, o sea 169 px fuera por cada
     lado. El encuadre real lo decide dónde se planta ese marco.

     20 px, y el número sale de mirar los dos cantos a lo largo de la intro: con
     el marco centrado la cara se sale por la izquierda; a +20 entra entera con
     aire y al canto derecho todavía le sobra; a +28 el aire de la derecha empieza
     a quedarse corto sin que la izquierda gane nada que se note. Es el mismo
     criterio que el eje x del hero: cuando no caben los dos lados, gana la
     CABEZA. */
  .escala__marco{ transform:translateX(calc(-50% + 20px)) translateZ(0); }
}
/* LA CAJA DEL CACHORRO, MEDIDA DEL VIDEO VERTICAL Y NO DEL APAISADO: x 545-862 e
   y 1801-2291 de los 1440×2560, pasados a marcos con la caja del fondo de aquí
   arriba (el marco ocupa x 115-1325 del video). El canto de abajo es la LÍNEA DE
   CONTACTO, que es la misma para el adulto y para el cachorro porque pisan el
   mismo suelo, y el de arriba son las orejas del cachorro sentado: por encima de
   y=1801 hay negro puro —medido, luminancia 0 en toda la banda 1760-1799—, así
   que el borde no es de gusto.
   SUS PATAS CAEN DONDE CAÍAN, que es lo único que el aterrizaje mira: 0.89492 del
   alto del marco contra 0.88158 de la toma anterior, trece milésimas — y eso son
   3.4 px en un teléfono y 3.7 en escritorio, dentro de los ±5 px que esta pieza
   se permite.
   EL CACHORRO NUEVO ES MÁS ALTO Y MENOS ANCHO EN EL MARCO —0.262 × 0.191 contra
   0.282 × 0.245— porque está sentado más erguido y más lejos del suelo. */
.escala__cachorro{ --x: 0.35537; --y:0.70313; --w:0.26198; --h:0.19180; }

/* EL VELO DE LOS CANTOS VUELVE A TRABAJAR, Y NO ES UNA REGLA NUEVA. Con el video
   apaisado el piso se dibujaba a 3243 px sobre una ventana de 1440 y el canto
   caía 900 px fuera de la pantalla: este velo era una red para una ventana
   absurdamente ancha y no se disparaba nunca. Con el archivo VERTICAL el fondo
   mide 1027 px CSS en esa misma ventana, o sea que sus dos cantos están DENTRO
   y son dos líneas verticales donde la madera corta contra el negro de página.
   El 6 % del ancho de la lámina son 62 px CSS de disolvencia a 1440×900, que es
   lo que convierte ese corte en un desvanecido. En teléfono el fondo va ceñido al
   marco (§ arriba) y el marco es más ancho que la ventana, así que el velo cae
   fuera de pantalla y no cuesta nada. */
.escala__fondo{
  -webkit-mask-image:linear-gradient(90deg, transparent 0, #000 6%,
                                     #000 94%, transparent 100%);
          mask-image:linear-gradient(90deg, transparent 0, #000 6%,
                                     #000 94%, transparent 100%);
}

/* ── TRES CAPAS EN LA MISMA CAJA, Y CADA UNA SE DESCUBRE CUANDO YA PINTA ──────
   Las tres ocupan la MISMA caja (`.escala__fondo`): abajo el `<img>` con el
   PRIMER cuadro del bucle —que es el estado de reposo de la pieza—, encima la
   INTRO, y encima de ella el BUCLE.

   EL ORDEN NO ES DECORATIVO: cada capa tapa a la anterior, así que descubrir una
   nunca puede abrir un hueco. La intro NO SE APAGA cuando entra el bucle; se
   queda debajo, congelada en su último cuadro, que es la misma imagen con la que
   el bucle empieza. Si el bucle tarda, lo que se ve es esa imagen sostenida.

   POR QUÉ NO SE VEN DESDE QUE EXISTEN, QUE ES LO NATURAL: si la intro se viera
   desde que existe, lo primero que enseñaría es su cuadro 1 —el cachorro
   TUMBADO— justo después de que el visitante haya visto la lámina de reposo —el
   cachorro SENTADO—. Eso se lee como un rebobinado. Descubriéndola en `playing`,
   el salto ocurre con la reproducción ya en marcha y, con el disparo media
   pantalla antes de entrar (§ index.html), fuera de la ventana.

   Y ES TAMBIÉN EL RESPALDO, EN DOS ESCALONES Y SIN UNA REGLA DE MÁS: si no hay
   JavaScript, ni video, ni decodificación, o el navegador rechaza la
   reproducción automática, no se pone ninguna clase y la pieza se queda en la
   lámina; si llega la intro y no el bucle, se queda en el último cuadro de la
   intro, que es la misma imagen que la lámina. Entera en los dos casos, sin un
   hueco negro y sin nada que explicar.

   `object-fit:cover` EXPLÍCITO PORQUE UN <video> NO SE COMPORTA COMO UN <img>: el
   ajuste por defecto de un video es `contain` y el de una imagen es `fill`, así
   que un redondeo de un píxel entre la caja y el archivo deja dos franjas negras
   en vez de rellenar. Con `cover` la caja se llena siempre y las dos capas se
   encuadran igual. */
.escala__video{ opacity:0; object-fit:cover; }
.escala.es-vivo  .escala__intro{ opacity:1; }
.escala.es-bucle .escala__bucle{ opacity:1; }
/* Y LA INTRO SE APAGA EN CUANTO EL BUCLE HA PINTADO, QUE NO ES UN DETALLE DE
   LIMPIEZA SINO EL ARREGLO DE UNA REGRESIÓN MEDIDA. Dejarla debajo cuesta una
   capa de compositor de 1080×2284 (2 460×5 202 en un teléfono a dpr 2) que ya no
   enseña un solo píxel, y eso SE VE EN EL CUADRO: con las dos capas vivas, cuatro
   flicks táctiles con CPU ×4 dan 58.0 fps y seis cuadros de 33.4 ms; quitando la
   segunda capa, 60.3 fps y CERO cuadros largos, medido con los brazos
   intercalados y reproducido en cinco vueltas seguidas. No es decodificación —el
   brazo con los dos videos PAUSADOS da los mismos 58.0—: es tener dos superficies
   de ese tamaño en el árbol de capas.
   `visibility` y no `opacity:0`: una capa a opacidad 0 sigue siendo una capa que
   el compositor sostiene, que es justo lo que se está pagando. Y es seguro
   porque la clase que la enciende sólo la pone el primer cuadro PRESENTADO del
   bucle (§ index.html), no su `playing`: cuando la intro desaparece, encima ya
   hay un cuadro opaco pintado. */
.escala.es-bucle .escala__intro{ visibility:hidden; }

/* ── LA ZONA QUE SE PICA, QUE YA NO TIENE LÁMINA PROPIA ───────────────────────
   Era una capa con dos imágenes dentro —el halo y la nítida—, las dos recortadas
   del PNG del cachorro. Con el video no hay recorte que valga: la pieza es UNA
   sola superficie, así que esto vuelve a ser lo que por debajo siempre fue, una
   caja medida encima del cachorro que lleva el `<a>` de WhatsApp.

   SU CAJA ES LA UNIÓN DE LOS 350 CUADROS —los 192 de la intro y los 158 del
   bucle— y no la de un cuadro suelto. El techo lo pone el cachorro SENTADO, que
   es la pose del bucle y la del reposo; durante los 8 s de la intro sube desde
   tumbado, o sea SIEMPRE POR DEBAJO de ese techo. El canto de abajo es la línea
   de contacto con el suelo, que en los 350 cuadros se mueve entre y=2289 y
   y=2293: cuatro píxeles de video, uno de CSS.

   EL HALO SE FUE CON EL RECORTE Y LO QUE LO SUSTITUYE NO VA SOBRE EL CACHORRO
   SINO BAJO ÉL: el charco de luz de aquí abajo (§ `.escala__charco`). `--brillo`
   y `--realce` los sigue escribiendo el mismo script de proximidad sobre
   `.escala` y ahora SÍ los lee alguien — esta caja se quedó sin lámina, pero el
   gancho no se movió ni un carácter.

   EL ACUSE DEL PICADO YA NO CUELGA DE ESTA CAJA. El `scale(1.035)` de abajo se
   queda escrito y sigue sin enseñar un píxel —escalar una caja vacía no dibuja
   nada— pero ha dejado de ser el único acuse: quien acusa hoy es el charco, que
   fogonea (§ `.escala__charco`). La regla se conserva porque el día que esta caja
   vuelva a tener algo dentro vuelve sola, y porque el `transform-origin:50% 96%`
   es la medida de dónde pisa el cachorro y no quiero perderla.

   Y LA FLECHA SÍ RECOGE EL RELEVO, POR FIN. Las dos reglas que lo pedían
   —`.escala.es-picado .escala__cta__flecha`, aquí y en el bloque de la flecha—
   estaban MUERTAS y lo estaban ya en HEAD: piden que la flecha esté DENTRO de la
   sección, y el rótulo vive FUERA desde que se sacó del marco por el contexto de
   apilado. Medido en el navegador: `document.querySelectorAll('.escala.es-picado
   .escala__cta__flecha').length` da 0 aun poniendo la clase a mano. El rótulo es
   el HERMANO INMEDIATO de la sección, así que el combinador correcto es `+` y no
   el descendente; con `.escala.es-picado + .escala__cta ...` el mismo selector da
   1 y la flecha vuelve a saltar al picar al cachorro, que es lo que el archivo
   llevaba diciendo que hacía. Es una conducta que se VE y por eso va con su
   número: 0 → 1. Lo que SÍ seguía vivo del picado es lo que no se dibuja: la
   vibración y el toque sintetizado, y no se tocan. */
.escala__cachorro{
  cursor:pointer;
  /* crece desde SUS PATAS: está sentado en el piso y escalar desde el centro lo
     despegaría del suelo */
  transition:transform 160ms cubic-bezier(.2,.9,.3,1.35);
  transform-origin:50% 96%;
}
.escala.es-picado .escala__cachorro{ transform:scale(1.035); }
.escala.es-picado + .escala__cta .escala__cta__flecha{ transform:translateY(-.7em); }
@media (prefers-reduced-motion: reduce){
  .escala__cachorro{ transition:none; }
  .escala.es-picado .escala__cachorro{ transform:none; }
}

/* ── EL CHARCO DE LUZ, QUE ES LO QUE DICE QUE EL CACHORRO SE PUEDE TOCAR ──────
   El halo dibujaba el contorno del cachorro, y para eso hacía falta un alfa que
   se murió con el recorte. Esto no: lo pinta la PÁGINA, no la fotografía. Tres
   cosas lo hacen la respuesta correcta y ninguna es de gusto —no necesita alfa,
   no se despega cuando el cachorro se mueve porque su contacto con el suelo no
   cambia, y es del idioma de la casa: el CSS del halo ya decía que un brillo
   quieto «de hecho ES una luz de estudio plausible», y un charco sobre un piso
   reflectante lo es todavía más—. Por eso, a diferencia del halo, ESTE SE VE EN
   REPOSO (`--reposo`): un pozo de luz encendido es fotografía, no interfaz.

   VA ENCIMA DEL VIDEO Y NO DEBAJO, porque el video es OPACO — no hay «debajo».
   De ahí sale `mix-blend-mode:screen`, que no es un adorno sino la única mezcla
   que cumple la premisa de la sección: `screen` NUNCA OSCURECE, así que sobre el
   negro de la página el resultado es exactamente el color del degradado y donde
   el degradado llega a alfa 0 el fondo se queda BIT A BIT como estaba. Un velo
   normal con el mismo dibujo ensuciaría el negro que la pieza entera se esfuerza
   en que valga `var(--negro)` — y además apagaría al cachorro, que es blanco:
   `normal` interpola HACIA el color del velo y sobre 255 eso resta.

   ES UNA ELIPSE Y NO UN CÍRCULO, Y EL ACHATAMIENTO ESTÁ MEDIDO. Un círculo sobre
   un suelo en perspectiva se lee como calcomanía. Los tres pasos de abajo se
   hicieron sobre la TOMA ANTERIOR (1056×608) y sus píxeles son de aquel archivo;
   valen para éste porque el marco enseña la misma vista, y el transporte está
   hecho y con su número más abajo. Quedan escritos con sus cifras originales
   porque son el MÉTODO, y el día que llegue una toma de verdad distinta hay que
   repetirlos y no reescalarlos:

     ① EL HORIZONTE, de la veta del piso. Las bandas horizontales de la madera son
       líneas de profundidad constante, así que su separación en `y` obedece
       u_k = K/(k+c) con u = y − y_horizonte. Ajustando las seis bandas limpias de
       los cuadros (y = 540, 547, 555, 563, 573, 582, en columnas sin reflejo)
       sale y_horizonte = 344.25 px con R² = 0.99963. El horizonte cae DENTRO del
       encuadre, 40 px por debajo del centro: la cámara mira un pelo hacia abajo.
     ② LA ESCALA HORIZONTAL, del adulto. Su cruz mide 435 px del piso al cráneo y
       un gran danés adulto mide ahí ~110 cm, o sea 3.95 px/cm en el plano de las
       patas. Con eso la ALTURA DE LA CÁMARA sale sola y sin más supuestos:
       H = u_contacto / escala = 191.75 / 3.95 = 48.5 cm. Cuarenta y ocho
       centímetros: la cámara está casi a ras del piso, y eso se ve sin medir
       nada en las patas del adulto —se les ve el frente de los dedos y no el
       lomo de la pata—.
     ③ EL ACHATAMIENTO de un círculo pequeño en el piso es b/a = u/f, con
       u = 191.75 px. La distancia focal es lo único que no se puede medir aquí
       —esto es un render y su madera es VETA, no duelas con juntas, así que no
       hay regla en el suelo; queda dicho para que nadie cite una duela que no
       existe—: para un encuadre de retrato de 35° a 50° horizontales sobre 1056
       px, f va de 1130 a 1670 px y b/a de 0.170 a 0.115. Se toma el centro,
       b/a = 0.14, o sea UNA ELIPSE DE 1 : 7.

   PERO LA ELIPSE MEDIDA ES LA DEL CHARCO EN EL PISO Y NO LA DE TODA LA LUZ, y
   ésa es la corrección de la segunda vuelta. Victor lo vio desplegado: «el charco
   de luz apenas si se nota y no le enseña a la persona que es un botón». Tenía
   razón, y el fallo no fue de ejecución sino de OBJETIVO: la primera versión
   optimizó la VEROSIMILITUD —367 : 1 entre lo que sube el piso y lo que sube el
   cachorro, o sea la luz cae en el suelo y no mancha al perro— cuando lo que
   estaba fallando era la LEGIBILIDAD. Un desconocido en un teléfono tiene que
   entender que ese cachorro se toca, y 0.088 de 255 sobre el cachorro no se lo
   dice nadie.

   Y EL ARREGLO NO ES SUBIR EL BRILLO, ES QUE HAYA DOS LUCES, porque en el mundo
   también las hay: un pozo de luz sobre un piso reflectante no se queda en el
   piso — REBOTA. Si el suelo brilla y el perro que está DENTRO no, el ojo lee
   «hay una mancha en el suelo» en vez de «este perrito está iluminado», y eso es
   exactamente lo que Victor vio. Así que el elemento pinta DOS degradados:

     ① EL CHARCO, en el piso, con la elipse de 1 : 7 medida arriba. Es la que
       tiene que ser plana; si ésta fuera redonda, calcomanía.
     ② EL REBOTE, mucho más alto que ancho, centrado en el MISMO contacto. Es la
       luz que sube del suelo y baña al cachorro desde abajo: fuerte en sus patas,
       menos en el pecho, nada en la cabeza. No es una licencia — es la única
       forma de que la luz alcance al sujeto sin dibujarle un contorno, que es lo
       que hacía el halo y que ya no se puede hacer sin recorte.

   EL CENTRO SE PONE EN EL CUADRO 539 DEL VIDEO, cuatro píxeles POR DELANTE del
   contacto (535), y esos cuatro no son gusto: la perspectiva ensancha el lado
   cercano, así que un charco real es asimétrico hacia el espectador.

   EL NÚCLEO SIGUE TALLADO AL CACHORRO AUNQUE EL CHARCO SEA MUCHO MÁS GRANDE, y
   ésa es la diferencia entre crecer y desparramarse. Su huella en el piso, medida
   en LOS 350 CUADROS, va de x 547 a 767 del video; las patas del adulto acaban en
   443 y vuelven a empezar en 876. HAY HUECO A LOS LADOS PERO NO SIRVE DE NADA: un
   charco que muriera dentro de ese hueco tendría 0.27 marcos de ancho y sería más
   estrecho que el propio cachorro, o sea una mancha bajo él en vez de una luz.
   No existe ningún charco que alumbre al cachorro Y llegue a leerse en un
   teléfono dejando al adulto a oscuras; quien pida eso está pidiendo un imposible
   de escala, no de geometría. Lo que se hace es poner la MESETA
   del degradado —el tramo que va casi a alfa 1— en el 45 % del radio, que son los
   ±45 px de la huella, y dejar que la caída se derrame hasta ±100. El adulto
   recibe COLA y el cachorro recibe núcleo, que es exactamente lo que hace una luz
   de verdad. Los tramos se abrieron MIRANDO EL PÍXEL y no calculándolos: en la
   primera versión el charco se leía más estrecho que la huella que señalaba.

   Y NO ES UN ANILLO NI UN PULSO TIPO RADAR. Se descarta a propósito y queda
   escrito para que nadie lo reproponga: eso es interfaz pegada encima, y esta
   casa habla el idioma de la luz fotográfica.

   LA CAJA VA EN EL MISMO SISTEMA QUE LAS DEMÁS CAPAS (`--x --y --w --h` en
   marcos) Y ESO NO ES PEREZA: es lo que hace que el charco caiga en el mismo
   sitio en el archivo de escritorio (1440×2560, con el fondo a 1.19 marcos) y en
   el de teléfono (1080×2284, ceñido al marco con `cover`), sin una sola media
   query. Y ES TAMBIÉN LO QUE SALVÓ ESTA CALIBRACIÓN AL CAMBIAR DE VIDEO: los
   cuatro números de abajo son los de la segunda vuelta con Victor, transportados
   TAL CUAL en marcos, porque el marco enseña la misma fotografía en las dos
   tomas (§ el bloque de `.escala`, `--perro` 0.8536 → 0.8527). Sólo se remidió
   el CENTRO, que es lo único que depende de dónde pisa este cachorro.

   EN PÍXELES DEL VIDEO NUEVO la caja mide 885 × 1221 y va centrada en (672,
   2308): el marco mide 1210 px de ancho y 2560 de alto, así que
              ancho  885 ÷ 1210 = 0.73128 marcos   (lo mismo que antes)
              alto  1221 ÷ 2560 = 0.47697 del alto (lo mismo que antes)
   El centro en x es la HUELLA DEL CACHORRO EN REPOSO —sus dos patas delanteras
   van de x=587 a x=758, punto medio 672— y no el centro de su caja, que cae 31 px
   a la derecha (703) porque sentado se recuesta hacia ese lado. Medida sobre los
   192 cuadros la huella se abre a 547-767 mientras está tumbado, o sea que el
   centro de la unión sería 657: se toma el de REPOSO porque el charco es fijo y
   el reposo es el estado en el que la pieza pasa el 99 % del tiempo, que es
   cuando la afordancia tiene que leerse. Los 15 px de diferencia son 5 px CSS en
   escritorio.
   EN `y` VA 17 PX POR DELANTE DEL CONTACTO (2291 → 2308), que es el mismo cuarto
   de por ciento del alto que llevaba la versión anterior: la perspectiva ensancha
   el lado cercano, así que un charco real es asimétrico hacia el espectador.

   LO ÚNICO QUE SE MOVIÓ EN LA RELACIÓN LUZ/HUELLA, Y VA DICHO PORQUE ES UNA
   CONCESIÓN: la huella de este cachorro es más estrecha DENTRO DEL MARCO que la
   del anterior —0.184 marcos contra 0.310— así que la meseta del degradado, que
   allí coincidía con la huella (45 % del radio), aquí la desborda: el tramo casi
   opaco llega al 26 % del radio, que son 109 px de video contra los 111 de
   semihuella. Coincide, pero por el tramo de la MESETA y no por el del 45 %. El
   radio no se baja para volver a cuadrar los porcentajes porque el que mandaba
   nunca fue la huella sino el TECHO DE TELÉFONO: a 390×844 el marco se dibuja a
   697 px CSS sobre una ventana de 390, o sea que sólo se ve el 56 % de él, y un
   charco más ancho deja de señalar para volverse un lavado de pared a pared.
   Ésa es la misma frontera que fijó los ±100 px de la vuelta anterior.

   Y ASÍ SALE EL REPARTO, MEDIDO CON EL CONTROL BUENO (el charco a `opacity:0` y
   no a `display:none`, para que el grupo de mezcla exista en los dos brazos): en
   reposo el piso bajo el cachorro sube +93.6 de 255 en escritorio (×2.49) y +95.6
   en teléfono (×2.41) — clavado en los +95.0 y +87.0 de la vuelta anterior— y
   dentro del cachorro la luz CAE de abajo arriba, que es la firma del rebote:
   patas +40.3, pecho +21.0, cabeza +7.2. Un foco cenital daría lo contrario.
   LO QUE SÍ CAMBIÓ ES CUÁNTO LE TOCA AL CACHORRO EN TOTAL, y no por una decisión
   sino por su tamaño: +21.3 contra los +7.7 de la vuelta anterior, o sea que la
   razón piso : cachorro pasa de 12.3 : 1 a 4.4 : 1. La luz es LA MISMA —los ocho
   números del degradado no se tocaron— pero este cachorro ocupa 0.192 del alto
   del marco donde el anterior ocupaba 0.245: es un 22 % más bajo y por eso cabe
   más adentro del pozo de luz. Queda dicho con su número por si alguien decide
   que es demasiado; bajarlo es bajar el radio vertical del rebote y nada más.

   LA CAJA LA MANDA EL REBOTE Y NO EL CHARCO —es lo alto—, así que los dos
   degradados van con RADIOS EXPLÍCITOS en porcentaje de ella y no con
   `closest-side`: el charco 47.6 % × 4.83 % y el rebote 29.5 % × 50 %. Escrito con
   `closest-side`, los dos habrían heredado la misma elipse y el charco se habría
   vuelto redondo — que es justamente la calcomanía que este bloque lleva veinte
   líneas evitando. Y LA ELIPSE SIGUE SIENDO 1 : 7 SIN VOLVER A DERIVARLA, porque
   b/a = u/f es una propiedad de la VISTA y el marco enseña la misma: transportada
   al video nuevo, la línea del horizonte cae en y≈1488 y u = 803 px, con f entre
   4763 y 7038 px para el mismo abanico de 35° a 50°, o sea b/a entre 0.114 y
   0.169 — el mismo centro, 0.14. NO PUDE REHACER EL AJUSTE DE LA VETA en este
   render y lo digo en vez de callarlo: por debajo del contacto sólo hay tres
   bandas limpias y su solución armónica pone el horizonte 35 px POR ENCIMA del
   contacto, que es geométricamente imposible. El número viejo se sostiene por el
   argumento de la vista, no por una segunda medición del piso.
   Y LA CAJA SE SALE DEL MARCO POR ABAJO A PROPÓSITO (0.663 + 0.477 = 1.140): la
   recorta el `overflow:hidden` de la sección y encima le pasa el velo del canto,
   así que la mitad de abajo del rebote muere donde tiene que morir. */
.escala__charco{
  /* centrada en la HUELLA del cachorro en reposo, x=676 del video, y=2308 */
  --x:0.09797; --y:0.66309; --w:0.73128; --h:0.47697;
  /* EN REPOSO SE VE, Y ES LO QUE HACE QUE LA AFORDANCIA NO DEPENDA DE UNA LÍNEA
     DE JAVASCRIPT: sin script, sin `--brillo` y con movimiento reducido, el
     charco sigue encendido en este valor. El halo no podía permitírselo porque un
     contorno encendido en reposo es un error de composición; una luz en el piso
     en reposo es la fotografía.
     SUBE DE .34 A .62 EN LA SEGUNDA VUELTA, y el .34 no era tímido por descuido:
     era el valor del halo, que estaba pegado a la silueta y por eso se veía con
     poco. Un charco vive en el suelo, lejos del ojo y sobre madera oscura, y a
     .34 se lo comía la fotografía. */
  --reposo:.70;
  /* `--brillo` lo escribe el puntero por proximidad y se topa en .78; `--realce`
     es del hover y es lo que separa «cerca» de «encima». El reposo se queda como
     SUELO y la proximidad reparte lo que falta hasta 1, así que ninguno de los
     dos pisa al otro y el charco nunca puede apagarse por debajo del reposo. */
  opacity:calc((var(--reposo) + (1 - var(--reposo)) * var(--brillo, 0))
               * var(--realce, 1));
  /* LOS DOS DEGRADADOS, Y EL ORDEN IMPORTA: el charco va PRIMERO, o sea encima,
     porque es el que manda donde los dos se pisan. Los alfas son el perfil de la
     luz y el color se cierra hacia el ámbar conforme cae — una luz cálida se lee
     como LUZ y una blanca como un defecto de pantalla, que es por lo que el halo
     viejo también era ámbar. La segunda vuelta calienta el núcleo entero: el
     (255,238,209) de antes era casi papel. Los tramos finales repiten el MISMO
     rgb con alfa 0 y no `transparent`: `transparent` es rgba(0,0,0,0) y al
     interpolar hacia él el degradado pasa por un gris sucio. */
  background:
    /* ① EL CHARCO EN EL PISO · 100 × 14 px de video, la elipse de 1 : 7 */
    radial-gradient(ellipse 47.6% 4.83% at 50% 50%,
      rgba(255,236,198,1)   0%,
      rgba(255,222,164,.94) 26%,
      rgba(255,206,134,.66) 44%,
      rgba(255,188,100,.34) 62%,
      rgba(255,172, 76,.12) 80%,
      rgba(255,164, 66,.03) 92%,
      rgba(255,164, 66,  0) 100%),
    /* ② EL REBOTE · 62 × 145 px, la luz que sube del suelo y baña al cachorro */
    radial-gradient(ellipse 29.5% 50% at 50% 50%,
      rgba(255,226,176,.68) 0%,
      rgba(255,210,142,.46) 28%,
      rgba(255,192,108,.24) 52%,
      rgba(255,176, 82,.09) 76%,
      rgba(255,164, 66,  0) 100%);
  mix-blend-mode:screen;
  pointer-events:none;
  /* el brillo lo escribe el puntero cuadro a cuadro, así que la opacidad NO lleva
     transición: la perseguiría con retraso. La única transición es la del gesto,
     que sí es un evento y no un seguimiento. */
  transition:transform 180ms cubic-bezier(.2,.9,.3,1.35);
  transform-origin:50% 50%;
  will-change:opacity, transform;
}

/* ENCIMA LA LUZ SE CIÑE. Es la traducción honesta de lo que hacía el halo en este
   estado —«pasa de brillar a estar RECORTADO»—: una luz que se cierra un punto se
   lee como un foco que enfoca, y el `--realce` la sube a la vez. Cerca se entera,
   encima se ofrece, picado acusa; y siguen siendo tres cosas distintas y no una
   con tres intensidades. El charco es hermano POSTERIOR del `<a>` para que este
   `~` exista: un hermano anterior no se puede alcanzar desde CSS.

   Y VA DENTRO DE LA MISMA GUARDA QUE USA EL SCRIPT, que no es simetría sino un
   bug cazado midiendo: en un teléfono `:hover` SE QUEDA PEGADO al último elemento
   tocado —comprobado con toque emulado de verdad, `--realce` seguía en 1.35 tras
   soltar—, así que sin la guarda un solo toque dejaba el charco ceñido al 94 %
   para siempre. «Encima» no existe donde no hay puntero que se pose, y ésta es la
   única frontera que lo dice. */
@media (hover:hover) and (pointer:fine){
  .escala__cachorro:hover ~ .escala__charco{
    --realce:1.35;
    transform:scale(.94, .90);
  }
}

/* Y AL PICAR, FOGONEA. El acuse se quedó sin lámina que escalar cuando se fue el
   recorte, así que sale de la misma pieza que ya está pintada y no pide un
   elemento nuevo: sube a tope, se ensancha un pelo y vuelve. `animation:none`
   porque en táctil la opacidad la lleva el latido y una regla de la hoja no le
   gana a un keyframe; a tope se escribe aquí y no inline como el `--brillo`,
   porque aquí sí hay clase que lo sostenga. */
.escala.es-picado .escala__charco{
  animation:none;
  opacity:1;
  transform:scale(1.14, 1.16);
}

/* SIN PUNTERO FINO NO HAY «ACERCARSE», ASÍ QUE EN UN TELÉFONO EL CHARCO RESPIRA.
   Es la misma decisión que llevaba el halo y con el mismo número, que no es
   arbitrario: 1.3 s es LA MITAD EXACTA de los 2.6 s del vaivén de la flecha, así
   que el charco late DOS veces por cada movimiento de ella y los dos coinciden en
   cada ciclo — se lee como un pulso y su eco, no como dos adornos que baten entre
   sí. Cualquier valor cercano pero no múltiplo (2.0, 2.2) los cruza y los separa
   sin repetir nunca, y una pieza con dos ritmos así se siente nerviosa.
   `ease-in-out` y no lineal: un latido lineal es un parpadeo de aviso, y esto no
   es una alarma. Y NUNCA LLEGA A APAGARSE DEL TODO — un charco que se apaga deja
   ver el corte del degradado contra el negro y salta a la vista como un fallo.
   Cuesta cero en el hilo principal: es OPACIDAD sobre una capa promovida, así que
   la resuelve el compositor sin tocar disposición ni pintura.

   EL COMPÁS NO SE TOCA Y EL RECORRIDO SÍ, Y ESA ES LA SEGUNDA VUELTA. Los 1.3 s
   se quedan clavados porque son la mitad de los 2.6 s de la flecha y ahí vive el
   pulso-y-eco; lo que estaba mal calibrado era el RANGO. El .18–.86 se midió para
   un halo pegado a una silueta, donde una diferencia pequeña se ve porque está
   junto al contorno. Un charco vive en el suelo, lejos, sobre madera: con ese
   recorrido se leía como una mancha quieta del piso y no como algo VIVO. Pasa a
   .26–1.00, o sea de 0.68 de recorrido a 0.74 pero sobre un charco que además
   parte de mucho más arriba — en píxeles el suelo bajo el cachorro respira ahora
   entre dos valores que se ven, que es lo único que el ojo juzga. */
@media (hover:none), (pointer:coarse){
  .escala__charco{ animation:escala-late 1.3s ease-in-out infinite; }
}
@keyframes escala-late{
  0%, 100% { opacity:.26; }
  50%      { opacity:1; }
}

/* CON MOVIMIENTO REDUCIDO EL CHARCO SE QUEDA, QUIETO. Apagarlo sería quitarle al
   visitante la única cosa que dice que el cachorro se puede tocar, y un brillo
   fijo no es movimiento: se queda en su valor de reposo, que es justo el que ya
   tiene sin JavaScript. */
@media (prefers-reduced-motion: reduce){
  .escala__charco{ animation:none; transition:none; }
  .escala.es-picado .escala__charco,
  .escala__cachorro:hover ~ .escala__charco{ transform:none; }
}

/* EL CANTO DE ABAJO SE DISUELVE, Y EL VIDEO PIDE MUCHO MENOS VELO QUE EL PNG.
   La sección era lo último del documento y el corte de la fotografía coincidía
   con el fin de la página; con la línea de disponibilidad debajo hay negro
   después, y entonces el piso acabaría en una raya horizontal dura — la misma
   fotografía pegada sobre la página que esta casa lleva tres secciones evitando,
   sólo que por el otro canto.

   LA MEDIDA SE REHÍZO OTRA VEZ PORQUE EL PISO VOLVIÓ A CAMBIAR, Y ESTA VEZ HACIA
   ARRIBA. La última fila del PNG viejo daba luminancia media 12 y máxima 133; la
   del video apaisado, 4.6 y 34 —ese piso se moría solo y por eso el velo bajó de
   26 % a 14 %—; la del video VERTICAL da 26.3 de media y 99 de máxima. El reflejo
   vuelve a llegar VIVO al canto, cinco veces y media más que en la toma anterior,
   así que el velo tiene que volver a trabajar: si se dejara en 14 % con las
   paradas de entonces, la fotografía cortaría contra el negro de la página con
   madera todavía encendida.
   PASA A 16 % Y LAS PARADAS SE CORREN, y el número que decide dónde empieza no es
   el piso sino EL CACHORRO: sus patas acaban en el 89.49 % del alto del marco, y
   el velo tiene que llegar ahí con el 11 % de arriba de la curva y no más — que
   es exactamente lo que le costaba el velo anterior (0.112 contra 0.114 de alfa,
   dos milésimas). O sea: dos puntos más de velo para un piso cinco veces más
   brillante, y al cachorro NO se le cobra ni un punto de más. */
.escala::after{
  content:""; position:absolute; left:0; right:0; bottom:0;
  /* Z-INDEX EXPLÍCITO, Y COSTÓ ENCONTRARLO: el rótulo se declaraba blanco puro
     —el computado decía rgb(255,255,255)— y en la captura su píxel más claro era
     191. No era la tipografía ni la sombra: era ESTE velo pintándose encima. Un
     pseudo-elemento posicionado sin `z-index` no está por debajo de un hermano
     con `z-index:2` por arte de magia, y aquí el orden acababa al revés. Con el
     velo en 1 y el rótulo en 2 el orden queda dicho y no supuesto: medido otra
     vez, el blanco vuelve a 255. */
  z-index:1;
  /* 16 % Y TRES PARADAS: empieza en el 84 % del alto —por debajo de las patas del
     cachorro, que acaban en el 89.49 %, con sólo el 11 % de arriba de la curva—, y
     de ahí al canto lleva el último 10 % del marco, que es reflejo del piso y
     nada más, hasta el negro de la página. */
  height:16%; pointer-events:none;
  background:linear-gradient(to bottom,
    rgba(0,0,0,0) 0%, rgba(0,0,0,.16) 48%, rgba(0,0,0,.70) 80%, var(--negro) 100%);
}

/* ── LA LÍNEA DE DISPONIBILIDAD ───────────────────────────────────────────────
   El cierre del sitio y lo único que esta casa le pide al visitante. Va DEBAJO de
   la fotografía, sobre el negro de la página, y sube una flecha desde ella hasta
   el cachorro: la flecha dice CUÁL y el rótulo dice para qué. Eran tres —el halo
   decía además que algo estaba vivo— y desde que la pieza es un video son dos,
   así que la flecha carga sola con señalar: es lo ÚNICO que dice qué hay que
   picar, y por eso no se toca.

   EL AIRE ES EL DISEÑO. Apretado contra la foto se leía como un pie de imagen —y
   así se veía en la captura de Victor, todo junto—. Con 14vh por arriba y 20vh
   por abajo el bloque mide un tercio de pantalla en escritorio, y ese tercio es
   NEGRO: es también lo que le da a la fotografía sitio donde morir.

   `--garalda` se declara aquí porque el token vive en `.concursos`, no en `:root`.
   El cuerpo es el de la PÁGINA y no el de la fotografía —la pieza se dibuja a 694
   px de ancho en un teléfono y a 862 en un monitor—, así que un rótulo que
   escalara con ella saldría diminuto donde más se necesita. */
.escala__cta{
  --garalda:"Cormorant Concursos", Garamond, "Hoefler Text", "Times New Roman", serif;
  position:relative; z-index:1;
  display:flex; flex-direction:column; align-items:center;
  /* EL ÚLTIMO CUADRO ES UNA COMPOSICIÓN, NO UNA COLA. Victor lo pidió como el
     logo de Apple al encender un teléfono: el perro centrado o un pelo por
     encima, y la palabra justo debajo — LOS DOS EN LA MISMA PANTALLA. Con
     relleno normal el bloque medía 477 px y empujaba al cachorro hasta el borde
     de arriba; el cachorro vive 403 px por encima del canto de la fotografía, o
     sea que cada píxel de este bloque se lo come.

     Por eso el relleno de arriba es CERO y la flecha sube con un margen negativo
     hasta solaparse con el piso: así el bloque sólo aporta la palabra y su aire,
     la flecha se dibuja SOBRE la fotografía apuntando al cachorro, y el conjunto
     cabe. Los números salen de la medida, no del gusto: ver el aire de después,
     que es el otro término de la misma ecuación. */
  /* LAS MISMAS CUATRO VARIABLES DE LA SECCIÓN, porque este bloque tiene que
     resolver la MISMA ecuación desde fuera: `--alto` se declara en `.escala` y
     aquí no se hereda. Repetirlas es feo; adivinar el alto de la fotografía lo
     sería más. */
  --aspecto:0.4723; --perro:0.850; --holgura:1.781; --nativo:862px;
  --pantallas:2; --invento:1;
  --alto:min(calc(var(--pantallas) * 100vh / var(--perro)),
             calc(100vw * var(--holgura) / var(--aspecto)),
             calc(var(--nativo) * var(--invento) / var(--aspecto)));
  /* EL CACHORRO VIVE 0.2211 DEL ALTO DE LA FOTOGRAFÍA POR ENCIMA DE SU CANTO
     —su centro está en el píxel 1421.5 de 1825, medido— y el scroll acaba en el
     canto de abajo del documento, así que:
         y del cachorro = alto de ventana − alto de ESTE bloque − 0.2211·alto
     Despejando para que caiga en el 40 % de la ventana —un pelo por encima del
     centro, el encuadre del logo al encender un teléfono— sale el relleno de
     abajo. El `max(2vh, …)` es el suelo para ventanas bajas, donde la ecuación
     pediría un número negativo. */
  padding:0 1.2rem max(2vh, calc(60vh - 0.2211 * var(--alto) - 1.2em));
  gap:.2em;
  background:var(--negro);
  text-decoration:none;
  color:#fff;
  /* EL TOPE BAJA DE 6.4rem A 4.8rem. Victor: «el título de arriba me lo hiciste
     enorme». No se lo hice yo —este número es el que había—, pero tiene razón en
     lo que ve: a 6.4rem la palabra topa en 102.4 px y el título de la sección
     siguiente topa en 32, o sea un salto de ×3.2 entre dos rótulos que se leen
     seguidos. Con 4.8rem son 76.8 px y el salto queda en ×2.4, que ya es un
     escalón y no un precipicio. Sigue siendo la palabra más grande de la página
     después del hero, que es lo que tiene que ser: es el botón que da dinero.

     Y NO ROMPE LA COMPOSICIÓN DEL CACHORRO: el relleno de abajo de esta misma
     regla se despeja en `em` DE ESTE CUERPO, así que al encoger la palabra el
     bloque mide menos y la ecuación se recoloca sola. La dirección además es la
     segura —el comentario de arriba cuenta que el problema era un bloque DE MÁS,
     que empujaba al cachorro contra el canto—. Encoger da holgura, no la quita. */
  font-size:clamp(2rem, 7.6vw, 4.8rem);
}

/* ── YA NO ES EL CANTO DEL DOCUMENTO, Y LA ECUACIÓN DE ARRIBA SÍ LO CREE ─────
   El relleno de abajo despeja «que el cachorro caiga en el 40 % de la ventana
   CUANDO EL SCROLL SE ACABA», y el scroll se acababa aquí. Desde que el carrusel
   de Liz y el cierre van detrás (index.html), debajo de este bloque hay dos
   piezas más: el rótulo se lee igual y el encuadre del cachorro sigue saliendo
   de la misma cuenta, pero ya nadie garantiza que el visitante lo mire con el
   documento tocando fondo. Se deja la cuenta intacta a propósito —rehacerla es
   rediseñar la sección, y eso no es de esta vuelta—; queda escrito para que
   quien la retome sepa que su premisa cambió de sitio.

   Y EL REBOTE DEL PIE (§ `body.rebota-pie`) ya no puede alcanzarlo: la goma del
   canto ocurre ahora bajo el cierre, dos bloques más abajo. La regla se conserva
   porque no cuesta nada y vuelve sola el día que este bloque vuelva al final.

   APARECE AL LLEGAR. Es lo único de la página que pide algo: que se
   revele cuando el visitante llega le da el peso de un cierre en vez
   del de un letrero que ya estaba. La clase que esconde se la pone el SCRIPT, no
   el HTML: esconder desde el HTML y revelar desde el script es la receta clásica
   para dejar un texto invisible para siempre en cuanto algo falle. */
/* LA OPACIDAD DEL REVELADO VA EN EL CONTENIDO, NUNCA EN EL BLOQUE, y esto fue un
   bug que se vio en pantalla: el bloque pinta el NEGRO que tapa al hero —que es
   `position:fixed` y sigue vivo debajo de todo el documento—, así que bajarle la
   opacidad para la entrada volvía translúcido también ese negro y durante los 900
   ms del revelado se leía GUARDIÁN del hero por detrás de AVAILABILITY. Victor lo
   cazó en una captura a media animación. El fondo del bloque es opaco SIEMPRE; lo
   que aparece es la palabra y la flecha. */
.escala__cta.es-oculto .escala__cta__texto,
.escala__cta.es-oculto .escala__cta__flecha{ opacity:0; }
.escala__cta.es-oculto .escala__cta__texto{ transform:translateY(.7em); }
/* EL EFECTO ES LA TIPOGRAFÍA ABRIÉNDOSE, no una caja deslizándose. La palabra
   entra con el tracking cerrado y se ABRE hasta el suyo mientras sube: en una
   versal de rótulo eso se lee como un rótulo asentándose en su sitio, que es
   el gesto de una portada impresa. Y la flecha llega DESPUÉS —200 ms de retraso—
   para que primero se lea QUÉ y luego se señale DÓNDE; las dos a la vez es una
   animación, escalonadas son una frase. */
.escala__cta.es-oculto .escala__cta__texto{ --pista:.14em; }

.escala__cta__texto{ transition:letter-spacing 1100ms cubic-bezier(.2,.7,.2,1),
                     text-indent 1100ms cubic-bezier(.2,.7,.2,1),
                     opacity 900ms ease,
                     transform 900ms cubic-bezier(.2,.7,.2,1); }
.escala__cta__flecha{ transition:transform 260ms ease, opacity 700ms ease 200ms; }

/* EL REBOTE APAGA LA TRANSICIÓN DEL TRACKING MIENTRAS DURA, y esto se vio
   MIDIENDO, no razonando: el revelado de arriba pone 1100 ms de transición sobre
   `letter-spacing`, y el rebote escribe esa misma propiedad SESENTA VECES POR
   SEGUNDO. Con la transición viva, cada valor que escribe el muelle arranca su
   propia interpolación de 1100 ms y lo que llega a la pantalla es el promedio de
   sesenta animaciones solapadas — o sea, papilla con un segundo de retraso: justo
   lo contrario de un gesto que va con el dedo. En el barrido salía en el número,
   con el tracking leyendo 21.47 px donde tocaban 30.70.

   Se apaga sólo mientras hay tensión, así que la ENTRADA conserva su transición
   entera: el revelado ocurre al llegar al cierre y el rebote sólo puede ocurrir
   en el canto del documento, que está más abajo. Nunca coinciden. Y al soltar,
   la clase se quita cuando el muelle YA está en reposo, así que no hay salto. */
body.rebota-pie .escala__cta__texto{ transition:none; }

/* ── QUÉ ACUSA EL EMPUJÓN ABAJO · SE DECIDE MIDIENDO, NO POR VENTANA ──────────
   LO NATURAL AQUÍ SERÍA ABRIR EL TRACKING, que es el gesto de la casa: el rótulo
   entra abriéndose de .14em a .30em (6af9c06) porque en una versal de rótulo
   eso es un rótulo asentándose. PERO ABRIR EL TRACKING CUESTA ANCHO, y en esta
   página casi nunca lo hay. Medido en español —«Disponibilidad», un 17 % más
   ancha que «Availability»— la palabra ocupa en reposo:

       320 px → 287.6 de 284.8 de hueco     821 px →  804.3 de  782.6
       375 px → 337.0 de 339.8              1024 px → 1003.2 de  985.6
       390 px → 350.5 de 354.8              1280 px → 1254.1 de 1241.6
       430 px → 386.3 de 394.8              1440 px → 1320.1 de 1401.6

   O sea que EN LA MITAD DE LAS VENTANAS YA SE SALE ELLA SOLA, sin que nadie la
   toque —eso es un bug de la página y no de esta lane, y va apuntado—, y en el
   resto le sobran cuatro píxeles. Abrirla un 4.7 % encima la sacaría entre 10 y
   62 px. Sólo a 1440 y más arriba, donde el cuerpo topa en 6.4rem y deja de
   crecer con la ventana, hay sitio de verdad.

   POR ESO EL CANAL NO LO ELIGE UNA MEDIA QUERY SINO UNA MEDIDA. Una media query
   no sabe qué idioma se está leyendo, y la diferencia entre las dos palabras es
   mayor que la que hay entre dos ventanas. El script mide el hueco que le sobra a
   la palabra ANTES de cada gesto y pone `rebote-abre` sólo si el tracking abierto
   cabe entero. Si no cabe —que es lo normal en un teléfono y en un portátil
   estrecho— el empujón se acusa en el eje que SÍ tiene sitio: la palabra CEDE
   HACIA ABAJO contra el dedo, dentro de los 11vh de aire que el bloque ya lleva
   debajo. Misma física, misma amplitud, cero píxeles de ancho.

   LAS DOS SON SEGURAS por lo mismo, y es lo que hace libre a este canto: con
   `hero-guardado` puesto el hero no se pinta, y el bloque es opaco. Mover la
   palabra aquí no puede destapar nada. */
body.rebota-pie .escala__cta__texto{ transform:translateY(calc(var(--pie, 0) * .10em)); }
body.rebota-pie.rebote-abre .escala__cta__texto{ transform:none; --tira:.034em; }

/* ── LA FLECHA ────────────────────────────────────────────────────────────────
   ES UN VECTOR SÓLIDO, no un filete: un `<path>` de 1 px sobre la veta de la
   madera y a media pantalla de distancia sencillamente no existe. Y se dibuja con
   DOS CAJAS y no con un `<svg>` porque tiene que cumplir dos cosas que no escalan
   igual — LLEGAR hasta las patas del cachorro (un largo en fracción de la
   SECCIÓN) y tener el grosor de un trazo tipográfico (un ancho en `em`, atado a
   la palabra). Un `viewBox` fijo tiene que elegir: o estira la punta al estirar el
   asta, o la punta se queda enana en un monitor.

   OJO: el `clip-path` va en el `::after` y NO en el elemento. En el elemento
   recorta también a sus hijos, y así fue como una versión anterior se comió su
   propia punta. */
.escala__cta__flecha{
  position:relative; flex:none;
  width:.9em;
  /* EL LARGO VA EN `em` Y NO EN FRACCIÓN DE LA SECCIÓN, y el cambio es
     obligatorio desde que el rótulo vive FUERA de `.escala`: `--alto` se declara
     en la sección y aquí ya no se hereda, así que el `calc` quedaba inválido y la
     flecha se quedaba sin asta — sólo la punta, flotando. En `em` escala con la
     palabra, que es a lo que pertenece ahora. */
  height:1.55em;
  /* SUBE Y SE SOLAPA CON EL PISO: no ocupa alto en el bloque, así que no empuja
     al perro. Es además donde tiene que estar — dentro de la fotografía,
     señalando al cachorro, no en el margen de debajo. */
  margin-top:-1.55em; margin-bottom:0;
  filter:drop-shadow(0 0 .1em rgba(0,0,0,.96)) drop-shadow(0 0 .34em rgba(0,0,0,.88));
  transition:transform 260ms ease;
  /* SE MECE SOLA. Una flecha quieta apuntando a un perro es una anotación; una
     que respira es una invitación, y en un teléfono —donde no hay hover que
     descubra nada— es lo único que dice que ahí hay algo vivo. */
  animation:escala-mece 2.6s ease-in-out infinite;
}
@keyframes escala-mece{
  0%, 100% { transform:translateY(.14em); }
  50%      { transform:translateY(-.14em); }
}
.escala__cta__flecha::after{          /* el ASTA, afilada hacia la punta */
  content:""; position:absolute; left:50%; bottom:0;
  transform:translateX(-50%);
  width:.18em; height:calc(100% - .52em);
  background:currentColor;
  clip-path:polygon(0 100%, 100% 100%, 81% 0, 19% 0);
}
.escala__cta__flecha::before{         /* la PUNTA: aguja, no triángulo de icono */
  content:""; position:absolute; left:50%; top:0;
  transform:translateX(-50%);
  border-left:.24em solid transparent;
  border-right:.24em solid transparent;
  border-bottom:.58em solid currentColor;
}
.escala__cta:hover .escala__cta__flecha,
.escala__cta:focus-visible .escala__cta__flecha{ animation:none; transform:translateY(-.45em); }
.escala.es-picado + .escala__cta .escala__cta__flecha{ animation:none; transform:translateY(-.7em); }

.escala__cta__texto{
  font-family:var(--garalda);
  /* ── EL CANTO DE ABAJO · EL TRACKING ACUSA EL EMPUJÓN ───────────────────────
     EL TRACKING SE ESCRIBE COMO UNA SUMA, y ésa es toda la razón por la que el
     rebote y el revelado de 6af9c06 pueden compartir la misma propiedad sin
     pisarse: `--pista` es el tracking de REPOSO —el que cambia entre escritorio,
     teléfono y la entrada—, y `--pie` es la TENSIÓN, de -1 a 1, que escribe el
     script. Ninguno de los dos sabe del otro.

     ES EL MISMO GESTO DE LA CASA Y NO UN `scale` DE INTERFAZ: en una versal de
     rótulo, abrir el tracking es lo que hace que se lea como que se asienta. El revelado lo usa para entrar; el rebote lo usa para acusar el
     empujón. Y `--pie` LLEGA EN NEGATIVO al soltar, porque el muelle rebasa: la
     palabra se pasa un pelo POR DEBAJO de su tracking de reposo antes de
     asentarse. Eso es, con estas letras, lo que pidió Victor — «que crezca
     tantito y se haga más chiquito y te empuje de vuelta». Aquí el rebasamiento
     sale gratis y arriba no: esto es texto blanco sobre un bloque OPACO, y con
     `hero-guardado` puesto el hero ni siquiera se pinta.

     `white-space:nowrap` NO ES ADORNO, ES EL SEGURO: si el tracking abierto
     partiera la palabra en dos renglones, el bloque crecería de alto, el
     documento entero cambiaría de altura A MEDIO GESTO y el scroll saltaría bajo
     el dedo. Una línea, siempre. */
  --pista:.30em;
  /* EL TRACKING NO SE ABRE POR DEFECTO: SE GANA MIDIENDO. Ver `.rebote-abre`
     ochenta líneas más abajo — en esta página la palabra suele llenar su caja. */
  --tira:0em;
  letter-spacing:calc(var(--pista) + var(--pie, 0) * var(--tira));
  text-indent:calc(var(--pista) + var(--pie, 0) * var(--tira));
  white-space:nowrap;
  /* wght 600 Y ESTÁ MEDIDO, NO ELEGIDO — y de paso la medida corrige el porqué
     que estaba escrito aquí. Decía que a 102 px una Bodoni de peso 400 se lee
     PLATEADA porque el ojo promedia asta y fino: a este cuerpo eso NO se
     reproduce en ninguna de las dos tipografías. Erosionando un píxel la máscara
     de tinta —o sea quitándole al trazo su antialias y quedándose con el centro
     del asta— el centro sale a 254.6 sobre 255 en Bodoni 400, en Bodoni 500 y en
     Cormorant a cualquier peso. A 102 px el asta llega a blanco siempre; el
     plateado de aquel día era de otro tamaño o de otro fondo.
     Lo que sí cambia con el peso, y es lo que se ve, es la DENSIDAD DE TINTA:
     la luminancia media del trazo con su antialias, en 1440x900:
                         @1x     @2x
         Bodoni    500   226.5   237.5     ← el estado que Victor aprobó
         Cormorant 500   222.4   235.2     por debajo: se lee más flaca
         Cormorant 600   229.6   239.0     el primero que lo iguala y lo pasa
         Cormorant 700   230.9   240.3     ya no es una garalda, es una negra
     600, que además es el peldaño que se esperaba: Cormorant dibuja más ligera
     que Bodoni al mismo número. */
  font-variation-settings:"wght" 600;
  font-size:1em;
  line-height:1;
  text-transform:uppercase;
  color:inherit;
  margin:0;
  /* la viñeta va en PÍXELES y no en `em`: en `em` el desenfoque crecía con la
     letra, se metía dentro de las astas y el blanco salía gris */
  text-shadow:0 0 8px rgba(0,0,0,.95), 0 0 26px rgba(0,0,0,.85), 0 0 70px rgba(0,0,0,.7);
}

/* EN UN TELÉFONO EL TRACKING SE CIERRA PARA QUE EL CUERPO PUEDA CRECER: con .30em
   la palabra medía 423 px en una ventana de 390 y se salía. Encogerla habría sido
   lo contrario de lo pedido; cerrar el tracking a cuerpos grandes es además lo
   tipográficamente correcto. Y el trazo sube un peldaño más — ver el bloque del
   final de concursos.css, que es donde está el porqué entero. */
@media (max-width:820px){
  .escala__cta{ padding:8vh 1.1rem 11vh; }
  .escala__cta__texto{
    font-variation-settings:"wght" 650;
    font-size:clamp(1.5rem, 8.2vw, 6.4rem);
    --pista:.15em;
  }
}

/* ── EL TELÉFONO APAISADO ES OTRA COMPOSICIÓN, Y LA CULPA ES DE `vh` ──────────
   MEDIDO Y NO DEDUCIDO: simulador iOS 26.5, iPhone 17 girado, Mobile Safari.
   `innerWidth` 874, `innerHeight` 292 — y `100vh` = 402. Los 110 px de diferencia
   son las barras de Safari, que apaisado se comen el 27 % de la pantalla y que
   `vh` NO CUENTA NUNCA: en iOS `100vh` es el viewport GRANDE, el de las barras
   escondidas. Con eso la pieza se dibujaba a 942 px de alto (2 × 402 / 0.8531)
   dentro de una ventana de 292, y al fondo del documento el cachorro aterrizaba
   en y = −75: FUERA DE PANTALLA. Cachorro y llamada a WhatsApp no se veían juntos
   nunca, que es lo único que esta sección tiene que hacer.

   `svh` Y NO `dvh`, Y NO CONTRADICE EL COMENTARIO DE `.escala`. Lo que aquél
   defiende es que el alto del documento NO SE MUEVA con el dedo dentro de la
   sección, y el que se mueve es `dvh`. `svh` es el viewport PEQUEÑO —barras
   puestas— y es tan fijo como `vh`; la diferencia es que es el que SE VE. Y falla
   por el lado bueno: con las barras escondidas sobran esos 110 px y el cachorro
   sube DENTRO de la ventana en vez de salirse por arriba.

   LA FRONTERA ES EL ALTO Y NO EL ANCHO, y por eso no sirve el `(max-width:820px)`
   de aquí arriba: un iPhone apaisado mide 874 de ancho y se cuela entero por el
   lado de escritorio —sus rellenos de 8vh/11vh tampoco valdrían aquí—. 520 px
   deja fuera cualquier escritorio y dentro cualquier teléfono de canto, que como
   mucho mide 430. En vertical no entra: el encuadre medido no se toca.

   Y EL RÓTULO CEDE CUERPO, que es lo único que se sacrifica. A 7.6vw medía 66 px
   y su bloque ocupaba 87 de los 292 px de ventana, el 30 %; a 4.6vw mide 40 px y
   el bloque 54, el 18 %. La cuenta que manda es

       y del cachorro = alto de ventana − alto del bloque − 0.29687 × --alto

   —0.10507 de piso que le queda debajo más los 0.19180 que mide él—, y con
   --alto = 684.6 px da y = 35 px de aire por encima en vez de −75. El campo de
   toque del enlace queda en 874 × 54, por encima de los 44 × 44 de Apple. */
@media (orientation:landscape) and (max-height:520px){
  .escala, .escala__cta{
    --alto:min(calc(var(--pantallas) * 100svh / var(--perro)),
               calc(100vw * var(--holgura) / var(--aspecto)),
               calc(var(--nativo) * var(--invento) / var(--aspecto)));
  }
  /* LA MISMA ECUACIÓN DEL BLOQUE DE ARRIBA CON EL VIEWPORT QUE SE VE, y el inset
     de abajo sumado aparte y no metido en el `max()`: con `viewport-fit=cover` el
     indicador de inicio vive en los últimos píxeles de la ventana y el rótulo se
     le metía debajo. Los laterales van por `max()` porque apaisado el inset del
     lado de la isla son 59 px y 1.1rem son 17.6: ahí manda el que sea mayor. */
  .escala__cta{
    padding:0 max(1.1rem, env(safe-area-inset-right, 0px))
              calc(max(2svh, calc(60svh - 0.2211 * var(--alto) - 1.2em))
                   + env(safe-area-inset-bottom, 0px))
              max(1.1rem, env(safe-area-inset-left, 0px));
  }
  .escala__cta__texto{ font-size:clamp(1.25rem, 4.4vw, 2.25rem); }
}

@media (prefers-reduced-motion: reduce){
  .escala__cta, .escala__cta__flecha, .escala__cachorro{ transition:none; animation:none; }
  /* EL REBOTE SE APAGA EN LA HOJA Y NO SÓLO EN EL SCRIPT. El script no se
     instala con reduced-motion, pero alguien puede cambiar la preferencia con la
     página ya abierta y el oyente ya puesto: poniendo a cero las dos amplitudes,
     los dos `calc` caen en su valor de reposo pase lo que pase. */
  .escala__cta__texto{ --tira:0em; }
  body.rebota-pie .escala__cta__texto{ transform:none; }
  body.rebota-cima .hero__foto,
  body.rebota-cima .hero__licua{ transform:none; }
  .escala.es-picado .escala__cachorro{ transform:none; }
  .escala__cta.es-oculto{ opacity:1; transform:none; }
}
