/* =========================================================================
   main.css — hoja de estilos única del sitio público.

   PORTADA DESDE comparalibros.com: es el mismo sistema de diseño, con el azul
   cambiado por el verde del tema y la tipografía de la casa (Baloo 2 +
   Plus Jakarta Sans) en lugar de la Montserrat autoalojada de allí.

   El color, la tipografía y la geometría salen de custom properties
   `--theme-*` que el servidor inyecta en un <style> del <head> a partir del
   preset de /admin/apariencia. Los literales de color del original se han
   mapeado a esos tokens uno a uno: si quedara alguno suelto, cambiar de tema
   dejaría esa pieza con la paleta anterior y el editor de Apariencia sería
   decorativo.

   Los `--ui-*` son la capa derivada (esquinas, sombras, tintes del acento) y
   se construyen SIEMPRE a partir de los `--theme-*`, para que el admin siga
   mandando sobre toda la interfaz y no sólo sobre la mitad.

   Móvil primero; breakpoints en 640 / 720 / 980 / 1080 px.
   ========================================================================= */

/* =========================================================================
   TIPOGRAFÍA AUTOALOJADA.

   Estaba servida desde fonts.googleapis.com con un <link rel="stylesheet">, y
   eso es una hoja BLOQUEANTE en un tercero: antes de pintar una letra el
   navegador tenía que resolver DNS y negociar TLS con fonts.googleapis.com
   para el CSS y otra vez con fonts.gstatic.com para los ficheros. En la
   primera visita eso son varios segundos de página en blanco; en la segunda no
   se nota porque ya está todo en la caché del navegador, que es justo lo que
   hace que el problema no aparezca mirando la web a diario.

   Ahora salen de este mismo origen, ya en el `immutable 30d` de /assets, y sin
   dos orígenes de terceros en el camino crítico. De paso deja de irse la IP de
   cada visitante a Google antes de que nadie acepte nada en el banner.

   Las dos familias son VARIABLES: un solo fichero por familia y subconjunto
   cubre todos los pesos, de ahí el rango en `font-weight`. Sólo se alojan los
   subconjuntos latinos — Google servía además cirílico, devanagari y vietnamita
   que aquí no pinta nadie. 4 ficheros, 107 KB.

   Para regenerarlos (al cambiar de familia o de pesos): `node
   scripts/fetch-fonts.mjs src/public/fonts`.
   ========================================================================= */

@font-face {
  font-family: 'Baloo 2';
  font-style: normal;
  font-weight: 600 800;
  font-display: swap;
  src: url('/assets/fonts/baloo-2-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Baloo 2';
  font-style: normal;
  font-weight: 600 800;
  font-display: swap;
  src: url('/assets/fonts/baloo-2-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Plus Jakarta Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/plus-jakarta-sans-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Plus Jakarta Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/plus-jakarta-sans-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  /*
   * Alto de la cabecera pegajosa. Va en `:root` y no en `.site-header` porque
   * lo necesitan DOS elementos que no son parientes: la propia cabecera
   * (`min-height`) y el buscador pegajoso, que se coloca respecto a ella. Con
   * el numero escrito en dos sitios, el segundo se desfasa en cuanto cambia el
   * contenido del primero — que es exactamente lo que habia pasado.
   *
   * No lo pisa la inyeccion de tema: ese bloque solo declara `--theme-*`.
   */
  --header-h: 4.85rem;

  /* Fallbacks (preset Confeti) por si la inyección de tema fallase. */
  --theme-bg: #F5F2EE;
  --theme-surface: #ffffff;
  --theme-surface-alt: #EDF7F0;
  --theme-ink: #1F1B2E;
  --theme-ink-soft: #524D68;
  --theme-ink-muted: #8B879C;
  --theme-border: #EFE6DA;
  --theme-accent: #0F8A4D;
  --theme-accent-soft: #E2F5EA;
  --theme-success: #12855C;
  --theme-danger: #D62B1F;
  --theme-radius: 4px;
  --theme-radius-lg: 8px;
  --theme-shadow: 0 1px 2px rgba(31, 27, 46, 0.06), 0 10px 28px rgba(31, 27, 46, 0.08);
  --theme-shadow-sm: 0 1px 2px rgba(31, 27, 46, 0.06);
  --theme-font-heading: "Baloo 2", "Plus Jakarta Sans", system-ui, sans-serif;
  --theme-font-body: "Plus Jakarta Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  --theme-font-mono: "JetBrains Mono", "Menlo", monospace;
  --theme-density-scale: 1;

  /* Aliases hacia atrás para que `admin.css` siga funcionando sin tocar
     todos sus tokens. */
  --color-bg: var(--theme-bg);
  --color-surface: var(--theme-surface);
  --color-border: var(--theme-border);
  --color-text: var(--theme-ink);
  --color-muted: var(--theme-ink-muted);
  --color-accent: var(--theme-accent);
  --color-accent-hover: var(--theme-accent);
  --color-success: var(--theme-success);
  --color-danger: var(--theme-danger);
  --radius: var(--theme-radius);
  --shadow-sm: var(--theme-shadow-sm);
  --shadow-md: var(--theme-shadow);
  --font-sans: var(--theme-font-body);

  /* Espaciado escalable por densidad. */
  --pad-xs: calc(0.25rem * var(--theme-density-scale));
  --pad-sm: calc(0.5rem * var(--theme-density-scale));
  --pad-md: calc(1rem * var(--theme-density-scale));
  --pad-lg: calc(1.5rem * var(--theme-density-scale));
  --pad-xl: calc(2.5rem * var(--theme-density-scale));

  /* ---- Tokens derivados para la capa visual "pro" (inspirada en el
     directorio de gasolineras pero en azul). Se construyen a partir de los
     `--theme-*` para respetar el sistema de temas y los overrides del admin. */
  --ui-accent: var(--theme-accent);
  --ui-accent-strong: color-mix(in srgb, var(--theme-accent) 82%, #000 18%);
  --ui-accent-soft: var(--theme-accent-soft);
  --ui-accent-tint: color-mix(in srgb, var(--theme-accent) 22%, #fff);
  --ui-accent-ring: color-mix(in srgb, var(--theme-accent) 30%, transparent);

  /* ESCALA ÚNICA DE REDONDEO. Antes había dos en paralelo —`--theme-radius` a
     4 px y `--ui-radius-md` a 12 px— conviviendo en la misma tarjeta, más nueve
     literales sueltos (3, 5, 9, 10, 11, 14 px…) y el mismo token escrito con
     tres fallbacks distintos (`--ui-radius-lg, 14px` / `, 16px` / `, 18px`).
     De ahí que cada caja tuviera su propia esquina.
     Los cuatro pasos derivan de `--theme-radius-lg`, que es lo que inyecta el
     preset de tema desde la BD (services/site-config/index.ts): así el admin
     sigue mandando y toda la interfaz escala junta en vez de por partes. Con el
     valor actual (8) salen 8/12/18/24, exactamente los de hoy. */
  --ui-radius-sm: var(--theme-radius-lg);
  --ui-radius-md: calc(var(--theme-radius-lg) * 1.5);
  --ui-radius-lg: calc(var(--theme-radius-lg) * 2.25);
  --ui-radius-xl: calc(var(--theme-radius-lg) * 3);
  --ui-radius-pill: 999px;
  /* Fondo de las fotos de producto. NO sale de `--theme-surface` a propósito y
     es la única excepción a «ni un literal de color»: las fotos de Amazon
     llevan el blanco INCRUSTADO en el píxel, así que sobre cualquier otro
     color se ve el recuadro blanco de la foto flotando dentro de la caja. Con
     el tema oscuro el efecto es peor, no mejor. */
  --ui-photo-bg: #fff;
  /* Radio de TODOS los botones de accion (comprar, anadir a la comparativa,
     barra movil). Existe para que no vuelva a pasar lo de agosto-2026: cada
     CTA habia elegido su esquina por su cuenta —8px en la comparativa, 12 en
     el rail, 18 en la barra movil y pildora en dos sitios— y el tema `planeta`
     parcheaba UNO solo, asi que en produccion convivian cuatro esquinas
     distintas en la misma pantalla. Se cambia aqui y se mueven todos. */
  --ui-radius-cta: var(--ui-radius-pill);

  --ui-shadow-sm: 0 1px 2px rgba(31, 27, 46, 0.05), 0 1px 3px rgba(31, 27, 46, 0.04);
  --ui-shadow-md: 0 6px 22px rgba(31, 27, 46, 0.08), 0 2px 6px rgba(31, 27, 46, 0.05);
  --ui-shadow-lg: 0 22px 50px rgba(31, 27, 46, 0.14), 0 4px 12px rgba(31, 27, 46, 0.06);
  --ui-shadow-accent: 0 12px 30px color-mix(in srgb, var(--theme-accent) 32%, transparent);

  /* Icono de lupa (data-uri) para máscaras CSS en el buscador del hero. */
  --ui-search-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.35-4.35'/%3E%3C/svg%3E");
}

* { box-sizing: border-box; }

html { font-size: 16px; }

body {
  margin: 0;
  font-family: var(--theme-font-body);
  color: var(--theme-ink);
  background-color: var(--theme-bg);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Decoración de fondo según tema. */

body.theme-pizarra {
  background-image:
    linear-gradient(var(--theme-border) 1px, transparent 1px),
    linear-gradient(90deg, var(--theme-border) 1px, transparent 1px);
  background-size: 24px 24px, 24px 24px;
  background-position: -1px -1px;
}


h1, h2, h3, h4, h5, h6 {
  font-family: var(--theme-font-heading);
  color: var(--theme-ink);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.01em;
}

p { margin: 0 0 0.85rem; }

a {
  color: var(--theme-accent);
  text-decoration: none;
}
a:hover, a:focus { text-decoration: underline; }

code, pre, .mono { font-family: var(--theme-font-mono); }

::selection {
  background: var(--theme-accent);
  color: var(--theme-surface);
}

/* ----------------------------- Layout shell ----------------------------- */

.container {
  max-width: 1440px;
  margin: 0 auto;
  padding: 0 1.5rem;
}

main.container {
  padding-top: var(--pad-lg);
  padding-bottom: var(--pad-xl);
  min-height: 60vh;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* -------------------------------- Header -------------------------------- */

/* El header es sticky (~70 px): sin esto, los saltos de ancla («Compara las
   3 tiendas ↓» de la ficha, #comprar y #mix de la lista…) alinean el destino
   con el borde superior de la ventana y el menú fijo se come el principio de
   la sección (12-ago-2026). Aplica a toda ancla y scrollIntoView del
   documento; 84 px = header + un poco de aire. */
html { scroll-padding-top: 84px; }

.site-header {
  min-height: var(--header-h);
  /* Flex en columna para CENTRAR el contenido en el alto del `min-height`: sin
     esto la fila se pegaba arriba y el aire sobrante caía todo debajo (se veía
     sobre todo en móvil, donde la fila mide ~59 px de los 77 de la banda). Los
     desplegables absolutos (nav, buscador) no se ven afectados: se anclan a la
     cabecera entera, que ya era `sticky` (= posicionada). */
  display: flex;
  flex-direction: column;
  justify-content: center;
  background: var(--theme-surface);
  border-bottom: 1px solid var(--theme-border);
  position: sticky;
  top: 0;
  z-index: 20;
  /* Sin `backdrop-filter`: el fondo ya es opaco, así que el desenfoque no se
     veía y sólo añadía una capa de composición que el navegador rehace en
     cada scroll. */
}

.site-header__inner {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding-top: 0.85rem;
  padding-bottom: 0.85rem;
  flex-wrap: wrap;
  /* La cabecera es flex en columna y este `.container` pasa a ser ITEM flex:
     sus `margin: 0 auto` absorben el espacio horizontal libre y lo encogían a
     su contenido (284 px medidos). Con ancho completo, el auto vuelve a ser
     solo centrado y el `margin-left: auto` de la lupa recupera su empuje. */
  width: 100%;
}

.site-header__brand {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--theme-font-heading);
  font-weight: 700;
  font-size: 1.15rem;
  color: var(--theme-ink);
  letter-spacing: -0.01em;
}
.site-header__brand:hover, .site-header__brand:focus {
  text-decoration: none;
  color: var(--theme-ink);
}

.site-header__logo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: var(--ui-radius-sm);
  background: var(--theme-accent-soft);
  font-size: 1.1rem;
}
.site-header__logo-mark { width: 1.35rem; height: 1.35rem; }
.site-footer__logo-mark { width: 1.3rem; height: 1.3rem; color: #fff; }

.site-header__brand-tagline {
  color: var(--theme-ink-muted);
  font-size: 0.78rem;
  font-weight: 400;
  font-family: var(--theme-font-body);
  letter-spacing: 0.01em;
}

.site-header__nav {
  display: none;
  gap: 1.1rem;
  margin-left: auto;
  font-size: 0.92rem;
  align-items: center;
}
.site-header__nav a {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  color: var(--theme-ink-soft);
  font-weight: 500;
}
.site-header__nav a:hover { color: var(--theme-accent); text-decoration: none; }
/* El icono va SIEMPRE en el acento, también con el enlace en reposo: es la
   marca de color pedida para el menú; el texto conserva su tinta. */
.site-header__nav-icon {
  flex: none;
  width: 1.05rem;
  height: 1.05rem;
  color: var(--theme-accent, currentColor);
}
@media (min-width: 720px) { .site-header__nav { display: inline-flex; } }

/* ---- Menú hamburguesa (móvil < 720px). CSS-only por la CSP estricta: un
   checkbox oculto controla el desplegable; el <label> es el botón. ---- */
.site-header__nav-toggle { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.site-header__burger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-left: auto;
  width: 2.6rem;
  height: 2.6rem;
  flex: none;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-sm);
  background: var(--theme-surface);
  color: var(--theme-ink);
  cursor: pointer;
}
.site-header__burger:hover { border-color: var(--theme-accent); color: var(--theme-accent); }
.site-header__burger-icon { width: 1.4rem; height: 1.4rem; }
.site-header__burger-icon--close { display: none; }
.site-header__nav-toggle:checked ~ .site-header__burger .site-header__burger-icon--open { display: none; }
.site-header__nav-toggle:checked ~ .site-header__burger .site-header__burger-icon--close { display: inline; }
/* Panel desplegable a todo el ancho, justo bajo la cabecera (sticky = posicionada). */
.site-header__nav-toggle:checked ~ .site-header__nav {
  display: flex;
  flex-direction: column;
  /* `stretch`, no el `center` heredado del nav de escritorio: en columna aquel
     centraba cada enlace y el menú salía con los items flotando en el medio.
     Estirados, el texto queda a la izquierda y el hover cubre la fila entera. */
  align-items: stretch;
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  gap: 0.1rem;
  padding: 0.5rem 1rem 0.9rem;
  background: var(--theme-surface);
  border-bottom: 1px solid var(--theme-border);
  box-shadow: 0 14px 22px rgba(31, 27, 46, 0.12);
}
.site-header__nav-toggle:checked ~ .site-header__nav a { padding: 0.65rem 0.5rem; border-radius: var(--ui-radius-sm); }
.site-header__nav-toggle:checked ~ .site-header__nav a:hover { background: var(--theme-accent-soft); }
@media (min-width: 720px) {
  .site-header__burger { display: none; }
  /* En escritorio el nav vuelve a su sitio aunque el checkbox quedara marcado. */
  .site-header__nav-toggle:checked ~ .site-header__nav {
    position: static; flex-direction: row; padding: 0; gap: 1.1rem;
    background: none; border: 0; box-shadow: none;
  }
}

/* CTA "Comparar lista": único llamado a la acción del header. En móvil queda
   pegado a la derecha (la marca a la izquierda); en >=720px va tras el nav. */
.site-header__cta {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-left: auto;
  padding: 0.5rem 1rem;
  border-radius: var(--ui-radius-cta);
  background: var(--theme-accent);
  color: var(--theme-surface);
  font-family: var(--theme-font-body);
  font-weight: 600;
  font-size: 0.9rem;
  white-space: nowrap;
  line-height: 1.3;
}
.site-header__cta:hover, .site-header__cta:focus {
  filter: brightness(0.93);
  color: var(--theme-surface);
  text-decoration: none;
}
.site-header__cta svg { width: 1rem; height: 1rem; }
@media (min-width: 720px) { .site-header__cta { margin-left: 0.75rem; } }

/* MÓVIL: la cabecera en UNA fila. Con `flex-wrap: wrap` y el rótulo del CTA
   visible, marca (183 px) + hamburguesa (42) + CTA (209) + huecos (32) pedían
   466 px sobre los ~260 útiles de un móvil de 320-390 px, así que el CTA saltaba
   a una segunda fila y la cabecera —que es `sticky`— se comía 126 px de alto
   medidos en producción. Sin el rótulo baja a 59 px. `nowrap` es deliberado: con
   `wrap` el navegador prefiere partir la fila antes que encoger la marca. */
@media (max-width: 719px) {
  .site-header__inner {
    flex-wrap: nowrap;
    gap: 0.5rem;
    padding-top: 0.6rem;
    padding-bottom: 0.6rem;
  }
  /* `min-width: 0` para que la marca sí pueda encoger: por defecto un item flex
     no baja de su ancho de contenido y sería ella la que fuerza el desbordamiento. */
  .site-header__brand { font-size: 1rem; min-width: 0; flex: 0 1 auto; }
  .site-header__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .site-header__logo { width: 1.75rem; height: 1.75rem; flex: none; }
  .site-header__cta { margin-left: auto; padding: 0.5rem 0.65rem; gap: 0.3rem; flex: none; }
  .site-header__cta-label { display: none; }
  /* Lupa y hamburguesa al BORDE derecho. El empuje vivía en el CTA (herencia
     de comparalibros), pero esta cabecera no tiene CTA: sin nadie con
     `margin-left: auto`, los botones se quedaban pegados a la marca. */
  .site-header__search-btn { margin-left: auto; }
  .site-header__burger { width: 2.4rem; height: 2.4rem; margin-left: 0; }
}
/* Por debajo de 380 px (iPhone SE y compañía) sólo el logotipo: «ComparaLi…»
   cortado a media palabra se lee peor que no poner el nombre, y el logo ya
   enlaza a la home con su `aria-label`. */
@media (max-width: 379px) {
  .site-header__name { display: none; }
}
.site-header__cta-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.35rem;
  height: 1.35rem;
  padding: 0 0.4rem;
  border-radius: var(--ui-radius-pill);
  background: rgba(255, 255, 255, 0.28);
  font-size: 0.8rem;
  font-weight: 800;
}

/* --------------------------------- Buttons ------------------------------ */

.button {
  padding: 0.55rem 1.1rem;
  border: 0;
  border-radius: var(--ui-radius-cta);
  background: var(--theme-accent);
  color: var(--theme-surface);
  font-family: var(--theme-font-body);
  font-weight: 600;
  cursor: pointer;
  font-size: 0.95rem;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  text-align: center;
  line-height: 1.5;
  transition: filter 0.12s ease;
}
.button:hover { filter: brightness(0.93); color: var(--theme-surface); text-decoration: none; }

.button--ghost {
  background: transparent;
  color: var(--theme-ink);
  border: 1px solid var(--theme-border);
}
.button--ghost:hover { color: var(--theme-accent); border-color: var(--theme-accent); }

.button--soft {
  background: var(--theme-accent-soft);
  color: var(--theme-accent);
}

.button--dark {
  background: var(--theme-ink);
  color: var(--theme-surface);
}

/* --------------------------------- Hero --------------------------------- */

.hero {
  position: relative;
  text-align: center;
  padding: clamp(2rem, 6vw, 3.75rem) 0 clamp(1.5rem, 4vw, 2.5rem);
}
.hero::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 0.5rem;
  width: 56px;
  height: 4px;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent);
  transform: translateX(-50%);
  opacity: 0.85;
}
body.theme-pizarra .hero::before { display: none; }

.hero__eyebrow {
  display: inline-block;
  margin: 0 0 0.75rem;
  padding: 0.2rem 0.65rem;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent-soft);
  color: var(--theme-accent);
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.hero__title {
  font-family: var(--theme-font-heading);
  /* Un punto más grande que el resto de titulares del sitio: es el único H1
     que compite con una banda de color a sangre. */
  font-size: clamp(2.2rem, 5.8vw, 3.9rem);
  margin: 0 0 0.85rem;
  line-height: 1.05;
  letter-spacing: -0.025em;
}
.hero__title strong { color: var(--theme-accent); font-weight: 700; }

.hero__lead {
  font-size: clamp(1rem, 1.6vw, 1.18rem);
  color: var(--theme-ink-soft);
  /* 720 y no 640: con 640 la entradilla caía en TRES líneas en escritorio y
     empujaba la caja de búsqueda 30 px hacia abajo. En dos líneas se lee mejor
     y el ancho sigue por debajo del límite de legibilidad (~75 caracteres). */
  max-width: 720px;
  margin: 0 auto 1.4rem;
}

/* Píldora «gratis» del hero. Iba como última frase de la entradilla y ahí no la
   leía nadie: es la primera duda del que llega, así que sale del párrafo y se
   pinta con contraste invertido (superficie clara sobre la banda del hero) para
   que gane al texto que la rodea sin robarle el sitio al comparador. */
.hero__free {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.15rem 0.45rem;
  margin: 0 auto;
  padding: 0.45rem 1.05rem;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-surface);
  border: 1px solid color-mix(in srgb, var(--theme-accent) 35%, var(--theme-border));
  box-shadow: var(--ui-shadow-sm);
  color: var(--theme-ink);
  font-size: 0.95rem;
  line-height: 1.35;
}
.hero__free strong {
  color: var(--theme-accent);
  font-weight: 800;
  letter-spacing: 0.01em;
}
.hero__free-icon {
  width: 1.05rem;
  height: 1.05rem;
  color: var(--theme-accent);
  flex-shrink: 0;
}

.hero__search {
  display: flex;
  gap: 0.5rem;
  max-width: 660px;
  margin: 0 auto;
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  padding: 0.4rem;
  box-shadow: var(--theme-shadow);
}

.hero__search input {
  flex: 1;
  padding: 0.85rem 1rem;
  border: 0;
  border-radius: var(--ui-radius-sm);
  font: inherit;
  font-size: 1rem;
  background: transparent;
  color: var(--theme-ink);
}
.hero__search input:focus { outline: none; }

.hero__search button {
  padding: 0.85rem 1.4rem;
  border: 0;
  border-radius: var(--ui-radius-cta);
  background: var(--theme-accent);
  color: var(--theme-surface);
  font: inherit;
  font-weight: 600;
  font-size: 1rem;
  cursor: pointer;
}
.hero__search button:hover { filter: brightness(0.93); }

.hero__hint {
  margin: 0.85rem auto 0;
  color: var(--theme-ink-muted);
  font-size: 0.85rem;
  max-width: 660px;
}
.hero__hint a { color: var(--theme-ink-soft); border-bottom: 1px dashed currentColor; }

/* ------------------- Enlazado interno por categorías -------------------- */
/* Nubes de chips en la home (curso / asignatura / editorial) y cabeceras de
   los hubs (/cursos, /asignaturas, /editoriales). Comparten .category-cloud
   y .category-chip para un look consistente. */

.home-categories {
  display: flex;
  flex-direction: column;
  gap: 1.75rem;
  padding: 0.5rem 0 2.5rem;
}

.home-categories__group {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 1.35rem 1.5rem 1.6rem;
  background: var(--theme-surface-alt);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  box-shadow: var(--ui-shadow-sm);
}

.home-categories__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}

.home-categories__title {
  margin: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-size: clamp(1.1rem, 1.8vw, 1.3rem);
  font-weight: 700;
}

.home-categories__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  flex: none;
  border-radius: var(--ui-radius-md);
  background: var(--theme-accent-soft);
  color: var(--theme-accent);
}
.home-categories__icon svg { width: 1.1rem; height: 1.1rem; }

.home-categories__all {
  font-weight: 600;
  white-space: nowrap;
  color: var(--theme-accent);
}

.category-cloud {
  display: flex;
  flex-wrap: wrap;
  gap: 0.55rem;
}

/* --- Cursos agrupados por etapa (home) --------------------------------- */
/* Cada etapa lleva su color para escanearse de un vistazo («busco 3º dentro
   del bloque Primaria»). MISMA paleta que las .stage-card del hub /cursos:
   un color por etapa en toda la web. Como esos tonos son de filete decorativo
   y no dan AA de texto pequeño, el texto usa --stage-ink (el tono oscurecido)
   y el color puro queda para bordes, fondos tintados y rellenos de hover.
   OJO: NO llamar a esto .stage-card — esa clase es del hub /cursos. */

.home-categories__group--courses {
  background: linear-gradient(160deg, var(--theme-accent-soft), var(--theme-surface-alt) 60%);
  border-color: color-mix(in srgb, var(--theme-accent) 20%, var(--theme-border));
}

.home-stages {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 0.75rem;
}
/* Las etapas se reparten el ancho entero de la tarjeta (14-ago-2026): con los
   anchos naturales la fila terminaba a media caja y el hueco de la derecha
   parecía un bloque a medio cargar. `flex-grow` con base `auto` reparte SOLO el
   sobrante a partes iguales, así que Primaria (seis cursos) sigue siendo la más
   ancha y FP la más estrecha; no las iguala. */
.home-stages > * { flex: 1 1 auto; }

.home-stage {
  --stage-color: var(--theme-accent);
  --stage-ink: color-mix(in srgb, var(--stage-color) 65%, var(--theme-ink));
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.55rem 0.85rem;
  border: 1px solid color-mix(in srgb, var(--stage-color) 35%, transparent);
  border-radius: var(--ui-radius-md);
  background: linear-gradient(135deg, color-mix(in srgb, var(--stage-color) 11%, #fff), color-mix(in srgb, var(--stage-color) 3%, #fff));
  box-shadow: var(--ui-shadow-sm);
}

.home-stage[data-stage='infantil'] { --stage-color: #E0763F; }
.home-stage[data-stage='primaria'] { --stage-color: var(--theme-success); }
.home-stage[data-stage='eso'] { --stage-color: var(--theme-accent); }
.home-stage[data-stage='bachillerato'] { --stage-color: #6D4AC8; }
.home-stage[data-stage='fp'] { --stage-color: #B8811C; }
.home-stage[data-stage='universidad'] { --stage-color: #0E7490; }

.home-stage__label {
  font-size: 0.8rem;
  font-weight: 800;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--stage-ink);
  white-space: nowrap;
}

.home-stage__years {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}

.home-stage__year {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.2rem;
  height: 2.2rem;
  padding: 0 0.5rem;
  border: 1px solid color-mix(in srgb, var(--stage-color) 45%, transparent);
  border-radius: var(--ui-radius-pill);
  background: var(--theme-surface);
  color: var(--stage-ink);
  font-size: 0.94rem;
  font-weight: 700;
  line-height: 1;
  transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}

.home-stage__year:hover,
.home-stage__year:focus-visible {
  background: var(--stage-ink);
  border-color: var(--stage-ink);
  color: #fff;
  text-decoration: none;
  transform: translateY(-1px);
  box-shadow: 0 4px 12px color-mix(in srgb, var(--stage-color) 35%, transparent);
}

/* Etapas de un solo curso (Infantil, FP, Universidad): la tarjeta es el enlace. */
a.home-stage {
  transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease, background-color 0.15s ease;
}
a.home-stage:hover,
a.home-stage:focus-visible {
  border-color: var(--stage-color);
  text-decoration: none;
  transform: translateY(-1px);
  box-shadow: 0 4px 12px color-mix(in srgb, var(--stage-color) 30%, transparent);
}

/* Categorías agrupadas bajo epígrafes en /categorias (auditoría de
   categorización 11-ago-2026). */
/* -------------------------------------------------------------------------
   Texto propio de la portada (`services/home/home-copy.ts`).

   A todo el ancho, como el resto de la portada. Para que una línea larga no se
   haga ilegible, los párrafos suben de interlineado: es lo que compensa el
   barrido de lado a lado cuando el renglón mide lo que mide la pantalla.
   ------------------------------------------------------------------------- */
.home-copy {
  margin: 2.5rem 0 0;
  color: var(--theme-ink-soft);
}
.home-copy h2 {
  margin: 1.9rem 0 0.6rem;
  font-size: 1.15rem;
  color: var(--theme-ink);
}
.home-copy h2:first-of-type { margin-top: 0; }
.home-copy h3 {
  margin: 1.2rem 0 0.35rem;
  font-size: 1rem;
  color: var(--theme-ink);
}
.home-copy p { margin: 0 0 0.9rem; line-height: 1.75; }
.home-copy strong { color: var(--theme-ink); }

.category-groups {
  display: flex;
  flex-direction: column;
  gap: 1.85rem;
}

/* -------------------------------------------------------------------------
   Portada de sección en /categorias.

   Mosaico de 2×2 con producto real de la propia sección. Va a la IZQUIERDA del
   bloque de texto en pantalla ancha y encima en móvil, sin tocar la estructura
   del documento: los 155 chips de subsección siguen donde estaban, que son los
   enlaces internos que reparten autoridad desde esta página.

   `aria-hidden` + `tabindex="-1"` en el enlace de la portada: lleva al mismo
   sitio que el título de al lado, así que para un lector de pantalla es un
   enlace duplicado sin texto. Con teclado se salta y se llega igual por el h2.
   ------------------------------------------------------------------------- */
/* La sección es una TARJETA. Sin el borde que la encierra, la portada quedaba
   como una foto pegada a la izquierda de un bloque de texto: la caja terminaba
   a media altura, los chips seguían por debajo y la raya del h2 cruzaba sola.
   El borde hace que el conjunto se lea como una unidad aunque el texto sea más
   alto que la portada. */
.category-group {
  display: grid;
  gap: 0.85rem;
  grid-template-columns: 1fr;
  padding: 1rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  background: var(--theme-surface);
}

.section-cover {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  /* Las FILAS también explícitas. Sin esto se dimensionan por el contenido: la
     segunda se salía de la caja cuadrada y `overflow: hidden` cortaba las dos
     fotos de abajo por la mitad. */
  grid-template-rows: repeat(2, 1fr);
  gap: 4px;
  width: 100%;
  max-width: 168px;
  aspect-ratio: 1;
  padding: 4px;
  border-radius: var(--ui-radius-md);
  background: var(--ui-accent-tint);
  overflow: hidden;
}

.section-cover__img {
  width: 100%;
  height: 100%;
  /* Una celda de rejilla no baja de su contenido mínimo si no se le dice. */
  min-width: 0;
  min-height: 0;
  object-fit: contain;
  border-radius: var(--ui-radius-sm);
  background: var(--theme-surface);
}

/* Con una sola foto ocupa el cuadro entero en vez de dejar tres huecos. */
.section-cover:has(.section-cover__img:only-child) .section-cover__img {
  grid-column: span 2;
  grid-row: span 2;
}

/* Dentro de la tarjeta la raya del título sobra: ya separa el borde. */
.category-group .category-group__title {
  margin: 0;
  padding: 0;
  border-bottom: 0;
  font-size: 1.08rem;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.category-group__from {
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--theme-ink-muted);
}

@media (min-width: 720px) {
  .category-group {
    grid-template-columns: 168px 1fr;
    align-items: start;
    column-gap: 1.15rem;
  }
  /* La portada ocupa las dos filas del bloque de texto (título y chips). */
  .section-cover {
    grid-row: span 2;
  }
  .category-group__title {
    align-self: center;
  }
}
.category-group__title {
  margin: 0 0 0.85rem;
  font-size: 1.02rem;
  font-weight: 700;
  color: var(--theme-ink, var(--theme-ink));
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--theme-border, var(--theme-border));
}
.category-chip__count {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--theme-ink-muted, #94a3b8);
  font-variant-numeric: tabular-nums;
}
.category-chip:hover .category-chip__count,
.category-chip:focus-visible .category-chip__count { color: inherit; }

/* -------------------------------------------------------------------------
   Rejilla de marcas (/marcas).

   Cada marca lleva su logo si lo tiene y, si no, un monograma con sus
   iniciales. El monograma es el caso NORMAL: de las 1.221 marcas del catálogo
   la mayoría son nombres de vendedor de Amazon que no tienen logotipo, así que
   una rejilla que sólo pintara logos saldría casi entera en blanco.

   El hueco de la marca es CUADRADO y de tamaño fijo para que la fila no baile
   según lo apaisado que sea cada logo, y el nombre se corta a dos líneas: hay
   marcas del marketplace con nombres de ocho palabras («Lito Angels Children's
   Apparel», «W WIDMANN MILANO Party Fashion») que estirarían la tarjeta hasta
   descuadrar la rejilla entera.
   ------------------------------------------------------------------------- */
.brand-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 0.75rem;
}

.brand-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  padding: 1rem 0.75rem 0.85rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  background: var(--theme-surface);
  color: var(--theme-ink);
  text-align: center;
  transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}

.brand-tile:hover,
.brand-tile:focus-visible {
  border-color: var(--theme-accent);
  box-shadow: var(--ui-shadow-md);
  transform: translateY(-2px);
}

.brand-tile__mark {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  border-radius: var(--ui-radius-md);
  background: var(--ui-accent-tint);
}

/**
 * El logo va sobre SUPERFICIE, no sobre el tinte: los logotipos se diseñan para
 * fondo blanco y varios de los que servimos llevan partes en blanco (Bandai,
 * Mattel, el cuadro de LEGO) que sobre un tinte claro desaparecerían.
 *
 * Y `color` fijado a propósito: el SVG de LEGO pinta su marca con
 * `fill="currentColor"`, así que sin esto heredaría el color del texto de la
 * tarjeta y saldría gris.
 */
.brand-tile__mark--logo {
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  color: var(--theme-accent);
}

.brand-tile__logo {
  max-width: 80%;
  max-height: 80%;
  object-fit: contain;
}

.brand-tile__initials {
  font-family: var(--theme-font-heading);
  font-size: 1.5rem;
  font-weight: 800;
  line-height: 1;
  color: var(--theme-accent);
}

.brand-tile__name {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-weight: 600;
  font-size: 0.9rem;
  line-height: 1.25;
}

.brand-tile__count {
  font-size: 0.78rem;
  color: var(--theme-ink-muted);
}

.category-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.6rem 0.5rem 0.95rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-pill);
  background: var(--theme-surface);
  color: var(--theme-ink);
  font-size: 0.9rem;
  font-weight: 500;
  line-height: 1.2;
  transition: border-color 0.15s ease, color 0.15s ease, background-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}

.category-chip:hover,
.category-chip:focus-visible {
  border-color: var(--theme-accent);
  color: var(--theme-accent);
  background: var(--theme-accent-soft);
  text-decoration: none;
  box-shadow: 0 3px 10px color-mix(in srgb, var(--theme-accent) 18%, transparent);
  transform: translateY(-1px);
}

/* Marcas de texto en /editoriales: primeras del listado y marcadas — son lo
   que se viene a buscar a ese hub. */
.category-chip--brand {
  border-color: color-mix(in srgb, var(--theme-accent) 45%, transparent);
  background: var(--theme-accent-soft);
  font-weight: 600;
}

/* Buscador de editoriales del hub (formulario GET, sin JS: CSP-safe). */
.hub-search {
  display: flex;
  gap: 0.5rem;
  max-width: 560px;
  margin: 0.25rem 0 1rem;
}

.hub-search__input {
  flex: 1;
  min-width: 0;
  padding: 0.6rem 1rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-pill);
  background: var(--theme-surface);
  color: var(--theme-ink);
  font: inherit;
  font-size: 0.95rem;
}
.hub-search__input:focus {
  outline: 2px solid color-mix(in srgb, var(--theme-accent) 55%, transparent);
  outline-offset: 1px;
  border-color: var(--theme-accent);
}

.hub-search__btn {
  padding: 0.6rem 1.25rem;
  border: none;
  border-radius: var(--ui-radius-cta, var(--ui-radius-pill));
  background: var(--theme-accent);
  color: #fff;
  font: inherit;
  font-size: 0.95rem;
  font-weight: 600;
  cursor: pointer;
  transition: filter 0.15s ease, transform 0.15s ease;
}
.hub-search__btn:hover { filter: brightness(1.08); transform: translateY(-1px); }

.hub-search__status {
  margin: -0.4rem 0 1rem;
  font-size: 0.92rem;
  color: var(--theme-ink-soft);
}

.category-chip__count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.6rem;
  height: 1.45rem;
  padding: 0 0.45rem;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent-soft);
  color: var(--theme-accent);
  font-size: 0.74rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.category-chip:hover .category-chip__count,
.category-chip:focus-visible .category-chip__count {
  background: var(--theme-accent);
  color: #fff;
}

/* ---- Barra del listado: recuento a la izquierda, orden a la derecha. ----
   Existe aquí y no en comparalibros porque allí las colecciones no se ordenan
   (una lista de curso trae su propio orden). En juguetes «de más barato a más
   caro» es lo primero que se busca en un listado. */
.collection-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem 1rem;
  margin: 0 0 1.1rem;
}
.collection-toolbar__count {
  margin: 0;
  color: var(--theme-ink-muted);
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
}
.collection-sort { display: flex; align-items: center; gap: 0.5rem; }
.collection-sort select {
  appearance: none;
  padding: 0.5rem 2.1rem 0.5rem 0.9rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-pill);
  background-color: var(--theme-surface);
  /* La flecha son dos gradientes y no un SVG: una petición menos, y sin fichero
     externo que se olvide de seguir al tema. */
  background-image:
    linear-gradient(45deg, transparent 50%, var(--theme-ink-muted) 50%),
    linear-gradient(135deg, var(--theme-ink-muted) 50%, transparent 50%);
  background-position: calc(100% - 1.05rem) 55%, calc(100% - 0.75rem) 55%;
  background-size: 0.32rem 0.32rem, 0.32rem 0.32rem;
  background-repeat: no-repeat;
  color: var(--theme-ink);
  font-size: 0.9rem;
  cursor: pointer;
}
.collection-sort select:hover { border-color: var(--theme-accent); }
.collection-sort__submit {
  padding: 0.5rem 0.9rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-pill);
  background: var(--theme-surface);
  cursor: pointer;
}

/* Subsecciones de una categoría (/categoria/ocio-y-deporte → Deportes, Juegos…).
   No tenían NI UNA regla propia: la nube de chips caía pegada a la barra de
   filtros y se leía como parte de ella. Son cosas distintas y conviene que se
   note —estas NAVEGAN a otra categoría, los filtros ACOTAN la página actual—,
   así que van en su propia caja, con rótulo y con aire por debajo. */
.collection-subcats {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  margin: 0.75rem 0 1.9rem;
  padding: 1.2rem 1.4rem 1.35rem;
  background: var(--theme-surface-alt);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
}

.collection-subcats__heading {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--theme-ink-soft);
}

/* El chip base lleva el padding derecho corto porque se diseñó con la burbuja
   del recuento pegada al borde. Aquí no hay recuento —decisión de Rafael el
   10-ago-2026—, así que se equilibra o los nombres quedan descentrados. */
.collection-subcats .category-chip {
  padding: 0.5rem 0.95rem;
  background: var(--theme-surface);
}

@media (max-width: 640px) {
  .collection-subcats {
    padding: 1rem 1rem 1.15rem;
    margin-bottom: 1.5rem;
  }
}

/* ------------------------------- Hubs ----------------------------------- */
/* Páginas índice de taxonomía (/cursos, /asignaturas, /editoriales). */

.hub {
  display: flex;
  flex-direction: column;
  gap: 1.75rem;
  padding: 0.5rem 0 2.5rem;
}

.hub__intro {
  /* A todo el ancho del contenedor. El tope de 68ch es la medida cómoda para
     leer PÁRRAFOS seguidos, y aquí es una entradilla de tres líneas sobre una
     página que debajo ya usa el ancho entero: la restricción sólo servía para
     dejar medio contenedor en blanco. El texto largo de más abajo
     (`.collection-seo-body`) conserva el suyo, que ahí sí hace falta. */
  color: var(--theme-ink-soft);
  font-size: 1.05rem;
  line-height: 1.6;
}

.hub__intro h1 {
  margin: 0 0 0.5rem;
  font-size: clamp(1.6rem, 3vw, 2.1rem);
  color: var(--theme-ink);
}

.hub__intro p { margin: 0; }

.hub__group {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
}

/* --------------------- Prosa SEO de colección/hub ----------------------- */
/* Bloque de texto largo (descripciones generadas) con ancho de lectura
   cómodo. Estiliza los hijos directos para no exigir clases por nodo. */

.collection-seo-body {
  max-width: none;
  color: var(--theme-ink-soft);
  line-height: 1.7;
  font-size: 1rem;
}

.collection-seo-body > * + * { margin-top: 0.9rem; }

.collection-seo-body h2 {
  margin: 1.6rem 0 0.6rem;
  font-size: clamp(1.2rem, 2.2vw, 1.5rem);
  color: var(--theme-ink);
}

.collection-seo-body h2:first-child { margin-top: 0; }

.collection-seo-body p { margin: 0; }

.collection-seo-body ul {
  margin: 0;
  padding-left: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.collection-seo-body li { padding-left: 0.15rem; }

.collection-seo-body a {
  color: var(--theme-accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.collection-seo-body a:hover { text-decoration: none; }

.features {
  padding: 1.5rem 0 2.5rem;
}

.features__title {
  font-size: clamp(1.4rem, 2.5vw, 1.75rem);
  margin: 0 0 1.25rem;
  text-align: center;
}

.features__grid {
  list-style: none;
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  margin: 0;
  padding: 0;
}

.features__item {
  position: relative;
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  padding: 1.25rem 1.25rem 1.4rem;
  box-shadow: var(--theme-shadow-sm);
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
.features__item:hover {
  transform: translateY(-2px);
  box-shadow: var(--theme-shadow);
  border-color: color-mix(in srgb, var(--theme-accent) 35%, var(--theme-border));
}

.features__item h3 {
  margin: 0;
  font-size: 1.08rem;
}

.features__item p {
  margin: 0;
  color: var(--theme-ink-soft);
  font-size: 0.95rem;
}

.features__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: var(--ui-radius-sm);
  background: var(--theme-accent-soft);
  color: var(--theme-accent);
  font-size: 1.15rem;
  margin-bottom: 0.25rem;
}

/* ------------------------------ How it works ---------------------------- */

/* Sin tarjeta (14-ago-2026). El fondo de la página y el de esta sección eran el
   MISMO blanco puro, así que el relleno no separaba nada y toda la caja la
   dibujaba un filete de 0,67 px: un recuadro que no encierra nada distinto es
   ruido, y con la banda de cifras justo debajo eran dos seguidos y la home
   parecía un formulario. Las secciones se separan por aire, como ya hacían la
   franja de librerías y las categorías. */
.how-it-works {
  /* Más aire abajo que arriba: sin el marco de la tarjeta, el botón «Ver cómo
     funciona en detalle» quedaba pegado a la banda de cifras y las dos
     secciones se leían como una. Los márgenes verticales contiguos colapsan al
     mayor, así que este 4,5rem es el hueco real entre ambas. */
  margin: 2.75rem 0 4.5rem;
  padding: 0;
}
.how-it-works h2 { margin: 0 0 1.25rem; font-size: 1.35rem; }
.how-it-works__steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  /* Más aire entre pasos: con 1,25rem y tres columnas de texto el bloque se
     leía como un párrafo partido en tres, no como tres pasos. */
  gap: 1.9rem 2.1rem;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.how-it-works__step {
  display: flex;
  gap: 1rem;
  align-items: flex-start;
}
/* Disco con el icono del paso; el número queda de chapa encima, encadenando el
   orden sin robarle el sitio al icono. */
.how-it-works__badge {
  position: relative;
  flex: 0 0 3rem;
  height: 3rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent-soft);
  color: var(--theme-accent);
}
.how-it-works__icon { width: 1.55rem; height: 1.55rem; }
/* Chapa del número, AL LADO DEL TÍTULO. Estuvo `position: absolute` mientras
   vivía encima del disco del icono; al mudarse dentro del <h3> se quedó
   colgando del contenedor de posicionamiento más cercano y los tres números se
   fueron al pie de la página, invisibles. Aquí va estática, como un hijo más
   del flex del título. */
.how-it-works__num {
  flex: none;
  width: 1.35rem;
  height: 1.35rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent);
  color: var(--theme-surface);
  font-family: var(--theme-font-heading);
  font-weight: 700;
  font-size: 0.72rem;
  line-height: 1;
}
.how-it-works__step h3 {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 0.3rem;
  font-size: 1rem;
}
.how-it-works__step p { margin: 0; color: var(--theme-ink-soft); font-size: 0.92rem; line-height: 1.55; }

/* --- Ilustración del paso: sólo de 720 px para arriba. En un móvil de 390 px
   subía el bloque de 664 a 927 px de alto (+40%) y empujaba el resto de la home
   justo donde el scroll pesa; ahí se queda el disco con el icono. --- */
.how-it-works .step-art { display: none; }
@media (min-width: 720px) {
  .how-it-works__step { flex-direction: column; align-items: flex-start; gap: 0.55rem; }
  .how-it-works .step-art { display: block; width: 128px; height: 96px; }
  .how-it-works__badge { display: none; }
}
/* Paleta de las ilustraciones por clases y no a fuego en el SVG: así siguen al
   preset del tema. Cada una declara primero el hex de reserva por si el
   navegador no soporta `color-mix`. */
.step-art { color: var(--theme-accent); }
.step-art .art-fill { fill: currentColor; }
.step-art .art-white { fill: #fff; }
.step-art .art-deep {
  fill: var(--ui-accent-strong);
  fill: color-mix(in srgb, currentColor 72%, #000);
}
.step-art .art-tint {
  fill: #fbd9cf;
  fill: color-mix(in srgb, currentColor 22%, #fff);
}
.step-art .art-tint2 {
  fill: color-mix(in srgb, var(--theme-accent) 38%, #fff);
  fill: color-mix(in srgb, currentColor 45%, #fff);
}
.step-art .art-on-fill { fill: rgba(255, 255, 255, 0.42); }
.step-art .art-paper {
  fill: #fff;
  stroke: var(--ui-accent-strong);
  stroke: color-mix(in srgb, currentColor 72%, #000);
  stroke-width: 2.5;
}
.step-art .art-ghost {
  fill: #fff;
  stroke: color-mix(in srgb, var(--theme-accent) 38%, #fff);
  stroke: color-mix(in srgb, currentColor 45%, #fff);
  stroke-width: 2.6;
}
.step-art .art-handle {
  fill: none;
  stroke: var(--ui-accent-strong);
  stroke: color-mix(in srgb, currentColor 72%, #000);
  stroke-width: 3.2;
  stroke-linecap: round;
}
.step-art .art-spine {
  stroke: color-mix(in srgb, var(--theme-accent) 38%, #fff);
  stroke: color-mix(in srgb, currentColor 45%, #fff);
  stroke-width: 2.2;
}
.step-art .art-tint-line {
  stroke: #fbd9cf;
  stroke: color-mix(in srgb, currentColor 22%, #fff);
  stroke-width: 2.2;
  stroke-linecap: round;
}
.step-art .art-ok {
  fill: var(--theme-success, var(--theme-success));
  stroke: #fff;
  stroke-width: 3;
}
.step-art .art-coin { fill: #F2A93B; stroke: #fff; stroke-width: 3; }
/* Puntero del paso «eliges tú»: relleno oscuro y filo blanco para que se
   recorte sobre la etiqueta azul que está señalando. */
.step-art .art-cursor {
  fill: var(--ui-accent-strong);
  fill: color-mix(in srgb, currentColor 72%, #000);
  stroke: #fff;
  stroke-width: 2.2;
  stroke-linejoin: round;
}
.step-art .art-deep-line {
  fill: none;
  stroke: var(--ui-accent-strong);
  stroke: color-mix(in srgb, currentColor 72%, #000);
}
.step-art .art-white-line {
  fill: none;
  stroke: #fff;
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ----------------------------- Book detail ------------------------------ */

.book-detail__header {
  display: grid;
  gap: 1.75rem;
  grid-template-columns: 1fr;
  margin-bottom: 1.5rem;
  padding: 1.5rem;
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  box-shadow: var(--theme-shadow-sm);
}
@media (min-width: 720px) {
  .book-detail__header {
    grid-template-columns: 320px 1fr;
    padding: 2rem;
  }
}
/* En pantalla ancha la foto se lleva sitio de verdad: es lo que vende, y de
   esta columna salen ADEMÁS los ~78 px de la tira de miniaturas cuando hay
   galería. Con los 300 px de antes la foto se quedaba en unos 195 y el
   `max-width` de 420 no llegaba a tocarse nunca. No se sube en el tramo de
   720-1023 px porque ahí el título se quedaría sin ancho. */
@media (min-width: 1024px) {
  .book-detail__header {
    grid-template-columns: 460px 1fr;
  }
}

.book-detail__cover {
  position: relative;
  min-width: 0;
}
/* min-width:0 deja que las columnas del grid encojan: sin esto, la fila de
   chips (que no envuelve) ensancha la columna y desborda la ficha en móvil,
   empujando la portada fuera del viewport. */
.book-detail__meta {
  min-width: 0;
}
/* HIJO DIRECTO a propósito: esta regla describe la portada SUELTA, la del
   producto con una sola foto. Sin el `>` alcanzaba también a las fotos y a las
   miniaturas de la galería, y su `display: block` —con especificidad (0,1,1),
   por encima del (0,1,0) de `.gallery__photo`— pisaba el `display: none` que
   oculta las no seleccionadas: la ficha enseñaba las siete a la vez, una
   debajo de otra. En el HTML no se veía nada raro. */
/* Aquí había una regla `.book-detail__cover > img` que duplicaba
   `.gallery__photo`. Se quitó el 19-ago-2026 al pasar TODAS las fichas con
   foto por el partial de la galería: dejó de casar con nada, y una copia
   muerta de un estilo vivo sólo sirve para que las dos se separen. La foto la
   dibuja ahora `.gallery__photo` en los dos casos, con una y con siete. */

/* Aquí había un marco de puntos alrededor de la portada. Se quitó el
   19-ago-2026: existía para despegar la foto del beige del fondo, y eso ya lo
   hace el borde de la propia foto desde que la caja es blanca. Con los dos
   puestos se veían DOS bordes concéntricos. */

/* ------------------------------------------------------------------ *
 * Galería de fotos (sólo Amazon publica más de una)
 *
 * Todo en CSS: la CSP es `script-src 'self'` y no hay JS que valga. El radio
 * marcado enseña su foto y resalta su miniatura, y eso obliga a EMPAREJAR
 * índice a índice — CSS no sabe decir «la enésima marcada». Hay OCHO pares
 * porque `_gallery.ejs` corta en ocho (lo medido en Keepa son 4-7). Si algún
 * día se sube ese corte, hay que añadir aquí los pares o las fotos de más
 * quedarán en la página sin poder seleccionarse jamás, y sin dar ningún error.
 * ------------------------------------------------------------------ */
.gallery {
  display: grid;
  gap: 0.65rem;
  min-width: 0;
  /* Alto de una miniatura y del hueco entre dos, en un sitio: de aquí sale el
     tope de la tira, y si se tocan por separado deja de cortar por una foto
     entera y se ve media asomando. */
  --thumb: 60px;
  --thumb-gap: 0.5rem;
  --thumb-box: calc(var(--thumb) + 8px);
  --thumbs-visible: 5;
  /* Ancho máximo de la foto. Vive AQUÍ y no en `.gallery__photo` porque quien
     tiene que medir eso es el escenario: la lupa se posiciona contra él, y si
     el escenario es más ancho que la imagen el botón se planta fuera (medido:
     escenario 460, foto 420, lupa 30 px por fuera del borde). */
  --photo-max: 420px;
}
/* Una sola foto: sin tira, y por tanto sin rejilla de dos columnas — que en
   escritorio dejaría la foto en la columna `auto`, la estrecha. Va después de
   `.gallery` a propósito: misma especificidad, gana el último. */
.gallery--unica { display: block; }
/* Visualmente oculto pero AÚN ENFOCABLE: con `display:none` el teclado no
   podría cambiar de foto. */
.gallery__radio {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
/* Móvil: foto arriba, miniaturas debajo en una tira que se desplaza. */
/* El escenario mide EXACTAMENTE lo que la foto: es el ancla de la lupa. */
.gallery__stage {
  order: 1;
  min-width: 0;
  width: 100%;
  max-width: var(--photo-max);
}
/* Carril: las flechas y la tira. En móvil va en fila (flechas a los lados) y
   en escritorio en columna (flechas arriba y abajo); lo cambia la media query
   de abajo girando también los chevrones. */
.gallery__rail {
  order: 2;
  display: flex;
  align-items: center;
  gap: 0.35rem;
  min-width: 0;
}
.gallery__thumbs {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  gap: var(--thumb-gap);
  overflow-x: auto;
  /* Barra oculta: esto se maneja con flechas, y una barra a medio camino entre
     «slider» y «scroll» es lo peor de las dos. Se sigue pudiendo arrastrar con
     el dedo y girar la rueda, que es el respaldo si el JS no llega. */
  scrollbar-width: none;
  /* `proximity` y no `mandatory`: el salto de las flechas ya redondea a
     miniatura entera en el JS, y un snap obligatorio peleaba con él. Esto
     sigue ayudando al dedo y a la rueda sin secuestrar nada. */
  scroll-snap-type: x proximity;
}
.gallery__thumbs::-webkit-scrollbar { display: none; }
.gallery__thumbs li { flex: none; scroll-snap-align: start; }
.gallery__rail-btn {
  display: grid;
  place-items: center;
  flex: none;
  width: 26px;
  height: 26px;
  padding: 0;
  cursor: pointer;
  color: var(--theme-ink-soft);
  background: var(--ui-photo-bg);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-pill);
}
.gallery__rail-btn:hover:not(:disabled) { color: var(--theme-primary); border-color: var(--theme-primary); }
/* Al final del carril el botón se queda, pero apagado: si desapareciera, la
   tira daría un salto de 26 px cada vez que se llega a un extremo. */
.gallery__rail-btn:disabled { opacity: 0.35; cursor: default; }
.gallery__thumbs label {
  display: block;
  cursor: pointer;
  border: 2px solid var(--theme-border);
  border-radius: var(--ui-radius-sm);
  padding: 2px;
  /* Blanco como la foto grande: las miniaturas son la MISMA imagen, y con un
     fondo distinto se ven como recortes pegados sobre otro color. */
  background: var(--ui-photo-bg);
  transition: border-color 0.15s ease;
}
.gallery__thumbs img {
  display: block;
  width: var(--thumb);
  height: var(--thumb);
  object-fit: contain;
  border-radius: calc(var(--ui-radius-sm) - 2px);
}
.gallery__thumbs label:hover { border-color: var(--theme-border); }
.gallery__photo {
  display: none;
  /* Llena el escenario, que es quien lleva el tope: así los dos miden lo mismo
     a cualquier ancho y la lupa cae siempre dentro. */
  width: 100%;
  height: auto;
  /* CUADRADA, no 2/3. El vertical venía de comparalibros, donde la portada de
     un libro ES vertical; una foto de juguete es apaisada o cuadrada y en una
     caja 2/3 quedaba pequeña y rodeada de hueco muerto. */
  aspect-ratio: 1 / 1;
  object-fit: contain;
  /* Aire entre el borde y la foto: pegada al filo parecía recortada. Con
     `box-sizing: border-box` el padding encoge la imagen y NO mueve el borde,
     así que la caja sigue midiendo lo mismo y el hueco reservado contra el CLS
     no cambia. */
  padding: 14px;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-sm);
  background: var(--ui-photo-bg);
}
/* Los ocho pares: radio marcado -> su foto. */
.gallery__radio:nth-of-type(1):checked ~ .gallery__stage .gallery__photo:nth-child(1),
.gallery__radio:nth-of-type(2):checked ~ .gallery__stage .gallery__photo:nth-child(2),
.gallery__radio:nth-of-type(3):checked ~ .gallery__stage .gallery__photo:nth-child(3),
.gallery__radio:nth-of-type(4):checked ~ .gallery__stage .gallery__photo:nth-child(4),
.gallery__radio:nth-of-type(5):checked ~ .gallery__stage .gallery__photo:nth-child(5),
.gallery__radio:nth-of-type(6):checked ~ .gallery__stage .gallery__photo:nth-child(6),
.gallery__radio:nth-of-type(7):checked ~ .gallery__stage .gallery__photo:nth-child(7),
.gallery__radio:nth-of-type(8):checked ~ .gallery__stage .gallery__photo:nth-child(8) {
  display: block;
}
/* Y los mismos ocho: radio marcado -> su miniatura resaltada. */
.gallery__radio:nth-of-type(1):checked ~ .gallery__rail li:nth-child(1) label,
.gallery__radio:nth-of-type(2):checked ~ .gallery__rail li:nth-child(2) label,
.gallery__radio:nth-of-type(3):checked ~ .gallery__rail li:nth-child(3) label,
.gallery__radio:nth-of-type(4):checked ~ .gallery__rail li:nth-child(4) label,
.gallery__radio:nth-of-type(5):checked ~ .gallery__rail li:nth-child(5) label,
.gallery__radio:nth-of-type(6):checked ~ .gallery__rail li:nth-child(6) label,
.gallery__radio:nth-of-type(7):checked ~ .gallery__rail li:nth-child(7) label,
.gallery__radio:nth-of-type(8):checked ~ .gallery__rail li:nth-child(8) label {
  border-color: var(--theme-primary);
}
/* El foco del teclado se ve en la miniatura, que es lo que el radio representa
   (el propio radio está oculto y su outline no se vería en ninguna parte). */
.gallery__radio:nth-of-type(1):focus-visible ~ .gallery__rail li:nth-child(1) label,
.gallery__radio:nth-of-type(2):focus-visible ~ .gallery__rail li:nth-child(2) label,
.gallery__radio:nth-of-type(3):focus-visible ~ .gallery__rail li:nth-child(3) label,
.gallery__radio:nth-of-type(4):focus-visible ~ .gallery__rail li:nth-child(4) label,
.gallery__radio:nth-of-type(5):focus-visible ~ .gallery__rail li:nth-child(5) label,
.gallery__radio:nth-of-type(6):focus-visible ~ .gallery__rail li:nth-child(6) label,
.gallery__radio:nth-of-type(7):focus-visible ~ .gallery__rail li:nth-child(7) label,
.gallery__radio:nth-of-type(8):focus-visible ~ .gallery__rail li:nth-child(8) label {
  outline: 2px solid var(--theme-primary);
  outline-offset: 2px;
}
/* ---- Ampliación (lightbox) ---------------------------------------- *
 * La galería funciona sin JS; esto es lo único que lo necesita, así que la
 * lupa nace `hidden` y la destapa el script. Ver `js/lightbox.js`.           */
.gallery__stage { position: relative; }
.gallery__photo { cursor: zoom-in; }
.gallery__zoom {
  position: absolute;
  right: 10px;
  bottom: 10px;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  padding: 0;
  cursor: zoom-in;
  color: var(--theme-ink);
  background: var(--ui-photo-bg);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-pill);
  box-shadow: var(--ui-shadow-sm);
}
.gallery__zoom:hover { color: var(--theme-primary); border-color: var(--theme-primary); }

.lightbox {
  /* El diálogo ocupa la ventana ENTERA: así un clic cuyo destino es el propio
     diálogo significa «has pulsado fuera de la foto», que es como cierra el JS
     sin tener que dibujar una capa aparte para el fondo.

     `inset: 0` y no `100vw/100dvh`: `100vw` INCLUYE el ancho de la barra de
     scroll, así que en cuanto la página tiene barra el diálogo se pasa de
     ancho, descentra la foto y puede asomar scroll horizontal. Con `inset` el
     diálogo cubre el viewport exacto sin depender de ese cálculo. */
  position: fixed;
  inset: 0;
  width: auto;
  max-width: none;
  height: auto;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: hidden;
  place-items: center;
}
.lightbox[open] { display: grid; }
.lightbox::backdrop { background: rgba(17, 17, 22, 0.82); }
.lightbox__img {
  max-width: 92vw;
  max-height: 86dvh;
  object-fit: contain;
  background: var(--ui-photo-bg);
  border-radius: var(--ui-radius-sm);
}
.lightbox__close,
.lightbox__nav {
  position: absolute;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  color: var(--theme-ink);
  background: var(--ui-photo-bg);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-pill);
}
.lightbox__close { top: 14px; right: 14px; }
.lightbox__nav--prev { left: 14px; top: 50%; transform: translateY(-50%); }
.lightbox__nav--next { right: 14px; top: 50%; transform: translateY(-50%); }
.lightbox__close:hover,
.lightbox__nav:hover { color: var(--theme-primary); border-color: var(--theme-primary); }
.lightbox__count {
  position: absolute;
  bottom: 16px;
  margin: 0;
  padding: 0.25rem 0.7rem;
  font-size: 0.82rem;
  color: var(--theme-ink);
  background: var(--ui-photo-bg);
  border-radius: var(--ui-radius-pill);
}

/* Escritorio: miniaturas a la izquierda, como en una tienda. */
@media (min-width: 640px) {
  .gallery {
    grid-template-columns: auto minmax(0, 1fr);
    align-items: start;
  }
  .gallery__rail {
    order: 0;
    flex-direction: column;
  }
  /* Los chevrones apuntan a izquierda y derecha en el marcado; en columna el
     carril pasa a vertical y girarlos 90º los deja mirando arriba y abajo. Un
     solo icono para las dos disposiciones. */
  .gallery__rail-btn svg { transform: rotate(90deg); }
  .gallery__thumbs {
    flex-direction: column;
    /* CINCO y a partir de ahí se pasa con las flechas. Con ocho fotos la tira
       crecía más que la foto y estiraba la tarjeta entera hacia abajo. El tope
       se calcula con los mismos tokens que dibujan la miniatura, así que corta
       siempre por una foto entera y nunca deja media asomando. */
    max-height: calc(
      var(--thumb-box) * var(--thumbs-visible) +
      var(--thumb-gap) * (var(--thumbs-visible) - 1)
    );
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
    scroll-snap-type: y proximity;
  }
}
.book-detail__cover-fallback {
  display: flex;
  align-items: center;
  justify-content: center;
  /* Misma caja que la foto real: si no, una ficha sin imagen cambia de alto
     respecto a las demás y el listado de al lado baila. */
  aspect-ratio: 1 / 1;
  width: 100%;
  max-width: 420px;
  font-size: 3.5rem;
  background: var(--theme-surface-alt);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-sm);
  color: var(--theme-ink-muted);
}

.book-detail__title {
  font-size: clamp(1.55rem, 3.2vw, 2.15rem);
  margin: 0 0 0.3rem;
  line-height: 1.15;
  letter-spacing: -0.02em;
}

/* ISBN destacado bajo el título: es el dato con el que se identifica el libro
   (las listas del colegio vienen en ISBN). Antes era un chip apagado al final de
   una fila con scroll horizontal. `user-select: all` para poder copiarlo de un
   clic sin necesitar JS, que la CSP no permitiría inline. */
.book-detail__isbn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 0.7rem;
  padding: 0.3rem 0.7rem 0.3rem 0.55rem;
  background: var(--theme-surface-alt);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-pill);
}
.book-detail__isbn-label {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--theme-accent);
}
.book-detail__isbn-value {
  font-family: var(--theme-font-mono);
  font-size: 1.02rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--theme-ink);
  user-select: all;
}

.book-detail__subtitle {
  color: var(--theme-ink-soft);
  margin: 0 0 0.75rem;
  font-size: 1.05rem;
}

/* Precio ganador en el hero (auditoría UX 11-ago-2026): el dato nº 1 de quien
   llega de un anuncio, visible sin scroll también en móvil, donde el rail de
   compra queda por debajo del primer viewport. Enlaza a la comparativa. */
/* Caja del mejor precio, pegada al título. Sustituye a la línea «Desde X»:
   decía el precio pero no llevaba a ninguna parte, y el botón más cercano
   estaba en el rail lateral (escritorio) o en la barra fija (móvil). Aquí el
   dato y la acción van juntos, que es lo que pidió Rafael viendo Kelkoo. */
.best-deal {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.6rem 1rem;
  margin: 0.4rem 0 0.5rem;
  padding: 0.7rem 0.9rem;
  background: var(--theme-surface-alt);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-md);
}
.best-deal__info { min-width: 0; }
.best-deal__label {
  margin: 0;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--theme-ink-muted);
}
.best-deal__price {
  margin: 0.1rem 0 0;
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.4rem;
}
.best-deal__price strong {
  font-size: 1.75rem;
  font-weight: 800;
  line-height: 1.1;
  color: var(--theme-accent);
}
.best-deal__where { font-size: 0.95rem; color: var(--theme-ink-soft); }
.best-deal__shipping {
  margin: 0.1rem 0 0;
  font-size: 0.85rem;
  color: var(--theme-ink-muted);
}
.best-deal__shipping.is-free { color: var(--theme-success, var(--theme-ink-soft)); }
.best-deal__cta {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.65rem 1.1rem;
  font-weight: 700;
  text-decoration: none;
  /* Blanco literal, como en el resto de botones sólidos del sitio: el fondo es
     el acento y no hay token de «texto sobre acento» del que tirar. */
  color: #fff;
  background: var(--theme-accent);
  border-radius: var(--ui-radius-cta);
}
.best-deal__cta:hover { filter: brightness(0.94); }
/* El «Compara las N tiendas» tiene que LEERSE como enlace (feedback de Rafael,
   11-ago-2026): color de acento y subrayado siempre, no solo en hover. */
.best-deal__compare { margin: 0 0 0.7rem; }
.best-deal__compare a {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--theme-accent);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.best-deal__compare a:hover { text-decoration-thickness: 2px; }

.book-detail__authors {
  margin: 0 0 0.5rem;
  color: var(--theme-ink-soft);
  font-size: 0.98rem;
}

.book-detail__publisher {
  margin: 0 0 1rem;
  font-size: 0.92rem;
}
.book-detail__publisher a {
  color: var(--theme-ink-soft);
  font-weight: 600;
  border-bottom: 1px solid transparent;
}
.book-detail__publisher a:hover { color: var(--theme-accent); border-bottom-color: currentColor; text-decoration: none; }

/* -------------------------------------------------------------------------
   Tira de otras versiones, en la cabecera de la ficha.

   Piezas pequeñas y en una sola fila desplazable: lo que distingue una versión
   de otra es su ETIQUETA («Rojo – Lancia 1:64») y su precio, no el título, que
   en una familia de ocho es el mismo nombre kilométrico repetido ocho veces.
   ------------------------------------------------------------------------- */
.variant-strip { margin: 0 0 1.1rem; }
.variant-strip__title {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0 0 0.5rem;
  font-size: 0.82rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--theme-ink-muted);
}
.variant-strip__n {
  padding: 0.05rem 0.4rem;
  border-radius: var(--ui-radius-pill);
  background: var(--ui-accent-tint);
  color: var(--theme-accent);
  font-size: 0.78rem;
  letter-spacing: 0;
}
.variant-strip__list {
  list-style: none;
  display: flex;
  gap: 0.5rem;
  margin: 0;
  padding: 0 0 0.3rem;
  overflow-x: auto;
  scrollbar-width: thin;
}
.variant-strip__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
  width: 92px;
  padding: 0.4rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-md);
  background: var(--theme-surface);
  color: var(--theme-ink);
  text-align: center;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.variant-strip__item:hover,
.variant-strip__item:focus-visible {
  border-color: var(--theme-accent);
  box-shadow: var(--ui-shadow-sm);
  text-decoration: none;
}
.variant-strip__thumb {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  aspect-ratio: 1;
  border-radius: var(--ui-radius-sm);
  background: var(--theme-surface-alt);
  overflow: hidden;
}
.variant-strip__thumb img { max-width: 100%; max-height: 100%; object-fit: contain; }
.variant-strip__tag {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: 0.72rem;
  line-height: 1.2;
  color: var(--theme-ink-soft);
}
.variant-strip__price {
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--theme-accent);
}

.book-chips {
  list-style: none;
  display: flex;
  flex-wrap: nowrap;
  gap: 0.4rem;
  margin: 0 0 1.25rem;
  padding: 0 0 0.15rem;
  overflow-x: auto;
  scrollbar-width: none;
}
.book-chips::-webkit-scrollbar { display: none; }
.book-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.28rem 0.65rem;
  background: var(--theme-surface-alt);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-pill);
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--theme-ink-soft);
  white-space: nowrap;
}
.book-chip--isbn {
  font-family: var(--theme-font-mono);
  font-weight: 500;
  color: var(--theme-ink-muted);
}

/* --------------------------------- Offers ------------------------------- */

.offers {
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  padding: 1.5rem;
  margin-bottom: 1.5rem;
  box-shadow: var(--theme-shadow-sm);
}

.offers__title {
  margin: 0 0 1.1rem;
  font-size: 1.25rem;
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
}
.offers__title::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--theme-border);
  margin-left: 0.4rem;
}

.offers__empty {
  color: var(--theme-ink-soft);
  margin: 0;
  padding: 1.5rem;
  background: var(--theme-bg);
  border-radius: var(--ui-radius-sm);
  border: 1px dashed var(--theme-border);
  text-align: center;
}

/* Aviso de ahorro.
   Primera version: recuadro verde con emoji de saco de dinero y la cifra
   enterrada en una frase. Leia a publicidad.
   Segunda: la cifra suelta sobre una barra lateral, sin fondo. Peor: «3,60 EUR»
   flotando bajo el titulo se lee como si fuera un precio hasta que llegas a la
   linea de abajo, o sea que el dato no se entendia solo.
   Esta: el fondo vuelve —agrupa las tres piezas y las separa de la tabla— y la
   etiqueta va ARRIBA, para que se sepa que es el numero antes de leerlo. */
.offers__savings {
  margin: 0 0 1.1rem;
  padding: 0.7rem 0.95rem;
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas:
    "tag  tag"
    "cifra texto";
  align-items: baseline;
  column-gap: 0.6rem;
  row-gap: 0.15rem;
  background: color-mix(in srgb, var(--theme-success) 8%, #fff);
  border: 1px solid color-mix(in srgb, var(--theme-success) 22%, transparent);
  border-left: 3px solid var(--theme-success);
  border-radius: var(--ui-radius-sm);
}
.offers__savings-tag {
  grid-area: tag;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--theme-success) 70%, #000 30%);
}
.offers__savings-figure {
  grid-area: cifra;
  font-size: 1.5rem;
  font-weight: 800;
  line-height: 1.1;
  color: color-mix(in srgb, var(--theme-success) 78%, #000 22%);
  font-variant-numeric: tabular-nums;
}
.offers__savings-label {
  grid-area: texto;
  font-size: 0.85rem;
  color: var(--theme-muted, var(--theme-ink-soft));
}
/* En pantallas estrechas la explicacion no cabe al lado de la cifra sin partirse
   en tres lineas raquiticas: pasa debajo. */
@media (max-width: 520px) {
  .offers__savings {
    grid-template-columns: 1fr;
    grid-template-areas: "tag" "cifra" "texto";
  }
}

.offers__list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

.offer {
  display: grid;
  gap: 0.5rem 1rem;
  grid-template-columns: 1fr;
  padding: 1.4rem 1.6rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-sm);
  background: var(--theme-bg);
  align-items: center;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
  /* Toda la tarjeta lleva a la tienda: la navegación la delega row-link.js al
     botón real (el stretched-link con ::after bloqueaba seleccionar texto y
     dejaba zonas muertas según el apilamiento del tema). El cursor avisa. */
  cursor: pointer;
}
.offer:hover {
  border-color: color-mix(in srgb, var(--theme-accent) 35%, var(--theme-border));
  box-shadow: var(--ui-shadow-sm);
}

@media (min-width: 640px) {
  .offer {
    /* La ultima columna es la del boton de compra. Se ensancha de 16,5 a 21 rem
       porque es el elemento que genera el ingreso y porque a 16,5 los nombres
       largos ("Comprar en El Corte Ingles") partian en dos lineas, que es
       justo lo que hace que un CTA se lea como apretado. */
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.9fr) minmax(0, 0.95fr) 21rem;
    align-items: center;
  }
}
/* Móvil (<640px): compacta cada oferta — librería arriba a todo el ancho,
   precio y total en dos columnas, y el botón de comprar a todo el ancho. Y
   centramos la portada, que en una sola columna quedaba descolgada. */
@media (max-width: 639px) {
  /* Precio a la izquierda y TOTAL alineado al borde derecho, centrados entre
   * sí en vertical: el layout 1fr/1fr con align start dejaba el precio
   * flotando arriba y el total descolgado hacia el centro (12-ago-2026). */
  .offer { grid-template-columns: 1fr auto; align-items: center; }
  .offer__merchant { grid-column: 1 / -1; }
  .offer__totals { justify-self: end; align-items: flex-end; text-align: right; }
  .offer__cta { grid-column: 1 / -1; }
  .offer__button { display: flex; justify-content: center; }
  .book-detail__cover { display: flex; justify-content: center; }
}

.offer--best {
  /* Realce sobrio, no un contorno de color. Antes llevaba borde de acento +
     fondo + un anillo de 3px, y el tema `planeta` anadia OTRO anillo encima: dos
     halos azules sobre fondo azul, que es lo que hacia que la fila ganadora
     pareciera un aviso de error en vez de una recomendacion.
     Ahora: filete de acento en el borde izquierdo —que marca la fila sin rodear
     nada—, un tinte de fondo muy leve y una sombra suave que la levanta del
     resto. El resto del borde se queda neutro como en las demas filas. */
  border-color: var(--theme-border);
  border-left: 3px solid var(--theme-accent);
  background: color-mix(in srgb, var(--theme-accent-soft) 55%, var(--theme-surface));
  box-shadow: 0 2px 10px color-mix(in srgb, var(--theme-accent) 10%, transparent);
}

.offer__merchant {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  flex-wrap: wrap;
}

.offer__swatch {
  width: 0.85rem;
  height: 0.85rem;
  border-radius: var(--ui-radius-sm);
  display: inline-block;
  border: 1px solid color-mix(in srgb, currentColor 15%, transparent);
}
.offer__logo {
  width: 1.5rem;
  height: 1.5rem;
  object-fit: contain;
  border-radius: var(--ui-radius-sm);
  flex: none;
}

.offer__merchant-name {
  font-weight: 600;
  font-size: 0.98rem;
}

.offer__badge {
  background: var(--theme-accent);
  color: var(--theme-surface);
  border-radius: var(--ui-radius-pill);
  padding: 0.15rem 0.7rem;
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.offer__pricing {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

/* TODOS los precios de la ficha en la MISMA fuente (Plus Jakarta Sans, la del
   carril lateral — pedido de Rafael, 18-ago-2026): precio, tachado, delta y
   total iban en Baloo y parecían de otro sitio. Ninguna de estas reglas
   declara font-family a propósito: heredan la del cuerpo, y la jerarquía la
   dan tamaño, peso y color. */
.offer__price {
  font-size: 1.05rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

.offer__price-original {
  text-decoration: line-through;
  color: var(--theme-ink-muted);
  font-size: 0.85rem;
}

.offer__shipping {
  font-size: 0.82rem;
  color: var(--theme-ink-muted);
}

.offer__totals {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.offer__total-label {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--theme-ink-muted);
}

.offer__total {
  font-size: 1.3rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--theme-ink);
  letter-spacing: -0.02em;
}

.offer__delta {
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--theme-danger);
}
.offer__delivery {
  font-size: 0.78rem;
  color: var(--theme-ink-muted);
}

.offer__cta {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.4rem;
}

.offer__button {
  display: flex;
  width: 100%;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  /* Altura mínima generosa + padding vertical pequeño: así el `min-height`
     domina y TODOS los botones miden lo mismo, tanto si el nombre cabe en una
     línea como si se ajusta a dos ("Casa del Libro"). */
  padding: 0.7rem 1.1rem;
  min-height: 3.9rem;
  /* El color de marca del comercio llega por `style` inline (merchantColorHex);
     este `background` es el respaldo si el comercio no tiene color. */
  background: var(--theme-accent);
  color: #fff;
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.22);
  border-radius: var(--ui-radius-cta);
  font-weight: 700;
  text-align: center;
  /* Sin `nowrap`: si el nombre del comercio es largo ("Casa del Libro") el
     texto se ajusta a dos líneas en vez de desbordar el botón/columna. */
  line-height: 1.2;
  /* Sube de 0,94 a 1,02 rem: es el unico texto de la fila que tiene que ganar
     al precio en jerarquia visual. Con la columna a 21 rem el nombre mas largo
     entra en una linea, asi que el ajuste a dos queda solo de red de seguridad. */
  font-size: 1.02rem;
  letter-spacing: -0.01em;
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.14);
  transition: transform 0.12s ease, filter 0.12s ease, box-shadow 0.12s ease;
}
.offer__button-logo {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  border-radius: 50%;
  background: #fff;
  padding: 2px;
  object-fit: contain;
}
.offer__button:hover, .offer__button:focus {
  filter: brightness(0.95);
  color: #fff;
  text-decoration: none;
  transform: translateY(-1px);
  box-shadow: 0 5px 14px rgba(0, 0, 0, 0.2);
}

.offer__condition {
  font-size: 0.72rem;
  color: var(--theme-ink-muted);
  text-align: center;
}

.offers__disclaimer {
  margin: 1.1rem 0 0;
  color: var(--theme-ink-muted);
  font-size: 0.82rem;
}

/* ---------------------------- Book description -------------------------- */

.book-description {
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  padding: 1.5rem;
  margin-bottom: 1.5rem;
  box-shadow: var(--theme-shadow-sm);
}
.book-description h2 { margin: 0 0 0.75rem; font-size: 1.2rem; }
.book-description p { margin: 0 0 0.85rem; color: var(--theme-ink-soft); }
.book-description p:last-child { margin-bottom: 0; }

/* Viñetas del vendedor recuperadas del churro (splitDescription). El punto en
   el color del tema separa sin convertir la ficha en un folleto. */
.book-description__list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.book-description__list li {
  position: relative;
  padding-left: 1.1rem;
  color: var(--theme-ink-soft);
  line-height: 1.6;
}
.book-description__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.58em;
  width: 6px;
  height: 6px;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent);
}
.book-description__list strong { color: var(--theme-ink); font-weight: 700; }

/* --------------------- Historial de precios (ficha) ---------------------- */
/* SVG generado en servidor; los colores de serie los pone cada tienda
   (merchants.color_hex), el resto sale de los tokens. */

.price-history {
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  padding: 1.5rem;
  margin-bottom: 1.5rem;
  box-shadow: var(--theme-shadow-sm);
}
.price-history h2 { margin: 0 0 0.35rem; font-size: 1.2rem; }
.price-history__since { margin: 0 0 1rem; font-size: 0.85rem; color: var(--theme-ink-muted); }
.price-history__legend {
  list-style: none;
  margin: 0 0 0.75rem;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.1rem;
  font-size: 0.85rem;
  color: var(--theme-ink-soft);
}
.price-history__legend li { display: flex; align-items: center; gap: 0.45rem; }
/* Muestra de LÍNEA, no punto: tiene que poder enseñar el punteado con el que
   se separan las tiendas que coinciden en precio. */
.price-history__swatch { width: 22px; height: 8px; flex: none; }
.price-history__chart { width: 100%; height: auto; display: block; }
.price-history__grid { stroke: var(--theme-border); stroke-width: 1; }
.price-history__tick { font-size: 11px; fill: var(--theme-ink-muted); }
.price-history__tick--y { text-anchor: end; }
.price-history__tick--x { text-anchor: middle; }
.price-history__tick--x.is-first { text-anchor: start; }
.price-history__tick--x.is-last { text-anchor: end; }
.price-history__last { font-size: 12px; font-weight: 800; }
/* Precio que comparten varias tiendas: sin color de tienda, que sugeriría que
   sólo lo tiene una. */
.price-history__last--shared { fill: var(--theme-ink); }
.price-history__stats {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 2rem;
  margin: 0.9rem 0 0;
}
.price-history__stats div { display: flex; align-items: baseline; gap: 0.5rem; }
.price-history__stats dt { font-size: 0.82rem; color: var(--theme-ink-muted); }
.price-history__stats dd { margin: 0; font-weight: 700; color: var(--theme-ink); }
.price-history__table { margin-top: 0.9rem; font-size: 0.88rem; }
.price-history__table summary { cursor: pointer; color: var(--theme-ink-soft); }
.price-history__table table { margin-top: 0.6rem; border-collapse: collapse; width: 100%; max-width: 420px; }
.price-history__table th { text-align: left; font-weight: 600; color: var(--theme-ink-muted); font-size: 0.8rem; padding: 0.25rem 0.75rem 0.25rem 0; }
.price-history__table td { padding: 0.25rem 0.75rem 0.25rem 0; color: var(--theme-ink-soft); border-top: 1px solid var(--theme-border); }
.price-history__note { margin: 0.9rem 0 0; font-size: 0.78rem; color: var(--theme-ink-muted); }

/* ------------------------------ Breadcrumbs ----------------------------- */

.breadcrumbs { margin: 0 0 1rem; }
.breadcrumbs ol {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 0.4rem;
  margin: 0;
  padding: 0;
  font-size: 0.84rem;
  color: var(--theme-ink-muted);
}
.breadcrumbs li { display: inline-flex; align-items: center; gap: 0.4rem; min-width: 0; }
.breadcrumbs a { color: var(--theme-ink-soft); }
.breadcrumbs a:hover { color: var(--theme-accent); text-decoration: none; }
.breadcrumbs__sep { color: var(--theme-ink-muted); }
.breadcrumbs [aria-current="page"] {
  color: var(--theme-ink-muted);
  max-width: 22rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ----------------------------- Ficha técnica ---------------------------- */

.book-specs {
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  padding: 1.5rem;
  margin-bottom: 1.5rem;
  box-shadow: var(--theme-shadow-sm);
}
.book-specs__title { margin: 0 0 1rem; font-size: 1.2rem; }
.book-specs__grid {
  display: grid;
  gap: 0.85rem 1.5rem;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  margin: 0;
}
.book-specs__grid > div { display: flex; flex-direction: column; }
.book-specs__grid dt {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--theme-ink-muted);
  margin: 0;
  font-weight: 500;
}
.book-specs__grid dd {
  margin: 0.15rem 0 0;
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--theme-ink);
}
.book-specs__grid dd a { color: var(--theme-accent); }
.book-specs__cat { grid-column: 1 / -1; }

/* --------------------- Cross-sell: comparar lista entera ---------------- */

.cross-compare {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.25rem;
  justify-content: space-between;
  background: var(--theme-accent-soft);
  border: 1px solid color-mix(in srgb, var(--theme-accent) 22%, transparent);
  border-radius: var(--ui-radius-lg);
  padding: 1.1rem 1.4rem;
  margin-bottom: 1.5rem;
}
.cross-compare__text { color: var(--theme-ink-soft); font-size: 0.95rem; max-width: 46ch; }
.cross-compare__text strong { display: block; color: var(--theme-ink); font-size: 1.02rem; margin-bottom: 0.1rem; }
.cross-compare__cta {
  flex: none;
  padding: 0.65rem 1.2rem;
  background: var(--theme-accent);
  color: var(--theme-surface);
  border-radius: var(--ui-radius-pill);
  font-weight: 700;
  white-space: nowrap;
}
.cross-compare__cta:hover { filter: brightness(0.93); color: var(--theme-surface); text-decoration: none; }

/* Añadir a la comparativa (carrito de la ficha) */
.add-compare {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.85rem;
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  padding: 1.1rem 1.4rem;
  margin-bottom: 1rem;
}
.add-compare__text { color: var(--theme-ink-soft); font-size: 0.95rem; }
.add-compare__text strong { display: block; color: var(--theme-ink); font-size: 1.02rem; margin-bottom: 0.1rem; }
.add-compare__form { flex: none; margin: 0; max-width: 100%; }
/* En móvil el rótulo «+ Añadir a la comparativa» pide más ancho del que queda
   dentro de la tarjeta (medido: 326 px de borde derecho en un viewport de 308),
   y con `align-items: flex-start` el formulario no encoge. A pantalla completa
   deja de salirse y de paso el CTA gana área táctil. */
@media (max-width: 719px) {
  .add-compare { padding: 1rem; }
  .add-compare__form { align-self: stretch; }
  .add-compare__btn { display: block; width: 100%; text-align: center; }
}
.add-compare__btn {
  padding: 0.65rem 1.3rem;
  background: var(--theme-accent);
  color: var(--theme-surface);
  border: 0;
  border-radius: var(--ui-radius-cta);
  font: inherit;
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
}
/* El CTA de «ya añadido» es un <a>, no un <button>: sin esto heredaba el
   subrayado y el color de enlace del layout y dejaba de parecer un boton. */
a.add-compare__btn { text-decoration: none; }
a.add-compare__btn:hover { text-decoration: none; }
.add-compare__hint {
  margin: 0.55rem 0 0;
  font-size: 0.85rem;
  color: var(--theme-ink-muted);
}
.add-compare__btn:hover { filter: brightness(0.93); }
.add-compare--ok .add-compare__btn { background: #16a34a; }

/* --------------------------- Related books ------------------------------ */

.related { margin: 0 0 1.5rem; }
.related__title {
  margin: 0 0 1rem;
  font-size: 1.25rem;
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
}
.related__title::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--theme-border);
}
/* -- Carril de relacionados ------------------------------------------------
   8 tarjetas en el DOM, ~4 a la vista. Sin JS por la CSP: `overflow-x` +
   `scroll-snap`, que en movil se arrastra con el dedo de forma nativa y en
   escritorio se mueve con rueda horizontal, teclado o arrastre.

   El `padding` vertical NO es decorativo: el hover de `.book-card` levanta la
   tarjeta 3px y le pone sombra (el tema `planeta` la sube a -3px en :4059), y
   sin holgura el `overflow` recortaria las dos cosas.

   `overscroll-behavior-x: contain` evita que al llegar al final del carril el
   gesto siga y dispare el "atras" del navegador. */
.related__rail {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  /* `mandatory` y no `proximity`: con proximity el carril se queda a medio
     camino entre dos tarjetas y parece roto. Mandatory da el enganche seco de
     un swipe nativo. */
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  padding: 6px 4px 10px;
  margin: 0 -4px;
  /* La barra de scroll del sistema (gris, con sus flechitas en Windows) es lo
     que estropeaba la seccion. Se oculta en los tres motores. El carril NO
     queda sin salida: sigue enfocable por teclado, se arrastra con el dedo, y
     el trozo de la tarjeta siguiente es la senal de que hay mas.
     Coste en rendimiento: cero. Es scroll nativo, sin JS ni listeners. */
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.related__rail::-webkit-scrollbar { width: 0; height: 0; }
/* Quien haya pedido menos animacion no quiere el desplazamiento suave. */
@media (prefers-reduced-motion: reduce) {
  .related__rail { scroll-behavior: auto; }
}
.related__rail:focus-visible {
  outline: 2px solid var(--theme-accent);
  outline-offset: 3px;
  border-radius: var(--ui-radius-sm);
}
/* Especificidad 0,2,0: gana a `.book-grid` (0,1,0) sin depender del orden del
   fichero, que es donde nos hemos tropezado antes. */
.related__rail .book-grid--rail {
  display: flex;
  gap: 1rem;
}
.related__rail .book-grid--rail > * {
  /* 4 a la vista MENOS un pellizco, para que asome la quinta. Sin ese trozo
     visible nada indica que haya mas libros detras: con 4 exactas y la barra
     de scroll ya oculta, la seccion parecia terminada ahi. */
  flex: 0 0 calc((100% - 3rem) / 4 - 1.1rem);
  scroll-snap-align: start;
}
@media (max-width: 900px) {
  .related__rail .book-grid--rail > * { flex-basis: calc((100% - 1rem) / 2); }
}
@media (max-width: 560px) {
  /* 1,3 tarjetas: el trozo de la siguiente es lo que le dice al visitante que
     hay mas y que esto se desliza. Con 1 exacta parece que no hay nada detras. */
  .related__rail .book-grid--rail > * { flex-basis: 78%; }
}

/* -- Flechas del carril ----------------------------------------------------
   Las inyecta `rail-nav.js`; sin JS no existen y el carril se maneja igual con
   el dedo, la rueda o el teclado. `has-rail-nav` la pone el propio script, asi
   que si no se ejecuta no queda hueco reservado ni botones muertos. */
.related__viewport { position: relative; }

.rail-nav {
  position: absolute;
  top: calc(50% - 1.6rem); /* centrado sobre las portadas, no sobre el titulo */
  z-index: 2;
  width: 2.5rem;
  height: 2.5rem;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 0;
  cursor: pointer;
  border: 1px solid var(--theme-border);
  border-radius: 50%;
  background: var(--theme-surface, #fff);
  color: inherit;
  box-shadow: 0 2px 8px rgb(0 0 0 / 12%);
}
.has-rail-nav .rail-nav { display: flex; }
.rail-nav--prev { left: -0.6rem; }
.rail-nav--next { right: -0.6rem; }
.rail-nav:hover:not(:disabled) { background: var(--theme-surface-alt, #f4f4f4); }
.rail-nav:focus-visible {
  outline: 2px solid var(--theme-accent);
  outline-offset: 2px;
}
/* En el extremo se apaga en vez de desaparecer: si se va, el otro boton salta
   de sitio y el raton pierde el objetivo justo cuando mas se usa. */
.rail-nav:disabled { opacity: 0.35; cursor: default; }

/* La flecha, dibujada con dos bordes: un glifo tipografico cambia de forma y de
   peso entre sistemas y aqui hay que casar dos botones simetricos. */
.rail-nav span {
  width: 0.55rem;
  height: 0.55rem;
  border-top: 2px solid currentColor;
  border-right: 2px solid currentColor;
}
.rail-nav--prev span { transform: rotate(-135deg); margin-left: 0.2rem; }
.rail-nav--next span { transform: rotate(45deg); margin-right: 0.2rem; }

/* En tactil sobran: ahi el gesto natural es arrastrar, y los botones tapan
   portada. Se ocultan por PUNTERO, no por ancho: un portatil tactil de 15"
   sigue teniendo raton. */
@media (hover: none) and (pointer: coarse) {
  .has-rail-nav .rail-nav { display: none; }
}

/* ------------------- Sticky buy bar (mobile only) ----------------------- */

.buybar { display: none; }
@media (max-width: 719px) {
  .buybar {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 40;
    padding: 0.6rem 1rem calc(0.6rem + env(safe-area-inset-bottom));
    background: var(--theme-surface);
    border-top: 1px solid var(--theme-border);
    box-shadow: 0 -6px 20px rgba(31, 27, 46, 0.12);
  }
  .buybar__info { display: flex; flex-direction: column; line-height: 1.15; min-width: 0; }
  .buybar__label { font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--theme-ink-muted); }
  .buybar__price {
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    font-size: 1.2rem;
    color: var(--theme-accent);
  }
  .buybar__merchant { font-size: 0.74rem; color: var(--theme-ink-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* Botón secundario «+ Lista» en la barra sticky: compacto (contorno, no
     relleno) para no competir con «Comprar», que es el ingreso. Empuja a
     «Comprar» al extremo con su propio margin-left:auto. */
  .buybar__add-form { display: contents; }
  .buybar__add {
    margin-left: auto;
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.62rem 0.85rem;
    border: 1.5px solid var(--theme-accent);
    border-radius: var(--ui-radius-cta);
    background: transparent;
    color: var(--theme-accent);
    font: inherit;
    font-weight: 700;
    font-size: 0.9rem;
    white-space: nowrap;
    cursor: pointer;
    text-decoration: none;
  }
  .buybar__add span { font-size: 1.05em; line-height: 1; }
  .buybar__add--done { border-color: var(--theme-border); color: var(--theme-ink-muted); }
  /* Con el «+ Lista» presente, «Comprar» ya no necesita el margin-left:auto
     (lo aporta el botón de lista); si no hay lista, lo recupera él. */
  .buybar__add ~ .buybar__cta,
  .buybar__add-form ~ .buybar__cta { margin-left: 0.5rem; }
  .buybar__cta {
    margin-left: auto;
    /* Encoge y recorta con elipsis en vez de salirse. En `/lista` el rotulo es
       «Como comprar en <libreria>», y con `flex: none` una libreria de nombre
       largo lo llevaba a 321 px dentro de un viewport de 308 (medido en prod con
       Casa del Libro). El nombre no cabe siempre; salirse de la pantalla, nunca. */
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    padding: 0.7rem 1.4rem;
    background: var(--theme-accent);
    color: var(--theme-surface);
    border-radius: var(--ui-radius-cta);
    font-weight: 700;
  }
  .buybar__cta:hover, .buybar__cta:focus { color: var(--theme-surface); text-decoration: none; }
  /* Hueco para que la barra fija no tape el último contenido del artículo. */
  .book-detail { padding-bottom: 4.5rem; }
}

/* ---------------------------- Status pages ------------------------------ */

.status-page {
  text-align: center;
  padding: 4rem 1rem;
}
.status-page__code {
  font-family: var(--theme-font-mono);
  font-size: 5rem;
  font-weight: 700;
  margin: 0;
  color: var(--theme-accent);
  letter-spacing: -0.04em;
  line-height: 1;
}
.status-page__title { margin: 0.5rem 0 0.75rem; font-size: 1.6rem; }
.status-page__message { color: var(--theme-ink-soft); max-width: 540px; margin: 0 auto 1.5rem; }
.status-page__actions { margin: 0; }

/* -------------------------------- Footer -------------------------------- */

.site-footer {
  background: var(--theme-surface);
  border-top: 1px solid var(--theme-border);
  margin-top: 3rem;
}

.site-footer__inner {
  padding: 2.5rem 1rem 2rem;
  display: grid;
  gap: 1.75rem 2rem;
  grid-template-columns: 1fr;
}
@media (min-width: 640px) {
  .site-footer__inner { grid-template-columns: 1fr 1fr; }
  .site-footer__brandcol { grid-column: 1 / -1; }
}
@media (min-width: 860px) {
  .site-footer__inner { grid-template-columns: 1.6fr 1fr 1fr 1fr 1fr; }
  .site-footer__brandcol { grid-column: auto; }
}

.site-footer__brand-row { display: flex; align-items: center; gap: 0.55rem; margin-bottom: 0.6rem; }
.site-footer__logo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: var(--ui-radius-md);
  background: var(--theme-accent-soft);
  font-size: 1.1rem;
}
.site-footer__brand { margin: 0; font-family: var(--theme-font-heading); font-weight: 800; color: var(--theme-ink); }
.site-footer__tagline { margin: 0 0 0.6rem; color: var(--theme-ink-soft); max-width: 340px; }
.site-footer__compare { margin: 0; color: var(--theme-ink-muted); font-size: 0.82rem; max-width: 340px; }

.site-footer__col { display: flex; flex-direction: column; gap: 0.55rem; }
.site-footer__links { display: flex; flex-direction: column; gap: 0.55rem; }
.site-footer__toggle { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.site-footer__heading {
  display: block;
  margin: 0 0 0.35rem;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--theme-ink-muted);
}
.site-footer__col a,
.site-footer__col .site-footer__linkish { color: var(--theme-ink-soft); font-size: 0.92rem; }
.site-footer__col a:hover,
.site-footer__col .site-footer__linkish:hover { color: var(--theme-accent); text-decoration: none; }

/* Reabrir el banner de cookies es una ACCIÓN, no una navegación, así que va en
   un <button> —lo contrario deja un enlace que no lleva a ninguna parte para
   quien navegue con teclado o lector de pantalla— y aquí se le quita el aspecto
   de control para que no desentone entre sus vecinos. */
.site-footer__linkish {
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  text-align: left;
  cursor: pointer;
  color: var(--theme-ink-soft);
  font-size: 0.92rem;
  font-family: inherit;
}
.site-footer__linkish:hover { color: var(--theme-accent); }

/* MÓVIL: acordeón. En una columna el pie son 18 enlaces apilados con sus cuatro
   rótulos; plegado son cuatro filas. Los enlaces siguen en el HTML —sólo se
   ocultan con `display: none`, no se quitan—, así que el enlazado interno, que
   es de lo poco que reparte autoridad hacia los hubs, no cambia. */
@media (max-width: 639px) {
  .site-footer__inner { grid-template-columns: 1fr; gap: 0; }
  .site-footer__brandcol { padding-bottom: 1.25rem; }
  .site-footer__col { gap: 0; border-top: 1px solid var(--theme-border); }
  .site-footer__heading {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin: 0;
    padding: 0.95rem 0.1rem;
    font-size: 0.78rem;
    cursor: pointer;
  }
  /* El signo es el único indicio de que la fila se abre, así que se dibuja con
     `content` y no con un SVG por sección. */
  .site-footer__heading::after {
    content: "+";
    font-size: 1.15rem;
    font-weight: 400;
    line-height: 1;
    transition: transform 0.18s ease;
  }
  .site-footer__toggle:checked ~ .site-footer__heading::after { content: "−"; }
  .site-footer__links { display: none; padding: 0 0.1rem 1rem; }
  .site-footer__toggle:checked ~ .site-footer__links { display: flex; }
  .site-footer__col a { padding: 0.2rem 0; }
}

.site-footer__bottom {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.5rem;
  justify-content: space-between;
  align-items: baseline;
  padding: 1.1rem 1rem 1.6rem;
  border-top: 1px solid var(--theme-border);
}
.site-footer__meta {
  margin: 0;
  font-size: 0.78rem;
  color: var(--theme-ink-muted);
  max-width: 720px;
}
.site-footer__made { margin: 0; font-size: 0.78rem; color: var(--theme-ink-muted); white-space: nowrap; }

/* --------------------------- Search results UI -------------------------- */

/* Sólo envuelve el <h1> y la línea de "resultados para…" — el buscador vive
   aparte, en `.search-sticky`. Así que la tarjeta blanca con borde y sombra no
   enmarcaba nada: era una caja vacía alrededor de un título. Sin fondo, el
   encabezado se lee como lo que es y el peso visual se lo llevan los libros. */
.search-header {
  margin-bottom: 1.5rem;
  padding: 0;
  background: none;
  border: 0;
  box-shadow: none;
}
.search-header__form {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
  /* OJO: el aspecto real en produccion NO se decide aqui. El tema `planeta`
     redefine este formulario mas abajo con `body.theme-confeti .search-header__form`,
     que gana por especificidad. Si quieres cambiar como se ve el buscador, hazlo
     ALLI — tocar solo esta regla no produce ningun efecto visible. */
}
.search-header__form input {
  flex: 1;
  /* `min-width: 0` o el buscador se rompe en móvil: `flex: 1` da base 0, pero el
     `min-width: auto` por defecto de un item flex lo ancla al ancho intrínseco de
     un <input> (~215 px por su `size` implícito), así que no encogía y empujaba
     al botón fuera. Medido en producción a 323 px de viewport: el botón acababa
     en x=399, 76 px fuera de la pantalla. */
  min-width: 0;
  padding: 0.75rem 1.1rem;
  border: 0;
  border-radius: var(--ui-radius-pill);
  font: inherit;
  font-size: 1.05rem;
  background: transparent;
  color: var(--theme-ink);
}
.search-header__form input:focus { outline: none; }
.search-header__form button {
  padding: 0.75rem 1.6rem;
  font-weight: 700;
  background: var(--theme-accent);
  color: var(--theme-surface);
  border: 0;
  /* Pildora, para que encaje dentro del contorno redondeado del formulario:
     con el radio cuadrado de antes asomaban las esquinas. */
  border-radius: var(--ui-radius-pill);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
/* El botón se lleva 112 px de la cápsula, y en un móvil estrecho eso dejaba el
   campo en 71 px — no cabe ni «ISBN, títul». Se le recorta el aire lateral al
   botón, que es lo prescindible: el input es donde se escribe. */
@media (max-width: 480px) {
  .search-header__form button,
  body.theme-confeti .search-header__form button { padding: 0.75rem 1.05rem; }
}
.search-header__meta { margin: 0; color: var(--theme-ink-soft); font-size: 0.92rem; }

/* Desplegable de búsqueda en vivo (as-you-type), poblado por live-search.js. */
.live-search-root { position: relative; }
.live-search__panel {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  z-index: 50;
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  box-shadow: var(--ui-shadow-lg, 0 16px 40px rgba(8, 30, 60, 0.16));
  max-height: min(70vh, 28rem);
  overflow-y: auto;
  padding: 0.35rem;
}
/* Fila = enlace a la ficha + botón de añadir. El botón no puede ir dentro del
   <a>, así que la fila los pone uno al lado del otro y el enlace se queda con
   todo el espacio sobrante. */
.live-search__row { display: flex; align-items: center; gap: 0.25rem; }
.live-search__item {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.5rem 0.6rem;
  border-radius: var(--ui-radius-md);
  color: var(--theme-ink);
  text-decoration: none;
  flex: 1 1 auto;
  min-width: 0;
}
/* Selector con el panel delante A PROPÓSITO: el desplegable se inserta DENTRO
   del <form> del buscador, así que `body.theme-confeti .search-header__form
   button` —el botón «Buscar», azul, en píldora y con 1,7 rem de padding
   lateral— ganaba por especificidad y deformaba el «+». `padding: 0` explícito
   por lo mismo. */
.live-search__panel .live-search__add {
  flex: none;
  padding: 0;
  width: 2rem;
  height: 2rem;
  min-width: 0;
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--theme-accent) 40%, var(--theme-border));
  background: var(--theme-surface);
  color: var(--theme-accent);
  font-size: 1.15rem;
  font-weight: 700;
  line-height: 1;
  font-family: inherit;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.live-search__panel .live-search__add:hover:not([disabled]) {
  background: var(--theme-accent);
  border-color: var(--theme-accent);
  color: #fff;
}
.live-search__panel .live-search__add[disabled] { opacity: 0.55; cursor: progress; }
.live-search__item:hover,
.live-search__item.is-active {
  background: var(--theme-accent-soft);
  text-decoration: none;
}
.live-search__cover {
  width: 32px;
  height: 44px;
  object-fit: contain;
  border-radius: var(--ui-radius-sm);
  flex-shrink: 0;
  background: var(--theme-surface-alt);
}
.live-search__cover--ph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.1rem;
}
.live-search__text { display: flex; flex-direction: column; min-width: 0; }
.live-search__title {
  font-weight: 600;
  font-size: 0.92rem;
  line-height: 1.25;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.live-search__authors {
  font-size: 0.8rem;
  color: var(--theme-ink-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.live-search__empty { padding: 0.7rem 0.6rem; color: var(--theme-ink-muted); font-size: 0.9rem; }

.search-layout {
  display: grid;
  gap: 1.5rem;
  grid-template-columns: 1fr;
}
/* La columna lateral de facetas se retiro el 08-ago-2026: ver .facet-bar. */

.search-facets {
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  padding: 1.25rem;
  align-self: start;
  box-shadow: var(--theme-shadow-sm);
}
/* -- Filtros plegables en movil ------------------------------------------
   En pantallas estrechas el panel tenia hasta 63 enlaces en 5 grupos, todos
   desplegados y ENCIMA de los resultados: habia que recorrerlos enteros para
   llegar al primer libro. Se pliegan tras un boton. Sin JS (la CSP es
   `script-src 'self'`): el estado lo lleva un checkbox y lo lee `:checked`.
   A partir de 980px —donde el panel ya es una columna lateral propia y no
   estorba— el boton se esconde y el cuerpo vuelve a estar siempre visible. */
.facets-toggle {
  /* Fuera de la vista pero NO `display:none` ni `hidden`: asi sigue estando en
     el arbol de accesibilidad y se puede alcanzar y accionar con el teclado. */
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.facets-toggle__label {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  /* 44px de alto: objetivo tactil comodo. */
  min-height: 44px;
  padding: 0 0.9rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-md);
  background: var(--theme-surface-alt, var(--theme-surface));
  color: var(--theme-ink);
  font-weight: 600;
  cursor: pointer;
  user-select: none;
}
.facets-toggle__label svg { width: 18px; height: 18px; display: block; }
.facets-toggle__text { flex: 1; }
.facets-toggle__chevron { transition: transform 0.2s ease; }
.facets-toggle:checked ~ .facets-toggle__label .facets-toggle__chevron {
  transform: rotate(180deg);
}
.facets-toggle:focus-visible ~ .facets-toggle__label {
  outline: 2px solid var(--theme-accent);
  outline-offset: 2px;
}
.search-facets__body { display: none; }
.facets-toggle:checked ~ .search-facets__body {
  display: block;
  margin-top: 1rem;
  /* Abierto tampoco debe empujar los resultados fuera de la pantalla: el panel
     se desplaza por dentro. */
  max-height: 60vh;
  overflow-y: auto;
  overscroll-behavior: contain;
}
@media (max-width: 979px) {
  /* Plegado, la tarjeta no es mas que el boton: sin esto el padding de columna
     lateral la dejaba como un bloque hueco de 70px encima de los resultados. */
  .search-facets { padding: 0.6rem; }
}
@media (min-width: 980px) {
  .facets-toggle__label { display: none; }
  .search-facets__body { display: block; max-height: none; overflow: visible; }
}
.search-facets section { margin-bottom: 1.25rem; }
.search-facets section:last-child { margin-bottom: 0; }
.search-facets h2 {
  margin: 0 0 0.5rem;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--theme-ink-muted);
  font-family: var(--theme-font-body);
}
.search-facets ul { list-style: none; margin: 0; padding: 0; }
.search-facets li { margin: 0.2rem 0; font-size: 0.92rem; }
.search-facets li a { color: var(--theme-ink-soft); }
.search-facets li a:hover { color: var(--theme-accent); }
.search-facets__stock p { margin: 0; }
.facet-count { color: var(--theme-ink-muted); font-size: 0.82rem; margin-left: 0.25rem; }

.search-results__empty {
  padding: 2rem;
  background: var(--theme-surface);
  border: 1px dashed var(--theme-border);
  border-radius: var(--ui-radius-lg);
  text-align: center;
}
.search-results__empty p { color: var(--theme-ink-soft); }

.book-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(4, 1fr);
}
@media (max-width: 900px) {
  .book-grid { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 640px) {
  .book-grid { grid-template-columns: repeat(2, 1fr); }
}

.book-card {
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  overflow: hidden;
  box-shadow: var(--theme-shadow-sm);
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
  display: flex;
  flex-direction: column;
}
.book-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--theme-shadow);
  border-color: color-mix(in srgb, var(--theme-accent) 35%, var(--theme-border));
}

.book-card__link { display: flex; flex-direction: column; flex: 1 1 auto; color: inherit; }
.book-card__link:hover { text-decoration: none; color: inherit; }

.book-card__cover {
  display: block;
  width: 100%;
  /* CUADRADA, no 2/3: la caja vertical es la proporción de una portada de libro,
     y una foto de juguete no lo es. Amazon publica sus imágenes de producto en
     un lienzo cuadrado con fondo blanco, así que 1/1 encaja sin franjas.

     Y `contain`, no `cover`: las fotos de los feeds vienen con proporciones muy
     dispares —una caja de LEGO es apaisada y un muñeco es alto—, y recortarlas
     a cuadrado corta justo por donde está lo que distingue una referencia de
     otra: el número de set, la variante de color, las piezas que incluye. La
     franja vacía es fea; esconder de qué juguete se trata es un error de
     producto. */
  aspect-ratio: 1 / 1;
  object-fit: contain;
  padding: 0.4rem;
  background: var(--theme-surface);
}
.book-card__cover--placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2.5rem;
  color: var(--theme-ink-muted);
}

.book-card__body { padding: 0.85rem 0.9rem 0.95rem; text-align: center; display: flex; flex-direction: column; flex: 1 1 auto; }
.book-card__title {
  margin: 0 0 0.4rem;
  font-size: 0.95rem;
  line-height: 1.3;
  font-family: var(--theme-font-heading);
  color: var(--theme-ink);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: calc(0.95rem * 1.3 * 3);
}
.book-card__authors { margin: 0 0 0.15rem; color: var(--theme-ink-soft); font-size: 0.82rem; }
.book-card__publisher { margin: 0 0 0.5rem; color: var(--theme-ink-muted); font-size: 0.78rem; }
/* 1.5rem y no 1.25: el precio es el dato por el que existe la tarjeta y a
   1.25 competía en peso con el título (pedido de Rafael con captura). */
.book-card__price { margin: auto 0 0.55rem; font-size: 1.5rem; font-weight: 700; line-height: 1.1; }
.book-card__price strong { font-family: var(--theme-font-body); font-weight: 700; }
.book-card__price--empty { display: block; margin: 0; color: var(--theme-ink-muted); font-size: 0.85rem; font-weight: 500; }
/* «desde» delante del importe. Va SIEMPRE que hay precio: el número es el
   mínimo con envío entre varias tiendas, y enseñarlo pelado prometería un
   importe que puede no ser el de la tienda a la que se acabe entrando. */
.book-card__from {
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--theme-ink-muted);
  text-transform: lowercase;
  letter-spacing: 0.01em;
}
/* Marca del juguete, ENCIMA del título: en un catálogo donde media rejilla se
   llama «Set de construcción 1200 piezas», la marca es lo primero que la gente
   reconoce. */
.book-card__brand {
  margin: 0 0 0.2rem;
  color: var(--theme-ink-muted);
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
/* Chip de variante («Original», «Talla M») en la tira de otras versiones. */
.book-card__variant {
  margin: 0 0 0.3rem;
  width: fit-content;
  padding: 0.1rem 0.55rem;
  border-radius: var(--ui-radius-pill, 999px);
  background: var(--ui-accent-soft, var(--theme-accent-soft));
  color: var(--ui-accent-strong, var(--theme-accent));
  font-size: 0.72rem;
  font-weight: 700;
}
/* Botón verde "N precios" — señal de comparativa (estilo comparador). */
.book-card__prices {
  display: block;
  padding: 0.55rem 0.75rem;
  background: var(--theme-accent);
  color: #fff;
  border-radius: var(--ui-radius-sm);
  font-weight: 700;
  font-size: 0.92rem;
  text-align: center;
}
.book-card:hover .book-card__prices { filter: brightness(0.93); }
.book-card__merchant {
  margin: 0.55rem 0 0;
  color: var(--theme-ink-soft);
  font-size: 0.76rem;
  font-style: italic;
  line-height: 1.3;
}

.pagination {
  margin-top: 1.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.4rem;
  font-size: 0.92rem;
}
/* Paginacion numerada en pildoras. La actual va rellena de color de marca y
   los demas numeros en superficie con borde: el usuario ve de un vistazo
   donde esta y cuantas paginas quedan, y llega a cualquiera de un clic. */
.pagination__pages {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  align-items: center;
  gap: 0.35rem;
}
.pagination__page {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 2,5 rem = 40 px: por encima del minimo tactil comodo en movil. */
  min-width: 2.5rem;
  height: 2.5rem;
  padding: 0 0.7rem;
  border: 1px solid var(--theme-border);
  /* Radio fijo, no 999px: con pildoras el «1» sale circulo y el «240» ovalo,
     y la fila queda con dos formas distintas. Con esquinas redondeadas todos
     los numeros son la misma figura mida lo que mida. */
  border-radius: var(--ui-radius-md);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-decoration: none;
  color: var(--theme-ink);
  background: var(--theme-surface);
  transition: border-color 0.18s ease, background-color 0.18s ease, color 0.18s ease;
}
.pagination__page:hover {
  border-color: color-mix(in srgb, var(--theme-accent) 45%, var(--theme-border));
  background: color-mix(in srgb, var(--theme-accent-soft) 60%, var(--theme-surface));
  color: var(--theme-accent);
  text-decoration: none;
}
.pagination__page--current {
  background: var(--theme-accent);
  border-color: var(--theme-accent);
  color: #fff;
  cursor: default;
}
/* La actual es un <span> y no lleva a ninguna parte, asi que el puntero encima
   no debe cambiarla. Sin esto heredaba el fondo palido del :hover de arriba
   conservando el color blanco del texto: el numero desaparecia al pasar por
   encima. Es el mismo motivo por el que se fija tambien el color. */
.pagination__page--current:hover {
  background: var(--theme-accent);
  border-color: var(--theme-accent);
  color: #fff;
}
.pagination__gap {
  padding: 0 0.15rem;
  color: var(--theme-ink-muted);
  user-select: none;
}
.pagination__step {
  display: inline-flex;
  align-items: center;
  height: 2.5rem;
  padding: 0 0.95rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-md);
  font-weight: 600;
  text-decoration: none;
  color: var(--theme-ink);
  background: var(--theme-surface);
  transition: border-color 0.18s ease, background-color 0.18s ease, color 0.18s ease;
}
.pagination__step:hover {
  border-color: color-mix(in srgb, var(--theme-accent) 45%, var(--theme-border));
  background: color-mix(in srgb, var(--theme-accent-soft) 60%, var(--theme-surface));
  color: var(--theme-accent);
  text-decoration: none;
}
/* En movil los rotulos Anterior/Siguiente se comen la fila: quedan los numeros,
   que es lo que de verdad permite saltar. */
@media (max-width: 460px) {
  .pagination__step { display: none; }
}
/* Aqui vivia un `.pagination a { ... }` de la paginacion anterior (la de
   «Anterior / Pagina 6 de 15 / Siguiente»). Al llegar la numerada dejo de
   describir nada y paso a estorbar: `.pagination a` tiene mas especificidad
   (0,1,1) que `.pagination__page` (0,1,0) y ademas iba despues, asi que le
   sobreescribia el radio y el padding a TODOS los enlaces. La pagina actual,
   que es un <span>, no la alcanzaba — y por eso salia redonda mientras las
   demas salian cuadradas. */
.pagination__status { color: var(--theme-ink-muted); }

/* -------------------------- Preguntas frecuentes ------------------------- */
/* `<details>` nativo: la CSP prohibe JS inline y el contenido de un <details>
   cerrado si lo indexa Google, asi que no hace falta nada mas. */
.faq {
  margin: 2.5rem 0 0;
  padding-top: 1.75rem;
  border-top: 1px solid var(--theme-border);
}
.faq__title { margin: 0 0 1rem; font-size: 1.35rem; }
.faq__item {
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-sm);
  background: var(--theme-surface);
  margin-bottom: 0.6rem;
  overflow: hidden;
}
.faq__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  /* Alto comodo para el dedo; el summary entero es el area de toque. */
  padding: 0.9rem 1.1rem;
  font-weight: 600;
  color: var(--theme-ink);
  cursor: pointer;
  list-style: none;
}
/* El triangulo por defecto se quita en los dos motores y se sustituye por un
   signo propio que ademas indica el estado. */
.faq__q::-webkit-details-marker { display: none; }
.faq__q::marker { content: ''; }
.faq__q::after {
  content: '+';
  flex: none;
  font-size: 1.35rem;
  font-weight: 400;
  line-height: 1;
  color: var(--theme-accent);
  transition: transform 0.18s ease;
}
.faq__item[open] .faq__q::after { content: '\2212'; }
.faq__q:hover { background: color-mix(in srgb, var(--theme-accent-soft) 45%, var(--theme-surface)); }
.faq__item:focus-within .faq__q { outline: 2px solid var(--theme-accent); outline-offset: -2px; }
.faq__a { padding: 0 1.1rem 1.1rem; }
.faq__a p { margin: 0; color: var(--theme-ink-soft); line-height: 1.65; }

/* ------------------------------- List page ------------------------------ */

/* Sin tarjeta (petición de Rafael, 14-ago-2026): el título de la lista no es una
   pieza de contenido que compita con las de abajo —las tarjetas blancas son las
   que SÍ hay que mirar y comparar—, así que va plano sobre el fondo. */
.list-detail__header {
  margin-bottom: 1.5rem;
  padding: 0;
}
.list-detail__header h1 { margin: 0 0 0.4rem; font-size: clamp(1.4rem, 3vw, 1.85rem); }
.list-detail__meta { margin: 0; color: var(--theme-ink-soft); font-size: 0.92rem; }

.list-cdl-highlight, .list-mix, .list-buys, .list-matrix, .list-items {
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  padding: 1.5rem;
  margin-bottom: 1.5rem;
  box-shadow: var(--theme-shadow-sm);
}
.list-cdl-highlight h2, .list-mix h2, .list-buys h2, .list-matrix h2, .list-items h2 {
  margin: 0 0 0.85rem;
  font-size: 1.2rem;
}
.list-cdl-highlight__meta, .list-mix__lead, .list-buys__lead {
  margin: 0 0 1rem;
  color: var(--theme-ink-soft);
  font-size: 0.95rem;
}
.list-cdl-highlight__cta {
  display: inline-block;
  padding: 0.65rem 1.2rem;
  background: var(--theme-accent);
  color: var(--theme-surface);
  border-radius: var(--ui-radius-cta);
  font-weight: 600;
}
.list-cdl-highlight__cta:hover { filter: brightness(0.93); color: var(--theme-surface); text-decoration: none; }
.list-cdl-highlight__missing, .list-mix__unassigned {
  margin: 0.85rem 0 0;
  color: var(--theme-ink-muted);
  font-size: 0.85rem;
}

/* Mix óptimo como desplegable: cabecera-resumen clicable (compra libro a libro). */
.list-mix > summary.list-mix__summary {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  cursor: pointer;
  list-style: none;
  font-weight: 700;
  font-size: 1.05rem;
}
.list-mix > summary.list-mix__summary::-webkit-details-marker { display: none; }
.list-mix__summary-label { color: var(--theme-ink); }
.list-mix__summary-total { margin-left: auto; color: var(--theme-ink-soft); font-family: var(--theme-font-heading); font-size: 0.95rem; font-weight: 600; }
.list-mix__summary-total strong { color: var(--theme-accent); }
.list-mix > summary.list-mix__summary::after {
  content: "";
  flex-shrink: 0;
  width: 0.6rem;
  height: 0.6rem;
  margin-left: 0.5rem;
  border-right: 2px solid var(--theme-ink-muted);
  border-bottom: 2px solid var(--theme-ink-muted);
  transform: rotate(45deg);
  transition: transform 0.2s ease;
}
.list-mix[open] > summary.list-mix__summary::after { transform: rotate(-135deg); }
.list-mix[open] > .list-mix__groups { margin-top: 1.1rem; }

.list-mix__groups { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.85rem; }
.list-mix-group {
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-sm);
  padding: 0.85rem 1rem;
  background: var(--theme-bg);
}
.list-mix-group__head {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  align-items: baseline;
  margin-bottom: 0.5rem;
}
.list-mix-group__swatch {
  display: inline-block;
  width: 0.85rem;
  height: 0.85rem;
  border-radius: var(--ui-radius-sm);
}
.list-mix-group__name { font-weight: 600; }
.list-mix-group__count { color: var(--theme-ink-muted); font-size: 0.85rem; }
.list-mix-group__total { margin-left: auto; color: var(--theme-ink-soft); font-size: 0.92rem; font-family: var(--theme-font-heading); }
.list-mix-group__total strong { color: var(--theme-ink); }
.list-mix-group__items { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.35rem; font-size: 0.9rem; }
.list-mix-group__items a { color: var(--theme-ink-soft); }
.list-mix-group__items a:hover { color: var(--theme-accent); }

/* ---- Quick-wins de /lista: ahorro, compartir, mix legible, buybar ------- */

/* Banner de ahorro cuantificado (el "gancho" de la lista). */
.list-savings {
  margin: 0 0 1.5rem;
  padding: 1rem 1.25rem;
  background: color-mix(in srgb, var(--theme-success) 10%, #fff);
  border: 1px solid color-mix(in srgb, var(--theme-success) 28%, transparent);
  border-radius: var(--ui-radius-sm);
}
.list-savings__headline {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem 0.55rem;
  font-size: 1.05rem;
  color: color-mix(in srgb, var(--theme-success) 78%, #000 22%);
}
.list-savings__lead { font-weight: 600; }
.list-savings__amount {
  font-family: var(--theme-font-heading);
  font-weight: 800;
  font-size: 1.5rem;
  color: var(--theme-success);
}
.list-savings__pct {
  font-weight: 700;
  font-size: 0.8rem;
  padding: 0.1rem 0.5rem;
  border-radius: var(--ui-radius-pill);
  background: color-mix(in srgb, var(--theme-success) 18%, #fff);
}
.list-savings__detail { color: color-mix(in srgb, var(--theme-success) 55%, var(--theme-ink) 45%); font-size: 0.95rem; }
.list-savings__detail strong { font-weight: 700; }
.list-savings__mix { margin: 0.5rem 0 0; font-size: 0.92rem; color: color-mix(in srgb, var(--theme-success) 65%, var(--theme-ink) 35%); }
.list-savings__mix strong { font-weight: 800; color: var(--theme-success); }

/* Acciones de la cabecera: botones de compartir. */
.list-detail__actions { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; }
.list-share-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.5rem 0.95rem;
  border-radius: var(--ui-radius-pill);
  border: 1px solid var(--theme-border);
  background: var(--theme-surface);
  color: var(--theme-ink);
  font: inherit;
  font-size: 0.88rem;
  font-weight: 600;
  cursor: pointer;
  line-height: 1;
}
.list-share-btn:hover { border-color: var(--theme-accent); color: var(--theme-accent); text-decoration: none; }
.list-share-btn__icon { width: 1rem; height: 1rem; flex-shrink: 0; }
.list-detail__share-label { font-size: 0.85rem; font-weight: 600; color: var(--theme-ink-muted); margin-right: 0.15rem; }
/* Botones de compartir con color de marca; el hover solo oscurece un poco. */
.list-share-btn--wa { background: #25d366; border-color: #25d366; color: #fff; }
.list-share-btn--wa:hover { filter: brightness(0.95); color: #fff; border-color: #25d366; }
.list-share-btn--tg { background: #229ed9; border-color: #229ed9; color: #fff; }
.list-share-btn--tg:hover { filter: brightness(0.95); color: #fff; border-color: #229ed9; }
.list-share-btn--x { background: #000; border-color: #000; color: #fff; }
.list-share-btn--x:hover { filter: brightness(1.25); color: #fff; border-color: #000; }
.list-share-btn--fb { background: #1877f2; border-color: #1877f2; color: #fff; }
.list-share-btn--fb:hover { filter: brightness(0.95); color: #fff; border-color: #1877f2; }
.list-share-btn--copy.is-copied { background: var(--theme-success); border-color: var(--theme-success); color: #fff; }

/* Panel "Guarda o comparte tu lista": propósito + copiar-enlace prominente +
   redes como acción secundaria. El copiar lo maneja list-share.js vía
   [data-copy-url] (sin JS inline, CSP-safe). */
.list-share {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  margin-top: 1.1rem;
  padding: 1.1rem 1.2rem;
  background: var(--theme-surface-alt);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-md);
}
.list-share__intro { display: flex; gap: 0.7rem; align-items: flex-start; }
.list-share__intro-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 2.2rem;
  height: 2.2rem;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent-soft);
  color: var(--theme-accent);
}
.list-share__intro-icon svg { width: 1.15rem; height: 1.15rem; }
.list-share__title { margin: 0; font-weight: 700; color: var(--theme-ink); font-size: 1rem; }
.list-share__hint { margin: 0.15rem 0 0; color: var(--theme-ink-soft); font-size: 0.88rem; line-height: 1.5; }
.list-share__copy { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.list-share__url {
  flex: 1 1 240px;
  min-width: 0;
  padding: 0.62rem 0.85rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-pill);
  background: var(--theme-surface);
  color: var(--theme-ink-soft);
  font-family: var(--theme-font-mono);
  font-size: 0.85rem;
}
.list-share__url:focus { outline: 2px solid var(--ui-accent-ring); outline-offset: 1px; }
.list-share__copy-btn {
  flex: 0 0 auto;
  padding: 0.62rem 1.3rem;
  border: 0;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent);
  color: #fff;
  font-weight: 700;
  font-size: 0.9rem;
  cursor: pointer;
  transition: filter 0.15s ease, background 0.15s ease;
}
.list-share__copy-btn:hover { filter: brightness(1.07); }
.list-share__copy-btn.is-copied { background: var(--theme-success); }
.list-share__socials { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; }
.list-share__socials-label { font-size: 0.82rem; font-weight: 600; color: var(--theme-ink-muted); margin-right: 0.1rem; }

/* Mix óptimo legible: miniatura + título en lugar del ISBN crudo. */
/* ============ /lista: veredicto, tabla de librerías y lista de la compra ====
   Reordenación del 08-ago-2026. La página abría pidiendo que la compartieras y
   el primer enlace que gana dinero estaba a 1,3 pantallas de scroll; ahora abre
   con la respuesta y el botón. */

.list-verdict {
  background: var(--theme-accent-soft);
  border: 1px solid color-mix(in srgb, var(--theme-accent) 28%, var(--theme-border));
  border-radius: var(--ui-radius-lg);
  padding: 1.5rem 1.5rem 1.6rem;
  margin: 0 0 1.5rem;
  text-align: center;
}
.list-verdict__eyebrow {
  margin: 0 0 0.35rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--theme-ink-soft);
}
.list-verdict__store {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  margin: 0 0 0.6rem;
  font-size: clamp(1.35rem, 3.5vw, 1.8rem);
  line-height: 1.15;
}
.list-verdict__logo { border-radius: var(--ui-radius-sm); flex: none; }
.list-verdict__total { margin: 0 0 0.9rem; display: flex; flex-direction: column; gap: 0.15rem; align-items: center; }
.list-verdict__amount {
  font-family: var(--theme-font-heading);
  font-weight: 800;
  font-size: clamp(2.1rem, 6vw, 3rem);
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--theme-accent);
  font-variant-numeric: tabular-nums;
}
.list-verdict__ship { font-size: 0.85rem; color: var(--theme-ink-muted); }
.list-verdict__facts {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.4rem 1.4rem;
  margin: 0 0 1.2rem;
  font-size: 0.92rem;
  color: var(--theme-ink-soft);
}
.list-verdict__fact strong { color: var(--theme-ink); }
.list-verdict__fact--save strong { color: var(--theme-success, var(--theme-success)); }
.list-verdict__cta {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.85rem 1.7rem;
  background: var(--theme-accent);
  color: var(--theme-surface);
  border-radius: var(--ui-radius-pill);
  font-weight: 700;
  font-size: 1.02rem;
}
.list-verdict__cta:hover, .list-verdict__cta:focus { color: var(--theme-surface); text-decoration: none; filter: brightness(0.93); }
.list-verdict__cta svg { width: 1.05rem; height: 1.05rem; }
.list-verdict__mixhint { margin: 1rem 0 0; font-size: 0.9rem; color: var(--theme-ink-soft); }

/* --- Tabla comparativa. Sustituye a cuatro tarjetas de 714 px que servían para
   comparar cuatro números; en columna se comparan de un vistazo. --- */
/* --- Matriz libro × librería: cada celda es el precio con su enlace. --- */
.list-matrix { margin: 0 0 1.75rem; }
.list-matrix__title { margin: 0 0 0.85rem; font-size: 1.2rem; }
.list-matrix__scroll { overflow-x: auto; }
.list-matrix__table { width: 100%; border-collapse: collapse; font-size: 0.94rem; }
.list-matrix__table th,
.list-matrix__table td { padding: 0.6rem 0.75rem; border-bottom: 1px solid var(--theme-border); text-align: left; vertical-align: middle; }
.list-matrix__table thead th {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--theme-ink-muted);
  font-weight: 700;
  white-space: nowrap;
}
.list-matrix__table .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.list-matrix__store { display: inline-flex; align-items: center; gap: 0.4rem; }
.list-matrix__store img { border-radius: var(--ui-radius-sm); flex: none; }
.list-matrix__book { display: flex; align-items: center; gap: 0.6rem; min-width: 14rem; }
.list-matrix__cover {
  flex: none;
  width: 28px;
  height: 40px;
  object-fit: cover;
  border-radius: var(--ui-radius-sm);
}
.list-matrix__cover--ph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--theme-accent-soft);
  font-size: 0.95rem;
}
.list-matrix__booktext { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.list-matrix__booklink { font-weight: 600; color: var(--theme-ink); text-decoration: none; }
a.list-matrix__booklink:hover { text-decoration: underline; }
/* El precio es un BOTÓN, y el más barato de cada fila va en sólido: es el
 * «destacado del proveedor» que se pidió — el fondo de celda de antes se
 * confundía con un simple estilado y en los empates parecía un error. */
.list-matrix__price {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4rem;
  padding: 0.4rem 0.85rem;
  border: 1.5px solid var(--theme-border);
  border-radius: var(--ui-radius-pill);
  font-weight: 700;
  color: var(--theme-accent);
  text-decoration: none;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}
.list-matrix__price:hover { background: var(--theme-accent-soft); border-color: var(--theme-accent); }
.list-matrix__table td.is-best .list-matrix__price {
  background: var(--theme-accent);
  border-color: var(--theme-accent);
  color: var(--theme-surface);
}
.list-matrix__cellstore { display: none; }
.list-matrix__none { color: var(--theme-ink-muted); }
.list-matrix__note { margin: 0.8rem 0 0; font-size: 0.85rem; color: var(--theme-ink-muted); }
.list-matrix__table tbody tr.is-bought { opacity: 0.55; }
.list-matrix__table tbody tr.is-bought .list-matrix__booklink { text-decoration: line-through; }
.list-mix-item.is-bought { opacity: 0.55; }
.list-mix-item.is-bought .list-mix-item__title { text-decoration: line-through; }

/* --- El diálogo de compartir al completar la lista (`list-celebrate`, NO
 * `list-share`: esa clase es de la sección «Guarda o comparte tu lista» y la
 * colisión vistió aquella sección de popup — 12-ago-2026). --- */
.list-celebrate {
  max-width: 24rem;
  border: 0;
  border-radius: var(--ui-radius-lg);
  padding: 1.6rem 1.5rem;
  text-align: center;
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.22);
}
.list-celebrate:not([open]) { display: none; }
.list-celebrate::backdrop { background: rgba(15, 30, 45, 0.55); }
.list-celebrate__emoji { margin: 0; font-size: 2.2rem; line-height: 1; }
.list-celebrate__title { margin: 0.5rem 0 0.4rem; font-size: 1.25rem; }
.list-celebrate__body { margin: 0 0 1.1rem; font-size: 0.92rem; color: var(--theme-ink-soft); }
.list-celebrate__actions { display: flex; flex-direction: column; gap: 0.55rem; }
.list-celebrate__wa,
.list-celebrate__copy {
  display: block;
  width: 100%;
  padding: 0.65rem 1rem;
  border-radius: var(--ui-radius-pill);
  font-weight: 700;
  font-size: 0.95rem;
  text-decoration: none;
  cursor: pointer;
}
.list-celebrate__wa { background: var(--theme-accent); color: var(--theme-surface); border: 0; }
.list-celebrate__wa:hover { opacity: 0.92; }
.list-celebrate__copy { background: var(--theme-surface); color: var(--theme-accent); border: 1.5px solid var(--theme-accent); }
.list-celebrate__copy:hover { background: var(--theme-accent-soft); }
.list-celebrate__close {
  background: none;
  border: 0;
  padding: 0.4rem;
  color: var(--theme-ink-muted);
  font-size: 0.85rem;
  cursor: pointer;
  text-decoration: underline;
}

/* En móvil la matriz no cabe ni con scroll: cada libro pasa a ser una
 * tarjeta con sus botones de tienda (los guiones de «no lo tiene» sobran). */
@media (max-width: 720px) {
  .list-matrix__scroll { overflow-x: visible; }
  .list-matrix__table, .list-matrix__table tbody { display: block; }
  .list-matrix__table thead { display: none; }
  .list-matrix__table tr {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    border: 1px solid var(--theme-border);
    border-radius: var(--ui-radius-md);
    background: var(--theme-surface);
    padding: 0.85rem;
    margin: 0 0 0.75rem;
  }
  .list-matrix__table th, .list-matrix__table td { border: 0; padding: 0; }
  .list-matrix__table th[scope="row"] { flex-basis: 100%; }
  .list-matrix__book { min-width: 0; }
  .list-matrix__none { display: none; }
  .list-matrix__cellstore {
    display: inline;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
  }
}

/* --- La lista de la compra. Abierta, no en acordeón: el CTA anterior tenía
   forma de botón de compra y lo único que hacía era desplegar un cajón. --- */
.list-buys__lead { margin: 0 0 1.1rem; color: var(--theme-ink-soft); }
.list-shop {
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  margin-bottom: 0.75rem;
  background: var(--theme-surface);
}
.list-shop--best { border-color: color-mix(in srgb, var(--theme-accent) 40%, var(--theme-border)); }
.list-shop__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.9rem 1.1rem;
  cursor: pointer;
  list-style: none;
  font-weight: 600;
}
.list-shop__head::-webkit-details-marker { display: none; }
/* Nada decía que estas filas se abren: se ocultó el marcador nativo y no se
   puso nada en su lugar, así que las librerías cerradas parecían un ranking
   muerto —nombre, progreso y total— en vez de la puerta a sus libros. Galón que
   gira al abrir (el mismo del mix, para que el gesto se aprenda una vez) y la
   fila entera se tiñe al pasar por encima (14-ago-2026). */
.list-shop__head::after {
  content: "";
  flex: none;
  width: 0.55rem;
  height: 0.55rem;
  margin-left: -0.2rem;
  border-right: 2px solid var(--theme-ink-muted);
  border-bottom: 2px solid var(--theme-ink-muted);
  transform: translateY(-0.15rem) rotate(45deg);
  transition: transform 0.2s ease, border-color 0.2s ease;
}
.list-shop[open] > .list-shop__head::after { transform: translateY(0.1rem) rotate(-135deg); }
/* `inherit` y no un valor fijo: la cabecera es el primer hijo de una caja
   redondeada, y sin esto el fondo del hover pinta esquinas cuadradas por fuera
   del borde. Abierta, sólo redondea arriba. */
.list-shop__head { border-radius: inherit; }
.list-shop[open] > .list-shop__head { border-radius: var(--ui-radius-lg) var(--ui-radius-lg) 0 0; }
.list-shop__head:hover { background: var(--theme-surface-alt); }
.list-shop__head:hover::after { border-color: var(--theme-accent); }
.list-shop__head:focus-visible { outline: 2px solid var(--ui-accent-ring); outline-offset: -2px; }
.list-shop__store { display: inline-flex; align-items: center; gap: 0.5rem; min-width: 0; }
.list-shop__store img { border-radius: var(--ui-radius-sm); flex: none; }
.list-shop__store span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* `margin-left: auto` porque el galón de `::after` es un tercer hijo del flex:
   con el `space-between` a secas, el precio se habría ido al centro. */
.list-shop__meta { display: flex; align-items: center; gap: 0.85rem; flex: none; margin-left: auto; }
.list-shop__progress { font-size: 0.82rem; font-weight: 600; color: var(--theme-ink-muted); }
.list-shop__progress.is-complete { color: var(--theme-success, var(--theme-success)); }
.list-shop__total { font-variant-numeric: tabular-nums; font-weight: 700; }
.list-shop__items { list-style: none; margin: 0; padding: 0 1.1rem 0.9rem; display: flex; flex-direction: column; gap: 0.35rem; }
.list-shop__item {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  padding: 0.5rem;
  border-radius: var(--ui-radius-sm);
  background: var(--theme-surface-alt);
}
/* Comprado: se atenúa pero NO se esconde — quien vuelve necesita ver la lista
   entera para saber que ya no le falta nada. */
.list-shop__item.is-bought { opacity: 0.55; }
.list-shop__item.is-bought .list-shop__title { text-decoration: line-through; }
.list-shop__tick {
  flex: none;
  width: 1.6rem;
  height: 1.6rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 2px solid var(--theme-border);
  border-radius: 50%;
  background: var(--theme-surface);
  color: transparent;
  cursor: pointer;
  padding: 0;
}
.list-shop__tick svg { width: 0.85rem; height: 0.85rem; }
.list-shop__item.is-bought .list-shop__tick {
  background: var(--theme-success, var(--theme-success));
  border-color: var(--theme-success, var(--theme-success));
  color: #fff;
}
.list-shop__cover { width: 32px; height: 44px; object-fit: contain; border-radius: var(--ui-radius-sm); flex: none; background: var(--theme-surface); }
.list-shop__cover--ph { display: inline-flex; align-items: center; justify-content: center; font-size: 1rem; }
.list-shop__body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 0.1rem; }
.list-shop__title { color: var(--theme-ink); font-size: 0.92rem; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.list-shop__title:hover { color: var(--theme-accent); }
.list-shop__price { font-size: 0.85rem; color: var(--theme-ink-muted); font-variant-numeric: tabular-nums; }
/* El ISBN como CHIP: es el dato con el que un padre coteja la lista impresa
 * del colegio, y en gris perdido no se encontraba (petición 12-ago). */
.list-shop__isbn, .list-mix-item__isbn, .list-matrix__isbn {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--theme-ink-soft);
  background: var(--theme-surface-alt);
  border-radius: var(--ui-radius-sm);
  padding: 0.12rem 0.5rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.list-shop__isbn, .list-matrix__isbn { align-self: flex-start; }
.list-mix-item__isbn { flex: none; }
.list-shop__buy {
  flex: none;
  padding: 0.45rem 1rem;
  background: var(--theme-accent);
  color: var(--theme-surface);
  border-radius: var(--ui-radius-pill);
  font-size: 0.88rem;
  font-weight: 700;
}
.list-shop__buy:hover, .list-shop__buy:focus { color: var(--theme-surface); text-decoration: none; filter: brightness(0.93); }
.list-shop__missing { margin: 0 1.1rem 0.9rem; font-size: 0.85rem; color: var(--theme-ink-muted); }

@media (max-width: 560px) {
  .list-shop__meta { gap: 0.5rem; }
  .list-shop__progress { font-size: 0.74rem; }
  .list-shop__buy { padding: 0.45rem 0.75rem; }
}

.list-mix-item { display: flex; align-items: center; gap: 0.6rem; }
.list-mix-item__cover {
  flex: none;
  width: 30px;
  height: 42px;
  object-fit: cover;
  border-radius: var(--ui-radius-sm);
  background: var(--theme-bg);
}
.list-mix-item__cover--ph { display: inline-flex; align-items: center; justify-content: center; font-size: 1rem; }
.list-mix-group__items .list-mix-item__title {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--theme-ink);
  font-weight: 500;
}
.list-mix-group__items .list-mix-item__title:hover { color: var(--theme-accent); }

/* Responsive de la lista (12-ago-2026, capturas de Rafael): en móvil el
 * título del mix quedaba a 0 px entre el chip de ISBN, el precio y el botón
 * —desaparecía—, y el de la checklist se truncaba a diez caracteres por el
 * nowrap de escritorio. Va DESPUÉS de las reglas base para ganar en cascada. */
@media (max-width: 720px) {
  .list-shop__title {
    white-space: normal;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
  }
  .list-shop__store { min-width: 0; }
  .list-mix-item { flex-wrap: wrap; row-gap: 0.35rem; }
  .list-mix-group__items .list-mix-item__title {
    flex: 1 1 calc(100% - 40px);
    white-space: normal;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
  }
  .list-mix-item__isbn { order: 2; }
  .list-mix-item__price { order: 3; margin-left: auto; }
  .list-mix-item__buy { order: 4; }
}
.list-mix-item__price { flex: none; font-family: var(--theme-font-heading); font-weight: 600; color: var(--theme-ink); }
.list-mix-group__items .list-mix-item__buy {
  flex: none;
  padding: 0.35rem 0.8rem;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent);
  color: var(--theme-surface);
  font-size: 0.82rem;
  font-weight: 700;
}
.list-mix-group__items .list-mix-item__buy:hover { filter: brightness(0.93); color: var(--theme-surface); text-decoration: none; }

/* Campo opcional "nombre de la lista" en /comparar. */
.compare-form__name {
  display: block;
  width: 100%;
  margin-top: 0.6rem;
  padding: 0.7rem 0.9rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-sm);
  background: var(--theme-surface);
  color: var(--theme-ink);
  font: inherit;
  font-size: 0.95rem;
}
.compare-form__name:focus { outline: 2px solid color-mix(in srgb, var(--theme-accent) 45%, transparent); outline-offset: 1px; border-color: var(--theme-accent); }

/* Hueco para que la buybar fija no tape el final de la lista en móvil. */
@media (max-width: 719px) {
  .list-detail { padding-bottom: 4.5rem; }
}

/* ---- Editar lista: añadir libro, quitar, y "los añadiremos pronto". ----- */
.list-add {
  margin: 0 0 1.5rem;
  padding: 0.9rem 1.1rem;
  border: 1px dashed var(--theme-border);
  border-radius: var(--ui-radius-sm);
  background: var(--theme-bg);
}
.list-add__label { display: block; font-weight: 600; font-size: 0.9rem; margin-bottom: 0.5rem; }
.list-add__row { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.list-add__input {
  flex: 1 1 240px;
  min-width: 0;
  padding: 0.6rem 0.85rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-sm);
  background: var(--theme-surface);
  color: var(--theme-ink);
  font: inherit;
}
.list-add__input:focus { outline: 2px solid color-mix(in srgb, var(--theme-accent) 45%, transparent); outline-offset: 1px; border-color: var(--theme-accent); }
.list-add__submit {
  flex: none;
  padding: 0.6rem 1.3rem;
  border: 0;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent);
  color: var(--theme-surface);
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}
.list-add__submit:hover { filter: brightness(0.93); }

/* Lista ajena (compartida o histórica sin dueño): aviso + CTA «crear mi copia». */
.list-foreign {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem 1rem;
  margin-top: 1rem;
  padding: 0.85rem 1rem;
  border: 1px dashed var(--theme-border);
  border-radius: var(--ui-radius-sm);
  background: var(--theme-accent-soft);
}
.list-foreign__note {
  margin: 0;
  flex: 1 1 16rem;
  color: var(--theme-ink-soft);
  font-size: 0.92rem;
}
.list-foreign__form { margin: 0; }
.list-foreign__btn {
  padding: 0.55rem 1.2rem;
  border: 0;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent);
  color: var(--theme-surface);
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}
.list-foreign__btn:hover { filter: brightness(0.93); }

/* Aviso de un solo uso tras clonar una lista compartida: «esta es tu copia». */
.list-forked-note {
  margin: 0 0 1.25rem;
  padding: 0.7rem 1rem;
  border: 1px solid var(--theme-border);
  border-left: 4px solid var(--theme-accent);
  border-radius: var(--ui-radius-sm);
  background: var(--theme-surface);
  color: var(--theme-ink);
  font-size: 0.95rem;
  box-shadow: var(--theme-shadow-sm);
}

/* ---- Mis listas (/mis-listas) ---- */
.mylists { max-width: 46rem; margin: 0 auto; }
.mylists__header { margin-bottom: 1.25rem; }
.mylists__header h1 { margin: 0 0 0.35rem; }
.mylists__lead { margin: 0; color: var(--theme-ink-soft); }
.mylists__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.5rem; }
.mylists__item {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.15rem 0.85rem;
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-sm);
  box-shadow: var(--theme-shadow-sm);
}
.mylists__item.is-active { border-color: var(--theme-accent); }
.mylists__link { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 0.15rem; padding: 0.6rem 0; }
.mylists__link:hover { text-decoration: none; }
.mylists__name { color: var(--theme-ink); font-weight: 700; }
.mylists__link:hover .mylists__name { color: var(--theme-accent); }
.mylists__meta { color: var(--theme-ink-soft); font-size: 0.85rem; }
.mylists__badge {
  flex: none;
  padding: 0.2rem 0.6rem;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent-soft);
  color: var(--theme-accent);
  font-size: 0.78rem;
  font-weight: 700;
}
.mylists__empty {
  padding: 1.5rem;
  border: 1px dashed var(--theme-border);
  border-radius: var(--ui-radius-lg);
  background: var(--theme-surface);
  text-align: center;
}
.mylists__empty-text { margin: 0 0 1rem; color: var(--theme-ink-soft); }
/* Dejó de ser un enlace a /comparar para ser un POST que suelta la comparativa
   activa, así que ahora es un <button>: hereda tipografía y pierde el borde.
   OJO al orden: este `margin: 0` (que sólo quiere anular el margen que algunos
   navegadores dan al <form>) tiene la misma especificidad que la separación de
   `.mylists__actions`, así que si va DESPUÉS se la come y el botón queda pegado
   a la última lista. Por eso el margen de la fila de acciones se declara aquí
   abajo, y no antes. */
.mylists__new { margin: 0; }
.mylists__actions { margin-top: 1.25rem; }
.mylists__new-btn {
  display: inline-block;
  font: inherit;
  padding: 0.6rem 1.3rem;
  border: 0;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent);
  color: var(--theme-surface);
  font-weight: 700;
  cursor: pointer;
}
.mylists__new-btn:hover { filter: brightness(0.93); text-decoration: none; color: var(--theme-surface); }
.mylists__new-btn:focus-visible { outline: 2px solid var(--ui-accent-ring); outline-offset: 2px; }
.mylists__note { margin-top: 1.25rem; color: var(--theme-ink-muted); font-size: 0.85rem; }

/* ---- Interstitial «¿dónde añadimos estos libros?» ---- */
.cmp-decide { max-width: 40rem; margin: 0 auto; text-align: center; }
.cmp-decide__title { margin: 0 0 0.6rem; }
.cmp-decide__lead { margin: 0 0 1.5rem; color: var(--theme-ink-soft); }
.cmp-decide__options { display: grid; gap: 0.85rem; }
.cmp-decide__option {
  margin: 0;
  padding: 1.1rem 1.25rem;
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  box-shadow: var(--theme-shadow-sm);
}
.cmp-decide__btn {
  display: inline-block;
  width: 100%;
  padding: 0.7rem 1.3rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-pill);
  background: var(--theme-surface);
  color: var(--theme-ink);
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}
.cmp-decide__btn:hover { border-color: var(--theme-accent); color: var(--theme-accent); }
.cmp-decide__btn--primary {
  border-color: var(--theme-accent);
  background: var(--theme-accent);
  color: var(--theme-surface);
}
.cmp-decide__btn--primary:hover { filter: brightness(0.93); color: var(--theme-surface); }
.cmp-decide__hint { margin: 0.55rem 0 0; color: var(--theme-ink-soft); font-size: 0.88rem; }
.cmp-decide__links { margin-top: 1.25rem; font-size: 0.9rem; color: var(--theme-ink-soft); }

/* Banner «envíanos tu lista» de las colecciones de curso/asignatura: banda
   clicable entera, delgada, entre el H1 y el buscador pegajoso. */
.collection-sendlist {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  margin: 0 0 1rem;
  padding: 0.85rem 1.1rem;
  background: var(--theme-accent-soft);
  border: 1px solid color-mix(in srgb, var(--theme-accent) 35%, var(--theme-border));
  border-radius: var(--ui-radius-md);
  color: var(--theme-ink);
}
.collection-sendlist:hover { text-decoration: none; border-color: var(--theme-accent); }
.collection-sendlist__icon { flex: none; width: 1.7rem; height: 1.7rem; color: var(--theme-accent); }
.collection-sendlist__text { flex: 1 1 auto; min-width: 0; font-size: 0.92rem; line-height: 1.4; color: var(--theme-ink-soft); }
.collection-sendlist__text strong { display: block; color: var(--theme-ink); }
.collection-sendlist__cta {
  flex: none;
  padding: 0.5rem 1.1rem;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent);
  color: #fff;
  font-weight: 700;
  font-size: 0.9rem;
  white-space: nowrap;
}
.collection-sendlist:hover .collection-sendlist__cta { filter: brightness(0.93); }
@media (max-width: 640px) {
  .collection-sendlist { flex-wrap: wrap; }
  .collection-sendlist__cta { margin-left: auto; }
}

/* Enlace de vuelta a Mis listas en la cabecera de la lista (solo dueño). */
.list-detail__mylists { margin: 0 0 0.5rem; font-size: 0.85rem; }
.list-detail__mylists a { color: var(--theme-accent); font-weight: 600; }

/* «Crear otra lista» en la cabecera: acción secundaria, en fantasma, para que no
   compite con el veredicto («Ver tus libros en X»), que es lo que convierte. */
.list-detail__new { margin: 0.6rem 0 0; }
.list-detail__new-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font: inherit;
  font-size: 0.88rem;
  font-weight: 600;
  padding: 0.4rem 0.9rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-pill);
  background: var(--theme-surface);
  color: var(--theme-accent);
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.list-detail__new-btn:hover { border-color: var(--theme-accent); background: var(--theme-accent-soft); }
.list-detail__new-btn:focus-visible { outline: 2px solid var(--ui-accent-ring); outline-offset: 2px; }

/* Renombrar la lista (details CSS-only en la cabecera, solo dueño). */
.list-rename { margin-top: 0.75rem; }
.list-rename__summary {
  display: inline-block;
  cursor: pointer;
  color: var(--theme-accent);
  font-size: 0.88rem;
  font-weight: 600;
}
.list-rename__summary:hover { text-decoration: underline; }
.list-rename__form { display: flex; gap: 0.5rem; margin-top: 0.6rem; max-width: 28rem; }
.list-rename__input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-sm);
  font: inherit;
}
.list-rename__submit {
  flex: none;
  padding: 0.5rem 1.1rem;
  border: 0;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent);
  color: var(--theme-surface);
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}
.list-rename__submit:hover { filter: brightness(0.93); }

/* Lista sin libros catalogados: que nunca sea una página muerta. */
.list-empty {
  padding: 1.5rem;
  margin-bottom: 1.5rem;
  background: var(--theme-surface);
  border: 1px dashed var(--theme-border);
  border-radius: var(--ui-radius-lg);
}
.list-empty__title { margin: 0 0 0.5rem; font-size: 1.15rem; }
.list-empty__text { margin: 0 0 1rem; color: var(--theme-ink-soft); }
.list-empty__alt { margin: 0.85rem 0 0; font-size: 0.9rem; }
.list-empty .list-add { margin-top: 0; }

/* Botón borrar en Mis listas + insignia de publicada. */
.mylists__delete { margin: 0; flex: none; }
.mylists__badge--promoted { background: var(--theme-surface-alt); color: var(--theme-ink-soft); }

/* Botón quitar (esquina del item; el item es un grid, así que va absoluto). */
.list-item { position: relative; }
.list-item__title { padding-right: 1.6rem; }
.list-item__remove { position: absolute; top: 0.4rem; right: 0.4rem; margin: 0; }
.list-item__remove-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.7rem;
  height: 1.7rem;
  padding: 0;
  border: 1px solid var(--theme-border);
  border-radius: 50%;
  background: var(--theme-surface);
  color: var(--theme-ink-muted);
  font-size: 0.85rem;
  line-height: 1;
  cursor: pointer;
}
.list-item__remove-btn:hover { border-color: #d23; color: #d23; background: color-mix(in srgb, #d23 8%, #fff); }

.list-contents { margin: 1.25rem 0; }
.list-contents__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin: 0 0 0.6rem;
}
.list-contents__title { font-size: 1.05rem; margin: 0; }
.list-contents__clear { margin: 0; }
.list-contents__clear-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.4rem 0.85rem;
  border-radius: var(--ui-radius-pill);
  border: 1px solid var(--theme-border);
  background: var(--theme-surface);
  color: var(--theme-ink-soft);
  font: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease, background-color 0.15s ease;
}
.list-contents__clear-btn:hover {
  border-color: var(--theme-danger);
  color: var(--theme-danger);
  background: #fdf1f1;
}
.list-contents__clear-btn svg { width: 0.95rem; height: 0.95rem; }
.list-contents__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.4rem; }
.list-contents__item {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0.65rem;
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-sm);
}
.list-contents__cover { width: 36px; height: 50px; object-fit: cover; border-radius: var(--ui-radius-sm); flex: none; }
.list-contents__cover--ph { display: inline-flex; align-items: center; justify-content: center; background: var(--theme-accent-soft); font-size: 1.1rem; }
.list-contents__body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 0.25rem; }
.list-contents__name { color: var(--theme-ink); font-size: 0.92rem; font-weight: 600; }
.list-contents__name:hover { color: var(--theme-accent); text-decoration: none; }
.list-contents__isbn {
  align-self: flex-start;
  padding: 0.12rem 0.5rem;
  border-radius: var(--ui-radius-sm);
  background: var(--theme-accent-soft);
  color: var(--theme-ink-soft);
  font-weight: 700;
  font-size: 0.82rem;
  font-family: var(--theme-font-mono);
  letter-spacing: 0.04em;
}
.list-contents__remove { flex: none; margin: 0; }

.list-missing { margin-top: 1.5rem; }
.list-missing__lead { color: var(--theme-ink-muted); font-size: 0.9rem; margin: 0 0 0.75rem; }
.list-missing__items { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.4rem; }
.list-missing__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  border: 1px dashed var(--theme-border);
  border-radius: var(--ui-radius-sm);
}
.list-missing__item form { margin: 0; }
.list-missing__isbn { font-family: var(--theme-font-mono); font-size: 0.88rem; }

.list-buys__grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}
.list-buy-card {
  flex: 1 1 240px;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-sm);
  padding: 1rem 1.1rem;
  background: var(--theme-bg);
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.list-buy-card--best {
  border-color: var(--theme-accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--theme-accent) 12%, transparent);
}
.list-buy-card--cdl { border-style: dashed; }
/* La opción "comprar todo de una vez" destaca: la librería más barata ocupa
   todo el ancho como tarjeta-héroe; el resto fluyen en la rejilla debajo. */
.list-buys__grid .list-buy-card--best {
  flex-basis: 100%;
  background: color-mix(in srgb, var(--theme-accent) 6%, var(--theme-surface));
}
.list-buys__grid .list-buy-card--best .list-buy-card__total dd { font-size: 1.4rem; }
.list-buys__grid .list-buy-card--best .list-buy-card__cta { padding: 0.8rem 1.2rem; font-size: 1rem; }
.list-buy-card__head { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; }
.list-buy-card__swatch { display: inline-block; width: 0.85rem; height: 0.85rem; border-radius: var(--ui-radius-sm); }
.list-buy-card__logo { width: 22px; height: 22px; object-fit: contain; flex: none; border-radius: var(--ui-radius-sm); }
.list-buy-card__merchant { font-weight: 600; }
.list-buy-card__badge {
  background: var(--theme-accent);
  color: var(--theme-surface);
  border-radius: var(--ui-radius-pill);
  padding: 0.1rem 0.65rem;
  font-size: 0.66rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.list-buy-card__stats { margin: 0; display: grid; gap: 0.35rem 0.75rem; grid-template-columns: 1fr 1fr; }
.list-buy-card__stats > div { display: flex; flex-direction: column; }
.list-buy-card__stats dt {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--theme-ink-muted);
  margin: 0;
}
.list-buy-card__stats dd { margin: 0; font-weight: 600; font-family: var(--theme-font-heading); }
.list-buy-card__total dd { color: var(--theme-accent); font-size: 1.15rem; }
.list-buy-card__cta {
  display: inline-block;
  padding: 0.55rem 0.95rem;
  background: var(--theme-accent);
  color: var(--theme-surface);
  border-radius: var(--ui-radius-cta);
  font-weight: 600;
  font-size: 0.9rem;
  text-align: center;
}
.list-buy-card__cta:hover { filter: brightness(0.93); color: var(--theme-surface); text-decoration: none; }
.list-buy-card__missing { font-size: 0.85rem; color: var(--theme-ink-muted); }
.list-buy-card__missing summary { cursor: pointer; }
.list-buy-card__missing ul { margin: 0.4rem 0 0; padding-left: 1.25rem; }

/* Librerías sin cesta multi-ítem (Awin): el CTA es un <summary> que despliega
   los N libros, cada uno con su enlace afiliado. CSP-safe (sin JS). */
.list-buy-card__shop, .list-cdl-highlight__shop { display: flex; flex-direction: column; gap: 0.6rem; }
.list-buy-card__cta--shop { cursor: pointer; list-style: none; }
.list-buy-card__cta--shop::-webkit-details-marker { display: none; }
.list-cdl-highlight__shop > summary.list-cdl-highlight__cta { cursor: pointer; list-style: none; }
.list-cdl-highlight__shop > summary.list-cdl-highlight__cta::-webkit-details-marker { display: none; }
.list-buy-card__shop-note, .list-cdl-highlight__shop-note {
  font-size: 0.82rem;
  color: var(--theme-ink-muted);
  margin: 0;
}
.list-buy-card__items { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.45rem; }
.list-buy-card__item { display: flex; align-items: center; gap: 0.6rem; font-size: 0.9rem; }
.list-buy-card__item-title {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--theme-ink);
  font-weight: 500;
}
.list-buy-card__item-title:hover { color: var(--theme-accent); }
.list-buy-card__item-price { flex: none; font-family: var(--theme-font-heading); font-weight: 600; color: var(--theme-ink); }
.list-buy-card__item-buy {
  flex: none;
  padding: 0.35rem 0.8rem;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent);
  color: var(--theme-surface);
  font-size: 0.82rem;
  font-weight: 700;
}
.list-buy-card__item-buy:hover { filter: brightness(0.93); color: var(--theme-surface); text-decoration: none; }

.list-matrix__scroll { overflow-x: auto; }
.list-matrix__table { width: 100%; border-collapse: collapse; font-size: 0.92rem; }
.list-matrix__table th, .list-matrix__table td {
  padding: 0.55rem 0.75rem;
  border-bottom: 1px solid var(--theme-border);
  text-align: left;
}
.list-matrix__table thead th {
  background: var(--theme-bg);
  color: var(--theme-ink-muted);
  font-weight: 600;
  text-transform: uppercase;
  font-size: 0.7rem;
  letter-spacing: 0.06em;
}
.list-matrix__cell { font-family: var(--theme-font-heading); }
.list-matrix__cell--empty { color: var(--theme-ink-muted); }
.list-matrix__book { font-weight: 500; }

.list-items__grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}
.list-item {
  display: grid;
  gap: 0.75rem;
  grid-template-columns: 80px 1fr;
  padding: 0.85rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-sm);
  background: var(--theme-bg);
}
.list-item--pending { opacity: 0.7; }
.list-item__cover {
  width: 80px;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: var(--ui-radius-sm);
  background: var(--theme-surface-alt);
}
.list-item__cover--placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.75rem;
  color: var(--theme-ink-muted);
}
.list-item__title { margin: 0 0 0.2rem; font-size: 0.98rem; }
.list-item__authors, .list-item__isbn { margin: 0; color: var(--theme-ink-muted); font-size: 0.82rem; }
.list-item__offers { list-style: none; margin: 0.5rem 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.2rem; }
.list-item__offer { display: flex; gap: 0.5rem; align-items: center; font-size: 0.85rem; }
.list-item__offer-merchant { color: var(--theme-ink-soft); }
.list-item__offer-price { font-family: var(--theme-font-heading); font-weight: 600; margin-left: auto; }
/* Era un «Ir» en texto plano de 0,82rem: el enlace más débil del sitio estaba
   justo donde ocurre la conversión, con menos peso visual que el precio que
   tiene al lado. Pasa a botón compacto — no puede crecer más porque hay hasta
   cuatro por libro y la fila es estrecha en móvil. */
.list-item__offer-link {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.3rem 0.7rem;
  border: 1px solid var(--theme-accent);
  border-radius: var(--ui-radius-pill);
  color: var(--theme-accent);
  background: transparent;
  font-size: 0.82rem;
  font-weight: 700;
  line-height: 1.2;
  text-decoration: none;
  transition: background-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}

.list-item__offer-link::after {
  content: '›';
  font-size: 1.05em;
  line-height: 1;
}

.list-item__offer-link:hover,
.list-item__offer-link:focus-visible {
  background: var(--theme-accent);
  color: #fff;
  text-decoration: none;
  box-shadow: 0 2px 8px color-mix(in srgb, var(--theme-accent) 30%, transparent);
}
.list-item__empty { color: var(--theme-ink-muted); font-size: 0.85rem; margin: 0.4rem 0 0; }

/* ------------------------- Best price card (ISBN) ----------------------- */

.best-price-card {
  background: var(--theme-surface-alt);
  border: 1px solid var(--theme-accent);
  border-radius: var(--ui-radius-lg);
  padding: 1.25rem;
  margin-top: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--theme-accent) 10%, transparent);
}
.best-price-card__label {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--theme-ink-muted);
}
.best-price-card__price {
  font-family: var(--theme-font-heading);
  font-size: 2.25rem;
  font-weight: 700;
  letter-spacing: -0.025em;
  color: var(--theme-accent);
  margin: 0;
}
.best-price-card__merchant { color: var(--theme-ink-soft); font-size: 0.95rem; margin: 0; }
.best-price-card__savings {
  margin: 0;
  font-size: 0.88rem;
  color: color-mix(in srgb, var(--theme-success) 78%, #000 22%);
  font-weight: 600;
}
.best-price-card__savings strong { font-weight: 800; }
.best-price-card__cta {
  margin-top: 0.5rem;
  padding: 0.7rem 1rem;
  background: var(--theme-accent);
  color: var(--theme-surface);
  text-align: center;
  border-radius: var(--ui-radius-cta);
  font-weight: 600;
}
.best-price-card__cta:hover { filter: brightness(0.93); color: var(--theme-surface); text-decoration: none; }
.best-price-card__foot { margin: 0; text-align: center; font-size: 0.82rem; }
.best-price-card__foot a { color: var(--theme-ink-soft); }
.best-price-card__foot a:hover { color: var(--theme-accent); }
.best-price-card--empty { border-color: var(--theme-border); box-shadow: none; }
.best-price-card--empty .best-price-card__merchant { color: var(--theme-ink-muted); }

/* =========================================================================
   CAPA UI "PRO" — componentes reutilizables (eyebrow, section-head, botones
   pill, chips, banda de estadísticas, hero-pill, landing del comparador).
   Inspirada en el directorio de gasolineras pero construida sobre los tokens
   `--theme-*` del proyecto. Es transversal a todos los presets; la capa
   `body.theme-confeti` de más abajo la refina para el look azul por defecto.
   ========================================================================= */

/* Eyebrow: etiqueta superior en mayúsculas con tracking amplio. */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--theme-font-body);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--theme-accent);
}

/* Section head: eyebrow + título + (opcional) descripción + CTA a la derecha. */
.section-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.5rem;
  flex-wrap: wrap;
  margin: 0 0 1.5rem;
}
.section-head__text { min-width: 0; }
.section-head__title {
  font-family: var(--theme-font-heading);
  font-weight: 700;
  font-size: clamp(1.5rem, 3vw, 2rem);
  line-height: 1.1;
  letter-spacing: -0.02em;
  margin: 0.35rem 0 0;
  color: var(--theme-ink);
}
.section-head__title em { font-style: normal; color: var(--theme-accent); }
.section-head__desc {
  margin: 0.6rem 0 0;
  color: var(--theme-ink-soft);
  font-size: 0.98rem;
  max-width: 42rem;
  line-height: 1.55;
}
.section-head--center { justify-content: center; text-align: center; }
.section-head--center .section-head__text { display: flex; flex-direction: column; align-items: center; }
.section-head--center .section-head__desc { margin-inline: auto; }

/* Botones pill (estilo directorio). */
.btn-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.72rem 1.4rem;
  border-radius: var(--ui-radius-pill);
  font-family: var(--theme-font-body);
  font-weight: 700;
  font-size: 0.95rem;
  line-height: 1.2;
  cursor: pointer;
  text-decoration: none;
  border: 1.5px solid transparent;
  transition: transform 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.btn-pill svg { width: 1.05em; height: 1.05em; }
.btn-pill--accent {
  background: var(--theme-accent);
  color: #fff;
  box-shadow: var(--ui-shadow-accent);
}
.btn-pill--accent:hover,
.btn-pill--accent:focus {
  color: #fff;
  text-decoration: none;
  transform: translateY(-1px);
  box-shadow: 0 16px 38px color-mix(in srgb, var(--theme-accent) 38%, transparent);
}
.btn-pill--outline {
  background: var(--theme-surface);
  color: var(--theme-ink);
  border-color: var(--theme-border);
  box-shadow: var(--ui-shadow-sm);
}
.btn-pill--outline:hover,
.btn-pill--outline:focus {
  color: var(--theme-accent);
  border-color: var(--theme-accent);
  text-decoration: none;
  transform: translateY(-1px);
}
.btn-pill--ghost-light {
  background: rgba(255, 255, 255, 0.16);
  color: #fff;
  border-color: rgba(255, 255, 255, 0.32);
  backdrop-filter: blur(4px);
}
.btn-pill--ghost-light:hover,
.btn-pill--ghost-light:focus {
  background: rgba(255, 255, 255, 0.26);
  color: #fff;
  text-decoration: none;
}

/* Chips / pills informativas pequeñas. */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.25rem 0.7rem;
  border-radius: var(--ui-radius-pill);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  background: var(--theme-surface-alt);
  color: var(--theme-ink-soft);
  border: 1px solid var(--theme-border);
}
.chip--accent { background: var(--theme-accent-soft); color: var(--theme-accent); border-color: transparent; }
.chip--success { background: color-mix(in srgb, var(--theme-success) 14%, #fff); color: var(--theme-success); border-color: transparent; }

/* Banda oscura de estadísticas (números clave) — equivalente al "averages
   strip" del directorio. */
.stats-band {
  position: relative;
  overflow: hidden;
  background: var(--theme-ink);
  color: #fff;
  border-radius: var(--ui-radius-xl);
  padding: 1.6rem 1.75rem;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 1.25rem;
}
.stats-band::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: radial-gradient(circle, rgba(255, 255, 255, 0.06) 1px, transparent 1px);
  background-size: 20px 20px;
  pointer-events: none;
}
.stats-band__item { position: relative; display: flex; flex-direction: column; gap: 0.25rem; }
.stats-band__value {
  font-family: var(--theme-font-heading);
  font-weight: 800;
  font-size: 1.7rem;
  line-height: 1.05;
  letter-spacing: -0.02em;
}
.stats-band__label {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.62);
}
.stats-band__meta { font-size: 0.78rem; color: rgba(255, 255, 255, 0.5); }

/* =========================================================================
   COMPARADOR DE LISTA — landing `/comparar`.
   El textarea es el protagonista: hero amplio, tarjeta blanca elevada.
   ========================================================================= */
.compare-landing {
  margin: 0;
}
.compare-landing__eyebrow {
  display: flex;
  justify-content: center;
  margin-bottom: 0.85rem;
}
.compare-landing__title {
  font-family: var(--theme-font-heading);
  font-weight: 600;
  font-size: clamp(1.8rem, 4.5vw, 2.9rem);
  line-height: 1.06;
  letter-spacing: -0.025em;
  margin: 0 0 0.6rem;
  text-align: center;
}
.compare-landing__lead {
  text-align: center;
  font-size: clamp(1rem, 1.6vw, 1.2rem);
  color: var(--theme-ink-soft);
  max-width: 46rem;
  margin: 0 auto 1.75rem;
}
.compare-landing__error {
  max-width: 44rem;
  margin: 0 auto 1.25rem;
  padding: 0.85rem 1.1rem;
  border-radius: var(--ui-radius-md);
  background: color-mix(in srgb, var(--theme-danger) 10%, #fff);
  border: 1px solid color-mix(in srgb, var(--theme-danger) 35%, transparent);
  color: var(--theme-danger);
  font-weight: 600;
  text-align: center;
}
/* Confirmación de «Crear otra lista» (?nueva=1): mismo hueco que el error, pero
   en verde de «hecho», no en rojo de «algo va mal». */
.compare-landing__fresh {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  max-width: 44rem;
  margin: 0 auto 1.25rem;
  padding: 0.75rem 1.1rem;
  border-radius: var(--ui-radius-md);
  background: color-mix(in srgb, var(--theme-success, var(--theme-success)) 10%, #fff);
  border: 1px solid color-mix(in srgb, var(--theme-success, var(--theme-success)) 32%, transparent);
  color: color-mix(in srgb, var(--theme-success, var(--theme-success)) 78%, #000);
  font-size: 0.92rem;
  text-align: left;
}
.compare-landing__fresh svg { flex: none; }
.compare-card {
  max-width: 48rem;
  margin: 0 auto;
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-xl);
  box-shadow: var(--ui-shadow-lg);
  padding: clamp(1.25rem, 3vw, 2rem);
}
.compare-card__steps {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
  margin: 0 0 1.1rem;
  padding: 0;
  list-style: none;
  font-size: 0.85rem;
  color: var(--theme-ink-muted);
}
.compare-card__steps li { display: inline-flex; align-items: center; gap: 0.4rem; }
.compare-card__steps b {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.35rem;
  height: 1.35rem;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent-soft);
  color: var(--theme-accent);
  font-size: 0.75rem;
  font-weight: 800;
}
.compare-form { display: flex; flex-direction: column; gap: 0.9rem; }
.compare-form__label {
  font-size: 0.92rem;
  color: var(--theme-ink-soft);
  line-height: 1.5;
}
.compare-form__textarea {
  width: 100%;
  min-height: 190px;
  resize: vertical;
  padding: 1rem 1.1rem;
  border: 1.5px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  background: var(--theme-bg);
  color: var(--theme-ink);
  font-family: var(--theme-font-mono);
  font-size: 0.98rem;
  line-height: 1.7;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
/* En la HOME la caja nace pequeña; en /comparar se queda alta.
   Son dos momentos distintos: a /comparar se llega con la lista ya copiada y
   una caja grande invita a pegarla, pero en la home el visitante todavía está
   entendiendo qué es esto, y 190 px de textarea vacío empujaban la franja de
   librerías y las categorías fuera del viewport (medido a 1512x795).
   `field-sizing: content` la hace crecer al escribir donde está soportado; el
   `min-height` es el suelo para el resto. */
.hero .compare-form__textarea {
  min-height: 96px;
  field-sizing: content;
}

.compare-form__textarea::placeholder { color: var(--theme-ink-muted); }
.compare-form__textarea:focus {
  outline: none;
  border-color: var(--theme-accent);
  box-shadow: 0 0 0 4px var(--ui-accent-ring);
}
.compare-form__submit {
  align-self: stretch;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  padding: 0.95rem 1.6rem;
  border: 0;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent);
  color: #fff;
  font-family: var(--theme-font-body);
  font-weight: 700;
  font-size: 1.05rem;
  cursor: pointer;
  box-shadow: var(--ui-shadow-accent);
  transition: transform 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease;
}
.compare-form__submit-icon { width: 1.2rem; height: 1.2rem; flex-shrink: 0; }
.compare-form__submit:hover {
  transform: translateY(-1px);
  box-shadow: 0 16px 38px color-mix(in srgb, var(--theme-accent) 38%, transparent);
}
.compare-landing__alt {
  text-align: center;
  margin: 1.5rem auto 0;
  color: var(--theme-ink-soft);
  font-size: 0.95rem;
}

/* Banda «te lo hacemos nosotros» bajo el comparador del hero. Translúcida sobre
   la banda azul: tiene que verse sin competir con la tarjeta blanca, que es la
   acción principal. Una sola línea en escritorio para no deshacer lo que se
   ganó al compactar el hero. */
.hero-handoff {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.9rem;
  flex-wrap: wrap;
  max-width: 48rem;
  margin: 1.1rem auto 0;
  padding: 0.7rem 1rem;
  border-radius: var(--ui-radius-lg);
  background: var(--theme-surface-alt);
  border: 1px solid var(--theme-border);
  text-align: left;
}
.hero-handoff__icon { width: 1.5rem; height: 1.5rem; flex: none; color: var(--theme-accent); }
/* Encogible: sin esto el bloque de texto pide su ancho natural, no cabe con el
   icono y el botón, y el botón se cae a una segunda fila. */
.hero-handoff__text { flex: 1 1 14rem; margin: 0; font-size: 0.92rem; line-height: 1.4; color: var(--theme-ink-soft); }
.hero-handoff__text strong { display: block; color: var(--theme-ink); font-size: 0.98rem; }
.hero-handoff__cta {
  flex: none;
  padding: 0.5rem 1.1rem;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent);
  color: var(--theme-surface);
  font-weight: 700;
  font-size: 0.92rem;
  white-space: nowrap;
}
.hero-handoff__cta:hover { filter: brightness(0.93); color: var(--theme-surface); text-decoration: none; }
@media (max-width: 719px) {
  .hero-handoff { flex-direction: column; text-align: center; gap: 0.6rem; padding: 0.9rem; }
  /* El eje principal pasa a ser vertical, así que aquel `flex-basis: 14rem` del
     texto deja de ser ancho y se convierte en ALTURA: la banda se iba a 336 px.
     En columna cada hijo ocupa lo que ocupa. */
  .hero-handoff__text { flex: 0 1 auto; }
  .hero-handoff__cta { width: 100%; text-align: center; }
}

/* Tira de confianza / "trust" debajo de un hero o landing. */
.trust-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.6rem 1.4rem;
  margin: 1.5rem auto 0;
  padding: 0;
  list-style: none;
  max-width: 52rem;
}
.trust-row li {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-size: 0.88rem;
  color: var(--theme-ink-soft);
  font-weight: 600;
}
.trust-row svg { width: 1.05rem; height: 1.05rem; color: var(--theme-accent); flex-shrink: 0; }

/* MÓVIL: tres columnas, no tres filas. Apiladas se comían media pantalla del
   hero, que es donde está el formulario. En columnas con el ✓ encima ocupan un
   tercio y se leen como argumentos en vez de como tres botones que no lo son. */
@media (max-width: 719px) {
  .trust-row {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.5rem;
    align-items: start;
  }
  .trust-row li {
    flex-direction: column;
    gap: 0.3rem;
    text-align: center;
    font-size: 0.74rem;
    line-height: 1.25;
  }
}

/* =========================================================================
   Página "Cómo funciona" (/como-funciona): hero centrado + 4 pasos + CTA.
   ========================================================================= */
/* Botón blanco para usar sobre fondos de marca (hero/CTA azules). */
.btn-pill--light {
  background: #fff;
  color: var(--theme-accent);
  box-shadow: 0 10px 28px rgba(8, 30, 60, 0.22);
}
.btn-pill--light:hover,
.btn-pill--light:focus {
  color: var(--theme-accent);
  text-decoration: none;
  transform: translateY(-1px);
  box-shadow: 0 14px 34px rgba(8, 30, 60, 0.28);
}

/* Hero con degradado de marca (mismo lenguaje que el hero de la home). */
.howto-hero {
  text-align: center;
  margin-top: 0.5rem;
  padding: clamp(2.5rem, 6vw, 4rem) clamp(1.25rem, 4vw, 2.5rem);
  background: var(--pl-hero, linear-gradient(135deg, color-mix(in srgb, var(--theme-accent) 82%, #fff) 0%, var(--theme-accent) 52%, var(--ui-accent-strong) 100%));
  border-radius: var(--ui-radius-xl);
  color: #fff;
  box-shadow: var(--ui-shadow);
}
.howto-hero__eyebrow {
  display: inline-block;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.88);
  padding: 0.32rem 0.9rem;
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: var(--ui-radius-pill);
}
.howto-hero__title {
  font-family: var(--theme-font-heading);
  font-weight: 600;
  font-size: clamp(1.8rem, 4.5vw, 2.9rem);
  line-height: 1.12;
  letter-spacing: -0.02em;
  margin: 1rem auto 0.9rem;
  max-width: 22ch;
  color: #fff;
}
.howto-hero__lead {
  font-size: clamp(1.02rem, 1.7vw, 1.18rem);
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.92);
  margin: 0 auto;
  max-width: 44rem;
}
.howto-hero__actions { margin-top: 1.6rem; }

/* Los pasos iban en CUATRO COLUMNAS estrechas. Para el publico de esta pagina
   —gente que no usa comparadores— eso es lo contrario de claro: cuatro cajas en
   paralelo se leen como cuatro opciones, no como una secuencia, y obligan a
   apretar el texto. En una sola columna se lee como lo que es, «primero esto,
   luego esto», y cabe explicar cada paso sin telegrafiar. */
.howto-steps {
  list-style: none;
  margin: clamp(2rem, 5vw, 3.25rem) auto;
  padding: 0;
  display: grid;
  gap: 1.25rem;
  /* UNA tarjeta por fila. El 2x2 que probé antes dejaba huecos por
     construcción: los pasos miden 608, 278, 278 y 389 px de alto, así que al
     emparejarlos siempre quedaba media fila vacía al lado del corto. Sin vecina
     no hay hueco posible; el ancho se aprovecha DENTRO de cada tarjeta, con el
     reparto en bandas de abajo. */
  grid-template-columns: 1fr;
}
/* Tres bandas: [título] [explicación] [lo que verás]. Así una tarjeta de ancho
   completo no deja el texto colgando a la izquierda con 800 px de blanco a la
   derecha, y de paso cada banda vuelve a una medida de lectura sana (~650 px la
   del cuerpo). Lo que ocupa dos columnas —las tres formas del paso 1, el aviso
   del paso 4— se declara abajo con `grid-column`. */
.howto-step {
  position: relative;
  display: grid;
  grid-template-columns: minmax(11rem, 1fr) 1.7fr 1.1fr;
  column-gap: clamp(1.25rem, 2.5vw, 2.25rem);
  row-gap: 0.7rem;
  align-items: start;
  padding: 2rem 1.5rem 1.6rem;
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-xl);
  box-shadow: var(--ui-shadow-sm);
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.howto-step:hover {
  transform: translateY(-3px);
  box-shadow: var(--ui-shadow);
  border-color: color-mix(in srgb, var(--theme-accent) 30%, var(--theme-border));
}
.howto-step__num {
  position: absolute;
  top: -0.9rem;
  left: 1.35rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent);
  color: #fff;
  font-weight: 800;
  font-size: 1rem;
  box-shadow: var(--ui-shadow-accent);
}
/* Los iconos abstractos (un codigo de barras, una balanza, un cubo 3D) se han
   quitado del marcado: no ilustraban nada que el titulo no dijera mejor, y en
   una columna unica ocupaban el sitio del texto que si hace falta. */
/* La ilustración encabeza la banda del título; la explicación y «lo que verás»
   pasan a ocupar las dos filas para que no queden huecos a su derecha. */
.howto-step .step-art {
  grid-column: 1;
  grid-row: 1;
  width: 112px;
  height: 84px;
  margin-bottom: 0.2rem;
}
.howto-step__title {
  grid-column: 1;
  grid-row: 2;
  font-family: var(--theme-font-heading);
  font-size: 1.22rem;
  font-weight: 700;
  line-height: 1.25;
  margin: 0.3rem 0 0;
  color: var(--theme-ink);
}
.howto-step__body {
  grid-column: 2;
  grid-row: 1 / span 2;
  margin: 0;
  /* 1.02rem y no 0.94: buena parte de quien llega a esta pagina lee con gafas.
     Es la razon por la que existe la pagina; la tipografia va a juego. */
  font-size: 1.02rem;
  line-height: 1.65;
  color: var(--theme-ink-soft);
}
/* Las tres formas de empezar el paso 1. Cada una con su titular en negro para
   que se vea que son ALTERNATIVAS, no tres cosas que hay que hacer. */
.howto-step__ways {
  /* De borde a borde de la tarjeta, no sólo las bandas de la derecha: al pasar
     de 3 cajas de 330 px a 3 de 440 el texto cabe en menos líneas y la altura
     de cada caja baja de 247 a 174 px —justo lo que mide su texto—, así que
     desaparece el hueco que quedaba dentro de las dos cortas. Y de paso llena
     el blanco que quedaba bajo el título, en la banda izquierda. */
  grid-column: 1 / -1;
  list-style: none;
  margin: 0.2rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.7rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  /* Cada caja hasta donde llega su texto. A ancho completo las tres miden ya lo
     mismo, pero en los anchos intermedios la tercera se alarga y con el
     estirado por defecto las otras dos heredaban su altura y se quedaban con un
     blanco dentro. */
  align-items: start;
}
.howto-step__ways li {
  padding: 0.75rem 0.9rem;
  background: var(--theme-surface-alt);
  border-radius: var(--ui-radius-lg);
  font-size: 0.99rem;
  line-height: 1.55;
  color: var(--theme-ink-soft);
}
.howto-step__ways strong {
  display: block;
  color: var(--theme-ink);
  margin-bottom: 0.15rem;
}
/* «Lo que veras»: la frase que le dice a la persona que lo que le ha salido en
   pantalla es lo correcto. Es lo que quita la duda de «me he equivocado». */
.howto-step__see {
  /* En su propia banda a la derecha: el separador deja de ser una línea de
     puntos arriba y pasa a serlo a la izquierda, que es por donde ahora limita
     con la explicación. */
  grid-column: 3;
  grid-row: 1 / span 2;
  margin: 0.3rem 0 0;
  padding: 0 0 0 clamp(1rem, 2vw, 1.5rem);
  border-left: 1px dashed var(--theme-border);
  font-size: 0.96rem;
  line-height: 1.55;
  color: var(--theme-ink-soft);
}
.howto-step__see span {
  display: inline-block;
  margin-right: 0.4rem;
  font-weight: 700;
  color: var(--theme-accent);
}
.howto-step__warn {
  grid-column: 2 / -1;
  margin: 0.3rem 0 0;
  padding: 0.75rem 0.9rem;
  border-left: 3px solid var(--theme-accent);
  background: var(--theme-accent-soft);
  border-radius: 0 var(--ui-radius) var(--ui-radius) 0;
  font-size: 0.98rem;
  line-height: 1.55;
  color: var(--theme-ink);
}

/* Por debajo de 900 px las tres bandas no caben sin estrangular el texto: cada
   paso vuelve a ser una columna y «lo que verás» recupera su línea de puntos
   arriba, que es donde vuelve a separar. */
@media (max-width: 899px) {
  .howto-step { grid-template-columns: 1fr; }
  .howto-step .step-art,
  .howto-step__title,
  .howto-step__body,
  .howto-step__ways,
  .howto-step__warn,
  .howto-step__see {
    grid-column: 1;
    grid-row: auto;
  }
  .howto-step__see {
    grid-row: auto;
    padding: 0.7rem 0 0;
    border-left: 0;
    border-top: 1px dashed var(--theme-border);
  }
}

/* Bloque «que es esta web», antes de los pasos. Responde el miedo de fondo
   («¿que me vais a cobrar y a quien le compro?») antes de explicar nada. */
.howto-what {
  margin: clamp(1.5rem, 4vw, 2.25rem) auto 0;
  padding: 1.5rem 1.6rem;
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-top: 4px solid var(--theme-accent);
  border-radius: var(--ui-radius-xl);
}
.howto-what__title {
  margin: 0 0 0.9rem;
  font-family: var(--theme-font-heading);
  font-size: 1.15rem;
}
/* Los tres puntos en columnas al ensanchar la caja: apilados a 1.392 px de
   ancho serían tres renglones larguísimos con un hueco enorme debajo. */
.howto-what__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.85rem 1.6rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 19rem), 1fr));
}
.howto-what__list li {
  font-size: 1.02rem;
  line-height: 1.6;
  color: var(--theme-ink-soft);
}
.howto-what__list strong { color: var(--theme-ink); }

/* Salida para quien ha leido todo y sigue sin verlo claro. Mandarle otra vez a
   la herramienta no le sirve: aqui se le ofrece que lo hagamos nosotros. */
.howto-help {
  margin: clamp(1.5rem, 4vw, 2.25rem) auto clamp(2rem, 5vw, 3rem);
  padding: 1.4rem 1.6rem;
  background: var(--theme-surface-alt);
  border-radius: var(--ui-radius-xl);
  text-align: center;
}
.howto-help__title { margin: 0 0 0.5rem; font-family: var(--theme-font-heading); font-size: 1.1rem; }
.howto-help__body { margin: 0 0 1rem; font-size: 1rem; line-height: 1.6; color: var(--theme-ink-soft); }
.howto-help__actions {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
  justify-content: center;
}
.howto-help__link {
  font-weight: 700;
  color: var(--theme-accent);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.howto-help__link--soft { font-weight: 500; color: var(--theme-ink-soft); }

.howto-benefits {
  list-style: none;
  margin: clamp(2rem, 5vw, 3rem) 0;
  padding: 0;
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(4, 1fr);
}
@media (max-width: 760px) { .howto-benefits { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 420px) { .howto-benefits { grid-template-columns: 1fr; } }
.howto-benefit {
  display: flex;
  align-items: flex-start;
  gap: 0.7rem;
  padding: 1rem 1.1rem;
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
}
.howto-benefit svg {
  flex: none;
  width: 1.4rem;
  height: 1.4rem;
  color: var(--theme-accent);
  margin-top: 0.1rem;
}
/* 0.92rem y no 0.85 (~13,6 px): esta pagina existe para quien se maneja peor
   con internet, que suele coincidir con quien lee con gafas. */
.howto-benefit span { display: flex; flex-direction: column; font-size: 0.92rem; line-height: 1.45; color: var(--theme-ink-soft); }
.howto-benefit strong { color: var(--theme-ink); font-size: 0.95rem; margin-bottom: 0.1rem; }

.howto-cta {
  text-align: center;
  margin: clamp(1.5rem, 4vw, 2.5rem) 0 0;
  padding: clamp(2rem, 5vw, 3rem) clamp(1.25rem, 4vw, 2.5rem);
  background: var(--pl-hero, linear-gradient(135deg, color-mix(in srgb, var(--theme-accent) 82%, #fff) 0%, var(--theme-accent) 52%, var(--ui-accent-strong) 100%));
  border-radius: var(--ui-radius-xl);
  color: #fff;
  box-shadow: var(--ui-shadow);
}
.howto-cta__title {
  font-family: var(--theme-font-heading);
  font-weight: 800;
  font-size: clamp(1.4rem, 3vw, 2rem);
  line-height: 1.2;
  margin: 0 0 0.7rem;
  color: #fff;
}
.howto-cta__lead {
  margin: 0 auto 1.4rem;
  max-width: 38rem;
  font-size: 1.02rem;
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.92);
}
.howto-cta__note {
  margin: 1rem 0 0;
  font-size: 0.9rem;
  color: rgba(255, 255, 255, 0.8);
}

/* =========================================================================
   HOME — bloque destacado del comparador de lista (función estrella) y
   variantes visuales de la home.
   ========================================================================= */
.home-compare {
  position: relative;
  overflow: hidden;
  margin: 2.5rem 0;
  padding: clamp(1.75rem, 4vw, 2.75rem);
  border-radius: var(--ui-radius-xl);
  background: var(--theme-ink);
  color: #fff;
  display: grid;
  gap: 1.5rem 2.5rem;
  grid-template-columns: 1fr;
  align-items: center;
}
@media (min-width: 860px) {
  .home-compare { grid-template-columns: 1.1fr 0.9fr; }
}
.home-compare::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: radial-gradient(circle, rgba(255, 255, 255, 0.06) 1px, transparent 1px);
  background-size: 22px 22px;
  pointer-events: none;
}
.home-compare__body { position: relative; }
/* Píldora verde en vez de versalitas sueltas (14-ago-2026): sobre el navy, un
   antetítulo en blanco al 85% se leía como un pie de foto —lo mismo que el
   resto del texto, sólo que más pequeño— y no destacaba el bloque, que es lo
   único que hace ahí. El verde es el único color cálido de la paleta que no
   compite con el azul de marca ni con el blanco del CTA principal, y la
   caja-píldora le da el peso que la versalita no tenía.
   `text-transform: none` a propósito: en píldora, las mayúsculas forzadas
   apretaban el texto contra los bordes y perdían legibilidad a 0,72rem. */
.home-compare__eyebrow {
  padding: 0.35rem 0.95rem;
  border-radius: var(--ui-radius-pill);
  background: #2ecf90;
  color: #0c3448;
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: 0;
  text-transform: none;
  opacity: 1;
}
.home-compare__title {
  font-family: var(--theme-font-heading);
  font-weight: 800;
  font-size: clamp(1.55rem, 3vw, 2.2rem);
  line-height: 1.1;
  letter-spacing: -0.02em;
  margin: 0.5rem 0 0.6rem;
  color: #fff;
}
.home-compare__title em {
  font-style: normal;
  color: #fff;
  text-decoration: underline;
  text-decoration-color: rgba(255, 255, 255, 0.5);
  text-underline-offset: 5px;
  text-decoration-thickness: 3px;
}
.home-compare__lead {
  margin: 0 0 1.25rem;
  color: rgba(255, 255, 255, 0.86);
  font-size: 1.02rem;
  line-height: 1.6;
  max-width: 32rem;
}
.home-compare__actions { display: flex; flex-wrap: wrap; gap: 0.7rem; }
.home-compare__visual {
  position: relative;
  background: var(--theme-surface);
  color: var(--theme-ink);
  border-radius: var(--ui-radius-lg);
  padding: 1.1rem 1.2rem;
  box-shadow: var(--ui-shadow-lg);
}
.home-compare__visual-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--theme-ink-muted);
}
.home-compare__dot { width: 0.6rem; height: 0.6rem; border-radius: var(--ui-radius-pill); background: var(--theme-accent); }
.home-compare__line {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.55rem 0;
  border-bottom: 1px solid var(--theme-border);
  font-size: 0.92rem;
}
.home-compare__line:last-child { border-bottom: 0; }
.home-compare__isbn { font-family: var(--theme-font-mono); color: var(--theme-ink-soft); }
.home-compare__price { font-family: var(--theme-font-mono); font-weight: 700; color: var(--theme-accent); }
.home-compare__best {
  margin-top: 0.85rem;
  padding-top: 0.85rem;
  border-top: 2px solid var(--theme-border);
  display: flex;
  align-items: baseline;
  justify-content: space-between;
}
.home-compare__best-label { font-size: 0.78rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--theme-ink-muted); }
.home-compare__best-value { font-family: var(--theme-font-mono); font-weight: 800; font-size: 1.4rem; color: var(--theme-ink); letter-spacing: -0.02em; }

/* =========================================================================
   HOME — hero "comparador": el comparador completo (pestañas + textarea) como
   protagonista del hero. Reutiliza .compare-card y el componente .ctabs__*
   (con ids `hmode-*`). Transversal a todos los presets; planeta lo refina.
   ========================================================================= */
.hero--compare { text-align: center; }
.hero__head { margin: 0 0 1.6rem; }
.hero__head .hero__title { margin-bottom: 0.6rem; }
.hero__head .hero__lead { margin-bottom: 0; }
.hero__head .hero__free { margin-top: 0.95rem; }

/* La tarjeta blanca del comparador centrada dentro del hero. `position` + `z-index`
   crean un contexto de apilado por ENCIMA de las secciones que siguen al hero
   (home-vprops, franja de librerías): sin esto el desplegable del buscador en
   vivo (position:absolute) quedaba tapado por esas secciones al desplegarse. */
.hero-compare-card {
  max-width: 44rem;
  text-align: left;
  position: relative;
  z-index: 40;
}
.hero-compare-card__pretitle {
  margin: 0 0 0.7rem;
  text-align: center;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--theme-ink-muted);
}

/* Explicación plegable "¿No sabes qué es el ISBN?" (sin JS). */
/* "¿Qué es el ISBN?" — modal CSS-only (checkbox-hack, sin JS por la CSP).
   El checkbox oculto controla la visibilidad del overlay vía `:checked ~`. */
.isbn-help__toggle {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  opacity: 0;
  pointer-events: none;
}
.isbn-help__link {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0 0 0.9rem;
  width: fit-content;
  cursor: pointer;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--theme-accent);
}
.isbn-help__link-icon { width: 1.05rem; height: 1.05rem; flex-shrink: 0; }
.isbn-help__link:hover { text-decoration: underline; }
.isbn-help__overlay {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 200;
  align-items: center;
  justify-content: center;
  padding: 1.25rem;
}
.isbn-help__toggle:checked ~ .isbn-help__overlay { display: flex; }
.isbn-help__backdrop {
  position: absolute;
  inset: 0;
  border: 0;
  background: rgba(8, 30, 60, 0.55);
  cursor: pointer;
}
.isbn-help__dialog {
  position: relative;
  width: min(30rem, 100%);
  padding: 1.7rem 1.5rem 1.5rem;
  background: var(--theme-surface);
  border-radius: var(--ui-radius-md);
  box-shadow: var(--ui-shadow-lg);
  animation: isbn-help-in 0.16s ease-out;
}
@keyframes isbn-help-in {
  from { opacity: 0; transform: translateY(8px) scale(0.98); }
  to { opacity: 1; transform: none; }
}
.isbn-help__close {
  position: absolute;
  top: 0.6rem;
  right: 0.6rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: var(--ui-radius-pill);
  color: var(--theme-ink-soft);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.isbn-help__close svg { width: 1.1rem; height: 1.1rem; }
.isbn-help__close:hover { background: var(--theme-surface-alt); color: var(--theme-ink); }
.isbn-help__title {
  margin: 0 1.8rem 0.55rem 0;
  font-family: var(--theme-font-heading);
  font-weight: 600;
  font-size: 1.2rem;
  color: var(--theme-ink);
}
.isbn-help__text {
  margin: 0;
  color: var(--theme-ink-soft);
  font-size: 0.95rem;
  line-height: 1.6;
}
/* Dibujo de la contraportada con el código de barras. Tamaño contenido: el
   diálogo tiene que caber entero en un móvil sin scroll interno. */
.isbn-help__figure { margin: 0.9rem 0; text-align: center; }
.isbn-help__art { display: block; width: 100%; max-width: 17rem; height: auto; margin: 0 auto; }
.isbn-help__caption {
  margin-top: 0.4rem;
  color: var(--theme-ink-muted);
  font-size: 0.82rem;
}
.isbn-help__art .ih-cover {
  fill: var(--theme-surface);
  stroke: var(--theme-border);
  stroke-width: 2;
}
.isbn-help__art .ih-spine { fill: var(--theme-accent-soft); }
.isbn-help__art .ih-line { fill: var(--theme-border); }
.isbn-help__art .ih-line-soft {
  fill: var(--theme-surface-alt);
  fill: color-mix(in srgb, var(--theme-border) 55%, #fff);
}
.isbn-help__art .ih-box {
  fill: #fff;
  stroke: var(--theme-accent);
  stroke-width: 2;
}
.isbn-help__art .ih-bar rect { fill: var(--theme-ink); }
.isbn-help__art .ih-code {
  fill: var(--theme-ink);
  font-family: var(--theme-font-mono);
  font-size: 11px;
  font-weight: 600;
}

/* =========================================================================
   Tema "Planeta" — look inspirado en planetadelibros.com: blanco, Montserrat,
   azul editorial (var(--theme-accent)), footer azul marino, bandas azules a sangre,
   tarjetas limpias centradas en la portada. Capa ADITIVA scopeada a
   `body.theme-confeti`: no afecta a los presets cuaderno/ticker/patio.
   ========================================================================= */
body.theme-confeti {
  /* Antes #16284b/#20335c: un navy violáceo que no pertenecía a la paleta y
     sólo aparecía en este bloque. Ahora es un tono OSCURO del azul de marca
     (var(--theme-accent)), así que unifica sin renunciar al contraste — si fuera el mismo
     azul del hero, la página sería una plancha azul sin jerarquía. */
  /* Fondo de las bandas oscuras (bloque «por qué comparar», CTA de cierre y
     pie). NO es un tono oscuro del acento, y es deliberado: el hero ya es una
     plancha roja a sangre, y repetir el mismo color en las otras tres bandas
     dejaría la página sin jerarquía —todo grita igual—. Sale del `ink` del
     tema, que es el morado oscuro de la paleta, así que contrasta con el rojo
     sin traer un color de fuera. Sigue al preset: cambiar el tema desde el
     admin mueve también estas bandas. */
  --pl-navy: color-mix(in srgb, var(--theme-ink) 94%, #000);
  --pl-navy-2: color-mix(in srgb, var(--theme-ink) 76%, var(--theme-accent));
  --pl-accent-strong: var(--ui-accent-strong);
  --pl-hero: linear-gradient(135deg, color-mix(in srgb, var(--theme-accent) 82%, #fff) 0%, var(--theme-accent) 52%, var(--ui-accent-strong) 100%);
  /* El fondo sale del TOKEN, no de un hex. Estuvo a fuego en #ffffff y eso
     convertía en decorativo el fondo elegido en /admin/apariencia: se cambiaba
     el preset y la página seguía blanca (regla del CLAUDE.md sobre literales de
     color en componentes). */
  background: var(--theme-bg);
  overflow-x: clip;
  font-weight: 400;
}
body.theme-confeti h1, body.theme-confeti h2, body.theme-confeti h3 { letter-spacing: -0.02em; }

/* Header limpio y blanco con marca azul */
body.theme-confeti .site-header { backdrop-filter: none; box-shadow: 0 1px 0 var(--theme-border); }
body.theme-confeti .site-header__logo { background: var(--theme-accent); color: #fff; border-radius: var(--ui-radius-sm); }
body.theme-confeti .site-header__name { color: var(--theme-accent); font-weight: 800; }
body.theme-confeti .site-header__nav a { font-weight: 600; color: var(--theme-ink); }
body.theme-confeti .site-header__nav a:hover { color: var(--theme-accent); }

/* Hero: banda azul a sangre con buscador blanco tipo "pill" */
body.theme-confeti .hero {
  width: 100vw;
  position: relative;
  left: 50%;
  right: 50%;
  margin-left: -50vw;
  margin-right: -50vw;
  margin-top: calc(-1 * var(--pad-lg));
  /* El `padding` NO va aquí: más abajo hay otro `body.theme-confeti .hero` (el
     del hero protagonista) con la misma especificidad que, por orden de
     aparición, pisaba a este. El que se declaraba aquí llevaba tiempo sin
     aplicarse —con su comentario de «medido a 1512x795» y todo—, así que el
     valor bueno vive en un único sitio: busca «Hero protagonista». */
  background: var(--pl-hero);
  color: #fff;
}
body.theme-confeti .hero::before { display: none; }
body.theme-confeti .hero__eyebrow { background: rgba(255, 255, 255, 0.18); color: #fff; }
body.theme-confeti .hero__title { color: #fff; font-weight: 600; }
body.theme-confeti .hero__title strong {
  color: #fff;
  text-decoration: underline;
  text-decoration-color: rgba(255, 255, 255, 0.55);
  text-underline-offset: 5px;
  text-decoration-thickness: 3px;
}
body.theme-confeti .hero__lead { color: rgba(255, 255, 255, 0.93); }
body.theme-confeti .hero__search {
  background: #fff;
  border: 0;
  border-radius: var(--ui-radius-pill);
  padding: 0.4rem 0.4rem 0.4rem 0.65rem;
  box-shadow: 0 16px 38px rgba(8, 30, 60, 0.30);
}
body.theme-confeti .hero__search button { border-radius: var(--ui-radius-cta); background: var(--theme-accent); }
body.theme-confeti .hero__search button:hover { background: var(--pl-accent-strong); filter: none; }
body.theme-confeti .hero__hint { color: rgba(255, 255, 255, 0.92); }
body.theme-confeti .hero__hint a { color: #fff; border-bottom-color: rgba(255, 255, 255, 0.6); }

/* Títulos de sección centrados y en negrita (estilo Planeta) */
body.theme-confeti .features__title,
body.theme-confeti .how-it-works h2,
body.theme-confeti .collection__title,
body.theme-confeti .section-title {
  text-align: center;
  font-weight: 600;
  color: var(--theme-ink);
  font-size: clamp(1.5rem, 2.6vw, 2rem);
}

/* Tarjetas de "por qué usarnos" limpias */
body.theme-confeti .features__item {
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-md);
  box-shadow: none;
  transition: border-color 0.14s ease, box-shadow 0.14s ease, transform 0.14s ease;
}
body.theme-confeti .features__item:hover {
  border-color: var(--theme-accent);
  box-shadow: 0 10px 26px rgba(31, 27, 46, 0.10);
  transform: translateY(-2px);
}
body.theme-confeti .features__icon { background: var(--theme-accent-soft); color: var(--theme-accent); }
body.theme-confeti .how-it-works__num { background: var(--theme-accent); color: #fff; }

/* Tarjetas de libro: limpias, foco en la portada */
body.theme-confeti .book-card { border: 1px solid var(--theme-border); border-radius: var(--ui-radius-md); box-shadow: none; }
body.theme-confeti .book-card:hover { box-shadow: 0 12px 28px rgba(31, 27, 46, 0.12); border-color: color-mix(in srgb, var(--theme-accent) 30%, var(--theme-border)); }
body.theme-confeti .book-card__price strong { font-family: var(--theme-font-heading); font-weight: 800; font-variant-numeric: tabular-nums; }

/* Footer azul marino con columnas (estilo Planeta) */
body.theme-confeti .site-footer {
  background: var(--pl-navy);
  border-top: 0;
  color: rgba(255, 255, 255, 0.80);
  margin-top: 3rem;
  padding-top: 0.5rem;
}
body.theme-confeti .site-footer__inner {
  display: grid;
  grid-template-columns: 1.6fr 1fr 1fr 1fr 1fr;
  gap: 1.75rem 2rem;
  align-items: start;
  padding-top: 2.75rem;
  padding-bottom: 1.75rem;
}
body.theme-confeti .site-footer__logo {
  background: rgba(255, 255, 255, 0.12);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.14);
}
body.theme-confeti .site-footer__brand { color: #fff; font-weight: 800; font-size: 1.15rem; }
body.theme-confeti .site-footer__tagline { color: rgba(255, 255, 255, 0.7); max-width: 320px; }
body.theme-confeti .site-footer__compare { color: rgba(255, 255, 255, 0.46); max-width: 320px; }
body.theme-confeti .site-footer__col { display: flex; flex-direction: column; gap: 0.55rem; }
body.theme-confeti .site-footer__heading {
  margin: 0 0 0.35rem;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: color-mix(in srgb, var(--theme-accent) 55%, #fff);
}
body.theme-confeti .site-footer__col a,
body.theme-confeti .site-footer__col .site-footer__linkish { color: rgba(255, 255, 255, 0.82); font-size: 0.92rem; }
body.theme-confeti .site-footer__col a:hover,
body.theme-confeti .site-footer__col .site-footer__linkish:hover { color: #fff; text-decoration: none; }
body.theme-confeti .site-footer__bottom {
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  padding: 1.2rem 1rem 1.7rem;
}
body.theme-confeti .site-footer__meta { color: rgba(255, 255, 255, 0.52); }
body.theme-confeti .site-footer__made { color: rgba(255, 255, 255, 0.52); }
@media (max-width: 859px) {
  body.theme-confeti .site-footer__inner { grid-template-columns: 1fr 1fr; }
  body.theme-confeti .site-footer__brandcol { grid-column: 1 / -1; }
}
/* El acordeón necesita una sola columna: en dos, cada sección lleva su filete
   superior y la rejilla los desalinea. Va aquí porque `body.theme-confeti` gana
   por especificidad a la regla base del mismo breakpoint. */
@media (max-width: 639px) {
  body.theme-confeti .site-footer__inner { grid-template-columns: 1fr; gap: 0; }
  body.theme-confeti .site-footer__col { border-top: 1px solid rgba(255, 255, 255, 0.14); }
  body.theme-confeti .site-footer__heading { color: #fff; }
}
@media (max-width: 460px) {
  body.theme-confeti .site-footer__inner { grid-template-columns: 1fr; }
}

/* =========================================================================
   PLANETA · refinamiento "pro" (rediseño 2026).
   Eleva el preset azul al nivel del directorio de gasolineras: lavado de
   color superior, hero potente con buscador protagonista, header pulido,
   tarjetas con sombras en capas, landing del comparador y home destacando
   la función estrella (pegar la lista de ISBN).
   ========================================================================= */

/* Aquí había un lavado de color superior: una banda de 560 px con
   `accent-soft` degradando a transparente, más una textura de puntos. Se quitó
   porque teñía de rosa la parte alta de TODAS las páginas interiores —ficha y
   listados incluidos— y era lo que impedía ver el fondo del tema por mucho que
   se cambiara el token. En la portada no se echa de menos: el hero es una
   plancha de color que la tapaba entera.

   `position: relative` se queda aunque ya no ancle a ningún pseudo-elemento:
   es el bloque contenedor de cualquier descendiente `absolute` que no tenga
   otro, y quitarlo movería cosas de sitio sin dar ningún error. */
body.theme-confeti { position: relative; }
body.theme-confeti main.container,
body.theme-confeti .site-footer { position: relative; z-index: 1; }

/* ---- Header pulido: blanco sólido, marca con icono en degradado,
   navegación con realce y CTA "Comparar lista" destacado. */
body.theme-confeti .site-header {
  /* Sticky en todas las anchuras: por encima del hero a sangre (que vive en
     main.container con z-index:1), tanto en desktop como en móvil. */
  position: sticky;
  top: 0;
  z-index: 30;
  /* Blanco opaco, sin translucidez. Con el 0.86 anterior el contenido se
     transparentaba al hacer scroll por debajo del header —portadas y titulares
     asomando tras la navegación— y el `backdrop-filter` obligaba al navegador a
     recomponer la franja en cada scroll. Opaco no necesita blur ninguno. */
  background: #fff;
  box-shadow: 0 1px 0 var(--theme-border);
}
body.theme-confeti .site-header__inner { gap: 1.1rem; }
body.theme-confeti .site-header__logo {
  background: linear-gradient(135deg, color-mix(in srgb, var(--theme-accent) 82%, #fff) 0%, var(--theme-accent) 55%, var(--pl-accent-strong) 100%);
  color: #fff;
  border-radius: var(--ui-radius-md);
  box-shadow: 0 4px 12px color-mix(in srgb, var(--theme-accent) 32%, transparent);
}
body.theme-confeti .site-header__name { font-weight: 800; letter-spacing: -0.02em; color: var(--theme-ink); }
body.theme-confeti .site-header__nav { gap: 0.25rem; }
body.theme-confeti .site-header__nav a {
  padding: 0.45rem 0.7rem;
  border-radius: var(--ui-radius-md);
  font-weight: 600;
  color: var(--theme-ink-soft);
  transition: color 0.14s ease, background-color 0.14s ease;
}
body.theme-confeti .site-header__nav a:hover { background: var(--theme-accent-soft); color: var(--theme-accent); text-decoration: none; }

/* CTA destacado del header (Comparar lista) — pill de acento con sombra. */
body.theme-confeti .site-header__cta {
  border-radius: var(--ui-radius-pill);
  padding: 0.55rem 1.1rem;
  font-weight: 700;
  box-shadow: var(--ui-shadow-accent);
  transition: transform 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease;
}
body.theme-confeti .site-header__cta:hover {
  color: #fff;
  text-decoration: none;
  transform: translateY(-1px);
  background: var(--pl-accent-strong);
  filter: none;
}

/* ---- Hero protagonista: banda azul a sangre, titular grande, buscador
   pill ancho y elevado, botones secundarios y tira de confianza. */
body.theme-confeti .hero {
  /* Más alto A PROPÓSITO (pedido de Rafael, 18-ago-2026): el hero es el
     escaparate y tiene que imponerse. El aire extra va repartido arriba y
     abajo; el buscador sigue entrando en el primer pantallazo a 1080p. */
  padding: clamp(2.5rem, 4.5vw, 4.25rem) 1rem clamp(3rem, 5.5vw, 4.75rem);
  /* SIN `overflow: hidden`: recortaba el desplegable del buscador en vivo.
     Medido en producción, el panel pide 448 px y dentro del hero sólo caben
     148: se comía 300 px, o sea 5 de las 8 sugerencias, cortando la tercera por
     la mitad. Y no se arreglaba con `z-index` —ya se intentó, ver el comentario
     de `.hero > .hero-compare-card`—: el recorte de un ancestro no lo levanta
     ningún apilamiento. Lo único que había dentro que pudiera desbordar es el
     `::after` del patrón de puntos, y va con `inset: 0`, así que no desborda. */
}
body.theme-confeti .hero::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: radial-gradient(circle, rgba(255, 255, 255, 0.08) 1px, transparent 1px);
  background-size: 22px 22px;
  pointer-events: none;
}
body.theme-confeti .hero > * { position: relative; z-index: 1; }
/* La tarjeta del buscador debe quedar por encima de sus hermanos del hero (la
   .trust-row, que va después en el DOM) para que el desplegable de autocompletado
   no quede tapado. Este selector gana en especificidad a la regla `.hero > *`.
   `main.container` es un contexto de apilado en z-index:1 < 30 del header sticky,
   así que subir la tarjeta aquí nunca la solapa con el header. */
body.theme-confeti .hero > .hero-compare-card { z-index: 40; }
body.theme-confeti .hero__eyebrow {
  background: rgba(255, 255, 255, 0.16);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.22);
  padding: 0.32rem 0.85rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  backdrop-filter: blur(4px);
}
body.theme-confeti .hero__title {
  font-size: clamp(2.1rem, 5.6vw, 3.75rem);
  font-weight: 600;
  letter-spacing: -0.03em;
  margin-bottom: 1.1rem;
}
body.theme-confeti .hero__lead {
  font-size: clamp(1.02rem, 1.7vw, 1.25rem);
  color: rgba(255, 255, 255, 0.94);
  max-width: 40rem;
  margin-bottom: 2rem;
}

/* Buscador del hero: pill blanco grande con icono de lupa. */
body.theme-confeti .hero__search {
  max-width: 720px;
  padding: 0.5rem 0.5rem 0.5rem 1.25rem;
  border-radius: var(--ui-radius-pill);
  box-shadow: 0 22px 50px rgba(8, 30, 60, 0.28), 0 4px 14px rgba(8, 30, 60, 0.12);
  border: 1.5px solid rgba(255, 255, 255, 0.5);
  align-items: center;
  gap: 0.4rem;
}
body.theme-confeti .hero__search::before {
  content: "";
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  background: var(--theme-ink-muted);
  -webkit-mask: var(--ui-search-icon) center / contain no-repeat;
  mask: var(--ui-search-icon) center / contain no-repeat;
}
body.theme-confeti .hero__search input {
  font-size: 1.08rem;
  padding: 0.95rem 0.5rem;
}
body.theme-confeti .hero__search button {
  padding: 0.95rem 1.85rem;
  border-radius: var(--ui-radius-pill);
  font-size: 1.05rem;
  font-weight: 700;
  flex-shrink: 0;
}
body.theme-confeti .hero__search button:hover { background: var(--pl-accent-strong); filter: none; }

/* Acciones secundarias bajo el buscador del hero. */
.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.65rem;
  justify-content: center;
  margin: 1.5rem auto 0;
}
body.theme-confeti .hero__hint { margin-top: 1.4rem; }

/* La tira de confianza dentro del hero azul: texto e iconos en blanco. */
body.theme-confeti .hero .trust-row li {
  color: #fff;
  background: rgba(255, 255, 255, 0.13);
  border: 1px solid rgba(255, 255, 255, 0.22);
  padding: 0.45rem 0.95rem;
  border-radius: var(--ui-radius-pill);
  backdrop-filter: blur(4px);
}
body.theme-confeti .hero .trust-row svg { color: #fff; }
/* En columnas la píldora sobra: tres cajas con borde y fondo dentro de una
   rejilla se leen como botones, y no son pulsables. Queda el ✓ y el texto. */
@media (max-width: 719px) {
  body.theme-confeti .hero .trust-row li {
    background: none;
    border: 0;
    padding: 0;
    backdrop-filter: none;
  }
}

/* ---- Hero "comparador" (home): tarjeta blanca del comparador sobre la banda
   azul. La tarjeta hereda la sombra fuerte de `.compare-card` en planeta. */
body.theme-confeti .hero--compare .hero__title {
  font-size: clamp(1.9rem, 4.8vw, 3.1rem);
  margin-bottom: 0.7rem;
}
/* Entradilla más pequeña y más ancha: a 1,35rem dentro de 40rem caía en TRES
   líneas y el bloque de texto pesaba más que el propio titular. A ~1,1rem en
   54rem entra en dos, se lee igual (sigue por debajo del límite de ~75
   caracteres por línea) y sube el comparador. */
body.theme-confeti .hero--compare .hero__lead {
  font-size: clamp(0.98rem, 1.3vw, 1.12rem);
  max-width: 54rem;
  margin-bottom: 0;
}

/* El H1 de la home en UNA línea también en el móvil.
   Medido en producción con Montserrat 600 y letter-spacing -0,03em (iframes de
   320/360/390/430/719 px sobre la home real): «Comparador de libros de texto»
   necesita ≤6,1vw a 320 px y el margen sólo crece con el ancho (6,5vw a 719).
   El suelo de la clamp de arriba —1,9rem = 30,4 px— lo partía en TRES líneas a
   360 px. 5,9vw entra en todo el rango con ~3% de holgura.
   ⚠️ Va calibrado a un titular de ~30 caracteres: si se alarga desde
   /admin/content hay que volver a medir. */
@media (max-width: 719px) {
  .hero--compare .hero__title,
  body.theme-confeti .hero--compare .hero__title {
    font-size: 5.9vw;
  }
  /* La píldora de «gratis» no puede comerse el alto del hero: es donde está el
     formulario, que es lo que convierte. */
  .hero__free {
    font-size: 0.82rem;
    padding: 0.4rem 0.8rem;
    gap: 0.1rem 0.35rem;
  }
  .hero__free-icon { width: 0.95rem; height: 0.95rem; }
}

/* Buscador del hero, rediseñado para MANDAR en la banda (pedido de Rafael con
   captura): fuera la tarjeta blanca con etiqueta dentro — la pieza es un único
   PILL gigante que flota sobre el degradado con un halo translúcido, el botón
   vive dentro del pill y todo sube un punto al recibir el foco. Los blancos
   literales siguen el idioma de este bloque del hero (van sobre el acento,
   como en .hero__eyebrow; no son piezas tematizables). */
/* `.hero .hero-compare-card` y no a secas: la regla genérica
   `body.theme-confeti .compare-card` (sombra grande) va DESPUÉS en el fichero y
   con la misma especificidad pisaba este reset — el «rectángulo casi sin
   opacidad» detrás del pill que señaló Rafael era esa sombra huérfana. */
body.theme-confeti .hero .hero-compare-card {
  background: transparent;
  border: 0;
  padding: 0;
  box-shadow: none;
  max-width: 56rem;
}
body.theme-confeti .hero-compare-card .compare-title-form__row {
  flex-wrap: nowrap;
  align-items: center;
  gap: 0.5rem;
  background: #fff;
  border-radius: var(--ui-radius-pill);
  padding: 0.45rem 0.45rem 0.45rem 1.5rem;
  box-shadow:
    0 0 0 6px rgba(255, 255, 255, 0.22),
    0 30px 70px rgba(8, 30, 60, 0.35),
    0 6px 18px rgba(8, 30, 60, 0.18);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
body.theme-confeti .hero-compare-card .compare-title-form__row:focus-within {
  transform: translateY(-2px);
  box-shadow:
    0 0 0 8px rgba(255, 255, 255, 0.3),
    0 36px 80px rgba(8, 30, 60, 0.4),
    0 8px 20px rgba(8, 30, 60, 0.2);
}
body.theme-confeti .hero-compare-card .compare-title-form__input {
  border: 0;
  background: transparent;
  font-size: 1.16rem;
  padding: 1.05rem 0.5rem;
  min-width: 0;
}
body.theme-confeti .hero-compare-card .compare-title-form__input:focus-visible {
  outline: none;
  box-shadow: none;
  border: 0;
}
body.theme-confeti .hero-compare-card .compare-form__submit {
  align-self: auto;
  flex-shrink: 0;
  border-radius: var(--ui-radius-pill);
  padding: 1rem 1.9rem;
  font-size: 1.08rem;
}
body.theme-confeti .hero-compare-card .compare-form__submit:hover { background: var(--pl-accent-strong); }
@media (max-width: 480px) {
  /* En estrecho el pill no puede partirse: el botón se queda en círculo con la
     lupa sola y el texto desaparece. */
  body.theme-confeti .hero-compare-card .compare-title-form__row { padding-left: 1.05rem; }
  body.theme-confeti .hero-compare-card .compare-title-form__input { font-size: 1rem; padding: 0.85rem 0.3rem; }
  body.theme-confeti .hero-compare-card .compare-form__submit { padding: 0.85rem 1.05rem; }
  body.theme-confeti .hero-compare-card .compare-form__submit span { display: none; }
}

/* Tarjetas de libro un punto más suaves y con elevación al hover. */
body.theme-confeti .book-card { border-radius: var(--ui-radius-md); box-shadow: var(--ui-shadow-sm); }
body.theme-confeti .book-card:hover {
  box-shadow: var(--ui-shadow-md);
  border-color: var(--ui-accent-tint);
  transform: translateY(-3px);
}
body.theme-confeti .book-card__price strong { color: var(--theme-accent); }

/* "Por qué usarnos": iconos en círculo de acento, tarjetas limpias. */
body.theme-confeti .features { padding-top: 2.5rem; }
body.theme-confeti .features__item { border-radius: var(--ui-radius-lg); padding: 1.4rem 1.35rem 1.5rem; }
body.theme-confeti .features__icon {
  width: 2.6rem;
  height: 2.6rem;
  border-radius: var(--ui-radius-md);
  font-size: 1.25rem;
}

/* "Cómo funciona": números en círculo de acento, tarjeta envolvente suave. */
/* Aquí vivía la tarjeta del preset (radio + sombra). Se queda sólo el centrado
   del titular: el marco se retiró en la regla base, y repetirlo aquí —con más
   especificidad— lo habría resucitado. */
body.theme-confeti .how-it-works {
  text-align: center;
}
body.theme-confeti .how-it-works > .eyebrow { justify-content: center; margin-bottom: 0.4rem; }
body.theme-confeti .how-it-works__steps { text-align: left; margin-top: 1.9rem; }
/* La elevación pasa del número al disco del icono: en una chapa de 1,35rem esa
   sombra era una mancha, y en el disco da el relieve que tenía el bloque. */
body.theme-confeti .how-it-works__badge {
  background: color-mix(in srgb, var(--theme-accent) 12%, #fff);
  box-shadow: 0 6px 16px color-mix(in srgb, var(--theme-accent) 18%, transparent);
}
body.theme-confeti .how-it-works__num {
  background: linear-gradient(135deg, color-mix(in srgb, var(--theme-accent) 82%, #fff) 0%, var(--theme-accent) 60%, var(--pl-accent-strong) 100%);
}

/* ---- Bloque destacado del comparador de lista en la home (función estrella).
   Ya tiene base transversal en .home-compare; aquí solo afinamos el azul. */
body.theme-confeti .home-compare {
  background: linear-gradient(135deg, var(--pl-navy) 0%, var(--pl-navy-2) 100%);
}
body.theme-confeti .home-compare__title em { text-decoration-color: rgba(127, 180, 221, 0.7); }
body.theme-confeti .home-compare .btn-pill--accent {
  background: #fff;
  color: var(--pl-navy);
  box-shadow: 0 12px 30px rgba(8, 30, 60, 0.3);
}
body.theme-confeti .home-compare .btn-pill--accent:hover { background: var(--theme-accent-soft); color: var(--pl-navy); }

/* ---- Landing `/comparar`: hero azul a sangre + tarjeta del textarea
   superpuesta. El textarea es el protagonista. */
body.theme-confeti .compare-landing {
  position: relative;
}
body.theme-confeti .compare-landing::before {
  content: "";
  position: absolute;
  left: 50%;
  right: 50%;
  margin-left: -50vw;
  margin-right: -50vw;
  top: calc(-1 * var(--pad-lg));
  width: 100vw;
  height: 320px;
  z-index: 0;
  background: var(--pl-hero);
  -webkit-mask-image: linear-gradient(180deg, #000 62%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 62%, transparent 100%);
}
body.theme-confeti .compare-landing > * { position: relative; z-index: 1; }
body.theme-confeti .compare-landing__eyebrow { color: #fff; }
body.theme-confeti .compare-landing__title { color: #fff; padding-top: clamp(1rem, 3vw, 2rem); }
body.theme-confeti .compare-landing__lead { color: rgba(255, 255, 255, 0.95); }
body.theme-confeti .compare-card { box-shadow: 0 30px 60px rgba(8, 30, 60, 0.22), var(--ui-shadow-md); }
body.theme-confeti .compare-form__submit:hover { background: var(--pl-accent-strong); }

/* ---- Banda de estadísticas: en planeta usamos el navy editorial. */
body.theme-confeti .stats-band {
  background: linear-gradient(135deg, var(--pl-navy) 0%, var(--pl-navy-2) 100%);
}
body.theme-confeti .stats-band__value { color: #fff; }

/* ---- Página de ficha (ISBN): cabecera con sutil degradado y mejor
   jerarquía del bloque "mejor precio". */
body.theme-confeti .book-detail__header { border-radius: var(--ui-radius-xl); box-shadow: var(--ui-shadow-sm); }
body.theme-confeti .best-price-card {
  border-radius: var(--ui-radius-lg);
  background: linear-gradient(135deg, var(--theme-accent-soft) 0%, #fff 100%);
  box-shadow: var(--ui-shadow-md);
}
body.theme-confeti .best-price-card__cta { border-radius: var(--ui-radius-cta); padding: 0.8rem 1.1rem; font-weight: 700; }
body.theme-confeti .best-price-card__cta:hover { background: var(--pl-accent-strong); filter: none; }

/* ---- Comparativa de ofertas (ISBN): mejor "oferta ganadora". */
body.theme-confeti .offers,
body.theme-confeti .book-description,
body.theme-confeti .book-specs {
  border-radius: var(--ui-radius-lg);
  box-shadow: var(--ui-shadow-sm);
}
body.theme-confeti .offer { border-radius: var(--ui-radius-md); }
body.theme-confeti .offer--best {
  /* Sin el anillo de 3px: se sumaba al de la regla base y dejaba un doble halo.
     Aqui solo la sombra suave del tema. */
  box-shadow: var(--ui-shadow-sm);
}
/* El radio ya lo pone `--ui-radius-cta` para todos los botones; aqui solo
   queda el peso tipografico propio del tema. */
body.theme-confeti .offer__button { font-weight: 700; }
body.theme-confeti .offer__button:hover { filter: brightness(0.92); }

/* ---- Cross-sell, related y buybar coherentes con el azul editorial. */
body.theme-confeti .cross-compare {
  border-radius: var(--ui-radius-lg);
  background: linear-gradient(135deg, var(--theme-accent-soft) 0%, #fff 70%);
  border-color: var(--ui-accent-tint);
}
body.theme-confeti .cross-compare__cta:hover { background: var(--pl-accent-strong); filter: none; }
body.theme-confeti .buybar__cta:hover { background: var(--pl-accent-strong); }

/* ---- Página de lista: tarjetas "comprar todo en X" más vendedoras. */
body.theme-confeti .list-cdl-highlight,
body.theme-confeti .list-mix,
body.theme-confeti .list-buys,
body.theme-confeti .list-matrix,
body.theme-confeti .list-items {
  border-radius: var(--ui-radius-lg);
  box-shadow: var(--ui-shadow-sm);
}
body.theme-confeti .list-cdl-highlight {
  background: linear-gradient(135deg, var(--theme-accent-soft) 0%, #fff 60%);
  border-color: var(--ui-accent-tint);
}
body.theme-confeti .list-cdl-highlight__cta,
body.theme-confeti .list-buy-card__cta {
  border-radius: var(--ui-radius-pill);
  font-weight: 700;
}
body.theme-confeti .list-cdl-highlight__cta:hover,
body.theme-confeti .list-buy-card__cta:hover { background: var(--pl-accent-strong); filter: none; }
body.theme-confeti .list-buy-card { border-radius: var(--ui-radius-md); }
body.theme-confeti .list-buy-card--best { box-shadow: 0 0 0 3px var(--ui-accent-ring), var(--ui-shadow-sm); }
body.theme-confeti .list-buy-card__cta--cart {
  background: linear-gradient(135deg, color-mix(in srgb, var(--theme-accent) 82%, #fff) 0%, var(--theme-accent) 60%, var(--pl-accent-strong) 100%);
}

/* ---- Búsqueda: cabecera con pill de búsqueda y facetas más limpias. */
/* El tema no vuelve a poner la tarjeta: sin fondo no hay nada que redondear ni
   que sombrear. (Esta regla ganaba por especificidad a la base.) */
body.theme-confeti .search-header { border-radius: 0; box-shadow: none; }
/* El buscador es la accion principal de estas paginas —quien llega con un ISBN en
   la mano viene exactamente a eso— y se camuflaba: un filete de 1px del mismo gris
   que el resto de tarjetas, sobre fondo casi blanco, en una pagina llena de
   tarjetas iguales. Se le da contorno en color de marca, mas cuerpo y sombra. */
body.theme-confeti .search-header__form {
  background: var(--theme-surface);
  border: 2px solid color-mix(in srgb, var(--theme-accent) 38%, var(--theme-border));
  border-radius: var(--ui-radius-pill);
  padding: 0.4rem 0.4rem 0.4rem 1.15rem;
  gap: 0.4rem;
  box-shadow: 0 2px 12px color-mix(in srgb, var(--theme-accent) 14%, transparent);
  transition: border-color 0.18s ease, box-shadow 0.18s ease;
}
body.theme-confeti .search-header__form:focus-within {
  border-color: var(--theme-accent);
  box-shadow: 0 3px 18px color-mix(in srgb, var(--theme-accent) 28%, transparent);
}
body.theme-confeti .search-header__form input { font-size: 1.05rem; padding: 0.75rem 0.4rem; }
body.theme-confeti .search-header__form button { padding: 0.75rem 1.7rem; }
body.theme-confeti .search-header__form input { border: 0; background: transparent; }
body.theme-confeti .search-header__form input:focus { outline: none; }
body.theme-confeti .search-header__form button { border-radius: var(--ui-radius-cta); font-weight: 700; }
body.theme-confeti .search-facets { border-radius: var(--ui-radius-lg); box-shadow: var(--ui-shadow-sm); }

/* ---- Responsive del hero/landing en móvil. */
@media (max-width: 640px) {
  body.theme-confeti .hero__search { padding: 0.4rem 0.4rem 0.4rem 1rem; }
  body.theme-confeti .hero__search input { font-size: 1rem; padding: 0.8rem 0.4rem; }
  body.theme-confeti .hero__search button { padding: 0.8rem 1.2rem; font-size: 0.98rem; }
  body.theme-confeti .hero__search::before { width: 18px; height: 18px; }
}

/* ---------------------------------------------------------------------------
   Pestañas ISBN/Título (CSS-only, sin JS por CSP) + fila de librerías
--------------------------------------------------------------------------- */
.ctabs__radio {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  opacity: 0;
  pointer-events: none;
}
.ctabs__bar {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: 0.3rem;
  width: 100%;
  margin: 0 0 1.3rem;
  padding: 0.34rem;
  background: var(--theme-surface-alt);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-pill);
}
/* Las inactivas se pintan como PASTILLAS y no como texto suelto sobre la barra
   (14-ago-2026): con la activa rellena de azul y las otras dos en texto plano,
   sólo se leía como pulsable la que ya estaba pulsada. El hover ya avisaba,
   pero en el móvil —donde más se usa esta caja— no hay hover que valga. Fondo
   blanco y borde tenue: tres botones a la vista, uno encendido. */
.ctabs__tab {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  padding: 0.62rem 0.4rem;
  border-radius: var(--ui-radius-pill);
  border: 1px solid var(--theme-border);
  background: var(--theme-surface);
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--theme-ink-soft);
  cursor: pointer;
  user-select: none;
  transition: background 0.18s ease, color 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
.ctabs__tab-icon { width: 1.15rem; height: 1.15rem; flex-shrink: 0; }
.ctabs__tab:hover { color: var(--theme-accent); background: var(--theme-accent-soft); border-color: color-mix(in srgb, var(--theme-accent) 45%, var(--theme-border)); }
@media (max-width: 480px) {
  .ctabs__tab { font-size: 0.82rem; gap: 0.3rem; padding: 0.58rem 0.25rem; }
  .ctabs__tab-icon { width: 1rem; height: 1rem; }
}
/* Las tres pestañas se salían de su propia barra: `grid-auto-columns: 1fr` es
   `minmax(auto, 1fr)`, y ese `auto` impide que una columna baje de su ancho de
   contenido — la más larga («Sube tu lista») fijaba el ancho de las tres y la
   barra pedía 232 px dentro de 217 (medido en producción). `minmax(0, 1fr)` sí
   las deja encoger; el icono, que es decorativo porque el <span> ya lleva el
   texto, se retira antes que el rótulo. */
@media (max-width: 480px) {
  .ctabs__bar { grid-auto-columns: minmax(0, 1fr); }
  .ctabs__tab {
    min-width: 0;
    font-size: 0.8rem;
    padding: 0.5rem 0.2rem;
    line-height: 1.15;
    text-align: center;
    /* Heredaba `nowrap`, así que el rótulo no podía ajustarse y se salía de su
       propia columna aunque la rejilla ya la dejase encoger. En el móvil más
       estrecho «Sube tu lista» parte en dos líneas; la rejilla iguala el alto de
       las tres pestañas, así que no descuadra. */
    white-space: normal;
  }
  .ctabs__tab > span { min-width: 0; }
  .ctabs__tab-icon { display: none; }
}
.ctabs__panel { display: none; }
#cmode-isbn:checked ~ .ctabs__panel--isbn,
#cmode-titulo:checked ~ .ctabs__panel--titulo,
#cmode-foto:checked ~ .ctabs__panel--foto,
#hmode-isbn:checked ~ .ctabs__panel--isbn,
#hmode-titulo:checked ~ .ctabs__panel--titulo,
#hmode-foto:checked ~ .ctabs__panel--foto { display: block; }
#cmode-isbn:checked ~ .ctabs__bar label[for="cmode-isbn"],
#cmode-titulo:checked ~ .ctabs__bar label[for="cmode-titulo"],
#cmode-foto:checked ~ .ctabs__bar label[for="cmode-foto"],
#hmode-isbn:checked ~ .ctabs__bar label[for="hmode-isbn"],
#hmode-titulo:checked ~ .ctabs__bar label[for="hmode-titulo"],
#hmode-foto:checked ~ .ctabs__bar label[for="hmode-foto"] {
  background: var(--theme-accent);
  border-color: var(--theme-accent);
  color: #fff;
  font-weight: 700;
  box-shadow: 0 4px 14px color-mix(in srgb, var(--theme-accent) 35%, transparent);
}
/* Permite enlazar directamente a la pestaña Foto/PDF con `/comparar#cmode-foto`
   (p. ej. desde la home). `:target` activa el panel sin JS; gana al `:checked`
   por defecto porque aparece después en la cascada. */
#cmode-foto:target ~ .ctabs__panel { display: none; }
#cmode-foto:target ~ .ctabs__panel--foto { display: block; }
#cmode-foto:target ~ .ctabs__bar label[for="cmode-foto"] {
  background: var(--theme-accent);
  border-color: var(--theme-accent);
  color: #fff;
  font-weight: 700;
  box-shadow: 0 4px 14px color-mix(in srgb, var(--theme-accent) 35%, transparent);
}
.ctabs__radio:focus-visible ~ .ctabs__bar label {
  outline: 2px solid var(--ui-accent-ring);
  outline-offset: 2px;
}

.compare-title-form__row {
  display: flex;
  gap: 0.6rem;
  flex-wrap: wrap;
}
.compare-title-form__input {
  flex: 1 1 240px;
  padding: 0.95rem 1.1rem;
  font-size: 1.05rem;
  border: 1px solid color-mix(in srgb, var(--theme-ink-muted) 30%, #fff);
  border-radius: var(--ui-radius-md);
  background: var(--theme-surface);
}
.compare-title-form__input:focus-visible {
  outline: none;
  border-color: var(--theme-accent);
  box-shadow: 0 0 0 4px var(--ui-accent-ring);
}

/* --- Pestaña Foto/PDF: zona de subida arrastrar-y-soltar --- */
.compare-upload { display: flex; flex-direction: column; gap: 0.9rem; }
.dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  padding: 2.25rem 1.25rem;
  text-align: center;
  border: 2px dashed color-mix(in srgb, var(--theme-accent) 45%, var(--theme-border));
  border-radius: var(--ui-radius-xl);
  background: var(--theme-accent-soft);
  color: var(--theme-ink-soft);
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
}
.dropzone:hover {
  border-color: var(--theme-accent);
  background: color-mix(in srgb, var(--theme-accent) 12%, var(--theme-surface));
  box-shadow: var(--ui-shadow-sm);
}
.dropzone__icon {
  width: 2.75rem;
  height: 2.75rem;
  color: var(--theme-accent);
}
.dropzone__title {
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--theme-ink);
}
.dropzone__hint { font-size: 0.9rem; color: var(--theme-ink-muted); }
.dropzone__cta {
  margin-top: 0.35rem;
  padding: 0.55rem 1.25rem;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  color: var(--theme-accent);
  font-weight: 700;
  font-size: 0.92rem;
}
/* El <input type=file> real ocupa toda la zona pero invisible: así un clic
   en cualquier punto del dropzone abre el selector, sin necesidad de JS. */
.dropzone__input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  opacity: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
}
/* Mostramos el nombre del fichero elegido vía pseudo-contenido no es posible
   sin JS; el navegador ya indica el archivo bajo el botón nativo si se hace
   visible. Mantenemos foco accesible con teclado sobre la etiqueta. */
.dropzone__input:focus-visible ~ .dropzone__cta,
.dropzone:focus-within {
  outline: 2px solid var(--ui-accent-ring);
  outline-offset: 2px;
}
/* Variante COMPACTA del dropzone: para cuando el adjunto es un campo más de un
   formulario (y encima opcional, como en /envianos-tu-lista) y no la acción
   principal de la página. En fila en vez de en columna y sin el hueco central,
   baja de ~150 px de alto a ~56 sin perder nada de lo que aporta el componente:
   nombre y peso del fichero, arrastrar y soltar, y la cámara en el móvil.
   Fondo blanco y no el tinte de acento: aquí la tarjeta que lo contiene ya es
   azul clara, y tinte sobre tinte deja el recuadro invisible. */
.dropzone--compact {
  flex-direction: row;
  justify-content: flex-start;
  gap: 0.7rem;
  padding: 0.65rem 0.9rem;
  text-align: left;
  border-radius: var(--ui-radius-md);
  background: var(--theme-surface);
}
.dropzone--compact:hover { background: var(--theme-surface); border-color: var(--theme-accent); }
.dropzone--compact .dropzone__icon { width: 1.5rem; height: 1.5rem; }
.dropzone--compact .dropzone__title { font-size: 0.95rem; font-weight: 600; }
.dropzone--compact .dropzone__cta {
  margin: 0 0 0 auto;
  padding: 0.4rem 0.95rem;
  font-size: 0.85rem;
  white-space: nowrap;
}
@media (max-width: 559px) {
  /* En pantallas estrechas el rótulo y el botón no caben en una línea; el
     recuadro pasa a dos filas antes de que el texto se estrangule. */
  .dropzone--compact { flex-wrap: wrap; }
  .dropzone--compact .dropzone__cta { margin-left: 2.2rem; }
}

/* Botón "hacer una foto": lo inyecta `upload-feedback.js` sólo en dispositivos
   con cámara (puntero grueso + soporte de `capture`), delante del dropzone. Va
   con contorno y no relleno porque el relleno sólido es del botón de enviar: el
   paso siguiente sigue siendo "Subir y comparar". */
.dropzone__camera {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  width: 100%;
  font: inherit;
  padding: 0.9rem 1rem;
  border-radius: var(--ui-radius-pill);
  border: 2px solid var(--theme-accent);
  background: var(--theme-surface);
  color: var(--theme-accent);
  font-weight: 700;
  font-size: 1rem;
  line-height: 1.2;
  cursor: pointer;
}
.dropzone__camera:active { background: var(--theme-accent-soft); }
.dropzone__camera:focus-visible {
  outline: 2px solid var(--ui-accent-ring);
  outline-offset: 2px;
}
.dropzone__camera-icon { width: 1.3rem; height: 1.3rem; flex-shrink: 0; }
.compare-upload__note {
  margin: 0;
  font-size: 0.85rem;
  color: var(--theme-ink-muted);
  line-height: 1.5;
}

.merchants-strip {
  text-align: center;
  padding: clamp(2.5rem, 6vw, 4rem) 1rem;
}
.merchants-strip__label {
  display: inline-flex;
  align-items: center;
  gap: 0.7em;
  font-size: clamp(0.84rem, 1.4vw, 0.98rem);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--theme-ink-muted);
  margin: 0 0 clamp(1.25rem, 2.5vw, 1.75rem);
}
/* Líneas finas a ambos lados del rótulo: lo enmarcan y le dan presencia sin
   robar protagonismo a los logos (que son el foco de la franja). */
.merchants-strip__label::before,
.merchants-strip__label::after {
  content: "";
  width: clamp(1.25rem, 5vw, 3rem);
  height: 1px;
  background: var(--theme-border);
}
.merchants-strip__list {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 0.9rem 1.1rem;
  margin: 0;
  padding: 0;
}

/* MÓVIL: carrusel horizontal en vez de columna. Con `wrap` las cuatro librerías
   se apilan una debajo de otra y la franja se come media pantalla — y es una
   sección de refuerzo, no el contenido. En una sola fila con scroll se ve que
   hay más a la derecha: medido en producción, de 4 filas apiladas a 69 px de
   alto con 731 px de recorrido. Sin sangrado por márgenes negativos: se probó y
   metía 8 px de scroll horizontal en la página. */
@media (max-width: 719px) {
  .merchants-strip__list {
    flex-wrap: nowrap;
    justify-content: flex-start;
    overflow-x: auto;
    padding: 0.5rem 0.25rem;
    gap: 0.65rem;
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .merchants-strip__list::-webkit-scrollbar { display: none; }
  .merchants-strip__item {
    flex: none;
    scroll-snap-align: start;
    padding: 0.7rem 1.1rem;
    font-size: 1rem;
  }
}

/* "Logos" wordmark de cada librería como chips con el color de marca aproximado.
   NO usamos los logos oficiales (copyright): son wordmarks tipográficos sobre
   chip claro con sombra suave, para dar aspecto de fila de partners.
   TODO: sustituir por los assets oficiales del kit de afiliado de cada librería
   (Amazon Associates / Awin: Casa del Libro, Fnac, El Corte Inglés, Agapea…)
   cuando estén disponibles; bastará con cambiar el contenido del <li> por un
   <img> y neutralizar estas reglas de color. */
.merchants-strip__item {
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  padding: 0.85rem 1.5rem;
  border-radius: var(--ui-radius-pill);
  background: #fff;
  border: 1px solid var(--theme-border);
  box-shadow: var(--ui-shadow-md, 0 6px 22px rgba(31, 27, 46, 0.08));
  font-family: var(--theme-font-heading), system-ui, sans-serif;
  font-weight: 700;
  font-size: clamp(1.05rem, 1.8vw, 1.25rem);
  line-height: 1;
  letter-spacing: -0.01em;
  color: var(--theme-ink);
  white-space: nowrap;
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.merchants-strip__item:hover {
  transform: translateY(-3px);
  box-shadow: var(--ui-shadow-lg, 0 22px 50px rgba(31, 27, 46, 0.14));
  border-color: color-mix(in srgb, var(--theme-accent) 35%, var(--theme-border));
}
/* Logo real de la marca (favicon de alta resolución). El nombre acompaña al
   icono; el texto se tinta con el color de marca para reforzar el reconocimiento. */
.merchants-strip__logo {
  width: 1.85em;
  height: 1.85em;
  object-fit: contain;
  border-radius: var(--ui-radius-sm);
  flex: none;
}
.merchants-strip__item[data-merchant="amazon"] { color: #131a22; }
.merchants-strip__item[data-merchant="cdl"] { color: #00843d; }
.merchants-strip__item[data-merchant="fnac"] { color: #111; }
.merchants-strip__item[data-merchant="eci"] { color: #1f8a3b; }
.merchants-strip__item[data-merchant="agapea"] { color: #c0228a; }
.merchants-strip__item[data-merchant="imosver"] { color: #0f5ca8; }
.merchants-strip__item[data-merchant="abacus"] { color: #e30613; }

/* ── Páginas legales / informativas (aviso legal, privacidad, contacto, about).
   Tarjeta de lectura con ancho de medida cómodo; el cuerpo se inyecta como HTML
   desde el CMS de textos, así que estilamos los hijos genéricos (p/h2/ul/a). ── */
.legal-page {
  max-width: none;
  margin: 2.5rem 0 3.5rem;
  padding: clamp(1.5rem, 4vw, 2.75rem);
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  box-shadow: var(--ui-shadow-sm, 0 1px 2px rgba(31, 27, 46, 0.06));
}
.legal-page__header {
  margin-bottom: 1.5rem;
  padding-bottom: 1.25rem;
  border-bottom: 1px solid var(--theme-border);
}
.legal-page__title {
  margin: 0;
  font-size: clamp(1.6rem, 3.5vw, 2.1rem);
  font-weight: 600;
}
.legal-page__body {
  color: var(--theme-ink);
  line-height: 1.7;
}
.legal-page__body > :first-child { margin-top: 0; }
.legal-page__body > :last-child { margin-bottom: 0; }
.legal-page__body h2 {
  margin: 1.85rem 0 0.6rem;
  font-size: 1.18rem;
  font-weight: 700;
}
.legal-page__body p {
  margin: 0 0 1rem;
  color: var(--theme-ink-muted);
}
.legal-page__body strong { color: var(--theme-ink); }
.legal-page__body ul,
.legal-page__body ol {
  margin: 0 0 1rem;
  padding-left: 1.3rem;
  color: var(--theme-ink-muted);
}
.legal-page__body li { margin: 0 0 0.4rem; }
.legal-page__body a {
  color: var(--theme-accent);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}
.legal-page__body a:hover,
.legal-page__body a:focus { color: var(--ui-accent-strong, var(--theme-accent)); }

/* ---- Formulario de contacto (/contacto) ---- */
/* El formulario va ARRIBA, antes de los datos de contacto: quien entra aquí
   viene a escribir, no a leer quiénes somos. El separador tuvo que darse la
   vuelta —era `border-top`, pensado para ir detrás del texto— o quedaba una
   línea suelta justo debajo del H1. */
.contact-form-wrap {
  margin-bottom: 2.25rem;
  padding-bottom: 1.9rem;
  border-bottom: 1px solid var(--theme-border);
}
.contact-form__heading { margin: 0 0 0.35rem; font-size: 1.25rem; }
/* Los <button> NO heredan la fuente: sin esto el navegador les pone su
   familia por defecto (Arial) y el boton desentonaba con toda la web. */
.contact-form__submit,
.contact-form__input,
.contact-form__textarea {
  font-family: inherit;
}

/* Casilla de privacidad: el texto al lado, no debajo, y el cuadro alineado con
   la primera linea. */
.contact-form__consent {
  display: flex;
  align-items: flex-start;
  gap: 0.65rem;
  margin: 0.4rem 0 0.2rem;
  font-size: 0.88rem;
  line-height: 1.5;
  color: var(--theme-ink-soft);
  cursor: pointer;
}
.contact-form__consent input {
  flex: none;
  width: 1.1rem;
  height: 1.1rem;
  margin-top: 0.15rem;
  accent-color: var(--theme-accent);
}
.contact-form__consent a { color: var(--theme-accent); text-decoration: underline; }

/* Caja de busqueda en /envianos-tu-lista. La tarjeta viene de la home, donde
   vive dentro de un hero de fondo oscuro; aqui va sobre el fondo normal de la
   pagina, asi que se le pone su propio respiro y un separador que deja claro
   donde acaba «buscalo tu» y empieza «te lo hacemos nosotros». */
.send-list__buscar {
  margin: 0 0 2.25rem;
}
.send-list__buscar .hero-compare-card {
  margin-top: 0.9rem;
  /* En la home la tarjeta va centrada y estrecha (`max-width: 44rem`) porque
     vive en un hero a pantalla completa. Aqui el resto de la pagina va a ancho
     completo, asi que centrada dejaba dos calles vacias a los lados y parecia
     un trozo pegado de otra pagina. Especificidad 0,2,0: gana a la regla base
     este donde este en el fichero. */
  max-width: none;
  /* Mas compacta que en la home (decision de Rafael, 11-ago-2026): esta pagina
     es la de ENVIAR el listado, no la de buscar. La caja seguia siendo la del
     hero, tan alta que empujaba el formulario de envio fuera de pantalla. Aqui
     el buscar es la alternativa, no el protagonista. */
  padding: 0.85rem 0.9rem;
}
.send-list__buscar .hero-compare-card__pretitle { margin-bottom: 0.45rem; }
.send-list__buscar .compare-form__textarea { min-height: 2.6rem; }
.send-list__buscar-nota {
  margin: 1.1rem 0 0;
  padding-top: 1.1rem;
  border-top: 1px solid var(--theme-border);
  font-size: 0.95rem;
  color: var(--theme-ink-soft);
  text-wrap: balance;
}

/* Turnstile. El iframe mide 300x65 fijos y no encoge, asi que en movil se deja
   desbordar en su propio contenedor en vez de estrujar la caja del formulario
   (que arrastraria a los inputs). `min-height` reserva el hueco desde el primer
   pintado: sin ella el boton de enviar da un salto cuando el widget monta. */
.form-turnstile {
  margin: 0.2rem 0 0.1rem;
  min-height: 65px;
  max-width: 100%;
  overflow-x: auto;
}

/* /contacto con la misma piel que /envianos-tu-lista: eran dos formularios que
   hacen lo mismo y se veian distintos. */
.contact-form-wrap {
  padding: 1.9rem 1.9rem 2rem;
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-top: 4px solid var(--theme-accent);
  border-radius: var(--ui-radius-lg);
  box-shadow: var(--theme-shadow, 0 12px 32px rgba(16, 42, 67, 0.08));
}
.contact-form-wrap .contact-form { max-width: none; }
.contact-form-wrap .contact-form__submit { width: 100%; padding: 0.95rem 1.5rem; font-size: 1.05rem; }

.contact-form__hint {
  font-size: 0.85rem;
  color: var(--theme-ink-soft);
  line-height: 1.4;
}

/* ---------------------------------------------------------------------------
   /envianos-tu-lista — el visitante nos manda la lista y se la comparamos a
   mano. Es la salida para quien no se apaña con la subida automática: antes de
   esto, esa persona simplemente se iba.
   --------------------------------------------------------------------------- */
/* El enlace de rescate bajo la subida de /comparar. Discreto pero visible: no
   compite con el botón, pero está justo donde alguien abandona. */
.compare-upload__fallback {
  margin: 1rem 0 0;
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--theme-ink-muted);
  text-align: center;
}
.compare-upload__fallback a {
  color: var(--theme-accent);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

/* Tachar los libros según se compran, cuando la librería no tiene cesta y hay
   que ir de uno en uno. Ver `js/buy-progress.js`. */
.buy-progress__summary {
  margin: 0 0 0.6rem;
  font-size: 0.9rem;
  font-weight: 700;
  color: var(--theme-accent);
}

.buy-progress__toggle {
  flex: 0 0 auto;
  width: 1.35rem;
  height: 1.35rem;
  margin-right: 0.7rem;
  padding: 0;
  border: 2px solid var(--theme-border);
  border-radius: var(--ui-radius-sm);
  background: var(--theme-surface);
  cursor: pointer;
  transition: border-color 0.15s ease, background-color 0.15s ease;
}
.buy-progress__toggle:hover { border-color: var(--theme-accent); }

.list-buy-card__item.is-comprado .buy-progress__toggle {
  border-color: var(--theme-success, var(--theme-accent));
  background: var(--theme-success, var(--theme-accent));
  /* La marca va en el fondo: un SVG inline en el JS chocaría con la CSP. */
  background-image: linear-gradient(45deg, transparent 45%, #fff 45%, #fff 55%, transparent 55%),
    linear-gradient(-45deg, transparent 45%, #fff 45%, #fff 55%, transparent 55%);
  background-size: 62% 62%;
  background-position: center;
  background-repeat: no-repeat;
}

/* El tachado va sobre el título y el precio, no sobre el botón: seguir pudiendo
   comprar es justo lo que se necesita si te has marcado uno por error. */
.list-buy-card__item.is-comprado .list-buy-card__item-title,
.list-buy-card__item.is-comprado .list-buy-card__item-price {
  text-decoration: line-through;
  opacity: 0.55;
}

.send-list__lead {
  margin: 0.6rem 0 0;
  font-size: 1.05rem;
  line-height: 1.6;
  color: var(--theme-ink-muted);
  /* Sin tope: la caja ya es ancha y 46rem partía la entradilla en tres líneas
     cortas dejando media cabecera vacía. */
  max-width: none;
}

.send-list__section-title {
  margin: 0 0 1rem;
  font-size: 1.22rem;
  font-weight: 700;
}

/* Formulario a la izquierda y pasos a la derecha, en paralelo. Apilados
   dejaban media pantalla en blanco y obligaban a leer la explicación antes de
   poder actuar; en dos columnas el visitante ve qué va a pasar MIENTRAS
   rellena, que es cuando le sirve.

   El formulario va PRIMERO en el DOM: en móvil es lo que tiene que verse
   antes, y para un lector de pantalla la acción manda sobre la explicación. */
.send-list__cols {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: 2rem;
  align-items: start;
  margin: 2rem 0;
}

@media (max-width: 900px) {
  .send-list__cols { grid-template-columns: 1fr; gap: 1.5rem; }
}

.send-list__cols > .send-list__form-wrap { margin: 0; }
.send-list__cols > .send-list__steps { margin: 0; }

/* En la columna estrecha los pasos van uno bajo otro, no en rejilla. */
.send-list__cols .send-list__steps-list { grid-template-columns: 1fr; }

.send-list__steps { margin: 2.25rem 0; }

.send-list__steps-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1rem;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: paso;
}

.send-list__steps-list li {
  counter-increment: paso;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 1.15rem 1.25rem 1.3rem;
  background: var(--theme-surface-alt);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-sm);
}

/* El número va en `::before` y no en el marcador de la lista para poder darle
   forma de ficha; la semántica de <ol> se conserva. */
.send-list__steps-list li::before {
  content: counter(paso);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.85rem;
  height: 1.85rem;
  margin-bottom: 0.15rem;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent);
  color: #fff;
  font-weight: 700;
  font-size: 0.95rem;
}

/* La ilustración encabeza cada ficha de paso. `order: -1` porque el número lo
   pinta un `::before`, que en un flex es un hijo más y va delante por defecto:
   sin esto la ilustración quedaba DEBAJO del número. */
.send-list__steps-list .step-art {
  order: -1;
  width: 104px;
  height: 78px;
  margin-bottom: 0.3rem;
}
.send-list__steps-list strong { color: var(--theme-ink); }
.send-list__steps-list span { color: var(--theme-ink-muted); line-height: 1.55; }

/* El formulario ES la página: antes era una sección más, separada por un filete
   y con los campos al mismo nivel visual que el texto de alrededor, así que se
   leía como «más contenido» en vez de como la acción. Ahora es una tarjeta con
   fondo propio y borde de acento — el mismo recurso que usa la caja de búsqueda
   de la home, que es la otra acción principal del sitio. */
/* Fondo azul claro (14-ago-2026): en blanco sobre blanco la tarjeta sólo se
   distinguía por el filete, o sea que la ACCIÓN de la página pesaba lo mismo que
   el texto de al lado. Con el tinte se ve el bloque antes de leerlo y, de
   regalo, los campos —que son blancos— ganan contraste dentro de él. El hex de
   reserva va primero por si el navegador no soporta `color-mix`. */
.send-list__form-wrap {
  margin: 2.25rem 0;
  padding: 1.9rem 1.9rem 2rem;
  background: var(--theme-accent-soft);
  background: color-mix(in srgb, var(--theme-accent) 8%, #fff);
  border: 1px solid var(--theme-border);
  border-top: 4px solid var(--theme-accent);
  border-radius: var(--ui-radius-lg);
  box-shadow: var(--theme-shadow, 0 12px 32px rgba(16, 42, 67, 0.08));
}

/* SIN `max-width`: la página ya es una tarjeta a ancho completo, así que capar
   el formulario a 44rem dejaba media pantalla en blanco a la derecha. Aquí
   llega gente que no se apaña con la herramienta: el formulario tiene que ser
   lo único que se ve y llenar el espacio. */
/* `form.` para ganar por especificidad: `.contact-form { max-width: 40rem }`
   está MÁS ABAJO en este fichero y con la misma especificidad ganaba la última,
   así que el formulario seguía ocupando media tarjeta. */
form.send-list__form {
  max-width: none;
  width: 100%;
}

/* Dos columnas de verdad, no `auto-fit`: con `minmax(13rem, 1fr)` sobre un
   contenedor ancho salían tres o cuatro columnas y los campos quedaban
   ridículamente estrechos. */
.send-list .send-list__grid {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem 1.5rem;
}
.send-list .send-list__grid--tres {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
@media (max-width: 700px) {
  .send-list .send-list__grid,
  .send-list .send-list__grid--tres {
    grid-template-columns: 1fr;
  }
}

/* El mensaje y el adjunto, a lo ancho: son los dos campos donde de verdad se
   escribe y se pega la lista. */
.send-list__form > .contact-form__row { width: 100%; }

/* Los pasos numerados dentro del propio formulario. Tres bloques cortos se
   leen mejor que once campos seguidos, y dejan claro que sólo el 1 y el 2 son
   obligatorios. */
.send-list__paso {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 1.6rem 0 0.9rem;
  font-weight: 700;
  font-size: 1.02rem;
  color: var(--theme-ink);
}
.send-list__paso:first-child { margin-top: 0; }
.send-list__paso span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.7rem;
  height: 1.7rem;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent);
  color: #fff;
  font-size: 0.92rem;
  flex: none;
}
.send-list__paso--opcional {
  font-weight: 600;
  color: var(--theme-ink-soft);
}
.send-list__paso--opcional span {
  background: var(--theme-border);
  color: var(--theme-ink-soft);
}

.send-list__grid--tres {
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
}

/* Los campos obligatorios, con más peso que los opcionales: el visitante ve de
   un vistazo que sólo hay tres cosas que rellenar de verdad. */
.send-list__form .contact-form__label {
  font-size: 0.95rem;
  color: var(--theme-ink);
}

.send-list__form .contact-form__input,
.send-list__form .contact-form__textarea {
  background: var(--theme-bg);
  border-width: 1.5px;
}

.send-list__form .contact-form__input:focus,
.send-list__form .contact-form__textarea:focus,
.send-list__form .dropzone--compact:focus-within {
  border-color: var(--theme-accent);
  box-shadow: 0 0 0 3px var(--theme-accent-soft);
  outline: none;
}

/* Etiqueta en línea con su pista («Adjunta tu lista: foto…»), como el
   formulario de referencia: la parte fuerte en tinta y el resto suave. */
.send-list__inline-label {
  display: block;
  margin-bottom: 0.45rem;
  color: var(--theme-ink-soft);
  line-height: 1.45;
}
.send-list__inline-label strong { color: var(--theme-ink); }

.send-list__form .contact-form__submit {
  width: 100%;
  padding: 0.95rem 1.5rem;
  font-size: 1.05rem;
}

.send-list__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: 1rem;
}

.send-list__faq { margin-top: 2.5rem; }

/* Pantalla de «recibida»: sin formulario, sólo la confirmación y qué pasa ahora. */
.send-list__done {
  margin: 2rem 0;
  padding: 1.75rem 1.75rem 1.9rem;
  background: var(--theme-accent-soft);
  border: 1px solid var(--theme-accent);
  border-radius: var(--ui-radius-lg);
}
.send-list__done-title { margin: 0 0 0.6rem; font-size: 1.3rem; }
.send-list__done p { margin: 0 0 0.75rem; color: var(--theme-ink); line-height: 1.6; }
.send-list__done-cta { margin: 0; }
.send-list__link { color: var(--theme-accent); font-weight: 600; text-decoration: underline; }
.contact-form__lead {
  margin: 0 0 1.25rem;
  color: var(--theme-ink-muted);
  font-size: 0.97rem;
}
.contact-form { display: flex; flex-direction: column; gap: 1rem; max-width: 40rem; }
.contact-form__row { display: flex; flex-direction: column; gap: 0.35rem; }
.contact-form__label { font-weight: 600; font-size: 0.92rem; color: var(--theme-ink); }
.contact-form__input,
.contact-form__textarea {
  width: 100%;
  padding: 0.7rem 0.85rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-sm);
  background: var(--theme-surface);
  color: var(--theme-ink);
  font: inherit;
}
.contact-form__input:focus,
.contact-form__textarea:focus {
  outline: none;
  border-color: var(--theme-accent);
  box-shadow: 0 0 0 3px var(--theme-accent-soft);
}
.contact-form__textarea { resize: vertical; min-height: 7rem; }
.contact-form__submit {
  align-self: flex-start;
  padding: 0.78rem 1.6rem;
  background: var(--theme-accent);
  color: #fff;
  border: 0;
  border-radius: var(--ui-radius-pill);
  font-weight: 700;
  cursor: pointer;
}
.contact-form__submit:hover { filter: brightness(0.93); }
.contact-form__note { margin: 0.85rem 0 0; font-size: 0.82rem; color: var(--theme-ink-muted); }
/* Honeypot anti-spam: fuera de pantalla, no debe verse ni recibir foco. */
.contact-form__hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.contact-form__success {
  margin: 0 0 1.1rem;
  padding: 0.85rem 1rem;
  background: color-mix(in srgb, var(--theme-success) 12%, #fff);
  border: 1px solid color-mix(in srgb, var(--theme-success) 30%, transparent);
  border-radius: var(--ui-radius-sm);
  color: color-mix(in srgb, var(--theme-success) 78%, #000 22%);
  font-weight: 500;
}
.contact-form__error {
  margin: 0 0 1.1rem;
  padding: 0.85rem 1rem;
  background: color-mix(in srgb, var(--theme-danger) 10%, #fff);
  border: 1px solid color-mix(in srgb, var(--theme-danger) 30%, transparent);
  border-radius: var(--ui-radius-sm);
  color: #b91c1c;
  font-weight: 500;
}

/* ---- Listado del blog: rejilla de 3 columnas con tarjetas ---- */
.blog-index__header {
  margin-bottom: 1.75rem;
}
.blog-index__lead {
  color: var(--theme-ink-soft);
  font-size: 1.02rem;
  margin: 0.35rem 0 0;
  /* Sin `max-width: 60ch`. Esa medida es buena tipografia para un parrafo
     suelto, pero aqui el lead convive con un H1 y una rejilla de tarjetas que
     ocupan el contenedor entero, y cortarlo a 60ch lo dejaba a media anchura,
     descolgado del resto. El ancho ya lo limita el contenedor de la pagina. */
}
/* El cuerpo SEO va DESPUES de la rejilla de tarjetas: sin separacion propia
   quedaba pegado a la ultima tarjeta, como si fuera parte de ella. */
.blog-index__seo {
  margin-top: 2.5rem;
  padding-top: 1.75rem;
  border-top: 1px solid var(--theme-border);
}
.blog-index__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
}
.blog-card {
  display: flex;
  flex-direction: column;
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  overflow: hidden;
  box-shadow: var(--ui-shadow-sm);
  transition: transform 0.14s ease, box-shadow 0.14s ease;
}
.blog-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--ui-shadow-md);
}
.blog-card__cover {
  display: block;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--theme-surface-alt);
}
.blog-card__cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.blog-card__body {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  padding: 1rem 1.15rem 1.2rem;
  flex: 1;
}
.blog-card__title {
  margin: 0;
  font-size: 1.1rem;
  line-height: 1.32;
}
.blog-card__title a {
  color: var(--theme-ink);
  text-decoration: none;
}
.blog-card__title a:hover {
  color: var(--theme-accent);
}
.blog-card__excerpt {
  margin: 0;
  color: var(--theme-ink-soft);
  font-size: 0.92rem;
  line-height: 1.55;
}
.blog-card__meta {
  margin: auto 0 0;
  padding-top: 0.4rem;
  color: var(--theme-ink-muted);
  font-size: 0.82rem;
}
.blog-index__pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.25rem;
  margin-top: 2rem;
  font-size: 0.95rem;
}
.blog-index__pagination a {
  color: var(--theme-accent);
  text-decoration: none;
  font-weight: 600;
}
.blog-index__pagination-status {
  color: var(--theme-ink-muted);
}
.blog-index__empty {
  color: var(--theme-ink-soft);
}
@media (max-width: 880px) {
  .blog-index__list {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (max-width: 560px) {
  .blog-index__list {
    grid-template-columns: 1fr;
  }
}

/* ---- Imagen de cabecera del post de blog ----
   `aspect-ratio` reserva el hueco antes de que cargue la imagen: sin él, la
   cabecera del post (una página indexable, y esta imagen es su LCP) daba un
   salto de layout de hasta 420px al cargar. `.blog-card__cover` ya lo declara;
   esto sólo alinea el post con la tarjeta. Manda sobre la proporción intrínseca,
   así que no hay salto, y el `max-height` sigue recortando con object-fit. */
.blog-post__cover {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  max-height: 420px;
  object-fit: cover;
  border-radius: var(--ui-radius-lg);
  margin: 0 0 1.75rem;
  background: var(--theme-surface-alt);
}

/* Enlaces dentro del cuerpo del post: subrayados y en color de acento para que
   se distingan claramente del texto (los CTAs internos a /comparar, /cursos…). */
.blog-post__body a {
  color: var(--theme-accent);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
}
.blog-post__body a:hover {
  text-decoration-thickness: 2px;
}

/* =========================================================================
   HOME — secciones markenianas del rediseño (propuestas de valor, teaser de
   "cómo funciona", intros de categorías, FAQ y banda CTA final). Estilos base
   transversales a todos los presets; el bloque `body.theme-confeti` de más
   abajo los afina al azul editorial.
   ========================================================================= */

/* ---- Propuestas de valor: rejilla de señales con icono + título + frase. --- */
/* ---- Banda de cifras de la home (sustituye a las seis tarjetas de ventajas).
   Sin marcos: lo que sostiene el bloque es el contraste de tamaño entre la
   cifra y su rótulo, no un borde alrededor de cada frase. Los separadores son
   filetes entre columnas, que es lo que hace que se lea como una banda y no
   como cuatro cajas sueltas. */
/* Tarjeta, no franja desnuda (feedback de Rafael con captura, 11-ago-2026):
   entre secciones que son todas cards, los cuatro números con filetes sueltos
   y la nota flotando debajo rompían el sistema. Misma caja que el resto y la
   nota integrada con su separador. */
/* Sin tarjeta, por lo mismo que `.how-it-works`: blanco sobre blanco con un
   filete alrededor. Las líneas verticales entre cifras ya dan la estructura. */
.home-proof {
  padding: 0;
  margin: 2.75rem 0 2rem;
}
.home-proof__figures {
  list-style: none;
  margin: 0;
  padding: 0;
  /* Flex con reparto igual, no una rejilla de N columnas: las cifras son
     CONDICIONALES (de una a tres) y una rejilla fijada en cuatro dejaba la
     banda arrinconada a la izquierda con una columna fantasma vacía. */
  display: flex;
}
.home-proof__item {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  /* Pegadas arriba: con cifras de ancho tan dispar («4» contra «849.237») cada
     columna centraba su propio alto y la banda se veía descuadrada. */
  justify-content: flex-start;
  gap: 0.45rem;
  align-items: center;
  text-align: center;
  padding: 0.5rem 1rem;
  border-left: 1px solid var(--theme-border);
}
.home-proof__item:first-child { border-left: 0; }
.home-proof__num {
  font-family: var(--theme-font-heading);
  font-weight: 800;
  font-size: clamp(1.9rem, 4vw, 2.7rem);
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--theme-accent);
  font-variant-numeric: tabular-nums;
}
.home-proof__label {
  font-size: 0.86rem;
  line-height: 1.35;
  color: var(--theme-ink-soft);
  /* 11rem y no 15: con 15 cada etiqueta partía por un sitio distinto y la
     primera dejaba «vez» sola en su línea. */
  max-width: 11rem;
  /* Reparte las líneas en vez de llenar la primera: mata las palabras
     huérfanas sin tener que ajustar el ancho al carácter. */
  text-wrap: balance;
}
.home-proof__note {
  /* Solo texto, centrado (el icono del camión se retiró: decoraba sin
     aportar — feedback de Rafael, 13-ago-2026). */
  text-align: center;
  margin: 1.5rem 0 0;
  padding-top: 1.2rem;
  border-top: 1px solid var(--theme-border, var(--theme-border));
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--theme-ink-soft);
  text-align: center;
}
.home-proof__note span { display: inline-block; max-width: 40rem; text-wrap: balance; }
/* Móvil: en columna. Tres cifras en fila encogen hasta dejar de ser cifras, y
   apiladas los filetes verticales sobran. */
@media (max-width: 720px) {
  .home-proof__figures { flex-direction: column; gap: 1.5rem; }
  .home-proof__item { border-left: 0; padding: 0 0.6rem; }
}

.home-vprops {
  padding: 2.5rem 0 0.75rem;
}
.home-vprops__grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.9rem;
  /* 6 ventajas → 3 columnas (3+3) en escritorio, 2 en tablet, 1 en móvil:
     una rejilla equilibrada en vez del 4+2 que dejaba un hueco. */
  grid-template-columns: repeat(3, 1fr);
}
@media (max-width: 920px) {
  .home-vprops__grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .home-vprops__grid { grid-template-columns: 1fr; }
}
/* Tarjeta PLANA: el borde sostiene la tarjeta en vez de la sombra, que es lo
   que envejecía el bloque. Rejilla de 2 columnas (icono | texto) con el título
   a la altura del icono: la tarjeta queda más baja y las dos filas dejan de
   arrastrar el hueco muerto que quedaba debajo del cuerpo más corto. */
.home-vprops__item {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: 0.95rem;
  row-gap: 0.4rem;
  align-content: start;
  padding: 1.45rem 1.45rem 1.55rem;
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  transition: border-color 0.18s ease, background-color 0.18s ease;
}
/* Sin translate al pasar: seis tarjetas saltando es ruido. Basta con que el
   borde tome el color de marca y el fondo se tiña un punto. */
.home-vprops__item:hover {
  border-color: color-mix(in srgb, var(--theme-accent) 45%, var(--theme-border));
  background: color-mix(in srgb, var(--theme-accent-soft) 40%, var(--theme-surface));
}
/* Icono al 10% de acento con el glifo en color de marca. Antes eran seis
   pastillas azules macizas que competían con los titulares y, al repetirse,
   dominaban el bloque entero. */
.home-vprops__icon {
  grid-column: 1;
  grid-row: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.4rem;
  height: 2.4rem;
  border-radius: var(--ui-radius-md);
  background: color-mix(in srgb, var(--theme-accent) 10%, transparent);
  color: var(--theme-accent);
}
.home-vprops__icon svg { width: 1.25rem; height: 1.25rem; }
.home-vprops__title {
  grid-column: 2;
  grid-row: 1;
  align-self: center;
  margin: 0;
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: -0.015em;
}
.home-vprops__body {
  grid-column: 2;
  grid-row: 2;
  margin: 0;
  color: var(--theme-ink-muted);
  font-size: 0.9rem;
  line-height: 1.6;
}

/* ---- Enlazado cruzado curso <-> asignatura al pie de las colecciones.
   Chips en vez de lista vertical: son hasta 24 enlaces y en columna
   empujarian el pie a dos pantallas de distancia. ---- */
.collection-crosslinks {
  margin-top: 2rem;
  display: grid;
  gap: 1.5rem;
}
.collection-crosslinks__title {
  margin: 0 0 0.7rem;
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: -0.015em;
}
.collection-crosslinks__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
}
.collection-crosslinks__list a {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.4rem 0.7rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-pill);
  font-size: 0.88rem;
  text-decoration: none;
  color: var(--theme-ink-soft);
  transition: border-color 0.18s ease, background-color 0.18s ease;
}
.collection-crosslinks__list a:hover {
  border-color: color-mix(in srgb, var(--theme-accent) 45%, var(--theme-border));
  background: color-mix(in srgb, var(--theme-accent-soft) 45%, var(--theme-surface));
}
.collection-crosslinks__count {
  font-size: 0.78rem;
  color: var(--theme-ink-muted);
}

/* ---- Teaser "cómo funciona": CTA centrada bajo los 3 pasos. ---- */
.how-it-works__cta {
  display: flex;
  justify-content: center;
  margin-top: 1.75rem;
}

/* ---- Intro de la sección de categorías (eyebrow + título + entradilla). ---- */
.home-categories__intro {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}
.home-categories__section-title {
  margin: 0.15rem 0 0;
  font-size: clamp(1.4rem, 2.6vw, 1.9rem);
  font-weight: 700;
  letter-spacing: -0.02em;
}
.home-categories__section-lead {
  margin: 0.35rem 0 0;
  color: var(--theme-ink-soft);
  font-size: 1rem;
  line-height: 1.6;
}

/* ---- Últimos libros añadidos (rejilla de novedades, 4 columnas). ---- */
.home-latest {
  padding: 1.5rem 0 2.5rem;
}
.home-latest__intro {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  max-width: 46rem;
  margin: 0 0 1.6rem;
}
.home-latest__title {
  margin: 0.15rem 0 0;
  font-size: clamp(1.4rem, 2.6vw, 1.9rem);
  font-weight: 700;
  letter-spacing: -0.02em;
}
.home-latest__lead {
  margin: 0.35rem 0 0;
  color: var(--theme-ink-soft);
  font-size: 1rem;
  line-height: 1.6;
}
.home-latest__cta {
  display: flex;
  justify-content: center;
  margin: 1.8rem 0 0;
}
body.theme-confeti .home-latest__title { font-weight: 800; }

/* ---- FAQ honesta (CSS-only con <details>). ---- */
.home-faq {
  padding: 1.5rem 0 2.5rem;
}
.home-faq__intro {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  margin: 0 0 1.5rem;
}
.home-faq__section-title {
  margin: 0.15rem 0 0;
  font-size: clamp(1.4rem, 2.6vw, 1.9rem);
  font-weight: 700;
  letter-spacing: -0.02em;
}
.home-faq__list {
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
}
.home-faq__item {
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-md);
  box-shadow: var(--ui-shadow-sm);
  overflow: hidden;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.home-faq__item[open] {
  border-color: var(--ui-accent-tint);
  box-shadow: var(--ui-shadow-md);
}
.home-faq__item > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.05rem 1.25rem;
  cursor: pointer;
  list-style: none;
  font-family: var(--theme-font-heading);
  font-weight: 700;
  font-size: 1.02rem;
  color: var(--theme-ink);
}
.home-faq__item > summary::-webkit-details-marker { display: none; }
.home-faq__item > summary::after {
  content: "";
  flex-shrink: 0;
  width: 1.1rem;
  height: 1.1rem;
  background: currentColor;
  color: var(--theme-accent);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") center / contain no-repeat;
  transition: transform 0.18s ease;
}
.home-faq__item[open] > summary::after { transform: rotate(180deg); }
.home-faq__item > summary:hover { color: var(--theme-accent); }
.home-faq__item > summary:focus-visible {
  outline: 2px solid var(--ui-accent-ring);
  outline-offset: -2px;
}
.home-faq__item p {
  margin: 0;
  padding: 0 1.25rem 1.15rem;
  color: var(--theme-ink-soft);
  font-size: 0.96rem;
  line-height: 1.65;
}

/* ---- Banda CTA final: cierre sobre fondo de marca. ---- */
.home-cta {
  margin: 2.5rem 0;
  padding: clamp(2rem, 5vw, 3rem) clamp(1.25rem, 4vw, 2.5rem);
  text-align: center;
  border-radius: var(--ui-radius-xl);
  background: linear-gradient(135deg, color-mix(in srgb, var(--theme-accent) 82%, #fff) 0%, var(--theme-accent) 55%, var(--ui-accent-strong) 100%);
  color: #fff;
}
.home-cta__title {
  margin: 0;
  font-size: clamp(1.5rem, 3.2vw, 2.2rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: #fff;
  max-width: 28ch;
  margin-inline: auto;
}
.home-cta__lead {
  margin: 0.75rem auto 0;
  max-width: 40rem;
  color: rgba(255, 255, 255, 0.92);
  font-size: clamp(1rem, 1.6vw, 1.15rem);
  line-height: 1.6;
}
.home-cta__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem;
  justify-content: center;
  margin-top: 1.6rem;
}

/* =========================================================================
   PLANETA · refinamiento de las nuevas secciones de la home (azul editorial).
   ========================================================================= */
body.theme-confeti .home-vprops { padding-top: 2.75rem; }
/* El tema `planeta` es el que corre en producción, así que sus overrides ganan:
   si no se rebajan aquí también, el rediseño plano no se ve. Se deja sólo un
   matiz de borde; la sombra grande y la pastilla azul maciza se retiran. */
body.theme-confeti .home-vprops__item {
  border-color: color-mix(in srgb, var(--theme-accent) 14%, var(--theme-border));
}

body.theme-confeti .home-categories__section-title,
body.theme-confeti .home-faq__section-title { font-weight: 800; }

body.theme-confeti .how-it-works__steps { text-align: left; }

body.theme-confeti .home-faq__item { border-radius: var(--ui-radius-md); }
body.theme-confeti .home-faq__item[open] { border-color: var(--theme-accent); }

/* CTA final: degradado navy editorial, coherente con el bloque "función
   estrella" y el footer. */
body.theme-confeti .home-cta {
  background: linear-gradient(135deg, var(--pl-navy) 0%, var(--pl-navy-2) 100%);
}
body.theme-confeti .home-cta .btn-pill--light { color: var(--pl-navy); }
body.theme-confeti .home-cta .btn-pill--light:hover,
body.theme-confeti .home-cta .btn-pill--light:focus { color: var(--pl-navy); background: var(--theme-accent-soft); }

/* =========================================================================
   Banner de consentimiento de cookies (RGPD / Guía AEPD). CSP-safe: la lógica
   vive en public/js/cookie-consent.js; el markup en partials/cookie-banner.ejs.
   "Rechazar" y "Aceptar" comparten EXACTAMENTE el estilo .cookie-btn--solid
   (mismo peso visual) para no incurrir en patrones engañosos.
   ========================================================================= */
/* MODAL centrado con overlay, no barra inferior (11-ago-2026): la barra se
   ignoraba, y en esta web ignorar = no medir NADA (sin decisión no se carga
   ningún tag con cookies). El modal fuerza una DECISIÓN, no una aceptación:
   Rechazar sigue al mismo nivel y peso que Aceptar (guía AEPD) y no hay X que
   lo esquive — se sale decidiendo. */
.cookie-banner {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background: rgba(15, 23, 42, 0.55);
}
.cookie-banner.is-hidden { display: none; }
/* Mientras el modal está abierto, el fondo no scrollea. `:has()` degrada con
   elegancia: sin soporte, solo se pierde el bloqueo de scroll. */
body:has(.cookie-banner:not(.is-hidden)) { overflow: hidden; }
.cookie-banner__inner {
  background: var(--theme-surface, #fff);
  border: 1px solid var(--theme-border, var(--theme-border));
  border-radius: var(--ui-radius-lg);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.35);
  max-width: 560px;
  width: 100%;
  max-height: min(88vh, 40rem);
  overflow-y: auto;
  padding: 1.35rem 1.35rem 1.15rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.85rem 1.5rem;
}
.cookie-banner__body { flex: 1 1 320px; min-width: 0; }
.cookie-banner__title { margin: 0 0 0.25rem; font-size: 1.05rem; font-weight: 700; }
.cookie-banner__text {
  margin: 0;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--theme-ink-soft, var(--theme-ink-soft));
}
.cookie-banner__text a { color: var(--theme-accent, var(--theme-accent)); }
.cookie-banner__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  /* A ancho completo bajo el texto: en el modal los botones cierran la caja. */
  flex: 1 1 100%;
  justify-content: flex-end;
}
.cookie-btn {
  appearance: none;
  cursor: pointer;
  font: inherit;
  font-weight: 600;
  font-size: 0.9rem;
  padding: 0.6rem 1.1rem;
  border-radius: var(--ui-radius-cta);
  border: 1px solid transparent;
  line-height: 1.1;
}
.cookie-btn:focus-visible { outline: 2px solid var(--ui-accent-ring, var(--theme-accent)); outline-offset: 2px; }
.cookie-btn--solid {
  background: var(--theme-accent, var(--theme-accent));
  color: #fff;
  border-color: var(--theme-accent, var(--theme-accent));
}
.cookie-btn--solid:hover { filter: brightness(0.94); }
.cookie-btn--ghost {
  background: transparent;
  color: var(--theme-ink, var(--theme-ink));
  border-color: var(--theme-border, color-mix(in srgb, var(--theme-border) 60%, var(--theme-ink-muted)));
}
.cookie-btn--ghost:hover { border-color: var(--theme-accent, var(--theme-accent)); }
.cookie-prefs {
  flex: 1 1 100%;
  margin-top: 0.5rem;
  padding-top: 0.85rem;
  border-top: 1px solid var(--theme-border, var(--theme-border));
  max-width: 1100px;
}
.cookie-prefs[hidden] { display: none; }
.cookie-prefs__intro { margin: 0 0 0.6rem; font-size: 0.85rem; color: var(--theme-ink-soft, var(--theme-ink-soft)); }
.cookie-prefs__row {
  display: flex;
  gap: 0.6rem;
  align-items: flex-start;
  padding: 0.4rem 0;
  font-size: 0.88rem;
  line-height: 1.45;
}
.cookie-prefs__row input { margin-top: 0.2rem; flex: 0 0 auto; }
.cookie-prefs__row--locked { color: var(--theme-ink-soft, var(--theme-ink-soft)); }
.cookie-prefs__actions { margin-top: 0.6rem; }

@media (max-width: 640px) {
  .cookie-banner__actions { width: 100%; }
  .cookie-btn { flex: 1 1 auto; text-align: center; }
}

/* =========================================================================
   Colegios por ciudad — índice /ciudades y ficha de ciudad /ciudad/:slug
   ========================================================================= */

/* Ficha técnica: ocupa el sitio del «Sobre este libro» cuando no hay sinopsis
   de verdad (antes salía el título repetido como descripción). */
.book-specs {
  background: var(--theme-surface, #fff);
  border: 1px solid var(--theme-border, var(--theme-border));
  border-radius: var(--ui-radius-lg);
  padding: 1.1rem 1.25rem;
  margin: 1.25rem 0;
}
.book-specs h2 { margin: 0 0 0.9rem; font-size: 1.15rem; }
/* Tiles con icono: etiqueta arriba en versalitas, valor en negrita debajo y el
   icono como ancla visual dentro de un círculo del acento suave. */
.spec-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 0.9rem 1.4rem;
}
.spec {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  min-width: 0;
}
.spec__icon {
  flex: none;
  width: 2.35rem;
  height: 2.35rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--theme-accent-soft, var(--theme-surface-alt, transparent));
  color: var(--theme-accent, var(--theme-accent));
}
.spec__icon svg { width: 1.15rem; height: 1.15rem; }
.spec__body { display: flex; flex-direction: column; min-width: 0; }
.spec__label {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
  color: var(--theme-ink-muted, var(--theme-ink-soft));
}
.spec__value {
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--theme-ink, var(--theme-ink));
  overflow-wrap: anywhere;
}
.spec__value a { color: var(--theme-accent, var(--theme-accent)); }

.cities-header,
.city-header { padding: 0.5rem 0 1.6rem; }
.cities-header__title,
.city-header__title {
  margin: 0 0 0.35rem;
  font-size: clamp(1.6rem, 3vw, 2.1rem);
  font-weight: 800;
  letter-spacing: -0.02em;
}
.cities-header__meta,
.city-header__meta { margin: 0; color: var(--theme-ink-soft); }

/* /ciudades — rejilla de ciudades */
.city-grid {
  list-style: none;
  margin: 0 0 2.5rem;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 0.75rem;
}
.city-grid__item { margin: 0; }
.city-grid__link {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  height: 100%;
  padding: 0.85rem 1rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  background: var(--theme-surface);
  color: var(--theme-ink);
  text-decoration: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}
.city-grid__link:hover,
.city-grid__link:focus-visible {
  border-color: var(--theme-accent);
  box-shadow: 0 6px 18px color-mix(in srgb, var(--theme-accent) 16%, transparent);
  transform: translateY(-2px);
}
.city-grid__pin {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.1rem;
  height: 2.1rem;
  flex: none;
  border-radius: var(--ui-radius-md);
  background: var(--theme-accent-soft);
  color: var(--theme-accent);
}
.city-grid__pin svg { width: 1.15rem; height: 1.15rem; }
.city-grid__text { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.city-grid__name { font-weight: 700; line-height: 1.2; }
.city-grid__count { font-size: 0.82rem; color: var(--theme-ink-soft); }

/* /ciudad/:slug — rejilla de colegios */
.school-cards {
  list-style: none;
  margin: 0 0 2rem;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 0.9rem;
}
.school-card { margin: 0; }
.school-card__link {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  height: 100%;
  padding: 1.1rem 1.2rem 1.2rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  background: var(--theme-surface);
  color: var(--theme-ink);
  text-decoration: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}
.school-card__link:hover,
.school-card__link:focus-visible {
  border-color: var(--theme-accent);
  box-shadow: 0 8px 22px color-mix(in srgb, var(--theme-accent) 15%, transparent);
  transform: translateY(-2px);
}
.school-card__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}
.school-card__badge {
  display: inline-flex;
  align-items: center;
  padding: 0.2rem 0.6rem;
  border-radius: var(--ui-radius-pill);
  font-size: 0.74rem;
  font-weight: 700;
  background: var(--theme-surface-alt);
  color: var(--theme-ink-soft);
}
.school-card__badge[data-type="publico"] { background: var(--theme-accent-soft); color: #1c54c4; }
.school-card__badge[data-type="concertado"] { background: #e7f6ec; color: #1f8a4c; }
.school-card__badge[data-type="privado"] { background: #f3ecfc; color: #6b39c9; }
.school-card__arrow {
  display: inline-flex;
  color: var(--theme-ink-muted);
  transition: transform 0.15s ease, color 0.15s ease;
}
.school-card__arrow svg { width: 1.1rem; height: 1.1rem; }
.school-card__link:hover .school-card__arrow {
  color: var(--theme-accent);
  transform: translateX(3px);
}
.school-card__name {
  margin: 0;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.3;
}
.school-card__addr {
  display: flex;
  align-items: flex-start;
  gap: 0.4rem;
  color: var(--theme-ink-soft);
  font-size: 0.85rem;
  line-height: 1.35;
}
.school-card__addr svg {
  width: 0.95rem;
  height: 0.95rem;
  flex: none;
  margin-top: 0.12rem;
  color: var(--theme-ink-muted);
}
.school-card__stages {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-top: auto;
  padding-top: 0.25rem;
}
.stage-tag {
  display: inline-flex;
  align-items: center;
  padding: 0.15rem 0.5rem;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-surface-alt);
  color: var(--theme-ink-soft);
  font-size: 0.72rem;
  font-weight: 600;
}

/* =========================================================================
   Ficha de colegio — /colegio/:slug
   ========================================================================= */

.school__header {
  display: flex;
  gap: 1.1rem;
  padding: 1.5rem 1.6rem;
  margin: 0 0 1.5rem;
  background: var(--theme-surface-alt);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
}
.school__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  flex: none;
  border-radius: var(--ui-radius-md);
  background: var(--theme-accent-soft);
  color: var(--theme-accent);
}
.school__icon svg { width: 1.6rem; height: 1.6rem; }
.school__head-body { display: flex; flex-direction: column; gap: 0.55rem; min-width: 0; }
.school__name {
  margin: 0;
  font-size: clamp(1.35rem, 2.6vw, 1.85rem);
  font-weight: 800;
  line-height: 1.2;
  letter-spacing: -0.02em;
}
.school__facts {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
  color: var(--theme-ink-soft);
  font-size: 0.9rem;
}
.school__addr { display: inline-flex; align-items: center; gap: 0.35rem; }
.school__addr svg { width: 0.95rem; height: 0.95rem; flex: none; color: var(--theme-ink-muted); }
.school__stages { display: flex; flex-wrap: wrap; gap: 0.35rem; }
.school__stats { display: flex; flex-wrap: wrap; gap: 0.55rem; margin-top: 0.15rem; }
.school__stat {
  display: inline-flex;
  align-items: baseline;
  gap: 0.3rem;
  padding: 0.35rem 0.75rem;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  font-size: 0.84rem;
  color: var(--theme-ink-soft);
}
.school__stat strong { font-size: 1.05rem; font-weight: 800; color: var(--theme-ink); }

/* Badge de tipo (compartido con las tarjetas de /ciudad) */
.school__badge {
  display: inline-flex;
  align-items: center;
  padding: 0.2rem 0.6rem;
  border-radius: var(--ui-radius-pill);
  font-size: 0.74rem;
  font-weight: 700;
  background: var(--theme-surface-alt);
  color: var(--theme-ink-soft);
}
.school__badge[data-type="publico"] { background: var(--theme-accent-soft); color: #1c54c4; }
.school__badge[data-type="concertado"] { background: #e7f6ec; color: #1f8a4c; }
.school__badge[data-type="privado"] { background: #f3ecfc; color: #6b39c9; }

/* Índice de cursos (chips de navegación) */
.school__toc {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 1.75rem;
}
.school__toc-label { font-weight: 600; color: var(--theme-ink-soft); font-size: 0.9rem; }
.school__toc-chip {
  display: inline-flex;
  align-items: center;
  padding: 0.4rem 0.85rem;
  border-radius: var(--ui-radius-pill);
  border: 1px solid var(--theme-border);
  background: var(--theme-surface);
  color: var(--theme-ink);
  font-size: 0.88rem;
  font-weight: 600;
  text-decoration: none;
  transition: border-color 0.15s ease, color 0.15s ease, background-color 0.15s ease;
}
.school__toc-chip:hover,
.school__toc-chip:focus-visible {
  border-color: var(--theme-accent);
  color: var(--theme-accent);
  background: var(--theme-accent-soft);
}

/* Cabecera de cada curso */
.school-course { scroll-margin-top: 84px; margin-bottom: 2.25rem; }
.school-course__title {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin: 0 0 1rem;
  padding-bottom: 0.6rem;
  font-size: clamp(1.2rem, 2.2vw, 1.5rem);
  font-weight: 800;
  border-bottom: 2px solid var(--theme-border);
}
.school-course__count {
  display: inline-flex;
  align-items: center;
  padding: 0.15rem 0.6rem;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent-soft);
  color: var(--theme-accent);
  font-size: 0.8rem;
  font-weight: 700;
}

.school__description {
  margin: 0 0 1.5rem;
  color: var(--theme-ink-soft);
  line-height: 1.6;
}
.school__links { margin-top: 2.25rem; }
.school__booklist-source { margin-top: 1.5rem; color: var(--theme-ink-soft); font-size: 0.9rem; }

/* Botón "añadir todo el curso a la comparativa" (tras el detalle por libro) */
.school-course__add { margin-top: 1.25rem; }
.school-course__add-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.7rem 1.35rem;
  border-radius: var(--ui-radius-pill);
  border: 1px solid var(--theme-accent);
  background: var(--theme-accent);
  color: #fff;
  font: inherit;
  font-weight: 700;
  font-size: 0.92rem;
  cursor: pointer;
  transition: filter 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}
.school-course__add-btn:hover {
  filter: brightness(1.06);
  box-shadow: 0 6px 16px color-mix(in srgb, var(--theme-accent) 28%, transparent);
  transform: translateY(-1px);
}

/* ===== Ofertas sin precio mostrable (Amazon: catálogo base sin refresco) ===== */
.offer__pricing--unknown .offer__price-unknown {
  display: block;
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--theme-ink-soft, #445);
}

.book-card__price--consult {
  color: var(--theme-ink-soft, #556);
  font-weight: 600;
}

/* ===== Mix óptimo destacado (la combinación más barata, abierta) ===== */
.list-mix--featured {
  border: 2px solid var(--theme-accent, var(--theme-accent));
  border-radius: var(--ui-radius-md);
  background: var(--theme-accent-soft, var(--theme-accent-soft));
  margin-bottom: 1.4rem;
}

.list-mix--featured > .list-mix__summary {
  font-size: 1.05rem;
}

.list-mix--featured .list-mix__summary-label {
  font-weight: 800;
  color: var(--theme-ink, #123);
}

.list-mix__saving {
  color: var(--theme-success, var(--theme-success));
  font-weight: 800;
}

/* ===== Cesta de Amazon como acción secundaria de la lista ===== */
.list-buys__amazon {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.7rem 1.2rem;
  margin-top: 1rem;
  padding: 0.9rem 1.1rem;
  border: 1px dashed var(--theme-border, #d5dde5);
  border-radius: var(--ui-radius-sm);
  background: var(--theme-surface-alt, #f7fafc);
}

.list-buys__amazon-text {
  flex: 1 1 18rem;
  font-size: 0.92rem;
  color: var(--theme-ink-soft, #445);
}

.list-buys__amazon-cta {
  display: inline-block;
  padding: 0.55rem 1.1rem;
  border-radius: var(--ui-radius-pill);
  background: #ff9900;
  color: #111;
  font-weight: 700;
  text-decoration: none;
  white-space: nowrap;
}

.list-buys__amazon-cta:hover { filter: brightness(0.95); }

/* ===== Feedback de subida de lista (foto/PDF) ===== */
.compare-upload__file {
  margin: 0.5rem 0 0;
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--theme-success, var(--theme-success));
  word-break: break-all;
}

.compare-form__submit[disabled] {
  opacity: 0.7;
  cursor: progress;
}

/* Archivo elegido: el recuadro tiene que cambiar lo bastante como para que se
   vea de un vistazo que el fichero entró. Antes no cambiaba nada y el usuario
   no sabía si había pasado algo ni que faltaba pulsar el botón. */
.dropzone.is-loaded {
  border-style: solid;
  border-color: var(--theme-success, var(--theme-success));
  background: color-mix(in srgb, var(--theme-success, var(--theme-success)) 8%, var(--theme-surface));
}
.dropzone.is-loaded .dropzone__icon { color: var(--theme-success, var(--theme-success)); }
.dropzone.is-loaded .dropzone__title { word-break: break-all; }

/* Arrastrando un fichero por encima: confirma que el recuadro acepta el drop. */
.dropzone.is-dragover {
  border-style: solid;
  border-color: var(--theme-accent);
  background: color-mix(in srgb, var(--theme-accent) 16%, var(--theme-surface));
  box-shadow: var(--ui-shadow-sm);
}

/* El botón pasa a primer plano en cuanto hay archivo: es el paso que se perdía. */
.compare-form__submit.is-ready {
  animation: upload-ready-pulse 1.6s ease-out 2;
}
@keyframes upload-ready-pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--theme-accent) 55%, transparent); }
  70%  { box-shadow: 0 0 0 0.65rem color-mix(in srgb, var(--theme-accent) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--theme-accent) 0%, transparent); }
}

/* Barra indeterminada durante la subida. El <form> nativo no expone progreso,
   así que no fingimos un porcentaje: sólo decimos "esto sigue vivo". Subir 3 MB
   por el enlace de subida de una conexión doméstica tarda, y sin esto parecía
   que la web se había colgado. */
.upload-progress {
  margin: 0;
  height: 0.3rem;
  border-radius: var(--ui-radius-pill);
  background: color-mix(in srgb, var(--theme-accent) 18%, var(--theme-surface));
  overflow: hidden;
}
.upload-progress__bar {
  display: block;
  height: 100%;
  width: 40%;
  border-radius: inherit;
  background: var(--theme-accent);
  animation: upload-progress-slide 1.1s ease-in-out infinite;
}
@keyframes upload-progress-slide {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(250%); }
}
.compare-upload.is-uploading .dropzone { cursor: progress; }

@media (prefers-reduced-motion: reduce) {
  .compare-form__submit.is-ready { animation: none; }
  .upload-progress__bar { animation: none; width: 100%; opacity: 0.65; }
}

/* ===== Precio más bajo en 30 días (price_history) ===== */
.offers__lowest30 {
  margin: 0.2rem 0 0.8rem;
  font-size: 0.92rem;
  color: var(--theme-ink-soft, #445);
}

.offers__lowest30 strong {
  color: var(--theme-success, var(--theme-success));
}

/* ===== Navegación de dos verticales (texto / todos los libros) ===== */
.nav-group {
  position: relative;
  display: inline-flex;
  align-items: center;
}

.nav-group__label {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  white-space: nowrap;
  font-weight: 600;
}

.nav-group__caret {
  font-size: 0.62em;
  line-height: 1;
  opacity: 0.65;
  transform: translateY(1px);
}

.nav-group:hover .nav-group__caret,
.nav-group:focus-within .nav-group__caret {
  opacity: 1;
}

/* Desktop: menú desplegable en hover/focus. */
@media (min-width: 721px) {
  .nav-group__menu {
    position: absolute;
    top: calc(100% + 0.55rem);
    left: 50%;
    transform: translateX(-50%);
    min-width: 15rem;
  }

  /* Puente invisible label→menú para que el hover no se corte en el hueco. */
  .nav-group::after {
    content: '';
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    height: 0.6rem;
  }

  .nav-group__menu {
    display: none;
    flex-direction: column;
    padding: 0.5rem 0;
    background: var(--theme-surface, #fff);
    border: 1px solid var(--theme-border, var(--theme-border));
    border-radius: var(--ui-radius-sm);
    box-shadow: var(--ui-shadow-md, 0 10px 26px rgba(16, 42, 67, 0.14));
    z-index: 60;
  }

  .nav-group:hover .nav-group__menu,
  .nav-group:focus-within .nav-group__menu {
    display: flex;
  }

  .nav-group__menu a {
    padding: 0.5rem 1.1rem;
    white-space: nowrap;
  }

  .nav-group__menu a:hover {
    background: var(--theme-accent-soft, var(--theme-accent-soft));
  }
}

/* Móvil (nav off-canvas): los grupos se muestran expandidos como secciones. */
@media (max-width: 720px) {
  .nav-group {
    display: block;
    width: 100%;
  }

  .nav-group__label {
    display: block;
    font-weight: 800;
    pointer-events: auto;
  }

  .nav-group__caret { display: none; }

  .nav-group__menu {
    display: flex;
    flex-direction: column;
    padding-left: 0.9rem;
  }
}

/* =========================================================================
   Chat widget (asistente de libros). Lógica en public/js/chat-widget.js
   (CSP-safe, solo se monta si /api/chat/status responde enabled). Colores,
   radios y sombras SIEMPRE vía tokens del tema para heredar el preset activo
   (Planeta por defecto): nada hardcodeado salvo los fallbacks.
   ========================================================================= */

.clchat-launcher {
  position: fixed;
  right: 1.2rem;
  bottom: 1.2rem;
  /* Bajo el banner de cookies (z 1000): el consentimiento siempre gana. */
  z-index: 90;
  width: 3.5rem;
  height: 3.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  background: var(--theme-accent, var(--theme-accent));
  color: #fff;
  cursor: pointer;
  box-shadow: var(--ui-shadow-accent, 0 12px 30px color-mix(in srgb, var(--theme-accent) 32%, transparent));
  transition: transform 0.15s ease, background 0.15s ease;
}

.clchat-launcher:hover {
  background: var(--ui-accent-strong, var(--ui-accent-strong));
  transform: translateY(-2px);
}

.clchat-launcher:focus-visible {
  outline: 3px solid var(--ui-accent-ring, color-mix(in srgb, var(--theme-accent) 30%, transparent));
  outline-offset: 2px;
}

.clchat-launcher svg { display: block; }

.clchat-panel {
  position: fixed;
  right: 1.2rem;
  /* Deja la burbuja visible debajo: sirve de segundo botón de cierre. */
  bottom: 5.4rem;
  z-index: 91;
  width: min(380px, calc(100vw - 2rem));
  height: min(560px, calc(100dvh - 6rem));
  display: flex;
  flex-direction: column;
  background: var(--theme-surface, #fff);
  border: 1px solid var(--theme-border, var(--theme-border));
  border-radius: var(--ui-radius-lg);
  box-shadow: var(--ui-shadow-lg, 0 22px 50px rgba(31, 27, 46, 0.14));
  overflow: hidden;
}

.clchat-panel[hidden] { display: none; }

.clchat-head {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.8rem 1rem;
  background: var(--theme-accent, var(--theme-accent));
  color: #fff;
}

.clchat-head__title {
  flex: 1;
  min-width: 0;
  font-family: var(--theme-font-heading, inherit);
  font-weight: 700;
  font-size: 1rem;
}

.clchat-head__close {
  display: flex;
  border: none;
  background: transparent;
  color: inherit;
  cursor: pointer;
  padding: 0.3rem;
  border-radius: var(--ui-radius-sm);
}

.clchat-head__close:hover { background: rgba(255, 255, 255, 0.18); }

.clchat-head__close:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
}

.clchat-msgs {
  flex: 1;
  overflow-y: auto;
  /* Evita que el scroll del hilo arrastre el scroll de la página. */
  overscroll-behavior: contain;
  padding: 1rem 0.9rem;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  background: var(--theme-bg, #fff);
}

.clchat-msg {
  max-width: 85%;
  padding: 0.55rem 0.8rem;
  border-radius: var(--ui-radius-md);
  font-size: 0.92rem;
  line-height: 1.45;
  overflow-wrap: break-word;
}

.clchat-msg--user {
  align-self: flex-end;
  background: var(--theme-accent, var(--theme-accent));
  color: #fff;
  border-bottom-right-radius: var(--theme-radius, 4px);
  /* El usuario puede meter saltos con Shift+Enter (textContent, sin <br>). */
  white-space: pre-wrap;
}

.clchat-msg--bot {
  align-self: flex-start;
  background: var(--theme-surface-alt, var(--theme-surface-alt));
  color: var(--theme-ink, var(--theme-ink));
  border-bottom-left-radius: var(--theme-radius, 4px);
}

.clchat-msg--error {
  background: color-mix(in srgb, var(--theme-danger, var(--theme-danger)) 8%, var(--theme-surface, #fff));
  border: 1px solid color-mix(in srgb, var(--theme-danger, var(--theme-danger)) 30%, transparent);
  color: var(--theme-danger, var(--theme-danger));
}

.clchat-msg__text a {
  color: var(--theme-accent, var(--theme-accent));
  text-decoration: underline;
}

.clchat-msg__text code {
  font-family: var(--theme-font-mono, monospace);
  font-size: 0.85em;
  background: rgba(0, 0, 0, 0.06);
  padding: 0.05rem 0.3rem;
  border-radius: var(--ui-radius-sm);
}

.clchat-msg__text ul {
  margin: 0.25rem 0 0.25rem 1.1rem;
  padding: 0;
}

/* Tarjetas de libro dentro de la respuesta del asistente */
.clchat-card {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  background: var(--theme-surface, #fff);
  border: 1px solid var(--theme-border, var(--theme-border));
  border-radius: var(--ui-radius-lg);
  padding: 0.5rem 0.6rem;
  margin: 0.45rem 0;
}

.clchat-card__img {
  width: 48px;
  height: auto;
  max-height: 72px;
  object-fit: contain;
  border-radius: var(--ui-radius-sm);
  flex-shrink: 0;
}

.clchat-card__body {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-width: 0;
}

.clchat-card__title {
  font-weight: 700;
  font-size: 0.88rem;
  color: var(--theme-ink, var(--theme-ink));
  text-decoration: none;
}

a.clchat-card__title:hover {
  color: var(--theme-accent, var(--theme-accent));
  text-decoration: underline;
}

.clchat-card__author {
  font-size: 0.78rem;
  color: var(--theme-ink-muted, var(--theme-ink-muted));
}

.clchat-card__price {
  font-size: 0.92rem;
  font-weight: 800;
  color: var(--theme-ink, var(--theme-ink));
}

.clchat-card__btn {
  align-self: flex-start;
  margin-top: 0.2rem;
  padding: 0.3rem 0.7rem;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent, var(--theme-accent));
  color: #fff;
  font-size: 0.78rem;
  font-weight: 700;
  text-decoration: none;
}

.clchat-card__btn:hover { background: var(--ui-accent-strong, var(--ui-accent-strong)); }

/* Chips de sugerencia inicial */
.clchat-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.clchat-chip {
  border: 1px solid var(--theme-accent, var(--theme-accent));
  color: var(--theme-accent, var(--theme-accent));
  background: var(--theme-surface, #fff);
  border-radius: var(--ui-radius-pill);
  padding: 0.35rem 0.75rem;
  font-size: 0.82rem;
  text-align: left;
  cursor: pointer;
}

.clchat-chip:hover { background: var(--theme-accent-soft, var(--theme-accent-soft)); }

.clchat-chip:focus-visible {
  outline: 2px solid var(--ui-accent-ring, color-mix(in srgb, var(--theme-accent) 30%, transparent));
  outline-offset: 2px;
}

/* Indicador de escritura (tres puntos) */
.clchat-typing {
  display: flex;
  gap: 0.3rem;
  padding: 0.7rem 0.9rem;
}

.clchat-typing span {
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
  background: var(--theme-ink-muted, var(--theme-ink-muted));
  animation: clchat-blink 1.1s infinite both;
}

.clchat-typing span:nth-child(2) { animation-delay: 0.18s; }
.clchat-typing span:nth-child(3) { animation-delay: 0.36s; }

@keyframes clchat-blink {
  0%, 80%, 100% { opacity: 0.25; transform: translateY(0); }
  40% { opacity: 1; transform: translateY(-2px); }
}

/* Formulario de envío */
.clchat-form {
  display: flex;
  align-items: flex-end;
  gap: 0.5rem;
  padding: 0.6rem 0.7rem;
  border-top: 1px solid var(--theme-border, var(--theme-border));
  background: var(--theme-surface, #fff);
}

.clchat-input {
  flex: 1;
  resize: none;
  min-height: 2.4rem;
  max-height: 120px;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--theme-border, var(--theme-border));
  border-radius: var(--ui-radius-md);
  font: inherit;
  font-size: 0.92rem;
  line-height: 1.35;
  color: var(--theme-ink, var(--theme-ink));
  background: var(--theme-bg, #fff);
}

.clchat-input:focus-visible {
  outline: 2px solid var(--ui-accent-ring, color-mix(in srgb, var(--theme-accent) 30%, transparent));
  border-color: var(--theme-accent, var(--theme-accent));
}

.clchat-send {
  flex-shrink: 0;
  width: 2.6rem;
  height: 2.6rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  background: var(--theme-accent, var(--theme-accent));
  color: #fff;
  cursor: pointer;
}

.clchat-send:hover { background: var(--ui-accent-strong, var(--ui-accent-strong)); }

.clchat-send:focus-visible {
  outline: 3px solid var(--ui-accent-ring, color-mix(in srgb, var(--theme-accent) 30%, transparent));
  outline-offset: 2px;
}

.clchat-send:disabled,
.clchat-input:disabled {
  opacity: 0.55;
  cursor: default;
}

/* Móvil: el panel ocupa casi toda la pantalla (tapa también la burbuja). */
@media (max-width: 480px) {
  .clchat-panel {
    left: 0.5rem;
    right: 0.5rem;
    bottom: 0.5rem;
    width: auto;
    height: calc(100dvh - 1.5rem);
  }
}

@media (prefers-reduced-motion: reduce) {
  .clchat-launcher { transition: none; }
  .clchat-launcher:hover { transform: none; }
  .clchat-typing span { animation: none; opacity: 0.6; }
}

/* ------------------------- Rail de compra (ficha) ------------------------ */
/* El clic a /out es la conversion del sitio y quedaba por debajo del pliegue.
   Este rail lo sube y lo mantiene a la vista mientras se lee la ficha. Reusa el
   MISMO enlace `/out/{merchant}/{isbn}` con sus atributos, asi que la medicion
   no cambia. La comparativa completa sigue abajo: esto no la sustituye. */
.buy-rail__inner {
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  background: var(--theme-surface);
  padding: 1rem;
  box-shadow: var(--theme-shadow-sm);
}
.buy-rail__title { margin: 0 0 0.75rem; font-weight: 700; font-size: 1rem; }
.buy-rail__list { list-style: none; margin: 0; padding: 0; }

/* Bloque de comparativa, encima de las tiendas. Va con fondo propio para que se
   lea como una accion DISTINTA de "comprar aqui" —es lo contrario: no te vayas
   todavia—, y separado por un borde inferior del listado de tiendas. */
/* Señal de la comparativa multi-libro en el hueco del hero: nota con enlace,
   no caja con botón — rellena el espacio que dejó la caja al mudarse tras los
   precios sin competir con el flujo de compra de un solo libro. */
.compare-hint {
  margin: 1.1rem 0 0;
  padding: 0.7rem 0.9rem;
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--theme-ink-soft, var(--theme-ink-soft));
  background: color-mix(in srgb, var(--theme-accent, var(--theme-accent)) 6%, transparent);
  border: 1px solid color-mix(in srgb, var(--theme-accent, var(--theme-accent)) 18%, transparent);
  border-radius: var(--ui-radius-md);
}
.compare-hint strong { color: var(--theme-ink, var(--theme-ink)); }
.compare-hint a {
  color: var(--theme-accent, var(--theme-accent));
  text-decoration: underline;
  text-underline-offset: 3px;
}
/* El botón que añade, con pinta de enlace: va en medio de la frase. */
.compare-hint__form { display: inline; }
.compare-hint__link {
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  cursor: pointer;
  color: var(--theme-accent, var(--theme-accent));
  text-decoration: underline;
  text-underline-offset: 3px;
}
.compare-hint__link:focus-visible { outline: 2px solid var(--ui-accent-ring, var(--theme-accent)); outline-offset: 2px; }

/* ------------------------- Buscador de cabecera -------------------------
   En posición PRIME tras el logo y ANCHO (crece hasta tocar el menú): es la
   herramienta nº 1 del sitio. Mismo diseño que el buscador del hero: pill
   claro con el botón-círculo de acento y la lupa DENTRO del botón. */
.site-header__inner { position: relative; }
.site-header__search-toggle { display: none; }
.site-header__search-btn { display: none; }
.site-header__search {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  flex: 1 1 auto;
  margin: 0 1rem 0 1.1rem;
  padding: 0.25rem 0.25rem 0.25rem 1rem;
  background: var(--theme-surface, #fff);
  border: 1.5px solid var(--theme-border, color-mix(in srgb, var(--theme-border) 60%, var(--theme-ink-muted)));
  border-radius: var(--ui-radius-pill);
  box-shadow: var(--theme-shadow-sm, none);
}
/* Sólo cambia el color del borde: borde + outline dibujaban un anillo doble
   (captura de Rafael). El borde pasando a acento ya señala el foco. */
.site-header__search:focus-within {
  border-color: var(--theme-accent, var(--theme-accent));
}
.site-header__search input[type='search'] {
  flex: 1 1 auto;
  min-width: 0;
  padding: 0.5rem 0.4rem;
  border: 0;
  font: inherit;
  font-size: 0.92rem;
  background: transparent;
  color: var(--theme-ink, var(--theme-ink));
}
.site-header__search input[type='search']:focus-visible { outline: none; }
.site-header__search-submit {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.3rem;
  height: 2.3rem;
  border: 0;
  border-radius: 50%;
  background: var(--theme-accent, var(--theme-accent));
  color: var(--theme-surface, #fff);
  cursor: pointer;
}
.site-header__search-submit svg { width: 1.1rem; height: 1.1rem; }
.site-header__search-submit:hover { filter: brightness(0.93); }
.site-header__search-submit:focus-visible {
  outline: 2px solid var(--ui-accent-ring, var(--theme-accent));
  outline-offset: 2px;
}
/* El panel de resultados hereda `left:0; right:0` del form y salía con el
   ancho del input: títulos truncados (feedback de Rafael con captura). Aquí se
   ensancha por encima del input, sin desbordar la pantalla. */
.site-header__search .live-search__panel {
  width: min(30rem, calc(100vw - 2rem));
  right: auto;
  z-index: 60;
}
@media (max-width: 719px) {
  /* La lupa junto a la hamburguesa; el formulario se despliega a ancho
     completo bajo la cabecera (mismo patrón checkbox CSS-only). */
  .site-header__search-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.4rem;
    height: 2.4rem;
    border: 1px solid var(--theme-border, color-mix(in srgb, var(--theme-border) 60%, var(--theme-ink-muted)));
    border-radius: var(--ui-radius-sm);
    color: var(--theme-ink, var(--theme-ink));
    cursor: pointer;
  }
  .site-header__search-btn svg { width: 1.25rem; height: 1.25rem; }
  .site-header__search {
    display: none;
    position: absolute;
    left: 0;
    right: 0;
    top: 100%;
    margin: 0;
    padding: 0.65rem 1rem;
    background: var(--theme-surface, #fff);
    border: 0;
    border-radius: 0;
    border-bottom: 1px solid var(--theme-border, var(--theme-border));
    box-shadow: 0 10px 24px rgba(15, 23, 42, 0.1);
    z-index: 30;
  }
  .site-header__search-toggle:checked ~ .site-header__search { display: flex; }
  .site-header__search .live-search__panel { width: 100%; right: 0; }
}

.buy-rail__trust {
  margin: 0.7rem 0 0;
  font-size: 0.78rem;
  line-height: 1.4;
  color: var(--theme-ink-muted, var(--theme-ink-muted));
  text-align: center;
}

.buy-rail__compare {
  /* Separacion mayor por debajo: va antes del titular «Comprar este libro» y
     tiene que leerse como un bloque APARTE, no como su entradilla. */
  margin: 0 0 1.1rem;
  padding: 0.75rem 0.8rem;
  /* `md`, no `sm`: esta caja queda pegada a la tarjeta del hero (radio lg) y
     el salto lg→sm entre vecinas era la esquina «rara» de la captura de
     Rafael (13-ago-2026). El paso intermedio suaviza la transición. */
  border-radius: var(--ui-radius-md);
  background: var(--theme-surface-alt, #f5f7fa);
  border: 1px solid var(--theme-border);
}
.buy-rail__compare--ok { border-color: color-mix(in srgb, var(--theme-success) 45%, transparent); }
.buy-rail__compare-text {
  margin: 0 0 0.6rem;
  font-size: 0.85rem;
  line-height: 1.4;
  color: var(--theme-muted, var(--theme-ink-soft));
}
.buy-rail__compare-text strong {
  display: block;
  color: inherit;
  font-size: 0.9rem;
  margin-bottom: 0.2rem;
  /* Entra en UNA linea por el copy, no por `nowrap`: con 23 caracteres sobra
     en los ~270px utiles de la columna. Forzarlo con `white-space: nowrap`
     habria bastado hoy, pero el texto es editable desde /admin/content y un
     override mas largo se saldria de la tarjeta en vez de partirse. */
}
/* Mismo boton azul que el CTA del medio (`.add-compare__btn`): el de contorno
   se leia como accion opcional cuando es la principal del sitio.

   `--buy-rail-btn-h` la comparten con los botones de tienda: aquel lleva el
   logo de 20px dentro y este no, asi que dejandolos al padding cada uno salia
   de una altura y en una columna estrecha, uno debajo de otro, el desajuste
   cantaba. Con `min-height` mandan los dos lo mismo lleve lo que lleve dentro. */
.buy-rail__inner { --buy-rail-btn-h: 2.75rem; }
.buy-rail__compare-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: var(--buy-rail-btn-h);
  padding: 0.4rem 0.7rem;
  font: inherit;
  font-size: 0.9rem;
  font-weight: 700;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  border: 0;
  border-radius: var(--ui-radius-cta);
  background: var(--theme-accent);
  color: var(--theme-surface);
}
a.buy-rail__compare-btn:hover,
.buy-rail__compare-btn:hover { filter: brightness(0.93); text-decoration: none; color: var(--theme-surface); }

.buy-rail__item { padding: 0.6rem 0; border-top: 1px solid var(--theme-border); }
.buy-rail__item:first-child { border-top: 0; padding-top: 0; }
.buy-rail__row { display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem; }
.buy-rail__merchant { font-weight: 600; font-size: 0.95rem; }
.buy-rail__total { font-weight: 800; font-size: 1.05rem; color: var(--theme-accent); }
.buy-rail__shipping {
  display: block;
  font-size: 0.8rem;
  color: var(--theme-ink-muted);
  margin: 0.1rem 0 0.5rem;
}
.buy-rail__btn {
  /* Flex, no block: el botón lleva el logo de la tienda junto al texto, igual
     que los de la comparativa completa (.offer__button-logo). El color de fondo
     lo pone la marca en línea, así que el logo es lo que hace reconocible el
     botón de un vistazo sin leerlo. */
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  text-align: center;
  min-height: var(--buy-rail-btn-h);
  padding: 0.4rem 0.8rem;
  border-radius: var(--ui-radius-cta);
  background: var(--theme-accent);
  color: #fff;
  font-weight: 700;
  font-size: 0.92rem;
  text-decoration: none;
}
.buy-rail__btn-logo {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  border-radius: 50%;
  background: #fff;
  padding: 2px;
  object-fit: contain;
}
.buy-rail__btn:hover { filter: brightness(0.93); text-decoration: none; color: #fff; }

/* Insignia «Más barato» junto al nombre de la mejor tienda: el mismo pill que
   la comparativa grande, para que el botón único del rail se lea como LO QUE
   ES — la ganadora — y no como la única opción. */
.buy-rail__flag {
  display: inline-block;
  margin-left: 0.3rem;
  padding: 0.12rem 0.5rem;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent);
  color: #fff;
  font-size: 0.66rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  vertical-align: 0.1em;
  white-space: nowrap;
}

/* Separador «También disponible en» entre la ganadora y las alternativas. */
.buy-rail__also {
  margin: 0.9rem 0 0.3rem;
  padding-top: 0.8rem;
  border-top: 1px solid var(--theme-border);
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--theme-ink-muted);
  list-style: none;
}
.buy-rail__also + .buy-rail__item { border-top: 0; }

/* Tiendas alternativas del rail: filas compactas donde TODA la fila es el
   enlace de compra. Con 5 tiendas, cinco botones grandes con su desglose
   medían más que el viewport y el rail sticky dejaba las últimas fuera de
   alcance (13-ago-2026, al entrar Abacus). Solo la mejor conserva el botón. */
/* Cada tienda alternativa es una FILA PULSABLE, y en reposo no lo parecia: era
   texto sobre el fondo de la tarjeta, separado por filetes, con el galon en
   gris. Habia hover, pero en el movil no hay hover. Ahora cada una es una
   pastilla con su borde —y el filete separador sobra, que si no son dos lineas
   juntas— y el galon va en color de marca, que es la senal de «esto lleva a
   algun sitio» (14-ago-2026). */
.buy-rail__item--alt { padding: 0.15rem 0; border-top: 0; }
.buy-rail__alt-link {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.55rem 0.6rem;
  border: 1px solid var(--theme-accent);
  border-radius: var(--ui-radius-md);
  background: var(--theme-accent-soft);
  color: var(--theme-ink);
  transition: background 0.15s ease, border-color 0.15s ease;
}
/* Reposo teñido y hover en blanco, no al revés: en la barra de compra estas
   filas son la alternativa REAL a la oferta destacada, y en blanco sobre tarjeta
   blanca no se leían como pulsables. El hover invierte el contraste, que sigue
   siendo un cambio visible al pasar por encima. */
.buy-rail__alt-link:hover {
  background: var(--theme-surface);
  border-color: var(--theme-accent);
  text-decoration: none;
}
.buy-rail__alt-logo { flex: none; border-radius: 4px; object-fit: contain; }
.buy-rail__alt-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 0.05rem; }
.buy-rail__alt-name { font-weight: 600; font-size: 0.9rem; line-height: 1.2; }
.buy-rail__alt-ship { font-size: 0.75rem; color: var(--theme-ink-muted); line-height: 1.2; }
/* «Envío gratis» en verde (señal positiva visible de un vistazo); el envío con
   coste queda en gris. Mismo tamaño: la visibilidad viene del color, no de
   crecer. */
.buy-rail__shipping.is-free,
.buy-rail__alt-ship.is-free { color: var(--theme-success, #16a34a); font-weight: 600; }
.buy-rail__alt-total { flex: none; font-weight: 800; font-size: 0.95rem; }
.buy-rail__alt-go { flex: none; color: var(--theme-accent); font-size: 1.15rem; line-height: 1; }
.buy-rail__alt-link:hover .buy-rail__alt-go { color: var(--theme-accent); }

.buy-rail__all {
  display: block;
  margin-top: 0.85rem;
  text-align: center;
  font-size: 0.88rem;
}

/* ESCRITORIO: columna pegajosa a la derecha. El rail necesita un AREA tan alta
   como el contenido de la izquierda; sin eso `sticky` no tiene recorrido y se
   queda quieto en su fila.

   Ojo con `grid-row: 1 / -1`, que es lo que habia aqui y NO hace lo que parece:
   `-1` apunta a la ultima linea de la rejilla EXPLICITA, y como aqui no hay
   `grid-template-rows`, esa linea es la 1. O sea que el rail se quedaba en la
   fila 1 —la cabecera del libro— y, al ser mas alto que ella, la estiraba: de
   ahi el hueco en mitad de la pagina, entre la cabecera y la comparativa.

   `span 99` si abarca todas las filas reales (las implicitas de mas se crean
   vacias y no ocupan). Al abarcarlas todas, el contenido de la izquierda ya
   suma mas alto que el rail y no hay sobrante que repartir. */
@media (min-width: 1100px) {
  .book-detail {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: 0 2rem;
    align-items: start;
  }
  .book-detail > *:not(.buy-rail) { grid-column: 1; }

  .buy-rail {
    grid-column: 2;
    grid-row: 1 / span 99;
    align-self: start;
    position: sticky;
    /* La cabecera tambien es `sticky` con `top: 0` y mide ~68px: con 1rem el
       rail se le pegaba por debajo sin aire. Se despeja su alto mas un margen. */
    top: 5.5rem;
    /* Red de seguridad: un sticky MAS ALTO que el viewport deja su final
       inaccesible mientras esta pegado (pasó con 5 tiendas y botón por tienda,
       13-ago-2026). Si el rail no cabe, scrollea por dentro en vez de cortarse.
       El padding/margin compensados evitan que el overflow recorte la sombra. */
    max-height: calc(100vh - 6rem);
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 4px;
    margin: -4px;
  }
}

/* POR DEBAJO DE 720 px NO HAY RAIL: manda `.buybar`.
   Las dos son barras `fixed; bottom: 0`, y en un movil se pintaban LAS DOS,
   apiladas una sobre otra, enseñando la misma oferta dos veces y tapandose entre
   ellas — el hueco reservado (`padding-bottom`) solo daba para una, asi que el
   final del contenido quedaba debajo. `.buybar` es la compacta (una fila: precio
   + boton) y la que se diseño para el movil; el rail-convertido-en-barra se
   queda para el tramo tablet, donde si es el unico. */
@media (max-width: 719px) {
  .buy-rail { display: none; }
}

/* TABLET: un rail lateral no cabe, asi que se convierte en barra inferior fija
   con SOLO la mejor oferta — mas de una en esa franja tapa la pagina. */
@media (min-width: 720px) and (max-width: 1099px) {
  .buy-rail {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 40;
    padding: 0.5rem 0.75rem calc(0.5rem + env(safe-area-inset-bottom));
    background: var(--theme-surface);
    border-top: 1px solid var(--theme-border);
    box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.08);
  }
  .buy-rail__inner { border: 0; padding: 0; box-shadow: none; background: none; }
  .buy-rail__title,
  .buy-rail__all,
  .buy-rail__compare,
  .buy-rail__also,
  .buy-rail__item:not(:first-child) { display: none; }
  .buy-rail__item:first-child { padding: 0; border: 0; }
  .buy-rail__row { display: inline-flex; }
  .buy-rail__shipping { display: inline; margin: 0 0 0 0.5rem; }
  .buy-rail__btn { margin-top: 0.4rem; }
  /* Hueco para que la barra no tape el final del contenido. */
  .book-detail { padding-bottom: 7.5rem; }
}

/* (La regla que apilaba las barras de compra sobre el banner de cookies se
   retiró el 11-ago-2026: el banner pasó de barra inferior a MODAL con overlay a
   pantalla completa, así que ya no hay solape que resolver — mientras el modal
   está abierto, decidir es lo único que se puede hacer, que es la intención.) */

/* ============ Buscador pegajoso + filtros en barra (08-ago-2026) ============
   La columna lateral de 240 px partia «Comercial Grupo Anaya S.a.» en dos
   lineas, apilaba veinte editoriales con sus recuentos y se quedaba con un
   quinto del ancho de forma permanente para una herramienta que se usa una vez
   y se cierra. Pasa a una barra de desplegables sobre los resultados. */

.search-sticky {
  position: sticky;
  /*
   * Se mete DEBAJO de la cabecera a propósito y despeja con el padding, no con
   * el `top`. Si empezara justo por debajo de la cabecera, entre las dos habría
   * una rendija por la que se ve pasar el contenido al desplazarse.
   *
   * El `top` era `3.6rem`/`4.2rem` a ojo, y la cabecera mide 77 px (4.83rem):
   * el desfase de 10 px se comía el borde superior del buscador, que quedaba 2
   * px POR ENCIMA del borde de la cabecera. Medido en producción.
   *
   * De ahí `--header-h`, que también dimensiona la cabecera: con el alto en un
   * solo sitio, los dos no pueden volver a desfasarse.
   */
  top: calc(var(--header-h) - 0.75rem);
  z-index: 12;
  margin: 0 0 1.25rem;
  padding: 1.15rem 0 0.5rem;
  /* Ni blanco sólido ni transparente: las dos fallan en un extremo distinto.
     Con `--theme-bg` opaco se recortaba un rectángulo blanco contra la capa
     decorativa azulada del tema; sin fondo, las portadas pasan nítidas por
     detrás al desplazarse. Un velo tenue + desenfoque del fondo funciona en los
     dos estados: arriba apenas se distingue de la capa decorativa (que es casi
     lisa) y en scroll disuelve lo que pasa por debajo. */
  background: color-mix(in srgb, var(--theme-bg) 72%, transparent);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
}
/* Sin soporte de `backdrop-filter` no hay desenfoque que valga: ahí sí compensa
   el fondo opaco, porque tapar mal es peor que recortar un rectángulo. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .search-sticky { background: var(--theme-bg); }
}

.search-layout { display: block; }

.facet-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 1.25rem;
}
.facet-bar__label {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--theme-ink-muted);
  margin-right: 0.15rem;
}
.facet-bar__label svg { width: 1rem; height: 1rem; }
.facet-bar__reset {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--theme-ink-muted);
  text-decoration: underline;
}
.facet-bar__reset:hover { color: var(--theme-accent); }

.facet-drop { position: relative; }
.facet-drop__btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.5rem 0.85rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-pill);
  background: var(--theme-surface);
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--theme-ink);
  cursor: pointer;
  list-style: none;
  white-space: nowrap;
}
.facet-drop__btn::-webkit-details-marker { display: none; }
.facet-drop__btn:hover { border-color: var(--theme-accent); color: var(--theme-accent); }
.facet-drop.is-active > .facet-drop__btn {
  background: var(--theme-accent-soft);
  border-color: color-mix(in srgb, var(--theme-accent) 45%, var(--theme-border));
  color: var(--theme-accent);
}
.facet-drop__value {
  max-width: 11rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 700;
}
.facet-drop__value::before { content: "· "; }
.facet-drop__caret { width: 0.85rem; height: 0.85rem; flex: none; transition: transform 0.15s ease; }
.facet-drop[open] > .facet-drop__btn > .facet-drop__caret { transform: rotate(180deg); }

.facet-drop__panel {
  position: absolute;
  top: calc(100% + 0.4rem);
  left: 0;
  z-index: 20;
  min-width: 15rem;
  max-width: min(24rem, 88vw);
  /* El tope de alto es lo que hace usable «Editorial», que trae veinte entradas
     con nombres largos: se desplaza dentro del panel en vez de estirar la barra. */
  max-height: min(60vh, 26rem);
  overflow-y: auto;
  padding: 0.4rem;
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  box-shadow: var(--ui-shadow-lg, 0 16px 40px rgba(8, 30, 60, 0.16));
}
.facet-drop__list { list-style: none; margin: 0; padding: 0; }
.facet-drop__list a {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.45rem 0.55rem;
  border-radius: var(--ui-radius-sm);
  color: var(--theme-ink-soft);
  font-size: 0.9rem;
}
.facet-drop__list a:hover { background: var(--theme-accent-soft); color: var(--theme-accent); text-decoration: none; }
.facet-drop__item-name { min-width: 0; }
.facet-drop__list .facet-count { flex: none; font-size: 0.8rem; color: var(--theme-ink-muted); font-variant-numeric: tabular-nums; }
.facet-drop__clear {
  display: block;
  padding: 0.45rem 0.55rem;
  margin-bottom: 0.25rem;
  border-bottom: 1px solid var(--theme-border);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--theme-danger, var(--theme-danger));
}

/* MOVIL: el panel deja de flotar y se abre a lo ancho, que a 360 px un
   desplegable posicionado se sale de la pantalla por un lado o por el otro.
   OJO: `.facet-drop` pasa a static, así que la barra TIENE que ser el ancla
   (`position: relative`) — sin ella, el panel absoluto buscaba el primer
   ancestro posicionado (ninguno en /editorial) y se pintaba al fondo del
   documento: los filtros «no funcionaban» en móvil (bug del 14-ago-2026). */
@media (max-width: 620px) {
  .facet-bar { position: relative; gap: 0.4rem; }
  .facet-bar__label { width: 100%; margin-bottom: 0.1rem; }
  .facet-drop { position: static; }
  .facet-drop__panel { left: 0; right: 0; max-width: none; }
  .facet-drop__value { max-width: 7rem; }
}

/* 404 con salida: buscador y accesos, en vez de solo «Volver al inicio». */
.status-page__search {
  display: flex;
  gap: 0.5rem;
  max-width: 30rem;
  margin: 1.5rem auto 0;
}
.status-page__search-input {
  flex: 1;
  min-width: 0;
  padding: 0.7rem 1rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-pill);
  font: inherit;
  background: var(--theme-surface);
  color: var(--theme-ink);
}
.status-page__search-btn {
  flex: none;
  padding: 0.7rem 1.3rem;
  border: 0;
  border-radius: var(--ui-radius-pill);
  background: var(--theme-accent);
  color: var(--theme-surface);
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}
.status-page__links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem 1.25rem;
  margin-top: 1.5rem;
  font-size: 0.92rem;
}
.status-page__links a { color: var(--theme-ink-soft); }
.status-page__links a:hover { color: var(--theme-accent); }

/* ===== Rejilla ancha de listados (08-ago-2026) =====================
   Con los filtros arriba en vez de en una columna de 240 px, el listado se
   queda con el ancho entero y caben cinco por fila. La home la usa también
   desde que pinta 20 libros, que cuadran exactos a cinco, cuatro y dos
   columnas; con los 16 de antes quedaba un huérfano en la cuarta fila. Los
   relacionados siguen fuera: son seis. */
@media (min-width: 1180px) {
  .book-grid--wide { grid-template-columns: repeat(5, 1fr); }
}

/* ===== Filtros con más presencia ===================================
   En barra y en gris pasaban por decoración. Se les da cuerpo: la barra tiene
   fondo y borde propios, y cada filtro es una píldora con sombra, del tamaño de
   algo pulsable. El que está aplicado va en color de marca y macizo, para que
   se vea de un vistazo por dónde está acotado el listado. */
.facet-bar {
  padding: 0.7rem 0.85rem;
  background: var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  box-shadow: var(--ui-shadow-sm, 0 1px 2px rgba(31, 27, 46, 0.06));
  gap: 0.55rem;
}
.facet-bar__label {
  font-size: 0.82rem;
  color: var(--theme-ink);
}
.facet-bar__label svg { width: 1.05rem; height: 1.05rem; color: var(--theme-accent); }

.facet-drop__btn {
  padding: 0.6rem 1.05rem;
  font-size: 0.95rem;
  border-width: 1.5px;
  box-shadow: 0 1px 2px rgba(31, 27, 46, 0.06);
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}
.facet-drop__btn:hover {
  border-color: var(--theme-accent);
  background: var(--theme-accent-soft);
  box-shadow: 0 3px 10px color-mix(in srgb, var(--theme-accent) 18%, transparent);
}
.facet-drop[open] > .facet-drop__btn {
  border-color: var(--theme-accent);
  box-shadow: 0 3px 12px color-mix(in srgb, var(--theme-accent) 22%, transparent);
}
/* Aplicado: macizo. Un borde de color no basta para distinguirlo de un simple
   hover cuando hay tres filtros seguidos. */
.facet-drop.is-active > .facet-drop__btn {
  background: var(--theme-accent);
  border-color: var(--theme-accent);
  color: var(--theme-surface);
  box-shadow: 0 3px 12px color-mix(in srgb, var(--theme-accent) 30%, transparent);
}
.facet-drop.is-active > .facet-drop__btn:hover {
  background: var(--theme-accent);
  color: var(--theme-surface);
  filter: brightness(0.94);
}
.facet-bar__reset {
  padding: 0.5rem 0.85rem;
  border-radius: var(--ui-radius-pill);
  text-decoration: none;
  border: 1px dashed var(--theme-border);
}
.facet-bar__reset:hover { border-color: var(--theme-danger, var(--theme-danger)); color: var(--theme-danger, var(--theme-danger)); }


/* ================= /cursos: mapa del sistema educativo =================
   Antes era una nube de píldoras: 15 enlaces en 1.500 px de scroll, con
   «Infantil» gastando 130 px para uno solo. Quien entra no viene a leer una
   taxonomía, viene a localizar el curso de su hijo — y a menudo no recuerda si
   2º de la ESO son 13 o 14 años. Cada etapa es un panel con su franja de edad y
   sus cursos dentro, y el conjunto cabe en una pantalla.

   El color es POR ETAPA y sólo tiñe el icono y el filete superior: seis colores
   sobre el texto convertirían la página en un circo. */
.stage-map {
  display: grid;
  /* CUATRO columnas fijas en escritorio, no `auto-fit`: los tramos son ocho y
     4+4 cuadra siempre; con tres quedaba una fila de dos y un hueco. */
  grid-template-columns: 1fr;
  align-items: stretch;
  gap: 1rem;
  margin: 1.75rem 0 2.5rem;
}
@media (min-width: 640px) { .stage-map { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .stage-map { grid-template-columns: repeat(4, 1fr); } }
.stage-card {
  --stage: var(--theme-accent);
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
  padding: 1.15rem;
  /* Lavado del color de la etapa que se funde hacia abajo: identifica el tramo
     sin gritar y deja el pie de la tarjeta limpio para las cifras. */
  background: linear-gradient(180deg, color-mix(in srgb, var(--stage) 7%, transparent), transparent 60%) var(--theme-surface);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
  box-shadow: var(--ui-shadow-sm, 0 1px 2px rgba(31, 27, 46, 0.06));
  overflow: hidden;
}
/* El mapa de edades es una ESCALA, así que el color también: del más cálido al
   más frío según sube el tramo. Ocho colores distintos elegidos al azar harían
   parecer que cada tramo es una cosa aparte; una progresión se lee de un
   vistazo como lo que es, una línea temporal.

   El `nth-child` va contra el orden de `age_ranges.position`, que es el que
   emite el hub. Si algún día se añade un tramo intermedio, la escala se
   recoloca sola en vez de quedarse un color huérfano. */
.stage-map .stage-card:nth-child(1) { --stage: #E8A33C; }
.stage-map .stage-card:nth-child(2) { --stage: #E0763F; }
.stage-map .stage-card:nth-child(3) { --stage: var(--theme-accent); }
.stage-map .stage-card:nth-child(4) { --stage: #D2417A; }
.stage-map .stage-card:nth-child(5) { --stage: #9B4BC4; }
.stage-map .stage-card:nth-child(6) { --stage: #5C5BD6; }
.stage-map .stage-card:nth-child(7) { --stage: #2F7FD6; }
.stage-map .stage-card:nth-child(8) { --stage: var(--theme-success); }

/* La tarjeta entera es el enlace: en un mapa de edades no hay nada dentro que
   se pueda pulsar por separado, así que obligar a acertar en un enlace de texto
   sería reducir a propósito el área de clic. */
.stage-card--link { text-decoration: none; color: inherit; transition: transform .15s ease, box-shadow .15s ease, border-color .15s ease; }
.stage-card--link:hover,
.stage-card--link:focus-visible {
  text-decoration: none;
  color: inherit;
  transform: translateY(-2px);
  box-shadow: var(--ui-shadow-md);
  border-color: color-mix(in srgb, var(--stage) 45%, var(--theme-border));
}
/* Un tramo sin catálogo NO se oculta: la escala se lee mal con un hueco. Se
   apaga, que dice «aquí todavía no hay nada» sin romper la secuencia. */
.stage-card--link.is-empty { opacity: .55; }

.stage-card__head { display: flex; align-items: center; gap: 0.75rem; }
.stage-card__icon {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  border-radius: var(--ui-radius-md);
  background: color-mix(in srgb, var(--stage) 14%, transparent);
  color: var(--stage);
}
.stage-card__icon svg { width: 1.5rem; height: 1.5rem; }
.stage-card__name {
  min-width: 0;
  font-family: var(--theme-font-heading);
  font-weight: 700;
  font-size: 1.125rem;
  line-height: 1.15;
  letter-spacing: -0.01em;
}
.stage-card__desc { font-size: 0.8125rem; line-height: 1.45; color: var(--theme-ink-muted); }
/* Las cifras van ancladas al pie con la raya discontinua encima: así los ocho
   pies quedan alineados aunque la descripción ocupe una línea o dos. */
.stage-card__stats {
  margin-top: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding-top: 0.75rem;
  border-top: 1px dashed var(--theme-border);
}
.stage-card__count { font-size: 0.8125rem; font-weight: 600; color: var(--theme-ink-soft); }
.stage-card__from {
  flex: none;
  font-size: 0.8125rem;
  font-weight: 700;
  padding: 0.25rem 0.6rem;
  border-radius: var(--ui-radius-pill);
  background: color-mix(in srgb, var(--stage) 14%, transparent);
  /* El color de la etapa oscurecido con tinta: legible sobre su propio tinte
     sin salirse de la escala. */
  color: color-mix(in srgb, var(--stage) 62%, var(--theme-ink));
}

.stage-card__courses {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.4rem;
}
/* Una etapa de un solo curso (Infantil, FP, Universidad) no necesita rejilla:
   su tarjeta ocupa el ancho y se lee como un botón. */
.stage-card__courses:has(> li:only-child) { grid-template-columns: 1fr; }

.stage-course {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 0.2rem;
  padding: 0.6rem 0.4rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-sm);
  background: var(--theme-surface-alt);
  color: var(--theme-ink);
  text-align: center;
  line-height: 1.1;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.stage-course:hover, .stage-course:focus-visible {
  text-decoration: none;
  background: color-mix(in srgb, var(--stage) 12%, var(--theme-surface));
  border-color: var(--stage);
  color: var(--theme-ink);
}
/* La cifra es lo que distingue «3º de Primaria» de sus cinco hermanas, así que
   es lo que se ve; el resto del nombre queda de apoyo. */
.stage-course__num {
  font-family: var(--theme-font-heading);
  font-weight: 800;
  font-size: 1.25rem;
  color: var(--stage);
  font-variant-numeric: tabular-nums;
}
.stage-course__ord { font-size: 0.7em; vertical-align: super; }
.stage-course__rest { display: none; }
/* Sin cifra (Infantil, FP, Universidad) el nombre ES el enlace. */
.stage-course__rest--solo {
  display: inline;
  font-weight: 600;
  font-size: 0.95rem;
}
@media (max-width: 380px) {
  .stage-card__courses { grid-template-columns: repeat(3, 1fr); }
  .stage-course { padding: 0.5rem 0.2rem; }
}

/* ===== Compartir la lista de un colegio ==============================
   Aquí tiene más sentido que en ninguna otra página: la lista del cole circula
   de padre a padre por el WhatsApp del grupo de clase, y esta URL es estable
   —no caduca como `/lista/:uuid`—, así que se puede reenviar el septiembre que
   viene y seguirá ahí. Sólo copiar enlace y WhatsApp: nadie tuitea la lista del
   colegio de su hijo. */
.school-share {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1.25rem;
  margin: 0 0 1.5rem;
  padding: 0.9rem 1.1rem;
  background: var(--theme-surface-alt);
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-lg);
}
.school-share__text { margin: 0; font-size: 0.95rem; color: var(--theme-ink-soft); }
.school-share__actions { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.school-share__copy,
.school-share__wa {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.55rem 1rem;
  border-radius: var(--ui-radius-pill);
  font: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}
.school-share__copy {
  border: 1px solid var(--theme-border);
  background: var(--theme-surface);
  color: var(--theme-ink);
}
.school-share__copy:hover { border-color: var(--theme-accent); color: var(--theme-accent); }
.school-share__copy.is-copied { border-color: var(--theme-success, var(--theme-success)); color: var(--theme-success, var(--theme-success)); }
.school-share__wa {
  border: 1px solid #25D366;
  background: #25D366;
  color: #fff;
}
.school-share__wa:hover, .school-share__wa:focus { color: #fff; text-decoration: none; filter: brightness(0.95); }
.school-share__copy svg, .school-share__wa svg { width: 1.05rem; height: 1.05rem; flex: none; }
@media (max-width: 560px) {
  .school-share { flex-direction: column; align-items: stretch; }
  .school-share__actions { justify-content: stretch; }
  .school-share__copy, .school-share__wa { flex: 1; justify-content: center; }
}

/* Correo y «más opciones» en el bloque de compartir de la lista. */
.list-share-btn--mail { background: var(--theme-surface); border: 1px solid var(--theme-border); color: var(--theme-ink); }
.list-share-btn--mail:hover { border-color: var(--theme-accent); color: var(--theme-accent); }
.list-share-btn--native {
  background: var(--theme-accent-soft);
  border: 1px solid color-mix(in srgb, var(--theme-accent) 35%, var(--theme-border));
  color: var(--theme-accent);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.list-share-btn--native:hover { background: color-mix(in srgb, var(--theme-accent) 18%, var(--theme-surface)); }

.list-buys__note {
  margin: -0.6rem 0 1.1rem;
  font-size: 0.86rem;
  color: var(--theme-ink-muted);
}


/* ===== Ajustes de la barra de filtros y del desplegable ===== */

/* En móvil los filtros se apilaban en dos y tres líneas, empujando la rejilla
   hacia abajo. Una sola fila que se desplaza a lo ancho ocupa lo mismo que un
   filtro y deja ver que hay más a la derecha. */
@media (max-width: 720px) {
  .facet-bar {
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: visible;
    padding-bottom: 0.15rem;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .facet-bar::-webkit-scrollbar { display: none; }
  .facet-bar > * { flex: none; }
  .facet-bar__label { display: none; }

  /*
   * El panel sale como HOJA INFERIOR, y no es una decisión estética.
   *
   * `overflow-x: auto` con `overflow-y: visible` no existe en CSS: cuando un eje
   * deja de ser `visible`, el otro se computa como `auto`. Así que esta misma
   * barra, al hacerse desplazable a lo ancho, se convirtió también en
   * contenedor de scroll VERTICAL y se comió el desplegable: medido en
   * producción el 17-ago-2026, del panel de 416 px se veían 5. El botón abría y
   * no pasaba nada — «los filtros no van en móvil».
   *
   * `position: fixed` lo saca del contenedor que lo recorta (comprobado que
   * ningún ancestro tiene `transform` ni `filter`, que lo volverían a atrapar).
   *
   * Es la SEGUNDA vez que este desplegable se rompe en móvil: el 14-ago fue
   * porque el panel absoluto no encontraba ancestro posicionado. Aquel arreglo
   * sigue tres bloques más arriba y seguía siendo correcto; lo que lo tumbó fue
   * añadir el scroll horizontal después, sin volver a abrir un filtro.
   */
  .facet-drop__panel {
    position: fixed;
    top: auto;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 60;
    min-width: 0;
    max-width: none;
    max-height: 72vh;
    border-radius: var(--ui-radius-lg) var(--ui-radius-lg) 0 0;
    box-shadow: var(--ui-shadow-lg, 0 -16px 40px rgba(8, 30, 60, 0.16));
  }
}

/* El texto SEO arrancaba pegado a la paginación y parecía continuación suya. */
.collection-seo-body { margin-top: 2.75rem; }

/* El botón "+" quedaba medio tapado por la barra de scroll del desplegable. */
.live-search__panel { padding-right: 0.6rem; }
.live-search__row { padding-right: 0.1rem; }

/* ------------------------ Buscador de colegios --------------------------- */
/* Formulario GET puro (la CSP prohíbe JS inline). El buscador de CENTROS es
   distinto del de libros a propósito: quien escribe «28034» busca su colegio,
   no un título. */

.school-search__title { margin: 0 0 0.4rem; font-size: 1.6rem; }
.school-search__lead {
  margin: 0 0 1.2rem;
  color: var(--theme-muted, var(--theme-ink-soft));
  max-width: 46rem;
}

.school-search__form {
  display: flex;
  gap: 0.5rem;
  margin: 0 0 1.5rem;
  max-width: 46rem;
}
.school-search__form--inline { margin: 0 0 1.75rem; }

.school-search__input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 0.7rem 0.9rem;
  font-size: 1rem;
  font-family: inherit;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-sm);
  background: var(--theme-surface, #fff);
  color: inherit;
}
.school-search__input:focus-visible {
  outline: 2px solid var(--theme-accent);
  outline-offset: 1px;
  border-color: var(--theme-accent);
}

.school-search__btn {
  flex: 0 0 auto;
  padding: 0.7rem 1.4rem;
  font-size: 1rem;
  font-family: inherit;
  font-weight: 600;
  cursor: pointer;
  border: 1px solid transparent;
  border-radius: var(--ui-radius-cta);
  background: var(--theme-accent);
  color: var(--theme-accent-contrast, #fff);
}
.school-search__btn:hover { filter: brightness(0.94); }

.school-search__count {
  margin: 0 0 0.6rem;
  color: var(--theme-muted, var(--theme-ink-soft));
  font-size: 0.9rem;
}

.school-search__results {
  list-style: none;
  padding: 0;
  margin: 0;
  border-top: 1px solid var(--theme-border);
}
.school-hit {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.75rem 0.25rem;
  border-bottom: 1px solid var(--theme-border);
}
.school-hit__link {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  text-decoration: none;
  color: inherit;
}
.school-hit__link:hover .school-hit__name { text-decoration: underline; }
.school-hit__name { font-weight: 600; }
.school-hit__where {
  font-size: 0.85rem;
  color: var(--theme-muted, var(--theme-ink-soft));
}
.school-hit__books {
  flex: 0 0 auto;
  font-size: 0.8rem;
  white-space: nowrap;
  color: var(--theme-muted, var(--theme-ink-soft));
}

.school-search__empty {
  padding: 1.1rem 1.2rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-sm);
  background: var(--theme-surface-alt, #fafafa);
  max-width: 46rem;
}
.school-search__empty p { margin: 0 0 0.5rem; }
.school-search__empty p:last-child { margin-bottom: 0; }

@media (max-width: 560px) {
  .school-search__form { flex-wrap: wrap; }
  .school-search__input { flex-basis: 100%; }
  .school-search__btn { flex: 1 1 auto; }
  .school-hit { flex-wrap: wrap; gap: 0.3rem 1rem; }
}

/* Confirmacion del rail cuando solo hay un libro en la comparativa. */
.buy-rail__compare-done {
  margin: 0 0 0.55rem;
  font-size: 0.82rem;
  line-height: 1.4;
  color: var(--theme-muted, var(--theme-ink-soft));
}


/* ------------------------- Accesibilidad (bichejos) ---------------------- */

/* Alias de `.visually-hidden`: las vistas de este proyecto usan `.sr-only`.
   Se mantienen las dos para que un partial portado tal cual siga funcionando. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* Salto al contenido: primer tabulador de la página. Fuera de pantalla hasta
   que recibe el foco — si se ocultara con `display:none` el teclado no podría
   alcanzarlo, que es justo para lo que existe. */
.skip-link {
  position: absolute;
  left: -999px;
  top: 0;
  z-index: 100;
  background: var(--theme-surface);
  color: var(--theme-ink);
  padding: 0.75rem 1rem;
  border-radius: var(--ui-radius-sm);
  box-shadow: var(--ui-shadow-md);
}
.skip-link:focus { left: 0.5rem; top: 0.5rem; }

/* =========================================================================
   Piezas propias de bichejos.

   Todo lo de aquí es marcado que este proyecto tiene y comparalibros no —o al
   revés—: la tarjeta de juguete con su CTA a la ficha, el encabezado de las
   colecciones, la barra de orden del buscador, el pie del blog y los estados
   de las ofertas agotadas. Va al FINAL para que se vea de un vistazo qué se ha
   añadido sobre el sistema portado, y todo sale de los mismos tokens.
   ========================================================================= */

/* ---- Tarjeta de juguete ------------------------------------------------- */

/* Botón «Comparar N tiendas»: es el que lleva a la ficha. Es un <a> HERMANO
   del enlace de la tarjeta, no un <span> dentro de él —dos destinos no caben
   en un solo enlace, y anidar <a> es HTML inválido que el navegador desanida
   por su cuenta rompiendo la tarjeta—. Al salir del flujo del cuerpo necesita
   su propio margen. */
.book-card__cta {
  display: block;
  margin: 0 0.9rem 0.95rem;
  padding: 0.55rem 0.75rem;
  background: var(--theme-accent);
  color: #fff;
  border-radius: var(--ui-radius-sm);
  font-weight: 700;
  font-size: 0.92rem;
  text-align: center;
}
.book-card__cta:hover { color: #fff; text-decoration: none; filter: brightness(0.93); }
.book-card__cta:focus-visible { outline: 2px solid var(--ui-accent-ring); outline-offset: 2px; }

/* ---- Ficha: chips y estado de las ofertas ------------------------------- */

.book-chip--category a { color: inherit; }
.book-chip--category a:hover { color: var(--theme-accent); text-decoration: none; }

/* Descuento sobre el PVP. Verde y no rojo: en una comparativa el rojo ya
   significa «cuidado» en el resto de la interfaz, y aquí es una buena noticia. */
.offer__badge--sale {
  background: color-mix(in srgb, var(--theme-success) 14%, transparent);
  color: var(--theme-success);
}

/* Tiendas sin stock, plegadas. No se ocultan del todo: saber que una tienda lo
   tenía y se ha agotado es información, y esconderla haría parecer que el
   juguete nunca estuvo ahí. */
.offers__gone {
  margin: 1rem 0 0;
  padding: 0.75rem 0.95rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-md);
  background: var(--theme-surface-alt);
  color: var(--theme-ink-soft);
  font-size: 0.9rem;
}
.offers__gone summary { cursor: pointer; font-weight: 600; }
.offers__gone ul { margin: 0.6rem 0 0; padding-left: 1.1rem; }

/* ---- Encabezado y resultados de colección ------------------------------- */

.collection-header { margin: 0 0 0.9rem; }
.collection-header__title { margin: 0; font-size: clamp(1.5rem, 1.1rem + 1.6vw, 2.1rem); }

/* La marca con logo lo pone al lado del título. Mismo criterio que en la
   rejilla de /marcas: fondo de superficie —los logotipos se diseñan para blanco
   y varios llevan partes en blanco— y `color` fijo para el `currentColor` del
   SVG de LEGO. */
.collection-header--with-logo {
  display: flex;
  align-items: center;
  gap: 0.85rem;
}
.collection-header__logo {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 76px;
  height: 76px;
  padding: 0.5rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-md);
  background: var(--theme-surface);
  color: var(--theme-accent);
}
.collection-header__logo img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}
.collection-intro { margin: 0 0 1.4rem; }
.collection-intro__text {
  margin: 0;
  color: var(--theme-ink-soft);
  font-size: 1.02rem;
}
.collection-results { margin: 0; }
.collection-results__empty {
  margin: 2rem 0;
  padding: 1.6rem;
  border: 1px dashed var(--theme-border);
  border-radius: var(--ui-radius-lg);
  color: var(--theme-ink-muted);
  text-align: center;
}

/* ---- Hub --------------------------------------------------------------- */

.hub__empty {
  margin: 1.6rem 0;
  padding: 1.6rem;
  border: 1px dashed var(--theme-border);
  border-radius: var(--ui-radius-lg);
  color: var(--theme-ink-muted);
  text-align: center;
}
.category-group__title a { color: inherit; }
.category-group__title a:hover { color: var(--theme-accent); text-decoration: none; }

/* ---- Buscador: título y orden ------------------------------------------ */

.search-header__title { margin: 0 0 0.35rem; font-size: clamp(1.4rem, 1.1rem + 1.4vw, 1.95rem); }

/* El orden vive DENTRO de la barra de facetas y no encima de la rejilla:
   filtrar y ordenar son la misma tarea y separarlos deja dos controles en dos
   sitios para lo mismo. `margin-left: auto` lo empuja al extremo. */
.facet-bar__sort { display: flex; align-items: center; gap: 0.5rem; margin-left: auto; }
.facet-bar__sort select {
  appearance: none;
  padding: 0.45rem 2rem 0.45rem 0.85rem;
  border: 1px solid var(--theme-border);
  border-radius: var(--ui-radius-pill);
  background-color: var(--theme-surface);
  background-image:
    linear-gradient(45deg, transparent 50%, var(--theme-ink-muted) 50%),
    linear-gradient(135deg, var(--theme-ink-muted) 50%, transparent 50%);
  background-position: calc(100% - 1rem) 55%, calc(100% - 0.72rem) 55%;
  background-size: 0.3rem 0.3rem, 0.3rem 0.3rem;
  background-repeat: no-repeat;
  color: var(--theme-ink);
  font-size: 0.88rem;
  cursor: pointer;
}
.facet-drop__name { font-weight: 600; }
.facet-drop__item-n {
  margin-left: 0.4rem;
  color: var(--theme-ink-muted);
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
}

/* ---- Portada: cabecera de las rejillas ---------------------------------- */

.home-latest__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.4rem 1rem;
  margin: 0 0 1rem;
}
.home-latest__all { font-weight: 600; font-size: 0.92rem; white-space: nowrap; }

/* ---- Blog: entrada ------------------------------------------------------ */

.blog-post { margin: 0 auto; }
.blog-post__header { margin: 0 0 1.2rem; }
.blog-post__title { margin: 0 0 0.4rem; font-size: clamp(1.7rem, 1.2rem + 2vw, 2.5rem); }
.blog-post__meta { margin: 0; color: var(--theme-ink-muted); font-size: 0.9rem; }
.blog-post__excerpt {
  margin: 0 0 1.4rem;
  font-size: 1.12rem;
  line-height: 1.6;
  color: var(--theme-ink-soft);
}
.blog-post__tags { margin: 1.8rem 0 0; }
.blog-post__footer {
  margin: 2rem 0 0;
  padding-top: 1.2rem;
  border-top: 1px solid var(--theme-border);
}
