/* ═══════════════════════════════════════════════════════════════════════════
   MERIDIAN — Ascenta

   The palette is not a taste: it is sampled from the film. The studio plate
   measures 3/3/4 over 388 frames, the diamond highlight lands on #F0E5DC and
   the dial on #2B3E68. Three values, and the product supplies all three.

   Dark, and dark on purpose: a diamond's brilliance IS contrast. A specular
   hit on white has nothing to stand against, and polished steel — which shows
   you whatever is around it — shows you white and stops reading as metal.
   (Milky white is the right answer for a matte or self-coloured product. Not
   for this one.)

   🔴 UNA SOLA GROTESCA, Y LOS TITULARES A MENOS DE LA MITAD.

   Aquí hubo primero Archivo sola ("el eje de anchura hace de segunda familia"),
   y luego Archivo + **Bodoni Moda** con un argumento largo sobre la didone como
   tipo histórico de la alta relojería. Alex, 29-jul: "el font sigue siendo una
   putísima basura. Especialmente los fonts de título son asquerosos y super
   típicos de IA, INCLUYENDO TAMAÑOS."

   Las dos mitades de esa frase importan y son distintas:

     · LA FAMILIA. Una didona de altísimo contraste a 116 px sobre negro ES el
       aspecto de "web de lujo generada" — Bodoni, Playfair y Cormorant son la
       misma decisión con tres nombres, y la eligen porque "lujo = serifa fina",
       que es un reflejo, no una lectura del producto.
     · EL TAMAÑO. Un titular de 116-140 px que ocupa media pantalla es el otro
       tell, y es independiente de la fuente: cámbiala y sigue pareciendo lo
       mismo. Aquí los titulares bajan un 55%.

   Lo que hay ahora es **Instrument Sans**, y es la única familia de la página.
   No es "poner una sans": es la lectura correcta del producto. Esto es un
   documento de un instrumento de precisión — un bulletin de marche, un índice
   de referencias, una tabla de marchas en cinco posiciones — y la relojería que
   se toma en serio a sí misma se compone así (Nomos, Braun, Sinn), no con la
   didona del anuncio de perfume.

   Por qué esta y no otra grotesca:
     · EJE DE ANCHURA REAL (wdth 75-100). Todo el sistema de esta página se
       apoya en condensar lo funcional y dejar ancho lo editorial; sin ese eje
       habría que traer una segunda familia para lo mismo.
     · CIFRAS TABULARES (`tnum`). El certificado, los precios y las referencias
       son columnas de números: sin tabulares bailan, y ese bloque es la mitad
       de la página.
     · `case`. Las cabeceras van en caja alta, y esta familia sube también los
       signos — el punto medio y el paréntesis se recolocan solos.

   El reparto ya no es por familia sino por ANCHURA Y PESO, que es lo que hace
   que se lea como un sistema y no como dos fuentes discutiendo:
     · editorial (titulares, nombres) — wdth 88-92, wght 550-600, cuerpos MEDIOS.
     · funcional (cabeceras, etiquetas, botones) — wdth 80-84, wght 620, 11-12 px.
     · datos (tablas, cifras, certificado) — wdth 92, tabular, wght 450.
   ═══════════════════════════════════════════════════════════════════════════ */

@font-face {
  font-family: 'Instrument';
  src: url('../fonts/instrument-var.woff2?v=2') format('woff2-variations');
  font-weight: 400 700;
  font-stretch: 75% 100%;
  font-display: optional;   /* uses it only if it is there in <100ms => 0 shift */
}
/* A fallback metric-matched to Instrument Sans, so if the web font loses the
   race nothing moves when it arrives. Measured off the file: upm 1000,
   asc 970, desc 250, x-height 510 — against Arial's 0.5186 x-height that is a
   size-adjust of 98.3%. */
@font-face {
  font-family: 'Instrument Fallback';
  src: local('Arial'), local('Helvetica Neue'), local('Liberation Sans');
  size-adjust: 98.3%;
  ascent-override: 97%;
  descent-override: 25%;
  line-gap-override: 0%;
}

:root {
  --void:  #020203;   /* the film's own cyclorama, measured */
  --ink:   #F4F1EC;
  --ink-2: rgba(244, 241, 236, .60);
  /* .40 measures 3.4:1 against the page black, and every one of the things
     drawn in it — running heads, captions, references, unit marks — is 11px
     functional text. Tone that reads as "quiet" at a glance can still be a
     failure at the size it is actually set. .52 is 5.1:1 and looks the same. */
  --ink-3: rgba(244, 241, 236, .52);
  --blue:  #2B3E68;
  --blue-lit: #6E8FC9;
  --line:  rgba(244, 241, 236, .12);
  /* for type that sits ON the film, where the backdrop is not the page black */
  --ink-film: rgba(244, 241, 236, .74);

  --pad: 44px;
  /* Ultrawide: a fixed 1620px ribbon on a 5120 monitor leaves 1750px of margin
     on each side. This grows the column with the screen and still stops. */
  --wrapw: min(max(1620px, 62vw), calc(100vw - var(--pad) * 2));
  --gut:   calc((100vw - var(--wrapw)) / 2);
  --measure: 64ch;

  --e-out: cubic-bezier(.16, 1, .3, 1);
  --e-io:  cubic-bezier(.65, 0, .35, 1);
}
@media (max-width: 900px) { :root { --pad: 24px; --measure: 60ch; } }

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

/* ⛔ `overflow-x: hidden` EN EL BODY NO BASTABA, y el motivo no se ve en la
   inspeccion normal: las pozas (`.scrim::before`) llevan margenes negativos
   horizontales, y un PSEUDO-elemento no aparece cuando recorres el DOM
   midiendo `getBoundingClientRect`. En movil sobresalian y la pagina se dejaba
   arrastrar 17 px a la derecha.

   Va `clip` y no `hidden` a proposito: `hidden` convierte al elemento en
   contenedor de scroll, y eso rompe `position: sticky` y las animaciones con
   `animation-timeline: view()` — que es justo de lo que vive esta pagina.
   `clip` recorta sin crear el contenedor.

   🔴 Y ESA MISMA FRASE ESTABA ESCRITA AQUI MIENTRAS EL BODY DE ABAJO SEGUIA EN
   `hidden`. Se arreglo el `html`, se dejo escrito POR QUE, y el elemento de al
   lado con el mismo defecto no se toco — que es el modo mas comun de que un bug
   sobreviva a su propia documentacion.

   Lo que costaba, medido: `overflow-x: hidden` con `overflow-y: visible` hace
   que el `overflow-y` COMPUTE a `auto` (verificado en vivo: el body daba
   `hidden/auto`), o sea que el body pasa a ser el contenedor de scroll mas
   cercano de todo lo que cuelga de el. Pero quien hace scroll de verdad es el
   viewport, no el body — asi que `.hero-pin`, con su `position: sticky` puesto
   y computando `sticky`, NO SE PEGABA NUNCA: a scroll 7000 su borde superior
   estaba en -7000, deslizandose 1:1 con la pagina.

   Es decir: el hero no ha estado pinchado en ningun momento. No se veia porque
   el titular se apaga por fotograma entre el 176 y el 228, asi que se
   desvanecia MIENTRAS se iba hacia arriba y las dos cosas juntas parecian el
   gesto que se habia disenado. El relevo es lo que lo destapo — un bloque que
   entra tiene que quedarse en pantalla, y este entraba ya fuera de ella. */
html { background: var(--void); overflow-x: clip; }
body {
  margin: 0;
  background: var(--void);
  color: var(--ink);
  font-family: 'Instrument', 'Instrument Fallback', system-ui, sans-serif;
  font-variation-settings: 'wght' 400, 'wdth' 100;
  font-size: 17px;
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: clip;   /* ⛔ NO `hidden`: rompe el sticky del hero. Ver arriba. */
}
/* Ultrawide is not "the same page, wider". A 112px headline is a caption next
   to a film 1920px across, and the vault has the note to prove it. */
@media (min-width: 2400px) {
  body { font-size: 18px; }
  .hero-copy h1 { font-size: clamp(62px, 1.7vw, 82px); }
  .hero-relay h2 { font-size: clamp(44px, 1.25vw, 60px); }
  .hero-copy .lede, .hero-relay .lede { font-size: 20px; }
  .stmt { font-size: clamp(50px, 1.5vw, 70px); }
  .slead { font-size: clamp(29px, .95vw, 40px); max-width: 30ch; }
  .runhead, .index-head { font-size: 12px; }
}

img, canvas { display: block; max-width: 100%; }
::selection { background: var(--blue-lit); color: var(--void); }

:where(a, button):focus-visible {
  outline: 2px solid var(--blue-lit);
  outline-offset: 3px;
  border-radius: 1px;
}

.skip {
  position: fixed; top: -100px; left: var(--pad); z-index: 90;
  background: var(--ink); color: var(--void);
  padding: 10px 18px; font-size: 13px; text-decoration: none;
}
.skip:focus { top: 14px; }

.wrap { width: var(--wrapw); margin-inline: auto; }

/* ── type scale ──────────────────────────────────────────────────────────── */
h1, h2, h3 { margin: 0; font-weight: 400; }

h1 {
  font-size: clamp(38px, 3.35vw, 64px);
  font-variation-settings: 'wght' 570, 'wdth' 90;
  line-height: .92;
  letter-spacing: -.028em;
}
h2 {
  font-size: clamp(27px, 2.4vw, 46px);
  font-variation-settings: 'wght' 570, 'wdth' 90;
  line-height: 1.02;
  letter-spacing: -.022em;
}
h3 {
  font-size: clamp(20px, 1.4vw, 27px);
  font-variation-settings: 'wght' 570, 'wdth' 90;
  line-height: 1.06;
  letter-spacing: -.018em;
}
p { margin: 0; }

/* ── nav ─────────────────────────────────────────────────────────────────────
   ⭐ UNA CÁPSULA DE CRISTAL FLOTANTE, Y EL LOGO DENTRO CON LOS ENLACES.

   Alex, 29-jul: "el nav bar debería estar visible en todo momento. El logo de
   ascenta debería estar al lado de los enlaces. Debería tener una forma super
   guapa y moderna y ser cristalino."

   🔴 Y ANTES QUE NADA, EL BUG: EL NAV NO ESTABA FIJO.
   Aquí ponía `position: fixed`, sí — y 70 líneas más abajo había
   `main, footer, .nav { position: relative; z-index: 1; }` para subir el
   contenido por encima de la película. Misma especificidad, y gana la última:
   el nav llevaba TODA la página en `position: relative`, así que se iba con el
   scroll y a los 13.700 px estaba a −13.700 de la pantalla. No es que se
   escondiera de forma elegante — es que no estaba. Por eso `.nav` sale de esa
   regla y su `z-index` vuelve a 50.

   🟡 Y AQUÍ PONÍA "not a floating blurred pill", con dos argumentos. Uno era
   real y el otro no:
     · el coste. `backdrop-filter` sobre un lienzo que se repinta obliga a
       re-desenfocar esa región en cada fotograma. Es cierto, y por eso el
       cristal es la CÁPSULA y no una barra de ancho completo: se difumina una
       caja de ~740x54 en vez de 1920x68, y lleva `contain: paint` para que el
       compositor no promueva de más.
     · "la pastilla es la forma que trae toda página generada". Eso ya no es un
       argumento de diseño, es una superstición: la cápsula es la convención de
       navegación de 2026 igual que la barra pegada arriba lo fue de 2015. Lo
       que delata a una plantilla no es la forma, es que la forma no esté
       resuelta. Ésta lo está: el logo y los enlaces van DENTRO de la misma
       pieza, separados por un filete, y la acción es un segmento propio al
       final — un solo objeto, no tres cosas repartidas por el ancho. */
.nav {
  position: fixed;
  top: 14px; left: 50%;
  transform: translateX(-50%);
  z-index: 50;
  display: flex; align-items: center;
  gap: 6px;
  max-width: calc(100vw - var(--pad));
  padding: 6px 6px 6px 16px;
  font-size: 11.5px;
  font-variation-settings: 'wght' 620, 'wdth' 84;
  letter-spacing: .1em;
  text-transform: uppercase;
  /* EL CRISTAL. Tinte del propio negro de la película (no un azul, que metería
     un material que no está en la bobina) + saturación, que es lo que hace que
     un cristal parezca cristal y no gasa gris: por debajo pasan el anillo de luz
     y la esfera azul, y sin `saturate` llegan lavados. */
  background: rgba(9, 11, 16, .44);
  -webkit-backdrop-filter: blur(22px) saturate(165%);
          backdrop-filter: blur(22px) saturate(165%);
  border: 1px solid rgba(244, 241, 236, .11);
  border-radius: 999px;
  /* El canto de luz de arriba es lo que le da grosor: sin él la cápsula es una
     silueta plana con un borde, con él es una pieza de vidrio con un bisel. */
  box-shadow: 0 1px 0 0 rgba(244, 241, 236, .07) inset,
              0 18px 40px -24px rgba(0, 0, 0, .9);
  contain: paint;
  transition: background .5s var(--e-io), border-color .5s var(--e-io),
              box-shadow .5s var(--e-io);
}
/* Al arrancar la página el nav está sobre el negro puro del hero y el cristal no
   tiene nada que hacer: se queda casi invisible. En cuanto la página se mueve,
   se asienta. */
body:not(.moved) .nav {
  background: rgba(9, 11, 16, .22);
  border-color: rgba(244, 241, 236, .07);
}
.nav a { color: var(--ink-2); text-decoration: none; transition: color .28s var(--e-out); }
.nav a:hover { color: var(--ink); }

/* EL LOGO, DENTRO Y PEGADO A LOS ENLACES. Iba en el extremo izquierdo de una
   barra de 1920 px, con los enlaces en el centro y la acción a 1.700 px de
   distancia: tres islas, no una navegación. */
.brand {
  display: inline-flex; align-items: center; gap: 9px;
  color: var(--ink) !important;
  font-variation-settings: 'wght' 650, 'wdth' 90;
  letter-spacing: .2em;
}
.brand img { width: 19px; height: auto; opacity: .95; }
/* El filete entre la marca y los enlaces. Es lo que hace que se lean como dos
   campos de una misma pieza en vez de como dos cosas que han caído juntas. */
.nav-sep {
  width: 1px; height: 17px;
  margin: 0 4px 0 14px;
  background: rgba(244, 241, 236, .16);
}
.nav-links { display: flex; align-items: center; gap: 4px; }
.nav-links a {
  padding: 9px 13px;
  border-radius: 999px;
  transition: color .28s var(--e-out), background-color .28s var(--e-out);
}
.nav-links a:hover { background: rgba(244, 241, 236, .07); }
/* La sección en la que estás, marcada dentro de la propia cápsula. */
.nav-links a[aria-current="true"] { color: var(--ink); background: rgba(244, 241, 236, .10); }
.nav-cta {
  margin-left: 6px;
  padding: 10px 20px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--void) !important;
  font-variation-settings: 'wght' 650, 'wdth' 84;
  transition: background-color .3s var(--e-out), color .3s var(--e-out);
}
.nav-cta:hover { background: #fff; color: var(--void) !important; }

/* El botón de menú sólo existe en pantallas estrechas. */
.nav-burger {
  display: none;
  width: 40px; height: 38px;
  margin-left: 2px;
  padding: 0;
  border: 0; border-radius: 999px;
  background: rgba(244, 241, 236, .07);
  color: var(--ink);
  cursor: pointer;
}
.nav-burger span {
  display: block; width: 15px; height: 1.5px;
  margin: 3px auto;
  background: currentColor;
  transition: transform .34s var(--e-out), opacity .2s linear;
}
.nav-panel { display: none; }

@media (max-width: 900px) {
  /* En el móvil la cápsula se queda con la marca y el menú; los enlaces bajan a
     un panel del mismo cristal. Lo que NO cambia es que la cápsula sigue en
     pantalla — que es lo que se pidió. */
  .nav { top: 10px; padding: 6px 6px 6px 14px; max-width: calc(100vw - 20px); }
  .nav-sep, .nav-links, .nav-cta { display: none; }
  .nav-burger { display: block; }
  .nav-panel {
    display: block;
    position: fixed; top: 66px; left: 50%;
    transform: translateX(-50%) translateY(-8px);
    z-index: 49;
    width: min(320px, calc(100vw - 24px));
    padding: 10px;
    background: rgba(9, 11, 16, .58);
    -webkit-backdrop-filter: blur(22px) saturate(165%);
            backdrop-filter: blur(22px) saturate(165%);
    border: 1px solid rgba(244, 241, 236, .11);
    border-radius: 22px;
    box-shadow: 0 1px 0 0 rgba(244, 241, 236, .07) inset,
                0 24px 50px -28px rgba(0, 0, 0, .95);
    opacity: 0; visibility: hidden;
    transition: opacity .3s var(--e-out), transform .38s var(--e-out),
                visibility 0s linear .38s;
  }
  body.nav-open .nav-panel {
    opacity: 1; visibility: visible;
    transform: translateX(-50%) translateY(0);
    transition-delay: 0s;
  }
  body.nav-open .nav-burger span:nth-child(1) { transform: translateY(4.5px) rotate(45deg); }
  body.nav-open .nav-burger span:nth-child(2) { opacity: 0; }
  body.nav-open .nav-burger span:nth-child(3) { transform: translateY(-4.5px) rotate(-45deg); }
  .nav-panel a {
    display: block;
    padding: 13px 14px;
    border-radius: 14px;
    color: var(--ink-2); text-decoration: none;
    font-size: 12px;
    font-variation-settings: 'wght' 620, 'wdth' 84;
    letter-spacing: .1em; text-transform: uppercase;
  }
  .nav-panel a:hover, .nav-panel a:focus-visible { background: rgba(244, 241, 236, .07); color: var(--ink); }
  .nav-panel .nav-panel-cta {
    margin-top: 4px;
    background: var(--ink); color: var(--void);
    text-align: center;
  }
}
/* Sin `backdrop-filter` (Firefox con el flag apagado, y algún WebKit antiguo) un
   fondo al 44% deja pasar la película entera y los enlaces se pierden sobre la
   mano iluminada. Ahí el cristal se cambia por un tinte opaco: se pierde el
   efecto, no la legibilidad. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .nav, .nav-panel { background: rgba(7, 9, 13, .93); }
  body:not(.moved) .nav { background: rgba(7, 9, 13, .82); }
}
@media (prefers-reduced-motion: reduce) {
  .nav, .nav-panel, .nav-burger span { transition: none; }
}

/* ── hero ────────────────────────────────────────────────────────────────────
   300lvh of scroll drives 388 frames. lvh, not vh: the mobile URL bar makes a
   height:100% fixed box breathe, and while the backing store has not caught up
   the browser stretches the film inside the new box — it visibly narrows as you
   scroll. The large viewport is constant, so the box never changes. */
/* 500lvh, no 300: la bobina paso de 388 a 772 fotogramas y la DENSIDAD tiene que
   quedarse igual o el descenso correria al doble de velocidad que el hero. El
   hero eran 388 sobre 200lvh de recorrido (300 de seccion menos el propio
   viewport) = 1,94 fotogramas por lvh; 772 sobre 400 = 1,93. La misma mano. */
/* ⭐ EL LIENZO ES EL FONDO DEL DOCUMENTO, NO EL DE UNA SECCIÓN.
   `fixed`, no `sticky`: un sticky sólo puede pegarse dentro de su padre, así
   que mientras la película fuera hija de `.hero` era imposible que siguiera
   pintando cuando `.hero` terminaba — se despegaba y salía de pantalla. Fija al
   viewport se queda ahí toda la página, que es lo que pidió Alex.
   height 100lvh y no 100%: la barra del navegador del móvil hace respirar una
   caja fija al 100%, y mientras el backing store no alcanza, el navegador
   estira la película dentro de la caja nueva — se ve estrecharse al hacer
   scroll. El viewport grande es constante. */
.filmbg {
  position: fixed; inset: 0; top: 0; left: 0;
  width: 100%; height: 100lvh;
  overflow: hidden;
  background: var(--void);
  z-index: 0;
  /* Sin esto, un contenido con backdrop-filter por encima puede promover el
     lienzo a una capa que se repinta entera en cada fotograma. */
  contain: strict;
}
/* Todo el contenido navega POR ENCIMA de la película.
   ⛔ `.nav` NO VA AQUÍ. Estuvo, y le ponía `position: relative` encima de su
   propio `position: fixed` — misma especificidad, gana la de abajo — así que el
   nav se iba con el scroll y a media página estaba a trece mil píxeles de la
   pantalla. El nav tiene su propia capa (z-index 50) y su propio anclaje. */
main, footer { position: relative; z-index: 1; }

/* El hero ya no mueve la película — la mueve el documento entero. Lo que mide
   esta altura ahora es cuánto tiempo la película corre SOLA antes de que entre
   la primera sección. */
.hero { position: relative; height: 500lvh; }
/* La caja pegajosa del texto del hero. Mismas dimensiones y misma esquina que
   `.filmbg`, porque `geometry()` coloca el titular contra las coordenadas de la
   película y da por hecho que ambos son 100lvh anclados arriba. */
.hero-pin {
  position: sticky; top: 0;
  height: 100lvh;
  overflow: hidden;
  pointer-events: none;
}
.hero-pin > * { pointer-events: auto; }
/* The plate seam.
   The film's own borders measure 5.8 / 6.2 / 3.0 of 255 on right / top / bottom
   over all 388 frames, and the page is at 3/3/4 — close, but a 2-3 level step
   across a straight edge is exactly what the eye is built to find, and it read
   as a rectangle sitting on the page. A short feather on those three sides
   removes it. Not a fade over a photograph — the vault is explicit about those
   — but a join between two blacks, in film coordinates, over content that never
   exceeds luminance 33 there. Asymmetric on purpose, and the picture is
   MIRRORED, so the side that gets the feather has swapped: the frame's black
   right edge now lands on the display's LEFT, against the plate, and that is
   the join to hide. The display's RIGHT is the hand — never feathered, because
   the viewport edge cuts it anyway and a fade over skin is a vignette. Two
   gradients need mask-composite, or they union and the corners stay opaque. */
/* The left ramp is a SMOOTHSTEP, not a linear one, and it is 190px not 150.
   A linear alpha ramp across the back of a lit hand still announces itself:
   measured across the join, the first 16px went 2 -> 26 of 255, which is a
   visible onset even though the ramp itself is correct. Weighting the stops so
   almost nothing happens in the first quarter puts the whole of that onset
   under the noise floor, and the light appears to run out instead of the
   picture appearing to start. The vertical ramps stay linear — they join black
   to black and have nothing to hide. */
#film {
  position: absolute;
  --fx: 190px;
  --fy: 110px;
  --lramp: linear-gradient(to right,
    transparent 0,
    rgba(0,0,0,.02) calc(var(--fx) * .16),
    rgba(0,0,0,.08) calc(var(--fx) * .32),
    rgba(0,0,0,.20) calc(var(--fx) * .48),
    rgba(0,0,0,.42) calc(var(--fx) * .64),
    rgba(0,0,0,.70) calc(var(--fx) * .80),
    rgba(0,0,0,.91) calc(var(--fx) * .92),
    #000 var(--fx));
  -webkit-mask-image: var(--lramp),
    linear-gradient(to bottom, transparent, #000 var(--fy), #000 calc(100% - var(--fy)), transparent);
  mask-image: var(--lramp),
    linear-gradient(to bottom, transparent, #000 var(--fy), #000 calc(100% - var(--fy)), transparent);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}
/* Band mode: the film is full-width, so the sides are the screen edges and
   only the horizontal join needs softening. The class is written by
   geometry(); see the note there on why this is no longer a media query. */
body.band #film { --fx: 0px; --fy: 46px; }

/* ⭐ EL TÍTULO Y EL RELEVO COMPARTEN CAJA, Y ESO ES EL EFECTO.
   No son dos bloques que casualmente se parecen: son la misma columna, el mismo
   borde izquierdo, la misma anchura y el mismo centrado vertical, y
   `placeCopy()` escribe `left` / `width` / `--copy-w` en LOS DOS con la misma
   medida contra la película. Si sólo se colocara uno, el relevo aparecería en el
   borde de la pantalla en vez de en el sitio que acaba de dejar el título — y
   entonces no es un relevo, es otra cosa que sale. */
.hero-copy, .hero-relay {
  position: absolute;
  top: 50%;
  /* `--rise` lo escribe `beat()` en píxeles: el titular SUBE y se va, no se
     apaga en el sitio. Va dentro del `calc` del centrado porque este bloque ya
     usaba el transform para centrarse — animarlo desde fuera lo descolocaba. */
  transform: translateY(calc(-50% - var(--rise, 0px)));
  will-change: transform, opacity;
  z-index: 2;
  /* The belt to the JS placement's braces. The plate is 32.5% of the screen and
     the type hangs off the same margin the nav does, so if a paint ever slips
     in ahead of the script what it paints is the layout, not the block sitting
     in the middle of the photograph. */
  left: var(--pad);
  width: min(30.5%, 1180px);
}
/* El relevo arranca APAGADO Y FUERA DEL ÁRBOL. `beat()` lo enciende, pero corre
   dentro del rAF de la película y el primer pintado puede llegar antes: sin
   esto, la página abre un cuarto de segundo con los dos bloques encima del
   mismo sitio. `visibility` además lo saca del recorrido de tabulación mientras
   no se ve — si no, hay dos enlaces invisibles sobre el hero. */
.hero-relay { opacity: 0; visibility: hidden; }
/* El titular del relevo es un h2 y hereda el tamaño de sección (52 px). Aquí
   tiene que pesar lo mismo que el título al que sustituye, no menos: es lo que
   ocupa el sitio que aquél deja. Mismo cuerpo que el h1 del hero. */
.hero-relay h2 {
  margin-bottom: 26px;
  font-variation-settings: 'wght' 570, 'wdth' 90;
  font-size: min(clamp(31px, 2.5vw, 47px), calc(var(--copy-w, 100vw) / 8.6));
  line-height: 1.06;
  letter-spacing: -.014em;
}
/* Sentence case, not caps. Thirty-seven characters of tracked uppercase is a
   band of shapes rather than words, and it is one of the tells. */
/* inline-block so the rule is as long as the line it belongs to. Stretched to
   the column it crossed the photograph at the height of the man's shoulder and
   read as a scratch on the print. */
.hero-spec::before {
  content: ''; position: absolute; z-index: -1; pointer-events: none;
  inset: -8px -20px -10px -18px;
  background: linear-gradient(to bottom, transparent, rgba(2, 3, 6, .72) 26%,
              rgba(2, 3, 6, .72) 74%, transparent);
}
.hero-spec {
  position: relative;
  display: inline-block;
  margin-top: 42px;
  padding-top: 22px;
  border-top: 1px solid var(--line);
  font-size: 14px;
  font-variation-settings: 'wght' 450, 'wdth' 88;
  letter-spacing: .04em;
  /* Ivory at 40% measures 3.4:1 against the film's dark third — fine over the
     page's own black, a WCAG failure over 47 luminance of studio. Anything
     sitting ON the film gets its own, brighter tone. */
  color: var(--ink-film);
}
/* 🔴 DOS ATENUACIONES SE MULTIPLICAN SOBRE EL MISMO CARÁCTER. El separador iba
   a opacidad .5 DENTRO de una línea ya puesta a `--ink-3` (.52): efectivo .26,
   o sea 2,0:1. Ninguna de las dos decisiones está mal por su cuenta y el
   producto de las dos es un fallo — por eso no se ve leyendo el CSS.
   El separador no necesita atenuación propia: ya es un punto medio. */
/* 🔴 UN PUNTO MEDIO NO ADMITE ATENUACION. Empezo en .5, subio a .68 y a .82
   persiguiendo la medida, y seguia fallando por un motivo que no es el color:
   un `·` a 14px son cuatro pixeles con borde suavizado, asi que medido PIXEL A
   PIXEL casi ninguno llega a cubrir del todo y el contraste real sale de 1,2:1
   por mucho que el valor declarado sea correcto. Una atenuacion encima de un
   glifo asi no se ve como "mas suave", se ve como "peor dibujado". El separador
   va a tinta plena y el aire lo da el `padding`. */
b { font-weight: inherit; opacity: 1; padding: 0 .45em; }
/* Sized against the COLUMN, not the viewport. 6.4vw at 1920 is 123px, at which
   "Meridian" is 529px of a 576px column — 92% of it — so the word ran to within
   113px of the glass and read as cramped no matter where the block sat. The
   divisor is the measured advance of the longest word at wght 480 / wdth 116
   (x4.30) plus 4% of slack. --copy-w is written by placeCopy(). */
/* ⛔ EL DIVISOR MEDIDO CAMBIA CON LA FAMILIA, Y HA CAMBIADO DOS VECES.
   Era 4,48 (avance de "Meridian" en Archivo a wght 480 / wdth 116), subio a
   5,05 con Bodoni — mas ancha por caracter — y ahora baja a 4,55 con Instrument
   Sans a wght 570 / wdth 90, que es sensiblemente mas estrecha que la didone.
   El numero no es un gusto: es el avance real de la palabra mas larga con un 4%
   de holgura, y si no se remide la palabra se sale de la placa y se mete en el
   hombro del hombre — que es justo el fallo que este divisor existe para evitar.
   Con el titular ya a 64 px de tope, ademas, el `clamp` manda casi siempre y
   este brazo del `min` solo actua en columnas estrechas. */
.hero-copy h1 {
  margin-bottom: 30px;
  font-variation-settings: 'wght' 570, 'wdth' 90;
  font-size: min(clamp(38px, 3.35vw, 64px), calc(var(--copy-w, 100vw) / 4.55));
  line-height: .94;
  letter-spacing: -.012em;
}
.hero-copy .lede, .hero-relay .lede {
  max-width: 46ch;
  color: var(--ink-2);
  font-size: clamp(16px, 1.05vw, 20px);
  line-height: 1.66;
}
.hero-cta { display: flex; align-items: center; gap: 30px; margin-top: 38px; flex-wrap: wrap; }

.btn {
  display: inline-block;
  padding: 15px 30px;
  background: var(--ink);
  color: var(--void);
  text-decoration: none;
  font-size: 12px;
  font-variation-settings: 'wght' 650, 'wdth' 84;
  letter-spacing: .12em;
  text-transform: uppercase;
  transition: transform .4s var(--e-out), background-color .4s var(--e-out);
}
.btn:hover { transform: translateY(-2px); background: #fff; }
/* The rule under this link is a pseudo-element scaled on the X axis, not a
   background-image sized from 100% to 34%. Two reasons, and both matter:
   background-size animates through PAINT every frame, where transform is
   composited; and a gradient painted on the element itself is an own surface to
   anything measuring contrast, so an ivory rule under ivory text reads as
   ivory-on-ivory at 1:1 and the checker is right about what it can see. */
.btn-quiet {
  position: relative;
  color: var(--ink);
  text-decoration: none;
  font-size: 12px;
  font-variation-settings: 'wght' 600, 'wdth' 84;
  letter-spacing: .12em;
  text-transform: uppercase;
  padding-bottom: 6px;
}
.btn-quiet::after {
  content: '';
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 1px;
  background: currentColor;
  transform-origin: left;
  transition: transform .5s var(--e-out);
}
.btn-quiet:hover::after { transform: scaleX(.34); }

/* Bottom LEFT, with the type, on the plate. Bottom right is the hand now. */
.hero-cue {
  position: absolute;
  left: var(--pad); bottom: 34px;
  display: flex; align-items: center; gap: 12px;
  margin: 0;
  font-size: 12px;
  font-variation-settings: 'wght' 600, 'wdth' 79;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink-film);
}
.hero-cue::before { content: ''; width: 34px; height: 1px; background: currentColor; }
/* It has been read the moment the page moves. Left up, it is still sitting in
   the corner telling you to scroll while you are three sections down, because
   the stage it lives in is sticky. */
.hero-cue { transition: opacity .5s var(--e-out); }
body.moved .hero-cue { opacity: 0; }

/* ── los tiempos del descenso ─────────────────────────────────────────────────
   Opacidad y NADA MAS. Ni translate, ni blur, ni scale: cualquiera de los tres
   obliga al compositor a rasterizar de nuevo un elemento que esta encima de un
   lienzo de 1920x1080 repintandose 60 veces por segundo, y eso se paga en el
   propio film. La opacidad es la unica propiedad que el compositor sirve gratis.
   La entrada la escribe el mismo rAF que mueve la pelicula (L4: un solo bucle),
   asi que el texto y el fotograma van clavados — con dos relojes derivan uno o
   dos fotogramas y se nota justo en el borde de la aparicion. */
.beats { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
.beat {
  position: absolute;
  margin: 0;
  opacity: 0;
  color: var(--ink);
  font-variation-settings: 'wght' 420, 'wdth' 96;
  text-wrap: balance;
}
.beat b, .beat br { font-weight: inherit; }
/* Arriba derecha. Una sola linea, grande: es un titulo, no un parrafo. */
.b1 {
  right: var(--pad); top: 17%;
  width: min(32%, 500px);
  font-size: clamp(26px, 2.5vw, 46px);
  line-height: 1.14;
  letter-spacing: -.01em;
}
/* Derecha. El parrafo, en el hueco donde la caja entera esta oscura. */
.b2 {
  right: var(--pad); top: 30%;
  width: min(34%, 540px);
  font-size: clamp(16px, 1.15vw, 21px);
  line-height: 1.62;
  color: var(--ink-2);
}
/* Abajo izquierda, y es el que entrega la seccion siguiente: por eso va al
   tamano del titular y no al del cuerpo. */
.b3 {
  left: var(--pad); bottom: 15%;
  width: min(36%, 620px);
  font-size: clamp(30px, 3.1vw, 60px);
  line-height: 1.08;
  letter-spacing: -.015em;
}
/* En banda el film ocupa una franja de 40% arriba y el texto vive debajo, en el
   vacio: no hay sitio para bloques flotando sobre la foto. */
body.band .beats { display: none; }

/* Phone: the film sits in a band up top and the copy lives underneath it, in
   the void, where nothing is in its way. A 16:9 whose subject owns 68% of the
   width cannot be full-bleed AND whole inside 393px — so it gets a composition
   rather than a crop. */
/* Igual en banda: eran 388 sobre 160lvh = 2,43 por lvh; 772 sobre 320 = 2,41. */
body.band .hero { height: 420lvh; }
body.band .hero-copy, body.band .hero-relay {
  top: auto; bottom: 5lvh;
  transform: translateY(calc(-1 * var(--rise, 0px)));
  left: var(--pad); right: var(--pad); width: auto;
}
body.band .hero-copy .lede, body.band .hero-relay .lede { max-width: none; font-size: 15.5px; }
body.band .hero-cue { display: none; }

/* ═══════════════════════════════════════════════════════════════════════════
   BELOW THE FILM — three material fields.

   The old page was one near-black surface from the hero to the footer, and a
   photograph, a headline and a price all sat on the same ground: nothing had a
   surface of its own, so nothing had any weight. The fix is not more contrast
   inside the black, it is FIELDS — regions that own a material and hand over to
   the next one at a hard edge.

     void   #020203   the film's own cyclorama. Hero, the frontal plate, the close.
     blue   #08152A   the DIAL, measured at #2B3E68 and run down to a page value.
                      Not an accent: it is 100% of the region it owns.
     paper  #D7DCE2   a cold document stock. Every macro on this page is a dark
                      photograph, and dark photographs on light stock is the only
                      arrangement in which they have contrast to give.

   Cold paper, not cream. Cream + high-contrast serif + terracotta is the look
   every generated page arrives wearing; this stock is pulled toward the blue it
   is standing next to, and the ink IS the blue, so the two fields are the same
   decision seen from either side.

   Type: one family, Archivo Variable, and its WIDTH axis carries the whole
   system. The hero is expanded (wdth 116). Everything below it is condensed
   (wdth 68-80) and much larger. "Meridian" at 100px measures 272px at wdth 62
   and 479px at wdth 125 — a 76% span, which is more range than most pairings
   buy with a second webfont.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  --blue-deep: #08152A;
  --blue-lift: #0E2140;   /* the plate bed, one step up from the field */
  --paper:     #D7DCE2;
  --paper-2:   #C7CDD6;
  --doc:      #0B1526;   /* ink — the dial blue at full strength */
  --doc-2:    rgba(11, 21, 38, .66);
  --doc-3:    rgba(11, 21, 38, .44);
  --rule-ink:  rgba(11, 21, 38, .17);
  /* Gold, sampled off the Aurum case. Two of six executions are gold, so it is
     the product's second colour and not a decorator's accent. Hairlines,
     figures and one button — never a fill. */
  --gold:      #C6A15E;
  --gold-lit:  #E0C084;
  /* 🔴 ESTOS DOS SE OSCURECIERON PARA UN PAPEL CLARO QUE YA NO EXISTE.
     `#6E5219` medía 5,2:1 contra el papel de #D7DCE2. Cuando el documento se dio
     la vuelta a oscuro, la misma variable pasó a ser oro OSCURO SOBRE OSCURO y
     los pies de placa cayeron a 2,7:1 — y siguieron ahí tres rondas, porque una
     variable con un nombre correcto y un comentario correcto no se vuelve a
     mirar. El campo cambió de signo; la tinta no. */
  --gold-ink:  #E0C084;
  --gold-bar:  #C6A15E;
}

/* ── the seam ────────────────────────────────────────────────────────────────
   The section under a sticky hero has to open ON the plate, or there is a step
   where one black meets the other. It now hands over to the BLUE, so the film
   dissolves into the field instead of into a second black. */
.seam { position: relative; }
/* La entrega ya no es de la película a un campo opaco: la película SIGUE ahí
   debajo. Lo único que hace falta es que el velo de la sección no empiece de
   golpe, así que entra desde transparente sobre los últimos 200px. */
.seam::before {
  content: ''; position: absolute; inset: -200px 0 auto; height: 200px;
  background: linear-gradient(180deg, transparent, rgba(4, 9, 20, .70));
  pointer-events: none;
}

/* ── respiros ────────────────────────────────────────────────────────────────
   El único elemento de la página cuyo trabajo es NO tener contenido: un tramo
   de scroll donde la película se queda sola. Sin él, "el film está detrás de
   todo" es cierto y a la vez invisible — medido en la maqueta de móvil, del
   fotograma ~130 en adelante no había un solo píxel de película sin una sección
   encima.

   90lvh y no 100: un respiro que mide justo la pantalla se lee como una página
   en blanco y da la sensación de que la web se ha acabado. Dejando asomar el
   borde de lo que viene, el hueco se lee como una pausa.

   ⛔ NO lleva `content-visibility: auto`. Está vacío, así que la tentación es
   pedirle al navegador que se lo salte — pero es justo el tramo donde el lienzo
   FIJO tiene que seguir pintando, y saltárselo cambia el alto del documento en
   caliente, que es de donde sale el mapeo scroll → fotograma. */
.breath { height: 90lvh; pointer-events: none; }
/* En banda el recorrido de scroll ya es mucho más largo por el ancho, y cuatro
   respiros de pantalla completa alargan la página más de lo que aporta. */
body.band .breath { height: 76lvh; }

/* ── fields ──────────────────────────────────────────────────────────────────
   ⭐ LOS CAMPOS DEJAN DE SER MATERIA OPACA Y PASAN A SER VELOS.

   Antes cada sección traía su propio suelo (azul del dial, papel del
   certificado, negro) y tapaba lo que hubiera detrás — que es justo lo que Alex
   no quiere: quiere ver la película debajo del contenido de arriba abajo.

   ⛔ Y NO SE PUEDE QUITAR EL SUELO SIN MÁS. La película tiene lado claro: el
   perfil del hombre y la mano miden hasta 237 de 255. Texto ivory sobre eso es
   ilegible, y la regla de contraste no se negocia porque el fondo sea bonito.
   Así que cada campo se queda EXACTAMENTE donde estaba, pero como cristal: el
   tono es el mismo, la opacidad es la que compra el contraste, y el desenfoque
   se lleva el detalle de la imagen sin llevarse el movimiento — sigues viendo
   la película viva detrás del texto.

   El velo va en ::after con inset:0 y z-index:0, y el contenido de la sección
   sube a z-index:1 (regla de abajo). Poner el velo como `background` no sirve:
   backdrop-filter necesita un elemento propio al que quedar por detrás. */
[data-field] { position: relative; isolation: isolate; }
[data-field]::after {
  content: ''; position: absolute; inset: 0; z-index: 0;
  pointer-events: none;
}
[data-field] > * { position: relative; z-index: 1; }

/* ⭐ EL CRISTAL ES DEL TONO DEL FONDO Y LA SOMBRA SIGUE AL TEXTO.
   ══════════════════════════════════════════════════════════════════════════
   Alex, 29-jul: "todo cristalino, pero no el azul cristalino que has puesto,
   porque entonces no se ve el fondo, tiene que ser igual que el fondo, como si
   hubiese un cristal encima".

   Lo que había: `rgba(8,21,42,.82)` y `rgba(6,10,18,.84)` a sangre. 82-84% de
   opacidad NO es cristal, es una placa — y el azul además metía un tono que no
   está en la película, así que encima de tapar cambiaba de material. Medido: en
   el descenso el velo cubría el 52% del viewport de media y 28 de 80 posiciones
   de scroll estaban tapadas al 100%.

   ⛔ Y NO SE ARREGLA BAJANDO LA OPACIDAD A SECAS. La película tiene lado claro:
      la mano y la cara llegan a 237 de 255. Para que el ivory (244) mida 4,5:1
      el fondo tiene que quedar por debajo de 107 ⇒ hace falta un 55% de negro
      justo DETRÁS DE LA TIPOGRAFÍA. A sangre, ese 55% es otra vez una placa.

   ⇒ Se parte en dos capas con trabajos distintos:

     · EL CRISTAL (este ::after) — al 30%, del negro de la propia película, con
       desenfoque que se lleva el detalle pero no el movimiento. Unifica el
       campo y deja ver la bobina entera. No compra contraste y no lo pretende.
     · LA SOMBRA (.scrim, más abajo) — una poza oscura, con bordes difuminados,
       pegada a cada bloque de texto. Es la que compra el contraste, y sólo
       donde hay letras.

   Y los bordes del campo se difuminan con `mask-image`: el corte recto de antes
   cruzaba la mano del hombre con una línea horizontal perfecta, que es la señal
   más clara de que hay una caja encima de una foto. */
[data-field="blue"]::after,
[data-field="paper"]::after {
  background: rgba(3, 5, 9, .30);
  backdrop-filter: blur(14px) saturate(104%);
  -webkit-backdrop-filter: blur(14px) saturate(104%);
  /* sin esto vuelve el borde recto */
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 90px,
                      #000 calc(100% - 90px), transparent);
          mask-image: linear-gradient(to bottom, transparent, #000 90px,
                      #000 calc(100% - 90px), transparent);
}
/* El azul del dial se queda, pero como INSINUACIÓN — un lavado que tiñe el
   cristal sin volverlo opaco. Sigue siendo el color del producto a escala de
   página; ya no es una pared. */
[data-field="blue"]::after {
  background-image:
    radial-gradient(140% 100% at 10% 0%, rgba(43, 62, 104, .16), transparent 66%);
}
[data-field="blue"] { --ink-3: rgba(244, 241, 236, .60); }

/* El documento se queda tirado en oscuro (un papel claro sobre una película
   negra sólo puede ser un rectángulo blanco encima de una foto). Las variables
   de tinta se invierten y las docenas de reglas que las usan no se tocan. */
[data-field="paper"] {
  --paper:   rgba(6, 10, 18, .42);
  --paper-2: rgba(10, 16, 26, .42);
  --doc:     var(--ink);
  --doc-2:   rgba(244, 241, 236, .72);
  --doc-3:   rgba(244, 241, 236, .58);
  color: var(--doc);
}

/* El vacío no pone cristal: es donde la película se ve tal cual. */
[data-field="void"]::after { background: none; backdrop-filter: none; }

/* ── la sombra que sigue al texto ────────────────────────────────────────────
   Radial y muy abierta, para que no tenga un borde que se pueda ver. El 62% del
   centro es lo que baja 237 a 90 — con margen sobre los 107 que pide el 4,5:1 —
   y a mitad de radio ya está en 24%, así que la película vuelve enseguida.

   Va en un ::before del propio bloque de texto y NO en un elemento aparte: así
   se estira solo con el contenido y no hay una segunda caja que mantener
   cuadrada con la primera. */
/* ⛔ `content` Y `position` VAN EN EL SELECTOR COMPARTIDO. Estuvieron sólo en
   `.scrim::before`, y como `.scrim-wide` es una clase aparte (no lleva `scrim`
   encima), su pseudo-elemento nunca llegó a existir: `content` daba `none` y la
   poza no pintaba. Se veía preciosa la página y el contraste se caía a 2,1:1 en
   los bloques anchos — un fallo que NO se ve mirando, sólo midiendo. */
.scrim, .scrim-wide { position: relative; }
.scrim::before, .scrim-wide::before {
  content: ''; position: absolute; z-index: -1; pointer-events: none;
}
.scrim::before {
  inset: -14% -10%;
  background: radial-gradient(58% 62% at 34% 50%,
              rgba(2, 3, 6, .80) 0%, rgba(2, 3, 6, .66) 38%,
              rgba(2, 3, 6, .26) 68%, transparent 100%);
}
/* Un bloque ancho de tabla o de rejilla necesita la poza a lo largo, no
   centrada: si no, las columnas de los extremos se quedan fuera. Los píxeles
   los pone el borde difuminado, no el centro: el núcleo va plano y sólo se
   desvanecen los extremos, porque un degradado que empieza transparente arriba
   deja la PRIMERA FILA de la tabla sin nada debajo — que es justo donde el ojo
   entra. */
.scrim-wide::before {
  inset: -22px -3%;
  background:
    linear-gradient(to bottom, transparent, rgba(2, 3, 6, .82) 7%,
                    rgba(2, 3, 6, .82) 93%, transparent),
    radial-gradient(80% 90% at 50% 50%, rgba(2, 3, 6, .34), transparent 100%);
}
/* La cabecera reglada vive suelta en el `.wrap`, sin bloque propio al que
   colgarse, y es texto de 11px: se lleva su propia tira. */
.runhead { position: relative; z-index: 0; }
.runhead::after {
  content: ''; position: absolute; z-index: -1; pointer-events: none;
  /* ⛔ EL DESVANECIDO LATERAL TIENE QUE ACABAR ANTES DE DONDE EMPIEZA EL TEXTO.
     Al ponerlo por primera vez la tira iba a -5% y el degradado se apagaba en el
     7%: la cabecera reparte sus tres textos a la IZQUIERDA, al centro y a la
     DERECHA, o sea justo en las dos zonas que acababa de dejar sin sombra, y
     "Bulletin de marche" y "No. 0001/0300" cayeron a 4,0:1. Arreglar el canto
     visible y romper el contraste, en el mismo gesto.
     Ahora la tira sobresale un 14% por lado y el desvanecido termina en el 8%,
     o sea 3 puntos antes del borde del texto. */
  inset: -18px -14%;
  background: linear-gradient(to bottom, transparent, rgba(2, 3, 6, .86) 24%,
              rgba(2, 3, 6, .86) 76%, transparent);
  -webkit-mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
}

/* La junta entre campos: sobre cristal una línea negra no se ve; la que se ve
   es una de luz — y ahora se desvanece por los lados en vez de cruzar la
   pantalla de lado a lado. */
[data-field="paper"] + [data-field], [data-field="void"] + [data-field="paper"] {
  border-top: 0;
}
[data-field="paper"] + [data-field]::before,
[data-field="void"] + [data-field="paper"]::before {
  content: ''; position: absolute; z-index: 0; pointer-events: none;
  top: 0; left: 8%; right: 8%; height: 1px;
  background: linear-gradient(to right, transparent,
              rgba(244, 241, 236, .16) 22%, rgba(244, 241, 236, .16) 78%, transparent);
}

/* ── rhythm ──────────────────────────────────────────────────────────────────
   padding-TOP only, plus a bottom on a field so its ground does not stop on the
   last line of type. */
.six, .frontal, .bulletin, .reserve {
  position: relative;
  padding-top: clamp(88px, 10vh, 168px);
}
.six    { padding-bottom: clamp(88px, 10vh, 160px); }
.bulletin { padding-bottom: clamp(96px, 11vh, 190px); }
.reserve { padding-bottom: clamp(80px, 9vh, 140px); }

/* ── the running head ────────────────────────────────────────────────────────
   NOT an eyebrow. An eyebrow is one tracked label floating above a headline,
   repeated per section because the template has a slot for it. This is the
   running head of a document: it spans the full measure, it is ruled top and
   bottom, and it carries three real fields — what this sheet is, how much of it
   there is, and the reference. It is the same object on every field, which is
   what makes it a system rather than decoration. */
.runhead {
  display: flex; align-items: baseline; gap: 26px;
  margin: 0 0 clamp(40px, 5vh, 78px);
  padding: 12px 0;
  border-top: 1px solid currentColor;
  border-bottom: 1px solid currentColor;
  font-size: 12px;
  font-variation-settings: 'wght' 650, 'wdth' 75;
  letter-spacing: .12em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
}
[data-field="paper"] .runhead { color: var(--doc-2); }
.runhead { justify-content: space-between; }
.runhead span:last-child { text-align: right; }
@media (max-width: 700px) {
  .runhead span:nth-child(2) { display: none; }
  .runhead { gap: 14px; font-size: 10px; }
}

/* ── the condensed statement ─────────────────────────────────────────────────
   The hero is expanded and sentence case; every heading below it is the same
   face at wdth 74, far larger, and set in three or four short lines so the
   block has a silhouette. This is the second half of the type system, not a
   different font — and it is why nothing down here reads like the hero repeated
   at 60%. */
/* ⛔ EL INTERLINEADO NO SE HEREDA DE UNA ESCALA QUE YA NO EXISTE. Fue .86 con
   la grotesca condensada a 140 px, y .96 con la didone a 116. A 52 px un
   interlineado por debajo de 1 aprieta un titular que ya no es un cartel: los
   saltos de linea de estos titulares estan escritos A MANO en el HTML, asi que
   el bloque son tres o cuatro lineas cortas y a .96 se leen como un logotipo en
   vez de como una frase. 1,04 las separa lo justo. */
.stmt {
  margin: 0;
  font-variation-settings: 'wght' 570, 'wdth' 90;
  font-size: clamp(29px, 2.6vw, 52px);
  line-height: 1.04;
  letter-spacing: -.012em;
  text-wrap: balance;
}
[data-field="paper"] .stmt { color: var(--doc); }
.stmt-note {
  max-width: 44ch;
  color: var(--ink-2);
  font-size: clamp(15px, .98vw, 18.5px);
  line-height: 1.6;
}
[data-field="paper"] .stmt-note { color: var(--doc-2); }

.six-head, .cert-head {
  display: grid; gap: 30px; align-items: end;
  margin-bottom: clamp(48px, 6vh, 96px);
}
@media (min-width: 1080px) {
  .six-head, .cert-head { grid-template-columns: minmax(0, 1fr) minmax(0, .72fr); gap: clamp(40px, 3.6vw, 88px); }
}

/* ── the gold action ─────────────────────────────────────────────────────────
   A hairline box, not a filled pill. The fill is the ivory button in the hero
   and there is exactly one of those on the page; down here the action is drawn
   in the same 1px the running heads and the index are drawn in, and the hover
   fills it from the baseline up — the one place the gold becomes a ground. */
/* ⛔ `background: transparent` NO SOBRA. Este botón nació sólo sobre `<a>`, que
   no tiene fondo propio, así que la regla nunca lo declaró. Al usarlo en el
   `<button>` del formulario apareció relleno de blanco: la hoja del navegador
   le da `background-color: buttonface` a todo `<button>`, y encima con el texto
   en oro claro — 1,3:1. La caja de oro llevaba tres rondas siendo correcta y se
   rompió al cambiar de ETIQUETA, no de estilo. */
.btn-gold {
  position: relative;
  display: inline-block;
  padding: 16px 34px;
  background: transparent;
  border: 1px solid var(--gold);
  color: var(--gold-lit);
  text-decoration: none;
  font-size: 12px;
  font-variation-settings: 'wght' 650, 'wdth' 79;
  letter-spacing: .12em;
  text-transform: uppercase;
  overflow: hidden;
  isolation: isolate;
  transition: color .42s var(--e-out);
}
.btn-gold::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  /* ⛔ EN REPOSO NO HAY SUELO DE ORO. Estaba `background: var(--gold)` con
     `scaleY(0)`: invisible para el ojo, pero el estado declarado es "texto oro
     claro sobre fondo oro" = 1,4:1, y asi lo lee cualquier analisis y asi lo
     heredaria cualquiera que toque el transform mas adelante. El color entra
     con el hover; el gesto lo sigue haciendo el transform, que es lo barato. */
  background: transparent;
  transform: scaleY(0); transform-origin: bottom;
  transition: transform .42s var(--e-out);
}
.btn-gold:hover { color: var(--blue-deep); }
.btn-gold:hover::before { transform: scaleY(1); background: var(--gold); }
[data-field="paper"] .btn-gold:hover { color: var(--paper); }
.btn-gold.big { padding: 20px 44px; font-size: 12.5px; }

/* ═══════════════════════════════════════════════════════════════════════════
   THE SIX
   ═══════════════════════════════════════════════════════════════════════════ */
.plate-stage {
  display: grid;
  gap: clamp(34px, 3.4vw, 84px);
  align-items: start;
  margin-bottom: clamp(56px, 7vh, 110px);
}
@media (min-width: 1000px) {
  .plate-stage { grid-template-columns: minmax(0, 1.12fr) minmax(0, 1fr); align-items: center; }
}

/* The window is the RIGHT 55.8% of the 16:9 studio plate — measured, that is
   where the ring and the watch are, and everything above luminance 170 sits
   inside it. Cropped here from the clean 16:9 master rather than taken from the
   ready-made unit-*.webp squares, whose ring edge has an aliased staircase
   baked into every size. 5504/3073 = 1.7914 puts the window on the right edge. */
.plate { margin: 0; }
.plate-win {
  position: relative;
  width: 100%;
  max-width: min(720px, 62vh);
  aspect-ratio: 3073 / 3072;
  overflow: hidden;
}
/* SCREEN, not a black box on a blue field.

   These six plates are lit objects photographed against a studio black that
   measures 2-4 of 255 — which is to say the file is almost entirely the ring
   of light and the watch, and everything else in it is nothing. Dropped onto
   the blue as an opaque rectangle it reads as a HOLE punched in the field, and
   no amount of framing fixes that; the eye is being shown two grounds where
   there is one subject. Screen composites the plate additively, so the studio
   black contributes zero and the ring, the case and the bracelet stand on the
   blue directly. It is the same arithmetic the photograph was made with, and
   it only works because the black really is black — measured, not assumed. */
.plate-win img {
  position: absolute; top: 0; right: 0;
  width: calc(100% * 5504 / 3073);
  max-width: none;   /* the global img{max-width:100%} clamps the DRAWN width
                        back to the window and the crop stops being a crop */
  height: auto;
  mix-blend-mode: screen;
  /* The studio black is 2-4 of 255, not 0, and under screen those two or three
     levels add up over the whole frame into a faintly lighter RECTANGLE sitting
     on the field — the box we were trying to get rid of, back at 1% strength
     and just as visible as an edge. contrast() maps everything under ~6/255 to
     zero, so the plate has no corners any more; the cost is 8% on a photograph
     that was lit for exactly this. */
  filter: contrast(1.09);
  opacity: 0;
  transition: opacity .55s var(--e-io);
}
.plate-win img.on { opacity: 1; }
.plate-cap {
  display: flex; justify-content: space-between; gap: 20px;
  max-width: min(720px, 62vh);
  margin-top: 14px;
  padding-top: 11px;
  border-top: 1px solid var(--line);
  font-size: 12px;
  font-variation-settings: 'wght' 620, 'wdth' 77;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.tab { font-variant-numeric: tabular-nums; }

/* La poza radial estaba centrada al 34% y las `dd` van alineadas a la DERECHA:
   "Horizon blue, embossed lacquer" se salía del charco y medía 3,6:1. Aquí la
   poza tiene que cubrir el ancho entero de la ficha. */
.plate-data { max-width: 780px; }
/* ⛔ LAS CABECERAS SON DE DOS COLUMNAS Y LA POZA ERA RADIAL Y CENTRADA AL 34%.
   El titular va a la izquierda y su nota al lado derecho, o sea justo fuera del
   charco: "Every case is machined…" medía 3,85:1 y "Everything a lathe…" 3,24:1
   mientras el titular de al lado iba sobrado. Una poza tiene que saber la forma
   del bloque al que sirve. */
.six-head.scrim::before, .anat-head.scrim::before, .cert-head.scrim::before {
  inset: -9% -8%;
  background:
    linear-gradient(to bottom, transparent, rgba(2, 3, 6, .76) 11%,
                    rgba(2, 3, 6, .76) 89%, transparent),
    radial-gradient(86% 80% at 50% 50%, rgba(2, 3, 6, .32), transparent 100%);
}
.plate-data.scrim::before {
  inset: -8% -12%;
  background:
    linear-gradient(to bottom, transparent, rgba(2, 3, 6, .80) 9%,
                    rgba(2, 3, 6, .80) 91%, transparent),
    radial-gradient(84% 74% at 50% 50%, rgba(2, 3, 6, .38), transparent 100%);
}
.pname {
  margin: 0;
  font-variation-settings: 'wght' 570, 'wdth' 90;
  font-size: clamp(25px, 1.95vw, 38px);
  line-height: 1.1;
  letter-spacing: -.008em;
}
.pmetal {
  margin-top: 12px;
  color: var(--ink-2);
  font-size: clamp(15px, .98vw, 18px);
}
/* Four ruled rows, term left and value right, the same object the certificate
   ends with. Repeating one table shape across two fields is what makes them one
   document instead of two pages. */
.prow { margin: clamp(26px, 3vh, 40px) 0 0; }
.prow > div {
  display: flex; align-items: baseline; justify-content: space-between; gap: 24px;
  padding: 13px 0;
  border-top: 1px solid var(--line);
}
.prow > div:last-child { border-bottom: 1px solid var(--line); }
.prow dt {
  flex: 0 0 auto;
  font-size: 12px;
  font-variation-settings: 'wght' 620, 'wdth' 77;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.prow dd {
  margin: 0; text-align: right;
  font-size: clamp(14.5px, .92vw, 17px);
  font-variation-settings: 'wght' 420, 'wdth' 94;
}
.pprice {
  margin: clamp(24px, 3vh, 38px) 0 clamp(22px, 2.6vh, 34px);
  font-size: clamp(23px, 1.6vw, 32px);
  font-variation-settings: 'wght' 450, 'wdth' 90;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.015em;
  line-height: 1;
  color: var(--gold-lit);
}

/* ── the executions ──────────────────────────────────────────────────────────
   🔴 AQUÍ HABÍA UNA HOJA DE CÁLCULO. Seis filas regladas con una miniatura de
   62 px, en una página de un reloj de 26.400 $. El argumento escrito era que un
   índice reglado deja comparar las seis de un vistazo y que las tarjetas obligan
   a comparar cruzando medianiles — y es cierto, pero contestaba a la pregunta
   equivocada: en un escaparate de lujo lo que hay que poder hacer con el
   producto no es COMPARARLO, es MIRARLO. A 62 px no se mira nada.

   Alex, 29-jul: "el catálogo de productos tiene que ser estilo de la web del
   perfume, o incluso mucho más moderno; esto así no".

   Así que el producto se pone grande y se puede tocar, y los datos que hacían
   valiosa la tabla — referencia, metal, engaste, precio — se quedan TODOS, pero
   dentro de cada pieza en vez de en una columna. Se sigue comparando, y ahora
   además se ve.

   El gesto es el de la web del perfume, mejorado en dos cosas:
     · el reloj SE SALE de su marco al pasar por encima y los hermanos se
       retiran, que es lo que hace que la pieza mirada sea la única que existe;
     · pero sin el flotar en bucle que trae el perfume. Una animación infinita
       pidiendo atención envejece mal y es justo lo que delata una plantilla:
       aquí el reloj se levanta, se asienta y se queda quieto. */
.execs {
  margin: 0; padding: 0; list-style: none;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(18px, 2.2vw, 40px) clamp(14px, 1.8vw, 32px);
}
.execs > li { display: flex; }
.exec {
  position: relative;
  display: flex; flex-direction: column;
  width: 100%;
  padding: 0 0 18px;
  border: 0; background: none; color: inherit; cursor: pointer;
  font: inherit; text-align: left;
  transition: opacity .5s var(--e-out);
}
/* El marco. `overflow: visible` a propósito: es lo que deja que el reloj salga
   por arriba. El recorte lo hace el degradado del fondo, no la caja. */
.exec-win {
  position: relative;
  aspect-ratio: 1 / 1.04;
  display: flex; align-items: center; justify-content: center;
  overflow: visible;
  border: 1px solid rgba(244, 241, 236, .10);
  /* ⛔ EL MARCO NECESITA SUELO OPACO, no puede ser cristal como el resto de la
     página. La lámina va en `mix-blend-mode: screen`, y `screen` SUMA: sobre el
     tramo claro de la película (la mano llega a 237 de 255) el reloj se quema y
     desaparece. Aquí el fondo es producto, no ambiente. */
  /* ⛔ AQUI HABIA UN FOCO RADIAL AZUL y sobraba por dos motivos: el detector lo
     marca como `radial-spotlight-glow`, que es el resplandor de plantilla de
     cualquier tarjeta de producto generada; y sobre todo era REDUNDANTE, porque
     la fotografia ya trae su propio anillo de luz. Dos focos discutiendo. Queda
     el suelo plano: una vitrina, no un escaparate iluminado por CSS. */
  background: linear-gradient(rgba(4, 7, 14, .90), rgba(4, 7, 14, .90));
  transition: border-color .5s var(--e-out), background .5s var(--e-out);
}
/* El charco de luz bajo el reloj: le da suelo para que el levantarse signifique
   algo. Sin él, la pieza flota en el vacío y el gesto no se lee. */
.exec-win::after {
  content: ''; position: absolute; left: 16%; right: 16%; bottom: 5%;
  height: 8%; pointer-events: none;
  background: radial-gradient(50% 100% at 50% 100%, rgba(198, 161, 94, .26), transparent 72%);
  filter: blur(11px);
  opacity: 0; transition: opacity .5s var(--e-out);
}
/* ⛔ SIN `screen`, LA LÁMINA ES UNA CAJA DENTRO DE OTRA CAJA. La foto es de
   estudio sobre negro, así que al ponerla dentro del marco se ve su propio
   rectángulo recortado contra el campo — dos bordes concéntricos, que es
   exactamente el aspecto de plantilla que se quería evitar.

   Con `screen` el negro del estudio desaparece en el campo y lo que queda
   flotando es el reloj con su anillo de luz. Pero el negro de estudio mide 2-4
   de 255 y NO cero, y bajo `screen` esos niveles suman un rectángulo levemente
   más claro: la caja vuelve, al 1%. `contrast(1.09)` los baja a cero y la remata.

   Y por eso aquí no hay `drop-shadow`: bajo `screen` una sombra oscura no suma
   nada, es literalmente invisible. El relieve lo da el charco de luz del suelo
   (`.exec-win::after`), que sí es claro y sí suma. */
.exec-shot {
  position: relative; z-index: 1;
  width: 100%; height: auto;
  transform-origin: 50% 78%;
  mix-blend-mode: screen;
  filter: contrast(1.09);
  transition: transform .58s var(--e-out), filter .58s var(--e-out);
}
/* Debajo del marco opaco no hay nada: la ficha se apoya en la pelicula cruda y
   ahi el metal y el engaste median 1,7:1. Su propia poza, ceñida al bloque. */
.exec-info::before {
  content: ''; position: absolute; z-index: -1; pointer-events: none;
  inset: -10px -12px -14px -12px;
  background: linear-gradient(to bottom, transparent, rgba(2, 3, 6, .80) 18%,
              rgba(2, 3, 6, .80) 84%, transparent);
}
.exec-info {
  position: relative;
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  gap: 4px 14px;
  margin-top: 18px;
  padding-top: 13px;
  border-top: 1px solid var(--line);
}
.exec-name {
  font-variation-settings: 'wght' 570, 'wdth' 90;
  font-size: clamp(17px, 1.12vw, 22px);
  letter-spacing: -.004em;
  line-height: 1.16;
}
.exec-price {
  font-size: clamp(15px, 1.05vw, 19px);
  font-variation-settings: 'wght' 430, 'wdth' 88;
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.exec-metal, .exec-set {
  grid-column: 1 / -1;
  font-size: 13.5px;
  color: var(--ink-2);
  font-variation-settings: 'wght' 400, 'wdth' 94;
  line-height: 1.4;
}
.exec-set { color: var(--ink-3); }
.exec-ref {
  position: absolute; top: 13px; left: 14px; z-index: 2;
  font-size: 12px;
  font-variation-settings: 'wght' 570, 'wdth' 79;
  font-variant-numeric: tabular-nums;
  letter-spacing: .12em;
  color: var(--ink-3);
  transition: color .4s var(--e-out);
}

/* Seleccionada: la regla de oro y la referencia en oro. Nada de tilde ni de
   pastilla — la pieza elegida es la que manda arriba, y con eso basta. */
.exec[aria-selected="true"] .exec-win { border-color: rgba(198, 161, 94, .46); }
.exec[aria-selected="true"] .exec-info { border-top-color: var(--gold); }
.exec[aria-selected="true"] .exec-ref { color: var(--gold-lit); }
.exec[aria-selected="true"] .exec-price { color: var(--gold-lit); }
.exec[aria-selected="true"] .exec-win::after { opacity: .7; }

/* Sólo donde hay puntero fino: en táctil no existe el estado intermedio y
   dejarlo puesto deja la tarjeta atascada en «hover» después de tocarla. */
@media (hover: hover) and (pointer: fine) {
  /* La lámina se sale de su marco, así que la pieza mirada tiene que pintarse
     por encima de sus vecinas o la de la derecha le corta el trozo que sobresale. */
  .exec:hover { z-index: 3; }
  .execs:has(.exec:hover) .exec:not(:hover) { opacity: .42; }
  .exec:hover .exec-win { border-color: rgba(198, 161, 94, .40); }
  .exec:hover .exec-win::after { opacity: 1; }
  .exec:hover .exec-shot {
    transform: translateY(-7%) scale(1.17);
    filter: contrast(1.12) brightness(1.06);
  }
}
.exec:active .exec-shot { transform: translateY(-3%) scale(1.06); }
.exec:focus-visible { outline: 2px solid var(--blue-lit); outline-offset: 4px; }

.execs-foot {
  margin-top: 26px;
  /* 191 caracteres por linea medidos: el pie cruzaba los 1512 px del wrap
     entero. El ojo pierde el renglon mucho antes de eso. */
  max-width: 72ch;
  font-size: 12.5px;
  color: var(--ink-3);
  font-variation-settings: 'wght' 400, 'wdth' 92;
}

@media (max-width: 1080px) { .execs { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px)  { .execs { grid-template-columns: 1fr; max-width: 24rem; margin-inline: auto; } }
@media (prefers-reduced-motion: reduce) {
  .exec-shot, .exec-win, .exec-win::after, .exec { transition: none; }
  .exec:hover .exec-shot { transform: none; }
}

/* ── the measure ─────────────────────────────────────────────────────────── */
.mrow {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 24px;
  margin: clamp(58px, 7vh, 110px) 0 0;
  padding: 30px 0 0;
  list-style: none;
  border-top: 1px solid var(--line);
}
.mrow li { display: flex; flex-direction: column; gap: 8px; }
.mrow .n {
  font-size: clamp(25px, 1.95vw, 40px);
  font-variation-settings: 'wght' 430, 'wdth' 86;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.022em;
  line-height: 1;
}
.mrow .n i {
  font-style: normal;
  /* An em-relative unit here lands the small caps at 10.98px at some viewport
     widths. Functional text under 11px is a legibility failure, not a style —
     so the unit is absolute and the floor is explicit. */
  font-size: clamp(11.5px, .3em, 18px);
  font-variation-settings: 'wght' 570, 'wdth' 77;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--gold);
  margin-left: .38em;
}
.mrow .l {
  font-size: 12px;
  font-variation-settings: 'wght' 620, 'wdth' 75;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
@media (max-width: 760px) {
  .mrow { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 28px 20px; }
  .mrow li:last-child { grid-column: 1 / -1; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   THE HAND — UNA LÁMINA ANOTADA

   Ver el comentario largo del HTML para el porqué. Aquí sólo la mecánica, que
   se apoya en una única decisión: EL ESCENARIO TIENE LA RAZÓN DE ASPECTO EXACTA
   DEL FICHERO (1920/1072). Con eso, un `left: 66.2%` del escenario y el 66,2%
   de la fotografía son el MISMO punto en cualquier anchura de pantalla, y los
   marcadores no necesitan que nadie recalcule nada al redimensionar.

   Si el escenario recortara la imagen (`object-fit: cover`) esa igualdad se
   rompería y los marcadores se irían del reloj — que es exactamente el fallo
   que tienen las anotaciones sobre foto cuando se ponen a ojo.
   ═══════════════════════════════════════════════════════════════════════════ */
.anat { padding-top: clamp(88px, 10vh, 168px); padding-bottom: clamp(70px, 8vh, 130px); }
.anat-head {
  display: grid; gap: 30px; align-items: end;
  margin-bottom: clamp(40px, 5vh, 74px);
}
@media (min-width: 1080px) {
  .anat-head { grid-template-columns: minmax(0, 1fr) minmax(0, .82fr); gap: clamp(40px, 3.6vw, 88px); }
}

.anat-stage {
  position: relative;
  width: 100vw; margin: 0 0 0 calc(50% - 50vw);
  aspect-ratio: 1920 / 1072;
  overflow: hidden;
  /* La lámina es OPACA: la película no pasa por detrás. Es el mismo corte duro
     que ya hacía `.frontal`, y es lo que le devuelve el contraste a unas fotos
     que antes flotaban sobre la mano iluminada del film. */
  background: #010102;
  isolation: isolate;
}
.anat-plate {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: fill;     /* el escenario YA tiene la razón del fichero: no recorta */
  z-index: 0;
}
/* El canto de arriba y el de abajo se difuminan contra el negro de la página.
   Un rectángulo fotográfico con dos bordes rectos cruzando la pantalla es la
   caja que se quería quitar; así la lámina emerge del campo. */
.anat-stage::after {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(180deg, var(--void), transparent 13%,
              transparent 87%, var(--void));
}

/* ── los marcadores ──────────────────────────────────────────────────────────
   Un anillo con su número dentro. En reposo son cuatro puntos discretos sobre
   la fotografía; el que se señala se levanta y se vuelve de oro. */
.anat-pins { position: absolute; inset: 0; z-index: 3; pointer-events: none; }
.anat-pin {
  position: absolute;
  left: var(--x); top: var(--y);
  display: grid; place-items: center;
  width: 30px; height: 30px;
  margin: -15px 0 0 -15px;
  border: 1px solid rgba(244, 241, 236, .62);
  border-radius: 50%;
  background: rgba(2, 3, 6, .42);
  -webkit-backdrop-filter: blur(2px);
          backdrop-filter: blur(2px);
  transition: transform .42s var(--e-out), border-color .42s var(--e-out),
              background-color .42s var(--e-out);
}
.anat-pin i {
  font-style: normal;
  font-size: 10px;
  font-variation-settings: 'wght' 650, 'wdth' 82;
  font-variant-numeric: tabular-nums;
  letter-spacing: .06em;
  color: var(--ink);
}
.anat-stage.lit .anat-pin { border-color: rgba(244, 241, 236, .26); }
.anat-stage.lit .anat-pin.on {
  transform: scale(1.42);
  border-color: var(--gold-lit);
  background: rgba(2, 3, 6, .72);
}
.anat-stage.lit .anat-pin.on i { color: var(--gold-lit); }

/* ── la guía ─────────────────────────────────────────────────────────────────
   Una sola, y sólo mientras se señala. Las cuatro a la vez se cruzarían sobre
   la caja del reloj — comprobado con las coordenadas reales: la del brazalete y
   la de la corona se cortan encima de la esfera. Una nunca se cruza con nada,
   en ninguna anchura, y además deja el reposo limpio.

   No hace falta `non-scaling-stroke`: el SVG va en píxeles del propio escenario
   (los escribe site.js), no en un viewBox escalado. */
.anat-lead {
  position: absolute; inset: 0; z-index: 2;
  width: 100%; height: 100%;
  pointer-events: none;
  overflow: visible;
}
.anat-lead polyline {
  fill: none;
  stroke-linejoin: round;
  stroke-linecap: round;
  /* Se DIBUJA, no aparece: el trazo entra desde el lado de la nota hacia el
     marcador, que es la dirección en la que se está mirando. */
  stroke-dasharray: var(--len, 0) var(--len, 0);
  stroke-dashoffset: var(--len, 0);
  opacity: 0;
}
.anat-lead .lead-line { stroke: var(--gold-lit); stroke-width: 1; }
/* La sombra propia de la guía. Ver el comentario del HTML: sin ella el tramo
   que cruza el anillo de luz simplemente no está. */
.anat-lead .lead-back { stroke: rgba(2, 3, 6, .82); stroke-width: 3.5; }
.anat-stage.lit .anat-lead .lead-line { opacity: .95; }
.anat-stage.lit .anat-lead .lead-back { opacity: .8; }
.anat-stage.lit .anat-lead polyline {
  stroke-dashoffset: 0;
  transition: stroke-dashoffset .5s var(--e-out), opacity .2s linear;
}

/* ── las notas ───────────────────────────────────────────────────────────────
   Van en el negro que la propia fotografía tiene a la izquierda — medido, el
   45% izquierdo del fichero no pasa de 6 de 255 — así que no necesitan poza ni
   velo: están sobre negro de estudio de verdad, no sobre una imagen a la que
   haya que taparle nada. */
.anat-notes {
  position: absolute; z-index: 4;
  left: var(--pad); top: 6%; bottom: 6%;
  width: min(42%, 620px);
  display: flex; flex-direction: column; justify-content: space-between;
  margin: 0; padding: 0; list-style: none;
}
.anote {
  display: grid;
  grid-template-columns: 116px minmax(0, 1fr);
  gap: 20px;
  align-items: start;
  cursor: default;
  transition: opacity .42s var(--e-out);
}
/* Los hermanos se retiran para que la señalada sea la única que existe — el
   mismo gesto que ya usa el índice de las seis piezas, por coherencia. */
.anat-stage.lit .anote { opacity: .34; }
.anat-stage.lit .anote.on { opacity: 1; }
.anote img {
  width: 116px; height: 116px;
  object-fit: cover;
  border: 1px solid rgba(244, 241, 236, .12);
  transition: border-color .42s var(--e-out), transform .5s var(--e-out);
}
.anat-stage.lit .anote.on img { border-color: rgba(198, 161, 94, .5); transform: scale(1.03); }
.anote-h {
  margin: 0 0 8px;
  font-size: 12px;
  font-variation-settings: 'wght' 620, 'wdth' 82;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink);
}
.anote-h b {
  padding: 0 .7em 0 0;
  font-weight: inherit;
  font-variant-numeric: tabular-nums;
  color: var(--gold-lit);
}
.anote-p {
  max-width: 40ch;
  font-size: clamp(14px, .92vw, 16.5px);
  line-height: 1.5;
  color: var(--ink-2);
}
.anote-d {
  margin-top: 10px;
  font-size: 11.5px;
  font-variation-settings: 'wght' 620, 'wdth' 80;
  letter-spacing: .1em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
}
.anote-d span { color: var(--ink); }
.anote-d span:last-child { color: var(--ink-3); padding: 0 .3em; }
.anote:focus-visible { outline: 2px solid var(--blue-lit); outline-offset: 6px; }

.anat-cap {
  position: absolute; z-index: 4;
  right: var(--pad); bottom: 5%;
  display: flex; gap: 22px;
  font-size: 11px;
  font-variation-settings: 'wght' 620, 'wdth' 80;
  letter-spacing: .12em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
}
.anat-cap span:first-child { color: var(--gold-ink); }

@media (prefers-reduced-motion: reduce) {
  .anat-lead polyline { stroke-dasharray: none; stroke-dashoffset: 0; transition: none; }
  .anat-pin, .anote, .anote img { transition: none; }
}

/* ── la lámina en pantallas estrechas ────────────────────────────────────────
   ⛔ AQUÍ NO SE ENCOGE, SE CAMBIA DE FORMA. Meter cuatro notas con su macro de
   116 px dentro del 42% de un teléfono deja columnas de 60 px, y los marcadores
   sobre un reloj de 180 px de ancho caen a 8 px unos de otros: dejarían de
   señalar nada. Así que por debajo de 1000 px la anotación DESAPARECE
   —marcadores, guía y apagado de hermanos— y lo que queda es la fotografía a
   sangre y debajo el mismo cuaderno de cuatro notas, cada una con su macro. Se
   pierde el gesto; no se pierde ninguna de las cuatro cosas que hay que contar. */
@media (max-width: 1000px) {
  .anat-stage {
    aspect-ratio: auto;
    display: flex; flex-direction: column;
  }
  .anat-plate {
    position: relative; inset: auto;
    width: 100%; height: auto;
    aspect-ratio: 16 / 11;
    object-fit: cover;
    /* El reloj vive en el 65% derecho del fichero: centrar el recorte lo
       partiría por la mitad. */
    object-position: 74% 50%;
  }
  .anat-stage::after {
    inset: 0 0 auto; height: 40%;
    background: linear-gradient(180deg, var(--void), transparent);
  }
  .anat-pins, .anat-lead { display: none; }
  .anat-notes {
    position: relative; z-index: 4;
    left: auto; top: auto; bottom: auto;
    width: auto;
    display: grid; gap: 30px;
    padding: 34px var(--pad) 0;
  }
  .anat-cap {
    position: relative; z-index: 4;
    right: auto; bottom: auto;
    margin: 30px var(--pad) 0;
    justify-content: space-between;
  }
}
@media (max-width: 560px) {
  .anote { grid-template-columns: 84px minmax(0, 1fr); gap: 16px; }
  .anote img { width: 84px; height: 84px; }
  .anat-cap { flex-direction: column; gap: 6px; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   FRONTAL — hard cut back into the void
   ═══════════════════════════════════════════════════════════════════════════ */
.frontal { padding-top: 0; padding-bottom: clamp(70px, 9vh, 140px); }
.frontal img { width: 100vw; margin-left: calc(50% - 50vw); height: auto; }
.fgrid { margin-top: clamp(44px, 5vh, 84px); }
.slead {
  margin: 0;
  font-variation-settings: 'wght' 570, 'wdth' 90;
  font-size: clamp(19px, 1.5vw, 30px);
  line-height: 1.42;          /* 1.24 lo marcaba el detector, y una didone lo pide */
  letter-spacing: -.004em;
  max-width: 26ch;
}
.fcite::before {
  content: ''; position: absolute; z-index: -1; pointer-events: none;
  inset: -8px -18px;
  background: linear-gradient(to bottom, transparent, rgba(2, 3, 6, .76) 26%,
              rgba(2, 3, 6, .76) 74%, transparent);
}
.fcite {
  position: relative;
  margin-top: 26px;
  font-size: 12px;
  font-variation-settings: 'wght' 620, 'wdth' 75;
  letter-spacing: .12em;
  text-transform: uppercase;
  /* va en el campo `void`, es decir SIN cristal: la tinta la mide contra el
     fotograma pelado, no contra el fondo de página */
  color: var(--ink-2);
}

/* ═══════════════════════════════════════════════════════════════════════════
   BULLETIN DE MARCHE
   ═══════════════════════════════════════════════════════════════════════════ */
/* El grano del papel. Vivía en `.hand::before, .bulletin::before` y se fue
   entero con el bloque de `.hand` al rehacer la sección; se recupera aquí para
   el único campo que aún lo usa. Una loseta de 160 px al 5% está por debajo del
   umbral en el que alguien lo llamaría textura y por encima de aquel en el que
   un relleno plano grande empieza a parecer una muestra de color. Va sobre el
   CAMPO, no sobre las fotografías. */
.bulletin::before {
  content: ''; position: absolute; inset: 0; z-index: 0;
  background-image: url('../assets/grain.png?v=2');
  background-size: 160px 160px;
  opacity: .05;
  mix-blend-mode: multiply;
  pointer-events: none;
}
.bulletin > * { position: relative; z-index: 1; }
.cert {
  display: grid;
  gap: clamp(46px, 5vw, 96px);
  padding-top: clamp(34px, 4vh, 58px);
  border-top: 2px solid var(--doc);
}
@media (min-width: 1000px) {
  .cert { grid-template-columns: minmax(0, 1.02fr) minmax(0, 1fr); }
}
.cert-h {
  display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap;
  margin: 0 0 22px;
  font-size: 12px;
  font-variation-settings: 'wght' 700, 'wdth' 75;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--doc);
}
.cert-h span {
  font-variation-settings: 'wght' 520, 'wdth' 82;
  letter-spacing: .08em;
  text-transform: none;
  color: var(--doc-3);
}

/* Five positions, and the bars make them one result. The zero is a real rule
   down the middle of the column, gaining runs right and losing runs left, so
   the shape of the regulation is legible before a single figure is read. */
.rates { margin: 0; padding: 0; list-style: none; }
.rates li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 6.5ch minmax(120px, 1.5fr);
  align-items: center;
  gap: clamp(12px, 1.4vw, 26px);
  padding: 12px 0;
  border-top: 1px solid var(--rule-ink);
}
.rates li:last-child { border-bottom: 1px solid var(--rule-ink); }
.rp {
  font-size: 12px;
  font-variation-settings: 'wght' 620, 'wdth' 77;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--doc-2);
}
.rn {
  text-align: right;
  font-size: clamp(17px, 1.25vw, 23px);
  font-variation-settings: 'wght' 430, 'wdth' 86;
  font-variant-numeric: tabular-nums;
  color: var(--doc);
}
.bar { position: relative; height: 9px; }
.bar::before {                       /* the zero rule */
  content: ''; position: absolute; left: 50%; top: -6px; bottom: -6px;
  width: 1px; background: var(--doc);
}
.bar i {
  position: absolute; top: 0; bottom: 0;
  width: calc(var(--v) / 2);
  background: var(--doc);
  transform: scaleX(0);
  transition: transform .9s var(--e-out);
}
.bar i.up { left: 50%; transform-origin: left; }
/* The losing side is the other metal, not the other tint of the same one: a
   diverging scale wants two identifiable ends. Darkened from the display gold
   until it measures 3.5:1 against the stock — a bar is a graphic and 3:1 is its
   floor, which #C6A15E misses at 1.8:1. */
.bar i.dn { right: 50%; transform-origin: right; background: var(--gold-bar); }
.rates.in i { transform: scaleX(1); }
@media (prefers-reduced-motion: reduce) { .bar i { transform: scaleX(1); transition: none; } }
.rates-note {
  margin-top: 16px;
  max-width: 68ch;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--doc-2);
  max-width: 40ch;
}

.sums { margin: 0; }
.sums > div {
  display: flex; align-items: baseline; justify-content: space-between; gap: 24px;
  padding: 12px 0;
  border-top: 1px solid var(--rule-ink);
}
.sums > div:last-child { border-bottom: 1px solid var(--rule-ink); }
.sums dt {
  font-size: 12px;
  font-variation-settings: 'wght' 620, 'wdth' 77;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--doc-2);
}
.sums dd {
  display: flex; align-items: baseline; gap: 16px;
  margin: 0;
  font-size: clamp(15px, 1.05vw, 19px);
  font-variation-settings: 'wght' 450, 'wdth' 88;
  font-variant-numeric: tabular-nums;
  color: var(--doc);
}
/* The permitted range in the margin is what turns a number into a RESULT: +0.5
   means nothing until the sheet says the window was -4 to +6. */
.sums dd em {
  font-style: normal;
  min-width: 8ch; text-align: right;
  font-size: 12px;
  font-variation-settings: 'wght' 550, 'wdth' 77;
  letter-spacing: .06em;
  color: var(--doc-2);
}

/* The seal is drawn in the page's own grammar — two rings, a meridian and the
   two halves of a horizon — and the legend is set on the arc, not a stock icon
   dropped into a corner. */
.seal {
  display: flex; align-items: center; gap: 22px;
  margin: clamp(34px, 4vh, 56px) 0 0;
}
.seal svg { flex: 0 0 auto; width: 118px; height: 118px; overflow: visible; }
.s-ring, .s-mer { fill: none; stroke: var(--doc); stroke-width: 1; opacity: .5; }
.s-mer { opacity: .34; }
.s-t {
  fill: var(--doc); font-size: 8.6px;
  font-variation-settings: 'wght' 650, 'wdth' 77;
  letter-spacing: .12em;
  text-anchor: middle;
}
.s-y {
  fill: var(--doc); font-size: 13px;
  font-variation-settings: 'wght' 550, 'wdth' 80;
  letter-spacing: .12em;
  text-anchor: middle;
}
.seal figcaption {
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--doc-2);
  max-width: 24ch;
}

.cert-specs { margin-top: clamp(58px, 7vh, 110px); }
.specs { margin: 0; }
@media (min-width: 900px) {
  .specs {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: clamp(48px, 5vw, 140px);
  }
  .specs > div:nth-child(2) { border-top: 1px solid var(--rule-ink); }
}
@media (min-width: 1500px) {
  .specs { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .specs > div:nth-child(3) { border-top: 1px solid var(--rule-ink); }
}
.specs > div {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 26px;
  padding: 13px 0;
  border-top: 1px solid var(--rule-ink);
}
.specs dt {
  font-size: 12px;
  font-variation-settings: 'wght' 620, 'wdth' 77;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--doc-2);
}
.specs dd {
  margin: 0; text-align: right;
  font-size: clamp(14.5px, .95vw, 17.5px);
  font-variation-settings: 'wght' 430, 'wdth' 92;
  font-variant-numeric: tabular-nums;
  color: var(--doc);
}

/* ═══════════════════════════════════════════════════════════════════════════
   RESERVE
   ═══════════════════════════════════════════════════════════════════════════ */
.rgrid { display: grid; gap: 46px; }
@media (min-width: 1080px) {
  .rgrid { grid-template-columns: minmax(0, 1fr) minmax(0, .78fr); gap: clamp(48px, 5vw, 110px); align-items: start; }
}
.rside p { color: var(--ink-2); max-width: 42ch; font-size: clamp(15px, .98vw, 18px); }
.rlede { margin-top: clamp(24px, 3vh, 38px); }
.rfine {
  margin-top: 22px;
  font-size: 13px;
  color: var(--ink-3);
}

/* ── el formulario ───────────────────────────────────────────────────────────
   Sin cajas. Los campos son la misma regla de 1 px con la que están dibujadas
   las cabeceras, el índice y el certificado: una línea bajo el dato, no un
   recuadro relleno con esquinas redondeadas. Es lo que hace que el formulario
   pertenezca a este documento en vez de parecer un widget incrustado.

   ⛔ Y NO LLEVA `placeholder` HACIENDO DE ETIQUETA. Es el atajo de siempre y
   deja al usuario sin saber qué campo está rellenando en cuanto escribe la
   primera letra; además el marcador de posición hereda un gris que casi nunca
   pasa el contraste. Cada campo tiene su `<label>` visible y permanente, y el
   `placeholder` dice otra cosa (un ejemplo), no lo mismo. */
.rform { margin: 0; }
.rform-h {
  margin: 0 0 clamp(24px, 3vh, 34px);
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line);
  font-size: 12px;
  font-variation-settings: 'wght' 620, 'wdth' 80;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink);
}
.fgrp { margin-bottom: 22px; }
.fgrp label {
  display: block;
  margin-bottom: 7px;
  font-size: 11px;
  font-variation-settings: 'wght' 620, 'wdth' 80;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.rform input, .rform select, .rform textarea {
  display: block;
  width: 100%;
  padding: 11px 2px;
  border: 0;
  border-bottom: 1px solid rgba(244, 241, 236, .22);
  border-radius: 0;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: 15.5px;
  font-variation-settings: 'wght' 400, 'wdth' 96;
  transition: border-color .3s var(--e-out);
}
.rform textarea { resize: vertical; min-height: 76px; line-height: 1.5; }
.rform input::placeholder, .rform textarea::placeholder { color: rgba(244, 241, 236, .34); }
.rform input:focus, .rform select:focus, .rform textarea:focus {
  outline: none;
  border-bottom-color: var(--gold-lit);
}
/* El desplegable nativo se pinta con los colores del sistema, así que en un
   tema claro las opciones salen en negro sobre blanco dentro de una página
   negra. `color-scheme: dark` es lo que le dice al navegador de qué lado está. */
.rform select { color-scheme: dark; cursor: pointer; }
.rform select option { background: #0B1018; color: var(--ink); }
/* Un campo en error se marca en la propia regla, no con un icono ni con un
   borde rojo de 2 px que reencuadra el bloque entero. */
.rform .bad input, .rform .bad select, .rform .bad textarea { border-bottom-color: #E4795F; }
.fgrp .err {
  display: none;
  margin-top: 6px;
  font-size: 12px;
  color: #E4795F;
  text-transform: none; letter-spacing: 0;
}
.fgrp.bad .err { display: block; }

/* La trampa. `visibility: hidden` y no `display: none` a propósito: algunos
   bots se saltan lo que está en `display:none` justamente porque saben que es
   una trampa. Y sale del flujo para no dejar un hueco. */
.fpot {
  position: absolute; left: -9999px;
  width: 1px; height: 1px; overflow: hidden;
}

#fSend { margin-top: 10px; cursor: pointer; border-radius: 0; }
#fSend[disabled] { cursor: default; opacity: .6; }
.fsend-busy { display: none; }
.rform.sending .fsend-idle { display: none; }
.rform.sending .fsend-busy { display: inline; }

.fmsg {
  margin-top: 18px;
  min-height: 1.2em;
  max-width: 44ch;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ink-2);
}
.fmsg.ok { color: var(--gold-lit); }
.fmsg.err { color: #E4795F; }
/* Enviado: el formulario se retira y deja el acuse. Dejar los campos puestos
   invita a mandarlo otra vez, y un segundo envío del mismo lead es ruido en el
   buzón y una duda para quien lo escribió. */
.rform.sent .fgrp, .rform.sent #fSend, .rform.sent .rform-h { display: none; }
.rform.sent .fmsg { font-size: clamp(16px, 1.1vw, 20px); color: var(--ink); }

/* ── footer ──────────────────────────────────────────────────────────────── */
footer { background: var(--void); padding: 40px 0 46px; border-top: 1px solid var(--line); }

/* La declaración de demo. En tinta plena y a cuerpo de texto: si va en el gris
   de la letra pequeña, pegada al copyright, deja de ser una declaración y pasa
   a ser un descargo — que es exactamente lo que no puede ser. */
.demo-note {
  max-width: 78ch;
  margin: 0 0 clamp(30px, 4vh, 46px);
  padding-bottom: clamp(26px, 3.4vh, 38px);
  border-bottom: 1px solid var(--line);
  font-size: clamp(14px, .92vw, 16px);
  line-height: 1.6;
  color: var(--ink-2);
}
.demo-note b {
  padding: 0; font-weight: inherit;
  font-variation-settings: 'wght' 620, 'wdth' 96;
  color: var(--ink);
}
.demo-note a {
  color: var(--ink);
  text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px;
}
.demo-note a:hover { color: var(--gold-lit); }

.foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 28px; flex-wrap: wrap;
  font-size: 12px;
  font-variation-settings: 'wght' 600, 'wdth' 80;
  letter-spacing: .12em;
  text-transform: uppercase;
}
.foot a { color: var(--ink-2); text-decoration: none; transition: color .28s var(--e-out); }
.foot a:hover { color: var(--ink); }
.foot nav { display: flex; gap: 30px; flex-wrap: wrap; }
.fine {
  margin: 26px 0 0;
  max-width: 70ch;
  font-size: 12px;
  line-height: 1.6;
  color: var(--ink-3);
}

/* ═══════════════════════════════════════════════════════════════════════════
   LAS PÁGINAS LEGALES

   Comparten esta hoja a propósito: son de la misma casa y tienen que parecerlo,
   y además así no hay una segunda hoja de estilos que se quede atrás cuando
   cambie la tipografía. Lo único que necesitan es una medida de lectura y una
   jerarquía; no hay película, ni campos, ni pozas.
   ═══════════════════════════════════════════════════════════════════════════ */
body.legal { background: var(--void); }
.legal-main { padding: 132px 0 clamp(70px, 9vh, 130px); }
.legal-head { margin-bottom: clamp(40px, 5vh, 70px); }
.legal-head h1 {
  margin: 0 0 14px;
  font-size: clamp(30px, 2.6vw, 52px);
  font-variation-settings: 'wght' 570, 'wdth' 90;
  line-height: 1.06;
  letter-spacing: -.014em;
}
.legal-date {
  font-size: 12px;
  font-variation-settings: 'wght' 620, 'wdth' 80;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.legal-body { max-width: 74ch; }
.legal-body h2 {
  margin: clamp(38px, 5vh, 60px) 0 14px;
  font-size: clamp(17px, 1.15vw, 21px);
  font-variation-settings: 'wght' 620, 'wdth' 92;
  line-height: 1.25;
  letter-spacing: -.006em;
}
.legal-body p, .legal-body li {
  font-size: 16px;
  line-height: 1.68;
  color: var(--ink-2);
}
.legal-body p + p { margin-top: 14px; }
.legal-body ul { margin: 14px 0 0; padding-left: 20px; }
.legal-body li { margin-bottom: 10px; }
.legal-body a { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
.legal-body a:hover { color: var(--gold-lit); }
.legal-body strong { font-weight: inherit; font-variation-settings: 'wght' 620, 'wdth' 96; color: var(--ink); }
/* El aviso de que nada de esto es real va ARRIBA y con su propio filete: en una
   página de términos es el hecho que cambia el significado de todo lo demás. */
.legal-flag {
  margin: 0 0 clamp(34px, 4vh, 52px);
  padding: 22px 26px;
  border: 1px solid rgba(198, 161, 94, .34);
  max-width: 74ch;
}
.legal-flag p { font-size: 15px; line-height: 1.6; color: var(--ink-2); }
.legal-flag b {
  display: block; padding: 0 0 6px;
  font-weight: inherit;
  font-size: 11px;
  font-variation-settings: 'wght' 620, 'wdth' 82;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--gold-lit);
}
.legal-back {
  display: inline-block;
  margin-top: clamp(44px, 5vh, 70px);
  font-size: 12px;
  font-variation-settings: 'wght' 620, 'wdth' 82;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-2);
  text-decoration: none;
}
.legal-back:hover { color: var(--ink); }

/* ── ⛔ LA INVERSIÓN SOBRE PAPEL SE HA CAÍDO, Y HACÍA FALTA QUE SE CAYERA ─────
   Aquí había un juego completo de reglas `.nav.on-paper` que ponía la barra en
   marfil claro, invertía el logo con un `filter` y oscurecía los enlaces,
   porque las secciones `data-field="paper"` traían un papel de #D7DCE2.

   Ese papel YA NO EXISTE. Cuando los campos pasaron a ser velos sobre la
   película, `[data-field="paper"]` se redefinió a `rgba(6, 10, 18, .42)` — o
   sea oscuro — y la tinta se invirtió con él. La regla del nav se quedó
   apuntando al color de antes: habría pintado una barra BLANCA sobre un campo
   oscuro, con el logo invertido, justo en el tramo del certificado.

   Nunca se vio, y no por suerte: se vio tapado por el otro fallo. El nav estaba
   en `position: relative`, así que a la altura de esas secciones ya no estaba
   en pantalla y la clase se ponía sobre un elemento invisible. Arreglar el
   `fixed` sin borrar esto habría ESTRENADO el fallo blanco en la misma tanda.
   Un campo cambió de signo y la regla que lo pintaba no se volvió a mirar.

   No hay sustituto porque no hace falta: los tres campos son ahora oscuros y la
   misma cápsula de cristal vale para los tres. El `measure()`/`update()` que
   movía la clase también sale de site.js. */

/* ── reveals ─────────────────────────────────────────────────────────────────
   🔴 LO QUE HABÍA ERA UN SOLO GESTO REPETIDO: `translateY(22px)` + fundido, en
   diez elementos, y nada más en toda la página. El índice de seis relojes, la
   tabla, el certificado y las cifras no se movían en absoluto. Un único
   «fade-up» aplicado por igual a todo es la firma más reconocible del motion
   generado — y además `animation-range: entry 4% cover 20%` lo remataba casi en
   cuanto el bloque asomaba, así que ni siquiera se llegaba a leer como gesto.

   Ahora hay CINCO gestos y cada uno dice algo distinto sobre lo que entra:

     · rv-type   los titulares se LEVANTAN tras un borde que los descubre —
                 tipografía que se pone de pie, no que aparece.
     · rv-rule   la cabecera reglada se DIBUJA: las dos reglas crecen desde el
                 lomo hacia fuera, como se traza el encabezado de una hoja.
     · rv-rows   las filas de datos se posan una a una, cada una disparada por
                 su propia entrada en pantalla — no por una cascada de delays,
                 que es el otro tell.
     · rv-plate  las fotografías se ASIENTAN: entran un 5% grandes y se paran,
                 dentro de un marco que las recorta. Es el gesto de una lámina
                 pegada en la página.
     · rv        el resto: el rise de siempre, ahora con recorrido para leerse.

   Todo va atado al SCROLL y no a un temporizador, a propósito: en esta página
   el scroll ya mueve una película: una entrada con duración propia iría a su
   aire mientras el fotograma de detrás va al ritmo de la rueda. Aquí la
   dependencia de la velocidad de scroll no es el defecto de siempre — es la
   única forma de que todo respire a la vez.

   Sólo se animan transform / opacity / filter / clip-path. */
/* ⭐ EL TEXTO CORRIDO ENTRA SIN TOCAR LA OPACIDAD, Y ESO NO ES UNA RENUNCIA.
   Una entrada por opacidad y un minimo de contraste en reposo son
   incompatibles por aritmetica, no por ajuste: lo que aun no ha entrado en
   pantalla se queda en el fotograma inicial de su animacion, asi que si ese
   fotograma es "medio transparente", el texto esta a 1,3:1 mientras espera. Y
   subir el suelo hasta que mida bien (~0,8) deja el fundido invisible, o sea
   deja de haber entrada. Se probaron los dos extremos y los dos fallan.

   La salida no es elegir cual de los dos incumplir: es que la entrada NO USE la
   opacidad. Un desplazamiento de 26 px con salida exponencial se lee
   perfectamente como entrada, y el texto esta a tinta plena todo el rato —
   antes, durante y despues. El fundido se queda donde el elemento no es texto
   que alguien pueda estar leyendo: los titulares (que entran tras un borde),
   las reglas y las laminas. */
@keyframes rise {
  from { transform: translate3d(0, 26px, 0); }
  to   { transform: none; }
}
/* ⛔ EL BORDE Y EL MOVIMIENTO IBAN EN SENTIDOS CONTRARIOS. El recorte abría de
   ARRIBA hacia abajo (`inset(0 0 108% 0)`) mientras el bloque SUBÍA, así que a
   media entrada lo que se veía era un titular partido por una línea horizontal
   — se lee como un fallo de pintado, no como un gesto. Y el rango era largo
   (`cover 40%`), o sea que ese estado partido duraba media pantalla de scroll.

   Ahora el borde abre de ABAJO hacia arriba, en el mismo sentido en que sube el
   texto: la tipografía emerge por detrás de una línea, que es el descubrimiento
   clásico de un titular. Y el rango termina cuando el bloque acaba de entrar,
   así que el estado intermedio pasa rápido y nunca se queda a la vista. */
@keyframes riseType {
  from { opacity: .34; transform: translate3d(0, 40px, 0);
         clip-path: inset(100% 0 -8% 0); }
  to   { opacity: 1; transform: none; clip-path: inset(-8% 0 -8% 0); }
}
/* ⛔ NO CON `scaleX`. La cabecera reglada no es una línea: es una caja flex con
   tres textos y dos bordes. Escalarla en X dibujaría las reglas, sí, y de paso
   dejaría "PLATE INDEX · SIX EXECUTIONS · REF. MRD-41" aplastado al 16% y
   estirándose hasta su sitio — que es exactamente el efecto barato que se
   intenta evitar. Se descubre desde el lomo con `clip-path`: las reglas crecen
   igual, y los tres textos aparecen a su anchura real. */
/* Sin opacidad, por la misma razon que `rise` y `settleRow`: la cabecera son
   TRES TEXTOS, y atenuarlos mientras entran los deja a 1,1-4,0:1 durante todo el
   tramo de entrada. El recorte solo ya hace el gesto — de hecho lo hace mejor,
   porque lo que se ve es la regla creciendo y no un bloque encendiendose. */
@keyframes drawRule {
  from { clip-path: inset(0 46% 0 46%); }
  to   { clip-path: inset(0 -2% 0 -2%); }
}
/* Blur→nítido: Jakub. La fila no aparece, entra en foco — que es lo que hace
   que una tabla de datos se sienta impresa y no pegada. */
/* 🔴 EL TEXTO NO ARRANCA EN OPACIDAD CERO. El detector lo midio: con las
   entradas atadas al scroll, el 46% del texto de la pagina (1.846 de 4.013
   caracteres) se queda a `opacity: 0` en reposo, porque todo lo que aun no ha
   entrado en pantalla esta ANTES del rango de su animacion y `both` le mantiene
   el fotograma inicial. Casi todo eso son estas filas: fichas, especificaciones,
   posiciones del certificado y las seis piezas — 47 elementos.

   Es inherente a que las entradas vayan por scroll, que es lo que se pidio. Lo
   que NO es inherente es que el suelo sea cero: arrancando en .28 el gesto se
   lee igual (lo que se percibe es el desenfoque abriendose y el desplazamiento,
   no el paso de 0 a 1) y el texto deja de estar tecnicamente oculto para quien
   lea la pagina sin ejecutar el scroll. */
@keyframes settleRow {
  from { opacity: .46; transform: translate3d(0, 14px, 0); filter: blur(3.5px); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}
@keyframes settlePlate {
  from { opacity: .3; transform: scale(1.055); clip-path: inset(0 0 34% 0); }
  to   { opacity: 1; transform: none; clip-path: inset(0 0 0 0); }
}

@supports (animation-timeline: view()) {
  .rv, .rv-type, .rv-plate, .rv-rows > *, .rv-rule {
    animation: rise linear both;
    animation-timeline: view();
    /* recorrido de verdad: `entry 4% cover 20%` terminaba el gesto antes de que
       al bloque le diera tiempo a entrar del todo */
    animation-range: entry 8% cover 34%;
  }
  .rv-type  { animation-name: riseType;  animation-range: entry 18% entry 100%; }
  .rv-plate { animation-name: settlePlate; animation-range: entry 0% cover 46%; }
  .rv-rows > * { animation-name: settleRow; animation-range: entry 12% cover 30%; }
  .rv-rule  { animation-name: drawRule; animation-range: entry 6% cover 26%; }
}
/* Firefox aún no tiene `view()`: el mismo reparto, disparado por observador. */
@supports not (animation-timeline: view()) {
  .rv, .rv-type, .rv-plate, .rv-rows > *, .rv-rule {
    transform: translate3d(0, 26px, 0);
    transition: opacity .9s var(--e-out), transform .9s var(--e-out),
                filter .9s var(--e-out), clip-path 1s var(--e-out);
  }
  .rv-type  { transform: translate3d(0, 40px, 0); clip-path: inset(100% 0 -8% 0); opacity: .34; }
  .rv-plate { transform: scale(1.055); clip-path: inset(0 0 34% 0); opacity: .3; filter: blur(6px); }
  .rv-rows > * { transform: translate3d(0, 16px, 0); }
  .rv-rule  { transform: none; clip-path: inset(0 46% 0 46%); }
  .rv.in, .rv-type.in, .rv-plate.in, .rv-rows.in > *, .rv-rule.in {
    opacity: 1; transform: none; filter: none; clip-path: inset(0 0 0 0);
  }
}
/* Obligatorio, no opcional: se conserva el estado FINAL para que no quede nada
   recortado ni desplazado. `clip-path` incluido — sin él, un bloque con la
   máscara puesta se quedaría invisible para quien pide menos movimiento. */
@media (prefers-reduced-motion: reduce) {
  .rv, .rv-type, .rv-plate, .rv-rule, .rv-rows > *,
  .rv.in, .rv-type.in, .rv-plate.in, .rv-rule.in, .rv-rows.in > * {
    opacity: 1 !important; transform: none !important;
    filter: none !important; clip-path: none !important;
    animation: none !important; transition: none !important;
  }
  * { scroll-behavior: auto !important; }
}

/* ── debug ───────────────────────────────────────────────────────────────── */
#dbg {
  display: none;
  position: fixed; left: 12px; bottom: 12px; z-index: 99;
  margin: 0; padding: 10px 12px;
  background: rgba(0, 0, 0, .82);
  color: #7CFFB2;
  font: 12px/1.45 ui-monospace, monospace;
  white-space: pre;
  pointer-events: none;
}
