/*
 * La portada, en hoja propia y no en un `<style>` en línea: las dos
 * páginas —`/` y `/en/`— la comparten, y un `<style>` duplicado se
 * desincroniza en cuanto alguien toca una sola de las dos. (Además, la
 * CSP del sitio lleva `style-src 'self'` sin `'unsafe-inline'`: un
 * `<style>` en el HTML no llegaría a aplicarse.)
 *
 * Dos reglas gobiernan todo lo de abajo:
 *   · el cuerpo no pasa de `--lectura`, que es donde el ojo deja de
 *     saltar de línea con comodidad; la figura sí va a todo el ancho,
 *     porque lo que se compara en ella son cuatro formas y dentro del
 *     ancho de lectura no se distinguen;
 *   · nada lleva ancho fijo, para que a 390 px no aparezca la barra
 *     horizontal que obliga a leer arrastrando.
 *
 * `--lectura` NO se escribe en `ch`. El porqué está en su declaración, y
 * es un error que ya se cometió una vez.
 *
 * ── EL LENGUAJE VISUAL, Y DE DÓNDE SALE ──────────────────────────────
 *
 * Hasta aquí esta hoja no tomaba ni una decisión: blanco puro, la pila
 * de letra del sistema, azul de enlace por defecto. Se leía como una
 * maqueta porque lo era.
 *
 * Lo que hay ahora sale de DOS sitios, y de ninguno más:
 *
 * 1. **El logotipo**, que existía y no se usaba en ninguna parte.
 *    `img/logo-aideatext.png`: dos discos —azul y rojo—, un punto azul y
 *    un anillo fino, con la palabra en una serif de trazo grueso. De ahí
 *    salen los dos colores de marca, muestreados del archivo:
 *    **#0b7ec5** y **#ae0025**. Y de ahí sale que los titulares vayan en
 *    serif: la palabra del logotipo ya lo es.
 *
 * 2. **El enfoque editorial** de la referencia que señaló el dueño:
 *    fondo cálido en vez de blanco puro, titulares en serif, etiquetas
 *    cortas en monoespaciada encima del titular, radios generosos, ritmo
 *    modular. Es el ENFOQUE lo que se toma; la paleta es otra y los
 *    valores son otros.
 *
 * ── LOS DOS COLORES HACEN UN TRABAJO, NO ADORNAN ─────────────────────
 *
 * El azul y el rojo del logotipo no se reparten «uno para titulares y
 * otro para acentos». Cada uno significa una cosa, y siempre la misma:
 *
 *   · **AZUL** = lo que se hace. Los enlaces, el botón de la entrevista,
 *     el de reproducir, el foco del teclado. Es por donde se avanza.
 *   · **ROJO** = el límite. La delimitación de alcance del héroe
 *     («no medimos el razonamiento completo»), el fragmento destacado
 *     del pie de la figura («es una demostración…»), y la sección «Lo
 *     que no hace» entera.
 *
 * Esto importa más de lo que parece: la precisión epistémica costó once
 * rondas de revisión y hasta ahora se leía como un párrafo gris más. El
 * filete rojo es lo que la separa del resto sin cambiarle una letra.
 *
 * ⚠️ El azul de marca #0b7ec5 NO se usa para texto en ninguna parte:
 * sobre el papel da 4,13:1 y el mínimo de AA para cuerpo es 4,5:1. Para
 * texto va `--azul-hondo` (6,70:1), que es el mismo azul oscurecido.
 * Las cifras de las dos son medidas, no estimadas; están en la tabla de
 * `:root`.
 */

/* ── Las letras, servidas desde este dominio ──────────────────────────
 *
 * ⚠️ NI UNA PETICIÓN A GOOGLE FONTS, Y NO ES UNA PREFERENCIA. El sitio
 * sostiene con pruebas que la carga inicial no toca ningún tercero
 * (`seguridad.test.ts` → «ninguna referencia sale del propio dominio»),
 * y la CSP es `default-src 'self'`. Un `@import` a fonts.googleapis.com
 * pondría roja esa prueba y, en producción, la CSP bloquearía la hoja y
 * el sitio se quedaría sin letras.
 *
 * Los archivos están en `public/fonts/`, en `woff2`, subconjunto latino.
 * Fraunces e IBM Plex son SIL OFL; las licencias van al lado de los
 * archivos, que es lo que la OFL pide.
 *
 * El subconjunto latino cubre U+0000-00FF más los tramos de puntuación
 * tipográfica. **Comprobado sobre la copia real**, no supuesto: un
 * recorrido por los literales de `src/textos/es.ts` y `en.ts` no
 * encuentra un solo carácter fuera de ese rango — ni las tildes, ni la
 * `ñ`, ni los signos de apertura, ni la raya `—`, ni los puntos
 * suspensivos `…`, ni el `·` que separan las cuatro formas.
 *
 * `font-display: swap`: el texto se lee desde el primer momento con la
 * letra del sistema y cambia cuando llega la de verdad. La alternativa
 * —`block`— deja el titular invisible hasta que el archivo aterriza, y
 * el titular es lo único que se lee sin desplazar.
 *
 * Peso, leído de los archivos: 36 620 B Fraunces + 22 588 y 24 252 de
 * IBM Plex Sans + 14 888 de IBM Plex Mono = **98 348 B, 96,0 KiB**. Es
 * con diferencia lo más pesado que añade el rediseño, y por eso la
 * variable de Fraunces es la del eje `wght` a solas (36 620 B) y no la
 * completa con `opsz`, `SOFT` y `WONK` (67 304 B): aquí sólo se varía el
 * grosor, así que los otros tres ejes eran 30 684 B de nada.
 */

@font-face {
  font-family: 'Fraunces Variable';
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url(/fonts/fraunces-latin-wght-normal.woff2) format('woff2-variations');
  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;
}

@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-display: swap;
  font-weight: 400;
  src: url(/fonts/ibm-plex-sans-latin-400-normal.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;
}

@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-display: swap;
  font-weight: 600;
  src: url(/fonts/ibm-plex-sans-latin-600-normal.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;
}

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-display: swap;
  font-weight: 500;
  src: url(/fonts/ibm-plex-mono-latin-500-normal.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;
}

:root {
  /*
   * El papel. **Cálido, nunca blanco puro.** Un #ffffff detrás de un
   * texto largo es la superficie más dura que sabe hacer una pantalla, y
   * la página es larga: nueve secciones de prosa seguidas.
   *
   * No es el blanco de la referencia: ése tira a marfil frío. Éste tira a
   * papel de libro, que es lo que hace juego con una serif.
   */
  --papel: #fbf8f3;
  /* El panel: el mismo papel, un paso más hondo. Las tarjetas, la
     sección del límite, el pie y los campos del formulario. */
  --panel: #f2eee6;
  /* La tinta. No es negro: lleva el azul del logotipo dentro, igual que
     el papel lleva el amarillo. Un negro puro sobre un fondo cálido se
     ve como un agujero. 15,54:1 sobre el papel. */
  --tinta: #16202b;
  /* La tinta suave, para lo secundario: pies, glosas, etiquetas.
     6,64:1 sobre el papel y 6,08:1 sobre el panel — AA de cuerpo en las
     dos, que es lo que hace falta porque aquí hay frases enteras y no
     sólo rótulos. */
  --tinta-suave: #4e5a68;

  /*
   * Los dos colores de marca, MUESTREADOS del logotipo, no elegidos.
   * `#ae0025` es además el color más repetido del archivo después del
   * negro y el blanco (589 píxeles), que es el borde del disco rojo.
   */
  --azul: #0b7ec5;
  --rojo: #ae0025;

  /*
   * ⚠️ `--azul` NO SE USA PARA TEXTO. Da 4,13:1 sobre el papel y el
   * mínimo de AA para cuerpo es 4,5:1. Sirve para lo que no se lee: el
   * filete de la cabecera, el estado de foco, una línea.
   *
   * Para todo lo que se lee o se pulsa va éste, que es el mismo azul
   * bajado de luminosidad hasta que cumple por los dos lados:
   *   · texto azul sobre el papel ....... 6,70:1
   *   · texto blanco sobre él (el botón)  7,10:1
   */
  --azul-hondo: #0a5c92;

  /* El borde. Cálido, como el papel; un gris neutro aquí se ve verde. */
  --borde: #e5dfd4;

  /*
   * ── LAS SUPERFICIES OSCURAS ─────────────────────────────────────
   *
   * ⚠️ ESTO NO ES UN «MODO OSCURO» NI UNA PREFERENCIA ESTÉTICA. Las
   * cinco imágenes nuevas —los cuatro grafos y la comparación de
   * borradores— las dibuja el motor del producto sobre lienzo oscuro,
   * porque el color de cada nodo es viridis y viridis está hecha para
   * fondo oscuro: el extremo amarillo (#fde725) sobre papel cálido da
   * 1,2:1 y el nodo más importante del grafo sería el que menos se ve.
   *
   * O sea que las imágenes son oscuras porque los DATOS mandan que lo
   * sean. Lo que hace esta sección es dejar de fingir que no: el pie
   * de página y los marcos de las imágenes usan el mismo tono, de modo
   * que las láminas se lean como parte de la página y no como cinco
   * agujeros negros pegados encima del papel.
   *
   * `--tinta` es el color de TEXTO del sitio, reutilizado aquí como
   * superficie. No es un color nuevo: es el mismo #16202b.
   */
  /* El filete de las láminas oscuras. Más claro que el lienzo y más
     oscuro que el papel: separa la imagen del fondo sin dibujar una
     caja dentro de otra. */
  --borde-oscuro: #26323f;
  /*
   * El azul para texto SOBRE fondo oscuro. `--azul-hondo` está
   * oscurecido para leerse sobre papel y sobre #16202b da 2,3:1, que
   * es ilegible: son dos problemas contrarios y necesitan dos valores.
   *
   * No se inventa: es el `--azul` del visor del propio producto
   * (`viz-test/vistas.html`), que ya resuelve exactamente este caso.
   * Medido: 6,47:1 sobre `--tinta`, AA de cuerpo con margen.
   */
  --azul-claro: #5aa9e6;

  /*
   * La tinta suave, del otro lado: texto secundario SOBRE fondo oscuro.
   *
   * `--tinta-suave` está pensada para leerse sobre papel y sobre `--tinta`
   * da 1,4:1, o sea nada. Son dos problemas contrarios y necesitan dos
   * valores, igual que los dos azules.
   *
   * Lo lleva la delimitación de alcance del héroe, que desde que la
   * portada abre con la lámina es texto claro sobre oscuro.
   *
   * 11,2:1 sobre `--tinta`. Y 5,82:1 en el PEOR caso del héroe, que no es
   * `--tinta` sino el suelo de `.caja` sobre un nodo amarillo de la
   * lámina: ver la nota de `.heroe`. (Aquí decía 5,8 y salía del velo que
   * ya no existe; la cifra de ahora la recalcula una prueba.)
   */
  --tenue-claro: #cdd6df;

  /*
   * ── EL LIENZO DE LAS LÁMINAS ────────────────────────────────────────
   *
   * No es una decisión de color de esta hoja: es el color con el que
   * `herramientas/generar-grafos.py` guarda las láminas —su constante se
   * llama `LIENZO`— y está aquí para que el héroe pueda usarlo como fondo
   * y la lámina no tenga borde.
   *
   * ⚠️ ENTRA AL QUITARSE EL VELO, Y POR UNA COSTURA QUE SE VIO. Mientras
   * había degradado, el fondo del héroe y la lámina se fundían por debajo
   * de 60rem —la lámina va al pie y el resto es color liso—. Sin velo, el
   * lienzo de la imagen (#101924) queda al lado de `--tinta` (#16202b) y
   * el canto de la lámina se dibuja como una raya horizontal a todo lo
   * ancho. Con este color de fondo no hay canto: la lámina empieza donde
   * no se nota.
   *
   * Por encima de 60rem no se ve nunca —la lámina cubre la caja entera—,
   * así que esto no cambia el héroe de escritorio ni un píxel.
   *
   * Hay una prueba que lo compara con la constante del generador: si
   * alguien recolorea las láminas y no toca esto, la costura vuelve y la
   * prueba se pone roja antes.
   */
  --lienzo: #101924;

  /*
   * ── EL MARCO DE LA PÁGINA ───────────────────────────────────────
   *
   * ⚠️ ESTO NO EXISTÍA, Y SU AUSENCIA ERA EL DEFECTO DE MAQUETACIÓN MÁS
   * GRANDE QUE TENÍA LA PÁGINA.
   *
   * Sin marco, cada bloque se centraba por su cuenta con el ancho que le
   * tocara. El resultado, MEDIDO a 1366 px con
   * `getBoundingClientRect().left` y no supuesto, eran CINCO bordes
   * izquierdos distintos en la misma página:
   *
   *   · 371 — los `h2` y los párrafos (la columna de lectura, centrada);
   *   · 315 — el formulario (46rem);
   *   · 203 — las tarjetas de «Lo que ganas» y el marco del vídeo (60rem);
   *   · 123 — la figura de los cuatro razonamientos (70rem);
   *   · 107 — las tres fichas de «Dónde se aplica» (72rem).
   *
   * En pantalla eso se lee como cinco maquetaciones superpuestas. Dentro
   * de la sección del método llegaban a verse tres a la vez: la figura
   * empezaba en 123 y su propio pie de foto 248 px más a la derecha.
   *
   * Y la cabecera lo remataba: el logotipo a 32 px del borde de la
   * ventana mientras el titular que tiene debajo empezaba 339 px más
   * adentro.
   *
   * El marco lo arregla sin un solo elemento nuevo en el marcado. Todo
   * —cabecera, héroe, secciones, pie— se alinea a la IZQUIERDA de una
   * banda de `--marco` centrada en la ventana, y cada bloque crece hacia
   * la derecha hasta donde le toque. Un borde izquierdo, no tres.
   *
   * `--marco` vale 70rem porque ése es el ancho de la figura, que es el
   * bloque más ancho del sitio y el único cuyo número está sujeto por una
   * prueba (ver `.figura`). Hacer el marco más ancho que la figura la
   * habría dejado descolgada otra vez.
   */
  --marco: 70rem;

  /*
   * Cuánto hay que meter un bloque para que empiece en el borde del
   * marco.
   *
   * El `100%` se resuelve contra el ancho de contenido del PADRE —la
   * sección, el héroe—, que ya lleva descontado su `padding`. Por debajo
   * de `--marco` + ese padding, el `max()` da cero y todo vuelve a pegarse
   * al borde de la página, que es lo que hace falta en un teléfono.
   *
   * Va aquí y no repetido en cada regla porque es la misma cuenta once
   * veces, y once copias de una cuenta se separan.
   */
  --sangria: max(0px, calc((100% - var(--marco)) / 2));

  /*
   * El ancho de lectura: la MEDIDA de la línea, en rem.
   *
   * `ch` se resuelve contra el tamaño de letra DEL ELEMENTO, no contra el
   * del cuerpo. Con `--lectura: 68ch` medido en la página: el párrafo
   * salía a 680 px y el `h1` a 1904 px, porque su letra es de 48 px. El
   * resultado en pantalla era un titular pegado al borde izquierdo y su
   * párrafo empezando 300 px más adentro, como si fueran dos columnas
   * distintas. Por eso está en rem, y por eso sigue estándolo.
   *
   * ⚠️ EL NÚMERO BAJA DE 42.5rem A 39rem, Y LA RAZÓN QUE PARECE NO ES LA
   * BUENA. Lo primero que se escribió aquí fue que IBM Plex Sans es más
   * estrecha que la pila del sistema y que por eso en los mismos 680 px
   * cabían más caracteres. **Es falso, y se comprobó.** Midiendo con el
   * canvas del navegador el avance medio del párrafo de «El problema» a
   * 18 px, que es el tamaño real a 1366:
   *
   *   · IBM Plex Sans ....... 8,13 px por carácter
   *   · la pila del sistema . 8,08 px por carácter
   *
   * Medio por ciento. Cambiar de letra no movió la medida de nada.
   *
   * Lo que la medición sí enseñó es que los 680 px de antes daban **84
   * caracteres por línea**, y el techo de lo que se lee cómodo está entre
   * 75 y 80: era demasiado larga desde el principio y nadie lo había
   * medido. 39rem son 624 px y **77 caracteres**, que entra.
   *
   * Los dos números están medidos en el navegador con la letra ya
   * cargada, no calculados aquí.
   */
  --lectura: 39rem;

  /*
   * Los radios. La referencia usa 14–26 px y ésa es la escala que se
   * toma: un radio pequeño se lee como una caja de formulario de 2010.
   */
  --radio-chico: 0.625rem; /* 10 px — los campos */
  --radio: 0.875rem; /* 14 px — la figura, el marco del vídeo */
  --radio-grande: 1.25rem; /* 20 px — las tarjetas y los paneles */

  --serif: 'Fraunces Variable', 'Iowan Old Style', Georgia, 'Times New Roman', serif;
  --sans: 'IBM Plex Sans', system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, 'SFMono-Regular', 'Cascadia Mono', Consolas, monospace;
}

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

html {
  /* El botón del héroe enlaza a #entrevista dentro de la misma página. */
  scroll-behavior: smooth;
  /*
   * ⚠️ ESTO LO EXIGE LA BARRA PEGAJOSA, Y ES LA MITAD DEL AVISO VIEJO QUE
   * SÍ ERA CIERTA. `.cabecera` decía que no podía ser `sticky` porque
   * «tapa el destino de `#entrevista` al llegar por el ancla». Sin este
   * `scroll-padding-top` pasa exactamente eso: el navegador pone el borde
   * superior de la sección en el borde superior de la ventana, que es
   * donde está la barra, y el encabezado queda debajo.
   *
   * `6rem` es el techo de lo que mide la barra en una fila —3,9rem de
   * logotipo más 1,55rem de `padding` más el filete—, redondeado hacia
   * arriba. NO es una medida exacta de la barra, y no puede serlo: en
   * estrecho la barra tiene dos filas y mide más. Sobrarse aquí no
   * cuesta nada —el ancla queda un poco más abajo de lo justo— y quedarse
   * corto esconde el encabezado, así que se sobra.
   *
   * Y a los cinco `#…` del sitio les vale el mismo número: son los cuatro
   * enlaces de la barra y el `#entrevista` de los tres botones.
   */
  scroll-padding-top: 6rem;
  background: var(--papel);
}

body {
  margin: 0;
  background: var(--papel);
  color: var(--tinta);
  font-family: var(--sans);
  font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
  line-height: 1.65;
  /* Una palabra larga sin espacios (una URL, un nombre técnico) es la
     causa más común de desbordamiento horizontal en un teléfono. */
  overflow-wrap: break-word;
  -webkit-font-smoothing: antialiased;
}

img {
  display: block;
  max-width: 100%;
  height: auto;
}

/*
 * Los titulares, en serif.
 *
 * La razón no es «queda más elegante»: la palabra del logotipo está
 * escrita en una serif de trazo grueso, y hasta ahora la página no se
 * parecía a su propia marca en nada. Fraunces es la que más se le acerca
 * de las que se pueden servir desde aquí (SIL OFL).
 *
 * `font-variation-settings` y no `font-weight` a secas para los pesos
 * intermedios: el archivo es el del eje `wght`, y así queda escrito cuál
 * es el eje que se está moviendo.
 *
 * `line-height: 1.12` y no el 1.2 de antes: una serif de display con
 * interlineado de texto corrido se deshilacha. Y `text-wrap: balance`
 * se queda: es lo que impide la línea huérfana de dos palabras.
 */
h1,
h2,
h3 {
  font-family: var(--serif);
  font-weight: 600;
  line-height: 1.12;
  letter-spacing: -0.012em;
  text-wrap: balance;
}

a {
  color: var(--azul-hondo);
  text-underline-offset: 0.16em;
  text-decoration-thickness: from-font;
}

a:hover {
  text-decoration-thickness: 2px;
}

strong {
  font-weight: 600;
}

/*
 * La etiqueta corta en monoespaciada, que es el elemento que más repite
 * el lenguaje visual de la referencia: rótulo mono → titular serif →
 * párrafo → tarjetas.
 *
 * Aquí lo llevan las dos cabeceras de la tabla del §4.7 —«Problema que
 * atiende», «Cliente objetivo»— y el ordinal de cada sección.
 */
.etiqueta,
.seccion > h2::before {
  font-family: var(--mono);
  font-weight: 500;
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* ── LA BARRA DE NAVEGACIÓN ───────────────────────────────────────────
 *
 * Era una cabecera con dos cosas —el logotipo y el selector de idioma— y
 * pasa a ser la `navbar` que pidió el dueño: la marca con el sello de
 * NVIDIA, los enlaces de sección, el selector y el botón.
 *
 * ⚠️ `position: sticky` Y NO `fixed`, Y AQUÍ DECÍA QUE NADA DE ESO. Lo
 * que decía era: «una cabecera pegada se come alto justo donde menos hay
 * y tapa el destino de `#entrevista` al llegar por el ancla». Las dos
 * mitades siguen vivas, cada una con su respuesta:
 *
 * · «Se come alto». Es cierto de una barra `fixed`, que sale del flujo y
 *   obliga a devolverle su altura al documento con un `padding-top`
 *   escrito a mano. Aquí esa altura NO ES UN NÚMERO: la pone el
 *   logotipo, que es un `clamp()` entre 2,9rem y 3,9rem, más la fila que
 *   en estrecho se añade debajo. Cualquier constante se separaría de la
 *   altura real en algún ancho, y el síntoma —contenido escondido bajo
 *   la barra, o una franja en blanco sobre el héroe— no da error, sólo
 *   se ve mal. `sticky` se queda EN el flujo y ocupa exactamente lo que
 *   mide.
 *
 *   Lo que eso costó está MEDIDO, y no es cero en los dos sitios. A
 *   1366×768 la barra cabe en una fila —88,2 px— y el botón del héroe se
 *   quedó donde estaba: y=712 antes de añadirla y y=712 después, sin
 *   mover un píxel. A 390×844 la barra son dos filas —167 px— y el botón
 *   bajó de **y=642 a y=743**, ciento un píxeles, y sigue sobre el
 *   pliegue con 101 de margen. Decir «no cuesta nada» habría sido falso
 *   en el segundo caso.
 *
 *   ⚠️ AQUÍ DECÍA «de y=670 a y=743», Y 670 NO ERA UNA MEDICIÓN. Era la
 *   cifra de una corrida INTERMEDIA —ya con la frase larga dentro— usada
 *   como si fuera el punto de partida. El punto de partida real, medido
 *   sobre `97e9bfd`, es 642. Es el defecto de esta casa en su forma más
 *   pequeña y más fea: un párrafo que existe para decir «medido y no
 *   estimado» llevaba dentro un número que no salía de la medición.
 * · «Tapa el destino del ancla». Sigue siendo cierto, y por eso `html`
 *   lleva ahora `scroll-padding-top`. Hay una prueba que ata las dos
 *   cosas: quien quite una tiene que quitar la otra.
 *
 * ⚠️ Y SÓLO SE PEGA A PARTIR DE 58rem. En un teléfono la barra mide dos
 * filas —167 px de 844, un 20 % de la pantalla—, y pegar eso arriba
 * durante una página tan larga cuesta más de lo que compra: la barra ya
 * la ha visto quien desplaza, y lo que quiere es leer. En ancho, 88 px de
 * 768 son un 11 % y la ventana es apaisada, que es donde una barra
 * pegada sirve de algo.
 *
 * Lo que NO cambia con el ancho es que la barra esté ENTERA en los dos:
 * los cuatro enlaces se ven los dos sitios. Lo que se decide aquí es si
 * se queda pegada, no qué lleva dentro.
 *
 * El fondo es opaco (`--papel`) y no transparente, y el `z-index` no
 * sobra: al desplazar, esta barra pasa por encima del héroe, que es
 * oscuro, y por encima de las bandas oscuras del método y del
 * formulario. Sin fondo propio, el rótulo de los enlaces se leería sobre
 * lo que hubiera debajo.
 *
 * ── LA REJILLA, Y POR QUÉ NO ES FLEXIBLE ─────────────────────────────
 *
 * Con `flex` + `flex-wrap`, el orden en que las cuatro piezas caen al
 * envolverse lo decide el ancho de cada una, y sale distinto en cada
 * idioma —«Solicitar una entrevista» y «Request a meeting» no miden lo
 * mismo—. Con rejilla, dónde cae cada pieza está DECLARADO:
 *
 *   · estrecho: fila 1 = marca + selector; fila 2 = los enlaces.
 *   · ancho:    una fila = marca · enlaces · selector · botón.
 *
 * ⚠️ Y LAS FILAS VAN ESCRITAS, NO DEJADAS A LA COLOCACIÓN AUTOMÁTICA.
 * Estaban dejadas, y salió mal: `grid-auto-flow: row` no retrocede, así
 * que al poner `.menu` a lo ancho de las dos columnas en la fila 2, el
 * selector de idioma —que va detrás en el marcado— no podía volver al
 * hueco libre de la fila 1 y caía a una TERCERA fila: la barra ganaba
 * 51 px —los 45,4 del selector más los 5,6 del hueco entre filas— y el
 * selector acababa debajo de los enlaces en lugar de al lado del
 * logotipo. Medido en el navegador (211,5 contra 160,5 con el relleno de
 * los enlaces de aquel momento; hoy la barra son 167 y el defecto sería
 * el mismo). No lo ve ninguna prueba de `npm test`.
 *
 * ⚠️ EL BOTÓN NO SE PINTA POR DEBAJO DE 58rem, y es una decisión, no un
 * olvido. En un teléfono el botón del héroe se ve sin desplazar —medido,
 * y hay una guarda que lo exige—, así que un segundo botón a 60 px de
 * distancia no convierte a nadie: sólo añade una tercera fila. La sección
 * «Tres formas de implementarlo» remata en el mismo botón más abajo, de
 * modo que quien desplaza vuelve a tenerlo a mano.
 */
.cabecera {
  z-index: 20;
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 0.35rem 1.25rem;
  background: var(--papel);
  padding-block: 0.85rem 0.7rem;
  /*
   * El logotipo arranca donde arranca el titular, y el selector de idioma
   * acaba donde acaba la figura: los dos, en el borde del marco.
   *
   * Aquí decía —y se hizo— que el enlace de idioma iba «a ras del borde
   * de la página, no a ras de la columna de lectura», para que no se
   * leyera como parte del texto. Con el marco puesto eso ya no hace
   * falta: no se alinea con la columna de lectura (624 px), se alinea con
   * el marco (1120 px), que es más ancho que cualquier párrafo. Lo que se
   * gana es que la cabecera deje de parecer de otra página.
   *
   * El `max()` es la misma cuenta de `--sangria`, pero contra la VENTANA
   * y no contra la sección: aquí el `100%` se resuelve sobre el ancho del
   * cuerpo, y el `padding` es lo que mete el contenido. Medido a 1366: el
   * logotipo empieza en 123, igual que el `h1` y que la figura.
   *
   * El filete de abajo sí llega a los dos bordes, como los `border-top`
   * de las secciones: es la línea que separa la cabecera de la página, no
   * un subrayado del contenido.
   */
  padding-inline: max(clamp(1rem, 5vw, 2rem), calc((100% - var(--marco)) / 2));
  border-bottom: 1px solid var(--borde);
}

/*
 * ── DÓNDE CAE CADA PIEZA ─────────────────────────────────────────────
 *
 * En estrecho, dos filas declaradas: la marca y el selector arriba, los
 * enlaces abajo. El botón no se pinta (ver la nota de `.cabecera`).
 *
 * `min-width: 0` en `.menu` no es adorno: un hijo de rejilla no baja de
 * su ancho de contenido por defecto, y con los cuatro rótulos en una
 * línea eso desbordaría la página a lo ancho en un teléfono. Con él, la
 * lista envuelve dentro de su celda. Hay una guarda que mide el
 * desbordamiento horizontal a 390 px.
 */
.marca-lockup {
  grid-column: 1;
  grid-row: 1;
  display: flex;
  align-items: center;
  gap: 0.7rem;
}

.menu {
  grid-column: 1 / -1;
  grid-row: 2;
  min-width: 0;
}

.llamada-barra {
  display: none;
}

/*
 * ── EL RETORNO FLOTANTE ──────────────────────────────────────────────
 *
 * Un objetivo de 44 px —el mismo mínimo que ya se midió a mano para el
 * selector de idioma y para los enlaces de sección, y por el mismo
 * motivo: en un teléfono un objetivo pequeño se falla—. `2.75rem` son
 * exactamente esos 44 px, y van en `rem` y no en `px` para que crezcan
 * con la letra de quien la tenga más grande.
 *
 * ⚠️ ARRANCA INVISIBLE Y **FUERA DEL ORDEN DE TABULACIÓN**. `opacity: 0`
 * a secas no basta: un enlace transparente sigue recibiendo el foco, y
 * quien navega con teclado se encontraría una parada que no puede ver.
 * `visibility: hidden` lo saca del recorrido, y por eso la transición
 * lleva `visibility 0s linear 160ms` — la propiedad no interpola, así
 * que se retrasa hasta que la opacidad ha terminado de irse. Al aparecer,
 * los tres retrasos vuelven a cero para que el foco sea alcanzable desde
 * el primer fotograma.
 *
 * El azul hondo y el blanco son el mismo par del botón del sitio, con su
 * 7,10:1 ya medido. No es «el botón» —no convierte, navega— pero es un
 * control flotante sobre contenido cualquiera, y necesita un fondo opaco
 * propio por la misma razón que la barra.
 *
 * La sombra no es adorno: es lo único que separa un círculo opaco de la
 * banda oscura del método o de la del formulario, donde un fondo azul
 * sobre fondo oscuro se lee como una mancha sin borde.
 *
 * ⚠️ CUÁNDO SE VE NO LO DECIDE ESTA HOJA. Lo decide `activarSubir` con un
 * `IntersectionObserver`: aparece cuando la cabecera deja de verse y se
 * esconde cuando el pie entra, para no taparlo. La hoja sólo dibuja los
 * dos estados. Sin JavaScript no hay clase y el botón no se ve nunca,
 * que es el lado bueno del fallo.
 */
.subir {
  display: grid;
  place-items: center;
  position: fixed;
  right: clamp(1rem, 5vw, 2rem);
  bottom: clamp(1rem, 5vw, 2rem);
  z-index: 30;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 999px;
  background: var(--azul-hondo);
  color: #fff;
  font-size: 1.15rem;
  line-height: 1;
  text-decoration: none;
  box-shadow: 0 2px 10px rgba(11, 17, 23, 0.45);
  opacity: 0;
  visibility: hidden;
  transform: translateY(0.5rem);
  transition:
    opacity 160ms ease,
    transform 160ms ease,
    visibility 0s linear 160ms;
}

.subir.a-la-vista {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: 0s, 0s, 0s;
}

.subir:hover,
.subir:focus-visible {
  background: #084a76;
}

@media (min-width: 58rem) {
  .cabecera {
    position: sticky;
    top: 0;
    grid-template-columns: auto 1fr auto auto;
  }

  .menu {
    grid-column: 2;
    grid-row: 1;
    justify-self: end;
  }

  /*
   * El botón entra en la barra a partir de aquí, y en la última columna.
   * `margin-block: 0` porque es un `<p>`: sin él, el margen de párrafo
   * del navegador estiraría la barra y empujaría el héroe hacia abajo,
   * que es justo lo que no puede pasar.
   */
  .llamada-barra {
    display: block;
    grid-column: 4;
    justify-self: end;
    margin-block: 0;
  }

  /*
   * El botón de la barra es más pequeño que el del héroe a propósito: no
   * compite con él, lo acompaña. El del héroe es la acción de la página;
   * éste es la que sigue estando cuando ya has desplazado.
   */
  .llamada-barra .boton {
    padding: 0.55em 1.1em;
    font-size: 0.88rem;
  }

  /*
   * ── Y AQUÍ SE APAGA EL RETORNO FLOTANTE ───────────────────────────
   *
   * ⚠️ ESTA LÍNEA Y EL `position: sticky` DE ARRIBA SON LA MISMA
   * DECISIÓN, Y POR ESO ESTÁN EN EL MISMO BLOQUE.
   *
   * El botón flotante existe porque por debajo de este umbral la
   * cabecera NO se pega: son dos filas y 167 px de una pantalla de 844,
   * y pegarlas cuesta el 20 % de lo que se lee. Sin barra a la vista, los
   * otros dos retornos —el rótulo y el logotipo— sólo existen arriba del
   * todo, que es donde no hacen falta.
   *
   * A partir de aquí la barra se queda pegada, el retorno está SIEMPRE a
   * la vista, y un tercer control flotando encima del contenido sería la
   * placa de NVIDIA otra vez: repetir lo que ya se ve deja de ayudar y
   * pasa a estorbar.
   *
   * Quien quite el `sticky` de arriba tiene que quitar este `display:
   * none`, y al revés. Hay una prueba que exige que el umbral sea el
   * mismo y que las dos declaraciones vivan en el mismo `@media`.
   */
  .subir {
    display: none;
  }
}

/*
 * ── LOS ENLACES DE SECCIÓN ───────────────────────────────────────────
 *
 * En monoespaciada y versalita, como las etiquetas del resto del sitio:
 * son rótulos de navegación, no prosa, y la letra lo dice antes que el
 * tamaño.
 *
 * El objetivo táctil vuelve a ser el de `.idiomas a` —44 px— y por el
 * mismo motivo: en un teléfono estos cuatro enlaces van uno al lado del
 * otro y un objetivo pequeño se falla.
 *
 * ⚠️ EL NÚMERO SE MIDIÓ Y NO CUADRABA, IGUAL QUE EN `.idiomas a`. Con
 * `padding-block: 0.7rem` la caja salía a **41,4 px** —`getBoundingClient
 * Rect`, no la cuenta—, tres por debajo del mínimo, y aquí llegó a estar
 * escrito «44,5» sin haberlo mirado. Con 0,8rem sube a 44,6. Es
 * literalmente el mismo tropiezo que ya documenta el selector de idioma
 * dos reglas más abajo, cometido otra vez en la regla de al lado.
 */
.secciones ul {
  display: flex;
  flex-wrap: wrap;
  gap: 0 1.1rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.secciones a {
  display: block;
  padding-block: 0.8rem;
  color: var(--tinta-suave);
  font-family: var(--mono);
  font-weight: 500;
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
}

/*
 * Aquí SÍ se quita el subrayado y en `.idiomas a` no, y la diferencia es
 * de contexto: esto es una lista de cuatro rótulos alineados en una fila,
 * que ya se lee como una barra de navegación; aquél es un enlace suelto
 * al lado de un botón, donde el subrayado es la única señal de que se
 * pulsa. El subrayado vuelve al pasar por encima y al enfocar, que es
 * donde hace falta.
 */
.secciones a:hover,
.secciones a:focus-visible {
  color: var(--azul-hondo);
  text-decoration: underline;
}

/*
 * ── EL SELLO DE NVIDIA, EN LA BARRA ──────────────────────────────────
 *
 * Sube aquí desde el bloque de logros, que es donde el dueño lo pidió, y
 * de allí desaparece: la misma placa dos veces en la misma página deja de
 * acreditar y pasa a ser decoración repetida.
 *
 * El archivo trae su propio fondo blanco y su propio marco negro —es una
 * placa—, así que no lleva borde ni fondo de esta hoja. Sobre el papel
 * cálido de la barra se lee como lo que es.
 *
 * ⚠️ EL TAMAÑO ESTÁ ATADO AL DEL LOGOTIPO, Y ES LO QUE IMPIDE QUE LA
 * BARRA CREZCA. El logotipo mide entre 2,9rem y 3,9rem de alto; el sello
 * es 500×216, o sea 2,315 de ancho por 1 de alto, y a 6,25rem de ancho da
 * 2,7rem de alto — por debajo del logotipo en TODO el rango. Si crece por
 * encima, la barra crece con él y empuja el botón del héroe fuera del
 * pliegue, que es lo que la guarda de `medir-portada.mjs` mide.
 *
 * Y no es un `srcset`: es un SVG, y un vectorial se pinta nítido a
 * cualquier densidad. El `width`/`height` del marcado son los del
 * `viewBox` (500×216), que es lo que reserva el hueco antes de que
 * llegue.
 */
.sello {
  width: clamp(4.5rem, 3.2rem + 4vw, 6.25rem);
  height: auto;
}

/*
 * El logotipo se sirve a 156 px de lado y se pinta entre 44 y 52: 3× de
 * holgura para una pantalla de densidad 3, que es la normal hoy.
 *
 * El archivo de marca son 300×300 y 36,7 kB. Reescalado a 156 y
 * cuantizado a 128 colores queda en **4,2 kB** sin diferencia visible: el
 * logotipo es plano salvo el degradado del disco rojo. Los atributos
 * `width`/`height` del marcado llevan las medidas REALES del archivo —lo
 * que reserva el hueco antes de que llegue—; el tamaño de pantalla lo
 * pone esta regla.
 *
 * ⚠️ AQUÍ DECÍA «no es un enlace y por eso no hay nada de `:hover`», Y
 * AHORA SÍ LO ES: lleva al principio de la página, que es lo que la
 * página no tenía. El porqué entero está en el comentario del marcado.
 * Lo que NO cambia es esta regla: las medidas siguen siendo las de la
 * imagen, y de ellas sale el alto de la barra —hay una prueba que compara
 * este `clamp` con el del sello justamente por eso—.
 */
.marca {
  width: clamp(2.9rem, 2.2rem + 2.2vw, 3.9rem);
  height: auto;
}

/*
 * El envoltorio del logotipo enlazado.
 *
 * `display: flex` y no `inline-block`: un `<img>` dentro de un elemento
 * en línea arrastra el espacio de la línea base —tres o cuatro píxeles
 * por debajo— y eso desalinea el logotipo respecto del sello, que es su
 * vecino de fila. Con `flex` la caja del enlace mide exactamente lo que
 * mide la imagen, y el alto de la barra no se mueve ni un píxel al
 * envolverla. Está medido: la barra sigue en 88,2 px a 1366 y en 167 a
 * 390, que son las dos cifras de las que depende el pliegue.
 *
 * El anillo de foco lo pone el `:focus-visible` global del final de la
 * hoja: es una parada de tabulación de verdad —la primera del documento—
 * y tiene que verse.
 *
 * `opacity` en lugar de un cambio de color al pasar por encima: el
 * logotipo es una imagen de cuatro colores y no hay un `color` que tocar.
 */
.marca-enlace {
  display: flex;
  border-radius: 4px;
  transition: opacity 120ms ease;
}

.marca-enlace:hover {
  opacity: 0.78;
}

/*
 * El selector de idioma.
 *
 * Aquí NO hay `text-decoration: none`, y es deliberado: se deja el
 * subrayado que pone el navegador. Es un enlace suelto, fuera de un
 * párrafo; sin subrayado, la única señal de que se puede pulsar sería el
 * color, y eso deja fuera a quien no lo distingue. Es justo lo contrario
 * de `.boton`, que sí se lo quita porque su forma ya dice que se pulsa.
 *
 * ⚠️ VA EN LA PRIMERA FILA DE LA BARRA EN LOS DOS ANCHOS, junto a la
 * marca y nunca debajo de los enlaces de sección. Quien llega a la
 * versión que no lee tiene que encontrar la salida sin recorrer nada: el
 * selector es lo primero que necesita, y en estrecho es lo único que
 * comparte fila con el logotipo.
 */
.idiomas {
  grid-column: 2;
  grid-row: 1;
  justify-self: end;
  display: flex;
  justify-content: flex-end;
  font-family: var(--mono);
  font-weight: 500;
  font-size: 0.8rem;
  letter-spacing: 0.06em;
}

@media (min-width: 58rem) {
  .idiomas {
    grid-column: 3;
  }
}

.idiomas a {
  /*
   * Objetivo táctil de 44 px, que es el mínimo que se pulsa sin fallar en
   * un teléfono.
   *
   * ⚠️ EL NÚMERO SE MIDIÓ Y NO CUADRABA. Al pasar el rótulo a
   * monoespaciada bajó de 0,95em a 0,8rem, y con el `padding` que traía
   * —0,75em— la caja del enlace quedó en **40,0 px**: cuatro por debajo
   * del mínimo, en las dos páginas y en los dos tamaños de ventana. Con
   * 0,95em vuelve a 45,4. Las dos cifras salen de
   * `getBoundingClientRect`, no de la cuenta.
   */
  padding: 0.95em 0.5em;
  color: var(--tinta-suave);
}

.idiomas a:hover,
.idiomas a:focus-visible {
  color: var(--azul-hondo);
}

/* ── El héroe, que ahora es la portada de un portafolio ───────────── */
/*
 * ⚠️ LA PÁGINA ABRE CON LA LÁMINA DE LOS CUATRO GRAFOS, A PANTALLA
 * COMPLETA. Es el `masthead` de la plantilla: una imagen que ocupa la
 * primera pantalla y el titular escrito encima.
 *
 * La lámina va como FONDO y no como `<img>`, y el motivo es una guarda:
 * `medir-portada.mjs` exige que todo hijo directo del héroe comparta
 * borde izquierdo con el `h1`, y una imagen a sangre tiene su borde en
 * cero mientras el titular lo tiene en el marco. El porqué entero está en
 * `heroe()` de portada.ts, con lo que esta decisión cuesta —el fondo no
 * lleva `alt`— y por qué es aceptable.
 *
 * ── LA LÁMINA ES `portada-*.webp` Y NO `razonamientos-*.webp` ───────
 *
 * Aquí iba la lámina de contacto del §5.5, y era la imagen equivocada:
 * ESA lámina es un documento. Lleva su título, cuatro cabeceras de panel,
 * dieciséis chips, cuatro párrafos, cuatro pies y una leyenda, y bajo el
 * velo todo eso se leía a media luz — dos sistemas tipográficos a la vez,
 * uno de ellos ilegible-pero-claramente-texto, compitiendo con el titular
 * que tiene encima. Una fotografía no trae tipografía dentro.
 *
 * `portada-*.webp` dibuja los MISMOS cuatro grafos, con el mismo motor y
 * la misma escala de color, en 2×2 y sin una sola letra. La lámina de
 * contacto sigue publicada donde se puede leer: en `#metodo`, con su
 * `alt` y su pie.
 *
 * ── EL VELO SE HA IDO ENTERO, Y LO QUE OSCURECE AHORA ES LA CAJA ────
 *
 * ⚠️ AQUÍ HABÍA UN DEGRADADO QUE TAPABA LA LÁMINA COMPLETA —0,82 · 0,80 ·
 * 0,94— PARA QUE EL TEXTO SE LEYERA ENCIMA. Funcionaba, y costaba
 * exactamente lo que el dueño acabó viendo: los cuatro grafos no se
 * distinguían. El fondo pagaba por el texto en TODA la lámina, incluida
 * la mitad donde no hay una sola letra.
 *
 * Ahora cada cosa resuelve su problema donde toca:
 *
 *   · la lámina va SIN velo — `background-image` es la imagen y nada
 *     más, y lo que se ve es la imagen;
 *   · el texto lleva su propio suelo, `.caja`, que es una losa de la
 *     tinta del sitio al 76 % bajo los cinco bloques y sólo bajo ellos.
 *
 * ⚠️ Y ESO INVALIDA LA MEDICIÓN VIEJA. Las cifras que había aquí se
 * calculaban componiendo el píxel más claro de la lámina BAJO EL VELO.
 * Sin velo, ese cálculo no describe nada: el fondo efectivo del texto es
 * ahora la caja sobre la imagen. Se ha rehecho, no relajado — mismo peor
 * caso (el píxel más claro que `generar-grafos.py` mide sobre los
 * píxeles reales y escribe en `laminas.json`: **#fde725, luminancia
 * 0,7817**), misma fórmula de WCAG, mismos umbrales, otra composición.
 *
 * Componiendo ese amarillo bajo la caja —`rgba(16, 25, 36, 0.74)`, que
 * es `--lienzo` al 74 %—, el fondo efectivo es **rgb(78, 79, 36)**,
 * luminancia 0,0726:
 *
 *   · el `h1` y el lema, `--papel` .................. 8,08:1  (pide 4,5)
 *   · la precisión, `--tenue-claro` ................. 5,82:1  (pide 4,5)
 *   · el subtítulo, `--azul-claro` .................. 3,37:1  (pide 3:1,
 *     que es el umbral de texto grande; el `clamp` del subtítulo arranca
 *     en 1,5rem = 24 px, que es justo ese umbral, así que cumple a
 *     cualquier ancho de ventana)
 *
 * El 0,74 NO es un número redondo: el mínimo que cumple los tres umbrales
 * es **0,71** —a 0,70 el subtítulo se queda en 2,96— y el publicado está
 * tres centésimas por encima. Subirlo más sólo apaga la lámina otra vez.
 *
 * (Aquí decía «por debajo de 0,74 se cae», con el suelo en `--tinta`, y
 * era falso por una centésima: 0,73 daba 3,0169, que cumple. Lo corrigió
 * quien volvió a correr la rejilla. La cifra de ahora sale de la misma
 * rejilla, de centésima en centésima, y la prueba la recalcula.)
 *
 * ⚠️ Y NO SON CIFRAS ESCRITAS A MANO EN UN COMENTARIO. Hay una prueba
 * —«el suelo de la caja aguanta el píxel más claro de la lámina»— que lee
 * la luminancia del manifiesto, lee el alfa de ESTA caja, lee los velos
 * que queden en el héroe —hoy ninguno, y lo afirma—, compone en ese orden
 * y compara. Si alguien aclara la caja, devuelve un velo o regenera la
 * lámina con un píxel más brillante, se pone roja.
 *
 * Lo que `medir-portada.mjs` da para el héroe (15,83 · 6,59 · 15,83 ·
 * 11,40) sigue siendo el caso MEDIO: esa herramienta compone las capas
 * translúcidas que encuentra al subir hasta el primer fondo opaco —la
 * caja al 74 % sobre `--lienzo`—, pero NO lee la imagen. Las dos cosas
 * son ciertas y ninguna sola basta.
 *
 * (Eran 15,54 · 6,47 · 15,54 · 11,19 hasta este commit, y suben por el
 * fondo del héroe: `--lienzo` es un paso más hondo que `--tinta`. Se
 * apuntan las de ahora para que nadie compare contra las de antes.)
 *
 * ── LA ALTURA ───────────────────────────────────────────────────────
 *
 * `100svh` menos la cabecera. El contenido NO se centra vertical: se
 * queda arriba y la lámina ocupa el resto. Centrado, el botón baja hasta
 * cerca del pliegue y la única llamada a la acción del sitio deja de
 * verse sin desplazar, que es lo que `medir-portada.mjs` comprueba a
 * 1366×768 y a 390×844. Arriba se ve en los dos.
 *
 * `svh` y no `vh`: en un teléfono, `vh` cuenta la barra del navegador
 * como si no existiera y la primera pantalla acaba siendo más alta que la
 * pantalla.
 */
/*
 * ── Y POR QUÉ EL TELÉFONO NO LLEVA `cover`, QUE ERA LO PRIMERO QUE SE
 *    ESCRIBIÓ AQUÍ ──────────────────────────────────────────────────
 *
 * La lámina es apaisada y la primera pantalla de un teléfono es 1:2. Con
 * `cover`, el navegador la amplía hasta cubrir el alto y se come la mayor
 * parte del ancho: lo que queda detrás del titular no son cuatro grafos,
 * son dos nodos gigantes. **Está MIRADO en el navegador a 390×844, no
 * deducido**, y se leía como ruido — justo el aspecto de maqueta que este
 * rediseño viene a quitar.
 *
 * Por debajo de 60rem la lámina va ENTERA y al pie: `100% auto` la pone a
 * todo lo ancho —219 px de alto a 390 de ventana— y no lleva velo encima.
 * Se reconocen las cuatro formas, que es lo que la página afirma que se
 * distingue.
 *
 * ⚠️ AQUÍ TAMBIÉN HABÍA VELO —0,94 · 0,90 · 0,18— Y AQUÍ DECÍA QUE
 * TAMPOCO HACÍA FALTA. **Era falso, y costó un texto ilegible.**
 *
 * Decía: «en estrecho NINGÚN texto se superpone a la imagen: la lámina
 * empieza donde el contenido ya ha acabado». Eso es cierto a 390×844 —la
 * ventana en la que se miró— y deja de serlo en cuanto la ventana es más
 * ancha o más baja, porque la lámina se ancla ABAJO y su alto es
 * `0,5625 × ancho`: cuanto más ancha la ventana, más sube su borde
 * superior, y cuanto más baja, menos sitio queda para el texto. En cuanto
 * `alto del héroe − 0,5625 × ancho < alto del texto`, el texto cae encima
 * de la lámina.
 *
 * Medido sobre los píxeles, con el peor píxel de la lámina y la fórmula
 * de WCAG, cuando aquí no había suelo ninguno:
 *
 *   ·  900×600 → la precisión a **1,03:1**, el `h1` a 1,68:1
 *   ·  844×390 (teléfono apaisado) → el `h1` a **1,16:1**
 *   ·  360×740 (Android vertical) → la precisión a **1,18:1**
 *   ·  959×700 → el lema a 3,07:1
 *
 * 1,03:1 es texto invisible. Y no lo cazó nada porque las dos ventanas
 * del expediente —1366×768 y 390×844— salían limpias **por casualidad**,
 * y porque la guarda de contraste de `npm test` componía `.caja`, que
 * sólo existía a partir de 60rem: modelaba el escritorio y decía modelar
 * «el héroe».
 *
 * ⚠️ POR ESO `.caja` PINTA SUELO A CUALQUIER ANCHO, y su regla vive
 * FUERA de toda consulta de medios. El velo no vuelve: lo que protege el
 * texto es el suelo que está debajo del texto, esté donde esté la lámina.
 * Hay una prueba que exige que esa regla no esté dentro de ningún
 * `@media` — que es exactamente la forma que tuvo esta regresión.
 */
/*
 * ⚠️ EL AIRE DE ARRIBA BAJA DE `clamp(3rem, 9vh, 5.5rem)` A
 * `clamp(2.25rem, 6.5vh, 4.5rem)`, Y ES POR EL PLIEGUE.
 *
 * Dos cosas de este commit empujaron el botón hacia abajo: el subtítulo,
 * que pasó a ser la frase entera, y la barra de navegación, que en
 * estrecho añade una fila de enlaces. Medido a 1366×768 en inglés, que
 * es el peor de los cuatro casos, el botón acababa en y=712 de 768: pasa
 * la guarda con 56 px, que es poco margen para el número más frágil de
 * la página.
 *
 * Quitar aire de arriba es lo que menos cuesta de las tres cosas que se
 * podían tocar —las otras dos eran encoger el titular o recortar la
 * frase—, y además es lo que pide el cambio: con una barra encima que ya
 * tiene peso visual, el héroe no necesita tanto respiro.
 *
 * El `padding` de abajo NO se toca: el contenido del héroe se alinea
 * arriba, así que el de abajo no mueve el botón ni un píxel.
 */
.heroe {
  min-height: calc(100svh - 5.5rem);
  padding: clamp(2.25rem, 6.5vh, 4.5rem) clamp(1rem, 5vw, 2rem) clamp(2.5rem, 6vh, 4.5rem);
  /* ⚠️ `--lienzo` Y NO `--tinta`: es el color con el que se guarda la
     lámina, y es lo que hace que su canto no se vea en estrecho, donde
     la imagen va al pie y el resto del héroe es color liso. En ancho la
     lámina cubre esto entero y da igual cuál sea. */
  background-color: var(--lienzo);
  background-image: url(/img/portada-960.webp);
  background-position: center bottom;
  background-repeat: no-repeat;
  background-size: 100% auto;
  color: var(--papel);
}

/*
 * La variante grande sólo donde se aprovecha. Por debajo de 60rem la
 * ranura del fondo no llega a 960 px ni con densidad 2, y bajar la lámina
 * de escritorio en un teléfono es justo lo que el §5.5 existe para evitar.
 * Son los dos únicos anchos que genera la herramienta para esta lámina: un
 * tercer archivo que no cite nadie es peso muerto, y un `background-image`
 * no tiene `srcset` — elige por `@media`.
 *
 * A partir de aquí la ventana ya es apaisada, la lámina cubre la pantalla
 * entera y el titular va ENCIMA de ella: hay que ver la una y leer el otro
 * a la vez.
 *
 * ⚠️ AQUÍ ESTABA EL VELO DE ESCRITORIO, Y ERA EL QUE APAGABA LOS CUATRO
 * GRAFOS: tres paradas de `rgba(11, 17, 23, …)` que tocaban fondo en 0,80
 * y cubrían la lámina ENTERA. Ya no hay ninguna. Lo que sostiene el
 * contraste del texto es `.caja`, aquí abajo, y la prueba que lo mide
 * compone la caja sobre el píxel más claro de la lámina — no un velo que
 * ya no existe.
 *
 * Esta regla se queda con lo que siempre fue suyo y nada más: la variante
 * grande de la lámina, y `cover` en vez de `100% auto`.
 */
@media (min-width: 60rem) {
  .heroe {
    background-image: url(/img/portada-1920.webp);
    background-position: center;
    background-size: cover;
  }
}

/*
 * ── EL SUELO DE LA CAJA DE TEXTO ─────────────────────────────────────
 *
 * Es lo único de la página que oscurece la lámina, y lo hace sólo donde
 * hay letras: el velo que tapaba la lámina entera se fue por eso.
 *
 * ⚠️ ESTA REGLA VIVIÓ DENTRO DE `@media (min-width: 60rem)` Y ESO FUE UNA
 * REGRESIÓN CON TEXTO ILEGIBLE DETRÁS.
 *
 * El razonamiento de entonces era: «en estrecho la lámina va al pie y el
 * texto no se le superpone, así que el suelo sobra y sólo estamparía un
 * rectángulo». La primera mitad se comprobó en UNA ventana —390×844— y
 * se dio por buena para todas. Es falsa en cuanto la ventana es más
 * ancha o más baja: la lámina se ancla abajo y mide `0,5625 × ancho`, así
 * que su borde superior sube con el ancho y el texto acaba encima. A
 * 900×600, la delimitación de alcance salía a **1,03:1** sobre el peor
 * píxel. Texto invisible.
 *
 * Ahora la regla es global y no la modifica ninguna consulta de medios.
 * Hay una prueba que lo exige leyendo la hoja con los bloques `@media`
 * quitados: si alguien vuelve a meterla dentro de uno, se pone roja.
 *
 * ── Y POR QUÉ EL COLOR ES `--lienzo` Y NO `--tinta` ─────────────────
 *
 * Porque ahora el suelo también se pinta donde NO hay lámina detrás —en
 * estrecho, toda la parte alta del héroe—, y ahí una losa de otro tono
 * se vería como un rectángulo pálido flotando sobre tinta lisa sin
 * ninguna razón. `--lienzo` es el color de fondo del héroe y el color con
 * el que `generar-grafos.py` guarda las láminas: sobre el fondo liso el
 * suelo es INVISIBLE, y sobre la lámina oscurece. Cada cosa donde toca.
 *
 * El alfa: **0,74**. El mínimo que cumple los tres umbrales sobre el peor
 * píxel es 0,71 —a 0,70 el subtítulo se queda en 2,96— y hay una prueba
 * que recorre la rejilla de centésima en centésima y exige que el
 * publicado no se aleje más de tres. Componiendo #fde725 bajo
 * `rgba(16, 25, 36, 0.74)` el fondo efectivo es **rgb(78, 79, 36)**,
 * luminancia 0,0726:
 *
 *   · el `h1` y el lema, `--papel` .................. 8,08:1  (pide 4,5)
 *   · la precisión, `--tenue-claro` ................. 5,82:1  (pide 4,5)
 *   · el subtítulo, `--azul-claro` .................. 3,37:1  (pide 3)
 *
 * ⚠️ EL COLOR VA UNA VEZ Y SE USA DOS. El fondo pinta dentro de la caja y
 * el `box-shadow` pinta fuera; si el color se escribiera dos veces, se
 * separarían el día que alguien toque uno. Hay una prueba que lee esta
 * variable —y sólo ésta— para calcular el contraste.
 *
 * ⚠️ `box-shadow` CON EXTENSIÓN Y SIN DESENFOQUE, Y NO `padding`, Y EL
 * MOTIVO ES LA GUARDA DE ALINEACIÓN.
 *
 * `medir-portada.mjs` exige que todo hijo directo del héroe comparta
 * borde izquierdo con el `h1` — es la guarda que nació de los cinco
 * bordes izquierdos que tenía la página—. Con `padding` en la caja, el
 * `h1` quedaría 1,75rem más adentro que su propio contenedor y la guarda
 * lo marcaría, con razón: el titular dejaría de empezar donde empiezan el
 * logotipo, la figura y todos los `<h2>` del sitio.
 *
 * Una sombra exterior sin desenfoque pinta un rectángulo macizo por FUERA
 * de la caja sin mover la caja ni un píxel: el aire visual existe, el
 * borde izquierdo del texto sigue siendo el del marco, y la guarda sigue
 * midiendo lo que fue escrita para medir. Una sombra exterior se recorta
 * contra la caja, así que no hay doble capa de alfa donde las dos se
 * tocan y el suelo queda de un solo tono.
 *
 * Tampoco entra en el desbordamiento desplazable —una sombra es tinta, no
 * caja—, así que la guarda de desbordamiento horizontal a 390 px sigue
 * valiendo aunque en estrecho la sombra se salga por los dos lados.
 */
.caja {
  --suelo-de-la-caja: rgba(16, 25, 36, 0.74);
  background: var(--suelo-de-la-caja);
  box-shadow: 0 0 0 1.75rem var(--suelo-de-la-caja);
}

/*
 * ⚠️ `var(--sangria) auto` Y NO `auto auto`.
 *
 * `auto auto` centra cada bloque por su cuenta, que es lo que producía
 * los tres bordes izquierdos descritos en `--marco`. Con la sangría a la
 * izquierda y `auto` a la derecha, el bloque se pega al borde del marco y
 * crece hacia dentro: todos empiezan en el mismo sitio, cada uno acaba
 * donde su ancho le deje.
 *
 * ⚠️ HOY EL HÉROE TIENE UN SOLO HIJO DIRECTO, `.caja`, y esta regla es la
 * que la mete en el marco. Los cinco bloques de texto viven dentro de
 * ella y heredan su ancho: `--lectura` no se les vuelve a poner, porque
 * la caja ya lo es. Lo que NO cambia es el borde izquierdo — la caja no
 * lleva relleno horizontal a propósito (ver su regla), así que el `h1`
 * sigue empezando exactamente donde empieza ella y donde empieza todo lo
 * demás del sitio.
 */
.heroe > * {
  max-width: var(--lectura);
  margin-inline: var(--sangria) auto;
}

/*
 * ⚠️ AQUÍ VA `margin-block`, NO `margin`.
 *
 * Tres veces en la historia de esta hoja un `margin: 0` en un encabezado
 * ha anulado el `margin-inline: auto` de la regla de arriba y ha dejado
 * el elemento pegado al borde izquierdo mientras su propio título
 * empezaba 300 px más adentro. La tercera fue `.logros`.
 *
 * `margin-block` no puede hacer eso: no toca los lados. Todas las reglas
 * de esta hoja que ponen margen a un hijo directo de `.heroe` o de
 * `.seccion` lo usan, y por eso. Si vas a escribir `margin:` a secas
 * aquí dentro, no lo escribas.
 *
 * Hay además una comprobación en el navegador que recorre los hijos de
 * cada `.seccion` y exige que compartan borde izquierdo con su
 * encabezado. Sigue verde; la salida está en el informe.
 */
.heroe h1 {
  margin-block: 0;
  font-size: clamp(1.9rem, 1.15rem + 2.75vw, 3.2rem);
  letter-spacing: -0.022em;
  /* Sobre la lámina, el titular es claro. El color va explícito y no
     heredado para que se lea aquí y no haya que ir a buscarlo. */
  color: var(--papel);
}

/*
 * El subtítulo va en la MISMA serif y en azul. Los dos juntos son una
 * sola frase partida en dos —«Quien evalúa a otro solo ve el resultado.»
 * / «AIdeaText hace visible cómo se construyó el argumento y la defensa
 * oral.»— y así se leen: el problema en tinta, la respuesta en el color
 * de la marca.
 *
 * Sigue siendo un `<p>` y no un `h2`, que es lo que dice el comentario de
 * `heroe()` en portada.ts: un `h2` aquí abriría un encabezado que no
 * encabeza ninguna sección. Se ve como un titular sin mentir sobre la
 * estructura, que es exactamente para lo que existe el CSS.
 *
 * ⚠️ EL TECHO DEL `clamp` BAJA DE 2.55rem A 2.05rem, Y ES CONSECUENCIA
 * DE QUE LA FRASE SE COMPLETARA. Con cuatro palabras —«hace visible cómo
 * se construyó»— a 40,8 px cabían en dos líneas; con la frase entera
 * —que nombra los dos canales, lo escrito y lo hablado— salían TRES, y
 * el subtítulo solo se comía 139 px del pliegue.
 *
 * Y el pliegue no sobraba. Los tres números son de `medir-portada.mjs` a
 * 1366×768 en la versión inglesa, que es el peor de los cuatro casos:
 *
 *   · con la frase corta ................................ y=695
 *   · con la frase entera al techo viejo (2,55rem) ...... y=741
 *   · con la frase entera y este techo .................. y=712
 *
 * Los 29 px que devuelve este techo son la línea que la frase larga
 * añadía. Lo que falta hasta volver al punto de partida lo pone el aire
 * de arriba del héroe, que bajó a la vez y por lo mismo.
 *
 * ⚠️ EL SUELO NO SE TOCA, Y HAY UNA PRUEBA QUE LO IMPIDE. 1,5rem son 24
 * px, que es el umbral de «texto grande» de WCAG: es lo que justifica
 * que este texto se mida contra 3:1 y no contra 4,5:1 sobre el peor
 * píxel de la lámina. Bajarlo a 1,4rem no rompe nada visible y deja la
 * guarda de contraste midiendo contra el umbral que no es.
 */
.heroe .subtitulo {
  margin-block: 0.28em 0;
  font-family: var(--serif);
  font-size: clamp(1.5rem, 1rem + 1.9vw, 2.05rem);
  font-weight: 600;
  line-height: 1.14;
  letter-spacing: -0.02em;
  /* ⚠️ ENTRA CON LA FRASE ENTERA, y es lo mismo que ya lleva `.lema`.
     Mirado a 1366 en inglés: la frase larga caía en tres líneas con
     «built.» sola en la tercera — una viuda de una palabra al pie del
     segundo titular más grande de la página. `balance` reparte las tres
     y no cambia cuántas son, así que no mueve el botón del héroe (y la
     guarda del pliegue lo comprueba). Donde no está soportado, el texto
     envuelve como siempre. */
  text-wrap: balance;
  /* ⚠️ `--azul-claro` Y NO `--azul-hondo`, y es el mismo caso que ya
     resolvió el pie: `--azul-hondo` está oscurecido para leerse sobre
     papel, y desde que el héroe va sobre la lámina esto es claro sobre
     oscuro. Sobre `--tinta` aquél da 2,3:1 y éste 6,47:1. */
  color: var(--azul-claro);
}

/*
 * ── EL PIE DE LA LÁMINA ─────────────────────────────────────────────
 *
 * «Modelando como piensan las personas, no solo lo que ellas producen.»
 * Es la frase que el dueño nombró como pie de la lámina de los cuatro
 * grafos, y hasta ahora el sitio sólo la decía DENTRO de la carátula del
 * vídeo: escrita en una imagen, donde ni un buscador ni un lector de
 * pantalla la alcanzan.
 *
 * El filete de arriba es lo que la separa del titular sin darle otro
 * tamaño: es un pie, no un tercer nivel de titular. Va en la serif
 * porque pertenece al bloque del titular, no al cuerpo.
 *
 * ⚠️ Y VA DELANTE DE LA PRECISIÓN. Es la afirmación más grande de la
 * página y la delimitación de alcance tiene que leerse pegada a ella.
 * Hay una prueba que fija ese orden.
 */
.heroe .lema {
  margin-block: 1.15em 0;
  padding-top: 1rem;
  border-top: 1px solid rgba(251, 248, 243, 0.3);
  font-family: var(--serif);
  font-size: clamp(1.05rem, 0.95rem + 0.45vw, 1.35rem);
  font-weight: 600;
  line-height: 1.3;
  color: var(--papel);
  text-wrap: balance;
}

/*
 * ⚠️ LA DELIMITACIÓN DE ALCANCE DEL §4.1, Y POR QUÉ LLEVA FILETE ROJO.
 *
 * «No medimos el razonamiento completo: medimos la huella que deja en el
 * texto.» Es la corrección que el dueño escribió a mano y la única
 * afirmación del sitio que dice lo que AIdeaText **no** hace. Tiene tres
 * pruebas detrás que garantizan que se rinde, y hasta ahora, una vez
 * rendida, se leía como un párrafo gris más.
 *
 * El filete la marca sin tocarle una letra. Y el rojo es el mismo que
 * llevan el alcance del pie de la figura y la sección «Lo que no hace»:
 * en esta página, el rojo es el límite.
 */
.heroe .precision {
  margin-block: 1.35em 0;
  padding-left: 1.05rem;
  border-left: 3px solid var(--rojo);
  font-size: 0.97em;
  /* ⚠️ `--tenue-claro` Y NO `--tinta-suave`. Desde que el héroe va sobre
     la lámina, esto es claro sobre oscuro: `--tinta-suave` sobre
     `--tinta` da 1,4:1, o sea que la única afirmación del sitio sobre lo
     que AIdeaText NO hace se habría quedado ilegible. */
  color: var(--tenue-claro);
}

.acciones {
  margin-block: 1.75em 0;
}

/*
 * El botón, en píldora.
 *
 * El logotipo son círculos; una píldora es un círculo estirado. Es la
 * única forma de la página que no es un rectángulo redondeado, y por eso
 * la única llamada a la acción del sitio no se confunde con una tarjeta.
 *
 * Blanco sobre `--azul-hondo`: 7,10:1, muy por encima del 4,5:1 de AA.
 * Con el azul de marca a pleno habrían sido 4,37:1, que pasa por los
 * pelos y sólo porque el rótulo va en negrita.
 */
.boton {
  display: inline-block;
  padding: 0.8em 1.6em;
  border: 0;
  border-radius: 999px;
  background: var(--azul-hondo);
  color: #fff;
  font: inherit;
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 120ms ease, transform 120ms ease;
}

.boton:hover,
.boton:focus-visible {
  background: #084a76;
}

.boton:active {
  transform: translateY(1px);
}

/* ── Las secciones ────────────────────────────────────────────────── */
/*
 * ⚠️ EL `padding` DE ESTA REGLA NO ES SÓLO ESPACIADO: de él sale el
 * `sizes` de la figura.
 *
 * Una prueba —«el sizes declara la ranura que el CSS construye, tramo
 * por tramo»— lee este `clamp` y el `max-width` de `.figura`, reconstruye
 * los cuatro tramos del atributo y los compara con lo que rinde
 * `portada.ts`. Cambiar cualquiera de los dos números sin cambiar el
 * `sizes` pone roja esa prueba, que es justo lo que se quiere.
 *
 * Por eso los dos se quedan como estaban aunque todo lo demás de esta
 * hoja haya cambiado: el rediseño no tenía por qué moverlos, y moverlos
 * habría arrastrado el `srcset` de cuatro archivos.
 */
.seccion {
  padding: clamp(2rem, 5vw, 3.5rem) clamp(1rem, 5vw, 2rem);
  border-top: 1px solid var(--borde);
  counter-increment: seccion;
}

/* El marco se aplica a los hijos, no a la sección: así el fondo alterno
   de `.limite` y el filete de arriba siguen llegando a los dos bordes.

   El tope es `--marco` y no `--lectura`, porque aquí dentro hay bloques
   que pasan de la medida de lectura a propósito: la figura, las fichas,
   las dos tarjetas. Lo que limita la MEDIDA de la línea es la regla
   siguiente, y sólo alcanza a lo que lleva texto corrido. */
.seccion > * {
  max-width: min(var(--marco), 100%);
  margin-inline: var(--sangria) auto;
}

/*
 * La medida de la línea, para lo que se lee renglón a renglón. Es la
 * lista de hijos de `.seccion` que llevan prosa: los titulares, los
 * párrafos —`.marco-teorico` es uno— y la lista de logros.
 *
 * No la llevan la figura, las rejillas ni el marco del vídeo: ésos
 * comparan formas o colocan tarjetas, y dentro de 624 px no se
 * distinguen. Son la excepción y por eso están escritos por omisión.
 */
.seccion > h2,
.seccion > p,
.seccion > ul {
  max-width: var(--lectura);
}

.seccion h2 {
  margin-block: 0 0.75em;
  font-size: clamp(1.45rem, 1.1rem + 1.35vw, 2.15rem);
}

/*
 * El ordinal de la sección: la etiqueta mono corta encima del titular,
 * que es el ritmo que repite la referencia.
 *
 * ⚠️ NO ES COPIA, Y ESO ES LA MITAD DE LA DECISIÓN. El contenido del
 * sitio está cerrado —once rondas de revisión— y no se le añade una
 * palabra. Un ordinal no es una palabra: es la posición que el elemento
 * ya ocupa, y esa posición **es el argumento**. Lo dice la cabecera de
 * `ORDEN_DE_SECCIONES` en portada.ts: «El orden ES el argumento: problema
 * → método → mapa → pagos → límite → …». Numerarlas es enseñar eso.
 *
 * Va por contador de CSS y no por marcado para que no exista fuera de la
 * presentación: si mañana se reordenan las secciones, los números se
 * reordenan solos y nadie tiene que acordarse.
 *
 * `/ ""` es el texto alternativo del contenido generado: vacío, para que
 * un lector de pantalla no anuncie «cero cinco» antes de cada titular.
 * Son once —diez de `ORDEN_DE_SECCIONES` más la del fundador, que el
 * §4.9 separa— y por eso `decimal-leading-zero`, que da 01…11 y no
 * 1…11 con la columna descuadrada.
 */
.seccion > h2::before {
  content: counter(seccion, decimal-leading-zero) / '';
  display: block;
  margin-bottom: 0.9em;
  color: var(--tinta-suave);
  letter-spacing: 0.14em;
}

/* El contador arranca en el `<main>`, que es donde viven las secciones.
   El héroe queda fuera: no es una sección, es la entrada. */
#contenido {
  counter-reset: seccion;
}

/*
 * ── LAS BANDAS, QUE SON LO QUE FALTABA ────────────────────────────────
 *
 * El dueño rechazó dos rediseños diciendo «es una maqueta todavía», y el
 * revisor anterior puso el dedo en la parte medible: a 1366 px la columna
 * de prosa acaba cerca del 45 % del ancho y las secciones de sólo texto
 * se quedan con medio lienzo vacío.
 *
 * Lo que NO arregla eso: meter más texto, ni ensanchar la medida de
 * lectura —77 caracteres ya están en el techo de lo cómodo, y el número
 * está medido en el navegador—. Lo que lo arregla es superficie: bloques
 * que ocupan el marco entero y bandas de fondo que separan un capítulo
 * del siguiente.
 *
 * Las dos secciones que llevan las láminas grandes —el método y el
 * vídeo— van sobre el papel hondo. El resto se queda sobre el papel, y
 * `.limite` conserva su banda propia con el filete rojo.
 *
 * Con el portafolio, la página tiene además dos superficies OSCURAS que
 * la abren y la cierran: el héroe sobre la lámina y la banda del
 * formulario con el pie. La secuencia entera, de arriba abajo:
 *
 *   tinta(héroe) · papel(problema) · panel(método) · papel(mapa) ·
 *   papel(pagos) · panel(límite) · papel(verticales) · panel(vídeo) ·
 *   papel(credibilidad) · papel(fundador) · panel(implementación) ·
 *   tinta(entrevista) · tinta(pie)
 *
 * Ninguna banda del mismo tono toca a otra, salvo las dos últimas, que
 * son el cierre y van juntas a propósito.
 */
#metodo,
#video {
  background: var(--panel);
}

/*
 * «Lo que no hace» va detrás del método, no escondido al final, y se
 * distingue del resto: es el filtro que hace creíble todo lo anterior.
 *
 * Lleva el panel Y el rojo, porque es la tercera pieza de la misma
 * familia que el `precision` del héroe y el alcance del pie de la
 * figura. Las tres dicen dónde está el borde de lo que se promete.
 */
.limite {
  background: var(--panel);
  border-top-color: var(--rojo);
}

/* El ordinal de ESTA sección sí va en rojo, y es el único de los diez
   que lo lleva: es la tercera pieza de la familia del límite, con el
   filete del héroe y el alcance del pie de la figura. Si todos fueran
   rojos, el rojo no diría nada. */
.limite > h2::before {
  color: var(--rojo);
}

/* ── El problema, en tres bloques ─────────────────────────────────── */
/*
 * Tres párrafos seguidos ocupaban 624 px de los 1 120 del marco y dejaban
 * el resto en blanco. Son los mismos tres párrafos —ni una palabra más ni
 * una menos—, puestos uno al lado del otro.
 *
 * El envoltorio `<div class="trio">` existe por la guarda de alineación:
 * todo hijo DIRECTO de una sección tiene que empezar donde empieza su
 * encabezado, y tres columnas de hijos directos rompen eso. Dentro del
 * envoltorio no hay guarda que romper. Está explicado en `portada.ts`.
 */
.trio {
  display: grid;
  gap: 1.25rem;
  max-width: min(var(--marco), 100%);
  /* `margin-block` y nada más: el de los lados lo pone `.seccion > *`.
     Es la cuarta regla de esta hoja que lo dice, y por el mismo motivo. */
  margin-block: 1.75rem 0;
}

@media (min-width: 58rem) {
  .trio {
    grid-template-columns: repeat(3, 1fr);
  }
}

.trio p {
  margin: 0;
  padding: 1.5rem 1.4rem;
  border: 1px solid var(--borde);
  border-radius: var(--radio-grande);
  background: var(--panel);
}

/*
 * ⚠️ EL BLOQUE DEL MEDIO VA OSCURO, Y NO ES ADORNO.
 *
 * «Con IA generativa, un resultado correcto ya no prueba que hubo
 * comprensión.» Es la frase que hace que el resto de la página tenga
 * sentido: sin ella, el problema que describe el §4.2 es el de siempre.
 * Entre dos párrafos largos del mismo gris se leía como el de en medio.
 *
 * Va en la serif de los titulares y sobre `--tinta`, que es la misma
 * superficie de las cinco láminas del producto. Blanco papel sobre
 * `--tinta`: 15,54:1.
 *
 * `text-wrap: balance` porque son dos líneas y una viuda de dos palabras
 * dentro de una tarjeta se ve como un error de maquetación.
 */
.trio p:nth-child(2) {
  border-color: var(--borde-oscuro);
  background: var(--tinta);
  color: var(--papel);
  font-family: var(--serif);
  font-size: 1.22em;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.012em;
  text-wrap: balance;
}

/* ── La figura de los cuatro razonamientos ────────────────────────── */
.figura {
  /* La excepción a `--lectura`: lo que aquí se compara son cuatro formas,
     y dentro del ancho de lectura no se distinguen.

     Estos 70rem son el ÚLTIMO TRAMO del `sizes` de portada.ts, no su
     punto de corte: el corte cae en 74rem, porque hasta ahí la figura
     sigue creciendo como `100vw - 4rem` y sólo entonces topa aquí. Aquí
     se decía «el punto de corte», y era falso por 4rem.

     Una prueba reconstruye el `sizes` entero a partir de este número y
     del `padding` de `.seccion` de aquí arriba, así que los dos archivos
     no pueden separarse en silencio. */
  max-width: min(70rem, 100%);
  margin-block: 0;
}

.figura img {
  width: 100%;
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  /* Reserva el hueco antes de que la imagen llegue: sin esto, el resto de
     la página salta al cargarla.

     1920 / 955, que es lo que MIDE `razonamientos-1920.webp`. Aquí ponía
     950 —la aproximación «1920×~950» del spec §5.5—, y con `contain` una
     caja más chata que la imagen le habría puesto dos franjas de fondo
     arriba y abajo. Mismo criterio que las carátulas: la medida se lee
     del archivo, no se supone.

     ⚠️ Este número lo lee una prueba. No se toca sin mirar el archivo. */
  aspect-ratio: 1920 / 955;
  object-fit: contain;
  /* ⚠️ AQUÍ PONÍA BLANCO «porque el gráfico viene con fondo blanco», y el
     archivo es OSCURO —lo es desde que el gráfico se dibuja con viridis,
     que sobre papel cálido deja el nodo más importante en 1,2:1—. El
     comentario describía una figura que ya no existía.

     El fondo no se ve nunca, porque el `aspect-ratio` de aquí arriba es
     exactamente el del archivo y `contain` no deja franja. Lo que sí
     hace es asomar durante la carga y detrás del radio, y ahí un blanco
     recortaba una esquina clara bajo una imagen oscura. Va el mismo
     `--tinta` que traen las cinco láminas. */
  background: var(--tinta);
}

/*
 * ⚠️ AQUÍ VIVÍA `<ul class="formas">`, LA LISTA DE CUATRO PÍLDORAS CON
 * LOS ROTULOS —«Deductivo · estrella»—, Y SE HA IDO A OTRO SITIO.
 *
 * Era una leyenda suelta debajo de la lámina de contacto. Desde que cada
 * grafo lleva su explicación al lado, ese rótulo es el `<h3>` de su
 * bloque: es donde de verdad rotula algo. Dejarlo en los dos sitios
 * habría sido decir lo mismo dos veces en la misma pantalla.
 *
 * Las cuatro cadenas siguen siendo `metodo.formas` y siguen llegando al
 * HTML; lo comprueba «toda cadena del diccionario llega al HTML», que no
 * mira dónde. Quién las ata a SU lámina es la prueba nueva «cada bloque
 * casa su lámina con su rótulo y su explicación».
 *
 * La muestra `.formas li` se ha quitado también de `medir-portada.mjs`.
 * Un selector que no casa devuelve `null` y la herramienta lo filtra en
 * silencio: la muestra se habría caído de la tabla de contraste sin que
 * nadie lo notara, que es exactamente cómo se quedaron fuera los dos
 * ordinales la vez anterior.
 */

.figura figcaption {
  max-width: var(--lectura);
  margin-block: 1.15em 0;
  /* A la izquierda del `<figure>`, no centrado bajo la imagen: el pie es
     texto y se lee, y un texto centrado bajo una imagen de 1120 px
     empezaba 248 px a la derecha de la imagen que explica. */
  margin-inline: 0 auto;
  font-size: 0.94em;
  color: var(--tinta-suave);
}

/*
 * El alcance del pie, en rojo.
 *
 * «Es una demostración de que las formas se distinguen» — el pie dice
 * DEMOSTRACIÓN y no validación, y esa palabra es media credibilidad de
 * la sección. `resaltar()` la envuelve en un `<strong>`; aquí se le pone
 * el color que en esta página significa «hasta aquí llega lo que se
 * afirma».
 *
 * 7,01:1 sobre el papel: es texto, y cumple AA de cuerpo.
 */
.figura figcaption strong {
  color: var(--rojo);
}

/* ── La galería: los cuatro grafos, cada uno legible ──────────────── */
/*
 * ⚠️ POR QUÉ ESTÁN AQUÍ Y NO SUSTITUYEN A LA LÁMINA DE ARRIBA.
 *
 * La lámina del §5.5 son los cuatro a la vez: es lo que sostiene «las
 * formas se distinguen» de un vistazo, y es la imagen que se pinta al
 * pegar el enlace en LinkedIn. Lo que NO es, es legible.
 *
 * Y esto está MIRADO, no supuesto. Publicada ocupa 1 120 px, o sea 280
 * por panel: la mitad de los 550 que da la galería. A ese tamaño sus
 * veintitantas etiquetas de concepto se pisaban entre sí y se leían
 * encadenadas —«diagnósticoiacrítica», «medicimagenracciónuntarhistor»,
 * «presentaciónonocimiento»—; el informe de la Tarea 5 ya lo dejaba
 * apuntado como defecto abierto.
 *
 * Al regenerarla desde una sola corrida se corrigió: ahora rotula **sólo
 * los uno a tres conceptos que el detector señala como firma**, que son
 * los que su propio pie nombra. La lámina de contacto enseña que las
 * cuatro formas se distinguen; los nombres, uno a uno, están aquí.
 *
 * Éstas resuelven eso: un grafo por lámina, con su cabecera, su escala y
 * sus etiquetas. Las genera `herramientas/generar-grafos.py` con el motor
 * del producto.
 *
 * ── LA MEDIDA, QUE ES LA DECISIÓN ENTERA, Y ESTÁ MEDIDA ─────────────
 *
 * Dos columnas dentro del marco dan **550,0 px** por lámina, medido con
 * `getBoundingClientRect` a 1366 y no calculado aquí. La lámina se dibuja
 * a 1 440 px con la etiqueta de concepto en 9,2 pt a 200 ppp —25,6 px—,
 * que en la variante de 1 120 son 19,9 px y en una ranura de 550 salen a
 * **9,8 px**. Se leen: está mirado en la captura del navegador, no
 * deducido de la cuenta. A tres columnas caerían a 6,4 px y entonces lo
 * correcto sería no publicarlas.
 *
 * Por debajo de 58rem la galería pasa a UNA columna. A 390 px de ventana
 * la ranura mide **351,0 px** (medido) y las etiquetas bajan a **6,2 px**:
 * en un teléfono estas cuatro láminas se ven, se distingue la forma —que
 * es lo que la sección afirma— y se leen la cabecera y el pie de cada
 * una, pero los nombres de los conceptos NO. Queda dicho aquí y en el
 * informe en vez de publicarse como si se leyeran; arreglarlo pide otra
 * composición para móvil, no otra resolución.
 *
 * Los dos candidatos del `srcset` bastan, y está comprobado cuál se lleva
 * el navegador en los tres casos: 1366 sin densidad → el de 560; 1366 con
 * densidad 2 → el de 1 120; 390 con densidad 3 → el de 1 120.
 */
/*
 * ── EL PORTAFOLIO, QUE ES LO QUE EL DUEÑO PIDIÓ ────────────────────
 *
 * «Que se vea como un portafolio de fotografías.» Lo que eso pide, en la
 * plantilla que él señaló, es la `projects-section`: bloques alternos de
 * imagen grande y texto, no una rejilla de miniaturas.
 *
 * La galería pasa de ser 2×2 de láminas sueltas a ser CUATRO bloques, uno
 * por razonamiento, cada uno con su lámina a un lado y lo que dice al
 * otro. La lámina mide lo mismo que antes —dos columnas dentro del marco,
 * 550 px medidos a 1366—, así que la legibilidad de las etiquetas de
 * concepto no cambia y el pie que la declara sigue valiendo.
 *
 * Lo que cambia es la altura de la sección: cuatro filas en vez de dos.
 * Es el precio de la forma que se pidió, y es el precio que paga la
 * plantilla entera.
 */
.galeria {
  display: grid;
  gap: 2.25rem;
  max-width: min(var(--marco), 100%);
  margin-block: 1.9rem 0;
}

/*
 * Un bloque: la lámina y lo que dice.
 *
 * En una columna —teléfono— la lámina va encima y el texto debajo, que es
 * el orden en que se leen. A partir de 58rem son dos columnas y se
 * ALTERNAN: el primero y el tercero con la lámina a la izquierda, el
 * segundo y el cuarto con la lámina a la derecha. Es lo que hace que
 * cuatro bloques seguidos no se lean como una lista.
 *
 * `nth-of-type` cuenta `<div>` hermanos, y los únicos `<div>` dentro de
 * `<figure class="galeria">` son los cuatro bloques: el pie es un
 * `<figcaption>`, que es otro tipo y no entra en la cuenta.
 *
 * Las dos piezas se colocan en la MISMA fila con `grid-row: 1`: sin eso,
 * cambiarles la columna las pone en filas distintas y el bloque se parte
 * en diagonal.
 */
.bloque {
  display: grid;
  gap: 1.25rem;
  align-items: stretch;
}

@media (min-width: 58rem) {
  .bloque {
    grid-template-columns: 1fr 1fr;
    gap: 1.5rem;
  }

  .bloque:nth-of-type(even) > .grafo {
    grid-column: 2;
    grid-row: 1;
  }

  .bloque:nth-of-type(even) > .dice {
    grid-column: 1;
    grid-row: 1;
  }
}

/*
 * El panel oscuro con lo que dice la lámina.
 *
 * Va sobre `--tinta` —el mismo lienzo que trae la imagen de al lado— por
 * lo mismo que el pie de página y el marco de las láminas: así el bloque
 * se lee como una pieza y no como una imagen con un párrafo pegado. Es el
 * `.project.bg-black` de la plantilla.
 *
 * El texto se centra en vertical dentro del panel: la lámina es alta
 * —1120×1229— y un párrafo de cuatro líneas pegado arriba deja medio
 * panel vacío. Medido: papel sobre `--tinta`, 15,54:1.
 */
.dice {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(1.5rem, 3.2vw, 2.6rem);
  border: 1px solid var(--borde-oscuro);
  border-radius: var(--radio);
  background: var(--tinta);
  color: var(--papel);
}

.dice h3 {
  margin-block: 0 0.65em;
  font-size: clamp(1.25rem, 1.05rem + 0.62vw, 1.6rem);
  color: var(--papel);
}

.dice p {
  margin: 0;
  font-size: 1.02em;
}

/*
 * El marco de una lámina. El fondo es `--tinta` —el mismo que trae el
 * archivo— para que el radio recorte sobre el color propio de la imagen
 * y no aparezca una esquina de papel debajo mientras carga.
 *
 * `aspect-ratio` son las medidas REALES del archivo, 1120×1229. Se leen
 * de la cabecera RIFF/VP8, no se suponen: es el error que este expediente
 * ya ha cometido tres veces.
 */
.grafo,
.progresion-lamina {
  width: 100%;
  border: 1px solid var(--borde-oscuro);
  border-radius: var(--radio);
  background: var(--tinta);
}

.grafo {
  aspect-ratio: 1120 / 1229;
}

/*
 * El pie de la galería. Dice lo que la galería NO consigue en un teléfono
 * —que los nombres de los conceptos no se leen a 6,2 px— y lo dice sin
 * disculparse, porque lo que la sección afirma es que la FORMA distingue
 * el tipo, y la forma se ve a cualquier tamaño.
 *
 * La alternativa era esconder la galería por debajo de 58rem, que es
 * quitar la prueba de la propia tesis del sitio justo en el dispositivo
 * donde más gente la va a mirar.
 *
 * Hereda de `.figura figcaption` el sitio y el tono; va aparte porque
 * `.galeria` no es `.figura` y encadenar los dos selectores habría atado
 * dos bloques que no tienen por qué moverse juntos.
 */
.galeria figcaption,
.progresion figcaption {
  max-width: var(--lectura);
  margin-block: 1.15em 0;
  /* A la izquierda, no centrado bajo la imagen: es texto y se lee. */
  margin-inline: 0 auto;
  font-size: 0.94em;
  color: var(--tinta-suave);
}

/*
 * ⚠️ LO QUE ESTÁ SIMULADO, EN ROJO.
 *
 * «la secuencia está simulada». Es la cuarta pieza de la familia del
 * límite —con la precisión del héroe, el alcance del pie de la figura y
 * la sección «Lo que no hace»— y la que más falta hacía: sin ella, una
 * progresión de cuatro borradores se lee como el trabajo real de una
 * alumna a lo largo de un semestre, y no lo es. Las MEDIDAS sí son
 * reales; la secuencia no.
 *
 * Mismo rojo que el alcance de la figura, 7,01:1 sobre el papel.
 */
.progresion figcaption strong {
  color: var(--rojo);
}

/* ── La comparación de borradores ─────────────────────────────────── */
/*
 * La imagen que le faltaba a «El movimiento es el diagnóstico», que es la
 * frase más fuerte del sitio. La sección eran tres párrafos y nada que
 * mirar.
 *
 * Ocupa el marco entero por lo mismo que la figura: lo que se compara son
 * cuatro formas puestas a la misma escala, y dentro de 624 px de columna
 * de lectura los cuatro paneles miden 150 px cada uno y no se distingue
 * ninguno.
 *
 * 1920×648, leído del archivo.
 *
 * Va envuelta en un `<figure>` porque lleva PIE, y un párrafo suelto
 * detrás de una imagen no es su pie: es el párrafo siguiente. Lo que ese
 * pie dice —qué parte de lo que se ve está simulado— no puede quedar
 * colgando de nada.
 */
.progresion-lamina {
  aspect-ratio: 1920 / 648;
}

.progresion {
  margin-block: 2.1rem 0;
}

.marco-teorico {
  margin-block: 1.6em 0;
  font-size: 0.94em;
  color: var(--tinta-suave);
}

/* ── Los dos pagos: una sección, dos bloques, nunca separados ─────── */
.pagos {
  display: grid;
  gap: 1.25rem;
  /* El marco entero: son dos tarjetas y a 60rem quedaban centradas en
     otro sitio que el titular de su seccion. */
  max-width: min(var(--marco), 100%);
}

@media (min-width: 52rem) {
  .pagos {
    grid-template-columns: 1fr 1fr;
  }
}

/*
 * Las tarjetas. Radio generoso (20 px), papel un paso más hondo, borde
 * cálido. Sin sombra: una sombra sobre papel cálido se ve sucia, y el
 * contraste de fondo ya separa la tarjeta de la página.
 */
.pago,
.vertical,
.modalidad {
  padding: 1.6rem 1.5rem;
  border: 1px solid var(--borde);
  border-radius: var(--radio-grande);
  background: var(--panel);
}

.pago h3,
.vertical h3,
.modalidad h3 {
  margin-block: 0 0.55em;
  font-size: 1.28em;
  letter-spacing: -0.01em;
}

.pago p,
.vertical p,
.modalidad p {
  margin-block: 0.6em;
}

.pago p:last-child,
.vertical p:last-child,
.modalidad p:last-child {
  margin-bottom: 0;
}

/* ── Las verticales ───────────────────────────────────────────────── */
.fichas {
  display: grid;
  gap: 1.25rem;
  /* `min(100%, …)` es lo que impide que a 390 px la columna mínima
     empuje la rejilla más allá del viewport. */
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  max-width: min(var(--marco), 100%);
  margin-block: 1.75rem 0;
}

/*
 * Las dos cabeceras de la tabla del spec §4.7. Se ven pequeñas, pero se
 * ven: sin ellas «Evaluar el razonamiento jurídico…» deja de leerse como
 * el problema del cliente y pasa a leerse como una promesa nuestra.
 *
 * La monoespaciada las separa del cuerpo mejor que la negrita que
 * llevaban: en una tarjeta con tres bloques de texto, dos niveles de
 * negrita del mismo tipo de letra se confunden entre sí.
 */
.etiqueta {
  margin-block: 1.3em 0.35em;
  color: var(--tinta-suave);
}

.vertical .etiqueta:first-of-type,
.modalidad .etiqueta:first-of-type {
  margin-top: 1em;
}

/* ── Las tres formas de implementarlo ─────────────────────────────── */
/*
 * ⚠️ SECCIÓN EN BORRADOR, PENDIENTE DE CONFIRMACIÓN DEL DUEÑO. Las tres
 * modalidades no están documentadas en el expediente del proyecto: lo que
 * se publica es descripción general, más lo poco que sí tiene documento
 * detrás. Está escrito con todas sus letras en `implementacion` de
 * `es.ts` y en `seccionImplementacion()` de portada.ts, y hay una prueba
 * —«la sección no promete nada que no esté documentado»— que persigue las
 * cinco familias de promesa que aquí no pueden aparecer.
 *
 * Las tres fichas son la misma pieza que las verticales: mismo panel,
 * mismo radio, misma cabecera en monoespaciada que convierte la segunda
 * mitad de la ficha en un juicio y no en una promesa.
 */
#implementacion {
  background: var(--panel);
}

.modalidades {
  display: grid;
  gap: 1.25rem;
  /* `min(100%, …)` es lo que impide que a 390 px la columna mínima
     empuje la rejilla más allá del viewport. Misma cuenta que `.fichas`. */
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  max-width: min(var(--marco), 100%);
  margin-block: 1.75rem 0;
}

/*
 * ── LAS TRES CABECERAS «A QUIÉN LE ENCAJA», A LA MISMA ALTURA ───────
 *
 * Los tres «qué es» miden distinto —seis líneas, tres y tres—, así que la
 * cabecera de la segunda mitad caía a tres alturas distintas y las tres
 * fichas se leían como tres bloques sueltos en vez de como una tabla de
 * tres columnas. Es el mismo defecto que las dos cabeceras del §4.7
 * existen para arreglar, un nivel más arriba.
 *
 * `subgrid`: cada ficha hereda las CUATRO filas de la rejilla de fuera
 * —titular, qué es, cabecera, a quién encaja—, y cada fila mide lo que
 * mida la más alta de las tres. Ninguna otra técnica lo consigue sin
 * recortar texto o sin fijar alturas a ojo.
 *
 * ⚠️ VA DETRÁS DE UN `@supports`, Y NO ES CEREMONIA. Sin él, un navegador
 * que no entienda `subgrid` se queda con `grid-template-rows: subgrid`
 * como valor inválido pero con el `grid-row: span 4`, y las fichas se
 * reparten en filas que no existen: la rejilla se desmonta. Con el
 * `@supports`, el que no lo entienda ve exactamente lo de antes —tres
 * fichas correctas con las cabeceras descuadradas—, que es un defecto
 * de ritmo, no una página rota.
 *
 * El `@media` es el ancho a partir del cual `auto-fit` puede dar más de
 * una columna: 2 × 17rem + 1,25rem de hueco ≈ 35,25rem de rejilla, que
 * con el `padding` de la sección son ~39rem de ventana. Por debajo hay
 * una sola columna y no hay nada que alinear.
 *
 * `row-gap: 0` dentro de la ficha: el hueco de 1,25rem del padre separa
 * las FICHAS, y heredado dentro separaría también sus cuatro filas. El
 * aire de dentro lo ponen los márgenes, como en las otras tarjetas.
 */
@supports (grid-template-rows: subgrid) {
  @media (min-width: 40rem) {
    .modalidades {
      grid-template-rows: auto auto auto auto;
    }

    .modalidad {
      display: grid;
      grid-row: span 4;
      grid-template-rows: subgrid;
      row-gap: 0;
    }
  }
}

/*
 * Las tres preguntas que hay que responder sea cual sea la modalidad.
 * Misma viñeta dibujada que los logros: es una lista de cosas, no prosa.
 */
.decisiones {
  margin-block: 0.35rem 0;
  padding: 0;
  list-style: none;
}

.decisiones li {
  position: relative;
  margin-block: 0 0.6em;
  padding-left: 1.45rem;
}

.decisiones li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--azul);
}

/*
 * «Aquí no hay cifras, y no es por prudencia.»
 *
 * Lleva el filete rojo porque es de la familia del límite, con la
 * precisión del héroe, el alcance del pie de la figura, «Lo que no hace»
 * y la nota de lo que está simulado. Las cinco dicen dónde acaba lo que
 * se afirma, y ésta es la que lo dice en la sección donde más caro
 * saldría afirmar de más.
 *
 * `--tinta-suave` sobre `--panel`: 6,08:1.
 */
.expediente {
  margin-block: 1.7em 0;
  padding-left: 1.05rem;
  border-left: 3px solid var(--rojo);
  font-size: 0.97em;
  color: var(--tinta-suave);
}

/* ── El video ─────────────────────────────────────────────────────── */
/*
 * Carátula y botón comparten celda: el botón va ENCIMA de la imagen, no
 * debajo. Una sola área de rejilla lo resuelve sin posicionamiento
 * absoluto, y mantiene la caja con su proporción aunque la carátula no
 * haya llegado todavía.
 */
.marco-video {
  display: grid;
  grid-template-areas: 'caratula';
  place-items: center;
  /* 60rem y no el marco entero: a 1120 px el reproductor mide 630 de
     alto y se come la pantalla de un portatil. Va a la izquierda del
     marco, como todo lo demas. */
  max-width: min(60rem, 100%);
  aspect-ratio: 16 / 9;
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  background: var(--panel);
  overflow: hidden;
  text-align: center;
}

.marco-video > * {
  grid-area: caratula;
}

.marco-video img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/*
 * El botón va ARRIBA. Ni centrado ni abajo, y las dos cosas están
 * medidas sobre el archivo, no supuestas.
 *
 * Centrado tapaba el logo y «Modelando cómo piensan las personas, no solo
 * lo que ellas producen», que es el mensaje entero de la miniatura — y la
 * miniatura es lo único que ve quien no pulsa play, o sea casi todo el
 * mundo.
 *
 * Abajo tampoco, aunque fuera lo pedido: en la carátula real la mitad
 * inferior está ocupada hasta el último píxel —titular hasta el 77 % de
 * la altura, subtítulo, autoría, y el aviso de marca registrada de
 * NVIDIA en la última franja, que es justo el que no conviene esconder—.
 * La única zona libre de la captura son los ~150 px de arriba (25 % de
 * la altura), que son fondo decorativo del grafo.
 *
 * ⚠️ EL REDISEÑO NO LO HA MOVIDO NI LO HA ENGORDADO. Sigue compacto por
 * lo mismo de antes: el texto es largo porque el §4.8 obliga a avisar de
 * la conexión con YouTube, y a tamaño normal no cabe en esa franja en un
 * teléfono.
 *
 * MEDIDO a 390 px, que es el caso apretado, sobre la carátula real:
 *
 *   · el marco mide 351 × 197,4; la franja libre de arriba, 49,4;
 *   · el botón mide 322,4 × 27,4 en castellano y 251,4 × 27,4 en inglés,
 *     y su borde inferior cae a 34,8 del borde de arriba.
 *
 * O sea que cabe entero en la franja en los dos idiomas, y **en una sola
 * línea**. Aquí decía «ahí el texto va a dos líneas», que era cierto con
 * el botón rectangular de antes y dejó de serlo al pasar a píldora con
 * menos `padding` horizontal: 322,4 de 351 disponibles. Se corrige en vez
 * de dejar el número viejo, que es el que habría guiado el siguiente
 * ajuste.
 */
.marco-video .reproducir {
  z-index: 1;
  align-self: start;
  margin: 0.4rem;
  max-width: calc(100% - 0.8rem);
  padding: 0.5em 0.9em;
  font-size: 0.78rem;
  line-height: 1.2;
}

.marco-video iframe {
  width: 100%;
  height: 100%;
  border: 0;
}

/* ── Credibilidad: dos bloques separados, y se nota ───────────────── */
/*
 * Son dos `<section>` hermanas, `#credibilidad` y `#fundador`, cada una
 * con su propio `h2` y su propia región accesible. La separación del
 * §4.9 es un requisito, no maquetación: SIAGIE es trayectoria del
 * fundador y no puede quedar colgando de «Lo que ha conseguido
 * AIdeaText», ni por jerarquía de encabezados ni por nombre de landmark.
 *
 * ⚠️ El rediseño NO ha juntado los dos bloques, ni cuando el sello de
 * NVIDIA vivía aquí ni ahora que se ha ido a la cabecera. Son dos
 * afirmaciones distintas y tienen que leerse como dos.
 */
/*
 * ⚠️ EL SELECTOR LLEVA `.seccion >` DELANTE, Y HACE FALTA. La regla
 * `.seccion > ul` de más arriba pone `max-width: var(--lectura)` con
 * especificidad (0,1,1); un `.logros` a secas es (0,1,0) y PIERDE, así
 * que la lista se quedaba en 624 px y las dos columnas no aparecían. Es
 * el mismo caso que ya documenta `.seccion > form`.
 */
.seccion > .logros {
  /* ⚠️ `margin-block` Y NADA MÁS. Es la tercera vez que un `margin: 0`
     escrito aquí anula el margen de los lados que pone `.seccion > *` y
     deja la lista pegada al borde mientras su propio título empieza 300 px
     más adentro. `margin-block` no puede hacerlo: no toca los lados. */
  margin-block: 0;
  padding: 0;
  list-style: none;
  /* Cinco renglones cortos en una columna de 624 px dejaban el resto del
     marco vacío, que es el defecto que el revisor anterior midió. En dos
     columnas la lista ocupa el marco y sigue siendo una lista. */
  max-width: min(var(--marco), 100%);
}

@media (min-width: 58rem) {
  .seccion > .logros {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: 2.5rem;
  }
}

/*
 * Cada logro, con su viñeta dibujada: un disco del azul de marca, del
 * tamaño de un punto. Es el único sitio donde el azul a pleno aparece
 * repetido, y no lleva texto encima, así que su 4,13:1 no interviene.
 */
.logros li {
  position: relative;
  margin-block: 0 0.75em;
  padding-left: 1.45rem;
}

.logros li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--azul);
}

/*
 * ── EL SELLO DE NVIDIA YA NO ESTÁ AQUÍ ────────────────────────────
 *
 * Vivía al pie de esta lista, y el dueño ha pedido que suba a la
 * cabecera, al lado de la marca. Su regla está ahora junto a la de
 * `.cabecera`, con las medidas atadas a las del logotipo.
 *
 * ⚠️ NO SE HA QUEDADO EN LOS DOS SITIOS, y la decisión es de fondo: la
 * misma placa dos veces en la misma página deja de acreditar —la segunda
 * no añade credencial, añade repetición— y obligaría a que una de las
 * dos fuera decorativa y la otra no, dentro del mismo documento. Lo que
 * esta sección pierde es su única prueba visual; lo que gana la
 * credencial es salir sin desplazar, que es más de lo que tenía.
 *
 * Y lo que la guarda vieja protegía NO se ha perdido con la mudanza. Lo
 * que protegía era que el sello saliera de los DATOS —se rendía sólo si
 * algún `credibilidad.logros` casaba con `/nvidia/i`— y no de una
 * posición escrita a mano. En la cabecera el sello está en el HTML
 * estático y no puede ser condicional, así que la guarda se ha mudado
 * con él: `rediseno.test.ts` exige que, mientras alguna página declare
 * el sello, TODOS los diccionarios sigan nombrando NVIDIA en sus logros.
 * El renglón de esta lista sigue siendo, por tanto, lo que autoriza la
 * placa de allá arriba.
 *
 * ⚠️ PERO LA PROPOSICIÓN HA DEJADO DE AUTO-IMPONERSE, Y ESO NO ES UN
 * DETALLE DE REDACCIÓN. Antes el acoplamiento vivía en el CÓDIGO DE
 * RENDER: quitar la credencial del diccionario hacía desaparecer el
 * sello, corriera o no corriera nadie las pruebas. Ahora vive SÓLO EN LA
 * TANDA: quitar la credencial deja el sello puesto, acreditando algo que
 * el sitio ya no afirma, y lo único que lo impide es que alguien ejecute
 * `npm test`.
 *
 * En la práctica la fuerza es casi la misma —el flujo de despliegue
 * corre la tanda dos veces y la primera bloquea la publicación—, pero
 * «casi la misma» no es «la misma»: se ha cambiado una propiedad que se
 * cumplía por construcción por una que se comprueba. Quien edite los
 * diccionarios en una rama sin CI ya no tiene la red debajo. Está
 * escrito aquí para que el siguiente lo sepa antes de mover el sello
 * otra vez.
 */

/*
 * El bloque del fundador, en panel.
 *
 * Sigue siendo una `<section>` hermana de la de los logros —eso es
 * requisito del §4.9 y no se toca—, pero era el único bloque del sitio
 * que seguía siendo un párrafo suelto sobre el papel. Con el panel se lee
 * como una ficha, que es lo que es.
 *
 * Se queda en el ancho de lectura a propósito: es prosa, y ensancharla
 * hasta el marco la dejaría en 120 caracteres por línea.
 */
#fundador > p {
  padding: 1.5rem 1.4rem;
  border: 1px solid var(--borde);
  border-radius: var(--radio-grande);
  background: var(--panel);
}

/* ── El formulario ────────────────────────────────────────────────── */
/*
 * ⚠️ ESTO ERA LO QUE EL DUEÑO SEÑALÓ CON EXTRAÑEZA, y tenía razón: eran
 * siete campos desnudos, sin caja, sin agrupación y con el mismo aire
 * entre ellos que entre dos párrafos. Parecía un trámite, no una
 * invitación a escribir.
 *
 * Lo que cambia, y por qué cada cosa:
 *
 * 1. **Un panel con marco y radio de 20 px.** El formulario deja de ser
 *    la continuación del texto y pasa a ser un sitio donde se hace algo.
 * 2. **Dos columnas a partir de 40rem.** Los seis campos cortos se
 *    emparejan —nombre/correo, institución/rol, vertical/qué busca— y el
 *    formulario pasa de ocho renglones a cinco. Un formulario que se
 *    abarca de una mirada se rellena; uno que hay que desplazar, no.
 *    Debajo de 40rem vuelve a una columna, que en un teléfono es la
 *    única forma legible.
 * 3. **Campos altos, con fondo propio y radio.** Un `<input>` del color
 *    del papel sobre papel es un renglón; con el papel un paso más hondo
 *    y 10 px de radio es una caja donde cabe algo.
 * 4. **El botón, a la izquierda y en píldora**, igual que el del héroe:
 *    son la misma acción y se ven iguales.
 *
 * Lo que NO cambia: ni un campo más, ni un campo menos, ni una etiqueta
 * distinta. Los siete nombres, los dos desplegables, el campo trampa y
 * los mensajes de validación son los mismos bytes que antes.
 *
 * ⚠️ EL SELECTOR ES `.seccion > form` Y NO `form`, y no es manía. La
 * regla `.seccion > *` de aquí arriba pone `max-width: var(--lectura)`
 * con especificidad (0,1,0); un `form` a secas es (0,0,1) y PIERDE, así
 * que el panel se quedaba en el ancho de lectura y las dos columnas
 * salían estrechas. Lo mismo le pasa a `.acciones` y a `.aviso` de
 * dentro, que por eso van con el `form >` delante.
 */
/*
 * ⚠️ LA SECCIÓN DEL FORMULARIO VA OSCURA, Y ES LA `signup-section` DE LA
 * PLANTILLA.
 *
 * La página abre con la lámina a pantalla completa y cierra con la banda
 * oscura del formulario y el pie, que ya lo era: principio y final del
 * mismo color, y en medio el papel. Sin esto, el sitio pasaba del papel
 * al pie negro de golpe y el formulario —que es lo único que esta página
 * existe para conseguir— se leía como un párrafo más.
 *
 * El panel del formulario se queda CLARO sobre la banda oscura. Es
 * deliberado: los siete campos, sus etiquetas y el aviso de estado están
 * todos probados y medidos sobre papel, y volver blanco sobre oscuro
 * catorce elementos de formulario es rehacer una pieza que funciona para
 * ganar coherencia de color. El contraste de la etiqueta y de los campos
 * no se mueve un punto.
 *
 * Lo que sí cambia de color es lo que queda FUERA del panel: el titular y
 * su ordinal. `--tinta-suave` sobre `--tinta` da 1,4:1, así que el
 * ordinal pasa a `--azul-claro` —6,47:1—, que es el mismo valor que ya
 * resolvía este caso en el pie.
 */
#entrevista {
  background: var(--tinta);
  border-top-color: var(--borde-oscuro);
  color: var(--papel);
}

#entrevista > h2 {
  color: var(--papel);
}

#entrevista > h2::before {
  color: var(--azul-claro);
}

.seccion > form {
  max-width: min(46rem, 100%);
  padding: clamp(1.25rem, 3.5vw, 2rem);
  border: 1px solid var(--borde);
  border-radius: var(--radio-grande);
  background: var(--panel);
  /* ⚠️ EL COLOR DE TEXTO SE REPONE AQUÍ, Y LO ENCONTRÓ LA HERRAMIENTA.
     Al pasar `#entrevista` a banda oscura, el `color: var(--papel)` de la
     sección se heredaba dentro del panel claro y las siete etiquetas del
     formulario quedaban en 1,09:1 —blanco sobre panel, ilegible— sin que
     ninguna prueba de `npm test` pudiera verlo: es un color computado.
     `medir-portada.mjs` lo marcó cuatro veces, una por ventana e idioma.
     Los `<input>` llevan `color: inherit` y lo heredan de aquí. */
  color: var(--tinta);
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.05rem 1.25rem;
}

@media (min-width: 40rem) {
  .seccion > form {
    grid-template-columns: 1fr 1fr;
  }

  /*
   * Lo que ocupa las dos columnas: el mensaje —es un `<textarea>` de
   * cuatro líneas y en media columna no cabe nada—, el botón y el aviso.
   *
   * Se eligen por lo que CONTIENEN y no por una clase nueva, para no
   * tener que tocar el marcado que rinde `portada.ts`: el día que se
   * añada otro campo largo, se coloca solo.
   */
  .campo:has(textarea),
  form > .acciones,
  form > .aviso {
    grid-column: 1 / -1;
  }
}

.campo {
  /* Sin margen: el hueco lo pone el `gap` de la rejilla. Con las dos
     cosas a la vez, las dos columnas dejaban de alinearse por abajo. */
  margin: 0;
}

.campo label {
  display: block;
  margin-bottom: 0.4em;
  font-weight: 600;
  font-size: 0.92em;
  letter-spacing: 0.002em;
}

.campo input,
.campo select,
.campo textarea {
  width: 100%;
  padding: 0.7em 0.85em;
  border: 1px solid var(--borde);
  border-radius: var(--radio-chico);
  /* Blanco dentro del panel: es lo que dice «aquí se escribe». Con el
     campo del mismo color que el panel, los siete se leían como una
     sola mancha. */
  background: #fff;
  color: inherit;
  font: inherit;
  font-size: 1em;
  line-height: 1.4;
}

.campo input:hover,
.campo select:hover,
.campo textarea:hover {
  border-color: #cfc6b5;
}

/*
 * El campo con el foco puesto se ve, y se ve con el color de la acción.
 * `:focus-visible` global pone el anillo; esto además le cambia el borde,
 * que es lo que señala CUÁL de los siete está activo cuando el anillo
 * queda fuera de la vista del que escribe en un teléfono.
 */
.campo input:focus,
.campo select:focus,
.campo textarea:focus {
  border-color: var(--azul-hondo);
}

.campo textarea {
  resize: vertical;
  min-height: 7.5rem;
}

/* El campo trampa del §5.3: fuera de la vista y fuera del árbol de
   accesibilidad, para que sólo lo rellene un robot. `display: none` no
   sirve — hay robots que lo detectan y lo saltan.

   Va `position: absolute`, así que NO ocupa una celda de la rejilla del
   formulario: un elemento fuera de flujo no se coloca en un track. */
.trampa {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

form > .acciones {
  margin-block: 0.4rem 0;
  margin-inline: 0;
}

/*
 * El aviso NO se oculta con `display: none`.
 *
 * Varios lectores de pantalla no anuncian una región viva que entra en
 * el árbol de accesibilidad a la vez que se puebla: para que `aria-live`
 * funcione, el contenedor tiene que estar ya ahí cuando llega el texto.
 * Con `display: none` hasta el primer mensaje, la única confirmación de
 * que la solicitud salió —que es lo que esta página entera existe para
 * conseguir— no se oía.
 *
 * Vacío no ocupa nada igualmente: un bloque sin contenido y sin margen
 * mide cero de alto.
 */
.aviso {
  margin: 0;
}

/*
 * Los tres estados del envío (§4.10). El color NO es el único portador
 * del estado: el texto ya dice qué ha pasado, y es lo que anuncia el
 * `role="status"`. Esto sólo lo refuerza para quien lo ve.
 *
 * Con el rediseño el aviso pasa de ser un párrafo de color a ser una
 * caja: sobre el panel del formulario, un párrafo verde suelto se leía
 * como una nota al pie y no como la respuesta a lo que se acababa de
 * pulsar.
 */
.aviso:not(:empty) {
  margin-top: 0.25rem;
  padding: 0.85em 1em;
  border-radius: var(--radio-chico);
  border-left: 3px solid currentcolor;
  background: #fff;
}

.aviso[data-estado='enviando'] {
  color: var(--tinta-suave);
}

.aviso[data-estado='exito'] {
  color: #0d5c38;
  font-weight: 600;
}

.aviso[data-estado='error'] {
  color: #8f1a1a;
  font-weight: 600;
}

/* Mientras hay una petición en vuelo, el botón no se puede volver a
   pulsar. Sin esta regla un botón deshabilitado se ve idéntico a uno que
   responde, y quien lo pulsa vuelve a pulsarlo creyendo que no pasó nada. */
.boton:disabled {
  background: var(--tinta-suave);
  cursor: default;
  transform: none;
}

/* ── El pie ───────────────────────────────────────────────────────── */
/*
 * El pie arranca donde arranca todo lo demás: en el borde del marco. La
 * misma cuenta que la cabecera y por el mismo motivo — aquí el `100%` se
 * resuelve sobre el `<footer>`, que ocupa el ancho de la ventana, así que
 * el `padding` es lo que mete el contenido.
 *
 * Sin `max-width`: los tres enlaces son cortos y van en fila; limitarlos
 * a la medida de lectura sólo conseguía que el tercero cayera solo a la
 * segunda línea en un portátil.
 */
.pie {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1.75rem;
  margin-block: 0;
  padding-block: 2.25rem 3rem;
  padding-inline: max(clamp(1rem, 5vw, 2rem), calc((100% - var(--marco)) / 2));
  font-size: 0.94em;
}

/*
 * ⚠️ EL PIE VA OSCURO, Y ES LA ÚLTIMA PIEZA DEL DIAGNÓSTICO.
 *
 * Sobre el panel, el pie era el mismo tono que la sección del límite y
 * que las tarjetas: la página se acababa sin que nada dijera que se
 * acababa, y ésa es una de las cosas que hacen que un sitio se lea como
 * un documento a medio maquetar.
 *
 * El tono es `--tinta`, el mismo de las cinco láminas del producto: el
 * pie y las imágenes son ahora la misma familia de superficie, y la
 * página tiene un principio claro y un final claro.
 *
 * Medido, no estimado:
 *   · texto del pie (papel sobre tinta) ..... 15,54:1
 *   · enlaces (`--azul-claro` sobre tinta) ... 6,47:1
 * Los dos por encima del 4,5:1 de AA para cuerpo.
 */
#pie {
  border-top: 1px solid var(--borde-oscuro);
  background: var(--tinta);
  color: var(--papel);
}

.pie a {
  color: var(--azul-claro);
}

/* ── Accesibilidad ────────────────────────────────────────────────── */
/*
 * El anillo de foco va en el azul de marca a pleno y con desplazamiento:
 * es lo único de la página que se dibuja encima de cualquier fondo, así
 * que necesita el tono más saturado de los dos y no el de texto. No
 * lleva texto encima; su 4,13:1 no interviene aquí.
 */
:focus-visible {
  outline: 3px solid var(--azul);
  outline-offset: 2px;
  border-radius: 2px;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .boton {
    transition: none;
  }

  /*
   * ⚠️ EL RETORNO FLOTANTE APARECE DE GOLPE, SIN DESLIZARSE.
   *
   * Es el único elemento de la página que se mueve SOLO —los demás se
   * mueven cuando alguien pasa el ratón o pulsa—, o sea que es justo el
   * caso que esta consulta existe para atender: algo que entra en la
   * pantalla sin que nadie lo haya pedido.
   *
   * Con `transition: none`, `visibility` conmuta en el mismo fotograma
   * que `opacity` —que es lo que aquí se quiere— y el botón sigue
   * entrando y saliendo del orden de tabulación en el momento justo. Lo
   * único que se pierde es el deslizamiento de medio `rem`, y `transform`
   * se anula con él para que no se quede a mitad de camino.
   *
   * `.marca-enlace` entra en la misma regla: su atenuación al pasar por
   * encima es movimiento de la misma familia.
   */
  .subir,
  .marca-enlace {
    transition: none;
  }

  .subir {
    transform: none;
  }
}
