/* Secciones below-the-fold de la home (cat-head, tumbe/ofertas, catx-tabs).
   Extraído del <style> inline de home.html (plan CWV A.4): el HTML no se
   cachea; este estático sí. El hero (above-the-fold) se mantiene inline.

   ── ESCALA TIPOGRÁFICA: por qué estos valores y no otros ──────────────────
   Medido sobre la página renderizada: había 28 tamaños de fuente distintos, y
   este fichero aportaba 27 de los valores declarados. Once de ellos vivían
   entre .78rem y 1rem — 3,2px de rango para once pasos, con cada par
   consecutivo separado por menos de medio píxel (.78/.8/.8125/.82/.84/.85/
   .88/.9/.92/.93/.95/.98). Eso no es una escala, es sedimento: nadie eligió
   .93rem, salió de ir empujando un valor vecino.

   El colapso se hizo con UNA regla dura, en dos pasadas: ningún texto se mueve
   más de medio píxel. Los destinos no se eligieron por gusto sino por
   cercanía, así que esto es verificable y no un rediseño encubierto.

   La segunda pasada aterriza en la escala que `plum.css` YA usaba —
   .75 / .8125 / .875 / .9375 / 1.125rem, o sea 12/13/14/15/18px— en vez de
   inventar una nueva. Ese es el hallazgo de fondo: la escala de la casa
   existía y el home había ido creando una paralela al lado, valor a valor.

     .6/.62/.625      -> .625rem     .78/.8/.82/.8125 -> .8125rem
     .7/.72           -> .7rem       .84/.85/.88/.9   -> .875rem
     .74/.76          -> .75rem      .92/.93/.95/.98  -> .9375rem
                                     1.1/1.15         -> 1.125rem

   `.tumbe-chip` pasó de .85 a .875rem con el resto. Su comentario justificaba
   .85 con una medición vieja (a .9rem los seis chips sumaban 1241px y
   desbordaban los 1184 disponibles a 1366px). Esa restricción YA NO APLICA:
   el cintillo es un marquee infinito con `width:max-content`, desbordar es su
   funcionamiento normal, y el JS deriva el recorrido midiendo un grupo real.
   Verificado tras el cambio en 8 anchos de 320 a 1920px.

   AL AÑADIR UN TAMAÑO NUEVO: usa uno de los que ya existen — y mira primero
   si plum.css tiene el paso que buscas. Si de verdad hace falta uno nuevo, que
   se separe del vecino más de 1px: por debajo de eso el ojo no lo distingue y
   sólo estás añadiendo una variante más que mantener. */

    .cat-head{display:flex;justify-content:space-between;align-items:flex-end;gap:1rem;flex-wrap:wrap;margin-bottom:1.6rem}
    .cat-eyebrow{display:inline-flex;align-items:center;gap:.5rem;font-size:.8125rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--acc,var(--pl-brand))}
    .cat-title{font-size:clamp(1.55rem, 1rem + 2vw, 2.15rem);font-weight:800;letter-spacing:-.02em;line-height:1.04;margin-top:.4rem;color:var(--pl-ink)}
    .pimg-ph{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.3rem;color:var(--pl-ink-faint);font-size:.7rem;font-weight:600}
    .pimg-ph i{font-size:1.8rem;opacity:.5}
    .cat-all{display:inline-flex;align-items:center;gap:.45rem;border:1px solid var(--pl-border);border-radius:999px;padding:.55rem 1rem;font-size:.8125rem;font-weight:700;text-decoration:none;color:var(--pl-ink);white-space:nowrap;transition:transform .18s cubic-bezier(.23,1,.32,1),background-color .2s ease,border-color .2s ease,color .2s ease,box-shadow .2s ease}
    .cat-all:hover{border-color:var(--acc,var(--pl-brand));color:var(--acc,var(--pl-brand))}
    .cat-spec{display:inline-flex;align-items:center;gap:.45rem;color:var(--pl-ink-soft)}
    .cat-spec i{color:var(--acc,var(--pl-brand-vivid));width:1rem;text-align:center}
    .cat-cta{display:inline-flex;align-items:center;gap:.6rem;background:var(--pl-ink);color:#fff;border-radius:999px;padding:.55rem .55rem .55rem 1.05rem;font-size:.8125rem;font-weight:700;text-decoration:none;transition:transform .18s cubic-bezier(.23,1,.32,1),background-color .2s ease,border-color .2s ease,color .2s ease,box-shadow .2s ease}
    .cat-cta .ic{width:1.55rem;height:1.55rem;border-radius:999px;background:rgba(255,255,255,.16);display:flex;align-items:center;justify-content:center;transition:transform .18s cubic-bezier(.23,1,.32,1),background-color .2s ease,border-color .2s ease,color .2s ease,box-shadow .2s ease}
    .cat-cta:hover{background:var(--pl-brand)}.cat-cta:hover .ic{transform:translate(2px,-2px)}
    .cat-brand{font-size:.625rem;font-weight:800;letter-spacing:.12em;text-transform:uppercase;color:var(--pl-brand)}
    .cat-model{color:var(--pl-ink);font-weight:800;letter-spacing:-.01em}
    .cat-price{color:var(--pl-ink);font-weight:800;letter-spacing:-.02em}
    .cat-badge{position:absolute;top:.6rem;left:.6rem;background:var(--acc-badge,var(--pl-brand));color:#fff;font-size:.625rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase;padding:.25rem .55rem;border-radius:999px;z-index:2}
    /* Comparador: el badge de condición (Nuevo/Usado) aparece en casi todas las
       cards — versión quieta (soft + texto acento) para que informe sin gritar.
       El sólido se mantiene en la sección dark (superficie de marca). */
    .catx-ph .cat-badge{background:var(--acc-soft,var(--pl-brand-soft));color:var(--acc-dark,var(--pl-brand))}

    .cat-full > .pl-landing-container, .pl-landing-container.cat-wide{max-width:none;padding-left:clamp(1.25rem,4vw,4.5rem);padding-right:clamp(1.25rem,4vw,4.5rem)}

    /* ── Ritmo vertical del home ──────────────────────────────────────────
       `.pl-section-spacing` global vale 3.5/7/9rem, pensado para páginas de
       texto largo. Aquí producía 144px arriba MÁS 144px abajo entre secciones:
       medido, ~300px de vacío entre bloques. Con la home reducida a cuatro
       secciones eso no se lee como aire, se lee como islas desconectadas y
       obliga a scrollear entre ellas sin nada que mirar.
       Escala propia: 48 / 64 / 80px, o sea ~160px entre secciones en desktop.

       REVISADO: 44 / 56 / 64px (~128px en desktop). Los 160px se calcularon
       cuando TODAS las secciones eran transparentes y el aire era el único
       límite entre ellas — ahí un espacio corto habría dejado los bloques
       pisándose. Con `.pl-band-brand` la home ya tiene un corte de superficie
       en medio que separa de verdad, así que el aire deja de cargar solo con
       ese trabajo y puede bajar sin volverse ambiguo.

       REVISADO OTRA VEZ, y esta vez MEDIDO CONTRA LA COMP en vez de razonado:
       la comp no usa padding simétrico. Cada sección lleva `padding-top` y
       `padding-bottom: 0`, así que el hueco entre dos bloques es UNA sola vez
       el valor, no dos. Medido en `FISM Home v2 Carrito.dc.html`: **56px en
       escritorio, 26px en móvil**. Nosotros teníamos 128 y 88 — más del doble,
       y de ahí salía buena parte de que nuestra home midiera 5563px contra los
       3189px de la comp.

       El esquema que reproduce ese ritmo, y por qué hacen falta las tres
       reglas y no sólo la primera:

       1. Toda sección: `padding-top: N`, `padding-bottom: 0`. Dos seguidas
          dejan exactamente N de aire.
       2. Una sección que ES una banda (fondo propio) necesita cerrar por
          abajo o su contenido toca el borde del color: recupera
          `padding-bottom: N`.
       3. …y entonces la de después tiene que empezar en 0, o el hueco sería
          2N justo en las fronteras de las bandas. Es la regla que se olvida
          y la que hace que el ritmo se mantenga en TODAS las fronteras y no
          sólo en las fáciles.

       Sólo aplica a `.cat-full`, que es exclusivo de home.html: el resto del
       sitio (garantía, términos, blog) conserva su ritmo. */
    .cat-full.pl-section-spacing{padding-top:1.625rem;padding-bottom:0}
    @media(min-width:768px){.cat-full.pl-section-spacing{padding-top:2.5rem}}
    @media(min-width:1024px){.cat-full.pl-section-spacing{padding-top:3.5rem}}

    /* La última sección antes del pie sí cierra por abajo: debajo no viene
       otra sección que aporte su aire, viene el footer con su propio fondo. */
    .cat-full.pl-section-spacing:last-of-type{padding-bottom:1.625rem}
    @media(min-width:1024px){.cat-full.pl-section-spacing:last-of-type{padding-bottom:3.5rem}}
    .dl-bg{background:#15101e;background-image:radial-gradient(40% 60% at 90% 0%,rgba(124,58,237,.24),transparent 70%),radial-gradient(35% 50% at 0% 100%,rgba(167,139,250,.14),transparent 70%);padding:3rem 0}
    .dl-bg .cat-eyebrow{color:var(--pl-brand-vivid)}.dl-bg .cat-title{color:#fff}
    .dl-grid{display:grid;grid-template-columns:1.5fr 1fr 1fr;gap:.9rem}
    .dl-card{background:rgba(255,255,255,.045);border:1px solid rgba(167,139,250,.22);border-radius:18px;padding:1.05rem;text-decoration:none;display:flex;flex-direction:column;transition:transform .2s cubic-bezier(.16,1,.3,1),border-color .2s ease,box-shadow .2s ease}
    .dl-card:hover{border-color:rgba(167,139,250,.6);background:rgba(124,58,237,.12);transform:translateY(-3px)}
    .dl-big{grid-row:1/3;justify-content:space-between}
    .dl-ph{background:radial-gradient(120% 110% at 50% 20%,rgba(167,139,250,.2),transparent 72%);border-radius:12px;display:flex;align-items:center;justify-content:center;flex:1;min-height:118px;position:relative;overflow:hidden}
    .dl-big .dl-ph{min-height:228px;margin:.7rem 0}
    .dl-card .cat-brand{color:var(--pl-brand-vivid)}.dl-card .cat-model{color:#fff}
    .dl-card .cat-spec{color:#c9bcd9}
    .dl-card .cat-price{color:#fff}
    .dl-cta{background:var(--pl-brand-vivid);color:#15101e}.dl-cta .ic{background:rgba(0,0,0,.18)}
    /* CTA quieto en las cards chicas del bloque dark: toda la card ya es <a>,
       esto hace visible la afordancia (antes solo la card grande tenía CTA). */
    .dl-more{display:inline-flex;align-items:center;gap:.4rem;margin-top:.55rem;font-size:.7rem;font-weight:700;letter-spacing:.02em;color:var(--pl-brand-vivid)}
    .dl-more i{font-size:.625rem;transition:transform .3s cubic-bezier(.16,1,.3,1)}
    .dl-card:hover .dl-more{color:#fff}.dl-card:hover .dl-more i{transform:translateX(2px)}

    .rail{display:flex;gap:1rem;overflow-x:auto;padding:.4rem .2rem 1.1rem;scroll-snap-type:x mandatory;scrollbar-width:thin}
    .rail::-webkit-scrollbar{height:8px}.rail::-webkit-scrollbar-thumb{background:var(--acc,var(--pl-border));border-radius:9px}
    .rail-card{flex:0 0 320px;scroll-snap-align:start;background:var(--pl-surface);border:1px solid var(--pl-border);border-radius:20px;overflow:hidden;display:flex;flex-direction:column;text-decoration:none;transition:transform .2s cubic-bezier(.16,1,.3,1),border-color .2s ease,box-shadow .2s ease}
    .rail-card:hover{border-color:var(--acc,var(--pl-brand-vivid));box-shadow:var(--shadow-lg)}
    .rail-ph{height:198px;background:radial-gradient(120% 120% at 50% 18%,var(--acc-soft,var(--pl-brand-soft)),var(--pl-surface) 82%);display:flex;align-items:center;justify-content:center;position:relative}
    @media(max-width:820px){.dl-grid,.bnt-grid{grid-template-columns:1fr}.dl-big{grid-row:auto}.bnt-star,.bnt-wide,.bnt-sm{grid-column:auto;grid-row:auto;flex-direction:column}}
    /* a11y: foco visible por teclado (con el acento de cada sección) */
    .star-card:focus-visible,.anchor:focus-visible,.catx-card:focus-visible,.val:focus-visible,.conv-wa:focus-visible,.cat-cta:focus-visible,.cat-all:focus-visible{outline:2px solid var(--pl-brand);outline-offset:3px;border-radius:14px}
    /* a11y: respeta movimiento reducido (solo secciones de catálogo, no hero/gaming) */
    @media(prefers-reduced-motion:reduce){.cat-full *{transition-duration:.01ms !important;animation-duration:.01ms !important}.bnt-card:hover,.rail-card:hover{transform:none !important}}
    /* ── Movimiento: stagger de tarjetas al entrar (cascada > todo a la vez) ── */
    html.aurora-ready [data-stagger]{opacity:1 !important;transform:none !important;transition:none !important}
    html.aurora-ready [data-stagger] > *{opacity:0;transform:translateY(18px);transition:opacity .3s cubic-bezier(.23,1,.32,1),transform .3s cubic-bezier(.23,1,.32,1)}
    html.aurora-ready [data-stagger].is-visible > *{opacity:1;transform:none}
    html.aurora-ready [data-stagger] > *:nth-child(1){transition-delay:.04s}
    html.aurora-ready [data-stagger] > *:nth-child(2){transition-delay:.10s}
    html.aurora-ready [data-stagger] > *:nth-child(3){transition-delay:.16s}
    html.aurora-ready [data-stagger] > *:nth-child(4){transition-delay:.22s}
    html.aurora-ready [data-stagger] > *:nth-child(5){transition-delay:.28s}
    html.aurora-ready [data-stagger] > *:nth-child(n+6){transition-delay:.34s}
    /* feedback de presión en CTAs (instant feedback al tocar) */
    .cat-cta,.cat-all{transition:transform .16s cubic-bezier(.23,1,.32,1),background-color .25s ease,border-color .25s ease,color .25s ease}
    .cat-cta:active,.cat-all:active{transform:scale(.97)}
    .catx-tab:active,.catx-sort-btn:active{transform:scale(.96)}
    .anchor:active{transform:scale(.985)}
    @media(prefers-reduced-motion:reduce){html.aurora-ready [data-stagger] > *{opacity:1 !important;transform:none !important;transition:none !important}.cat-cta:active,.cat-all:active,.catx-tab:active,.catx-sort-btn:active,.anchor:active{transform:none}}
    

    /* El aire vertical vive DENTRO de .tumbe-marquee, no en .tumbe: el marquee es
       overflow:hidden y eso recorta pintado Y hit-testing, así que el ::before de
       44px del enlace al mapa quedaba cortado a la altura del chip (22px) y perdía
       el objetivo táctil. Con 12px de padding dentro cabe completo; .tumbe cede
       esos 12px para que la banda mida lo mismo que antes (60px desktop / 54 móvil). */
    /* Sin reglas arriba ni abajo: las dos líneas convertían la banda en una
       barra encajonada. La regla del borde vivía en el CSS crítico inline
       (_critical_css.html), no aquí — quitarla sólo de esta hoja no hacía nada
       porque esta no la reseteaba, la omitía. Se quitó en la fuente.
       El fondo también sale: --pl-surface (#fdf8fc) contra el de la página
       (#fefcff) dejaba una franja tenue pero visible, o sea la misma barra sin
       las líneas. Transparente hereda el fondo y el cintillo desaparece como
       caja: quedan sólo las señales moviéndose. */
    .tumbe{background:transparent;padding:.4rem 0}

    /* La sección que sigue al cintillo NO usa el espaciado de sección completo.
       Medido: 144px de padding superior dejaban 162px entre la última señal y
       el título, y con eso el cintillo queda flotando solo entre el hero y el
       contenido, como si no perteneciera a ninguno de los dos. La tira es una
       transición, no una sección: pertenece visualmente a lo que introduce.
       El selector es por hermano adyacente y no una clase en el marcado, así
       que sigue funcionando si mañana se reordenan las secciones. Se conserva
       el `padding-bottom` de sección: el ritmo hacia abajo no cambia. */
    .tumbe + section.pl-section-spacing,
    .tumbe + section.dl-bg{padding-top:1.75rem}
    @media(min-width:768px){
      .tumbe + section.pl-section-spacing,
      .tumbe + section.dl-bg{padding-top:2.5rem}
    }
    @media(min-width:1024px){
      .tumbe + section.pl-section-spacing,
      .tumbe + section.dl-bg{padding-top:3rem}
    }
    /* Era .85rem, con esta razón: "con .9 las seis señales suman 1241px y
       desbordan los 1184 del contenedor a 1366px, o sea un chip cortado en la
       pantalla más común". Esa medición era CORRECTA cuando el cintillo era
       una tira estática centrada. Dejó de aplicar cuando pasó a marquee: el
       carril es `width:max-content` y desbordar el contenedor es su
       funcionamiento normal, no un fallo — el JS clona grupos y deriva el
       recorrido midiendo un grupo real, así que el ancho total le da igual.
       Por eso .875rem entra en la escala común sin excepción. Verificado en 8
       anchos de 320 a 1920px: el bucle sigue sin costura y sin desborde de
       página. */
    .tumbe-chip{display:inline-flex;align-items:center;gap:.55rem;font-size:.875rem;font-weight:700;color:var(--pl-ink)}
    .tumbe-chip i{color:var(--pl-brand);font-size:1.05rem}
    /* ── Banda de confianza: tira deslizable en TODOS los anchos ──
       Historia, para que nadie la repita: primero fue grid de 2 columnas con 3
       chips y el tercero caía huérfano pegado a la izquierda (medido a 375px).
       Flex con wrap arregló el pegado pero no el reparto —depende de los anchos
       de texto: con 6 chips dio 5+1 a 1366px y 3+2+1 al acotar el ancho—. Grid
       de 3 columnas lo hizo determinista pero costaba 2 filas (99px desktop,
       121px móvil). Una sola tira horizontal cuesta UNA fila en cualquier ancho.

       `max-width:max-content` + `margin-inline:auto` es lo que unifica los dos
       mundos sin duplicar reglas: cuando las seis señales caben, la tira mide lo
       que su contenido y queda centrada, sin scroll ni barra; cuando no caben, el
       ancho se limita al disponible y desliza. Un mecanismo, todos los anchos.

       Sin autoplay a propósito: contenido que se mueve solo, dura más de 5s y
       convive con el resto exige control de pausa (WCAG 2.2.2), y un botón de
       pausa dentro de una tira de ~55px es peor que el problema que resuelve.
       Afordancia según el puntero: con ratón, la barra nativa cuando desborda;
       en táctil se oculta (es overlay) y avisa el desvanecido del borde. */
    /* Cintillo: el carril lleva DOS copias del grupo de chips y se desplaza
       -50%, así el bucle no tiene costura. La segunda copia va aria-hidden y sus
       enlaces con tabindex=-1: es decoración visual, no debe duplicarse para
       lector de pantalla ni añadir tab stops.
       Máscara en los dos bordes: los chips entran y salen suavizados en vez de
       aparecer cortados de golpe.
       Se detiene en cuatro casos: puntero encima, foco dentro, banda fuera del
       viewport (IntersectionObserver en home.html — también evita animar en la
       carga, cuando está bajo el fold, que es lo que inflaría el Speed Index) y
       prefers-reduced-motion, donde queda quieta y deslizable a mano. */
    .tumbe-marquee{
      overflow:hidden;padding-block:12px;
      -webkit-mask-image:linear-gradient(to right,transparent,#000 6%,#000 94%,transparent);
              mask-image:linear-gradient(to right,transparent,#000 6%,#000 94%,transparent)
    }
    /* El recorrido y la duración los calcula el JS midiendo un grupo real
       (--tumbe-shift = ancho de UN grupo, --tumbe-duration = ese ancho / la
       velocidad en px/s). Los fallbacks mantienen el cintillo vivo sin JS.

       Por qué no se anima a -50% fijo: eso asume que el track son exactamente
       dos copias. Si un grupo mide menos que la pantalla —a 1.269px de ancho el
       grupo medía 1.175px— la segunda copia se acaba antes de que la primera
       vuelva a entrar y queda una franja en blanco al final de cada vuelta. El
       JS clona grupos hasta cubrir C + 2G, que es la condición para que SIEMPRE
       haya contenido bajo el viewport.

       translate3d y no translateX: fuerza capa propia en WebKit viejo. Con
       will-change, el recorrido es sólo compositor: cero layout, cero paint. */
    .tumbe-track{
      display:flex;width:max-content;
      animation:tumbe-scroll var(--tumbe-duration,34s) linear infinite;
      will-change:transform;
    }
    .tumbe-track.is-paused,
    .tumbe-marquee:hover .tumbe-track,
    .tumbe-marquee:focus-within .tumbe-track{animation-play-state:paused}
    .tumbe-group{display:flex;flex-wrap:nowrap;align-items:center;gap:1.5rem;padding-inline:.75rem}
    .tumbe-chip{flex:0 0 auto}
    @keyframes tumbe-scroll{
      from{transform:translate3d(0,0,0)}
      to{transform:translate3d(var(--tumbe-shift,-50%),0,0)}
    }
    @media(max-width:768px){
      .tumbe{padding:.25rem 0}
      .tumbe-group{gap:1rem;padding-inline:.5rem}
      .tumbe-chip{font-size:.8125rem}
    }
    @media(prefers-reduced-motion:reduce){
      .tumbe-track{animation:none;width:auto}
      /* Sin movimiento, la copia decorativa no aporta y la banda se lee
         deslizando a mano: así el usuario con reduced-motion llega igual a las
         seis señales. */
      .tumbe-group+.tumbe-group{display:none}
      .tumbe-marquee{overflow-x:auto;overscroll-behavior-x:contain;scroll-behavior:auto}
    }
    /* Único chip accionable: enlace al mapa. El ::before le da 44px de objetivo
       táctil (20px de chip + 12px arriba y abajo) sin engordar la tira, y cabe
       dentro del padding-block:20px que ya absorbe el reveal. */
    .tumbe-chip--link{position:relative;text-decoration:none;transition:color .2s ease}
    .tumbe-chip--link::before{content:"";position:absolute;inset:-12px -8px}
    .tumbe-chip--link:hover,.tumbe-chip--link:focus-visible{color:var(--pl-brand)}
    .tumbe-chip--link:hover .tumbe-txt,
    .tumbe-chip--link:focus-visible .tumbe-txt{text-decoration:underline;text-underline-offset:3px}
    .tumbe-chip--link:focus-visible{outline:2px solid var(--pl-brand);outline-offset:4px;border-radius:6px}
    @media(prefers-reduced-motion:reduce){
      .tumbe-chip--link{transition:none}
    }
    html{scroll-behavior:smooth}
    /* La isla nav fija mide ~84-100px con su offset; 64px dejaba los títulos
       de sección debajo del nav al navegar por anchors (#catalog, #destacado). */
    :target{scroll-margin-top:108px}
    @media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
    .star-wrap{display:grid;grid-template-columns:1.7fr 1fr;gap:1.2rem;align-items:stretch;margin-top:1.6rem}
    /* Trampa min-content de grid/flex (min-width:auto): un nombre de modelo largo
       (p.ej. "TUF Gaming F16 FX607VU-ES51") inflaba el min-content de .star-body
       y la card crecía a ~595px en un viewport de 375px — imagen recortada y
       sección desbordada en móvil. min-width:0 permite encoger a los items y
       overflow-wrap:anywhere deja quebrar el token largo del modelo. */
    .star-wrap>*{min-width:0}
    .star-ph,.star-body{min-width:0}
    .star-body .cat-model{overflow-wrap:anywhere}
    .star-card{position:relative;background:var(--pl-surface);border:1px solid var(--pl-border);border-radius:24px;overflow:hidden;display:grid;grid-template-columns:1.05fr 1fr;text-decoration:none;transition:transform .2s cubic-bezier(.16,1,.3,1),border-color .2s ease,box-shadow .2s ease}
    .star-card:hover{box-shadow:var(--shadow-lg);transform:translateY(-3px)}
    .star-ph{background:var(--pl-surface-2,#f5edf4);display:flex;align-items:center;justify-content:center;position:relative;min-height:310px;padding:1.5rem}
    .star-ph picture,.star-ph img{max-width:90%;max-height:90%;object-fit:contain}
    .star-body{padding:1.8rem 2rem;display:flex;flex-direction:column;justify-content:center;gap:.65rem}
    .star-badge{position:absolute;top:1rem;left:1rem;background:var(--pl-brand);color:#fff;font-size:.7rem;font-weight:800;text-transform:uppercase;letter-spacing:.08em;padding:.42rem .85rem;border-radius:999px;z-index:2;display:inline-flex;align-items:center;gap:.4rem}
    .scarce{display:inline-flex;align-items:center;gap:.4rem;font-size:.8125rem;font-weight:800;padding:.32rem .7rem;border-radius:999px;width:fit-content}
    /* El texto NO usa --pl-err: medido sobre el velo del 14% da 4.44:1, a seis
       centesimas de AA. Este tono lo cierra sin cambiar la lectura del chip. */
    .scarce--1{background:color-mix(in srgb,var(--pl-err,#e24b4a) 14%,transparent);color:#8f2222}
    .scarce--n{background:color-mix(in srgb,var(--pl-warn,#ba7517) 18%,transparent);color:var(--pl-warn,#92520a)}
    /* El pulso era INFINITO (`scarcePulse 2.4s ease-in-out infinite`) sobre el
       icono de escasez. Es el único elemento de la home que se movía todo el
       tiempo, y estaba encima del dato que más interesa leer con calma —
       cuántas unidades quedan. Tras el primer segundo no aporta información
       nueva: sólo compite con el contenido y consume ciclos en cada tarjeta
       visible. Ahora late DOS veces al aparecer y se queda quieto: la llamada
       de atención ocurre, el ruido permanente no. */
    @keyframes scarcePulse{0%,100%{opacity:1}50%{opacity:.5}}
    /* Solo late el ICONO (rayo), no el texto: urgencia legible sin parpadeo.
       El dato es real (quantity<=3) — motion como indicador de estado. */
    .scarce i{animation:scarcePulse 1.6s ease-in-out 2}
    .lossguard{font-size:.8125rem;color:var(--pl-ink-soft);margin-top:.15rem}
    .star-trust{display:flex;flex-wrap:wrap;gap:.4rem 1rem;margin-top:.5rem}
    .star-trust span{display:inline-flex;align-items:center;gap:.4rem;font-size:.75rem;font-weight:600;color:var(--pl-ink-soft)}
    .star-trust i{color:var(--pl-brand);font-size:.8125rem}
    .star-grating{display:inline-flex;align-items:center;gap:.4rem;margin-top:.45rem;font-size:.8125rem;color:var(--pl-ink-soft);text-decoration:none}
    .star-grating .star-grating-stars{color:var(--pl-brand);letter-spacing:.04em}
    .star-grating strong{color:var(--pl-ink)}
    .star-grating:hover{color:var(--pl-brand)}
    .star-grating:focus-visible{outline:2px solid var(--pl-brand);outline-offset:2px;border-radius:6px}
    .anchors{display:flex;flex-direction:column;gap:1.2rem}
    .anchor{flex:1;background:var(--pl-surface);border:1px solid var(--pl-border);border-radius:18px;padding:1rem 1.1rem;display:flex;align-items:center;gap:1rem;text-decoration:none;transition:transform .2s cubic-bezier(.16,1,.3,1),border-color .2s ease,box-shadow .2s ease}
    .anchor:hover{border-color:var(--pl-brand);background:var(--pl-brand-soft)}
    .anchor-ph{width:72px;height:62px;border-radius:12px;background:var(--pl-brand-soft);display:flex;align-items:center;justify-content:center;flex-shrink:0;overflow:hidden}
    .anchor-ph img{max-width:90%;max-height:90%;object-fit:contain}
    .anchor-tag{font-size:.625rem;font-weight:800;text-transform:uppercase;letter-spacing:.1em;color:var(--pl-ink-soft)}
    .val-grid{display:grid;grid-template-columns:1.5fr 1fr;grid-template-rows:auto auto;gap:1rem;margin-top:1.6rem}
    .val-lead{grid-row:1/3;background:linear-gradient(160deg,var(--pl-brand-soft),var(--pl-surface));border:1px solid var(--pl-border);border-radius:22px;padding:2rem;display:flex;flex-direction:column;justify-content:center}
    .val-metric{font-size:2.8rem;font-weight:800;color:var(--pl-brand);letter-spacing:-.03em;line-height:1}
    .val{background:var(--pl-surface);border:1px solid var(--pl-border);border-radius:18px;padding:1.4rem;transition:transform .2s cubic-bezier(.16,1,.3,1),border-color .2s ease,box-shadow .2s ease}
    .val:hover{border-color:var(--pl-brand);transform:translateY(-3px);box-shadow:var(--shadow-md)}
    .val h3{font-size:1rem;font-weight:800;color:var(--pl-ink);margin:.85rem 0 .3rem}
    .val p{font-size:.875rem;color:var(--pl-ink-soft);line-height:1.5;margin:0}
    /* .fab-wa removido — home usa el FAB global .pl-whatsapp-fab (verde) de base_landing. */
    /* Los dos señuelos SOLO van en fila si hay ancho real para los dos. En
       tablet (<=820px) la regla los ponía en fila siempre: a 375px eso daba
       576px de ancho en un contenedor de 303px y la segunda ancla quedaba
       cortada fuera de pantalla. Debajo de 560px se quedan apilados (columna,
       que es el default) y cada uno conserva su foto, su etiqueta y su precio
       legibles. */
    @media(min-width:560px) and (max-width:820px){.anchors{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.7rem}}
    @media(max-width:820px){.star-wrap{grid-template-columns:1fr}.star-card{grid-template-columns:1fr}.val-grid{grid-template-columns:1fr}.val-lead{grid-row:auto}}
    /* Kit de conversión (iconos, CTA WhatsApp, testimonios, FAQ, CTA final) */
    .conv-ic{width:3rem;height:3rem;border-radius:14px;background:var(--pl-brand-soft);color:var(--pl-brand);display:flex;align-items:center;justify-content:center;font-size:1.3rem}
    .conv-wa{display:inline-flex;align-items:center;justify-content:center;gap:.5rem;background:var(--pl-wa);color:#fff;font-weight:700;border-radius:var(--pl-radius);padding:.85rem 1.5rem;text-decoration:none;font-size:.9375rem;box-shadow:0 10px 24px rgba(37,211,102,.28);transition:background .28s cubic-bezier(.2,.8,.2,1),box-shadow .28s,transform .28s,filter .2s}
    .conv-wa:hover{filter:brightness(1.05);transform:translateY(-2px);box-shadow:0 14px 30px rgba(37,211,102,.34)}.conv-wa:active{transform:translateY(0) scale(.97)}
    @media(prefers-reduced-motion:reduce){.conv-wa:hover,.conv-wa:active{transform:none}}
    .card-link{position:absolute;inset:0;z-index:1;border-radius:inherit}
    /* El anillo se pintaba y NO SE VEÍA. Probado por mutación: enfocar el enlace
       cambiaba 0 píxeles de la tarjeta; forzando `overflow:visible` en la
       tarjeta, 3.060. El enlace es `inset:0` —llena la caja— y la tarjeta
       recorta con `overflow:hidden`, así que un contorno a 3px de separación
       cae ENTERO fuera del recorte. Quien navega con teclado no veía dónde
       estaba en la única superficie que abre el producto.
       El aro va en la TARJETA: el contorno de un elemento no lo recorta su
       propio `overflow`, sólo el de un ancestro. Y además es lo correcto de
       leer: el objetivo del foco es la tarjeta entera, no un rectángulo
       invisible encima de ella. */
    .catx-card:has(.card-link:focus-visible),
    .rail-card:has(.card-link:focus-visible),
    .star-card:has(.card-link:focus-visible){outline:2px solid var(--pl-brand);outline-offset:3px}
    /* Respaldo donde `:has()` no exista: contorno HACIA DENTRO, que el recorte
       no se come. Sólo se aplica si el navegador no soporta `:has()`, para no
       pintar dos aros donde sí lo soporta. */
    @supports not selector(:has(*)){
      .card-link:focus-visible{outline:2px solid var(--pl-brand);outline-offset:-3px}
    }
    .has-stretch{position:relative}
    .has-stretch .conv-wa{position:relative;z-index:2}
    .testi-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1.2rem;margin-top:1.7rem}
    .testi{background:var(--pl-surface);border:1px solid var(--pl-border);border-radius:18px;padding:1.5rem;display:flex;flex-direction:column;gap:.9rem}
    .stars{color:var(--pl-brand);font-size:1rem;letter-spacing:.12em}
    .testi blockquote{margin:0;font-size:.9375rem;color:var(--pl-ink-body);line-height:1.6}
    .testi .who{display:flex;align-items:center;gap:.7rem;margin-top:auto}
    .testi .av{width:2.4rem;height:2.4rem;border-radius:999px;background:var(--pl-brand);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:.9375rem;flex-shrink:0}
    .testi .av--photo{object-fit:cover;display:block}
    .testi-verify{display:flex;align-items:center;gap:.5rem;font-size:.875rem;color:var(--pl-ink-soft);margin-top:1.3rem}.testi-verify i{color:var(--pl-brand)}
    .testi-verify a{color:var(--pl-brand);font-weight:700;text-decoration:none}.testi-verify a:hover{text-decoration:underline}
    .g-rating{display:inline-flex;align-items:center;gap:.55rem;background:var(--pl-surface);border:1px solid var(--pl-border);border-radius:999px;padding:.5rem .9rem;min-height:24px;text-decoration:none;margin-top:1rem;transition:border-color .2s,transform .16s}
    .g-rating:hover{border-color:var(--pl-brand);transform:translateY(-1px)}
    .g-rating:focus-visible{outline:2px solid var(--pl-brand);outline-offset:2px}
    .g-rating-num{font-weight:800;font-size:1.125rem;color:var(--pl-ink)}
    .g-rating-stars{color:var(--pl-brand);letter-spacing:.06em}
    .g-rating-txt{font-size:.875rem;color:var(--pl-ink-soft);font-weight:600}
    .faq{max-width:780px;margin:1.7rem auto 0}
    .faq details{border:1px solid var(--pl-border);border-radius:14px;background:var(--pl-surface);margin-bottom:.7rem;overflow:hidden;transition:border-color .25s}
    .faq details[open]{border-color:#cbb6f5}
    .faq summary{list-style:none;cursor:pointer;padding:1.1rem 1.3rem;font-weight:700;color:var(--pl-ink);display:flex;align-items:center;justify-content:space-between;gap:1rem;font-size:.9375rem}
    .faq summary::-webkit-details-marker{display:none}
    .faq summary i{color:var(--pl-brand);transition:transform .25s;flex-shrink:0}
    .faq details[open] summary i{transform:rotate(180deg)}
    .faq .ans{padding:0 1.3rem 1.2rem;color:var(--pl-ink-soft);line-height:1.65;font-size:.9375rem}
    .conv-wa-lg{font-size:1.125rem;padding:1.1rem 2.2rem;margin-top:1.9rem}
    @media(max-width:820px){.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}.testi{scroll-snap-align:start}}
    /* A — Saltar al contenido */
    .skip-link{position:absolute;left:.5rem;top:0;transform:translateY(-3rem);z-index:80;background:var(--pl-brand);color:#fff;padding:.6rem 1rem;border-radius:0 0 10px 10px;font-weight:700;text-decoration:none;transition:transform .2s cubic-bezier(.23,1,.32,1)}
    .skip-link:focus{transform:none;outline:2px solid #fff;outline-offset:-4px}
    /* B — Volver arriba. Apilado SOBRE el FAB de WhatsApp (bottom-right):
       en la esquina izquierda tapaba el copyright/enlaces legales del footer. */
    .to-top{position:fixed;right:1.5rem;bottom:calc(1.5rem + 56px + 12px);width:44px;height:44px;border-radius:999px;border:1px solid var(--pl-border);background:var(--pl-surface);color:var(--pl-ink);display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:var(--pl-shadow-md);z-index:55;opacity:0;transform:translateY(8px);transition:opacity .25s,transform .25s}
    .to-top.show{opacity:1;transform:none}
    .to-top:hover{border-color:var(--pl-brand);color:var(--pl-brand)}
    .to-top:focus-visible{outline:2px solid var(--pl-brand);outline-offset:2px}
    @media(prefers-reduced-motion:reduce){.to-top{transition:none}}
    /* C — Toast de WhatsApp */
    .wa-toast{position:fixed;left:50%;bottom:5rem;transform:translateX(-50%) translateY(10px);background:var(--pl-ink);color:#fff;padding:.65rem 1.1rem;border-radius:999px;font-size:.875rem;font-weight:600;z-index:70;opacity:0;transition:opacity .2s,transform .2s;pointer-events:none}
    .wa-toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
    @media(prefers-reduced-motion:reduce){.wa-toast{transition:opacity .2s}}
    

    .catx-tabs{display:flex;gap:.6rem;overflow-x:auto;padding:.2rem 0 1.3rem;scrollbar-width:none;-webkit-mask-image:linear-gradient(90deg,#000 calc(100% - 32px),transparent);mask-image:linear-gradient(90deg,#000 calc(100% - 32px),transparent)}
    .catx-tabs::-webkit-scrollbar{display:none}
    .catx-tab{display:inline-flex;align-items:center;gap:.5rem;white-space:nowrap;border:1px solid var(--pl-border);background:var(--pl-surface);color:var(--pl-ink);font-weight:700;font-size:.875rem;border-radius:999px;padding:.6rem 1.1rem;min-height:44px;box-sizing:border-box;cursor:pointer;transition:transform .18s cubic-bezier(.23,1,.32,1),background-color .2s ease,border-color .2s ease,color .2s ease,box-shadow .2s ease}
    .catx-tab:hover{border-color:var(--pl-brand);color:var(--pl-brand)}
    .catx-tab.on{background:var(--pl-brand);color:#fff;border-color:var(--pl-brand)}
    .catx-tab.on:hover{color:#fff}
    .catx-tab i{font-size:.9375rem}
    .catx-count{font-size:.7rem;font-weight:800;background:var(--pl-brand-soft);color:var(--pl-brand);border-radius:999px;padding:.08rem .5rem}
    .catx-tab.on .catx-count{background:rgba(255,255,255,.22);color:#fff}
    .catx-tab:focus-visible{outline:2px solid var(--pl-brand);outline-offset:2px}
    /* NO se convierte a transición aunque los keyframes reinicien desde cero al
       alternar pestañas rápido. `.catx-panel` sólo existe en `templates/landing/demo/`,
       no en la home viva: el cambio no tendría superficie donde comprobarse, y
       un intento previo con `left:-9999px` habría dejado los paneles ocultos
       ENFOCABLES. Cambiar código que no se puede probar es riesgo sin ganancia. */
    .catx-panel{display:none}.catx-panel.on{display:block;animation:catxPanelIn .35s cubic-bezier(.22,1,.36,1)}
    /* Cambio de pestaña: el panel entrante asienta con fade+rise corto en
       cada activación (antes el swap display:none→block era un corte seco). */
    @keyframes catxPanelIn{from{opacity:0;transform:translateY(10px)}}
    /* ── Cuántas tarjetas caben, lo decide el ancho ───────────────────────
       Antes eran tres saltos tecleados (4 → 3 → 2 columnas). Ahora la rejilla
       se llena sola: cada tarjeta no baja de `--catx-min` y el `max()` de
       dentro impide pasar de `--catx-cols` aunque sobre sitio — que es lo que
       le falta a un `auto-fill` a secas, donde una pantalla de 2560px pinta
       ocho tarjetas diminutas.
       El mínimo de 276px NO es estético: la tarjeta necesita 244px libres para
       que «Comprar ahora» y «Agregar» quepan uno al lado del otro, y el cuerpo
       gasta 2×14 de padding. Por debajo de eso los botones se apilan solos —no
       se rompe nada— pero se pierde la fila que el dueño pidió igual que la
       del hero. */
    .catx-grid{--catx-min:276px;--catx-cols:5;--catx-gap:1rem;
      display:grid;gap:var(--catx-gap);
      grid-template-columns:repeat(auto-fill,
        minmax(max(var(--catx-min),
                   (100% - (var(--catx-cols) - 1) * var(--catx-gap)) / var(--catx-cols)), 1fr))}
    /* KAN-23 — forma de la comp. La tarjeta se INVIERTE respecto a la versión
       anterior: antes la foto iba sobre superficie teñida y el cuerpo sobre
       blanco; ahora la foto respira sobre blanco (con margen propio, no a
       sangre) y el cuerpo baja a superficie hundida con filete arriba. El
       recorte nobg de los productos es sobre blanco, así que la foto sobre
       blanco es además el fondo que el recorte espera. */
    .catx-card{background:var(--pl-surface-0);border:1px solid var(--pl-border);border-radius:16px;overflow:hidden;display:flex;flex-direction:column;text-decoration:none;transition:transform .2s cubic-bezier(.16,1,.3,1),border-color .2s ease,box-shadow .2s ease}
        /* Gateado como el zoom de la foto (más abajo, misma hoja): en táctil el
       toque dispara `:hover` y la tarjeta se quedaba levantada después de
       pulsarla. Que una de las dos estuviera gateada y la otra no era la
       incoherencia real. */
    @media (hover:hover) and (pointer:fine){
      .catx-card:hover{border-color:var(--pl-border-strong,var(--pl-brand));transform:translateY(-4px);box-shadow:var(--shadow-lg)}
    }
    /* El equipo manda en la tarjeta: la caja sube de 160 a 190px. El tope del
       84% baja al 80% a propósito y NO es empequeñecer — 80% de 190 son 152px
       contra los 134 de antes, así que el equipo se ve más grande de partida y
       además queda HOLGURA para que crezca al pasar el cursor sin salirse: la
       tarjeta recorta (`overflow:hidden`) y un zoom sobre una foto que ya toca
       el borde se corta por arriba y por abajo. Con 80% + 1.22 llega al 97,6%
       de la caja: entra justo, medido en las dos alturas. */
    .catx-ph{height:190px;margin:1rem 1rem .25rem;background:var(--pl-surface-0);display:flex;align-items:center;justify-content:center;position:relative}
    .catx-ph picture,.catx-ph img{max-width:80%;max-height:80%;object-fit:contain}
    /* ── Etiquetas de la tarjeta, en la esquina de la foto ────────────────
       Misma píldora de cristal oscuro que las del hero, y por el mismo motivo:
       el fondo de la foto es claro y un chip pastel encima se lee como una
       pegatina. Antes el aviso de existencias era un chip ámbar ABAJO, entre
       las specs y el precio, y la condición un chip lila arriba: dos registros
       para la misma clase de dato.
       `pointer-events:none` en la columna: encima está el enlace estirado de
       la tarjeta y una etiqueta se comería el clic en la esquina de la foto. */
    .catx-etiquetas{position:absolute;top:.6rem;left:.6rem;z-index:2;
      display:flex;flex-direction:column;align-items:flex-start;gap:.3rem;
      pointer-events:none}
    .catx-etiq{display:inline-flex;align-items:center;gap:.35rem;
      padding:.3rem .6rem;border-radius:999px;
      /* 11px, no 10: «Nuevo», «Reacondicionada» y «Quedan 2» son la condición y
         la escasez — dos de los tres datos por los que se elige— y estaban por
         debajo del piso legible. La píldora no crece: el peso 600 sobre cristal
         oscuro ya la mantiene compacta. */
      font-size:.6875rem;font-weight:600;line-height:1.2;letter-spacing:.02em;
      white-space:nowrap;color:#fff;
      background:color-mix(in srgb, var(--pl-ink) 84%, transparent);
      border:1px solid rgba(255,255,255,.18);
      -webkit-backdrop-filter:blur(10px) saturate(1.25);
      backdrop-filter:blur(10px) saturate(1.25);
      box-shadow:0 8px 20px -10px rgba(15,10,25,.55)}
    /* El rayo es el único color del cristal: ámbar sobre negro es urgencia sin
       gritar, igual que en el hero. */
    .catx-etiq--urgente i{color:#fbbf24;font-size:.9em}
    /* La etiqueta que aparece al pasar es la de EXISTENCIAS (decisión del
       dueño): la condición se queda fija arriba porque define qué se compra, y
       el aviso de que quedan pocas es el que empuja — no tiene que estar
       gritando en reposo. En táctil no hay hover que lo revele, así que ahí se
       queda visible: un dato que no se puede alcanzar es un dato que no
       existe. */
    .catx-etiq--hover{opacity:0;transform:translateY(-2px);
      transition:opacity .25s cubic-bezier(.16,1,.3,1),transform .25s cubic-bezier(.16,1,.3,1)}
    .catx-card:hover .catx-etiq--hover{opacity:1;transform:none}
    @media (hover:none){.catx-etiq--hover{opacity:1;transform:none}}
    @media(prefers-reduced-motion:reduce){.catx-etiq--hover{transition:opacity .25s linear;transform:none}}

    /* ── Compartir ────────────────────────────────────────────────────────
       Sutil quiere decir: no compite. Es un círculo de 32px sin relleno, con
       el mismo filete de un píxel que las fichas de spec, en la esquina que
       la insignia deja libre. En escritorio vive al 0 de opacidad y aparece
       con la tarjeta —el hover ya dice «esta tarjeta responde», y el botón se
       suma a esa conversación en vez de pedir turno antes—; en táctil, donde
       no hay hover que lo revele, está siempre visible.
       El objetivo táctil son 44px aunque el círculo mida 32: los saca el
       ::after, que no ocupa sitio ni empuja la foto. Y `z-index:2` porque
       encima de la tarjeta está su enlace estirado. */
    /* ABAJO a la derecha, no arriba. Medido a 375px: en la esquina superior
       derecha su caja solapaba la etiqueta «Reacondicionada» 26x22px y el texto
       se leía «Reacondiciona» en 2 de 10 tarjetas. Nuevo-vs-reacondicionado es
       el dato que esta audiencia más necesita inequívoco, y lo estaba cortando
       el control menos importante del naipe. La franja superior queda reservada
       a condición y escasez (`.catx-etiquetas`, arriba a la izquierda). */
    /* Compartir: esquina SUPERIOR derecha y SIEMPRE visible (pedido del dueño,
       2026-08-09). Antes vivía abajo y sólo aparecía al pasar por encima, y eso
       lo dejaba fuera de alcance de la mitad del tráfico: en un teléfono no hay
       hover, y el `@media (hover:none)` que lo encendía no cubre a quien navega
       con teclado ni al que simplemente no pasa el ratón por la foto.
       Arriba a la derecha es además la esquina LIBRE: las insignias ocupan la
       izquierda, así que las dos cosas se leen a la vez sin pisarse. */
    .catx-share{position:absolute;top:.6rem;bottom:auto;right:.6rem;z-index:2;
      width:32px;height:32px;display:grid;place-items:center;
      border-radius:50%;border:1px solid color-mix(in srgb, var(--pl-ink) 24%, #fff);
      background:color-mix(in srgb, var(--pl-surface-0,#fff) 82%, transparent);
      -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
      color:var(--pl-ink-soft);font-size:.72rem;cursor:pointer;padding:0;
      transition:color .2s,border-color .2s,background-color .2s,
                 transform .13s cubic-bezier(.23,1,.32,1)}
    .catx-share::after{content:"";position:absolute;top:50%;left:50%;
      width:44px;height:44px;transform:translate(-50%,-50%)}
    /* Respuesta al pulsar. Era el ÚNICO pulsable de la tarjeta sin ella —
       `.conv-buy` baja a .985 y `.cat-tile` a .98— y desde que el botón está
       siempre visible es el control más expuesto de la página. Baja algo más
       (.94) porque mide 32px: a ese tamaño un .97 no se percibe. */
    .catx-share:active{transform:scale(.94)}
    /* El hover, sólo donde hay cursor. En táctil el toque lo dispara y el
       botón se quedaba morado DESPUÉS de compartir, como si siguiera activo.
       Los cinco controles de catalog-page.css ya llevan este gate. */
    @media (hover:hover) and (pointer:fine){
      .catx-share:hover{color:var(--pl-brand);border-color:var(--pl-brand)}
    }
    .catx-share:focus-visible{outline:2px solid var(--pl-brand);outline-offset:2px}
    /* Copiado: el mismo verbo que el botón del carrito —el estado se queda un
       momento en el sitio donde ocurrió— sin sacar un aviso flotante. */
    .catx-share.esta-listo{color:var(--pl-brand);border-color:var(--pl-brand);
      background:color-mix(in srgb, var(--pl-brand) 12%, #fff)}
    /* El símbolo y el check viven los dos en el botón; sólo cambia cuál se ve.
       El SVG hereda el color por `currentColor`, así que pasa a morado con el
       botón sin una regla propia. */
    .catx-share__ok{display:none;font-size:.8rem}
    .catx-share.esta-listo .catx-share__ico{display:none}
    .catx-share.esta-listo .catx-share__ok{display:block}
    /* Ya no hay nada que «encender»: el botón está visible siempre, tambien
       sin hover y sin JavaScript. Las dos reglas que vivían aquí —una para
       `hover:none` y otra para movimiento reducido— sobran cuando no hay
       aparición que atenuar. */
    .catx-body{background:var(--pl-surface-1);border-top:1px solid var(--pl-surface-3,var(--pl-border));padding:.875rem;display:flex;flex-direction:column;gap:.5rem;flex:1}
    /* Chips de spec: valor corto, sin icono (la comp los quita) y sobre el
       tinte plano de la casa. `min-width:0` + ellipsis para que un valor largo
       de una categoría no-laptop no ensanche la tarjeta. */
    .catx-id{display:flex;flex-direction:column;gap:.1rem;min-width:0}
    /* La marca deja el morado y pasa a tinta tenue, como en la comp: dentro de
       la tarjeta el acento tiene que quedar para el precio y el botón, no
       repartido en tres sitios.
       NO usa el gris de la comp (#8B819F = --ink-faint): medido sobre el
       píxel compuesto real da 3,36:1 contra la superficie hundida del cuerpo,
       y a 10px es texto normal, así que no llega al 4,5:1 de AA. El siguiente
       gris del propio sistema (--text-faint #6E6584) da 5,10:1 y conserva la
       jerarquía. La comp se sigue en forma, no en un valor que no pasa. */
    /* La marca pesa más (pedido del dueño): sube de 10 a 11.5px y de la tinta
       desvaída a la tenue. Antes era casi un pie de foto encima del nombre;
       ahora es lo primero que se lee de la tarjeta, que es como se compra un
       portátil —marca y luego modelo—.
       Y se ENCIENDE en morado al pasar por la tarjeta: la tarjeta entera es un
       enlace, así que el color en el hover no es adorno, es la señal de que
       eso lleva a algún sitio. Va la marca VIVA, que es la que se lee como
       encendida; medido sobre la superficie del cuerpo da 5,24:1, por encima
       del 4,5:1 que pide AA para texto pequeño (el morado oscuro daría 6,53
       pero se lee apagado, que es lo contrario de lo que se pide aquí). */
    .catx-body .cat-brand{color:var(--pl-text-faint,var(--pl-ink-soft));
      font-size:.71875rem;letter-spacing:.1em;
      transition:color .25s cubic-bezier(.16,1,.3,1)}
    .catx-card:hover .cat-brand{color:var(--pl-brand)}
    @media(prefers-reduced-motion:reduce){.catx-body .cat-brand{transition:none}}
    .catx-body .cat-model{font-size:.9375rem;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
    /* Fila de precio: puede quebrar ENTRE las dos cifras, nunca dentro de una.
       En la tarjeta de 170px de la rejilla móvil «RD$ 86,990 RD$ 100,000» no
       cabe de un tirón, y con `nowrap` en el contenedor el tachado se salía
       por el costado de la tarjeta. */
    .catx-body .cat-price{font-family:var(--font-display,inherit);font-size:1.1875rem;font-weight:700;margin-top:auto;
      display:flex;flex-wrap:wrap;align-items:baseline;column-gap:.5rem;row-gap:.1rem}
    .catx-body .cat-price__ahora,
    .catx-body .cat-price__antes{white-space:nowrap}
    /* El precio anterior, cuando hay rebaja real. Vive DENTRO de `.cat-price`
       para no abrir una línea propia —la tarjeta ya reparte su alto entre foto,
       specs y acciones— y baja de peso y de tono para que el tachón informe sin
       competir con la cifra que se paga. Lo trae la tarjeta unificada: en el
       catálogo ya existía (`.card-old-price`) y en la home no, así que sin esto
       una misma laptop rebajada se contaba distinto según por dónde entraras. */
    .catx-body .cat-price__antes{font-size:.75rem;font-weight:600;
      color:var(--pl-ink-soft,#6b7280);text-decoration:line-through}
    /* «ITBIS incluido». Va pegada al precio (margen negativo que se come el
       `gap` del cuerpo) porque es una nota AL PRECIO, no otro dato de la
       tarjeta: separada se leía como una tercera línea de igual rango. */
    .catx-body .cat-tax{margin:-.35rem 0 0;font-size:.7rem;font-weight:600;
      color:var(--pl-ink-soft,#6b7280)}
    /* ── Las specs, en fichas de dato ─────────────────────────────────────
       Eran cinco rectángulos grises idénticos sobre el gris del cuerpo: se
       leían como un bloque, no como cinco datos, y el relleno plano sobre otro
       plano es justo lo que abarata una tarjeta de producto.
       Ahora cada una es una ficha sobre superficie clara con filete de un
       píxel: el contorno es lo que las separa entre sí y del cuerpo, y no
       hace falta más color para lograrlo. Alto fijo de 22px para que las dos
       filas queden alineadas —una ficha de 20 junto a otra de 22 es lo que se
       ve como descuido— y `tabular-nums` para que los números (16GB, 512GB,
       16.0") no bailen de ancho entre tarjetas.
       El PRIMERO es el procesador y va en tinta plena con un punto de marca
       delante: es el dato que el comprador compara primero, y cinco fichas sin
       jerarquía no dicen por dónde empezar. */
    .catx-specs{display:flex;flex-wrap:wrap;gap:.3rem;align-content:flex-start}
    .catx-chip{display:inline-flex;align-items:center;gap:.3rem;
      background:var(--pl-surface-0,#fff);color:var(--pl-ink-soft);
      /* El filete se calcula, no se elige de la paleta: la ficha es blanca
         sobre una superficie casi blanca (1,09:1 entre las dos, medido), así
         que lo único que dibuja su forma es esta línea. Los bordes del sistema
         daban 1,30:1 contra el cuerpo y se desvanecían; un 24% de tinta sobre
         blanco sube a ~1,55:1 — sigue siendo un hilo, pero existe. */
      border:1px solid color-mix(in srgb, var(--pl-ink) 24%, #fff);
      font-size:.6875rem;font-weight:600;line-height:1;
      font-variant-numeric:tabular-nums;letter-spacing:.005em;
      min-height:22px;padding:.2rem .5rem;border-radius:7px;
      max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
    .catx-chip:first-child{color:var(--pl-ink);
      border-color:color-mix(in srgb, var(--pl-brand) 30%, #fff)}
    /* El icono lo pone el propio dato (`h.icon`), así que dice QUÉ es la ficha
       antes de leerla: microchip, pantalla, disco, memoria. Va a .66em —ligado
       al tamaño de la ficha, así que encoge con ella en móvil— y TODOS en
       morado (decisión del dueño): el color hace de familia, y la jerarquía de
       la primera ficha la siguen marcando su tinta plena y su filete teñido,
       que es donde no compite con el dato. */
    .catx-chip i{flex:none;font-size:.66em;line-height:1;color:var(--pl-brand)}
    .catx-help{margin-top:1.4rem;font-size:.875rem;color:var(--pl-ink-soft);display:flex;align-items:center;gap:.5rem;justify-content:center}.catx-help i{color:var(--pl-brand)}.catx-help a{color:var(--pl-brand);font-weight:700;text-decoration:none}.catx-help a:hover{text-decoration:underline}
    /* Tablet y móvil grande: el mínimo baja a 220px. Con 276 la rejilla caía a
       UNA columna entre 481 y 620px de ancho, que es peor que dos tarjetas algo
       más estrechas. Los botones se apilan ahí dentro, y está bien: es el mismo
       comportamiento que ya tiene la rejilla de dos columnas del móvil. */
    @media(max-width:768px){.catx-grid{--catx-min:220px}}
    /* El comp móvil trae DOS tarjetas por línea (grid 1fr 1fr, gap 10px), no
       una: la tarjeta se compacta (foto 112px, cuerpo y tipos menores) para
       que dos quepan sin desbordar a 320-480px. El botón se queda en 44px:
       el mínimo táctil no se negocia por densidad. */
    @media(max-width:480px){
      /* minmax(0,1fr), no 1fr: 1fr respeta el min-content de la tarjeta y a
         320px un chip/botón anchos desbordaban el viewport entero. */
      .catx-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:.625rem}
      /* Sube con la de escritorio (112 -> 132): la foto es lo que hace que se
         distinga un equipo de otro en una rejilla de dos columnas. */
      .catx-ph{height:132px;margin:.75rem .75rem .125rem}
      .catx-body{padding:.625rem;gap:.4rem}
      .catx-body .cat-model{font-size:.8125rem}
      .catx-body .cat-price{font-size:.96875rem}
      /* Misma ficha, un punto más compacta: baja la letra y el costado, pero
         el filete, el alto fijo y los números tabulares se quedan — es lo que
         hace que en móvil se sigan leyendo como datos y no como manchas. */
      /* .6875rem (11px) y no .625rem (10px): los chips son las specs, o sea el
         dato que se compara, y a 10px eran 71 trozos de texto por debajo del
         piso legible en la pantalla donde más cuesta leer. Lo compacto lo
         siguen dando el costado y el alto, que no cambian. */
      .catx-chip{font-size:.6875rem;padding:.15rem .4rem;min-height:20px;gap:.25rem}
    }
    /* Las reglas compactas del BOTÓN no viven aquí: la base .catx-add se
       declara cientos de líneas más abajo y, a igual especificidad, pisaría
       cualquier media query anterior (las medias no suman especificidad).
       Van pegadas a su base, al final del archivo. */
    /* D — Ayuda para categorías con pocos productos */
    .catx-thin{margin-top:1rem;font-size:.875rem;color:var(--pl-ink-soft);display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.catx-thin i{color:var(--pl-brand)}.catx-thin a{color:var(--pl-brand);font-weight:700;text-decoration:none}.catx-thin a:hover{text-decoration:underline}
    /* E — Orden por precio */
    .catx-sort{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;margin:-.4rem 0 1.1rem}
    .catx-sort-lbl{font-size:.8125rem;color:var(--pl-ink-soft);font-weight:600}
    .catx-sort-btn{font-size:.8125rem;font-weight:700;color:var(--pl-ink-soft);background:var(--pl-surface);border:1px solid var(--pl-border);border-radius:999px;padding:.4rem .8rem;min-height:36px;cursor:pointer;transition:transform .18s cubic-bezier(.23,1,.32,1),background-color .2s ease,border-color .2s ease,color .2s ease,box-shadow .2s ease}
    .catx-sort-btn:hover{border-color:var(--pl-brand);color:var(--pl-brand)}
    .catx-sort-btn.on{background:var(--pl-brand);color:#fff;border-color:var(--pl-brand)}
    .catx-sort-btn:focus-visible{outline:2px solid var(--pl-brand);outline-offset:2px}
    /* H1 — región viva para lectores de pantalla (cambios de pestaña/orden) */
    .sr-live{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
    /* Hover diferenciado — zoom de imagen en tarjetas de producto */
    .star-ph img,.catx-ph img,.catx-ph picture img{transition:transform .25s cubic-bezier(.16,1,.3,1)}
    .star-card:hover .star-ph img{transform:scale(1.04)}
    /* ── El equipo se ACERCA al pasar el cursor ───────────────────────────
       1.04 era un guiño que no se veía; el dueño lo quiere grande. 1.22 sobre
       una foto que ocupa el 80% de la caja la lleva al 97,6% — crece de
       verdad y sigue sin tocar el recorte de la tarjeta.
       Elegancia = una sola curva, larga y sin rebote (la misma
       cubic-bezier(.16,1,.3,1) del resto de la home) más una sombra que
       aparece DEBAJO del equipo: es lo que lo despega del papel en vez de
       limitarse a inflarlo. Va en `filter: drop-shadow`, que sigue el alfa del
       recorte —el portátil, no su caja— y se compone en GPU igual que el
       `transform`; ninguna de las dos toca la maquetación.
       `@media (hover:hover)`: en táctil no hay cursor, así que el estado no
       existe y lo que se ve es la foto grande de base. */
    @media (hover:hover){
      .catx-ph img,.catx-ph picture img{transition:transform .28s cubic-bezier(.16,1,.3,1),
                                                   filter .5s cubic-bezier(.16,1,.3,1)}
      .catx-card:hover .catx-ph img,.catx-card:hover .catx-ph picture img{
        transform:scale(1.22);
        filter:drop-shadow(0 16px 20px color-mix(in srgb, var(--pl-ink) 24%, transparent))}
    }
    @media(prefers-reduced-motion:reduce){
      .star-card:hover .star-ph img,.catx-card:hover .catx-ph img,.catx-card:hover .catx-ph picture img{transform:none;filter:none}
    }
    
    /* Estilos del router por intención (.uso*) eliminados junto con su
       sección: quedaban sin ningún selector que los usara. */

    /* ── Vitrina única (superficie de marca oscura) ───────────────────────
       Una ficha grande + seis chicas: composición editorial en vez de seis
       tarjetas idénticas. Encaja exacto en 4 columnas × 2 filas. */
    .vit-grid{display:grid;grid-template-columns:1.6fr minmax(0,1fr) minmax(0,1fr) minmax(0,1fr);gap:.9rem}
    .vit-grid > .dl-big{grid-row:1/3;grid-column:1}
    .dl-was{font-size:.8125rem;font-weight:600;color:#b9a9cc;text-decoration:line-through;letter-spacing:0}
    .dl-trust{margin-top:.85rem;padding-top:.7rem;border-top:1px solid rgba(167,139,250,.18);font-size:.7rem;font-weight:600;color:#c9bcd9;display:flex;align-items:center;gap:.4rem;flex-wrap:wrap}
    .dl-trust i{color:var(--pl-brand-vivid)}
    .cat-all--dark{border-color:rgba(167,139,250,.4);color:#fff}
    .cat-all--dark:hover{border-color:var(--pl-brand-vivid);color:var(--pl-brand-vivid)}
    .cat-badge--off{background:var(--pl-err,#e24b4a)}
    .vit-help{margin-top:1.4rem;font-size:.875rem;color:#c9bcd9}
    .vit-help i{color:var(--pl-brand-vivid);margin-right:.4rem}
    .vit-help a{color:#fff;text-underline-offset:3px}
    @media(max-width:1024px){.vit-grid{grid-template-columns:1.4fr minmax(0,1fr) minmax(0,1fr)}.vit-grid > .dl-big{grid-row:1/3;grid-column:1/2}}
    @media(max-width:820px){.vit-grid{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}.vit-grid > .dl-big{grid-row:auto;grid-column:1/-1}}
    /* En teléfono NO se baja a una columna: siete fichas apiladas a ancho
       completo son 2.800 px de scroll (3,4 pantallas) para ver la vitrina. A
       dos columnas la ficha compacta sigue siendo legible y la sección cabe en
       la mitad del recorrido. */
    @media(max-width:420px){.vit-grid{gap:.55rem}.vit-grid .dl-card{padding:.7rem}}

    /* ── Cómo compras: secuencia REAL de tres pasos ───────────────────────
       Los números informan orden (no son eyebrow decorativo). Numeral grande
       en tinta suave, sin caja: el ritmo lo da el aire, no un borde. */
    /* KAN-23 — forma de la comp: los tres pasos viven DENTRO de un panel
       teñido con el título centrado, y el numeral pasa de cifra grande suelta
       a ficha circular sólida junto al texto. El cambio no es cosmético: la
       cifra grande empujaba título y cuerpo hacia abajo y cada paso ocupaba
       una columna alta; en fila, los tres pasos se leen como una secuencia
       horizontal, que es lo que son.
       El numeral va `aria-hidden` en el marcado porque el <ol> ya numera para
       el lector de pantalla: leerlo dos veces ("uno, uno, agrega al carrito")
       es ruido. */
    /* ── Los tres pasos, versión ESCENIFICADA (2026-08-08) ────────────────
       El bloque anterior (panel teñido + numeral en pastilla + dos líneas de
       texto) contaba el proceso. Este lo REPRESENTA: cada paso tiene un objeto
       que se arma solo —la ficha con su botón, el resumen de pago con las
       formas que la tienda cobra hoy, la caja sellada— y empuja al siguiente.

       Tres cosas que NO son adorno:

       · Todo el estado apagado cuelga de `.pasos-anim`, que pone el JS. Sin JS
         o con reduced-motion la sección se sirve MONTADA. La versión anterior
         dependía del reveal compartido y llegó a servirse vacía en producción.
       · Sólo se anima `transform`/`opacity`. El hilo de progreso crece con
         `scaleX`, no con `width`: animar `width` reflowa la fila entera en
         cada frame.
       · El papel del panel se define por tema. En oscuro no se aclara el mismo
         morado: se cambia por superficie, o el bloque brillaba como un faro. */
    .pasos-panel{--pasos-papel:#faf7fe; --pasos-filo:#f1e9fb; --pasos-carton:#efe0cd; --pasos-carton-2:#e0cdb2;
      position:relative;border-radius:28px;overflow:hidden;border:1px solid var(--pasos-filo);
      padding:clamp(1.7rem,4vw,3rem) clamp(1.2rem,4vw,2.75rem);
      background:
        radial-gradient(120% 90% at 18% 0%, #f7f2ff 0%, rgba(247,242,255,0) 62%),
        radial-gradient(90% 80% at 88% 8%, #fdf0fb 0%, rgba(253,240,251,0) 55%),
        var(--pasos-papel)}
    [data-theme="dark"] .pasos-panel{--pasos-papel:var(--pl-surface-2); --pasos-filo:var(--pl-border);
      --pasos-carton:#3b3350; --pasos-carton-2:#2f2942;
      background:
        radial-gradient(120% 90% at 18% 0%, rgba(124,58,237,.20) 0%, rgba(124,58,237,0) 62%),
        var(--pasos-papel)}
    /* Grano: un punto por cada 5px al 10% de morado. Da textura sin pesar un
       byte de imagen. `pointer-events:none` para no comerse ningún clic. */
    .pasos-panel::after{content:"";position:absolute;inset:0;pointer-events:none;opacity:.5;
      background-image:radial-gradient(rgba(124,58,237,.10) .6px,transparent .6px);background-size:5px 5px}

    .pasos-head{position:relative;z-index:1;text-align:center;max-width:44rem;margin:0 auto clamp(1.5rem,3vw,2.25rem)}
    .pasos-h{font-family:var(--font-display,inherit);font-size:clamp(1.5rem,1rem + 2vw,2.05rem);
      font-weight:800;letter-spacing:-.03em;line-height:1.12;color:var(--pl-ink);margin:0 0 .45rem}
    .pasos-sub{font-size:.9375rem;line-height:1.55;color:var(--pl-ink-soft);margin:0;text-wrap:pretty}

    .pasos-riel-wrap{position:relative;z-index:1;padding-top:78px}
    .pasos-riel{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
      gap:clamp(1rem,2.4vw,2.25rem)}
    .pasos-hilo{position:absolute;left:14%;right:14%;top:182px;height:2px;z-index:0;
      background:linear-gradient(90deg,transparent,var(--pl-border) 12%,var(--pl-border) 88%,transparent)}
    .pasos-hilo-luz{position:absolute;inset:0;transform-origin:left center;transform:scaleX(0);
      background:linear-gradient(90deg,transparent,var(--pl-brand) 15%,var(--pl-brand) 85%,transparent)}

    .paso{position:relative;z-index:1;min-width:0}
    .paso-escena{position:relative;height:208px}
    /* El numeral vive ARRIBA del naipe, no detrás: `.paso-obj` ocupa `inset:0`,
       así que un numeral en z-index 0 dentro de la escena queda tapado al 100%
       y no se pinta un solo píxel. Colocado en el aire, los tres forman además
       una línea de ritmo que ata la fila. */
    .paso-cifra{position:absolute;left:4px;bottom:100%;margin-bottom:-4px;z-index:0;user-select:none;
      font-family:var(--font-display,inherit);font-size:4.5rem;font-weight:800;letter-spacing:-.06em;
      line-height:.82;color:var(--pl-brand);opacity:.16}
    .paso-obj{position:absolute;inset:0;border-radius:16px;background:var(--pl-surface);
      border:1px solid var(--pl-border);
      box-shadow:0 1px 2px rgba(45,31,61,.05),0 20px 40px -18px rgba(45,31,61,.26)}
    [data-theme="dark"] .paso-obj{box-shadow:0 20px 44px -20px rgba(0,0,0,.75)}
    .paso-pie{margin-top:1.05rem}
    .paso-h{font-size:1rem;font-weight:700;letter-spacing:-.02em;color:var(--pl-ink);margin:0 0 .2rem;
      display:flex;align-items:center;gap:.45rem}
    .paso-tick{flex:none;width:1.05rem;height:1.05rem;border-radius:999px;background:var(--pl-brand);
      display:grid;place-items:center}
    .paso-tick svg{width:.6rem;height:.6rem;stroke:#fff;fill:none;stroke-width:3.2;stroke-linecap:round;stroke-linejoin:round}
    .paso-p{font-size:.875rem;line-height:1.55;color:var(--pl-ink-soft);margin:0;max-width:32ch;text-wrap:pretty}

    /* ── Paso 1: la ficha ── */
    .paso-ficha{padding:12px;display:flex;flex-direction:column;gap:7px}
    .pf-foto{display:block;height:88px;border-radius:11px;overflow:hidden;
      background:radial-gradient(70% 70% at 50% 62%,#f4eeff 0%,#fbf9ff 70%)}
    [data-theme="dark"] .pf-foto{background:radial-gradient(70% 70% at 50% 62%,rgba(167,139,250,.20) 0%,rgba(0,0,0,0) 72%)}
    .pf-foto picture{height:100%}
    .pf-foto img{width:100%;height:100%;object-fit:contain;padding:2px 6px}
    .pf-foto img{max-height:88px;filter:drop-shadow(0 8px 14px rgba(45,31,61,.20))}
    .pf-nombre{font-size:.75rem;font-weight:700;letter-spacing:-.01em;color:var(--pl-ink);line-height:1.25;
      margin:0;display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden}
    .pf-specs{font-size:.625rem;color:var(--pl-ink-soft);margin:0;line-height:1.3;
      display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden}
    .pf-precio{display:flex;align-items:baseline;gap:.4rem;margin:auto 0 0}
    .pf-precio b{font-size:.9375rem;font-weight:800;letter-spacing:-.03em;color:var(--pl-ink)}
    .pf-precio del{font-size:.625rem;color:var(--pl-ink-soft)}
    .pf-btn{position:relative;overflow:hidden;height:30px;border-radius:999px;background:var(--pl-brand);
      color:#fff;font-size:.6875rem;font-weight:700;display:grid;place-items:center;letter-spacing:-.01em}
    .pf-btn > span{position:relative;z-index:2}
    .pf-btn::before{content:"";position:absolute;inset:0;z-index:1;transform:translateX(-120%);
      background:linear-gradient(100deg,transparent,rgba(255,255,255,.42),transparent)}
    .pf-onda{position:absolute;left:50%;top:50%;width:12px;height:12px;border-radius:999px;z-index:1;
      background:rgba(255,255,255,.55);transform:translate(-50%,-50%) scale(0)}
    .pf-cursor{position:absolute;left:52%;bottom:-14px;width:17px;height:17px;z-index:9;opacity:0;
      transform:translate(-8px,-24px)}
    .pf-cursor svg{width:17px;height:17px;fill:var(--pl-ink);stroke:var(--pl-surface);stroke-width:1.4}
    .pf-vuela{position:absolute;left:12px;top:12px;width:calc(100% - 24px);height:88px;z-index:8;opacity:0;
      pointer-events:none;display:block}
    .pf-vuela img{max-height:88px}
    .pf-carro{position:absolute;right:-6px;top:-14px;z-index:10;display:flex;align-items:center;gap:.32rem;
      background:var(--pl-surface);border:1px solid var(--pl-border);border-radius:999px;
      padding:.3rem .55rem .3rem .45rem;box-shadow:0 6px 16px -8px rgba(45,31,61,.3)}
    .pf-carro svg{width:14px;height:14px;stroke:var(--pl-ink-soft);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
    .pf-carro b{font-size:.6875rem;font-weight:700;color:var(--pl-ink);min-width:.55rem;text-align:center}
    .pf-carro::after{content:"";position:absolute;inset:-4px;border-radius:999px;border:2px solid var(--pl-brand);
      opacity:0;transform:scale(.85)}

    /* ── Paso 2: el resumen de pago ── */
    .paso-pago{padding:13px 14px;display:flex;flex-direction:column;gap:8px}
    .pp-lin{display:flex;align-items:center;gap:8px;padding-bottom:9px;border-bottom:1px solid var(--pl-border)}
    .pp-mini{width:32px;height:26px;border-radius:6px;flex:none;overflow:hidden;
      background:radial-gradient(70% 70% at 50% 60%,#f4eeff,#fbf9ff)}
    [data-theme="dark"] .pp-mini{background:rgba(167,139,250,.16)}
    .pp-mini img{max-height:26px}
    .pp-txt{font-size:.625rem;color:var(--pl-ink-soft);line-height:1.3;flex:1;min-width:0;
      overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
    .pp-precio{font-size:.6875rem;font-weight:700;color:var(--pl-ink);letter-spacing:-.02em;flex:none}
    .pp-opts{display:flex;flex-direction:column;gap:4px}
    .pp-opt{display:flex;align-items:center;gap:8px;font-size:.6875rem;color:var(--pl-ink-soft);
      padding:.34rem .45rem;border-radius:9px;border:1px solid transparent;line-height:1.2}
    .pp-rad{width:13px;height:13px;border-radius:999px;flex:none;border:1.8px solid var(--pl-border);position:relative}
    .pp-rad::after{content:"";position:absolute;inset:2.4px;border-radius:999px;background:var(--pl-brand);
      transform:scale(0)}
    .pp-total{display:flex;justify-content:space-between;align-items:baseline;margin-top:auto}
    .pp-total span{font-size:.625rem;color:var(--pl-ink-soft)}
    .pp-total b{font-size:.9375rem;font-weight:800;letter-spacing:-.03em;color:var(--pl-ink)}
    .pp-btn{height:28px;border-radius:999px;background:var(--pl-brand);color:#fff;font-size:.6875rem;
      font-weight:700;display:grid;place-items:center}
    /* CONTRASTE: `--pl-ok` (#16a34a) sobre el naipe daba 3.03:1 medido, y a 9px
       el mínimo AA es 4.5:1, no 3:1 — no es «texto grande» por mucho que sea
       secundario. Se sube a un verde oscuro que cierra el ratio sin dejar de
       leerse como confirmación. */
    .pp-seguro{display:flex;align-items:center;justify-content:center;gap:.3rem;font-size:.625rem;
      font-weight:700;color:var(--pl-ok-ink,#0d5c2c);text-align:center;line-height:1.2}
    .pp-seguro svg{width:10px;height:10px;flex:none;stroke:currentColor;fill:none;stroke-width:2.4;stroke-linecap:round}
    /* El sello de aprobado tapa el naipe entero cuando llega. Va oculto de
       base —incluso sin JS— porque NO es contenido: es el resultado de un
       gesto que en la home no ha ocurrido. Servirlo visible diría que hay un
       pago aprobado donde no hay ninguno. Por eso `visibility` y no sólo
       opacidad: sin JS no debe capturarlo ni el lector de pantalla (ya va
       `aria-hidden`) ni el buscador de texto del navegador. */
    /* z-index EXPLÍCITO: sin él, los hermanos del naipe (opciones, total, botón)
       se pintaban encima del sello y el resultado era «Pago aprobado» mezclado
       con el formulario que supuestamente ya se resolvió. Visto en pantalla, no
       deducido: el orden del DOM ganaba porque ninguno declaraba capa. */
    /* El sello SUSTITUYE al botón en el flujo; no se superpone a nada.
       Antes era `position:absolute; inset:0` y terminaba OPACO sobre el naipe:
       al acabar la animación tapaba las formas de pago, el total con ITBIS y la
       línea de AZUL. La home renderizaba la respuesta a una de sus propias seis
       preguntas frecuentes y luego la escondía; quien llegaba pasados los 3 s no
       la veía nunca. Peor: la regla base servía `visibility:hidden`, así que sin
       JS y con reduced-motion los métodos SÍ quedaban visibles y los caminos
       degradados resultaban más persuasivos que el principal.
       El intento intermedio —insignia flotante con `bottom` a ojo— seguía
       tapando las opciones: perseguir una banda con desplazamientos absolutos es
       adivinar geometría que cambia con el breakpoint. El intercambio en flujo
       no tiene ese problema: ocupa exactamente el hueco del botón.
       `display:none` de base es además mejor gate que `visibility`: sin JS no es
       que esté invisible, es que no existe — y un pago aprobado que no ha
       ocurrido no debe existir en el DOM de la home. */
    /* `height`, no `min-height`: el naipe comprime a sus hijos en móvil (el botón
       declara 28px y se renderiza a 17). Con `min-height` el sello se negaba a
       encoger y empujaba la línea de AZUL 11px fuera de la caja. Debe encoger
       igual que la pieza a la que sustituye. */
    .pp-ok{display:none;height:28px;box-sizing:border-box;align-items:center;justify-content:center;
      gap:.4rem;border-radius:999px;background:var(--pl-ok-soft,#f0fdf4);border:1px solid var(--pl-ok);
      padding:0 .6rem}
    .pp-ok svg{width:17px;height:17px;flex:none;fill:none;stroke-linecap:round;stroke-linejoin:round}
    .pp-ok-aro{stroke:var(--pl-ok-ink,#0d5c2c);stroke-width:3;stroke-dasharray:114;stroke-dashoffset:114;
      transform:rotate(-90deg);transform-origin:50% 50%}
    .pp-ok-check{stroke:var(--pl-ok-ink,#0d5c2c);stroke-width:3.4;stroke-dasharray:30;stroke-dashoffset:30}
    .pp-ok b{font-size:.75rem;font-weight:800;letter-spacing:-.02em;color:var(--pl-ok-ink,#0d5c2c)}
    /* El subtexto se va: en una pastilla de una línea competía con el titular y
       obligaba a encoger la tipografía por debajo de lo legible. */
    .pp-ok > span{display:none}
    .pp-cierre{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.25rem;
      margin:auto 0;text-align:center}
    .pp-cierre i{font-size:1.5rem;color:var(--pl-wa,#0F7A42)}
    .pp-cierre b{font-size:.8125rem;font-weight:700;color:var(--pl-ink)}
    .pp-cierre span{font-size:.625rem;color:var(--pl-ink-soft);line-height:1.35}

    /* ── Paso 3: la caja ── */
    /* La escena 3 deja de ser una pila centrada: es un escenario. Ella ocupa
       la derecha y se recorta contra el borde inferior del naipe (de ahí el
       `overflow:hidden`), la caja entra por la izquierda y aterriza a la
       altura de sus manos, y los sellos caen abajo a la izquierda, en el
       hueco que ella no ocupa. */
    .paso-entrega{padding:14px;overflow:hidden}
    /* ── La furgoneta ─────────────────────────────────────────────────
       Dibujada, no traída de un banco de iconos: así lleva el morado de marca
       y el logo real en vez de un camión genérico con licencia que revisar.
       El logo va CENTRADO en el panel de carga —centro geométrico exacto de
       la caja (x 2..106, y 12..56 del viewBox)— porque ahí es donde lo rotula
       una flota de verdad. */
    .pe-van{position:absolute;left:2px;bottom:8px;width:150px;height:77px;z-index:1;display:block}
    .pe-van svg{width:100%;height:100%;display:block;overflow:visible}
    .pv-carga,.pv-cabina{fill:var(--pl-brand)}
    .pv-techo{fill:#a78bfa;opacity:.55}
    .pv-parabrisas{fill:#dcd0f7}
    .pv-faja{fill:var(--pl-brand-hover,#6d28d9)}
    .pv-paragolpes{fill:#4c3a70}
    .pv-faro{fill:#ffe9a8}
    .pv-manilla{fill:#4c3a70;opacity:.7}
    .pv-llanta{fill:#241d33}
    .pv-llanta-int{fill:#4a4060}
    .pv-radios rect{fill:#cdbff0}
    .pv-rueda{transform-box:fill-box;transform-origin:50% 50%}
    .pv-cuerpo{transform-box:fill-box;transform-origin:20% 100%}
    .pv-piso{transform-box:fill-box;transform-origin:50% 50%}
    .pv-buje{fill:#efe9ff}
    .pv-piso{fill:rgba(45,31,61,.16)}
    /* Centrado en el panel de carga, calculado y comprobado en pantalla, no a
       ojo: el panel ocupa x 2..106 del viewBox (centro 54 = 32,1%) y el logo
       mide 20,2% de ancho, así que su BORDE va en 32,1 − 20,2/2 = 22,0%.
       Poner el 32,1% en `left` centraba el borde, no la pieza: 15 px a la
       derecha, medidos. Igual en vertical: panel y 12..56 (centro 34 = 39,5%)
       menos la mitad del 34% de alto = 22,6%. */
    .pv-logo{position:absolute;left:22%;top:22.6%;width:20.2%;height:34%;background-color:#fff}
        /* ALTURA MENOR QUE LA ESCENA, a propósito: a 214 px dentro de un naipe de
       208 y anclada abajo, la coronilla se salía por arriba — el pelo recogido
       quedaba decapitado por el borde. 188 px deja 10 px de aire sobre la
       cabeza y 10 abajo, y la figura entra ENTERA. */
    .pe-chica{position:absolute;bottom:10px;height:188px;width:auto;
      object-fit:contain;object-position:bottom right;
      filter:drop-shadow(0 12px 20px rgba(45,31,61,.24))}
    /* Las dos fotos NO comparten anclaje: la de ella sola es estrecha y va
       pegada al borde; la que trae el portátil es mucho más ancha (la máquina
       sale hacia su izquierda) y necesita sitio, o el equipo se salía del
       naipe. Anclar las dos igual descuadraba una de las dos, siempre. */
    .pe-chica--sin{right:6px}
    /* Centrada: al terminar el reparto la furgoneta ya se fue y el naipe se queda
       sólo con ella — anclada a la derecha quedaba descompensada contra el hueco
       vacío que dejó el camión. */
    .pe-chica--con{left:50%;right:auto;transform:translateX(-50%);opacity:0}
    .pe-caja{position:absolute;left:44%;bottom:30px;display:block;width:88px;height:68px;z-index:2}
    .pe-caja i{position:absolute;display:block}
    .pe-cuerpo{inset:15px 0 0;border-radius:5px;background:linear-gradient(160deg,var(--pasos-carton),var(--pasos-carton-2))}
    .pe-tapa{left:0;right:0;top:0;height:19px;border-radius:5px 5px 2px 2px;
      background:linear-gradient(160deg,color-mix(in srgb,var(--pasos-carton) 70%,#fff),var(--pasos-carton))}
    .pe-cinta{left:50%;top:0;bottom:0;width:15px;transform:translateX(-50%);opacity:.9;
      background:linear-gradient(180deg,var(--pl-brand-vivid),var(--pl-brand))}
    .pe-lustre{left:50%;top:0;bottom:0;width:15px;transform:translateX(-50%);overflow:hidden}
    .pe-lustre::after{content:"";position:absolute;inset:0;transform:translateY(-110%);
      background:linear-gradient(180deg,transparent,rgba(255,255,255,.75),transparent)}
    .pe-sombra{left:-6%;right:-6%;bottom:-9px;height:11px;border-radius:50%;
      background:radial-gradient(50% 50% at 50% 50%,rgba(45,31,61,.30),rgba(45,31,61,0) 70%);
      opacity:0}
    /* En COLUMNA, no en filas: envueltos quedaban 2+1 y el renglón huérfano de
       abajo rompía la lectura; además el ancho de cada sello variaba con el
       texto y los bordes izquierdos no alineaban con nada. Apilados, los tres
       comparten margen izquierdo y se leen como una lista de garantías.
       `align-items:flex-start` para que cada píldora mida lo que dice, no el
       62% de la columna. */
    .pe-sellos{position:absolute;left:12px;top:12px;width:auto;max-width:64%;
      display:flex;flex-direction:column;align-items:flex-start;gap:7px;z-index:3}
    .pe-sello{font-size:.5625rem;font-weight:700;padding:.24rem .5rem;border-radius:999px;
      background:var(--pl-brand-soft);color:var(--pl-brand-hover);display:inline-flex;align-items:center;gap:.24rem}
    /* Aquí vivía un `[data-theme="dark"] .pe-sello{color:var(--pl-brand-vivid)}`
       y era un fallo de contraste esperando su turno: la tienda va clavada a
       `data-theme="light"` (base_landing.html:7) pero plum-theme.js sigue
       cargado, y al forzar el atributo se vio que ESTA regla sí aplica
       mientras los tokens NO giran (el ámbito `data-ds="fism"` los pisa). El
       resultado medido era lila claro #c4b5fd sobre chip lila claro #f1ebfc.
       Sin la regla, el sello hereda `--pl-brand-hover`, que es legible sobre
       el chip claro Y sobre el translúcido oscuro. */
    .pe-sello svg{width:8px;height:8px;stroke:currentColor;fill:none;stroke-width:3.4;stroke-linecap:round;stroke-linejoin:round}

    @media(max-width:820px){
      /* El hueco NO es de ritmo: apilado, cada numeral se cuelga 44px por
         encima de su naipe, y con 1.4rem de gap el «3» caía sobre el párrafo
         del paso 2 (visto en 375px). El aire tiene que cubrir el numeral
         entero. */
      .pasos-riel{grid-template-columns:1fr;gap:3.6rem}
      .pasos-hilo{display:none}
      .paso-escena{height:186px;max-width:340px;margin:0 auto}
      .paso-pie{max-width:340px;margin-left:auto;margin-right:auto}
      /* MENOS alta que la escena, o el naipe la recorta: `paso-entrega` lleva
         `overflow:hidden` y aquí la escena baja a 186 px. A 190 px de alto más
         los 10 de `bottom`, se comía 14 px por arriba — la cabeza. Y el
         `right:-10px` la sacaba además por el costado. 164 + 10 = 174 dentro de
         186: entra entera con 12 px de aire. */
      /* El naipe de pago va justo a 375px: medido, desbordaba 3px INCLUSO
         antes de tocar nada, y el sello de aprobado sumaba 4 más, empujando la
         línea de AZUL fuera de la caja y encima del pie. Cuatro huecos a 5px en
         vez de 8 devuelven 12px, que cubre ambos. */
      .paso-pago{gap:5px}
      .pe-chica{height:164px}
      .pe-chica--sin{right:8px}
      .pe-van{width:128px;height:66px;bottom:6px}
      .paso-cifra{font-size:3.5rem;left:0}
      .pasos-riel-wrap{padding-top:62px}
    }

    /* ══ Coreografía ═══════════════════════════════════════════════════════
       TODO lo apagado vive bajo `.pasos-anim`, y esa clase la pone el JS sólo
       cuando va a animar de verdad (hay IntersectionObserver y el usuario no
       pidió menos movimiento). Sin JS, con JS caído, en un crawler o con
       reduced-motion, no se aplica ni una de estas reglas y las tres escenas
       se sirven montadas y legibles. Es la lección de la versión anterior de
       esta misma sección, que se sirvió VACÍA en producción.

       Curvas: `--pasos-out` (expo) para lo que tiene masa —tarjetas, caja—, y
       `--pasos-snap` con un rebase mínimo SÓLO en tres piezas diminutas (el
       check, el radio, el contador), donde lee como chasquido y no como
       muelle. */
    .pasos-panel{--pasos-out:cubic-bezier(.16,1,.3,1); --pasos-snap:cubic-bezier(.2,1.18,.5,1)}

    .pasos-anim .paso{opacity:.5;transition:opacity .6s var(--pasos-out)}
    .pasos-anim .paso.is-on,.pasos-anim .paso.is-done{opacity:1}
    .pasos-anim .paso-obj{opacity:0;transform:translateY(14px) scale(.97);
      transition:opacity .5s var(--pasos-out),transform .7s var(--pasos-out)}
    .pasos-anim .paso.is-on .paso-obj,.pasos-anim .paso.is-done .paso-obj{opacity:1;transform:none}
    .pasos-anim .paso-cifra{opacity:.08;transform:translateY(6px);
      transition:opacity .6s var(--pasos-out),transform .6s var(--pasos-out)}
    .pasos-anim .paso.is-on .paso-cifra,.pasos-anim .paso.is-done .paso-cifra{opacity:.16;transform:none}
    .pasos-anim .paso-tick{transform:scale(0);transition:transform .45s var(--pasos-snap)}
    .pasos-anim .paso.is-done .paso-tick{transform:scale(1)}
    .pasos-anim .pasos-hilo-luz{transition:transform 1.4s var(--pasos-out)}
    .pasos-anim .pasos-riel-wrap.t1 .pasos-hilo-luz{transform:scaleX(.36)}
    .pasos-anim .pasos-riel-wrap.t2 .pasos-hilo-luz{transform:scaleX(.7)}
    .pasos-anim .pasos-riel-wrap.t3 .pasos-hilo-luz{transform:scaleX(1)}

    /* Paso 1 */
    .pasos-anim .pf-cursor{opacity:0;transform:translate(-8px,42px);
      transition:opacity .35s,transform .8s var(--pasos-out)}
    .pasos-anim .paso.is-on .pf-cursor{opacity:1;transform:translate(-8px,-24px)}
    .pasos-anim .pf-btn{transition:transform .22s var(--pasos-out),background .2s}
    .pasos-anim .paso.is-click .pf-btn{transform:scale(.94);background:var(--pl-brand-hover)}
    .pasos-anim .paso.is-click .pf-cursor{transform:translate(-8px,-21px) scale(.9)}
    .pasos-anim .paso.is-click .pf-btn::before{animation:pasosBrillo .7s var(--pasos-out) .1s}
    .pasos-anim .paso.is-click .pf-onda{animation:pasosOnda .65s var(--pasos-out) forwards}
    .pasos-anim .paso.is-fly .pf-vuela{animation:pasosVuela .85s var(--pasos-out) forwards}
    .pasos-anim .pf-carro{opacity:0;transform:translateY(-6px) scale(.9);
      transition:opacity .4s var(--pasos-out),transform .5s var(--pasos-snap)}
    .pasos-anim .paso.is-on .pf-carro{opacity:1;transform:none}
    .pasos-anim .paso.is-fly .pf-carro::after{animation:pasosPulso .7s var(--pasos-out) .55s}
    .pasos-anim .paso.is-fly .pf-carro b{animation:pasosSube .5s var(--pasos-snap) .6s}
    @keyframes pasosBrillo{to{transform:translateX(120%)}}
    @keyframes pasosOnda{to{transform:translate(-50%,-50%) scale(11);opacity:0}}
    @keyframes pasosVuela{0%{opacity:1;transform:none}
      100%{opacity:0;transform:translate(38%,-118px) scale(.16) rotate(-8deg)}}
    @keyframes pasosPulso{0%{opacity:.8;transform:scale(.85)}100%{opacity:0;transform:scale(1.35)}}
    @keyframes pasosSube{0%{transform:translateY(9px);opacity:0}70%{transform:translateY(-1.5px);opacity:1}100%{transform:none;opacity:1}}

    /* Paso 2 */
    .pasos-anim .pp-opt{transition:border-color .4s var(--pasos-out),background .4s var(--pasos-out),color .4s}
    .pasos-anim .pp-rad{transition:border-color .35s}
    .pasos-anim .pp-rad::after{transition:transform .4s var(--pasos-snap)}
    .pasos-anim .paso.is-pick .pp-opt.is-pick{border-color:var(--pl-brand);background:var(--pl-brand-soft);color:var(--pl-ink)}
    .pasos-anim .paso.is-pick .pp-opt.is-pick .pp-rad{border-color:var(--pl-brand)}
    .pasos-anim .paso.is-pick .pp-opt.is-pick .pp-rad::after{transform:scale(1)}
    .pasos-anim .pp-btn{transition:transform .22s var(--pasos-out)}
    .pasos-anim .paso.is-click .pp-btn{transform:scale(.95)}
    .pasos-anim .pp-seguro{opacity:0;transform:translateY(4px);
      transition:opacity .45s var(--pasos-out),transform .45s var(--pasos-out)}
    .pasos-anim .paso.is-click .pp-seguro{opacity:1;transform:none;transition-delay:.3s}
    .pasos-anim .pp-arco{stroke-dasharray:22;stroke-dashoffset:22;transition:stroke-dashoffset .5s var(--pasos-out) .45s}
    .pasos-anim .paso.is-click .pp-arco{stroke-dashoffset:0}
    /* Aprobado: el botón se retira y el sello ocupa su hueco. El aro se traza
       y el check entra detrás — un check que aparece antes de cerrarse el aro
       lee como icono estático, no como confirmación recién ocurrida. */
    .pasos-anim .paso.is-ok .pp-btn{display:none}
    .pasos-anim .paso.is-ok .pp-ok{display:flex}
    .pasos-anim .pp-ok-aro{transition:stroke-dashoffset .65s var(--pasos-out)}
    .pasos-anim .pp-ok-check{transition:stroke-dashoffset .35s var(--pasos-out)}
    .pasos-anim .paso.is-ok .pp-ok-aro{stroke-dashoffset:0;transition-delay:.1s}
    .pasos-anim .paso.is-ok .pp-ok-check{stroke-dashoffset:0;transition-delay:.6s}

    /* Paso 3 */
    /* Ella llega primero y se asienta; la caja entra DESPUÉS, por la
       izquierda, y al posarse ella acusa el peso con un gesto mínimo (2px de
       hundida y medio grado de giro) antes de recomponerse. Ese acuse es lo
       que convierte «caja junto a una foto» en «se la están entregando»: la
       foto es fija y no puede mover los brazos, así que la entrega la cuenta
       la REACCIÓN, no la anatomía. */
        /* La furgoneta no se desliza como una calcomanía: entra rodando (las ruedas
       giran de verdad), la carrocería copia el bache y al frenar hunde el morro
       antes de recomponerse. Sin el giro de rueda, cualquier vehículo que se
       traslada lee como imagen arrastrada. */
    .pasos-anim .pe-van{opacity:0;transform:translateX(-150px)}
    .pasos-anim .paso.is-on .pe-van{animation:pasosReparto 3.1s var(--pasos-out) forwards}
    /* Llega, frena, deja el paquete y SE VA por la derecha desvaneciéndose: el
       naipe se queda con la foto de ella sosteniendo el equipo, que es el
       único final que el paso 3 tiene que dejar en la cabeza. Un vehículo que
       aparca y no se marcha convierte la escena en un decorado. */
    @keyframes pasosReparto{
      0%{opacity:0;transform:translateX(-150px)}
      12%{opacity:1}
      42%{opacity:1;transform:none}
      62%{opacity:1;transform:none}
      100%{opacity:0;transform:translateX(190px)}}
    .pasos-anim .paso.is-on .pv-rueda{animation:pasosRueda .42s linear 5, pasosRueda 1.1s var(--pasos-out) 2.1s 1}
    .pasos-anim .paso.is-on .pv-cuerpo{animation:pasosBache .3s ease-in-out 3, pasosFrena .5s var(--pasos-out) .95s}
    .pasos-anim .paso.is-on .pv-piso{animation:pasosPiso 1.05s var(--pasos-out)}
    @keyframes pasosRueda{to{transform:rotate(360deg)}}
    @keyframes pasosBache{0%,100%{transform:translateY(0)}50%{transform:translateY(-.9px)}}
    @keyframes pasosFrena{0%{transform:rotate(0)}35%{transform:rotate(-1.4deg)}100%{transform:rotate(0)}}
    @keyframes pasosPiso{0%{transform:scaleX(.6);opacity:.5}100%{transform:none;opacity:1}}
    /* Ella NO se anima: está fija desde que se pinta el naipe. Lo que ocurre es
       la entrega — furgoneta y paquete—; hacerla entrar a ella también convertía
       el paso en tres cosas moviéndose a la vez y ninguna se leía. */
    .pasos-anim .pe-caja{opacity:0;transform:translateX(-92px) translateY(6px) rotate(-14deg) scale(.72)}
    .pasos-anim .paso.is-on .pe-caja{animation:pasosPaquete 3.1s var(--pasos-out) forwards}
    /* El paquete no se queda: se apaga justo cuando ella aparece con el equipo
       en las manos. Es el corte que cuenta «lo abriste» sin dibujarlo. */
    @keyframes pasosPaquete{
      0%,24%{opacity:0;transform:translateX(-92px) translateY(6px) rotate(-14deg) scale(.72)}
      46%{opacity:1;transform:none}
      62%{opacity:1;transform:none}
      78%,100%{opacity:0;transform:translateY(-8px) scale(.9)}}
    /* El relevo: el paquete se apaga y ella aparece YA con el equipo. Las dos
       curvas se cruzan a propósito — un corte seco entre las dos fotos se ve
       como un parpadeo, y un solape largo enseña dos cuerpos a la vez. */
    .pasos-anim .paso.is-on .pe-chica--sin{animation:pasosSaleSin 3.1s var(--pasos-out) forwards}
    .pasos-anim .paso.is-on .pe-chica--con{animation:pasosEntraCon 3.1s var(--pasos-out) forwards}
    @keyframes pasosSaleSin{0%,62%{opacity:1}78%,100%{opacity:0}}
    @keyframes pasosEntraCon{0%,64%{opacity:0}80%,100%{opacity:1}}
    .pasos-anim .pe-sombra{transition:opacity .45s var(--pasos-out)}
    .pasos-anim .paso.is-on .pe-sombra{opacity:1;transition-delay:1.3s}
    .pasos-anim .paso.is-on .pe-lustre::after{animation:pasosLustre .9s var(--pasos-out) 1.65s}
    @keyframes pasosLustre{to{transform:translateY(110%)}}
    .pasos-anim .pe-sello{opacity:0;transform:translateY(7px) scale(.94);
      transition:opacity .4s var(--pasos-out),transform .45s var(--pasos-snap)}
    .pasos-anim .paso.is-on .pe-sello:nth-of-type(1){opacity:1;transform:none;transition-delay:3.05s}
    .pasos-anim .paso.is-on .pe-sello:nth-of-type(2){opacity:1;transform:none;transition-delay:3.17s}
    .pasos-anim .paso.is-on .pe-sello:nth-of-type(3){opacity:1;transform:none;transition-delay:3.29s}

    /* Cinturón y tirantes: aunque el JS nunca ponga `.pasos-anim` con
       reduced-motion, si alguien la pusiera a mano nada se movería. */
    @media(prefers-reduced-motion:reduce){
      .pasos-anim .paso,.pasos-anim .paso-obj,.pasos-anim .paso-cifra,.pasos-anim .paso-tick,
      .pasos-anim .pf-cursor,.pasos-anim .pf-carro,.pasos-anim .pe-caja,.pasos-anim .pe-sello,
      .pasos-anim .pp-seguro{opacity:1 !important;transform:none !important;transition:none !important}
      .pasos-anim .pf-vuela{display:none}
      .pasos-anim .pe-van,.pasos-anim .pe-chica,.pasos-anim .pe-sombra{opacity:1 !important;transform:none !important;animation:none !important;transition:none !important}
      .pasos-anim .pp-ok{display:none !important}
      .pasos-anim .pp-arco{stroke-dashoffset:0 !important;transition:none !important}
      .pasos-anim .pasos-hilo-luz{transform:scaleX(1) !important;transition:none !important}
    }

    /* ── Cierre de página: cuenta de cliente ──────────────────────────────
       Superficie de marca sólida, la única de la home. Es el último bloque y
       tiene UNA cosa que pedir, así que aquí el color sí carga el volumen.
       CONTRASTE: el degradado va del extremo oscuro (#6d28d9) al claro
       (--pl-brand); el peor caso para el texto es el claro. Blanco puro da
       5,79:1 ahí, pero un blanco al 85% —lo que trae la comp— cae a ~4,1:1 y
       no llega a AA para texto normal. Por eso el cuerpo va al 94% (5,3:1) y
       el enlace de WhatsApp al 90% (5,0:1), no a los valores de la comp. */
    .cierre{background:linear-gradient(135deg,var(--pl-brand-hover,#6d28d9),var(--pl-brand));
      border-radius:24px;padding:clamp(2.2rem,5vw,3.25rem) clamp(1.4rem,5vw,3.25rem);text-align:center;color:#fff}
    .cierre-h{font-family:var(--font-display,inherit);font-size:clamp(1.6rem, 1rem + 2vw, 1.875rem);font-weight:700;letter-spacing:-.02em;color:#fff;margin:0 0 .6rem}
    .cierre-p{font-size:.9375rem;line-height:1.55;color:rgba(255,255,255,.94);margin:0 auto 1.5rem;max-width:34rem;text-wrap:pretty}
    .cierre-acts{display:flex;align-items:center;justify-content:center;gap:1rem;flex-wrap:wrap}
    /* Geometria del sistema (2026-08-18): era la unica capsula de la home. */
    .cierre-cta{display:inline-flex;align-items:center;gap:.6rem;background:#fff;color:var(--pl-brand-hover,#6d28d9);
      font-size:.9375rem;font-weight:700;padding:.875rem 1.75rem;border-radius:var(--cta-radio,10px);
      text-decoration:none;min-height:var(--cta-alto-lg,52px);
      transition:transform .18s cubic-bezier(.2,.8,.2,1),box-shadow .25s}
    .cierre-cta:hover{color:var(--ds-brand-dark,#5b21b6);transform:translateY(-2px);box-shadow:0 12px 28px rgba(26,21,35,.22)}
    .cierre-cta:active{transform:translateY(0) scale(.985)}
    .cierre-cta:focus-visible{outline:2px solid #fff;outline-offset:3px}
    .cierre-alt{color:#fff;font-size:.875rem;font-weight:700;text-decoration:underline;text-underline-offset:3px}
    .cierre-alt:hover{color:#fff}
    .cierre-alt:focus-visible{outline:2px solid #fff;outline-offset:3px;border-radius:6px}
    .cierre-wa{display:inline-flex;align-items:center;gap:.45rem;margin-top:1.1rem;font-size:.8125rem;
      color:rgba(255,255,255,.9);text-decoration:none;padding:.35rem .2rem}
    .cierre-wa:hover{color:#fff;text-decoration:underline;text-underline-offset:3px}
    .cierre-wa:focus-visible{outline:2px solid #fff;outline-offset:3px;border-radius:6px}
    @media(prefers-reduced-motion:reduce){.cierre-cta{transition:none}.cierre-cta:hover,.cierre-cta:active{transform:none}}

    .entrega{display:grid;grid-template-columns:1fr 1fr;gap:clamp(1.5rem,4vw,3.2rem);background:var(--pl-surface-2);border-radius:var(--pl-radius,18px);padding:clamp(1.4rem,3vw,2.2rem)}
    .entrega-h{display:flex;align-items:center;gap:.55rem;font-size:.9375rem;font-weight:800;letter-spacing:-.01em;color:var(--pl-ink);margin:0 0 .7rem}
    .entrega-h i{color:var(--pl-brand)}
    .entrega-p{font-size:.875rem;line-height:1.55;color:var(--pl-ink-soft);margin:0 0 .45rem;max-width:46ch}
    .entrega-p strong{color:var(--pl-ink)}
    .entrega-map{color:var(--pl-brand);font-weight:700;text-decoration:none;text-underline-offset:3px}
    .entrega-map:hover{text-decoration:underline}
    .entrega-meta{font-size:.8125rem;color:var(--pl-ink-soft);margin:.6rem 0 0;line-height:1.5}
    .entrega-meta a{color:var(--pl-brand);text-underline-offset:3px}
    .pagos{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:.45rem}
    .pagos li{display:inline-flex;align-items:center;gap:.45rem;font-size:.8125rem;font-weight:600;color:var(--pl-ink);background:var(--pl-surface);border:1px solid var(--pl-border);border-radius:999px;padding:.4rem .8rem}
    .pagos li i{color:var(--pl-brand);font-size:.8125rem}
    @media(max-width:768px){.entrega{grid-template-columns:1fr}}

    /* ── Banda de marca: "Cómo compras y cuándo te llega" ─────────────────
       Por qué ESTA sección y no otra. Las cuatro secciones de la home eran
       transparentes sobre el mismo fondo, separadas sólo por 160px de vacío:
       mucho aire y ningún límite, o sea una columna indiferenciada donde el
       ojo no sabe dónde acaba un bloque y empieza el siguiente. El remedio no
       es más espacio, es un BORDE: un cambio de superficie separa mejor que
       cualquier cantidad de aire, y además permite recortarlo (ver el ritmo
       más abajo). Se banda ésta porque es la única que no vende un equipo
       sino la operación de compra completa — entrega, pago, factura,
       garantía — así que leerla como una zona aparte es lo correcto también
       de contenido, no sólo de forma.

       POR QUÉ ES UN LAVADO CLARO Y NO UN BAÑO DE VIOLETA. Hubo una versión
       saturada (#4c1d95 -> #6d28d9 a sangre, texto en blanco). Separaba, sí,
       pero a un costo que no se sostenía: el registro del proyecto es
       `product` — acento disciplinado, no baño de color — y esta sección no
       vende un equipo, explica la operación (entrega, pago, factura). Gritaba
       tan fuerte como el hero teniendo bastante menos que decir, y de paso
       metía dos saltos de casi-blanco a violeta profundo en 600px de scroll.
       Volumen y contenido desalineados. Aquí lo intenso es la ESTRUCTURA, no
       el color: el aire, la jerarquía y el panel hacen el trabajo, y el matiz
       sólo declara dónde empieza la zona.

       El degradado resuelve HACIA EL BLANCO, y la asimetría es deliberada: el
       borde de arriba entra con lavanda (ahí está el límite que separa de
       "Explora por categoría") y el de abajo llega exactamente a --surface-0,
       o sea se disuelve en la página y entrega el paso a Testimonios sin
       costura. Una frontera declarada y una salida elegante, en vez de dos
       cortes duros. Los resplandores son los mismos matices del sweep del
       Hero (--brand-vivid #a78bfa, --brand-sweep-1 #d946ef) a alfa baja: la
       banda habla el idioma que la home ya hablaba, no introduce paleta nueva.

       CONTRASTE. Al ser clara, el texto vuelve a la tinta del sistema y casi
       todos los overrides de la versión saturada DESAPARECEN — que es el
       movimiento correcto al bajar el volumen: menos casos especiales, no
       más. Sólo sobrevive lo que la banda cambia de verdad. Medido sobre el
       píxel COMPUESTO real, no sobre el token. */
    .pl-band-brand{
      background:
        radial-gradient(72% 104% at 14% -8%, rgba(167,139,250,.32), transparent 66%),
        radial-gradient(56% 88% at 94% 12%, rgba(217,70,239,.12), transparent 64%),
        linear-gradient(180deg,#f2ecff 0%,#faf6ff 46%,var(--pl-surface-0) 100%);
    }
    [data-theme="dark"] .pl-band-brand{
      /* "Hacia el blanco" no se traduce literal en oscuro: una losa clara
         sobre una página #16121f sería un foco. El equivalente honesto es
         hacia el extremo CLARO de la propia escala oscura — una superficie
         levantada con tinte violeta — y la misma resolución al fondo de
         página al final, para que la salida siga siendo sin costura. */
      background:
        radial-gradient(72% 104% at 14% -8%, rgba(167,139,250,.14), transparent 66%),
        radial-gradient(56% 88% at 94% 12%, rgba(217,70,239,.07), transparent 64%),
        linear-gradient(180deg,#241d33 0%,#1d1729 46%,var(--pl-surface-0) 100%);
    }
    /* El panel deja de ser --pl-surface-2 (#f5edf4): sobre el lavado lavanda
       ese gris rosado se ensucia y el panel parece una mancha, no una capa.
       Blanco puro de sistema + filete teñido de marca: se levanta del lavado
       con una sola señal, sin sombra ni vidrio. */
    .pl-band-brand .entrega{
      background:var(--pl-surface-0);
      border:1px solid var(--pl-border);
    }
    /* Las píldoras de pago van al revés que fuera de la banda: sobre el panel
       blanco, un chip blanco desaparece. Toman el tinte suave de marca. */
    .pl-band-brand .pagos li{background:var(--pl-brand-soft);border-color:transparent}

    /* ── Variante inversa: "Preguntas que todos hacen" ────────────────────
       El mismo lavado, con el degradado espejado. La de compras entra con
       lavanda y sale en blanco; ésta entra en blanco y sale en lavanda. Leídas
       en orden, las dos zonas teñidas de la home se miran: el cuerpo central
       (Testimonios) queda enmarcado entre una que se disuelve hacia abajo y
       otra que se materializa hacia abajo, y el color aparece exactamente en
       las dos fronteras que importan — dónde empieza la operación de compra y
       dónde termina la página. No es simetría decorativa: la FAQ es el último
       bloque, y un cierre que se OSCURECE hacia el pie entrega el paso al
       footer (que ya es --pl-surface-2 teñido) en vez de cortar en seco.
       Los resplandores se espejan con el degradado, si no la luz vendría de
       arriba mientras el tinte cae hacia abajo, que es justo lo que delata un
       degradado invertido a mano. */
    .pl-band-brand--inv{
      background:
        radial-gradient(72% 104% at 14% 108%, rgba(167,139,250,.32), transparent 66%),
        radial-gradient(56% 88% at 94% 88%, rgba(217,70,239,.12), transparent 64%),
        linear-gradient(180deg,var(--pl-surface-0) 0%,#faf6ff 54%,#f2ecff 100%);
    }
    [data-theme="dark"] .pl-band-brand--inv{
      background:
        radial-gradient(72% 104% at 14% 108%, rgba(167,139,250,.14), transparent 66%),
        radial-gradient(56% 88% at 94% 88%, rgba(217,70,239,.07), transparent 64%),
        linear-gradient(180deg,var(--pl-surface-0) 0%,#1d1729 54%,#241d33 100%);
    }
    /* Los overrides de filete del acordeón sobre esta banda se retiraron con
       KAN-23: la FAQ dejó de vivir dentro de `--inv` (ahora la banda la lleva
       el cierre de cuenta), así que eran selectores sin ningún elemento que
       los aplicara. */
    /* El pie trae `margin-top:4rem` global, y contra esta banda eso dejaba 64px
       de fondo de página PELADO entre la lavanda y el footer: la zona cortaba
       en seco y parecía recortada, justo lo contrario del cierre que busca.
       Se anula SÓLO donde existe esta banda (`body:has`), o sea únicamente en
       la home — el resto del sitio conserva su margen. El aire no se pierde:
       los 96px de padding inferior de la banda ya lo dan, y ahora dentro del
       color. El remate queda lavanda -> filete del pie -> superficie del pie,
       tres tonos encadenados en vez de un salto y un hueco.
       El selector va aquí y no en plum.css a propósito: es una consecuencia de
       esta banda, y separarlo de ella lo convertiría en una regla huérfana que
       nadie sabría por qué existe si mañana se quita la banda. */
    body:has(.pl-band-brand--inv) .pl-footer{margin-top:0}

    /* ── Ritmo: el aire se reparte según lo que ya separa ──────────────────
       Entre dos secciones transparentes el espacio ES el único límite y se
       conserva entero. La banda no lo recorta: cuando era un corte duro de
       violeta se justificaba ceder aire contra su borde (el color ya
       separaba), pero un lavado suave separa menos, así que ese aire se
       devuelve — bajar el volumen del color y quedarse con el espacio
       recortado habría dejado la frontera peor que antes de todo esto.
       Lo que la banda sí conserva es su interior generoso: una zona con
       fondo propio y el mismo padding que una transparente se lee apretada,
       porque el color llega hasta donde antes había aire de página. */
    /* Las bandas cierran por abajo (punto 2 del ritmo, arriba): un fondo propio
       con `padding-bottom: 0` dejaría su contenido pegado al borde del color.
       Mismo valor que el aire entre secciones, para que la banda no se lea ni
       más apretada ni más suelta que el resto de la página. */
    .cat-full.pl-section-spacing.pl-band-brand{padding-bottom:1.625rem}
    @media(min-width:768px){.cat-full.pl-section-spacing.pl-band-brand{padding-bottom:2.5rem}}
    @media(min-width:1024px){.cat-full.pl-section-spacing.pl-band-brand{padding-bottom:3.5rem}}

    /* Punto 3: quien viene DESPUÉS de una banda arranca en 0. Sin esto la
       frontera de cada banda mediría el doble que las demás.

       `:not(.pl-band-brand)` no es cosmética: una banda que empiece en 0 pega
       su primer texto al borde de su propio color, que es peor que el hueco
       que la regla venía a arreglar. Medido: «Comprar te toma 3 pasos» salió
       así en el primer intento. Cuando dos bandas se tocan no hay fondo de
       página entre ellas, así que sus 56px interiores son interior, no aire
       sobrante. */
    .pl-band-brand + .cat-full.pl-section-spacing:not(.pl-band-brand){padding-top:0}

    /* Punto 4: cuando dos bandas SE TOCAN, sus dos interiores se suman y el
       hueco sale del doble. Medido: 113px entre «Pagas cuando lo ves» y
       «Comprar te toma 3 pasos», contra los 56 de todas las demás fronteras —
       el punto más suelto de la página. Se reparte a mitades para que sume lo
       mismo que el resto.

       La comp no resuelve este caso porque no tiene ninguna banda a sangre:
       sus equivalentes son tarjetas y paneles sobre blanco. Aquí el criterio
       es el suyo (56px entre bloques), aplicado a una estructura que es
       nuestra. */
    /* Punto 5: quien viene ANTES de una banda tiene que cerrar.
       El sistema daba `padding-bottom: 0` a todas las secciones normales y
       confiaba en el `padding-top` de la siguiente para el aire. Con una banda
       detrás eso no funciona: su fondo empieza EXACTAMENTE donde acaba el
       contenido anterior, así que las fichas de «Completa tu setup» quedaban
       pegadas al borde del color y los 56px de la banda eran interior suyo, no
       separación (reporte del dueño; medido: 0px del contenido al borde).
       No se veía porque hasta hoy ahí en medio estaba la banda de confianza;
       al retirarla, el caso quedó al descubierto. La otra frontera igual —
       «Preguntas que todos hacen» contra «Crea tu cuenta»— llevaba así desde
       siempre: medía 11px.
       El valor es el aire entre secciones de la página, el mismo de todas las
       demás fronteras: la banda se lee entonces como un bloque con su interior
       propio, no como algo que empuja a lo de arriba. */
    .cat-full.pl-section-spacing:not(.pl-band-brand):has(+ .cat-full.pl-band-brand){padding-bottom:1.625rem}
    @media(min-width:768px){
        .cat-full.pl-section-spacing:not(.pl-band-brand):has(+ .cat-full.pl-band-brand){padding-bottom:2.5rem}
    }
    @media(min-width:1024px){
        .cat-full.pl-section-spacing:not(.pl-band-brand):has(+ .cat-full.pl-band-brand){padding-bottom:3.5rem}
    }

    /* Este punto 4 regulaba el encuentro de DOS bandas pegadas, y la de arriba
       era `.confia`, que ya no existe. Ahora la banda de «Comprar te toma 3
       pasos» viene después de una sección normal, que es el caso que ya cubre
       el punto 3. Las reglas se retiran en vez de dejarlas apuntando a una
       clase muerta: una regla que no puede coincidir con nada es una pista
       falsa la próxima vez que alguien venga a tocar el ritmo. */

    /* Estilos de la banda "Compras sin riesgo" (.riesgo*) eliminados con su
       sección. */

    /* ── FAQ: <details> nativo, lista con reglas (no tarjetas) ───────── */
    .cat-full > .pl-landing-container.faq-wrap{max-width:58rem;margin-inline:auto}
    .faq-list{border-top:1px solid var(--pl-border)}
    .faq-item{border-bottom:1px solid var(--pl-border)}
    .faq-q{display:flex;align-items:center;justify-content:space-between;gap:1rem;padding:1.1rem .25rem;font-size:1rem;font-weight:700;letter-spacing:-.01em;color:var(--pl-ink);cursor:pointer;list-style:none;min-height:44px}
    .faq-q::-webkit-details-marker{display:none}
    .faq-q i{flex:none;font-size:.8125rem;color:var(--pl-brand);transition:transform .2s cubic-bezier(.16,1,.3,1)}
    .faq-item[open] .faq-q i{transform:rotate(45deg)}
    .faq-q:hover{color:var(--pl-brand)}
    .faq-a p{margin:0 0 1.1rem;padding:0 2rem 0 .25rem;font-size:.875rem;line-height:1.65;color:var(--pl-ink-soft);max-width:68ch;text-wrap:pretty}
    @media(prefers-reduced-motion:reduce){
        .faq-q i{transition:none}
    }

    /* ── CTAs del checkout propio en la home ──────────────────────────────
       El primario lleva el morado de marca; el verde de WhatsApp queda para el
       canal de WhatsApp, no para "comprar aquí". Un botón verde con icono de
       WhatsApp que abre un checkout propio miente sobre a dónde va. */
    .conv-buy{display:inline-flex;align-items:center;justify-content:center;gap:.5rem;background:var(--pl-brand);color:#fff;font-weight:800;border-radius:var(--pl-radius);padding:.85rem 1.5rem;text-decoration:none;font-size:.9375rem;min-height:var(--cta-alto-lg,52px);box-shadow:0 10px 24px rgba(124,58,237,.26);transition:background .25s cubic-bezier(.2,.8,.2,1),box-shadow .25s,transform .18s}
    .conv-buy:hover{background:var(--pl-brand-hover,#6d28d9);box-shadow:0 14px 30px rgba(124,58,237,.32)}
    .conv-buy:active{transform:scale(.985)}
    .conv-buy:focus-visible{outline:2px solid var(--pl-ink);outline-offset:3px}
    button.conv-ask{font:inherit;background:none;border:0;cursor:pointer}
    .conv-ask{display:inline-flex;align-items:center;gap:.45rem;margin-top:.55rem;align-self:flex-start;font-size:.875rem;font-weight:700;color:var(--pl-ink-soft);text-decoration:none;padding:.3rem 0}
    .conv-ask i{color:var(--pl-wa)}
    .conv-ask:hover{color:var(--pl-brand)}
    .has-stretch .conv-buy,.has-stretch .conv-ask{position:relative;z-index:2}
    @media(prefers-reduced-motion:reduce){.conv-buy{transition:none}.conv-buy:active{transform:none}}

    /* Cierre de página: dos acciones sobre superficie oscura. El primario
       devuelve al embudo (catálogo) con el morado de marca; WhatsApp queda como
       alternativa de baja jerarquía, legible sobre el fondo oscuro (la variante
       clara de .conv-ask usa --pl-ink-soft y ahí sería casi invisible). */

    /* Botón de alta al carrito dentro de la tarjeta del explorador: mismo
       primario de marca que el resto del sitio, pero compacto para que no pese
       más que el precio en una tarjeta chica. */
    button.conv-buy{font:inherit;border:0;cursor:pointer}
    /* Misma geometría que los botones del hero, y no por copia: los tokens
       `--cta-*` los define el CSS crítico de home.html y los escriben los dos
       sitios. El selector lleva el contenedor porque `button.conv-buy` de
       arriba trae `font:inherit` con más peso (0,1,1) que una clase suelta —
       por eso el botón de agregar salía a 14px mientras el de comprar iba a
       12 (medido). */
    .catx-add{width:100%;justify-content:center;box-shadow:none}
    .catx-acciones .catx-add{font-size:var(--cta-fs,.8125rem);
      font-weight:var(--cta-peso,800);gap:var(--cta-gap-ico,.5rem);
      padding:var(--cta-pad,.6rem 1rem);min-height:var(--cta-alto,44px);
      border-radius:var(--cta-radio,var(--pl-radius,10px));white-space:nowrap}
    .catx-acciones .catx-add i{font-size:var(--cta-icono,.78rem)}
    .catx-add:hover{box-shadow:0 8px 18px rgba(124,58,237,.24)}
    /* El doble texto (largo/corto) se retiró con la fila: ahora el botón dice
       «Agregar» siempre, porque en fila nunca tiene más de media tarjeta. La
       forma completa vive en el `aria-label`. Y los tamaños de móvil tampoco
       se tocan aquí: los recortan los tokens `--cta-*`, que valen igual para
       el hero. */
    /* 320-360: ni con el texto corto cabe el icono en una tarjeta de ~119px. */
    @media(max-width:360px){.catx-add i{display:none}}
    /* Las DOS acciones de la tarjeta, apiladas. El plano propio (z-index) es
       obligatorio: encima va el `card-link` estirado que hace clicable la
       tarjeta entera, y sin él los dos botones serían decorado — el clic
       caería en el enlace de la ficha. `display:contents` en el form para que
       el botón entre en la columna como un hijo más y los dos midan igual. */
    /* En FILA, como en el hero (pedido del dueño). `wrap` con base de 118px es
       lo que lo hace sobrevivir a la rejilla: la tarjeta mide 265px de ancho
       útil en escritorio —caben los dos— y 132px en la de dos columnas de
       móvil, donde 2×118+gap no entra y los botones se apilan solos. Sin
       media queries: el que decide es el ancho que hay, no el del viewport,
       que en una rejilla no son lo mismo. */
    .catx-acciones{position:relative;z-index:2;display:flex;flex-wrap:wrap;
      gap:var(--cta-gap,.5rem)}
    /* El `form` es `display:contents`, así que el hijo flex REAL es el botón,
       no el form: con `> *` a secas el botón se quedaba con su `width:100%` y
       forzaba el salto de línea aunque cupieran los dos (medido: 265px de
       hueco, dos botones de 265). De ahí el segundo selector y el `width:auto`. */
    .catx-acciones > *,
    .catx-acciones > form > *{flex:1 1 118px;width:auto;min-width:0}
    .catx-acciones form{display:contents}
    /* Agregar al carrito es la acción SECUNDARIA: dos botones llenos seguidos
       compiten y ninguno gana. Contorno sobre blanco, con la misma altura
       táctil y el mismo ancho que el primario. */
    /* El selector lleva el contenedor a propósito: `button.conv-buy` de arriba
       pone `border:0` y con más peso (0,1,1) que una clase suelta, así que
       `.catx-add--sec` sola perdía el contorno y el botón salía blanco sobre
       blanco. Medido: `border` computaba `0px none`. */
    .catx-acciones .catx-add--sec{background:var(--pl-surface-0,#fff);
      color:var(--pl-brand-hover,#5b21b6);
      border:1px solid var(--pl-border-strong);box-shadow:none}
    .catx-acciones .catx-add--sec:hover{background:var(--pl-surface-0,#fff);
      border-color:var(--pl-brand);box-shadow:none}
    /* El secundario mientras la tarjeta no cobra: WhatsApp. Aquí SÍ va relleno
       y no contorno como `--sec`, porque no compite con «Comprar» por la misma
       acción — es otro canal, y en verde se distingue de un vistazo en una
       rejilla de cincuenta tarjetas.
       El verde es el token de sistema (`--pl-wa`, 5.41:1 sobre blanco), no un
       hex propio: el #25D366 de la marca de WhatsApp da 1.98:1 con texto
       blanco encima y hunde AA. Y la sombra del hover se tiñe de verde: la de
       `.catx-add` es morada (`rgba(124,58,237,.24)`) y bajo un botón verde
       queda un halo lila que no pertenece a nada. */
    .catx-acciones .catx-add--wa{background:var(--pl-wa,#0F7A42);color:#fff;
      border:0;box-shadow:none}
    .catx-acciones .catx-add--wa:hover{background:var(--pl-wa-hover,#0c6636);
      box-shadow:0 8px 18px rgba(15,122,66,.26)}
    .catx-acciones .catx-add--wa:focus-visible{outline:2px solid var(--pl-wa,#0F7A42);
      outline-offset:3px}

    /* «Ver detalle» bajo el botón, como en el comp. Sobre el card-link estirado
       necesita su propio plano (z-index) o el clic caería en la tarjeta entera
       — mismo motivo que el form del carrito. Los 44px táctiles solo pueden
       comerse el padding de ABAJO del cuerpo (margen negativo inferior, sin
       vecino): hacia arriba solaparían el botón y sus últimos píxeles pasarían
       a ser del enlace. */
    .catx-ver{position:relative;z-index:2;display:flex;align-items:center;justify-content:center;
      min-height:44px;margin-bottom:-.45rem;font-size:.8125rem;font-weight:700;
      color:var(--pl-brand);text-decoration:none}
    .catx-ver:hover{color:var(--pl-brand-hover,#6d28d9);text-decoration:underline;text-underline-offset:3px}
    .catx-ver:focus-visible{outline:2px solid var(--pl-brand);outline-offset:2px;border-radius:8px}

/* EL HERO YA NO VIVE AQUÍ. Sus reglas (.hero2*) se movieron al <style> inline
   de home.html, y no por gusto: esta hoja llega ASYNC (preload + swap por JS),
   así que todo lo que esté sobre el pliegue se pinta SIN ESTILOS hasta que el
   swap ocurre. Con el hero aquí, la home se veía como texto crudo al cargar —
   regresión real, medida en el sandbox.
   La regla es la que ya decía el comentario de home.html: aquí SOLO lo que va
   debajo del pliegue. */

/* Las reglas de `.confia*` se fueron con su sección (ver el comentario en
   home.html, donde está la medición que justificó retirarla). Eran 19 reglas
   que ya no pintaban nada: CSS muerto en una hoja que además llega async. */

/* ═══ FICHAS «desde RD$X» (uso y setup) ═══ */
.cat-sub{margin:.25rem 0 0;font-size:.85rem;color:var(--pl-ink-soft)}
.ficha-grid{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(2,1fr);gap:.75rem}
@media (min-width:768px){.ficha-grid{grid-template-columns:repeat(4,1fr);gap:1rem}}
.ficha{display:flex}
/* Móvil: foto arriba y texto debajo (la ficha es estrecha, dos columnas no
   caben). Desde 768px cambia a fila —texto a la izquierda, foto a la
   derecha— que es la forma del comp en escritorio. */
.ficha-a{flex:1;display:flex;flex-direction:column;gap:.55rem;text-decoration:none;
         background:var(--pl-surface-0,#fff);border:1px solid var(--pl-border);border-radius:18px;
         padding:1rem;transition:border-color .18s var(--aurora-ease,ease),
                                 box-shadow .18s var(--aurora-ease,ease),
                                 transform .18s var(--aurora-ease,ease)}
.ficha-a:hover{border-color:var(--pl-brand-soft,var(--pl-border-strong));
               box-shadow:0 14px 34px color-mix(in srgb, var(--pl-brand) 10%, transparent);
               transform:translateY(-2px)}
.ficha-a:focus-visible{outline:2px solid var(--pl-brand);outline-offset:3px}
.ficha-txt{display:flex;flex-direction:column;gap:.15rem;min-width:0}
.ficha-i{width:36px;height:36px;display:grid;place-items:center;border-radius:11px;
         background:var(--pl-surface-2);color:var(--pl-brand);font-size:.9rem}
/* La foto NO lleva fondo propio: los recortes vienen sin fondo y una caja
   detrás sólo añadiría un borde que el comp no tiene. */
.ficha-ph{display:flex;align-items:center;justify-content:center;flex:none}
.ficha-ph img{width:84px;height:66px;object-fit:contain}
.ficha-ph picture{display:block;line-height:0}
/* Ofertas lleva los TRES usos, solapados. Tres fotos en fila a tamaño completo
   no caben en la ficha (84px es el hueco de una), así que van a 52px y se
   montan 14: el ojo lee «varios equipos» sin que ninguno pierda su silueta. La
   del medio va un 12% más grande y por delante — un trío plano se lee como una
   tira, y con jerarquía se lee como una selección. */
.ficha-ph--trio picture{width:52px}
.ficha-ph--trio picture + picture{margin-left:-14px}
.ficha-ph--trio img{width:52px;height:41px}
.ficha-ph--trio picture:nth-child(2){position:relative;z-index:1;transform:scale(1.12)}
.ficha-t{font-size:.92rem;font-weight:700;color:var(--pl-ink)}
.ficha-s{font-size:.78rem;color:var(--pl-ink-soft)}
.ficha-v{margin-top:auto;padding-top:.5rem;display:inline-flex;align-items:center;gap:.35rem;
         font-size:.76rem;font-weight:700;color:var(--pl-brand-hover,#5b21b6)}
.ficha-v i{font-size:.62rem}
@media (min-width:768px){
    .ficha-a{flex-direction:row;align-items:center;gap:.75rem;padding:1rem 1.1rem}
    .ficha-txt{flex:1}
    .ficha-v{padding-top:.35rem}
    /* La foto va primero en el DOM porque en móvil manda arriba; en escritorio
       el comp la quiere a la derecha. Reordenar por CSS es seguro AQUÍ y no en
       general: la foto es `aria-hidden` y no es focusable, así que no hay orden
       de lectura ni de tabulación que desincronizar. */
    .ficha-ph{order:2}
}
/* La ficha de Ofertas rompe la rejilla a propósito: cuatro tarjetas idénticas
   no dicen cuál mirar primero, y ésta es la que lleva el descuento. Es el
   mismo recurso del comp. */
.ficha--dark .ficha-a{background:var(--pl-ink);border-color:var(--pl-ink)}
.ficha--dark .ficha-t{color:#fff}
/* Medido en navegador sobre el fondo real (--pl-ink resuelve a #1A1523 dentro
   del ámbito del sistema): 10.12:1. --pl-ink-soft, que es el de las otras
   fichas, caería muy por debajo de AA sobre este fondo. */
.ficha--dark .ficha-s{color:#cbbde0}
.ficha--dark .ficha-v{color:var(--pl-brand-vivid,#a78bfa)}
.ficha--dark .ficha-i{background:rgba(255,255,255,.10);color:var(--pl-brand-vivid,#a78bfa)}
.ficha--dark .ficha-a:hover{border-color:var(--pl-brand);
                            box-shadow:0 14px 34px color-mix(in srgb, var(--pl-ink) 28%, transparent)}
.ficha--dark .ficha-a:focus-visible{outline-color:var(--pl-brand-vivid,#a78bfa)}

/* ── Tramos de presupuesto ── */
.presu{margin-top:1.1rem;display:flex;flex-wrap:wrap;align-items:center;gap:.5rem}
.presu-lbl{font-size:.8rem;font-weight:600;color:var(--pl-ink-soft);margin-right:.15rem}
.presu-p{display:inline-flex;align-items:center;background:var(--pl-surface-0,#fff);
         border:1px solid var(--pl-border);border-radius:999px;padding:.45rem .9rem;
         font-size:.78rem;font-weight:600;color:var(--pl-ink);text-decoration:none;min-height:36px}
.presu-p:hover{border-color:var(--pl-brand);color:var(--pl-brand-hover,#5b21b6)}
.presu-p:focus-visible{outline:2px solid var(--pl-brand);outline-offset:2px}
.presu-cuotas{display:inline-flex;align-items:center;gap:.35rem;margin-left:.2rem;
              font-size:.78rem;font-weight:700;color:var(--pl-brand-hover,#5b21b6);
              text-decoration:none;min-height:36px}
.presu-cuotas:hover{text-decoration:underline;text-underline-offset:3px}
.presu-cuotas:focus-visible{outline:2px solid var(--pl-brand);outline-offset:2px;border-radius:4px}
.presu-cuotas i{font-size:.62rem}


    /* ── Zonas táctiles: el mínimo de 44px que exige el propio PRODUCT.md ──
       Medido a 375px sobre la home servida. Se corrigen SÓLO los que fallan de
       verdad; tres candidatos del escaneo NO son defectos y no se tocan:

         · `.catx-share` (32x32) ya amplía a 44x44 con un `::after` centrado.
         · `.hero2-slider__dot` (28x28) está documentado en home.html:374 como
           decisión WCAG 2.5.8 AA — el mínimo de ese criterio es 24px y entrega 28.
         · `.skip-link` vive fuera de pantalla hasta recibir foco: es de teclado,
           no un objetivo táctil.

       Se amplía por `min-height` y no por padding para no mover la maqueta: el
       texto sigue donde estaba y sólo crece la caja que recibe el dedo. Y se
       acota a punteros gruesos (`pointer:coarse`), porque en escritorio un
       enlace de 44px de alto en una fila de píldoras rompe el ritmo sin ganar
       nada — el criterio 2.5.8 mide el dedo, no el ratón. */
    @media (pointer:coarse){
      .cat-all,.presu-p,.presu-cuotas,.cierre-alt,.aurora-footer__logo{
        min-height:44px;display:inline-flex;align-items:center}
      .cierre-alt{padding-inline:.25rem}
    }


    /* ── FAQ: la caja se ajusta a la medida, no al revés ───────────────────
       Medido a 1280px: la respuesta topa en 634px (~68 caracteres) dentro de un
       item de 826, dejando 192px de canal muerto a la derecha.

       La tentación es ensanchar el texto para llenar la caja. Sería un error:
       65-75 caracteres es la medida legible, y pasarse la empeora. El defecto
       no es el párrafo, es el contenedor — sobra caja, no falta texto.

       Así que se estrecha la lista. El acordeón sigue teniendo aire de sobra y
       el bloque deja de verse desequilibrado hacia la izquierda. */
    @media (min-width:1024px){
      .faq-list{max-width:52rem;margin-inline:auto}
    }


    /* ── Ritmo de las fichas «desde RD$» ──────────────────────────────────
       Medido a 375px: la misma línea medía 39px de alto (dos renglones) en unas
       tarjetas y 19 (uno) en otras, porque el ancho disponible variaba entre 95
       y 128px según lo que la acompañara. Cuatro tarjetas en fila con el precio
       partido de forma distinta leen como un error de maquetación, no como una
       rejilla.
       Se le da fila propia y se prohíbe el corte: todas parten igual, y como ya
       no comparte renglón, los 95px dejan de ser el techo. */
    @media (max-width:820px){
      .ficha-s{width:100%;white-space:nowrap}
    }
