/* ═══════════════════════════════════════════════════════════════════════════
   BASE Y COMPONENTES — compartidos por las versiones A, B y C
   ═══════════════════════════════════════════════════════════════════════════
   Aquí vive lo que las tres versiones comparten: la base tipográfica, el
   botón, la tarjeta, la etiqueta, la ventana de producto y el nav. Lo que
   cambia entre versiones es la COMPOSICIÓN, y ésa vive en cada página.

   Ni un color, tamaño, espacio, radio o sombra escrito a mano: todo sale de
   tokens.css. La prueba `sin literales fuera de :root` del chequeo lo verifica
   en cada corrida, así que no es una convención sino un contrato.
   ═════════════════════════════════════════════════════════════════════════ */

/* ── reset corto ──────────────────────────────────────────────────────────── */
*,*::before,*::after{box-sizing:border-box}
html{
  -webkit-text-size-adjust:100%;
  /* Lenis lo maneja donde exista; aquí se deja el del navegador. Nunca
     `scroll-behavior:smooth` a la vez que Lenis: pelean y el scroll da tirones
     (HANDOFF.md, 25-sep). */
  scroll-behavior:auto;
  /* Safari de iPhone ensancha la ventana si algo (las líneas del hero, la
     marquesina) asoma por la derecha: se recorta en la raíz. `clip`, no
     `hidden`, para no romper el nav fijo ni el scroll. */
  overflow-x:clip;
}
body{
  margin:0;
  background:var(--bg);
  color:var(--fg-body);
  font-family:var(--font-sans);
  font-size:var(--t-body);
  font-weight:var(--w-body);
  line-height:var(--lh-body);
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}
img,svg,video{display:block;max-width:100%}
a{color:inherit}
h1,h2,h3,p,ul,ol,figure{margin:0}
ul,ol{padding:0;list-style:none}
button{font:inherit;color:inherit}

/* El ancla del scroll: el nav es sticky, así que un salto a #algo lo deja
   debajo de la barra si no se reserva su alto. Vale para cualquier elemento
   con id, no sólo para las secciones: el CTA «Ver cómo funciona» apunta a la
   ventana de producto, que es un div. */
:where([id]){scroll-margin-top:calc(var(--nav-h) + var(--s-5))}

/* Foco visible en todo lo que se puede enfocar. Va con outline y no con
   box-shadow para que no lo tape un `overflow:hidden`. */
:focus-visible{
  outline:2px solid var(--fg);
  outline-offset:3px;
  border-radius:var(--r-1);
}

/* ── layout ───────────────────────────────────────────────────────────────── */
.wrap{
  width:100%;
  max-width:var(--maxw);
  margin-inline:auto;
  padding-inline:var(--gutter);
}
.section{padding-block:var(--s-section)}
.section--alt{background:var(--bg-alt)}
.section--dark{background:var(--bg-dark);color:var(--fg-on-dark)}

/* Sólo para lectores de pantalla. */
.sr-only{
  position:absolute;width:1px;height:1px;
  margin:-1px;padding:0;border:0;
  overflow:hidden;clip-path:inset(50%);white-space:nowrap;
}

/* ── tipografía ───────────────────────────────────────────────────────────── */
.display{
  font-size:var(--t-display);
  font-weight:var(--w-display);
  letter-spacing:var(--track-display);
  line-height:var(--lh-display);
  color:var(--fg);
  text-wrap:balance;
}
/* El segundo tono del titular. Es el gris que pasa AA de texto grande sobre
   blanco Y sobre el lavado pastel del hero; no es decorativo, es medido. */
.display .t2{color:var(--fg-2)}
/* La segunda línea se equilibra sola (#22). Chrome no equilibra un párrafo
   con un <br> dentro, y a 390 y 360 quedaban viudas: «vida.» en el hero y
   «solo» en los pasos. Como bloque, el segundo tono es su propio párrafo y
   el `balance` lo parte en líneas parejas; si cabe en una, no cambia nada. El <br> sigue en el HTML para
   leer sin CSS. */
.display .t2,.h2 .t2{display:block}

.h2{
  font-size:var(--t-h2);
  font-weight:var(--w-display);
  letter-spacing:var(--track-h2);
  line-height:var(--lh-display);
  color:var(--fg);
  text-wrap:balance;
}
.h3{
  font-size:var(--t-h3);
  font-weight:var(--w-semi);
  line-height:var(--lh-h3);
  color:var(--fg);
}
.lead{
  font-size:var(--t-lead);
  color:var(--fg-body);
  max-width:var(--measure);
  text-wrap:pretty;
}
.fineprint{
  font-size:var(--t-small);
  color:var(--fg-muted);
}
.section--dark .h2,.section--dark .h3{color:var(--fg-on-dark)}
/* El segundo tono también en los titulares de sección: la regla de la v2 es
   «titulares de sección con el mismo tratamiento» que el del hero. Hasta #31
   sólo existía la de .display y los de sección salían enteros en tinta. El h2
   mide 32px o más en 700, así que --fg-2 (AA de texto grande) le alcanza.
   Sobre oscuro, el gris medido ahí. */
.h2 .t2{color:var(--fg-2)}
.section--dark .h2 .t2{color:var(--fg-on-dark-2)}
.section--dark .lead{color:var(--fg-on-dark-2)}
/* --fg-muted está medido contra blanco (4.94:1) y sobre tinta cae a 3.4:1, que
   no pasa AA ni de cerca. Sobre oscuro el fineprint usa el gris que sí está
   medido ahí (6.69:1). */
.section--dark .fineprint,.pie .fineprint{color:var(--fg-on-dark-2)}

/* ── etiqueta ─────────────────────────────────────────────────────────────── */
/* Mono pequeña y en mayúsculas, SÓLO para metadatos. Nunca para un párrafo:
   el detector de julio lo marca como all-caps-body y con razón. */
.tag{
  display:inline-block;
  font-family:var(--font-mono);
  font-size:var(--t-label);
  font-weight:var(--w-medium);
  letter-spacing:var(--track-label);
  text-transform:uppercase;
  color:var(--fg-muted);
}
.tag--boxed{
  padding:var(--s-1) var(--s-2);
  border:1px solid var(--line);
  border-radius:var(--r-pill);
}
/* El verde como firma: fondo verde con el contenido en tinta. Es la ÚNICA
   forma en que el verde puede tocar un texto, con 9.74:1 de tinta sobre verde.
   Como color de texto sobre blanco mide 1.78:1 y por eso no existe ese token. */
.tag--ok{
  background:var(--firma);
  color:var(--fg-on-firma);
  border-color:transparent;
}
.section--dark .tag{color:var(--fg-on-dark-2)}
.section--dark .tag--boxed{border-color:var(--line-on-dark)}
.section--dark .tag--ok{color:var(--fg-on-firma)}

/* ── botón ────────────────────────────────────────────────────────────────── */
.btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:var(--s-2);
  padding:var(--s-4) var(--s-6);
  border:1px solid transparent;
  border-radius:var(--r-pill);
  font-size:var(--t-small);
  font-weight:var(--w-semi);
  line-height:1;
  text-decoration:none;
  white-space:nowrap;
  cursor:pointer;
  transition:transform var(--d-1) var(--e-out),background-color var(--d-1) var(--e-out),border-color var(--d-1) var(--e-out);
}
.btn--lg{padding:var(--s-5) var(--s-7);font-size:var(--t-body)}
.btn--sm{padding:var(--s-3) var(--s-5)}

.btn--primary{
  background:var(--fg);
  color:var(--bg);
  box-shadow:var(--sh-btn);
}
.btn--secondary{
  background:var(--g-100);
  color:var(--fg);
}
.btn:hover{transform:translateY(-1px)}
.btn--primary:hover{background:var(--g-700)}
.btn--secondary:hover{background:var(--g-200)}
.btn:active{transform:translateY(0)}

/* Sobre superficie oscura el primario se invierte: blanco con texto tinta. */
.section--dark .btn--primary{background:var(--fg-on-dark);color:var(--brand-ink)}
.section--dark .btn--primary:hover{background:var(--g-200)}
.section--dark .btn--secondary{background:var(--line-on-dark);color:var(--fg-on-dark)}
.section--dark .btn--secondary:hover{background:var(--g-700)}

/* ── tarjeta ──────────────────────────────────────────────────────────────── */
.card{
  background:var(--bg);
  border:1px solid var(--line);
  border-radius:var(--r-4);
  box-shadow:var(--sh-card);
  padding:var(--s-6);
}
/* La cifra o la palabra suelta de una tarjeta (MIT, $0, Self-host). Va en
   --t-step y NO en --t-h2: el titular de sección llega a 64px, y a ese tamaño
   «Self-host» dentro de una tarjeta pesa más que el titular que la introduce. */
.card__fig{
  font-size:var(--t-step);
  font-weight:var(--w-display);
  letter-spacing:var(--track-h2);
  line-height:1;
  color:var(--fg);
}
.card__cap{font-size:var(--t-small);color:var(--fg-muted);margin-top:var(--s-2)}
.section--dark .card{background:var(--g-700);border-color:var(--line-on-dark);box-shadow:none}
.section--dark .card__fig{color:var(--fg-on-dark)}
.section--dark .card__cap{color:var(--fg-on-dark-2)}

/* ── ventana de producto ──────────────────────────────────────────────────── */
/* El producto vive aquí: el panel gris claro con una sombra amplia y suave
   sobre el fondo claro (#30). El panel es EXACTAMENTE el gris del fondo de
   los vídeos en claro (--window-chrome). Si se separan, se ve un escalón de
   un pixel alrededor del clip. */
.window{
  position:relative;
  background:var(--window-chrome);
  border-radius:var(--r-5);
  box-shadow:var(--sh-window);
  overflow:hidden;
  /* El alto se reserva antes de que baje nada. Sin esto el póster llega y
     empuja media página: es el CLS que costó 0.19 en móvil en julio. */
  aspect-ratio:var(--window-ratio,16/9);
}
.window > video,
.window > img{
  width:100%;
  height:100%;
  object-fit:cover;
  border-radius:inherit;
}
/* El borde interior levanta el panel del fondo sin meter un segundo color:
   es la tinta a baja opacidad. */
.window::after{
  content:'';
  position:absolute;
  inset:0;
  border-radius:inherit;
  box-shadow:inset 0 0 0 1px var(--window-rim);
  pointer-events:none;
}

/* ── texto provisional ────────────────────────────────────────────────────── */
/* Copy que NO está aprobado. Se marca con `data-provisional` para buscarlo con
   grep antes de publicar. La marca no se ve (#49): antes llevaba un subrayado
   punteado y en la revisión se leía como un enlace o un error. No hay regla
   aquí a propósito. Desde el #25 el copy de la final es el definitivo y no
   lleva ninguna marca (guard-copy.sh para el build si vuelve); quedan sólo
   en B y C, que son de trabajo. */

/* ── titulares con movimiento (#47) ───────────────────────────────────────── */
/* El titular del hero y los h2, partidos por shared/titulares.js en palabras
   y letras. Todo lo de aquí cuelga de clases que pone ese script, así que
   sin él (o con movimiento reducido, donde no se arma) el titular se ve tal
   como está en el HTML. */
.tit__palabra{
  display:inline-block;
  transform-origin:50% 100%;
}
/* La entrada es un pop (#49): palabras escondidas, más abajo y más chicas
   hasta que el titular llega a la pantalla; después suben de a una, se pasan
   de su sitio y vuelven. El fundido es corto: la palabra se ve ya mientras
   rebota.
   La transición cuelga sólo de «entra»: pasar a «espera» es instantáneo. El
   script se arma después de `load`, con la página ya pintada, y con la
   transición en las dos direcciones las palabras de abajo tardaban casi un
   segundo en terminar de esconderse. */
.tit[data-tit="espera"] .tit__palabra{
  opacity:0;
  transform:translateY(var(--tit-sube)) scale(var(--tit-escala));
}
.tit[data-tit="entra"] .tit__palabra{
  transition:opacity var(--d-2) var(--e-out),transform var(--d-tit) var(--e-spring);
  transition-delay:calc(var(--i) * var(--d-escalon));
}
/* El rebote de verdad es --e-rebote, un linear() de resorte; donde linear()
   no existe queda el overshoot corto de --e-spring. */
@supports (transition-timing-function:linear(0,1)){
  .tit[data-tit="entra"] .tit__palabra{transition-timing-function:var(--e-out),var(--e-rebote)}
}
/* La ola del cursor: el peso sale del eje `wght` y no de font-weight, que es
   lo que se puede animar letra por letra. En reposo vale lo mismo que el
   font-weight del titular.
   Chrome recorta `font-variation-settings` al rango del @font-face, y el de
   cada versión declara de 400 a 700: con él, la ola llegaba a 900 en el estilo y
   se pintaba en 700. Esta cara es el MISMO fichero (ya bajado, sale de la
   caché) con el eje entero, y sólo la usan las letras de un titular armado
   para la ola. */
@font-face{font-family:'Hanken Grotesk Ola';font-style:normal;font-weight:100 900;font-display:swap;
  src:url("../assets/fonts/hanken-grotesk-latin-wght.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
.tit--ola .tit__letra{
  font-family:'Hanken Grotesk Ola',var(--font-sans);
  font-variation-settings:"wght" var(--peso,var(--w-display));
  transition:font-variation-settings var(--d-1) var(--e-out);
}

/* ── nav ──────────────────────────────────────────────────────────────────── */
.nav{
  position:sticky;
  top:0;
  z-index:var(--z-nav);
  background:var(--bg);
  box-shadow:var(--sh-nav);
}
.nav__in{
  display:flex;
  align-items:center;
  gap:var(--s-6);
  height:var(--nav-h);
}
.nav__brand{display:flex;align-items:center;text-decoration:none;flex:0 0 auto}
/* Marca y logotipo comparten la altura de la F a propósito (KIT.md): cambiar
   uno por otro en el breakpoint no cambia el tamaño de la letra. */
.nav__brand img{height:var(--s-5);width:auto}
.nav__wordmark{display:none}
.nav__links{
  display:none;
  gap:var(--s-6);
  margin-inline-start:var(--s-2);
}
.nav__links ul{display:contents}
.nav__links a{
  font-size:var(--t-small);
  font-weight:var(--w-medium);
  color:var(--fg-body);
  text-decoration:none;
  transition:color var(--d-1) var(--e-out);
}
.nav__links a:hover{color:var(--fg)}
.nav__end{display:flex;align-items:center;gap:var(--s-4);margin-inline-start:auto}

/* Idioma. El actual no es un enlace —no se navega a donde ya estás— y el otro
   sólo es enlace cuando esa página existe; si no, sale como texto inerte. El
   guardia de nav-links.js decide cuál de los dos. */
.nav__lang{
  display:flex;
  align-items:center;
  gap:var(--s-1);
  font-size:var(--t-label);
  font-family:var(--font-mono);
  letter-spacing:var(--track-label);
  color:var(--fg-muted);
}
.nav__lang [aria-current]{color:var(--fg);font-weight:var(--w-medium)}
.nav__lang a{text-decoration:none}
.nav__lang a:hover{color:var(--fg)}
/* Sin `opacity`: bajarle la opacidad a --fg-muted lo deja en ~2:1 sobre
   blanco y se salta los grises medidos de tokens.css. Que esté inerte ya lo
   dice `aria-disabled` al lector de pantalla. */
.nav__lang [aria-disabled='true']{cursor:default}

/* En móvil el menú de secciones no cabe y se esconde; el blog no es una
   sección de la página, así que sale suelto junto al idioma. */
.nav__blog{
  font-size:var(--t-small);
  font-weight:var(--w-medium);
  color:var(--fg-body);
  text-decoration:none;
}
.nav__blog:hover{color:var(--fg)}
@media (max-width:399px){.nav__end{gap:var(--s-2)}}
/* Por debajo de 370 px no cabe junto al botón: queda el enlace del pie. */
@media (max-width:369px){.nav__blog{display:none}}

@media (min-width:900px){
  .nav__mark{display:none}
  .nav__wordmark{display:block}
  .nav__links{display:flex}
  .nav__blog{display:none}
}

/* ── placeholder ──────────────────────────────────────────────────────────── */
/* Lo que todavía no existe se ve INTENCIONAL, no roto. Un placeholder dice dos
   cosas y nada más: qué pieza va ahí y qué ticket la trae. Nunca reproduce
   nada, nunca imita el contenido final y nunca se queda en blanco.

   Va sobre `.window`, así que hereda el panel gris claro, el radio, la sombra
   y el alto reservado del componente de producto: cuando llegue la pieza, el
   hueco que ocupa ya es exactamente el suyo, del mismo gris que el fondo del
   vídeo, y la página no se mueve. El rótulo va en los grises medidos sobre
   claro: --fg-muted da 5.15:1 sobre el panel. */
.ph{
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:var(--s-3);
  padding:var(--s-6);
  text-align:center;
}
.ph__pieza{
  font-family:var(--font-mono);
  font-size:var(--t-small);
  color:var(--fg);
}
.ph__que{
  font-size:var(--t-small);
  color:var(--fg-muted);
  max-width:var(--measure);
}
/* El ticket, en la misma píldora de metadato que el resto de la página. Va
   en blanco sobre el panel, como los componentes de los vídeos en claro: un
   filete de --line sobre el gris del panel casi no se ve. */
.ph__tk{
  padding:var(--s-1) var(--s-3);
  border:1px solid var(--line);
  border-radius:var(--r-pill);
  background:var(--bg);
  font-family:var(--font-mono);
  font-size:var(--t-label);
  letter-spacing:var(--track-label);
  color:var(--fg-muted);
}
/* El de dentro de una tarjeta del carrusel: más bajo, más apretado y con el
   radio de la tarjeta, no el de la ventana. */
.ph--mini{
  --window-ratio:16/10;
  gap:var(--s-2);
  padding:var(--s-4);
  border-radius:var(--r-3);
}

/* En pantalla angosta el hueco deja de tener proporción y crece con su rótulo.
   Un 16/9 sobre los 320px que quedan a 360 son 180px de alto, y el rótulo
   ocupa 218: el nombre de la pieza se cortaba contra el borde, que es
   exactamente el placeholder roto que no puede haber. `min-height:min-content`
   no sirve —la proporción le gana en Chrome, medido—, así que aquí se quita.

   Lo que se pierde es que el hueco deje reservado en móvil el alto exacto de
   la pieza que vendrá. Se pierde a sabiendas: el ticket que traiga la pieza
   vuelve a componer su sección, y un rótulo recortado es peor que un
   reacomodo. Las mini del carrusel se quedan como están: su rótulo son dos
   líneas y cabe de sobra. */
@media (max-width:640px){
  .ph:not(.ph--mini){
    aspect-ratio:auto;
    padding-block:var(--s-8);
  }
}

/* La variante que NO es una ventana: una nota al pie de una pieza que ya está
   pero a la que le falta algo (la marquesina tiene los nombres, le faltan los
   logos). Va sobre fondo claro y se lee como metadato, no como copy. */
.ph-nota{
  display:inline-flex;
  align-items:center;
  gap:var(--s-2);
  padding:var(--s-2) var(--s-4);
  border:1px dashed var(--line);
  border-radius:var(--r-pill);
  font-family:var(--font-mono);
  font-size:var(--t-label);
  letter-spacing:var(--track-label);
  text-transform:uppercase;
  color:var(--fg-muted);
}

/* ── marquesina ───────────────────────────────────────────────────────────── */
/* Un raíl de nombres que corre despacio, con los dos bordes desvanecidos. El
   track lleva la lista DUPLICADA y se desplaza justo la mitad: al terminar
   está exactamente donde empezó y el bucle no tiene costura.

   La separación va en `margin-inline-end` de cada ítem y NO en `gap` del
   track. Con `gap`, la mitad del ancho no cae en el mismo punto del patrón
   (sobra media separación) y se ve un salto en cada vuelta. */
.mq{
  position:relative;
  overflow:hidden;
  -webkit-mask-image:linear-gradient(to right,transparent,var(--matte) var(--fade),var(--matte) calc(100% - var(--fade)),transparent);
  mask-image:linear-gradient(to right,transparent,var(--matte) var(--fade),var(--matte) calc(100% - var(--fade)),transparent);
}
.mq__track{
  display:flex;
  width:max-content;
  animation:mq-correr var(--d-marquesina) linear infinite;
  /* Se compone en la GPU y no toca el layout: es lo que pide HANDOFF.md para
     no meter cuadros largos en el scroll. */
  will-change:transform;
}
.mq--rev .mq__track{animation-direction:reverse}
/* Fuera de pantalla no se mueve nada (regla de movimiento de PLAN-V2 §4). La
   clase la pone shared/vista.js.
   Se suelta también el `will-change`: pausada, la promesa de que esto se va a
   mover es mentira, y mantenerla deja dos capas de compositor vivas por dos
   raíles que están a pantallas de distancia. */
.mq.fuera .mq__track{animation-play-state:paused;will-change:auto}
/* El paso es una copia: la mitad con la lista y una copia, y lo que calcule
   completarMarquesinas() de shared/vista.js cuando hacen falta más. */
@keyframes mq-correr{
  from{transform:translateX(0)}
  to{transform:translateX(var(--mq-paso,-50%))}
}

.mq__item{
  display:inline-flex;
  align-items:center;
  gap:var(--s-3);
  margin-inline-end:var(--s-5);
  padding:var(--s-3) var(--s-5);
  border:1px solid var(--line);
  border-radius:var(--r-pill);
  background:var(--bg);
  box-shadow:var(--sh-card);
  font-size:var(--t-small);
  font-weight:var(--w-medium);
  color:var(--fg);
  white-space:nowrap;
}
/* El hueco del logo oficial. Es un placeholder de un cuadrado, no un logo
   inventado: los oficiales llegan con su ticket. */
.mq__logo{
  flex:0 0 auto;
  width:var(--s-5);
  height:var(--s-5);
  border-radius:var(--r-1);
  background:var(--g-200);
}

/* Con movimiento reducido no hay marquesina: el raíl se convierte en un
   racimo centrado que cabe entero. Es obligatorio y no un detalle — el bloque
   de `prefers-reduced-motion` de más abajo congela la animación, y un raíl
   congelado deja la mitad de los nombres recortados y sin forma de llegar a
   ellos. Se esconde la copia, que sólo existía para cerrar el bucle. */
@media (prefers-reduced-motion:reduce){
  .mq{-webkit-mask-image:none;mask-image:none}
  .mq__track{
    flex-wrap:wrap;
    justify-content:center;
    width:auto;
    gap:var(--s-3);
    animation:none;
    will-change:auto;
  }
  .mq__item{margin-inline-end:0}
  .mq__item--copia{display:none}
}

/* ── raíl de tarjetas ─────────────────────────────────────────────────────── */
/* El carrusel. Se desplaza DENTRO de su fila, nunca la página: por eso el
   `overflow-x` vive aquí y los márgenes negativos llegan justo al borde del
   contenedor, no más allá.

   Las tarjetas son de ancho FIJO. Con `1fr` se encogerían hasta que cupieran
   las diez y dejaría de ser un raíl. */
.rail{
  display:flex;
  gap:var(--s-5);
  margin-inline:calc(var(--gutter) * -1);
  /* El padding devuelve el margen: la primera tarjeta arranca alineada con el
     resto de la página y la última puede llegar al borde. */
  padding-inline:var(--gutter);
  /* Sitio para que la sombra de la tarjeta no salga cortada arriba y abajo. */
  padding-block:var(--s-2);
  overflow-x:auto;
  overscroll-behavior-x:contain;
  scroll-snap-type:x mandatory;
  scrollbar-width:thin;
}
.rail > *{
  flex:0 0 var(--w-tarjeta);
  scroll-snap-align:start;
}

/* ── tabla de comparación ─────────────────────────────────────────────────── */
.tabla{width:100%;border-collapse:collapse}
.tabla th,.tabla td{
  padding:var(--s-4);
  border-bottom:1px solid var(--line);
  font-size:var(--t-small);
  text-align:start;
  vertical-align:top;
}
.tabla thead th{
  font-family:var(--font-mono);
  font-size:var(--t-label);
  font-weight:var(--w-medium);
  letter-spacing:var(--track-label);
  text-transform:uppercase;
  color:var(--fg-muted);
}
.tabla tbody th{font-weight:var(--w-semi);color:var(--fg)}
.tabla td{color:var(--fg-body)}
/* La columna propia se marca con peso, no con color: el verde no se lee sobre
   blanco y un segundo tinte rompería la página monocroma. */
.tabla [data-col='dForms']{color:var(--fg);font-weight:var(--w-semi)}

/* A 390 y 360 tres columnas dejan «Analítica por pregunta» en cuatro líneas de
   dos palabras. Cada fila pasa a ser un bloque: el nombre de la función arriba
   y debajo las dos respuestas, cada una con su columna delante. */
@media (max-width:640px){
  .tabla,.tabla tbody,.tabla tr,.tabla th,.tabla td{display:block}
  /* Misma receta que `.sr-only` de más arriba, repetida a sabiendas: la
     cabecera sólo se esconde a esta anchura y una clase en el marcado no puede
     aparecer y desaparecer con una media query. Si se toca una, se tocan las
     dos. Se esconde en vez de borrarse porque los nombres de columna siguen
     haciendo falta a quien no ve el `::before` de cada celda. La receta
     va en cada celda y no en el <thead>: con la cabecera recortada, cada <th>
     de bloque medía su texto dentro de una caja de 1 px y se leía como texto
     desbordado (el detector de Impeccable, #22). La fila de la cabecera
     queda sin alto y sin filete. */
  .tabla thead tr{padding:0;border:0}
  .tabla thead th{
    position:absolute;width:1px;height:1px;
    margin:-1px;padding:0;border:0;
    overflow:hidden;clip-path:inset(50%);white-space:nowrap;
  }
  .tabla tr{padding-block:var(--s-4);border-bottom:1px solid var(--line)}
  .tabla th,.tabla td{padding:0;border-bottom:0}
  .tabla tbody th{margin-bottom:var(--s-3);font-size:var(--t-body)}
  .tabla td{
    display:flex;
    justify-content:space-between;
    gap:var(--s-4);
    padding-block:var(--s-2);
    text-align:end;
  }
  .tabla td::before{
    content:attr(data-col);
    flex:0 0 auto;
    font-family:var(--font-mono);
    font-size:var(--t-label);
    letter-spacing:var(--track-label);
    text-transform:uppercase;
    color:var(--fg-muted);
  }
}

/* ── pie ──────────────────────────────────────────────────────────────────── */
.pie{background:var(--bg-dark);color:var(--fg-on-dark)}
.pie__cols{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(var(--w-col),1fr));
  gap:var(--s-7);
  padding-block:var(--s-8);
}
.pie__tit{
  font-family:var(--font-mono);
  font-size:var(--t-label);
  font-weight:var(--w-medium);
  letter-spacing:var(--track-label);
  text-transform:uppercase;
  color:var(--fg-on-dark-2);
  margin-bottom:var(--s-4);
}
.pie__lista{display:grid;gap:var(--s-3)}
.pie__lista a{
  font-size:var(--t-small);
  color:var(--fg-on-dark);
  text-decoration:none;
}
.pie__lista a:hover{color:var(--fg-on-dark-2)}
.pie__fin{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  justify-content:space-between;
  gap:var(--s-4);
  padding-block:var(--s-5);
  border-top:1px solid var(--line-on-dark);
}
.pie__marca{display:flex;align-items:center;gap:var(--s-2)}
.pie__marca img{height:var(--s-5);width:auto}

/* ── zona de toque ────────────────────────────────────────────────────────── */
/* Los enlaces chicos del nav y del pie se tocan con el dedo (#22): la marca
   medía 38 × 24, «EN» 16 × 19, el botón del nav 41 de alto y los enlaces del
   pie 20. Un ::before transparente y centrado les da --hit de lado sin mover
   nada de lo que se ve: el clic en él es un clic en el enlace. Los enlaces
   dentro de un párrafo quedan fuera, como deja WCAG para el texto corrido. */
.nav__brand,.nav__links a,.nav__lang a,.nav .btn,.pie__lista a,.pie__logo a{position:relative}
.nav__brand::before,.nav__links a::before,.nav__lang a::before,.nav .btn::before,.pie__lista a::before,.pie__logo a::before{
  content:'';
  position:absolute;
  top:50%;
  left:50%;
  width:max(100%,var(--hit));
  height:max(100%,var(--hit));
  transform:translate(-50%,-50%);
}
/* Con 12 px entre enlaces del pie, dos zonas de 44 se pisaban. En pantalla de
   dedo la lista se abre hasta que cada zona queda entera: 20 de texto más 24
   de hueco son los 44. */
@media (max-width:640px),(pointer:coarse){
  .pie__lista{gap:var(--s-5)}
}

/* ── movimiento reducido ──────────────────────────────────────────────────── */
/* Nada se mueve solo. Los vídeos los para player.js, que es quien sabe que
   además tienen que quedarse en el póster. */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:1ms !important;
    animation-iteration-count:1 !important;
    transition-duration:1ms !important;
    scroll-behavior:auto !important;
  }
}
