@charset "UTF-8";
/* =========================================================================
   DescargasWindows — hoja de estilo única
   Identidad: blanco dominante + azul claro + azul marino, con degradados
   cianes de apoyo. Todo el color pasa por tokens: cambiar la marca es
   cambiar :root, no perseguir valores por el fichero.
   ========================================================================= */

/* ------------------------------------------------------------- tipografía */
/* Todas autoalojadas: cero peticiones a terceros (y por tanto nada que
   consentir en materia de cookies).
   DM Sans viene recortada al eje de peso 500-700, que es el único que usa el
   sitio: de 36 KB a 23 KB sin perder un solo glifo. Si algún día hace falta
   un peso fuera de ese rango, hay que regenerarla (ver CLAUDE.md). */
@font-face {
  font-family: 'DM Sans'; font-style: normal; font-weight: 500 700;
  font-display: swap; src: url('../fonts/dm-sans-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'DM Sans'; font-style: normal; font-weight: 500 700;
  font-display: swap; src: url('../fonts/dm-sans-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'JetBrains Mono'; font-style: normal; font-weight: 100 800;
  font-display: swap; src: url('../fonts/jetbrains-mono-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Source Sans 3 — la fuente del TEXTO. DM Sans es geométrica: distingue bien
   en titulares y en interfaz, pero cansa en párrafos largos. Source Sans es
   humanista y está diseñada para leer. El par geométrica/humanista es un
   contraste real, no dos sans que se parecen por accidente.
   Para español solo se descarga el subconjunto "latin" (~29 KB): las tildes y
   la eñe viven en U+00C0-U+00FF, dentro de ese rango. */
@font-face {
  font-family: 'Source Sans 3'; font-style: normal; font-weight: 300 700;
  font-display: swap; src: url('../fonts/source-sans-3-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Source Sans 3'; font-style: normal; font-weight: 300 700;
  font-display: swap; src: url('../fonts/source-sans-3-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ----------------------------------------------------------------- tokens
   Dos temas, una sola definición de cada uno. El script de arranque resuelve
   siempre data-tema a "claro" u "oscuro" ANTES de pintar (leyendo la
   preferencia guardada o, si no hay, la del sistema), así que aquí no hace
   falta repetir la paleta oscura dentro de un @media. Sin JS se queda en
   claro, que es la identidad de la marca.                                   */
:root,
:root[data-tema="claro"] {
  color-scheme: light;
  /* Superficies: el blanco manda. */
  --blanco:        #ffffff;
  --fondo:         #ffffff;
  --fondo-suave:   #f5f9ff;
  --fondo-tarjeta: #ffffff;
  --borde:         #dfe8f6;
  --borde-fuerte:  #c5d5ee;

  /* Azules de marca */
  --marino:        #0f2557;   /* titulares */
  --marino-hondo:  #0a1a3f;
  --azul:          #0369a1;   /* texto de enlace: 5,8:1 sobre blanco */
  --azul-claro:    #0ea5e9;   /* acento gráfico */
  --azul-cielo:    #38bdf8;
  --azul-bruma:    #e8f4fe;

  /* Cian de apoyo: el color del aro del Amazon Echo, que es lo que la gente
     asocia con Alexa. Sustituye al morado del motor original (venía de
     descargaswindows) y NO es un cambio de gusto: el logotipo del sitio ya es
     azul cian (#30a0f0) y el morado peleaba con él en la misma pantalla.
     El tono de texto es el oscuro (#0e7490, 5,3:1): el cian brillante solo
     vale como grafico. */
  --cian:        #0e7490;   /* 5,3:1 sobre blanco: vale como texto */
  --cian-claro:  #22d3ee;   /* solo gráfico, nunca texto sobre blanco */
  --cian-bruma:  #e2f8fd;

  /* Texto */
  /* Contrastes medidos sobre #ffffff. "tenue" se usa en fechas y metadatos a
     0,75rem: es texto normal para la WCAG, así que necesita 4,5:1 — por eso
     no es más claro de lo que parece que podría ser. */
  --texto:         #16233d;   /* 15,65:1 */
  --texto-suave:   #4a5a75;   /*  6,98:1 */
  --texto-tenue:   #65738b;   /*  4,80:1 */

  --degradado:     linear-gradient(120deg, var(--azul-claro), var(--cian));
  --degradado-sutil: linear-gradient(120deg, var(--azul-bruma), var(--cian-bruma));

  --sombra-s: 0 1px 2px rgba(15, 37, 87, .06), 0 2px 8px rgba(15, 37, 87, .04);
  --sombra-m: 0 4px 14px rgba(15, 37, 87, .08), 0 12px 32px rgba(15, 37, 87, .06);
  --sombra-l: 0 10px 40px rgba(15, 37, 87, .12);

  /* Proporción de TODAS las portadas del sitio: 1200x628, la misma que pide
     Open Graph. Las miniaturas usan este mismo valor, así que la tarjeta
     enseña exactamente el mismo encuadre que la vista previa de WhatsApp o
     Facebook y no se recorta nada. Una portada con otra proporción SÍ se
     recortaría: el estándar del sitio es 1200x628. */
  --proporcion-portada: 1200 / 628;

  --radio-s: 8px;
  --radio:   14px;
  --radio-l: 22px;

  /* Ancho del sitio. Ya NO es fijo. Medido antes de tocarlo: a 1920 el bloque
     seguia siendo 1160 y quedaban 380 px muertos a cada lado, y a 2560 eran
     700. Peor aun, el contenido era MAS ESTRECHO en pantalla grande que en
     pequena (768 px de columna a 1920 contra 789 a 1280), porque el hueco
     entre columnas si crecia con la ventana y se lo comia. Ahora casi la mitad
     de cada pixel que trae la pantalla va al contenido y el resto al margen,
     con tope en 1440: el rango que recomiendan las guias de maquetacion para
     el contenedor principal (1200-1440).
     Lo que NO crece es la PROSA: se queda en --ancho-lectura porque ya esta en
     76 caracteres, el techo del rango comodo (45-75, tope AAA de WCAG en 80).
     Lo que crece es todo lo demas: capturas, codigo, tablas y tarjetas. */
  --ancho: clamp(1160px, calc(1160px + (100vw - 1280px) * .45), 1440px);
  /* Aire a los lados. Único sitio donde se decide: lo usan el contenedor, el
     menú móvil y el aviso de borrador, así que TODO alinea por el mismo canto.
     Crece con la pantalla en vez de saltar en un breakpoint: 22 px en un móvil
     de 360 (antes 20, y el texto se sentía pegado al filo) y 40 en escritorio.
     Si se toca, hay que recalcular los `sizes` de lib/imagen.php.             */
  --margen-lateral: clamp(1.25rem, 1rem + 2vw, 2.5rem);
  /* Medida de lectura definida en CARACTERES, no en píxeles.
     32,3 veces el cuerpo = 72 caracteres por línea. El número NO está estimado:
     se cuenta carácter a carácter en el navegador (herramientas/medir-medida.py)
     detectando el salto de renglón por el cambio de `top`. Estimarlo con "el
     ancho medio de un carácter es medio em" daba 65 y eran 80: el error que
     llevaba el comentario viejo de este mismo token.
     72 está dentro del rango cómodo (45-75) y aprovecha pantalla sin llegar al
     tope. Al derivarse del cuerpo, la medida NO PUEDE desajustarse: si el
     cuerpo crece en una pantalla grande, la columna crece con él y el recuento
     de caracteres se queda clavado.
     OJO: esto es el ancho del TEXTO. Donde el bloque además lleva el relleno
     del contenedor, se usa --caja-lectura, que se lo suma. */
  --ancho-lectura: calc(var(--t-2) * 32.3);
  --caja-lectura:  calc(var(--ancho-lectura) + 2 * var(--margen-lateral));

  --fuente:        'Source Sans 3', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --fuente-titulo: 'DM Sans', var(--fuente);
  --mono:          'JetBrains Mono', ui-monospace, 'Cascadia Code', monospace;

  /* Escala tipográfica modular (razón ~1,2), fluida entre móvil y escritorio.
     Tener la escala en tokens evita el goteo de tamaños inventados sobre la
     marcha, que es lo que hace que un sitio parezca descuidado. */
  --t--1: .8125rem;                          /* metadatos, cintillos          */
  --t-0:  .9375rem;                          /* interfaz, textos secundarios  */
  --t-1:  1.0625rem;                         /* base de interfaz              */
  /* CUERPO de artículo. Crece de 18 px a 20 px entre un portátil pequeño y una
     pantalla grande: no es capricho, una pantalla de 1920 se mira desde más
     lejos. Es también la mitad de la respuesta a "se ve muy fino en el PC" —
     como la medida se calcula de aquí, la columna pasa de 672 a 747 px sin
     tocar los 65 caracteres por línea. La otra mitad es el índice lateral. */
  --t-2:  clamp(1.125rem, 1.05rem + .22vw, 1.25rem);
  --t-3:  clamp(1.15rem, 1.05rem + .5vw, 1.3rem);
  --t-4:  clamp(1.35rem, 1.15rem + 1vw, 1.6rem);
  --t-5:  clamp(1.6rem, 1.25rem + 1.7vw, 2.1rem);
  --t-6:  clamp(1.9rem, 1.35rem + 2.7vw, 2.9rem);
  --t-7:  clamp(2.2rem, 1.4rem + 4vw, 3.6rem);

  --interlineado-texto: 1.7;
  --interlineado-corto: 1.28;                /* titulares y títulos de tarjeta */

  --transicion: .18s ease;
}

/* Tema oscuro. Solo se redefinen tokens: ninguna regla de más abajo sabe que
   existe. Contrastes medidos sobre #0b1220 — texto 16,04:1, suave 9,30:1,
   tenue 6,24:1, enlaces 11,23:1, titulares 15,11:1. Todos AAA. */
:root[data-tema="oscuro"] {
  color-scheme: dark;

  --blanco:        #0d1526;
  --fondo:         #0b1220;
  --fondo-suave:   #101a2e;
  --fondo-tarjeta: #101a2e;
  --borde:         #1e2c47;
  --borde-fuerte:  #2c3d5e;

  --marino:        #dbe8fb;
  --marino-hondo:  #f0f6ff;
  --azul:          #7dd3fc;
  --azul-claro:    #38bdf8;
  --azul-cielo:    #7dd3fc;
  --azul-bruma:    #12243d;

  --cian:        #7dd3fc;
  --cian-claro:  #bae6fd;
  --cian-bruma:  #10222e;

  --texto:         #e6eefb;
  --texto-suave:   #a8b8d0;
  --texto-tenue:   #8496b3;

  --degradado:       linear-gradient(120deg, #38bdf8, #a78bfa);
  --degradado-sutil: linear-gradient(120deg, #12243d, #1d1934);

  --sombra-s: 0 1px 2px rgba(0, 0, 0, .4);
  --sombra-m: 0 4px 14px rgba(0, 0, 0, .45);
  --sombra-l: 0 10px 40px rgba(0, 0, 0, .5);
}

/* El pie es azul marino en claro; en oscuro se separa del fondo con un borde
   porque si no, se funde con la página. */
:root[data-tema="oscuro"] .pie { background: var(--fondo-suave); border-top: 1px solid var(--borde); }
:root[data-tema="oscuro"] .pie__lista a,
:root[data-tema="oscuro"] .pie__claim { color: var(--texto-suave); }
:root[data-tema="oscuro"] .pie__legal { color: var(--texto-tenue); }
:root[data-tema="oscuro"] .tabla-scroll thead th { background: var(--fondo-suave); color: var(--marino); }
:root[data-tema="oscuro"] .boton--primario { color: #0b1220; }
:root[data-tema="oscuro"] .etiqueta-afiliado { background: #3a2a12; color: #fbd38d; border-color: #6b4d1c; }

/* ------------------------------------------------------------------ reset */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}
body {
  font-family: var(--fuente);
  font-size: var(--t-1);
  color: var(--texto);
  background: var(--fondo);
  line-height: var(--interlineado-texto);
  font-optical-sizing: auto;
  /* Ligaduras y kerning explícitos: Source Sans trae buen kerning para las
     combinaciones que abundan en español (Vo, Ta, "¿A"). */
  font-feature-settings: 'kern' 1, 'liga' 1;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
img, svg, video { display: block; max-width: 100%; height: auto; }
/* <picture> es solo el envoltorio que elige el formato: no debe generar caja
   propia ni interponerse entre la <img> y su contenedor (si no, reglas como
   ".tarjeta__imagen img { height: 100% }" dejan de tener a quién referirse). */
picture { display: contents; }
/* …pero eso tiene una consecuencia que no se ve venir: al no generar caja, los
   <source> del <picture> pasan a ser hijos directos del contenedor de verdad, y
   en un flex o un grid CUENTAN como elemento aunque no pinten nada — cada uno
   se lleva su hueco (gap). Es lo que empujaba el logotipo 9,6 px a la derecha
   del canto de la página, y el motivo de que la cabecera no alineara con nada.
   El navegador no le da `display: none` de serie: hay que ponérselo. */
source { display: none; }
/* Rutas del registro (HKEY_LOCAL_MACHINE\SYSTEM\...), nombres de fichero y
   URLs largas: sin esto empujan el ancho de toda la página en el móvil. */
p, li, td, th, h1, h2, h3, h4, dd, dt, blockquote, figcaption { overflow-wrap: break-word; }
code { overflow-wrap: anywhere; }
a { color: var(--azul); text-underline-offset: 3px; }
h1, h2, h3, h4 {
  font-family: var(--fuente-titulo);
  color: var(--marino);
  line-height: var(--interlineado-corto);
  letter-spacing: -.021em;      /* DM Sans va suelta de serie en tamaños grandes */
  text-wrap: balance;
  font-weight: 700;
}
:focus-visible { outline: 3px solid var(--azul-claro); outline-offset: 3px; border-radius: 4px; }

.contenedor { width: 100%; max-width: var(--ancho); margin-inline: auto; padding-inline: var(--margen-lateral); }

.saltar {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  background: var(--marino); color: #fff; padding: .75rem 1.25rem; border-radius: 0 0 var(--radio-s) 0;
}
.saltar:focus { left: 0; }

/* ------------------------------------------------------- aviso de borrador */
.aviso-borrador {
  background: var(--degradado); color: #fff;
  font-size: .8125rem; text-align: center; padding: .5rem var(--margen-lateral);
}
.aviso-borrador a { color: #fff; font-weight: 600; }
/* El aviso de conflicto de URL usa rojo plano y no el degradado de marca: es un
   error que hay que arreglar, no un cintillo informativo más. */
.aviso-borrador--alerta { background: #b91c1c; }

/* --------------------------------------------------------------- cabecera */
.cabecera {
  position: sticky; top: 0; z-index: 100;
  background: color-mix(in srgb, var(--fondo) 88%, transparent);
  backdrop-filter: saturate(1.6) blur(12px);
  border-bottom: 1px solid var(--borde);
}
.cabecera__fila { display: flex; align-items: center; gap: 1.5rem; min-height: 68px; }

.marca { display: inline-flex; align-items: center; gap: .6rem; text-decoration: none; flex: 0 0 auto; }
/* Logotipo del sitio. Tamaño fijo en píxeles y no en rem a propósito: no debe
   crecer si el visitante agranda el texto del navegador, o desplaza el menú.
   El width/height del HTML es el del fichero, así que aquí hacen falta los dos
   ejes para que no reserve un hueco enorme antes de aplicar el CSS.

   AQUÍ NO VA EL NOMBRE AL LADO, al revés que en descargaswindows: el logotipo
   de AlexaESP ya es la marca denominativa (lleva la palabra dentro), y ponerla
   otra vez la escribía dos veces en la misma línea. Por eso tampoco es
   cuadrado: se respeta su proporción real, 406x183, o el navegador lo aplasta. */
.marca__logo {
  width: 92px; height: 41px; flex: 0 0 auto;
  object-fit: contain;
}
/* En oscuro la mitad izquierda del logotipo es negra sobre transparente y
   desaparece. Se aclara con un filtro en vez de mantener dos ficheros: así el
   día que cambie el logotipo solo hay uno que cambiar. */
:root[data-tema="oscuro"] .marca__logo { filter: invert(1) hue-rotate(180deg) brightness(1.15); }
/* El pie es de fondo oscuro en los DOS temas, asi que ahi el filtro va siempre
   y no depende de data-tema. */
.pie .marca__logo { filter: invert(1) hue-rotate(180deg) brightness(1.15); }

/* Los ajustes de móvil van DESPUÉS de las reglas base, no antes: tienen la
   misma especificidad, así que gana la última que aparece en el fichero. Antes
   estaban arriba y no llegaban a aplicarse nunca — la cabecera se salía 15 px
   a 320 px y el botón de menú quedaba cortado. */
@media (max-width: 30rem) {
  .cabecera__fila { gap: .5rem; }
  .marca { min-width: 0; }                      /* puede encogerse dentro del flex */
  .marca__logo { width: 76px; height: 34px; }
}
/* A 320 px (el móvil pequeño que todavía existe) la fila de la cabecera (el
   logotipo y los tres botones) no cabe: se pasaba 15 px y el botón de menú
   quedaba cortado. Aquí se encoge lo justo. */
@media (max-width: 22.5rem) {
  .marca { gap: .4rem; }
  .marca__logo { width: 64px; height: 29px; }
}


.menu { margin-left: auto; }
/* El hueco y el relleno son ajustados a propósito: con «Guías» delante, a
   1024 px la barra iba a 597 de 1024 y se comía el botón de tema. Medido con
   herramientas/comprobar-menu.py, que es quien vigila que no vuelva a pasar. */
.menu__lista { display: flex; align-items: center; gap: .1rem; list-style: none; padding: 0; }
.menu__lista a {
  display: block; padding: .45rem .62rem; border-radius: 999px;
  color: var(--texto-suave); text-decoration: none; font-size: .9375rem; font-weight: 600;
  transition: color var(--transicion), background var(--transicion);
}
.menu__lista a:hover { color: var(--azul); background: var(--azul-bruma); }
/* «Guías» es el índice de todo, no un tema más: va en el color del texto y
   separada por una raya. Sin esa jerarquía se lee como una quinta categoría. */
.menu__indice { color: var(--texto); }
.menu__separa {
  margin-right: .45rem; padding-right: .55rem; border-right: 1px solid var(--borde);
}

/* Salida al final del artículo: el enlace al tema entero. Es un botón, no un
   enlace de texto, porque compite con el pie de página y tiene que ganarle. */
/* El titular ocupaba tres renglones en un portátil. Baja el tope y se aprieta
   el interlineado: sigue mandando sin comerse la primera pantalla. */
.articulo__titulo { font-size: clamp(2rem, 3.4vw, 2.85rem); letter-spacing: -.022em; }

.relacionados__salida {
  display: inline-flex; align-items: center; gap: .5rem; margin-top: 1.5rem;
  padding: .7rem 1.25rem; border-radius: 999px;
  border: 1px solid var(--borde); background: var(--fondo-tarjeta);
  color: var(--texto); text-decoration: none; font-weight: 600;
  transition: border-color var(--transicion), color var(--transicion);
}
.relacionados__salida:hover, .relacionados__salida:focus-visible {
  border-color: var(--azul-claro); color: var(--azul);
}

/* ------------------------------------------------- portada «revista» */
/* Diseño elegido por Jonatan el 2026-08-22. La anterior gastaba media pantalla
   en un eslogan y ponía cuatro tarjetas de tema enormes en tres columnas, con
   una huérfana. Aquí: dos líneas, temas en pastilla, un destacado con
   jerarquía y dos bloques cortos. De 3.729 px de alto a ~2.300. */
.portada-intro { padding-block: 2.25rem .25rem; }
.portada-intro__titulo {
  font-size: clamp(1.9rem, 4.4vw, 3rem); line-height: var(--interlineado-corto);
  letter-spacing: -.02em; margin: .7rem 0 .55rem; max-width: 22ch;
}
.portada-intro__texto { color: var(--texto-suave); font-size: var(--t-1); max-width: 62ch; }

/* Las secciones de la portada respiran menos que las de un artículo: aquí se
   escanea, no se lee. */
.seccion--apretada { padding-block: 1.75rem; }
.fila-titulo {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: .5rem 1rem; margin-bottom: 1.1rem;
}
.fila-titulo .seccion__titulo { margin-bottom: 0; }
.fila-titulo__mas {
  color: var(--azul); text-decoration: none; font-weight: 600; font-size: .9375rem;
}
.fila-titulo__mas:hover { text-decoration: underline; }

/* El destacado. Imagen y texto a dos columnas desde 52rem; por debajo se apila
   y se comporta como una tarjeta normal, que en el móvil es lo único que cabe. */
.destacado {
  display: grid; grid-template-columns: 1fr; text-decoration: none;
  border: 1px solid var(--borde); border-radius: var(--radio); overflow: hidden;
  background: var(--fondo-tarjeta);
  transition: border-color var(--transicion), transform .12s ease;
}
.destacado:hover { border-color: var(--azul-claro); transform: translateY(-2px); }
.destacado:hover .destacado__titulo { color: var(--azul); }
@media (min-width: 52rem) { .destacado { grid-template-columns: 1.15fr 1fr; } }
.destacado__imagen { display: block; aspect-ratio: var(--proporcion-portada); overflow: hidden; }
.destacado__imagen img { width: 100%; height: 100%; object-fit: cover; display: block; }
@media (min-width: 52rem) {
  .destacado__imagen { aspect-ratio: auto; height: 100%; }
}
.destacado__cuerpo {
  display: flex; flex-direction: column; justify-content: center; gap: .6rem;
  padding: clamp(1.25rem, 3vw, 2rem);
}
.destacado__cat {
  font-size: .6875rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--cian);
}
.destacado__titulo {
  font-family: var(--fuente-titulo); font-weight: 700; color: var(--marino);
  font-size: var(--t-4); line-height: var(--interlineado-corto); letter-spacing: -.015em;
  transition: color var(--transicion);
}
.destacado__resumen { color: var(--texto-suave); }
.destacado__meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: .2rem .7rem;
  font-size: var(--t--1); color: var(--texto-tenue); font-weight: 500;
  font-variant-numeric: tabular-nums;
}

/* «Y también»: el resto de guías como lista de enlaces. Cuatro líneas y la
   portada —la página con más fuerza del sitio— sigue enlazando a todo. */
.seccion__titulo--menor { font-size: var(--t-2); }
.lista-simple { list-style: none; padding: 0; display: grid; gap: .1rem; }
.lista-simple li {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .4rem .8rem;
  padding: .6rem 0; border-bottom: 1px solid var(--borde);
}
.lista-simple a {
  font-family: var(--fuente-titulo); font-weight: 600; color: var(--marino);
  text-decoration: none;
}
.lista-simple a:hover { color: var(--azul); text-decoration: underline; }
.lista-simple__meta { color: var(--texto-tenue); font-size: var(--t--1); }

.filtro--todo { border-style: dashed; }

/* ------------------------------------------------------ filtros por tema */
/* Enlaces de verdad a las categorías, no un filtro de JavaScript: cada tema es
   una página con su propio texto y su propia URL. Y el número no es adorno: un
   enlace que no dice cuánto hay detrás es una puerta cerrada. */
.filtros {
  display: flex; flex-wrap: wrap; align-items: center; gap: .6rem;
  margin-top: 1.5rem;
}
.filtros__etiqueta {
  font-size: .75rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--texto-tenue);
}
.filtros__lista { display: flex; flex-wrap: wrap; gap: .5rem; list-style: none; padding: 0; margin: 0; }
.filtro {
  display: inline-flex; align-items: center; gap: .45rem;
  padding: .42rem .8rem; border-radius: 999px;
  border: 1px solid var(--borde); background: var(--fondo-tarjeta);
  color: var(--texto); text-decoration: none; font-size: .9375rem; font-weight: 600;
  transition: border-color var(--transicion), color var(--transicion), background var(--transicion);
}
.filtro:hover, .filtro:focus-visible { border-color: var(--azul-claro); color: var(--azul); }
.filtro__n {
  display: inline-grid; place-items: center; min-width: 1.55em; height: 1.55em;
  padding: 0 .35em; border-radius: 999px;
  background: var(--azul-bruma); color: var(--azul);
  font-size: .8125rem; font-variant-numeric: tabular-nums;
}

/* Atajo a los grupos de Telegram, junto al interruptor de tema. Solo en
   escritorio: en el móvil ya está en el menú desplegable y aquí no cabría. */
.atajo-tg {
  display: none; place-items: center; width: 44px; height: 44px; flex: 0 0 auto;
  border: 1px solid var(--borde); border-radius: 12px;
  color: var(--texto-suave); background: none;
  transition: color var(--transicion), border-color var(--transicion);
}
.atajo-tg svg { width: 21px; height: 21px; }
.atajo-tg:hover { color: var(--azul); border-color: var(--azul-claro); }
@media (min-width: 62.01rem) { .atajo-tg { display: grid; } }

/* Interruptor de tema. Se muestran sol y luna en el mismo hueco y solo se ve
   el que toca, así el botón nunca cambia de tamaño al pulsarlo. */
.tema {
  display: grid; place-items: center; width: 44px; height: 44px; flex: 0 0 auto;
  padding: 0; background: none; border: 1px solid var(--borde);
  border-radius: var(--radio-s); cursor: pointer; color: var(--texto-suave);
  transition: color var(--transicion), border-color var(--transicion), background var(--transicion);
}
.tema:hover { color: var(--azul); border-color: var(--azul-claro); background: var(--azul-bruma); }
.tema[hidden] { display: none; }
.tema svg {
  grid-area: 1 / 1; width: 20px; height: 20px;
  fill: none; stroke: currentColor; stroke-width: 1.9;
  stroke-linecap: round; stroke-linejoin: round;
}
.tema__luna { fill: currentColor; stroke: none; }
:root[data-tema="claro"] .tema__sol   { display: none; }   /* en claro ofrecemos ir a oscuro */
:root[data-tema="oscuro"] .tema__luna { display: none; }

.menu__boton {
  display: none; width: 44px; height: 44px; padding: 10px;
  background: none; border: 1px solid var(--borde); border-radius: var(--radio-s); cursor: pointer;
}
.menu__boton span { display: block; height: 2px; background: var(--marino); border-radius: 2px; margin: 4px 0; transition: var(--transicion); }
.menu__boton[aria-expanded="true"] span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.menu__boton[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.menu__boton[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

.menu-movil { display: none; flex-direction: column; border-top: 1px solid var(--borde); background: var(--fondo); }
.menu-movil a {
  padding: .9rem var(--margen-lateral); color: var(--texto); text-decoration: none;
  font-weight: 500; border-bottom: 1px solid var(--borde);
}
.menu-movil a:last-child { border-bottom: none; }

@media (max-width: 62rem) {
  .menu { display: none; }
  /* Sin el nav, es el interruptor quien empuja el grupo a la derecha. */
  .tema:not([hidden]) { margin-left: auto; }
  .menu__boton { display: block; }
  .menu-movil:not([hidden]) { display: flex; }
}

/* ------------------------------------------------------------------- hero */
.hero { position: relative; overflow: hidden; background: var(--degradado-sutil); border-bottom: 1px solid var(--borde); }
.hero::after {
  content: ''; position: absolute; inset: auto -10% -60% 40%; height: 22rem;
  background: radial-gradient(closest-side, rgba(124, 58, 237, .18), transparent 70%);
  pointer-events: none;
}
/* La caja del hero NO lleva max-width propio: es un .contenedor normal, así
   que su canto izquierdo cae en la misma vertical que el logotipo, que
   "Explora por versión" y que las tarjetas. Antes eran 54rem centradas y el
   hero aparecía metido 148 px respecto de todo lo demás — el desajuste que
   más se notaba en escritorio. Quien limita la medida es el TEXTO, no la caja. */
.hero__caja { position: relative; padding-block: clamp(3rem, 8vw, 5.5rem); }
.hero__titulo { font-size: var(--t-7); letter-spacing: -.032em; margin-bottom: 1rem; max-width: 20ch; }
.degradado { background: var(--degradado); -webkit-background-clip: text; background-clip: text; color: transparent; }
.hero__texto {
  font-size: var(--t-2); line-height: 1.65; color: var(--texto-suave);
  max-width: 40rem; text-wrap: pretty;
}
.hero__acciones { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 2rem; }

/* ---------------------------------------------------------------- botones */
.boton {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 48px; padding: .8rem 1.6rem; border-radius: 999px;
  font-weight: 600; font-size: 1rem; text-decoration: none;
  transition: transform .12s ease, box-shadow var(--transicion), background var(--transicion);
}
.boton--primario { background: var(--degradado); color: #fff; box-shadow: var(--sombra-m); }
.boton--primario:hover { transform: translateY(-2px); box-shadow: var(--sombra-l); }
.boton--secundario { background: var(--fondo-tarjeta); color: var(--marino); border: 1.5px solid var(--borde-fuerte); }
.boton--secundario:hover { border-color: var(--azul-claro); color: var(--azul); }
@media (prefers-reduced-motion: reduce) { .boton:hover { transform: none; } }

/* -------------------------------------------------------------- secciones */
.seccion { padding-block: clamp(2.5rem, 6vw, 4rem); }
.seccion__titulo { font-size: var(--t-5); margin-bottom: 1.75rem; }

.cintillo {
  display: inline-flex; align-items: center; gap: .5rem; margin-bottom: .75rem;
  font-size: .75rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--cian);
}
.cintillo__punto { width: 6px; height: 6px; border-radius: 50%; background: var(--degradado); flex: 0 0 auto; }
.cintillo--hero { color: var(--azul); }

/* ----------------------------------------------------- tarjetas categoría */
/* Misma pista mínima que .rejilla-posts a propósito: las dos rejillas de la
   portada rompen en el mismo sitio y comparten columna, así que la página
   tiene UNA retícula y no dos. Con 15rem salían cuatro columnas y la quinta
   categoría se quedaba sola en una fila con tres huecos. */
.rejilla-cats {
  list-style: none; padding: 0; display: grid; gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(min(19rem, 100%), 1fr));
}
.tarjeta-cat {
  display: flex; flex-direction: column; gap: .35rem; height: 100%;
  padding: 1.35rem; border: 1px solid var(--borde); border-radius: var(--radio);
  background: var(--fondo-tarjeta); text-decoration: none; box-shadow: var(--sombra-s);
  transition: border-color var(--transicion), transform .12s ease, box-shadow var(--transicion);
}
.tarjeta-cat:hover { border-color: var(--azul-claro); transform: translateY(-3px); box-shadow: var(--sombra-m); }
.tarjeta-cat__nombre {
  font-family: var(--fuente-titulo); font-weight: 700; font-size: var(--t-3);
  color: var(--marino); letter-spacing: -.018em;
}
.tarjeta-cat__desc { font-size: var(--t-0); line-height: 1.55; color: var(--texto-suave); flex: 1; }
.tarjeta-cat__n {
  font-size: var(--t--1); color: var(--cian); font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------- tarjetas posts */
.rejilla-posts {
  list-style: none; padding: 0; display: grid; gap: 1.5rem;
  grid-template-columns: repeat(auto-fill, minmax(min(19rem, 100%), 1fr));
}
/* TRES columnas fijas en cuanto caben (~1040 px de ventana), no auto-fill hasta
   el infinito. Con --ancho fluido, a partir de ~1700 px cabria una cuarta pista
   de 19rem y la portada se fragmentaba igual que cuando la pista era de 15rem:
   las cinco categorias salian 4+1 y la fila de «Empieza por aqui», que son
   tres, dejaba un hueco. Por debajo de 65rem manda el auto-fill: 1 y 2. */
@media (min-width: 65rem) {
  .rejilla-cats, .rejilla-posts { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.tarjeta { display: flex; }
/* Sin esto la paginacion NO oculta nada. `[hidden]` de la hoja del navegador
   es `display: none` con la misma especificidad que `.tarjeta`, y al ir esta
   despues, gana. El contador decia «1-6 de 18» y se veian las 18.
   (Heredado del motor de descargaswindows, donde pasa lo mismo.) */
.tarjeta[hidden] { display: none; }
.tarjeta__enlace {
  display: flex; flex-direction: column; width: 100%;
  background: var(--fondo-tarjeta); border: 1px solid var(--borde); border-radius: var(--radio);
  overflow: hidden; text-decoration: none; box-shadow: var(--sombra-s);
  transition: border-color var(--transicion), transform .12s ease, box-shadow var(--transicion);
}
.tarjeta__enlace:hover { border-color: var(--azul-claro); transform: translateY(-3px); box-shadow: var(--sombra-m); }
/* El hueco tiene la proporción EXACTA de las portadas (1200x628), no 16/9: con
   16/9 el `cover` se comía un 7 % por los lados y en la portada de "Descargar e
   instalar Windows 11" cortaba el "DVD" del título. El object-fit se queda como
   red de seguridad para una portada futura que no cumpla el estándar. */
.tarjeta__imagen {
  display: block; aspect-ratio: var(--proporcion-portada);
  overflow: hidden; background: var(--fondo-suave);
}
.tarjeta__imagen img { width: 100%; height: 100%; object-fit: cover; }
.tarjeta__cuerpo { display: flex; flex-direction: column; gap: .5rem; padding: 1.25rem; flex: 1; }
.tarjeta__cat {
  font-size: .6875rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--cian);
}
.tarjeta__titulo {
  font-family: var(--fuente-titulo); font-size: var(--t-3); font-weight: 700;
  color: var(--marino); line-height: var(--interlineado-corto);
  letter-spacing: -.018em; text-wrap: balance;
}
.tarjeta__resumen { font-size: var(--t-0); line-height: 1.6; color: var(--texto-suave); flex: 1; text-wrap: pretty; }
/* Fecha y tiempo de lectura, uno al lado del otro y con permiso para partir en
   dos líneas: en una tarjeta estrecha caben justos, y prefiero dos renglones
   claros a «5 min» a secas, que era lo que se leía como «publicado hace 5
   minutos». El punto de separación se fue con ellos: el icono ya separa. */
.tarjeta__meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: .2rem .7rem;
  font-size: var(--t--1); color: var(--texto-tenue); font-weight: 500;
  font-variant-numeric: tabular-nums;
}

/* Tiempo de lectura. El icono mide 1em y hereda el color, así que sigue al
   texto si cambia de tamaño o de tema. Ver tiempo_lectura() en lib/render.php,
   que explica por qué no es el emoji 📖. */
/* NO es inline-flex. La línea base de una caja inline-flex es la de su primer
   hijo, y aquí el primer hijo es un SVG: su «base» es el canto inferior, así
   que el grupo entero subía y el tiempo de lectura quedaba desalineado del
   resto de la línea. Con inline normal y el icono ajustado con
   `vertical-align`, el texto se apoya en la misma base que sus vecinos. */
.lectura { white-space: nowrap; }
/* `display: inline-block` a mano: la regla global `img, svg, video {display:
   block}` convertía este icono en bloque y partía la línea, dejándolo solo en
   su renglón y el texto en el siguiente. Ese era el desalineado de verdad. */
.lectura__icono {
  display: inline-block; width: 1.02em; height: 1.02em;
  vertical-align: -.16em; margin-right: .34em; opacity: .85;
}
.tarjeta__enlace:hover .tarjeta__titulo { color: var(--azul); }

/* ------------------------------------------------------- listados/cabecera */
.cabecera-listado { padding-block: 2.5rem 0; }
.cabecera-listado__texto { max-width: var(--ancho-lectura); }
/* Aquí vivía la cabecera de categoría a dos columnas, con la imagen a la
   derecha. Se quitó el 2026-08-22: parecía una tarjeta de artículo que no
   llevaba a ninguna parte y retrasaba los artículos de verdad. La imagen sigue
   siendo la og:image; ver plantillas/categoria.php. */
.categoria__entradilla { margin-top: 1.25rem; font-size: var(--t-2); }
.categoria__entradilla p { margin-bottom: 0; color: var(--texto-suave); text-wrap: pretty; }
/* Entradilla de categoría: hereda la tipografía de lectura de .articulo__cuerpo
   pero sin su relleno inferior de 3rem, que aquí dejaba un socavón entre el
   texto y las tarjetas. */
/* La entradilla hereda de .articulo__cuerpo la tipografía de lectura, pero NO
   su caja: en una página de categoría el canto lo marca el contenedor, igual
   que el H1 y las tarjetas. Así que la caja es la del contenedor y quien
   limita la medida es el TEXTO —los hijos—, no el bloque. Con la caja de
   lectura centrada, la entradilla flotaba en medio de la página; con el
   bloque pegado a la izquierda sin contenedor, se iba al filo. */
/* Selector compuesto y no `.categoria__intro` a secas: las dos clases pesan
   igual (0,1,0) y `.articulo__cuerpo` está más abajo en el fichero, así que
   ganaba ella y la entradilla seguía centrada. Con las dos clases juntas
   (0,2,0) el orden deja de importar. */
.articulo__cuerpo.categoria__intro {
  padding-block: 1.25rem 0;
  max-width: var(--ancho);
}
.categoria__intro > * { max-width: var(--ancho-lectura); }
/* Con una sola tarjeta, el aire de .seccion (hasta 4rem arriba) más el de la
   cabecera del listado dejaban media pantalla vacía antes del primer artículo.
   La sección de un listado arranca antes que una sección de la portada. */
.seccion--listado { padding-block: 1.75rem clamp(2.5rem, 6vw, 4rem); }
.titulo-listado { font-size: var(--t-6); margin-block: .5rem; }
.subtitulo-listado { color: var(--texto-suave); font-size: var(--t-2); max-width: 40rem; text-wrap: pretty; }
.vacio { color: var(--texto-suave); }

/* ------------------------------------------------------------------ migas */
.migas ol { display: flex; flex-wrap: wrap; gap: .4rem; list-style: none; padding: 0; font-size: .8125rem; }
.migas li + li::before { content: '/'; margin-right: .4rem; color: var(--texto-tenue); }
.migas a { color: var(--texto-suave); text-decoration: none; }
.migas a:hover { color: var(--azul); text-decoration: underline; }
.migas li[aria-current] span { color: var(--texto-tenue); }

/* -------------------------------------------------- barra de progreso */
.progreso { position: fixed; inset: 0 0 auto 0; height: 3px; z-index: 200; pointer-events: none; }
.progreso span { display: block; height: 100%; width: 0; background: var(--degradado); transition: width .08s linear; }

/* --------------------------------------------------------------- artículo */
.articulo__cabecera { padding-top: 2rem; max-width: var(--caja-lectura); }
.articulo__titulo { font-size: var(--t-6); margin-bottom: .85rem; }
.articulo__entradilla {
  font-size: var(--t-4); font-weight: 300; line-height: 1.5;
  color: var(--texto-suave); margin-bottom: 1.5rem; text-wrap: pretty;
}

.firma { display: flex; align-items: center; gap: .8rem; padding-block: 1.25rem; border-block: 1px solid var(--borde); }
/* El avatar es un ENVOLTORIO de la foto, no la foto: <picture> es
   display:contents y no puede recortar nada, así que el círculo y el recorte
   viven aquí y la <img> solo rellena. */
.firma__avatar {
  display: block; width: 42px; height: 42px; border-radius: 50%; overflow: hidden;
  flex: 0 0 auto; background: var(--degradado-sutil);
}
.retrato { width: 100%; height: 100%; object-fit: cover; display: block; }
/* `flex: 1` y no el tamaño del contenido: sin él la columna se quedaba en 315
   px de los 634 disponibles y la sublínea partía en tres renglones, dejando el
   icono del tiempo de lectura solo en el suyo. */
.firma__datos { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.firma__nombre { color: var(--marino); font-weight: 600; text-decoration: none; }
.firma__nombre:hover { color: var(--azul); }
/* Como en calculadorapro: sublínea corta, en la tipografía de titulares y algo
   más apagada. «Actualizado el 20 de agosto de 2026» ocupaba media línea para
   decir lo mismo que «act. 20 ago 2026». */
.firma__meta {
  font-family: var(--fuente-titulo); font-size: .8125rem; color: var(--texto-tenue);
  letter-spacing: .005em;
}
.firma__nombre { font-family: var(--fuente-titulo); font-weight: 700; }

.articulo__portada { max-width: var(--caja-lectura); margin-block: 2rem; }
.articulo__portada img { width: 100%; border-radius: var(--radio); border: 1px solid var(--borde); box-shadow: var(--sombra-m); }

.articulo__cuerpo {
  max-width: var(--caja-lectura); padding-block: 1.5rem 3rem;
  font-size: var(--t-2);                    /* el cuerpo manda: 1,125rem */
}

/* CONVENCIÓN — el contenedor de prosa va SIEMPRE dentro de :where().
   Las reglas de abajo dan estilo a etiquetas sueltas (p, ul, li, a, img…) que
   salen del Markdown y no llevan clase. Escritas como `.articulo__cuerpo li`
   pesarían (0,1,1) y le ganarían a CUALQUIER componente de una sola clase que
   se meta dentro: pasó con la lista de grupos de Telegram —las tarjetas
   quedaban 24 px metidas por la izquierda y el texto pegado al borde— y con el
   color del texto de los botones. Con :where() el contenedor aporta CERO
   especificidad, el selector queda en (0,0,1) y basta una clase para mandar.
   Regla práctica: dentro de este bloque, nunca subir la especificidad para
   ganar una pelea; si hace falta, es que el selector está mal escrito.        */
:where(.articulo__cuerpo) p {
  margin-bottom: 1.35rem; color: var(--texto);
  /* Evita que un párrafo termine en una palabra suelta colgando. */
  text-wrap: pretty;
}
/* Ritmo vertical: el espacio ANTES de un titular es grande y el de después
   pequeño, para que la cabecera se agrupe con su texto y no flote en medio. */
:where(.articulo__cuerpo) h2 {
  font-size: var(--t-5); margin: 3rem 0 1rem; padding-bottom: .5rem;
  border-bottom: 2px solid var(--borde); scroll-margin-top: 5.5rem;
}
:where(.articulo__cuerpo) h3 {
  font-size: var(--t-3); margin: 2.25rem 0 .6rem; scroll-margin-top: 5.5rem;
  color: var(--marino-hondo); letter-spacing: -.015em;
}
:where(.articulo__cuerpo) h2 + p, :where(.articulo__cuerpo) h3 + p,
:where(.articulo__cuerpo) h2 + ul, :where(.articulo__cuerpo) h2 + ol,
:where(.articulo__cuerpo) h3 + ul, :where(.articulo__cuerpo) h3 + ol { margin-top: 0; }
:where(.articulo__cuerpo) ul, :where(.articulo__cuerpo) ol:not(:where(.toc__lista)) { margin: 0 0 1.35rem; padding-left: 1.5rem; }
:where(.articulo__cuerpo) li { margin-bottom: .55rem; padding-left: .25rem; color: var(--texto); text-wrap: pretty; }
:where(.articulo__cuerpo) ol:not(:where(.toc__lista)) { counter-reset: paso; list-style: none; padding-left: 0; }
/* Pasos numerados: el número en su propia columna, alineado, para que un paso
   de tres líneas no rompa la sangría. Es lo que más se lee en este sitio. */
:where(.articulo__cuerpo) ol:not(:where(.toc__lista)) > li {
  counter-increment: paso; position: relative; padding-left: 2.4rem; margin-bottom: .85rem;
}
:where(.articulo__cuerpo) ol:not(:where(.toc__lista)) > li::before {
  content: counter(paso); position: absolute; left: 0; top: .1em;
  display: grid; place-items: center; width: 1.65rem; height: 1.65rem;
  background: var(--azul-bruma); color: var(--azul); border-radius: 50%;
  font-family: var(--fuente-titulo); font-size: .8125rem; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
:where(.articulo__cuerpo) ol:not(:where(.toc__lista)) ol { margin-top: .7rem; }
:where(.articulo__cuerpo) li::marker { color: var(--azul-claro); font-weight: 700; }
:where(.articulo__cuerpo) strong { color: var(--marino-hondo); font-weight: 700; }
:where(.articulo__cuerpo) a { color: var(--azul); font-weight: 500; text-decoration: underline; text-decoration-thickness: 1.5px; text-decoration-color: color-mix(in srgb, var(--azul) 40%, transparent); }
:where(.articulo__cuerpo) a:hover { text-decoration-color: var(--azul); }
:where(.articulo__cuerpo) img { margin: 1.5rem auto; border-radius: var(--radio-s); border: 1px solid var(--borde); box-shadow: var(--sombra-s); }
:where(.articulo__cuerpo) li img { margin: .85rem 0; }

/* Imagen CON pie. Solo la llevan las que aportan algo por sí mismas: en el
   .md se escribe ![alt](ruta "pie"). El margen pasa a la <figure> para que el
   pie quede pegado a su imagen y no flotando entre las dos. */
:where(.articulo__cuerpo) .figura { margin: 1.75rem 0; }
:where(.articulo__cuerpo) .figura img { margin: 0; }
/* A ras del canto izquierdo de su imagen. Antes llevaba un filete de 2 px y
   0,7rem de sangría: el filete casi no se veía en claro y a cambio el pie
   quedaba descolgado respecto de la foto y del texto. Lo que lo distingue del
   cuerpo es que es más pequeño y más tenue, que ya basta. */
:where(.articulo__cuerpo) .figura figcaption {
  margin-top: .6rem;
  font-size: var(--t--1); line-height: 1.5; color: var(--texto-tenue);
}
:where(.articulo__cuerpo) li .figura { margin: .85rem 0; }

:where(.articulo__cuerpo) blockquote {
  margin: 1.75rem 0; padding: 1.1rem 1.35rem;
  background: var(--azul-bruma); border: 1px solid var(--borde);
  border-left: 4px solid var(--azul-claro); border-radius: 0 var(--radio-s) var(--radio-s) 0;
}
:where(.articulo__cuerpo) blockquote p:last-child { margin-bottom: 0; }
:where(.articulo__cuerpo) blockquote p { color: var(--texto-suave); }

:where(.articulo__cuerpo) code {
  font-family: var(--mono); font-size: .875em; background: var(--fondo-suave);
  border: 1px solid var(--borde); padding: .12em .4em; border-radius: 5px; color: var(--cian);
}
/* Bloques de código. El sitio no tenía ninguno hasta el artículo de Impr Pant,
   y sin estas reglas una orden larga empujaba el ancho de la página entera:
   `comprobar-movil.py` lo cazó a 768 px con 272 px de desbordamiento.
   La orden NO se parte en varias líneas: se copia de una pieza o no sirve. Por
   eso scrolla en horizontal, igual que una tabla ancha. */
:where(.articulo__cuerpo) pre {
  margin-block: 1.75rem; padding: 1rem 1.1rem;
  background: var(--fondo-suave); border: 1px solid var(--borde);
  border-radius: var(--radio-s);
  overflow-x: auto; -webkit-overflow-scrolling: touch;
}
:where(.articulo__cuerpo) pre code {
  display: block; font-size: .8125rem; line-height: 1.6;
  background: none; border: none; padding: 0; border-radius: 0;
  color: var(--texto); white-space: pre; overflow-wrap: normal;
}
:where(.articulo__cuerpo) pre:focus-visible { outline: 2px solid var(--azul); outline-offset: 2px; }

:where(.articulo__cuerpo) hr { border: none; height: 1px; background: var(--borde); margin-block: 2.5rem; }

/* Divulgación de afiliación. Ámbar a propósito: tiene que verse, no camuflarse
   con el texto. Contraste 6,4:1 sobre su fondo. */
.etiqueta-afiliado {
  display: inline-block; vertical-align: baseline; white-space: nowrap;
  font-size: .6875rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  padding: .08em .45em; border-radius: 5px;
  background: #fdf3d8; color: #7a5410; border: 1px solid #e8cf94;
}

/* ------------------------------------------------------------------ tablas */
.tabla-scroll {
  overflow-x: auto; margin-block: 1.75rem; border: 1px solid var(--borde);
  border-radius: var(--radio-s); -webkit-overflow-scrolling: touch;
}
.tabla-scroll table { width: 100%; border-collapse: collapse; font-size: .9375rem; }
.tabla-scroll th, .tabla-scroll td { padding: .7rem 1rem; text-align: left; border-bottom: 1px solid var(--borde); }
.tabla-scroll thead th {
  background: var(--marino); color: #fff; font-weight: 600; white-space: nowrap;
  font-size: .75rem; letter-spacing: .05em; text-transform: uppercase;
}
.tabla-scroll tbody th { color: var(--marino); font-weight: 600; background: var(--fondo-suave); }
.tabla-scroll tbody tr:last-child th, .tabla-scroll tbody tr:last-child td { border-bottom: none; }
.tabla-scroll tbody tr:hover th, .tabla-scroll tbody tr:hover td { background: var(--azul-bruma); }

/* En móvil cada fila se convierte en una tarjeta con su etiqueta delante
   (data-label lo pone el renderizador desde el <thead>). Una tabla de 3
   columnas es ilegible a 360px por mucho scroll horizontal que le pongas. */
@media (max-width: 40rem) {
  .tabla-scroll { border: none; overflow: visible; }
  .tabla-scroll table, .tabla-scroll tbody, .tabla-scroll tr, .tabla-scroll td, .tabla-scroll tbody th { display: block; width: auto; }
  .tabla-scroll thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .tabla-scroll tbody tr {
    background: var(--fondo-tarjeta); border: 1px solid var(--borde);
    border-radius: var(--radio-s); padding: .3rem 1rem .8rem; margin-bottom: 1rem; box-shadow: var(--sombra-s);
  }
  .tabla-scroll tbody th, .tabla-scroll td { border: none; padding: .5rem 0 0; background: none; }
  .tabla-scroll tbody th { font-size: 1.05rem; color: var(--azul); padding-top: .6rem; }
  .tabla-scroll td::before {
    content: attr(data-label); display: block; font-size: .6875rem; font-weight: 700;
    letter-spacing: .06em; text-transform: uppercase; color: var(--cian); margin-bottom: .1rem;
  }
  /* La primera celda es el asunto de la fila: hace de título de la tarjeta y no
     necesita que le repitan encima la cabecera de su columna. */
  .tabla-scroll td:first-child {
    font-family: var(--fuente-titulo); font-size: 1.05rem; font-weight: 700;
    color: var(--marino); padding: .2rem 0 .7rem; margin-bottom: .2rem;
    border-bottom: 1px solid var(--borde);
  }
  .tabla-scroll td:first-child::before { content: none; }
  .tabla-scroll td + td { border-top: 1px solid var(--borde); margin-top: .5rem; padding-top: .6rem; }
  .tabla-scroll td:nth-child(2) { border-top: none; margin-top: 0; }
}

/* --------------------------------------- artículo a dos columnas en pantalla
   El problema medido: la columna de lectura son 65-66 caracteres —la medida
   correcta, no se toca— pero a 1920 px eso deja el 65 % de la pantalla vacío.
   La solución no es ensanchar el texto (a 100 caracteres se lee peor), sino
   darle al hueco un trabajo: el índice se muda ahí y se queda pegado mientras
   se baja. En un sitio de tutoriales por pasos es justo lo que hace falta, y
   además quita del principio del artículo un bloque que retrasaba el texto.

   El umbral son 72rem porque es donde caben las dos columnas: a 1152 px la
   medida son 722 px y al índice le quedan 240 mínimos con hueco de sobra.
   `space-between` y no `center`: así el canto izquierdo del artículo cae en la
   misma vertical que el logotipo y el pie, y el derecho también.               */
@media (min-width: 72rem) {
  /* :has() evita la columna fantasma en los artículos cortos, que no llevan
     índice (html_indice() lo omite con menos de 3 secciones). Si el navegador
     no lo soporta, se queda una columna vacía a la derecha: se degrada feo,
     no roto. */
  /* ÍNDICE A LA IZQUIERDA, como carril. Elegido por Jonatan el 2026-08-22
     sobre dos maquetas. Medido antes de tocar nada: a 1280 px el bloque son
     1160, el texto solo 634 y entre las dos columnas quedaban 206 px de hueco.
     La medida de lectura estaba bien —70 caracteres—; lo que sobraba era el
     aire, y con el índice a la derecha el texto quedaba escorado a un lado de
     la pantalla. Con el carril a la izquierda, el bloque de lectura se centra. */
  .articulo:has(.articulo__indice) {
    display: grid;
    grid-template-columns: 16rem minmax(0, 1fr);
    grid-template-rows: auto 1fr;      /* explícitas: sin ellas el índice no
                                          puede abarcar en alto su columna */
    column-gap: clamp(2.5rem, 4vw, 4.5rem);
    width: 100%; max-width: var(--ancho);
    margin-inline: auto; padding-inline: var(--margen-lateral);
  }
  /* La rejilla asume el papel de contenedor: los hijos sueltan el suyo o
     sumarían dos rellenos y dos anchos máximos. */
  .articulo:has(.articulo__indice) .articulo__previo,
  .articulo:has(.articulo__indice) .articulo__resto { grid-column: 2; min-width: 0; }
  .articulo:has(.articulo__indice) .articulo__previo > *,
  .articulo:has(.articulo__indice) .articulo__resto > * {
    max-width: none; margin-inline: 0; padding-inline: 0;
  }
  /* La PROSA se queda en su medida; el resto no. Una captura de un menú no es
     prosa: cuanto más grande, mejor se lee, y al lado hay sitio de sobra. */
  .articulo:has(.articulo__indice) .articulo__cabecera,
  .articulo:has(.articulo__indice) :where(.articulo__cuerpo) > :where(p, ul, ol, h2, h3, h4, blockquote, .desplegable) {
    max-width: var(--ancho-lectura);
  }
  /* El tope era 52rem (832) y la columna llega a 1032 con --ancho fluido: se
     quedaba corto y dejaba el hueco a la derecha que se veia en pantalla
     grande. 64rem (1024) es justo la columna a tope, asi que no sobra nada y
     sigue habiendo techo declarado. Todo alineado por el mismo canto izquierdo
     que la prosa: centrarlo separaria los bordes y se leeria como un fallo. */
  .articulo:has(.articulo__indice) :where(.articulo__cuerpo) :where(.figura, pre, .comparativa, .tabla-scroll, .comprar),
  .articulo:has(.articulo__indice) .articulo__portada,
  .articulo:has(.articulo__indice) .telegram__caja,
  .articulo:has(.articulo__indice) .relacionados {
    width: min(64rem, 100%); max-width: none;
  }
  .articulo:has(.articulo__indice) .articulo__indice {
    grid-area: 1 / 1 / -1 / 2;
    align-self: start;
    position: sticky; top: 5.5rem;     /* justo debajo de la cabecera pegajosa */
    padding-inline: 0; max-width: none; margin: 0;
    /* Un índice de quince entradas no puede tapar la pantalla: se desplaza él. */
    max-height: calc(100vh - 7rem); overflow-y: auto;
    /* El relleno y el margen negativo se anulan a la vista, pero le dan al
       punto de lectura sitio DENTRO de la caja. `overflow-y: auto` convierte
       esto en un contenedor de desplazamiento, y entonces el eje horizontal
       tampoco puede desbordar: sin este hueco, el punto salía cortado por la
       izquierda. */
    padding-left: 10px; margin-left: -10px;
  }
  /* El carril pierde la caja: con el índice pegado al texto, la tarjeta pesaba
     más que el propio índice. */
  .articulo:has(.articulo__indice) .articulo__indice .toc {
    border: none; background: none; padding: 0;
  }
  .articulo:has(.articulo__indice) .articulo__indice .toc__titulo { padding-left: .7rem; }
  .articulo:has(.articulo__indice) .toc__lista a { font-size: .875rem; }
  .articulo:has(.articulo__indice) .articulo__indice .toc { margin-bottom: 0; }
}


/* ---------------------------------------------------------------- comprar
   Caja de compra. El enlace de afiliado era antes una línea de texto azul con
   una etiqueta al lado, y en el móvil parecía spam: quien busca dónde comprar
   quiere un botón. El botón es <a>, no <button>: es navegación, no una acción
   del formulario, y así funciona el clic derecho, el "abrir en pestaña nueva"
   y el teclado sin escribir una línea de JS.

   La etiqueta de afiliado va DEBAJO del botón y no dentro: dentro se pierde
   contra el fondo azul y la divulgación tiene que verse. Con `order` se pinta
   después aunque en el HTML vaya donde va.                                  */
.comprar {
  margin: 2rem 0;
  padding: clamp(1rem, .6rem + 1.6vw, 1.5rem);
  background: var(--fondo-suave);
  border: 1px solid var(--borde);
  border-radius: 14px;
}
.comprar__titulo {
  font-family: var(--fuente-titular);
  font-weight: 600;
  font-size: var(--t-1);
  color: var(--marino);
  margin-bottom: .85rem;
}
.comprar__opciones {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1rem;
}
.comprar__opcion { display: flex; flex-direction: column; align-items: flex-start; gap: .4rem; }

/* Dos niveles a propósito: el recomendado va relleno y el resto con borde.
   Dos botones idénticos uno encima de otro no recomiendan nada, y el artículo
   sí tiene una recomendación. Se marca desde el .md poniendo el texto del
   enlace en negrita. */
.comprar__boton {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  width: 100%;
  /* Ancho máximo para que en el escritorio no salga una barra de lado a lado:
     un botón de 700 px no parece un botón, parece una cabecera. */
  max-width: 30rem;
  min-height: 3.25rem;              /* objetivo táctil holgado */
  padding: .85rem 1.15rem;
  background: transparent;
  color: var(--azul);
  border: 2px solid var(--borde-fuerte);
  font-weight: 600;
  font-size: var(--t-0);
  line-height: 1.3;
  text-decoration: none;
  border-radius: 10px;
  transition: transform .12s ease, box-shadow .12s ease,
              background-color .12s ease, border-color .12s ease;
}
.comprar__boton:hover,
.comprar__boton:focus-visible {
  border-color: var(--azul);
  background: var(--azul-bruma);
  box-shadow: var(--sombra-s);
  text-decoration: none;
}

.comprar__boton--principal {
  background: var(--azul);
  border-color: var(--azul);
  color: var(--blanco);
  font-size: var(--t-1);
  min-height: 3.5rem;
  box-shadow: var(--sombra-m);
}
.comprar__boton--principal:hover,
.comprar__boton--principal:focus-visible {
  background: var(--marino);
  border-color: var(--marino);
  box-shadow: var(--sombra-l);
  transform: translateY(-1px);
}

.comprar__texto { min-width: 0; }
.comprar__flecha { flex: none; font-size: 1.15em; }

/* La etiqueta de afiliado, aquí, en tono de nota y no de pegatina: sigue
   siendo visible y va junto al enlace, que es lo que exige la ley, pero sin
   gritar. La versión con recuadro se queda para los enlaces sueltos dentro
   del texto, donde sí hace falta que salte a la vista. */
.comprar__etiqueta {
  background: none;
  border: 0;
  padding: 0;
  margin-left: .15rem;
  text-transform: none;
  letter-spacing: 0;
  font-weight: 500;
  font-size: var(--t--1);
  /* "suave" y no "tenue": sobre el fondo de la caja, tenue se queda en 4,54:1
     y esto es una divulgación obligatoria, no un metadato. Con suave sube a
     casi 7:1 y se lee sin esfuerzo, que es justo lo que pide la norma. */
  color: var(--texto-suave);
}
:root[data-tema="oscuro"] .comprar__etiqueta { background: none; color: var(--texto-suave); }

.comprar__nota {
  margin-top: 1rem;
  font-size: var(--t--1);
  color: var(--texto-suave);
  line-height: 1.55;
}

/* En oscuro el azul de marca es CLARO: sobre un botón relleno de ese azul el
   texto tiene que ser oscuro, o no se lee. El secundario no se toca: ahí el
   azul es el texto, sobre el fondo de la página. */
:root[data-tema="oscuro"] .comprar__boton--principal { color: #08131f; }
:root[data-tema="oscuro"] .comprar__boton--principal:hover,
:root[data-tema="oscuro"] .comprar__boton--principal:focus-visible {
  background: var(--azul-cielo);
  border-color: var(--azul-cielo);
  color: #08131f;
}

/* -------------------------------------------------------- bloques ::: ---
   Desplegable. <details> nativo: sin JS, sin depender de nada, y el navegador
   ya sabe abrirlo con teclado. El contenido de dentro SÍ lo indexa Google
   (lleva años tratando lo plegable como contenido normal), así que aquí se
   pliega lo que estorba al que ya sabe, no lo que hay que esconder.          */
.desplegable {
  margin: 1.25rem 0; border: 1px solid var(--borde); border-radius: var(--radio);
  background: var(--fondo-tarjeta); overflow: hidden;
}
.desplegable__titulo {
  display: flex; align-items: center; gap: .6rem; cursor: pointer;
  padding: .85rem 1.1rem; list-style: none;
  font-family: var(--fuente-titulo); font-weight: 700; font-size: var(--t-1);
  color: var(--marino); line-height: var(--interlineado-corto);
}
.desplegable__titulo::-webkit-details-marker { display: none; }
/* La flecha se dibuja aquí y no con un carácter: así gira al abrir y no
   depende de qué emoji tenga instalado el sistema. */
.desplegable__titulo::before {
  content: ''; flex: 0 0 auto; width: .5rem; height: .5rem;
  border-right: 2px solid var(--azul-claro); border-bottom: 2px solid var(--azul-claro);
  transform: rotate(-45deg); transition: transform var(--transicion);
}
.desplegable[open] > .desplegable__titulo::before { transform: rotate(45deg); }
.desplegable__titulo:hover { color: var(--azul); background: var(--fondo-suave); }
.desplegable__cuerpo { padding: 0 1.1rem 1rem; font-size: var(--t-1); }
.desplegable__cuerpo > *:last-child { margin-bottom: 0; }

/* Gráfico comparativo. La rejilla de marcas se queda RESTRINGIDA en anchura a
   propósito: las columnas de "sí/no" no necesitan más de 2,75rem, y con eso
   una comparativa de cuatro ediciones entra en un móvil de 360 px. Antes esto
   era una tabla normal y en el móvil se convertía en una tarjeta por fila:
   cuarenta tarjetas seguidas para comparar dos ediciones. */
.comparativa { margin: 1.75rem 0; }
.comparativa__titulo {
  font-family: var(--fuente-titulo); font-weight: 700; font-size: var(--t-1);
  color: var(--marino); margin-bottom: .6rem;
}
.comparativa__caja {
  overflow-x: auto; border: 1px solid var(--borde); border-radius: var(--radio);
  background: var(--fondo-tarjeta); -webkit-overflow-scrolling: touch;
}
.comparativa table { width: 100%; border-collapse: collapse; font-size: .9375rem; }
.comparativa thead th {
  position: sticky; top: 0; z-index: 1;
  background: var(--fondo-suave); color: var(--marino);
  font-size: .75rem; letter-spacing: .04em; text-transform: uppercase;
  padding: .6rem .35rem; text-align: center;
  /* Sin `nowrap`: un rótulo de dos palabras como "IoT LTSC" forzaba su columna
     a ser más ancha de la cuenta. Y sin `overflow-wrap: anywhere`, que se probó
     y parte por donde le da la gana: "LibreOffice" salía como "LI-BREO-FFICE".
     Cuando un rótulo es una palabra larga, el corte se marca EN EL TEXTO con un
     guion suave (U+00AD) y así rompe por donde tiene sentido. */
  border-bottom: 1px solid var(--borde-fuerte);
}
/* padding-inline y no solo padding-left: si se toca un lado, el otro se queda
   con el valor de la regla de arriba y la celda sale descuadrada (lo cazó
   comprobar-alineacion.py con 14,4 px a la izquierda y 8 a la derecha). */
.comparativa thead th:first-child { text-align: left; padding-inline: .9rem; }
.comparativa tbody th {
  text-align: left; font-weight: 500; color: var(--texto);
  padding: .6rem .9rem; line-height: 1.35;
  /* El mínimo del rótulo es fluido: 8rem en cuanto hay sitio, pero nunca más
     del 30 % de la ventana. Con 8rem fijos, una comparativa de cuatro columnas
     empujaba la PÁGINA 4 px a lo ancho en un móvil de 320 —la caja no absorbía
     ese desbordamiento pese a tener overflow— y lo cazó el comprobador de
     móvil. Medido, no supuesto. */
  min-width: min(8rem, 30vw);
  /* Pegada al borde al desplazar: sin esto, al mirar la cuarta columna en un
     móvil ya no sabes de qué función estás leyendo el dato. */
  position: sticky; left: 0; background: var(--fondo-tarjeta);
}
/* La anchura estrecha vale solo para las celdas de marca: si se le mete texto
   a una columna, esa celda tiene que poder crecer. Antes `width` iba en todos
   los `td` y `--valor` llevaba además `nowrap`, así que una tabla de dos
   columnas con frases dentro se salía de la pantalla. El componente es para
   ✓/✗ y valores cortos; para texto, tabla normal. */
.comparativa td { padding: .6rem .25rem; text-align: center; }
.comparativa__celda--si, .comparativa__celda--no { width: 2.75rem; }
.comparativa tbody tr + tr th, .comparativa tbody tr + tr td { border-top: 1px solid var(--borde); }
.comparativa__celda--si  { color: #15803d; font-weight: 700; }
.comparativa__celda--no  { color: var(--texto-tenue); }
.comparativa__celda--valor { font-size: .8125rem; color: var(--texto-suave); }
:root[data-tema="oscuro"] .comparativa__celda--si { color: #4ade80; }
/* El rótulo de la fila viaja sobre las marcas al desplazar, así que necesita
   fondo opaco propio en los dos temas. */
:root[data-tema="oscuro"] .comparativa tbody th { background: var(--fondo-tarjeta); }

/* ------------------------------------------------------------------- índice */
.toc {
  background: var(--fondo-suave); border: 1px solid var(--borde);
  border-radius: var(--radio); padding: 1.15rem 1.4rem; margin-bottom: 2.25rem;
}
.toc__titulo {
  font-size: .6875rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--cian); margin-bottom: .5rem; border: none; padding: 0;
}
.toc__lista { list-style: none; margin: 0; padding: 0; counter-reset: toc; position: relative; }
/* Carril de progreso a la izquierda: el filete se enciende en las secciones por
   las que ya has pasado, así que la parte encendida ES cuánto llevas leído. Va
   en el <li> y no en un ::after medido con JS, porque así no hay que calcular
   píxeles ni se descuadra al cambiar el tamaño de la ventana. */
.toc__lista li {
  counter-increment: toc; margin: 0;
  border-left: 2px solid var(--borde); padding-left: .7rem;
  transition: border-color var(--transicion);
}
/* Tres estados, y el porqué de que sean tres: con uno solo el índice contesta
   "dónde estoy" pero no "cuánto me queda", que es la pregunta de quien llega
   por primera vez. Lo leído se apaga, lo actual se marca, lo pendiente espera. */
.toc__lista li[data-estado="leido"],
.toc__lista li[data-estado="actual"] { border-left-color: var(--azul-claro); }
.toc__lista li[data-estado="leido"] a { color: var(--texto-tenue); }
.toc__lista li[data-estado="leido"] a::before { color: var(--texto-tenue); opacity: .7; }
.toc__lista li[data-estado="actual"] a { color: var(--azul); font-weight: 600; }
.toc__lista li[data-estado="actual"] a::before { color: var(--azul); }
/* El punto de "estás aquí": un marcador sólido sobre el carril, que es lo que
   hace que la posición se lea sin comparar colores entre sí.
   Con JS, el punto lo pone `sitio.js` y se DESLIZA dentro del apartado según lo
   que llevas leído de él; este ::before es el respaldo para cuando no hay JS, y
   por eso se apaga en cuanto la lista se marca como viva. */
.toc__lista li[data-estado="actual"] {
  border-left-color: var(--azul); position: relative;
}
.toc__lista li[data-estado="actual"]::before {
  content: ''; position: absolute; left: -5px; top: 50%; width: 8px; height: 8px;
  margin-top: -4px; border-radius: 50%; background: var(--azul);
  box-shadow: 0 0 0 3px var(--fondo-suave);
}
.toc__lista--vivo li[data-estado="actual"]::before { content: none; }
.toc__punto {
  /* Centrado sobre el carril, medido: el carril es el borde izquierdo del <li>
     (2 px), así que su centro cae en x=1 y el punto —de 9— tiene que empezar en
     1 - 4,5 = -3,5. Con -5 quedaba 1,5 px a la izquierda, poco pero se ve. */
  position: absolute; left: -3.5px; top: 0; width: 9px; height: 9px;
  margin-top: -4.5px; border-radius: 50%; background: var(--azul);
  box-shadow: 0 0 0 3px var(--fondo-suave);
  opacity: 0; pointer-events: none;
  transition: transform .18s ease-out, opacity var(--transicion);
}
/* Quien pide menos movimiento no quiere un punto persiguiéndole por el carril:
   sigue marcando la posición, pero sin animar el salto. */
@media (prefers-reduced-motion: reduce) { .toc__punto { transition: none; } }
/* Flex y no `display: block`: con el número como ::before en línea, un título
   de dos renglones devolvía el segundo al margen izquierdo y quedaba debajo de
   la cifra. En columnas, el texto que envuelve cae bajo el texto — la misma
   sangría francesa que ya usan los pasos numerados del artículo. */
.toc__lista a {
  display: flex; gap: .6rem; align-items: baseline;
  padding: .42rem 0; font-size: .9375rem; color: var(--texto-suave);
  text-decoration: none;
  transition: color var(--transicion);
}
.toc__lista a::before {
  content: counter(toc, decimal-leading-zero); font-family: var(--mono); font-size: .8em;
  font-weight: 700; color: var(--azul-claro); flex: 0 0 auto;
}
.toc__lista a:hover { color: var(--azul); }
.toc__n3 a { padding-left: 1.5rem; font-size: .875rem; }

/* ------------------------------------------------------------------ catálogo
   Paginación de la portada. Las tarjetas están TODAS en el HTML —si no, la
   portada enlazaría a seis guías en vez de a once— y aquí solo se esconde lo
   que no toca. Sin JavaScript no se esconde nada y se ven las once seguidas. */
/* `[hidden]` lo pone el JS cuando solo hay una página, pero `display: flex`
   gana al `display: none` del navegador: hay que decirlo a mano. */
.paginas { display: flex; align-items: center; gap: .6rem; }
.paginas[hidden] { display: none; }
.paginas__fl {
  display: grid; place-items: center; width: 34px; height: 34px; padding: 0;
  border: 1px solid var(--borde); border-radius: 9px; background: var(--fondo-tarjeta);
  color: var(--texto-suave); cursor: pointer;
  transition: color var(--transicion), border-color var(--transicion);
}
.paginas__fl svg { width: 16px; height: 16px; }
.paginas__fl:hover:not(:disabled) { color: var(--azul); border-color: var(--azul-claro); }
.paginas__fl:disabled { opacity: .35; cursor: default; }
.paginas__cuenta {
  font-size: .85rem; color: var(--texto-tenue); font-variant-numeric: tabular-nums;
  min-width: 6.5em; text-align: center;
}
.rejilla-vacia { color: var(--texto-suave); padding: 1.5rem 0; }
/* El filtro es un <button>, no un enlace: no navega, reordena lo que ya está. */
.filtro[aria-pressed="true"] {
  background: var(--azul); border-color: var(--azul); color: #fff;
}
.filtro[aria-pressed="true"] .filtro__n { background: rgba(255, 255, 255, .22); color: #fff; }
button.filtro { font-family: inherit; cursor: pointer; }

/* ----------------------------------------------------------------- compartir
   UN botón que abre un menú pequeño. Tres iconos siempre a la vista ocupaban
   una banda entera para algo que casi nadie pulsa, y competían con el titular
   justo donde hay que empezar a leer. */
.compartir { position: relative; margin-top: 1rem; }
.compartir__abrir {
  display: inline-flex; align-items: center; gap: .5rem;
  padding: .5rem .95rem; border: 1px solid var(--borde); border-radius: 999px;
  background: var(--fondo-tarjeta); color: var(--texto-suave);
  font-family: var(--fuente-titulo); font-weight: 600; font-size: .875rem; cursor: pointer;
  transition: color var(--transicion), border-color var(--transicion);
}
.compartir__abrir svg { width: 16px; height: 16px; }
.compartir__abrir:hover, .compartir__abrir[aria-expanded="true"] {
  color: var(--azul); border-color: var(--azul-claro);
}
.compartir__menu {
  position: absolute; top: calc(100% + .45rem); left: 0; z-index: 20;
  min-width: 13rem; padding: .35rem;
  display: flex; flex-direction: column;
  border: 1px solid var(--borde); border-radius: var(--radio-s);
  background: var(--fondo-tarjeta); box-shadow: var(--sombra-m);
}
.compartir__menu[hidden] { display: none; }
.compartir__menu > * {
  display: flex; align-items: center; gap: .6rem; width: 100%;
  padding: .55rem .7rem; border: 0; border-radius: 8px; background: none;
  color: var(--texto); text-decoration: none; text-align: left;
  font: inherit; font-size: .9375rem; cursor: pointer;
}
.compartir__menu > *:hover { background: var(--azul-bruma); color: var(--azul); }
.compartir__menu svg { width: 17px; height: 17px; flex: none; }

/* ------------------------------------------------------------------ telegram
   Banda de los grupos. Está en la portada y al final de cada artículo porque en
   escritorio solo se veían en el pie, y son la página con más orgánico del sitio
   y lo único a lo que un lector puede volver: una guía se lee una vez. */
.telegram {
  display: grid; gap: 1.5rem; margin-block: 2rem;
  padding: clamp(1.4rem, 3vw, 2rem);
  border: 1px solid var(--borde); border-radius: var(--radio);
  background: linear-gradient(135deg,
              color-mix(in srgb, var(--azul-claro) 12%, var(--fondo-tarjeta)),
              var(--fondo-tarjeta) 60%);
}
@media (min-width: 52rem) { .telegram { grid-template-columns: 1fr 1.25fr; align-items: center; } }
.telegram__eco {
  font-size: .6875rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--cian); margin-bottom: .35rem;
}
.telegram__titulo {
  font-family: var(--fuente-titulo); font-size: var(--t-3); color: var(--marino);
  line-height: var(--interlineado-corto); margin-bottom: .5rem; border: none; padding: 0;
}
.telegram__resumen { color: var(--texto-suave); margin-bottom: .75rem; }
.telegram__mas { color: var(--azul); text-decoration: none; font-weight: 600; font-size: .9375rem; }
.telegram__mas:hover { text-decoration: underline; }
.telegram__grupos { list-style: none; margin: 0; padding: 0; display: grid; gap: .75rem; }
@media (min-width: 34rem) { .telegram__grupos { grid-template-columns: 1fr 1fr; } }
.telegram__grupo {
  display: grid; gap: .2rem; height: 100%; padding: 1rem 1.1rem;
  border: 1px solid var(--borde); border-radius: var(--radio-s);
  background: var(--fondo); text-decoration: none;
  transition: border-color var(--transicion), transform .12s ease;
}
.telegram__grupo:hover { border-color: var(--azul-claro); transform: translateY(-2px); }
.telegram__icono { color: var(--azul-claro); line-height: 0; margin-bottom: .15rem; }
.telegram__nombre { font-family: var(--fuente-titulo); font-weight: 700; color: var(--marino); }
.telegram__corto { color: var(--texto-suave); font-size: .9rem; }
.telegram__alias {
  color: var(--texto-tenue); font-size: .8125rem; font-family: var(--mono);
}
/* En el artículo la banda va dentro de la columna de lectura, no a todo lo ancho. */
.telegram__caja { max-width: var(--caja-lectura); }

/* ------------------------------------------------------------------ telegram
   Banda de los grupos. Está en la portada y al final de cada artículo porque en
   escritorio solo se veían en el pie, y son la página con más orgánico del sitio
   y lo único a lo que un lector puede volver: una guía se lee una vez.
   Sobria a propósito: un borde, un fondo apenas teñido y nada de color plano.
   Un banner llamativo al final de un tutorial ensucia y resta credibilidad. */
.telegram {
  display: grid; gap: 1.25rem; margin-block: 2rem;
  padding: clamp(1.2rem, 2.6vw, 1.6rem);
  border: 1px solid var(--borde); border-radius: var(--radio);
  background: color-mix(in srgb, var(--azul-claro) 6%, var(--fondo-tarjeta));
}
@media (min-width: 52rem) { .telegram { grid-template-columns: 1fr 1.15fr; align-items: center; } }
.telegram__eco {
  font-size: .6875rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--cian); margin-bottom: .3rem;
}
.telegram__titulo {
  font-family: var(--fuente-titulo); font-size: var(--t-2); color: var(--marino);
  line-height: var(--interlineado-corto); margin-bottom: .4rem; border: none; padding: 0;
}
.telegram__resumen { color: var(--texto-suave); font-size: .95rem; margin-bottom: .6rem; }
.telegram__mas { color: var(--azul); text-decoration: none; font-weight: 600; font-size: .9rem; }
.telegram__mas:hover { text-decoration: underline; }
.telegram__grupos { list-style: none; margin: 0; padding: 0; display: grid; gap: .7rem; }
@media (min-width: 34rem) { .telegram__grupos { grid-template-columns: 1fr 1fr; } }
.telegram__grupo {
  display: grid; gap: .15rem; height: 100%; padding: .9rem 1rem;
  border: 1px solid var(--borde); border-radius: var(--radio-s);
  background: var(--fondo); text-decoration: none;
  transition: border-color var(--transicion), transform .12s ease;
}
.telegram__grupo:hover { border-color: var(--azul-claro); transform: translateY(-2px); }
.telegram__icono { color: var(--azul-claro); line-height: 0; margin-bottom: .1rem; }
.telegram__nombre { font-family: var(--fuente-titulo); font-weight: 700; color: var(--marino); }
.telegram__corto { color: var(--texto-suave); font-size: .875rem; }
.telegram__alias { color: var(--texto-tenue); font-size: .8125rem; font-family: var(--mono); }
/* En el artículo la banda va dentro de la columna de lectura, no a todo lo ancho. */
.telegram__caja { max-width: var(--caja-lectura); }

/* -------------------------------------------------------------- relacionados */
.relacionados { max-width: var(--caja-lectura); padding-bottom: 4rem; }
.relacionados h2 { font-size: var(--t-4); margin-bottom: 1.15rem; padding-top: 2rem; border-top: 1px solid var(--borde); }
.relacionados ul { list-style: none; padding: 0; display: grid; gap: .75rem; }
/* `.relacionados ul a` y no `.relacionados a`: el enlace de salida del final
   NO está en la lista y con el selector suelto se lo comía —salía a todo lo
   ancho y con la flecha en otra línea—. Acotar el selector es la solución;
   subirle la especificidad al botón habría sido tapar el problema. */
.relacionados ul a {
  display: flex; flex-direction: column; gap: .25rem; padding: 1rem 1.2rem;
  background: var(--fondo-tarjeta); border: 1px solid var(--borde); border-radius: var(--radio);
  text-decoration: none; transition: border-color var(--transicion), transform .12s ease;
}
.relacionados ul a:hover { border-color: var(--azul-claro); transform: translateY(-2px); }
.relacionados__cat { font-size: .6875rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--cian); }
.relacionados__titulo {
  font-family: var(--fuente-titulo); color: var(--marino); font-weight: 700;
  font-size: var(--t-1); line-height: var(--interlineado-corto); letter-spacing: -.015em;
}
.relacionados__meta {
  font-size: var(--t--1); color: var(--texto-tenue); font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.relacionados a:hover .relacionados__titulo { color: var(--azul); }

/* ------------------------------------------------------------ ficha autor */
.ficha-autor {
  display: flex; align-items: center; gap: 1.25rem; margin-bottom: 2rem; padding: 1.25rem;
  background: var(--degradado-sutil); border: 1px solid var(--borde); border-radius: var(--radio);
  /* Envuelve en móvil: a 320 px la foto y el bloque de texto no caben en una
     fila sin que el nombre se parta letra a letra. */
  flex-wrap: wrap;
}
.ficha-autor__foto {
  display: block; width: 112px; height: 112px; border-radius: 50%; overflow: hidden;
  flex: 0 0 auto; box-shadow: 0 0 0 3px var(--fondo), 0 0 0 5px var(--azul);
}
.ficha-autor__datos { min-width: 0; }
.ficha-autor__nombre { font-weight: 700; font-size: 1.15rem; color: var(--marino); }
.ficha-autor__rol { font-size: .9375rem; color: var(--texto-suave); }
.ficha-autor__perfiles { display: flex; flex-wrap: wrap; gap: .25rem 1.1rem; margin-top: .5rem;
  font-size: .9375rem; font-weight: 600; }

/* ------------------------------------------------ caja de autor del artículo */
.caja-autor {
  display: flex; align-items: flex-start; gap: 1.25rem; flex-wrap: wrap;
  max-width: var(--caja-lectura); margin-block: 1rem 0; padding: 1.25rem;
  background: var(--degradado-sutil); border: 1px solid var(--borde); border-radius: var(--radio);
}
.caja-autor__foto {
  display: block; width: 72px; height: 72px; border-radius: 50%; overflow: hidden; flex: 0 0 auto;
}
.caja-autor__datos { flex: 1 1 16rem; min-width: 0; }
.caja-autor__nombre { font-weight: 700; color: var(--marino); margin-bottom: .3rem; }
.caja-autor__texto { font-size: .9375rem; color: var(--texto-suave); line-height: 1.6; }
.caja-autor__perfiles { display: flex; flex-wrap: wrap; gap: .25rem 1.1rem; margin-top: .6rem;
  font-size: .9375rem; font-weight: 600; }

/* Título que solo existe para los lectores de pantalla: la caja se entiende
   sola mirándola, pero un <aside> sin nombre accesible no se anuncia. */
.visualmente-oculto {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* ------------------------------------------------------- grupos de Telegram */
/* min() en el minmax: sin la guarda, la pista no baja de 18rem y la página
   desborda a lo ancho en un móvil de 360 px. Misma trampa que le pasó al pie. */
.lista-grupos {
  display: grid; gap: 1rem; margin-block: 1.5rem 2rem; padding: 0; list-style: none;
  grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
}
.grupo {
  display: flex; flex-direction: column; gap: .6rem; padding: 1.25rem;
  background: var(--fondo-tarjeta); border: 1px solid var(--borde); border-radius: var(--radio);
}
/* Sin prefijo de contenedor: la prosa vive en :where() y no le gana a una
   clase, así que el componente se describe una vez y vale en cualquier página
   (el `text-decoration: none` ya lo trae .boton de serie). */
.grupo__nombre { font-size: var(--t-3); margin: 0; padding-bottom: 0; border-bottom: 0; }
.grupo__texto { font-size: .9375rem; color: var(--texto-suave); flex: 1 1 auto; margin: 0; }
.grupo__acciones { margin: 0; }
.grupo__acciones .boton { width: 100%; justify-content: center; }

/* -------------------------------------------------------------------- 404 */
.error404 { text-align: center; max-width: 42rem; }
.error404__codigo {
  font-family: var(--mono); font-size: clamp(4rem, 14vw, 7rem); font-weight: 800; line-height: 1;
  background: var(--degradado); -webkit-background-clip: text; background-clip: text; color: transparent;
}
.error404__titulo { font-size: clamp(1.5rem, 4vw, 2rem); margin-block: .5rem 1rem; }
.error404__texto { color: var(--texto-suave); }
.error404 .hero__acciones { justify-content: center; }
.error404__lista { margin-top: 1.5rem; text-align: left; }
.error404__titulo-lista { margin-top: 3rem; text-align: left; font-size: var(--t-4); }
.error404__pista { margin-top: 2rem; color: var(--texto-suave); font-weight: 600; }
/* Las sugerencias son la parte útil de un 404: van con peso de botón, no de
   lista suelta, porque son la acción que se espera que haga el visitante. */
.error404__sugerencias {
  list-style: none; padding: 0; margin: .75rem auto 0; display: grid; gap: .5rem;
  max-width: 34rem; text-align: left;
}
.error404__sugerencias a {
  display: block; padding: .8rem 1.1rem; border-radius: var(--radio);
  background: var(--fondo-tarjeta); border: 1px solid var(--borde-fuerte);
  color: var(--marino); font-weight: 600; text-decoration: none;
  transition: border-color var(--transicion), color var(--transicion);
}
.error404__sugerencias a:hover { border-color: var(--azul-claro); color: var(--azul); }

/* ---------------------------------------------------------- páginas legales */
.aviso-pendiente {
  margin-bottom: 2rem; padding: 1rem 1.25rem; border-radius: var(--radio-s);
  background: #fdf3d8; color: #5c3f0c; border: 1px solid #e8cf94; border-left: 4px solid #c9922a;
}
.falta-dato {
  background: #ffe9a8; color: #6b4a0a; padding: .1em .4em; border-radius: 4px;
  font-weight: 700; font-size: .875em; letter-spacing: .02em;
}
.nota-actualizacion { margin-top: 2.5rem; padding-top: 1.25rem; border-top: 1px solid var(--borde);
  font-size: .875rem; color: var(--texto-tenue); }
:root[data-tema="oscuro"] .aviso-pendiente { background: #3a2a12; color: #f3d9a0; border-color: #6b4d1c; }
:root[data-tema="oscuro"] .falta-dato { background: #6b4d1c; color: #ffe9a8; }

/* -------------------------------------------------------------------- pie */
.pie { background: var(--marino-hondo); color: #c9d7ef; margin-top: 2rem; }
/* Móvil primero: una columna. La rejilla anterior declaraba
   `minmax(16rem, 2fr)` como pista FIJA (fuera del auto-fit), así que no bajaba
   de 256 px, y sumada a la siguiente daba 416 px mínimos: en un móvil de 360
   la página entera desbordaba a lo ancho y el fondo del pie se cortaba. */
.pie__rejilla { display: grid; gap: 2rem; padding-block: 3rem 2rem; }
@media (min-width: 48rem) {
  .pie__rejilla { grid-template-columns: 2fr 1fr 1fr; gap: 2.5rem; }
}
.pie__claim { margin-top: .75rem; font-size: .9375rem; color: #9fb3d4; max-width: 28rem; }
.pie__titulo { font-size: .75rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--azul-cielo); margin-bottom: .75rem; }
.pie__lista { list-style: none; padding: 0; display: grid; gap: .5rem; }
.pie__lista a { color: #c9d7ef; text-decoration: none; font-size: .9375rem; }
.pie__lista a:hover { color: #fff; text-decoration: underline; }
.pie__legal { padding-block: 1.5rem; border-top: 1px solid rgba(255, 255, 255, .1); font-size: .8125rem; color: #8fa5c8; }
.pie__nota { margin-top: .4rem; }
.pie a:focus-visible { outline-color: var(--azul-cielo); }

/* El aire entre secciones baja en el móvil: cuatro medios rellenos a lo largo
   de la primera pantalla son 38 px, que en escritorio no se notan y en un móvil
   son media tarjeta. Medido con Playwright a 390x844, no a ojo. */
@media (max-width: 48rem) {
  .seccion--apretada { padding-block: 1.15rem; }
}

/* ====================================================================
   PORTADA
   ====================================================================
   Portada «magazine», elegida por Jonatan el 2026-09-06 entre tres bocetos que
   se montaron a la vez en la web para poder compararlos en el móvil. El
   esqueleto viene de descargaswindows.com; la rejilla del catálogo es propia
   de aquí (dos columnas, no tres). El porqué de cada pieza está en el
   comentario de cabecera de plantillas/home.php.
   ==================================================================== */

/* Portada «magazine»: banda fina de titular y, debajo, la guía destacada a dos
   tercios con la lista de las tres siguientes al lado. Copiado de
   descargaswindows.com, que es lo que pidió Jonatan el 2026-09-06.

   Las dos columnas acaban a la misma altura porque las filas de la lista se
   reparten el alto (`flex: 1`): la lista crece hasta igualar a la tarjeta, no
   al revés. Por eso las filas NO llevan alto fijo. */
.portada-titular { padding-block: 1.9rem .25rem; }
.portada-titular__h1 {
  font-family: var(--fuente-titulo); font-weight: 700; color: var(--marino);
  font-size: clamp(1.7rem, 3.2vw, 2.35rem); line-height: var(--interlineado-corto);
  letter-spacing: -.02em; margin: .6rem 0 .5rem; max-width: 26ch;
}
.portada-titular__entrada { color: var(--texto-suave); font-size: var(--t-0); max-width: 74ch; }

.portada-revista { display: grid; gap: 1.75rem; }
.siguiente { display: flex; flex-direction: column; gap: .55rem; }
/* Rótulo con filete debajo, no en caja: es la etiqueta de una columna, no una
   tarjeta más compitiendo con las de al lado. `line-height: 1` quita el aire
   muerto que la interlínea deja por encima de las mayúsculas. */
.siguiente__titulo {
  margin: 0; padding-bottom: .5rem; border-bottom: 2px solid var(--borde);
  font-size: var(--t--1); font-weight: 700; line-height: 1; letter-spacing: .09em;
  text-transform: uppercase; color: var(--texto-tenue);
}
.siguiente__lista {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; flex: 1;
}
.siguiente__lista li { display: flex; flex: 1; }
/* Dos columnas y DOS FILAS: el rótulo ocupa la primera él solo, y la tarjeta
   grande y la lista comparten la segunda. Con `row-gap: 0` el filete del rótulo
   y el canto superior de la tarjeta caen en la MISMA línea, así que la
   alineación es un hecho de la rejilla y no márgenes cuadrados a ojo.
   `display: contents` disuelve el div `.siguiente` para que el rótulo y la
   lista sean celdas de ESTA rejilla. Va DESPUÉS de `.siguiente { display: flex }`:
   misma especificidad, gana la última. */
@media (min-width: 62rem) {
  .portada-revista {
    grid-template-columns: 1.9fr 1fr;
    grid-template-rows: auto auto auto;
    column-gap: clamp(1.5rem, 2.6vw, 2.25rem);
    row-gap: 0;
    align-items: stretch;
  }
  /* La tarjeta ocupa las filas 2 y 3, y con `subgrid` sus dos partes se
     enganchan a ESAS filas: la 2 la marca la IMAGEN y la 3 el texto. Por eso la
     lista, que vive solo en la fila 2, acaba justo donde acaba la imagen sin
     calcular nada. */
  .portada-revista .destacado {
    grid-row: 2 / 4; grid-column: 1;
    grid-template-columns: 1fr; grid-template-rows: subgrid;
  }
  .siguiente { display: contents; }
  .siguiente__titulo { grid-area: 1 / 2; align-self: end; margin: 0; }
  .siguiente__lista  { grid-area: 2 / 2; }
}
/* El relleno vertical es CORTO a propósito: con `flex: 1` las filas se reparten
   el alto de la columna y el aire sale de ahí. Subirlo hace que la lista pase
   de largo a la imagen y abra una banda vacía dentro de la tarjeta. */
.guia-fila {
  display: flex; gap: .8rem; align-items: center; width: 100%;
  padding-block: .25rem; text-decoration: none; border-radius: var(--radio-s);
  transition: transform .12s ease;
}
.guia-fila:hover { transform: translateX(2px); }
.guia-fila:hover .guia-fila__titulo { color: var(--azul); }
/* La miniatura son DOS QUINTOS de su columna, con suelo y techo: en una portada
   de 1200x628 el título va rotulado dentro, así que por debajo de ~125 px no se
   lee y la miniatura deja de decir de qué guía es. Sin techo, en 2560 se comería
   el título de al lado. */
.guia-fila__imagen {
  flex: 0 0 clamp(7.75rem, 41%, 11rem); display: block;
  aspect-ratio: var(--proporcion-portada);
  border: 1px solid var(--borde); border-radius: var(--radio-s); overflow: hidden;
}
.guia-fila__imagen img { width: 100%; height: 100%; object-fit: cover; display: block; }
.guia-fila__cuerpo { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
.guia-fila__cat {
  font-size: .625rem; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--cian);
}
.guia-fila__titulo {
  font-family: var(--fuente-titulo); font-weight: 700; font-size: var(--t-0);
  line-height: 1.28; letter-spacing: -.012em; color: var(--marino);
  transition: color var(--transicion);
}
.guia-fila__meta {
  display: flex; align-items: center; gap: .4rem;
  font-size: .75rem; color: var(--texto-tenue);
}
/* La tarjeta del destacado se APILA siempre: dentro de dos tercios son ~674 px
   a 1280 y partirla en dos dejaba el título en cuatro renglones. Gana a la
   regla de 52rem de `.destacado`, que mira la VENTANA y no sabe que aquí vive
   dentro de media banda. */
.destacado--apilado { grid-template-columns: 1fr; }
.destacado--apilado .destacado__imagen { aspect-ratio: var(--proporcion-portada); height: auto; }

.esc-cat {
  font-size: .6875rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--cian);
}
.esc-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: .2rem .7rem;
  font-size: var(--t--1); color: var(--texto-tenue); font-weight: 500;
  font-variant-numeric: tabular-nums;
}
/* Lo que se queda de la B original: DOS columnas, no tres. Las portadas llevan
   el título rotulado dentro y a 344 px (tres columnas) no se lee, así que la
   imagen dejaría de informar y solo decoraría. */
.esc-rejilla {
  grid-template-columns: repeat(auto-fill, minmax(min(24rem, 100%), 1fr));
}
.esc-ficha {
  display: grid; grid-template-rows: auto 1fr; height: 100%; width: 100%; text-decoration: none;
  border: 1px solid var(--borde); border-radius: var(--radio); overflow: hidden;
  background: var(--fondo-tarjeta); box-shadow: var(--sombra-s);
  transition: border-color var(--transicion), transform .12s ease, box-shadow var(--transicion);
}
.esc-ficha:hover, .esc-ficha:focus-visible {
  border-color: var(--azul-claro); transform: translateY(-3px); box-shadow: var(--sombra-m);
}
.esc-ficha:hover .esc-ficha__titulo { color: var(--azul); }
.esc-ficha__imagen { display: block; aspect-ratio: var(--proporcion-portada); overflow: hidden; }
.esc-ficha__imagen img { width: 100%; height: 100%; object-fit: cover; display: block; }
.esc-ficha__cuerpo {
  display: flex; flex-direction: column; gap: .35rem; justify-content: center;
  padding: .9rem 1.1rem 1.1rem;
}
.esc-ficha__titulo {
  font-family: var(--fuente-titulo); font-weight: 700; color: var(--marino);
  font-size: var(--t-1); line-height: var(--interlineado-corto);
  transition: color var(--transicion);
}


/* ====================================================================
   BUSCADOR: botón en la barra + diálogo
   ====================================================================
   Estaba en una caja dentro de la portada y ocupaba una fila entera. Jonatan,
   2026-09-06: «ponlo en un botón en la barra superior, no abajo ocupando
   espacio en feo». Al subirlo funciona además en TODAS las páginas, no solo en
   la portada, que era la limitación de la caja.
   ==================================================================== */
.atajo-buscar {
  display: grid; place-items: center; flex: 0 0 auto;
  width: 42px; height: 42px; border-radius: var(--radio-s);
  border: 1px solid var(--borde); background: var(--fondo-tarjeta);
  color: var(--texto-suave); cursor: pointer;
  transition: border-color var(--transicion), color var(--transicion);
}
.atajo-buscar:hover, .atajo-buscar:focus-visible {
  border-color: var(--azul-claro); color: var(--azul);
}
.atajo-buscar svg { width: 1.15rem; height: 1.15rem; }
.atajo-buscar[hidden] { display: none; }

/* El diálogo se ancla ARRIBA y no centrado: al escribir crece hacia abajo, y
   centrado daría un salto en cada tecla. */
.buscador-dlg {
  width: min(38rem, calc(100vw - 2rem));
  margin: 4.5rem auto auto; padding: 0;
  border: 1px solid var(--borde); border-radius: var(--radio);
  background: var(--fondo-tarjeta); color: var(--texto);
  box-shadow: var(--sombra-l);
}
.buscador-dlg::backdrop { background: rgba(10, 20, 40, .55); backdrop-filter: blur(2px); }
.buscador-dlg__caja {
  display: flex; align-items: center; gap: .65rem;
  padding: .85rem 1rem; border-bottom: 1px solid var(--borde);
}
.buscador-dlg__lupa { width: 1.15rem; height: 1.15rem; flex: 0 0 auto; color: var(--texto-tenue); }
.buscador-dlg__campo {
  flex: 1 1 auto; min-width: 0; border: 0; background: none; padding: 0;
  font: inherit; font-size: 1.0625rem; color: var(--texto);
}
.buscador-dlg__campo:focus { outline: none; }
/* Fuera la cruz nativa de `type="search"`: al lado del botón de cerrar salían
   DOS aspas iguales y pegadas, una que vacía y otra que cierra, sin manera de
   saber cuál hace qué. Se queda la del diálogo; para vaciar está Escape, que ya
   se trata a mano en sitio.js. */
.buscador-dlg__campo::-webkit-search-cancel-button,
.buscador-dlg__campo::-webkit-search-decoration { -webkit-appearance: none; appearance: none; }
.buscador-dlg__cerrar {
  display: grid; place-items: center; flex: 0 0 auto;
  width: 30px; height: 30px; border-radius: var(--radio-s);
  border: 0; background: none; color: var(--texto-tenue); cursor: pointer;
}
.buscador-dlg__cerrar:hover, .buscador-dlg__cerrar:focus-visible { color: var(--azul); }
.buscador-dlg__cerrar svg { width: 1.05rem; height: 1.05rem; }
.buscador-dlg__ayuda {
  margin: 0; padding: .6rem 1rem;
  font-size: var(--t--1); color: var(--texto-tenue); font-variant-numeric: tabular-nums;
}
.buscador-dlg__lista {
  list-style: none; margin: 0; padding: 0 .5rem .5rem;
  max-height: min(24rem, 60vh); overflow-y: auto;
}
/* Igual que en la rejilla: `[hidden]` de la hoja del navegador empata con la
   regla de al lado y perdería por ir antes. Sin esto no se oculta nada. */
.buscador-dlg__lista li[hidden] { display: none; }
.buscador-dlg__lista a {
  display: flex; flex-direction: column; gap: .1rem;
  padding: .55rem .75rem; border-radius: var(--radio-s);
  text-decoration: none; color: var(--texto);
}
.buscador-dlg__lista a:hover, .buscador-dlg__lista a:focus-visible {
  background: var(--azul-bruma); outline: none;
}
.buscador-dlg__cat {
  font-size: .625rem; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--cian);
}
.buscador-dlg__titulo {
  font-family: var(--fuente-titulo); font-weight: 600; font-size: var(--t-0);
  line-height: 1.3; color: var(--marino);
}
