/* WayGroup — páginas internas.
   El home es cine. Esto es para leer: rápido, legible, sin fijado de scroll.
   Del spec: un lector de contratación pública tiene que llegar a specs sin
   atravesar una película. Se apoya en tokens.css y base.css, no los repite. */

/* El salto al contenido estaba aquí y, copiado, en cinema.css. Ahora es una
   sola regla en base.css, que cargan las dos familias de página. */

.page{background:var(--surface)}
.page main{display:block}

/* ---------- nav ----------
   Cada enlace tiene su propia superficie: el fondo aparece al pasar por encima,
   en vez de cambiar sólo el color de la letra. Con la barra flotando sobre
   fotografía, un cambio de tinta solo se pierde; una superficie no. */
.page .nav .menu{display:flex;align-items:center;gap:2px}
/* El padding ya no es sólo para agrandar el objetivo: es la forma de la
   superficie de hover. 8x11 deja la zona pulsable en 30px de alto, holgada
   sobre los 24x24 que exige WCAG 2.2 AA 2.5.8. Antes eran 4px arriba y abajo y
   ni un píxel a los lados, porque la barra tenía altura fija y no había sitio.
   El canto es el de control, el mismo de los botones: un enlace de menú es un
   control, no un sello. */
.page .nav .menu a{font-family:var(--font-display);font-size:12px;font-weight:600;color:var(--text-2);
  letter-spacing:.01em;padding:8px 11px;border-radius:var(--r-md);
  transition:color var(--t-ui) var(--ease),background var(--t-ui) var(--ease);
  white-space:nowrap}
.page .nav .menu a:hover,.page .nav .menu a:focus-visible{color:var(--text);
  background:var(--veil)}
.page .nav .menu a[aria-current="page"]{color:var(--accent)}
/* LA SEGUNDA MARCA DE LA BARRA: el grupo que CONTIENE la página actual.
   `client/pages.ts:364` le pone `aria-current="true"` al disparador cuando el
   enlace que casa vive dentro de su panel —`/cobertura`, `/hubs`,
   `/certificaciones`, `/simuladores-educativos`, que no comparten prefijo con la
   página que encabeza su grupo—. La regla de arriba es de valor exacto, así que
   `"true"` no casaba y en esas cuatro páginas la barra visible no señalaba nada
   mientras el lector de pantalla ya lo decía. Un selector de atributo a secas
   —`a[aria-current]`— habría teñido las dos marcas del mismo acento y borrado la
   distinción: «estás dentro de esto» no es «ésta es la página».
   POR QUÉ --text Y NO UN SEGUNDO ACENTO. La diferencia es de presencia, no de
   tinta de marca: el rótulo sube de --text-2 a --text, el escalón que esta misma
   barra ya usa para el puntero, y el acento se queda como propiedad exclusiva de
   la página exacta. Con el chevron en `currentColor`, el control entero sube.
   No lleva superficie: la superficie es la señal de hover (ver el comentario del
   bloque), y dársela dejaría el grupo con aspecto de estar pulsado siempre.
   MEDIDO EN LOS CINCO FONDOS QUE PUEDE TENER LA BARRA. La tabla mide LAS DOS
   marcas, no sólo ésta: --text es la del grupo, --accent la de la página exacta
   (la regla de arriba), y --text-2 es la tinta base contra la que se comparan.
   Composición al 70 % del cristal —al 90 % la fila sin JavaScript—, y las filas
   segunda y tercera reproducen las dos composiciones de `base.css:280-287`:
                                                        --text-2  --text  --accent
     barra oscura sobre página oscura  rgb(3,8,13)          9,78   18,70      7,46
     barra oscura sobre sección clara  rgb(75,80,84)        3,97    7,59      3,03  x
     barra oscura sin JS (--ink-a90)   rgb(27,32,37)        7,98   15,26      6,09
     barra clara sobre página clara    rgb(244,247,250)     5,73   17,82      8,46
     barra clara sobre sección oscura  rgb(172,175,179)     2,80    8,70      4,13  x
   --text sale limpia: es la tinta de MÁS contraste de su tema sobre la
   superficie de su tema, así que no puede fallar donde --text-2 pasa.
   --accent NO SALE LIMPIA, Y HAY QUE DECIRLO. Las dos filas marcadas con «x»
   quedan por debajo de los 4,5:1 que pide AA para 12px/600. Son los dos estados
   en los que la barra y la sección de debajo tienen temas opuestos: la barra
   servida antes de que el observador la voltee, y la vuelta. No los estrena
   esta regla —el acento lleva ahí desde que hay barra— pero sí los multiplica:
   la navegación pasó de 2 entradas a 4 más 7 hijos, o sea que hay muchas más
   páginas en las que una marca de acento está en pantalla.
   Y ojo con el matiz: en esas dos filas la tinta BASE ya falla (3,97 y 2,80),
   así que no hay un estado nuevo en el que el acento sea lo único ilegible;
   pero el acento está PEOR que la base (3,03 contra 3,97), así que tampoco
   queda cubierto por «ahí ya fallaba todo».
   POR QUÉ NO SE ARREGLA AQUÍ, con las dos salidas medidas. Cambiar el acento
   por --accent-soft arregla una fila y rompe la otra más hondo: 4,60 en la
   barra oscura (pasa) pero 2,52 en la clara, peor que los 4,13 de ahora. Y
   subir el rótulo a 14px/700 para caer en el umbral de texto grande (3,0) es
   rehacer la tipografía de la barra en las 552 páginas. La salida que arregla
   las cuatro casillas de una vez es subir la opacidad del cristal, que es
   `--glass` en tokens.css y no es de esta hoja: al 90 % —el valor que la fila
   sin JavaScript ya usa— la barra oscura da --text-2 7,98 y --accent 6,09, y la
   clara 4,61 y 6,80. Las cuatro pasan. El precio es la translucidez, que
   `base.css` defiende por escrito, así que la decisión es del sistema visual. */
.page .nav .menu a[aria-current="true"]{color:var(--text)}
/* La CTA del menú es .btn-p, pero el bloque de arriba la pisaba: .page .nav
   .menu a (0,3,1) puede más que .btn-p (0,1,0), así que la etiqueta de la
   acción principal salía en --body sobre el degradado naranja —1,00:1 en el
   extremo ámbar, invisible— y en blanco al pasar el cursor. La tinta correcta
   ya existe y es la de .btn-p: --on-brand, el patrón de la casa para texto
   sobre el naranja de marca. Se fija también en hover/focus porque la regla de
   :hover de arriba empata en especificidad con la base y gana por orden. */
.page .nav .menu a.btn-p,
.page .nav .menu a.btn-p:hover,
.page .nav .menu a.btn-p:focus-visible{color:var(--on-brand)}
.nav-toggle{display:none;width:36px;height:36px;position:relative;flex:none;
  border:0;border-radius:var(--r-md);margin-left:var(--s1);
  transition:background var(--t-ui) var(--ease)}
.nav-toggle:hover,.nav-toggle:focus-visible{background:var(--veil)}
.nav-toggle span{display:block;width:18px;height:2px;background:var(--text);margin:var(--s1) auto;
  transition:transform var(--t-ui) var(--ease),opacity var(--t-ui) var(--ease)}
.nav-toggle[aria-expanded="true"] span:nth-child(1){transform:translateY(6px) rotate(45deg)}
.nav-toggle[aria-expanded="true"] span:nth-child(2){opacity:0}
.nav-toggle[aria-expanded="true"] span:nth-child(3){transform:translateY(-6px) rotate(-45deg)}

/* ---------- desplegable (Industrias) ----------
   Único ítem del nav con submenú, así que el marcado y el estilo se resuelven
   para ese caso concreto y no para un mecanismo genérico de N desplegables. */
.nav-item--dropdown{position:relative}
.nav-dropdown-trigger{display:inline-flex;align-items:center;gap:5px}
.nav-dropdown-trigger::after{content:'';width:6px;height:6px;flex:none;
  border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;
  transform:translateY(-2px) rotate(45deg);transition:transform var(--t-ui) var(--ease)}
.nav-dropdown-trigger[aria-expanded="true"]::after{transform:translateY(1px) rotate(225deg)}

/* Ancla a la izquierda del propio trigger, no al centro de la píldora: con
   siete títulos y sin descripción el panel es angosto y no necesita el ancho
   de un mega menú ni el riesgo de desbordar el viewport por el otro lado.
   El panel traía 16px y sus filas 10px: dos radios que no salían de ninguna
   escala y que hacían del desplegable la única superficie del sitio con canto
   propio. Panel es contenedor; fila es control. */
/* El ocultamiento por defecto vive en DOS sitios a propósito, y no es
   duplicación: el atributo `hidden` del marcado lo aplica la hoja del navegador
   antes del primer byte de CSS de autor —es lo que mata el destello— y este
   `display:none` es el que sigue mandando cuando el panel se abre y se cierra
   por clase. Quien los mantiene sincronizados es client/pages.ts. */
.dropdown-panel{display:none;position:absolute;top:calc(100% + var(--s2));left:0;
  min-width:220px;padding:6px;border:1px solid var(--hairline-2);border-radius:var(--r-lg);
  /* El panel cuelga de la barra y hereda su `data-tema`: sobre una sección
     clara sale claro, con su filete azul y sus rótulos en tinta oscura. Antes
     era --ink-900 fijo, o sea un rectángulo casi negro colgando de una barra
     clara. --surface-2 vale --ink-900 en el tema oscuro, así que el estado que
     ya existía no cambia ni un byte. */
  background:var(--surface-2);box-shadow:0 16px 48px var(--ink-a45);z-index:90}
.dropdown-panel.open{display:block}
.dropdown-item{display:block;padding:8px 12px;border-radius:var(--r-md);white-space:nowrap;
  font-family:var(--font-display);font-size:13px;font-weight:600;color:var(--text);
  text-decoration:none;transition:background var(--t-ui) var(--ease)}
.dropdown-item:hover,.dropdown-item:focus-visible{background:var(--veil)}

@media (max-width:940px){
  .nav-toggle{display:block}
  /* La barra se queda como está —marca a la izquierda, hamburguesa a la
     derecha— y el menú deja de vivir dentro: se despliega como panel debajo,
     anclado a la barra. Antes crecía dentro de la barra y la barra se
     estiraba, y el resultado era un bloque de 300px de alto con el logotipo
     colgado arriba a la izquierda. */
  .nav-pill{position:relative;justify-content:space-between;width:100%;
    max-width:min(520px,calc(100vw - var(--gutter) * 2))}
  .page .nav .menu{display:none;position:absolute;top:calc(100% + var(--s2));left:0;right:0;
    flex-direction:column;align-items:stretch;gap:2px;padding:var(--s2);
    border:1px solid var(--hairline-2);border-radius:var(--r-lg);
    /* El panel es opaco, y la barra no. No es incoherencia: la barra tapa
       una franja de 46px y su translucidez es la gracia —se adivina el fotograma
       que pasa por debajo—; el panel tapa media pantalla y encima lleva seis
       rótulos que hay que leer. Al 97% el titular del hero seguía asomando lo
       justo para estorbar. Sin `backdrop-filter`: nada que desenfocar detrás de
       un color sólido, y es una capa compuesta menos en el móvil.
       Opaco sí, pero del tema de la barra: el cajón cuelga de ella y hereda su
       `data-tema`. --surface-2 vale --ink-900 en oscuro, así que el estado que
       ya existía no cambia. */
    background:var(--surface-2);
    /* EL CAJÓN NO PUEDE PASAR DEL BORDE DE LA VENTANA, y hasta hoy podía.
       Es `position:absolute` dentro de `.nav-pill`, que cuelga de
       `.nav{position:fixed}`: lo que cae por debajo del borde NO entra en el
       scroll del documento, así que no se alcanza de ninguna manera. Con dos
       entradas de menú nunca llegó a pasar; con cuatro y dos acordeones sí.
       Medido a 390x568, con fila de 48,3px (15px x 1,62 + 2 x 12px de padding)
       y el cajón empezando a 68px del borde superior:
         ningún acordeón abierto   262,2px -> borde 330,2   sobra +237,8
         sólo Simuladores          457,4px ->       525,4   sobra  +42,6
         sólo Nosotros             409,1px ->       477,1   sobra  +90,9
         LOS DOS ABIERTOS          604,3px ->       672,3   sobra -104,3
       En el último caso se perdían «Certificaciones y convenios» y el
       conmutador de idioma, o sea una de las páginas que este menú venía a
       rescatar.
       El tope se resta de lo mismo que separa la barra del borde: el `max()`
       del recorte superior —no `--nav-top` a secas, que en un teléfono con
       muesca se queda corto—, el alto de la barra y dos veces `--s2`, que son
       el hueco de arriba del cajón y el aire de abajo.
       Van las dos declaraciones y en este orden: quien no entienda `dvh` se
       queda con `vh`, que es la unidad de siempre; quien lo entienda pisa la
       primera y mide la ventana real, con la barra del navegador dentro.
       `overscroll-behavior:contain` es lo que impide que al llegar al final del
       cajón el gesto siga arrastrando la página de debajo.
       Esto es el suelo, no el arreglo: quien evita llegar aquí es
       `client/pages.ts`, que cierra el acordeón hermano al abrir uno. Los dos
       hacen falta —ver el comentario de allí—. */
    max-height:calc(100vh - max(var(--nav-top),env(safe-area-inset-top,0px)) - var(--nav-h) - var(--s2) * 2);
    max-height:calc(100dvh - max(var(--nav-top),env(safe-area-inset-top,0px)) - var(--nav-h) - var(--s2) * 2);
    overflow-y:auto;overscroll-behavior:contain;
    box-shadow:0 16px 48px var(--ink-a45)}
  .page .nav .menu.open{display:flex}
  /* Aquí el enlace es una fila entera y la zona pulsable pasa de 40px de alto,
     así que la holgura sobre WCAG 2.5.8 es aún mayor que en escritorio. */
  .page .nav .menu a{padding:var(--s3);font-size:15px;border-radius:var(--r-md);text-align:left}
  .lang-link{align-self:flex-start;margin-top:var(--s1)}

  /* El desplegable, en móvil, es una fila más del drawer: sin
     fondo ni sombra propios, hereda los de `.page .nav .menu.open`. */
  .dropdown-panel{position:static;display:none;width:100%;margin-top:2px;padding:0;
    border:0;border-radius:0;background:transparent;box-shadow:none}
  .dropdown-panel.open{display:block}
  .dropdown-item{padding:var(--s3);padding-left:calc(var(--s3) * 2);
    border-radius:var(--r-md);font-size:15px;white-space:normal}
}

/* ---------- hero de página ---------- */
/* El padding de arriba deja de ser un número redondo y pasa a derivarse de la
   barra: hasta ahora la nav ocupaba 78px de flujo y el hero empezaba debajo;
   flotando, el hero empieza en y=0 y la copia se metería bajo el cristal. Son
   la píldora, su separación del borde, y --s6 de aire para que el rótulo no la
   roce. La foto sí sube hasta arriba del todo, que es lo que se quiere: la
   imagen pasa por debajo de la píldora. */
.phero{padding:calc(var(--nav-top) + var(--nav-h) + var(--s6)) 0 var(--s9);
  position:relative;width:100%;min-height:100svh;overflow:hidden;border-bottom:1px solid var(--hairline)}
.phero::after{content:"";position:absolute;inset:auto 0 -60% 0;height:100%;
  background:radial-gradient(60% 100% at 50% 0%,var(--org-a10),transparent 70%);
  pointer-events:none}
.phero .wrap{position:relative;z-index:2}
/* LA MEDIDA DEL TITULAR NO PUEDE SER MÁS ESTRECHA QUE EL SALTO QUE TRAE ESCRITO.
   El titular del hero se escribe en dos bloques —el texto suelto y <span
   class="b">—, y ese salto lo decide quien redacta, no la maquetación. La medida
   estaba en 17ch aquí y en 19ch en .phero--media, y los dos números son más
   estrechos que varios de los bloques declarados: el más ancho de las 96
   portadas mide 28,61ch («cobertura, trazabilidad, contratación»,
   /para/entidades-publicas), y le seguían «that manufactures its simulators»
   con 25,71 y «cuando compras un programa» con 23,66. Una medida de 19ch parte
   en dos una línea que ya venía partida, y de ahí salían los tres renglones de
   /industrias, /programas, /nosotros y sus espejos ingleses en 1440 y en 768.
   El defecto no era la longitud de la copia: a 1440 el h1 va a 63px y sobran
   1252px de columna para un bloque que pide 1186. Era la medida, que recortaba
   la columna al 63% de lo disponible y forzaba el tercer renglón dentro de una
   caja que tenía sitio de sobra.
   29ch es el ancho declarado más ancho redondeado hacia arriba. Por encima de
   eso quien parte la línea vuelve a ser la columna, que es lo correcto.
   Dos medidas para un mismo papel eran además la clase de duplicado que este
   sistema retira: .phero--media ya no declara la suya.
   `balance` reparte el sobrante cuando aun así hay dos renglones —los dos
   titulares legales, que son nombres de documento y no caben en una línea a
   ningún tamaño— y evita que el segundo quede en dos palabras. Es el mismo
   recurso que ya usan .sequence-chapter h1 y .editorial-row h3. */
.phero h1{max-width:29ch;text-wrap:balance}
.phero .lead{color:var(--text-2);font-size:clamp(16px,1.6vw,19px);max-width:60ch;margin-top:var(--s5);
  line-height:1.6}
/* ---------- secciones ---------- */
.sect{padding:var(--s10) 0;border-bottom:1px solid var(--hairline)}
.sect:last-of-type{border-bottom:0}
/* Aquí vivía `.sect--deep{background:var(--deep)}`. Ese modificador es el que
   convirtió un token de FONDO en el nombre de un tema, y de ahí salió el
   titular invisible. Ahora la sección declara su tema en el marcado
   —`data-tema`— y el fondo lo pone el rol --surface. */
.sect-head{max-width:62ch;margin-bottom:var(--s8)}
.sect-head p{color:var(--text-2);margin-top:var(--s5);font-size:16.5px}

/* ---------- prosa ---------- */
.prose{max-width:68ch;color:var(--text-2);font-size:16.5px}
.prose > * + *{margin-top:var(--s5)}
.prose h2{margin-top:var(--s8)}
.prose h3{font-family:var(--font-display);font-size:19px;font-weight:800;color:var(--text);
  margin-top:var(--s7);text-transform:none;letter-spacing:0}
.prose strong{color:var(--text);font-weight:600}
.prose a{color:var(--accent);text-decoration:underline;text-underline-offset:3px}
.prose ul,.prose ol{padding-left:1.25em}
.prose li + li{margin-top:var(--s3)}
.prose li::marker{color:var(--accent)}
.prose blockquote{border-left:2px solid var(--accent);padding-left:var(--s5);color:var(--text);
  font-family:var(--font-display);font-size:19px;font-weight:300;line-height:1.45}

/* ---------- rejillas ----------
   Aquí había tres. `.grid--3` y `.grid--4` se van con §6.5, que las sustituye
   por índice de filas o por bento de recuento exacto, y se van del fichero y no
   sólo del marcado: una clase que existe en la hoja vuelve al marcado sola, y
   volvería sin que nada lo cante. `.grid--2` se queda porque §6.5 no la nombra:
   dos pistas son el reparto de una comparación, no una lista repartida entre
   columnas iguales.
   El bento tampoco vive ya en esta hoja: se fue con su componente en la poda de
   septiembre de 2026, y se fue por lo mismo que las otras dos.

   EL `min(…,100%)` DE DENTRO DEL `minmax` NO ES ADORNO: es lo que impide que una
   pista se quede más ancha que su contenedor. `minmax(300px,1fr)` declararía un
   suelo DURO de 300px, así que cuando la columna útil mide menos, la pista no
   encoge: desborda. Y la columna útil baja de ese suelo en los dos anchos de
   teléfono más comunes que existen por debajo del iPhone: 360 —la mitad del
   parque Android— y 320. Medido en su día sobre el bloque partido a 360px: la
   pista salía a 320px dentro de una rejilla de 316 y la fotografía se cortaba
   4px por el canto derecho; a 320px el documento entero ganaba desplazamiento
   horizontal, 349px de ancho para una pantalla de 320. Con `min(…,100%)` el
   suelo se rinde ante el contenedor y la pista pasa a una columna, que es lo que
   la maquetación ya quería hacer. Por encima del punto de ruptura no cambia
   absolutamente nada.
   El razonamiento vivía junto a `.split`, que se fue con su componente en la
   poda de septiembre de 2026. Se queda aquí porque las rejillas con suelo fijo
   que sobreviven —`.grid--2`, que rompía a 344px, y `.logos`, a 192px— llevan la
   misma corrección y no tenían dónde leerla. */
.grid{display:grid;gap:var(--s5)}
.grid--2{grid-template-columns:repeat(auto-fit,minmax(min(300px,100%),1fr))}

/* ---------- tarjeta ---------- */
.card{background:var(--surface-3);border:1px solid var(--hairline);border-radius:var(--r-lg);
  padding:var(--s6);display:flex;flex-direction:column;gap:var(--s4);
  transition:border-color var(--t-ui) var(--ease),transform var(--t-ui) var(--ease)}
a.card:hover,a.card:focus-visible{border-color:var(--hairline-2);transform:translateY(-3px)}
/* El cuerpo sólo estaba definido bajo `.card--media`, así que una tarjeta que
   envolviera su texto sin llevar foto perdía la columna y el aire y se quedaba
   con el h3 pegado al párrafo. Eso obligaba a escribir dos marcados distintos
   para la misma tarjeta según tuviera imagen o no, y en el bento de entonces,
   donde sólo dos de siete celdas llevaban fotografía, eso eran dos maquetaciones
   para una fila.
   Aquí va el cuerpo sin padding —lo pone la tarjeta— y `.card--media .card-body`
   sigue añadiendo el suyo cuando la imagen llega hasta el canto. */
.card-body{display:flex;flex-direction:column;gap:var(--s4);flex:1;min-width:0}
.card h3{font-family:var(--font-display);font-size:18px;font-weight:800;color:var(--text);line-height:1.25}
.card p{color:var(--text-2);font-size:15px;flex:1}
/* `flex:none` porque `.card p` lleva `flex:1` y un rótulo también es un <p>:
   cuando el rótulo va DEBAJO del h3 (que es donde deja de ser antetítulo, §6.1)
   se repartía el alto sobrante con el párrafo y abría un hueco de 40 px entre
   los dos. El rótulo mide lo que mide su línea. */
.card .lbl{color:var(--accent);flex:none}
/* `min-height:24px` no es aire, es el objetivo táctil. El rótulo mide 12px a
   interlínea 1,62, o sea 19,4px de caja: por debajo de los 24x24 de WCAG 2.2 AA
   2.5.8 en las nueve tarjetas de /simuladores, las tres de /hubs y el índice de
   cuerpo. Tampoco lo salva la excepción de «enlace en línea», que ampara al que
   va dentro de una frase: éste es la última fila de una tarjeta, en bloque y con
   su flecha.
   Cuando la tarjeta ENTERA es el enlace (`a.card`) el objetivo real es la
   tarjeta y esto sobra; cuando no lo es, esto es lo único que hay. Se declara
   una vez para los dos casos porque 24px de caja dentro de una tarjeta de 300
   no mueven ni un píxel de la maquetación. La misma solución, con el mismo
   número, que usaba la matriz de /industrias antes de que la ruta se fuera. */
.card-more{font-family:var(--font-display);font-size:12px;font-weight:700;letter-spacing:.1em;
  text-transform:uppercase;color:var(--accent);display:inline-flex;align-items:center;
  min-height:24px;gap:var(--s2)}
.card-more::after{content:"→";transition:transform var(--t-ui) var(--ease)}
a.card:hover .card-more::after{transform:translateX(4px)}
.card img{border-radius:var(--r-sm);aspect-ratio:16/10;object-fit:cover;width:100%}

/* ---------- índice de filas ----------
   §6.5: `.grid--3` y `.grid--4` producen columnas iguales, y el reparto lo hace
   `auto-fit` sobre píxeles, así que el número de columnas lo decide el ancho del
   viewport y nunca el número de elementos. Medido a 1440 en la caja real de cada
   sección: `.grid--3` daba CUATRO pistas de 295px en /industrias/construccion,
   que sirve siete experiencias, y dejaba una celda vacía; y `.grid--4` daba
   CINCO pistas de 231,2px en /educacion-inmersiva, que sirve ocho principios, y
   dejaba dos. Ni el 3 ni el 4 del nombre de la clase eran ciertos en pantalla.

   Índice de filas: una fila por elemento, un filete por fila, pistas
   asimétricas. El nombre ocupa lo que ocupa un nombre y el cuerpo manda en el
   resto, así que ninguna fila afirma que sus dos mitades pesan igual, y el
   recuento de columnas deja de depender del viewport porque no hay columnas que
   contar. Es la primera de las dos salidas que da §6.5.

   Hubo dos formas de fila y una sola familia:
     · `.dindex` a secas — número, nombre, meta y flecha, con miniatura al pasar
       el puntero. Era el índice del home, y se fue en la poda de septiembre de
       2026: sus cuatro piezas —`.dix`, `.dmeta`, `.darr` y `.dthumb`— ya no las
       emitía ningún componente. Lo que queda de esa forma es la envoltura
       (`.dindex`, su filete por fila y su rejilla), que la otra reutiliza.
     · `.dindex--cuerpo` — nombre a la izquierda y su párrafo a la derecha, para
       las listas de tarjetas con texto que sustituyen a las rejillas. Es la
       única que se sirve hoy, en 12 páginas.
   La hoja estaba en home-sequence.css, que sólo carga el home; §6.5 nombra
   `.dindex` como sustituto en todo el sitio, así que el componente vive aquí y
   en home-sequence.css se queda sólo la superficie que lo enmarca. */
.dindex{list-style:none;margin-top:var(--s7)}
.dindex > li{border-top:1px solid var(--hairline)}
.dindex > li:last-child{border-bottom:1px solid var(--hairline)}
.dindex a:where(:not(.card-more)){display:grid;grid-template-columns:64px minmax(0,1fr) auto 34px;align-items:center;
  gap:var(--s5);padding:clamp(18px,3vh,30px) 0;position:relative}
.dname{font-family:var(--font-display);font-weight:300;font-size:clamp(24px,3.2vw,48px);
  line-height:1.06;letter-spacing:-.015em;transition:color var(--t-ui) var(--ease),
  transform var(--t-ui) var(--ease)}
.dindex a:hover .dname,.dindex a:focus-visible .dname{color:var(--accent-soft);transform:translateX(6px)}
/* La fila con cuerpo. La pista del nombre es del 34% y no de la mitad a
   propósito: un nombre de dos palabras y un párrafo de tres líneas no pesan
   igual, y dos pistas iguales volverían a decir que sí. El nombre baja de los
   48px del índice del home —que aquí, con texto al lado, lo aplastarían— a la
   escala que usaba `.figname`, el índice de cifras que se fue en la poda de
   septiembre de 2026. */
.dindex--cuerpo .drow{display:grid;grid-template-columns:minmax(0,34%) minmax(0,1fr);
  align-items:start;gap:var(--s3) var(--s7);padding:clamp(20px,3vh,32px) 0;position:relative}
.dindex--cuerpo .dname{font-size:clamp(19px,2vw,27px);line-height:1.12;color:var(--text)}
.dindex--cuerpo .dbody{color:var(--text-2);font-size:15px;line-height:1.6;min-width:0}
.dindex--cuerpo .dbody > * + *{margin-top:var(--s4)}
.dindex--cuerpo .dbody .lbl{color:var(--accent);display:block}
.dindex--cuerpo .dbody .lbl + p{margin-top:var(--s3)}
/* La fila que trae fotografía abre una tercera pista para ella. El plano va en
   16/9 y lee `--media-focus`, y los dos números son el mismo dato: 16/9 es uno
   de los dos aspectos en los que `site/data/fotos.json` tiene auditado el
   encuadre (§7), así que recortar en ese aspecto es recortar por un punto que
   alguien ha mirado. La pista mide el 22% de la fila —275px a 1440—, de modo
   que el recorte es siempre apaisado. Sin rótulo encima, que es lo que prohíbe
   §6.4: el nombre de la fila ya está a la izquierda. */
.dindex--cuerpo .drow--media{grid-template-columns:minmax(0,34%) minmax(0,1fr) minmax(0,22%)}
.dmedia{display:block;border-radius:var(--r-sm);overflow:hidden;border:1px solid var(--hairline)}
.dmedia img{width:100%;aspect-ratio:16/9;object-fit:cover;display:block;
  object-position:var(--media-focus,50% 50%)}
/* El nombre no se desplaza al pasar por encima: en el índice del home la fila
   entera es el enlace y el nombre es lo único que hay, aquí al lado hay un
   párrafo que se quedaría quieto y el desplazamiento se leería como un salto. */
.dindex--cuerpo a:hover .dname,.dindex--cuerpo a:focus-visible .dname{color:var(--accent);transform:none}
.dindex--cuerpo a:hover .card-more::after{transform:translateX(4px)}
@media (max-width:820px){
  /* De canto la fila se apila, que es lo que hace un índice de filas cuando no
     hay ancho: sigue habiendo un filete por elemento y sigue sin haber columnas
     iguales, porque no hay columnas. */
  .dindex--cuerpo .drow,.dindex--cuerpo .drow--media{grid-template-columns:minmax(0,1fr);gap:var(--s4)}
  .dindex--cuerpo .dmedia{max-width:min(100%,420px)}
}
@media (max-width:760px){
  .dindex a:where(:not(.card-more)){grid-template-columns:44px minmax(0,1fr) 24px;gap:var(--s4)}
}

/* ---------- tabla ----------
   LA SOMBRA QUE DICE QUE HAY MÁS TABLA, Y NO CUESTA UNA LÍNEA DE JAVASCRIPT.
   Cuatro capas de fondo en dos parejas. Las dos primeras son TAPAS del color de
   la superficie y van `local`, o sea que se desplazan CON el contenido; las dos
   últimas son las sombras y van `scroll`, o sea clavadas a la caja. En el
   extremo izquierdo la tapa está encima de su sombra y la borra; en cuanto la
   tabla se desplaza, la tapa se va con ella y la sombra queda a la vista. El
   mecanismo es el estado de scroll, sin escucharlo.
   Las medidas salen del relleno de la celda: la sombra ocupa 16px, que es
   exactamente --s4, el padding lateral de `th` y `td`, así que la degradación
   cae sobre el aire de la celda y nunca por debajo de una palabra. La tapa mide
   28px para que su propio degradado termine de apagarse antes.
   El color no es un literal: --surface es el rol de lienzo, así que la tapa
   funciona igual en el acto oscuro y en el claro sin una regla por tema. */
.tbl-scroll{overflow-x:auto;
  background:
    linear-gradient(to right,var(--surface),transparent) 0 0/28px 100% no-repeat local,
    linear-gradient(to left,var(--surface),transparent) 100% 0/28px 100% no-repeat local,
    linear-gradient(to right,var(--ink-a45),transparent) 0 0/16px 100% no-repeat scroll,
    linear-gradient(to left,var(--ink-a45),transparent) 100% 0/16px 100% no-repeat scroll}
.tbl-scroll:focus-visible{outline:2px solid var(--accent);outline-offset:4px}
/* La línea de instrucción. Nace escondida y sólo la enseña el atributo que
   escribe client/pages.ts cuando la tabla desborda DE VERDAD en ese ancho: el
   dato es el del elemento, no el de una consulta de medios, así que la misma
   tabla la dice a 390px y se calla a 1440 sin que la hoja tenga que adivinar
   cuál de las cinco tablas del sitio es la ancha.
   No es `.lbl`: no es un antetítulo, no orienta ni encabeza nada, y colgarle esa
   clase le cargaría el presupuesto de §6.1 a cinco páginas por una nota de
   manejo. La voz es la de `.equipo3d__pista`, que es la otra nota de manejo del
   sitio. */
.tbl-hint{display:none;margin-top:var(--s3);color:var(--text-3);font-size:13px;line-height:1.4}
.tbl-scroll[data-desplaza] + .tbl-hint{display:block}
.sr-only{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;
  overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}
.tbl{width:100%;border-collapse:collapse;font-size:15px;min-width:520px}
.tbl th,.tbl td{text-align:left;padding:var(--s4);border-bottom:1px solid var(--hairline);vertical-align:top}
.tbl th{font-family:var(--font-display);font-size:11px;font-weight:700;letter-spacing:.16em;
  text-transform:uppercase;color:var(--text-3);white-space:nowrap}
.tbl td{color:var(--text-2)}
.tbl td:first-child{color:var(--text);font-weight:600}
.tbl .num{font-variant-numeric:tabular-nums;white-space:nowrap}

/* ---------- muro de logos ---------- */
.logos{display:grid;gap:var(--s4);grid-template-columns:repeat(auto-fill,minmax(min(148px,100%),1fr));
  align-items:center}
.logos li{list-style:none;background:var(--surface-3);border:1px solid var(--hairline);border-radius:var(--r-sm);
  padding:var(--s5) var(--s4);display:grid;place-items:center;min-height:92px}
.logos img{max-height:38px;width:auto;object-fit:contain;
  filter:grayscale(1) brightness(1.7) contrast(.85);opacity:.78;
  transition:filter var(--t-ui) var(--ease),opacity var(--t-ui) var(--ease)}
.logos li:hover img{filter:none;opacity:1}

/* ---------- certificaciones-latam ----------
   El único consumidor de `.logos` es `CertificacionesLatam.astro`, que compone
   ese muro, `.grid--2` (vía `Rejilla2`) y tres párrafos `.prose` sueltos sin
   envoltorio propio. Ninguna de las tres clases trae margen hacia su hermano
   anterior, así que quedaban pegadas (`base.css:3` resetea a 0). `--s7` es el
   mismo escalón que `separacion.ts` documenta para «la separación entre
   bloques de una misma sección»; el selector es tan acotado como una clase
   propia porque `p.prose` no existe en ningún otro sitio del árbol. */
.logos + p.prose,.grid--2 + p.prose,p.prose + p.prose{margin-top:var(--s7)}

/* ---------- cinta de logos (TrustMarquee) ----------
   La cinta infinita de logos de cliente, dos instancias: el pliegue del home
   (.fold-trust, sobre el oscuro) y la cabecera de /clientes
   (.video-harvey-signal, sobre el claro). El tratamiento de la tinta lo decide
   el tema del anfitrión, no el bloque. La pista son dos listas idénticas, así
   que la mitad de su ancho es exactamente una vuelta: añadir un cliente no
   obliga a recalcular nada. El degradado de máscara va en la ventana y no en
   la pista, porque la pista se mueve y la máscara tiene que quedarse quieta. */
.trust-marquee{flex:1;min-width:0;overflow:hidden;
  /* verify: color literal — una máscara lee alfa, no color: aquí #000 significa «opaco». */
  --mascara-cinta:linear-gradient(90deg,transparent,#000 12%,#000 88%,transparent);
  -webkit-mask-image:var(--mascara-cinta);
  mask-image:var(--mascara-cinta)}
.trust-track{display:flex;width:max-content;animation:trust-scroll 60s linear infinite}
@keyframes trust-scroll{to{transform:translate3d(-50%,0,0)}}
.trust-set{display:flex;align-items:center;margin:0;padding:0}
.trust-set li{list-style:none;flex:0 0 auto;padding:0 clamp(20px,2.4vw,34px)}
.trust-set img{display:block;height:30px;width:auto;object-fit:contain;
  filter:grayscale(1) brightness(1.7) contrast(.85);opacity:.6;
  transition:opacity var(--t-ui) var(--ease)}
.trust-marquee:hover .trust-set img{opacity:.85}
[data-tema="claro"] .trust-set img{filter:grayscale(1) contrast(1.1);opacity:.72}
[data-tema="claro"] .trust-marquee:hover .trust-set img{opacity:1}
@media (max-width:760px){
  .trust-set img{height:24px}
}
/* SIN MOVIMIENTO LA CINTA NO SE CONVIERTE EN UN WIDGET DE SCROLL, SE DESPLIEGA.
   Aquí ponía `overflow-x:auto`, que era un arreglo bienintencionado —parada la
   animación, deja al menos alcanzar los 35 logotipos— y que creaba un fallo de
   WCAG 2.1.1 justo sobre la población para la que se escribió: el subárbol es
   `<ul><li><img>`, cero elementos enfocables, así que una región desplazable sin
   forma de desplazarla con el teclado. Y el scroll recorría 70 logotipos, porque
   la pista sirve la lista dos veces y la segunda es el clon `aria-hidden`.

   La cura no es hacer enfocable el contenedor: `tabindex` no se puede poner tras
   una consulta de medios, así que sería una parada de tabulación en las 552
   páginas para todo el que no pide movimiento reducido, y en esas páginas la
   ventana ni siquiera desplaza (`overflow:hidden`). La cura es que no haya nada
   que desplazar: la lista se envuelve y se ve entera, que es lo que el lector
   quería del scroll.

   Medido sobre `clientes.json`, 35 logotipos: una vuelta de pista mide 5.256 px
   a 1440 y 3.701 px a 390. Envuelta son 5 filas (~230 px) a 1440. En una sección
   propia eso cabe de sobra, y es el caso de /casos-de-exito, donde esta cinta ES
   el muro de clientes y no hay otra lista en la página.
   El pliegue del inicio es el caso contrario —una banda de 88 px, 72 en móvil— y
   su excepción vive en `home-sequence.css`, junto a la banda que la impone.

   El clon decorativo se va: envuelto sería la lista repetida a la vista, y su
   único trabajo era que el bucle no tuviera costura. Sin bucle no hay costura.
   La máscara también, porque desvanecía los bordes de una pista que se movía;
   sobre un bloque envuelto sólo apagaría el primer y el último logotipo. */
@media (prefers-reduced-motion:reduce){
  .trust-marquee{overflow:hidden;-webkit-mask-image:none;mask-image:none}
  /* `display:block` y no sólo `width:auto`: la pista es flex, y ahí el `<ul>` es
     un ítem de eje principal, o sea que se mide por su contenido y seguiría
     saliéndose por mucho que la pista se estreche. Como bloque, el `<ul>` pasa a
     ocupar el ancho y su `flex-wrap` tiene contra qué envolver.
     `animation:none` está escrito aunque el bloque de `prefers-reduced-motion`
     de `base.css` ya la neutraliza en esta misma consulta, con su
     `animation-duration:.01ms!important` sobre todo el árbol: quien lea este
     bloque tiene que ver que la cinta se para, no deducirlo de otra hoja. */
  .trust-track{display:block;width:auto;animation:none}
  .trust-set{flex-wrap:wrap;justify-content:center;row-gap:var(--s4)}
  .trust-set[aria-hidden="true"]{display:none}
}

/* ---------- sellos ----------
   Aquí, y sólo aquí, el óvalo es la forma correcta: un sello. Es el único
   consumidor de --r-seal junto con .cert y los chips de estado. */
.pills{display:flex;flex-wrap:wrap;gap:var(--s3)}
.pill{display:inline-block;font-family:var(--font-display);font-size:11.5px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase;padding:var(--s2) var(--s4);border-radius:var(--r-seal);
  border:1px solid var(--hairline-2);color:var(--text-2)}
a.pill:hover{border-color:var(--accent);color:var(--text)}
/* El nombre de la clase es marcado y no se toca en esta fase; lo que era falso
   es su color. `--org-a45` es paleta, no rol: pintaba de naranja el canto de 20
   píldoras repartidas por 8 rutas cuya sección es `data-tema="claro"`, justo al
   lado de píldoras azules con el mismo papel. --accent-line es el mismo 45 %
   pero del acento del tema. */
.pill--org{border-color:var(--accent-line);color:var(--accent-soft)}

/* ---------- descargas ---------- */
.downloads{display:flex;flex-wrap:wrap;gap:var(--s4)}
.download{display:flex;align-items:center;gap:var(--s4);background:var(--surface-3);
  border:1px solid var(--hairline);border-radius:var(--r-md);padding:var(--s5) var(--s6);
  transition:border-color var(--t-ui) var(--ease)}
.download:hover{border-color:var(--accent)}
.download b{display:block;font-family:var(--font-display);font-size:14.5px;font-weight:700;color:var(--text)}
.download span{display:block;font-size:12.5px;color:var(--text-3);margin-top:var(--s1)}
.download::before{content:"↓";font-family:var(--font-display);font-weight:900;font-size:19px;color:var(--accent)}

/* ---------- aviso ---------- */
.note{border:1px solid var(--hairline-2);border-left:3px solid var(--accent);border-radius:var(--r-sm);
  background:var(--surface-3);padding:var(--s5) var(--s6);color:var(--text-2);font-size:15px}
.note b{color:var(--text)}

/* ---------- banda de cierre ---------- */
.cta-band{padding:var(--s10) 0;background:var(--surface-2);border-top:1px solid var(--hairline);text-align:center}
.cta-band h2{margin:0 auto;max-width:22ch}
.cta-band p{color:var(--text-2);max-width:52ch;margin:var(--s5) auto 0}
.cta-band .actions{display:flex;flex-wrap:wrap;gap:var(--s4);justify-content:center;margin-top:var(--s7)}

.page main{background:linear-gradient(180deg,var(--surface),var(--ink-900) 48%,var(--surface))}

/* ---------- superficies editoriales ----------
   Aquí vivían SEIS bloques que construían un tema reasignando variables una a
   una: `.page .sect`, `.page .sect--deep`, `.page .qualifier-section` y los
   tres de `industries-*`. Entre los seis declaraban 48 literales de color y
   redefinían --void, --wht, --body, --mut, --dim, --line y --line2 trece veces
   cada uno. De ahí salió el titular invisible: `.page .sect` reasignó --deep,
   que era un fondo, y una regla de industrias lo usaba como tinta.
   Los seis se han ido enteros. Lo que queda es marcado —`data-tema` en la
   sección— más los roles de tokens.css, y por eso todo este bloque de reglas
   redundantes desaparece con ellos:
     · `.industries-*` reimplementaba a mano el mismo tema claro y el mismo azul
       que `.page .sect` ya daba. Cada uno de sus colores coincide token a token
       con el rol que ahora los sirve, así que borrarlo no cambia un píxel.
     · `--section-accent`, `--section-link` y `--section-focus` eran un segundo
       sistema de acentos por sección. Ahora son un solo rol, `--accent`, que ya
       cambia con el tema.
   Héroes, bandas fotográficas, banda de cierre y pie no llevan tema: se quedan
   en el oscuro del documento, que es lo que hacían antes. */

/* La sección claro y la sección de marca comparten estos ajustes, que no son
   color sino cómo se comporta un componente cuando la superficie cambia. */
.sect h2 b{color:var(--accent-soft)}
.tbl td:first-child a{color:var(--accent)}
.sect .card:hover,.sect .card:focus-within{
  background:var(--surface-4);border-color:var(--accent);transform:translateY(-3px)
}
/* Los logotipos se sirven en un solo fichero para las dos superficies: sobre
   oscuro hay que subirles el brillo y sobre claro no. Es un filtro, no un
   color. */
[data-tema="claro"] .logos img{filter:grayscale(1) contrast(1.1);opacity:.72}
[data-tema="claro"] .logos li:hover img{filter:none;opacity:1}

.foot-globe-stage{position:relative;width:100%;min-height:clamp(320px,42vw,520px);margin:var(--s7) 0}
/* EL GLOBO NO PUEDE COMERSE EL DESPLAZAMIENTO DE LA PÁGINA, Y ANTES SE LO COMÍA.
   `touch-action:none` le entrega al lienzo TODOS los gestos, incluido el de
   subir y bajar. En un escritorio no se nota porque la rueda del ratón no pasa
   por ahí; en un teléfono, el globo mide 380px de alto y ocupa el ancho entero
   del pie de las 493 páginas, así que quien arrastra el dedo sobre él para
   seguir bajando no baja: gira el planeta. Es una trampa de scroll en el camino
   de salida de cada página.
   `pan-y` reparte: el eje vertical es del documento, el resto sigue siendo del
   globo. Se pierde la inclinación con el dedo, que era un extra —la órbita
   horizontal, que es la que cuenta algo, se conserva— y el pie vuelve a
   atravesarse.
   Esto es la mitad del arreglo. La otra mitad está en `tresd/globo/escena.ts`:
   three pone su propio `touch-action` en línea al montar los controles, y un
   estilo en línea gana a esta hoja. */
.foot-globe{position:absolute;inset:0;cursor:grab;touch-action:pan-y}
/* EL PÓSTER ABRE LA ETAPA EN TODOS LOS ANCHOS. Va servido en el HTML, pesa
   ~40 KB y no lleva JavaScript: es lo que se ve mientras llega el chunk de
   1.245 KB, y lo único que se ve con ahorro de datos o sin WebGL. */
/* EL DESPLIEGUE DEL PÓSTER. Base visible para no depender de JavaScript; con
   .js arranca escalado y apagado y asienta cuando el observador de .reveal le
   pone .in al entrar en viewport —el mismo disparador de las cifras—. Cuando
   el lienzo vivo monta, `tiene-globo` desvanece el póster debajo del canvas,
   cuyo fondo es transparente: el tránsito no se ve. */
.foot-globe-poster{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  object-position:center;transition:opacity 620ms var(--ease),transform 1100ms var(--ease)}
.js .foot-globe-stage.reveal:not(.in) .foot-globe-poster{opacity:0;transform:scale(.93)}
.foot-globe-stage.tiene-globo .foot-globe-poster{opacity:0}
/* En teléfono el fondo del póster, un punto más claro que el pie, dibujaba un
   rectángulo mientras no hay lienzo encima: va a sangre y se funde arriba y abajo. */
@media not all and (min-width:820px){
  /* A sangre: el globo ocupa el ancho del teléfono, sin el margen del .wrap. */
  .foot-globe-stage{width:100vw;margin-inline:calc(50% - 50vw);min-height:min(112vw,520px)}
  .foot-globe-poster{mask-image:linear-gradient(transparent,black 8%,black 92%,transparent)}
}
.foot-globe.is-hovering{cursor:pointer}
.foot-globe:active{cursor:grabbing}
.foot-globe canvas{display:block}
.globe-marker-label{width:clamp(104px,14vw,164px);background:transparent;border:0;pointer-events:none;text-align:center;user-select:none}
/* EL CENTRADO HORIZONTAL YA ESTÁ HECHO Y NO HAY QUE REPETIRLO. three-globe
   escribe el `transform` del contenedor y ahí lleva su propio `translate(-50%)`,
   así que la caja llega centrada sobre el punto; añadir aquí otro `translateX`
   la corría 82px —media caja— a la izquierda, medido. En este hijo va sólo el
   eje vertical, en píxeles: el país por encima de su punto, la ciudad por debajo
   del suyo, que es lo que los despega cuando caen a un cuarto de grado. */
/* EL RÓTULO ES EL BLANCO DEL DEDO. La capa de rótulos de globe.gl va con
   `pointer-events:none` y el punto mide dos píxeles en un teléfono; el nombre
   recoge el toque. El relleno vertical lo lleva a 44px sin mover el texto: el
   -50% del transform se mide sobre la caja ya rellena y la recentra. */
.globe-marker-label__content{transform:translateY(calc(-50% - 12px));border:0;background:transparent;pointer-events:auto;cursor:pointer;padding:12px 0;text-shadow:0 1px 12px var(--ink-a90)}
.globe-marker-label__country,.globe-marker-label__city{display:block}
.globe-marker-label__country{font-family:var(--font-display);font-size:clamp(16.8px,1.624vw,23.52px);font-weight:900;line-height:1;letter-spacing:-.035em;color:var(--text)}
/* LA CIUDAD CUELGA POR DEBAJO DE SU PUNTO Y EL PAÍS POR ENCIMA DEL SUYO, Y ES
   una regla de colocación y no de gusto: el ancla de Colombia (4.5709,-74.2973)
   está a un cuarto de grado de la de Bogotá (4.7110,-74.0721), así que a la
   altura de cámara con la que se abre el país los dos rótulos caen sobre el
   mismo pixel. Empujar uno arriba y otro abajo los separa unos treinta píxeles
   sea cual sea el acercamiento, que es lo que no consigue subir la altitud del
   rótulo: sobre el centro del encuadre, «más alto» es hacia la cámara y no
   hacia arriba, y no mueve nada en pantalla. */
.globe-marker-label--ciudad{width:clamp(72px,8vw,104px)}
.globe-marker-label--ciudad .globe-marker-label__content,.globe-marker-label--abajo .globe-marker-label__content{transform:translateY(calc(-50% + 26px))}
.globe-marker-label__city{font-family:var(--font-display);font-size:clamp(12.8px,1.05vw,15.2px);font-weight:700;line-height:1.1;letter-spacing:.02em;color:var(--steel-200)}
.globe-marker-label.is-elegida .globe-marker-label__city{font-weight:900;color:var(--text)}
@media (max-width:760px){
  .globe-marker-label{width:104px}
  .globe-marker-label__country{font-size:16.8px}
  .globe-marker-label--ciudad{width:72px}
  .globe-marker-label__city{font-size:12.8px}
}

.foot-contacto{display:flex;flex-wrap:wrap;justify-content:center;gap:var(--s3) var(--s6);
  padding:var(--s5) 0;border-top:1px solid var(--hairline)}
.foot-contacto a{display:inline-flex;align-items:center;min-height:44px;
  font-family:var(--font-display);font-size:13px;font-weight:600;color:var(--text-2);
  transition:color var(--t-ui) var(--ease)}
.foot-contacto a:hover,.foot-contacto a:focus-visible{color:var(--accent)}
/* La dirección de la sede, que desde los ajustes de agosto de 2026 reemplaza
   al teléfono y al WhatsApp en esta fila. No es un enlace —no hay a dónde
   llevarla—, así que tampoco toma la caja de 44px de los pulsables: es dato,
   y se sienta un escalón de tinta por debajo del correo. */
.foot-contacto .foot-dir{display:inline-flex;align-items:center;max-width:68ch;
  font-size:12.5px;line-height:1.5;color:var(--text-3)}

/* ---------- movimiento ----------
   .reveal solo se oculta cuando hay JavaScript para volver a mostrarlo. Sin JS
   la clase .js nunca se pone y el contenido se ve siempre. Una animación no
   puede ser la razón de que una cifra no exista. */
.js .reveal{opacity:0;transform:translateY(14px)}
.js .reveal.in{opacity:1;transform:none;transition:opacity 520ms var(--ease),transform 520ms var(--ease)}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  .js .reveal,.js .reveal.in{opacity:1;transform:none;transition:none}
  *,*::before,*::after{animation-duration:.001ms!important;transition-duration:.001ms!important}
}

@media (max-width:640px){
  .sect{padding:var(--s9) 0}
  .phero{padding:var(--s7) 0 var(--s8)}
  .card{padding:var(--s5)}
}

/* Enlaces dentro de un aviso: el .note es texto corrido y un enlace sin
   subrayado ahí dentro no se distingue del resto. */
.note a{color:var(--accent);text-decoration:underline;text-underline-offset:3px}

/* ═══════════════════════════════════════════════════════════════════════
   IMAGEN, COLOR Y MOVIMIENTO
   Las páginas internas eran texto sobre fondo oscuro. El sitio vende una
   experiencia física y tenemos 224 fotografías propias de ese hardware: la
   imagen no es adorno aquí, es el argumento. Todo lo de abajo existe para
   ponerla en pantalla sin romper el rendimiento móvil.
   ═══════════════════════════════════════════════════════════════════════ */

/* El acento por dominio vive en tokens.css con los demás nombres de color. Los
   cuatro que estaban sueltos en hexadecimal aquí —#ff4d14, #4aa3e0, #12a594 y
   #6fdccb— entraron allí como --dom-*, que es lo que pide §2 del sistema
   visual: «o entran a tokens.css como --dom-* o se retiran». */

/* ---------- hero con imagen ----------
   La imagen va en un <img> real, no en background-image: así entra en el
   preload, sirve srcset y el LCP la ve. El velo es un pseudo-elemento. */
.phero--media{padding:0;border-bottom:0;min-height:100svh;width:100%;
  display:grid;grid-template-columns:minmax(0,1fr)}
.phero--media > *{grid-area:1/1}
.phero-bg{position:relative;overflow:hidden}
.phero-bg img,.phero-bg video{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;object-position:var(--media-focus,50% 50%);display:block;z-index:1}
/* El segundo encuadre, y por qué hacen falta dos.
   El hero mide `min-height:clamp(380px,52vw,600px)` con el ancho del viewport:
   en escritorio es una caja apaisada que recorta poco, y en un teléfono es más
   alta que ancha y sólo enseña el 45% del ancho de la fotografía. Con un solo
   punto focal —y hasta hoy con tres genéricos para 29 fotografías— el sujeto
   sobrevivía al recorte apaisado y desaparecía o quedaba partido en el
   vertical: medido foto a foto en 4/5, 20 de las 29 fallaban.
   `--media-focus-tall` lo escribe el build desde `site/data/fotos.json`, que
   declara el encuadre POR FOTOGRAFÍA y en los dos aspectos. El umbral es el
   mismo que usa el lienzo del home en sequence.ts: la caja más alta que ancha. */
@media (max-aspect-ratio:1/1){
  .phero-bg img,.phero-bg video{object-position:var(--media-focus-tall,var(--media-focus,50% 50%))}
}
.phero-bg video{z-index:2}
/* El único literal de color que queda fuera de tokens.css en todo el repo, y
   por qué no puede ser un token: la opacidad del primer tramo no la decide esta
   hoja. La escribe el build en el marcado, ruta a ruta, desde el campo `scrim`
   de media.json, porque una foto de mina a mediodía y una
   de taller cerrado no necesitan el mismo velo para que el titular siga pasando
   AA. Un token no puede sustituirlo: la alfa llega como número en
   --route-scrim, y una variable personalizada resuelve sus var() en el elemento
   donde se DECLARA, no donde se usa; un `--ink-a-route` definido en :root leería
   un --route-scrim que allí no existe y se quedaría siempre en el valor de
   respaldo. Los otros dos tramos sí son fijos y sí son tokens. */
.phero-bg::after{content:"";position:absolute;inset:0;
  /* verify: color literal — alfa por ruta desde media.json, ver arriba */
  background:linear-gradient(180deg,rgba(3,8,13,var(--route-scrim,.55)) 0%,var(--ink-a70) 45%,var(--surface) 100%)}
.phero-bg::after{z-index:3}
.phero--media .wrap{align-self:end;width:100%;padding-top:var(--s9);padding-bottom:var(--s8);z-index:3}
.phero--media .wrap{z-index:4}
/* Sin max-width: la medida del titular del hero se declara una sola vez, arriba
   en `.phero h1`. Aquí quedaba una segunda medida, más estrecha que varios de
   los bloques que el marcado declara, y era la que servía a las 80 portadas con
   foto de las 96: las quince que llegaban a tres renglones son .phero--media. */
.phero--media h1{text-shadow:0 2px 30px var(--ink-a55)}
.phero--media .lead{color:var(--steel-200);max-width:56ch}
.phero--media::after{content:"";grid-area:1/1;align-self:end;height:2px;width:100%;
  background:linear-gradient(90deg,var(--acc,var(--accent)),transparent 62%);z-index:4}

/* El vídeo del hero arranca mudo para poder reproducirse. Este control ofrece
   la pista original sólo después del gesto y desaparece con el póster estático. */
.phero-sound{position:absolute;z-index:5;
  top:max(92px,calc(env(safe-area-inset-top,0px) + 72px));left:var(--gutter);
  min-height:44px;padding:0 var(--s4);display:inline-flex;align-items:center;gap:var(--s3);
  border:1px solid var(--hairline-2);border-radius:var(--r-md);background:var(--ink-a70);
  -webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);color:var(--text);
  font:600 12px/1 var(--font-display);letter-spacing:.06em;text-transform:uppercase;cursor:pointer}
.phero-sound[hidden]{display:none}
.phero-sound:hover{border-color:var(--accent)}
.phero-sound svg{flex:none}
.phero-sound path{fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.phero-sound path:first-child{fill:currentColor;stroke-width:1}
.phero-sound[aria-pressed="false"] .wave{display:none}
.phero-sound[aria-pressed="true"] .cross{display:none}

/* ---------- aquí estuvo la cinta de nombres de /simuladores ----------
   Diecisiete reglas —`.sim-name-slider*`, `main:has(> .sim-name-slider)`, las
   tres `.phero--media:has(+ .sim-name-slider)` y su bloque de movimiento
   reducido entero— y se van con su marcado: la cinta la retiró
   `domains/catalogo/pages/simuladores.astro`, que explica por qué, y ninguna
   otra página la servía. El grep es la prueba: la clase ya no sale en un solo
   `.astro` del árbol.

   POR QUÉ LA HISTORIA NO LA ENCUENTRA, y no es que aquí se inventara nada. La
   cinta existió sólo en el ÁRBOL DE TRABAJO de este checkout compartido, escrita
   por otra sesión, y nunca llegó a un commit. Por eso `git log -S
   'sim-name-slider'` sale vacío en toda la historia del repositorio y por eso su
   retirada no aparece en ningún diff: no falta un borrado, es que no había nada
   confirmado que borrar. La auditoría sí pudo medir sus 104 px porque el `dist`
   se construyó desde ese mismo árbol. Un revisor ya hizo ese grep, no encontró
   nada y dio esta lápida por falsa; queda escrito para que el siguiente no
   repita el razonamiento.

   EL RECUENTO DE DIECISIETE ESTÁ CONTRASTADO: se contaron una a una sobre la
   copia que se conservó antes de retirarlas, y coinciden con las que se fueron
   de aquí. Esa copia —marcado y rótulos verbatim, con las líneas de continuación
   de cada regla marcadas como no capturadas y SIN reconstruir— quedó fuera del
   repositorio, en el scratchpad de la sesión, como `cinta-de-nombres-retirada.md`.
   Es lo único que queda de la cinta, porque git no puede devolverla.

   LO QUE SE VA CON ELLAS, para que nadie lo eche de menos y lo reponga. La cinta
   le recortaba el hero a su página —`min-height:calc(100svh - …)`— y le centraba
   el `wrap`, el `h1` y el `lead`. Sin esas tres reglas, `/simuladores` vuelve a
   `100svh` y a `wrap` alineado a la izquierda, que es como abren las otras
   quince páginas con hero de medios. Eso es lo correcto y no se compensa aquí.

   `@keyframes trust-scroll` SE QUEDA donde está (más arriba, con la cinta de
   logotipos): la pista lo reutilizaba, pero su dueño es `.trust-track`, que
   sigue sirviendo `TrustMarquee`. */

@media (max-width:760px){
  .phero-sound{top:max(82px,calc(env(safe-area-inset-top,0px) + 64px));right:var(--gutter);left:auto}
  /* Deja la última línea por encima de la placa ISO y el lanzador de Edu. */
  .phero--media .wrap{padding-bottom:calc(24px + 56px + var(--s4) + env(safe-area-inset-bottom,0px))}
}

/* ---------- la indicación de scroll del hero con film ----------
   §6.4 del sistema visual prohíbe las indicaciones de scroll por su nombre, y
   §5.5 registra que `.sequence-rail` —un aro de progreso con su contador
   «01 / 06»— se retiró por esa misma regla. Esto es una EXCEPCIÓN DECLARADA, no
   un descuido, y está registrada en el spec al lado de la prohibición.

   La razón, medida, y el límite. En las cinco páginas que abren con film
   —/simuladores-educativos y las cuatro familias de /simuladores que declaran
   `film`, hoy todas— el hero mide 100svh, no enseña filete de
   sección debajo, y lo que viene después es EL MISMO
   FOTOGRAMA que ya se está viendo: el hero pinta el póster del film y el film
   arranca sobre él. Sin esta indicación no queda ni una señal de que la página
   continúe. Es el argumento de §5.5 aplicado del revés: allí sobraba porque
   adornaba un avance que ya se veía; aquí hace falta porque no hay avance
   visible que adornar. Sólo `.phero-cue`, y sólo en heros seguidos de
   `[data-story]`.

   VA CENTRADA y debajo del titular, que está alineado a la izquierda. No es un
   descuido de composición: la indicación no pertenece a la columna de texto —no
   se lee, se obedece— y centrada al pie deja de competir con el titular por el
   mismo eje y cae donde el pulgar y la vista ya están cuando toca bajar.

   LA FLECHA ES UN SOLO ELEMENTO. El astil y la punta salen del mismo `::after`
   con un `clip-path` de polígono, y no de dos pseudoelementos ni de un SVG:
   §6.4 prohíbe el SVG decorativo dibujado a mano, y dos cajas con bordes
   girados 45° son la misma figura con el doble de sitios donde desalinearse.
   El polígono va en porcentajes para que la figura siga a `--s6` si la escala
   de espacio cambia; a 32px de alto, el astil llega al 69% y la punta ocupa el
   tercio de abajo.

   La animación dice la DIRECCIÓN y no el estado: la flecha entra desde arriba,
   se asienta y sale por abajo. Sólo `transform` y `opacity`, las dos en la
   lista de §5.4. Un parpadeo en el sitio sería el punto de estado decorativo
   que §6.4 prohíbe en la misma frase; esto se desplaza, que es lo que se le
   pide al lector. */
/* EL COLOR ES EL DE MARCA Y NO EL DEL DOMINIO, que es la única regla de esta
   pieza que no se deduce mirando el resto de la hoja. `--acc` cambia con
   `data-acento` —naranja en vial, ROJO en alto riesgo, AZUL en cargas—, así que
   colgada de él la misma indicación salía de tres colores distintos en cuatro
   páginas y en dos de ellas fuera de la paleta cálida del sitio. El acento de
   dominio pinta lo que ES de ese dominio: su filete de sección, sus sellos. La
   indicación de scroll no es del dominio, es del sitio, y va en los dos roles de
   marca —`--accent` naranja para la flecha, `--accent-soft` ámbar para la
   palabra—, que es lo mismo que hace la barra de navegación. */
.phero-cue{display:flex;flex-direction:column;align-items:center;gap:var(--s3);
  width:100%;margin-top:var(--s6);
  font-family:var(--font-mono);font-size:10.5px;letter-spacing:.12em;
  text-transform:uppercase;font-weight:600;color:var(--accent-soft)}
.phero-cue::after{content:"";flex:none;width:9px;height:var(--s6);
  background:var(--accent);
  clip-path:polygon(44.4% 0,55.6% 0,55.6% 69%,100% 69%,50% 100%,0 69%,44.4% 69%);
  animation:cue-baja 2600ms var(--ease-out) infinite}
@keyframes cue-baja{
  0%{opacity:0;transform:translateY(-8px)}
  38%,62%{opacity:1;transform:none}
  100%{opacity:0;transform:translateY(8px)}
}

/* ---------- banda a sangre ---------- */
.band{position:relative;min-height:clamp(300px,38vw,460px);display:grid;overflow:hidden;
  grid-template-columns:minmax(0,1fr);border-block:1px solid var(--hairline)}
.band > *{grid-area:1/1}
.band > img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:1}
/* El velo va por encima de la foto y por debajo del texto. Sin los z-index el
   data-parallax le pone will-change:transform al <img>, eso lo promociona a su
   propio contexto de apilado y la foto tapaba el degradado: titular blanco
   sobre cielo claro, ilegible. */
/* El velo es --veil-band y no un degradado escrito aquí porque la banda es la
   única superficie que aparece en los dos actos: 2 de las 82 construidas van
   antes del acto claro —/industrias y su espejo— y las otras 80 van dentro de
   él. Escrito a mano se quedaba oscuro siempre, y eso convertía cada banda del
   acto claro en una inversión de superficie. Como rol, el velo lo pone el acto,
   y el porqué está entero en tokens.css. */
.band::after{content:"";grid-area:1/1;z-index:2;background:var(--veil-band)}
.band .wrap{position:relative;z-index:3;align-self:center;width:100%;padding-block:var(--s8)}
.band h2{max-width:16ch}
/* --text y no --steel-200: la bajada de la banda tiene que seguir al acto,
   igual que el velo, y --steel-200 es paleta, no sabe de tema; sobre el velo
   claro era azul pálido sobre casi blanco. Y --text y no --text-2, que sería el
   rol de una bajada, porque esta bajada no se apoya en una superficie plana
   sino en una fotografía a través de un velo. Medido con los glifos ocultos,
   sobre el peor píxel de la caja del párrafo en 14 rutas: con --text-2 da entre
   2.75 y 3.92, con --text entre 7.5 y 11.2. La jerarquía frente al titular la
   llevan aquí el cuerpo y el peso, que ya son 46px contra 16px. */
.band p{color:var(--text);max-width:46ch;margin-top:var(--s5)}

/* ---------- mosaico asimétrico ---------- */
.mosaic{display:grid;gap:var(--s4);grid-template-columns:repeat(4,1fr);
  grid-auto-rows:minmax(120px,auto)}
/* Un medio enmarcado es contenedor, no control: mismo canto que la tarjeta,
   para que dos fotos vecinas del mismo bloque no lleven dos cantos distintos
   según en qué componente hayan caído. El tercer medio enmarcado de la casa era
   `.split-media`, que se fue con su componente en la poda de septiembre de 2026
   llevándose el mismo --r-lg. */
.mosaic figure{margin:0;border-radius:var(--r-lg);overflow:hidden;border:1px solid var(--hairline);
  position:relative;background:var(--surface-3);display:flex;flex-direction:column}
.mosaic img{width:100%;height:100%;flex:1;min-height:0;object-fit:cover;
  transition:transform var(--t-scene) var(--ease)}
.mosaic figure:hover img{transform:scale(1.05)}
/* El pie sale de encima de la foto. Estaba montado sobre un velo negro pegado
   al borde inferior de la imagen, que es el adorno que el sistema visual §6.4
   prohíbe por su nombre: un rótulo sobre fotografía tapa lo que la fotografía
   argumenta, y aquí la fotografía ES el argumento.
   Debajo, el pie deja de necesitar velo, deja de necesitar una tinta clara
   escrita a mano —era `--ink-50` fijo, paleta y no rol, porque sobre el velo no
   podía ser otra— y pasa a `--text-2`, que ya cambia con el tema de la sección.
   Con eso desaparece también el par velo/tinta que hubo que reparar aquí una
   vez: sin velo no hay pareja que se pueda romper por orden de fuente. */
.mosaic figcaption{flex:none;padding:var(--s4);border-top:1px solid var(--hairline);
  font-size:13px;color:var(--text-2)}
.mosaic .m-tall{grid-row:span 2}
.mosaic .m-wide{grid-column:span 2}
@media (max-width:820px){
  .mosaic{grid-template-columns:repeat(2,1fr)}
  .mosaic .m-wide{grid-column:span 2}
}

/* ---------- tarjeta con imagen ---------- */
.card--media{padding:0;overflow:hidden}
.card--media .card-img{position:relative;aspect-ratio:16/10;overflow:hidden;background:var(--surface-4)}
.card--media .card-img img{width:100%;height:100%;object-fit:cover;border-radius:0;
  transition:transform var(--t-scene) var(--ease)}
a.card--media:hover .card-img img{transform:scale(1.06)}
.card--media .card-img::after{content:"";position:absolute;inset:auto 0 0 0;height:52%;
  background:linear-gradient(transparent,var(--ink-a80))}
.card--media .card-body{padding:var(--s5) var(--s6) var(--s6);display:flex;flex-direction:column;
  gap:var(--s3);flex:1}
/* El acento por dominio dibuja FILETES y marcas, no tinta de texto. Aquí era
   tinta: el rótulo de la tarjeta tomaba el color de la familia —naranja, verde,
   azul— y lo pintaba sobre la superficie que tocara. Sobre la tarjeta blanca
   del tema claro eso da 2.69:1 y sobre la azul 1.27:1. Funcionaba de milagro,
   porque `.page .sect:not(.sect--deep) .card .lbl` lo pisaba con más
   especificidad; al retirar ese bloque el fallo salió a la luz en 47 páginas.
   Un rótulo es texto y el texto usa el acento del tema, que sí está medido
   contra su fondo. El color de familia sigue vivo en los dos filetes de abajo,
   que no tienen que pasar AA porque no son texto. */
.card--media .lbl{color:var(--accent)}

/* ---------- filete de acento ---------- */
.sect--acc{position:relative}
.sect--acc::before{content:"";position:absolute;inset:0 auto 0 0;width:2px;
  background:linear-gradient(180deg,var(--acc,var(--accent)),transparent)}
/* En /contacto, /cifras y /casos la primera sección clara ES la del filete, y
   con la conmutación en corte duro el filete arranca en el borde mismo del
   cambio de acto, que es donde empieza la caja de la sección. */

/* ---------- movimiento ----------
   Aquí estaba el parallax: `.js [data-parallax]{will-change:transform}` más su
   apagado bajo reduced-motion. Se ha ido entero, hoja y runtime, por dos
   razones que se refuerzan.

   La primera es la prueba de §5: cada animación se justifica en una frase que
   diga qué comunica —jerarquía, relato, respuesta a una acción, cambio de
   estado—. Un desplazamiento de ±6px sobre una fotografía de hero no comunica
   ninguna de las cuatro; §5.1 no lo lista entre los gestos narrativos y §5.2 lo
   prohíbe por su nombre en las superficies de evidencia, que son las 80 páginas
   donde vivía.

   La segunda es que era el último `addEventListener('scroll')` del cliente, que
   §5.4 prohíbe: leía la geometría de cada elemento visible en cada fotograma de
   scroll para moverlo seis píxeles.

   El `will-change` se va con él y eso además retira una promoción de capa por
   imagen de hero en las 80. Los z-index explícitos de `.band` se quedan: el
   comentario de ahí arriba explica que el motivo de que existan fue esta
   promoción, y sin ella siguen siendo correctos, sólo que ya no imprescindibles. */
/* El barrido llevaba el mismo 900ms literal que el zoom del bloque partido, que
   ya no existe. Que un recorrido del 100% del alto y un zoom del 3,5% compartiesen duración exacta
   es la prueba de que no era una duración calibrada para cada gesto sino el
   mismo número escrito dos veces. --t-scene es el token de lo que dura un
   cambio de escena y esto lo es; base.css ya revela así (.rv). Sigue leyéndose
   más lento que el fundido de .reveal (520ms), que es la jerarquía que había. */
.js [data-wipe]{clip-path:inset(0 0 100% 0);transition:clip-path var(--t-scene) var(--ease)}
.js [data-wipe].in{clip-path:inset(0 0 0 0)}

/* ---------- el presupuesto de movimiento del documento ----------
   §5.2: en una superficie de evidencia sólo hay :hover, :active y :focus-visible.
   Sin revelado al entrar, sin parallax, sin fijado. El motivo está escrito en la
   cabecera de esta hoja —«El home es cine. Esto es para leer»— y hasta ahora se
   aplicaba al fijado de scroll pero no al movimiento: un jefe de HSE que busca
   la Resolución 90708 de 2013 esperaba igualmente a que el párrafo entrase.

   El presupuesto lo declara el <body> con data-movimiento, que escribe el build.
   Estas dos reglas son el mismo estado final que ya producen `.in` y el bloque
   de reduced-motion, sólo que sin transición ninguna: el contenido está donde
   tiene que estar desde el primer pintado.

   El selector lleva `body` a propósito. `.js .reveal` pesa (0,2,0) igual que
   `[data-movimiento] .reveal`, así que sin el elemento esto dependería del orden
   de las reglas dentro del fichero. Con `body` pesa (0,2,1) y gana siempre, esté
   donde esté. pages.js además no llega ni a observar estos elementos en un
   documento de evidencia, así que esto es la red y no el mecanismo. */
body[data-movimiento="evidencia"] .reveal,
body[data-movimiento="evidencia"] .reveal.in{opacity:1;transform:none;transition:none}
body[data-movimiento="evidencia"] [data-wipe],
body[data-movimiento="evidencia"] [data-wipe].in{clip-path:none;transition:none}

@media (prefers-reduced-motion:reduce){
  .js [data-wipe],.js [data-wipe].in{clip-path:none;transition:none}
  .mosaic figure:hover img,
  a.card--media:hover .card-img img{transform:none}
  /* La flecha se queda entera y quieta: sigue diciendo que hay página debajo,
     que es su trabajo, sin moverse. El `clip-path` NO se anula — es la figura,
     no el movimiento; anularlo dejaría un rectángulo naranja. */
  .phero-cue::after{animation:none}
}

@media (max-width:640px){
  .phero--media{min-height:100svh}
  .band{min-height:260px}
}

/* ---------- tarjetas y controles compartidos del catálogo audiovisual ---------- */
.video-card__meta{display:flex;flex-wrap:wrap;gap:var(--s2) var(--s4);font-family:var(--font-mono);font-size:10px;letter-spacing:.04em;color:var(--accent-soft);line-height:1.35}
.video-card__meta span+span,.video-card__meta time{color:var(--text-3)}
.video-card__link{display:inline-flex;align-items:center;gap:var(--s2);margin-top:var(--s5);font-family:var(--font-display);font-size:12px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--accent-soft)}
.video-card__link::after{content:"↗";font-size:16px;line-height:1;transition:transform var(--t-ui) var(--ease)}
.video-card:hover .video-card__link::after,.video-card:focus-visible .video-card__link::after{transform:translate(3px,-2px)}
.video-filter{min-height:44px;padding:var(--s3) var(--s4);border:1px solid var(--hairline-2);border-radius:var(--r-md);font-family:var(--font-display);font-size:12px;font-weight:700;color:var(--text-2);white-space:nowrap;transition:background var(--t-ui) var(--ease),border-color var(--t-ui) var(--ease),color var(--t-ui) var(--ease),transform var(--t-ui) var(--ease)}
.video-filter:hover{border-color:var(--accent);color:var(--text);transform:translateY(-1px)}
.video-filter:active{transform:translateY(1px)}
.video-filter.is-active,.video-filter[aria-pressed="true"]{background:var(--accent);border-color:var(--accent);color:var(--on-accent)}
.video-results{font-family:var(--font-mono);font-size:11px;letter-spacing:.05em;color:var(--text-3);margin-top:var(--s5)}
.video-results [data-video-count]{color:var(--text);font-weight:700;font-variant-numeric:tabular-nums}
.video-card{display:flex;flex-direction:column;min-width:0;background:var(--surface-3);border:1px solid var(--hairline);border-radius:var(--r-lg);overflow:hidden;box-shadow:var(--shadow);transition:transform var(--t-ui) var(--ease),border-color var(--t-ui) var(--ease),background var(--t-ui) var(--ease)}
.video-card:hover,.video-card:focus-visible{transform:translateY(-3px);border-color:var(--accent);background:var(--surface-4)}
.video-card__image{aspect-ratio:16/9;overflow:hidden;background:var(--surface-4)}
.video-card__image img{width:100%;height:100%;object-fit:cover;transition:transform var(--t-scene) var(--ease)}
.video-card:hover .video-card__image img,.video-card:focus-visible .video-card__image img{transform:scale(1.04)}
.video-card__body{display:flex;flex-direction:column;align-items:flex-start;flex:1;padding:var(--s5) var(--s5) var(--s6)}
.video-card__body h3{font-size:clamp(17px,1.7vw,22px);line-height:1.18;letter-spacing:-.02em;color:var(--text);margin-top:var(--s4);text-wrap:balance}
.video-card--compact .video-card__body h3{font-size:17px}
.video-card__meta time{font-variant-numeric:tabular-nums}
.video-empty{padding:var(--s8);border:1px dashed var(--hairline-2);color:var(--text-2);text-align:center;margin-top:var(--s6)}
@media (prefers-reduced-motion:reduce){
  .video-card,.video-filter,.video-card__image img,.video-card__link::after{transition:none}
  .video-card:hover,.video-card:focus-visible,.video-filter:hover,.video-filter:active{transform:none}
  .video-card:hover .video-card__image img,.video-card:focus-visible .video-card__image img{transform:none}
}

/* ---------- ficha individual de video ---------- */
.video-detail{background:var(--surface);color:var(--text)}
.video-detail-hero{padding:calc(var(--nav-top) + var(--nav-h) + var(--s7)) 0 var(--s10);background:var(--surface-2);border-bottom:1px solid var(--hairline)}
.video-detail-breadcrumb{display:flex;align-items:center;flex-wrap:wrap;gap:var(--s2);font-family:var(--font-mono);font-size:10px;letter-spacing:.06em;text-transform:uppercase;color:var(--text-3)}
.video-detail-breadcrumb a{color:var(--accent);transition:color var(--t-ui) var(--ease),transform var(--t-ui) var(--ease)}
.video-detail-breadcrumb a:hover,.video-detail-breadcrumb a:focus-visible{color:var(--accent-soft);transform:translateX(-3px)}
.video-detail-breadcrumb span:last-child{color:var(--text-3)}
/* Los tres enlaces sueltos de la plantilla de caso, a 24px de caja mínima.
   Medidos a 390px en las 222 fichas: la miga de vuelta daba 149x14,6, el enlace
   al vídeo fuente del pie de figura 128x14 y la vuelta del cierre 189x22. Los
   tres por debajo de los 24x24 de WCAG 2.2 AA 2.5.8 y ninguno amparado por la
   excepción de «enlace en línea», que pide que el objetivo vaya DENTRO de una
   frase: éstos son navegación suelta, cada uno en su propia fila.
   Se gana con `padding-block` y no con `min-height` a propósito: los tres son
   elementos flex de su fila, así que un `min-height` los estiraría sin centrar
   el texto, y convertirlos en `inline-flex` para centrarlo partiría el rótulo y
   su flecha en dos elementos flex, que es como se pierde el espacio entre
   «vídeo» y «↗». El relleno simétrico centra por construcción y no toca el flujo
   del texto: 14,6+10 = 24,6, 14+10 = 24 y 22+10 = 32. */
.video-detail-breadcrumb a,
.video-detail-embed figcaption a,
.video-back{padding-block:5px}
.video-detail-hero__intro{max-width:930px;margin-top:var(--s8)}
.video-detail-eyebrow{font-family:var(--font-mono);font-size:10px;font-weight:600;letter-spacing:.1em;line-height:1.35;text-transform:uppercase;color:var(--accent)}
.video-detail-hero h1{max-width:18ch;margin-top:var(--s4);font-size:clamp(50px,6.2vw,88px);font-weight:400;line-height:.96;letter-spacing:-.075em;text-wrap:balance}
.video-detail-hero__lead{max-width:52ch;margin-top:var(--s6);color:var(--text-2);font-size:clamp(16px,1.45vw,20px);line-height:1.55;text-wrap:pretty}
.video-detail-embed{width:min(100%,1120px);margin:var(--s9) 0 0 clamp(0px,5.9vw,80px);background:var(--ink-950);border:1px solid var(--hairline-2);border-radius:var(--r-lg);overflow:hidden;box-shadow:var(--shadow)}
.video-detail-embed__frame{aspect-ratio:16/9}
.video-detail-embed iframe{display:block;width:100%;height:100%;border:0}
.video-detail-embed figcaption{display:flex;justify-content:space-between;gap:var(--s4);align-items:center;padding:var(--s3) var(--s4);background:var(--surface-3);color:var(--text-3);font-family:var(--font-mono);font-size:10px;letter-spacing:.04em;line-height:1.4;text-transform:uppercase}
.video-detail-embed figcaption a{color:var(--accent);white-space:nowrap;transition:color var(--t-ui) var(--ease)}
.video-detail-embed figcaption a:hover,.video-detail-embed figcaption a:focus-visible{color:var(--accent-soft)}
.video-detail-highlights{padding:var(--s8) 0;border-bottom:1px solid var(--hairline);background:var(--surface)}
.video-detail-highlights__grid{display:grid;grid-template-columns:minmax(180px,.7fr) minmax(0,2.3fr);gap:clamp(var(--s7),8vw,var(--s10));align-items:start}
.video-detail-highlights__heading h2{max-width:8ch;margin-top:var(--s3);font-size:clamp(28px,3.2vw,48px);font-weight:400;line-height:1;letter-spacing:-.06em;text-wrap:balance}
.video-detail-facts{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));border-top:1px solid var(--hairline-2)}
.video-detail-facts div{min-width:0;padding:var(--s4) var(--s4) var(--s5) 0;border-bottom:1px solid var(--hairline-2)}
.video-detail-facts dt{font-family:var(--font-mono);font-size:10px;letter-spacing:.06em;line-height:1.35;text-transform:uppercase;color:var(--text-3)}
.video-detail-facts dd{margin-top:var(--s2);color:var(--text);font-size:14px;line-height:1.4}
.video-detail-story{padding:var(--s10) 0;background:var(--surface-2);border-bottom:1px solid var(--hairline)}
.video-detail-story__layout{display:grid;grid-template-columns:minmax(180px,.8fr) minmax(0,2.2fr);gap:clamp(var(--s7),8vw,var(--s10));align-items:start}
.video-detail-story__aside{position:sticky;top:calc(var(--nav-top) + var(--nav-h) + var(--s6));padding-top:var(--s2)}
.video-detail-story__aside h2{max-width:9ch;margin-top:var(--s3);font-size:clamp(30px,3.4vw,50px);font-weight:400;line-height:1;letter-spacing:-.065em;text-wrap:balance}
.video-detail-story__aside > p:last-child{max-width:24ch;margin-top:var(--s5);color:var(--text-2);font-size:14px;line-height:1.6}
.video-detail-story__column{max-width:720px}
.video-detail-chapter{display:grid;grid-template-columns:56px minmax(0,1fr);gap:var(--s5);padding:var(--s6) 0;border-top:1px solid var(--hairline-2)}
.video-detail-chapter:last-of-type{border-bottom:1px solid var(--hairline-2)}
.video-detail-chapter__index{padding-top:6px;color:var(--accent);font-family:var(--font-mono);font-size:10px;letter-spacing:.06em}
.video-detail-chapter h3{font-size:clamp(24px,2.35vw,34px);font-weight:500;line-height:1.06;letter-spacing:-.045em}
.video-detail-chapter p:not(.video-detail-chapter__index){max-width:62ch;margin-top:var(--s4);color:var(--text-2);font-size:16px;line-height:1.7}
.video-detail-source{display:grid;grid-template-columns:minmax(160px,.8fr) minmax(0,1.2fr);gap:var(--s6);margin-top:var(--s8);padding:var(--s5) 0 0;border-top:2px solid var(--accent)}
.video-detail-source h2{max-width:12ch;margin-top:var(--s3);font-size:clamp(22px,2.2vw,30px);font-weight:500;line-height:1.05;letter-spacing:-.04em}
.video-detail-source p:not(.video-detail-eyebrow){color:var(--text-2);font-size:14px;line-height:1.6}
.video-detail-source a{display:inline-flex;align-items:center;min-height:44px;margin-top:var(--s4);color:var(--accent);font-family:var(--font-display);font-size:12px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;transition:color var(--t-ui) var(--ease),transform var(--t-ui) var(--ease)}
.video-detail-source a:hover,.video-detail-source a:focus-visible{color:var(--accent-soft);transform:translateX(3px)}
.video-related{padding:var(--s9) 0 var(--s10);background:var(--surface);border-bottom:1px solid var(--hairline)}
.video-related__heading{display:flex;align-items:end;justify-content:space-between;gap:var(--s6);border-bottom:1px solid var(--hairline-2);padding-bottom:var(--s5)}
.video-related__heading h2{margin-top:var(--s3);font-size:clamp(28px,3.2vw,46px);font-weight:400;line-height:1;letter-spacing:-.06em;text-wrap:balance}
.video-related__heading .video-back--bottom{margin:0 0 2px auto}
.video-related-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--s5);margin-top:var(--s7)}
.video-detail .video-card{box-shadow:none}

@media (max-width:940px){
  .video-detail-embed{margin-left:0}
  .video-detail-highlights__grid,.video-detail-story__layout{grid-template-columns:minmax(150px,.7fr) minmax(0,2fr);gap:var(--s7)}
  .video-detail-facts{grid-template-columns:repeat(2,minmax(0,1fr))}
}

@media (max-width:767px){
  .video-detail-hero{padding-bottom:var(--s8)}
  .video-detail-hero__intro{margin-top:var(--s7)}
  /* EL TITULAR DE LA FICHA DE CASO OBEDECE LA LEY MÓVIL DEL SITIO, QUE HASTA HOY
     SE SALTABA. Estas 222 fichas x2 lenguas traen su titular de la metadata de
     YouTube, así que el más largo del corpus mide 94 caracteres y nadie lo
     escribió pensando en una columna de 346px. Con `clamp(46px,13vw,66px)` ese
     titular salía a 50,7px y ocupaba NUEVE renglones y 438px de alto: más de la
     mitad del viewport de un iPhone gastada en el título, con el vídeo —que es
     lo que la página es— empujado fuera de pantalla. Medido a 390px sobre las
     cuatro fichas de referencia: 9, 8, 4 y 1 renglones.
     El número es una anomalía dentro del propio sitio: a ese mismo ancho, el h1
     de las otras 95 portadas vale 28px (base.css) porque su escala se aplana con
     la columna. Esta plantilla llegó con escala propia y sin ese tramo.
     `clamp(30px,8.6vw,46px)` lo devuelve al sistema: 46px hasta 535px de ancho,
     33,5px a 390 y suelo de 30 por debajo de 349. El peor caso pasa de 9
     renglones a 5, y de 438px a 176. Los 5 no son 3, que es lo que pide la
     composición: bajar a tres pediría 22px, por debajo del suelo de h2, y eso es
     cambiar un defecto de escala por otro peor. Es la misma excepción, y por la
     misma razón medida, que base.css documenta para las 15 portadas que no caben
     en dos renglones.
     Se suelta también el `max-width:12ch`, que a 33,5px vale 267px sobre una
     columna de 346 y partía en cuatro lo que ya cabía en tres. */
  .video-detail-hero h1{max-width:16ch;font-size:clamp(30px,8.6vw,46px)}
  .video-detail-hero__lead{margin-top:var(--s5)}
  .video-detail-embed{margin-top:var(--s8);border-radius:var(--r-sm)}
  .video-detail-embed figcaption{align-items:flex-start;flex-direction:column;gap:var(--s2)}
  .video-detail-highlights,.video-detail-story,.video-related{padding:var(--s8) 0}
  .video-detail-highlights__grid,.video-detail-story__layout{grid-template-columns:1fr;gap:var(--s6)}
  .video-detail-highlights__heading h2{max-width:none;font-size:36px}
  .video-detail-story__aside{position:static;padding:0}
  .video-detail-story__aside h2{max-width:none;font-size:38px}
  .video-detail-story__aside > p:last-child{max-width:46ch;margin-top:var(--s4)}
  .video-detail-chapter{grid-template-columns:40px minmax(0,1fr);gap:var(--s4);padding:var(--s5) 0}
  .video-detail-chapter p:not(.video-detail-chapter__index){font-size:15px;line-height:1.65}
  .video-detail-source{grid-template-columns:1fr;gap:var(--s4);margin-top:var(--s7)}
  .video-detail-source h2{max-width:none}
  .video-related__heading{display:block}
  .video-related__heading .video-back--bottom{margin-top:var(--s4)}
  .video-related-grid{grid-template-columns:1fr;gap:var(--s4);margin-top:var(--s6)}
}

@media (max-width:420px){
  .video-detail-breadcrumb{font-size:9px}
  /* Aquí había un segundo cuerpo para el titular, `clamp(43px,13vw,58px)`, y lo
     que hacía por debajo de 420px era SUBIR el suelo a 43px justo donde la
     columna es más estrecha. El clamp de 767 ya cubre este tramo entero y lo
     cubre en el sentido correcto. */
  .video-detail-facts{grid-template-columns:1fr}
}

@media (prefers-reduced-motion:reduce){
  .video-detail-breadcrumb a,.video-detail-embed figcaption a,.video-detail-source a{transition:none}
}

.video-harvey-page{background:var(--ink-50);color:var(--ink-900)}
/* La única página del sitio que suelta `--maxw`: la retícula de doce columnas a
   sangre es su composición y no un descuido. Lo que sí se le pone es un techo,
   y el techo es 1920 porque por encima de ahí la página deja de crecer y empieza
   a estirarse: medido a 2560, las cuatro tarjetas de categoría pasan a 1240px de
   ancho con recorte 2,25:1 —un sujeto de pie no cabe en esa rendija— mientras el
   titular se queda en los 52px con los que nació, o sea el 2% del ancho de la
   pantalla. A 1920 y por debajo no cambia ni un píxel: es exactamente la página
   de hoy, con su ancho máximo puesto donde ya estaba probada.
   Los 32px laterales absorben el recorte lateral como el gutter de tokens.css.
   No usan `--gutter` a propósito: esta página declara su propio ritmo y tomarlo
   de la retícula general la cambiaría en todos los anchos. */
.video-harvey-page .wrap{max-width:1920px;margin-inline:auto;
  padding-right:max(32px,env(safe-area-inset-right,0px));
  padding-left:max(32px,env(safe-area-inset-left,0px))}
.video-harvey-grid{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:16px}
.video-harvey-hero,.video-harvey-signal,.video-harvey-stories,.video-harvey-stats{background:var(--ink-50);color:var(--ink-900)}

.video-harvey-hero{padding:calc(var(--nav-top) + var(--nav-h) + var(--s8)) 0 11px}
.video-harvey-grid--hero{row-gap:20px}
.video-harvey-hero h1{grid-column:1 / -1;max-width:none;margin:0 auto;text-align:center;font-family:var(--font-display);font-size:52px;font-weight:400;line-height:.98;letter-spacing:-.065em;text-wrap:balance;color:var(--ink-900)}
.video-harvey-intro{grid-column:4 / 10;max-width:650px;margin:0 auto;text-align:center;font-family:var(--font-text);font-size:20px;line-height:1.3;color:var(--steel-500);text-wrap:pretty}

.video-harvey-signal{display:flex;align-items:center;height:180px;padding:0;border-top:0;border-bottom:0}

.video-harvey-stories{padding:48px 0 64px}
/* TRECE TARJETAS EN CUATRO COLUMNAS: TODOS, doble, los once sectores y Educación.
   TODOS ocupa dos columnas y dos filas (el doble en cada eje: misma proporción
   que las demás, cuatro veces el área) arriba a la izquierda; las dos primeras
   tarjetas se apilan a su derecha y las ocho restantes llenan dos filas. 4+12
   = 16 casillas = cuatro filas de cuatro, sin hueco ni tarjeta huérfana. Los
   sectores bajan de 2,25/1 a 16/10 porque a un tercio del ancho el sujeto de
   pie del render y de las fotos ya no cabe en una rendija. */
.video-harvey-grid--stories .video-category-card{grid-column:span 3;aspect-ratio:16 / 10}
.video-harvey-grid--stories .video-category-card--todos{grid-column:span 6;grid-row:span 2;aspect-ratio:auto}
.video-category-card--todos .video-category-card__mosaic{display:grid;grid-template-columns:1fr 1fr;grid-template-rows:1fr 1fr}
.video-category-card--todos .video-category-card__mosaic img{min-height:0;opacity:.45}
.video-category-card--todos .video-category-card__category{font-size:clamp(44px,8vw,150px);font-weight:500;letter-spacing:-.06em;text-transform:uppercase}
.video-category-card--todos .video-category-card__count strong{font-size:clamp(56px,7vw,120px)}
/* El render 3D de Emergencias: recorte sobre transparente, anclado a la derecha
   con el acento de dominio detrás; el texto queda a la izquierda, sobre tinta. */
.video-category-card--render .video-category-card__image{background:radial-gradient(70% 90% at 80% 60%,var(--glow) 0%,var(--ink-950) 70%)}
.video-category-card--render .video-category-card__image::after{opacity:.35}
.video-category-card--render .video-category-card__image img{object-fit:contain;object-position:right bottom;padding-top:6%;opacity:1}
/* El rótulo no llega a la figura: con el blanco del visor detrás, un rótulo largo en una línea queda blanco sobre blanco. */
.video-category-card--render .video-category-card__category{max-width:55%;text-wrap:balance}
.video-category-card{position:relative;display:block;aspect-ratio:2.25 / 1;min-width:0;overflow:hidden;border:0;border-radius:8px;background:var(--ink-950);color:var(--ink-0);box-shadow:none;transition:transform 620ms var(--ease),box-shadow 620ms var(--ease)}
.video-category-card__image{position:absolute;inset:0;background:var(--ink-950)}
.video-category-card__image::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,var(--ink-a10) 8%,var(--ink-a45) 55%,var(--ink-a90) 100%);opacity:.9;transition:opacity 620ms var(--ease)}
.video-category-card__image img{width:100%;height:100%;object-fit:cover;opacity:.68;transition:transform 1000ms var(--ease),opacity 620ms var(--ease)}
.video-category-card__body{position:relative;z-index:1;display:flex;flex-direction:column;justify-content:space-between;height:100%;padding:20px;color:var(--ink-0)}
.video-category-card__category{font-family:var(--font-display);font-size:clamp(18px,2vw,30px);font-weight:500;line-height:1.05;letter-spacing:-.04em;color:var(--ink-0);transform:translateY(4px);transition:transform 620ms var(--ease)}
.video-category-card__footer{display:flex;align-items:flex-end;justify-content:space-between;gap:16px;opacity:.86;transform:translateY(8px);transition:opacity 540ms var(--ease),transform 620ms var(--ease)}
.video-category-card__count{font-family:var(--font-display);font-size:11px;font-weight:600;letter-spacing:.055em;line-height:1.2;text-transform:uppercase;color:var(--steel-200)}
.video-category-card__count strong{margin-right:4px;font-size:clamp(38px,4vw,64px);font-weight:400;line-height:.8;letter-spacing:-.07em;color:var(--ink-0);font-variant-numeric:tabular-nums}
.video-category-card__link{font-family:var(--font-display);font-size:10px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-0)}
.video-category-card__link::after{content:"↗";margin-left:5px}
.video-harvey-grid--stories.has-card-motion .video-category-card{opacity:0;transform:translateY(28px) scale(.985)}
.video-harvey-grid--stories.has-card-motion.is-visible .video-category-card{animation:video-category-card-in 1100ms var(--ease) var(--card-delay,0ms) both}
.video-category-card:nth-of-type(1){--card-delay:0ms}
.video-category-card:nth-of-type(2){--card-delay:180ms}
.video-category-card:nth-of-type(3){--card-delay:360ms}
.video-category-card:nth-of-type(4){--card-delay:540ms}
.video-category-card:nth-of-type(5){--card-delay:720ms}
@keyframes video-category-card-in{from{opacity:0;transform:translateY(28px) scale(.985)}to{opacity:1;transform:translateY(0) scale(1)}}

.video-category-card:focus-visible{transform:translateY(-5px);box-shadow:0 18px 38px -24px var(--ink-a80)}
.video-category-card:focus-visible .video-category-card__image::after{opacity:1}
.video-category-card:focus-visible .video-category-card__image img{transform:scale(1.04);opacity:.86}
.video-category-card:focus-visible .video-category-card__category{transform:none}
.video-category-card:focus-visible .video-category-card__footer{opacity:1;transform:none}
@media (hover:hover) and (pointer:fine){
  .video-category-card:hover{transform:translateY(-5px);box-shadow:0 18px 38px -24px var(--ink-a80)}
  .video-category-card:hover .video-category-card__image::after{opacity:1}
  .video-category-card:hover .video-category-card__image img{transform:scale(1.04);opacity:.86}
  .video-category-card:hover .video-category-card__category{transform:none}
  .video-category-card:hover .video-category-card__footer{opacity:1;transform:none}
}
.video-harvey-stats{padding:var(--s10) 0;border-top:1px solid var(--blu-a20);border-bottom:0}
.video-harvey-grid--stats h2{grid-column:1 / -1;max-width:none;margin:0 0 var(--s6);font-family:var(--font-display);font-size:42px;font-weight:500;line-height:1.05;letter-spacing:-.055em;text-align:center;color:var(--ink-900)}
.video-harvey-stat-list{grid-column:1 / -1;border-top:1px solid var(--ink-900)}
.video-harvey-stat-list>div{position:relative;display:grid;grid-template-columns:1fr 1fr;align-items:center;gap:0;min-height:136px;padding:var(--s5) 0;border-bottom:1px solid var(--blu-a20)}
.video-harvey-stat-list span{grid-column:auto;max-width:22ch;font-family:var(--font-text);font-size:20px;line-height:1.2;color:var(--ink-900)}
.video-harvey-stat-list strong{grid-column:auto;font-family:var(--font-display);font-size:86px;font-weight:400;line-height:.82;letter-spacing:-.075em;text-align:left;color:var(--ink-900);font-variant-numeric:tabular-nums}
.video-harvey-stat-list.has-stat-motion>div{opacity:0;transform:translateY(28px);transition:opacity 520ms var(--ease),transform 700ms var(--ease)}
.video-harvey-stat-list.has-stat-motion>div::after{position:absolute;right:0;bottom:-1px;left:0;height:2px;background:var(--brand-org);content:"";transform:scaleX(0);transform-origin:left center;transition:transform 1400ms var(--ease)}
.video-harvey-stat-list.has-stat-motion>div.is-visible{opacity:1;transform:none}
.video-harvey-stat-list.has-stat-motion>div.is-visible::after{transform:scaleX(1)}
.video-harvey-stat-list strong.is-counting{color:var(--brand-org);text-shadow:0 0 24px var(--brand-amb)}
.video-harvey-stat-list strong.is-complete{animation:video-stat-settle 420ms var(--ease)}
.video-harvey-grid--stats.has-stat-motion h2{opacity:0;transform:translateY(18px);transition:opacity 520ms var(--ease),transform 700ms var(--ease)}
.video-harvey-grid--stats.has-stat-motion.is-visible h2{opacity:1;transform:none}
@keyframes video-stat-settle{0%{transform:scale(1.08);color:var(--brand-org)}100%{transform:scale(1);color:var(--ink-900)}}

.video-harvey-library,.video-harvey-close{--surface:var(--ink-950);--surface-2:var(--ink-900);--surface-3:var(--ink-800);--surface-4:var(--ink-700);--text:var(--ink-50);--text-2:var(--steel-300);--text-3:var(--steel-400);--hairline:var(--hair-a13);--hairline-2:var(--hair-a26);--control-edge:var(--hair-a45);--accent:var(--brand-org);--accent-soft:var(--brand-amb);background:var(--ink-950);color:var(--ink-50)}
.video-harvey-library{padding:var(--s10) 0 calc(var(--s10) + var(--s6))}
.video-harvey-grid--library-intro{margin-bottom:var(--s7)}
.video-harvey-grid--library-intro h2{grid-column:1 / -1;max-width:18ch;font-family:var(--font-display);font-size:44px;font-weight:400;line-height:1.02;letter-spacing:-.06em;color:var(--ink-50)}
.video-harvey-grid--library-intro p{grid-column:1 / 8;max-width:58ch;margin-top:var(--s4);font-family:var(--font-text);font-size:16px;line-height:1.55;color:var(--steel-300)}
/* Once pastillas: con cinco columnas fijas, entre 700 y 1100 px cada caja se
   quedaba en 130 px y los nombres largos partían en cuatro líneas pegadas al
   borde. Cada columna pide ahora 210 px y la rejilla decide cuántas caben. */
.video-harvey-filters{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:16px;border:0;overflow:visible}
.video-harvey-filters .video-filter{display:flex;align-items:center;justify-content:flex-start;min-height:63px;padding:12px 18px;border:1px solid var(--hair-a26);border-radius:8px;background:transparent;color:var(--steel-300);font-family:var(--font-display);font-size:13px;font-weight:500;line-height:1.2;text-align:left;white-space:normal;transition:border-color var(--t-ui) var(--ease),background var(--t-ui) var(--ease),color var(--t-ui) var(--ease)}
.video-harvey-filters .video-filter:hover,.video-harvey-filters .video-filter:focus-visible{border-color:var(--hair-a45);background:var(--ink-a08);color:var(--ink-50);transform:none}
.video-harvey-filters .video-filter.is-active,.video-harvey-filters .video-filter[aria-pressed="true"]{border-color:var(--ink-50);background:var(--ink-a08);color:var(--ink-50)}
.video-harvey-library .video-results{margin-top:var(--s5);font-family:var(--font-display);font-size:11px;font-weight:600;letter-spacing:.075em;text-transform:uppercase;color:var(--steel-400)}
.video-harvey-library .video-results [data-video-count]{color:var(--ink-50)}
.video-harvey-grid--library{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));align-items:start;gap:32px 16px;margin-top:var(--s7)}
.video-harvey-grid--library .video-card--archive{display:block;min-width:0;height:auto;aspect-ratio:auto;overflow:visible;border:0;border-radius:0;background:transparent;box-shadow:none;color:var(--ink-50)}
.video-harvey-grid--library .video-card--archive[hidden]{display:none!important}
.video-harvey-page .video-card--archive:hover,.video-harvey-page .video-card--archive:focus-visible{transform:none;border-color:transparent;background:transparent}
.video-harvey-page .video-card--archive .video-card__image{position:relative;inset:auto;aspect-ratio:4 / 3;overflow:hidden;border-radius:8px;background:var(--ink-800)}
.video-harvey-page .video-card--archive .video-card__image::after{display:none}
.video-harvey-page .video-card--archive .video-card__image img{width:100%;height:100%;object-fit:cover;object-position:center center;opacity:1;transition:transform 260ms var(--ease)}
.video-harvey-page .video-card--archive:hover .video-card__image img,.video-harvey-page .video-card--archive:focus-visible .video-card__image img{transform:scale(1.04)}
.video-harvey-page .video-card--archive .video-card__body{position:relative;inset:auto;display:block;padding:12px 0 0;color:var(--ink-50)}
.video-harvey-page .video-card--archive .video-card__meta{display:flex;flex-wrap:wrap;gap:4px 10px;width:100%;font-family:var(--font-display);font-size:10px;font-weight:600;letter-spacing:.055em;line-height:1.25;text-transform:uppercase;color:var(--steel-300)}
.video-harvey-page .video-card--archive .video-card__meta span+span,.video-harvey-page .video-card--archive .video-card__meta time{color:var(--steel-400)}
.video-harvey-page .video-card--archive .video-card__body h3{display:block;overflow:visible;width:100%;margin:8px 0 0;font-family:var(--font-display);font-size:20px;font-weight:500;line-height:1.22;letter-spacing:-.035em;color:var(--ink-50);-webkit-line-clamp:unset}
.video-harvey-page .video-card--archive .video-card__link{display:none}

@media (hover:hover) and (pointer:fine){
  .video-harvey-page .video-card--archive:hover .video-card__image img,.video-harvey-page .video-card--archive:focus-visible .video-card__image img{transform:scale(1.04)}
}
.video-harvey-library .video-empty{margin-top:var(--s7);padding:var(--s6) 0;border:0;border-top:1px solid var(--hair-a26);border-bottom:1px solid var(--hair-a26);color:var(--steel-300);text-align:left}
/* El botón de la siguiente tanda. Toma la forma y el cuerpo de los filtros de
   arriba, que son los otros controles de esta sección, pero se queda del tamaño
   de su rótulo y centrado bajo la rejilla: es un paso adelante en la lectura, no
   la acción principal de la sección, y esa la tiene la banda de cierre.
   44px de alto, que es el objetivo táctil que WCAG 2.2 AA 2.5.8 pide holgado.
   El canto va en `--control-edge` y no en `--hairline-2`: no tiene relleno en
   reposo, así que el filete es lo único que dice que ahí hay un control, y eso
   es lo que WCAG 1.4.11 pide a 3:1. Medido sobre `--ink-950`: 3,33:1. */
.video-harvey-library .video-more{display:block;min-height:44px;margin:var(--s7) auto 0;padding:0 22px;border:1px solid var(--control-edge);border-radius:8px;background:transparent;color:var(--ink-50);font-family:var(--font-display);font-size:13px;font-weight:500;line-height:1.2;transition:border-color var(--t-ui) var(--ease),background var(--t-ui) var(--ease)}
.video-harvey-library .video-more:hover,.video-harvey-library .video-more:focus-visible{border-color:var(--ink-50);background:var(--ink-a08)}
.video-harvey-library .video-more[hidden]{display:none}

.video-harvey-close{padding:var(--s9) 0 var(--s10);border-top:1px solid var(--hair-a13)}
.video-harvey-grid--close h2{grid-column:1 / 8;max-width:14ch;font-family:var(--font-display);font-size:54px;font-weight:400;line-height:1.02;letter-spacing:-.065em;color:var(--ink-50)}
.video-harvey-grid--close .edu-cta{grid-column:10 / -1;justify-self:end;color:var(--ink-50)}

@media (max-width:1023px){
  .video-harvey-page .wrap{padding-right:max(28px,env(safe-area-inset-right,0px));
    padding-left:max(28px,env(safe-area-inset-left,0px))}
  .video-harvey-grid{grid-template-columns:repeat(6,minmax(0,1fr));gap:16px}
  .video-harvey-hero{padding:calc(var(--nav-top) + var(--nav-h) + var(--s7)) 0 32px}
  .video-harvey-grid--hero{row-gap:64px}
  .video-harvey-hero h1{grid-column:1 / -1;max-width:none;margin:0;text-align:left;font-size:42px}
  .video-harvey-intro{grid-column:1 / -1;max-width:48ch;margin:0;text-align:left;font-size:18px}
  .video-harvey-signal{height:156px}
  .video-harvey-stories{padding-top:56px}
  /* Dos por fila: TODOS a ancho completo y las doce restantes en seis filas exactas. */
  .video-harvey-grid--stories .video-category-card{grid-column:span 3}
  .video-harvey-grid--stories .video-category-card--todos{grid-column:1 / -1;grid-row:auto;aspect-ratio:2 / 1}
  .video-harvey-grid--stats h2{grid-column:1 / -1;font-size:38px}
  .video-harvey-stat-list{grid-column:1 / -1}
  .video-harvey-stat-list>div{min-height:120px}
  .video-harvey-stat-list strong{font-size:72px}
  .video-harvey-grid--library-intro h2{grid-column:1 / -1;font-size:42px}
  .video-harvey-grid--library-intro p{grid-column:1 / 6}
  /* Dos por fila desde tablet: a una columna aquí y a dos bajo 479px la
     escala se invertiría —el teléfono mostraría más por fila que el iPad—. */
  .video-harvey-grid--library{grid-template-columns:repeat(2,minmax(0,1fr));gap:24px 14px}
  .video-harvey-page .video-card--archive .video-card__body h3{font-size:18px}
  .video-harvey-grid--close h2{grid-column:1 / 5;font-size:46px}
  .video-harvey-grid--close .edu-cta{grid-column:5 / 7}
}

@media (max-width:479px){
  .video-harvey-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:14px}
  .video-harvey-hero{padding:calc(var(--nav-top) + var(--nav-h) + var(--s7)) 0 37px}
  .video-harvey-grid--hero{row-gap:64px}
  .video-harvey-hero h1{grid-column:1 / -1;max-width:none;font-size:48px;line-height:.98}
  .video-harvey-intro{grid-column:1 / -1;max-width:none;margin:0;text-align:left;font-size:17px}
  .video-harvey-signal{height:156px}
  .video-harvey-stories{padding:56px 0 var(--s8)}
  /* Dos por fila también en el teléfono: doce tarjetas a una columna eran doce pantallas.
     TODOS ocupa el ancho entero y las doce restantes caen en seis filas de dos. */
  .video-harvey-grid--stories .video-category-card{grid-column:auto;aspect-ratio:auto;min-height:168px}
  .video-harvey-grid--stories .video-category-card--todos{min-height:240px}
  .video-harvey-grid--stories .video-category-card--todos{grid-column:1 / -1}
  .video-category-card__category{font-size:16px}
  .video-category-card--todos .video-category-card__category{font-size:56px}
  .video-category-card--todos .video-category-card__count strong{font-size:48px}
  .video-category-card--render .video-category-card__image img{width:42%;margin-left:auto}
  /* En el teléfono la figura es pequeña y el rótulo ya cabía a dos renglones: el tope de escritorio aquí sobra. */
  .video-category-card--render .video-category-card__category{max-width:none}
  .video-harvey-grid--stories .video-category-card--render{min-height:260px}
  /* LA TARJETA DE CATEGORÍA, QUE A UNA COLUMNA SE ROMPÍA POR EL PIE.
     Con `aspect-ratio:2.25/1` la tarjeta mide 334x148 en un iPhone, y dentro de
     esos 148px hay que meter el nombre de la categoría, un número a 38px, su
     rótulo y el enlace. Medido a 390: el rótulo «CASOS DE ÉXITO» partía en dos
     renglones y el segundo caía DEBAJO del número, y el enlace «VER CASOS DE
     ÉXITO» partía también. El pie de la tarjeta era un amasijo.
     Tres cambios, y ninguno toca la tarjeta de escritorio:
     · 16/10 en vez de 2.25/1. La tarjeta gana 61px de alto y la fotografía deja
       de ser una rendija: a 2,25:1 y 334px de ancho no cabe un sujeto entero.
     · El recuento pasa a caja propia con `baseline`, así que el rótulo envuelve
       AL LADO del número y no por debajo de él.
     · El enlace no parte. A 10px cabe entero en una línea y compite mejor por el
       ancho que el recuento, que ya no lo necesita. */
  .video-category-card
  .video-category-card__count{display:flex;align-items:baseline;gap:6px}
  .video-category-card__count strong{margin-right:0}
  /* Móvil: nada se recorta. La tarjeta crece con su contenido, el pie se apila
     (recuento y enlace uno bajo otro) y ningún texto es `nowrap`. */
  .video-category-card,
  .video-category-card__body{height:auto;min-height:168px;gap:12px;padding:14px}
  .video-category-card__footer{flex-direction:column;align-items:flex-start;gap:6px}
  .video-category-card__count{flex-wrap:wrap}
  .video-harvey-stats{padding:var(--s8) 0}
  .video-harvey-grid--stats h2,.video-harvey-stat-list{grid-column:1 / -1}
  .video-harvey-grid--stats h2{max-width:none;margin-bottom:var(--s5);font-size:36px}
  .video-harvey-stat-list>div{display:block;min-height:0;padding:var(--s5) 0}
  .video-harvey-stat-list span,.video-harvey-stat-list strong{display:block;max-width:none;text-align:left}
  .video-harvey-stat-list span{font-size:16px}
  .video-harvey-stat-list strong{margin-top:var(--s3);font-size:68px}
  .video-harvey-library{padding:var(--s8) 0}
  .video-harvey-grid--library-intro{margin-bottom:var(--s6)}
  .video-harvey-grid--library-intro h2,.video-harvey-grid--library-intro p{grid-column:1 / -1}
  .video-harvey-grid--library-intro h2{max-width:13ch;font-size:40px}
  .video-harvey-grid--library-intro p{margin-top:var(--s3);font-size:15px}
  /* Diez sectores desde 2026-09-29: en una columna las pastillas ocupaban la
     pantalla entera del teléfono antes de la primera ficha. En dos se quedan en
     cinco filas, y un nombre largo («Seguridad, Defensa y Fuerza Pública») parte
     en dos líneas dentro de su caja, que ya admite `white-space:normal`. */
  .video-harvey-filters{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
  .video-harvey-filters .video-filter{min-height:52px;padding:var(--s2) 12px}
  .video-harvey-grid--library{grid-template-columns:repeat(2,minmax(0,1fr));gap:20px 12px;margin-top:var(--s6)}
  .video-harvey-page .video-card--archive .video-card__body h3{font-size:16px}
  .video-harvey-close{padding:var(--s8) 0}
  .video-harvey-grid--close h2,.video-harvey-grid--close .edu-cta{grid-column:1 / -1;justify-self:start}
  .video-harvey-grid--close h2{font-size:44px}
  .video-harvey-grid--close .edu-cta{margin-top:var(--s5)}
}

@media (prefers-reduced-motion:reduce){
  .video-category-card,.video-category-card__image::after,.video-category-card__image img,.video-category-card__category,.video-category-card__footer{transition:none}
  .video-harvey-grid--stories.has-card-motion .video-category-card,.video-harvey-grid--stories.has-card-motion.is-visible .video-category-card{animation:none;opacity:1;transform:none}
  .video-category-card:hover,.video-category-card:focus-visible{transform:none;box-shadow:none}
  .video-category-card:hover .video-category-card__image img,.video-category-card:focus-visible .video-category-card__image img{transform:none}
  .video-category-card:hover .video-category-card__category,.video-category-card:focus-visible .video-category-card__category,.video-category-card:hover .video-category-card__footer,.video-category-card:focus-visible .video-category-card__footer{transform:none}
  .video-harvey-stat-list.has-stat-motion>div,.video-harvey-grid--stats.has-stat-motion h2{opacity:1;transform:none;transition:none}
  .video-harvey-stat-list.has-stat-motion>div::after{transform:scaleX(1);transition:none}
  .video-harvey-stat-list strong.is-complete{animation:none}
  .video-harvey-page .video-card--archive .video-card__image img{transition:none}
  .video-harvey-page .video-card--archive:hover .video-card__image img,.video-harvey-page .video-card--archive:focus-visible .video-card__image img{transform:none}
}

/* ═══════════════════════════════════════════════════════════════════════
   EL VISOR DEL EQUIPO EN 3D
   Lo pintan las tres fichas de experiencia que declaran `modelo3d`. El
   marcado lo escribe `plataforma/ui/blocks/Equipo3D.astro` y quien lo anima
   es `plataforma/ui/tresd/visor.ts`, que llega por importación dinámica.

   LAS DOS CAPAS ESTÁN SIEMPRE APILADAS y sólo cambia cuál se ve. La
   fotografía del equipo vacío se sirve en el HTML y es lo que hay hasta que
   el motor pinta; `is-activo` lo pone el visor cuando ya hay un fotograma
   dibujado, nunca antes, para que no exista un instante con el hueco vacío.
   Sin JavaScript, sin WebGL o con la red caída, `is-activo` no llega nunca y
   la sección se queda en la fotografía, que es contenido y no marcador.

   Cero literales de color: todo sale de los roles de `tokens.css`, así que
   el visor sigue al tema de la sección como cualquier otro panel.
   ═══════════════════════════════════════════════════════════════════════ */
.equipo3d{margin:var(--s6) 0 0}
/* Un solo vídeo de fondo; el texto no depende de que cargue. */
.page--simulator{background:var(--surface);color:var(--text)}
.page--simulator #main{height:100svh;height:100dvh;min-height:0}
.sim-scene{position:relative;isolation:isolate;box-sizing:border-box;min-height:100%;
  display:flex;align-items:flex-end;overflow:hidden;background:var(--surface);color:var(--text);
  padding:100px clamp(24px,6vw,96px) max(110px,env(safe-area-inset-bottom,0px))}
.sim-scene::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(180deg,var(--ink-a55) 0%,var(--ink-a30) 35%,var(--ink-a90) 100%)}
.sim-scene__video{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;object-position:center;pointer-events:none}
.sim-scene__video[hidden]{display:none}
/* En vertical sólo cabe una franja del 16/9 y la persona casi nunca está en el
   centro del plano. `--shot-focus` es la fracción del ancho donde está en el plano
   en pantalla (lo escribe simulador.ts desde `data-shots`): el vídeo se desplaza
   hasta dejarla en el eje, sin pasarse de sus dos bordes. 177.78dvh es lo que
   mide de ancho un 16/9 que llena el alto. Sin el dato, .5 es el centro de siempre. */
@media(orientation:portrait){
  .sim-scene__video{object-position:clamp(100vw - 177.78dvh,50vw - var(--shot-focus,.5) * 177.78dvh,0px) 50%}
}
.sim-scene__content{position:relative;z-index:2;max-width:680px}
.sim-scene__back{position:absolute;z-index:2;top:max(24px,env(safe-area-inset-top,0px));
  left:clamp(24px,6vw,96px);display:flex;align-items:center;justify-content:center;
  width:44px;height:44px;color:var(--text);font-size:32px;text-decoration:none;
  text-shadow:0 2px 8px var(--ink-a90)}
.sim-scene h1{font-size:clamp(32px,4.5vw,60px);line-height:1.08;font-weight:500;
  letter-spacing:-.03em;margin-top:10px;text-wrap:balance;max-width:20ch}
.sim-scene__description{max-width:52ch;margin:20px 0 0;color:var(--text);
  font-size:clamp(18px,1.5vw,22px);line-height:1.6;text-wrap:pretty}
.sim-scene :focus-visible{outline:2px solid var(--accent);outline-offset:4px}
@media(max-width:760px){
  .sim-scene h1{font-size:clamp(28px,7vw,40px);margin-top:6px}
  .sim-scene__description{font-size:16px;margin-top:16px}
}
@media(max-height:520px){
  .sim-scene{padding-top:90px;padding-bottom:90px}
  .sim-scene h1{font-size:28px;max-width:none}
}

.equipo3d__escena{position:relative;aspect-ratio:16/10;overflow:hidden;
  border:1px solid var(--hairline);border-radius:var(--r-lg);background:var(--surface-3)}
.equipo3d__foto{position:absolute;inset:0;transition:opacity .45s ease}
.equipo3d__foto img{display:block;width:100%;height:100%;object-fit:cover}
/* `pan-y` y no `none`, por lo mismo que el globo del pie: con `none` el lienzo
   se queda con el gesto vertical y quien arrastra el dedo sobre el visor para
   seguir leyendo la ficha no avanza, gira el equipo. Aquí el arranque está
   limitado a 820px de ancho (`tresd/arranque.ts`), así que el atrapado no es un
   teléfono sino una tableta o un portátil táctil, que son exactamente las dos
   máquinas donde nadie prueba. El eje vertical vuelve al documento; el azimut,
   que es el que enseña la máquina por todos sus lados, se conserva, y la
   inclinación sigue disponible con las flechas del teclado, que el visor ya
   sirve. */
/* EL CURSOR ES LA OTRA MITAD DE LA PISTA, Y SE QUEDÓ DICIENDO LO QUE LA FRASE
   YA NO DICE. El lienzo se sirve SIEMPRE y en `position:absolute;inset:0`, o
   sea tapando la fotografía entera; `opacity:0` lo hace invisible pero NO le
   quita los eventos de puntero. Con `cursor:grab` de fábrica, quien visita una
   de las catorce páginas sin malla montada —sin WebGL, sin JavaScript o por
   debajo de 820px, que son los tres cortes de `tresd/arranque.ts`— pasa el ratón
   sobre una foto fija y ve la mano de agarrar. Arrastra, y no pasa nada.
   Retirar el `<figcaption>` y dejar esto puesto es cambiar de canal la misma
   mentira.
   `is-activo` ya era el interruptor de «hay malla»: lo pone el arrancador
   cuando `montaVisor` ha devuelto y hay un fotograma. Sólo le faltaba mandar
   también sobre el cursor, que es lo que hacen las dos reglas de abajo. */
.equipo3d__lienzo{position:absolute;inset:0;opacity:0;touch-action:pan-y;cursor:default;
  transition:opacity .45s ease}
.equipo3d__lienzo canvas{display:block;width:100%;height:100%}
.equipo3d.is-activo .equipo3d__foto{opacity:0}
.equipo3d.is-activo .equipo3d__lienzo{opacity:1;cursor:grab}
.equipo3d.is-girando .equipo3d__lienzo{cursor:grabbing}
.equipo3d:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:var(--r-lg)}

/* ESTA CLASE NO SALE EN NINGÚN HTML SERVIDO, Y ES A PROPÓSITO. «Arrastre el
   equipo para girarlo, o use las flechas del teclado» sólo es verdad con la
   malla montada, así que el marcado ya no la emite: `Equipo3D.astro` deja el
   texto en `data-equipo-pista` y el `<figcaption>` con esta clase lo CREA
   `plataforma/ui/tresd/arranque.ts` cuando `montaVisor` ha devuelto. El otro
   extremo del renombre está ahí, en `CLASE_PISTA`, y ninguna puerta lo canta:
   el censo de huérfanos de `verify.mts` cuenta ficheros de css/ y js/, no
   selectores. Mismo caso que `.is-activo` y `.is-girando`, aquí arriba. */
.equipo3d__pista{margin-top:var(--s3);color:var(--text-3);font-size:14.4px;line-height:1.4}

@media (max-width:760px){
  .equipo3d__escena{aspect-ratio:4/3}
}

@media (prefers-reduced-motion:reduce){
  .equipo3d__foto,.equipo3d__lienzo{transition:none}
}

/* Laboratorios de Educación (retoque 2026-10-07): rótulo del hero y los cuatro artículos de laboratorio.
   Cada regla cuelga de su clase raíz (.labs, .lab, .phero .lbl). */
.phero .lbl{color:var(--accent-soft);margin-bottom:var(--s4)}

.labs{display:flex;flex-direction:column;gap:var(--s9)}
.labs .lab{display:grid;grid-template-columns:1fr;gap:var(--s6);align-items:center}
.labs .lab img{display:block;width:100%;height:auto;aspect-ratio:4/3;object-fit:cover;
  border-radius:var(--r-lg);background:var(--surface-3)}
.labs .lab-texto{display:flex;flex-direction:column;gap:var(--s4);max-width:60ch}
.labs .lab-texto h3{font-family:var(--font-display);font-size:clamp(19px,2vw,27px);font-weight:500;line-height:1.12;color:var(--text)}
.labs .lab-texto p{color:var(--text-2)}
.labs .lab-datos{display:flex;flex-wrap:wrap;gap:var(--s4) var(--s7);margin:var(--s3) 0 0;
  padding-top:var(--s4);border-top:1px solid var(--hairline-2)}
.labs .lab-datos div{display:flex;flex-direction:column;gap:var(--s1)}
.labs .lab-datos dt{font-family:var(--font-mono);font-size:10.5px;letter-spacing:.12em;
  text-transform:uppercase;font-weight:600;color:var(--text-3)}
.labs .lab-datos dd{margin:0;color:var(--text);font-weight:600}

@media (min-width:821px){
  .labs .lab{grid-template-columns:1fr 1fr;gap:var(--s8)}
  .labs .lab:nth-child(even) img{order:2}
}

/* HUBs: composición centrada, fotografía sin recorte y bloques blancos/azules.
   Los paneles nativos funcionan sin JavaScript. El revelado es una mejora
   opcional: nunca deja contenido escondido si el script no llega. */
.hubs-page{background:var(--ink-0);color:var(--text);text-align:center}
.hubs-page .wrap{max-width:none}
.hubs-page section{padding:var(--s10) 0;scroll-margin-top:calc(var(--nav-top) + var(--nav-h) + var(--s5))}
.hubs-page .hubs-hero{padding-top:calc(var(--nav-top) + var(--nav-h) + var(--s6))}
.hubs-page h1,.hubs-page h2{max-width:28ch;margin:0 auto var(--s4);font-weight:500;line-height:1.12;letter-spacing:-.055em;text-wrap:balance}
.hubs-page h1{font-size:clamp(30px,4vw,58px)}
.hubs-page h2{font-size:clamp(27px,3vw,44px)}
.hubs-page p{max-width:68ch;margin:0 auto var(--s4);color:var(--text-2);line-height:1.7}
.hubs-page .hubs-word{display:inline-block}
.hubs-page .hubs-lead{color:var(--ink-700);font-size:clamp(17px,1.5vw,21px)}
.hubs-page .hubs-explore{display:inline-flex;align-items:center;justify-content:center;min-height:48px;padding:var(--s3) var(--s5);margin-top:var(--s2);border:1px solid var(--ink-700);border-radius:var(--r-md);color:var(--ink-700);font-weight:600}
.hubs-page .hubs-fotos{display:grid;grid-template-columns:1fr;gap:var(--s5);margin:var(--s7) auto;max-width:1600px}
.hubs-page figure{margin:0}
.hubs-page img{display:block;width:100%;height:auto;border-radius:var(--r-lg)}
.hubs-page .hubs-intro{max-width:80ch;margin-inline:auto}
/* El mismo lienzo del documento y el mismo tinte superpuesto que .foot. */
.hubs-page .hubs-practica,.hubs-page .hubs-cierre{background-color:var(--surface);background-image:linear-gradient(180deg,transparent,var(--blu-a15));color:var(--text)}
.hubs-page .hubs-practica p,.hubs-page .hubs-cierre p{color:var(--text-2)}
.hubs-page .hubs-linea{max-width:1200px;margin:var(--s7) auto 0}
.hubs-page .hub-item{border-top:1px solid var(--wht-a22)}
.hubs-page .hub-item:last-child{border-bottom:1px solid var(--wht-a22)}
.hubs-page summary{list-style:none;display:grid;grid-template-columns:44px minmax(0,1fr) 44px;align-items:center;min-height:64px;padding:var(--s5) 0;cursor:pointer;font-family:var(--font-display);font-size:clamp(18px,2.2vw,28px);font-weight:500;line-height:1.3;color:var(--ink-0)}
.hubs-page summary::-webkit-details-marker{display:none}
.hubs-page summary::before{content:""}
.hubs-page summary::after{content:"+" / "";font-weight:400;font-size:1.3em;line-height:1}
.hubs-page .hub-item[open] summary::after{content:"\2212" / ""}
.hubs-page summary:focus-visible,.hubs-page .hubs-contacto:focus-visible{outline:2px solid var(--ink-0);outline-offset:5px;border-radius:var(--r-focus)}
.hubs-page .hub-cuerpo{display:grid;grid-template-columns:1fr;gap:var(--s5);align-items:center;padding:var(--s3) var(--s4) var(--s6)}
.hubs-page .hub-cuerpo p{margin:0 auto}
.hubs-page .hub-cuerpo img{max-width:560px;margin-inline:auto}
.hubs-page .hubs-organizaciones{display:grid;grid-template-columns:1fr;gap:var(--s6);max-width:1320px;margin:var(--s7) auto}
.hubs-page .hubs-organizaciones dt{font-family:var(--font-display);font-size:clamp(20px,2vw,26px);font-weight:600;color:var(--ink-700);margin:0 0 var(--s3)}
.hubs-page .hubs-organizaciones dd{max-width:44ch;margin:0 auto;color:var(--text-2);line-height:1.7}
.hubs-page .hubs-arl{max-width:1200px;margin:var(--s7) auto 0}
.hubs-page .hubs-contacto{display:inline-flex;justify-content:center;min-height:48px;margin-top:var(--s4);background:var(--ink-0);color:var(--ink-700);border:1px solid var(--ink-0);font-weight:600}
@media (min-width:821px){
  .hubs-page .hubs-fotos{grid-template-columns:repeat(2,minmax(0,1fr))}
  .hubs-page .hub-cuerpo{grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s7)}
  .hubs-page .hubs-organizaciones{grid-template-columns:repeat(3,minmax(0,1fr))}
}
@media (max-width:820px){
  .hubs-page section{padding:var(--s8) 0}
  .hubs-page .hubs-fotos{gap:var(--s4);margin-block:var(--s6)}
  .hubs-page .hub-cuerpo{padding-inline:0}
  .hubs-page summary{grid-template-columns:28px minmax(0,1fr) 28px}
  .hubs-page .hubs-contacto{width:100%;max-width:360px}
}
@media (prefers-reduced-motion:no-preference){
  .hubs-page .hubs-visible{animation:hubs-entrada .85s var(--ease-out) both;animation-delay:var(--hubs-delay,0ms)}
  .hubs-page .hubs-hero .hubs-heading.hubs-visible{animation:none}
  .hubs-page .hubs-heading.hubs-visible .hubs-word{animation:hubs-palabra .9s var(--ease-out) both;animation-delay:var(--hubs-word-delay,0ms)}
  .hubs-page .hubs-heading.hubs-visible .hubs-lead{animation:hubs-entrada .9s var(--ease-out) .2s both}
  .hubs-page .hubs-heading.hubs-visible .hubs-explore{animation:hubs-boton .85s var(--ease-out) .35s backwards}
  .hubs-page .hubs-fotos figure.hubs-visible{animation-name:hubs-foto;animation-duration:1.1s}
  .hubs-page .hubs-fotos figure:nth-child(even).hubs-visible{animation-name:hubs-foto-inversa}
  .hubs-page .hub-item[open] .hub-cuerpo p{animation:hubs-entrada .55s var(--ease-out) both}
  .hubs-page .hub-item[open] .hub-cuerpo img{animation:hubs-foto .75s var(--ease-out) .08s both}
  .hubs-page summary::after{transition:transform .4s var(--ease-out)}
  .hubs-page .hub-item[open] summary::after{transform:rotate(180deg)}
  .hubs-page .hubs-organizaciones dt::after{content:"";display:block;width:48px;height:2px;margin:var(--s3) auto 0;background:var(--ink-700);transform:scaleX(0);transform-origin:center}
  .hubs-page .hubs-organizaciones .hubs-visible dt::after{animation:hubs-linea .7s var(--ease-out) .3s both}
  .hubs-page .hubs-cierre .hubs-visible .hubs-contacto{animation:hubs-boton .9s var(--ease-out) .15s backwards}
  .hubs-page .hubs-explore,.hubs-page .hubs-contacto{transition:transform .4s var(--ease-out),background-color var(--t-ui) var(--ease)}
  .hubs-page .hubs-explore:hover{background:var(--ink-100);transform:translateY(-5px) scale(1.03)}
  .hubs-page .hubs-contacto:hover{background:var(--ink-100);transform:translateY(-5px) scale(1.03)}
  .hubs-page .hubs-explore:active,.hubs-page .hubs-contacto:active{transform:scale(.96)}
  @supports (animation-timeline:view()){
    .hubs-page .hubs-arl img{animation:hubs-recorrido linear both;animation-timeline:view();animation-range:entry 0% exit 100%}
  }
  @media (hover:hover) and (pointer:fine){
    .hubs-page .hubs-fotos img{transition:transform .6s var(--ease-out)}
    .hubs-page .hubs-fotos figure:hover img{transform:translateY(-8px)}
  }
}
@keyframes hubs-entrada{
  from{transform:translateY(40px)}
  to{transform:translateY(0)}
}
@keyframes hubs-palabra{
  from{transform:translateY(30px) rotate(2deg)}
  to{transform:translateY(0) rotate(0)}
}
@keyframes hubs-foto{
  from{transform:translateY(48px) scale(.96) rotate(-1deg)}
  to{transform:translateY(0) scale(1) rotate(0)}
}
@keyframes hubs-foto-inversa{
  from{transform:translateY(48px) scale(.96) rotate(1deg)}
  to{transform:translateY(0) scale(1) rotate(0)}
}
@keyframes hubs-boton{
  from{transform:translateY(20px) scale(.94)}
  65%{transform:translateY(-4px) scale(1.02)}
  to{transform:translateY(0) scale(1)}
}
@keyframes hubs-linea{
  from{transform:scaleX(0)}
  to{transform:scaleX(1)}
}
@keyframes hubs-recorrido{
  from{transform:translateY(18px)}
  to{transform:translateY(-18px)}
}
