/* ==========================================================================
   PDP — Página de detalle de producto (rediseño full-bleed, orientado a venta)
   Construido SOLO con tokens de plum.css + aurora-glass.css. Light + dark.
   Todo bajo el scope .pdp. Motion: compositor-only, easing fuerte, <300ms,
   gated por prefers-reduced-motion. (REQ-LAYOUT/STICKY/RESP/A11Y/PRICE/STOCK)
   ========================================================================== */

.pdp {
  /* CTA WhatsApp. Estos tres alias APUNTAN al token de sistema `--pl-wa`
     (aurora-glass.css) en vez de traer su propio verde: hasta hoy la ficha
     llevaba #0a7c33 y la barra de navegación #0F7A42 — dos verdes distintos
     para el mismo canal, cada uno con su propia medición de contraste y
     ninguno enterándose del otro. El de sistema está documentado y medido
     (5.41:1 sobre blanco) y es el que usan la barra y el hero. Los alias se
     quedan para no reescribir los usos de esta hoja. */
  --wa-cta-bg: var(--pl-wa, #0F7A42);
  --wa-cta-bg-hover: var(--pl-wa-hover, #0c6636);
  --wa-cta-ink: #ffffff;
  /* Stock: variantes legibles del verde/ámbar en ambos temas. */
  --pd-ok: color-mix(in srgb, var(--ok) 82%, #000 18%);
  --pd-warn: color-mix(in srgb, var(--warn) 84%, #000 16%);
  --pd-ease: cubic-bezier(0.23, 1, 0.32, 1);
  --pd-measure: var(--content-max, 1280px);
  /* Dorado de rating. Ha bajado DOS veces, y las dos por medición:
       #f5a623  1.86:1 sobre el tintado de reseñas, 2.18:1 sobre blanco
       #a97a0a  3.84:1 sobre blanco, 3.53:1 sobre `--surface-1`
       #8a6200  cierra AA
     El primer arreglo apuntó al 3:1 de WCAG 1.4.11, el umbral de los gráficos
     que hay que distinguir. Pero las estrellas son TEXTO —caracteres ★ dentro
     de un <span>— y a 14px les toca el 4.5:1 de 1.4.3, no el 3:1. Ese es el
     escalón que faltaba. Se corrige EL TOKEN y no cada uso, así que también
     quedan legibles las del bloque de reseñas. */
  --pd-star: #8a6200;
  /* Card + panel de imagen: blanco puro para matchar el fondo de las fotos.
     En dark cae al surface elevado del tema. */
  --pd-card-bg: #fff;
  color: var(--ink);
}
[data-theme="dark"] .pdp {
  --pd-ok: var(--ok);
  --pd-warn: var(--warn);
  --pd-card-bg: var(--surface-0);
  /* El oro oscurecido del tema claro se hunde contra una superficie oscura:
     el problema se invierte, así que el valor también. En oscuro vuelve el oro
     brillante, que ahí es el que contrasta. */
  --pd-star: #f5a623;
}

/* ---- Bandas full-bleed + medida de lectura interna -------------------- */
.pd-band { width: 100%; }

/* El hero, BLANCO PURO (pedido del dueño, 2026-08-18). El resto de la tienda
   va sobre `--surface-0`, que es un blanco tintado de purpura (#fefcff): con la
   caja contenedora retirada, la foto del equipo quedaba sobre ese tinte. El
   recorte sin fondo de los productos se hace sobre BLANCO, asi que este es
   ademas el fondo que la propia foto espera.
   `first-of-type` y no una clase nueva porque el hero es, por construccion, la
   primera banda de la ficha — el orden lo fija `product_detail.html`. */
.pdp > .pd-band:first-of-type { background: #fff; }
/* La galeria y sus controles heredan el mismo blanco: si se quedan en
   `--pd-card-bg` (que en claro ES `--surface-0`) se ve el escalon de tinte
   dentro de una zona que tiene que leerse como una sola superficie. */
.pdp > .pd-band:first-of-type .pd-gallery-main,
.pdp > .pd-band:first-of-type .pd-thumb { background: #fff; }
.pd-band--tint { background: var(--surface-1); }
.pd-band--strip { background: var(--surface-0); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
.pd-band--brandtint {
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--brand) 5%, var(--surface-0)) 0%, var(--surface-0) 100%);
}
.pd-measure {
  max-width: none;
  margin-inline: auto;
  padding-inline: clamp(1rem, 4vw, 3rem);
}
/* Ritmo vertical entre bloques del PDP.
 *
 * MEDIDO contra la comp (`FISM Producto IdeaPad.dc.html`), no razonado: sus
 * bloques de contenido llevan `padding-top: 56px` y `padding-bottom: 0` en
 * escritorio (24/0 en móvil), así que el hueco entre dos bloques es UNA vez el
 * valor. El `padding-block` de antes era SIMÉTRICO y a 1440px valía 72px, o sea
 * 144px de hueco — medido en navegador, y 80px en móvil contra los 24 de la
 * comp. Casi el triple en las dos.
 *
 * Sale asimétrico como en la comp, con dos salvedades que la comp no necesita
 * porque sus bloques van sobre blanco y los nuestros son bandas a sangre:
 *
 *  · una banda CON fondo propio (--tint, --strip, --brandtint) recupera su
 *    cierre, o su último texto queda pegado al borde del color;
 *  · y entonces el bloque siguiente arranca en 0, o esa frontera mide el doble
 *    que las demás. Es la misma regla que ya rige en la home. */
.pd-section-gap { padding-top: 1.5rem; padding-bottom: 0; }
@media (min-width: 768px) { .pd-section-gap { padding-top: 2.5rem; } }
@media (min-width: 1024px) { .pd-section-gap { padding-top: 3.5rem; } }

.pd-band--tint > .pd-section-gap,
.pd-band--strip > .pd-section-gap,
.pd-band--brandtint > .pd-section-gap { padding-bottom: 1.5rem; }
@media (min-width: 768px) {
  .pd-band--tint > .pd-section-gap,
  .pd-band--strip > .pd-section-gap,
  .pd-band--brandtint > .pd-section-gap { padding-bottom: 2.5rem; }
}
@media (min-width: 1024px) {
  .pd-band--tint > .pd-section-gap,
  .pd-band--strip > .pd-section-gap,
  .pd-band--brandtint > .pd-section-gap { padding-bottom: 3.5rem; }
}

.pd-band--tint + .pd-band > .pd-section-gap,
.pd-band--strip + .pd-band > .pd-section-gap,
.pd-band--brandtint + .pd-band > .pd-section-gap { padding-top: 0; }
.pd-band--tint + .pd-band--tint > .pd-section-gap,
.pd-band--strip + .pd-band--tint > .pd-section-gap,
.pd-band--brandtint + .pd-band--tint > .pd-section-gap,
.pd-band--tint + .pd-band--brandtint > .pd-section-gap,
.pd-band--strip + .pd-band--brandtint > .pd-section-gap,
.pd-band--brandtint + .pd-band--brandtint > .pd-section-gap { padding-top: 1.5rem; }
@media (min-width: 1024px) {
  .pd-band--tint + .pd-band--tint > .pd-section-gap,
  .pd-band--strip + .pd-band--tint > .pd-section-gap,
  .pd-band--brandtint + .pd-band--tint > .pd-section-gap,
  .pd-band--tint + .pd-band--brandtint > .pd-section-gap,
  .pd-band--strip + .pd-band--brandtint > .pd-section-gap,
  .pd-band--brandtint + .pd-band--brandtint > .pd-section-gap { padding-top: 1.75rem; }
}

/* La última banda cierra siempre: debajo viene el pie, con su propio fondo. */
main > .pd-band:last-of-type > .pd-section-gap { padding-bottom: 1.5rem; }
@media (min-width: 1024px) { main > .pd-band:last-of-type > .pd-section-gap { padding-bottom: 3.5rem; } }
.pd-prose { max-width: 68ch; }
/* Subtitulo de la ficha consolidada (2026-08-18): «Descripcion»,
   «Especificaciones» y «Notas del equipo» pasaron de ser tres h2 de seccion a
   tres h3 dentro de una. Mas pequeno que .pd-section-title —que sigue siendo el
   escalon de SECCION— para que la jerarquia se vea, no solo se marque. */
.pd-sub-title {
  font-size: clamp(1.05rem, 1.4vw, 1.25rem); font-weight: 700;
  letter-spacing: -.01em; line-height: 1.25; color: var(--ink);
  margin: 1.9rem 0 .7rem;
}
.pd-sub-title:first-of-type { margin-top: 1rem; }
.pd-section-title {
  font-size: clamp(1.5rem, 3vw, 2.25rem); font-weight: 800;
  letter-spacing: -.02em; line-height: 1.1; color: var(--ink); margin: .3rem 0 1.2rem;
}

/* ---- Breadcrumb ------------------------------------------------------- */
.pd-breadcrumb {
  display: flex; flex-wrap: wrap; gap: .35rem; align-items: center;
  font-size: .8125rem; color: var(--ink-soft); padding-block: 1rem;
}
.pd-breadcrumb a { color: var(--ink-soft); text-decoration: none; }
.pd-breadcrumb a:hover { color: var(--brand); }
.pd-breadcrumb .sep { color: var(--ink-faint); }

/* ======================================================================
   HERO — galería + buy box
   ====================================================================== */
/* SIN tarjeta contenedora (pedido del dueño, 2026-08-18). La galería y el buy
   box eran un solo `card` con fondo, borde, sombra y relleno; ahora respiran
   directamente sobre la página. Se conserva la REJILLA —que es lo que coloca
   foto y compra en dos columnas— y se va sólo el envoltorio.
   El `gap` sube un punto porque, sin la caja que las agrupaba, las dos columnas
   necesitan su propio aire para no leerse como un bloque suelto. */
.pd-hero {
  display: grid; grid-template-columns: 1fr; gap: clamp(1.5rem, 4vw, 3rem);
  padding: 0;
}
@media (min-width: 1024px) {
  .pd-hero { grid-template-columns: minmax(0, 1.25fr) minmax(360px, 1fr); align-items: start; }
}

/* Galería */
.pd-gallery { position: relative; }
.pd-gallery-stage {
  position: relative; border-radius: var(--radius-lg); overflow: hidden;
  background: var(--pd-card-bg); border: none;
  aspect-ratio: 4 / 3; display: flex; align-items: center; justify-content: center;
}
.pd-gallery-stage--nobg { background: transparent; border: none; }
/* Halo púrpura desactivado: sobre el card blanco unificado se leía como una
   mancha lila. El stage nobg queda 100% blanco (matchea el fondo de las fotos). */
.pd-gallery-glow { display: none; }
.pd-gallery-img {
  position: relative; z-index: 1;
  width: 100%; height: 100%;
  max-width: 100%; max-height: 100%;
  min-width: 0; min-height: 0; /* deja que el flex item encoja y respete el stage 4/3 */
  object-fit: contain; display: block; cursor: zoom-in;
}
/* El <picture> es el flex item real del stage (no el <img>). Sin esto, la
   imagen local se ve reventada hasta el primer swap de JS (que elimina los
   <source> y fuerza reflow). Debe llenar el stage y poder encoger. */
.pd-gallery-stage picture {
  display: block; width: 100%; height: 100%;
  min-width: 0; min-height: 0;
}
.pd-gallery-badges { position: absolute; top: .8rem; left: .8rem; z-index: 2;
  display: flex; flex-direction: column; gap: .4rem; align-items: flex-start; }
.pd-badge {
  font-size: .7rem; font-weight: 800; letter-spacing: .04em; text-transform: uppercase;
  padding: .3rem .6rem; border-radius: var(--radius-pill); color: #fff;
}
.pd-badge--discount { background: var(--err); }
.pd-badge--cond { background: var(--brand); }
.pd-badge--ext { background: var(--surface-3); color: var(--ink-soft); }
.pd-zoom-btn {
  position: absolute; bottom: .8rem; right: .8rem; z-index: 2;
  width: 44px; height: 44px; border-radius: 50%; border: 1px solid var(--border);
  background: var(--pd-card-bg); color: var(--ink-soft); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: transform 160ms var(--pd-ease), color 160ms var(--pd-ease);
}
.pd-zoom-btn:hover { color: var(--brand); }
.pd-zoom-btn:active { transform: scale(.95); }

/* Flechas prev/next sobre la imagen principal (antes solo existían en el visor). */
.pd-gallery-nav {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 3;
  width: 44px; height: 44px; border-radius: 50%; border: 1px solid var(--border);
  background: var(--pd-card-bg); color: var(--ink-soft); cursor: pointer; opacity: .9;
  display: flex; align-items: center; justify-content: center;
  transition: transform 160ms var(--pd-ease), color 160ms var(--pd-ease), opacity 160ms var(--pd-ease);
}
.pd-gallery-prev { left: .8rem; }
.pd-gallery-next { right: .8rem; }
.pd-gallery-nav:hover { color: var(--brand); opacity: 1; }
.pd-gallery-nav:active { transform: translateY(-50%) scale(.95); }

.pd-thumb-rail { display: flex; gap: .5rem; margin-top: .75rem; flex-wrap: wrap; }
.pd-thumb {
  width: 64px; height: 64px; border-radius: var(--radius-md); overflow: hidden;
  border: 2px solid var(--border); background: var(--surface-1); cursor: pointer; padding: 0;
  display: flex; align-items: center; justify-content: center;
  transition: border-color 160ms var(--pd-ease);
}
.pd-thumb img { width: 100%; height: 100%; object-fit: contain; }
.pd-thumb[aria-current="true"] { border-color: var(--brand); }
.pd-thumb:hover { border-color: var(--brand-vivid); }

/* Buy box */
.pd-buybox { display: flex; flex-direction: column; gap: 1rem; }
@media (min-width: 1024px) and (min-height: 820px) {
  .pd-buybox {
    position: sticky; top: 5.5rem;
    max-height: calc(100dvh - 7rem); overflow: auto;
    padding-right: .25rem;
  }
}
.pd-buybox-card {
  background: transparent; border: none;
  border-radius: 0; padding: 0;
  box-shadow: none; display: flex; flex-direction: column; gap: 1rem;
}
.pd-title { display: flex; flex-wrap: wrap; align-items: baseline; gap: .35rem .5rem; line-height: 1.1; }
.pd-title-brand { font-size: clamp(1.4rem, 3vw, 2rem); font-weight: 800; letter-spacing: -.02em; color: var(--ink); }
.pd-title-model {
  font-size: clamp(1.4rem, 3vw, 2rem); font-weight: 800; letter-spacing: -.02em;
  color: var(--brand); /* color sólido de marca; énfasis por peso/color, sin gradient-text */
}

/* Valoración de la TIENDA junto al nombre (MIGRACIÓN KAN-25). Es un enlace al
   bloque de reseñas de más abajo, no un adorno: el número tiene que llevar a la
   prueba. Se sube contra el título (margin negativo) porque pertenece al mismo
   bloque de identidad, no a la fila de specs. */
.pd-rating {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  margin-top: -.55rem;
  align-self: flex-start;
  font-size: .85rem;
  color: var(--ink-soft);
  text-decoration: none;
  min-height: 32px;
}
.pd-rating strong { color: var(--ink); font-size: .95rem; }
/* El token de rating, no el de aviso: aquí no se advierte de nada. */
.pd-rating__estrellas { color: var(--pd-star); letter-spacing: .05em; font-size: .9rem; }
.pd-rating__n { text-decoration: underline; text-underline-offset: 2px; }
.pd-rating:hover .pd-rating__n { color: var(--brand-hover); }
.pd-rating:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; border-radius: 4px; }

/* `pd-pills` pasó de <div>/<span> a <ul>/<li> el 20-ago-2026: es una lista
   de puntos clave y marcarla como lista la hace legible para lectores de
   pantalla y extractores. `list-style:none` + `margin/padding:0` mantienen
   el aspecto EXACTO que tenía como div. */
.pd-pills { display: flex; flex-wrap: wrap; gap: .4rem;
            list-style: none; margin: 0; padding: 0; }
.pd-pill {
  display: inline-flex; align-items: center; gap: .4rem;
  background: var(--surface-2); border: 1px solid var(--border); color: var(--ink-soft);
  font-size: .8rem; font-weight: 600; padding: .35rem .7rem; border-radius: var(--radius-pill);
}
.pd-pill i { color: var(--brand); }

/* Precio (ancla honesta) */
.pd-price { display: flex; flex-direction: column; gap: .2rem; }
.pd-price-row { display: flex; align-items: baseline; flex-wrap: wrap; gap: .6rem; }
.pd-price-now { font-size: clamp(1.9rem, 4vw, 2.6rem); font-weight: 800; letter-spacing: -.02em; color: var(--ink); }
.pd-price-was { font-size: 1rem; color: var(--ink-soft); text-decoration: line-through; }
.pd-save {
  display: inline-flex; align-items: center; gap: .35rem; align-self: flex-start;
  background: color-mix(in srgb, var(--ok) 14%, transparent); color: var(--pd-ok);
  border: 1px solid color-mix(in srgb, var(--ok) 30%, transparent);
  font-size: .8rem; font-weight: 700; padding: .25rem .6rem; border-radius: var(--radius-pill);
}
/* [E1] "Precio final. ITBIS 18% incluido." Va justo bajo el precio y en tinta
   suave: es una aclaracion que desarma el sobreprecio percibido del 18%, no un
   reclamo publicitario que deba competir con la cifra. */
.pd-itbis { display: block; margin-top: .25rem; font-size: .78rem; color: var(--ink-soft); }
/* Camino real cuando no se puede cobrar en linea. Tinta suave bajo el boton:
   explica, no compite con la accion. */
.pd-sinpago { margin: .6rem 0 0; font-size: .8rem; line-height: 1.55;
              color: var(--ink-soft); text-wrap: pretty; }
.pd-msrp { font-size: .78rem; color: var(--ink-soft); }
.pd-msrp s { color: var(--ink-soft); }

/* Stock (no solo color; con icono + texto SR) */
.pd-stock { display: inline-flex; align-items: center; gap: .5rem; font-size: .9rem; font-weight: 600; }
.pd-stock i { font-size: .9rem; }
.pd-stock--in { color: var(--pd-ok); }
.pd-stock--low { color: var(--pd-warn); }
.pd-stock--out { color: var(--ink-soft); }

/* Stepper */
.pd-stepper { display: flex; align-items: center; gap: .75rem; }
.pd-stepper-label { font-size: .85rem; color: var(--ink-soft); }
.pd-stepper-box { display: inline-flex; align-items: center; border: 1px solid var(--border-strong); border-radius: var(--radius); overflow: hidden; }
.pd-stepper-btn {
  width: 44px; height: 44px; border: none; background: var(--surface-1); color: var(--ink);
  font-size: 1.1rem; cursor: pointer; transition: background 150ms var(--pd-ease);
}
.pd-stepper-btn:hover { background: var(--surface-2); }
.pd-stepper-btn:active { transform: scale(.96); }
.pd-stepper-input {
  width: 52px; height: 44px; text-align: center; border: none; border-inline: 1px solid var(--border);
  background: var(--surface-0); color: var(--ink); font-weight: 700; font-size: 1rem;
  -moz-appearance: textfield;
}
.pd-stepper-input::-webkit-outer-spin-button,
.pd-stepper-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* CTA stack — una acción obvia */
.pd-cta-stack { display: flex; flex-direction: column; gap: .6rem; }
/* El acolchado vertical empujaba al primario a 54px mientras el secundario se
   quedaba en los 52 del min-height: los dos botones de la MISMA fila median
   distinto (medido 2026-08-18). El alto lo fija el token, no el relleno. */
.pd-cta {
  display: inline-flex; align-items: center; justify-content: center; gap: .55rem;
  font-size: 1rem; font-weight: 700; min-height: var(--cta-alto-lg,52px); padding: 0 1.25rem;
  border-radius: var(--cta-radio,10px); text-decoration: none; cursor: pointer; border: 1px solid transparent;
  transition: transform 200ms var(--pd-ease), background 160ms var(--pd-ease),
              box-shadow 200ms var(--pd-ease), border-color 160ms var(--pd-ease), filter 160ms var(--pd-ease);
}
.pd-cta:hover { transform: translateY(-2px); }
.pd-cta:active { transform: translateY(0); }
.pd-cta--wa { background: var(--wa-cta-bg); color: var(--wa-cta-ink); box-shadow: var(--shadow-sm); }
.pd-cta--wa:hover { background: var(--wa-cta-bg-hover); box-shadow: 0 12px 28px rgba(15,122,66,.30); }
.pd-cta--cart { background: var(--surface-0); color: var(--ink); border-color: var(--border-strong); }
.pd-cta--cart:hover { background: var(--surface-1); border-color: var(--brand-soft); box-shadow: 0 8px 20px rgba(var(--shadow-brand-rgb),.14); }
/* Checkout propio: el primario es la marca, no el verde del canal. El verde de
   WhatsApp identifica un canal externo; usarlo para "comprar aquí" promete una
   cosa y hace otra. `--brand-on` y no #fff crudo: en tema oscuro el blanco
   sobre la variante clara del morado no llega a 4.5:1. */
.pd-cta--buy { background: var(--brand); color: var(--brand-on, #fff); box-shadow: 0 10px 24px rgba(var(--shadow-brand-rgb),.28); }
.pd-cta--buy:hover { background: var(--brand-hover, var(--brand)); box-shadow: 0 14px 30px rgba(var(--shadow-brand-rgb),.34); }
/* WhatsApp degradado a secundario: conserva su verde en el icono (sigue siendo
   ese canal) pero pierde el relleno, para que no compita con el primario. */
.pd-cta-form { display: contents; }
.pd-cta--ask { font: inherit; font-size: 1rem; font-weight: 700;
              background: var(--surface-0); color: var(--ink); border-color: var(--border-strong); }
.pd-cta--ask i { color: var(--wa-cta-bg, #25D366); }
.pd-cta--ask:hover { background: var(--surface-1); border-color: var(--brand-soft); }
@media (prefers-reduced-motion: reduce) { .pd-cta:hover, .pd-cta:active { transform: none; } }

/* `.pd-trustmini` se fue con su tira del buy box (2026-08-18): sin marcado que
   las use, eran estilos huerfanos. */

/* Claridad de pago, ultima linea del buy box (metodos + RD$/USD). Es
   informacion secundaria de apoyo a la decision, no un badge: de ahi el tamaño
   y el tono apagados. El separador superior la desligaba de la retIcula de
   trust items; ahora la desliga de los botones, que es el papel que necesita
   —sin el, la frase queda pegada al CTA como si fuera parte del boton. */
.pd-pay { display: flex; align-items: baseline; gap: .5rem; margin: .35rem 0 0;
  padding-top: .6rem; border-top: 1px solid var(--border);
  font-size: .8rem; line-height: 1.45; color: var(--ink-soft); }
.pd-pay i { color: var(--brand); flex-shrink: 0; position: relative; top: 1px; }

/* ======================================================================
   Testimonios (port honesto del home) + cómo comprar
   ====================================================================== */
/* `.pd-trust-grid` / `.pd-trust-item` se fueron con la banda de confianza
   (2026-08-18): sin marcado que las use eran estilos huérfanos. `--strip`
   SIGUE en las reglas de ritmo de más arriba a propósito: son inertes sin
   marcado, y quitarlas obligaría a reconstruir el ritmo si vuelve una banda
   de ese tipo. */

.pd-testi-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.2rem; }
@media (max-width: 820px) {
  .pd-testi-grid {
    grid-auto-flow: column; grid-auto-columns: 86%; grid-template-columns: none;
    overflow-x: auto; scroll-snap-type: x mandatory; padding-bottom: .5rem;
  }
  .pd-testi { scroll-snap-align: start; }
}
.pd-testi {
  background: var(--surface-1); border: 1px solid var(--border); border-radius: 18px;
  padding: 1.5rem; display: flex; flex-direction: column; gap: .9rem;
}
.pd-testi .stars { color: var(--pd-star); font-size: 1rem; letter-spacing: .12em; }
.pd-testi blockquote { margin: 0; font-size: .93rem; color: var(--ink); line-height: 1.6; }
.pd-testi .who { display: flex; align-items: center; gap: .7rem; margin-top: auto; }
.pd-testi .av {
  width: 2.4rem; height: 2.4rem; border-radius: 999px; background: var(--brand); color: #fff;
  display: flex; align-items: center; justify-content: center; font-weight: 800; flex-shrink: 0;
}
/* Avatar = foto real de perfil de Google del autor (recortada a círculo). */
.pd-testi .av--photo { object-fit: cover; display: block; }
.pd-testi .who strong { color: var(--ink); }
.pd-testi .who small { color: var(--ink-soft); font-size: .8rem; }

.pd-howto { display: grid; grid-template-columns: 1fr; gap: 1rem; }
@media (min-width: 768px) { .pd-howto { grid-template-columns: repeat(3, 1fr); } }
.pd-howto-step { display: flex; gap: .8rem; align-items: flex-start; }
.pd-howto-num {
  width: 2rem; height: 2rem; flex-shrink: 0; border-radius: 50%; background: var(--brand-soft);
  color: var(--brand); font-weight: 800; display: flex; align-items: center; justify-content: center;
}
.pd-howto-step h4 { margin: 0 0 .2rem; font-size: .95rem; color: var(--ink); }
.pd-howto-step p { margin: 0; font-size: .85rem; color: var(--ink-soft); line-height: 1.5; }

/* ======================================================================
   UPSELL (comparación) + CROSS-SELL + SIMILAR (cards)
   ====================================================================== */
.pd-card-grid { display: grid; grid-template-columns: 1fr; gap: 1rem; }
@media (min-width: 640px) { .pd-card-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 980px) { .pd-card-grid--3 { grid-template-columns: repeat(3, 1fr); } }

/* Recomendaciones del PDP: UNA sola fila, con las que quepan (2026-08-18).
   El reparto de columnas y el tamaño de tarjeta los pone `.catx-grid`, la
   rejilla de la tienda; esto solo recorta el alto.
   Las sobrantes las marca `hidden` pdp.js, no un `overflow:hidden`: recortar
   por CSS cortaria tambien el `translateY(-4px)` del hover de la tarjeta, que
   se sale de la caja por arriba. Sin JS se ven todas —dos filas, como antes—:
   degrada, no rompe.
   El `!important` NO es pereza: `.catx-card` trae `display:flex` de la hoja de
   autor y gana a `[hidden]`, que solo vale `display:none` del user-agent. Es
   la trampa de cascada de este repo; sin esta linea el `hidden` no oculta. */
.pd-reco-grid > [hidden] { display: none !important; }

.pd-card {
  display: flex; flex-direction: column; background: var(--surface-0);
  border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden;
  text-decoration: none; color: inherit;
  transition: transform 300ms var(--pd-ease), box-shadow 300ms var(--pd-ease), border-color 200ms var(--pd-ease);
}
.pd-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); border-color: var(--brand-soft); }
.pd-card-img { aspect-ratio: 4 / 3; background: var(--surface-1); display: flex; align-items: center; justify-content: center; padding: 1rem; position: relative; }
.pd-card-img img { max-width: 100%; max-height: 100%; object-fit: contain; }
.pd-img-fallback { display: none; font-size: 2rem; color: var(--ink-faint); opacity: .5; }
.pd-card-img--noimg .pd-img-fallback { display: block; }
.pd-card-body { padding: 1rem; display: flex; flex-direction: column; gap: .3rem; flex: 1; }
.pd-card-brand { font-size: .65rem; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--brand); }
.pd-card-model { font-weight: 700; color: var(--ink); letter-spacing: -.01em; }
.pd-card-price { font-weight: 800; color: var(--ink); margin-top: auto; }
.pd-card-was { font-size: .8rem; color: var(--ink-soft); text-decoration: line-through; margin-left: .4rem; }

/* Upsell: badge de delta de precio + spec destacado */
.pd-up-delta {
  display: inline-flex; align-items: center; gap: .35rem; align-self: flex-start;
  background: var(--brand-soft); color: var(--brand); font-weight: 800; font-size: .78rem;
  padding: .25rem .55rem; border-radius: var(--radius-pill); margin-bottom: .2rem;
}
.pd-up-spec { font-size: .8rem; color: var(--ink-soft); }

/* Cross-sell add + combo */
.pd-mini-add {
  display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
  margin-top: .5rem; min-height: 44px; padding: .5rem .8rem; border-radius: var(--radius);
  background: var(--surface-1); border: 1px solid var(--border-strong); color: var(--ink);
  font-size: .85rem; font-weight: 600; cursor: pointer;
  transition: transform 140ms var(--pd-ease), background 150ms var(--pd-ease);
}
.pd-mini-add:hover { background: var(--surface-2); }
.pd-mini-add:active { transform: scale(.97); }
.pd-combo-cta { margin-top: 1.2rem; display: flex; justify-content: center; }

/* Similar rail */
/* `.pd-rail` se retiro (2026-08-18): era el unico carril de la pagina y
   clavaba la tarjeta a 280px, distinta de las de las otras dos vitrinas.
   Ahora las TRES usan `.catx-grid` + `.pd-reco-grid`. */

/* ======================================================================
   SPECS
   ====================================================================== */
.pd-highlights { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: .75rem; margin-bottom: 1.5rem; }
.pd-highlight { display: flex; align-items: center; gap: .6rem; background: var(--surface-1); border: 1px solid var(--border); border-radius: var(--radius-md); padding: .8rem; }
.pd-highlight i { color: var(--brand); font-size: 1.2rem; width: 1.4rem; text-align: center; }
.pd-highlight-txt { font-size: .85rem; color: var(--ink); font-weight: 600; line-height: 1.3; }

/* ── Descripcion: prosa de LECTURA, no texto vertido ──────────────────────
   Medido antes: 14px con 91 caracteres por linea. Las dos cosas mal para leer
   un parrafo —el suelo del proyecto es 16px de cuerpo y 65-75ch de medida— y
   ademas este es el unico texto propio de la ficha, el que rankea y el que una
   IA puede citar. Ahora: 1rem, medida 66ch y ritmo vertical propio. El HTML
   viene del catalogo externo (p/strong/ul/li), asi que se estiliza por
   descendencia: no hay clases que poner en un contenido que no escribimos. */
.pd-desc-prose { max-width: 66ch; font-size: 1rem; line-height: 1.7; color: var(--ink); text-wrap: pretty; }
.pd-desc-prose > * + * { margin-top: .9rem; }
.pd-desc-prose strong, .pd-desc-prose b { font-weight: 650; color: var(--ink); }
.pd-desc-prose ul, .pd-desc-prose ol { padding-left: 1.15rem; display: grid; gap: .35rem; }
.pd-desc-prose ul { list-style: none; }
/* Marcador propio: un punto del acento, del tamano del texto. El disco por
   defecto del navegador es mas grande y mas oscuro que la tipografia de al
   lado, y en una lista de specs pesa mas que el dato. */
.pd-desc-prose ul > li { position: relative; padding-left: .35rem; }
.pd-desc-prose ul > li::before {
  content: ""; position: absolute; left: -.8rem; top: .62em;
  width: 5px; height: 5px; border-radius: 50%; background: var(--brand);
}
.pd-desc-prose ol > li::marker { color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.pd-desc-prose a { color: var(--brand); text-underline-offset: 2px; }

/* ── Ficha tecnica ────────────────────────────────────────────────────────
   Antes: una fila por dato, etiqueta a la izquierda y valor alineado a la
   DERECHA, con la fila midiendo 652px. El ojo tenia que cruzar la fila entera
   para emparejar «Procesador» con su valor, y a mitad de camino no habia nada
   que lo guiara. Ahora el par va apilado —etiqueta encima, valor debajo— asi
   que el emparejamiento es de un vistazo y no depende del ancho.

   Y los iconos pierden la caja: eran ONCE rectangulos de 34px en morado claro,
   uno por fila. `--brand-soft` repetido once veces deja de ser acento y pasa a
   ser fondo; el principio del proyecto es justo el contrario. El glifo se
   queda —ayuda a escanear— en tamano de texto y sin caja. */
.pd-spec-sheet { display: grid; grid-template-columns: 1fr; gap: 0; }
@media (min-width: 560px) { .pd-spec-sheet { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 2.5rem; } }
@media (min-width: 1100px) { .pd-spec-sheet { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.pd-spec-row {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  column-gap: .6rem; row-gap: .1rem; align-items: baseline;
  padding: .8rem 0; border-bottom: 1px solid var(--border);
}
.pd-spec-ico {
  grid-row: 1 / 3; align-self: center;
  display: flex; align-items: center; justify-content: center;
  width: 1.1rem; color: var(--brand); font-size: .82rem;
}
.pd-spec-row dt {
  grid-column: 2; margin: 0;
  font-size: .69rem; font-weight: 600; letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink-soft);
}
.pd-spec-row dd {
  grid-column: 2; margin: 0; text-align: left;
  font-size: .95rem; font-weight: 600; line-height: 1.35; color: var(--ink);
  overflow-wrap: anywhere;
}

/* ── Notas del equipo ─────────────────────────────────────────────────────
   Es la voz del vendedor sobre ESTA unidad —el unico texto de la ficha escrito
   a mano por la tienda— y solo lo tienen 7 de 105 productos. Merece leerse
   como una nota y no como un parrafo mas: superficie hundida, aire propio y el
   glifo que la firma. SIN filete lateral de color: ese patron esta prohibido
   en el sistema de diseno de este proyecto. */
.pd-notas {
  max-width: 66ch; margin-top: .2rem;
  background: var(--surface-1); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: 1.1rem 1.25rem;
  font-size: .95rem; line-height: 1.65; color: var(--ink);
}
.pd-notas__txt { margin: 0; white-space: pre-line; text-wrap: pretty; }
.pd-notas__firma {
  display: flex; align-items: center; gap: .45rem;
  margin: 0 0 .55rem; font-size: .69rem; font-weight: 700;
  letter-spacing: .07em; text-transform: uppercase; color: var(--ink-soft);
}
.pd-notas__firma i { color: var(--brand); font-size: .8rem; }

/* ======================================================================
   CLOSING band
   ====================================================================== */
.pd-closing { text-align: center; display: flex; flex-direction: column; align-items: center; gap: 1rem; }
.pd-closing-price { font-size: clamp(1.6rem, 3.5vw, 2.2rem); font-weight: 800; color: var(--ink); }
/* La fila de acciones del cierre. Con la tarjeta apagada son dos botones y
   `.pd-closing` los separaría 1rem, la misma distancia que usa entre bloques
   distintos: quedarían leyéndose como dos secciones en vez de como un par. */
.pd-closing-ctas { display: flex; flex-wrap: wrap; gap: .6rem; justify-content: center; }
.pd-closing-meta { font-size: .9rem; color: var(--ink-soft); display: flex; flex-wrap: wrap; gap: .35rem 1.2rem; justify-content: center; }
.pd-closing-meta i { color: var(--brand); margin-right: .35rem; }

/* ======================================================================
   STICKY MÓVIL / TABLET
   ====================================================================== */
.pd-stickybar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 1100;
  display: flex; align-items: center; gap: .8rem;
  padding: .7rem clamp(1rem, 4vw, 1.5rem);
  padding-bottom: calc(.7rem + env(safe-area-inset-bottom));
  background: var(--surface-0); border-top: 1px solid var(--border);
  box-shadow: 0 -4px 20px rgba(0,0,0,.08);
}
.pd-stickybar-info { display: flex; flex-direction: column; line-height: 1.2; }
.pd-stickybar-label { font-size: .7rem; color: var(--ink-soft); }
.pd-stickybar-price { font-size: 1.1rem; font-weight: 800; color: var(--ink); }
.pd-stickybar .pd-cta { flex: 1; min-height: var(--cta-alto-lg,52px); }
@media (min-width: 1024px) { .pd-stickybar { display: none; } }
/* En la PDP el FAB global de WhatsApp sobra: el buy box ya tiene su CTA
   "Comprar por WhatsApp" (y en móvil está el sticky bar). Lo ocultamos en
   TODO ancho para no mostrar dos botones de WhatsApp. (pdp.css solo carga
   en la PDP, así que el FAB sigue en el resto del sitio.) */
.pl-whatsapp-fab { display: none !important; }
body.pdp-has-stickybar { padding-bottom: 84px; scroll-padding-bottom: 84px; }
@media (min-width: 1024px) { body.pdp-has-stickybar { padding-bottom: 0; } }

/* ======================================================================
   LIGHTBOX
   ====================================================================== */
.pd-lightbox {
  position: fixed; inset: 0; z-index: 1200; display: none;
  align-items: center; justify-content: center; padding: 0;
  background: rgba(0,0,0,.95); backdrop-filter: blur(4px);
}
.pd-lightbox.open { display: flex; }
/* El visor ocupa toda la pantalla: la imagen llena el viewport (contain
   preserva el aspecto). 100dvh evita que el chrome del navegador móvil corte. */
.pd-lightbox img { max-width: 100vw; max-height: 100vh; max-height: 100dvh; object-fit: contain; border-radius: 0; }
.pd-lightbox-close { position: absolute; top: 1.2rem; right: 1.2rem; width: 48px; height: 48px; border-radius: 50%; border: none; background: rgba(255,255,255,.15); color: #fff; font-size: 1.3rem; cursor: pointer; z-index: 2; }
.pd-lightbox-nav { position: absolute; top: 50%; transform: translateY(-50%); width: 52px; height: 52px; border-radius: 50%; border: none; background: rgba(255,255,255,.15); color: #fff; font-size: 1.4rem; line-height: 1; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: background .2s; z-index: 2; }
.pd-lightbox-nav:hover { background: rgba(255,255,255,.3); }
.pd-lightbox-prev { left: 1.2rem; }
.pd-lightbox-next { right: 1.2rem; }
.pd-lightbox-counter { position: absolute; bottom: 1.4rem; left: 50%; transform: translateX(-50%); color: #fff; font-size: .9rem; font-weight: 600; background: rgba(0,0,0,.45); padding: .3rem .85rem; border-radius: 999px; }
@media (max-width: 600px) { .pd-lightbox-nav { width: 44px; height: 44px; font-size: 1.2rem; } .pd-lightbox-prev { left: .4rem; } .pd-lightbox-next { right: .4rem; } }

/* ======================================================================
   A11Y + MOTION
   ====================================================================== */
.pdp a:focus-visible, .pdp button:focus-visible, .pdp [tabindex]:focus-visible {
  outline: 3px solid var(--ring); outline-offset: 2px; border-radius: var(--radius-sm);
}
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}
@media (hover: none) {
  .pd-card:hover { transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .pdp *, .pdp *::before, .pdp *::after {
    transition-duration: .01ms !important; animation-duration: .01ms !important;
  }
}

/* ── Enlace interno contextual: chips hacia landings de categoría/marca
   activas (SEO: link equity con ancla-keyword desde la PDP hacia las
   landings transaccionales). Markup: pdp/_pd_landings.html ── */
/* Entra en el ritmo del PDP en vez de tener el suyo (2026-08-18). Con
   `padding: clamp(...) 0` simetrico se salia del sistema por los dos lados:
   la frontera de entrada media 48px contra los 56 de las demas, y la de
   salida 104 —sus 48 de cierre MAS los 56 de apertura de la banda teñida
   siguiente—, casi el doble del ritmo. Medido en navegador. Ahora abre con el
   valor del sistema y cierra en 0, como cualquier bloque sin fondo propio. */
.pd-landings { padding-top: 1.5rem; padding-bottom: 0; padding-inline: 0; }
@media (min-width: 768px) { .pd-landings { padding-top: 2.5rem; } }
@media (min-width: 1024px) { .pd-landings { padding-top: 3.5rem; } }
/* NO se le anade `+pd-band > .pd-section-gap{padding-top:0}`: eso es para las
   bandas CON fondo, que cierran con su propio valor. `.pd-landings` no tiene
   fondo y cierra en 0, asi que la siguiente TIENE que abrir con el ritmo o la
   frontera se va a 0 (medido: eso es justo lo que paso al intentarlo). */
.pd-landings__wrap {
  max-width: var(--pd-max, 1200px); margin: 0 auto;
  padding: 0 clamp(1rem, .5rem + 2vw, 2rem);
}
.pd-landings__title {
  font-size: .78rem; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--ink-soft, #6b7280); margin: 0 0 .9rem;
}
.pd-landings__chips { display: flex; flex-wrap: wrap; gap: .6rem; }
.pd-landings__chip {
  display: inline-flex; align-items: center; padding: 0 1.05rem;
  min-height: var(--cta-alto-sm,36px);
  border: 1px solid var(--border, #e5e7eb); border-radius: var(--cta-radio,10px);
  font-size: .9rem; font-weight: 600; color: var(--ink, #111);
  background: var(--surface-1, #fff); text-decoration: none;
  transition: border-color var(--pd-ease, .18s ease),
              color var(--pd-ease, .18s ease), transform var(--pd-ease, .18s ease);
}
.pd-landings__chip:hover {
  border-color: var(--brand, #2563eb); color: var(--brand, #2563eb);
  transform: translateY(-1px);
}
.pd-landings__chip:focus-visible { outline: 2px solid var(--brand, #2563eb); outline-offset: 2px; }

/* Los estilos del configurador (.pd-mejoras*) NO viven aqui: se movieron a
   `plum.css` porque el CHECKOUT tambien los usa y esa pagina no carga
   `pdp.css` — comprobado en el HTML servido: alli el bloque salia como HTML
   crudo, con el surco por defecto del <fieldset> y las casillas sin marca. */
