/* ============================================================
   mockup.css — laboratorio de diseño de Cotejo

   MAQUETA: contenido quemado, sin datos reales. Nunca consulta el
   backend — eso es lo que la mantiene barata.

   NO define color, tipografía, espaciado ni radios: todo eso vive en
   web/assets/css/tokens.css, que es la fuente de verdad. Si necesitas
   un valor que no existe allá, agrégalo ALLÁ y corre
   `py tools/check_contrast.py`.

   Dirección única: maqueta → funcional. Nada funcional vive aquí.
   ============================================================ */

/* tokens.css ya se enlaza aparte, antes que este archivo, en index.html */

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

body {
  font-family: var(--ff-sans);
  background: var(--bg-elev);
  color: var(--fg);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  /* Footer pegado al fondo: en paginas cortas (indice de colecciones con
     pocas fichas, detalle en estado "no encontrada"/"sin productos") el
     .ftr flotaba a media pantalla con un hueco en blanco debajo. */
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}
/* El contenedor de contenido crece para empujar al footer; el .wrap de
   dentro del propio footer no es hijo directo de body, no se afecta. */
body > .wrap { flex: 1 0 auto; }

img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
h1,h2,h3,h4 { line-height: 1.15; letter-spacing: -.02em; text-wrap: balance; font-weight: 800; }
p { text-wrap: pretty; }

:focus-visible { outline: 3px solid var(--accent-solid); outline-offset: 3px; border-radius: 6px; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

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

/* Enlace "Saltar al contenido": ayuda a quien navega con teclado/lector
   de pantalla a brincarse el menú. Oculto hasta que recibe foco con Tab
   -- sin esto se ve como un link suelto arriba a la izquierda. */
.skip {
  position: absolute; left: var(--sp-3); top: var(--sp-3);
  transform: translateY(-150%);
  z-index: 1000;
  background: var(--accent-solid); color: var(--accent-ink);
  padding: var(--sp-2) var(--sp-4); border-radius: var(--r-md);
  font-weight: 600; text-decoration: none;
  transition: transform var(--dur) var(--ease);
}
.skip:focus { transform: translateY(0); }

.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--sp-5); }
@media (min-width: 768px) { .wrap { padding-inline: var(--sp-6); } }

/* ============================================================
   CABECERA
   ============================================================ */
.hdr {
  position: sticky; top: 0; z-index: 50;
  background: var(--bg-elev-blur);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid transparent;
}
.hdr.is-stuck { border-bottom-color: var(--line); }
.hdr__in {
  display: flex; align-items: center; gap: var(--sp-5);
  padding-block: var(--sp-4);
}
.logo { display: flex; align-items: center; gap: var(--sp-3); }
/* El logo real (bolsa + audifonos + tenis + celular, arte del usuario en
   web/assets/img/shopeable-icon.png) ya trae sus propios colores y fondo
   transparente -- a diferencia del icono anterior, NO va sobre una tarjeta
   de color: eso lo iba a tapar/desentonar. Solo se controla el tamano. */
.logo__mark {
  display: grid; place-items: center; flex-shrink: 0;
}
.logo__mark img { display: block; height: 64px; width: auto; }
.logo__name {
  font-size: 2rem; font-weight: 800; letter-spacing: -.01em; line-height: 1;
  text-transform: uppercase;
}
.logo__name span { color: var(--accent-solid); }
.logo__sub {
  display: block; white-space: nowrap;
  font-size: .7rem; font-weight: 700; letter-spacing: .16em;
  text-transform: uppercase; color: var(--fg-faint); margin-top: 4px;
}
/* Pedido 2026-09-14: el eslogan del header debe verse SIEMPRE, en una
   sola línea, en cualquier ancho -- antes se escondía < 1240px porque
   envolvía a varias líneas y chocaba con el botón de acción del header.
   Eso cambió de raíz el mismo día: el botón ("Comparar algo →") ahora
   solo aparece fuera del home (ver body[data-page-home] más abajo), y el nav
   se simplificó a un solo dropdown ("Inicio") + 3 links -- ambas cosas
   liberan el ancho que antes faltaba. `white-space:nowrap` de arriba
   evita el envolvido; estos tamaños more angostos hacen que quepa incluso
   en el home (donde el botón sigue oculto iguial, pero el buscador del
   hero ya compite por atención) y en el menú móvil con todo desplegado.
   Medido en vivo con Playwright barriendo 320px-1920px, no adivinado. */
@media (max-width: 1239px) {
  .site-header__in .logo__mark img { height: 44px; }
  .site-header__in .logo__name { font-size: 1.4rem; }
  .site-header__in .logo__sub { font-size: .58rem; letter-spacing: .09em; }
}
@media (max-width: 480px) {
  .site-header__in .logo__mark img { height: 34px; }
  .site-header__in .logo__name { font-size: 1.1rem; }
  .site-header__in .logo__sub { font-size: .5rem; letter-spacing: .05em; margin-top: 2px; }
}
/* La .nav inline solo aparece desde 1360px: entre 1240 y 1359 el logo (con
   eslogan) + nav + acciones + boton de sesion iban demasiado justos y las
   acciones se envolvian debajo. Debajo de 1360 se usa el menu hamburguesa. */
.nav { display: none; gap: var(--sp-4); margin-inline: auto; font-weight: 600; font-size: .94rem; min-width: 0; overflow: hidden; }
.nav a { white-space: nowrap; }
@media (min-width: 1360px) { .nav { display: flex; } }
.nav a { color: var(--fg-muted); transition: color .18s var(--ease); }
.nav a:hover { color: var(--accent); }

/* "Inicio" con submenú de anclas (2026-09-14) -- <details> nativo: cero JS
   propio, funciona igual en desktop (dropdown flotante) y en el panel
   móvil (se expande inline, el <details> ya hace eso solo). */
.nav__dd { position: relative; }
.nav__dd > summary {
  cursor: pointer; list-style: none; color: var(--fg-muted);
  transition: color .18s var(--ease);
}
.nav__dd > summary::-webkit-details-marker { display: none; }
.nav__dd > summary::after { content: ' ▾'; font-size: .7em; }
.nav__dd:hover > summary, .nav__dd > summary:hover { color: var(--accent); }
.nav__dd-menu { display: flex; flex-direction: column; }
@media (min-width: 1360px) {
  /* .nav tiene overflow:hidden para que el flex no empuje el header a un
     2º renglón (ver arriba) -- eso mismo recortaría el dropdown si está
     abierto, así que se libera solo mientras lo está. */
  .nav:has(.nav__dd[open]) { overflow: visible; }
  .nav__dd[open] > .nav__dd-menu {
    position: absolute; top: 100%; left: 0; margin-top: var(--sp-2);
    background: var(--bg-elev); border: 1px solid var(--line);
    border-radius: var(--r-md); box-shadow: var(--shadow-2);
    padding: var(--sp-2); min-width: 210px; z-index: 40;
  }
  .nav__dd-menu a { padding: var(--sp-2) var(--sp-3) !important; border-radius: var(--r-sm); }
  .nav__dd-menu a:hover { background: var(--bg-sunken); }
}
@media (max-width: 1359px) {
  .nav__dd-menu { padding-left: var(--sp-4); }
}

/* ---- Menu movil (<1360px, donde .nav no cabe en el header) ---- */
.nav-toggle {
  display: grid; place-items: center;
  width: 38px; height: 38px; border-radius: var(--r-md);
  border: 1px solid var(--line); color: var(--fg-muted);
  transition: color .18s var(--ease), border-color .18s var(--ease);
}
.nav-toggle:hover { color: var(--fg); border-color: var(--line-strong); }
.nav-toggle svg { width: 20px; height: 20px; }
.nav-toggle .i-close { display: none; }
.site-header[data-menu-open] .nav-toggle .i-open { display: none; }
.site-header[data-menu-open] .nav-toggle .i-close { display: block; }
@media (min-width: 1360px) { .nav-toggle { display: none; } }

@media (max-width: 1359px) {
  /* .site-header ya es position:sticky (bloque contenedor de este absolute) */
  .site-header[data-menu-open] .nav {
    display: flex; flex-direction: column; gap: var(--sp-1);
    position: absolute; left: 0; right: 0; top: 100%;
    margin: 0;
    background: var(--bg-elev);
    border-top: 1px solid var(--line);
    border-bottom: 1px solid var(--line);
    box-shadow: var(--shadow-2);
    padding: var(--sp-3) var(--sp-6) var(--sp-4);
    z-index: 30;
  }
  .site-header[data-menu-open] .nav a { padding: var(--sp-3) 0; font-size: 1rem; }
}
.hdr__actions { display: flex; align-items: center; gap: var(--sp-3); margin-left: auto; }
@media (min-width: 1024px) { .hdr__actions { margin-left: 0; } }

/* index.html real usa .site-header/.site-header__actions (no .hdr/.hdr__actions
   del mockup) y esta clase no tenia NINGUNA regla — el boton (inline-flex,
   nivel-inline) y el toggle de tema (.theme-toggle, display:grid, nivel-bloque)
   quedaban cada uno en su propia linea, el toggle apilado debajo del boton
   en vez de al lado. */
/* flex:0 0 auto + nowrap: las acciones (Iniciar sesión / tema / menú)
   SIEMPRE van en una fila con el logo, nunca caen debajo del título.
   Lo que se iría a un 2º renglón si algo no cabe es la .nav, no esto. */
.site-header__actions { display: flex; flex: 0 0 auto; flex-wrap: nowrap; align-items: center; gap: var(--sp-3); }
/* "Comparar algo →" del header sobra en el HOME (el buscador del hero ya
   está a la vista, justo debajo) -- pedido 2026-09-14. `data-page-home`
   solo lo trae <body> de index.html -- OJO, NO confundir con el atributo
   `data-home` (sin "page") que ya existía en un <div> de index.html como
   hook de JS para el contenedor de Destacados/Recientes; un choque de
   nombre aquí haría que `document.querySelector('[data-home]')` de app.js
   devolviera el <body> en vez de ese div. En las demás páginas
   (colecciones, cupón, categoría...) no hay buscador visible, así que
   ahí el botón sí se queda. */
body[data-page-home] .site-header__actions > .btn-primary { display: none; }
/* En pantallas chicas "Comparar algo →" (el <a class="btn btn-primary">
   del header) sobra tambien fuera del home -- el ancho es lo que
   empujaba las acciones a un 2º renglón. Se oculta ahí también; queda
   logo + menú + Iniciar sesión + tema, que caben en una fila. */
@media (max-width: 700px) {
  .site-header__actions > .btn-primary { display: none; }
  /* "Instalar app" del header también sobra en móvil angosto -- probado
     en vivo con Playwright a 375px: el eslogan (ahora siempre visible,
     ver más arriba) quedaba cortado justo contra este botón. Sigue
     disponible desde el footer (mismo botón, mismo prompt nativo, ver
     pwa.js) -- no se pierde la función, solo se destraba el header. */
  .site-header__actions [data-pwa-install] { display: none; }
  /* apretar el header en móvil para que logo + menú + Iniciar sesión +
     tema quepan sin overflow ni 2º renglón. */
  .site-header__in { padding-inline: var(--sp-3); }
  .site-header__actions { gap: var(--sp-2); }
  .site-header__actions [data-auth-signin] { padding: var(--sp-2) var(--sp-3); font-size: var(--fs--1); }
  .nav-toggle, .theme-toggle { width: 34px; height: 34px; }
}

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-5); border-radius: var(--r-pill);
  font-weight: 700; font-size: .94rem; white-space: nowrap;
  transition: transform .18s var(--ease), box-shadow .18s var(--ease), background .18s var(--ease);
}
.btn--primary {
  /* #0E4568: extremo oscuro del gradiente, 10.15:1 con --accent-ink.
     Unico literal de color permitido aqui — el sistema no expone un
     token para el segundo tono de un gradiente. El original iba de
     #0E86D9 a #0A6FB5 y el extremo claro daba 3.87:1: reprobaba AA. */
  background: linear-gradient(150deg, var(--accent-solid), #0E4568);
  color: var(--accent-ink); box-shadow: 0 4px 14px rgba(10,111,181,.34);
}
.btn--primary:hover { transform: translateY(-1px); box-shadow: 0 8px 22px rgba(10,111,181,.42); }
.btn--ghost { color: var(--fg-muted); }
.btn--ghost:hover { color: var(--accent); }
.btn--outline { border: 1.5px solid var(--line); color: var(--fg); background: var(--bg-elev); }
.btn--outline:hover { border-color: var(--accent); color: var(--accent); }
.btn--lg { padding: var(--sp-4) var(--sp-6); font-size: 1rem; }
.btn--sm { padding: var(--sp-2) var(--sp-4); font-size: .85rem; }
/* --bg-elev/--band-dark son las variables normales del tema, pero este
   boton siempre vive sobre el banner oscuro sin importar el tema del
   sitio -- y en tema oscuro --bg-elev pasa a valer lo MISMO que
   --band-dark (mismo hex, ver tokens.css), asi que fondo y texto del
   boton quedaban casi identicos: invisible sin hover. --band-dark-fg y
   --band-dark no cambian con el tema (son del banner, no de la pagina),
   asi que fijan el contraste sin importar claro/oscuro. */
.btn--onDark { background: var(--band-dark-fg); color: var(--band-dark); }
.btn--onDark:hover { transform: translateY(-1px); }

/* ============================================================
   TOGGLE DE TEMA
   Copiado tal cual de web/assets/css/components.css: al compartir
   tokens, el mismo CSS da el mismo resultado en las dos. Portarlo de
   vuelta es copiar y pegar.
   ============================================================ */
.theme-toggle {
  display: grid;
  place-items: center;
  width: 38px; height: 38px;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  color: var(--fg-muted);
  transition: color .18s var(--ease), border-color .18s var(--ease);
}
.theme-toggle:hover { color: var(--fg); border-color: var(--line-strong); }
.theme-toggle svg { width: 18px; height: 18px; }
:root[data-theme='light'] .theme-toggle .i-sun,
:root:not([data-theme='dark']) .theme-toggle .i-sun { display: none; }
:root[data-theme='dark'] .theme-toggle .i-moon { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) .theme-toggle .i-sun { display: block; }
  :root:not([data-theme]) .theme-toggle .i-moon { display: none; }
}

/* ============================================================
   BUSQUEDAS RECIENTES
   ============================================================ */
.recientes { margin-top: var(--sp-5); }
.recientes__tit {
  font-size: .72rem; font-weight: 800; letter-spacing: .12em;
  text-transform: uppercase; color: var(--fg-faint);
}
.recientes .chips { margin-top: var(--sp-3); }
.chip--recent { border-style: dashed; }

/* ============================================================
   HERO
   ============================================================ */
.hero { padding-block: var(--sp-8) var(--sp-7); position: relative; overflow: hidden; }
.hero__grid { display: grid; gap: var(--sp-7); align-items: center; }
@media (min-width: 1024px) { .hero__grid { grid-template-columns: 1.05fr .95fr; gap: var(--sp-8); } }
/* Sin min-width:0, los items de grid usan min-width:auto por default: el
   boton "Comparar ahora ->" con white-space:nowrap empuja el min-content
   de la 1a columna hasta comerse todo el ancho disponible, y la 2a
   columna (la imagen, sizeada a width:100% — que no cuenta para su
   propio min-content) queda en 0px. Confirmado con Playwright:
   grid-template-columns computaba "1061.77px 0px" sin esta regla. */
.hero__grid > * { min-width: 0; }

.pill {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4); border-radius: var(--r-pill);
  background: var(--accent-wash); color: var(--accent);
  font-size: .74rem; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
}
.pill--onDark { background: rgba(255,255,255,.14); color: var(--band-dark-fg-muted); }

.hero h1 { font-size: clamp(2.4rem, 5.6vw, 3.9rem); margin-block: var(--sp-4) var(--sp-4); }
.hero h1 span { color: var(--accent-solid); display: block; }
.hero__lead { font-size: 1.12rem; color: var(--fg-muted); max-width: 46ch; }

/* --- Buscador --- */
.search { margin-top: var(--sp-6); }
.search__box {
  display: flex; gap: var(--sp-2); align-items: center;
  background: var(--bg-elev); border: 1.5px solid var(--line);
  border-radius: var(--r-pill); padding: var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-5);
  box-shadow: var(--shadow-2);
  transition: border-color .18s var(--ease), box-shadow .18s var(--ease);
}
.search__box:focus-within { border-color: var(--accent); box-shadow: var(--shadow-2), 0 0 0 4px var(--accent-wash); }
/* Se dispara al dar "Comparar" con el buscador vacío -- antes no pasaba
   nada visible. border-color inline porque --warn no tiene su propio
   "-wash" como --accent;0 0 0 4px con el mismo color al 22% de alpha
   logra el mismo halo sin inventar un token nuevo. */
.search__box.search__box--vacio { animation: search-shake .32s var(--ease); border-color: var(--warn); box-shadow: var(--shadow-2), 0 0 0 4px color-mix(in srgb, var(--warn) 22%, transparent); }
@keyframes search-shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-6px); }
  75% { transform: translateX(6px); }
}
@media (prefers-reduced-motion: reduce) {
  .search__box.search__box--vacio { animation: none; }
}
.search__box svg { width: 20px; height: 20px; color: var(--fg-faint); flex-shrink: 0; }
.search__box input {
  flex: 1; min-width: 0; border: none; outline: none; background: none;
  font: inherit; padding-block: var(--sp-3);
}
.search__box input::placeholder { color: var(--fg-faint); }
/* :not([hidden]) -- mismo bug de especificidad de siempre con la regla
   [hidden] del navegador (ver nota en .hero de este archivo). Se revela
   solo si el navegador soporta Web Speech API (pwa.js lo detecta). */
.search__mic:not([hidden]) {
  display: flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; flex-shrink: 0;
  border: none; border-radius: 50%; background: var(--bg-sunken);
  color: var(--fg-muted); cursor: pointer;
  transition: background .16s var(--ease), color .16s var(--ease);
}
.search__mic:not([hidden]):hover { background: var(--accent-wash); color: var(--accent-solid); }
.search__mic:not([hidden]) svg { width: 19px; height: 19px; }
.search__mic.search__mic--activo:not([hidden]) { background: var(--accent-solid); color: var(--bg-elev); }
@keyframes mic-pulso { 0%, 100% { box-shadow: 0 0 0 0 var(--accent-wash); } 50% { box-shadow: 0 0 0 6px var(--accent-wash); } }
.search__mic.search__mic--activo:not([hidden]) { animation: mic-pulso 1.2s var(--ease) infinite; }
@media (prefers-reduced-motion: reduce) { .search__mic.search__mic--activo:not([hidden]) { animation: none; } }

.chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-4); list-style: none; padding: 0; }
.chip {
  min-height: 44px; /* cómodo con el pulgar; AA solo pide 24 */
  padding: var(--sp-2) var(--sp-4); border-radius: var(--r-pill);
  border: 1.5px solid var(--line); font-size: .86rem; font-weight: 600; color: var(--fg-muted);
  transition: all .18s var(--ease);
}
.chip:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-wash); }

/* ============================================================
   SECCIONES
   ============================================================ */
.sec { padding-block: var(--sp-8); }
/* El hero y el banner ya son dos "tarjetas" con esquinas redondeadas y
   fondo propio — el padding-block completo de .sec (pensado para separar
   franjas planas sin borde) se sentia como un salto de mas entre dos
   cajas que ya se distinguen solas. Sube menos, solo aqui. */
.sec:has(.banner) { padding-top: var(--sp-6); }
/* Antes .sec--tint pintaba --bg (igual al fondo de la pagina) de pared a
   pared: no se veia ninguna franja, y dos .sec--tint seguidas (Como
   funciona + Destacados) se sentian una sola caja sin borde. Ahora es un
   panel propio -- mismo ancho/inset que .wrap, radio igual al hero/banner,
   fondo --bg-sunken (un tercer tono ya en tokens.css, distinto de --bg y
   de --bg-elev de las tarjetas de adentro) -- para que cada seccion se lea
   como su propia tarjeta, igual que el hero y el banner. */
.sec--tint {
  background: var(--bg-sunken);
  width: calc(100% - var(--sp-5) * 2);
  max-width: var(--wrap);
  margin-inline: auto;
  border-radius: var(--r-2xl);
  /* margin-block + sombra: el fondo --bg-sunken llena TODO el padding de
     .sec, asi que dos .sec--tint seguidas (cuando "Destacados" no carga
     entre ellas) se leian como un solo bloque crema. El margen deja pasar
     el fondo de la pagina entre las dos tarjetas y la sombra levanta cada
     una como panel propio -- mismo criterio que el hero/banner. */
  margin-block: var(--sp-5);
  box-shadow: var(--shadow-1);
}
@media (min-width: 768px) { .sec--tint { width: calc(100% - var(--sp-6) * 2); } }
.sec__head { text-align: center; max-width: 62ch; margin-inline: auto; margin-bottom: var(--sp-7); }
.sec__head h2 { font-size: clamp(1.8rem, 3.6vw, 2.6rem); margin-block: var(--sp-3); }
.sec__head p { color: var(--fg-muted); font-size: 1.05rem; }

/* ============================================================
   BANNER: lo mejor de dos tiendas
   ============================================================ */
.banner {
  position: relative; overflow: hidden;
  border-radius: var(--r-2xl);
  background:
    /* #10527A: brillo decorativo del banner, no lleva texto encima */
    radial-gradient(120% 140% at 88% 12%, #10527A 0%, transparent 55%),
    linear-gradient(155deg, var(--band-dark-2) 0%, var(--band-dark) 100%);
  color: var(--band-dark-fg);
  display: grid; gap: var(--sp-6);
  padding: var(--sp-7) var(--sp-6);
  box-shadow: var(--shadow-3);
}
@media (min-width: 900px) {
  .banner { grid-template-columns: 1fr 1fr; align-items: center; padding: var(--sp-8); gap: var(--sp-7); }
}
.banner h2 { font-size: clamp(1.9rem, 4vw, 2.9rem); margin-block: var(--sp-4) var(--sp-4); }
.banner p { color: #B9D3E6; font-size: 1.05rem; max-width: 44ch; margin-bottom: var(--sp-5); }
.banner__art { position: relative; min-height: 260px; }

/* ============================================================
   CÓMO FUNCIONA — 3 pasos
   ============================================================ */
.steps { display: grid; gap: var(--sp-5); counter-reset: step; }
@media (min-width: 860px) { .steps { grid-template-columns: repeat(3, 1fr); gap: var(--sp-6); } }
.step {
  position: relative; background: var(--bg-elev);
  border: 1.5px solid var(--line); border-radius: var(--r-xl);
  padding: var(--sp-6); transition: transform .2s var(--ease), box-shadow .2s var(--ease);
}
.step:hover { transform: translateY(-3px); box-shadow: var(--shadow-2); }
.step__icon {
  width: 56px; height: 56px; border-radius: var(--r-md);
  background: var(--accent-wash); color: var(--accent);
  display: grid; place-items: center; margin-bottom: var(--sp-4);
}
.step__icon svg { width: 28px; height: 28px; }
/* Número de paso: adorno visual, no información — el <h3> ya dice el paso,
   y va aria-hidden. Con --blue-100 daba 1.15:1, o sea invisible; este da
   1.66:1, que se lee como marca de agua sin competir con el título. */
.step__n {
  position: absolute; top: var(--sp-5); right: var(--sp-5);
  font-size: 2.6rem; font-weight: 800; color: var(--band-dark-fg-muted); line-height: 1;
}
.step h3 { font-size: 1.2rem; margin-bottom: var(--sp-3); }
.step p { color: var(--fg-muted); font-size: .96rem; }

/* ============================================================
   TIENDAS QUE COMPARAMOS
   ============================================================ */
.stores { display: grid; gap: var(--sp-5); }
@media (min-width: 780px) { .stores { grid-template-columns: 1fr 1fr; } }
.store {
  background: var(--bg-elev); border: 1.5px solid var(--line);
  border-radius: var(--r-xl); padding: var(--sp-6);
  display: flex; gap: var(--sp-5); align-items: flex-start;
}
.store__logo {
  width: 60px; height: 60px; border-radius: var(--r-md);
  display: grid; place-items: center; flex-shrink: 0; font-weight: 800; font-size: 1.5rem;
}
.store__logo--az { background: var(--store-az-wash); color: var(--store-az); }
.store__logo--ml { background: var(--store-ml-wash); color: var(--store-ml); }
.store h3 { font-size: 1.25rem; margin-bottom: var(--sp-2); }
.store p { color: var(--fg-muted); font-size: .95rem; }
.store__meta { display: flex; gap: var(--sp-4); margin-top: var(--sp-4); font-size: .85rem; color: var(--fg-faint); font-weight: 600; }

/* ============================================================
   TARJETAS DE PRODUCTO
   ============================================================ */
.pgrid { display: grid; gap: var(--sp-5); grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
.pcard {
  position: relative; display: flex; flex-direction: column;
  background: var(--bg-elev); border: 1.5px solid var(--line);
  border-radius: var(--r-lg); overflow: hidden;
  transition: transform .2s var(--ease), box-shadow .2s var(--ease), border-color .2s var(--ease);
}
.pcard:hover { transform: translateY(-4px); box-shadow: var(--shadow-2); border-color: var(--accent); }
.pcard__media { aspect-ratio: 4/3; background: var(--bg); display: grid; place-items: center; padding: var(--sp-4); }
.pcard__media img { max-height: 100%; width: auto; object-fit: contain; mix-blend-mode: multiply; }
/* Mismo problema y mismo arreglo que .ganador__foto/.tarjeta__foto/
   .fcard__media (2026-08-27): esta tarjeta (colecciones) nunca habia
   tenido el arreglo de oscuro -- las fotos se veian manchadas siempre
   en oscuro, con o sin toggle manual. */
:root[data-theme='dark'] .pcard__media img { mix-blend-mode: normal; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .pcard__media img { mix-blend-mode: normal; }
}
.pcard__body { padding: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-3); flex: 1; }
.pcard__title {
  font-size: .95rem; font-weight: 700; line-height: 1.35;
  display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.pcard__foot { margin-top: auto; display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-3); }
.price { font-size: 1.25rem; font-weight: 800; letter-spacing: -.02em; }
.price s { display: block; font-size: .8rem; font-weight: 500; color: var(--fg-faint); }

.tag {
  display: inline-flex; align-items: center; align-self: flex-start;
  padding: 3px var(--sp-3); border-radius: var(--r-sm);
  font-size: .68rem; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
}
.tag--az { background: var(--store-az-wash); color: var(--store-az); }
.tag--ml { background: var(--store-ml-wash); color: var(--store-ml); }

.stars { display: flex; align-items: center; gap: var(--sp-1); font-size: .82rem; color: var(--fg-muted); font-weight: 600; }
.stars svg { width: 14px; height: 14px; color: var(--verdict-accent-solid); }

/* ============================================================
   POR QUÉ COTEJO
   ============================================================ */
.why { display: grid; gap: var(--sp-5); }
/* 2x2 fijo -- con la 4a tarjeta ("Donamos el 1%", 2026-08-25) un grid de
   3 columnas la dejaba sola en una fila aparte; auto-fit tambien elegia
   3+1 en la mayoria de anchos de pantalla reales, en vez del 2x2 mas
   equilibrado que pidio el usuario en la revision del 2026-08-25. */
@media (min-width: 640px) { .why { grid-template-columns: repeat(2, 1fr); } }
.why__card {
  border-radius: var(--r-xl); padding: var(--sp-6);
  border: 1.5px solid var(--line); background: var(--bg-elev);
}
.why__card--accent {
  background: linear-gradient(160deg, var(--band-dark-2), var(--band-dark));
  border-color: transparent; color: var(--band-dark-fg);
}
.why__card--accent p { color: var(--band-dark-fg-muted); }
.why__card--soft { background: var(--accent-wash); border-color: var(--accent-wash); }
.why__ico {
  width: 48px; height: 48px; border-radius: var(--r-md); display: grid; place-items: center;
  background: var(--accent-wash); color: var(--accent); margin-bottom: var(--sp-4);
}
.why__card--accent .why__ico { background: rgba(255,255,255,.14); color: var(--band-dark-fg); }
.why__ico svg { width: 24px; height: 24px; }
.why__card h3 { font-size: 1.15rem; margin-bottom: var(--sp-3); }
.why__card p { color: var(--fg-muted); font-size: .96rem; }
/* Unico link dentro de texto corrido de esta seccion (Fundación Dibujando
   un Mañana) -- a{color:inherit} global lo dejaria identico al texto
   plano, sin ninguna señal de que es clickeable. */
.why__card p a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.why__card p a:hover { color: var(--verdict-accent); }
/* Va DESPUÉS de .why__card p a propósito: ambas tienen especificidad (0,2,0),
   así que gana la última. Declarada antes, la tarjeta azul marino quedaba con
   texto oscuro encima (1.69:1, ilegible). Así da 8.34:1. */
.why__card--accent p { color: var(--band-dark-fg-muted); }

/* ============================================================
   PREGUNTAS FRECUENTES
   ============================================================ */
.faq { max-width: 820px; margin-inline: auto; display: grid; gap: var(--sp-3); }
.faq details {
  background: var(--bg-elev); border: 1.5px solid var(--line);
  border-radius: var(--r-md); overflow: hidden;
  transition: border-color .18s var(--ease);
}
.faq details[open] { border-color: var(--accent); }
.faq summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
  padding: var(--sp-5); font-weight: 700; cursor: pointer; list-style: none;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: '+'; font-size: 1.5rem; font-weight: 400; color: var(--accent-solid);
  line-height: 1; flex-shrink: 0; transition: transform .2s var(--ease);
}
.faq details[open] summary::after { transform: rotate(45deg); }
.faq__body { padding: 0 var(--sp-5) var(--sp-5); color: var(--fg-muted); }

/* ============================================================
   AVISO DE AFILIADOS
   ============================================================ */
.disclose {
  display: flex; gap: var(--sp-4); align-items: flex-start;
  background: var(--accent-wash); border: 1.5px solid var(--accent-wash);
  border-radius: var(--r-xl); padding: var(--sp-5);
  font-size: .92rem; color: var(--fg-muted);
}
.disclose svg { width: 20px; height: 20px; color: var(--accent); flex-shrink: 0; margin-top: 2px; }
.disclose strong { color: var(--fg); }

/* ============================================================
   PIE
   ============================================================ */
/* .ftr ya no vive dentro del .wrap de pagina completa (ver .site-header
   arriba, mismo problema y mismo fix): antes su fondo oscuro quedaba
   encajonado a 1180px con el fondo de la pagina asomando a los lados en
   pantallas anchas, en vez de una franja de ancho completo como en
   cualquier sitio real. Ahora .ftr es full-bleed y su contenido
   (.ftr__grid + .ftr__bot) vive dentro de un .wrap propio que lo centra.
   Reportado por el usuario 2026-08-25. */
.ftr { background: var(--band-dark); color: #92AEC2; padding-block: var(--sp-8) var(--sp-6); margin-top: var(--sp-8); }
/* El logo del pie era un <span> sin link -- no llevaba a ningún lado al
   hacer clic. Ahora es <a data-nav-home>, mismo comportamiento que el
   logo del header (vuelve al inicio). Reset de estilos de link nativo:
   sin esto heredaría azul/subrayado de navegador. */
.ftr .logo { color: inherit; text-decoration: none; }
/* Botones del footer (2026-09-14): .btn--outline normal usa --bg-elev/--fg,
   que siguen el tema claro/oscuro de la PAGINA -- pero .ftr es una banda
   oscura fija (no voltea con el tema, ver docs/marca.md), así que en tema
   oscuro ese botón casi desaparece contra un fondo casi del mismo tono.
   Se sobreescribe aquí con los tokens --band-dark-fg (fijos también) para
   que el contraste no dependa del tema. */
.ftr__actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-5); }
.ftr__actions .btn--outline {
  background: transparent; border-color: rgba(247,244,233,.3); color: var(--band-dark-fg);
}
.ftr__actions .btn--outline:hover { border-color: var(--band-dark-fg); color: #fff; }
.ftr__grid { display: grid; gap: var(--sp-6); }
@media (min-width: 780px) { .ftr__grid { grid-template-columns: 1.6fr 1fr 1fr; gap: var(--sp-7); } }
.ftr h4 { color: #fff; font-size: .74rem; letter-spacing: .14em; text-transform: uppercase; margin-bottom: var(--sp-4); }
.ftr ul { list-style: none; padding: 0; display: grid; gap: var(--sp-2); font-size: .94rem; }
/* Los enlaces medían 19px de alto: por debajo de los 24px que pide
   WCAG 2.5.8 (AA). El padding los lleva a 32px sin cambiar el aspecto. */
.ftr ul a { display: inline-block; padding-block: var(--sp-2); }
.ftr a:hover { color: var(--band-dark-fg); }
/* Antes vivía como .disclosure, su propia franja con fondo claro entre
   <main> y el footer -- el usuario pidió juntarla con el copyright en la
   misma fila (disclosure a la izquierda, "© 2026 Cotejo" a la derecha)
   en vez de dos bloques apilados, para recortar el alto del footer y no
   dejar tanto vacío debajo de la columna "Aviso". */
.ftr__bot {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--sp-3) var(--sp-6);
  border-top: 1px solid rgba(255,255,255,.1);
  margin-top: var(--sp-6);
  padding-top: var(--sp-5);
  font-size: .86rem;
}
.ftr__disclosure {
  font-size: .82rem;
  color: var(--band-dark-fg-muted);
  flex: 1 1 480px;
}
.ftr__copy { white-space: nowrap; }
.ftr .logo__name { color: var(--band-dark-fg); }
.ftr .logo__sub { color: var(--band-dark-fg-muted); }

/* ============================================================
   PAGINA DE RESULTADOS
   Todo sale de tokens.css. Ningun color literal aqui.
   ============================================================ */
.res {
  display: flex; flex-direction: column; gap: var(--sp-7);
  padding-block: var(--sp-6) var(--sp-8);
}

.eyebrow {
  font-size: .72rem; font-weight: 800; letter-spacing: .12em;
  text-transform: uppercase; color: var(--fg-faint);
}

.sec-tit {
  font-size: clamp(1.2rem, 2.6vw, 1.5rem);
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--sp-5);
}

/* ---------- 1. Acuse: lo que entendi ---------- */
.acuse { display: flex; flex-direction: column; gap: var(--sp-3); }
.acuse__query {
  font-size: clamp(1.5rem, 3.6vw, 2.1rem);
  line-height: 1.2; max-width: 30ch;
}
.acuse__meta {
  display: flex; flex-wrap: wrap; gap: var(--sp-4);
  align-items: center; font-size: .9rem; color: var(--fg-muted);
}
.acuse__conteo strong { color: var(--fg); }

.fuente { display: inline-flex; align-items: center; gap: var(--sp-2); font-size: .84rem; }
.fuente__punto {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--ok); flex-shrink: 0;
}
.fuente--live { color: var(--fg-muted); }

/* Checklist de requisitos — la prueba de fidelidad.
   DATO PENDIENTE: extract_requirements() ya lo calcula pero no viaja
   al front. Ver docs/contrato-datos.md */
.requisitos {
  background: var(--accent-wash);
  border-radius: var(--r-md);
  padding: var(--sp-4) var(--sp-5);
  display: flex; flex-direction: column; gap: var(--sp-3);
  margin-top: var(--sp-2);
}
.requisitos__tit {
  font-size: .74rem; font-weight: 800; letter-spacing: .1em;
  text-transform: uppercase; color: var(--accent);
}
.requisitos__lista {
  display: flex; flex-wrap: wrap; gap: var(--sp-2);
  list-style: none; padding: 0;
}
.req {
  background: var(--bg-elev); border: 1px solid var(--line);
  border-radius: var(--r-pill); padding: var(--sp-2) var(--sp-4);
  font-size: .88rem; font-weight: 600;
}
.req--num strong { font-variant-numeric: tabular-nums; }
/* Palabra clave cualitativa (Tramo 1, #3): "Bluetooth", "Con micrófono".
   Mismo chip pero SIN el peso del valor -- se distingue del requisito
   numérico verificable con un punto delante y color más tenue, porque no
   trae ✓/✗ (no hay spec que comprobar, solo confirma que se entendió). */
.req--kw { font-weight: 500; color: var(--fg-muted); }
.req--kw::before { content: "•"; margin-right: 6px; color: var(--accent); }
.requisitos__nota { font-size: .84rem; color: var(--fg-muted); }

/* Badge de envío en la tarjeta (Tramo 1, #1). Verde, para no chocar con
   el MSI (indigo, .precio__contexto) ni con el acento naranja de marca.
   Hardcodeado + override oscuro, mismo patrón que .precio__contexto. */
.envio-badge:not([hidden]) {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: .78rem; font-weight: 600; padding: 3px 10px; border-radius: var(--r-pill);
  background: #DDEEEC; color: #0F5C54; border: 1.5px solid #B4D9D4;
  white-space: nowrap;
}
:root[data-theme='dark'] .envio-badge { background: rgba(91,185,140,.16); color: #8FD8BC; border-color: rgba(91,185,140,.34); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .envio-badge { background: rgba(91,185,140,.16); color: #8FD8BC; border-color: rgba(91,185,140,.34); }
}

/* Precio histórico (Tramo 1, #2) -- "↓ Precio más bajo en N días".
   Texto en acento, sin fondo: es una nota sobre el precio, no otra
   pastilla que compita con envío/MSI. El backend solo lo manda cuando el
   dato real lo respalda. */
.precio-hist:not([hidden]) {
  display: inline-flex; align-items: center;
  font-size: .8rem; font-weight: 700; color: var(--accent);
}

/* ---------- 2. Veredicto ----------
   Unica excepcion editorial del sistema: serif y acento calido sobre
   base fria, para que la OPINION se distinga de la EVIDENCIA sin leer. */
.veredicto {
  position: relative; overflow: hidden;
  background: var(--bg-elev);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
  padding: var(--sp-5) var(--sp-5) var(--sp-5) var(--sp-6);
  display: flex; flex-direction: column; gap: var(--sp-3);
}
.veredicto::before {
  content: ""; position: absolute; inset-block: 0; inset-inline-start: 0;
  width: 4px; background: var(--verdict-accent-solid);
}
.veredicto .eyebrow { color: var(--verdict-accent); }
.veredicto__txt {
  font-family: var(--ff-verdict);
  font-size: clamp(1.1rem, 2.3vw, 1.4rem);
  line-height: 1.5; letter-spacing: -.005em;
  max-width: var(--measure);
}
.veredicto__txt strong { font-weight: 700; }
.veredicto__compartir {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  align-self: flex-start;
  font-size: var(--fs--1); font-weight: 600;
  color: var(--fg-muted);
  text-decoration: none;
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.veredicto__compartir:hover { color: var(--verdict-accent); border-color: var(--verdict-accent); }
.veredicto__compartir svg { flex: none; }

/* Veredicto plegado dentro de la tarjeta ganadora (2026-09): ocupa el
   ancho completo arriba de la tarjeta (grid-column 1/-1 sirve con 1 o 2
   columnas). Sin sombra ni fondo elevado propio -- ya vive dentro de una
   tarjeta --bg-elev; se asienta como panel inset igual que .ganador__foto
   (fondo --bg). La barra de acento a la izquierda se conserva. */
.ganador > .veredicto {
  grid-column: 1 / -1;
  margin: 0;
  box-shadow: none;
  background: var(--bg);
  border-radius: var(--r-md);
  padding: var(--sp-4) var(--sp-4) var(--sp-4) var(--sp-5);
  gap: var(--sp-2);
}
.ganador > .veredicto .veredicto__txt { font-size: clamp(1.02rem, 1.9vw, 1.2rem); }

/* Con dona de puntaje: grid de 2 columnas -- texto del veredicto a la
   izquierda (3 filas: eyebrow, texto, compartir), dona a la derecha
   ocupando el alto de las 3. En movil se apila. */
.ganador > .veredicto.veredicto--con-score {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "eyebrow donut" "txt donut" "share donut";
  align-items: start;
  gap: var(--sp-2) var(--sp-5);
}
.ganador > .veredicto.veredicto--con-score .eyebrow { grid-area: eyebrow; }
.ganador > .veredicto.veredicto--con-score .veredicto__txt { grid-area: txt; }
.ganador > .veredicto.veredicto--con-score .veredicto__compartir { grid-area: share; align-self: start; }
.ganador > .veredicto.veredicto--con-score .score-donut { grid-area: donut; align-self: center; }
@media (max-width: 559px) {
  .ganador > .veredicto.veredicto--con-score {
    grid-template-columns: 1fr;
    grid-template-areas: "eyebrow" "txt" "donut" "share";
    justify-items: start;
  }
  .ganador > .veredicto.veredicto--con-score .score-donut { justify-self: center; }
}

/* Dona de puntaje del ganador -- mismo aro que la tabla comparativa pero
   mas chica y con etiqueta. --score es 0-100; 2.827 = circunferencia(r45)/100. */
.score-donut {
  position: relative; flex: none; align-self: center;
  width: 84px; display: grid; place-items: center; text-align: center;
}
.score-donut svg { width: 84px; height: 84px; }
.score-donut__track { fill: none; stroke: var(--bg-sunken); stroke-width: 7; }
.score-donut__fill {
  fill: none; stroke: var(--verdict-accent-solid); stroke-width: 7; stroke-linecap: round;
  transform: rotate(-90deg); transform-origin: 50px 50px;
  stroke-dasharray: calc(var(--score, 0) * 2.827) 282.7;
  transition: stroke-dasharray .6s var(--ease);
}
.score-donut__num {
  position: absolute; top: 44%; left: 50%; transform: translate(-50%, -50%);
  font-weight: 700; font-size: 1.5rem; color: var(--fg); font-variant-numeric: tabular-nums;
}
.score-donut__cap {
  position: absolute; top: 66%; left: 50%; transform: translateX(-50%);
  font-size: .6rem; letter-spacing: .08em; text-transform: uppercase; color: var(--fg-faint);
}

/* Imagen / celda que navega al detalle. El click vive en JS
   (.tarjeta__foto / .comp-product-col), con guarda para las miniaturas
   de galeria que tienen su propio handler. */
.is-clickable { cursor: pointer; }
.is-clickable:hover img,
img.is-clickable:hover { opacity: .82; transition: opacity .15s var(--ease); }
.comp-product-col.is-clickable:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.feedback {
  background: var(--bg-elev);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--sp-5);
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-3);
  margin-top: var(--sp-6);
}
.feedback__pregunta { font-weight: 600; margin: 0; }
/* :not([hidden]) en vez de display:flex sin condicion -- mismo bug ya
   documentado arriba en .hero (2026-08-21): display de autor empata en
   especificidad con la regla [hidden] del navegador y gana por orden,
   dejando el bloque visible aunque JS ya haya puesto hidden=true. */
.feedback__botones:not([hidden]) { display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.feedback__gracias { color: var(--verdict-accent); font-size: var(--fs--1); margin: 0; }
.feedback__comentario:not([hidden]) { display: flex; flex-direction: column; gap: var(--sp-3); width: 100%; max-width: 480px; }
.feedback__comentario textarea {
  width: 100%; resize: vertical; font-family: var(--ff-sans); font-size: var(--fs--1);
  padding: var(--sp-3); border-radius: var(--r-md); border: 1px solid var(--line);
  background: var(--bg); color: var(--fg);
}
.feedback__comentario .btn { align-self: flex-end; }

.ver-mas { align-self: center; }
.ver-mas[disabled] { cursor: wait; }
.ver-mas__spinner {
  display: inline-block;
  width: 14px; height: 14px;
  margin-right: var(--sp-2);
  vertical-align: -2px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: ver-mas-girar .7s linear infinite;
}
@keyframes ver-mas-girar { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .ver-mas__spinner { animation-duration: 1.6s; }
}

/* Tarjeta fantasma mientras carga "Ver más" -- misma rejilla que .tarjeta */
.tarjeta--sk {
  display: grid; gap: var(--sp-4);
  background: var(--bg-elev); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: var(--sp-4);
}
@media (min-width: 640px) { .tarjeta--sk { grid-template-columns: 150px 1fr; } }
.tarjeta--sk__foto { align-self: start; }
.tarjeta--sk__cuerpo { display: flex; flex-direction: column; gap: var(--sp-3); padding-top: var(--sp-2); }

/* ---------- Piezas compartidas de tarjeta ---------- */
.tienda {
  display: inline-block; border-radius: var(--r-sm);
  padding: 2px var(--sp-2); font-size: .68rem;
  font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
}
.tienda--az { background: var(--store-az); color: var(--store-az-fg); }
.tienda--ml { background: var(--store-ml); color: var(--store-ml-fg); }

.estrellas { display: inline-flex; align-items: baseline; gap: var(--sp-2); font-size: .86rem; }
.estrellas__num { font-weight: 700; font-variant-numeric: tabular-nums; }
.estrellas__conteo { color: var(--fg-muted); }
.estrellas__conteo--nd { font-style: italic; color: var(--fg-faint); }

/* Cumple / no cumple / sin dato, contra los requisitos de la busqueda.
   El estado "sin dato" es distinto de "no cumple" a proposito: casi
   siempre la tienda no publica el dato, y afirmar que no cumple seria
   falso. */
.cumple {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-size: .78rem; font-weight: 700;
  padding: 2px var(--sp-3); border-radius: var(--r-pill);
  border: 1px solid currentColor;
}
.cumple::before { font-weight: 800; }
.cumple--si { color: var(--ok); }
.cumple--si::before { content: "\2713"; }
.cumple--no { color: var(--bad); }
.cumple--no::before { content: "\2715"; }
.cumple--nd { color: var(--fg-faint); }
.cumple--nd::before { content: "\2014"; }

.rango {
  position: absolute; top: var(--sp-3); left: var(--sp-3); z-index: 2;
  min-width: 26px; height: 26px; padding-inline: 6px;
  display: grid; place-items: center;
  border-radius: var(--r-pill);
  background: var(--fg); color: var(--bg-elev);
  font-size: .78rem; font-weight: 800;
}
/* Favoritos (Tramo 9, 2026-09-08): esquina opuesta a .rango. Empieza
   [hidden] -- app.js lo revela solo tras confirmar sesión (auth.js),
   igual que el resto de la UI que depende de Clerk. Estrella outline
   sin guardar, rellena con --accent (mismo color que las estrellas de
   rating, ver .rating .star) cuando ya esta guardado. */
.fav-toggle {
  position: absolute; top: var(--sp-3); right: var(--sp-3); z-index: 2;
  width: 32px; height: 32px; display: grid; place-items: center;
  border-radius: 50%; border: none; cursor: pointer;
  background: color-mix(in srgb, var(--bg-elev) 85%, transparent);
  box-shadow: var(--shadow-2);
  transition: transform .12s var(--ease);
}
.fav-toggle:hover { transform: scale(1.08); }
.fav-toggle svg { width: 18px; height: 18px; fill: none; stroke: var(--fg-muted); stroke-width: 1.6; }
.fav-toggle[aria-pressed="true"] svg { fill: var(--accent); stroke: var(--accent); }
.fav-toggle.is-busy { opacity: .6; pointer-events: none; }

/* Sello dentado en vez de circulo liso para el ganador -- el numero
   "1" quedaba casi igual que los demas (2,3,4,5), sin distinguirse.
   Forma via mask (no background-image): el color sigue viniendo de
   --accent-solid, tokens.css sigue siendo la unica fuente de color. */
.rango--1 {
  min-width: 40px; height: 40px; font-size: 1rem;
  background: linear-gradient(140deg,
    color-mix(in srgb, var(--accent-solid) 65%, white),
    var(--accent-solid),
    color-mix(in srgb, var(--accent-solid) 55%, black));
  color: var(--accent-ink);
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M16.00,1.00L19.83,6.76L26.61,5.39L25.24,12.17L31.00,16.00L25.24,19.83L26.61,26.61L19.83,25.24L16.00,31.00L12.17,25.24L5.39,26.61L6.76,19.83L1.00,16.00L6.76,12.17L5.39,5.39L12.17,6.76Z'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M16.00,1.00L19.83,6.76L26.61,5.39L25.24,12.17L31.00,16.00L25.24,19.83L26.61,26.61L19.83,25.24L16.00,31.00L12.17,25.24L5.39,26.61L6.76,19.83L1.00,16.00L6.76,12.17L5.39,5.39L12.17,6.76Z'/%3E%3C/svg%3E");
  -webkit-mask-size: contain; mask-size: contain;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center; mask-position: center;
}

.tarjeta__meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); }
.tarjeta__titulo { font-size: 1rem; font-weight: 700; line-height: 1.35; }
.tarjeta__titulo a {
  display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2;
  -webkit-box-orient: vertical; overflow: hidden;
}
.tarjeta__titulo a:hover { color: var(--accent); }
.tarjeta__marca {
  font-size: var(--fs--1); color: var(--fg-muted);
  text-transform: uppercase; letter-spacing: 0.04em;
  margin: 0;
}
.porque { font-size: .92rem; color: var(--fg-muted); max-width: var(--measure); }
/* Nota de una colección curada: puede traer bullets/negritas (ver
   collection_pipeline._sanitize_rich_text) en vez de una sola oración. */
.porque p { margin: 0 0 var(--sp-2); }
.porque p:last-child { margin-bottom: 0; }
.porque ul, .porque ol { margin: var(--sp-1) 0 0; padding-left: 1.2em; }
.porque li { margin-bottom: 2px; }
.porque b, .porque strong { color: var(--fg); }

.precio {
  display: inline-flex; align-items: baseline; flex-wrap: wrap;
  gap: var(--sp-2);
  font-size: 1.3rem; font-weight: 800; font-variant-numeric: tabular-nums;
}
.precio__moneda { font-size: .8rem; font-weight: 600; color: var(--fg-faint); margin-left: var(--sp-1); }
.precio__antes { font-size: .9rem; font-weight: 500; color: var(--fg-faint); }
/* Badge de % de descuento -- mismo patron de pill que .ganador__etiqueta
   (accent-wash de fondo, accent de texto), para que el precio tachado se
   sienta a promocion real y no a un simple numero cruzado. Agregado
   2026-08-26: la clase .precio__antes ya existia pero nunca se aplicaba
   (el <s> se creaba sin clase), asi que el precio anterior se veia con el
   mismo tamano/peso grande que el precio actual -- de ahi la queja. */
.precio__badge {
  display: inline-flex; align-items: center;
  background: var(--accent-wash); color: var(--accent);
  border-radius: var(--r-pill); padding: 2px var(--sp-2);
  font-family: var(--ff-display); font-size: .72rem; font-weight: 700;
  white-space: nowrap;
}

/* ---------- 3. Ganador ---------- */
.ganador {
  display: grid; gap: var(--sp-5);
  background: var(--bg-elev); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: var(--sp-5);
  box-shadow: var(--shadow-2);
}
@media (min-width: 820px) { .ganador { grid-template-columns: 300px 1fr; gap: var(--sp-6); } }
.ganador__foto { position: relative; background: var(--bg); border-radius: var(--r-md); padding: var(--sp-4); }
.ganador__etiqueta {
  position: absolute; top: var(--sp-3); left: calc(var(--sp-3) + 48px); z-index: 2;
  display: inline-flex; align-items: center;
  background: var(--bg-elev); border: 1.5px solid var(--accent);
  border-radius: var(--r-pill); padding: 4px var(--sp-3);
  font-family: var(--ff-display); font-size: .72rem; font-weight: 700;
  color: var(--fg); box-shadow: var(--shadow-1); white-space: nowrap;
}
.ganador__foto img {
  width: 100%; height: auto; max-height: 320px;
  object-fit: contain; mix-blend-mode: multiply;
}
/* Las fotos de producto vienen con fondo blanco de la tienda. En claro,
   multiply las integra; en oscuro produciria manchas, asi que se apaga.
   OJO (bug real encontrado 2026-08-27, mismo patron que el de los
   badges MSI/MercadoLider ese mismo dia): esto solo cubria el toggle
   MANUAL de tema -- alguien con el sistema en oscuro por default
   ("Auto", sin tocar el boton) seguia viendo las fotos con multiply,
   manchadas. Falta el bloque @media para el caso sin toggle. */
:root[data-theme='dark'] .ganador__foto img,
:root[data-theme='dark'] .tarjeta__foto img { mix-blend-mode: normal; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .ganador__foto img,
  :root:not([data-theme='light']) .tarjeta__foto img { mix-blend-mode: normal; }
}
.ganador__cuerpo { display: flex; flex-direction: column; gap: var(--sp-4); align-items: flex-start; }
.ganador__cuerpo .tarjeta__titulo { font-size: 1.15rem; }
.ganador__cuerpo .tarjeta__titulo a { -webkit-line-clamp: 3; line-clamp: 3; }
.ganador__precio { display: flex; align-items: flex-start; flex-direction: column; gap: 4px; }
.ganador__precio .precio { font-size: 1.9rem; }

/* Miniaturas de galeria dentro de la tarjeta ganadora (2026-08-27) -- la
   columna de foto es mas angosta que en el detalle, thumbs mas chicos que
   el default de .detail-gallery para no desbordar. */
.ganador__foto .detail-gallery__thumb { width: 40px; height: 40px; }
/* Galeria en las tarjetas de alternativas (2026-09): thumbs mas chicos
   que en el ganador -- la foto de la alternativa ya es de 200px, no 300. */
.tarjeta__foto .detail-gallery { margin-top: var(--sp-2); gap: 4px; }
.tarjeta__foto .detail-gallery__thumb { width: 34px; height: 34px; }
.ganador__foto .detail-variantes { margin-top: var(--sp-2); }

/* Carrusel de reviews reales (2026-08-27, maqueta final aprobada): debajo
   de la foto/variantes en la tarjeta ganadora, aprovecha el espacio que
   esa columna deja vacio en desktop. Cambia sola (ver fillCarrusel en
   render.js), se pausa con el mouse encima. Datos reales del mismo
   producto (specs.review_texts en ML, specs.review_evidence.citas en
   Amazon) -- no depende de Groq, sigue funcionando con "ai_ocupado". */
.mini-carrusel {
  margin-top: var(--sp-3); padding: var(--sp-3);
  background: var(--bg-sunken); border-radius: var(--r-sm); border: 1px solid var(--line);
}
.mini-carrusel__eyebrow {
  font-family: var(--ff-display); font-size: .68rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .06em; color: var(--fg-faint); margin: 0 0 6px;
}
.mini-carrusel__stack { position: relative; min-height: 48px; }
.mini-carrusel__slide {
  font-size: .8rem; color: var(--fg-muted); font-style: italic; margin: 0;
  opacity: 0; position: absolute; inset: 0; transition: opacity .5s var(--ease);
}
.mini-carrusel__slide.is-activa { opacity: 1; position: relative; }
.mini-carrusel__dots { display: flex; gap: 5px; margin-top: 8px; }
.mini-carrusel__dot {
  width: 5px; height: 5px; border-radius: 50%; background: var(--line-strong);
  transition: background var(--dur) var(--ease); border: none; padding: 0; cursor: pointer;
}
.mini-carrusel__dot.is-activa { background: var(--accent); }

/* Volumen mensual (Amazon, 2026-08-27) -- junto a rating/reviews, misma
   fila que las demas señales de popularidad. */
.volumen-mensual { font-size: .85rem; color: var(--fg-muted); }

/* Fila de confianza (2026-08-27, maqueta final aprobada): Tienda
   Oficial/Amazon's Choice + reputacion del vendedor, entre marca y precio
   -- justifica pagar ANTES de mostrar cuanto cuesta. */
.confianza-row { display: flex; flex-wrap: wrap; gap: 6px; }
.trust-pill {
  display: inline-flex; align-items: center; gap: 5px; border-radius: var(--r-pill);
  padding: 3px 10px; font-size: .78rem; font-weight: 600; border: 1.5px solid var(--line); color: var(--fg);
}
.trust-pill--gold { background: #FFF7DE; color: #6B5300; border-color: #E8C547; }
:root[data-theme='dark'] .trust-pill--gold { background: rgba(232,197,71,.14); color: #E8C547; border-color: rgba(232,197,71,.4); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .trust-pill--gold { background: rgba(232,197,71,.14); color: #E8C547; border-color: rgba(232,197,71,.4); }
}

/* Disponibilidad (2026-08-27) -- pegada al precio, es el ultimo filtro
   antes de decidir comprar. Booleano a proposito (nunca el numero exacto
   de existencias), ver CLAUDE.md "Frescura de datos mas alla del precio". */
/* :not([hidden]) -- .disponibilidad-row/.precio__contexto ponen display sin
   condicion y eso le gana a la regla [hidden] del navegador (mismo bug
   documentado arriba en .feedback__botones). Sin esto, la fila se veia
   vacia (solo el punto) cuando el producto no trae stock/MSI. */
.disponibilidad-row:not([hidden]) { display: flex; align-items: center; gap: 8px; font-size: .85rem; color: var(--fg-muted); }
.disponibilidad-row .punto { width: 8px; height: 8px; border-radius: 50%; background: var(--ok); flex: none; }
.disponibilidad-row--agotado .punto { background: var(--bad); }

/* MSI (2026-08-27, ML unicamente) -- pegado al precio, es donde se busca
   este dato en Mexico. Badge de color propio (indigo, distinto del
   dorado de Tienda Oficial y el verde de Disponible) para que el bloque
   de arriba no se sienta todo del mismo tono. */
.precio__contexto:not([hidden]) {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: .78rem; font-weight: 600; padding: 3px 10px; border-radius: var(--r-pill);
  background: #E4E7FA; color: #4A5FB8; border: 1.5px solid #C7CCF2;
}
:root[data-theme='dark'] .precio__contexto { background: rgba(139,156,232,.16); color: #B3BEF0; border-color: rgba(139,156,232,.35); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .precio__contexto { background: rgba(139,156,232,.16); color: #B3BEF0; border-color: rgba(139,156,232,.35); }
}

.prosycontras { display: grid; gap: var(--sp-4); width: 100%; }
@media (min-width: 560px) { .prosycontras { grid-template-columns: 1fr 1fr; } }
.pyc__tit {
  font-size: .72rem; font-weight: 800; letter-spacing: .1em;
  text-transform: uppercase; margin-bottom: var(--sp-2);
}
.pyc__tit--pro { color: var(--ok); }
.pyc__tit--con { color: var(--bad); }
.pyc { list-style: none; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); font-size: .9rem; }
.pyc li { position: relative; padding-left: var(--sp-4); color: var(--fg-muted); }
.pyc li::before { content: "\2022"; position: absolute; left: 0; color: var(--fg-faint); }

.specs { display: grid; gap: 0; width: 100%; border-top: 1px solid var(--line); }
.specs > div {
  display: flex; justify-content: space-between; gap: var(--sp-4);
  padding: var(--sp-3) 0; border-bottom: 1px solid var(--line); font-size: .9rem;
}
.specs dt { color: var(--fg-muted); }
.specs dd { font-weight: 600; text-align: right; }

/* Desglose "por qué quedó en #1" (grab-bag): plegable, una barra por
   factor de la formula de ranking. Ancho relativo al factor que mas peso. */
.porque-score { width: 100%; font-size: .88rem; }
.porque-score > summary {
  cursor: pointer; color: var(--accent); font-weight: 600;
  padding: var(--sp-2) 0; list-style: none;
}
.porque-score > summary::-webkit-details-marker { display: none; }
.porque-score > summary::before { content: "\25B8\00a0"; display: inline-block; transition: transform .15s var(--ease); }
.porque-score[open] > summary::before { transform: rotate(90deg); }
.porque-score__body { display: flex; flex-direction: column; gap: var(--sp-2); margin-top: var(--sp-2); }
.porque-score__fila { display: grid; grid-template-columns: 11rem 1fr 2.5rem; align-items: center; gap: var(--sp-2); }
.porque-score__label { color: var(--fg-muted); }
.porque-score__barra { height: 8px; border-radius: var(--r-pill); background: var(--bg-sunken); overflow: hidden; }
.porque-score__fill { display: block; height: 100%; background: var(--accent); border-radius: inherit; }
.porque-score__pct { font-family: var(--ff-mono); font-size: .8rem; color: var(--fg-muted); text-align: right; }
.porque-score__nota { margin-top: var(--sp-2); font-size: .78rem; color: var(--fg-faint); }
@media (max-width: 559px) { .porque-score__fila { grid-template-columns: 8rem 1fr 2.2rem; } }

.btn--comprar { width: 100%; }
@media (min-width: 560px) { .btn--comprar { width: auto; min-width: 16rem; } }

/* ---------- 4. Alternativas ---------- */
.alternativas { list-style: none; padding: 0; display: flex; flex-direction: column; gap: var(--sp-4); }
.tarjeta {
  position: relative; /* para la mini-dona de puntaje, arriba a la derecha */
  display: grid; gap: var(--sp-4);
  background: var(--bg-elev); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: var(--sp-4);
  transition: border-color .18s var(--ease), box-shadow .18s var(--ease);
}
.tarjeta__reviews { font-size: .82rem; color: var(--fg-muted); }

/* Banner suave "guarda esta comparación" -- arriba de los resultados,
   descartable, nunca bloquea. Ver renderSavePrompt / maybeShowSavePrompt. */
.save-prompt {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3) var(--sp-4);
  justify-content: space-between;
  background: var(--accent-wash); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-5);
}
.save-prompt__txt { font-size: .9rem; color: var(--fg-muted); margin: 0; flex: 1 1 16rem; }
.save-prompt__acciones { display: flex; align-items: center; gap: var(--sp-2); flex: none; }
.save-prompt__cerrar {
  width: 30px; height: 30px; border-radius: var(--r-sm);
  color: var(--fg-faint); font-size: .9rem; line-height: 1;
  display: grid; place-items: center;
}
.save-prompt__cerrar:hover { color: var(--fg); background: var(--bg-elev); }

/* Mini-dona de puntaje de las alternativas (mismo numero que la dona del
   ganador y la tabla -- scorePoints en render.js). Arriba a la derecha
   del card. --score (0-100) lo pone render.js en el contenedor. */
.score-mini {
  position: absolute; top: var(--sp-3); right: var(--sp-3);
  width: 40px; height: 40px; display: grid; place-items: center;
}
.score-mini svg { width: 40px; height: 40px; }
.score-mini__track { fill: none; stroke: var(--bg-sunken); stroke-width: 4; }
.score-mini__fill {
  fill: none; stroke: var(--accent); stroke-width: 4; stroke-linecap: round;
  transform: rotate(-90deg); transform-origin: 20px 20px;
  stroke-dasharray: calc(var(--score, 0) / 100 * 106.8) 106.8;
}
.score-mini__num {
  position: absolute; font-weight: 700; font-size: .8rem; color: var(--fg);
  font-variant-numeric: tabular-nums;
}
/* Reserva un carril a la derecha del cuerpo para que el titulo/meta no
   corran por debajo de la mini-dona. */
.tarjeta:has(.score-mini:not([hidden])) .tarjeta__cuerpo { padding-right: 2.75rem; }
/* En movil (card apilado) la mini-dona no debe tapar el badge/rating:
   baja un poco su prioridad visual quedandose en la esquina de la foto. */
@media (max-width: 639px) {
  .score-mini { top: auto; bottom: var(--sp-3); right: var(--sp-3); }
}
@media (min-width: 640px) { .tarjeta { grid-template-columns: 150px 1fr; } }
.tarjeta:hover { border-color: var(--accent); box-shadow: var(--shadow-1); }
.tarjeta__foto { position: relative; background: var(--bg); border-radius: var(--r-sm); padding: var(--sp-3); }
.tarjeta__foto img {
  width: 100%; height: auto; max-height: 170px;
  object-fit: contain; mix-blend-mode: multiply;
}
.tarjeta__cuerpo { display: flex; flex-direction: column; gap: var(--sp-3); }
/* "Mi cuenta" > favoritos (2026-09-08): bajada de precio desde que se
   guardó -- --ok es el mismo verde que ya usa el punto de "Del catálogo"
   en el acuse, reusado aquí como señal positiva. */
.fav-bajo-precio { color: var(--ok); font-size: .84rem; font-weight: 600; margin: 0; }
.tarjeta__pie {
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: var(--sp-3); margin-top: auto;
}
/* "Ver detalle" junto a "Ver oferta" (2026-08-25) -- antes la unica forma
   de abrir el detalle era el titulo, poco visible. */
.tarjeta__botones { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.ganador__acciones { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); }

/* ---------- 5. Comparativa ---------- */
.tabla-scroll { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--r-md); }
.comparativa { width: 100%; border-collapse: collapse; font-size: .9rem; min-width: 44rem; }
.comparativa th, .comparativa td {
  text-align: left; padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--line);
}
.comparativa thead th {
  font-size: .7rem; letter-spacing: .09em; text-transform: uppercase;
  color: var(--fg-faint); background: var(--bg);
}
.comparativa tbody th {
  font-weight: 600; display: flex; flex-direction: column;
  gap: var(--sp-2); align-items: flex-start;
}
.comparativa tbody tr:last-child th,
.comparativa tbody tr:last-child td { border-bottom: none; }
.comparativa td { font-variant-numeric: tabular-nums; }
.comparativa .mejor { background: var(--store-ml-wash); font-weight: 700; }
.mejor__tag {
  display: inline-block; margin-left: var(--sp-2);
  font-size: .64rem; font-weight: 800; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ok);
}
.mejor__tag--suelto { margin: 0; padding: 2px var(--sp-2); background: var(--store-ml-wash); border-radius: var(--r-sm); }
.comparativa .nd, .tabla-nota .nd { color: var(--fg-faint); font-style: italic; }
.comparativa .no { color: var(--bad); font-weight: 600; }
.asterisco { color: var(--fg-faint); cursor: help; }
.tabla-nota { font-size: .84rem; color: var(--fg-muted); margin-top: var(--sp-3); max-width: var(--measure); }

/* ---------- 6. Aviso de afiliados ---------- */
.afiliados {
  border-top: 1px solid var(--line); padding-top: var(--sp-5);
  display: flex; flex-direction: column; gap: var(--sp-2);
  font-size: .88rem; color: var(--fg-muted); max-width: var(--measure);
}
.afiliados strong { color: var(--fg); }
.afiliados__nota { color: var(--fg-faint); font-size: .84rem; }

/* ============================================================
   BANDA DE MOCKUP — se quita al pasar a producción

   Los colores de abajo son literales A PROPÓSITO y NO deben migrar a
   tokens: esta banda es chrome de la maqueta, no parte del producto.
   Tiene que verse ajena al diseño para que nadie confunda una maqueta
   con la app real. Es la única sección de este archivo exenta de la
   regla "todo pasa por var(--…)".
   ============================================================ */
.mockbar {
  position: sticky; top: 0; z-index: 100;
  background: #12141C; color: #F6F3EC;
  padding: var(--sp-3) var(--sp-5); font-size: .82rem;
  display: flex; gap: var(--sp-4); align-items: center; flex-wrap: wrap; justify-content: center;
}
.mockbar strong { color: #E8A33D; letter-spacing: .08em; text-transform: uppercase; font-size: .72rem; }
.mockbar a { color: #7FC4F5; font-weight: 700; }
/* ============================================================
   Rediseño de hero — inspirado en una referencia visual (Cotelo).
   Reglas de componente adoptadas del experimento original; los
   tokens de color que traia ese experimento (bloque :root aparte
   que pisaba tokens.css sin pasar por su verificacion de contraste)
   se quitaron 2026-08-19 -- tokens.css es la unica fuente de verdad
   de color, como dice CLAUDE.md.
   ============================================================ */

/* Boton primario: naranja oscuro (accent-solid), hover mas oscuro. */
.btn--primary {
  background: #B85609;
  background-image: none;
  box-shadow: 0 4px 14px rgba(184, 86, 9, .34);
  color: #FFFFFF;
}
.btn--primary:hover {
  background: #A84E08;
  box-shadow: 0 8px 22px rgba(168, 78, 8, .38);
}

/* Kicker de texto sobre el H1 — palabra dinámica en color accent */
.hero__kicker {
  display: inline-flex;
  align-items: center; gap: var(--sp-3);
  font-family: var(--ff-display); font-size: 0.85rem; font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase; color: var(--fg-muted);
  margin: 0 0 var(--sp-4);
}
.hero__kicker-icon {
  width: 18px; height: 18px; flex-shrink: 0; color: var(--accent-solid);
}
.hero__kicker-word {
  color: var(--accent-solid); font-weight: 700;
  transition: opacity 0.4s ease;
}

/* Fondo del hero + espaciado tipo "hero v2": encajar copy + badges en
   el primer viewport en vez del padding largo por defecto de mockup.css,
   centrado en mobile. Adaptado de hero-v2.css a las clases de esta pagina
   (mockbar + hdr miden ~6.5rem, igual que en ese experimento). */
.hero {
  /* var(--hero-grad), no el gradiente literal que traia esta regla: ese
     hardcode ignoraba el tema por completo y el hero se quedaba con el
     fondo claro fijo incluso en modo oscuro. tokens.css ya trae version
     clara y oscura de --hero-grad, pensadas para verse bien cada una. */
  background: var(--hero-grad);
  border-radius: var(--r-2xl);
  align-items: flex-start;
  padding-block: var(--sp-5) var(--sp-5);
  /* Sin esto, el header fijo (sticky, sin margen propio) queda pegado
     directo a la esquina redondeada del hero -- se veian "chocar". */
  margin-top: var(--sp-4);
}
/* display:flex vivia arriba sin condicion -- misma especificidad que la
   regla por defecto del navegador para [hidden] (ambas 0,1,0), y como es
   CSS de autor le ganaba: showView() ponia hidden=true en cada busqueda
   pero el hero se seguia viendo igual, con flex, ocupando su alto normal.
   Bug real, reportado por el usuario 2026-08-21 -- la primera revision de
   este mismo punto del plan (misma sesion, mas temprano) solo habia
   revisado la propiedad hidden en JS, nunca el display calculado. */
.hero:not([hidden]) { display: flex; }
.hero > .wrap { width: 100%; }
/* align-items:center, no start: los chips de tendencias son dinamicos
   (texto real del backend, no las 6 frases fijas del mockup) y la
   columna de texto puede terminar bastante mas alta que la imagen.
   Con "start" toda esa diferencia quedaba como hueco vacio debajo de
   la imagen (326px de sobra medido con Playwright); centrando, el
   espacio de sobra se reparte arriba y abajo en vez de amontonarse. */
@media (min-width: 1024px) { .hero__grid { align-items: center; } }

/* El h1 original (clamp hasta 3.9rem, con la 2a frase en su propio
   bloque) mide 6 lineas visuales y por si solo empuja los badges de
   confianza fuera del primer viewport. Se achica aqui -- no en
   tokens.css -- para que "hasta los badges" quepa sin scroll en un
   laptop tipico, sin tocar el tamano del resto del sitio. */
.hero h1 { font-size: clamp(2rem, 3.6vw, 3.1rem); margin-block: var(--sp-3) var(--sp-3); }
.hero__lead { font-size: 1.02rem; }
.hero .search { margin-top: var(--sp-4); }
/* Etiqueta arriba, chips abajo (columna, no fila): con label+chips en
   fila, el grid de 3 columnas parejas repartia el ancho ya reducido del
   buscador entre 3, y las queries reales del backend (bastante mas
   largas que las 6 frases cortas de ejemplo del mockup original)
   quedaban truncadas incluso en desktop ancho. */
.hero-v2__try { display: flex; flex-direction: column; gap: var(--sp-2); margin-top: var(--sp-3); }
.hero-v2__try-label { font-size: .7rem; font-weight: 600; color: var(--fg-faint); }
/* flex-wrap, no grid de columnas parejas: cada chip mide lo que su
   propio texto necesita (sin elipsis) y los que no caben pasan a la
   siguiente fila — con 6 chips normalmente da 3 y 3, pero se ajusta
   solo si algun texto es mas largo. */
.hero-v2__try .chips { margin-top: 0; display: flex; flex-wrap: wrap; gap: var(--sp-2); list-style: none; padding: 0; }
.hero-v2__try .chips > li { min-width: 0; flex: 0 1 auto; }
/* min-width:0 en el <li> (el item real del grid): sin esto, el texto
   nowrap del boton de adentro (queries largas como "cafetera espresso
   con al menos 15 bares de presion") empuja el min-content del item
   por encima del ancho de su columna 1fr, y el elipsis nunca llega a
   activarse porque el grid ya crecio para darle espacio de mas.
   Confirmado con Playwright: boton a 393px de ancho, desbordando. */
.hero-v2__try .chips > li { min-width: 0; }
/* width:100% + min-width:0 siguen siendo necesarios para que el <li>
   flex no crezca con el texto nowrap del boton (ver comentario de arriba).
   Cambio 2026-09: el texto ya no se recorta con elipsis a 1 linea
   (escondia queries reales del backend) — ahora envuelve hasta 2 lineas
   con -webkit-line-clamp y solo pasada la 2a linea recorta. El title=
   (lo pone render.js) deja ver la query completa al pasar el mouse. */
.hero-v2__try .chip { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; width: 100%; min-width: 0; min-height: 32px; padding: 6px var(--sp-3); font-size: .75rem; line-height: 1.3; border: 1.5px solid var(--line); color: var(--fg-muted); background: transparent; border-radius: var(--r-md); transition: all .18s var(--ease); white-space: normal; overflow: hidden; text-align: center; }
.hero-v2__try .chip:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-wash); }

/* "Ver todas las categorias" -- solo aparece en movil (ver breakpoint
   abajo), donde .cat-chips se recorta a ~6. En desktop las 18 caben
   comodas en 2-3 filas (chip de ancho automatico, no 100%) y el link
   sobraria. */
.cat-chips__more { display: none; }

/* Animación fade in/out del placeholder */
.search__input-dynamic {
  transition: opacity 0.3s var(--ease);
}
.search__input-dynamic.fade-out {
  opacity: 0;
}

/* ============================================================
   Banner: Dos tiendas con características
   ============================================================ */
.features-badges {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-3);
  margin-top: var(--sp-5);
  /* Es un <ul>: sin esto hereda el padding-left:40px de lista del
     navegador (mockup.css solo resetea margin globalmente, no padding),
     y quedaba desalineado respecto al parrafo de arriba. */
  padding: 0;
  list-style: none;
}

.feature-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  background: rgba(255, 255, 255, 0.12);
  color: var(--band-dark-fg);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-pill);
  font-size: 0.8rem;
  font-weight: 600;
  backdrop-filter: blur(10px);
  min-width: 0;
}

.feature-badge svg {
  width: 14px;
  height: 14px;
  max-width: none;
  color: #5BB98C;
}

/* Arte visual: tiendas con VS */
.stores-visual {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: var(--sp-6);
  height: auto;
  width: 100%;
  max-width: 500px;
}

.store-visual {
  width: 180px;
  height: auto;
  border-radius: var(--r-2xl);
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.25);
  padding: var(--sp-4);
}

.store-card {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  width: 100%;
}

.store-header {
  display: flex;
  justify-content: center;
}

.store-logo {
  width: 56px;
  height: 56px;
  object-fit: contain;
  filter: brightness(1.2) contrast(1.1);
}

.store-visual--amazon .store-logo {
  filter: brightness(1.3) contrast(1.15);
}

.store-feature {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.store-feature h4 {
  font-size: 0.75rem;
  font-weight: 700;
  color: white;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin: 0;
}

.feature-bars {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.feature-bars .bar {
  height: 6px;
  border-radius: 3px;
}

/* MercadoLibre - longitudes */
.store-visual--mercadolibre .store-feature:nth-child(2) .bar:nth-child(1) { width: 100%; }
.store-visual--mercadolibre .store-feature:nth-child(2) .bar:nth-child(2) { width: 85%; }

.store-visual--mercadolibre .store-feature:nth-child(3) .bar:nth-child(1) { width: 95%; }
.store-visual--mercadolibre .store-feature:nth-child(3) .bar:nth-child(2) { width: 75%; }

.store-visual--mercadolibre .store-feature:nth-child(4) .bar:nth-child(1) { width: 90%; }
.store-visual--mercadolibre .store-feature:nth-child(4) .bar:nth-child(2) { width: 70%; }

.store-visual--mercadolibre .store-feature:nth-child(5) .bar:nth-child(1) { width: 100%; }
.store-visual--mercadolibre .store-feature:nth-child(5) .bar:nth-child(2) { width: 80%; }

/* Amazon - longitudes diferentes */
.store-visual--amazon .store-feature:nth-child(2) .bar:nth-child(1) { width: 95%; }
.store-visual--amazon .store-feature:nth-child(2) .bar:nth-child(2) { width: 65%; }

.store-visual--amazon .store-feature:nth-child(3) .bar:nth-child(1) { width: 100%; }
.store-visual--amazon .store-feature:nth-child(3) .bar:nth-child(2) { width: 78%; }

.store-visual--amazon .store-feature:nth-child(4) .bar:nth-child(1) { width: 88%; }
.store-visual--amazon .store-feature:nth-child(4) .bar:nth-child(2) { width: 72%; }

.store-visual--amazon .store-feature:nth-child(5) .bar:nth-child(1) { width: 92%; }
.store-visual--amazon .store-feature:nth-child(5) .bar:nth-child(2) { width: 76%; }

.store-visual--amazon {
  background: #273648;
}

.store-visual--amazon .feature-bars .bar {
  background: #FF9900;
}

.store-visual--mercadolibre {
  background: #FFFFFF;
}

.store-visual--mercadolibre .feature-bars .bar {
  background: #FFD032;
}

.store-visual--mercadolibre .store-feature h4,
.store-visual--mercadolibre .store-icon {
  color: #12313B;
}

.store-badge-large {
  font-size: 3.2rem;
  font-weight: 800;
  color: white;
  letter-spacing: -0.05em;
}

.store-badge-amazon {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 3.6rem;
  font-weight: 900;
  letter-spacing: -0.1em;
  text-transform: lowercase;
}

.store-badge-ml {
  font-family: var(--ff-display);
  color: #FFFFFF;
  font-weight: 800;
}

.store-icon {
  width: 42px;
  height: 42px;
  background: rgba(255, 255, 255, 0.2);
  border-radius: var(--r-lg);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: white;
}

.store-icon svg {
  width: 24px;
  height: 24px;
}

.store-lines {
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex-grow: 1;
}

.store-lines .line {
  height: 6px;
  background: rgba(255, 255, 255, 0.25);
  border-radius: 3px;
}

.store-lines .line:last-child {
  width: 75%;
}

.store-bars {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: auto;
}

.store-bars .bar {
  height: 8px;
  border-radius: 4px;
}

.store-visual--amazon .bar {
  background: rgba(255, 255, 255, 0.3);
}

.store-visual--amazon .bar-1 {
  width: 100%;
}

.store-visual--amazon .bar-2 {
  width: 90%;
}

.store-visual--amazon .bar-3 {
  width: 60%;
}

.store-visual--mercadolibre .bar {
  background: rgba(255, 255, 255, 0.3);
}

.store-visual--mercadolibre .bar-1 {
  width: 100%;
}

.store-visual--mercadolibre .bar-2 {
  width: 85%;
}

.store-visual--mercadolibre .bar-3 {
  width: 55%;
}

.vs-circle {
  position: absolute;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: white;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 1rem;
  color: #12313B;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.3);
  z-index: 10;
}

.hero__trust {
  display: flex; flex-wrap: wrap; gap: var(--sp-3) var(--sp-4);
  margin-top: var(--sp-4); list-style: none; padding: 0;
}
.hero__trust li {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-size: .8rem; font-weight: 600; color: var(--fg-muted); white-space: nowrap;
}
.hero__trust svg { width: 15px; height: 15px; max-width: none; color: var(--verdict-accent); flex-shrink: 0; }
/* En escritorio los 5 items caben en un solo renglón (pedido 2026-09-14):
   más grandes y repartidos hasta el otro extremo de la columna de texto
   del hero, en vez de envueltos en 2-3 líneas apretadas a la izquierda. */
@media (min-width: 1160px) {
  .hero__trust { flex-wrap: nowrap; justify-content: space-between; gap: var(--sp-4); }
  .hero__trust li { font-size: .9rem; }
  .hero__trust svg { width: 17px; height: 17px; }
}

@media (max-width: 1023px) {
  .hero { padding-block: var(--sp-6); }
  .hero__grid > div:first-child {
    text-align: center; display: flex; flex-direction: column; align-items: center;
  }
  .hero h1, .hero__lead { max-width: 28ch; }
  .search { width: 100%; max-width: 36rem; }
  .chips { justify-content: center; }
  .hero__trust, .hero__kicker { justify-content: center; }
  .hero__art { display: none; }
  .hero-v2__try .chips { justify-content: center; }

  /* Categorías en móvil (rehecho 2026-09-14, pedido del usuario): antes
     mostraba hasta 6 chips truncados + el link "ver todas" -- dos cosas
     pareciadas compitiendo por espacio. Ahora solo el link; los 18 chips
     completos siguen ahí para quien entra por escritorio. */
  [data-cat-chips-wrap] .hero-v2__try-label,
  [data-cat-chips-wrap] .cat-chips { display: none; }
  .cat-chips__more {
    display: inline-block; margin-top: var(--sp-2);
    font-family: var(--ff-display); font-size: .78rem; font-weight: 700;
    color: var(--accent-solid); text-decoration: none;
  }
  .cat-chips__more:hover { text-decoration: underline; }

  /* "Prueba Tendencias" a 3 en móvil, para que quepan en un solo renglón
     (pedido 2026-09-14) -- el resto que ya haya traído /trending se
     esconde, no se recorta el fetch ni se pide menos al backend. */
  .hero-v2__try [data-chips] > li:nth-child(n+4) { display: none; }
}
@media (max-width: 1023px) and (min-height: 780px) {
  .hero__art { display: flex; margin-top: var(--sp-5); }
}

/* El boton del buscador dice "Comparar →" normalmente y solo "Ir →" en
   movil (mas espacio para el input). Los dos labels viven en el HTML,
   se alternan por CSS. */
.btn-txt-narrow { display: none; }

/* En pantallas angostas: la lupa decorativa se oculta (el boton ya dice
   que es un buscador), el boton pasa a "Ir →" y se recorta el padding,
   todo para dejarle el maximo ancho posible al input. font-size 1rem
   (=16px) evita el zoom automatico de iOS al enfocar. Una sola fila. */
@media (max-width: 600px) {
  .search__box { padding-left: var(--sp-4); padding-right: 5px; gap: var(--sp-2); }
  .search__box svg { display: none; }
  .search__box input { font-size: 1rem; }
  /* min-width alarga el boton: "Ir ->" solo es tan corto que con el radio
     pill quedaba casi circular y se veia tosco. 4.75rem lo deja como
     capsula (ratio ~1.6) sin comerle mas ancho del necesario al input. */
  .search__box [data-submit] { min-width: 4.75rem; padding-inline: var(--sp-3); }
  .btn-txt-wide { display: none; }
  .btn-txt-narrow { display: inline; }
}
@media (min-width: 1024px) and (max-height: 820px) {
  .hero { padding-block: var(--sp-4); min-height: 0; }
  .hero h1 { font-size: clamp(2rem, 3.6vw, 2.8rem); margin-block: var(--sp-3); }
  .hero__lead { font-size: 1rem; }
  .search { margin-top: var(--sp-4); }
  .hero__trust { margin-top: var(--sp-4); }
}

/* Imagen de resultado con animación float suave */
.hero__art {
  position: relative; display: flex; justify-content: center; align-items: center; padding: var(--sp-5) 0 0;
  min-height: 0;
}
.hero__result-shot {
  width: 100%; height: auto;
  max-height: min(60vh, 580px);
  max-width: 100%;
  object-fit: contain;
  object-position: center;
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-3);
  display: block;
  background: transparent;
  animation: hero-float 5.5s ease-in-out infinite;
}

@keyframes hero-float {
  0%, 100% { transform: translateY(0px); }
  50% { transform: translateY(-12px); }
}

/* ============================================================
   Banner reorganizado: visual + botón en columna a la derecha
   ============================================================ */
.banner {
  display: grid !important;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-7);
  align-items: stretch;
}

.banner > div:first-child {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}

.banner__art {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: center;
  gap: var(--sp-5);
  min-height: auto;
}

.banner__art .stores-visual {
  width: 100%;
  height: auto;
  justify-content: center;
  min-height: 200px;
}

.banner__art .btn {
  width: 100%;
  max-width: 280px;
  justify-content: center;
  margin-top: auto;
  padding: var(--sp-4) var(--sp-5);
}

/* Mobile: banner 1 columna */
@media (max-width: 1023px) {
  .banner {
    grid-template-columns: 1fr !important;
  }

  .banner > div:first-child {
    text-align: center;
    /* Sin esto, el min-content de .features-badges (grid de 3 columnas
       que no se reduce) empuja este item mas alla del ancho real del
       banner — el mismo bug de min-width:auto que .hero__grid, aqui
       anidado un nivel mas adentro. Confirmado con Playwright:
       scrollWidth de este div daba 365px contra 279px del banner. */
    min-width: 0;
  }

  .features-badges {
    grid-template-columns: repeat(2, 1fr);
  }

  .banner .pill {
    display: inline-block;
  }

  .banner h2,
  .banner p {
    margin-left: auto;
    margin-right: auto;
  }

  /* Las tarjetas de tienda (width:180px fijo) mas el gap no caben una
     al lado de la otra en un telefono angosto — el banner tiene
     overflow:hidden, asi que en vez de desbordar se recortaban en
     silencio (sin scroll visible). Se piden mas chicas (no se apilan:
     el mockup las quiere lado a lado siempre, con el VS encimado). */
  .stores-visual {
    gap: var(--sp-3);
  }
  .store-visual {
    width: 42%;
    padding: var(--sp-3);
  }
  .store-feature h4 { font-size: 0.68rem; }
}

/* ============================================================
   Tabla comparativa visual (Opción A)
   Grid: 6 columnas (1 rótulo + 5 productos)
   ============================================================ */

.comparativa-wrapper {
  margin-top: 2rem;
  background: var(--bg-elev);
  border-radius: var(--r-xl);
  border: 1px solid var(--line);
  overflow-x: auto;
}

/* Grid con columnas fijas compartidas por TODAS las celdas — las celdas
   son hijas directas del grid (sin wrapper .comp-row de por medio: un
   wrapper con display:contents rompía el sticky de la primera columna
   en algunos navegadores, haciendo que solo se viera "fija" al llegar
   al final del scroll). grid-auto-flow acomoda 7 celdas por fila solo. */
.comparativa-visual {
  display: grid;
  grid-template-columns: 180px repeat(7, 130px);
  gap: 0;
  padding: 1.5rem;
}

/* Borde inferior por celda */
.comp-product-col,
.comp-header,
.comp-data-cell {
  border-bottom: 1px solid var(--line);
}

/* Fila de headers: .comp-header solo existe ahí, y la celda de producto
   correspondiente lleva su propia clase --header */
.comp-header,
.comp-product-col--header {
  border-bottom: 2px solid var(--line-strong);
  font-weight: 600;
}

/* Columna de productos (fija al hacer scroll horizontal) */
.comp-product-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  text-align: center;
  padding: 1rem;
  border-right: 1px solid var(--line);
  position: sticky;
  left: 0;
  background: var(--bg-elev);
  z-index: 10;
}

.comp-product-col--header {
  font-size: 0.85rem;
  color: var(--fg);
}

.comp-product-col img {
  width: 90px;
  height: 90px;
  background: var(--bg-sunken);
  border-radius: var(--r-lg);
  object-fit: contain;
  padding: 8px;
  flex-shrink: 0;
}

.comp-product__name {
  font-weight: 600;
  font-size: 0.85rem;
  color: var(--fg);
  line-height: 1.3;
  /* El mockup usa nombres cortos ("JBL Grip"); los titulos reales de la
     tienda pueden pasar de 300 caracteres (ver web/assets/js/mock.js) y
     sin limite estiran la fila entera del grid. */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Header de criterios */
.comp-header {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  font-weight: 600;
  font-size: 0.85rem;
  color: var(--fg);
  text-align: center;
}

/* Celda de datos */
/* justify-content: center (2026-08-27, antes flex-end): la fila la marca
   .comp-product-col (imagen de 90px + hasta 3 lineas de titulo,
   justify-content:center) -- con flex-end las celdas de datos quedaban
   pegadas hasta abajo de esa fila alta, con un hueco vacio enorme arriba
   que se veia "muy bajo, no centrado" (reportado por el usuario
   2026-08-27). Para que las barras sigan alineadas entre columnas de la
   misma fila (el problema original del 2026-08-25: la celda de envío
   envuelve a 2 líneas y las demás a 1, así que centrar cada bloque de
   contenido por separado las desalineaba un poco), .comp-cell__value
   ahora reserva altura fija de 2 líneas -- todas las celdas ocupan el
   mismo alto sin importar si el texto es de 1 o 2 líneas, y centrar ese
   bloque fijo dentro de la celda alinea las barras Y centra vertical
   mente en la fila alta, las dos cosas a la vez. */
.comp-data-cell {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  align-items: center;
  justify-content: center;
  padding: 1rem;
}

.comp-cell__value {
  display: flex;
  align-items: center;
  justify-content: center;
  /* rem, no em: envio usa un font-size mas chico (.74rem) para su texto
     mas largo -- en em, el mismo "2 lineas" da una altura en px distinta
     por columna y las barras se desalinean otra vez. rem es fijo sin
     importar el font-size del elemento. */
  min-height: 2rem;
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--fg);
}

/* La celda de envío es la que más texto trae ("Sin envío destacado",
   "Envío gratis y rápido") -- al mismo tamaño que las demás (precio,
   rating) se envolvía a 2 líneas dentro de los 130px de columna, y la
   barra de abajo quedaba más abajo que la de las demás columnas de esa
   misma fila. Reportado por el usuario 2026-08-25. */
.comp-data-cell--envio .comp-cell__value {
  font-size: 0.74rem;
  line-height: 1.2;
}

/* Columnas de specs de la tabla (2026-09, dinámicas -- unión de los pares
   [etiqueta, valor] que Groq generó por producto). Valores mas largos que
   precio/rating ("IP68 (agua y polvo)"), asi que font mas chico y recorte
   a 3 lineas -- el title= (render.js) deja ver el valor completo. */
.comp-data-cell--spec .comp-cell__value {
  font-size: 0.76rem;
  line-height: 1.25;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
}

.comp-cell__score {
  font-weight: 700;
  font-size: 0.9rem;
}


/* Barra de progreso */
.comp-bar {
  width: 100%;
  max-width: 100px;
  height: 8px;
  background: var(--bg-sunken);
  border-radius: 4px;
  overflow: hidden;
}

.comp-bar__fill {
  height: 100%;
  border-radius: 4px;
  transition: width 0.4s ease;
}

/* Color de barras por producto */
.comp-product--1 .comp-bar__fill { background-color: var(--comp-1); }
.comp-product--2 .comp-bar__fill { background-color: var(--comp-2); }
.comp-product--3 .comp-bar__fill { background-color: var(--comp-3); }
.comp-product--4 .comp-bar__fill { background-color: var(--comp-4); }
.comp-product--5 .comp-bar__fill { background-color: var(--comp-5); }

/* Círculo de puntaje */
.comp-score {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
}

.comp-score__circle {
  width: 90px;
  height: 90px;
}

.comp-score__track {
  fill: none;
  stroke: var(--bg-sunken);
  stroke-width: 6;
}

.comp-score__fill {
  fill: none;
  stroke-width: 6;
  stroke-linecap: round;
  transform: rotate(-90deg);
  transform-origin: 50px 50px;
  transition: stroke-dasharray 0.6s ease;
}

.comp-product--1 .comp-score__fill { stroke: var(--comp-1); stroke-dasharray: calc(var(--score, 0) * 2.827) 282.7; }
.comp-product--2 .comp-score__fill { stroke: var(--comp-2); stroke-dasharray: calc(var(--score, 0) * 2.827) 282.7; }
.comp-product--3 .comp-score__fill { stroke: var(--comp-3); stroke-dasharray: calc(var(--score, 0) * 2.827) 282.7; }
.comp-product--4 .comp-score__fill { stroke: var(--comp-4); stroke-dasharray: calc(var(--score, 0) * 2.827) 282.7; }
.comp-product--5 .comp-score__fill { stroke: var(--comp-5); stroke-dasharray: calc(var(--score, 0) * 2.827) 282.7; }

.comp-score__number {
  font-weight: 700;
  font-size: 1.6rem;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  /* --fg a proposito, no var(--comp-N): --comp-2/--comp-4 no pasan AA
     como texto (ver comentario en tokens.css). El color queda solo en
     el aro (trazo, no texto), aqui el numero necesita ser legible. */
  color: var(--fg);
}

/* Nota al pie */
.comp-nota {
  font-size: 0.85rem;
  color: var(--fg-muted);
  margin-top: 1.5rem;
  text-align: center;
}

/* Responsive: mobile — mismas columnas del grid, más angostas */
@media (max-width: 768px) {
  .comparativa-visual {
    grid-template-columns: 130px repeat(7, 100px);
    padding: 1rem;
  }

  .comp-product-col,
  .comp-header,
  .comp-data-cell {
    padding: 0.75rem;
  }

  .comp-product-col img {
    width: 70px;
    height: 70px;
  }

  .comp-product__name {
    font-size: 0.75rem;
  }

  .comp-header {
    font-size: 0.7rem;
  }

  .comp-cell__value {
    font-size: 0.8rem;
  }

  .comp-score__circle {
    width: 65px;
    height: 65px;
  }

  .comp-score__number {
    font-size: 1.15rem;
  }
}

/* ============================================================
   TARJETA DE DESTACADOS (.fcard) — copia renombrada de .pcard de
   mockup.css. NO se reutiliza .pcard tal cual porque esa clase ya
   la usa la pagina de resultados (ganador/alternativas) con otra
   estructura interna en components.css (.pcard .thumb/.title/.meta,
   no BEM), y components.css carga despues de este archivo — dos
   .pcard distintos peleando por la misma clase daban una tarjeta
   hibrida rota (mitad grid con padding del otro componente, mitad
   flex sin el suyo).
   ============================================================ */
/* El grid item real es el <li> (pgrid > li), que si se estira parejo por
   comportamiento default de grid -- pero .fcard adentro es un bloque
   normal, sin altura ligada a la de su <li>, asi que cada tarjeta salia
   del alto de su propio contenido (mas alta si tenia highlight de 2
   lineas, mas baja si no). Bug real reportado por el usuario 2026-08-25:
   "los destacados se ven disparejos". */
.pgrid > li { display: flex; }
.fcard {
  flex: 1;
  position: relative; display: flex; flex-direction: column;
  background: var(--bg-elev); border: 1.5px solid var(--line);
  border-radius: var(--r-xl); overflow: hidden;
  transition: transform .2s var(--ease), box-shadow .2s var(--ease), border-color .2s var(--ease);
}
.fcard:hover { transform: translateY(-4px); box-shadow: var(--shadow-2); border-color: var(--accent); }
.fcard__media { aspect-ratio: 4/3; background: var(--bg); display: grid; place-items: center; padding: var(--sp-4); }
/* Colección sin portada subida -- render.js marca esto para no dejar un
   recuadro 4:3 vacio; la tarjeta queda compacta, solo texto. */
.fcard__media--empty { display: none; }
.fcard__media img { max-height: 100%; width: auto; object-fit: contain; mix-blend-mode: multiply; }
/* Fotos de producto con fondo blanco de la tienda: multiply las integra en
   claro, pero en oscuro las ennegrece -- mismo problema y mismo arreglo que
   .ganador__foto/.tarjeta__foto (ver esa nota mas arriba en este archivo,
   incluye el fix del 2026-08-27 para el modo oscuro sin toggle manual). */
:root[data-theme='dark'] .fcard__media img { mix-blend-mode: normal; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .fcard__media img { mix-blend-mode: normal; }
}
/* Portada de coleccion (colecciones.html): NO es una foto de producto sobre
   fondo blanco -- es una ilustracion a sangre, estilo poster vertical. Se
   trata distinto para que TODAS las tarjetas se vean EXACTAMENTE del mismo
   ancho y alto sin importar la proporcion del archivo que suba el dueno:
   la caja manda (3:4 vertical, calza con el arte tipo poster) y la imagen
   la llena con recorte desde el centro (object-fit: cover), posicionada en
   absoluto para que NO pueda estirar la caja segun su proporcion propia
   (con el display:grid heredado de .fcard__media, la imagen decidia el alto
   y cada tarjeta salia de distinto tamano). Sin padding, sin el multiply
   que teniria las zonas claras del arte. */
.fcard--coleccion .fcard__media {
  aspect-ratio: 3 / 4;
  padding: 0;
  display: block;
  position: relative;
  overflow: hidden;
}
.fcard--coleccion .fcard__media img {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  mix-blend-mode: normal;
}
.fcard__body { padding: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-3); flex: 1; }
.fcard__title {
  font-size: .95rem; font-weight: 700; line-height: 1.35;
  display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
/* Enlace-estirado: el <a> del titulo es el unico foco/enlace real de la
   tarjeta, pero su area clickeable se extiende a toda la tarjeta via este
   pseudo-elemento -- asi cualquier parte es clickeable sin anidar mas
   enlaces (invalido en HTML) ni perder el foco de teclado en un solo lugar. */
.fcard__title a { position: static; }
.fcard__title a::after { content: ""; position: absolute; inset: 0; }
.fcard__title a:hover { text-decoration: underline; text-underline-offset: 3px; }
.fcard__meta { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.fcard__reviews { font-size: .82rem; color: var(--fg-muted); }
.fcard__highlight {
  font-size: .82rem; color: var(--fg-muted);
  display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.fcard__foot { margin-top: auto; display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-3); }
.coleccion__nums:not([hidden]) {
  margin-top: auto;
  padding-top: var(--sp-3);
  display: flex;
  gap: var(--sp-3);
  flex-wrap: wrap;
  font-family: var(--ff-display);
  font-size: .8rem;
  color: var(--fg-faint);
}
.coleccion__nums b { color: var(--fg); }
/* En la tarjeta del indice (.fcard__body es flex-columna) los numeros van
   al fondo con margin-top:auto + un padding-top de separacion. En el
   encabezado del detalle (.acuse) esa misma clase heredaba ese padding y
   se sumaba al gap del flex -> los numeros quedaban ~24px bajo el titulo
   en vez de 12, desalineados con "Curada por...". */
.acuse .coleccion__nums:not([hidden]) { margin-top: 0; padding-top: 0; }

.prio-tag {
  font-family: var(--ff-display); font-weight: 600; font-size: .68rem;
  text-transform: uppercase; letter-spacing: .04em;
  padding: 3px 8px; border-radius: var(--r-sm);
  border: 1px solid var(--line-strong); color: var(--fg-muted);
}
.prio-tag--alta { border-color: var(--accent); color: var(--accent); }
