/*
 * Kantei — hoja de estilo del sitio público.
 *
 * De dónde viene: el acero y el índigo del informe de compra con el que empezó todo. (El nombre
 * del fichero de aquel informe no se escribe aquí: esta hoja se publica, y una ruta de la parte
 * privada leída en un comentario del CSS ya le cuenta a cualquiera que existe.)
 * Fondo de ji —la superficie pulida entre el hamon y el shinogi—, tinta casi negra, índigo para
 * todo lo que se pulsa, bermellón con cuentagotas y oro reservado a los papeles. IBM Plex Sans para
 * leer, Zen Old Mincho para los nombres y las cifras que importan.
 *
 * Qué se ha hecho con ello: kantei es una tabla de trabajo sin fotos; esto es una galería. Se
 * queda el rasgo que ninguna otra web tiene y se le da el sitio principal —**cada hoja dibujada a
 * escala real, y todas a la misma**, alineadas por el machi sobre una línea que baja por la lista
 * entera, de modo que recorrer el catálogo es mirar un perchero de hojas y ver cuál es más larga y
 * cuál curva más—; y alrededor, aire, fotografía grande y silencio. Sin sombras, sin tarjetas, sin
 * esquinas redondeadas más allá de los tres píxeles de un botón: lo único que llama la atención es
 * la hoja.
 *
 * Reglas de la casa:
 *  - Los números van con cifras tabulares. Esto es un catálogo de medidas.
 *  - El color es información: el tono dice el periodo, el oro dice papel, el bermellón dice lo que
 *    hay que saber antes de comprar. Nada de color decorativo.
 *  - El movimiento sólo responde a un clic. Nada aparece al desplazar.
 *  - Todo lo que necesita JavaScript lleva `needs-js` y no se enseña sin él: un filtro que no
 *    filtra es peor que ningún filtro.
 */

/* ------------------------------------------------------------------ tipografías */

@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/ibm-plex-sans-latin-400-normal.3b646991.woff2") format("woff2");
}
@font-face {
  font-family: "IBM Plex Sans";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/ibm-plex-sans-latin-400-italic.6de912e5.woff2") format("woff2");
}
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/assets/fonts/ibm-plex-sans-latin-600-normal.8960851d.woff2") format("woff2");
}
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/fonts/ibm-plex-sans-latin-700-normal.42e7b0c1.woff2") format("woff2");
}
@font-face {
  font-family: "Zen Old Mincho";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/zen-old-mincho-latin-400-normal.ef359bfd.woff2") format("woff2");
}
@font-face {
  font-family: "Zen Old Mincho";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/fonts/zen-old-mincho-latin-700-normal.1ce304c3.woff2") format("woff2");
}

/* ----------------------------------------------------------------------- tokens */

:root {
  color-scheme: light dark;

  --ji: #edeff1;
  --hamon: #f9fafb;
  --ink: #1b2229;
  --ink2: #4b5865;
  --line: #d1d7dc;
  --line2: #e2e6ea;
  --ai: #24406b;
  --ai2: #e4eaf4;
  --shu: #b8322a;
  --kin: #9c7a2e;
  /*
   * El mismo oro, hundido hasta poder leerse (corrección de E1, 23/09/2026).
   *
   * `--kin` es el oro de los filetes, los papeles y el rótulo grande: a ese oficio le basta con
   * 3:1. Pero se escribía también en letra pequeña —el sello NBTHK de cada tarjeta y de cada
   * ficha, el puesto de los diez primeros, el estado «reservada»—, y ahí se quedaba en 3,84:1
   * sobre la tarjeta y 3,48:1 sobre la página, con la norma AA pidiendo 4,5:1 a 13 y 14 px. Dos
   * tokens, cada uno con su oficio, como ya estaba resuelto en el panel. En oscuro el oro ya llega
   * de sobra (7,8:1), así que allí los dos valen lo mismo y el token existe sólo para no tener que
   * preguntarse cuál toca.
   */
  --kin-text: #7a5f20;

  /*
   * El papel de los diagramas. A diferencia de todo lo demás, estos dos NO cambian en tema oscuro:
   * un diagrama invertido —hoja blanca sobre fondo negro— deja de parecer un dibujo y pasa a
   * parecer un negativo, y además los ocho diagramas de la guía llevan dentro acentos calculados
   * sobre papel (el bermellón de las marcas, el oro de los papeles NBTHK). Así que en oscuro el
   * dibujo no se invierte: se le da su propia lámina de papel dentro de la página, como una hoja
   * sobre la mesa (bloque C, 22/09/2026). El tono es el de los diagramas del glosario.
   */
  --paper: #f5f2ec;
  --ink-on-paper: #2b2320;

  /*
   * Las dos superficies (pasada estética, 23/09/2026).
   *
   * `--surface-1` es la cara de lo que se levanta del papel —una tarjeta, el panel de filtros, la
   * banda de portada—; `--surface-2`, lo que se hunde dentro de ella: el pie de la tarjeta, el
   * riel de una barra, una celda de datos. Ese oficio lo hacían `--hamon` y `--ji` a la vez, y por
   * eso una tarjeta sobre la página y un pie dentro de la tarjeta acababan del mismo tono en uno
   * de los dos temas: dos superficies distintas pidiendo el mismo color. Ahora son dos tokens, y
   * la jerarquía —página, tarjeta, pie— se lee igual en claro y en oscuro.
   */
  --surface-1: #ffffff;
  --surface-2: #f1f4f7;

  /*
   * El fondo de la banda de portada: papel en claro y tinta profunda en oscuro. No es `--paper`
   * —ése es el de los diagramas, que no cambia con el tema— sino su pariente de la página, un
   * punto más cálido que el fondo para que la banda se despegue sin necesitar borde ni sombra.
   */
  --hero-bg: #f2efe7;

  /*
   * El acento sobre cada una de las dos superficies, sin depender del tema (tarea E1, 23/09/2026).
   *
   * `--ai` cambia con el tema porque la página cambia con el tema; el papel de los diagramas y el
   * cuarto oscuro del visor, no. Ahí el acento del tema contrario no se ve: el azul pálido sobre el
   * papel da 1,97:1 y el índigo sobre el negro del visor, 1,55:1, con lo que un anillo de foco
   * dentro del diagrama o del visor desaparecía justo en el tema equivocado. Estos dos son los
   * mismos valores que `--ai` toma en cada tema, pero atados a la superficie en vez de al tema, y
   * las dos superficies se redefinen `--ai` con el que les toca.
   */
  --ai-on-paper: #24406b;
  --ai2-on-paper: #e4eaf4;
  --ai-on-ink: #8fb0e8;
  --ai2-on-ink: #1f2c40;

  /*
   * Los cuatro periodos. Aquel informe pintaba el shinshintō del mismo bermellón que las
   * advertencias, y aquí no vale: un cuarto del catálogo es shinshintō, de modo que el color que
   * debe usarse con cuentagotas aparecería en quince filas y dejaría de querer decir nada. Se le da
   * su propio ámbar y el bermellón queda para lo que hay que saber antes de comprar.
   */
  --koto: #6f4f86;
  --shinto: #2a6b77;
  --shinshinto: #9a5b2e;
  --gendai: #6b7280;

  --sans: "IBM Plex Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Helvetica, Arial,
    sans-serif;
  --mincho: "Zen Old Mincho", "Hiragino Mincho ProN", "Yu Mincho", "Noto Serif JP", ui-serif,
    Georgia, serif;

  /*
   * Las tres esquinas del sistema y la píldora (tarea E1, 23/09/2026). Antes había tres tamaños
   * con nombre y otros tres escritos a mano —6, 10 y 12 px, según quién escribiera la regla—, que
   * es lo que hace que dos paneles vecinos no parezcan de la misma casa. `--r` es el filo de un
   * control, `--r1` la caja de una miniatura o de un cuadro, `--r2` el panel de una tarjeta.
   */
  --r: 3px;
  --r1: 6px;
  --r2: 12px;
  --pill: 999px;

  /*
   * La escala tipográfica (tarea E1, 23/09/2026).
   *
   * Ocho pasos y ni uno más. Venían quince cuerpos distintos de ir ajustando pantallas a ojo, y
   * seis de ellos —11, 15, 17, 18, 19 y 22 px— caían entre dos pasos vecinos: nadie los decidió, y
   * son justo los que impiden que la jerarquía se lea de un vistazo. La escala sube de 12 a 28 px y
   * remata en el título de la página, que sí crece con la ventana.
   */
  --fs-1: 0.75rem; /* 12 px — recuentos, créditos, pies */
  --fs-2: 0.8125rem; /* 13 px — metadatos y etiquetas */
  --fs-3: 0.875rem; /* 14 px — controles y tablas */
  --fs-4: 1rem; /* 16 px — el cuerpo del texto */
  --fs-5: 1.25rem; /* 20 px — h3 y las cifras de la tarjeta */
  --fs-6: 1.5rem; /* 24 px — h2 de una página de texto */
  --fs-7: 1.75rem; /* 28 px — h2 */
  --fs-8: clamp(2rem, 1.2rem + 3vw, 3.25rem); /* h1 */
  /*
   * Y las dos cifras grandes de la ficha —la nota sobre 100 y el precio—, que no son texto sino
   * rótulo: van fuera de la escala a propósito, porque su tamaño lo decide el sitio que ocupan en
   * la página y no el renglón en el que se leen.
   */
  --fs-cifra: 2rem;
  --fs-cifra-alta: 3rem;

  --wrap: 77.5rem; /* 1240 px */
  --prose: 38rem;
  --gap: 1.5rem;
  /* La columna del panel de filtros, a la derecha de la lista (22/09/2026). */
  --rail-filters: 20rem;

  /*
   * La escala de las hojas: cuántos píxeles vale un centímetro, y a qué distancia del borde de la
   * columna cae el machi. Las dos son de toda la página, no de cada silueta: en eso consiste que
   * las hojas se puedan comparar de un vistazo.
   */
  --px-cm: 2.6px;
  /*
   * Y la de las láminas del catálogo, que es aparte y NO cambia con la ventana (23/09/2026): la
   * tarjeta mide 20 rem en cualquier pantalla, así que encoger la hoja al estrecharse la ventana
   * sólo conseguía que dos capturas del mismo catálogo no se pudieran comparar.
   */
  --px-cm-card: 2.4px;
  /*
   * Y la de la silueta de la ficha, que es la grande: allí hay una sola hoja y toda la columna para
   * ella. La escribe también la regla de 10 cm que va debajo (`.blade-key`), y por eso es una
   * variable y no un número suelto: una regla que no mide lo que dibuja es peor que ninguna.
   */
  --px-cm-piece: 6px;
  /* El relleno de la lámina y la columna de la firma en vertical. */
  --card-pad: 1.25rem;
  --mei-col: 2.5rem;
  /*
   * Lo que la ficha de la lámina reserva siempre al resumen: su margen de arriba más DOS líneas
   * —el recorte por omisión—. Es el suelo del hueco, no su techo: por encima manda el `1fr`. Va
   * escrito con los mismos números que `.piece-body .summary` (cuerpo `--fs-3`, interlínea 1,55);
   * si allí cambian, aquí también.
   */
  --summary-min: calc(0.7rem + 2 * 1.55 * var(--fs-3));

  /*
   * El movimiento, en dos tiempos (tarea E1, 23/09/2026). `--mov-1` para un cambio de estado —un
   * borde, un fondo, una opacidad— y `--mov-2` para algo que entra o sale de la pantalla: la hoja
   * de filtros, la bandeja del comparador, el relevo del carril. Cortas las dos: por encima de un
   * cuarto de segundo la interfaz se hace de esperar. Quien no quiera movimiento las pone a cero
   * (ver «preferencias», al final de la hoja).
   */
  --mov-1: 0.12s;
  --mov-2: 0.24s;

  /*
   * Las sombras. Suaves y de dos capas —un filo cerca y un halo lejos—, que es lo que levanta una
   * tarjeta del papel sin que parezca un botón. En oscuro no valen las mismas: sobre tinta, una
   * sombra gris aclara en vez de hundir, así que se pintan en negro y más abiertas.
   */
  --shadow-1: 0 1px 2px rgb(16 24 32 / 0.05), 0 6px 18px rgb(16 24 32 / 0.06);
  --shadow-2: 0 2px 6px rgb(16 24 32 / 0.08), 0 14px 32px rgb(16 24 32 / 0.1);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ji: #14181c;
    --hamon: #1c2126;
    --ink: #e6e9ec;
    --ink2: #a5b0ba;
    --line: #2b333b;
    --line2: #242b32;
    --ai: #8fb0e8;
    --ai2: #1f2c40;
    --shu: #e5766b;
    --kin: #d2b060;
    --kin-text: #d2b060;
    --surface-1: #1d232a;
    --surface-2: #252c34;
    --hero-bg: #10151a;
    --koto: #b695c7;
    --shinto: #6fb6c2;
    --shinshinto: #d69a62;
    --gendai: #9ba3ac;
    --shadow-1: 0 1px 2px rgb(0 0 0 / 0.4), 0 6px 18px rgb(0 0 0 / 0.3);
    --shadow-2: 0 2px 6px rgb(0 0 0 / 0.5), 0 14px 32px rgb(0 0 0 / 0.4);
  }
}

:root[data-theme="dark"] {
  --ji: #14181c;
  --hamon: #1c2126;
  --ink: #e6e9ec;
  --ink2: #a5b0ba;
  --line: #2b333b;
  --line2: #242b32;
  --ai: #8fb0e8;
  --ai2: #1f2c40;
  --shu: #e5766b;
  --kin: #d2b060;
  --kin-text: #d2b060;
  --surface-1: #1d232a;
  --surface-2: #252c34;
  --hero-bg: #10151a;
  --koto: #b695c7;
  --shinto: #6fb6c2;
  --shinshinto: #d69a62;
  --gendai: #9ba3ac;
  --shadow-1: 0 1px 2px rgb(0 0 0 / 0.4), 0 6px 18px rgb(0 0 0 / 0.3);
  --shadow-2: 0 2px 6px rgb(0 0 0 / 0.5), 0 14px 32px rgb(0 0 0 / 0.4);
}

/* El tema elegido manda también sobre los controles del navegador y la barra de desplazamiento. */
:root[data-theme="light"] {
  color-scheme: light;
}
:root[data-theme="dark"] {
  color-scheme: dark;
}

/* ------------------------------------------------------------------------- base */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-padding-top: 5rem;
}

body {
  margin: 0;
  background: var(--ji);
  color: var(--ink);
  font: 400 var(--fs-4)/1.6 var(--sans);
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
  overflow-wrap: break-word;
}

h1,
h2,
h3,
h4 {
  font-family: var(--mincho);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: 0.005em;
  margin: 0;
  text-wrap: balance;
}

h1 {
  font-size: var(--fs-8);
}
h2 {
  font-size: var(--fs-7);
}
h3 {
  font-size: var(--fs-5);
}

p,
ul,
ol,
dl {
  margin: 0;
}

a {
  color: var(--ai);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}
a:hover {
  text-decoration-thickness: 2px;
}

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

button,
input,
select {
  font: inherit;
  font-variant-numeric: inherit;
  color: inherit;
}

button {
  cursor: pointer;
}

:focus-visible {
  outline: 2px solid var(--ai);
  outline-offset: 2px;
  border-radius: 1px;
}

[hidden] {
  display: none !important;
}

::selection {
  background: var(--ai2);
  color: var(--ink);
}

/* -------------------------------------------------------------------- utilidades */

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Lo que sin JavaScript no funciona no se enseña. */
:root:not(.js) .needs-js {
  display: none !important;
}

.skip-link {
  position: absolute;
  left: 0.5rem;
  top: -4rem;
  z-index: 60;
  padding: 0.6rem 1rem;
  background: var(--ai);
  color: var(--ji);
  border-radius: var(--r);
  text-decoration: none;
  transition: top var(--mov-1) ease;
}
.skip-link:focus {
  top: 0.5rem;
}

.wrap,
.site-header,
.site-footer,
main > * {
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: 1.5rem;
}

/* ---------------------------------------------------------------------- cabecera */

.site-header {
  display: flex;
  align-items: center;
  gap: 0.5rem 1.25rem;
  min-height: 4rem;
  border-bottom: 1px solid var(--line);
  max-width: 100%;
  padding-inline: max(1.5rem, calc((100vw - var(--wrap)) / 2 + 1.5rem));
  position: sticky;
  top: 0;
  z-index: 40;
  background: color-mix(in srgb, var(--ji) 88%, transparent);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
}

.brand {
  font-family: var(--mincho);
  font-weight: 700;
  font-size: var(--fs-5);
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.brand a {
  color: inherit;
  text-decoration: none;
}
.brand a::after {
  /* La marca lleva su propia hoja: el mismo trazo diagonal del icono, a tamaño de texto. */
  content: "";
  display: inline-block;
  width: 0.7em;
  height: 0.7em;
  margin-left: 0.45em;
  background: var(--ai);
  clip-path: polygon(0 100%, 12% 88%, 100% 6%, 100% 18%, 14% 100%);
}

.main-nav ul,
.lang-nav ul {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.125rem;
  list-style: none;
  padding: 0;
  margin: 0;
}

.main-nav a {
  display: block;
  padding: 0.35rem 0.6rem;
  font-size: var(--fs-3);
  color: var(--ink2);
  text-decoration: none;
  border-radius: var(--r);
  white-space: nowrap;
}
.main-nav a:hover {
  color: var(--ink);
  background: var(--hamon);
}
.main-nav a[aria-current="page"] {
  color: var(--ai);
  font-weight: 600;
}

/* «Acceso» no es una sección del sitio: lleva fuera, tras Google. Se separa y se apaga. */
.nav-access {
  margin-left: 0.5rem;
  padding-left: 0.75rem;
  border-left: 1px solid var(--line);
}
.nav-access a {
  font-size: var(--fs-2);
}

.lang-nav {
  margin-left: auto;
}
.lang-nav a {
  display: block;
  padding: 0.2rem 0.4rem;
  font-size: var(--fs-2);
  color: var(--ink2);
  text-decoration: none;
  border-radius: 2px;
}
.lang-nav a:hover {
  color: var(--ink);
}
.lang-nav a[aria-current="page"] {
  color: var(--ink);
  font-weight: 600;
  box-shadow: inset 0 -2px 0 var(--ai);
}

.nav-toggle,
.theme-toggle {
  border: 1px solid var(--line);
  background: var(--hamon);
  border-radius: var(--r);
  padding: 0.35rem 0.7rem;
  font-size: var(--fs-2);
  color: var(--ink2);
}
.nav-toggle:hover,
.theme-toggle:hover {
  border-color: var(--ink2);
  color: var(--ink);
}

.nav-toggle {
  display: none;
}

.theme-toggle {
  padding: 0.35rem;
  line-height: 0;
}
/* Un disco mitad lleno: el sol y la luna del mismo trazo, sin librería de iconos. */
.theme-mark {
  display: block;
  width: 1rem;
  height: 1rem;
  border: 1.5px solid currentColor;
  border-radius: 50%;
  background: linear-gradient(90deg, currentColor 50%, transparent 50%);
}

/* -------------------------------------------------------------------------- pie */

/*
 * Tres columnas desde la pasada estética del 23/09/2026: las secciones del sitio, los seis idiomas
 * y el © con el aviso legal. Era una línea con el aviso y nada más, de modo que al final de una
 * ficha larga no había por dónde seguir. El filete de arriba es el de siempre; lo que cambia es
 * que ahora debajo hay algo.
 */
.site-footer {
  margin-top: 5rem;
  padding-block: 2rem 3.5rem;
  border-top: 1px solid var(--line);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 1.5rem 2.5rem;
  font-size: var(--fs-2);
  color: var(--ink2);
}
.site-footer ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.35rem;
}
.footer-langs ul {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.site-footer a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
.site-footer a:hover {
  color: var(--ink);
  border-bottom-color: var(--line);
}
.site-footer a[aria-current="page"] {
  color: var(--ink);
  font-weight: 600;
}
/* El © y el aviso, a la derecha del todo cuando hay sitio: es la letra pequeña de la contraportada. */
.footer-rights {
  display: grid;
  align-content: start;
  gap: 0.35rem;
}
@media (min-width: 52rem) {
  .footer-rights {
    text-align: right;
  }
}

/* ------------------------------------------------------------ cabecera de página */

.page-head {
  padding-block: 3.5rem 2rem;
}

/*
 * La banda de portada del Catálogo (pasada estética, 23/09/2026).
 *
 * El catálogo abría con un título y una entradilla flotando sobre el fondo de la página: la
 * primera pantalla no decía qué sitio es éste, sólo cómo se llama. La banda le da suelo —papel en
 * claro, tinta profunda en oscuro— y sitio a lo que viene: a la izquierda el título con su filete
 * de oro y la entradilla, a la derecha una hoja dibujada a línea que no compite con nada, y bajo
 * las dos la línea de cifras que trae la portada.
 *
 * Es `.page-head` además de `.hero`, así que las dos reglas se pisan: ésta va después a propósito
 * y manda sobre el relleno de la otra.
 */
.hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: end;
  gap: 1.5rem 3rem;
  margin-block: 2.5rem 1.5rem;
  padding: 2.75rem 2rem;
  border: 1px solid var(--line2);
  border-radius: var(--r2);
  background: var(--hero-bg);
}
.hero h1 {
  font-size: var(--fs-8);
  line-height: 1.04;
  letter-spacing: -0.015em;
  text-wrap: balance;
}
/* El filete de oro: dice dónde acaba el título sin cruzar la banda de lado a lado. */
.hero h1::after {
  content: "";
  display: block;
  width: 4.5rem;
  height: 2px;
  margin-top: 1.1rem;
  background: var(--kin);
}
.hero .lede {
  margin-top: 1.1rem;
  max-width: 36rem;
}
/*
 * El motivo sólo se enseña donde tiene columna propia (revisión de E1b, 23/09/2026): debajo de
 * 52 rem la banda es de una sola columna y la hoja, dibujada a línea y en 8:1, quedaba de rayita
 * suelta bajo la entradilla —parecía un fallo de pintado, no una decoración—.
 */
.hero-aside {
  display: none;
  justify-self: end;
  align-self: center;
  width: 100%;
  color: var(--ink2);
  /* Decoración, y se comporta como tal: una quinta parte de tinta y ni un gramo más. */
  opacity: 0.2;
}
.hero-blade {
  display: block;
  width: 100%;
  height: auto;
}
/*
 * El MOSAICO de la pieza de portada (bloque J, 23/09/2026).
 *
 * Antonio: «en la home la espada de presentación no se identifica bien… yo pondría otra cosa, algo
 * como una composición de piezas de una». Donde estaba la hoja a línea van cuatro fotos de una
 * pieza de verdad —hoja, montura, guarnición y un detalle—, y la columna deja de ser decoración:
 * se ve la tinta entera, no un 20 %.
 *
 * La rejilla es de hileras JUSTIFICADAS y no una cuadrícula: dentro de una hilera cada foto crece
 * en proporción a su forma (`flex: <ancho/alto>`) y lleva esa misma forma en `aspect-ratio`, así
 * que todas acaban con la MISMA altura sin recortar ni deformar ninguna. Una cuadrícula de celdas
 * iguales convertiría la montura de 692 × 2.000 en una banda negra recortada, que es de lo que
 * venimos.
 */
.hero-piece {
  display: block;
  color: inherit;
  text-decoration: none;
}
.hero-mosaic {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.hero-mosaic-row {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
}
.hero-shot {
  /* El `flex-grow` es la proporción de la foto: con la base a 0, los anchos salen proporcionales
     a ella y las alturas de la hilera coinciden. `--grow` y `--ar` los escribe el generador, foto
     a foto; son la misma forma dicha de las dos maneras que hacen falta. */
  flex: var(--grow, 1) 1 0;
  min-width: 0;
  aspect-ratio: var(--ar, 1);
  width: 100%;
  height: auto;
  object-fit: cover;
  border: 1px solid var(--line2);
  border-radius: var(--r1);
  box-shadow: var(--shadow-1);
  background: var(--hero-bg);
}
/* El pie: de quién son las cuatro fotos y adónde llevan. Letra pequeña, sin robarle al título. */
.hero-piece-caption {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.15rem 0.6rem;
  margin-top: 0.85rem;
  font-size: var(--fs-2);
  line-height: 1.4;
  color: var(--ink2);
}
.hero-piece-caption b {
  color: var(--ink);
  font-weight: 600;
}
.hero-piece-cta {
  margin-inline-start: auto;
  /* `--kin-text` y no `--kin`: esto es texto pequeño que hay que leer, y el oro de los filetes se
     queda en 3,5:1 sobre el papel (la pasada de contraste de E1, 23/09/2026). */
  color: var(--kin-text);
  border-bottom: 1px solid transparent;
}
.hero-piece:hover .hero-piece-cta,
.hero-piece:focus-visible .hero-piece-cta {
  border-bottom-color: var(--kin);
}
.hero-piece:hover .hero-shot {
  border-color: var(--kin);
}
.hero-piece:focus-visible {
  outline: 2px solid var(--kin);
  outline-offset: 4px;
  border-radius: var(--r2);
}
/*
 * El corte de la banda, y va DESPUÉS de `.hero-aside` a propósito: las dos reglas tienen la misma
 * especificidad, así que la de arriba se quedaba con el `display: none` y el motivo no salía en
 * ningún ancho (visto cotejando la captura de 1.440 con la de la pasada anterior, 23/09/2026).
 */
/*
 * En el teléfono la hoja a línea no sale —en 8:1 quedaba de rayita suelta— pero el MOSAICO sí: es
 * lo que Antonio quiere que se vea al entrar. Va debajo del texto y ANTES de la línea de cifras
 * (`order`), y ahí se queda con DOS fotos, estrechado a 16 rem.
 *
 * Las cuatro en una tira se probaron primero y se descartaron mirando la captura de 390: repartidos
 * 318 px entre cuatro fotos justificadas, las dos de pie salen de 40 px de ancho —dos rayitas
 * azules— y vuelve a pasar exactamente lo que Antonio dijo de la hoja a línea, que no se identifica.
 * Dos fotos de 135 y 96 px son dos katana que se reconocen; las otras dos están a un toque, en la
 * ficha (23/09/2026).
 *
 * Cuáles son esas dos lo cambió el revisor del bloque J: escondiendo la segunda HILERA quedaban las
 * dos de pie —la hoja y la montura, la misma silueta dos veces—. Ahora se esconde foto a foto y se
 * queda la PRIMERA de cada hilera, que por cómo se reparten (`render/featured.ts`) es una de pie y
 * una tumbada: la pieza contada con dos formas distintas. Para que quepan al lado, las dos hileras
 * se ponen en fila y se reparten el ancho a medias; cada una conserva la forma de su foto, así que
 * la de pie sale alta y estrecha y la tumbada, baja y ancha, alineadas por arriba.
 */
@media (max-width: 51.999rem) {
  .hero:has(.hero-mosaic) .hero-aside {
    display: block;
    order: 1;
    opacity: 1;
    color: inherit;
  }
  .hero:has(.hero-mosaic) .hero-text {
    order: 0;
  }
  .hero:has(.hero-mosaic) .home-stats {
    order: 2;
  }
  .hero-mosaic {
    max-width: 16rem;
    flex-direction: row;
    align-items: flex-start;
  }
  .hero-mosaic-row {
    flex: 1 1 0;
    min-width: 0;
  }
  /* Foto a foto, y no la hilera entera: así queda una de pie y una tumbada, no dos de pie. */
  .hero-shot:not(.is-lead) {
    display: none;
  }
  /* Y la que queda llena su mitad: con el `flex-grow` de su forma, la de pie (0,49) se quedaba en
     60 px de los 124 de su hilera y volvía a ser una rayita (visto en la captura de 390). */
  .hero-shot {
    flex-grow: 1;
  }
}
@media (min-width: 52rem) {
  .hero {
    grid-template-columns: minmax(0, 1fr) minmax(0, 18rem);
  }
  /* Con mosaico la columna es más ancha: cuatro fotos en 18 rem salen de sello de correos. */
  .hero:has(.hero-mosaic) {
    grid-template-columns: minmax(0, 1fr) minmax(0, 21rem);
  }
  /* El mosaico no es decoración: se ve entero, con su tinta y su papel. */
  .hero-aside:has(.hero-mosaic) {
    opacity: 1;
    color: inherit;
  }
  /*
   * Fila 1, columna 2, dicho a mano: la línea de cifras que va en medio cruza las dos columnas
   * (`grid-column: 1 / -1`), así que la colocación automática mandaba el motivo a la fila de
   * debajo y a la primera columna, donde estorbaba a la prosa en vez de acompañar al título.
   */
  .hero-aside {
    display: block;
    grid-area: 1 / 2;
  }
}
/*
 * Las cifras del catálogo, que pinta la portada (`render/home-intro.ts`).
 *
 * E1b dejó preparada una rejilla de números grandes, `.hero-stats`, contando con que el bloque F
 * traería tres cifras sueltas. No las trae: trae frases enteras —«135 katana publicadas», «25
 * provincias», «por época: Kotō 21, …»—, que es lo único que sale bien en seis idiomas con sus
 * singulares y sus plurales. Una frase no cabe en una columna de 5,5 rem, así que la rejilla se
 * fue con su prueba (23/09/2026) y manda `.home-stats` (más abajo): una línea que se apoya a lo
 * ancho de la banda, bajo el título y cruzando las dos columnas.
 *
 * Aquí hubo dos reglas más —`.hero:has(.home-stats)` volvía la banda a una columna y escondía el
 * motivo— que el revisor tumbó el mismo día: `renderCatalogue` se llama SIEMPRE con el texto de la
 * portada, así que no escondían el motivo «cuando hay cifras», lo escondían en las seis portadas,
 * y el corte de 52 rem no disparaba en ninguna. El motivo se enseña.
 */
.page-head h1 + .lede {
  margin-top: 1rem;
}
.lede {
  max-width: 44rem;
  font-size: var(--fs-5);
  line-height: 1.55;
  color: var(--ink2);
  text-wrap: pretty;
}
.lede b {
  color: var(--ink);
  font-weight: 600;
}

/* ------------------------------------------------------ portada: texto editorial */

/*
 * El bloque editorial de la portada (bloque F1, 22/09/2026 — Antonio: «necesitamos texto en la
 * home, hay que conseguir que nos indexen bien»).
 *
 * Tres párrafos antes de la primera hoja son tres pantallas de texto en un teléfono, y quien llega
 * a un catálogo quiere ver una hoja. De ahí el reparto: en pantalla ancha la prosa va a DOS
 * columnas —cabe entera sin empujar la rejilla hacia abajo— y en el teléfono sólo se lee el primer
 * párrafo, con los otros dos detrás de «Leer más». En el HTML están siempre los tres: el buscador
 * los lee, que es justo para lo que se han escrito.
 */

/*
 * La banda de la portada es la del catálogo (`.hero`) con el texto de `home.json` dentro: aquí
 * sólo se afina lo que cambia por ser un título escrito y no una palabra. Un título de portada se
 * lee en dos o tres líneas; sin tope, en pantalla ancha se estira hasta el borde y deja de leerse
 * de una pasada.
 */
.home-intro h1 {
  max-width: 20em;
}
/*
 * Las cifras van dentro de la banda, apoyadas bajo el texto y separadas por un filete: no son la
 * entradilla, son el pie de la primera pantalla. `grid-column` las lleva de lado a lado, que a
 * partir de 52 rem son dos: el texto ocupa la primera y el motivo la segunda, y la línea de cifras
 * pasa por debajo de las dos. El margen de arriba se escribe aquí y sólo aquí: la línea no existe
 * fuera de la banda (revisor del bloque F, 23/09/2026).
 */
.hero .home-stats {
  grid-column: 1 / -1;
  margin-top: 1.9rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line2);
}

/*
 * La prosa y los enlaces de casa, ya fuera de la banda y sobre el papel de la página. El filete de
 * abajo los separa del «Catálogo» que viene detrás: lo que se acaba aquí es la presentación del
 * sitio, y lo que empieza debajo es la lista.
 */
.home-body {
  padding-bottom: 2.25rem;
  border-bottom: 1px solid var(--line2);
}

/*
 * La línea de cifras vivas. Cada apunte es una frase entera —«53 katana publicadas»— porque el
 * singular y el plural de seis lenguas no caben en un número pegado a un rótulo. Van en mincho y
 * con cifras tabulares, como la nota y el precio de la ficha, porque lo que se mira de ellas es el
 * número.
 *
 * En el teléfono los apuntes van uno debajo de otro y sin separador: puestos en fila se parten por
 * la mitad —«por época: Kotō 3, Shintō 34,» y el resto abajo— y el punto medio amanece al
 * principio de una línea, donde no separa nada. De 700 px en adelante sí caben en fila, y entonces
 * el punto va DETRÁS de cada apunte menos el último: si la línea se parte igual, el punto se queda
 * colgando al final de la anterior, que es donde un punto de separación no molesta.
 *
 * Que la raya la ponga el CSS y no el HTML no es capricho: es adorno entre elementos de una lista,
 * y un lector de pantalla que la leyera en voz alta no estaría diciendo nada. La lista sigue
 * siendo una lista, con un `<li>` por cifra.
 */
.home-stats {
  list-style: none;
  padding: 0;
  display: grid;
  justify-items: start;
  gap: 0.35rem;
  font-family: var(--mincho);
  font-size: var(--fs-5);
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
@media (min-width: 43.75rem) {
  .home-stats {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem 1rem;
  }
  .home-stats li:not(:last-child)::after {
    content: '\00b7';
    margin-left: 1rem;
    color: var(--ink2);
  }
}

.home-prose {
  margin-top: 1.25rem;
  max-width: 68rem;
}
.home-block {
  margin-top: 1.5rem;
}
.home-prose > .home-block:first-child {
  margin-top: 0;
}
.home-block h2 {
  font-size: var(--fs-5);
  margin-bottom: 0.35rem;
}
.home-block p {
  color: var(--ink2);
  line-height: 1.6;
  text-wrap: pretty;
}

.home-more > summary {
  margin-top: 1.25rem;
  color: var(--ai);
  font-size: var(--fs-3);
  font-weight: 600;
  cursor: pointer;
}

.home-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 2rem;
  margin-top: 1.75rem;
  font-size: var(--fs-3);
  font-weight: 600;
}

/*
 * A partir de 700 px el pliegue se deshace: el `<summary>` desaparece y los dos párrafos se leen
 * seguidos. `display: contents` saca el `<details>` de la caja —los párrafos pasan a ser hijos
 * directos de la prosa, que es lo que necesita el reparto a dos columnas— y `::details-content`
 * hace lo mismo en los motores que ya lo implementan. Las dos declaraciones dicen lo mismo a dos
 * generaciones de navegadores; sobrará una el día que todos entiendan la otra.
 */
@media (min-width: 43.75rem) {
  .home-more {
    display: contents;
  }
  .home-more::details-content {
    content-visibility: visible;
    block-size: auto;
  }
  .home-more > summary {
    display: none;
  }
}

@media (min-width: 62rem) {
  .home-prose {
    columns: 2;
    column-gap: 3rem;
  }
  /*
   * La prosa fluye de una columna a otra como en una página impresa, y lo único que no se parte es
   * el subtítulo ni el salto entre él y su párrafo. Con los tres bloques enteros (`break-inside:
   * avoid`) el reparto salía 1 + 2 y dejaba media columna en blanco: tres bloques nunca caen a
   * partes iguales.
   */
  .home-block h2 {
    break-after: avoid;
    break-inside: avoid;
  }
  /* En dos columnas el primer párrafo tampoco abre pegado al de al lado. */
  .home-prose > .home-block:first-child {
    margin-top: 1.5rem;
  }
}

/*
 * «Catálogo» dejó de ser el título de la página el 22/09/2026 y pasó a ser el de la lista: sigue
 * siendo una cabecera, pero más apretada, porque lo que la precede ya ha presentado el sitio.
 */
.catalogue-head {
  padding-block: 2.5rem 1.5rem;
}

/* ---------------------------------------------------------------- barra de filtros */

/*
 * La barra se pega bajo la cabecera y se pinta como ella: fondo a medias y desenfoque detrás
 * (pasada estética, 23/09/2026). Con el fondo opaco, la barra era un tabique que cortaba la
 * rejilla en dos; traslúcida, las tarjetas se ven pasar por debajo y la página sigue siendo una.
 */
.filters {
  position: sticky;
  top: 4rem;
  z-index: 30;
  background: color-mix(in srgb, var(--ji) 86%, transparent);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
  margin-bottom: 1.25rem;
}
/*
 * La barra envuelve SIEMPRE, no sólo en el teléfono (deuda del bloque A, 23/09/2026).
 *
 * Sus cinco piezas —resultados, buscador, orden, sentido y «Filtros»— miden 868 px juntas, así que
 * no cabían en una hilera y el desbordamiento no se quedaba en la barra: lo heredaba el documento y
 * el catálogo entero se arrastraba de lado en cualquier tableta. Medido con el navegador: desbordaba
 * a 700, 760 y 820 px (`scrollWidth` 891 contra `clientWidth` 760) y no a 640 ni a 900, así que el
 * tramo roto era ~660–860 px y no los 640–1.100 que se escribieron primero. Lo que crece al envolver
 * es el alto de la barra, que es lo barato.
 */
.filters-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  padding-block: 0.6rem;
}

.result-count {
  font-family: var(--mincho);
  font-weight: 700;
  font-size: var(--fs-4);
  white-space: nowrap;
  margin-right: auto;
}

.field {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.field label {
  font-size: var(--fs-2);
  color: var(--ink2);
}

.search {
  position: relative;
}
.search input {
  width: 13rem;
  padding: 0.35rem 2rem 0.35rem 0.75rem;
  border: 1px solid var(--line);
  border-radius: var(--pill);
  background: var(--hamon);
  font-size: var(--fs-3);
}
/*
 * El foco del buscador: el anillo del sistema, no un halo propio (tarea E1, 23/09/2026).
 *
 * Antes se anulaba el contorno y se dibujaba el foco con una sombra de `--ai2`, que es el índigo
 * más pálido de la paleta: 1,1:1 contra el fondo del campo, o sea nada, justo lo que WCAG 2.2 SC
 * 1.4.11 pide que se vea a 3:1. El borde índigo se queda porque dice «aquí se escribe»; quien dice
 * «aquí está el foco» es el contorno.
 */
.search input:focus-visible {
  border-color: var(--ai);
  outline: 2px solid var(--ai);
  outline-offset: 2px;
}
.search kbd {
  position: absolute;
  right: 0.55rem;
  top: 50%;
  transform: translateY(-50%);
  font: inherit;
  font-size: var(--fs-1);
  color: var(--ink2);
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 2px;
  padding: 0 0.3rem;
  pointer-events: none;
}
.search input:not(:placeholder-shown) + kbd,
.search input:focus + kbd {
  display: none;
}

/*
 * Un `<select>` no baja de lo que mide el texto de su opción más larga («Descendente», 191 px), y
 * en una hilera compartida eso empuja a lo que venga detrás. `min-width: 0` lo convierte en un
 * hijo flexible como los demás, que es lo que hace que la barra se parta por donde toca.
 */
.sort select,
.f-shop select {
  min-width: 0;
  padding: 0.3rem 0.5rem;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--hamon);
  font-size: var(--fs-3);
}

.filters-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  border: 1px solid var(--line);
  background: var(--hamon);
  border-radius: var(--r);
  padding: 0.35rem 0.85rem;
  font-size: var(--fs-3);
  white-space: nowrap;
}
.filters-toggle:hover {
  border-color: var(--ink2);
}
.filters-toggle[aria-expanded="true"] {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--ji);
}
/* Cuántos filtros hay puestos: con la hoja cerrada es lo único que se ve de ellos. */
.active-count {
  min-width: 1.25rem;
  padding: 0 0.3rem;
  border-radius: var(--pill);
  background: var(--ai);
  color: var(--ji);
  font-size: var(--fs-1);
  font-weight: 700;
  text-align: center;
}
.active-count[hidden] {
  display: none;
}

/*
 * Las dos columnas del catálogo: la lista y el panel de filtros (22/09/2026).
 *
 * De partida una sola, la de la lista, porque es la que tiene que funcionar en cualquier ancho y
 * sin JavaScript. La del panel se añade a partir de 1.100 px, que es donde caben 20 rem de filtros
 * sin robarle sitio a las fotos.
 */
.catalogue-layout {
  display: grid;
  gap: var(--gap);
}

/*
 * El panel, de teléfono: una hoja que sube desde el borde inferior.
 *
 * Fuera de la pantalla mientras está cerrada y no `display: none`, para que el movimiento exista y
 * para que lo de dentro conserve su tamaño. Quien no quiera movimiento no lo tendrá: la regla
 * general de `prefers-reduced-motion` apaga la transición.
 *
 * Cerrada va además `visibility: hidden` (22/09/2026): apartada sólo con la transformación, seguía
 * contando para el teclado y para el lector de pantalla, y el tabulador caía en controles que
 * están bajo el borde inferior de la pantalla. El guión le pone `inert`, y esto lo sostiene donde
 * `inert` no llegue. La visibilidad no se interpola: se esconde al acabar de bajar (retraso de
 * 0,24 s) y se enseña a la vez que empieza a subir (sin retraso), porque el guión enfoca el aspa
 * en cuanto la abre y no se puede enfocar lo que aún está invisible.
 */
.filters-panel {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 50;
  max-height: 85vh;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 1rem 1.25rem 1.25rem;
  background: var(--ji);
  border-top: 1px solid var(--line);
  border-radius: var(--r2) var(--r2) 0 0;
  box-shadow: var(--shadow-2);
  transform: translateY(100%);
  visibility: hidden;
  transition: transform var(--mov-2) ease, visibility 0s linear var(--mov-2);
}
.filters-panel[data-open="true"] {
  transform: none;
  visibility: visible;
  transition: transform var(--mov-2) ease, visibility 0s linear;
}

/* El velo que apaga el catálogo mientras la hoja está abierta. Pulsarlo la cierra. */
.filters-backdrop {
  position: fixed;
  inset: 0;
  z-index: 49;
  background: rgb(16 24 32 / 0.45);
}
.filters-backdrop[hidden] {
  display: none;
}

.filters-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.75rem;
}
.filters-title {
  font-family: var(--mincho);
  font-weight: 700;
  font-size: var(--fs-4);
}
.filters-close {
  border: 0;
  background: transparent;
  color: var(--ink2);
  font-size: var(--fs-6);
  line-height: 1;
  padding: 0 0.35rem;
}
.filters-close:hover {
  color: var(--ink);
}

.filters-fields {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: 1.25rem 2.5rem;
}

.filters-panel fieldset {
  border: 0;
  margin: 0;
  padding: 0;
  min-width: 0;
}
/* Los títulos de grupo, en versalitas: se leen como rótulos de vitrina y no compiten con la opción. */
.filters-panel legend {
  padding: 0;
  font-size: var(--fs-2);
  font-weight: 600;
  font-variant-caps: all-small-caps;
  letter-spacing: 0.09em;
  color: var(--ink2);
  margin-bottom: 0.5rem;
}

.option,
.switch {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  cursor: pointer;
  font-size: var(--fs-3);
}
.option {
  border: 1px solid var(--line);
  background: var(--hamon);
  border-radius: var(--pill);
  padding: 0.2rem 0.7rem;
  margin: 0 0.25rem 0.35rem 0;
  transition: border-color var(--mov-1), background var(--mov-1), color var(--mov-1);
}
.option:hover {
  border-color: var(--ai);
  background: var(--ai2);
}
.option:has(input:checked) {
  background: var(--ai);
  border-color: var(--ai);
  color: var(--ji);
}
.option:has(input:focus-visible) {
  outline: 2px solid var(--ai);
  outline-offset: 2px;
}
.option input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}
.option .tally {
  font-style: normal;
  font-size: var(--fs-1);
  opacity: 0.6;
  min-width: 1.1em;
  text-align: right;
}
/* Una opción que no deja nada se apaga, pero sigue siendo pulsable: dice cuánto hay, que es cero. */
.option.is-empty {
  opacity: 0.4;
}
.option.is-empty:hover {
  opacity: 0.75;
}

.switch {
  display: flex;
  margin-bottom: 0.3rem;
  color: var(--ink2);
}
.switch input {
  accent-color: var(--ai);
  width: 1rem;
  height: 1rem;
}
.switch:hover {
  color: var(--ink);
}

/* Etiquetas de lo que está filtrando ahora mismo, cada una con su aspa. */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  list-style: none;
  padding: 0 0 0.6rem;
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  border: 1px solid var(--ai);
  background: var(--ai2);
  color: var(--ai);
  border-radius: var(--pill);
  padding: 0.1rem 0.6rem;
  font-size: var(--fs-2);
}
/*
 * El aspa de las etiquetas de los filtros es un elemento de verdad desde el 22/09/2026, y no un
 * pseudoelemento, porque la prueba del panel pregunta por ella y un contenido de CSS no está en el
 * documento. La de la bandeja del comparador también: ver `.compare-thumb .x`.
 */
.chip-x {
  font-size: var(--fs-4);
  line-height: 1;
  opacity: 0.7;
}
.chip:hover {
  background: var(--ai);
  color: var(--hamon);
}
/*
 * La etiqueta ya lleva borde de acento, así que el anillo del sistema pegado a ella se lee como un
 * borde más grueso y no como «aquí está el foco». Un pelo más de separación y se despega: lo único
 * que cambia respecto al suelo, porque el color y el grosor son los del sitio (tarea E1).
 */
.chip:focus-visible {
  outline-offset: 3px;
}

/* -------------------------------------------------------- deslizadores y histograma */

.range {
  position: relative;
  height: 4.75rem;
  padding-top: 2.75rem;
}
.histogram {
  position: absolute;
  inset: 0 0.5rem auto;
  height: 2.25rem;
  display: flex;
  align-items: flex-end;
  gap: 1px;
  border-bottom: 1px solid var(--line2);
}
/* Un tramo sin piezas no dibuja nada: una barra de un píxel en cada hueco sería una línea de ruido
   justo encima del carril, indistinguible de él. */
.histogram i {
  flex: 1;
  height: var(--h, 0%);
  /* Acento a medio gas: el histograma es el telón de fondo de los dos pulsadores, no un control. */
  background: color-mix(in srgb, var(--ai) 60%, transparent);
  border-radius: 1px 1px 0 0;
  transition: background var(--mov-1);
}
/* Fuera del tramo elegido la barra se apaga: lo que hay ahí no se está enseñando. */
.histogram i[data-out] {
  background: var(--line);
}

.range .track {
  position: absolute;
  left: 0.5rem;
  right: 0.5rem;
  top: 3rem;
  height: 4px;
  background: var(--line);
  border-radius: 2px;
}
.range .fill {
  position: absolute;
  left: var(--from, 0%);
  right: calc(100% - var(--to, 100%));
  top: 0;
  height: 4px;
  background: var(--ai);
  border-radius: 2px;
}

/*
 * Los dos deslizadores comparten carril. Van uno encima de otro, transparentes salvo el pulsador,
 * y sin sucesos de puntero salvo en el pulsador mismo: si no, el de arriba se comería los clics
 * destinados al de abajo en toda la mitad que solapan.
 */
.range input[type="range"] {
  position: absolute;
  left: 0;
  right: 0;
  top: 2.65rem;
  width: 100%;
  height: 1.25rem;
  margin: 0;
  appearance: none;
  background: transparent;
  pointer-events: none;
}
.range input[type="range"]::-webkit-slider-runnable-track {
  height: 1.25rem;
  background: transparent;
}
.range input[type="range"]::-moz-range-track {
  height: 1.25rem;
  background: transparent;
}
.range input[type="range"]::-webkit-slider-thumb {
  appearance: none;
  pointer-events: auto;
  width: 1.125rem;
  height: 1.125rem;
  border-radius: 50%;
  background: var(--hamon);
  border: 2px solid var(--ai);
  cursor: grab;
}
.range input[type="range"]::-moz-range-thumb {
  pointer-events: auto;
  width: 0.875rem;
  height: 0.875rem;
  border-radius: 50%;
  background: var(--hamon);
  border: 2px solid var(--ai);
  cursor: grab;
}
/*
 * Los dos deslizadores: el contorno dice que el foco está en el carril y el anillo del pulsador,
 * cuál de los dos se mueve. Antes sólo estaba el anillo, y va en `--ai2` —casi el color del
 * panel—, con lo que en el tema oscuro el foco del precio no se veía (tarea E1, 23/09/2026).
 */
.range input[type="range"]:focus-visible {
  outline: 2px solid var(--ai);
  outline-offset: 2px;
}
.range input[type="range"]:focus-visible::-webkit-slider-thumb {
  box-shadow: 0 0 0 4px var(--ai2);
}
.range input[type="range"]:focus-visible::-moz-range-thumb {
  box-shadow: 0 0 0 4px var(--ai2);
}

.range-values {
  display: flex;
  justify-content: space-between;
  font-size: var(--fs-2);
  font-weight: 600;
  margin-top: -0.4rem;
  margin-bottom: 0.4rem;
  color: var(--ink2);
}

/* Las dos cajas: la cifra exacta, para quien no quiera pelearse con el pulsador. */
.range-boxes {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-bottom: 0.5rem;
  color: var(--ink2);
}
.range-box {
  flex: 1 1 0;
  min-width: 0;
  padding: 0.25rem 0.45rem;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--hamon);
  color: inherit;
  font: inherit;
  font-size: var(--fs-2);
}
/* La caja de la cifra exacta, con el mismo anillo que el buscador y por el mismo motivo. */
.range-box:focus-visible {
  border-color: var(--ai);
  outline: 2px solid var(--ai);
  outline-offset: 2px;
}

/*
 * El pie del panel: limpiar a la izquierda, ver resultados a la derecha.
 *
 * En la hoja se queda pegado al borde inferior mientras se recorre la lista de filtros: con nueve
 * grados de montura y dos histogramas, un botón «Ver resultados» al final del todo obliga a
 * desplazarse hasta abajo cada vez que se marca algo.
 */
.filters-actions {
  position: sticky;
  bottom: -1.25rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 1rem;
  padding-block: 0.75rem 1.25rem;
  border-top: 1px solid var(--line2);
  background: var(--ji);
}
#filters-clear {
  border: 0;
  background: transparent;
  padding: 0.35rem 0;
  font-size: var(--fs-3);
  color: var(--ink2);
  text-decoration: underline;
}
#filters-clear:hover {
  color: var(--ink);
}

/*
 * De 1.100 px en adelante el panel deja de ser una hoja y pasa a ser una columna pegajosa a la
 * derecha de la lista. Entonces el catálogo de al lado sigue vivo mientras se filtra, así que no
 * hace falta ni velo ni aspa: el botón de la barra lo pliega y lo despliega.
 */
@media (min-width: 68.75rem) {
  .catalogue-layout {
    grid-template-columns: minmax(0, 1fr) var(--rail-filters);
    align-items: start;
  }
  .filters-panel {
    position: sticky;
    inset: auto;
    top: 5.5rem;
    z-index: 20;
    max-height: calc(100vh - 7rem);
    border: 1px solid var(--line);
    border-radius: var(--r2);
    box-shadow: var(--shadow-1);
    transform: none;
    transition: none;
  }
  .filters-head {
    display: none;
  }
  /* En la columna no hace falta: el pie cabe entero y el botón de la barra ya la cierra. */
  .filters-actions {
    position: static;
    padding-bottom: 0;
  }
  #filters-apply {
    display: none;
  }
  /* Plegado, el panel se quita de en medio y la lista recupera el ancho de la página. */
  .filters-panel[data-open="false"] {
    display: none;
  }
  /* Desplegado es una columna a la vista: la visibilidad de la hoja no pinta nada aquí. */
  .filters-panel {
    visibility: visible;
  }
  .catalogue-layout:has(.filters-panel[data-open="false"]) {
    grid-template-columns: minmax(0, 1fr);
  }
  .filters-fields {
    grid-template-columns: minmax(0, 1fr);
    gap: 1.25rem;
  }
  .filters-backdrop {
    display: none;
  }
}

/* ------------------------------------------------------------------ la rejilla */

/*
 * El Catálogo es una REJILLA de láminas (pasada estética, 23/09/2026).
 *
 * Hasta hoy cada pieza era una fila a todo el ancho: a 1.440 px la foto quedaba pequeña a la
 * izquierda, el precio pequeño a la derecha y entre los dos medio metro de pasillo vacío. Un
 * catálogo de museo no se lee así; se recorre con la vista, y para eso las piezas tienen que estar
 * una al lado de la otra. La rejilla se llena sola: tres columnas en escritorio con el panel de
 * filtros abierto, cuatro sin él, dos en tableta y una en el teléfono, sin un solo punto de corte
 * escrito a mano. El `min(100%, 20rem)` es lo que impide que la columna pida más ancho del que hay
 * y el documento se arrastre de lado en una pantalla estrecha.
 */
.catalogue {
  list-style: none;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr));
  gap: 1.5rem;
  /*
   * Todas las láminas de una hilera, a la misma altura (cambio de criterio, 23/09/2026).
   *
   * E1b las había dejado sin estirar: con la foto apaisada y dos líneas de resumen, una pieza se
   * quedaba con un palmo de tarjeta en blanco antes del pie, y ese hueco se leía como un error de
   * maquetación. Lo que fallaba era el remedio, no el estirado —una hilera de tarjetas desiguales
   * es una escalera, y sus pies no se comparan de un barrido—. Ahora el hueco tiene dueño: el
   * resumen crece hasta donde llegue la lámina (`--summary-lines`), así que estirar no deja aire
   * muerto sino más texto de la pieza.
   */
  align-items: stretch;
}

/*
 * La aparición de la lista.
 *
 * Va en la lista y no en cada tarjeta a propósito: el guión filtra moviendo los nodos de sitio, y
 * volver a insertar un elemento reinicia su animación —con lo que cada tecla del buscador haría
 * parpadear el catálogo entero—. La lista, en cambio, se pinta una sola vez.
 */
@media (prefers-reduced-motion: no-preference) {
  .catalogue {
    animation: catalogue-in var(--mov-2) ease both;
  }
  @keyframes catalogue-in {
    from {
      opacity: 0;
      transform: translateY(6px);
    }
    to {
      opacity: 1;
      transform: none;
    }
  }
}

/*
 * Un hueco se dibuja, no se deja en blanco: un texto suelto en medio de la nada parece que la
 * página se ha roto. El marco de trazos dice «aquí no hay nada todavía», que es otra cosa.
 */
.empty,
.empty-catalogue {
  margin: 2.5rem 0;
  padding: 3rem 1.5rem;
  border: 1px dashed var(--line);
  border-radius: var(--r2);
  text-align: center;
  font-size: var(--fs-4);
  color: var(--ink2);
}

/* ------------------------------------------------------------ la lámina de una pieza */

/*
 * La tarjeta: una lámina de museo en tres bandas —foto, ficha y pie— y nunca en columnas.
 *
 * Las columnas eran lo que obligaba a la fila de ancho completo. Apiladas, la misma tarjeta cabe
 * en 20 rem y la rejilla decide cuántas caben; y como todas las láminas de una hilera se estiran a
 * la misma altura, sus pies —nota, precio y comparador— caen en la misma línea y se leen de un
 * barrido, que es lo que se hace al comparar diez piezas.
 *
 * `container-type: inline-size` la convierte en su propio contenedor de consulta: lo que la
 * tarjeta esconde cuando se estrecha ya no depende del ancho de la ventana —la misma tarjeta vive
 * en una rejilla de cuatro columnas, en la parte privada y en el teléfono— sino del ancho que de
 * verdad le ha tocado.
 */
.piece {
  /*
   * La escala de las hojas es de la tarjeta y no de la ventana. Antes bajaba de 2,6 a 2,1 px/cm
   * según el ancho de la pantalla porque la fila se estrechaba con ella; la lámina mide 20 rem en
   * cualquier pantalla, así que la escala se queda quieta y dos capturas a dos anchos distintos
   * siguen siendo comparables.
   */
  --px-cm: var(--px-cm-card);
  container-type: inline-size;
  position: relative;
  display: grid;
  grid-template-rows: auto 1fr auto;
  border: 1px solid var(--line2);
  border-radius: var(--r2);
  background: var(--surface-1);
  box-shadow: var(--shadow-1);
  overflow: hidden;
  transition: border-color var(--mov-1), box-shadow var(--mov-1);
}
.piece:hover {
  border-color: var(--line);
  box-shadow: var(--shadow-2);
}
.piece::after {
  /* Un teñido del periodo, tan tenue que sólo se nota al pasar por encima. */
  content: "";
  position: absolute;
  inset: 0;
  /*
   * Capa 2: por encima de la foto y de la barra del pie, que van en la 1. Las dos tienen fondo
   * propio y opaco, así que un teñido por debajo dejaba sin teñir justo las dos bandas que más
   * ocupan: la lámina se encendía por el centro y se quedaba fría por arriba y por abajo.
   */
  z-index: 2;
  border-radius: inherit;
  background: currentColor;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--mov-1);
}
.piece:hover::after {
  opacity: 0.03;
}

/*
 * El enlace de la pieza.
 *
 * Es el nombre, y se estira sobre la tarjeta entera con un pseudoelemento: se puede pulsar en
 * cualquier parte, pero el teclado se para una sola vez y lo que se anuncia es el nombre del
 * herrero. Lo que no puede hacerse es envolver con el enlace la foto y el nombre, que viven en
 * bandas distintas de la rejilla: eso obligaría a `display: contents`, y un enlace así **no
 * recibe el foco** en Chromium, de modo que el catálogo se quedaba fuera del alcance del teclado.
 */
.piece .piece-link {
  color: inherit;
  text-decoration: none;
}
.piece .piece-link::after {
  content: "";
  position: absolute;
  inset: 0;
  /*
   * Capa 0: el manto se pulsa, pero no tapa. Lo que tiene destino propio —la foto, que lleva a la
   * ficha, y los botones del pie— va en la capa 1 y le gana; el manto recoge lo demás.
   */
  z-index: 0;
  border-radius: inherit;
}
.piece .piece-link:focus-visible {
  outline: none;
}
.piece .piece-link:focus-visible::after {
  /*
   * Enfocado, el mismo manto sube a la capa 3 para que el anillo rodee la lámina ENTERA: en la 0
   * lo tapaban la foto y la barra del pie, y el anillo salía partido por arriba y por abajo.
   * Arriba sólo es un dibujo, así que suelta el puntero: si subiera pulsable, un clic del ratón
   * sobre un botón del pie mientras el nombre tiene el foco se lo llevaría el manto.
   */
  z-index: 3;
  pointer-events: none;
  outline: 2px solid var(--ai);
  outline-offset: -2px;
  border-radius: var(--r2);
}
/* Lo que se pulsa por su cuenta tiene que quedar por encima de ese manto. */
.piece .compare-btn,
.piece-action > * {
  position: relative;
  z-index: 1;
}

/* ------------------------------------------------------------ la banda de la foto */

.piece-media {
  position: relative;
  overflow: hidden;
  background: var(--surface-2);
}

/*
 * La banda entera es el enlace a la ficha (tarea B1, 23/09/2026), y va por encima del manto que el
 * nombre estira sobre la lámina: sin la capa, el clic sobre la foto se lo llevaría el nombre —que
 * desde hoy abre la lectura rápida— y la foto no llevaría a ninguna parte. Así queda lo pedido: la
 * foto manda a la ficha, el texto abre el cuadro.
 */
.piece-media .piece-cover {
  position: relative;
  z-index: 1;
  display: block;
  color: inherit;
  text-decoration: none;
}
.piece-media .piece-cover:focus-visible {
  outline: 2px solid var(--ai);
  outline-offset: -3px;
}

/*
 * El puesto, en un disco traslúcido sobre la esquina de la foto. Grande y en serif: es el primer
 * dato de la lámina y el que ordena el catálogo, así que se lee antes que el nombre.
 */
.piece-media .rank {
  position: absolute;
  top: 0.75rem;
  left: 0.75rem;
  z-index: 2;
  display: grid;
  place-items: center;
  min-width: 2.5rem;
  height: 2.5rem;
  padding-inline: 0.45rem;
  border-radius: var(--pill);
  background: color-mix(in srgb, var(--surface-1) 78%, transparent);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}
.piece-media .rank b {
  font: 700 var(--fs-5) / 1 var(--mincho);
  color: var(--ink2);
  /* Con más de 99 piezas el puesto tiene tres cifras y la caja lo partía en dos líneas. */
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
/* Los diez primeros llevan el oro del ranking; el resto, la tinta apagada. */
.piece:nth-child(-n + 10) .rank b {
  color: var(--kin-text);
}

.piece-media .thumb {
  display: block;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--surface-2);
}
.piece-media .thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--mov-2) ease;
}
/*
 * La forma de la foto NO cambia la banda, sólo el encuadre (Antonio, 23/09/2026: «lo que sea por
 * igualar»). Hasta hoy la hoja tumbada abría en 5:2 y la montura de pie en 1:1, y una hilera del
 * catálogo eran tres láminas con tres cabeceras distintas: lo primero que se ve de cada pieza medía
 * distinto en cada una, que es justo lo que impide compararlas de un barrido.
 *
 * Y quien decide el encuadre es una clase del generador, `is-cover` o `is-contain` (`coverFit` en
 * `render/card.ts`), no las clases de FORMA —`is-wide`, `is-tall`, `is-sliver`—, que salen de los
 * umbrales de ELEGIR portada. Colgarlo de la forma fue el fallo que cazó la revisión xhigh: entre
 * 0,8 y 2,5 cabe la foto cuadrada, y 22 portadas del catálogo lo son; recortadas a 4:3 perdían un
 * cuarto de la pieza —la punta o la empuñadura— y ninguna clase lo decía.
 *
 * A sangre se recorta sólo lo que ya viene casi en 4:3 (de 1,15 a 1,55), donde el recorte se lleva
 * un dedo de aire y no la pieza. Lo demás se pinta entero dentro de la banda, sobre el pedestal de
 * papel de la propia lámina, que es el fondo de `.piece-media` y para eso está.
 */
.piece-media .thumb.is-contain img {
  object-fit: contain;
}
/*
 * El acercamiento al pasar por encima, sólo para quien no ha pedido lo contrario: es movimiento
 * que nadie ha disparado a propósito, y con `prefers-reduced-motion` no se hace ni de golpe.
 */
@media (prefers-reduced-motion: no-preference) {
  .piece:hover .thumb img,
  .piece:focus-within .thumb img {
    transform: scale(1.02);
  }
}
.no-photo {
  display: block;
  height: 100%;
  background: repeating-linear-gradient(-45deg, var(--line2) 0 6px, transparent 6px 12px);
}

/* -------------------------------------------------------------- la banda de la ficha */

/*
 * La ficha es a su vez dos columnas: el texto y, a su derecha, la firma en vertical —que es como
 * está escrita en la espiga—. Las filas se declaran porque la firma las cruza de arriba abajo, y
 * un `grid-row: 1 / -1` sin filas explícitas se queda en la primera.
 */
.piece-body {
  /*
   * El cuerpo se pulsa para leer (tarea B4, 23/09/2026): con guión abre el cuadro de lectura
   * rápida, y sin él lleva a la ficha por el manto del nombre. En los dos casos pulsar hace algo,
   * así que el puntero no promete nada que no vaya a pasar.
   */
  cursor: pointer;
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--mei-col);
  /*
   * Cuatro filas: nombre, datos, etiquetas y resumen. La última es `minmax(--summary-min, 1fr)` y
   * es la que hace que las láminas estiradas no tengan aire muerto: se come todo lo que sobre en
   * la tarjeta —que es justo lo que le sobraba a la más baja de la hilera— y nunca baja de dos
   * líneas, de modo que a una sola columna (teléfono), donde no sobra nada, la lámina es la que
   * era. Como la fila tiene mínimo FIJO, el resumen no empuja la altura de la lámina por mucho
   * texto que lleve: mide el hueco, no lo crea.
   */
  grid-template-rows: auto auto auto minmax(var(--summary-min), 1fr);
  align-content: start;
  gap: 0 0.75rem;
  padding: 1.1rem var(--card-pad) 1rem;
}
.piece-body > * {
  grid-column: 1;
}

.piece-name {
  font-family: var(--mincho);
  font-size: var(--fs-6);
  line-height: 1.15;
  text-wrap: balance;
}
.piece:hover .piece-name {
  color: var(--ai);
}

.piece-body .mei {
  grid-column: 2;
  grid-row: 1 / -1;
  justify-self: center;
  align-self: start;
  writing-mode: vertical-rl;
  font-family: var(--mincho);
  font-size: var(--fs-2);
  line-height: 1.5;
  letter-spacing: 0.06em;
  color: var(--ink2);
  max-height: 9rem;
  overflow: hidden;
}
.piece-body .mei.is-mumei {
  writing-mode: horizontal-tb;
  justify-self: end;
  font-size: var(--fs-1);
  letter-spacing: 0.02em;
  opacity: 0.75;
  max-height: none;
}
/*
 * En una columna estrecha —una rejilla de cuatro, media pantalla en la parte privada— la firma en
 * vertical le roba al nombre el ancho que necesita para no partirse en cinco líneas. Por debajo de
 * 17 rem de TARJETA, no de ventana, se retira: está en la ficha, que es donde se lee entera.
 */
@container (max-width: 17rem) {
  .piece-body {
    grid-template-columns: minmax(0, 1fr);
  }
  .piece-body .mei {
    display: none;
  }
}

/* La línea de datos, en versalitas: periodo, año, provincia y centímetros. */
.piece-body .meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  font-size: var(--fs-3);
  font-variant-caps: all-small-caps;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.07em;
  color: var(--ink2);
  margin-top: 0.5rem;
}
/*
 * Los separadores.
 *
 * El generador los emite como elementos sueltos entre dato y dato. Sueltos se comportan mal: en
 * cuanto la línea se parte —y en alemán se parte— uno de ellos amanece al principio del renglón
 * siguiente, colgando de nada. Se esconden y se vuelven a dibujar como parte del dato anterior,
 * que es a lo que pertenecen: así el que sobra queda al final de la línea, donde se lee como un
 * «sigue» en vez de como un error.
 */
.meta .sep,
.piece-meta .sep {
  display: none;
}
.meta > span:not(:last-child)::after,
.piece-meta > span:not(:last-child)::after {
  content: "";
  display: inline-block;
  width: 1px;
  height: 0.8em;
  margin-inline: 0.65rem -0.05rem;
  background: var(--line);
  vertical-align: baseline;
}
.sep {
  display: inline-block;
  width: 1px;
  height: 0.8em;
  margin-inline: 0.65rem;
  background: var(--line);
}
.meta .period {
  font-weight: 600;
}
.piece-meta .cert {
  color: var(--kin-text);
  font-weight: 600;
}

/*
 * Las etiquetas: el papel y la disponibilidad (23/09/2026). Salen de la línea de datos porque no
 * son datos de la hoja sino su estado en el mundo —quién la certificó y si se puede comprar—, y
 * porque son lo único de la lámina que hay que poder mirar sin leer. El papel va en oro, que es el
 * color que este sitio reserva a los certificados.
 */
.piece-body .tags {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.7rem;
}
.piece-body .tags .cert {
  padding: 0.05rem 0.55rem;
  border: 1px solid color-mix(in srgb, var(--kin) 50%, transparent);
  border-radius: var(--pill);
  background: color-mix(in srgb, var(--kin) 12%, transparent);
  font-size: var(--fs-1);
  font-weight: 600;
  line-height: 1.5;
  color: var(--kin-text);
  white-space: nowrap;
}
.piece-body .tags .badge {
  margin-top: 0;
}

.period.koto,
.piece[data-period="KOTO"]::after {
  color: var(--koto);
}
.period.shinto,
.piece[data-period="SHINTO"]::after {
  color: var(--shinto);
}
.period.shinshinto,
.piece[data-period="SHINSHINTO"]::after {
  color: var(--shinshinto);
}
.period.gendai,
.piece[data-period="GENDAI"]::after {
  color: var(--gendai);
}

/*
 * El resumen: lo único de la lámina que se estira.
 *
 * Ocupa su fila entera (nada de `align-self: start`) para que su caja MIDA el hueco libre, que es
 * lo que el guión lee para decidir cuántas líneas caben. El recorte es una variable: sin
 * JavaScript se queda en las dos de siempre —y el hueco, en blanco: degradación aceptable, el
 * catálogo se lee igual—; con él, `summary-fit.ts` escribe `--summary-lines` en cada lámina. El
 * `line-clamp` corta SIEMPRE por línea entera y pone sus puntos suspensivos, nunca a media letra,
 * y el `overflow: hidden` con `min-height: 0` impide que el texto que no cabe empuje al pie.
 */
.piece-body .summary {
  font-size: var(--fs-3);
  line-height: 1.55;
  color: var(--ink2);
  margin-top: 0.7rem;
  min-height: 0;
  display: -webkit-box;
  -webkit-line-clamp: var(--summary-lines, 2);
  -webkit-box-orient: vertical;
  overflow: hidden;
  /*
   * Y un techo de esas mismas líneas (23/09/2026). El recorte de Chromium corta el texto y pone sus
   * puntos suspensivos, pero NO esconde lo que asoma cuando la caja es más alta que las líneas
   * recortadas: al pie de la lámina quedaba media frase cortada por la mitad. El techo la tapa. Va
   * en `em` porque la interlínea es 1,55 del cuerpo del propio párrafo; `summary-fit.ts` lo suelta
   * (`max-height: none`) mientras mide, que si no mediría el techo en vez del hueco.
   */
  max-height: calc(var(--summary-lines, 2) * 1.55em);
}

/* ------------------------------------------------------------- carril de hojas */

.silhouette {
  margin: 0;
}
.silhouette svg {
  width: 100%;
  height: auto;
  overflow: visible;
}
.silhouette .blade {
  fill: currentColor;
  stroke: none;
}
/* El machi se dibuja en el color del fondo: es la muesca, no una línea añadida. */
.silhouette .machi {
  fill: none;
  stroke: var(--ji);
  stroke-width: 1.6;
}

/* --------------------------------------------------------------- el pie de la lámina */

/*
 * La barra del pie: la nota, el precio y lo que se pulsa, en una hilera sobre la superficie
 * hundida. Es lo que se compara de lámina a lámina, así que va a ras de suelo en todas: con la
 * rejilla estirando las tarjetas de una hilera a la misma altura, los pies caen en una línea.
 *
 * Entre el precio y el comparador queda la ranura que rellena la parte privada; aquí no lleva nada
 * más, y por eso lo de dentro no puede asomar a este lado ni por descuido.
 */
.piece-action {
  /*
   * Por delante del manto del nombre (revisión xhigh, 23/09/2026): `.piece-link::after` se estira
   * por toda la lámina, así que sin esto pulsar la silueta —o el hueco de la barra— abría la
   * lectura rápida desde una banda que no es texto. Antonio pidió que la abriera «la parte del
   * texto»; la barra del pie es dato y botones.
   */
  position: relative;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.9rem;
  padding: 0.7rem var(--card-pad);
  border-top: 1px solid var(--line2);
  background: var(--surface-2);
}

/*
 * La nota, como sello con anillo. El anillo lo dibuja un SVG de 40 unidades con `pathLength="100"`,
 * y por eso `--v` va sin unidad: un tanto por ciento en `stroke-dasharray` se resolvería contra la
 * diagonal del `viewBox` —36 unidades— y no contra la circunferencia, con lo que el arco caería
 * donde no es. Con la longitud normalizada a 100, el número ES el tanto por ciento.
 */
.score:has(.ring) {
  position: relative;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 3.5rem;
  height: 3.5rem;
}
.score .ring {
  position: absolute;
  inset: 0;
}
.score .ring svg {
  display: block;
  width: 100%;
  height: 100%;
  /* El arco arranca arriba, como en un reloj, y no a las tres. */
  transform: rotate(-90deg);
}
.ring-track {
  fill: none;
  stroke: var(--line);
  stroke-width: 2.5;
}
.ring-value {
  fill: none;
  stroke: var(--ai);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-dasharray: var(--v, 0) 100;
}
/* La cifra cabe dentro del anillo con su decimal: «72,5» son cuatro caracteres, no dos. */
.score:has(.ring) b {
  font: 700 var(--fs-3) / 1 var(--mincho);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}
/* El «/100» se dice, no se pinta: dentro del sello no cabe, y el anillo ya cuenta sobre cuánto va. */
.score:has(.ring) small {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.piece-action .price {
  flex: 1 1 auto;
  min-width: 0;
}
.piece-action .price b {
  display: block;
  font: 700 var(--fs-5) / 1.2 var(--mincho);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.badge {
  display: inline-block;
  margin-top: 0.4rem;
  padding: 0.05rem 0.55rem;
  border: 1px solid currentColor;
  border-radius: var(--pill);
  font-size: var(--fs-1);
  line-height: 1.5;
  white-space: nowrap;
}
.badge-status.is-available {
  color: var(--shinto);
}
.badge-status.is-reserved {
  color: var(--kin-text);
}
.badge-status.is-sold {
  color: var(--ink2);
  opacity: 0.8;
}

/*
 * El botón de comparar, siempre pintado (22/09/2026). Antes era una casilla con `opacity: 0` que
 * sólo aparecía al pasar el ratón: en un móvil eso es no tener comparador. Quien dice si la pieza
 * está elegida es `aria-pressed`, que además es lo que anuncia el lector de pantalla.
 */
.compare-btn {
  /* Al final de la barra del pie, pegado a su borde derecho. */
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  background: var(--surface-1);
  border: 1px solid var(--line);
  border-radius: var(--pill);
  padding: 0.25rem 0.75rem;
  font: inherit;
  font-size: var(--fs-2);
  color: var(--ink2);
  cursor: pointer;
  transition: background-color var(--mov-1), border-color var(--mov-1), color var(--mov-1);
}
.compare-btn .ico {
  width: 0.9em;
  height: 0.9em;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
}
.compare-btn:hover {
  border-color: var(--ai);
  color: var(--ai);
}
/*
 * Pulsado: relleno de acento y la tinta del fondo de la página. Blanco no vale —lo que se hizo el
 * 22/09 y se cazó en la revisión—: en tema oscuro el acento es azul pálido y el blanco encima se
 * queda en 2,2:1 con letra de 12 px. `--ji` acompaña al tema y pasa de 8:1 en los dos
 * (`site-css.test.ts`, «contraste sobre el acento»).
 */
.compare-btn[aria-pressed="true"] {
  background: var(--ai);
  border-color: var(--ai);
  color: var(--ji);
}
.compare-btn[aria-pressed="true"] .ico {
  fill: currentColor;
  stroke: none;
}
.compare-btn:focus-visible {
  outline: 2px solid var(--ai);
  outline-offset: 2px;
}

/*
 * La silueta de la hoja, al cierre del pie y en hilera propia (Antonio, 23/09/2026).
 *
 * Hasta hoy era una marca de agua sobre la portada y ahí mentía: la hoja va dibujada en
 * centímetros de verdad y la foto no, así que encima de una saya fotografiada en primer plano el
 * ojo leía las dos a la misma escala —«esa saya sería de 40 cm de grosor»—. Aquí no se superpone a
 * nada: es el último dato de la barra.
 *
 * Y va en hilera propia, no al lado de los botones: a 20 rem de lámina el pie deja 280 px de ancho
 * y la hoja más larga del catálogo se lleva 230 —95,85 cm de dibujo a 2,4 px cada uno, con el machi
 * anclado a 3,25 rem—, así que no cabe al lado de dos botones en ninguna de las dos partes.
 *
 * La hilera la abre el ENVOLTORIO y no la figura (revisión xhigh, 23/09/2026). Un `flex: 0 0 100%`
 * puesto a la propia hoja la pone en su renglón, sí, pero de paso le anula el `width`: en una caja
 * flexible una `flex-basis` distinta de `auto` manda sobre el ancho declarado, y las 53 hojas se
 * dibujaban con el ancho del pie —370 px las 53 a 1440— con la escala colgando de la ventana. Con
 * el envoltorio ocupando la hilera, la figura no es un elemento flexible y su `width` en
 * centímetros es el que manda.
 *
 * El `margin-left` es lo que hace que sirva de algo: ancla el MACHI —no el borde de la espiga— a
 * 3,25 rem del comienzo del pie en todas las láminas, de modo que lo que sobresale a la derecha es,
 * literalmente, la longitud de la hoja y dos láminas vecinas se comparan de un barrido. La escala
 * es la de la tarjeta (`--px-cm`, que en `.piece` vale `--px-cm-card`) y no cambia con la ventana.
 */
.piece-action .blade-row {
  flex: 0 0 100%;
  min-width: 0;
}
.piece-action .card-blade {
  /*
   * Con `max(0px, …)` (revisión xhigh, 23/09/2026): el anclaje del machi es una RESTA, y la hoja
   * más larga del catálogo la deja en −0,8 px. Un margen negativo no ancla, recorta: la punta de
   * la espiga se salía por la izquierda del pie y la lámina, que va con `overflow: hidden`, se la
   * comía. Donde la cuenta vale, manda; donde saldría negativa, la hoja arranca en el borde.
   */
  margin-left: max(0px, calc(3.25rem - var(--machi-cm) * var(--px-cm)));
  width: calc(var(--blade-cm) * var(--px-cm));
  color: var(--ink2);
  opacity: 0.75;
  pointer-events: none;
}
.piece .silhouette .machi {
  /* La muesca se dibuja en el color de lo que hay detrás: aquí, la superficie del pie. */
  stroke: var(--surface-2);
}

.status-note {
  max-width: var(--prose);
  margin: 2.5rem 0 0;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
  font-size: var(--fs-2);
  color: var(--ink2);
}

/* ------------------------------------------------------------------ comparador */

/*
 * La bandeja (revisión del bloque A, 23/09/2026). A 390 px no cabía: el carril de las elegidas se
 * quedaba en cero ancho —las aspas de quitar no se veían— y «Vaciar» acababa con su borde derecho
 * en x=408 con la ventana en 390.
 *
 * Sigue siendo una línea de flex, y a propósito: la bandeja no tiene ancho propio —se ancha con lo
 * que lleva dentro—, y en cuanto se le pone `flex-wrap`, ese ancho pasa a ser el de su elemento MÁS
 * ancho en vez de el de la suma. Medido a 1440 px: con `flex-wrap` la bandeja se quedaba en 753 px
 * y apilaba los controles en cuatro líneas teniendo 1.400 de sitio. Lo que cede cuando no hay sitio
 * es el carril, que puede encoger a cero y desplazarse de lado; envolver se queda para el móvil,
 * donde la bandeja sí tiene ancho fijo (`left`/`right`) y es lo que hace falta.
 */
.compare-tray {
  position: fixed;
  left: 50%;
  bottom: 1.25rem;
  transform: translateX(-50%);
  z-index: 45;
  display: flex;
  align-items: center;
  gap: 0.5rem 0.75rem;
  max-width: calc(100vw - 2rem);
  padding: 0.6rem 1rem;
  background: var(--ink);
  color: var(--ji);
  border-radius: var(--pill);
  box-shadow: var(--shadow-2);
}
.compare-count {
  flex: 0 0 auto;
  font-family: var(--mincho);
  font-weight: 700;
  white-space: nowrap;
}
.compare-list {
  flex: 1 1 auto;
  /* Es el carril el que encoge y se desplaza; si no puede, empuja a los botones fuera. */
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 0.35rem;
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: thin;
}

/*
 * Cada elegida, con su portada (especificación §1: «la bandeja con las miniaturas de las
 * elegidas»). La foto se clona de la tarjeta, así que no se pide nada dos veces, y el botón entero
 * es el que quita la pieza: el aspa sólo lo dibuja.
 */
.compare-thumb {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  max-width: 11rem;
  padding: 0.2rem 0.5rem 0.2rem 0.2rem;
  border: 1px solid transparent;
  border-radius: var(--pill);
  background: color-mix(in srgb, var(--ji) 18%, transparent);
  color: inherit;
  font: inherit;
  font-size: var(--fs-2);
  cursor: pointer;
  transition: background-color var(--mov-1);
}
.compare-thumb img,
.compare-thumb .no-photo {
  flex: 0 0 auto;
  width: 2rem;
  height: 2rem;
  border-radius: var(--r1);
  object-fit: cover;
  background: color-mix(in srgb, var(--ji) 12%, transparent);
}
/* La portada que no viene casi en 4:3 se enseña entera, como en la lámina: ver `render/card.ts`. */
.compare-thumb img.is-contain {
  object-fit: contain;
}
/* El nombre se recorta; el aspa que lo quita se queda siempre a la vista. */
.compare-thumb .name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.compare-thumb .x {
  flex: 0 0 auto;
  font-size: var(--fs-4);
  line-height: 1;
  opacity: 0.7;
}
.compare-thumb:hover {
  background: color-mix(in srgb, var(--ji) 32%, transparent);
}
.compare-thumb:focus-visible {
  outline: 2px solid var(--ji);
  outline-offset: 2px;
}

/*
 * El aviso del tope: su propia banda, a todo el ancho de la bandeja y justo encima de ella. Metido
 * en la fila de los controles se quedaba en 71 px de ancho y 166 de alto a 390 px, e inflaba la
 * bandeja de 54 a 186; y metido en una segunda línea, la bandeja dejaba de poder anchearse con su
 * contenido. Fuera del flujo no hace ninguna de las dos cosas: aparece y desaparece sin mover un
 * solo control.
 */
.compare-limit {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(100% + 0.4rem);
  margin: 0;
  padding: 0.45rem 1rem;
  border-radius: var(--r2);
  background: var(--ink);
  box-shadow: var(--shadow-2);
  font-size: var(--fs-2);
  white-space: normal;
  text-align: center;
  /* Bermellón sobre la banda oscura no se lee; mezclado con su tinta pasa de 6:1 en los dos temas. */
  color: color-mix(in srgb, var(--shu) 45%, var(--ji));
}
/*
 * Vacío no ocupa nada, pero NO desaparece: una región `role="status"` escondida con `display: none`
 * o con `hidden` no está en el árbol de accesibilidad y no anuncia lo que se le escriba después.
 * Son las declaraciones de `.visually-hidden`, escritas aquí porque la clase la pone el generador y
 * esto depende de si hay texto.
 */
.compare-limit:empty {
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
  overflow: hidden;
  clip-path: inset(50%);
}

.cta {
  border: 0;
  border-radius: var(--pill);
  padding: 0.4rem 1.1rem;
  background: var(--ai);
  color: var(--ji);
  font-weight: 600;
  font-size: var(--fs-3);
  white-space: nowrap;
}
.cta:hover {
  background: color-mix(in srgb, var(--ai) 85%, var(--ink));
}
.cta:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
.compare-tray .cta {
  background: var(--ji);
  color: var(--ink);
}
.compare-tray .link {
  border: 0;
  background: transparent;
  color: inherit;
  opacity: 0.7;
  font-size: var(--fs-2);
  text-decoration: underline;
  white-space: nowrap;
}
.compare-tray .link:hover {
  opacity: 1;
}

dialog {
  border: 1px solid var(--line);
  border-radius: var(--r2);
  background: var(--hamon);
  color: var(--ink);
  padding: 0;
  max-width: min(64rem, calc(100vw - 2rem));
  max-height: calc(100dvh - 3rem);
}
dialog::backdrop {
  background: rgb(10 14 18 / 0.55);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
}

.dialog-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--line);
}
.dialog-head h2 {
  font-size: var(--fs-5);
}
.close {
  border: 1px solid var(--line);
  background: transparent;
  border-radius: var(--r);
  padding: 0.25rem 0.7rem;
  font-size: var(--fs-2);
  color: var(--ink2);
}
.close:hover {
  border-color: var(--ink);
  color: var(--ink);
}
.dialog-body {
  padding: 1.25rem;
  overflow: auto;
}

.compare-table {
  border-collapse: collapse;
  width: 100%;
  font-size: var(--fs-3);
}
.compare-table th,
.compare-table td {
  border-bottom: 1px solid var(--line2);
  padding: 0.5rem 0.75rem;
  text-align: left;
  vertical-align: top;
}
.compare-table thead th {
  border-bottom: 1px solid var(--line);
  vertical-align: bottom;
}
.compare-table thead img {
  width: 100%;
  max-width: 8rem;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--r1);
  margin-bottom: 0.5rem;
}
/* La columna copia el `<img>` de la fila sin su envoltorio: el encuadre viaja en la propia imagen. */
.compare-table thead img.is-contain {
  object-fit: contain;
  background: var(--ji);
}
.compare-table thead img.is-tall {
  aspect-ratio: 1 / 1;
}
.compare-table thead a {
  font-family: var(--mincho);
  font-weight: 700;
  font-size: var(--fs-4);
}
.compare-table tbody th {
  font-weight: 400;
  color: var(--ink2);
  white-space: nowrap;
}
/* Las siete líneas de la nota, con la misma barra que la ficha: comparar notas de memoria, número
   contra número, es justo lo que el cuadro tiene que ahorrar. */
.compare-score-head th {
  padding-top: 1.25rem;
  font-family: var(--mincho);
  font-weight: 700;
  color: var(--ink);
  white-space: normal;
}
.compare-score .bar {
  height: 6px;
  min-width: 4rem;
  background: var(--line);
  border-radius: 3px;
  overflow: hidden;
}
.compare-score .bar::after {
  content: "";
  display: block;
  height: 100%;
  width: var(--v, 0%);
  background: var(--ai);
}
.compare-score small {
  display: block;
  margin-top: 0.25rem;
  font-size: var(--fs-1);
  color: var(--ink2);
  white-space: nowrap;
}

/* La silueta viaja copiada de su fila, donde estaba posicionada sobre el carril: aquí vuelve al
   flujo, y a una escala común a las columnas para que se sigan pudiendo comparar. */
.compare-table .silhouette {
  position: static;
  transform: none;
  margin-top: 0.75rem;
  color: var(--ink2);
  width: calc(var(--blade-cm) * 1.9px);
}

/* ---------------------------------------------------------------- ficha: cabecera */

.piece-page {
  padding-top: 2.5rem;
}

.piece-header {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.5rem 2rem;
  padding-bottom: 2rem;
}
.piece-header .ref {
  grid-column: 1 / -1;
  display: flex;
  gap: 1rem;
  font-size: var(--fs-1);
  letter-spacing: 0.08em;
  color: var(--ink2);
}
.ref-code {
  font-weight: 600;
  color: var(--ink);
}

.piece-title {
  display: flex;
  align-items: flex-start;
  gap: 1.25rem;
}
.piece-title h1 {
  margin-top: 0.35rem;
}
/* La firma, en vertical junto al título: es como está escrita en la espiga. */
.piece-title .mei {
  writing-mode: vertical-rl;
  font-family: var(--mincho);
  font-size: var(--fs-4);
  letter-spacing: 0.1em;
  line-height: 1.4;
  color: var(--ink2);
  /* La línea va entre el nombre y la firma: las une en vez de dejar la firma colgando. */
  border-left: 1px solid var(--line);
  padding-left: 1rem;
  max-height: 12rem;
}
.piece-title .mei.mumei {
  writing-mode: horizontal-tb;
  border: 0;
  padding: 0;
  font-size: var(--fs-3);
  align-self: center;
}

.piece-header .summary {
  grid-column: 1;
  max-width: var(--prose);
  font-size: var(--fs-4);
  line-height: 1.55;
  color: var(--ink2);
  margin-top: 0.75rem;
}
.piece-meta {
  grid-column: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  font-size: var(--fs-3);
  color: var(--ink2);
  margin-top: 0.75rem;
}
.piece-meta .cert {
  color: var(--kin-text);
  font-weight: 600;
}

.piece-blade {
  grid-column: 1 / -1;
  width: calc(var(--blade-cm) * var(--px-cm-piece));
  max-width: 100%;
  margin-top: 1.5rem;
  color: var(--ink2);
}
.blade-caption {
  grid-column: 1 / -1;
  font-size: var(--fs-1);
  color: var(--ink2);
  margin-top: 0.4rem;
}
/*
 * La regla de la escala, bajo el pie de la silueta (23/09/2026).
 *
 * Venía de colgar encima de la rejilla del catálogo, donde desde la lámina no medía nada: las
 * siluetas ya no comparten carril, cada una vive en el pie de su tarjeta. Aquí sí mide: hay UNA
 * hoja dibujada a escala y el pie dice que está alineada por el machi, así que un segmento de diez
 * centímetros es con lo que se lee. Se dibuja con la MISMA variable que da el ancho a la silueta
 * (`--px-cm-piece`): si allí cambia la escala, la regla cambia con ella o deja de ser una regla.
 */
.blade-key {
  grid-column: 1 / -1;
  display: flex;
  align-items: flex-end;
  gap: 0.4rem;
  margin-top: 0.4rem;
  font-size: var(--fs-1);
  font-variant-caps: all-small-caps;
  letter-spacing: 0.08em;
  color: var(--ink2);
}
.blade-key span {
  display: flex;
  align-items: flex-end;
  gap: 0.4rem;
  white-space: nowrap;
}
.blade-key span::before {
  content: "";
  width: calc(10 * var(--px-cm-piece));
  height: 0.45rem;
  border: 1px solid var(--line);
  border-top: 0;
}

/* ---------------------------------------------------------------- ficha: galería */

.gallery {
  margin-bottom: 3rem;
}
.gallery-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.5rem;
  list-style: none;
  padding: 0;
}
.gallery-grid li {
  min-width: 0;
}
/* La primera foto es lo más grande de la página: es lo que se ha venido a ver. */
.gallery-grid .cover {
  grid-column: 1 / -1;
}
/*
 * En mosaico desde la pasada estética del 23/09/2026: la portada ocupa tres cuartos de la primera
 * fila y la siguiente foto se le pone al lado; las demás bajan a la hilera de abajo. Antes la
 * portada era una banda a todo lo ancho con la rejilla debajo, y entre las dos partían la página
 * en dos bloques que no se miraban juntos.
 *
 * La portada ocupa UNA fila y no dos: estas fotos son de hojas tumbadas, de hasta diez a uno, y en
 * un hueco del alto de dos miniaturas la hoja se queda en una rayita en medio de un campo de aire.
 * Con una, el hueco se parece a la foto.
 *
 * Y sólo cuando hay de la tercera en adelante (`:has`): con dos fotos el mosaico deja la hilera de
 * abajo vacía.
 */
@media (min-width: 45rem) {
  .gallery-grid:has(li:nth-child(3)) .cover {
    grid-column: 1 / 4;
    grid-row: 1;
  }
  .gallery-grid:has(li:nth-child(3)) .cover button {
    height: 100%;
    max-height: none;
  }
  .gallery-grid:has(li:nth-child(3)) .cover img {
    height: 100%;
    max-height: none;
    object-fit: contain;
  }
}
/* La misma caja de miniatura que la tarjeta del catálogo: esquina de `--r1` y borde tenue. */
.gallery-grid button {
  display: block;
  width: 100%;
  padding: 0;
  border: 1px solid var(--line2);
  border-radius: var(--r1);
  background: var(--hamon);
  overflow: hidden;
  cursor: zoom-in;
}
/*
 * La foto de portada se enseña entera, sin recortar. Estas fotos son de hojas tumbadas a lo largo
 * —relaciones de hasta diez a uno— y cualquier recorte en una proporción fija se queda con una
 * franja de fondo de estudio. Las demás sí se recortan: en una rejilla importa más que casen.
 */
.gallery-grid .cover button {
  cursor: zoom-in;
  max-height: 34rem;
}
.gallery-grid .cover img {
  width: 100%;
  max-height: 34rem;
  height: auto;
  object-fit: contain;
}
.gallery-grid li:not(.cover) button {
  aspect-ratio: 4 / 3;
}
.gallery-grid li:not(.cover) img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.gallery-grid img {
  transition: transform var(--mov-2) ease;
}
/* Como en la lámina del catálogo: quien ha pedido menos movimiento no recibe este acercamiento. */
@media (prefers-reduced-motion: no-preference) {
  .gallery-grid button:hover img {
    transform: scale(1.02);
  }
}
.credit {
  margin-top: 0.6rem;
  font-size: var(--fs-1);
  color: var(--ink2);
}

/* ---------------------------------------------------------------- ficha: cuerpo */

.piece-columns {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 20rem;
  gap: 3rem;
  align-items: start;
}

.piece-main > section + section {
  margin-top: 2.5rem;
}
/*
 * El mismo filete de oro que abre el catálogo: es lo que ata las dos páginas a un solo sistema. Y
 * desde la tarea B (23/09/2026) titula también las secciones del fragmento de lectura rápida, que
 * son literalmente las mismas: el fragmento se pinta con las funciones de la ficha.
 */
.piece-main h2,
.quick-read-doc h2 {
  font-size: var(--fs-6);
  margin-bottom: 0.75rem;
}
.piece-main h2::after,
.quick-read-doc h2::after {
  content: "";
  display: block;
  width: 2.75rem;
  height: 2px;
  margin-top: 0.6rem;
  background: var(--kin);
}
.description p {
  max-width: var(--prose);
  font-size: var(--fs-4);
  line-height: 1.7;
  text-wrap: pretty;
}

.highlights ul,
.caveats ul {
  list-style: none;
  padding: 0;
  max-width: var(--prose);
}
.highlights li,
.caveats li {
  position: relative;
  padding-left: 1.5rem;
  margin-bottom: 0.5rem;
  line-height: 1.55;
}
.highlights li::before,
.caveats li::before {
  position: absolute;
  left: 0;
  top: 0;
  font-weight: 700;
}
.highlights li::before {
  content: "+";
  color: var(--shinto);
}
/* Lo que hay que saber antes de comprar va en bermellón. Es el único sitio donde aparece. */
.caveats li::before {
  content: "–";
  color: var(--shu);
}

/* --------------------------------------------------------------- desglose de la nota */

.score-total {
  font-family: var(--mincho);
  line-height: 1;
  margin-bottom: 0.5rem;
}
.score-total b {
  font-size: var(--fs-cifra-alta);
  font-weight: 700;
}
.score-total small {
  font-size: var(--fs-5);
  color: var(--ink2);
}
.score-intro {
  max-width: var(--prose);
  font-size: var(--fs-3);
  color: var(--ink2);
  margin-bottom: 1.25rem;
}
.score-lines {
  list-style: none;
  padding: 0;
  max-width: 40rem;
}
.score-lines li {
  display: grid;
  grid-template-columns: 8.5rem minmax(0, 1fr) 3.75rem;
  gap: 0.25rem 1rem;
  align-items: center;
  padding: 0.6rem 0;
  border-top: 1px solid var(--line2);
}
.score-lines .component {
  font-weight: 600;
  font-size: var(--fs-3);
}
.score-lines .bar {
  height: 6px;
  background: var(--line);
  border-radius: 3px;
  overflow: hidden;
}
.score-lines .bar::after {
  content: "";
  display: block;
  height: 100%;
  width: var(--v, 0%);
  background: var(--ai);
}
/*
 * El color de cada línea dice de qué habla, con el vocabulario del sitio: oro para lo que es papel
 * —la montura con papeles propios y el certificado—, el verde apagado del shintō para el estado, y
 * el acento para lo que es la hoja en sí. Siete barras del mismo azul no se leen; éstas sí.
 */
.score-lines li[data-component="koshirae"] .bar::after,
.score-lines li[data-component="certificate"] .bar::after {
  background: var(--kin);
}
.score-lines li[data-component="condition"] .bar::after {
  background: var(--shinto);
}
.score-lines .points {
  text-align: right;
  font-size: var(--fs-3);
  font-variant-numeric: tabular-nums;
  color: var(--ink2);
  white-space: nowrap;
}
.score-lines .reason {
  grid-column: 2 / -1;
  font-size: var(--fs-2);
  color: var(--ink2);
}

/* ----------------------------------------------------------------- ficha: aparte */

.piece-aside {
  position: sticky;
  top: 5.5rem;
  display: grid;
  gap: 1.5rem;
}
/*
 * La tarjeta del precio abre con la nota y su anillo (23/09/2026): son las dos cifras con las que
 * se decide comprar, y la nota estaba al final de la página, a dos pantallas de aquí. El desglose
 * sigue abajo, que es donde se lee con calma.
 */
.piece-aside .price {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 0.5rem 1rem;
  border: 1px solid var(--line2);
  background: var(--surface-1);
  border-radius: var(--r2);
  padding: 1.25rem;
  box-shadow: var(--shadow-1);
}
.piece-aside .price > * {
  grid-column: 1 / -1;
}
.piece-aside .price .score {
  grid-column: 1;
  grid-row: 1;
}
.piece-aside .price .amount {
  grid-column: 2;
  grid-row: 1;
  margin: 0;
}
.price .amount {
  font: 700 var(--fs-cifra)/1.1 var(--mincho);
}
.price-note {
  font-size: var(--fs-2);
  color: var(--ink2);
  margin-top: 0.35rem;
}
.price .status {
  margin-top: 0.75rem;
}
.price .cta {
  width: 100%;
  margin-top: 1rem;
  padding-block: 0.6rem;
  font-size: var(--fs-3);
}
.price .status-note {
  margin-top: 1rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--line2);
  font-size: var(--fs-1);
}

/*
 * Las medidas, con la misma chapa que el precio (revisión de E1b, 23/09/2026). El brief pedía una
 * «tarjeta de hechos» y hasta hoy colgaban desnudas de la columna pegajosa, al lado de una tarjeta
 * con borde y sombra: dos bloques hermanos con dos pesos distintos y sin motivo.
 */
.piece-aside .facts {
  border: 1px solid var(--line2);
  background: var(--surface-1);
  border-radius: var(--r2);
  padding: 1.25rem;
  box-shadow: var(--shadow-1);
}
.facts h2 {
  font-size: var(--fs-4);
  margin-bottom: 0.75rem;
}
.facts dl {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: 0 1rem;
  font-size: var(--fs-3);
}
.facts dt {
  color: var(--ink2);
  padding: 0.3rem 0;
  border-top: 1px solid var(--line2);
}
.facts dd {
  margin: 0;
  padding: 0.3rem 0;
  border-top: 1px solid var(--line2);
  text-align: right;
  font-weight: 600;
}

/* --------------------------------------------------------------- anterior y siguiente */

.pager {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 1rem;
  align-items: center;
  margin-top: 4rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
  font-size: var(--fs-3);
}
.pager .next {
  text-align: right;
}
.pager .back {
  white-space: nowrap;
}
.pager a {
  text-decoration: none;
}
.pager a:hover b {
  text-decoration: underline;
}
.pager span {
  display: block;
  font-size: var(--fs-1);
  color: var(--ink2);
}
.pager b {
  font-family: var(--mincho);
  font-weight: 700;
}

/* ------------------------------------------------------------------------ visor */

/*
 * El visor es un cuarto oscuro, y desde la tarea E1 lo dice con su paleta y no con dos colores
 * sueltos (23/09/2026).
 *
 * La foto se mira a oscuras en los dos temas —esa es toda la idea del visor—, así que redefine
 * dentro los cuatro tokens que le hacen falta en vez de dejar que hereden los de la página. Lo que
 * lo arregla de verdad es `--ai`: el anillo de foco de sus botones salía del acento de la página, y
 * en el tema claro eso es índigo oscuro sobre este negro, 1,55:1, o sea que pasar de foto con el
 * teclado se hacía a ciegas. Y `color-scheme: dark` para que la barra de desplazamiento y lo que
 * pinte el navegador vayan a juego aunque el sitio esté en claro.
 */
.viewer {
  color-scheme: dark;
  --ji: #0b0f13;
  --ink: #e6e9ec;
  --ink2: #9aa4ae;
  /*
   * El filete del cuarto oscuro sube de tono (corrección de E1, 23/09/2026). Aquí dentro la única
   * línea que se dibuja es el contorno de los botones de pasar foto, y contra este negro el gris de
   * la página daba 1,70:1: un control cuyo borde no se ve (WCAG 2.2 SC 1.4.11 pide 3:1). Es su
   * propio valor y no el de la página porque el visor es su propia superficie, como el papel de los
   * diagramas.
   */
  --line: #5a636d;
  --ai: var(--ai-on-ink);
  --ai2: var(--ai2-on-ink);
  width: 100vw;
  max-width: 100vw;
  height: 100dvh;
  max-height: 100dvh;
  border: 0;
  border-radius: 0;
  background: var(--ji);
  color: var(--ink);
  display: none;
  grid-template-rows: minmax(0, 1fr) auto;
}
.viewer[open] {
  display: grid;
}
.viewer figure {
  margin: 0;
  min-height: 0;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  gap: 0.75rem;
  padding: 1.5rem 1.5rem 0;
}
.viewer img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  margin: 0 auto;
}
.viewer figcaption {
  text-align: center;
  font-size: var(--fs-2);
  opacity: 0.75;
}
/* Pasar de foto se hace en el centro, donde están las manos; cerrar, en la esquina. */
.viewer-bar {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  padding: 1rem 1.5rem 1.5rem;
}
.viewer-bar button {
  border: 1px solid var(--line);
  background: transparent;
  color: inherit;
  border-radius: var(--r);
  padding: 0.1rem 1rem;
  font-size: var(--fs-6);
  line-height: 1.5;
}
.viewer-bar button:hover {
  border-color: var(--ink2);
}
.viewer-bar .close {
  position: absolute;
  right: 1.5rem;
  bottom: 1.5rem;
  font-size: var(--fs-2);
  padding: 0.3rem 0.85rem;
}
#viewer-position {
  font-size: var(--fs-2);
  opacity: 0.75;
  min-width: 5rem;
  text-align: center;
}

/* ---------------------------------------------------------- guía y páginas fijas */

.guide-index,
.guide-topic,
.static-page {
  padding-block: 3.5rem 2rem;
}
.guide-index h1,
.guide-topic h1,
.static-page h1 {
  max-width: 24ch;
}
/* El mismo filete que abre el Catálogo: un solo gesto para todos los títulos del sitio. */
.guide-index h1::after,
.guide-topic h1::after,
.static-page h1::after {
  content: "";
  display: block;
  width: 4.5rem;
  height: 2px;
  margin-top: 1.1rem;
  background: var(--kin);
}
.guide-index .intro,
.guide-topic .intro,
.static-page .intro {
  max-width: var(--prose);
  font-size: var(--fs-5);
  line-height: 1.6;
  color: var(--ink2);
  margin-top: 1rem;
}

/*
 * Índice de la guía: tarjetas compactas, no huecos. Antes el título vivía en el `<a>` y la
 * entradilla en un `<p>` hermano fuera de él; el `<a>` llevaba `height:100%` para ocupar toda la
 * fila de la rejilla y, con sólo el título dentro, se inflaba hasta esa altura completa antes del
 * `<p>` — el «hueco de 400 px en medio» (Antonio, 21/09/2026). Ahora título, miniatura e
 * introducción van dentro del mismo enlace, en columna, y la tarjeta crece con su contenido.
 */
.guide-index ul {
  list-style: none;
  padding: 0;
  margin-top: 2.5rem;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 18rem), 1fr));
  gap: 1.5rem;
}
/*
 * Cada tema, una tarjeta con la foto a sangre y el título encima (pasada estética, 23/09/2026).
 * Eran ocho celdas de texto separadas por una raya de un píxel: ocho párrafos iguales que no
 * invitaban a entrar en ninguno. La imagen es lo que distingue un tema del siguiente.
 */
.guide-index li {
  background: var(--surface-1);
  border: 1px solid var(--line2);
  border-radius: var(--r2);
  box-shadow: var(--shadow-1);
  overflow: hidden;
  transition: box-shadow var(--mov-1), border-color var(--mov-1);
}
.guide-index li:hover {
  border-color: var(--line);
  box-shadow: var(--shadow-2);
}
.guide-index li a {
  display: grid;
  grid-template-rows: auto 1fr;
  padding-bottom: 1.25rem;
  text-decoration: none;
  color: inherit;
  height: 100%;
}
/*
 * El título se apoya sobre la foto, con un velo que le hace sitio. Sólo sobre una FOTO: ni sin
 * miniatura —el velo sería una banda negra sobre el papel, y el título blanco sobre blanco— ni
 * sobre un diagrama, que es papel claro en los dos temas (corrección de E1b, 23/09/2026: el título
 * de «Herreros célebres» se medía a 2,46:1 sobre su lámina, y el texto grande exige 3:1).
 *
 * El velo llega opaco hasta donde acaba el relleno de arriba y sólo entonces se desvanece: antes se
 * aclaraba a media palabra —0,45 al 45 %— y el renglón de arriba de un título de dos líneas se
 * quedaba en 3,2:1 sobre una portada clara. Atado en `site-css.test.ts` con la cuenta de la WCAG
 * sobre el peor fondo posible, una foto de blanco puro, y medido en píxeles por
 * `scripts/contraste-guia.mts`.
 */
.guide-index li a:has(.thumb:not(.is-diagram)) strong {
  grid-row: 1;
  grid-column: 1;
  align-self: end;
  z-index: 1;
  margin: 0;
  padding: 3rem 1.1rem 0.9rem;
  color: #fff;
  background: linear-gradient(
    to top,
    rgb(10 13 18 / 0.9),
    rgb(10 13 18 / 0.78) calc(100% - 3rem),
    transparent
  );
  text-wrap: balance;
}
.guide-index li a:has(.thumb) .thumb {
  grid-row: 1;
  grid-column: 1;
}
/* Sin foto debajo —no hay miniatura, o la miniatura es un diagrama—, el título va sobre el papel. */
.guide-index li a:not(:has(.thumb:not(.is-diagram))) strong {
  padding: 1.25rem 1.1rem 0;
}
/*
 * Y entonces la tarjeta tiene tres bandas, no dos: lámina, título y entradilla. La entradilla lleva
 * escrita su fila más abajo —la necesita cuando comparte fila con la foto—, así que aquí se la
 * corrige, o se subiría encima del título.
 */
.guide-index li a:has(.thumb.is-diagram) {
  grid-template-rows: auto auto 1fr;
}
.guide-index li a:has(.thumb.is-diagram) p {
  grid-row: 3;
}
/*
 * La miniatura del índice va en su propio cuadro desde el 22/09/2026: antes era la `<img>` a pelo
 * y no había dónde poner el papel de un diagrama. La foto llena el cuadro; el dibujo, no (ver
 * «panel de papel», más abajo).
 */
.guide-index .thumb {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  overflow: hidden;
}
.guide-index .thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.guide-index li a strong,
.guide-index li a b {
  display: block;
  font-family: var(--mincho);
  font-size: var(--fs-5);
  line-height: 1.2;
}
/* La entradilla, recortada a cinco renglones: ocho fichas de veinte líneas no se leen, se hojean. */
.guide-index li a span,
.guide-index li a p {
  grid-row: 2;
  margin: 0;
  /*
   * Sin relleno abajo: el recorte de `line-clamp` mide la CAJA, así que un relleno inferior deja
   * asomar media línea de la siguiente por debajo del corte. El aire lo pone el enlace.
   */
  padding: 0.9rem 1.1rem 0;
  font-size: var(--fs-3);
  line-height: 1.55;
  color: var(--ink2);
  display: -webkit-box;
  -webkit-line-clamp: 5;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/*
 * Prosa a lo ancho de un renglón legible, se envuelva en secciones o no. Las páginas fijas vienen
 * de una plantilla y ponen sus párrafos directamente bajo la página, así que el tope se pone a
 * todo hijo y no sólo a `section`, que era por donde se escapaban. `.guide-grid` queda fuera a
 * propósito: es el tema entero con su rejilla de dos columnas, y necesita todo el ancho (ver más
 * abajo, «rejilla continua del tema»).
 */
.guide-topic > *,
.static-page > * {
  max-width: var(--prose);
}
.guide-topic > .guide-index,
.guide-index > ul,
.guide-topic > .guide-grid {
  max-width: none;
}
.guide-topic section,
.static-page section {
  margin-top: 2.5rem;
}
.guide-topic h2,
.static-page h2 {
  font-size: var(--fs-6);
  margin: 2.5rem 0 0.75rem;
}
.guide-topic h3,
.static-page h3 {
  font-size: var(--fs-5);
  margin: 1.5rem 0 0.5rem;
}
.guide-topic p,
.static-page p {
  margin-bottom: 1rem;
  line-height: 1.7;
  text-wrap: pretty;
}
.guide-topic ul,
.guide-topic ol,
.static-page ul,
.static-page ol {
  margin: 0 0 1rem 1.25rem;
  padding: 0;
}
.guide-topic li,
.static-page li {
  margin-bottom: 0.4rem;
}
.guide-topic table,
.static-page table {
  border-collapse: collapse;
  width: 100%;
  font-size: var(--fs-3);
  margin-bottom: 1rem;
}
.guide-topic th,
.guide-topic td,
.static-page th,
.static-page td {
  border-bottom: 1px solid var(--line2);
  padding: 0.4rem 0.6rem;
  text-align: left;
}

/*
 * Rejilla del tema y carril único de figuras (Antonio, 21/09/2026, visto en vivo en
 * /guide/gokaden/: «desaprovechamos la mitad de la pantalla siempre» en toda sección sin figura;
 * y 22/09/2026, sobre el arreglo del día anterior: «cuando el tramo es más corto que el bloque, el
 * siguiente se le superpone»).
 *
 * `.guide-grid` es la rejilla del TEMA entero: prosa a la izquierda, figuras a la derecha. El
 * 21/09 la columna derecha la ocupaban varios bloques pegajosos, uno por sección con figuras,
 * anclados a un tramo de filas con `--row`/`--span`; un bloque más alto que su tramo se comía el
 * de abajo. Desde el 22/09 hay UN solo bloque pegajoso, `.guide-rail`, que ocupa la segunda
 * columna de arriba abajo y cuyo contenido cambia con el scroll (`client/guide-rail.ts`): dos
 * bloques no pueden solaparse si sólo hay uno.
 *
 * Por eso el carril lleva `grid-row: 1 / span 999` (las filas son implícitas, así que `-1` no
 * sirve para llegar al final) y `align-self: start`: el área tiene que ser alta —toda la altura
 * del tema— para que quede recorrido donde pegarse, y el bloque, de su alto natural, para poder
 * deslizarse dentro de ella.
 *
 * Las figuras de cada sección se pintan dentro de su sección (`.guide-figures`) y ése es el estado
 * de partida: en móvil y en un navegador sin JavaScript se leen ahí, tras la prosa que acompañan.
 * De 1.100 px en adelante, y sólo cuando el carril tiene ya un grupo dentro, se quitan de la vista
 * —que no del árbol de accesibilidad— y pasa a enseñarlas el carril. El carril, a su vez, arranca
 * en `display: none` y sólo aparece en ese mismo tramo: sin JavaScript se queda vacío y no debe
 * dejar una columna en blanco.
 *
 * `.guide-prose` no lleva tope de ancho: ocupa toda la columna 1, y son los párrafos y las listas
 * los que se quedan en `--prose` para seguir siendo legibles. Las tablas SÍ se quedan sin tope
 * porque una comparativa de escuelas con muchas columnas necesita más sitio que un párrafo.
 *
 * Una figura `wide` (diagrama panorámico: línea de tiempo, comparativa ancha) no cabe en el carril
 * de 18rem y no viaja a él: se queda en línea con la prosa, dentro de su sección.
 *
 * La separación entre secciones es ahora la misma en las dos anchuras (2,5 rem). Antes en
 * escritorio la ponían las filas de la rejilla, que ya no existen; poner el margen a mano evita que
 * dos secciones seguidas queden pegadas cuando la primera no trae figuras.
 */
.guide-grid {
  margin-top: 2.5rem;
}
.guide-section {
  margin-top: 2.5rem;
}
.guide-grid > .guide-section:first-of-type {
  margin-top: 0;
}
.guide-prose p,
.guide-prose ul,
.guide-prose ol {
  max-width: var(--prose);
}
.guide-prose table {
  max-width: none;
}
/*
 * La figura ancha vive dentro de su sección, o sea en la columna de prosa (~910 px de las 1.240
 * del tema). Antes del 22/09/2026 se estiraba a las dos columnas con `grid-column: 1 / -1`; ya no
 * puede: el carril ocupa la columna 2 de arriba abajo y una figura a dos columnas se le montaría
 * encima. Hoy no se nota —ningún tema trae figuras `wide`—, pero cuando C2 o C4 quieran una línea
 * de tiempo panorámica de verdad, el sitio es la columna de prosa, no «todo el ancho».
 */
.guide-figures-wide {
  margin: 1.5rem 0;
}
.guide-rail {
  display: none;
}
@media (min-width: 68.75rem) {
  /* 1.100 px */
  /*
   * 23/09/2026, Antonio sobre un tema a ~1.000 px: «las fotos se ven pequeñas y hay mucho espacio
   * entre el texto y las imágenes flotantes sin usar». Hasta hoy las columnas eran
   * `minmax(0, 1fr) 18rem`: la primera se quedaba con TODO el ancho sobrante, pero dentro de ella
   * los párrafos siguen capados a `--prose` (38 rem), así que el texto acababa a 608 px del borde
   * y desde ahí hasta el carril quedaba un pasillo en blanco tan ancho como el propio carril
   * (~344 px a 1.240 px de sitio), mientras las figuras se apretaban en 288 px.
   *
   * Ahora la columna del texto se acota a `--prose` —el mismo ancho de lectura de siempre: a
   * 1.100 px la prosa no pierde ni un píxel, porque 38 rem + 3 rem + 18 rem = 944 px caben en los
   * 1.052 px útiles— y el carril se lleva TODO lo que sobre a partir de sus 18 rem mínimos. El
   * pasillo se reduce al `column-gap`.
   *
   * El tope lo pone el ancho de la rejilla, no la columna: `max-width: prosa + gap + 34rem`. Las
   * fotos de Wikimedia rondan los 1.000 px de origen y los diagramas SVG se leen de sobra a 34 rem
   * (544 px); más allá sólo se ampliaría el mapa de bits. Con `--wrap` en 1.240 px el ancho útil
   * es 1.192 px y el carril se queda en 536 px, así que el tope sólo entraría en juego si el sitio
   * se ensanchara. La rejilla queda alineada a la izquierda, como el resto de la página (el título
   * del tema y las migas arrancan en ese mismo borde): centrarla la desalinearía de su encabezado.
   */
  .guide-grid {
    display: grid;
    grid-template-columns: minmax(0, var(--prose)) minmax(18rem, 1fr);
    column-gap: 3rem;
    max-width: calc(var(--prose) + 3rem + 34rem);
  }
  .guide-grid > .guide-section {
    grid-column: 1;
    margin-top: 0;
  }
  .guide-grid > .guide-section + .guide-section {
    margin-top: 2.5rem;
  }
  .js .guide-grid > .guide-rail:not([hidden]) {
    display: block;
    grid-column: 2;
    grid-row: 1 / span 999;
    align-self: start;
    position: sticky;
    top: 5.5rem;
    /*
     * 23/09/2026: sin tope de alto, un grupo más alto que la ventana quedaba recortado PARA
     * SIEMPRE. `align-self: start` le da el alto natural y `sticky` lo clava a 5,5 rem del borde:
     * si el grupo mide 2.376 px —el de koshirae-styles §2— su final cae en 2.464 px y no sube en
     * ninguna posición del scroll, así que tres de sus seis figuras no se veían nunca, con sus
     * créditos, que la Regla 1 exige visibles. El carril se queda dentro de la ventana (5,5 rem
     * arriba + 1,5 rem de aire abajo) y lo que no cabe se alcanza desplazando por dentro.
     */
    max-height: calc(100vh - 7rem);
    overflow-y: auto;
    overscroll-behavior: contain;
    /* El carril es una lámina apoyada al lado de la prosa, no un margen con dibujos sueltos. */
    padding: 1rem;
    border: 1px solid var(--line2);
    border-radius: var(--r2);
    background: var(--surface-1);
    box-shadow: var(--shadow-1);
  }
  /*
   * Con el carril lleno, el grupo de la sección sobra A LA VISTA: se vería dos veces lo mismo.
   * Pero no `display: none` (23/09/2026): eso lo saca también del árbol de accesibilidad, y como
   * el carril sólo lleva dentro las figuras de UNA sección, un lector de pantalla recorría el tema
   * sin encontrar ni un `alt` ni un crédito de las secciones 2..N. Se queda donde está, en orden
   * de lectura, quitado de la vista; la copia del carril va con `aria-hidden` y fuera del
   * tabulador (`client/guide-rail.ts`), que para eso es decoración.
   *
   * Y cuelga de que el carril tenga un grupo dentro, no de `.js`: `main.ts` pone esa clase antes
   * de arrancar nada, así que un fallo en cualquier otro `init` dejaba el tema sin UNA sola figura
   * en escritorio. Con `:has` el fallo es inocuo: se leen donde el HTML las dejó.
   */
  .guide-grid:has(.guide-rail-group) > .guide-section > .guide-figures {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  /*
   * Salvo cuando tiene el foco dentro: la figura de la sección sigue siendo tabulable —el enlace
   * que la abre y el del crédito, dos paradas por figura— y un foco que no se ve es un foco
   * perdido. Al enfocarlo, la figura vuelve a su sitio en la columna de prosa.
   */
  .guide-grid:has(.guide-rail-group) > .guide-section > .guide-figures:focus-within {
    position: static;
    width: auto;
    height: auto;
    margin: 1.5rem 0 0;
    overflow: visible;
    clip-path: none;
    white-space: normal;
  }
}

/*
 * El relevo de un grupo por el siguiente. Cada cambio inserta un `.guide-rail-group` nuevo, así
 * que la animación arranca sola al pintarlo: no hay que cronometrar nada desde el guión.
 */
@media (prefers-reduced-motion: no-preference) {
  .guide-rail-group {
    animation: guide-rail-in var(--mov-2) ease-out;
  }
}
@keyframes guide-rail-in {
  from {
    opacity: 0;
    transform: translateY(0.35rem);
  }
}
.guide-rail-group .figure:last-child {
  margin-bottom: 0;
}

/*
 * Una figura de sección: foto de Wikimedia Commons o diagrama propio, con su pie y su crédito
 * (Regla 1 — sin crédito visible no se publica). En móvil, entre el párrafo de su sección y el
 * encabezado de la siguiente, no incrustada a mitad de un párrafo.
 */
.figure {
  margin: 0 0 1.5rem;
}
.guide-figures .figure:last-child {
  margin-bottom: 0;
}
.figure img {
  display: block;
  /* Escala con el carril, que desde el 23/09/2026 ya no mide 18 rem fijos; la proporción la
   * mantiene el `height: auto` del reset de arriba, que ya alcanza a toda imagen del sitio. */
  width: 100%;
  border-radius: var(--r);
  border: 1px solid var(--line2);
}
/* El pie de una figura se lee como un pie: pequeño y en cursiva, aparte de la prosa. */
.figure figcaption {
  margin-top: 0.5rem;
  font-size: var(--fs-2);
  font-style: italic;
  line-height: 1.5;
}
.figure-caption {
  display: block;
  color: var(--ink);
}
.figure-credit {
  display: block;
  margin-top: 0.15rem;
  color: var(--ink2);
}
.figure-credit a {
  color: inherit;
}

/*
 * La figura se abre a tamaño completo (Antonio, 23/09/2026: «que esas fotos de la derecha al
 * clicar en ellas se abran en un modal para verlas completas»).
 *
 * El enlace no viste nada: la figura tiene que verse exactamente igual que antes de existir él.
 * Lo único que añade es la lupa —que es lo que dice que ahí se puede pulsar— y un anillo de foco
 * con aire, porque la imagen ya lleva su propio filo y pegados no se distinguen.
 */
.figure-open {
  display: block;
  cursor: zoom-in;
  border-radius: var(--r);
}
.figure-open:focus-visible {
  outline: 2px solid var(--ai);
  outline-offset: 3px;
}

/*
 * El cuadro de la figura a tamaño completo.
 *
 * No es el cuarto oscuro de la ficha (`.viewer`): allí se recorre una galería de fotos de dos mil
 * píxeles y la página desaparece; aquí se agranda UNA figura de la guía sin salir de la lectura,
 * así que el cuadro es transparente y lo que oscurece es el fondo del navegador. La imagen manda
 * —cabe entera, sin recortar ni deformar— y el pie viaja con ella sobre la superficie del sitio,
 * con su filete de oro y la sombra de la pasada estética: la misma lámina que levantan una tarjeta
 * o el panel de filtros.
 */
.figure-viewer {
  /*
   * `inset: 0` y no `width: 100vw`: en un sistema con barras de desplazamiento sólidas, `100vw`
   * cuenta la barra y el cuadro sobresale por la derecha. Con el cuadro pegado a los cuatro lados
   * de la ventana no hay cifra que sobre.
   */
  inset: 0;
  width: auto;
  height: auto;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--ink);
  display: none;
  place-items: center;
}
.figure-viewer[open] {
  display: grid;
}
.figure-viewer::backdrop {
  background: rgb(10 14 18 / 0.82);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}
/* El margen que deja el cuadro: fuera de la imagen se pulsa para cerrar, así que tiene que haberlo. */
/*
 * Las medidas van con `100%` y no con `100vw`: el cuadro ya está pegado a los cuatro lados con
 * `inset: 0`, así que su hueco ES la ventana, y con barras de desplazamiento sólidas `100vw` cuenta
 * además la barra y todo sobresale por la derecha (revisión del bloque guía, 23/09/2026).
 */
.figure-viewer figure {
  margin: 0;
  min-width: 0;
  min-height: 0;
  /*
   * Y ocupa el hueco: sin `width`, el `<figure>` se encoge a su contenido y el `width: 100%` del
   * diagrama se medía contra ese ancho encogido —es decir, contra su propio tamaño intrínseco— y
   * el SVG se abría a 848 px en una ventana de 1440 (revisión del bloque guía, 23/09/2026).
   */
  width: 100%;
  max-width: calc(100% - 2.5rem);
  max-height: calc(100dvh - 2.5rem);
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  justify-items: center;
}
/*
 * La imagen crece hasta el hueco del cuadro conservando su proporción: los dos `auto` la ponen, y
 * los dos topes —el ancho de la figura, el alto que deja el pie— la paran.
 */
.figure-viewer img {
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: calc(100dvh - 9rem);
  object-fit: contain;
  border-radius: var(--r2) var(--r2) 0 0;
}
/*
 * Un diagrama se lee sobre su papel también aquí: invertido dejaría de parecer un dibujo. Y llena
 * el ancho del hueco: un SVG no tiene resolución que perder, y sin `width` se abría a su tamaño
 * intrínseco —unos 848 px en una ventana de 1440— dejando el cuadro sin sentido (revisión del
 * bloque guía, 23/09/2026). El alto lo sigue mandando el `max-height` de arriba.
 */
.figure-viewer.is-diagram img {
  width: 100%;
  background: var(--paper);
  padding: 0.75rem;
}
.figure-viewer figcaption {
  width: 100%;
  max-width: 36rem;
  padding: 0.85rem 1.1rem;
  background: var(--surface-1);
  border-top: 2px solid var(--kin);
  border-radius: 0 0 var(--r2) var(--r2);
  box-shadow: var(--shadow-2);
  font-size: var(--fs-2);
  font-style: italic;
  line-height: 1.5;
  text-align: center;
}
.figure-viewer .figure-caption {
  display: block;
  color: var(--ink);
}
.figure-viewer .figure-credit {
  display: block;
  margin-top: 0.2rem;
  color: var(--ink2);
}
.figure-viewer .figure-credit a {
  color: inherit;
}
/* La salida, en la esquina: donde no tapa la figura y donde el pulgar la encuentra. */
.figure-viewer .close {
  position: fixed;
  top: 1rem;
  right: 1rem;
  background: var(--surface-1);
  box-shadow: var(--shadow-1);
}
@media (max-width: 34rem) {
  .figure-viewer figure {
    max-width: calc(100% - 1rem);
  }
  /* El pie, que fuera del teléfono se para en 36 rem, aquí llega hasta donde llegue la figura. */
  .figure-viewer figcaption {
    max-width: 100%;
  }
}
/*
 * Aparece subiendo un poco, como el relevo del carril: el salto seco de un cuadro que ocupa la
 * pantalla entera se nota más que el de un panel.
 */
@media (prefers-reduced-motion: no-preference) {
  .figure-viewer[open] {
    animation: figure-viewer-in var(--mov-2) ease-out;
  }
}
@keyframes figure-viewer-in {
  from {
    opacity: 0;
    transform: translateY(0.5rem);
  }
}


/*
 * El cuadro de la lectura rápida (tarea B4, 23/09/2026).
 *
 * Antonio: «si clicamos en la parte del texto… que abra un modal con esta parte para una lectura
 * rápida». Es un cuadro de LEER, no de comparar: por eso no hereda el ancho del comparador —64 rem,
 * que es lo que pide una tabla de siete columnas— sino un ancho de lectura, el mismo orden de
 * magnitud que `--prose`, donde una línea cabe de un vistazo sin que el ojo se pierda al volver.
 *
 * Lo demás es el sistema del sitio: la superficie que se levanta del papel, el filete de oro
 * arriba y la sombra de la pasada E1b, como la lámina y el panel de filtros.
 *
 * El techo de altura con el desplazamiento DENTRO del cuerpo es lo que hace que funcione en un
 * teléfono: la cabecera se queda quieta —con el rótulo y la X— mientras la descripción y el
 * desglose pasan por debajo, y no hay que subir dos pantallas para encontrar el cierre.
 */
.quick-read {
  width: min(44rem, calc(100vw - 2rem));
  max-width: none;
  max-height: calc(100dvh - 4rem);
  padding: 0;
  border: 1px solid var(--line2);
  border-top: 2px solid var(--kin);
  border-radius: var(--r2);
  background: var(--surface-1);
  color: var(--ink);
  box-shadow: var(--shadow-2);
  /*
   * Cerrado no se pinta. Hay que decirlo: una regla de `display` del autor gana a la del navegador
   * —que esconde el `<dialog>` cerrado— sin importar la especificidad, y el cuadro se quedaría
   * dibujado en medio de la portada. El reparto en dos filas —la cabecera quieta, el texto
   * desplazándose debajo— va con el cuadro abierto.
   */
  display: none;
}
.quick-read[open] {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
}
.quick-read::backdrop {
  background: rgb(10 14 18 / 0.6);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
}
.quick-read .dialog-head {
  border-bottom: 1px solid var(--line2);
}
/* El rótulo del cuadro no es un encabezado: el del fragmento es el nombre de la pieza. */
.quick-read .dialog-kicker {
  font-size: var(--fs-2);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink2);
}
.quick-read .dialog-body {
  overflow-y: auto;
  overscroll-behavior: contain;
}
/*
 * El nombre de la pieza, que rotula el cuadro. Es un `<h2>` desde la revisión xhigh del 23/09/2026
 * —dos `<h1>` en un documento con el cuadro abierto—, así que hay que sacarlo del vestido de los
 * títulos de sección: el filete de oro es de las secciones, no del nombre. Y el selector lleva el
 * `.quick-read-doc` delante para pesar lo mismo que `.quick-read-doc h2`, que si no gana él.
 */
.quick-read-doc .quick-read-name {
  font-family: var(--mincho);
  font-size: var(--fs-6);
  line-height: 1.2;
  margin-bottom: 1.25rem;
}
.quick-read-doc .quick-read-name::after {
  content: none;
}
.quick-read-doc > section + section,
.quick-read-doc .score {
  margin-top: 1.75rem;
}
/* El aviso de que el fragmento viene en camino: una línea apagada, no una pantalla de carga. */
.quick-read-loading {
  color: var(--ink2);
  font-size: var(--fs-3);
}
.quick-read-more {
  margin-top: 1.75rem;
  padding-top: 1rem;
  border-top: 1px solid var(--line2);
}
.quick-read-open {
  font-size: var(--fs-3);
  font-weight: 600;
}
/*
 * Aparece subiendo un poco, como el cuadro de las figuras. Quien pidió menos movimiento la ve
 * puesta y ya está.
 */
@media (prefers-reduced-motion: no-preference) {
  .quick-read[open] {
    animation: quick-read-in var(--mov-2) ease-out;
  }
}
@keyframes quick-read-in {
  from {
    opacity: 0;
    transform: translateY(0.5rem);
  }
}

/*
 * El panel de papel de los diagramas (bloque C, 22/09/2026).
 *
 * Hasta el 22/09 los dibujos de la guía eran tinta oscura sobre el fondo de la página: en tema
 * claro se leían y en oscuro desaparecían —ocho SVG, y la miniatura de «Tipos de hoja» era un
 * cuadro en blanco en el índice (Antonio, 22/09/2026, sobre kantei.eu en vivo)—. Ahora el dibujo
 * trae sus trazos en `currentColor` y esta regla le pone debajo el papel y encima la tinta, iguales
 * en los dos temas.
 *
 * Las dos variables `--diagram-*` son para el propio SVG: el diagrama del tema se incrusta en la
 * página y las lee de aquí; las figuras de sección se sirven como `<img>`, en un documento aparte
 * que no hereda nada, y caen en el valor de reserva que llevan escrito dentro
 * (`var(--diagram-bg, #f5f2ec)` y el atributo `color` de su raíz). El mismo tono por los dos
 * caminos: `site-css.test.ts` ata la pareja.
 */
figure.is-diagram,
.guide-index .thumb.is-diagram {
  --diagram-bg: var(--paper);
  --diagram-ink: var(--ink-on-paper);
  /*
   * Y el acento de la lámina, que tampoco cambia con el tema (tarea E1, 23/09/2026). Todo lo que
   * cae dentro del panel —un enlace del pie, el anillo de foco del carril, el de un número del
   * diagrama— se pinta con `--ai`, y el `--ai` de la página es azul pálido en el tema oscuro: 1,97:1
   * sobre este papel. Redefinirlo aquí arregla los tres de una vez, y cualquiera que llegue mañana.
   */
  --ai: var(--ai-on-paper);
  --ai2: var(--ai2-on-paper);
  background: var(--paper);
  color: var(--ink-on-paper);
  /*
   * El papel es claro en los dos temas, así que el panel declara su esquema (23/09/2026). Un SVG
   * servido como `<img>` hereda el `color-scheme` usado del elemento: con esto, un diagrama que
   * traiga variante oscura se pinta en la clara, la que casa con el papel. El guión de validación
   * ya no admite esa variante en los diagramas de la guía —`periods/sugata-evolucion.svg` la traía
   * y sus rótulos salían a 1,09:1 en oscuro—, pero una figura de fuera podría traerla.
   */
  color-scheme: light;
}
/* El dibujo entero, sin recortar: un diagrama a media asta no explica nada. */
.guide-index .thumb.is-diagram img {
  object-fit: contain;
  padding: 0.35rem;
}
figure.figure.is-diagram {
  padding: 0.75rem;
  border: 1px solid var(--line2);
  border-radius: var(--r2);
}
/* Dentro del panel manda el marco del panel: el filo de la imagen sobraría. */
figure.figure.is-diagram img {
  border: 0;
  border-radius: 0;
}
/*
 * El pie viaja sobre el mismo papel, así que no puede seguir tirando de `--ink`/`--ink2`: en
 * oscuro son casi blancos y se borrarían contra la lámina.
 */
figure.is-diagram .figure-caption,
figure.is-diagram .diagram-hint {
  color: var(--ink-on-paper);
}
figure.is-diagram .figure-credit {
  color: color-mix(in srgb, var(--ink-on-paper) 72%, var(--paper));
}

.guide-links {
  list-style: none;
  margin-left: 0;
}
.guide-links li {
  padding: 0.6rem 0;
  border-top: 1px solid var(--line2);
}
.guide-links .note,
.note {
  display: block;
  font-size: var(--fs-2);
  color: var(--ink2);
}

/*
 * «Cómo comprar» (spec §6, bloque C4, 23/09/2026).
 *
 * La página es un tema más para la rejilla —dos columnas y carril de figuras, de `guide-grid`—;
 * lo suyo son tres piezas: la línea de tiempo de los cinco pasos, la tarjeta del desglose del
 * precio y las preguntas plegables. Hasta hoy era prosa a 38 rem sin una sola figura.
 */
.how-to-buy .timeline {
  list-style: none;
  margin: 2rem 0 0;
  padding: 0;
}
.how-to-buy .timeline > li {
  position: relative;
  display: grid;
  grid-template-columns: 2.75rem minmax(0, 1fr);
  column-gap: 1.25rem;
  margin: 0;
  padding-bottom: 2rem;
}
/*
 * El hilo que une un paso con el siguiente: nace bajo el disco y muere en el de abajo. Va en el
 * `li` y no en una columna aparte para que el último no lo pinte y la línea no se quede colgando.
 */
.how-to-buy .timeline > li::before {
  content: "";
  position: absolute;
  left: 1.3125rem;
  top: 3rem;
  bottom: 0.25rem;
  width: 1.5px;
  background: var(--line);
}
.how-to-buy .timeline > li:last-child {
  padding-bottom: 0;
}
.how-to-buy .timeline > li:last-child::before {
  display: none;
}
.how-to-buy .step-mark {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.05rem;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--hamon);
  color: var(--ai);
}
.how-to-buy .timeline .ico {
  width: 1.05rem;
  height: 1.05rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
}
.how-to-buy .step-mark b {
  font-size: var(--fs-1);
  font-variant-numeric: tabular-nums;
}
.how-to-buy .step-text {
  margin-bottom: 0.75rem;
  max-width: var(--prose);
}
/*
 * La figura del paso se queda con su paso: es SU dibujo, y el carril de la derecha cuenta otra
 * cosa. Por eso la sección de los pasos no abre `.guide-figures` (ver `render/how-to-buy.ts`).
 */
.how-to-buy .timeline .figure {
  max-width: 22rem;
  margin-bottom: 0;
}

/*
 * El desglose del precio. Es una tarjeta y no una tabla suelta porque lo que se enseña es UN
 * ejemplo entero —cuatro partidas y su total—, y porque las cifras salen de los ajustes vigentes
 * (`domain/pricing.ts`): conviene que se lea como un recibo y no como parte de la prosa.
 */
.how-to-buy .price-breakdown {
  margin: 1.5rem 0;
  max-width: var(--prose);
  padding: 1.25rem 1.25rem 0.75rem;
  border: 1px solid var(--line);
  border-radius: var(--r2);
  background: var(--hamon);
  box-shadow: var(--shadow-1);
}
.how-to-buy .price-breakdown h3 {
  margin: 0 0 0.75rem;
  font-size: var(--fs-4);
}
.how-to-buy .price-breakdown table {
  margin-bottom: 0.75rem;
}
.how-to-buy .price-breakdown th {
  font-weight: 400;
  color: var(--ink2);
}
.how-to-buy .price-breakdown td {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.how-to-buy .price-breakdown tr.total th,
.how-to-buy .price-breakdown tr.total td {
  border-bottom: 0;
  border-top: 1.5px solid var(--line);
  font-size: var(--fs-4);
  font-weight: 700;
  color: var(--ink);
}
.how-to-buy .price-breakdown .note {
  margin: 0 0 0.5rem;
}

/*
 * Las preguntas, plegadas. Cerradas se lee la lista entera de un vistazo —que es lo que se busca
 * en una página de dudas— y abiertas no mueven nada de su sitio. `details` funciona sin
 * JavaScript, así que no lleva `needs-js`.
 */
.how-to-buy .faq {
  max-width: var(--prose);
  border-top: 1px solid var(--line2);
}
.how-to-buy .faq:last-of-type {
  border-bottom: 1px solid var(--line2);
}
.how-to-buy .faq > summary {
  position: relative;
  padding: 0.85rem 2rem 0.85rem 0;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
}
.how-to-buy .faq > summary::-webkit-details-marker {
  display: none;
}
/* La punta de flecha que dice si está abierta: dos filos girados, sin fuente de iconos. */
.how-to-buy .faq > summary::after {
  content: "";
  position: absolute;
  right: 0.4rem;
  top: 1.15rem;
  width: 0.55rem;
  height: 0.55rem;
  border-right: 1.5px solid var(--ai);
  border-bottom: 1.5px solid var(--ai);
  transform: rotate(45deg);
}
.how-to-buy .faq[open] > summary::after {
  transform: rotate(-135deg);
  top: 1.35rem;
}
.how-to-buy .faq > summary:hover {
  color: var(--ai);
}
.how-to-buy .faq > summary:focus-visible {
  outline: 2px solid var(--ai);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: no-preference) {
  .how-to-buy .faq > summary::after {
    transition: transform var(--mov-1) ease;
  }
}
.how-to-buy .faq-body p:last-child {
  margin-bottom: 0.85rem;
}
.how-to-buy > .contact {
  margin-top: 2.5rem;
}

/*
 * El diagrama de anatomía y su carril.
 *
 * El dibujo mide 1.160 unidades de ancho y rotula las piezas con números de 14 px, así que sólo se
 * lee si se dibuja ancho: en la columna de texto (38rem) los números caen a 7 px y en un teléfono,
 * a 4. De modo que el diagrama se salta la columna —como ya hace el índice de la guía— y, cuando
 * ni así cabe, se recorre de lado en vez de encogerse. `site-css.test.ts` ata el ancho mínimo de
 * aquí abajo con el `viewBox` y el cuerpo de los números del SVG.
 */
.diagram {
  margin: 1.5rem 0;
  max-width: none;
  /* Desde el 22/09 la figura es una lámina de papel (ver «panel de papel»): el dibujo va con aire. */
  padding: 0.75rem;
  border-radius: var(--r2);
}
.diagram-scroll {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: thin;
  border: 1px solid var(--line2);
  border-radius: var(--r);
  padding: 0.5rem;
  /*
   * La pista de que hay más a los lados: dos sombras pegadas al contenido que sólo se ven mientras
   * queda diagrama por ese lado. Las dos primeras capas son el «tapón» del color del papel, y van
   * con `local` para viajar con el desplazamiento; las dos sombras se quedan quietas. La sombra se
   * mezcla desde la tinta, no de un negro fijo: en tema oscuro un negro sobre negro no se ve.
   *
   * Y desde el 22/09/2026 el color del tapón y el de la sombra salen del diagrama, no de la
   * página: dentro de `figure.is-diagram` el fondo es papel, y taparlo con `--ji` dejaba asomar
   * dos franjas de tinta a los lados de la lámina en tema oscuro. La reserva es la de siempre,
   * para cualquier carril que no cuelgue de un panel de papel.
   */
  background:
    linear-gradient(to right, var(--diagram-bg, var(--ji)) 40%, transparent) left center / 2rem 100%
      no-repeat local,
    linear-gradient(to left, var(--diagram-bg, var(--ji)) 40%, transparent) right center / 2rem 100%
      no-repeat local,
    radial-gradient(
        farthest-side at 0 50%,
        color-mix(in srgb, var(--diagram-ink, var(--ink)) 30%, transparent),
        transparent
      )
      left center / 0.8rem 100% no-repeat scroll,
    radial-gradient(
        farthest-side at 100% 50%,
        color-mix(in srgb, var(--diagram-ink, var(--ink)) 30%, transparent),
        transparent
      )
      right center / 0.8rem 100% no-repeat scroll;
}
.diagram-scroll:focus-visible {
  outline: 2px solid var(--ai);
  outline-offset: 3px;
}
.diagram-scroll svg {
  display: block;
  width: 100%;
  min-width: 920px;
  height: auto;
}
.diagram-hint {
  display: none;
  margin-top: 0.5rem;
  font-size: var(--fs-2);
  color: var(--ink2);
}
/* 60,5rem es el ancho de ventana a partir del cual el diagrama ya cabe entero. */
@media (max-width: 60.5rem) {
  .diagram-hint {
    display: block;
  }
}

/*
 * Los números del diagrama y su leyenda (spec §5, bloque C, 22/09/2026).
 *
 * `render/guide.ts` envuelve cada cifra y su disco en un `.hotspot[data-n]` con papel de botón, y
 * la leyenda del tema es un `ol.legend` con el mismo número en cada línea;
 * `client/anatomy-tooltips.ts` los empareja. Aquí va lo que hace falta para que se vea que el
 * número se puede señalar y para que resaltar uno se note en los dos sitios a la vez.
 */
.hotspot {
  cursor: help;
}
/*
 * El disco pasa de aro hueco a disco de papel: se ve exactamente igual que antes —papel sobre el
 * papel del dibujo— pero deja de ser una circunferencia de un píxel y pasa a ser un blanco de 24
 * unidades que el puntero y el dedo aciertan sin puntería.
 */
.hotspot circle.badge {
  fill: var(--diagram-bg, #f5f2ec);
}
.hotspot:hover circle.badge,
.hotspot.is-hot circle.badge {
  fill: color-mix(in srgb, var(--diagram-ink, #2b2320) 18%, transparent);
  stroke-width: 2;
}
/*
 * El foco, con el acento del papel. Hasta la tarea E1 se dibujaba con la tinta del diagrama, y con
 * razón: el panel es papel claro en los DOS temas y el `--ai` de la página, azul pálido en oscuro,
 * daba 1,97:1 sobre el papel —por debajo del 3:1 de WCAG 2.2 SC 1.4.11—. Desde que el panel
 * redefine su propio `--ai` (ver «panel de papel») ya no hace falta la excepción: el índigo del
 * papel pasa de 9:1 y el foco del sitio vuelve a ser uno solo, aquí y en el resto (23/09/2026).
 */
.hotspot:focus-visible {
  outline: 2px solid var(--ai);
  outline-offset: 2px;
}

/* La leyenda numerada: la numera el navegador, que para eso es una lista ordenada. */
.legend {
  margin: 1rem 0;
  padding-left: 1.75rem;
}
.legend > li {
  margin: 0.35rem 0;
  padding: 0.15rem 0.5rem;
  border-radius: var(--r);
  /* El resalte entra y sale; el color, a secas, daría un parpadeo a cada línea que se roza. */
  transition: background-color var(--mov-1) ease-out;
}
.legend > li.is-hot {
  background: var(--ai2);
}

/*
 * El globo del número.
 *
 * Va en coordenadas de ventana (`fixed`) porque el diagrama vive dentro de un carril que se
 * desplaza de lado: colgado del carril, el globo de los números del borde se cortaría contra él.
 * El módulo lo coloca sobre la cifra y lo recoloca al desplazar la página; el `translateY` de aquí
 * lo sube su propio alto, que el guión no tiene que medir. Y sin `pointer-events` el globo se
 * pondría bajo el puntero, robaría el `pointerover` del número y se cerraría solo.
 *
 * El precio de ese `pointer-events: none` es que no se puede posar el ratón sobre el globo para
 * leerlo con calma o seleccionar su texto (WCAG 2.2 SC 1.4.13, «al pasar por encima»). Se asume a
 * sabiendas: el mismo texto está entero y seleccionable en la leyenda de abajo, que es adonde se
 * va a leer despacio, y el globo es un rótulo de paso (23/09/2026).
 */
.anatomy-tip {
  position: fixed;
  z-index: 55;
  max-width: min(22rem, calc(100vw - 2rem));
  transform: translateY(calc(-100% - 0.5rem));
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--line);
  border-radius: var(--r2);
  background: var(--hamon);
  color: var(--ink);
  box-shadow: var(--shadow-2);
  font-size: var(--fs-3);
  line-height: 1.45;
  pointer-events: none;
}
/* Cuando encima no cabe, el guión lo baja bajo el número y lo dice con esta clase. */
.anatomy-tip.is-below {
  transform: translateY(0.5rem);
}
.anatomy-tip[hidden] {
  display: none;
}

.steps {
  list-style: none;
  counter-reset: paso;
  margin-left: 0;
}
/* Aquí la numeración sí dice algo: las compras ocurren en este orden. */
.steps > li {
  counter-increment: paso;
  position: relative;
  padding-left: 2.75rem;
  margin-bottom: 1.5rem;
}
.steps > li::before {
  content: counter(paso);
  position: absolute;
  left: 0;
  top: -0.15rem;
  font: 700 var(--fs-6)/1 var(--mincho);
  color: var(--kin);
}

.provisional {
  border-left: 3px solid var(--kin);
  padding-left: 1rem;
  color: var(--ink2);
  font-size: var(--fs-3);
}
.contact {
  margin-top: 2rem;
}
.eml {
  border: 1px solid var(--ai);
  background: transparent;
  color: var(--ai);
  border-radius: var(--pill);
  padding: 0.4rem 1.1rem;
  font-size: var(--fs-3);
  font-weight: 600;
}
.eml:hover {
  background: var(--ai);
  color: var(--ji);
}
.eml.cta {
  border-color: transparent;
  background: var(--ai);
  color: var(--ji);
}

.not-found {
  text-align: center;
  padding-block: 7rem 6rem;
}
/* El tope de renglón legible sigue puesto; para centrar hay que centrar también la caja. */
.not-found > * {
  margin-inline: auto;
}
.not-found p {
  margin-top: 1rem;
}
.not-found h1 {
  max-width: none;
}

/* ---------------------------------------------------- aviso del botón de correo */

.eml-aviso {
  position: fixed;
  left: 50%;
  bottom: 1.5rem;
  transform: translateX(-50%);
  z-index: 2147483647;
  max-width: calc(100vw - 2rem);
  padding: 0.75rem 1.15rem;
  border-radius: var(--r2);
  background: var(--ink);
  color: var(--ji);
  text-align: center;
  opacity: 0;
  transition: opacity var(--mov-2) ease;
}
.eml-aviso.visible {
  opacity: 1;
}
/* La dirección va invertida en el DOM y se endereza aquí: quien lea el texto se la lleva al revés. */
.eml-aviso .addr {
  unicode-bidi: bidi-override;
  direction: rtl;
  user-select: all;
  font-weight: 700;
}

/* -------------------------------------------------------------------- pantallas */

/*
 * La lámina ya no cambia de forma con la ventana: es la rejilla la que decide cuántas caben, y la
 * tarjeta es la misma en las cuatro columnas de un escritorio y en la única de un teléfono. De
 * aquel escalonado —tres columnas, dos, una— sólo queda lo que de verdad es de la ventana: la
 * ficha de la pieza y la galería.
 */
@media (max-width: 62rem) {
  .piece-columns {
    grid-template-columns: minmax(0, 1fr);
    gap: 2.5rem;
  }
  .piece-aside {
    position: static;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  }
  .gallery-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

/*
 * La cabecera se pliega antes que la lista: cuatro secciones, seis idiomas y el botón de tema no
 * caben en una línea mucho antes de que la fila deje de funcionar.
 *
 * El corte estaba en 56rem (896 px), y entre eso y el ancho del sitio (`--wrap`, 1240 px) quedaba
 * una tierra de nadie: ni cabecera de una línea —«Cómo comprar» y «Deutsch» se partían a una
 * segunda línea dentro de su propia lista, sin que la cabecera llegara a plegarse— ni menú
 * plegado (Antonio, 21/09/2026). El corte sube a un pelo por debajo de `--wrap`: a partir de
 * 1240 px cabe entera en una línea, y por debajo se pliega limpio, sin ese hueco intermedio.
 */
@media (max-width: 77.4375rem) {
  /* 1.239 px: un píxel menos que --wrap (1.240 px), para que a 1.240 px exacto ya sea la fila. */
  .site-header {
    flex-wrap: wrap;
    gap: 0.5rem;
  }
  .nav-toggle {
    display: block;
    margin-left: auto;
    order: 1;
  }
  .theme-toggle {
    order: 2;
  }
  /*
   * Los seis idiomas escritos con todas sus letras no caben en 360 px —«Portugiesisch» solo ya
   * ocupa media línea—, así que bajan al menú plegable con el resto. Cambiar de idioma pasa a
   * costar dos toques; se hace una vez por visita.
   */
  .main-nav,
  .lang-nav {
    order: 3;
    flex: 1 1 100%;
    margin-left: 0;
  }
  .lang-nav {
    order: 4;
  }
  /*
   * Se pliegan **sólo si hay JavaScript**. El botón que los despliega tampoco se enseña sin él, de
   * modo que plegarlos siempre dejaría el menú y los seis idiomas fuera de alcance: la página se
   * podría leer y no se podría recorrer.
   */
  :root.js .main-nav,
  :root.js .lang-nav {
    display: none;
  }
  :root.js.nav-open .main-nav,
  :root.js.nav-open .lang-nav {
    display: block;
  }
  :root.nav-open .lang-nav {
    padding-bottom: 0.75rem;
  }
  .lang-nav ul {
    flex-wrap: wrap;
    gap: 0.25rem 0.5rem;
    padding-top: 0.75rem;
    border-top: 1px solid var(--line);
  }
  .lang-nav a {
    padding: 0.25rem 0;
  }
  .main-nav ul {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
  }
  .main-nav a {
    padding: 0.6rem 0;
    font-size: var(--fs-4);
    border-radius: 0;
  }
  .nav-access {
    margin-left: 0;
    padding-left: 0;
    border-left: 0;
    border-top: 1px solid var(--line);
    margin-top: 0.25rem;
    padding-top: 0.25rem;
  }
  /*
   * Con la cabecera en dos líneas, una barra de filtros pegada debajo se come un tercio de la
   * pantalla y tapa la primera fila. En vertical el espacio vale más que la comodidad: la barra se
   * queda donde está y se vuelve a ella subiendo.
   */
  .filters {
    position: static;
  }
}

@media (max-width: 40rem) {
  :root {
    --px-cm: 2.2px;
  }

  .wrap,
  .site-header,
  .site-footer,
  main > * {
    padding-inline: 1rem;
  }

  .page-head {
    padding-block: 2.5rem 1.5rem;
  }
  .hero {
    margin-block: 1.5rem 1rem;
    padding: 1.75rem 1.25rem;
  }

  .result-count {
    flex: 1 1 100%;
    margin-right: 0;
  }
  .search input {
    width: 100%;
  }
  .field.search {
    flex: 1 1 10rem;
  }
  .field.sort label {
    display: none;
  }
  .filters-fields {
    grid-template-columns: minmax(0, 1fr);
  }

  /* A 390 px la lámina es una y ocupa la pantalla: el nombre se lee, pero un punto menos. */
  .piece-name {
    font-size: var(--fs-5);
  }

  /* A 360 px la firma va delante del nombre: si va detrás, el nombre se queda sin ancho. */
  .piece-title {
    flex-direction: row-reverse;
    justify-content: flex-end;
    gap: 1rem;
  }
  .piece-title .mei {
    max-height: 8rem;
    border-left: 0;
    border-right: 1px solid var(--line);
    padding-left: 0;
    padding-right: 1rem;
  }
  /*
   * En el teléfono la hoja se estira al ancho de la columna: cabe justa y encogerla más la deja
   * ilegible. A cambio deja de estar a escala, así que la regla de los 10 cm se retira con ella:
   * una regla que no mide lo que hay al lado miente, y eso es peor que no tenerla.
   */
  .piece-blade {
    width: 100%;
  }
  .blade-key {
    display: none;
  }
  .gallery-grid {
    grid-template-columns: repeat(2, 1fr);
  }
  .gallery-grid .cover button {
    aspect-ratio: 3 / 2;
  }
  .score-lines li {
    grid-template-columns: minmax(0, 1fr) 3.5rem;
  }
  .score-lines .component {
    grid-column: 1;
  }
  .score-lines .bar {
    grid-column: 1 / -1;
    grid-row: 2;
  }
  .score-lines .points {
    grid-column: 2;
    grid-row: 1;
  }
  .score-lines .reason {
    grid-column: 1 / -1;
    grid-row: 3;
  }
  /*
   * Aquí la bandeja va de `left` a `right`: el ancho lo pone la pantalla y no el contenido, así que
   * envolver ya no le quita sitio a nadie y es justo lo que hace falta, porque los cuatro controles
   * en una línea no caben en 390 px.
   */
  .compare-tray {
    left: 1rem;
    right: 1rem;
    transform: none;
    max-width: none;
    border-radius: var(--r2);
    padding: 0.6rem 0.75rem;
    flex-wrap: wrap;
  }
  /*
   * Dos líneas, y repartidas: el carril de miniaturas se queda arriba con el contador y los dos
   * botones bajan juntos. Las 10 rem de base son las que lo consiguen —medido a 390 px: con menos,
   * «Ver la comparación» se cuela en la primera línea y deja el carril en 101 px—; el carril crece
   * luego con todo lo que sobra.
   */
  .compare-list {
    flex: 1 1 10rem;
  }
  .compare-tray .cta {
    flex: 1 1 auto;
    text-align: center;
  }
  .compare-tray .link {
    flex: 0 0 auto;
  }
  .pager {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.75rem;
  }
  .pager .next {
    text-align: left;
  }
}

/* ----------------------------------------------------------------- preferencias */

/*
 * Quien pide menos movimiento se queda sin él, por dos caminos a la vez (tarea E1, 23/09/2026).
 *
 * El de arriba son los tokens: desde el rediseño, cada transición de la hoja dura `--mov-1` o
 * `--mov-2`, así que ponerlos a cero apaga el sistema entero desde su raíz y sin `!important`, que
 * es lo limpio. El de abajo es el suelo, y se queda: alcanza a lo que no sale de los tokens —una
 * animación de un componente, el desplazamiento suave del navegador— y a cualquier regla que entre
 * mañana sin acordarse de esto.
 */
@media (prefers-reduced-motion: reduce) {
  :root {
    --mov-1: 0s;
    --mov-2: 0s;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

@media (prefers-contrast: more) {
  :root {
    --line: var(--ink2);
    --line2: var(--ink2);
    --ink2: var(--ink);
  }
}

@media print {
  .site-header,
  .filters,
  .filters-panel,
  .filters-backdrop,
  .compare-tray,
  .pager,
  .theme-toggle,
  .compare-btn {
    display: none !important;
  }
  body {
    background: #fff;
    color: #000;
  }
}
