/* =========================================================================
   REVISTA FUGA — hoja de estilos del sitio.

   CÓMO SE CONVIERTEN LOS VALORES DE FIGMA
   Los frames están armados a 1920 × 1080. La conversión es siempre la misma:
     · posición horizontal → x / 1920 * 100 %
     · posición vertical   → y / 1080 * 100 %
     · tamaño de letra     → clamp(mínimo, px/1920*100 vw, px)
   El máximo del clamp hace de tope: pasados los 1920 de ventana, deja de
   crecer. A 16:9 el resultado es idéntico al diseño; en otras proporciones
   la composición se estira parejo en vez de romperse.

   Los nombres de las variables son los mismos que los estilos del archivo de
   Figma, para no traducir entre los dos lados.
   ========================================================================= */

:root {
  /* --- color --- */
  --violeta-oscuro: #180C1A;
  --violeta-principal: #301934;
  --blanco-1: #F7EDF0;
  --gris-2: #85756E;
  --violeta-claro: #47254D;
  --naranja-principal: #F46036;
  --amarillo-principal: #FFF275;

  /* --- tipografía ---
     Dos familias con roles distintos:
     · Adobe Jenson Pro → SOLO las marcas REVISTA y FUGA
     · Thermal          → todo lo demás, en dos tamaños ópticos (Display
                          para los títulos, Text para el resto)
     Las dos salen del kit buh7php. OJO con el nombre: la familia que sirve
     el kit se llama "adobe-jenson-pro-display", no "adobe-jenson-pro".
     El kit trae Jenson en una sola cara, redonda y de peso 300, así que las
     marcas van en 300: pedirle un peso que no existe deja que el navegador lo
     falsifique y engorda el trazo. Thermal sí es variable, de 100 a 900, y
     desde el 15/9 viene también en itálica de verdad. */
  --marca: 'adobe-jenson-pro-display', Garamond, 'EB Garamond',
           'Times New Roman', serif;
  --thermal: 'thermal-variable', Georgia, serif;

  /* --- medidas de la grilla (a 1920) --- */
  --margen: 3.3333%;      /*  64px  */
  --nav-y: 4.4444%;       /*  48px  */

  /* --- tamaños de letra --- */
  --t-16: clamp(11px, 0.8333vw, 16px);
  --t-18: clamp(12px, 0.9375vw, 18px);
  --t-20: clamp(13px, 1.0417vw, 20px);
  --t-24: clamp(13px, 1.25vw, 24px);
  --t-32: clamp(17px, 1.6667vw, 32px);
  --t-64: clamp(28px, 3.3333vw, 64px);

  /* --- altura de pantalla ---
     svh es la altura REALMENTE visible en mobile: vh no descuenta la barra
     del navegador y deja el contenido cortado. */
  --pantalla: 100vh;
  --pantalla: 100svh;

  /* --- tiempos --- */
  --t-corto: 0.45s;
  --t-medio: 0.8s;
  --t-largo: 1.1s;
  /* --- curvas ---
     Tres, y cada movimiento usa la que le toca por lo que está haciendo:

     · SALE   arranca despacio y acelera: algo que se va toma carrera y
              desaparece. Frenar al final sería quedarse en la puerta.
     · ENTRA  entra lanzado y se posa: llega con impulso y se acomoda. Es la
              inversa de la anterior, a propósito.
     · MUTA   lento, rápido, lento: no va a ningún lado, cambia de forma, y
              tiene que arrancar y llegar con calma en los dos extremos.

     Los nombres viejos quedan apuntando a estas para no dejar nada suelto. */
  --sale:  cubic-bezier(0.55, 0, 0.85, 0.35);
  --entra: cubic-bezier(0.16, 0.84, 0.44, 1);
  --muta:  cubic-bezier(0.65, 0, 0.35, 1);

  --ease: var(--entra);
  --ease-abre: var(--sale);
  --ease-entra: var(--entra);
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--violeta-oscuro);
  color: var(--blanco-1);
  font-family: var(--thermal);
  font-weight: 300;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;

  /* Cifras tabulares en todo el sitio: todos los dígitos ocupan lo mismo, así
     un precio o una cantidad que cambia no sacude lo que tiene al lado. */
  font-variant-numeric: lining-nums tabular-nums;
}

/* Los controles de formulario no heredan la tipografía del documento: el
   navegador les impone la suya, y con ella se pierde el ajuste de arriba. */
input, select, textarea, button { font-variant-numeric: inherit; }

body.trabado { overflow: hidden; height: 100%; }

img { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
p { margin: 0; }

/* =========================================================================
   SISTEMA DE ENTRADA
   Cada elemento entra por UN solo eje: nunca en diagonal. Para un recorrido
   quebrado se anidan dos, y el de adentro arranca cuando el de afuera
   termina. Mientras el contenido use estas clases, la regla no se rompe.
   ========================================================================= */

/* El desplazamiento va en la propiedad `translate`, NO en `transform`.
   Es a propósito: muchas piezas ya usan transform para centrarse sobre su
   propio punto (translate(-50%, -50%)), y si la entrada escribiera ahí, al
   terminar lo borraría y la pieza quedaría colgada de su esquina en vez de
   centrada. Siendo propiedades distintas, las dos conviven. */
[data-entra] {
  opacity: 0;
  transition: opacity var(--t-medio) var(--ease-entra),
              translate var(--t-medio) var(--ease-entra);
  transition-delay: var(--retardo, 0ms);
  will-change: translate, opacity;
}
[data-entra="abajo"]     { translate: 0 40px; }
[data-entra="arriba"]    { translate: 0 -40px; }
[data-entra="derecha"]   { translate: 40px 0; }
[data-entra="izquierda"] { translate: -40px 0; }
[data-entra="quieto"]    { translate: none; }
[data-entra].visible     { opacity: 1; translate: none; }

.quebrado > [data-entra] { transition-delay: var(--t-medio); }

/* Cuando el contenido ya estaba a la vista antes de llegar, aparece puesto en
   vez de entrar. Dura un cuadro; js/fuga.js saca la clase enseguida. */
body.sin-entrada [data-entra],
body.sin-entrada .ficha__encabezado,
body.sin-entrada .ficha__tapa,
body.sin-entrada .ficha__precio,
body.sin-entrada .ficha__reservar { transition: none; }

/* Al cambiar de página, lo que entró se retira antes de que el navegador se
   lleve la página. En el inicio esto lo maneja el motor de la escena, porque
   ahí las opacidades se escriben a mano en cada cuadro; acá queda cubierto
   todo lo demás: Conseguila, Convocatoria y lo que venga. */
body.despidiendo [data-entra].visible,
body.despidiendo .ficha__encabezado,
body.despidiendo .ficha__tapa,
body.despidiendo .ficha__precio,
body.despidiendo .ficha__reservar,
body.despidiendo .ficha__volver,
body.despidiendo .compra,
body.despidiendo .novedades,
body.despidiendo .compra__cantidad,
body.despidiendo .compra__confirmar,
body.despidiendo .compra__aviso {
  opacity: 0;
  translate: 0 -40px;
  /* Hay que repetir la transición acá: las piezas de Conseguila declaran la
     suya para el viaje horizontal, y esa pisa la del sistema de entrada. Y
     tiene que ser corta, porque la página se va a los 480 ms: con la duración
     de entrada, la salida quedaría cortada por la mitad. */
  transition: opacity var(--t-corto) var(--sale) var(--retardo, 0ms),
              translate var(--t-corto) var(--sale) var(--retardo, 0ms);
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  [data-entra] { opacity: 1; translate: none; transition: none; }
}

/* =========================================================================
   RECTÁNGULO TEXTURADO — el recurso gráfico de la marca.
   En Figma es "Rectangulo plano": violeta principal con Texture (radio 12)
   y Noise. Acá es un SVG con el filtro exportado del propio archivo, con la
   caja en las medidas del frame para que el grano conserve su escala.
   ========================================================================= */

.rect {
  position: absolute;
  pointer-events: none;
}
.rect > svg { width: 100%; height: 100%; display: block; overflow: visible; }

/* =========================================================================
   CHROME DEL SITIO — navegación, marcas y contacto.
   Se repiten en todos los frames, así que viven fijos por encima de las
   pantallas en vez de repetirse en cada una.
   ========================================================================= */

.chrome { position: fixed; inset: 0; z-index: 60; pointer-events: none; }
.chrome > * { pointer-events: auto; }

.nav {
  position: absolute;
  top: var(--nav-y);
  left: var(--margen);
  display: flex;
  /* En el frame los cinco ítems están separados por exactamente 64px, así
     que alcanza una fila con esa separación en vez de posicionar cada uno. */
  gap: clamp(16px, 3.3333vw, 64px);
  font-size: var(--t-24);
  /* Entra desde arriba cuando arranca el sitio: vertical puro.
     El desplazamiento va en vh y no en el % de --nav-y: dentro de un
     translateY, un porcentaje se mide contra la altura del propio nav, no
     contra la de la pantalla, así que subía apenas cuarenta píxeles y quedaba
     asomando arriba. Antes no se veía porque lo tapaba el landing; con la
     apertura en círculo quedó a la vista. La opacidad es el cinturón: aunque
     el cálculo falle, no se ve. */
  transform: translateY(calc(-100% - 4.4444vh - 2vh));
  opacity: 0;
  transition: transform var(--t-medio) var(--ease),
              opacity var(--t-corto) var(--ease);
}
body.en-sitio .nav { transform: translateY(0); opacity: 1; }

.nav a { color: var(--gris-2); transition: color var(--t-corto) ease; white-space: nowrap; }
.nav a.activo,
.nav a:active { color: var(--blanco-1); }

/* La barra que aparta a Conseguila del resto. Va como elemento suelto y no
   como pseudo-elemento del enlace: así el flex le da la misma separación de
   los dos lados y queda centrada entre una cosa y la otra. */
.nav__corte {
  color: var(--blanco-1);
  user-select: none;
}

/* Conseguila no se comporta como las demás, y es a propósito: es el punto de
   venta. El resto del nav es una lista de secciones que se encienden cuando
   pasás por encima; esta ya viene encendida en amarillo y lo que responde al
   mouse es el subrayado.

   El subrayado está siempre puesto, transparente, y lo que cambia es su
   color: es la única forma de que aparezca de a poco en vez de un golpe, y
   además no mueve a los vecinos, como haría un borde. */
.nav a.venta {
  color: var(--amarillo-principal);
  text-decoration: underline;
  text-decoration-color: transparent;
  text-decoration-thickness: 1px;
  text-underline-offset: 5px;
  transition: text-decoration-color var(--t-corto) ease;
}
.nav a.venta.activo,
.nav a.venta:active { text-decoration-color: currentColor; }

/* Una sola marca, arriba a la derecha. Era un par —REVISTA arriba y FUGA
   abajo, enmarcando la página— y quedó FUGA sola, en el lugar que ocupaba
   REVISTA: y = 45, con el mismo borde derecho en x = 1856. */
.marca {
  position: absolute;
  right: var(--margen);
  top: 4.1667%;                /* y = 45 */
  font-family: var(--marca);
  font-weight: 300;
  font-size: var(--t-32);
  color: var(--gris-2);
  line-height: 1.2;
  opacity: 0;
}
body.en-sitio .marca { opacity: 1; }

/* Y es un enlace: la única vuelta al landing dentro de una misma visita. Se
   enciende en blanco, como el resto del chrome.

   Apagada tampoco atiende. Cuando era un párrafo daba igual que estuviera ahí
   con la opacidad en cero, pero un enlace invisible se puede tocar igual: en
   el inicio, entre que el landing suelta los clics y el sitio termina de
   presentarse, quedaba un par de décimas en las que tocar esa esquina te
   mandaba de vuelta al landing sin que hubiera nada a la vista. */
.marca {
  cursor: pointer;
  pointer-events: none;
  transition: opacity var(--t-medio) var(--ease), color var(--t-corto) ease;
}
body.en-sitio .marca,
html.sin-umbral .marca { pointer-events: auto; }
.marca:active { color: var(--blanco-1); }
.marca:focus-visible { outline: 2px solid var(--amarillo-principal); outline-offset: 4px; }

/* ---------- Redes sociales ----------
   Era el enlace al correo y pasó a ser un botón: las dos redes salen de
   atrás de la palabra, hacia la derecha.

   El ancho se anima con la grilla de 0fr a 1fr, que es lo mismo que hace el
   acordeón de Convocatoria y por el mismo motivo: es lo único que anima una
   medida que no se sabe de antemano. `width: auto` no se puede transicionar,
   y fijar un ancho a mano obligaría a recalcularlo cada vez que cambie el
   cuerpo de letra. */

/* El bloque se usa en dos sitios: abajo a la izquierda del chrome y adentro
   del menú de mobile. Lo común va acá; lo que cambia —dónde se para y cuándo
   aparece— va en cada uno. */
.redes {
  display: flex;
  align-items: center;
  color: var(--gris-2);
}

.chrome > .redes {
  position: absolute;
  left: var(--margen);
  bottom: 6.9444%;   /* y = 1005 */
  font-size: var(--t-24);
  opacity: 0;
  transition: opacity var(--t-medio) var(--ease);
}
body.en-sitio .chrome > .redes { opacity: 1; }

.redes__boton {
  padding: 0;
  border: 0;
  background: transparent;
  font: inherit;
  color: inherit;
  cursor: pointer;
  transition: color var(--t-corto) ease;
}
.redes__boton:active { color: var(--blanco-1); }
.redes__boton:focus-visible { outline: 2px solid var(--amarillo-principal); outline-offset: 4px; }

.redes__caja {
  display: grid;
  grid-template-columns: 0fr;
  transition: grid-template-columns var(--t-corto) var(--muta);
}
.redes.abierto .redes__caja { grid-template-columns: 1fr; }
.redes__caja > div {
  overflow: hidden;
  display: flex;
  align-items: center;
  gap: 0.85em;
  /* Aire adentro del recorte. Los dos dibujos llegan hasta el borde mismo de
     su caja —no traen margen propio— así que sin esto el recorte que abre el
     despliegue les come un píxel del contorno. En una pantalla que redondea
     distinto a la de escritorio, ese píxel se ve. */
  padding: 0.14em 0.14em 0.14em 0;
}

/* Los dibujos se miden en em y no en píxeles: así el mismo bloque sirve en el
   chrome, donde la palabra va en 24, y adentro del menú, donde va en 20. */
.redes__enlace {
  display: block;
  padding-left: 0.05em;
  color: var(--gris-2);
  opacity: 0;
  translate: -8px 0;
  transition: opacity var(--t-corto) var(--entra) var(--retardo, 0ms),
              translate var(--t-corto) var(--entra) var(--retardo, 0ms),
              color var(--t-corto) ease;
}
.redes__enlace:first-child { margin-left: 0.9em; }
.redes__enlace:nth-child(2) { --retardo: 70ms; }
.redes.abierto .redes__enlace { opacity: 1; translate: none; }
.redes__enlace svg { display: block; width: 0.85em; height: 0.85em; }
.redes__enlace:active { color: var(--blanco-1); }
.redes__enlace:focus-visible { outline: 2px solid var(--amarillo-principal); outline-offset: 4px; }

/* Cerrado, lo de adentro no se tabula: es una caja de ancho cero, pero los
   enlaces siguen existiendo. */
.redes:not(.abierto) .redes__enlace { visibility: hidden; }
.redes.abierto .redes__enlace { visibility: visible; }

@media (max-width: 599px) {
  .nav { font-size: 13px; gap: 14px; }
}

/* Si esta visita ya cruzó el umbral, el landing no existe: no alcanza a verse
   ni un cuadro. La clase la pone un script en el <head>,
   antes del primer pintado; esperar a fuga.js deja pasar un destello. Y el
   chrome ya está puesto por la misma razón. */
html.sin-umbral .landing,
html.sin-umbral .landing__aro { display: none; }

html.sin-umbral .nav { transform: none; opacity: 1; }
html.sin-umbral .marca,
html.sin-umbral .redes { opacity: 1; }

/* El sitio se presenta una sola vez por visita. Si ya pasó, todo lo que entra
   —el nav desde arriba, las marcas, el landing abriéndose— aparece puesto y
   sin transición: repetir la presentación en cada página la vuelve un peaje. */
body.sin-estreno,
body.sin-estreno .nav,
body.sin-estreno .marca,
body.sin-estreno .redes,
body.sin-estreno .landing,
body.sin-estreno .landing__aro { transition: none; }

/* =========================================================================
   LANDING — frame "Inicio Landing" (591:2)
   Las posiciones verticales van en porcentaje del alto de la pantalla: así
   la composición conserva sus proporciones aunque la ventana no sea 16:9.
   ========================================================================= */

/* El landing no se corre: se abre. Donde cae el gesto se hace un agujero
   redondo que crece hasta comerse la pantalla, y por ahí aparece el sitio.
   El centro lo pone js/fuga.js con el punto del click o del cursor.

   El radio se registra como longitud para que el navegador pueda
   interpolarlo: sin eso saltaría de un valor al otro y no habría apertura. Y
   se hereda, porque no lo usa solo el landing para su máscara: también el aro
   naranja que marca el borde mientras se abre. Por eso vive en el <body>. */
@property --agujero {
  syntax: '<length>';
  inherits: true;
  initial-value: 0px;
}

body {
  --agujero: 0px;
  --cx: 50%;
  --cy: 50%;
  transition: --agujero var(--t-largo) var(--ease-abre);
}
body.intro-vista { --agujero: var(--lejos, 150vmax); }

.landing {
  position: fixed;
  inset: 0;
  z-index: 90;
  background: var(--violeta-oscuro);
  text-align: center;
  -webkit-mask-image: radial-gradient(circle at var(--cx) var(--cy),
                      transparent 0 var(--agujero), #000 calc(var(--agujero) + 1px));
          mask-image: radial-gradient(circle at var(--cx) var(--cy),
                      transparent 0 var(--agujero), #000 calc(var(--agujero) + 1px));
  transition: visibility 0s linear var(--t-largo);
}

/* Una vez que empieza a abrirse, el landing deja de atender el mouse. La
   máscara lo vuelve invisible pero NO le saca los clics: sigue siendo una caja
   a pantalla completa por encima de todo, y se comía lo que hubiera debajo.
   Antes no pasaba porque se iba de la pantalla; ahora se queda en su sitio. */
body.intro-vista .landing { pointer-events: none; }

/* El filo de la apertura. Sin esto el corte entre el landing y el sitio es
   casi invisible —los dos son del mismo violeta— y la apertura no se lee. */
.landing__aro {
  position: fixed;
  left: var(--cx);
  top: var(--cy);
  width: calc(var(--agujero) * 2);
  height: calc(var(--agujero) * 2);
  transform: translate(-50%, -50%);
  border: 2px solid var(--naranja-principal);
  border-radius: 50%;
  box-shadow: 0 0 22px rgba(244, 96, 54, 0.35);
  pointer-events: none;
  z-index: 95;
  opacity: 0;
  visibility: hidden;
}
body.intro-vista .landing__aro {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.18s ease;
}
/* Y se apaga recién cuando el círculo terminó de abrirse. */
body.en-sitio .landing__aro {
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--t-medio) ease var(--t-largo),
              visibility 0s linear calc(var(--t-largo) + var(--t-medio));
}
/* El landing sale ni bien arranca la apertura: hay que ver la escena de
   atrás, que es donde el rectángulo empieza a subir.

   La clase es propia y no se saca nunca. Colgada de los estados del recorrido,
   entre que se quita uno y se pone el otro queda un hueco de unas décimas en
   el que el landing vuelve a bajar: tapa la pantalla entera y la
   transformación del rectángulo se ve cortada en dos, como un salto. */
/* Y una vez abierto del todo, se saca de en medio para siempre. */
body.en-sitio .landing { visibility: hidden; }

/* La estela del cursor, contra el fondo del landing. El lienzo se calcula a
   media resolución y se estira: es puro difuminado, no se nota, y sale a la
   mitad de precio. */
.landing__estela {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 0;
  pointer-events: none;
}

.landing__marca,
.landing__logo,
.landing__bajada,
.landing__pista { z-index: 1; }

.landing__marca,
.landing__logo,
.landing__bajada {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  width: max-content;
  max-width: 92vw;
}
/* Jenson viene en una sola cara, de peso 300; Thermal es variable de 100 a 900. */
.landing__marca, .landing__logo { font-weight: 300; }
.landing__bajada { font-weight: 300; }

.landing__marca {   /* REVISTA — 48px, y=185 */
  top: 17.13%;
  font-family: var(--marca);
  font-size: clamp(20px, 2.5vw, 48px);
  line-height: 1.2;
}
.landing__logo {    /* FUGA — 264px, y=352 */
  top: 32.59%;
  font-family: var(--marca);
  font-size: clamp(88px, 13.75vw, 264px);
  line-height: 1.2;
}
.landing__bajada {  /* bajada — 24px, y=669 */
  top: 61.94%;
  font-family: var(--thermal);
  font-size: var(--t-24);
  line-height: 1.25;
}

.landing__pista {
  position: absolute;
  bottom: 5%;
  left: 50%;
  transform: translateX(-50%);
  font-size: 13px;
  letter-spacing: 0.08em;
  color: var(--gris-2);
  animation: respira 3.4s ease-in-out infinite;
  transition: opacity var(--t-corto) ease;
}
@keyframes respira { 0%, 100% { opacity: 0.35; } 50% { opacity: 0.9; } }
@media (prefers-reduced-motion: reduce) { .landing__pista { animation: none; } }

/* =========================================================================
   EL CURSOR
   Un círculo naranja en lugar de la flecha. Si se lo agita, crece un poco y
   se enciende en amarillo: la energía sube con el movimiento y se apaga sola.
   Solo donde hay un puntero de verdad; en pantallas táctiles no aparece.
   ========================================================================= */

.cursor { display: none; }

@media (hover: hover) and (pointer: fine) {
  html.con-cursor,
  html.con-cursor * { cursor: none; }
  /* Menos donde hace falta ver dónde se escribe. */
  html.con-cursor input,
  html.con-cursor textarea { cursor: text; }

  /* La nube de partículas de js/cursor.js: es el cursor del umbral. Cuando
     el landing se abre le deja el lugar al círculo, y al revés. */
  .cursor-canvas {
    position: fixed;
    inset: 0;
    z-index: 210;
    pointer-events: none;
    transition: opacity var(--t-medio) var(--ease);
  }
  /* El relevo va con el gesto de apertura: la nube espera a juntarse en el
     punto antes de irse y el círculo entra detrás. */
  body.intro-vista .cursor-canvas {
    opacity: 0;
    transition: opacity var(--t-medio) ease var(--t-medio);
  }
  /* El círculo espera solo donde hay umbral, o sea en el inicio: en el resto
     de las páginas no hay landing que abrir y tiene que estar desde el vamos.
     La clase la pone js/fuga.js cuando encuentra el landing. */
  body.con-umbral:not(.intro-vista) .cursor,
  .cursor.cursor--fuera { opacity: 0; }
  /* Salvo que no haya umbral que esperar: ahí el círculo está desde el vamos
     y la nube del landing no llega a dibujarse. */
  html.sin-umbral .cursor { opacity: 1; }
  html.sin-umbral .cursor-canvas { display: none; }

  /* Con la foto del circuito a la vista, el círculo sobra: la foto ya es el
     cursor —sigue al mouse y dice dónde está—, y dos cosas persiguiendo al
     puntero se estorban. Va después de la regla de arriba a propósito: las dos
     pesan igual y acá gana la última.

     En la página que tiene foto al cursor el círculo se desvanece en --t-corto
     y no en --t-medio: es el mismo tiempo que usa .fotocursor, así los dos se
     cruzan parejo en vez de quedar medio segundo encimados. La regla va sobre
     `html.con-foto-cursor` —que se pone una sola vez al armar la página— para
     que valga también a la vuelta, cuando `foto-al-cursor` ya se sacó. */
  html.con-foto-cursor .cursor { transition: opacity var(--t-corto) ease; }
  html.foto-al-cursor .cursor { opacity: 0; }
  body.con-umbral.intro-vista .cursor { transition: opacity var(--t-medio) var(--ease) var(--t-largo); }

  .cursor {
    display: block;
    position: fixed;
    top: 0;
    left: 0;
    z-index: 200;
    width: var(--bola, 14px);
    aspect-ratio: 1;
    margin: calc(var(--bola, 14px) / -2);
    border-radius: 50%;
    /* El borde está siempre, transparente: así el paso de relleno a trazo es
       un cambio de color y no un cambio de caja, que no se puede animar. */
    border: 1.5px solid transparent;
    background-color: color-mix(in oklab,
                      var(--amarillo-principal) calc(var(--energia, 0) * 100%),
                      var(--naranja-principal));
    translate: var(--x, -100px) var(--y, -100px);
    pointer-events: none;
    will-change: translate;
    transition: opacity var(--t-medio) var(--ease),
                background-color var(--t-corto) ease,
                border-color var(--t-corto) ease;
  }

  /* Sobre algo que se puede tocar: se vacía, se enciende en amarillo y late.
     El latido va en `scale`, que no toca ni el translate de la posición ni el
     ancho que maneja la energía. */
  .cursor--liga {
    background-color: transparent;
    border-color: var(--amarillo-principal);
    animation: cursor-pulso 1.15s ease-in-out infinite;
  }

  @keyframes cursor-pulso {
    0%, 100% { scale: 1; }
    50%      { scale: 1.16; }
  }

  /* Haciendo de loader no late: el latido y el crecimiento a la vez se leen
     como dos cosas distintas pasando encima. */
  .cursor--cargando { animation: none; }

  @media (prefers-reduced-motion: reduce) {
    .cursor--liga { animation: none; }
  }
}


/* =========================================================================
   PANTALLAS
   El scroll es el nativo del navegador, con anclaje por pantalla: capturar
   la rueda a mano pelea con el momentum del trackpad.
   ========================================================================= */

.sitio { scroll-snap-type: y mandatory; }

.pantalla {
  position: relative;
  min-height: var(--pantalla);
  scroll-snap-align: start;
  scroll-snap-stop: always;
  overflow: hidden;
}

/* Título grande de manifiesto — Thermal Display 64px */
.enunciado {
  position: absolute;
  font-family: var(--thermal);
  font-weight: 300;
  font-size: var(--t-64);
  line-height: 1;
  color: var(--naranja-principal);
}

/* Texto corrido — Thermal Text 24px */
.texto {
  position: absolute;
  font-size: var(--t-24);
  line-height: 1.35;
  color: var(--blanco-1);
}

/* ---------- Pantalla 1 (748:26) ---------- */

.p1__enunciado { left: 12.240%; top: 40.370%; width: 52.188%; transform: translateY(-50%); }
.p1__texto     { left: 58.490%; top: 52.315%; width: 30.313%; }

/* ---------- Pantallas 2 a 5 (748:48, 748:60, 748:71, 748:84) ----------
   Comparten el texto en x=841; el rectángulo lo dibuja js/fuga.js, que es
   quien lo lleva de una forma a la otra. */

.p2__texto, .p3__texto, .p4__texto, .p5__texto { left: 43.802%; top: 34.444%; }
.p2__texto, .p3__texto { width: 30.313%; }   /* 582 */
.p4__texto, .p5__texto { width: 31.250%; }   /* 600 */

/* ---------- Pantalla 6 (748:125) — el cierre ----------
   Acá el texto no es blanco: el cierre habla en naranja, como los enunciados. */

/* Sin left/top/width propios: acá los pone la grilla de #bienvenida, unas
   líneas más abajo. Lo único que esta pantalla no comparte con las otras es el
   color. */
.p6__texto { color: var(--naranja-principal); }

/* Y el saludo se sale del párrafo y se dice en grande, en el cuerpo de los
   enunciados: es el punto final del manifiesto, no un renglón más del mismo
   bloque. Va alineado a la derecha contra el mismo borde donde termina el
   párrafo —x = 1294— y arranca justo donde el párrafo termina, sin aire de por
   medio: las dos cosas son una sola frase dicha en dos tonos. En el frame
   arranca en 492, pegado al pie del párrafo; la relación que hay que respetar
   es esa y no el número.

   Y por eso esta pantalla es la única que no cuelga sus dos piezas de un `top`
   propio. Un `top` fijo mide en alto de pantalla; el párrafo, en cambio, crece
   con el ancho, porque de ahí salen su cuerpo de letra y su cantidad de
   renglones. Las dos medidas son independientes, así que en cuanto la ventana
   se hace ancha y baja (1920 × 860, 2200 × 900) el párrafo pasa de largo el
   punto donde empieza el saludo y se le monta encima: 26 píxeles de más en un
   caso, 21 en el otro.

   La grilla ata una cosa a la otra. La primera fila es aire —34.444% del alto,
   el mismo y = 372 de siempre— y la primera columna también —34.844% del
   ancho, x = 669—; las dos piezas van en la segunda columna, una abajo de la
   otra. El saludo ya no declara dónde empieza: empieza donde el párrafo
   termina, tenga los renglones que tenga. Al ras, nunca encima. */
#bienvenida {
  display: grid;
  grid-template-columns: 34.844% 32.552%;   /* x = 669, ancho 625 */
  grid-template-rows: 34.444% auto;         /* y = 372 */
  align-content: start;
}
#bienvenida > * {
  position: static;
  grid-column: 2;
}
.p6__texto { grid-row: 2; }    /* la fila 1 es el aire de arriba */

.p6__cierre {
  grid-row: 3;
  text-align: right;
  line-height: 1.27;           /* 64 × 1.27 = 81, el alto del renglón del frame */
}

/* Índice del manifiesto — el activo en amarillo y grande, el resto listado.

   En los frames los cuatro ítems caen en 372, 412, 452, 492 y 532: o sea
   una columna que arranca en 372, con ítems de 30px y 10px de separación.
   El activo mide 70px y corre a los que siguen. Eso es exactamente una
   columna en flujo, así que va así y no con posiciones sueltas: el mismo
   marcado sirve para las cuatro pantallas cambiando cuál lleva .activo. */
.indice {
  position: absolute;
  left: 12.240%;               /* x = 235 */
  top: 34.444%;                /* y = 372 */
  display: flex;
  flex-direction: column;
  gap: clamp(4px, 0.5208vw, 10px);
  align-items: flex-start;
}
/* El ítem no se enciende de golpe al llegar: crece y se tiñe a medida que el
   scroll se le acerca. `--cerca` va de 0 a 1 y lo escribe js/fuga.js; entre
   los dos extremos están exactamente los valores del Figma, 24 → 64 y
   1.25 → 1.1 de interlínea, o sea 30 → 70 de alto. */
.indice { --final: 0; }
.indice a {
  --cerca: 0;
  font-size: calc(var(--t-24) + (var(--t-64) - var(--t-24)) * var(--cerca));
  line-height: calc(1.25 - 0.15 * var(--cerca));
  /* Amarillo por dos motivos distintos: porque el scroll se le acerca
     (--cerca) o porque llegó la última pantalla, donde se encienden todos sin
     que ninguno crezca (--final). Gana el que esté más alto. */
  color: color-mix(in oklab,
                   var(--amarillo-principal) calc(max(var(--cerca), var(--final)) * 100%),
                   var(--gris-2));
  white-space: nowrap;
  cursor: pointer;
}
.indice a:active {
  color: color-mix(in oklab,
                   var(--amarillo-principal) calc(max(var(--cerca), var(--final)) * 100%),
                   var(--blanco-1));
}

/* =========================================================================
   EL MANIFIESTO — una escena quieta que avanza por pasos

   La página no scrollea. Cada gesto —un diente de rueda, un swipe, una
   flecha— vale una pantalla entera, y la animación la hace el sitio de
   corrido: así nadie queda varado en un intermedio donde no se lee nada.
   Una plana por pantalla del Figma, todas superpuestas, y el paso decide
   cuánto se ve cada una y dónde está el rectángulo.
   ========================================================================= */

/* Con la escena en pantalla, el documento no tiene a dónde ir: el avance lo
   maneja js/fuga.js, no la barra de scroll. */
body.sin-scroll { overflow: hidden; height: 100%; }

.escena {
  position: relative;
  height: var(--pantalla);
  overflow: hidden;
}

/* El lienzo del rectángulo texturado. Cubre la pantalla entera y de ahí no
   se mueve: lo que cambia es la figura de adentro. La caja fija es lo que
   permite que el filtro se recalcule en cada tamaño en vez de estirarse. */
.lienzo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;
}

/* Cada plana ocupa la escena entera; adentro, cada pieza conserva la
   posición que tiene en su frame. Entran y salen en vertical: la que se va
   sube, la que viene llega desde abajo.

   La plana no atiende el mouse: es una caja a pantalla completa y, como va
   después en el marcado, tapaba el índice y se comía sus clics. Lo que sí
   atiende es su texto, para poder seleccionarlo. */
.plana {
  position: absolute;
  inset: 0;
  opacity: var(--op, 0);
  translate: 0 var(--dy, 0px);
  will-change: opacity, translate;
  pointer-events: none;
}
.plana .enunciado,
.plana .texto { pointer-events: auto; }

/* Dentro de una plana, cada pieza tiene su propio turno para aparecer: al
   llegar a la pantalla, primero se acomoda el rectángulo, después entra el
   enunciado y al final el párrafo. --opp lo escribe js/fuga.js. */
.plana > * { opacity: var(--opp, 1); }

/* Y el índice va arriba de todo, que es con lo único que se interactúa. */
.indice {
  opacity: var(--op, 0);
  z-index: 2;
}

@media (prefers-reduced-motion: reduce) {
  .plana, .indice { transition: none; }
}

/* Las secciones que todavía no existen. No es una marca de trabajo como la de
   abajo: esto lo lee el visitante, así que va en el gris de servicio del
   sitio —el mismo del nav en reposo— y centrado, sin nada alrededor. */
.proximamente {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  font-size: var(--t-32);
  line-height: 1;
  color: var(--gris-2);
  white-space: nowrap;
}

/* Marca de trabajo: pantalla todavía sin implementar desde Figma. */
.pendiente {
  position: absolute;
  left: var(--margen);
  top: 45%;
  max-width: 52ch;
  border: 1px dashed rgba(229, 218, 218, 0.22);
  padding: 18px;
  font-size: 13px;
  color: var(--gris-2);
}

/* =========================================================================
   CONSEGUILA — frames 748:11 y 757:39

   Los dos frames son la misma escena en dos momentos, no dos pantallas: la
   tapa está en el centro en uno y contra la izquierda en el otro, a la misma
   altura. Así que acá hay UNA pantalla con dos pasos, y el pasaje es el
   viaje que el propio diseño describe: la tapa, el encabezado y el precio
   corren en horizontal, y el formulario entra desde la derecha. Un solo eje.

   Al formulario se llega por el botón, nunca scrolleando.

   El fondo es el del sitio; lo violeta es el rectángulo, no la página, y ese
   rectángulo es el mismo que viene viajando desde el inicio.
   ========================================================================= */

/* El fondo es el del sitio; lo violeta es el rectángulo, no la página.
   Antes estaba al revés y por eso no había nada que pudiera transformarse. */
/* Lo de adentro se recorta contra la figura: cuando el
   rectángulo se cierra o cambia de sitio, el contenido se barre con él en vez
   de quedar flotando por fuera. Las cuatro medidas las escribe js/fuga.js en
   cada cuadro con la forma que tiene la figura en ese momento. */
.conseguila__dentro {
  /* El ancho de la portada, con nombre, porque no es solo suyo: el encabezado
     y el precio arrancan en su borde izquierdo y RESERVAR termina en el
     derecho. Antes cada uno lo tenía escrito a mano como porcentaje del ancho
     de la ventana, y eso solo coincidía a 1920: la portada se mide también
     contra el alto —para no pisar el precio en una ventana baja— así que en
     cuanto la pantalla se hacía ancha o baja ella encogía y los tres textos se
     quedaban donde estaban. A 2560 se iban 55 píxeles, a 3440 setenta y seis.
     Leyéndolo de acá, se mueven con ella. */
  --tapa-ancho: min(17.1875%, 30.5501svh);

  position: absolute;
  inset: 0;
  clip-path: inset(var(--rec-t, 0%) var(--rec-r, 0%) var(--rec-b, 0%) var(--rec-l, 0%));
}

.conseguila {
  background: var(--violeta-oscuro);
  /* Cuánto espera el contenido a que el rectángulo termine de acomodarse. Lo
     pone js/fuga.js: si la figura llega ya en su forma no hay nada que
     esperar, y si viene viajando desde otra página, sí. */
  --espera: 0ms;
}

/* --- Lo que viaja: encabezado, tapa y precio ---
   La posición base es la del frame 1 y el paso 2 solo cambia `left`. Se
   anima `left` y no `transform` porque transform ya está ocupado centrando
   cada pieza sobre su punto; son cuatro cajas absolutas, el costo es nulo. */

/* Ojo con esta regla: declarar `transition` acá pisa entera la del sistema de
   entrada, que es anterior en la hoja. Si solo dijera `left`, estas tres
   piezas aparecerían de golpe en vez de entrar: hay que repetir acá la
   opacidad y el desplazamiento, cada uno con su retardo. `left` va sin
   retardo, que es el viaje y arranca de una. */
.ficha__encabezado,
.ficha__tapa,
.ficha__precio {
  /* `left` es transformación —la tapa cambia de sitio, no entra ni sale— así
     que va con --muta. La opacidad y el desplazamiento sí son entrada. */
  transition: left var(--t-largo) var(--muta),
              opacity var(--t-medio) var(--entra) var(--retardo, 0ms),
              translate var(--t-medio) var(--entra) var(--retardo, 0ms);
}

/* El título y la portada son botones: abren el formulario. Hay que apagarles
   lo que el navegador les pone por ser botones —fondo, borde, relleno— y
   dejarles solo lo del diseño. */
.ficha__abre {
  padding: 0;
  border: 0;
  background: transparent;
  font: inherit;
  cursor: pointer;
}
.ficha__abre:disabled { cursor: default; }   /* ya abierto: no hay nada que abrir */
.ficha__abre:focus-visible { outline: 2px solid var(--amarillo-principal); outline-offset: 6px; }

/* Se encienden los dos a la vez, esté el mouse donde esté: son la misma
   acción, y encender solo la mitad los haría parecer dos cosas. */
.conseguila__dentro:has(.ficha__tapa:active) .ficha__encabezado,
.ficha__encabezado:active { color: var(--amarillo-principal); }

.conseguila__dentro:has(.ficha__encabezado:active) .ficha__tapa,
.ficha__tapa:active { border-color: var(--amarillo-principal); }

.ficha__encabezado {
  position: absolute;
  left: calc(50% - var(--tapa-ancho) / 2);   /* el borde izquierdo de la portada */
  top: 24.4444%;               /* y = 264 (centro) */
  transform: translateY(-50%);
  display: flex;
  align-items: baseline;
  /* Un espacio fijo entre el número y el nombre: si dependiera del cuerpo, el
     conjunto mediría distinto en cada tamaño de ventana. */
  gap: clamp(6px, 0.7292vw, 14px);
  font-family: var(--thermal);
  font-weight: 300;
  font-size: var(--t-24);
  line-height: 1;
  color: var(--blanco-1);
  white-space: nowrap;
  transition: left var(--t-largo) var(--muta),
              opacity var(--t-medio) var(--entra) var(--retardo, 0ms),
              translate var(--t-medio) var(--entra) var(--retardo, 0ms),
              color var(--t-corto) ease;
}

/* La tapa se mide por los dos ejes a la vez: 330 de ancho son 17.1875 % del
   ancho, pero 443 de alto son 41.02 % del alto. Tomando el menor de los dos
   nunca se estira hasta pisar el precio en una ventana baja y ancha. */
.ficha__tapa {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: var(--tapa-ancho);
  aspect-ratio: 330 / 443;
  border: 2px solid var(--blanco-1);
  background: var(--violeta-oscuro);
  display: block;
  transition: left var(--t-largo) var(--muta),
              opacity var(--t-medio) var(--entra) var(--retardo, 0ms),
              translate var(--t-medio) var(--entra) var(--retardo, 0ms),
              border-color var(--t-corto) ease;
}
.ficha__tapa img { width: 100%; height: 100%; object-fit: cover; display: block; }

.ficha__precio {
  position: absolute;
  left: calc(50% - var(--tapa-ancho) / 2);   /* el borde izquierdo de la portada */
  top: 74.2593%;               /* y = 802 */
  font-size: var(--t-24);
  color: var(--blanco-1);
}

/* --- Las piezas del paso 2 ---
   Todas esperan fuera del borde derecho y entran juntas, en horizontal. */

/* Entrar y salir no son el mismo gesto, y por eso usan propiedades
   distintas:

   · ENTRAR es un acento corto: el formulario asoma 40px desde la derecha
     mientras aparece. Eso vive en `translate`.
   · SALIR es un viaje: la tapa vuelve al centro y el formulario tiene que
     despejarle el camino a la par, o se cruzan. Eso vive en `transform`, y
     mide exactamente lo que recorre la tapa (de left 25.1563% a 50% son
     24.8437% del ancho). Misma distancia, misma curva y misma duración que
     ella: se mueven en paralelo y la separación nunca se achica.

   Al entrar, `transform` vuelve a cero en 0s: el salto ocurre con el
   formulario todavía invisible, así que no se ve. */
.compra,
.novedades,
.compra__cantidad,
.compra__confirmar,
.compra__aviso {
  opacity: 0;
  visibility: hidden;
  translate: 40px 0;
  transform: translateX(24.8437vw);
  transition: opacity var(--t-largo) var(--sale),
              translate var(--t-largo) var(--sale),
              transform var(--t-largo) var(--sale),
              visibility 0s linear var(--t-largo);
}

.paso-formulario .compra,
.paso-formulario .novedades,
.paso-formulario .compra__cantidad,
.paso-formulario .compra__confirmar,
.paso-formulario .compra__aviso {
  opacity: 1;
  visibility: visible;
  translate: none;
  transform: none;
  transition: opacity var(--t-medio) var(--entra) var(--t-corto),
              translate var(--t-medio) var(--entra) var(--t-corto),
              transform 0s,
              visibility 0s linear var(--t-corto);
}

/* El volver queda abajo a la izquierda, fuera del camino de la tapa: no
   necesita viajar, solo aparecer al final y apagarse. */
.ficha__volver {
  opacity: 0;
  visibility: hidden;
  translate: 40px 0;
  transition: opacity var(--t-medio) var(--sale),
              translate var(--t-medio) var(--sale),
              visibility 0s linear var(--t-medio);
}
.paso-formulario .ficha__volver {
  opacity: 1;
  visibility: visible;
  translate: none;
  transition: opacity var(--t-medio) var(--entra) var(--t-medio),
              translate var(--t-medio) var(--entra) var(--t-medio),
              visibility 0s linear var(--t-medio);
}

/* Paso 2: lo que viajó llega a su lugar. */
.paso-formulario .ficha__encabezado { left: calc(25.1563% - var(--tapa-ancho) / 2); }   /* el borde de la portada */
.paso-formulario .ficha__tapa       { left: 25.1563%; }   /* x = 483   */
.paso-formulario .ficha__precio     { left: calc(25.1563% - var(--tapa-ancho) / 2); }



/* La vuelta a la ficha. No está en el frame: va con el criterio del sitio,
   en el gris de servicio, alineada con la columna de la tapa y el precio. */
.ficha__volver {
  position: absolute;
  left: calc(25.1563% - var(--tapa-ancho) / 2);   /* la columna de la portada */
  top: 81.4815%;               /* y = 880 */
  display: flex;
  align-items: center;
  gap: clamp(5px, 0.4167vw, 8px);
  padding: 0;
  border: 0;
  background: transparent;
  font-family: var(--thermal);
  font-weight: 300;
  font-size: var(--t-18);
  color: var(--gris-2);
  cursor: pointer;
}
.ficha__volver:active { color: var(--blanco-1); }
.ficha__volver:focus-visible { outline: 2px solid var(--amarillo-principal); outline-offset: 4px; }
/* La misma flecha del sitio: mira hacia abajo, así que gira para mirar
   hacia la izquierda. Al girar, los 9 de ancho pasan a ser el alto. */
.ficha__volver svg {
  display: block;
  width: clamp(7px, 0.4688vw, 9px);
  aspect-ratio: 18 / 12;
  rotate: 90deg;
}
/* --- El formulario ---
   En el frame los campos caen en filas de 103px, con dos columnas de 385 y
   13 de separación. Eso es una grilla, así que va como grilla: reproduce la
   misma geometría y además se puede apilar en mobile sin rehacer nada. */
/* Recibe el foco al abrirse en el celular, pero es un contenedor y no algo que
   se pulse: no lleva marca. */
.compra:focus { outline: none; }

.compra {
  position: absolute;
  left: 42.0313%;              /* x = 807 */
  top: 29.5370%;               /* y = 319 */
  width: 40.7813%;             /* 783 */
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 0.6771vw;        /* 13px */
  row-gap: clamp(8px, 1.0417vw, 20px);   /* 20px */
}

.campo { display: flex; flex-direction: column; gap: clamp(4px, 0.5208vw, 10px); }

/* Cada campo tiene su casilla fija en la grilla. Es lo que permite esconder
   Zona de retiro sin que Método de pago se corra a ocupar su lugar. */
.compra .campo:nth-of-type(1) { grid-area: 1 / 1; }
.compra .campo:nth-of-type(2) { grid-area: 1 / 2; }
.compra .campo:nth-of-type(3) { grid-area: 2 / 1; }
.compra .campo:nth-of-type(4) { grid-area: 2 / 2; }
.compra .campo:nth-of-type(5) { grid-area: 3 / 1; }
.compra .campo:nth-of-type(6) { grid-area: 3 / 2; }

.campo[hidden] { display: none; }

/* La aclaración del asterisco de "Envío a domicilio*". Ocupa la casilla 3/1,
   la misma que Zona de retiro: una aparece exactamente cuando la otra se va,
   así que nunca se pisan y no hay que mover nada de sitio.

   Apoyada abajo, al pie de la columna: así queda al ras de la caja de Método
   de pago que tiene al lado en vez de flotar en el medio del renglón. */
.compra__nota {
  grid-area: 3 / 1;
  align-self: end;
  font-size: var(--t-18);
  line-height: 1.3;
  color: var(--blanco-1);
}
.compra__nota[hidden] { display: none; }

/* Al aparecer no se planta de golpe: entra como el resto del sitio. */
.campo--asoma { animation: campo-asoma var(--t-corto) var(--entra); }
@keyframes campo-asoma {
  from { opacity: 0; translate: 0 10px; }
}
@media (prefers-reduced-motion: reduce) {
  .campo--asoma { animation: none; }
}

.campo > span {
  font-size: var(--t-18);
  color: var(--gris-2);
}

.campo input,
.campo select {
  font-family: var(--thermal);
  font-weight: 300;
  font-size: var(--t-24);
  color: var(--blanco-1);
  background-color: transparent;
  border: 1px solid var(--gris-2);
  border-radius: 0;
  height: clamp(38px, 2.6042vw, 50px);     /* 50px */
  padding: 0 clamp(6px, 0.5208vw, 10px);   /* el valor arranca 10px adentro */
  width: 100%;
  appearance: none;
  transition: border-color var(--t-corto) ease,
              background-color var(--t-corto) ease;
}
/* Un campo resuelto se pinta. Es la señal de qué falta: mirando el formulario
   de un vistazo se ve cuántas cajas siguen vacías, y para confirmar tienen que
   estar todas pintadas. La clase la pone js/fuga.js cuando el campo tiene
   contenido y además es válido —un correo a medio escribir no cuenta— y recién
   al salir de él, no mientras se tipea. */
.campo input.completo,
.campo select.completo { background-color: var(--violeta-claro); }

.campo input::placeholder { color: var(--blanco-1); opacity: 0.55; }
.campo input:focus,
.campo select:focus { outline: none; border-color: var(--blanco-1); }
.campo select { cursor: pointer; }
.campo select option { background: var(--violeta-principal); color: var(--blanco-1); }

/* Acepto recibir novedades. El cuadro son 20 y la marca de adentro 12,
   centrada; el texto arranca a 31 del borde, como en el frame. */
.novedades {
  position: absolute;
  left: 42.0313%;              /* x = 807 */
  top: 60.7407%;               /* y = 656 */
  display: flex;
  align-items: center;
  gap: clamp(6px, 0.5729vw, 11px);
  font-size: var(--t-18);
  color: var(--blanco-1);
  cursor: pointer;
}
.novedades input { position: absolute; opacity: 0; pointer-events: none; }
.novedades::before {
  content: "";
  width: clamp(14px, 1.0417vw, 20px);
  aspect-ratio: 1;
  border: 1px solid var(--blanco-1);
  transition: background var(--t-corto) ease, box-shadow var(--t-corto) ease;
}
.novedades:has(input:checked)::before {
  background: var(--blanco-1);
  box-shadow: inset 0 0 0 4px var(--violeta-principal);
}
.novedades:has(input:focus-visible)::before { outline: 2px solid var(--amarillo-principal); outline-offset: 2px; }

/* Fila de abajo: cantidad y confirmar, a la altura del precio (y = 802). */
.compra__cantidad,
.compra__confirmar {
  position: absolute;
  top: 74.2593%;
  font-size: var(--t-24);
  color: var(--blanco-1);
}
/* Anclada por la derecha y no por la izquierda: lo que tiene que quedar fijo
   es dónde termina —en x = 648, el borde derecho de la portada—, y así el
   número puede crecer a dos dígitos sin pasarse de esa línea. */
.compra__cantidad {
  left: auto;
  /* Termina donde termina la portada. La portada en este paso está centrada en
     25.1563 % y se mide con --tapa-ancho, así que su borde derecho es
     25.1563 % + mitad del ancho; el `right` es lo que sobra hasta el borde de
     la ventana. Antes era un 66.25 % clavado, que es la cuenta hecha a mano
     para una portada de 330: coincidía solo a 1920 y en cuanto ella encogía,
     el renglón se le escapaba por la derecha. */
  right: calc(100% - 25.1563% - var(--tapa-ancho) / 2);
  display: flex;
  align-items: baseline;
  /* 20 px, que es lo que separa la palabra del número en el frame. Estaba en
     60 y quedaba un hueco raro en el medio. */
  gap: clamp(10px, 1.0417vw, 20px);
}

.compra__cantidad input {
  /* El subrayado del frame mide 20, que alcanza para un dígito y no para dos:
     con "20" el texto se salía de la caja y el navegador lo cortaba —y encima
     solo al perder el foco, porque mientras escribís el campo se desplaza para
     mostrar el final.

     La medida va en `ch` —el ancho de un dígito en esta tipografía— y no en px:
     así sigue al cuerpo de letra, que es un clamp y cambia con la ventana, y
     dos dígitos entran siempre. Los 6 de más son el aire a los costados. */
  width: calc(2ch + 6px);
  font-family: inherit;
  font-size: inherit;
  color: inherit;
  background: transparent;
  border: 0;
  border-bottom: 1px solid currentColor;
  border-radius: 0;
  text-align: center;
  padding: 0 0 4px;
  appearance: textfield;
  -moz-appearance: textfield;
}
.compra__cantidad input::-webkit-outer-spin-button,
.compra__cantidad input::-webkit-inner-spin-button { appearance: none; margin: 0; }


/* Con el rectángulo más bajo, el aviso ya no entra abajo a la derecha: el
   frame lo pone dentro de la columna del formulario, alineado a la izquierda. */
.compra__aviso {
  position: absolute;
  left: 42.0313%;              /* x = 807, la columna del formulario */
  right: auto;
  top: 66.2963%;               /* y = 716 */
  width: 23.125%;              /* 444 */
  text-align: left;
  font-size: var(--t-18);
  line-height: 1.3;
  color: var(--blanco-1);
}

/* El campo trampa: fuera de la vista sin usar display:none ni visibility, que
   son justo lo que un robot mira para saltearlo. */
.trampa {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

/* Cuando el envío falla. Va donde está el aviso de siempre y en naranja, que
   en este sitio es el color de lo que hay que leer. */
.compra__error {
  position: absolute;
  left: 42.0313%;
  top: 74.2593%;
  width: 30%;
  font-size: var(--t-18);
  line-height: 1.35;
  color: var(--naranja-principal);
}
.compra__error[hidden] { display: none; }

/* Una vez enviada la reserva, el paso 2 se retira y queda el aviso. */
.conseguila.enviado .compra,
.conseguila.enviado .novedades,
.conseguila.enviado .compra__cantidad,
.conseguila.enviado .compra__confirmar,
.conseguila.enviado .compra__aviso {
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--t-corto) var(--ease),
              visibility 0s linear var(--t-corto);
}

/* Sin JS no hay quién cambie de paso: en ese caso la escena arranca armada
   como el frame 2, con el formulario a la vista, y sobran los dos botones
   que no tendrían a quién avisar. */
html:not(.con-js) .ficha__encabezado { left: calc(25.1563% - var(--tapa-ancho) / 2); }
html:not(.con-js) .ficha__tapa       { left: 25.1563%; }
html:not(.con-js) .ficha__precio     { left: calc(25.1563% - var(--tapa-ancho) / 2); }

html:not(.con-js) .ficha__volver     { display: none; }
html:not(.con-js) .compra,
html:not(.con-js) .novedades,
html:not(.con-js) .compra__cantidad,
html:not(.con-js) .compra__confirmar,
html:not(.con-js) .compra__aviso {
  opacity: 1;
  visibility: visible;
  translate: none;
  transform: none;
  transition: none;
}

/* ---------- el botón del renglón del precio ----------
   Un solo dibujo para los dos: RESERVAR en la ficha y CONFIRMAR en el
   formulario. Es la palabra subrayada y nada más —ni caja ni
   relleno—, y siempre a la altura del precio.

   Va acá abajo a propósito: .ficha__abre le apaga el borde a sus botones para
   dejarlos limpios, así que esto tiene que venir después para devolverle el
   subrayado al que lo lleva. Es el mismo orden del que ya depende .ficha__tapa
   para recuperar su marco. */
.boton-subrayado {
  font-family: var(--thermal);
  font-weight: 300;
  font-size: var(--t-24);
  /* El mismo interlineado del precio: los dos arrancan en el mismo `top`, y
     con la misma caja las dos palabras se apoyan en el mismo renglón. */
  line-height: 1.25;
  color: var(--blanco-1);
  background: transparent;
  border: 0;
  border-bottom: 1px solid currentColor;
  border-radius: 0;
  padding: 0 0 5px;
  letter-spacing: 0.01em;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}
.boton-subrayado:active { color: var(--amarillo-principal); }
.boton-subrayado:focus-visible { outline: 2px solid var(--amarillo-principal); outline-offset: 4px; }

.compra__confirmar {
  right: 17.1875%;             /* borde derecho en x = 1590 */
  left: auto;
}

/* RESERVAR termina donde termina la portada (x = 1125), que es el espejo
   exacto de dónde empieza el precio (x = 795): la portada está centrada, así
   que el renglón queda equilibrado bajo ella. */
.ficha__reservar {
  position: absolute;
  right: calc(50% - var(--tapa-ancho) / 2);  /* el borde derecho de la portada */
  left: auto;
  top: 74.2593%;               /* y = 802, el renglón del precio */
}

/* Al abrirse el formulario, RESERVAR se retira con la portada —que se va a la
   izquierda— y CONFIRMAR toma el renglón por la derecha. */
.conseguila.paso-formulario .ficha__reservar {
  opacity: 0;
  visibility: hidden;
  translate: -40px 0;
  transition: opacity var(--t-corto) var(--sale),
              translate var(--t-corto) var(--sale),
              visibility 0s linear var(--t-corto);
}
/* Sin JS la escena arranca con el formulario a la vista: este botón no
   tendría a quién avisar, igual que el volver. */
html:not(.con-js) .ficha__reservar { display: none; }

/* Mientras se confirma. La pantalla se oscurece apenas y gira un aro amarillo
   incompleto: el hueco es lo que deja ver que está girando, porque un círculo
   entero girando se vería quieto. */
.cargando {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: grid;
  place-items: center;
  background: rgba(24, 12, 26, 0.62);
  opacity: 0;
  transition: opacity var(--t-corto) var(--entra);
}
.cargando[hidden] { display: none; }
.cargando.visible { opacity: 1; }

.cargando svg {
  width: clamp(38px, 3.125vw, 60px);
  aspect-ratio: 1;
  color: var(--amarillo-principal);
  animation: cargando-gira 1s linear infinite;
}

@keyframes cargando-gira {
  to { rotate: 360deg; }
}

/* El texto está para quien no ve el aro: lo lee el lector de pantalla. */
.cargando__texto {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
  .cargando svg { animation-duration: 2.4s; }
}

/* Aviso de que la reserva se envió. */
.compra__gracias {
  position: absolute;
  left: 42.0313%;
  top: 29.5370%;
  width: 40.7813%;
  font-size: var(--t-24);
  line-height: 1.4;
  color: var(--blanco-1);
}

/* =========================================================================
   CONVOCATORIA — frame 748:15

   Dos columnas que arrancan a la misma altura (y = 319) y llegan hasta
   y = 871. En el frame el contenido sigue de largo y se desvanece contra el
   fondo: esos dos rectángulos (171→1749, uno degradado de 144 y otro macizo)
   no son piezas de la página sino la forma de dibujar un corte suave. Acá
   eso es una máscara sobre cada columna, que además las vuelve scrolleables:
   el degradado queda quieto en el borde y avisa que hay más abajo.
   ========================================================================= */

.conv__titulo {
  position: absolute;
  top: 24.3519%;                 /* y = 263 (centro) */
  transform: translateY(-50%);
  margin: 0;
  font-family: var(--thermal);
  font-weight: 300;
  font-size: var(--t-32);
  line-height: 1;
  color: var(--naranja-principal);
  white-space: nowrap;
}
.conv__titulo--bases      { left: 17.1875%; }    /* x = 330 */
.conv__titulo--requisitos { left: 50.3125%; }    /* x = 966 */

.conv__columna {
  position: absolute;
  top: 29.5370%;                 /* y = 319 */
  height: 51.1111%;              /* 552 → termina en y = 871 */
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: none;
  font-size: var(--t-18);
  line-height: 1.3;
  color: var(--blanco-1);

  /* El desvanecido del frame: 144 de los 552 → el último 26 %. */
  -webkit-mask-image: linear-gradient(to bottom, #000 73.913%, transparent 100%);
          mask-image: linear-gradient(to bottom, #000 73.913%, transparent 100%);
}
.conv__columna::-webkit-scrollbar { width: 0; height: 0; }

.conv__columna--bases      { left: 16.5625%;  width: 29.5833%; }   /* x = 318, 568 */
.conv__columna--requisitos { left: 50.1563%;  width: 30.8854%; }   /* x = 963, 593 */

/* Aire después del último renglón. Sin esto el final del texto no puede
   subir más allá del pie de la columna (y = 871) y queda siempre debajo del
   degradado, que arranca en y = 727: leíble a medias y sin forma de
   rescatarlo. Con este colchón el scroll llega hasta dejar la última línea
   a mitad de pantalla (y = 540), bien afuera de la sombra.
       871 − 540 = 331 → 30.6481 svh
   Va en el hijo y no en la columna: el padding de abajo de un contenedor con
   scroll no es terreno firme en todos los navegadores. */
.bases,
.requisitos { padding-bottom: 30.6481svh; }

/* --- Las bases: una lista numerada, con el número colgando afuera --- */

.bases {
  margin: 0;
  padding-left: clamp(16px, 1.4063vw, 27px);   /* el texto arranca en x = 345 */
  list-style: decimal;
}
.bases li { margin-bottom: clamp(7px, 0.625vw, 12px); }
.bases li:last-child { margin-bottom: 0; }
.bases li::marker { color: var(--blanco-1); }

/* --- Los requisitos: acordeón de categorías ---
   La flecha ocupa una columna de 18 (lo que mide acostada) y el texto
   arranca 7 después, o sea en x = 988, igual que en el frame. */

.requisito + .requisito { margin-top: clamp(17px, 1.5625vw, 30px); }

.requisito__titulo {
  display: grid;
  grid-template-columns: clamp(11px, 0.9375vw, 18px) 1fr;
  align-items: center;
  column-gap: clamp(4px, 0.3646vw, 7px);
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  font-family: var(--thermal);
  font-weight: 700;
  font-size: var(--t-18);
  line-height: 1.28;             /* 18 × 1.28 = 23, el alto del título */
  color: var(--blanco-1);
  text-align: left;
  cursor: pointer;
  transition: color var(--t-corto) ease;
}
.requisito__titulo:active { color: var(--amarillo-principal); }
.requisito__titulo:focus-visible { outline: 2px solid var(--amarillo-principal); outline-offset: 4px; }

/* La flecha gira en lugar de cambiar de dibujo: es el mismo vector del
   frame, apuntando a la derecha cerrado y hacia abajo abierto. */
.requisito__flecha {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  aspect-ratio: 1;               /* 18 × 18: lo que ocupa el dibujo en los dos giros */
  color: var(--blanco-1);
  rotate: -90deg;                /* cerrada: el dibujo, que mira hacia abajo, mira a la derecha */
  transition: rotate var(--t-corto) var(--muta);
}
.requisito__flecha svg { display: block; width: 100%; aspect-ratio: 18 / 12; }
.requisito.abierto > .requisito__titulo .requisito__flecha { rotate: 0deg; }

/* El cuerpo se abre midiendo de verdad: 0fr → 1fr es lo único que anima
   una altura desconocida sin medirla a mano desde JS. */
.requisito__cuerpo {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--t-corto) var(--muta);
}
.requisito.abierto > .requisito__cuerpo { grid-template-rows: 1fr; }

/* El borde por el que asoma el texto es un recorte al ras, y mientras dura
   la apertura se lee como un barrido. Así que el recorte lleva su propio
   velo: un degradado en los últimos píxeles, igual que el de la columna, que
   se retira a medida que el desplegable termina de abrirse.

   `--velo` se registra para que el navegador la trate como una longitud y
   pueda interpolarla; si no, saltaría de un valor al otro y el degradado no
   acompañaría el movimiento. */
@property --velo {
  syntax: '<length>';
  inherits: false;
  initial-value: 0px;
}

.requisito__cuerpo > div {
  overflow: hidden;
  --velo: clamp(26px, 2.9167vw, 56px);
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - var(--velo)), transparent 100%);
          mask-image: linear-gradient(to bottom, #000 calc(100% - var(--velo)), transparent 100%);
  transition: --velo var(--t-corto) var(--muta);
}
.requisito.abierto > .requisito__cuerpo > div { --velo: 0px; }

.requisito__cuerpo p { padding-top: clamp(6px, 0.5208vw, 10px); }
.requisito__cuerpo p + p { padding-top: clamp(7px, 0.625vw, 12px); }
.requisito__cantidad { color: var(--blanco-1); }

/* Sin JS no hay quién abra nada: en ese caso queda todo desplegado. */
html:not(.con-js) .requisito__cuerpo { grid-template-rows: 1fr; }
html:not(.con-js) .requisito__flecha { rotate: 0deg; }

/* --- El pie de la convocatoria ---
   Va anclado abajo y no arriba, en el mismo renglón que Contacto y FUGA:
   mismo `bottom` y mismo cuerpo que Contacto, y sin line-height propio, para
   que las dos líneas de base caigan exactamente en el mismo sitio. */

.conv__envio {
  position: absolute;
  left: 50%;
  bottom: 6.9444%;               /* y = 1005, el renglón del pie */
  transform: translateX(-50%);
  font-size: var(--t-24);
  color: var(--blanco-1);
  white-space: nowrap;
}
.conv__envio a {
  color: var(--amarillo-principal);
  border-bottom: 1px solid transparent;
  transition: border-color var(--t-corto) ease;
}
.conv__envio a:active { border-bottom-color: currentColor; }


/* =========================================================================
   LIBRERÍAS AMIGAS — frame 1041:24

   La lista es lo único del sitio que NO va posicionado renglón por renglón.
   El frame tiene un ritmo exacto y repetido —73 de alto por local, la raya 10
   arriba del nombre, la dirección 5 abajo— y una lista que va a crecer: cada
   librería nueva sería un `top` más que calcular a mano y tres más que correr.
   Escrito como ritmo, sumar una librería es sumar un <li>.

   El mapa va adentro del rectángulo, con 20 de aire por lado, y no se carga
   hasta que alguien lo pide: lo que se ve antes es esta caja con el botón.
   ========================================================================= */

/* Los retardos de entrada. Van acá y no en un style= del marcado por un motivo
   que no es de prolijidad: escritos en el marcado ganan siempre, y la regla de
   salida no podría ponerlos en cero. Y hay que ponerlos en cero, porque --espera
   puede valer 1150 ms —lo que tarda el rectángulo en llegar desde la página
   anterior— y la página se va a los 480: con ese retardo puesto, al irse las
   piezas no alcanzaban a moverse y la página desaparecía en seco. */
.libreria__titulo { --retardo: var(--espera, 0ms); }
.libreria__tabla  { --retardo: calc(var(--espera, 0ms) + 120ms); }
.libreria__marco  { --retardo: calc(var(--espera, 0ms) + 400ms); }

/* Al irse, todas juntas y sin esperar a nadie. */
body.despidiendo .libreria__titulo,
body.despidiendo .libreria__tabla,
body.despidiendo .libreria__marco { --retardo: 0ms; }

.libreria__titulo {
  /* El margen del <h1> que pone el navegador: sin esto, en una caja absoluta
     se suma al `top` y el título baja veintiún píxeles. */
  margin: 0;
  position: absolute;
  left: 8.9063%;                 /* x = 171 */
  top: 24.3519%;                 /* y = 263, el centro de la caja de texto */
  transform: translateY(-50%);
  font-family: var(--thermal);
  font-weight: 300;
  font-size: var(--t-32);
  line-height: 1;
  color: var(--amarillo-principal);
  white-space: nowrap;
}

/* El ritmo. Los tres valores que definen la lista están acá arriba y en un
   solo lugar: cambiarlos mueve los cinco locales a la vez. */
.libreria__tabla {
  --lib-aire: clamp(6px, 0.5208vw, 10px);   /* 10: de la raya al nombre */
  --lib-salto: clamp(3px, 0.2604vw, 5px);   /*  5: del nombre a la calle */
  --lib-raya: 1px solid var(--gris-2);
  --lib-velo: clamp(28px, 2.9167vw, 56px);  /* el desvanecido del pie */

  position: absolute;
  left: 8.9063%;                 /* x = 171 */
  top: 30.4630%;                 /* y = 329, el borde de la primera raya */
  /* Termina en y = 950, justo arriba de "Redes sociales". El alto sale de los
     dos bordes y no de una medida propia: así se acomoda solo a cualquier
     ventana, que es de lo que se trata.

     Y se desplaza por dentro. Con nueve librerías la lista mide 696 y necesita
     1001 de alto libre para entrar entera; un monitor de 1080, con el
     navegador abierto, deja unos 930. Antes de esto se cortaba la última
     librería y la nota del final, sin aviso: `.pantalla` recorta lo que se
     sale. El título y el mapa se quedan quietos, igual que en el índice de
     Archivo.

     `overscroll-behavior` para que al llegar al final la rueda no siga de
     largo y arrastre la página entera. */
  bottom: 12.0370%;
  width: 40.7813%;               /* 783: termina en x = 954 */
  overflow-y: auto;
  overscroll-behavior: contain;
  /* El pie se apaga con una máscara y no con un degradado encima: así no hay
     una caja de color que haya que mantener del mismo violeta que el fondo. */
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - var(--lib-velo)), transparent 100%);
          mask-image: linear-gradient(to bottom, #000 calc(100% - var(--lib-velo)), transparent 100%);
  /* La barra de desplazamiento no está en el diseño; el desvanecido del pie es
     el que avisa que ahí abajo sigue habiendo cosas. */
  scrollbar-width: none;
}
.libreria__tabla::-webkit-scrollbar { display: none; }

/* Dos columnas: la zona a la izquierda y los locales a la derecha, en 489.
   La raya de arriba cruza las dos —es la que separa Montevideo de Interior—;
   las de adentro son solo de la columna derecha, que es lo que hace el frame. */
.libreria__grupo {
  display: grid;
  grid-template-columns: 40.6130% 59.3870%;   /* 318 y 465 */
  border-top: var(--lib-raya);
}

/* El mismo paso que los locales, para que "Montevideo" y la primera librería
   apoyen en el mismo renglón. */
.libreria__zona {
  margin: 0;
  padding-top: calc(var(--lib-aire) - 1px);
  font-family: var(--thermal);
  font-weight: 700;
  font-size: var(--t-24);
  line-height: 1.2;
  color: var(--blanco-1);
}

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

/* El paso de arriba lleva un píxel menos porque la raya ya ocupa ese píxel: en
   el frame los 10 van de la raya al nombre, raya incluida. Sin descontarlo,
   cada local empuja uno al siguiente y el quinto termina cinco abajo. */
.libreria__locales li {
  padding: calc(var(--lib-aire) - 1px) 0 var(--lib-aire);
  border-top: var(--lib-raya);
}
/* El primero de cada grupo no lleva raya propia: ya tiene encima la del grupo,
   y dos rayas pegadas se ven como una más gruesa. El paso de arriba no cambia
   —sigue descontando un píxel— porque ese píxel lo sigue ocupando una raya, la
   del grupo: así el ritmo cruza el borde entre Montevideo e Interior sin dar
   un salto. */
.libreria__locales li:first-child { border-top: 0; }

.libreria__nombre {
  margin: 0 0 var(--lib-salto);
  font-size: var(--t-24);
  line-height: 1.2;
  color: var(--blanco-1);
}
.libreria__nombre span { color: var(--amarillo-principal); }

/* Cinturón para lo mismo que evita la etiqueta format-detection del <head>:
   si alguna versión de Safari igual convierte una dirección en enlace, acá se
   le saca el color y el subrayado punteado y vuelve a parecer texto. Los
   enlaces de verdad del sitio no llevan este atributo, así que no los toca. */
a[x-apple-data-detectors] {
  color: inherit !important;
  text-decoration: none !important;
  pointer-events: none;
}

/* El nombre es un botón: lleva el mapa a esa librería. Hay que apagarle todo
   lo que el navegador le pone por ser botón y dejarlo igual al texto que era,
   porque lo que cambia es lo que hace, no cómo se ve. El subrayado aparece al
   pasar por encima o al presionar, como el resto de los enlaces del sitio. */
.libreria__ir {
  padding: 0;
  border: 0;
  background: transparent;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: transparent;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
  transition: text-decoration-color var(--t-corto) ease;
}
.libreria__ir:active { text-decoration-color: currentColor; }
.libreria__ir:focus-visible { outline: 2px solid var(--amarillo-principal); outline-offset: 4px; }
/* El que ya está mostrándose en el mapa queda subrayado. */
.libreria__ir.activo { text-decoration-color: currentColor; }

/* --- el pin y su etiqueta, adentro del mapa ---
   El contenido de un marcador de Google se ancla por el borde de abajo. Si la
   etiqueta estuviera en el flujo, el conjunto mediría más ancho y la punta del
   pin dejaría de caer sobre la coordenada; por eso la caja mide exactamente lo
   que mide el pin y el nombre va colgado afuera, sin ocupar lugar. */
.pin-fuga {
  position: relative;
  width: var(--pin-ancho, 24px);
  height: var(--pin-alto, 30px);
}
.pin-fuga img { display: block; width: 100%; height: 100%; }
.pin-fuga__nombre {
  position: absolute;
  left: calc(100% + 5px);
  top: 42%;                      /* el centro del círculo del pin, no de la punta */
  transform: translateY(-50%);
  white-space: nowrap;
  /* La tipografía del mapa, no la del sitio: la etiqueta tiene que leerse como
     un nombre más de los que dibuja Google, no como texto pegado encima. */
  font-family: Roboto, 'Helvetica Neue', Arial, sans-serif;
  font-size: 12px;
  line-height: 1;
  color: var(--blanco-1);
  /* Un halo del color del mapa para que el nombre se lea también cuando cae
     sobre una calle clara. */
  text-shadow: 0 0 3px var(--violeta-oscuro), 0 0 6px var(--violeta-oscuro);
}

.libreria__calle {
  margin: 0;
  font-size: var(--t-16);
  line-height: 1.2;
  color: var(--blanco-1);
}

/* La aclaración del final. Mismo cuerpo que las direcciones y pegada al borde
   izquierdo de la tabla, o sea en la columna de Montevideo e Interior: se lee
   como un pie de la lista entera y no como una librería más.
   El aire de arriba es el doble del que separa una raya de un nombre, que es
   la única medida vertical que tiene esta lista. */
.libreria__nota {
  /* Tanto aire abajo como mide el desvanecido: si no, la nota nunca se puede
     terminar de leer, porque al llegar al final queda justo adentro de la
     parte que se apaga. */
  margin: calc(var(--lib-aire) * 2) 0 var(--lib-velo);
  font-size: var(--t-16);
  line-height: 1.2;
  color: var(--blanco-1);
}

/* El recorte: una caja del tamaño de la sección que se achica contra la figura.
   Los porcentajes de `inset` se miden contra la caja propia, así que tiene que
   ir pegada a los cuatro lados de la sección para que las cuatro medidas que
   escribe js/fuga.js signifiquen lo mismo acá que para el rectángulo.

   No atiende clics —sería una tapa sobre toda la pantalla— salvo el marco, que
   sí. Fuera del recorte tampoco hay clics, que es justo lo que queremos: el
   mapa recortado no se toca donde no se ve. */
.libreria__recorte {
  position: absolute;
  inset: 0;
  clip-path: inset(var(--rec-t, 0%) var(--rec-r, 0%) var(--rec-b, 0%) var(--rec-l, 0%));
  pointer-events: none;
}
.libreria__recorte > * { pointer-events: auto; }

/* El marco es el que lleva la posición, y no el mapa que tiene adentro. Es a
   propósito y costó un rato entenderlo: el marco entra con el resto del
   contenido, o sea que el sistema de entradas le escribe un `translate`, y una
   propiedad `translate` convierte al elemento en la referencia de cualquier
   descendiente absoluto. Con el mapa posicionado adentro, sus porcentajes
   pasaban a medirse contra un marco de alto cero: el mapa quedaba de 0 de alto
   y pegado arriba. Posicionando el marco, el que se mueve y el que mide son el
   mismo, y adentro no queda nada absoluto que confundir.

   El marco es la caja del mapa: el rectángulo violeta menos 20 de aire por
   lado. */
.libreria__marco {
  position: absolute;
  left: 59.6354%;                /* x = 1145 */
  top: 32.3148%;                 /* y = 349  */
  width: 30.4167%;               /* 584 */
  height: 38.4259%;              /* 415 */
}

/* El fondo del hueco es el violeta principal, el mismo del rectángulo: así el
   lugar del mapa se lee como parte de la figura y no como una placa aparte. */
.libreria__mapa {
  position: relative;            /* el aro de carga se apoya acá */
  width: 100%;
  height: 100%;
  background: var(--violeta-principal);
  display: grid;
  place-items: center;
  overflow: hidden;
}

/* El aro de carga, acá adentro de la caja y no sobre toda la pantalla como el
   del formulario. El fondo es opaco y del mismo violeta de la caja: lo que
   tapa es el blanco con el que Google arranca antes de dibujar el primer
   cuadro, que dura poco pero se ve feo. */
.cargando--mapa {
  position: absolute;
  inset: 0;
  z-index: 2;
  background: var(--violeta-principal);
}

.libreria__ver { position: relative; z-index: 1; }

/* Cargado el mapa, el botón se va y deja la caja entera. */
.libreria__mapa.cargado .libreria__ver { display: none; }
.libreria__mapa > div { width: 100%; height: 100%; }


/* =========================================================================
   CIRCUITO — frame 1098:184

   Una tabla de presentaciones agrupada en dos niveles: por año, y dentro del
   año en curso, en Próximas y Pasadas. Ninguno de los dos grupos está escrito
   en el marcado: los arma js/fuga.js leyendo la fecha de cada renglón, así el
   día después de una presentación se mueve sola de grupo.

   Las rayas son de dos largos y eso solo alcanza para leer la jerarquía: la
   ancha arranca en 171 y abre cada año; la corta arranca en 648 y cierra cada
   renglón. Las dos terminan en 1749.

   En escritorio el año abre con los tres rótulos en una misma línea —2026 en
   171, "#1 nuevas coordenadas" en 330 y "Próximas" en 648— y el primer
   renglón entra por la derecha de esa misma línea.

   El ritmo es 58 por renglón: 18 de texto, 20 hasta la raya de abajo y 20 de
   la raya al texto del siguiente.
   ========================================================================= */

.circuito__bajada {
  position: absolute;
  left: 8.9063%;                 /* x = 171 */
  top: 22.8704%;                 /* y = 247 */
  width: 33.1250%;               /* 636 */
  margin: 0;
  font-family: var(--thermal);
  font-weight: 300;
  font-size: var(--t-32);
  line-height: 1.1;
  color: var(--blanco-1);
}
/* El <strong> acá no es énfasis de peso: es el cambio de color. Por eso vuelve
   a la Light y se pinta de naranja, igual que en los dos frames. */
.circuito__bajada strong {
  font-weight: 300;
  color: var(--naranja-principal);
}

.circuito__tabla {
  /* El ritmo, en un solo lugar: cambiarlos mueve la tabla entera. */
  --circ-aire: clamp(12px, 1.0417vw, 20px);   /* 20: del texto a la raya */
  /* El paso de arriba lleva un píxel menos porque la raya ya ocupa ese píxel:
     en el frame los 20 van de la raya al texto, raya incluida. Sin descontarlo,
     cada renglón empuja uno al siguiente. */
  --circ-sube: calc(var(--circ-aire) - 1px);
  --circ-raya: 1px solid var(--gris-2);

  position: absolute;
  left: 8.9063%;                 /* x = 171 */
  top: 33.0556%;                 /* y = 357, el borde de la primera raya */
  width: 82.1875%;               /* 1578: termina en x = 1749 */
}

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

/* --- el año --- */
/* Tres columnas sobre los 1578 de la tabla: el año (159 = 330 − 171), la
   etiqueta de la edición (318 = 648 − 330) y los grupos, que se quedan con lo
   que sobra y arrancan en 648. */
.circuito__anio {
  display: grid;
  grid-template-columns: 10.0761% 20.1521% 1fr;
  grid-template-areas: "anio edicion grupos";
  border-top: var(--circ-raya);
}

/* El año va partido en dos renglones, como en el frame. Las dos mitades son
   dos <span> y no un salto de línea automático: "2026" es una sola palabra y
   un navegador no la corta salvo que se le fuerce, y forzarlo tendría efectos
   en cualquier otro número que apareciera acá. */
.circuito__numeroanio {
  grid-area: anio;
  margin: 0;
  padding-top: var(--circ-sube);
  font-family: var(--thermal);
  font-weight: 300;
  font-size: var(--t-64);
  line-height: 0.8;
  letter-spacing: -0.05em;       /* −3.2 sobre 64 */
  color: var(--gris-2);
}
.circuito__anio--vigente .circuito__numeroanio { color: var(--naranja-principal); }

.circuito__numeroanio span { display: block; }

/* --- la edición ---
   El número de la revista dejó de repetirse renglón por renglón: ahora es un
   rótulo del año, al lado del 2026. Lo mueve ahí js/fuga.js, leyéndolo del
   primer renglón de cada año. */
.circuito__numeroedicion {
  grid-area: edicion;
  margin: 0;
  /* Dos menos que el resto: el cuerpo 20 es dos más alto que el 18 del
     renglón, y en el frame los dos apoyan en la misma línea de base. */
  padding-top: calc(var(--circ-sube) - 2px);
  font-family: var(--thermal);
  font-weight: 300;
  font-size: var(--t-20);
  line-height: 1;
  color: var(--blanco-1);
}

/* --- los grupos: Próximas y Pasadas --- */
.circuito__grupos { grid-area: grupos; display: grid; }

/* El título del grupo no tiene columna propia: entra por la izquierda de la
   banda del primer renglón, que es ancha de sobra porque el lugar y la fecha
   van pegados a la derecha. Por eso el título y el listado comparten celda
   —los dos en 1/1— en vez de ponerse uno al lado del otro: si tuviera columna,
   las rayas de los renglones empezarían después del título y no en 648.
   `pointer-events: none` para que pasar por arriba de la palabra "Pasadas"
   siga encendiendo el renglón que tiene debajo, con su foto. */
.circuito__grupo { display: grid; }

.circuito__titulogrupo {
  grid-area: 1 / 1;
  align-self: start;
  pointer-events: none;
  margin: 0;
  /* El título es cuerpo 24 y el renglón 18, y los dos tienen que apoyar en la
     misma línea de base: por eso arranca más arriba, lo que mide la diferencia
     entre dónde cae la base de un cuerpo y la del otro. En esta fuente la base
     está a 0,917 del cuerpo, así que son 5,5 a 1920. Va en proporción y no en
     píxeles fijos porque los dos cuerpos son clamp y encogen juntos. */
  padding-top: calc(var(--circ-sube) - (var(--t-24) - var(--t-18)) * 0.917);
  font-family: var(--thermal);
  font-weight: 700;
  /* El mismo cuerpo que "Montevideo" e "Interior" en Librerías amigas: los dos
     hacen de encabezado de grupo y no había motivo para que midieran distinto. */
  font-size: var(--t-24);
  line-height: 1;
  color: var(--gris-2);
}
/* El título toma el color de sus renglones: encendido el de las que vienen,
   apagado el de las que pasaron. */
.circuito__grupo--proximas .circuito__titulogrupo { color: var(--blanco-1); }

.circuito__fechas { grid-area: 1 / 1; margin: 0; padding: 0; list-style: none; }

/* --- el renglón ---
   Dos columnas, las dos contra la derecha: el lugar y, al final, la fecha. */
.circuito__fecha {
  display: grid;
  /* La fecha lleva ancho fijo —88, de 1661 a 1749— y no `auto`: si no, el
     borde derecho de los lugares bailaría renglón a renglón según midiera
     "vie. 13/nov." o "sáb. 05/dic.". En el frame todos terminan en 1637. */
  grid-template-columns: 1fr 7.9927%;
  align-items: baseline;
  /* 24 entre el borde derecho del lugar y la fecha: 1661 − 1637. */
  column-gap: 2.1798%;
  padding: var(--circ-sube) 0 var(--circ-aire);
  /* La raya va abajo y en todos los renglones: en el frame cada uno cierra con
     la suya, incluido el último de la tabla. */
  border-bottom: var(--circ-raya);
  font-size: var(--t-18);
  line-height: 1;
  color: var(--gris-2);
  transition: color var(--t-corto) ease;
}
/* Salvo cuando abajo viene otro año: ahí la raya ancha de ese año hace de
   cierre, y dos rayas pegadas se leerían como una sola más gruesa. */
.circuito__anio:not(:last-child) .circuito__grupo:last-child .circuito__fecha:last-child {
  border-bottom: 0;
}
.circuito__lugar { text-align: right; white-space: nowrap; }
/* Sin JS no hay año ni grupos y el número de la edición se queda en cada
   renglón: que ocupe su propia línea arriba, en vez de meterse en la grilla
   del lugar y la fecha. */
.circuito__fecha .circuito__numero { grid-column: 1 / -1; }
/* Sin font-variant-numeric propio: el del sitio ya es tabular y de caja alta,
   y repetir acá solo "tabular-nums" apagaba lo otro y devolvía las cifras a la
   caja baja de la fuente. Es lo que hacía que las fechas se vieran distintas
   al resto. */
.circuito__dia   { white-space: nowrap; }

/* Las que todavía no pasaron se leen encendidas; las pasadas, apagadas. */
.circuito__grupo--proximas .circuito__fecha { color: var(--blanco-1); }

/* --- la foto que sigue al cursor ---
   Una sola tela fija del tamaño de la pantalla. La foto no es un elemento que
   se mueve: es un dibujo que cambia de lugar adentro de ella, y de eso depende
   que el borde roto quede clavado al fondo en vez de viajar congelado.
   La crea js/fuga.js, y solo en escritorio. */
.fotocursor {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 40;                   /* debajo del chrome, encima de la página */
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--t-corto) ease;
}
.fotocursor.visible { opacity: 1; }


/* =========================================================================
   ARCHIVO — frame 748:13

   Dos columnas. A la izquierda el número: qué es, cuándo salió y su tapa. A
   la derecha el índice, que es lo único que se mueve: la lista se desplaza
   sola por dentro mientras la tapa y los títulos se quedan quietos.

   Las rayas son de dos largos, como en Circuito, y de nuevo eso solo alcanza
   para leer la jerarquía: la larga arranca en 648 y cierra un género; la
   corta arranca en 966 y separa dos obras del mismo género. Las dos terminan
   en 1749.

   El ritmo es 66 por obra: 23 de título, 23 de autor, 10 hasta la raya y 10
   de la raya al título de la siguiente.
   ========================================================================= */

.archivo {
  /* El ritmo, en un solo lugar. El paso de arriba lleva un píxel menos porque
     la raya ya ocupa ese píxel: en el frame los 10 van de la raya al texto,
     raya incluida. */
  --arch-aire: clamp(6px, 0.5208vw, 10px);
  --arch-sube: calc(var(--arch-aire) - 1px);
  --arch-raya: 1px solid var(--gris-2);
  /* Cuánto mide el desvanecido del pie de la lista. */
  --arch-velo: clamp(40px, 5.8333vw, 112px);
}

/* --- la columna del número --- */

.archivo__numero {
  position: absolute;
  left: 8.9063%;                 /* x = 171 */
  top: 22.8704%;                 /* y = 247 */
  margin: 0;
  display: flex;
  align-items: baseline;
  /* El hueco entre el número y el nombre, el mismo de Conseguila: medido una
     vez y no atado al cuerpo, para que el conjunto no mida distinto en cada
     tamaño de ventana. */
  gap: clamp(6px, 0.7292vw, 14px);
  font-family: var(--thermal);
  font-weight: 300;
  font-size: var(--t-32);
  line-height: 1;
  color: var(--blanco-1);
  white-space: nowrap;
}

.archivo__cuando {
  position: absolute;
  left: 8.9063%;
  top: 26.7593%;                 /* y = 289 */
  margin: 0;
  font-family: var(--thermal);
  font-weight: 300;
  font-size: var(--t-20);
  line-height: 1.28;             /* el interlineado natural de la fuente */
  color: var(--blanco-1);
}

/* La tapa: 306 de ancho contando el marco, que en el frame mide 2 y es blanco.

   El alto NO se fija: lo pone la imagen. La caja del frame mide 306 × 411, y
   ahí adentro, descontando el marco, quedan 302 × 407; pero la tapa es de
   990 × 1329, que para 302 de ancho pide 405,4 de alto. Con el alto clavado
   sobraban dos píxeles y la tapa se recortaba por arriba y por abajo.

   Así la proporción es siempre la del archivo —cualquier archivo— y la tapa
   no se recorta de ningún lado. El precio es un alto final de 409 en vez de
   411, que es lo que el frame estaba recortando. */
.archivo__tapa {
  position: absolute;
  left: 8.9063%;                 /* x = 171 */
  top: 31.8519%;                 /* y = 344, a la par de la primera raya */
  width: 15.9375%;               /* 306 */
  height: auto;
  margin: 0;
  border: 2px solid var(--blanco-1);
}
.archivo__tapa img {
  display: block;
  width: 100%;
  height: auto;                  /* la proporción la manda la imagen */
}

/* --- el índice --- */

.archivo__rotulo {
  position: absolute;
  left: 33.75%;                  /* x = 648 */
  top: 22.8704%;                 /* a la par del número, y = 247 */
  margin: 0;
  font-family: var(--thermal);
  font-weight: 300;
  font-size: var(--t-32);
  line-height: 1;
  color: var(--blanco-1);
}

/* La lista es lo único que se desplaza en esta página. El pie se apaga contra
   el fondo con una máscara en vez de taparse con un degradado encima: así no
   hay una caja de color que haya que mantener del mismo violeta que el fondo,
   y el desvanecido no le roba el mouse a lo que tiene debajo.

   `overscroll-behavior` para que al llegar al final la rueda no siga de largo
   y arrastre la página entera. */
.archivo__lista {
  position: absolute;
  left: 33.75%;                  /* x = 648 */
  top: 31.8519%;                 /* y = 344 */
  width: 57.3438%;               /* 1101: termina en x = 1749 */
  height: 53.1481%;              /* 574: hasta y = 918 */
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - var(--arch-velo)), transparent 100%);
          mask-image: linear-gradient(to bottom, #000 calc(100% - var(--arch-velo)), transparent 100%);
  /* La barra de desplazamiento no está en el diseño; el desvanecido del pie
     es el que avisa que ahí abajo sigue habiendo cosas. */
  scrollbar-width: none;
}
.archivo__lista::-webkit-scrollbar { display: none; }

.archivo__secciones {
  margin: 0;
  padding: 0;
  list-style: none;
  /* Tanto aire abajo como mide el desvanecido: si no, la última reseña nunca
     se puede terminar de leer, porque al llegar al final queda justo adentro
     de la parte que se apaga. */
  padding-bottom: var(--arch-velo);
}

/* El género a la izquierda —318, de 648 a 966— y sus obras a la derecha. */
.archivo__seccion {
  display: grid;
  grid-template-columns: 28.8828% 1fr;
  /* La raya larga, la que cierra el género: va en la sección y por eso cruza
     las dos columnas. */
  border-bottom: var(--arch-raya);
}
/* La primera abre la lista con una raya igual, arriba. */
.archivo__seccion:first-child { border-top: var(--arch-raya); }

.archivo__genero {
  margin: 0;
  padding-top: var(--arch-sube);
  font-family: var(--thermal);
  font-weight: 300;
  font-size: var(--t-32);
  line-height: 1;
  color: var(--blanco-1);
}

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

/* El título y el autor son dos renglones; a la derecha, pegado al borde,
   puede ir el crédito de ilustración, que ocupa esos mismos dos renglones. */
.archivo__entrada {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas:
    "obra  credito"
    "autor ilustra";
  column-gap: clamp(10px, 1.25vw, 24px);
  padding: var(--arch-sube) 0 var(--arch-aire);
  /* La raya corta, la que separa dos obras del mismo género. */
  border-bottom: var(--arch-raya);
  font-family: var(--thermal);
  font-size: var(--t-18);
  color: var(--blanco-1);
}
/* La última de cada género no lleva raya propia: la cierra la de la sección,
   que es más larga. Dos rayas pegadas se leerían como una sola más gruesa. */
.archivo__entrada:last-child { border-bottom: 0; }

/* El interlineado va en dos partes y no en una sola declaración heredada:

   · 100 % dentro del título, que es lo que se nota cuando una obra ocupa dos
     renglones —"Leonardo de León: la escritura, las clases y la vida"—;
   · 130 % entre el título y su autor, que son dos cosas distintas y necesitan
     verse separadas.

   Los dos renglones van en 100 % y el 30 % que falta se agrega como hueco:
   con el mismo interlineado arriba y abajo, la distancia de una base a la
   otra es exactamente 1 em + el hueco, o sea 1,3 em. En `em` y no en píxeles
   porque el cuerpo es un clamp y cambia con el ancho de la ventana.

   El crédito de ilustración sigue el mismo par, así que en escritorio queda
   renglón a renglón con el título y el autor que tiene al lado. */
.archivo__obra    { grid-area: obra;    margin: 0;        line-height: 1; font-weight: 700; }
.archivo__autor   { grid-area: autor;   margin: 0.3em 0 0; line-height: 1; font-weight: 300; }
.archivo__credito { grid-area: credito; margin: 0;        line-height: 1; font-weight: 700; text-align: right; white-space: nowrap; }
.archivo__ilustra { grid-area: ilustra; margin: 0.3em 0 0; line-height: 1; font-weight: 300; text-align: right; white-space: nowrap; }


/* =========================================================================
   MOBILE — frames 859:152 (Convocatoria) y 859:213 (el menú)

   Los frames de celular están armados a 402 de ancho, con márgenes de 24 y
   tres cuerpos: 48 para el menú, 32 para los títulos y 16 para el texto.

   Acá la conversión NO es la de escritorio. Allá todo se mide en vw contra
   1920, y a 402 de ancho ese cálculo deja cada tamaño en el mínimo de su
   clamp: la página entera se lee en letra chica. Así que mobile tiene su
   propia escala, en px, que a 402 da exactamente lo del frame y por debajo
   encoge en vez de desbordar. Los valores verticales van en px pelados: el
   ritmo de una página no depende de lo ancha que sea la pantalla.
   ========================================================================= */

/* Fuera de mobile no existen ni el botón, ni el panel, ni las cortinas, ni el
   Conseguila del encabezado: en escritorio ese ya está en el nav. */
.menu__boton,
.menu,
.chrome__velo,
.chrome__venta { display: none; }

@media (max-width: 767px) {

  :root {
    --m-margen: clamp(16px, 5.9701vw, 24px);    /* 24 */
    --m-12:     clamp(11px, 2.9851vw, 12px);
    --m-16:     clamp(14px, 3.9801vw, 16px);
    --m-48:     clamp(36px, 11.9403vw, 48px);
    --m-32:     clamp(24px, 7.9602vw, 32px);
    --m-20:     clamp(17px, 4.9751vw, 20px);
    --m-20:     clamp(15px, 4.9751vw, 20px);
    --m-24:     clamp(18px, 5.9701vw, 24px);
    --m-36:     clamp(26px, 8.9552vw, 36px);

    /* Las paradas de las dos cortinas, la de arriba y la del pie. Es una sola
       lista y no dos degradados sueltos: el recurso es el mismo, y lo único
       que cambia entre una y otra es para qué lado corre.

       Y no son dos paradas sino seis. Con dos, la rampa es recta: el ojo ve
       el punto donde arranca como una línea, y el texto que pasa por debajo
       parece cortado ahí. Con la curva el apagón no tiene principio.

       El transparente se escribe con el mismo color en alfa cero: escrito
       `transparent`, algunos navegadores lo interpolan pasando por un gris y
       el degradado ensucia el violeta. */
    --cortina: var(--violeta-oscuro) 0%,
               var(--violeta-oscuro) 52%,
               rgba(24, 12, 26, 0.92) 64%,
               rgba(24, 12, 26, 0.70) 76%,
               rgba(24, 12, 26, 0.38) 88%,
               rgba(24, 12, 26, 0) 100%;
  }

  /* La cortina de arriba. Va dentro del chrome y por debajo de todo lo suyo:
     tapa la página, no al botón ni a FUGA.

     Se nombra por el padre a propósito: `.chrome > *` le da pointer-events a
     todos los hijos, y con la misma fuerza que este bloque el desempate
     quedaría en el orden del archivo. Nombrando los dos, gana siempre este. */
  .chrome > .chrome__velo {
    display: block;
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    z-index: 0;
    /* Termina justo donde arranca el rectángulo de Conseguila, que en el
       frame está en 128: así, con la página arriba del todo, la cortina no le
       toca el borde de arriba. Lo macizo llega a 67 y el encabezado —el botón
       hasta 76, FUGA hasta 83— cae en el primer tramo del desvanecido, donde
       todavía tapa el 90 %. */
    height: 128px;
    pointer-events: none;
    background-image: linear-gradient(to bottom, var(--cortina));
    opacity: 0;
    transition: opacity var(--t-medio) var(--ease);
  }
  body.en-sitio .chrome__velo,
  html.sin-umbral .chrome__velo { opacity: 1; }

  /* --- el chrome --- */

  /* Los cinco ítems en fila no entran, y el bloque de redes se muda adentro
     del menú: se oculta el del chrome, no el de adentro. */
  .nav,
  .chrome > .redes { display: none; }

  .marca {
    right: var(--m-margen);
    top: 45px;
    font-size: var(--m-32);
    z-index: 2;
  }

  /* El botón y FUGA quedan por encima del panel: están en el mismo sitio con
     el menú abierto y cerrado, así que abrirlo no los mueve ni los tapa. */
  .menu__boton {
    display: grid;
    place-items: center;
    position: absolute;
    /* La caja mide 48 y el dibujo 24: 12 de aire de cada lado dejan el dibujo
       en 24, 52, que es donde lo pone el frame. */
    left: calc(var(--m-margen) - 12px);
    top: 40px;
    z-index: 2;
    width: 48px;
    height: 48px;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--blanco-1);
    cursor: pointer;
    /* Apagado hasta que el sitio esté a la vista. Y sin atender: una opacidad
       en cero se sigue pudiendo tocar, y abrir el menú por detrás del landing
       es abrirlo a ciegas. */
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--t-medio) var(--ease);
  }
  body.en-sitio .menu__boton,
  html.sin-umbral .menu__boton { opacity: 1; pointer-events: auto; }

  /* La página de atrás no se mueve mientras el menú está encima. */
  body.menu-abierto { overflow: hidden; }
  .menu__boton:focus-visible { outline: 2px solid var(--amarillo-principal); outline-offset: 2px; }

  /* Los dos dibujos ocupan la misma casilla y se cruzan girando: no hay dos
     botones ni un cambio de icono, hay uno que se da vuelta. */
  .menu__boton svg {
    grid-area: 1 / 1;
    width: 24px;
    height: 24px;
    fill: currentColor;
    transition: opacity var(--t-corto) var(--muta),
                rotate var(--t-corto) var(--muta);
  }
  .menu__cruz { opacity: 0; rotate: -90deg; }
  body.menu-abierto .menu__barras { opacity: 0; rotate: 90deg; }
  body.menu-abierto .menu__cruz   { opacity: 1; rotate: 0deg; }

  /* Conseguila, a la vista y sin abrir nada. Apoyado en el mismo renglón que
     el botón y FUGA: los dos tienen su centro en 64, así que este se centra
     sobre esa misma línea en vez de declarar un `top` propio, que habría que
     recalcular cada vez que cambie el cuerpo de letra.

     Arranca 30 a la derecha del dibujo de la hamburguesa, que termina en 48
     (el margen más sus 24 de ancho). La cuenta va escrita en sus partes y no
     resuelta en un 78 suelto, para que se siga leyendo de dónde sale.

     En amarillo y en el cuerpo de Redes sociales. El subrayado está siempre
     puesto en transparente y lo que cambia es su color: aparece de a poco en
     vez de un golpe, y no corre a los vecinos como haría un borde. */
  .chrome__venta {
    display: block;
    position: absolute;
    left: calc(var(--m-margen) + 24px + 30px);
    top: 64px;
    transform: translateY(-50%);
    z-index: 2;
    font-size: var(--m-20);
    line-height: 1.25;
    color: var(--amarillo-principal);
    white-space: nowrap;
    text-decoration: underline;
    text-decoration-color: transparent;
    text-decoration-thickness: 1px;
    text-underline-offset: 5px;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--t-medio) var(--ease),
                text-decoration-color var(--t-corto) ease;
  }
  body.en-sitio .chrome__venta,
  html.sin-umbral .chrome__venta { opacity: 1; pointer-events: auto; }

  /* Con el menú abierto sobra: ahí Conseguila ya está, grande y arriba. */
  body.menu-abierto .chrome__venta { opacity: 0; pointer-events: none; }

  /* En Librerías amigas no va. La página entera responde "dónde conseguirla",
     así que un enlace a Conseguila arriba compite con lo que la persona vino a
     leer. Se reconoce la página por su sección y no por una clase en el
     <body>: el encabezado es el mismo marcado en las seis páginas y no quiero
     empezar a diferenciarlas por ahí. */
  body:has(#librerias) .chrome__venta { display: none; }

  .chrome__venta.activo,
  .chrome__venta:active { text-decoration-color: currentColor; }
  .chrome__venta:focus-visible { outline: 2px solid var(--amarillo-principal); outline-offset: 4px; }

  /* --- el panel --- */

  .menu {
    display: flex;
    flex-direction: column;
    position: fixed;
    inset: 0;
    z-index: 1;
    /* Arriba, el aire que deja el encabezado; abajo, el de la casa más lo que
       se coma el indicador del teléfono. */
    padding: 110px var(--m-margen) calc(48px + env(safe-area-inset-bottom));
    background-color: var(--violeta-oscuro);
    overflow-y: auto;
    overscroll-behavior: contain;
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--t-corto) var(--sale),
                visibility 0s linear var(--t-corto);
  }
  body.menu-abierto .menu {
    opacity: 1;
    visibility: visible;
    transition: opacity var(--t-corto) var(--entra),
                visibility 0s linear 0s;
  }

  /* Las tres piezas entran escalonadas. La lista no se anima como bloque:
     se animan sus ítems, uno atrás del otro. */
  .menu__venta,
  .menu__lista a,
  .redes--menu {
    opacity: 0;
    translate: 0 16px;
    transition: opacity var(--t-corto) var(--entra) var(--retardo, 0ms),
                translate var(--t-corto) var(--entra) var(--retardo, 0ms),
                color var(--t-corto) ease;
  }
  body.menu-abierto .menu__venta,
  body.menu-abierto .menu__lista a,
  body.menu-abierto .redes--menu { opacity: 1; translate: none; }

  .menu__lista a:nth-child(1) { --retardo:  60ms; }
  .menu__lista a:nth-child(2) { --retardo: 100ms; }
  .menu__lista a:nth-child(3) { --retardo: 140ms; }
  .menu__lista a:nth-child(4) { --retardo: 180ms; }
  .redes--menu             { --retardo: 220ms; }

  /* Conseguila arriba a la derecha y en amarillo, apartada del resto: es el
     punto de venta, igual que en el nav de escritorio. */
  .menu__venta {
    align-self: flex-end;
    margin-top: 30px;            /* y = 140 */
    /* 32, el mismo cuerpo que los títulos de sección. En el frame el menú iba
       en 36; emparejarlos hace que el sitio tenga un solo tamaño grande en
       celular en vez de dos parecidos, que es lo que se notaba. */
    font-size: var(--m-32);
    line-height: 1.28;
    color: var(--amarillo-principal);
    text-decoration: underline;
    text-decoration-color: transparent;
    text-decoration-thickness: 1px;
    text-underline-offset: 6px;
  }
  .menu__venta.activo { text-decoration-color: currentColor; }

  /* Todo el aire libre se va arriba: la lista y Contacto se apoyan contra el
     pie y Conseguila queda sola allá arriba a la derecha. Son dos anclajes
     opuestos —una arriba y a la derecha, el resto abajo y a la izquierda— y
     entre los dos queda el vacío.

     El aire va como margen automático y no como medida para que el bloque se
     apoye igual de bien en cualquier alto de pantalla: lo que se estira es el
     hueco del medio, nunca lo que está adentro de la lista. */
  .menu__lista {
    display: flex;
    flex-direction: column;
    margin-top: auto;
  }
  /* Cada ítem trae su línea arriba y el último cierra con la de abajo: cinco
     líneas para cuatro ítems, como en el frame. Del renglón a la línea van 10
     de cada lado, y de un ítem al siguiente, 66.

     Arriba son 9 y no 10 porque en Figma la línea es un trazo sin alto y acá
     es un borde que sí ocupa: el píxel que se come el borde se le descuenta al
     aire. Sin eso, la lista se iba corriendo un píxel por ítem. */
  .menu__lista a {
    font-size: var(--m-32);
    line-height: 1.28;
    color: var(--gris-2);
    /* Un poco más juntos que antes —iban 9 y 10— ahora que el cuerpo bajó de
       36 a 32 y la lista tiene cinco ítems en vez de cuatro. */
    padding: 7px 0 8px;
    border-top: 1px solid var(--gris-2);
  }
  .menu__lista a:last-child { border-bottom: 1px solid var(--gris-2); }
  .menu__lista a.activo { color: var(--blanco-1); }

  /* Contacto ya no va en el cuerpo de la lista: baja a 20, que es lo que lo
     aparta de las secciones sin sacarlo del menú.

     Y lo separan 66 de la lista, que es justo lo que va de un ítem al
     siguiente: queda a un renglón de distancia. En el frame ese hueco es 144,
     pero el frame mide 874 de alto y un teléfono de verdad anda por los 670.
     A esa altura el contenido del menú ocupa casi todo, no sobra aire para
     repartir, y un hueco fijo de 144 se lo queda entero: la lista terminaba
     pegada a Conseguila y el vacío caía del lado equivocado. Con 66 el aire
     sobrante vuelve a estar arriba, que es donde tiene que estar para que el
     resto se lea apoyado abajo. */
  .redes--menu {
    margin-top: 66px;
    font-size: var(--m-20);
    line-height: 1.25;
  }

  .menu a:focus-visible { outline: 2px solid var(--amarillo-principal); outline-offset: 4px; }

  /* --- CONVOCATORIA --- */

  /* Una sola columna de corrido. Se van las dos columnas con scroll propio,
     sus máscaras y el encaje de pantalla: acá se scrollea la página entera,
     que es lo que un celular espera. */
  .sitio:has(.pantalla--convocatoria) { scroll-snap-type: none; }

  .pantalla--convocatoria {
    min-height: 0;
    overflow: visible;
    /* Arriba, los 150 hasta "Bases generales". Va como padding de la sección
       y no como margen del título: el margen del primer hijo se escapa del
       padre y termina empujando la sección entera, que acá da lo mismo pero
       deja de darlo en cuanto la sección tenga fondo propio.
       Abajo, aire para que el último renglón pueda subir por encima del pie
       fijo en vez de quedarse siempre debajo del degradado. */
    padding: 150px 0 200px;
  }

  .conv__titulo {
    position: static;
    transform: none;
    margin: 0 var(--m-margen);
    font-size: var(--m-32);
    white-space: normal;
  }
  /* "Bases generales" arranca en y = 150, que lo pone el padding de la
     sección. "Requisitos por categoría", 71 después de la última base. */
  .conv__titulo--requisitos { margin-top: 71px; }

  .conv__columna {
    position: static;
    width: auto;
    height: auto;
    overflow: visible;
    margin: 20px var(--m-margen) 0;
    font-size: var(--m-16);
    line-height: 1.3;
    -webkit-mask-image: none;
            mask-image: none;
  }
  /* El colchón de escritorio era para poder rescatar el final del texto de
     abajo del degradado de su columna. Acá no hay columna ni degradado. */
  .bases,
  .requisitos { padding-bottom: 0; }

  .bases { padding-left: 24px; }
  .bases li { margin-bottom: 12px; }

  .requisito + .requisito { margin-top: 33px; }
  .requisito__titulo {
    grid-template-columns: 18px 1fr;
    column-gap: 7px;             /* el texto arranca en x = 49 */
    font-size: var(--m-16);
  }

  /* --- el pie de la convocatoria ---
     Queda fijo abajo, y el contenido se va metiendo debajo: el degradado lo
     apaga antes de que llegue al mail en vez de cortarlo al ras. */
  .conv__envio {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    transform: none;
    z-index: 50;                 /* debajo del chrome, encima de la página */
    padding: 72px var(--m-margen) calc(24px + env(safe-area-inset-bottom));
    font-size: var(--m-16);
    line-height: 1.35;
    white-space: normal;
    /* La misma cortina de arriba, corriendo para el otro lado. */
    background-image: linear-gradient(to top, var(--cortina));
    /* El degradado es una cortina, no una superficie: lo único que se toca
       acá es el mail. */
    pointer-events: none;
  }
  /* El mail en su propio renglón: los dos juntos no entran a lo ancho. */
  .conv__envio a { display: block; pointer-events: auto; }

  /* --- EL MANIFIESTO — frames 865:272 a 865:344 ---

     Las mismas seis pantallas, reacomodadas para una vertical. El
     funcionamiento no cambia: sigue siendo una escena fija donde el
     rectángulo se transforma y el contenido entra y sale.

     Las posiciones van en porcentaje de la ventana y no en píxeles, igual que
     en escritorio y por el mismo motivo: acá el rectángulo lo dibuja el script
     en fracciones de la ventana, y si el texto se midiera en píxeles los dos
     dejarían de coincidir en cuanto la pantalla no midiera 402 × 874.

     Los cuerpos sí van en píxeles con tope, que es lo que evita que el texto
     se achique hasta no leerse en un teléfono angosto. */

  .indice {
    left: 5.9701%;               /* x = 24 */
    top: 18.6499%;               /* y = 163 */
    gap: 10px;
  }
  /* Acá el ítem que se enciende crece de 24 a 32, no de 24 a 64: en 402 de
     ancho, "El discernimiento" en 64 no entra en un renglón. Y el interlineado
     se queda quieto en 1.25, porque 24 y 32 dan 30 y 40 de alto, que son los
     dos pasos del frame. */
  .indice a {
    font-size: calc(var(--m-24) + (var(--m-32) - var(--m-24)) * var(--cerca));
    line-height: 1.25;
  }

  /* Pantalla 1: el enunciado adentro del rectángulo y el párrafo debajo,
     montado sobre el pie de la figura. */
  .p1__enunciado {
    left: 10.9453%;              /* x = 44  */
    top: 27.5744%;               /* centro en y = 241 */
    width: 68.4080%;             /* 275 */
    font-size: var(--m-36);
  }
  .p1__texto { left: 23.1343%; top: 48.2838%; width: 68.4080%; }   /* 93, 422, 275 */

  /* Las cuatro del medio y el cierre comparten columna: 69 de borde, 309 de
     ancho, y todas arrancan en el mismo renglón. */
  /* Los párrafos bajan 48 respecto del frame, y con ellos las cinco figuras
     que se mueven. Arriba quedaban pegados al índice: entre el último renglón
     de la lista y la primera línea del párrafo había 61, y ahora hay 109. Lo
     que NO se movió es el bloque de arriba —el índice y el enunciado de la
     primera pantalla— que es donde se entra a leer. */
  .p2__texto,
  .p3__texto,
  .p4__texto,
  .p5__texto,
  .p6__texto {
    left: 17.1642%;              /* x = 69  */
    top: 48.2838%;               /* y = 422 */
    width: 76.8657%;             /* 309 */
  }

  .texto { font-size: var(--m-16); line-height: 1.3; }

  /* En escritorio el párrafo del cierre y el saludo van en una grilla, para que
     el saludo siga al párrafo por más renglones que este tenga. Acá no hace
     falta: el ancho es uno solo, los renglones son siempre los mismos y cada
     pieza tiene su lugar medido en el frame. Vuelven a colgar de su `top`. */
  #bienvenida { display: block; }
  #bienvenida > * { position: absolute; }

  /* Y el saludo del final, anclado por la derecha: sin ancho propio, la caja
     mide lo que mide la frase y termina en x = 358. */
  .p6__cierre {
    left: auto;
    right: 10.9453%;             /* termina en x = 358 */
    top: 65.9039%;               /* y = 576, bajó con el párrafo */
    width: auto;
    font-size: var(--m-36);
    line-height: 1.1;            /* 36 × 1.1 = 40, el alto del frame */
    white-space: nowrap;
  }

  /* --- CIRCUITO — frame 1107:321 ---

     La tabla deja de ser tabla. El año queda en una columna angosta a la
     izquierda y todo lo demás se apila: el título del grupo arriba y abajo los
     renglones, cada uno en dos líneas —el lugar, y debajo la fecha y el
     número—. La imagen que sigue al cursor no existe acá, que es lo que pidió
     Maxi: en una pantalla que se toca no hay cursor al que seguir. */

  .sitio:has(.circuito) { scroll-snap-type: none; }

  .circuito {
    min-height: 0;
    overflow: visible;
    /* Arriba, hasta la bajada chica. Abajo, aire para el pie. */
    padding: 141px 0 160px;
  }

  .circuito__bajada {
    position: static;
    width: auto;
    margin: 0 var(--m-margen);
    font-size: var(--m-16);
    line-height: 1;
  }
  /* "¡Vení a conocernos!" pasa a ser su propio renglón, y grande. */
  .circuito__bajada strong {
    display: block;
    /* La bajada mide dos renglones de 16 y termina en 173; el título va en 178. */
    margin-top: 5px;
    font-size: var(--m-32);
    line-height: 1;
  }

  .circuito__tabla {
    --circ-aire: 10px;
    position: static;
    width: auto;
    margin: 50px var(--m-margen) 0;   /* la primera raya, 50 abajo del título */
  }

  /* Acá el año no comparte línea con nada: abre con una banda propia —la
     edición a la izquierda y el 2026 grande a la derecha, entre dos rayas de
     ancho completo— y los grupos bajan abajo, corridos a 116.

     El orden del marcado es 2026 → edición → grupos, así que las áreas no son
     decorativas: son las que ponen la edición primero en la línea. */
  .circuito__anio {
    grid-template-columns: 1fr auto;
    grid-template-areas:
      "edicion anio"
      "grupos  grupos";
  }

  /* La raya de abajo de la banda va en las dos celdas y no en el año: juntas
     cubren los 354 de ancho y se lee como una sola. */
  .circuito__numeroanio {
    padding: 19px 0 11px;
    border-bottom: var(--circ-raya);
    font-size: var(--m-48);
    letter-spacing: -0.05em;
  }
  /* En celular el año va en un solo renglón, no partido en dos. */
  .circuito__numeroanio span { display: inline; }

  /* Apoyado abajo, para que termine a la par del 2026 aunque mida la mitad. */
  .circuito__numeroedicion {
    align-self: end;
    padding: 0 0 11px;
    border-bottom: var(--circ-raya);
    font-size: var(--m-16);
    line-height: 1.2;
  }

  .circuito__grupos { margin-left: 92px; }   /* 92 = 116 − 24 */

  /* El grupo deja de ser una celda compartida: el título va arriba de sus
     renglones, con raya propia, y vuelve a ser seleccionable porque acá no
     tapa nada. */
  .circuito__grupo { display: block; }

  .circuito__titulogrupo {
    pointer-events: auto;
    padding: 19px 0 11px;
    border-bottom: var(--circ-raya);
    font-weight: 700;
    font-size: var(--m-16);
    line-height: 1.2;
  }

  /* Dos líneas, una columna sola: la fecha arriba contra la derecha y el lugar
     abajo contra la izquierda. Los dos bordes, 116 y 378, son los mismos de la
     raya. El relleno de arriba y abajo lo hereda de escritorio: con --circ-aire
     en 10 da justo el paso de 64 del frame. */
  .circuito__fecha {
    grid-template-columns: 1fr;
    grid-template-areas:
      "dia"
      "lugar";
    row-gap: 10px;
    column-gap: 0;
    /* 10,4 y no 10: en el frame los renglones van cada 64 clavados, y lo que
       hay dentro —1 de raya, 9 de aire, 14,4 de fecha, 10 de separación y 19,2
       de lugar— suma 53,6. Con 10 el paso daba 63,6 y el error se iba sumando
       renglón a renglón. */
    padding-bottom: 10.4px;
  }
  .circuito__dia    { grid-area: dia;   font-size: var(--m-12); line-height: 1.2; text-align: right; }
  .circuito__lugar  { grid-area: lugar; text-align: left; font-size: var(--m-16); line-height: 1.2; }

  /* --- ARCHIVO — frame 1134:2 ---

     Acá no hay dos columnas ni una lista que se desplace por dentro: se
     desplaza la página entera y todo baja en un solo hilo. "Contenidos" pasa
     a encabezar la página —en el marcado va después del número, así que se
     reordena— y cada género se pone en su propio renglón, con sus obras
     corridas a 116.

     Los valores verticales son los del frame, en píxeles: 136 al rótulo, 208
     al número, 250 a la fecha, 286 a la tapa y 535 a la primera raya. */

  .sitio:has(.archivo) { scroll-snap-type: none; }

  .archivo {
    --arch-aire: 10px;
    min-height: 0;
    overflow: visible;
    padding: 136px 0 160px;      /* arriba hasta el rótulo; abajo, aire para el pie */
    display: flex;
    flex-direction: column;
    align-items: flex-start;
  }

  /* El pie se apaga contra el fondo, como en Convocatoria y en Librerías: la
     lista se mete por debajo en vez de cortarse al ras. */
  .archivo::after {
    content: '';
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    /* La mitad de los 112 del frame: acá abajo no hay nada fijo que esconder
       —en Convocatoria hay un mail, en Librerías el rectángulo del mapa— así
       que el degradado es solo el apagado, y a 112 se comía un renglón y medio
       de contenido legible. */
    height: 56px;
    z-index: 50;                 /* debajo del chrome, encima de la página */
    background-image: linear-gradient(to top, var(--cortina));
    pointer-events: none;
  }

  .archivo__rotulo {
    order: -1;                   /* encabeza la página, aunque vaya después */
    position: static;
    margin: 0 var(--m-margen);
    font-size: var(--m-32);
  }

  /* Acá el número no compite con "Contenidos": va en cuerpo 20 y arranca 20
     abajo del rótulo. Todo lo que sigue sube solo, porque va en el hilo. */
  .archivo__numero {
    position: static;
    margin: 20px var(--m-margen) 0;
    font-size: var(--m-20);
    gap: 8px;                    /* los dos espacios del frame, a este cuerpo */
  }

  .archivo__cuando {
    position: static;
    margin: 10px var(--m-margen) 0;
    font-size: var(--m-16);
    line-height: 1;
  }

  /* El alto lo pone la imagen, igual que en escritorio: 171 de ancho con el
     marco dejan 167 adentro, y a esa proporción le tocan 224 de alto. */
  .archivo__tapa {
    position: static;
    width: 171px;
    margin: 20px var(--m-margen) 0;
  }

  .archivo__lista {
    position: static;
    width: auto;
    height: auto;
    align-self: stretch;
    margin: 20px var(--m-margen) 0;
    overflow: visible;
    /* Sin máscara: el desvanecido lo hace la cortina del pie, que es fija. */
    -webkit-mask-image: none;
            mask-image: none;
  }
  .archivo__secciones { padding-bottom: 0; }

  /* El género deja de tener columna propia: va arriba de sus obras. */
  .archivo__seccion { display: block; }

  .archivo__genero { font-size: var(--m-32); }

  .archivo__entradas { margin-left: 92px; }   /* 92 = 116 − 24 */

  /* Todo en una columna: título, autor y, si lo hay, el crédito de
     ilustración debajo, contra la derecha. */
  .archivo__entrada {
    grid-template-columns: 1fr;
    grid-template-areas:
      "obra"
      "autor"
      "credito"
      "ilustra";
    column-gap: 0;
    font-size: var(--m-16);
  }
  /* La primera de cada género viene de un título y no de una raya, y una raya
     ocupa un píxel: sin esto quedaría uno más arriba que las demás. */
  .archivo__entradas > .archivo__entrada:first-child { padding-top: var(--arch-aire); }

  /* El interlineado no se repite acá: el de escritorio está en `em` y en
     proporciones, así que a este cuerpo da lo mismo —16 de renglón y 4,8 de
     hueco— sin tener que escribir otro juego de números. */

  /* --- LIBRERÍAS AMIGAS — frame 1050:47 ---

     Acá el rectángulo no está en el medio de la pantalla sino clavado abajo, y
     la lista se scrollea por debajo. Es el mismo trato que el pie de la
     Convocatoria: una cortina apaga el texto antes de que llegue al borde del
     rectángulo, en vez de cortarlo al ras. */

  .sitio:has(.libreria) { scroll-snap-type: none; }

  .libreria {
    min-height: 0;
    overflow: visible;
    /* Arriba, los 136 hasta el título —el frame lo centra en 168 y mide dos
       renglones de 32—. Abajo, los 200 del mapa más aire, para que el último
       renglón de la lista pueda subir por encima de él en vez de quedarse
       siempre tapado. */
    padding: 136px 0 260px;
  }

  .libreria__titulo {
    position: static;
    transform: none;
    margin: 0 var(--m-margen);
    /* 263 es lo que el frame le da para que corte en "¿Dónde conseguir /
       revista Fuga?". Como máximo y no como ancho fijo: en una pantalla más
       angosta tiene que poder achicarse. */
    max-width: 263px;
    font-size: var(--m-32);
    /* Interlineado 1, como el frame. Con 1.1 el título mide 70 en vez de 64 y
       esos seis píxeles empujan la lista entera para abajo. */
    line-height: 1;
    white-space: normal;
  }

  .libreria__tabla {
    /* El ritmo del celular es más chico que el de escritorio, pero la cuenta
       es la misma: 59 de alto por local en vez de 73. */
    --lib-aire: 10px;
    --lib-salto: 5px;
    --lib-velo: 0px;              /* acá no hay desvanecido: lo hace el pie */

    position: static;
    width: auto;
    margin: 20px var(--m-margen) 0;   /* la primera raya, 20 abajo del título */
    /* Acá se desplaza la página entera, así que la lista no tiene por qué
       desplazarse por dentro ni apagarse abajo. */
    bottom: auto;
    overflow: visible;
    -webkit-mask-image: none;
            mask-image: none;
  }

  /* 111 = 135 − 24: la columna de la derecha arranca en x = 135 y mide 243,
     que es el ancho de las rayas de adentro en el frame. */
  .libreria__grupo { grid-template-columns: 111px 1fr; }

  .libreria__zona,
  .libreria__nombre { font-size: var(--m-16); }
  /* La nota del final va en el mismo cuerpo que las direcciones, acá también. */
  .libreria__calle,
  .libreria__nota   { font-size: var(--m-12); }

  /* Acá no hay figura que viaje, así que no hay nada contra qué recortar. Y el
     clip-path tiene que irse sí o sí: un ancestro con clip-path se convierte en
     la referencia de cualquier `position: fixed` que tenga adentro, y el marco
     de abajo es justamente fijo. Con el recorte puesto dejaría de estar clavado
     a la pantalla y se iría a scrollear con la página. */
  .libreria__recorte {
    position: static;
    clip-path: none;
    pointer-events: none;
  }

  /* Acá el mapa es el bloque, no hay rectángulo que lo enmarque: de borde a
     borde de la pantalla y la mitad de alto que en el frame. En una pantalla
     de teléfono, 400 se comían más de la mitad del alto útil; con 200 el mapa
     sigue siendo legible y la lista no queda arrinconada.

     Sin relleno y sin fondo propio, entonces: lo que se ve es el mapa. */
  .libreria__marco {
    position: fixed;
    left: 0;
    right: 0;
    top: auto;
    bottom: 0;
    width: auto;
    height: 200px;
    padding: 0;
    background: none;
    z-index: 50;                 /* debajo del chrome, encima de la página */
  }
  /* La cortina de 36 que apaga la lista justo antes del rectángulo. */
  .libreria__marco::before {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    bottom: 100%;
    height: 36px;
    background-image: linear-gradient(to top, var(--cortina));
    pointer-events: none;
  }

  .libreria__mapa { height: 100%; }

  /* --- CONSEGUILA — frames 838:40 (ficha) y 838:67 (formulario) ---

     En escritorio esto son dos pantallas fijas y el rectángulo se ensancha
     de una a la otra; acá crece hacia abajo, hasta medir más que la pantalla,
     y la página se scrollea entera con él.

     Eso da vuelta el planteo: el rectángulo deja de ser una figura con
     coordenadas propias y pasa a ser la caja del contenido. Su alto ya no se
     declara, sale de lo que tiene adentro. Todo lo que en escritorio está
     posicionado a mano vuelve al flujo, en una grilla de dos columnas que
     solo usa la segunda para RESERVAR y CONFIRMAR, que van a la derecha. */

  /* --- el rectángulo en el celular: sin textura, con el borde desenfocado ---

     La textura de la marca no viaja al teléfono. El filtro se vuelve a
     rasterizar en CADA cuadro en que la figura cambia de tamaño, y medido
     cuadro por cuadro sobre una grabación de pantalla de un iPhone eso sale a
     unos 250 ms por cuadro: la tapa encogía en cuatro saltos a lo largo de
     1,1 s en vez de en sesenta y pico. Dos feTurbulence, un feDisplacementMap
     y seis primitivas más sobre varios millones de píxeles reales no entran en
     el presupuesto de un cuadro, y ningún ajuste de la cadena los hacía
     entrar.

     Y tampoco va desenfocada, que fue el segundo intento. El desenfoque se
     veía bien quieto, pero al moverse dejaba el fantasma del rectángulo
     anterior pegado en pantalla: WebKit no repinta la zona que el desenfoque
     ocupaba antes, y durante la transición se veían los dos a la vez. Es un
     error de repintado del motor, no un número que se pueda ajustar.

     Así que en el celular la figura va limpia: color plano y borde al ras.
     Se pierde el grano, que es la parte de la identidad que no sobrevive al
     viaje, y a cambio el movimiento es el que tiene que ser. En escritorio la
     textura sigue intacta. */
  #figura { filter: none; }

  .sitio:has(.conseguila) { scroll-snap-type: none; }

  .pantalla.conseguila {
    height: auto;
    min-height: 100svh;
    /* El SVG del rectángulo mide 1400 de alto a propósito, para que su caja no
       cambie nunca. Pero es absoluto, así que estiraba el área scrolleable de
       la página: quedaban ochocientos y pico de píxeles de scroll vacío por
       debajo de la ficha. Recortar acá lo deja afuera de esa cuenta sin
       esconder nada: lo que se recorta es la cola del SVG, donde no se dibuja
       la figura, y el aire de abajo de la sección alcanza de sobra para el
       borde desplazado. */
    overflow: clip;
    /* Los 128 hasta el rectángulo van acá y no como margen de la caja. El
       margen del primer hijo en flujo se escapa del padre y empuja la sección
       entera: la sección arrancaba en 128, y el SVG, que se posiciona contra
       ella, quedaba 128 más abajo que su contenido. */
    padding: 128px 0 60px;
  }

  /* La caja del rectángulo. Ancho fijo a 354 —el del frame— y centrada: sin
     el tope, a 767 de ventana la tapa se iría a 679 de ancho y su alto, que
     sale de la proporción, se dispararía. */
  .conseguila__dentro {
    position: relative;
    inset: auto;
    width: min(354px, 100% - 2 * var(--m-margen));
    margin: 0 auto;
    padding: 22px 20px 20px;
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: start;
    /* El recorte de escritorio era contra una figura que se movía sola. Acá
       la figura ES esta caja, así que alcanza con esconder lo que sobresale:
       mientras la caja crece, el formulario se va destapando en vez de
       aparecer de golpe por fuera. */
    clip-path: none;
    overflow: hidden;
    /* El alto lo escribe js/fuga.js al cambiar de paso, en píxeles: `auto` no
       se puede transicionar. Al llegar vuelve a `auto`, que es lo que deja que
       la caja crezca sola si después se despliega un campo. */
    transition: height var(--t-largo) var(--muta);
  }
  /* El relleno de abajo. Es el violeta plano, metido hacia adentro para que
     no asome nunca por el borde ondulado del SVG, que se desplaza hasta 12.
     Está para que la caja jamás se vea vacía: ni en el primer cuadro, antes
     de que el script dibuje la figura, ni en medio del crecimiento. */
  .conseguila__dentro::before {
    content: "";
    position: absolute;
    inset: 14px;
    z-index: -1;
    background-color: var(--violeta-principal);
  }
  .conseguila.paso-ficha .conseguila__dentro { padding-bottom: 29px; }

  /* El SVG no acompaña a la caja: se queda quieto, bien alto, y lo único que
     cambia adentro es el alto de la figura. Si el SVG creciera, cambiaría el
     viewBox y con él la región del filtro, y la turbulencia se recalcularía
     en cada cuadro: el grano nadaría y el teléfono se arrastraría. */
  .conseguila .lienzo {
    inset: auto;
    left: 50%;
    translate: -50% 0;
    top: 128px;
    width: min(354px, 100% - 2 * var(--m-margen));
    height: 1400px;            /* más que el formulario más largo posible */
  }

  /* --- las piezas, en orden --- */

  .ficha__encabezado,
  .ficha__tapa,
  .ficha__precio,
  .ficha__reservar,
  .compra,
  .compra__cantidad,
  .novedades,
  .compra__aviso,
  .compra__confirmar,
  .compra__gracias {
    position: static;
    left: auto;
    top: auto;
    right: auto;
    width: auto;
    transform: none;
  }

  .ficha__encabezado {
    grid-area: 1 / 1 / 2 / 3;
    font-size: 20px;
    gap: 8px;
  }

  .ficha__tapa {
    grid-area: 2 / 1 / 3 / 3;
    margin-top: 20px;
    width: 100%;                /* 314, el ancho útil de la caja */
    aspect-ratio: 313 / 421;
    transition: width var(--t-largo) var(--muta),
                opacity var(--t-medio) var(--entra) var(--retardo, 0ms),
                translate var(--t-medio) var(--entra) var(--retardo, 0ms),
                border-color var(--t-corto) ease;
  }
  /* Cuánto encoge la tapa: 150 de los 314 útiles. Va como variable porque
     js/fuga.js necesita el mismo número para saber cuánto va a medir la caja
     cuando la tapa termine de encoger, y no hay dos sitios donde escribirlo. */
  .conseguila__dentro { --tapa-form: 47.7707%; }
  .conseguila.paso-formulario .ficha__tapa { width: var(--tapa-form); }   /* 150 */

  .ficha__precio {
    grid-area: 3 / 1 / 4 / 2;
    margin-top: 20px;
    font-size: 20px;
    line-height: 1.25;
  }
  .ficha__reservar {
    grid-area: 3 / 2 / 4 / 3;
    margin-top: 20px;
    justify-self: end;
    font-size: 20px;
  }

  .compra__cantidad {
    grid-area: 4 / 1 / 5 / 3;
    margin-top: 20px;
    display: flex;
    align-items: baseline;
    gap: 36px;                  /* "Cantidad:" termina en 127, el número va en 163 */
    font-size: 20px;
    line-height: 1.25;
  }
  /* Sin ancho propio: hereda el de escritorio, que está en `ch` y se acomoda
     solo a estos 20 de cuerpo. */
  .compra__cantidad input { font-size: 20px; padding-bottom: 0; }

  /* En los dos frames el subrayado va pegado al pie del renglón, sin los 5 de
     aire que lleva en escritorio: la línea de RESERVAR cae en 704 y el texto
     termina ahí, y lo mismo CONFIRMAR en 1284. Son todas mayúsculas, así que
     no hay nada que baje que la pueda tocar. */
  .boton-subrayado { padding-bottom: 0; }

  /* Los campos, uno abajo del otro. En escritorio van en dos columnas con
     casillas fijas; acá el orden es el del frame, y como es una fila sola,
     esconder Zona de retiro cierra el hueco en vez de dejarlo. */
  .compra {
    grid-area: 5 / 1 / 6 / 3;
    margin-top: 50px;
    display: flex;
    flex-direction: column;
    gap: 20px;
  }
  .compra .campo:nth-of-type(1) { order: 1; }   /* nombre  */
  .compra .campo:nth-of-type(2) { order: 2; }   /* correo  */
  .compra .campo:nth-of-type(3) { order: 4; }   /* entrega */
  .compra .campo:nth-of-type(4) { order: 3; }   /* celular */
  .compra .campo:nth-of-type(5) { order: 5; }   /* zona    */
  .compra .campo:nth-of-type(6) { order: 6; }   /* pago    */
  .compra__nota { order: 5; grid-area: auto; align-self: auto; }

  .campo { gap: 10px; }
  .campo > span { font-size: 16px; }
  .campo input,
  .campo select {
    height: 45px;
    padding: 0 10px;
    font-size: 20px;
  }

  .novedades {
    grid-area: 6 / 1 / 7 / 3;
    margin-top: 30px;
    gap: 10px;                  /* el texto arranca a 30 del borde de la caja */
    font-size: 16px;
  }
  .novedades::before { width: 20px; }

  .compra__aviso {
    grid-area: 7 / 1 / 8 / 3;
    margin-top: 30px;
    font-size: 16px;
    line-height: 1.375;
  }

  /* Del mismo cuerpo que RESERVAR y no de 24: son el mismo botón en los dos
     pasos, y verlo cambiar de tamaño al abrir el formulario lo delata como
     dos cosas distintas. */
  .compra__confirmar {
    grid-area: 8 / 2 / 9 / 3;
    margin-top: 73px;
    justify-self: end;
    font-size: 20px;
  }

  .compra__gracias {
    grid-area: 9 / 1 / 10 / 3;
    font-size: 20px;
  }

  .compra__error {
    position: static;
    grid-area: 8 / 1 / 9 / 2;
    align-self: center;
    width: auto;
    font-size: var(--m-16);
  }

  /* El viaje horizontal del formulario es de escritorio: ahí la tapa se va a
     la izquierda y el formulario entra por la derecha, a la par. Acá la tapa
     no viaja, encoge, y lo que entra lo hace desde abajo con la caja. */
  .compra,
  .novedades,
  .compra__cantidad,
  .compra__confirmar,
  .compra__aviso {
    transform: none;
    translate: 0 16px;
  }
  .paso-formulario .compra,
  .paso-formulario .novedades,
  .paso-formulario .compra__cantidad,
  .paso-formulario .compra__confirmar,
  .paso-formulario .compra__aviso { translate: none; }

  /* Con la ficha puesta, lo del formulario no ocupa lugar: si solo se
     apagara, la caja seguiría midiendo lo que mide el formulario entero. */
  .conseguila.paso-ficha .compra,
  .conseguila.paso-ficha .novedades,
  .conseguila.paso-ficha .compra__cantidad,
  .conseguila.paso-ficha .compra__confirmar,
  .conseguila.paso-ficha .compra__aviso { display: none; }
}


/* =========================================================================
   EL MOUSE — todo lo que se enciende al pasar por encima

   Va junto y detrás de una pregunta: ¿hay un puntero que pueda pasar por
   encima sin tocar? En una pantalla táctil no lo hay, y ahí el :hover es una
   trampa. El navegador se lo aplica igual al primer toque, se come ese toque
   para "pasar por encima", y hay que tocar de nuevo para que algo pase; y
   cuando pasa, el estado queda pegado hasta que se toque en otro lado. Eso
   era la tapa de Conseguila que a veces no respondía y se quedaba amarilla.

   El encendido no se pierde en el celular: lo hereda :active, que está en las
   reglas de arriba. En el escritorio los dos conviven —se enciende al pasar y
   sigue encendido al apretar—, y en el teléfono queda solo mientras el dedo
   está apoyado, que es lo que un dedo puede decir.
   ========================================================================= */

@media (hover: hover) and (pointer: fine) {
  .nav a:hover { color: var(--blanco-1); }
  .nav a.venta:hover,
  .chrome__venta:hover,
  .libreria__ir:hover { text-decoration-color: currentColor; }

  /* El renglón del circuito se enciende al pasar por encima. En las
     presentaciones que ya pasaron, además aparece la foto. */
  .circuito__fecha:hover { color: var(--blanco-1); }
  .redes__boton:hover,
  .redes__enlace:hover { color: var(--blanco-1); }
  .marca:hover { color: var(--blanco-1); }

  .indice a:hover {
    color: color-mix(in oklab,
                     var(--amarillo-principal) calc(max(var(--cerca), var(--final)) * 100%),
                     var(--blanco-1));
  }

  .conseguila__dentro:has(.ficha__tapa:hover) .ficha__encabezado,
  .ficha__encabezado:hover { color: var(--amarillo-principal); }
  .conseguila__dentro:has(.ficha__encabezado:hover) .ficha__tapa,
  .ficha__tapa:hover { border-color: var(--amarillo-principal); }
  .ficha__volver:hover { color: var(--blanco-1); }

  .boton-subrayado:hover { color: var(--amarillo-principal); }
  .requisito__titulo:hover { color: var(--amarillo-principal); }
  .conv__envio a:hover { border-bottom-color: currentColor; }
}

/* Y el recuadro gris que el navegador dibuja solo al tocar: sobra, porque
   ahora cada cosa dice por su cuenta que está siendo apretada. */
@media (hover: none) {
  a, button, label, summary, [role="button"] { -webkit-tap-highlight-color: transparent; }
}
