@font-face { font-family: "Great Vibes"; src: url("/fonts/great-vibes-latin.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }

/* =====================================================================
   Violeta Crochet — Landing de venta (rediseño noth-style 2026-07-08).
   Fiel al mock APROBADO `redisenio/landing-noth.html`:
   - Loader violeta profundo (letras que forman VIOLETA + ciclo de amigurumis
     en la "o" + morph a o blanca + telón) — solo 1ª visita (home.js).
   - Hero: base sólida lavanda + el VIDEO se revela con fluido WebGL2 bajo el
     mouse (+ titular rasterizado dentro del shader). Fallback no-gl / poster.
   - Coverflow 3D XL full-bleed (categorías REALES del catálogo).
   - "Violeta en números" (countUp), "Personaliza el tuyo" (timeline + video),
     "Presentaciones" (6 reales), "Sobre mí", reseñas en FILA de tarjetas, FAQ,
     footer violeta profundo. Cursor anillo (puntero nativo visible).
   La topbar (pp-topbar--landing) la inyecta posible-pedido.js (gate data-vc-home).
   ===================================================================== */
:root {
  /* ===== Escala violeta ÚNICA de toda la web (unificada 2026-08-12) =====
     ⚠️ ESPEJO EXACTO de `public/css/tokens.css` (la tienda no carga ese archivo y el taller no
     carga éste) — tocar uno = tocar el otro. Jamás hex crudo nuevo. ⚠️ El módulo «Colores y tema»
     NO toca esta escala: solo se carga en /taller/ y la paleta pública es FIJA (es la marca que ve
     la clienta). Las 4 páginas legales cargan este archivo ANTES de legal.css, así que tampoco
     re-declaran la escala.
     (2026-08-12: se completó la escala con 50/100/200 —solo estaban en el taller— y se declaró
     --violet-900, que se usaba 15 veces viva solo por su fallback; --violet-800 se retiró: 0 usos.) */
  --violet-50: #f6f2ff; --violet-100: #efe7ff; --violet-200: #ddd0fb;
  --violet-300: #c4b5fd; --violet-400: #a98fe6; --violet-500: #8b66de;
  --violet-600: #7c4fd0; --violet-700: #5a3aa8; --violet-900: #3a2f66;
  /* Cabecera MÓVIL única (2026-09-18, pedido de Jean: «el header tiene diferentes diseños por cada
     página… debe ser consistente»). Es el tono de tinta de los iconos del header (lupa, carrito) y el
     fondo del contador, y vive AQUÍ porque las cuatro superficies que lo pintan cargan home.css pero
     solo tres cargan posible-pedido.css: las 30 landings usan guia.css. Repetir el hex en las dos
     hojas es justo lo que hizo divergir las cabeceras. Es el mismo tono de la tienda móvil que Jean
     aprobó en su mock (la paleta `--vc-*` de posible-pedido.css lo llama `--vc-cta-left`), pero su
     ROL aquí es otro —tinta de icono, no stop de gradiente— y por eso tiene token propio. */
  /* Tanda 1b (Jean 2026-09-29, «colores neutros profesionales y dejar el violeta en lo que quiera
     atención»): los iconos del header van en TINTA; solo el CONTADOR del carrito conserva el violeta
     (--hdr-count), que es la única señal de «tienes algo». */
  --hdr-ic: var(--ink);
  --hdr-count: #7856d9;
  /* Grises NEUTROS (sin tinte violeta), los mismos del taller. Medidos: --ink-2 8.8:1 sobre blanco ·
     --muted 5.05:1 sobre blanco y 4.60 sobre --fill-soft · --help (ayudas) 4.95 / 4.51 — el #767676
     que pedía el plan daba 4.14 sobre --fill-soft, así que baja un paso. ⚠️ --muted lo usan también
     portada y landings: cambiarlo es INTENCIONAL (antes #686189, lila). */
  --ink: #211b57; --ink-2: #4a4a52; --muted: #6e6e77; --help: #707070; --faint: #888888; --pink: #ec5f9e;
  /* --pink es el rosa de MARCA y mide 3.14:1 sobre blanco: alcanza para gráficos e iconos
     (≥3:1) pero NO para texto normal. --pink-ink es su versión legible (4.53:1) y es la
     que va en cualquier palabra rosa sobre fondo claro. */
  --pink-ink: #d6337f;
  /* ===== Base visual de la web pública (Tanda 1 del rediseño, 2026-09-29) =====
     Regla: el violeta es para ACTUAR, SELECCIONAR y ENFOCAR; la tinta, para LEER. Los neutros salen
     de mezclar la tinta con el blanco (`color-mix`), así que ninguno es un hex nuevo y todos cambian
     si cambia `--ink`. Contraste medido sobre blanco: --line 1.17:1 (solo separa, decorativo) ·
     --line-strong / --control-line 3.25:1 (borde de un control sin elegir: WCAG 1.4.11 pide ≥3) ·
     --fill-soft 1.1:1 (relleno de secundarios y chips en reposo; el texto encima mide igual que
     sobre blanco menos un 9 %). La escala violeta NO se toca: es espejo exacto del taller. */
  --surface: var(--card);
  --line: color-mix(in srgb, var(--ink) 8%, #fff);   /* Tanda 1b: un tono más claro (11 → 8 %): el borde de un contenedor separa, no llama */
  --line-strong: #8e8e96;   /* gris NEUTRO 3.25:1 — SOLO el borde de un control que se escribe o se despliega (campo, select, segmentado) */
  --control-line: var(--line-strong);
  --fill-soft: color-mix(in srgb, var(--ink) 5%, #fff);
  --fill-soft-2: color-mix(in srgb, var(--ink) 9%, #fff);   /* hover del secundario */
  --selected: var(--violet-50);                             /* fondo de una opción elegida (tenue) */
  --danger: var(--urgent-ink); --danger-bg: var(--urgent-bg);
  /* beneficio (Tanda 1b): «Ahorra 10 %» / «Ahorras S/ X» es el ÚNICO color semántico de la oferta —
     verde suave con tinta verde oscura, 4.80:1 (antes #00915c sobre el mismo fondo: 3.57) */
  --ok-bg: #e4f5ef; --ok-ink: #16794c;
  /* Radios (Jean 2026-09-29, «como el taller»): controles 8 · tarjetas y fotos 12 · chips 999 */
  --ctl-r: 8px; --r-card: 12px;
  /* Jerarquía tipográfica (Tanda 1b, 4 niveles; ≥721 cambian 1, 2 y 4 en el @media de abajo):
     1 protagonista (título de ficha, precio, total) · 2 identificación («Tu pedido», nombre en el pedido)
     · 3 operación (rótulos, «Editar opciones») · 4 contexto (ayudas, metadatos, «Elegido: …») */
  --fs-l1: 28px; --fs-l2: 16px; --fs-l3: 14px; --fs-l4: 12px;
  /* Espaciado: espejo EXACTO de --sp-1..7 del taller (public/css/tokens.css) */
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 24px; --sp-6: 32px; --sp-7: 48px;
  /* Margen lateral de TODA superficie pública (tienda, ficha, checkout, cabecera, barra del carrito,
     Mi cuenta, pie): 12 móvil · 24 tablet · 32 laptop (ver los @media justo debajo de este bloque).
     --pp-side = ese margen, o el que centra el contenido en 1480 px cuando la ventana es más ancha. */
  --pp-gut: 12px;
  --pp-side: max(var(--pp-gut), calc((100% - 1480px) / 2 + 14px));
  /* Motion (solo transform/opacity): entrada con ease-out, salida con ease-in */
  --ease-out: cubic-bezier(.22, 1, .36, 1); --ease-in: cubic-bezier(.4, 0, 1, 1);
  --t-press: 120ms; --t-fb: 160ms; --t-pop: 180ms; --t-tr: 240ms; --t-sheet: 280ms;
  /* urgencia suave (apartado de fecha del checkout): rojo tenue de fondo + tinta AA (5.6:1 sobre --urgent-bg) */
  --urgent-ink: #c0392b; --urgent-bg: #fff1ee; --urgent-line: #f6cfc6;
  --gold-500: #eab54a; /* destello dorado (sección presentaciones, fiel al mock) */
  --grad: linear-gradient(135deg, #845ee0 0%, #8158dc 52%, #7145d2 100%);
  --bg: #f6eff9; --bg-2: #f2e9f7; --panel: #f3ebfa; --card: #ffffff;
  /* crema cálido de la banda «Personaliza el tuyo» (mock de Jean 2026-09-01): el ÚNICO sitio
     con fondo distinto del blanco dentro de <main>. Rompe el bloque y da respiro. */
  --cream: #fdf9f2;
  /* paleta suave de la banda de pasos (tomada del mock): rosa de las fichas y tinta de los
     números. Los iconos son SVG inline y leen estos mismos tokens. */
  --paso-rosa: #f7c4d6; --num-ink: #3d2270;
  /* relleno de los corazones y del cuerpo del lapiz DENTRO de los iconos de paso (SVG). */
  --paso-heart: #f3a9c6; --paso-lapiz: #f7e4b8;
  --glass: rgba(255,255,255,.62); --glass-border: rgba(255,255,255,.7);
  --shadow-sm: 0 1px 2px rgba(33,27,87,.05), 0 12px 28px -14px rgba(90,58,168,.22);
  --shadow: 0 26px 60px -26px rgba(90,58,168,.42);
  --r: 22px;
  /* Escala tipográfica (rem, base 16px) */
  --fs-2xs: 0.625rem; --fs-xs: 0.6875rem; --fs-sm: 0.75rem; --fs-md: 0.8125rem; --fs-base: 0.875rem;
  --fs-lg: 0.9375rem; --fs-xl: 1rem; --fs-2xl: 1.0625rem; --fs-3xl: 1.125rem; --fs-4xl: 1.25rem;
  --fs-5xl: 1.375rem; --fs-6xl: 1.5rem; --fs-7xl: 1.625rem; --fs-8xl: 1.75rem;
  /* Eases noth */
  --p4-inout: cubic-bezier(.77,0,.175,1);
  --p3-out: cubic-bezier(.215,.61,.355,1);
  --p3-in: cubic-bezier(.55,.055,.675,.19);
  --back12: cubic-bezier(.34,1.4,.64,1);
  --back09: cubic-bezier(.34,1.2,.64,1);
  --back18: cubic-bezier(.34,1.8,.64,1);
}
/* Tiers del margen lateral: móvil ≤720 · tablet 721–900 · laptop ≥901 (frontend.md). */
@media (min-width: 721px) { :root { --pp-gut: 24px; --fs-l1: 36px; --fs-l2: 18px; --fs-l4: 13px; } }
@media (min-width: 901px) { :root { --pp-gut: 32px; } }
* { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
  font-family: "Nunito Sans", system-ui, sans-serif; color: var(--ink-2); line-height: 1.6; overflow-x: hidden;
  background: linear-gradient(180deg, #f8f2f8 0%, #f6eef6 100%); min-height: 100vh; position: relative;
}
.hero-copy .hero-h1, h1, h2, h3 { font-family: "Fredoka", "Nunito Sans", sans-serif; color: var(--ink); line-height: 1.06; letter-spacing: -.01em; text-wrap: balance; font-weight: 600; }
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
.heart { display: inline-block; }

/* ===================== Accesibilidad ===================== */
.btn:focus-visible, .link-cats:focus-visible, .pill-cats:focus-visible, .cf-nav:focus-visible,
.cat-dot:focus-visible, .cf-card:focus-visible, .cf-stage:focus-visible,
.faq summary:focus-visible, .to-top:focus-visible, .wa-float:focus-visible,
.foot-col button:focus-visible, .foot-col a:focus-visible, .foot-disc-body button:focus-visible, .skip:focus-visible {
  outline: 2px solid var(--violet-500); outline-offset: 2px;
}
/* Oculto a la vista pero VIVO para lectores de pantalla y para el esquema de títulos:
   un encabezado que estorba visualmente se oculta, no se borra. */
.vc-vh { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
.skip { position: fixed; left: 12px; top: -60px; z-index: 1100; padding: 10px 16px; border-radius: 12px;
  background: var(--violet-700); color: #fff; font-weight: 800; font-size: var(--fs-base); text-decoration: none;
  box-shadow: 0 10px 26px rgba(90,58,168,.4); transition: top var(--t-pop) var(--ease-out); }
.skip:focus-visible { top: 12px; }

/* ============ LOADER — violeta profundo (solo 1ª visita) ============ */
.loader {
  position: fixed; top: 0; left: 0; right: 0; height: 100vh; height: 100lvh; z-index: 100;   /* lvh: cubre TODO aun con la barra móvil colapsable */
  font-family: 'Fredoka', sans-serif;
  background: radial-gradient(120% 100% at 50% 35%, #251543 0%, #1a0d31 55%, #110724 100%);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  color: #fff; overflow: hidden;
  /* ⚠️ El telón se anima con TRANSFORM, no con `height`. Con height el contenido va centrado en una
     altura que decrece, así que sube frame a frame: 82 layout shifts = CLS 0,52 medido en local el
     2026-08-31, el 100% del CLS de la portada. Para conservar el movimiento exacto, el contenido
     compensa la MITAD del recorrido (con height el centro subía 422px mientras el borde inferior
     subía 844: aquí el loader sube 100% y `.loader-inner` baja 50%, mismo neto). */
  transition: transform 1.8s var(--p4-inout); will-change: transform;
}
.loader-inner { transition: transform 1.8s var(--p4-inout); }
.loader.curtain { transform: translateY(-100%); }
/* ⚠️ 50lvh, NO 50%: un porcentaje en translateY se mide contra la ALTURA DEL PROPIO elemento
   (199px), no contra el recorrido del telón (100lvh). Con `50%` el contenido subía de más y la
   animación no coincidía con la original; con 50lvh el centro recorre exactamente los mismos
   422px que recorría al encoger `height` (verificado congelando el 50%: centro en y=211). */
.loader.curtain .loader-inner { transform: translateY(50lvh); }
.loader-inner { display: flex; flex-direction: column; align-items: center; }
.brand { display: flex; align-items: center; gap: .02em; font-weight: 500; letter-spacing: .015em; line-height: .9;
  font-size: clamp(64px, min(17vw, 26vh), 230px); color: #fdfbff; text-shadow: 0 0 40px rgba(180,140,255,.25); }
.brand .l { display: inline-block; }
/* la o = el AMIGURUMI, grande y desbordando las letras (sin círculo de fondo) */
.o-slot { position: relative; display: inline-block; flex: 0 0 auto;
  width: .1em; height: .72em; margin: 0 .035em; overflow: visible;
  transition: width 1.2s var(--p4-inout); }
.o-slot.open { width: .74em; }
.o-slot.to-o { width: .58em; }   /* con la o blanca las letras se cierran un pelín */
.o-slot img { position: absolute; left: 50%; bottom: -.3em; width: 1.24em; max-width: none;
  filter: drop-shadow(0 .06em .12em rgba(0,0,0,.45));
  opacity: 0; transform: translateX(-50%) scale(.8); transform-origin: 50% 88%; }
.o-slot img.on { opacity: 1; transform: translateX(-50%) scale(1); transition: opacity .32s var(--back12), transform .32s var(--back12); }
.o-slot img.first { opacity: 1; transform: translateX(-50%) scale(1); transition: transform .8s var(--back09); }
.o-slot img.exit0 { opacity: 0; transform: translateX(-50%) scale(0); transition: transform .55s var(--p4-inout), opacity .45s ease .1s; }
/* al FINAL el amigurumi se transforma en la letra o BLANCA (morph) */
.o-letter { position: absolute; left: 50%; bottom: -.09em; line-height: .9; color: #fff;
  opacity: 0; transform: translateX(-50%) scale(0); transform-origin: 50% 62%;
  transition: transform .7s var(--back12) .18s, opacity .3s ease .18s; }
.o-slot.to-o .o-letter { opacity: 1; transform: translateX(-50%) scale(1); }
.sub { font-weight: 500; font-size: clamp(19px, min(3.3vw, 5vh), 44px); letter-spacing: .4em; color: #a583ea;
  margin-top: .9em; padding-left: .4em; display: flex; align-items: center; gap: .55em;
  opacity: 0; transform: translateY(12px); transition: opacity .7s ease 1s, transform .8s var(--p4-inout) 1s; }
.sub .sdot { font-size: .6em; opacity: .75; letter-spacing: 0; }
.loader.brand-in .sub { opacity: 1; transform: none; }
.lheart { margin-top: 1.6em; font-size: clamp(15px, 1.6vw, 22px); color: #b18cf2; line-height: 1;
  opacity: 0; transform: scale(.3); transition: opacity .5s ease 1.25s, transform .7s var(--back18) 1.25s; }
.loader.brand-in .lheart { opacity: 1; transform: scale(1); }
.ltag { font-family: "Caveat", cursive; font-style: normal; font-weight: 600;   /* antes Fraunces itálica: 80 KB de fuente para una línea del loader (perf 2026-09-04) */
  margin-top: 1.7em; font-size: clamp(16px, 2.1vw, 27px); letter-spacing: .12em; color: #cbb6f2;
  opacity: 0; transform: translateY(14px); transition: opacity .7s ease 1.45s, transform .9s var(--p4-inout) 1.45s; }
.loader.brand-in .ltag { opacity: 1; transform: none; }
/* doodle de corazón (línea continua que se DIBUJA) */
.ldoodle { position: absolute; left: -2%; bottom: 5%; width: min(46vw, 600px); height: auto; pointer-events: none; }
.ldoodle path { fill: none; stroke: url(#ldg); stroke-width: 3.4; stroke-linecap: round;
  stroke-dasharray: 1; stroke-dashoffset: 1; opacity: .9;
  transition: stroke-dashoffset 2.6s var(--p4-inout) 1.5s; }
.loader.brand-in .ldoodle path { stroke-dashoffset: 0; }
.loader-foot { position: absolute; left: 0; right: 0; bottom: clamp(26px, 6vh, 64px);
  display: flex; align-items: center; justify-content: center; gap: 18px;
  opacity: 0; transition: opacity .8s ease 1.6s; }
.loader.brand-in .loader-foot { opacity: 1; }
.cdot { color: #a583ea; font-size: clamp(13px, 1.4vw, 20px); opacity: .8; }
@media (max-height: 520px) {   /* pantallas BAJAS (móvil apaisado): compactar */
  .lheart { margin-top: .7em; }
  .ltag { margin-top: .7em; }
  .loader-foot { bottom: 10px; }
  .ldoodle { display: none; }
}
/* MÓVIL — ritual comprimido a la mitad (espejo de `LF` en home.js; tocar uno = tocar el otro).
   La clase la pone el JS con el MISMO umbral (max-width:860px): con un @media suelto, un cambio
   de breakpoint en un lado dejaría el copy entrando después de que el telón ya subió. */
.loader.fast .o-slot { transition-duration: .7s; }
.loader.fast .o-slot img.first { transition-duration: .5s; }
.loader.fast .o-slot img.exit0 { transition: transform .32s var(--p4-inout), opacity .26s ease .05s; }
.loader.fast .o-letter { transition: transform .4s var(--back12) .1s, opacity .2s ease .1s; }
.loader.fast .sub { transition: opacity .45s ease .5s, transform .5s var(--p4-inout) .5s; }
.loader.fast .lheart { transition: opacity .35s ease .62s, transform .45s var(--back18) .62s; }
.loader.fast .ltag { transition: opacity .45s ease .72s, transform .55s var(--p4-inout) .72s; }
.loader.fast .ldoodle path { transition: stroke-dashoffset 1.3s var(--p4-inout) .7s; }
.loader.fast .loader-foot { transition: opacity .5s ease .8s; }
.loader.fast { transition-duration: 1s; }
.counter { font-variant-numeric: tabular-nums; font-size: clamp(26px, 3vw, 48px);
  font-weight: 500; color: #c9aef5; letter-spacing: .08em; transition: opacity .5s var(--p4-inout); }
.counter.fade { opacity: 0; }

/* ============ HERO — capa "limpia" (hero-f1-base = clean_0); el VIDEO VIVO se revela detrás ============ */
/* ⚠️ `z-index:1` NO es decorativo: crea el CONTEXTO DE APILADO del hero. Sin él, `.hero` era
   `position:relative` con z-index AUTO —que no crea contexto—, así que sus hijos (.hero-copy y
   .hero-hint, ambos en 3) competían en la raíz contra `<main>` (z-index 2) y se pintaban ENCIMA
   de la hoja blanca, que sube sobre el hero con su margen negativo. Al hacer scroll se leía el
   titular y el CTA flotando sobre «Regalos personalizados» (obs Jean 2026-09-01). El hero es
   HERMANO de <main>, no su hijo: por eso el z-index del hijo alcanzaba la raíz.
   `overflow:hidden` tampoco crea contexto — es un error frecuente darlo por hecho. */
.hero { position: relative; z-index: 1; width: 100%; height: auto; aspect-ratio: 16/9; min-height: 520px; overflow: hidden; background: #e9e2eb; }   /* promedio de hero-f1-base */
.hero-vid { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; pointer-events: none; }
.hero.no-gl .hero-vid { opacity: 1; }   /* sin GL (o poster estático móvil/reduced): se ve el video/poster */
/* sin GL la escena VIVA (pastel, pared lavanda media) queda visible → scrim claro LOCALIZADO bajo el
   titular + tinta oscura (AA real; un degradado oscuro ensuciaría la escena pastel) */
.hero.no-gl::before { content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background: radial-gradient(ellipse 62% 80% at 26% 52%, rgba(243,237,246,.9) 0%, rgba(243,237,246,.55) 55%, transparent 78%); }
/* (sin overrides de color en no-gl: el diseño dos-tonos del mock aplica igual — el scrim da el contraste) */
.reveal-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block;
  pointer-events: none; z-index: 1; opacity: 0; transition: opacity .8s ease; }
body.ready .reveal-canvas { opacity: 1; }
.hero-copy { position: absolute; z-index: 3; left: clamp(20px, 9vw, 190px); top: 50%;
  transform: translateY(-52%) translateY(var(--hcy, 0px));   /* --hcy = parallax de salida (scrollFx, home.js) */
  max-width: min(56vw, 1180px); color: var(--ink); pointer-events: none; }
.hero-pill { display: inline-flex; align-items: center; gap: .5em; background: #fff; border-radius: 999px;
  padding: 10px 22px; font-weight: 700; font-size: clamp(13px, 1.3vw, 26px); color: var(--violet-700);
  box-shadow: 0 10px 26px -14px rgba(43,22,92,.35);
  opacity: 0; transform: translateY(16px); transition: opacity .7s ease .15s, transform .9s var(--p4-inout) .15s; }
body.revealed .hero-pill { opacity: 1; transform: none; }
/* liquid glass SOLO texto (pedido de Jean): translúcido + blur + saturación + highlight inset y
   reflejo superior; fallback sin backdrop-filter = blanco casi opaco */
.hero-pill--glass { background: rgba(255,255,255,.82); border: 1px solid rgba(255,255,255,.6);
  color: var(--ink); box-shadow: inset 0 1px 0 rgba(255,255,255,.75), 0 12px 30px -16px rgba(43,22,92,.35); }
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .hero-pill--glass { background: rgba(255,255,255,.3);
    -webkit-backdrop-filter: blur(14px) saturate(180%); backdrop-filter: blur(14px) saturate(180%); }
}
.hero-pill--glass em { font-style: normal; color: var(--ink); }   /* «experiencia» del mismo azul marino que «Amigurumis» (Jean 2026-07-12) */
.hero-copy h1, .hero-copy .hero-h1 { font-size: clamp(38px, 5.4vw, 132px); font-weight: 700; line-height: 1.04; margin: 0; letter-spacing: -.01em; }
.hero-copy h1:first-of-type { margin-top: .35em; }
.hero-copy .hero-title-line { display: block; white-space: nowrap; }   /* Jean 2026-09-30: una línea escrita a mano no se parte nunca (captura con «en / Trujillo / ♥» apilados) */
.hero-copy .hero-title-line.h1-violet { color: var(--ink); } /* una sola jerarquía H1; las líneas son solo presentación */
.hero-copy .truj { color: var(--pink); font-family: "Caveat", cursive; font-weight: 700;
  font-size: 1.24em; letter-spacing: 0; }                /* «Trujillo» en cursiva Caveat, rosa fucsia — resalta sobre la Fredoka (Jean 2026-07-12) */
.hero-copy .truj-w { position: relative; display: inline-block; }
/* la línea rosada se dibuja PRIMERO (1.0s) y de ella «nace» Trujillo (chars a 1.5s+, ver splitHero) */
.hero-copy .truj-w::after { content: ""; position: absolute; left: 2%; right: 4%; bottom: -.08em; height: .09em;
  border-radius: 99px; background: var(--pink); transform: scaleX(0); transform-origin: left;
  transition: transform .8s var(--p4-inout) 1.0s, background .25s ease; }
body.revealed .hero-copy .truj-w::after { transform: scaleX(1); }
.hero-copy .truj-w.ink-white::after { background: #fff; }
/* corazón DOODLE: se DIBUJA a sí mismo (recorrido del trazo, tras nacer Trujillo) y los 3 destellos
   se pintan UNO A LA VEZ (pedido de Jean). pathLength=1 en el SVG normaliza el dasharray. */
.hero-copy .heart { color: var(--pink); font-weight: 400; display: inline-block;
  opacity: 0; transition: opacity .3s ease 2.0s, color .25s ease; }
body.revealed .hero-copy .heart { opacity: 1; }
.hero-copy .heart-doodle { vertical-align: baseline; }
.hero-copy .heart-doodle svg { width: .92em; height: .72em; display: inline-block; transform: rotate(6deg); overflow: visible; }
.hero-copy .hd-heart, .hero-copy .hd-spark { stroke-dasharray: 1; stroke-dashoffset: 1; }
.hero-copy .hd-spark { stroke: var(--pink, #ec5f9e); transition: stroke var(--t-tr) var(--ease-out); }
body.revealed .hero-copy .hd-heart { animation: hdDraw .85s var(--p4-inout) 2.05s forwards; }
body.revealed .hero-copy .hd-spark:nth-of-type(2) { animation: hdDraw .28s ease-out 2.95s forwards; }
body.revealed .hero-copy .hd-spark:nth-of-type(3) { animation: hdDraw .28s ease-out 3.13s forwards; }
body.revealed .hero-copy .hd-spark:nth-of-type(4) { animation: hdDraw .28s ease-out 3.31s forwards; }
@keyframes hdDraw { to { stroke-dashoffset: 0; } }
@media (prefers-reduced-motion: reduce) {
  .hero-copy .hd-heart, .hero-copy .hd-spark { stroke-dashoffset: 0; animation: none !important; }
}
.hero-copy .chmask { display: inline-block; overflow: hidden; vertical-align: bottom; }
/* La palabra es indivisible: sin esto la línea puede cortarse entre dos letras (splitHero
   en home.js las convierte en inline-blocks independientes) y el titular se parte a la
   mitad en cuanto la tipografía de respaldo mide más ancho que Fredoka. */
.hero-copy .chw { white-space: nowrap; }
/* «Trujillo» va en Caveat ITÁLICA: sus trazos (T inicial, o final) desbordan el ancho del glifo y
   el overflow del mask los recorta → ensancho la caja de recorte horizontalmente con padding y lo
   compenso con margin negativo (no mueve el layout ni el subrayado). El recorte vertical del reveal
   se conserva (padding solo en los lados). */
.hero-copy .truj .chmask { padding: 0 .14em; margin: 0 -.14em; }
.hero-copy .ch { display: inline-block; transform: translateY(120%); color: inherit;
  transition: transform 1.8s var(--p4-inout) var(--chd, 0s), color .25s ease; }   /* color SIN el delay de entrada */
body.revealed .hero-copy .ch { transform: none; }
/* tinta→blanco bajo la brocha (por pieza, con transición — inkSample en home.js) */
.hero-copy .ch.ink-white, .hero-copy .heart.ink-white { color: #fff; }
.hero-copy .heart.ink-white .hd-spark { stroke: #fff; }
.hero-copy .pline p.ink-white, .hero-copy .pline p.ink-white .pl-pin { color: #fff; }
.hero-copy .pline { overflow: hidden; display: block; margin-top: 1.1em; }
.hero-copy .pline > span { display: block; transform: translateY(115%); transition: transform 1s var(--p4-inout) 1.2s; }
body.revealed .hero-copy .pline > span { transform: none; }
.hero-copy p { font-size: clamp(15px, 1.6vw, 34px); margin: 0; color: var(--violet-600); font-weight: 700;
  display: flex; align-items: center; gap: .45em; transition: color var(--t-tr) var(--ease-out); }   /* subtítulo «Envíos…» en violeta vivo (imagen Jean 2026-07-12) */
.hero-copy .pl-pin { width: 1.05em; height: 1.05em; flex: none; color: var(--violet-600); transition: color var(--t-tr) var(--ease-out); }
.hero-actions-glass { display: contents; }
.hero-pill-mobile, .hero-ship-copy small, .hero-btn-arrow, .hero-ship-arrow, .hero-trust-mobile { display: none; }
.hero-ship-copy { display: inline; }
.hero-ship-copy strong { font: inherit; }
.hero-cta { margin-top: 1.4em; pointer-events: auto;
  opacity: 0; transform: translateY(18px); transition: opacity .7s ease 1.5s, transform .9s var(--p4-inout) 1.5s; }
body.revealed .hero-cta { opacity: 1; transform: none; }
/* Pasó desapercibido (obs Jean 2026-09-01) y con él la interacción entera del hero: sube de
   13px al 600 (5,4:1 — el 500 medía 4,16 y no llegaba al AA), gana peso, y el latido ya no baja
   de .62 y suma un deslizamiento suave que insinúa el gesto que se pide. */
.hero-hint { position: absolute; z-index: 3; right: clamp(18px, 5vw, 64px); top: 50%; transform: translateY(-50%);
  color: var(--violet-600); font-size: clamp(13px, 1vw, 16px); font-weight: 700; letter-spacing: .16em; text-transform: uppercase;
  writing-mode: vertical-rl; pointer-events: none; opacity: 0; transition: opacity .8s ease 1.6s; }
body.revealed .hero-hint { opacity: 1; }
@keyframes hintPulse {
  0%, 100% { opacity: .62; transform: translateY(-6px); }
  50%      { opacity: 1;   transform: translateY(6px); }
}
.hero-hint span { display: block; animation: hintPulse 2.6s ease-in-out infinite; }
/* reduced-motion: sin latido, pero VISIBLE y quieto (un `animation:none` a secas lo dejaría
   en la opacidad del frame 0 y volvería a desaparecer). */
@media (prefers-reduced-motion: reduce) {
  .hero-hint span { animation: none; opacity: 1; transform: none; }
}
@media (hover: none) { .hero-hint { display: none; } }   /* en táctil no hay mouse que mover */
@media (max-width: 620px) { .hero-vid { object-position: 70% center; } }   /* favorecer el blob de amigurumis */

/* ===== Hero vivo (tanda premium motion) — solo transform/opacity ===== */
/* wrapper del media: parallax de salida (--hmy lo setea scrollFx de home.js; ≥720px) */
.hero-media { position: absolute; inset: 0; transform: translateY(var(--hmy, 0px)); }
.hero-mobile-slides { display: none; }
/* Ken Burns sutil en video Y canvas GL (el mapping mouse→UV usa el rect ESCALADO: sigue correcto;
   el buffer se dimensiona por clientWidth, no lo toca el transform) */
@keyframes heroKb { from { transform: scale(1); } to { transform: scale(1.06); } }
.hero-vid, .reveal-canvas { animation: heroKb 22s ease-in-out infinite alternate; }
/* glow vivo del CTA — z-index:0 fija el stacking context: el aura (::after z:-1) pinta IGUAL en
   reposo y hover (sin él, el transform del hover la subía sobre el fondo del botón = salto) */
#ctaPersonaliza { position: relative; z-index: 0; }
#ctaPersonaliza::after { content: ""; position: absolute; inset: -16px -22px; border-radius: 999px; z-index: -1;
  background: radial-gradient(58% 70% at 50% 55%, rgba(139,102,222,.5) 0%, rgba(139,102,222,.18) 55%, transparent 74%);
  opacity: .35; pointer-events: none; animation: ctaGlow 3.5s ease-in-out infinite alternate; transition: opacity var(--t-sheet) var(--ease-out); }
@keyframes ctaGlow { to { opacity: .7; } }
#ctaPersonaliza:hover::after { animation: none; opacity: .9; }
/* float ambiental (pill + corazón doodle), desfasados y con delay > orquestación de entrada
   (la animación toma el transform recién cuando la transición de entrada ya terminó) */
@keyframes heroFloat { from { transform: translateY(0); } to { transform: translateY(-4px); } }
body.revealed .hero-pill { animation: heroFloat 6.5s ease-in-out 3.4s infinite alternate; }
body.revealed .hero-copy .heart-doodle { animation: heroFloat 7.6s ease-in-out 4.6s infinite alternate; }
/* Tanda 4 (2026-09-30): ningún adorno infinito corre donde no se ve. `.vc-paused` lo pone home.js (IO) en la
   sección que salió de pantalla; con una página ENCIMA (tienda, ficha, checkout, Mi cuenta) la portada sigue en
   el DOM debajo y en la misma posición, así que el IO la daría por visible: esa pausa la decide `:has`. */
.vc-paused, .vc-paused *, .vc-paused::before, .vc-paused::after, .vc-paused *::before, .vc-paused *::after,
body:has(> .pp-page.show) :is(#hero, main) *,
body:has(> .pp-page.show) :is(#hero, main) *::before,
body:has(> .pp-page.show) :is(#hero, main) *::after,
body > [inert] *, body > [inert] *::before, body > [inert] *::after { animation-play-state: paused !important; }
/* ↑ la última línea: toda capa TAPADA por otra página queda `inert` (posible-pedido.js: seoLayerHidden /
   capasBajoPagina), y con ella se duermen también sus adornos — p. ej. la mascota de la barra de la capa de abajo. */

/* ============ Botones ============ */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 9px; padding: 14px 28px; border-radius: 999px;
  font-weight: 800; font-size: clamp(15px, 1.05vw, 21px); cursor: pointer; border: 0; text-decoration: none; font-family: inherit;
  transition: transform var(--t-tr) var(--ease-out), box-shadow var(--t-tr) var(--ease-out), filter var(--t-pop) var(--ease-out); }
.btn-primary { background: var(--grad); color: #fff; border: 1px solid rgba(255,255,255,.32);
  box-shadow: 0 16px 32px -12px rgba(113,69,210,.55), inset 0 1px 0 rgba(255,255,255,.5), inset 0 -10px 18px -12px rgba(60,32,120,.4); }
.btn-primary:hover { transform: translateY(-2px); box-shadow: 0 24px 46px -14px rgba(113,69,210,.6), inset 0 1px 0 rgba(255,255,255,.6); }
.btn:active { transform: scale(.97); transition-duration: .12s; }
.btn-lg { padding: clamp(16px, 1.15vw, 22px) clamp(34px, 2.3vw, 46px); font-size: clamp(16px, 1.15vw, 23px); }
.ic-heart { font-size: 1.05em; line-height: 1; }
.btn-ghost { background: #fff; color: var(--violet-700); border: 1.5px solid rgba(124,79,208,.25); box-shadow: var(--shadow-sm); }
.btn-ghost:hover { transform: translateY(-2px); border-color: var(--violet-500); box-shadow: var(--shadow); }
.btn-ghost svg { width: 18px; height: 18px; }
/* Un SVG sin ancho propio dentro de un botón mide 0×0 y desaparece sin error: el icono de
   WhatsApp vivía del tamaño que le daba `.btn-ghost svg` y al pasar el botón a primario
   (2026-09-01) se quedó sin regla. `.btn-wa` lo dimensiona sea cual sea la variante. */
.btn-wa svg { width: 19px; height: 19px; flex: none; }
.btn-ghost-dark { background: rgba(255,255,255,.06); color: #e8defc; border: 1.5px solid rgba(255,255,255,.22); box-shadow: none; }
.btn-ghost-dark:hover { transform: translateY(-2px); background: rgba(255,255,255,.11); border-color: rgba(255,255,255,.4); }

/* ============ PANEL BLANCO del contenido — FULL WIDTH (hoja que cubre todo el navegador) ============ */
main { position: relative; z-index: 2; display: block; background: #fff;
  width: 100%; margin: clamp(-56px, -3.4vw, -34px) auto 0;
  border-radius: clamp(28px, 3.2vw, 46px) clamp(28px, 3.2vw, 46px) 0 0;
  box-shadow: 0 -30px 66px -30px rgba(90,58,168,.2); }
/* --gut = el margen lateral REAL del contenido. Los raíles horizontales lo leen para sangrar
   hasta el borde y devolver el aire exacto (si se pisa el padding, hay que pisar la variable). */
.wrap { --gut: clamp(20px, 4vw, 80px); max-width: 1920px; margin: 0 auto; padding: 0 var(--gut); position: relative; z-index: 1; }
.sec { padding: clamp(52px, 6vw, 104px) 0; position: relative; z-index: 1; }
.sec-title { font-size: clamp(26px, 2.9vw, 64px); font-weight: 600; color: var(--ink); display: inline-flex; align-items: center; gap: 10px; position: relative; cursor: default; }
.sec-title::after { content: ""; position: absolute; left: 1%; bottom: -8px; width: 96%; height: 4px; border-radius: 99px;
  background: var(--pink); opacity: .85; transform: scaleX(0); transform-origin: left; transition: transform .5s var(--p4-inout); }
.sec-title:hover::after { transform: scaleX(1); }
.sec-head-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; flex-wrap: wrap; margin-bottom: clamp(18px, 2.4vw, 30px); }
.sec-head-txt { min-width: 0; }
.pill-cats { flex: none; align-self: center; background: linear-gradient(180deg, #f3ecfd, #ece1fb); border: 1px solid rgba(124,79,208,.16);
  cursor: pointer; font-family: inherit; font-weight: 800; font-size: clamp(15px, 1.05vw, 21px); color: var(--violet-600); text-decoration: none;
  display: inline-flex; align-items: center; gap: 9px; padding: 12px 22px; border-radius: 999px;
  box-shadow: 0 10px 24px -14px rgba(90,58,168,.45), inset 0 1px 0 rgba(255,255,255,.7);
  transition: transform var(--t-pop) var(--ease-out), box-shadow var(--t-pop) var(--ease-out), background var(--t-pop) var(--ease-out); }
.pill-cats:hover { transform: translateY(-2px); background: linear-gradient(180deg, #f6f0ff, #ecdffb); box-shadow: 0 16px 30px -14px rgba(90,58,168,.5); }
.pill-cats:active { transform: scale(.97); }
.pill-cats .arr { transition: transform var(--t-pop) var(--ease-out); }
.pill-cats:hover .arr { transform: translateX(4px); }
.link-cats { background: none; border: 0; cursor: pointer; font-family: inherit; font-weight: 800; font-size: 15px; color: var(--violet-600); display: inline-flex; align-items: center; gap: 6px; padding: 6px 4px; text-decoration: underline; }

/* ============ SISTEMA DE TRANSICIONES (recetas noth) ============ */
[data-line] { --d: 0ms; }
[data-line] .lnmask { display: inline-block; overflow: hidden; padding-bottom: .15em; margin-bottom: -.15em; vertical-align: bottom; }
[data-line] .ln { display: inline-flex; align-items: center; gap: 10px; transform: translateY(110%); transition: transform 1s var(--p4-inout) var(--d); }
[data-line].in .ln { transform: none; }
[data-fade] { --d: 0ms; opacity: 0; transform: translateY(20px);
  transition: opacity .9s var(--p3-out) var(--d), transform 1s var(--p4-inout) var(--d); }
[data-fade].in { opacity: 1; transform: none; }
/* variante zoom: mismo timing, entra con un scale-up sutil (coverflows, reseñas, foot-cta) */
[data-fade="zoom"] { transform: translateY(14px) scale(.94); }
[data-wipe] { --d: 0ms; clip-path: var(--clip0, inset(100% 100% 0% 0%)); transition: clip-path 1s var(--p4-inout) var(--d); }
[data-wipe].in { clip-path: inset(0% 0% 0% 0%); }
[data-rise] { --d: 0ms; --rz: 2.5deg; opacity: 0; transform: translateY(46px) rotate(var(--rz));
  transition: opacity .9s var(--p3-out) var(--d), transform 1.1s var(--back12) var(--d); }
[data-rise].in { opacity: 1; transform: translateY(0) rotate(var(--rzf, 0deg)); }
.pxwrap { overflow: hidden; position: relative; }
.pxwrap .pximg { position: absolute; left: 0; top: 0; width: 100%; height: 112%;
  background-size: cover; background-position: center; will-change: transform; }
/* Foto del taller por tamaño de pantalla: la de 1536 px pesa 265 KB y un celular la pinta a ~360 px
   (perf 2026-09-04). La URL vive aquí y no en el style inline para poder cambiarla por media query. */
.px-taller { background-image: url(/landing/taller4.webp); }
@media (max-width: 720px) { .px-taller { background-image: url(/landing/taller4-m.webp); } }
@keyframes heroRise { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }

/* ============ Elige tu favorito — COVERFLOW 3D XL full-bleed ============ */
/* ⚠️ `z-index: 2` (las `.sec` van a 1): la sección SIGUIENTE se pinta después y con el mismo
   z-index, así que se comía la mitad de abajo del área de toque de los puntitos — medido: el
   ::after declara 24px de alto y solo respondían 12 (7,5 arriba + 4 abajo). El dato no se ve
   leyendo el CSS: hay que sondear con elementFromPoint alrededor del punto. */
.sec-cats { padding-bottom: clamp(40px, 5vw, 66px); overflow-x: hidden; overflow-x: clip; z-index: 2; }
.cat-coverflow { position: relative; width: 100vw; margin-left: calc(50% - 50vw); padding: 34px 0 24px;
  --cf-cardw: clamp(184px, 17.5vw, 460px); --cf-unit: calc(var(--cf-cardw) * .95); }
.cat-coverflow.in .cf-stage { animation: heroRise .6s cubic-bezier(.16,1,.3,1) backwards; }
/* ⚠️ La sombra de las tarjetas (0 18px 40px -22px) baja ~16px y el carril solo dejaba 10 abajo y
   2 arriba, así que se veía cortada (censo 2026-09-09). El padding NO sirve aquí: las tarjetas son
   `position:absolute; top:50%` y se resuelven contra el PADDING BOX, así que añadirlo les movería
   el centro y descolocaría el coverflow entero. `overflow-y: clip` + `overflow-clip-margin` amplía
   el área de recorte sin tocar una sola medida del layout; donde no se soporte, `clip` se comporta
   como el `hidden` de antes (degradación segura, nunca peor que hoy). */
.cf-stage { position: relative; width: 100%; height: calc(var(--cf-cardw) * 1.26 + 60px); perspective: 1200px; perspective-origin: 50% 46%;
  /* ⚠️ SIN recorte vertical, y no es un descuido. Aquí hubo `overflow-y: clip` +
     `overflow-clip-margin`, y ese par NO FUNCIONA: el margen de recorte solo se aplica cuando la
     caja está recortada en AMBOS ejes, así que con `overflow-x: visible` el navegador cortaba la
     sombra a ras del borde por mucho que se subiera el margen (22 → 80px no cambió nada). Medido
     leyendo los píxeles de una captura: a 5px bajo la tarjeta el color era blanco puro (255,255,255)
     con clip, y el degradado real de la sombra con `visible`. Es el «se ven cortadas» que Jean
     reportó tres veces. Recortar tampoco hacía falta: las tarjetas no sobresalen del stage ni un
     píxel (medido arriba y abajo, en reposo y girando) — la que se sale es la de los LADOS, y ese
     eje ya era visible a propósito (el sangrado del carrusel). */
  overflow: visible;
  touch-action: pan-y; user-select: none; -webkit-user-select: none; cursor: grab; outline: none; }
.cf-stage:active { cursor: grabbing; }
.cf-card { position: absolute; top: 50%; left: 50%; width: var(--cf-cardw);
  --tx: 0; --sc: 1; --ry: 0deg; --op: 1; --bl: 0px;
  transform: translate(-50%, -50%) translateX(calc(var(--cf-unit) * var(--tx))) scale(var(--sc)) rotateY(var(--ry));
  opacity: var(--op); filter: blur(var(--bl));
  background: var(--card); border-radius: 22px; overflow: visible; border: 1px solid rgba(124,79,208,.07);
  box-shadow: 0 18px 40px -22px rgba(90,58,168,.4); cursor: pointer; text-align: left; padding: 0;
  display: flex; flex-direction: column; font-family: inherit; }
/* ⚠️ `will-change` SOLO mientras gira, nunca permanente (Jean 2026-09-09: «las letras se
   distorsionan después de un rato en la web, también en móvil»). Un `will-change: transform` fijo
   promueve cada tarjeta a su propia capa de GPU y el TEXTO de dentro (`.cf-name`) se rasteriza una
   vez a esa resolución; en un móvil, cuando el compositor necesita memoria, re-rasteriza esas capas
   más bajas y las letras salen sucias — de ahí que empeore CON EL TIEMPO y no desde el principio.
   La clase `.cf-animate` la pone y la quita el propio carrusel al animar, así que la pista de
   optimización llega cuando sirve y desaparece cuando no. */
.cf-stage.cf-animate .cf-card { will-change: transform, opacity, filter;
  transition: transform .5s cubic-bezier(.22,1,.36,1), opacity .5s ease, filter .5s ease; }
.cf-card.is-center { box-shadow: 0 34px 70px -26px rgba(90,58,168,.6), 0 0 0 1px rgba(124,79,208,.14); }
.cf-media { position: relative; aspect-ratio: 1/1; overflow: hidden; border-radius: 22px 22px 0 0; display: grid; place-items: center;
  background: radial-gradient(120% 100% at 50% 14%, var(--bg) 0%, rgba(169,143,230,.32) 100%); }
.cf-media img { width: 100%; height: 100%; object-fit: cover; -webkit-user-drag: none; }
/* Categoría sin foto: plato circular con aro lavanda tras el emoji */
.cf-media:has(.cf-emoji)::before { content: ''; position: absolute; width: 56%; aspect-ratio: 1; border-radius: 50%; background: rgba(255,255,255,.8); box-shadow: inset 0 0 0 6px rgba(169,143,230,.26), 0 14px 30px -12px rgba(90,58,168,.35); }
.cf-emoji { position: relative; font-size: clamp(40px, 5vw, 80px); filter: drop-shadow(0 10px 16px rgba(90,58,168,.28)); }
.cf-foot { position: relative; display: flex; align-items: center; gap: 10px; padding: clamp(12px, 1vw, 18px) clamp(15px, 1.2vw, 22px) clamp(15px, 1.2vw, 20px); }   /* sin icono ni flecha (Jean 2026-09-03): solo categoría + «Desde» */
.cf-info { min-width: 0; flex: 1 1 auto; }
.cf-name { font-family: "Fredoka", sans-serif; font-weight: 600; font-size: clamp(16px, 1.35vw, 35px); color: var(--ink); line-height: 1.15; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cf-price { font-size: clamp(13px, 1vw, 25px); color: var(--muted); font-weight: 700; margin-top: 1px; }
.cf-price .cf-was { font-weight: 600; opacity: .7; font-size: .86em; margin-left: 3px; }
.cf-nav { position: absolute; top: 50%; transform: translateY(-50%); z-index: 200; width: 48px; height: 48px; border-radius: 50%;
  border: 1px solid rgba(255,255,255,.6); background: rgba(255,255,255,.55);
  -webkit-backdrop-filter: blur(10px) saturate(160%); backdrop-filter: blur(10px) saturate(160%);
  color: var(--violet-600); cursor: pointer; display: grid; place-items: center;
  box-shadow: 0 14px 30px -12px rgba(90,58,168,.4), inset 0 1px 0 rgba(255,255,255,.7);
  transition: background var(--t-pop) var(--ease-out), color var(--t-pop) var(--ease-out), transform var(--t-pop) var(--ease-out), opacity var(--t-pop) var(--ease-out), border-color var(--t-pop) var(--ease-out); }
.cf-nav svg { width: 20px; height: 20px; }
.cf-nav.prev { left: clamp(14px, 3vw, 72px); } .cf-nav.next { right: clamp(14px, 3vw, 72px); }
.cf-nav:hover { background: var(--grad); color: #fff; border-color: transparent; box-shadow: 0 18px 34px -12px rgba(113,69,210,.6); }
.cf-nav:active { transform: translateY(-50%) scale(.92); }
.cf-nav[disabled] { opacity: .32; pointer-events: none; }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) { .cf-nav { background: rgba(255,255,255,.92); } }
.cat-dots { display: flex; gap: 8px; justify-content: center; margin-top: 8px; flex-wrap: wrap; }
.cat-dot { position: relative; width: 9px; height: 9px; border-radius: 50%; background: rgba(124,79,208,.24); border: 0; padding: 0; cursor: pointer;
  transition: background var(--t-pop) var(--ease-out), transform var(--t-pop) var(--ease-out); }
.cat-dot::after { content: ""; position: absolute; inset: -7.5px -4px; }   /* WCAG 2.5.8: 24px de alto sin solapar vecinos */
.cat-dot.on { background: var(--violet-500); transform: scale(1.15); }
/* skeleton de carga (mismas piezas del coverflow, sin datos) — política 2026-07-18: nace invisible
   y aparece a los ~300ms (caché SWR = ni se ve); timing 1.3s unificado con .pp-sk/.sk-sh de
   posible-pedido.css (tocar uno = tocar los tres). */
.cf-card.is-sk { pointer-events: none; box-shadow: 0 18px 40px -24px rgba(90,58,168,.32); opacity: 0; animation: skIn .2s ease forwards .3s; }
.cf-card.is-sk .cf-media { background: linear-gradient(100deg, #efe6f8 30%, #f7f1fc 50%, #efe6f8 70%); background-size: 200% 100%; animation: sk 1.3s ease-in-out infinite; }
.cf-card.is-sk .cf-foot { height: 74px; }
@keyframes sk { to { background-position: -200% 0; } }
@keyframes skIn { to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  /* sin animar pero VISIBLES (matar animation mata también el fade-in → opacity 0 eterno) */
  .cf-card.is-sk, .presg-it.is-sk, .cf-card.is-sk .cf-media, .presg-it.is-sk .presg-media { animation: none; }
  .cf-card.is-sk, .presg-it.is-sk { opacity: 1; }
}

/* ============ Los más elegidos — rail de productos REALES (top por ventas) ============
   La sección la revela home.js (renderTop) solo si hay ≥3 productos con ventas: por eso la
   guardia de `hidden` va en ESTE mismo commit (`.sec` declara padding, no display, pero la
   regla del repo es explícita: elemento que el JS alterna con `hidden` lleva su guardia). */
/* padding-bottom 0: el aire hasta el puente lo pone el MARGEN del puente, y así es idéntico
   al de abajo. Con el padding de .sec puestos los dos, arriba medía 148px y abajo 52. */
.sec-top { padding-top: clamp(10px, 1.6vw, 24px); padding-bottom: 0; }
/* z-index 2 (no el 1 de `.sec`): con padding-bottom 0, la sombra de las tarjetas (y en ≤900 el
   carril, que sangra hacia abajo con margen negativo) cae sobre `.sec-pres`, que va DESPUÉS en el
   DOM con el mismo z-index 1 y fondo blanco — en empate gana el orden y la tapaba (trampa de «una
   sección posterior con el mismo z-index»). Se sube la SECCIÓN, no la tarjeta. */
.sec-top { z-index: 2; }
.sec-top[hidden] { display: none !important; }
/* Desktop: grilla de 4. Móvil/tablet: rail horizontal con scroll-snap (mismo gesto que el resto
   de la web y sin robarle alto a la pantalla). */
/* El ancho se limita a 1560px para que las 4 tarjetas midan como las de categorías (~330px
   a 1920) en vez de 420. El límite va en el .wrap de la sección para que el encabezado y
   el rail sigan alineados. */
.sec-top .wrap { max-width: 1560px; }
.top-rail { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: clamp(14px, 1.5vw, 26px); }
.tp-card { position: relative; isolation: isolate; --tp-r: clamp(18px, 1.6vw, 26px); display: flex; flex-direction: column;
  background: var(--card); border: 1px solid #ececf0; border-radius: var(--tp-r);
  box-shadow: var(--shadow-sm); transition: transform var(--t-sheet) var(--ease-out), box-shadow var(--t-sheet) var(--ease-out), border-color var(--t-sheet) var(--ease-out); }
/* hover que ELEVA ⇒ área de hit estable (::after inset, z-index -1 para no tapar el contenido).
   ⚠️⚠️ La tarjeta llevaba `overflow: hidden` (para recortar la foto contra su esquina redondeada) y
   eso SE COMÍA su propia franja: un ::after con inset NEGATIVO queda fuera de la caja de relleno y
   el recorte lo borra entero, así que la franja no existía en pantalla y el parpadeo seguía tal cual
   (Jean 2026-09-21, dos veces, la segunda con captura). No se ve leyendo la hoja —la regla del
   ::after está ahí, perfecta— y `getBoundingClientRect` tampoco sirve: un pseudo-elemento no tiene
   rect propio. Se caza sondeando con `elementFromPoint` unos píxeles FUERA del borde: devolvía la
   sección, nunca la tarjeta. Es la misma trampa que ya obligó a mover la franja al <li> en
   `.guide-peek` y la que `.pp-pcard` evita recortando en su `-media`, no en la tarjeta: hoy el
   redondeo de la foto vive en `.tp-media` (menos 1px del borde) y la tarjeta no recorta nada.
   ⚠️ Con `inset:-6px` fijo e igual a lo que sube la tarjeta, la franja PRODUCE el parpadeo en vez de
   evitarlo: al salir, la tarjeta baja con transición y el borde vuelve a alcanzar el cursor, que la
   levanta otra vez. Por eso `isolation` SIEMPRE (sin ella, un z-index:-1 solo es alcanzable mientras
   la tarjeta tiene transform) e HISTÉRESIS — franja chica en reposo (3px, lo que ENCIENDE) y grande
   levantada (lo que MANTIENE encendido), con el extra abajo = lateral + los 6px que sube. El lateral
   se queda por debajo de la mitad del gap (14px mínimo) o dos vecinas se roban el hover. */
.tp-card::after { content: ""; position: absolute; inset: -4px; z-index: -1; border-radius: inherit; }
.tp-card:hover::after { inset: -5px -5px -11px; }
.tp-card:hover { transform: translateY(-6px); box-shadow: var(--shadow); border-color: rgba(124,79,208,.22); }
.tp-card:active { transform: translateY(-2px) scale(.99); }
.tp-card:focus-visible { outline: 2px solid var(--violet-500); outline-offset: 3px; }
/* el recorte de la foto vive AQUÍ, no en la tarjeta (ver arriba): −1px por el borde de la tarjeta,
   o el fondo asoma como un hilo claro en las dos esquinas de arriba. */
.tp-media { position: relative; display: block; aspect-ratio: 4 / 3; overflow: hidden;
  border-radius: calc(var(--tp-r) - 1px) calc(var(--tp-r) - 1px) 0 0;
  background: linear-gradient(135deg, var(--pc, #c4b5fd) 0%, #fff 100%); }
.tp-media img { width: 100%; height: 100%; object-fit: cover; transition: transform .5s cubic-bezier(.16,1,.3,1); }
.tp-card:hover .tp-media img { transform: scale(1.05); }
.tp-emoji { position: absolute; inset: 0; display: grid; place-items: center; font-size: clamp(38px, 4vw, 64px); }
/* Espera del motor de la tienda (carga diferida) al abrir el PDP: la tarjeta queda inerte y la ESFERA
   (home.js la inyecta en .tp-media) asoma a los ~300 ms — una apertura rápida jamás la muestra. */
.tp-card.is-wait { pointer-events: none; }
/* «Más vendido» = la MISMA pastilla de la tarjeta de la tienda (`.pp-pcard-flag`, posible-pedido.css):
   neutra, sin icono ni sombra — mismo concepto, mismas palabras y mismo dibujo (Jean 2026-09-30). */
.tp-badge { position: absolute; top: 10px; left: 10px; z-index: 2; display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 9px; border-radius: var(--ctl-r); background: var(--fill-soft); color: var(--ink-2);
  font-family: "Nunito Sans", sans-serif; font-size: var(--fs-xs); font-weight: 500; box-shadow: none; pointer-events: none; }
.tp-body { display: flex; flex-direction: column; gap: 4px; padding: clamp(13px, 1.1vw, 20px) clamp(14px, 1.2vw, 22px) clamp(15px, 1.3vw, 22px); }
/* Estilo de la tarjeta de la TIENDA (Jean 2026-09-30): la categoría es contexto → gris, sin mayúsculas
   ni tracking, tamaño de nivel 4; el nombre en tinta y el precio en tinta y negrita (el violeta es para
   actuar/seleccionar/enfocar, no para leer). --muted mide 5.05:1 sobre blanco. */
.tp-cat { font: 500 var(--fs-l4)/1.2 "Nunito Sans", sans-serif; color: var(--muted); }
.tp-name { font-family: "Fredoka", sans-serif; font-weight: 600; color: var(--ink); line-height: 1.2;
  font-size: clamp(16px, 1.15vw, 26px);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.tp-price { margin-top: 4px; font-family: "Fredoka", sans-serif; font-weight: 700; color: var(--ink);
  font-size: clamp(16px, 1.2vw, 27px); font-variant-numeric: tabular-nums; }
.tp-price i { font-style: normal; font-family: "Nunito Sans", sans-serif; font-weight: 400;
  font-size: .62em; color: var(--muted); margin-right: 4px; }
.tp-was { color: var(--muted); font-weight: 700; font-size: .72em; margin-left: 4px; }
@media (max-width: 1180px) and (min-width: 901px) {
  .top-rail { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  /* 4 productos en 3 columnas dejan una fila coja: aquí se muestran 3. El cuarto sigue en el
     DOM y el rail móvil lo desliza. */
  .top-rail > :nth-child(n+4) { display: none; }
}
@media (max-width: 900px) {   /* tier tablet/móvil de la web pública (≤900), Tanda 4b */
  /* rail horizontal: se ve media tarjeta de más, que es lo que comunica «hay más». El margen
     negativo sangra hasta el borde del viewport y el padding devuelve el aire del .wrap. */
  /* Aire de la sombra = padding + margen negativo que lo COMPENSA exacto (patrón de `.rev-row`): un
     `overflow-x:auto` recorta también en vertical, y con 22px abajo la sombra se cortaba a ~14px
     (medido). Arriba 20 − 16 = los 4 de antes y abajo 56 − 44 = los 12 de antes: el carril no se
     mueve de sitio. 56px abajo caben `--shadow-sm` y el `--shadow` del :hover (blur 60, sin elevar). */
  .top-rail { display: flex; overflow-x: auto; overflow-y: hidden; scroll-snap-type: x mandatory; gap: 12px;
    margin-inline: calc(var(--gut, 20px) * -1); margin-block: -16px -44px; padding: 20px var(--gut, 20px) 56px;
    /* sin scroll-padding el snap pega la tarjeta al borde del scrollport y se COME el aire */
    scroll-padding-inline: var(--gut, 20px);
    -webkit-overflow-scrolling: touch; scrollbar-width: none; }
  .top-rail::-webkit-scrollbar { display: none; }
  .tp-card { flex: 0 0 min(62vw, 260px); scroll-snap-align: start; }
  .tp-card:hover { transform: none; }
  /* Arrastre con RATÓN (home.js, `topDrag`): el dedo sigue por scroll nativo con inercia. Durante el
     arrastre se suelta el snap — con `mandatory`, escribir scrollLeft pelea contra él — y al soltar
     vuelve y el navegador asienta la tarjeta. */
  .top-rail { cursor: grab; user-select: none; -webkit-user-select: none; }
  .top-rail.is-drag { cursor: grabbing; scroll-snap-type: none; }
}

/* ============ Línea puente: producto ↔ presentación ============ */
/* El aire de arriba lo aportaba el padding-top de .sec-pres (104px) y el de abajo solo este
   margen (48px): 124 vs 28 medidos. Ahora la sección arranca sin padding y el puente pone los
   DOS márgenes, así que son iguales por construcción (obs Jean 2026-08-31). */
.sec-bridge { display: flex; align-items: center; justify-content: center; gap: clamp(16px, 2.4vw, 46px);
  margin: clamp(26px, 3.2vw, 52px) auto; max-width: 1100px; text-align: center;
  font-family: "Fredoka", sans-serif; font-weight: 500; color: var(--ink);
  font-size: clamp(17px, 1.5vw, 32px); line-height: 1.35; text-wrap: balance; }
.sec-bridge b { font-weight: 600; color: var(--pink-ink); }
.sec-bridge .sb-arr { flex: none; width: clamp(30px, 3vw, 54px); height: auto; color: var(--pink); opacity: .85; }
@media (max-width: 760px) { .sec-bridge .sb-arr { display: none; } }

/* ============ Violeta en números — solo métricas, compacto y centrado (sin banda ni cajas) ============ */
/* El aire visible NO es solo el de esta sección: se suma al de la vecina. Antes daba 164 arriba
   (104 del pie de Presentaciones + 60) contra 90 abajo (60 + 30 de Personaliza). Se igualan
   recortando los dos vecinos al mismo valor (obs Jean 2026-08-31). */
.sec-stats { background: none; padding: clamp(30px, 4vw, 60px) 0; }
.sec-pres { padding-bottom: clamp(30px, 4vw, 60px); }
/* fila ÚNICA centrada (sin wrap): los 4 caben; el padding en vw hace el bloque compacto */
.sec-stats .stats-grid { display: flex; justify-content: center; align-items: center; gap: 0;
  max-width: 960px; margin: 0 auto; }
/* El JS alterna esta tarjeta con `hidden` (sin reseñas no se muestra): la guardia va en el MISMO
   commit — `.stat-card` es item flex y basta con que algún día se le declare un `display` propio
   para que el atributo deje de surtir efecto. */
.stat-card[hidden] { display: none !important; }
.stat-card { position: relative; background: none; border: 0; box-shadow: none; text-align: center;
  padding: clamp(6px, 1vw, 12px) clamp(16px, 2.6vw, 42px); }
.stat-card.in { transition: opacity .9s var(--p3-out) var(--d), transform 1.1s var(--back12) var(--d); }
/* divisor vertical sutil entre métricas (no antes de la primera; se oculta al apilar en móvil) */
.stat-card + .stat-card::before { content: ""; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  width: 1px; height: clamp(40px, 4vw, 58px); background: #e7ddf3; }
.stat-card b { display: block; font-family: "Fredoka", sans-serif; font-weight: 700; line-height: 1;
  font-size: clamp(32px, 3.4vw, 58px); color: var(--violet-600); font-variant-numeric: tabular-nums; }
.stat-card small { display: block; margin-top: 8px; color: var(--muted); font-weight: 700; font-size: clamp(13px, 1vw, 17px); white-space: nowrap; }
@media (max-width: 760px) {
  .sec-stats .stats-grid { flex-wrap: wrap; max-width: 420px; gap: clamp(20px, 6vw, 30px) 0; }
  .stat-card { flex: 0 0 50%; padding: 6px 8px; }
  .stat-card + .stat-card::before { display: none; }   /* al apilar 2×2 el divisor estorba */
}

/* ============ Personaliza el tuyo (timeline vertical + video) ============ */
/* Banda crema a TODO el ancho, solo para esta sección, con bordes ondeados. Las olas son
   pseudo-elementos con un SVG inline (data URI): cero peticiones extra y se estiran a cualquier
   ancho con `background-size: 100% 100%`. Van en BLANCO porque las secciones vecinas (stats
   arriba, Sobre mí abajo) no traen fondo propio y heredan el blanco de <main>.
   El -1px de top/bottom evita la costura de subpíxel entre la ola y el borde de la banda. */
/* `overflow-x: clip` (no `hidden`: no crea contenedor de scroll y no rompe el sticky de nadie):
   la mancha ::before del marco está rotada y sobresale del ancho de su columna. Un pseudo-
   elemento NO aparece en getBoundingClientRect del elemento, así que el desborde no se ve
   auditando nodos: solo se caza intentando hacer scroll horizontal de verdad. Medido: 8px
   de scroll real a 1024px. */
.sec-perso { position: relative; background: var(--cream); overflow-x: clip;
  padding: clamp(58px, 7vw, 108px) 0; margin: clamp(18px, 2.4vw, 36px) 0; }
.sec-perso::before, .sec-perso::after {
  content: ""; position: absolute; left: 0; right: 0; height: clamp(22px, 3.2vw, 54px); z-index: 1;
  pointer-events: none;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 60' preserveAspectRatio='none'%3E%3Cpath fill='%23ffffff' d='M0 0h1440v24c-240 34-480-14-720 6S240 62 0 32Z'/%3E%3C/svg%3E") no-repeat center / 100% 100%; }
.sec-perso::before { top: -1px; }
.sec-perso::after { bottom: -1px; transform: scaleY(-1); }
/* Sin la banda lavanda (obs Jean 2026-08-31): el panel es solo la REJILLA. Al perder el relleno
   también se retiró el `overflow:hidden` que lo recortaba, así que las decoraciones que salían
   por los bordes (sparks, corazón colgante, chips) ahora se contienen con el padding lateral. */
/* ===== «Personaliza el tuyo» — banda de 3 columnas (rediseño 2026-09-01, mock de Jean) =====
   Izquierda: título + firma manuscrita + CTA · centro: los 3 pasos EN HORIZONTAL con flechas ·
   derecha: el video, que CONSERVA su 16/10 (pedido explícito). Los pasos son <ol>/<li> con <h3>
   y <p> REALES: los iconos son SVG decorativos con aria-hidden, así que ni una palabra se
   convierte en imagen y el texto sigue contando para SEO. */
.perso-panel { position: relative; background: none; border: 0; box-shadow: none; border-radius: 0;
  padding: clamp(6px, 1vw, 18px) clamp(0px, 1vw, 22px);
  display: grid; grid-template-columns: minmax(226px, .80fr) minmax(0, 1.92fr) minmax(310px, 1.62fr);
  gap: clamp(24px, 3vw, 54px); align-items: center; }
.perso-left { position: relative; z-index: 1; min-width: 0; }
.perso-h2-heart { color: var(--pink); font-weight: 400; }
/* Firma manuscrita con sus corazones, como el mock: par pequeño a la izquierda (rosa + violeta)
   y uno grande al final de la línea subrayada. Son decorativos → `aria-hidden` en el markup. */
.perso-script { position: relative; margin: clamp(10px, 1.2vw, 18px) 0 clamp(20px, 2.4vw, 32px);
  font-family: "Caveat", cursive; font-weight: 700; line-height: 1.14;
  font-size: clamp(17px, 1.24vw, 29px); color: var(--ink); padding-left: clamp(20px, 1.6vw, 32px); }
.psc-l1, .psc-l2 { display: block; }
.psc-l2 { padding-left: clamp(6px, .7vw, 16px); }
.psc-h { display: inline-block; color: var(--pink); }
.psc-h svg { width: 100%; height: auto; display: block; fill: currentColor; }
.psc-h--v { color: var(--violet-400); }
.psc-hearts--l { position: absolute; left: 0; top: .28em; display: grid; gap: 2px; }
.psc-hearts--l .psc-h { width: clamp(9px, .72vw, 14px); }
.psc-hearts--l .psc-h--v { margin-left: clamp(5px, .5vw, 10px); }
.psc-h--big { width: clamp(15px, 1.15vw, 24px); vertical-align: -.15em; margin-left: 6px; }
.perso-script .ps-u { position: relative; display: inline-block; }
.perso-script .ps-u::after { content: ""; position: absolute; left: 1%; right: 1%; bottom: -.12em;
  height: .085em; border-radius: 999px; background: var(--pink); }

/* ---- los 3 pasos, en fila ---- */
.perso-steps { display: grid; grid-template-columns: 1fr auto 1fr auto 1fr;
  align-items: start; gap: clamp(10px, 1.3vw, 26px); margin: 0; padding: 0; list-style: none; }
.ps-step { min-width: 0; text-align: center; }
.ps-art { position: relative; display: inline-grid; place-items: center;
  width: clamp(76px, 6.2vw, 118px); aspect-ratio: 1; margin-bottom: clamp(10px, 1vw, 16px); }
/* Mancha suave detrás del icono: en el mock es un borrón PÁLIDO y DESCENTRADO que asoma por un
   lado, no un círculo saturado detrás. Va muy diluida para no competir con el trazo. */
.ps-blob { position: absolute; inset: -4% -10% 4% 4%; border-radius: 46% 54% 58% 42% / 52% 44% 56% 48%;
  transform: rotate(-8deg); }
.ps-blob--v { background: color-mix(in srgb, var(--violet-200) 30%, transparent); }
.ps-blob--p { background: color-mix(in srgb, var(--paso-rosa) 28%, transparent); }
/* el 2º paso lleva la mancha volcada al otro lado, como en el mock */
.ps-step:nth-of-type(2) .ps-blob { inset: -2% 4% 6% -10%; transform: rotate(9deg); }
/* ICONOS: los tres se generaron en UNA SOLA imagen y luego se recortaron. Ese es el punto: tres
   generaciones independientes no comparten grosor de trazo ni paleta (el papel salió con la mitad
   de grosor que la caja y cada corazón de un rosa distinto), pero dentro de un mismo dibujo sí.
   Del recorte solo se rotó el TONO de la tinta a violeta; la textura del rotulador queda intacta. */
.ps-ico { position: relative; z-index: 1; display: block; width: 92%; }
.ps-ico img { width: 100%; height: auto; display: block; }
/* el número va en su propia ficha, arriba a la izquierda del icono (como el mock) */
/* Número BLANCO sobre los tonos del mock (decisión de Jean 2026-09-01, pedida tres veces). Deja
   constancia de lo medido: blanco sobre #a98fe6 da 2,71:1 y sobre #f3a9c6 da 1,86:1, por debajo
   del 4,5:1 de AA. Se sostiene porque el número es un ordinal decorativo —el <h3> del paso dice
   lo mismo en texto legible— pero si algún día hay que subirlo, el cambio es el `color` de
   `.ps-num`, no los fondos. */
.ps-num { position: absolute; z-index: 2; top: -2%; left: -6%;
  width: clamp(22px, 1.75vw, 34px); aspect-ratio: 1; border-radius: 50%;
  display: grid; place-items: center; color: #fff;
  font-family: "Fredoka", sans-serif; font-weight: 600; font-variant-numeric: tabular-nums;
  font-size: clamp(12px, .92vw, 18px); line-height: 1;
  box-shadow: 0 6px 14px -8px rgba(43, 22, 92, .4); }
.ps-num--v { background: var(--violet-400); }
.ps-num--p { background: var(--paso-heart); }
/* `min-height` de DOS líneas: basta con que un título envuelva (p. ej. «Diseño y propuesta»)
   para que su descripción baje y la fila se lea torcida. Reservando el alto, las tres
   descripciones arrancan a la misma altura envuelva quien envuelva. */
.ps-t { margin: 0 0 6px; font-family: "Fredoka", sans-serif; font-weight: 600;
  font-size: clamp(15px, 1.08vw, 25px); color: var(--ink); line-height: 1.15; text-wrap: balance;
  min-height: 2.3em; display: flex; align-items: center; justify-content: center; }
.ps-d { margin: 0; font-size: clamp(13px, .87vw, 19px); line-height: 1.45; color: var(--muted); text-wrap: pretty; }
.ps-arrow { align-self: start; margin-top: clamp(30px, 3.1vw, 58px); color: var(--violet-500); }
.ps-arrow svg { width: clamp(24px, 2.3vw, 44px); height: auto; display: block; }

.perso-cta-row { display: flex; align-items: center; gap: clamp(16px, 2vw, 28px); flex-wrap: wrap; }
.perso-spark, .perso-mini-heart { position: absolute; pointer-events: none; z-index: 0; }
.perso-spark { color: var(--violet-400); }
.perso-spark.s1 { top: 30%; right: -4px; font-size: 20px; } .perso-spark.s2 { top: 46%; right: 9%; font-size: 13px; }
.perso-mini-heart { color: #cdb4f0; }
.perso-mini-heart.mh1 { bottom: 6%; left: -6px; font-size: 20px; } .perso-mini-heart.mh2 { top: 1%; left: 33%; font-size: 14px; }
/* El padding-left es el CANAL donde vive la nota manuscrita. Un elemento absoluto se coloca
   contra la caja de PADDING de su ancestro posicionado, así que `left:0` cae justo al inicio del
   canal y la foto —que sí respeta el padding— nunca lo invade. */
.perso-right { position: relative; min-width: 0; padding-left: clamp(0px, 8vw, 132px); }
/* MARCO tipo polaroid del mock: borde blanco grueso, giro leve y cinta lavanda arriba, sobre una
   mancha violeta. El video conserva su 16/10 DENTRO del marco (pedido explícito de Jean). */
.perso-frame { position: relative; background: #fff;
  padding: clamp(7px, .7vw, 12px) clamp(7px, .7vw, 12px) clamp(16px, 1.5vw, 26px);
  border-radius: 5px; transform: rotate(1.6deg);
  box-shadow: 0 22px 48px -22px rgba(43, 22, 92, .45), 0 0 0 1px rgba(124, 79, 208, .07); }
/* la mancha va DETRÁS (z-index -1) para no interceptar el video ni la nota */
.perso-frame::before { content: ""; position: absolute; z-index: -1; inset: -7% -9% -8% -5%;
  background: color-mix(in srgb, var(--violet-300) 34%, transparent);
  border-radius: 52% 48% 44% 56% / 46% 54% 46% 54%; transform: rotate(-6deg); }
.perso-tape { position: absolute; z-index: 2; top: clamp(-9px, -.7vw, -6px); right: 14%;
  width: clamp(46px, 4.4vw, 80px); height: clamp(15px, 1.35vw, 24px);
  background: color-mix(in srgb, var(--violet-400) 62%, transparent);
  transform: rotate(-4deg); border-radius: 2px; }
.perso-media { position: relative; border-radius: 3px; overflow: hidden; aspect-ratio: 16/10;
  background: #e7d9f4; }
.perso-vid { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center 62%; display: block; }
/* la nota vive FUERA de la foto (como el mock), no encima */
/* La nota se sale a la izquierda de la columna (right:100%), que es el hueco entre los pasos y
   la foto: así la foto usa TODO el ancho de su columna en vez de repartirlo. */
.perso-note { position: absolute; z-index: 2; left: 0; top: 50%; transform: translateY(-62%);
  width: clamp(90px, 7.4vw, 120px); padding-right: clamp(6px, .6vw, 12px); text-align: right;
  font-family: "Caveat", cursive; font-weight: 700; font-size: clamp(16px, 1.36vw, 30px);
  line-height: 1.08; color: var(--ink); pointer-events: none; }
.perso-note .nh { display: inline-block; width: clamp(13px, 1.05vw, 22px); color: var(--pink); vertical-align: -.12em; }
.perso-note .nh svg { width: 100%; height: auto; display: block; fill: currentColor; }
.perso-note-arrow { display: block; width: clamp(44px, 3.8vw, 68px); height: auto;
  margin: 6px 0 0 auto; color: var(--pink); opacity: .8; }

/* entrada escalonada del arte de cada paso (fill BACKWARDS para no pelear con nada) */
.perso-panel.in .ps-art { animation: stepPop .55s cubic-bezier(.16,1,.3,1) backwards .15s; }
.perso-panel.in .ps-step:nth-of-type(2) .ps-art { animation-delay: .28s; }
.perso-panel.in .ps-step:nth-of-type(3) .ps-art { animation-delay: .41s; }
@keyframes stepPop { from { opacity: 0; transform: scale(.55) translateY(10px); } to { opacity: 1; transform: none; } }
/* la flecha se dibuja sola hacia la derecha, insinuando la secuencia */
.perso-panel.in .ps-arrow { animation: psArrow .5s var(--p3-out) backwards .34s; }
@keyframes psArrow { from { opacity: 0; transform: translateX(-8px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .perso-panel.in .ps-art, .perso-panel.in .ps-arrow { animation: none; opacity: 1; transform: none; }
}

/* Bajo 1180px ya no hay hueco a la izquierda de la foto → la nota vuelve DENTRO, arriba a la
   izquierda, con su sombra de texto para leerse sobre el video. */
@media (max-width: 1180px) {
  .perso-right { padding-left: 0; }
  .perso-note { left: 14px; top: 16px; transform: none; width: auto; padding: 0;
    text-align: left; text-shadow: 0 1px 10px rgba(255,255,255,.85); }
  .perso-note-arrow { margin: 4px auto 0 0; transform: scaleX(-1); }
}
/* ≤1180px las 3 columnas no caben: título+video arriba, los pasos en su propia fila completa. */
@media (max-width: 1180px) {
  .perso-panel { grid-template-columns: minmax(0, 1fr) minmax(240px, .95fr); }
  .perso-left { grid-column: 1; }
  .perso-right { grid-column: 2; grid-row: 1; }
  .perso-steps { grid-column: 1 / -1; margin-top: clamp(18px, 2.4vw, 30px); }
}
/* ≤820px todo en una columna y los pasos se APILAN: tres columnas de texto a este ancho
   quedarían en dos palabras por línea. La flecha horizontal deja de tener sentido → fuera. */
@media (max-width: 820px) {
  .perso-panel { grid-template-columns: 1fr; }
  .perso-left, .perso-right, .perso-steps { grid-column: 1; }
  .perso-right { grid-row: auto; }
  .perso-steps { grid-template-columns: 1fr; gap: clamp(14px, 3vw, 22px); }
  .ps-arrow { display: none; }
  /* icono a la izquierda y texto a la derecha: se lee como una lista, no como tarjetas sueltas */
  .ps-step { display: grid; grid-template-columns: clamp(56px, 15vw, 74px) 1fr;
    column-gap: 14px; align-items: center; text-align: left; }
  .ps-art { width: 100%; margin: 0; grid-row: 1 / span 2; }
  .ps-t { align-self: end; min-height: 0; display: block; }
  .ps-d { align-self: start; }
}

/* ============ Presentaciones para regalar — vitrina flotante (presg-) ============ */
.sec-pres { padding-top: 0; background: #fff; overflow-x: hidden; overflow-x: clip; }
.presg-title { margin: 0; }
.presg-sparkle { display: inline-flex; width: 1em; height: 1em; color: var(--gold-500); vertical-align: -.08em; }
.presg-sparkle svg { width: 100%; height: 100%; }
/* Tarjeta «Todas las presentaciones incluyen» (a la derecha del título, en sec-head-row) */
.presg-incl { flex: 1 1 320px; max-width: 460px; display: flex; align-items: center; gap: clamp(12px, 1.1vw, 18px);
  padding: clamp(14px, 1.3vw, 20px) clamp(16px, 1.5vw, 24px); border-radius: clamp(16px, 1.6vw, 22px);
  background: color-mix(in srgb, var(--violet-500) 9%, #fff);
  border: 1px solid color-mix(in srgb, var(--violet-500) 18%, transparent); }
.presg-incl-ic { flex: none; width: clamp(38px, 3vw, 48px); aspect-ratio: 1; display: grid; place-items: center;
  border-radius: 50%; color: var(--violet-600); background: color-mix(in srgb, var(--violet-500) 16%, #fff); }
.presg-incl-ic svg { width: 52%; height: 52%; }
.presg-incl-txt { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.presg-incl-txt strong { color: var(--ink); font-weight: 700; font-size: clamp(14px, 1vw, 18px); }
.presg-incl-txt span { color: var(--ink-2); font-size: clamp(13px, .92vw, 16px); }
.presg-incl-card { flex: none; width: clamp(34px, 2.8vw, 46px); color: var(--violet-500); }
.presg-incl-card svg { width: 100%; height: 100%; }

/* COVERFLOW de presentaciones — espejo del de categorías (full-bleed, la central MÁS GRANDE,
   drag, flechas, dots, auto-avance). Las variables --tx/--sc/--ry/--op/--bl las setea home.js. */
.presg-flow { position: relative; width: 100vw; margin-left: calc(50% - 50vw); padding: 30px 0 10px;
  /* 14.2vw, no 19vw: la tarjeta de presentación es más ALTA que la de categoría (1.55 del
     ancho contra 1.26), así que con el mismo ancho se veía mucho más grande. Este valor
     iguala el ALTO de las dos familias (obs Jean 2026-08-31). */
  --pf-cardw: clamp(190px, 14.2vw, 300px); --pf-unit: calc(var(--pf-cardw) * .95); }
.presg-flow.in .presg-stage { animation: heroRise .6s cubic-bezier(.16,1,.3,1) backwards; }
/* Con las tarjetas más chicas, unas flechas ancladas al borde del escenario (que es full-bleed)
   quedaban a media pantalla del grupo. Se colocan RELATIVAS al centro, justo fuera de la
   tarjeta lateral, con un piso para que nunca se salgan en pantallas angostas. */
.presg-flow .cf-nav.prev { left: max(clamp(14px, 3vw, 72px), calc(50% - var(--pf-cardw) * 1.7)); }
.presg-flow .cf-nav.next { right: max(clamp(14px, 3vw, 72px), calc(50% - var(--pf-cardw) * 1.7)); }
/* MODO FILA (lo enciende home.js cuando hay 5 presentaciones o menos y ancho de sobra): deja de
   ser un escenario 3D con hijos absolutos y pasa a una fila centrada con TODAS a la vista.
   `!important` en transform/opacity/filter porque el coverflow las escribe en línea. */
.presg-stage.is-flat { position: static; height: auto !important; perspective: none;
  display: flex; flex-wrap: wrap; justify-content: center; align-items: stretch;
  gap: clamp(14px, 1.6vw, 26px); cursor: default; padding: 10px 0; }
.presg-stage.is-flat .presg-it { position: relative; top: auto; left: auto;
  transform: none !important; opacity: 1 !important; filter: none !important; cursor: default; }
/* sin coverflow no hay a dónde navegar */
.presg-flow:has(.is-flat) .cf-nav { display: none; }
/* Mismo caso que .cf-stage: tarjetas absolutas centradas y ningún desborde vertical que recortar. */
.presg-stage { position: relative; width: 100%; height: calc(var(--pf-cardw) * 1.55 + 60px);
  overflow: visible;   /* mismo caso que .cf-stage: el clip de un solo eje ignora su clip-margin */
  perspective: 1200px; perspective-origin: 50% 42%;
  touch-action: pan-y; user-select: none; -webkit-user-select: none; cursor: grab; outline: none; }
.presg-stage:active { cursor: grabbing; }
.presg-it { position: absolute; top: 50%; left: 50%; width: var(--pf-cardw);
  --tx: 0; --sc: 1; --ry: 0deg; --op: 1; --bl: 0px;
  transform: translate(-50%, -50%) translateX(calc(var(--pf-unit) * var(--tx))) scale(var(--sc)) rotateY(var(--ry));
  opacity: var(--op); filter: blur(var(--bl));
  display: flex; flex-direction: column; align-items: center; text-align: center; cursor: pointer;
  background: var(--card); border-radius: 22px; border: 1px solid rgba(124,79,208,.07);
  box-shadow: 0 18px 40px -22px rgba(90,58,168,.4); outline: none; }
/* Mismo caso que .cf-card: la capa permanente ensuciaba `.presg-title`. Solo mientras gira. */
.presg-stage.pf-animate .presg-it { will-change: transform, opacity, filter;
  transition: transform .5s cubic-bezier(.22,1,.36,1),
  opacity .5s ease, filter .5s ease, box-shadow .4s ease; }
.presg-it.is-center { cursor: default;
  box-shadow: 0 34px 70px -26px rgba(90,58,168,.6), 0 0 0 2px var(--violet-500); }
.presg-it:focus-visible { box-shadow: 0 18px 40px -22px rgba(90,58,168,.4),
  0 0 0 3px color-mix(in srgb, var(--violet-500) 45%, transparent); }
/* media 1:1 en BLANCO (la sombra de contacto del icono pone el «suelo») */
.presg-media { position: relative; width: 100%; aspect-ratio: 1; border-radius: 22px 22px 0 0; }
/* sombra de contacto en el «suelo»: se queda quieta y se encoge cuando el icono levita */
.presg-media::after { content: ''; position: absolute; left: 50%; bottom: 6%; width: 56%; height: 8%;
  border-radius: 50%; background: radial-gradient(50% 50% at 50% 50%, rgba(64,38,110,.30), transparent 74%);
  transform: translateX(-50%); transition: transform .5s var(--p3-out), opacity .5s ease; }
.presg-it:hover .presg-media::after, .presg-it:focus-visible .presg-media::after {
  transform: translateX(-50%) scale(.7); opacity: .55; }
/* el icono flota en 3 capas y al saltar SOBRESALE del borde superior de la card:
   fl = levitación idle (animation) · tilt = imán al cursor (JS) · img = salto al hover (transition) */
.presg-fl { position: absolute; inset: 3%; display: block; animation: presgFloat 4s ease-in-out infinite alternate; }
.presg-it:nth-child(2) .presg-fl { animation-delay: -1.3s; }
.presg-it:nth-child(3) .presg-fl { animation-delay: -2.6s; }
.presg-it:nth-child(4) .presg-fl { animation-delay: -.7s; }
.presg-it:nth-child(5) .presg-fl { animation-delay: -2s; }
.presg-it:nth-child(6) .presg-fl { animation-delay: -3.2s; }
.presg-it:nth-child(7) .presg-fl { animation-delay: -1.7s; }
@keyframes presgFloat { from { transform: translateY(3px); } to { transform: translateY(-5px); } }
.presg-tilt { position: absolute; inset: 0; display: block; transition: transform .45s cubic-bezier(.22,1,.36,1);
  will-change: transform; }
.presg-tilt img { width: 100%; height: 100%; object-fit: contain; -webkit-user-drag: none;
  filter: drop-shadow(0 10px 14px rgba(90,58,168,.22));
  transition: transform .55s cubic-bezier(.3,1.6,.4,1); }
.presg-it:hover .presg-tilt img, .presg-it:focus-visible .presg-tilt img {
  transform: translateY(-6.5%) rotate(-4deg) scale(1.05); }
/* sparkles que brotan al acercar el mouse */
.presg-spk { position: absolute; z-index: 2; font-size: clamp(13px, 1.1vw, 19px); line-height: 1;
  color: var(--gold-500); opacity: 0; transform: scale(.2) rotate(-30deg); pointer-events: none;
  transition: opacity .3s ease, transform .5s var(--back12); }
.presg-spk.k1 { top: 6%; left: 8%; }
.presg-spk.k2 { top: 0; right: 12%; color: var(--violet-500); font-size: .8em; transition-delay: 80ms; }
.presg-spk.k3 { bottom: 18%; right: 0; transition-delay: 150ms; font-size: .75em; }
.presg-it:hover .presg-spk, .presg-it:focus-visible .presg-spk { opacity: 1; transform: scale(1) rotate(0deg); }
/* destacada: badge colgado + CORONITA dorada sobre el icono (el borde violeta ya no es suyo:
   marca a la card CENTRAL/seleccionada) */
.presg-badge { position: absolute; top: 0; left: 50%; transform: translate(-50%, -46%) rotate(-3deg); z-index: 3;
  display: inline-flex; align-items: center; gap: 5px; padding: 5px 12px; border-radius: 999px;
  background: var(--grad); color: #fff; font-weight: 700; font-size: clamp(12px, .82vw, 14px);
  white-space: nowrap; box-shadow: 0 10px 20px -8px rgba(90,58,168,.6); }
.presg-badge svg { width: 13px; height: 13px; flex: none; }
.presg-crown { position: absolute; top: 9%; right: 10%; z-index: 3; width: clamp(26px, 2.2vw, 40px);
  color: var(--gold-500); transform: rotate(16deg);
  filter: drop-shadow(0 4px 8px rgba(160,110,20,.45)); pointer-events: none; }
.presg-crown svg { width: 100%; height: 100%; }
.presg-it:hover .presg-crown { animation: crownBop .6s cubic-bezier(.3,1.6,.4,1); }
@keyframes crownBop { 40% { transform: rotate(8deg) translateY(-16%) scale(1.12); } }
.presg-name { font-family: "Fredoka", sans-serif; font-weight: 600; color: var(--ink); line-height: 1.15;
  font-size: clamp(15px, 1.2vw, 21px); margin: clamp(10px, 1vw, 16px) 10px 0;
  max-width: calc(100% - 20px); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* descripción SIEMPRE visible y de alto FIJO (2 líneas) → todas las cards miden lo mismo */
.presg-desc { margin: 6px 14px 0; color: var(--ink-2); font-weight: 500; line-height: 1.45;
  font-size: clamp(13px, .92vw, 15px); display: -webkit-box; -webkit-line-clamp: 2;
  -webkit-box-orient: vertical; overflow: hidden; min-height: calc(2 * 1.45em); }
.presg-noimg { position: absolute; inset: 0; display: grid; place-items: center;
  font-size: clamp(50px, 5vw, 90px); }
/* skeleton (mientras llega pack_nivel_publico) — misma política de aparición ~300ms (bloque cf-card) */
.presg-it.is-sk { pointer-events: none; opacity: 0; animation: skIn .2s ease forwards .3s; }
.presg-it.is-sk .presg-media { background: linear-gradient(100deg, #f3edf9 30%, #faf7fd 50%, #f3edf9 70%);
  background-size: 200% 100%; animation: sk 1.3s ease-in-out infinite; border-radius: 22px 22px 0 0; }
.presg-sk-l { width: 60%; height: 16px; border-radius: 8px; margin: 14px auto 0; background: #f1eaf8; }
.presg-sk-l.s { width: 38%; height: 24px; border-radius: 999px; margin: 10px auto 16px; }
.presg-price { font-family: "Fredoka", sans-serif; font-weight: 600; font-size: clamp(13px, .95vw, 16px); color: var(--violet-700);
  background: color-mix(in srgb, var(--violet-500) 12%, #fff); border: 1px solid color-mix(in srgb, var(--violet-500) 18%, transparent);
  border-radius: 999px; padding: 6px 15px; margin: clamp(8px, .8vw, 12px) 10px clamp(14px, 1.3vw, 20px); }
.presg-price.presg-free { background: var(--grad); color: #fff; border-color: transparent; }

/* Sin puntero fino (táctil): la levitación idle no aporta y gasta batería */
@media (hover: none) {
  .presg-fl { animation: none; }
}
/* móvil: cards más chicas (el JS cambia a los parámetros M en este mismo breakpoint) */
@media (max-width: 620px) {
  .presg-flow { --pf-cardw: clamp(170px, 46vw, 210px); padding-top: 20px; }
}
@media (max-width: 640px) {
  /* flex:none — si la fila del header apila, el flex-basis:320px se volvería ALTO mínimo */
  .presg-incl { max-width: none; width: 100%; flex: none; }
}
@media (prefers-reduced-motion: reduce) {
  .presg-fl { animation: none; }
  .presg-it:hover .presg-crown { animation: none; }
  .presg-it, .presg-media::after, .presg-tilt, .presg-tilt img, .presg-spk { transition: none; }
  .presg-it:hover .presg-tilt img, .presg-it:focus-visible .presg-tilt img { transform: none; }
  .presg-it:hover .presg-media::after, .presg-it:focus-visible .presg-media::after { transform: translateX(-50%); opacity: 1; }
  .presg-spk { display: none; }
}

/* ============ Sobre mí ============ */
.sobre-title { margin-bottom: clamp(18px, 2.4vw, 28px); }
.sobre-grid { display: grid; grid-template-columns: 1.05fr 1fr; gap: clamp(26px, 4vw, 56px); align-items: center; }
.sobre-img { aspect-ratio: 4/3; border-radius: clamp(18px, 2vw, 26px); box-shadow: var(--shadow-sm); }
.sobre-txt { max-width: 52ch; }
.sobre-txt p { color: var(--ink-2); font-size: clamp(15px, 1.1vw, 25px); margin-bottom: 14px; text-wrap: pretty; }
.sobre-txt .sobre-lead { color: var(--ink); font-weight: 800; font-size: clamp(17px, 1.25vw, 29px); margin-bottom: 16px; }

/* ============ Reseñas (fila de tarjetas) + FAQ centrado ============ */
.sec-social { --review-star:#c49bdc; position: relative; z-index: 2; padding-bottom: clamp(96px, 9vw, 150px); background: none; }
.rev-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 20px; flex-wrap: wrap; margin-bottom: clamp(20px, 2.4vw, 32px); }
.rev-score { display: flex; align-items: center; gap: 14px; }
.rev-score[hidden] { display: none !important; }
.rev-score-t .st .off { color:#e4e4e9; }
.rev-score-n { font-family: "Fredoka", sans-serif; font-weight: 700; font-size: clamp(34px, 2.6vw, 68px); color: var(--ink-2); line-height: 1; }
.rev-score-t { font-size: clamp(13px, .95vw, 21px); font-weight: 700; color: var(--muted); line-height: 1.45; }
.rev-score-t .st { display: flex; gap: 5px; color: var(--review-star); margin-bottom: 6px; }
.rev-score-t .st svg { width: 15px; height: 15px; }
/* FILA de tarjetas (obs Jean 2026-08-31: fuera el marquee vertical). Desktop = grilla de 4;
   ≤980px = rail horizontal con scroll-snap. Nunca hay scroll horizontal del BODY: el rail se
   desborda dentro de sí mismo. */
/* CARRIL en todos los anchos (no grilla): así el contenido puede desbordar y home.js sabe
   cuándo hay más reseñas de las que caben para encender el carrusel. `safe center` centra
   cuando caben pocas SIN dejar la primera fuera de alcance al desbordar (el bug clásico de
   `justify-content:center` con overflow). `scroll-snap` NO se usa a propósito: pelearía con el
   desplazamiento continuo del rAF y daría tirones. */
/* ⚠️ `overflow-x: auto` deja el eje Y en `auto` TAMBIÉN (el CSS no admite un eje recortado y el
   otro visible), y de ahí salían los dos síntomas que reportó Jean el 2026-09-08 en móvil: la
   sombra de las tarjetas cortada (necesita 12px por abajo y solo había 12px justos, que el
   `mask-image` remata en el border-box) y el carril «no tan scrolleable», porque un scroller
   vertical se queda el gesto del dedo aunque no tenga nada que desplazar. Por eso el eje Y va
   `hidden` EXPLÍCITO —como ya hacía `.reels-stage`— y la sombra se gana su aire con padding +
   margen negativo, el patrón del repo: el hueco no altera el ritmo vertical de la sección. */
.rev-row { display: flex; align-items: stretch; justify-content: safe center;
  /* el aire de la sombra se gana con padding + margen negativo simétricos (un `overflow-x:auto`
     recorta TAMBIÉN en vertical). 22px abajo se quedaban cortos en :hover, donde la sombra pasa a
     `--shadow` y baja 34px: la tarjeta levantada se cortaba justo al pasar el mouse. */
  gap: clamp(14px, 1.6vw, 26px); padding: 20px 2px 40px; margin-block: -16px -28px;
  overflow-x: auto; overflow-y: hidden;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
  /* ⚠️ El dedo lo mueve el navegador (`pan-x`), NO el JS: un arrastre por pointer events va 1:1 y
     se frena en seco al soltar — sin inercia, un barrido de pantalla completa apenas avanzaba una
     tarjeta («esta como bugeado que avanza muy poquito», Jean 2026-09-09; medido: 238px de dedo =
     258px de carril). Es lo que ya hacen el coverflow de categorías y los reels en móvil.
     `pan-y` sigue presente para que el gesto vertical siga scrolleando la página. */
  touch-action: pan-x pan-y; }
/* A SANGRE hasta el borde del viewport y con los extremos desvanecidos: así la tarjeta parcial
   de los lados se lee como «sigue habiendo más» y no como una tarjeta cortada por un fallo de
   maquetación (obs Jean 2026-08-31). El desvanecido solo se aplica cuando de verdad rota. */
/* El sangrado llega al BORDE REAL de la pantalla, no al del `.wrap`: con `--wrap` topado en
   1480px el carril terminaba a media pantalla y la última tarjeta quedaba cortada con un vacío
   blanco a su derecha — se leía como maquetación rota (obs Jean 2026-09-01). Ahora el carril
   mide `--vw` (ancho real sin barra de scroll, lo publica home.js) y el `padding-inline`
   devuelve la primera tarjeta a la línea del título: el 50% resuelve contra el ancho de
   contenido del `.wrap`, así que `--vw/2 - 50%` == el margen del título, exacto y sin JS.
   Sin `--vw` (antes del primer frame de JS) el fallback `100%` deja el carril dentro del wrap:
   se pierde el sangrado, nunca aparece scroll horizontal. */
.rev-row.is-carrusel {
  margin-inline: calc(50% - var(--vw, 100%) / 2);
  padding-inline: calc(var(--vw, 100%) / 2 - 50%);
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 clamp(36px, 5vw, 96px), #000 calc(100% - clamp(36px, 5vw, 96px)), transparent 100%);
  mask-image: linear-gradient(to right, transparent 0, #000 clamp(36px, 5vw, 96px), #000 calc(100% - clamp(36px, 5vw, 96px)), transparent 100%); }
.rev-row::-webkit-scrollbar { display: none; }
.rev-row[hidden], .rev-empty[hidden] { display: none !important; }
.rev-row .rev-card { flex: 0 0 clamp(260px, 24vw, 360px); }
/* `user-select:none` es PERMANENTE en el carrusel, no solo durante `.is-drag`: si se activara
   al empezar a arrastrar, el navegador ya habría iniciado la selección y el gesto pintaba media
   reseña de violeta. */
.rev-row.is-carrusel { justify-content: flex-start; cursor: grab; user-select: none; -webkit-user-select: none; }
.rev-row.is-carrusel.is-drag { cursor: grabbing; }
.rev-row.is-drag .rev-card { transform: none; }
.rev-empty { max-width: 820px; margin: 0 auto; display: grid; grid-template-columns: 170px 1fr; align-items: center;
  gap: clamp(20px, 3vw, 38px); padding: clamp(22px, 3vw, 34px); border: 1px solid color-mix(in srgb, var(--violet-400) 28%, transparent);
  border-radius: 24px; background: color-mix(in srgb, var(--violet-100) 58%, var(--card)); box-shadow: var(--shadow-sm); }
.rev-empty img { width: 170px; height: auto; aspect-ratio: auto; object-fit: contain; border-radius: 0; transform: none; }   /* mascota recortada (fondo transparente): sin marco ni giro */
.rev-empty-copy strong { display: block; margin-bottom: 18px; color: var(--ink); font: 600 clamp(20px, 2vw, 30px)/1.18 "Fredoka", sans-serif; text-wrap: balance; }
.rev-empty-copy .btn { min-height: 44px; }
/* ⚠️ SIN `height:100%`: en un flex con `align-items:stretch`, fijar la altura del hijo ANULA el
   estirado y cada tarjeta quedaba con su alto natural (378/322/210/210 medidos). El estirado lo
   hace el contenedor; aquí solo se declara la columna interna. */
.rev-card { position: relative; isolation: isolate; display: flex; flex-direction: column; background: var(--card);
  border: 1px solid #ececf0; border-radius: clamp(18px, 1.5vw, 24px);
  padding: clamp(18px, 1.5vw, 26px) clamp(18px, 1.6vw, 28px) clamp(16px, 1.4vw, 24px);
  box-shadow: var(--shadow-sm); transition: box-shadow .35s, transform .3s cubic-bezier(.16,1,.3,1); }
/* misma franja con histéresis que `.tp-card` (aquí sube 3px, así que abajo 4 + 3) */
.rev-card::after { content: ""; position: absolute; inset: -3px; z-index: -1; border-radius: inherit; }
.rev-card:hover::after { inset: -4px -4px -7px; }
.rev-card:hover { box-shadow: var(--shadow); transform: translateY(-3px); }
.rev-stars { display: flex; gap: 4px; margin-bottom: 12px; }
.rev-stars .on { color: var(--review-star); }
.rev-stars .off { color: #e4e4e9; }
.rev-stars svg { width: clamp(15px, 1vw, 19px); height: clamp(15px, 1vw, 19px); display: block; }
/* la cita crece y empuja la firma al pie: las 4 tarjetas alinean su autoría */
.rev-quote { flex: 1 1 auto; color: var(--ink-2); font-size: clamp(14px, .95vw, 21px); line-height: 1.55; }
.rev-quote::before { content: "\201C"; } .rev-quote::after { content: "\201D"; }
.rev-author { display: flex; align-items: center; gap: 10px; margin-top: clamp(14px, 1.2vw, 20px); }
.rev-ava { width: clamp(30px, 2vw, 40px); height: clamp(30px, 2vw, 40px); border-radius: 50%; flex: none;
  background: var(--grad); color: #fff; display: grid; place-items: center; font-weight: 900;
  font-family: "Fredoka", sans-serif; font-size: clamp(13px, .9vw, 17px); }
.rev-who { min-width: 0; }
.rev-nm { display: block; font-weight: 800; color: var(--ink); font-size: clamp(13.5px, .92vw, 19px); }
.rev-loc { display: block; font-size: clamp(11.5px, .75vw, 15px); color: var(--muted); }
/* «Ver todas las reseñas» = misma píldora que «Ver todas las categorías» (un solo juego de botones) */
.rev-all { align-self: center; }
@media (max-width: 980px) {
  .rev-row { gap: 14px; padding: 18px 2px 34px; margin-block: -14px -24px; }   /* padding-block: aire para la sombra en AMBOS lados */
  .rev-row .rev-card { flex: 0 0 min(78vw, 320px); }
  .rev-card:hover { transform: none; }
}
/* FAQ: una sola columna protagonista, centrada */
.faq-wrap { max-width: 960px; margin: clamp(56px, 5.6vw, 88px) auto 0; }
.faq-title-row { text-align: center; margin-bottom: clamp(22px, 2.6vw, 34px); }
.faq details { background: var(--card); border-radius: 18px; box-shadow: var(--shadow-sm); margin-bottom: 14px; overflow: hidden;
  border: 1px solid rgba(124,79,208,.06); transition: box-shadow var(--t-sheet) var(--ease-out); }
.faq details:hover { box-shadow: var(--shadow); }
.faq summary { padding: clamp(18px, 1.5vw, 24px) clamp(20px, 1.8vw, 28px); font-weight: 800; color: var(--ink); cursor: pointer; list-style: none;
  display: flex; justify-content: space-between; align-items: center; gap: 14px; font-size: clamp(15px, 1.1vw, 25px); }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; flex: none; width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center;
  background: linear-gradient(180deg, #f3ecfd, #ece1fb); border: 1px solid rgba(124,79,208,.14);
  font-size: 21px; color: var(--violet-600); font-weight: 400; line-height: 1; transition: transform var(--t-sheet) var(--ease-out), background var(--t-pop) var(--ease-out); }
.faq details[open] summary::after { transform: rotate(45deg); background: var(--grad); color: #fff; }
.faq p { padding: 0 clamp(20px, 1.8vw, 28px) 20px; color: var(--ink-2); max-width: 68ch; font-size: clamp(14.5px, 1vw, 22px); }
.faq details[open] p { animation: heroRise var(--t-sheet) var(--ease-out) backwards; }
.faq summary:active { transform: scale(.995); }
.faq-cta { text-align: center; margin-top: clamp(24px, 2.6vw, 34px); display: flex; align-items: center; justify-content: center; gap: 16px; flex-wrap: wrap; }
.faq-cta .q { font-weight: 800; color: var(--muted); font-size: clamp(14px, 1vw, 22px); }
@supports (interpolate-size: allow-keywords) {
  :root { interpolate-size: allow-keywords; }
  .faq details::details-content { height: 0; overflow: hidden; transition: height var(--t-sheet) var(--ease-out), content-visibility allow-discrete var(--t-sheet) var(--ease-out); }
  .faq details[open]::details-content { height: auto; }
}

/* ============ Footer compacto — una sola jerarquía, menos saturación visual ============ */
.vc-wordmark { font-family: "Great Vibes", "Satisfy", "Caveat", cursive; font-weight: 400; letter-spacing: -.025em; line-height: 1; }
/* ⭐ Footer LILA CLARO (obs Jean 2026-08-31, mock adjunto): el pie dejó de ser una placa violeta
   profunda. Lo oscuro ahora es SOLO la banda del CTA, que así resalta en vez de diluirse.
   Todo el texto pasó a los tokens de tinta (--ink / --ink-2 / --muted): sobre lila claro los
   grises claros de antes (#b8aace, #9687b3…) quedaban por debajo de 2:1. */
/* BLANCO, el mismo color del resto de la página (obs Jean 2026-08-31). El contenido va sobre la
   hoja blanca de `main` y el pie queda FUERA de ella: con fondo propio —o transparente, que deja
   ver el degradado del body— aparecía un escalón de color justo donde arranca el footer. */
/* Sin margin-top: entre <main> (blanco) y el pie (blanco) un margen deja ver el degradado lavanda del
   body como una FRANJA vacía (Jean 2026-09-03: «esa línea antes del footer»). El aire va DENTRO, como padding. */
#footer, .pp-sitefoot { position: relative; z-index: 5; margin-top: 0; color: var(--ink-2); padding-top: calc(clamp(34px, 5vw, 64px) + clamp(50px, 7vw, 92px));
  background: #fff; overflow: hidden; }
/* Logo de marca en vez del wordmark cursivo (obs Jean): la MISMA imagen del header, versión de
   dos líneas. Alto fijo + ancho auto para que no se deforme. */
/* Grande a propósito (Jean 2026-09-08): con la marca ya centrada en su propia fila hay sitio, y a
   74px se perdía entre las cuatro columnas de enlaces. Alto fijo + ancho auto para no deformarla. */
.foot-logo-img { height: clamp(168px, 14vw, 248px); width: auto; }   /* Jean 2026-09-09: más grande */
.foot-wave, .foot-doodle { display: none; }
/* ⭐ Banda OSCURA que encierra el CTA (rectángulo del mock). Es lo único violeta profundo del
   pie, así que aquí sí mandan los claros: blanco para el título y lavanda para el apoyo. */
.foot-cta { position: relative; z-index: 1; max-width: 1180px; margin: 0 auto clamp(30px, 4vw, 48px);
  padding: clamp(26px, 3.4vw, 42px) clamp(24px, 3.4vw, 52px); text-align: center; border: 0;
  border-radius: clamp(18px, 1.8vw, 26px);
  background: linear-gradient(115deg, #2b1550 0%, #22103f 55%, #1a0b31 100%);
  box-shadow: 0 24px 50px -30px rgba(29,12,66,.55); }
.foot-cta::before { content: "♡"; display: block; margin-bottom: 10px; color: var(--violet-400); font: 500 clamp(30px, 3vw, 40px)/1 "Nunito Sans", sans-serif; }
.foot-cta h2 { max-width: none; margin: 0 auto; font-size: clamp(23px, 2.4vw, 40px); color: #fff; font-weight: 600; line-height: 1.14; }
/* Una sola línea desde que hay sitio (obs Jean 2026-08-31). Bajo 700px la tarjeta es
   estrecha a propósito y el titular DEBE envolver, o se saldría del recuadro. */
@media (min-width: 701px) { .foot-cta h2 { white-space: nowrap; } }
.foot-cta h2 .heart { color: #c9adf7; }
.foot-cta .foot-sub { max-width: 44ch; margin: 12px auto 0; color: #beafdf; font-weight: 600; line-height: 1.5; font-size: clamp(14px, 1.05vw, 18px); }
.foot-cta-btns { max-width: 480px; margin: clamp(20px, 2.4vw, 28px) auto 0; display: grid; justify-items: stretch; gap: 13px; }
.foot-cta-btns .btn { width: 100%; min-height: 52px; justify-content: center; }
.foot-wrap { position: relative; z-index: 1; max-width: 860px; display: flex; flex-direction: column; align-items: stretch; gap: 0; padding-bottom: clamp(26px, 4vw, 42px); }
.foot-brand { display: flex; flex-direction: column; align-items: center; text-align: center; margin-bottom: clamp(30px, 4vw, 46px); }
.foot-logo-link { display: inline-flex; color: var(--violet-700); text-decoration: none; }
.foot-tag { margin-top: 10px; color: var(--muted); font-size: clamp(14px, 1vw, 17px); font-weight: 600; }
.foot-socials { display: flex; justify-content: center; gap: 12px; margin-top: 18px; }
.foot-socials a { width: 42px; height: 42px; border-radius: 50%; display: grid; place-items: center; background: var(--violet-100); color: var(--violet-700);
  border: 1px solid var(--violet-200); box-shadow: none; transition: transform var(--t-pop) var(--ease-out), background var(--t-pop) var(--ease-out), border-color var(--t-pop) var(--ease-out); }
.foot-socials a:hover { transform: translateY(-2px); background: var(--violet-200); border-color: var(--violet-300); }
.foot-socials svg { width: 18px; height: 18px; }
.foot-nav-main { display: none; }
.foot-wrap > .foot-col:not(.foot-nav-main) { width: 100%; padding: 18px 20px; border: 1px solid var(--violet-200); border-bottom: 0; background: var(--violet-50); }
.foot-wrap > .foot-col:not(.foot-nav-main):first-of-type { border-radius: 18px 18px 0 0; }
.foot-wrap > .foot-col:not(.foot-nav-main):last-of-type { border-bottom: 1px solid var(--violet-200); border-radius: 0 0 18px 18px; }
.foot-wrap > .foot-col:not(.foot-nav-main) h3 { margin-bottom: 10px; color: var(--ink); font-family: "Fredoka", sans-serif; font-size: clamp(16px, 1.1vw, 19px); }
.foot-wrap > .foot-col:not(.foot-nav-main) a, .foot-wrap > .foot-col:not(.foot-nav-main) .fc-line { display: flex; align-items: center; gap: 8px; padding: 5px 0; color: var(--ink-2); font-size: clamp(13px, .9vw, 16px); font-weight: 600; text-decoration: none; }
.foot-disclosure { border: 1px solid var(--violet-200); border-bottom: 0; background: var(--violet-50); }
.foot-disclosure:first-of-type { border-radius: 18px 18px 0 0; }
.foot-disclosure:last-of-type { border-bottom: 1px solid var(--violet-200); border-radius: 0 0 18px 18px; }
.foot-disclosure summary { min-height: 64px; padding: 12px 20px; display: grid; grid-template-columns: 34px 1fr 26px; align-items: center; gap: 12px; color: var(--ink);
  font-family: "Fredoka", sans-serif; font-weight: 600; font-size: clamp(16px, 1.1vw, 19px); cursor: pointer; list-style: none; }
.foot-disclosure summary::-webkit-details-marker { display: none; }
.foot-disc-ic { width: 28px; height: 28px; border: 1px solid var(--violet-300); border-radius: 50%; display: grid; place-items: center; color: var(--violet-600); font: 800 15px/1 "Nunito Sans", sans-serif; }
.foot-disc-ic svg { width: 15px; height: 15px; }
.foot-disc-caret { justify-self: end; display: inline-flex; color: var(--violet-600); transition: transform var(--t-tr) var(--ease-out); }
.foot-disc-caret svg { width: 18px; height: 18px; }
.foot-disclosure[open] .foot-disc-caret { transform: rotate(180deg); }
.foot-disc-body { display: grid; gap: 3px; padding: 0 66px 17px; }
.foot-disc-body a, .foot-disc-body button, .foot-disc-body .fc-line { display: flex; align-items: center; gap: 8px; padding: 6px 0; border: 0; background: none; color: var(--ink-2); font: 600 clamp(13px, .9vw, 16px)/1.6 "Nunito Sans", system-ui, sans-serif; text-align: left; text-decoration: none; }
.foot-disc-body button { cursor: pointer; }
.foot-disc-body a:hover, .foot-disc-body button:hover { color: var(--violet-700); }
.foot-contact .fc-line { cursor: default; }
.fc-ic { display: inline-flex; opacity: .8; }
.foot-bottom { position: relative; z-index: 1; max-width: 860px; margin: 0 auto; border-top: 1px solid var(--violet-200); padding: 24px 20px 30px; display: flex; flex-direction: column; align-items: center; gap: 8px; text-align: center; }
.foot-copy, .foot-madewith { font-size: clamp(12px, .85vw, 14px); color: var(--muted); font-weight: 600; }

/* Enlaces legales SIEMPRE visibles: antes solo vivían dentro del acordeón «Ayuda», cerrado por
   defecto, y la auditoría de YouTube pide ver dónde está el enlace a la política (2026-09-11). */
.foot-legal{display:inline-flex;gap:6px;flex-wrap:wrap;align-items:center}
.foot-legal a{color:inherit;text-decoration:underline;text-underline-offset:2px}
.foot-legal a:hover{text-decoration-thickness:2px}
.foot-madewith .heart { color: var(--violet-500); font-size: 17px; }

/* El footer cambia de composición junto con la ficha pública: a 1280px ambos conservan el
   modo apilado de 860px; desde 1281px ya caben las tres columnas reales del PDP y el footer
   amplio sin mezclar lenguajes de escritorio y móvil en una misma pantalla. */
@media (min-width: 901px) {   /* laptop = footer amplio (tier ≥901, Jean 2026-09-03; antes 1281 dejaba el pie «celular» en toda laptop) */
  #footer, .pp-sitefoot { margin-top: clamp(-88px, -6vw, -56px); color: var(--ink-2); padding-top: clamp(48px, 4.6vw, 76px);
    background: #fff; }
  .foot-doodle { position: absolute; right: -3%; bottom: -4%; width: min(38vw, 560px); height: auto; display: block; pointer-events: none; opacity: .5; }
  .foot-doodle path { fill: none; stroke: rgba(124,79,208,.16); stroke-width: 3; stroke-linecap: round; }
  /* la banda se CONSERVA en escritorio (antes se deshacía en una fila con una línea abajo) y
     se pone horizontal: mensaje a la izquierda, botón a la derecha, como el mock. */
  .foot-cta { max-width: 1920px; margin: 0 auto clamp(30px, 3vw, 46px); padding: clamp(26px, 2.4vw, 40px) clamp(30px, 3vw, 56px);
    display: flex; flex-direction: row; align-items: center; justify-content: space-between;
    gap: clamp(24px, 3vw, 56px); text-align: left; flex-wrap: wrap; }
  .foot-cta::before { display: none; }
  .foot-cta h2 { max-width: none; margin: 0; font-size: clamp(22px, 1.9vw, 38px); }
  .foot-cta .foot-sub { max-width: 46ch; margin: 8px 0 0; font-size: clamp(14px, 1.05vw, 20px); }
  .foot-cta-btns { max-width: none; margin: 0; display: flex; align-items: center; justify-items: initial; gap: 14px; }
  .foot-cta-btns .btn { width: auto; min-height: 0; }
  /* Composición 2026-09-08 (Jean: «el footer se ve sobrecargado»): la MARCA ocupa una fila propia
     centrada y los enlaces van debajo en cuatro columnas. Antes eran cinco columnas con la marca
     dentro, y «Ideas de regalo» —18 enlaces, el triple que sus vecinas— estiraba la fila a 612px
     dejando media pantalla vacía a su derecha. Ahora esa lista fluye en DOS subcolumnas (abajo),
     así que la fila la marca «Ayuda» y nada queda escondido. En móvil siguen plegados en <details>.
     ⚠️ minmax(0,·) obligatorio: el correo de contacto no tiene espacios y con `1fr` pelado su
     min-content ensancharía esa columna a costa de las vecinas (regla del repo). */
  .foot-wrap { max-width: 1920px; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2.1fr) minmax(0, 1.15fr) minmax(0, 1.4fr); gap: 30px; align-items: start; padding-bottom: 34px; }
  .foot-brand { grid-column: 1 / -1; display: flex; flex-direction: column; align-items: center; text-align: center;
    margin: 0 0 clamp(26px, 3vw, 40px); padding-bottom: clamp(22px, 2.6vw, 34px); border-bottom: 1px solid var(--violet-200); }
  .foot-logo-link { color: var(--violet-700); }
  .foot-tag { margin-top: 10px; color: var(--muted); font-weight: 700; }
  .foot-socials { justify-content: center; gap: 10px; margin-top: 16px; }
  .foot-socials a { width: 38px; height: 38px; background: var(--grad); border-color: transparent; color: #fff; box-shadow: 0 8px 18px -10px rgba(90,58,168,.6); }
  .foot-nav-main { display: block; }
  .foot-wrap > .foot-col, .foot-wrap > .foot-col:not(.foot-nav-main), .foot-disclosure,
  .foot-disclosure:first-of-type, .foot-disclosure:last-of-type { width: auto; padding: 0; border: 0; border-radius: 0; background: none; }
  .foot-col h3, .foot-disclosure summary span:nth-child(2) { display: block; margin: 0 0 14px; color: var(--ink); font-family: "Fredoka", sans-serif; font-weight: 600; font-size: clamp(16px, 1vw, 22px); }
  .foot-col button, .foot-col a, .foot-col .fc-line, .foot-disc-body button, .foot-wrap > .foot-col:not(.foot-nav-main) a, .foot-wrap > .foot-col:not(.foot-nav-main) .fc-line,
  .foot-disc-body a, .foot-disc-body .fc-line { display: flex; align-items: center; gap: 8px; padding: 5px 0; border: 0; background: none; color: var(--ink-2); font-family: inherit; font-size: clamp(14px, .9vw, 19px); font-weight: 600; text-align: left; text-decoration: none; }
  .foot-col button:hover, .foot-col a:hover, .foot-disc-body a:hover, .foot-disc-body button:hover { color: var(--violet-700); transform: translateX(3px); }
  .foot-disclosure summary { min-height: 0; padding: 0; display: block; pointer-events: none; }
  .foot-disc-ic, .foot-disc-caret { display: none; }
  .foot-disclosure:not([open]) > .foot-disc-body, .foot-disc-body { display: grid !important; gap: 0; padding: 0; }
  /* Ideas siempre en dos columnas en laptop: no permitir que column-width la vuelva
     una lista única. El orden fluye de arriba abajo dentro de cada columna. */
  .foot-disclosure:first-of-type .foot-disc-body { display: block !important; column-count: 2; column-gap: 18px; }
  .foot-disclosure:first-of-type .foot-disc-body a { break-inside: avoid; overflow-wrap: anywhere; }
  .foot-contact a, .foot-contact .fc-line { overflow-wrap: anywhere; min-width: 0; }
  .foot-disclosure::details-content { content-visibility: visible !important; }
  .foot-bottom { max-width: 1920px; padding: 18px clamp(26px, 4vw, 80px); flex-direction: row; justify-content: space-between; gap: 12px; text-align: left; }
  .foot-copy, .foot-madewith { color: var(--muted); font-size: 12px; font-weight: 700; }
}

@media (min-width: 901px) and (max-width: 1440px) {
  .foot-wrap { grid-template-columns: minmax(0, .8fr) minmax(0, 2.7fr) minmax(0, 1.2fr) minmax(0, 1.3fr); gap: 20px; }
  .foot-col button, .foot-col a, .foot-disc-body a, .foot-disc-body button, .foot-disc-body .fc-line { font-size: 13px; line-height: 1.45; }
}

/* ============ Flotantes ============ */
/* Verde de WhatsApp (Jean 2026-09-18): el botón es de WhatsApp, no de la marca, y en violeta se
   confundía con el resto de acciones. El #25D366 oficial mide 1.98:1 contra el glifo blanco —bajo el
   mínimo de 3:1 de un icono—, así que el relleno va en #17a34a (3.29:1): el mismo verde, legible. */
.wa-float { position: fixed; right: 18px; bottom: 18px; z-index: 75; width: 58px; height: 58px; border-radius: 50%; background: #17a34a;
  border: 1px solid rgba(255,255,255,.42); display: grid; place-items: center; text-decoration: none;
  box-shadow: 0 14px 30px -8px rgba(13,110,54,.5), inset 0 1px 0 rgba(255,255,255,.42); transition: transform var(--t-pop) var(--ease-out), box-shadow var(--t-pop) var(--ease-out); opacity: 0; pointer-events: none; }
/* pointer-events: mientras es invisible (opacity:0, hasta 1.2s), un toque en la esquina abría WhatsApp
   «a ciegas» (Codex). Se habilita al comenzar el reveal. */
body.revealed .wa-float { opacity: 1; pointer-events: auto; transition: opacity .6s ease 1.2s, transform .2s; }
.wa-float:hover { transform: scale(1.08); }
.wa-float svg { width: 32px; height: 32px; }
.to-top { position: fixed; right: 21px; bottom: 86px; z-index: 76; width: 46px; height: 46px; border-radius: 50%; cursor: pointer;
  border: 1px solid rgba(255,255,255,.7); background: rgba(255,255,255,.6); color: var(--violet-700); display: grid; place-items: center;
  -webkit-backdrop-filter: blur(16px) saturate(180%); backdrop-filter: blur(16px) saturate(180%);
  box-shadow: 0 10px 26px rgba(90,58,168,.24); opacity: 0; transform: translateY(16px) scale(.85); pointer-events: none;
  transition: opacity var(--t-sheet) var(--ease-out), transform var(--t-sheet) var(--ease-out); }
.to-top.show { opacity: 1; transform: none; pointer-events: auto; }
.to-top:hover { background: #fff; }
.to-top svg { width: 20px; height: 20px; }
.toast { position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%) translateY(20px); opacity: 0; background: var(--ink); color: #fff; padding: 12px 20px; border-radius: 14px; font-weight: 700; font-size: var(--fs-base); box-shadow: 0 14px 30px rgba(0,0,0,.25); transition: transform var(--t-sheet) var(--ease-out), opacity var(--t-sheet) var(--ease-out); z-index: 90; pointer-events: none; }
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ============ CURSOR — anillo decorativo, puntero NATIVO visible ============ */
.vc-cursor { position: fixed; top: 0; left: 0; z-index: 200; pointer-events: none;
  width: 30px; height: 30px; border-radius: 50%; border: 1.5px solid rgba(124,79,208,.55);
  opacity: 0; transition: opacity .4s ease; }
body.ready .vc-cursor { opacity: 1; }
.vc-cursor .core { position: absolute; inset: -1.5px; border-radius: 50%;
  display: grid; place-items: center; color: #fff; font-size: 11px; font-weight: 600; white-space: nowrap;
  background: var(--violet-600); transform: scale(0); opacity: 0;
  transition: transform .38s var(--p3-in), opacity .38s var(--p3-in); }
.vc-cursor.grow .core { transform: scale(2.4); opacity: .92; transition: transform .6s var(--back18), opacity .3s ease; }
.vc-cursor.soft .core { transform: scale(1.7); opacity: .14; transition: transform .6s var(--back18), opacity .3s ease; }
.vc-cursor .lbl { opacity: 0; transition: opacity .2s ease .15s; font-size: 5px; font-family: "Fredoka", sans-serif; }
.vc-cursor.grow .lbl { opacity: 1; }

/* ============ Responsive ============ */
@media (max-width: 980px) {
  .perso-panel { grid-template-columns: 1fr; }
  .perso-right { margin-top: clamp(20px, 4vw, 34px); }
  .sobre-grid { grid-template-columns: 1fr; }
}
@media (max-width: 900px) { .vc-cursor { display: none; } }
@media (max-width: 620px) {
  .wrap { --gut: 18px; padding: 0 var(--gut); }
  /* Los CTA grandes conservan un área táctil de 44px, pero dejan de heredar la escala de
     escritorio. Aplica en pareja a «Personaliza…» y «Ver la tienda» para que se vean proporcionales. */
  .btn-lg { min-height: 44px; padding: clamp(11px, 3.2vw, 14px) clamp(20px, 6vw, 28px); font-size: clamp(14px, 3.8vw, 16px); }
  .foot-cta { padding: 28px 20px; }
  .foot-cta-btns { gap: 8px; }
  .cat-coverflow { --cf-cardw: clamp(136px, 37vw, 164px); padding-top: 18px; }
  .cf-foot { display: block; padding: 10px 12px 12px; }
  .cf-name { font-size: 16px; }
  .cf-price { font-size: 12px; margin-top: 0; }
  .cf-nav { width: 42px; height: 42px; }
  .cf-nav.prev { left: 8px; } .cf-nav.next { right: 8px; }
  .foot-disc-body { padding-left: 20px; padding-right: 20px; }
  .hero-copy { max-width: 86vw; }
}

/* Landing móvil — implementación directa de la propuesta A aprobada.
   Las medidas y capas salen del mock funcional; escritorio conserva su diseño WebGL. */
@media (max-width: 620px) {
  html { overflow-x: clip; }
  /* El hero empieza exactamente donde termina el header fijo: no queda franja entre ambos. */
  body { padding-top: calc(72px + env(safe-area-inset-top)); }
  .hero { width: 100%; height: 575px; min-height: 0; aspect-ratio: auto; margin: 0;
    border-radius: 0 0 24px 24px; background: linear-gradient(155deg, #f7f1fa, #e2cae6 68%, #cfacd5);
    box-shadow: 0 14px 34px rgba(45,23,82,.12); }
  .hero-media { inset: 0; overflow: hidden; }
  .hero-media::before { display: none; }
  .hero-mobile-slides { position: absolute; inset: 0; z-index: 1; display: block; overflow: hidden; }
  .hero-mobile-slides > span { position: absolute; left: 0; right: 0; top: 0; width: 100%; height: 419px;
    background-image: var(--hero-slide); background-position: 86% 72%; background-size: cover; background-repeat: no-repeat;
    -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 76%, rgba(0,0,0,.94) 82%, rgba(0,0,0,.55) 92%, transparent 100%);
    mask-image: linear-gradient(180deg, #000 0%, #000 76%, rgba(0,0,0,.94) 82%, rgba(0,0,0,.55) 92%, transparent 100%);
    opacity: 0; transform: translateY(34px) scale(1.28); transform-origin: 84% 73%; }
  /* La rotación arranca recién con `body.slides-go` (primer toque/scroll o 7 s tras `load`, home.js):
     un hero que cambia cada 6 s desde el segundo 0 dejaba el Speed Index en 15 s y Lighthouse tomaba
     como LCP el slide que aparecía a los 20 s (perf 2026-09-04). Hasta entonces se ve el primero fijo. */
  .hero-mobile-slides > span:first-child { opacity: 1; }
  body:not(.slides-go) .hero-mobile-slides > span:not(:first-child) { background-image: none; }   /* los otros 5 slides (115 KB) recién se piden al arrancar la rotación */
  body.slides-go .hero-mobile-slides > span { animation: heroMobileSlide 36s ease-in-out infinite; }
  /* ⚠️ Los delays LLEVAN el mismo prefijo `body.slides-go` a propósito. El shorthand `animation` de
     la línea de arriba resetea `animation-delay` a 0 y su selector puntúa (0,2,2), así que le ganaba
     a `.hero-mobile-slides > span:nth-child(N)` (0,2,1) por especificidad —no por orden— y los seis
     delays computaban 0s: los seis slides se encendían y apagaban A LA VEZ, dejando el hero VACÍO
     31 de cada 36 s (Jean lo vio en su iPhone el 2026-09-09; recargar «lo arreglaba» porque el ciclo
     reinicia en el tramo visible). Un shorthand nunca se deja pisar por longhands menos específicos:
     o comparten prefijo, o el delay entra en el propio shorthand. */
  body.slides-go .hero-mobile-slides > span:nth-child(1) { animation-delay: -1s; }
  body.slides-go .hero-mobile-slides > span:nth-child(2) { animation-delay: 5s; }
  body.slides-go .hero-mobile-slides > span:nth-child(3) { animation-delay: 11s; }
  body.slides-go .hero-mobile-slides > span:nth-child(4) { animation-delay: 17s; }
  body.slides-go .hero-mobile-slides > span:nth-child(5) { animation-delay: 23s; }
  body.slides-go .hero-mobile-slides > span:nth-child(6) { animation-delay: 29s; }
  .hero-vid { display: none; }
  .reveal-canvas { display: none; }
  .hero::before, .hero.no-gl::before { content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none; background:
    linear-gradient(180deg, #faf7fc 0%, rgba(250,247,252,.76) 20px, rgba(250,247,252,0) 86px),
    linear-gradient(180deg, rgba(246,239,249,0) 0%, rgba(238,216,240,.02) 40%, rgba(228,199,232,.1) 50%, rgba(220,188,225,.24) 62%, rgba(214,181,220,.55) 76%, #d4b5da 91%, #d4b5da 100%),
    radial-gradient(ellipse 138% 55% at 0 0, #f7f0f9 0%, rgba(247,240,249,.98) 36%, rgba(242,226,244,.68) 55%, rgba(234,207,237,0) 79%); }
  .hero-copy { inset: 0; left: 0; top: 0; width: 100%; max-width: none; transform: translateY(var(--hcy, 0px)); color: var(--ink); }
  .hero-pill { position: absolute; left: 22px; top: 22px; min-height: 34px; padding: 0 12px; gap: 0;
    font-size: 11px; opacity: 1; transform: none; color: #34206f;
    border-color: rgba(255,255,255,.66); background: linear-gradient(135deg, rgba(244,237,252,.94), rgba(232,218,248,.94));
    box-shadow: inset 0 1px 0 rgba(255,255,255,.78), 0 9px 22px -16px rgba(76,42,139,.42);
    -webkit-backdrop-filter: blur(8px) saturate(145%); backdrop-filter: blur(8px) saturate(145%); }
  .hero-pill-desktop { display: none; }
  .hero-pill-mobile { display: inline; }
  .hero-copy h1, .hero-copy .hero-h1 { position: absolute; left: 22px; top: 72px; width: 245px; margin: 0; font-size: 28px; font-weight: 600; line-height: 1.06; letter-spacing: .008em; filter: none; }
  .hero-copy h1:first-of-type { margin-top: 0; }
  .hero-copy .truj { color: #7543db; font-family: "Caveat", cursive; font-size: 27px; font-weight: 700; line-height: 1; }   /* Caveat como en escritorio (Satisfy se retiró: una fuente entera para una palabra, perf 2026-09-04) */
  .hero-copy .truj-w::after { background: var(--violet-600); }
  .hero-copy .heart { color: var(--violet-600); }
  .hero-actions-glass { position: absolute; z-index: 4; left: 12px; right: 12px; bottom: 28px; display: flex;
    flex-direction: column; gap: 8px; padding: 9px; border: 1px solid rgba(255,255,255,.48); border-radius: 21px;
    background: rgba(255,255,255,.2); box-shadow: 0 12px 28px rgba(63,30,88,.11);
    -webkit-backdrop-filter: blur(11px); backdrop-filter: blur(11px); pointer-events: auto; }
  .hero-cta { order: 1; width: 100%; margin: 0; opacity: 1; transform: none; }
  .hero-cta .btn { position: relative; width: 100%; min-height: 48px; padding: 0 38px; border-radius: 15px;
    justify-content: center; font-size: 13px; box-shadow: 0 10px 24px rgba(117,67,219,.28); }
  .hero-btn-arrow { position: absolute; right: 18px; top: 50%; display: inline; font-size: 24px; font-weight: 400; transform: translateY(-54%); }
  .hero-copy .pline { order: 2; margin: 0; overflow: visible; }
  .hero-copy .pline > span { transform: none; }
  .hero-copy .pline p { position: relative; min-height: 68px; padding: 10px 38px 10px 54px; gap: 8px;
    border: 0; border-radius: 17px; background: rgba(255,255,255,.93); color: #39275d; font-size: 11px; line-height: 1.25;
    box-shadow: 0 9px 20px rgba(45,23,82,.08); }
  .hero-copy .pl-pin { position: absolute; left: 11px; top: 16px; width: 34px; height: 34px; padding: 8px; border-radius: 12px; color: #7543db; background: #eee5fa; }
  .hero-ship-copy { display: flex; flex-direction: column; align-items: flex-start; min-width: 0; }
  .hero-ship-copy strong { font-weight: 800; text-align: left; }
  .hero-ship-copy small { display: block; margin-top: 3px; color: var(--muted); font-size: 9px; font-weight: 600; text-align: left; }
  .hero-ship-arrow { position: absolute; right: 13px; top: 50%; display: inline; color: var(--violet-600); font-size: 25px; transform: translateY(-54%); }
  .hero-trust-mobile { order: 3; display: block; padding-top: 0; color: #70637e; font-size: 9px; font-weight: 700; text-align: center; }
  .hero-hint { display: none; }
  main { margin-top: -18px; }

  /* Ritmo, escalas y carriles del mock móvil. */
  .sec { padding: 36px 0 0; }
  .wrap { --gut: 16px; padding: 0 var(--gut); }
  .sec-title { margin: 0; font-size: 25px; line-height: 1.08; }
  .sec-head-row { align-items: flex-end; gap: 10px; }
  .sec-cats { padding-top: 30px; padding-bottom: 0; }
  .sec-cats .sec-head-row { display: block; }
  .pill-cats { min-height: 44px; margin: 2px 0 8px; padding: 0 10px; border: 0; background: transparent; box-shadow: none; font-size: 13px; }
  .cat-coverflow { width: 100%; margin-left: 0; padding: 2px 0 10px; }
  /* Aquí las tarjetas ya son `position: relative` (abajo), así que el aire de la sombra se gana con
     padding + margen negativo, el patrón normal. El `overflow-clip-margin` del modo 3D no sirve en
     este modo porque esta regla redeclara `overflow-y: hidden` y gana por orden. */
  .cf-stage { position: relative; display: flex; gap: 12px; height: auto; min-height: 183px; overflow-x: auto; overflow-y: hidden;
    margin-block: -8px -6px; padding: 10px 0 16px; perspective: none; touch-action: pan-x pan-y; scrollbar-width: none; cursor: grab; }
  .cf-stage.is-dragging { cursor: grabbing; user-select: none; scroll-behavior: auto; }
  .cf-stage::-webkit-scrollbar { display: none; }
  .cf-card { position: relative; top: auto; left: auto; flex: 0 0 46%; width: auto; min-width: 0;
    transform: none !important; opacity: 1 !important; filter: none !important; border-radius: 13px;
    box-shadow: 0 4px 12px rgba(45,25,83,.06); }
  .cf-card.is-center { box-shadow: 0 8px 18px rgba(45,25,83,.11), 0 0 0 1px rgba(124,79,208,.1); }
  .cf-media { height: 116px; aspect-ratio: auto; border-radius: 13px 13px 0 0; }
  .cf-foot { min-height: 57px; display: block; padding: 9px 10px; }
  .cf-info { width: 100%; }
  .cf-name { font-size: 15px; }
  .cf-price { font-size: 10px; }
  .cf-nav { display: none; }
  .cat-dots { margin-top: 0; }
  .cat-dot { width: 8px; height: 8px; }
  .cat-dot::after { inset: -8px -4px; }   /* con el punto a 8px hacen falta 8 arriba y 8 abajo para los 24 */

  .sec-stats { padding: 16px 16px 0; }
  .sec-stats .wrap { padding: 0; }
  .sec-stats .stats-grid { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); max-width: none; gap: 0; padding: 13px 0; border-top: 1px solid #e8def1; border-bottom: 1px solid #e8def1; }
  .stat-card { min-width: 0; padding: 3px 5px; }
  .stat-card + .stat-card::before { display: block; height: 100%; background: #e8def1; }
  .stat-card b { font-size: 20px; }
  .stat-card small { margin-top: 2px; font-size: 9px; line-height: 1.18; white-space: normal; }

  .sec-perso { padding-top: 36px; }
  .perso-panel { display: block; padding: 0; border: 0; border-radius: 0; background: none; box-shadow: none; }
  .perso-panel .sec-title { font-size: 25px; }
  .perso-steps { margin: 14px 0; gap: 12px; }
  .ps-step { grid-template-columns: 52px 1fr; column-gap: 11px; }
  .ps-t { font-size: 15px; }
  .ps-d { font-size: 12.5px; line-height: 1.4; }
  .perso-script { font-size: 18px; margin: 8px 0 14px; }
      .perso-cta-row { margin: 10px 0 16px; gap: 4px; }
  .perso-cta-row .btn { min-height: 44px; padding: 0 14px; font-size: 12px; }
  .perso-right { margin-top: 0; }
  .perso-media { border-radius: 14px; box-shadow: none; }

  .sec-pres .sec-head-row { display: block; }
  .presg-incl { max-width: none; margin-bottom: 12px; padding: 12px; border-radius: 12px; background: #fff; }
  .presg-incl-ic { width: 34px; border-radius: 10px; }
  .presg-incl-txt strong { font-size: 13px; }
  .presg-incl-txt span { font-size: 11px; line-height: 1.3; }
  .presg-flow { width: 100%; margin-left: 0; padding: 2px 0 10px; }
  .presg-stage { position: relative; display: flex; gap: 12px; height: auto; min-height: 244px; overflow-x: auto; overflow-y: hidden;
    margin-block: -8px -6px; padding: 10px 0 16px; perspective: none; touch-action: pan-x pan-y; scrollbar-width: none; cursor: grab; }
  .presg-stage.is-dragging { cursor: grabbing; user-select: none; scroll-behavior: auto; }
  .presg-stage::-webkit-scrollbar { display: none; }
  .presg-it { position: relative; top: auto; left: auto; flex: 0 0 48%; width: auto; height: 232px;
    transform: none !important; opacity: 1 !important; filter: none !important; border-radius: 13px;
    align-items: flex-start; padding: 10px; text-align: left; box-shadow: 0 4px 12px rgba(45,25,83,.06); }
  .presg-flow .cf-nav { display: none; }
  .presg-media { height: 88px; aspect-ratio: auto; border-radius: 10px; }
  .presg-name { display: -webkit-box; width: calc(100% - 8px); max-width: none; min-height: 35px; margin: 6px 4px 0;
    overflow: visible; white-space: normal; text-overflow: clip; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
    font-size: 15px; line-height: 1.15; }
  .presg-desc { min-height: 25px; margin: 4px 4px 0; font-size: 10px; line-height: 1.25; }
  .presg-price { margin: 6px 4px 8px; padding: 5px 12px; }

  .sec-sobre .sobre-grid { gap: 0; }
  .sobre-img { width: 100%; margin: 10px 0 14px; border-radius: 0; }
  .sobre-lead { font-size: 17px; }
  .sobre-txt p { margin: 8px 0; font-size: 13px; line-height: 1.52; }

  .sec-social .rev-head { display: block; }
  .rev-empty { grid-template-columns: 106px 1fr; gap: 16px; min-height: 148px; padding: 18px; border-radius: 17px; }
  .rev-empty img { width: 106px; height: auto; object-fit: contain; border-radius: 0; }
  .rev-empty-copy strong { margin-bottom: 14px; font-size: 17px; line-height: 1.18; }
  .rev-empty-copy .btn { width: 100%; min-height: 44px; padding: 8px 10px; font-size: 11px; }
  .reels { margin: 36px 0 0; text-align: left; }
  .reels-head { align-items: flex-start; }
  .reels-stage { height: 248px; padding: 2px 0 10px; overflow-x: auto; overflow-y: hidden; perspective: none; scrollbar-width: none; cursor: grab; }
  .reels-stage.is-dragging { cursor: grabbing; user-select: none; scroll-behavior: auto; }
  .reels-stage::-webkit-scrollbar { display: none; }
  .reels-ring { position: relative; inset: auto; display: flex; gap: 12px; width: 100%; height: 238px; margin: 0;
    transform: none !important; touch-action: pan-x pan-y; }
  .reel-card { position: relative; top: auto; left: auto; flex: 0 0 46%; width: auto; height: 238px; margin: 0;
    aspect-ratio: auto; transform: none !important; border-radius: 14px; }
  .faq-wrap { margin-top: 36px; }
  .faq { gap: 8px; }
  .faq details { border-radius: 11px; }
  .faq summary { min-height: 48px; padding: 0 12px; font-size: 13px; }
  .faq-cta { margin-top: 14px; }
}
/* ===== Topbar sobre el reveal: tinta→blanco por control (lo alterna home.js muestreando el dye) ===== */
.pp-topbar--landing .pp-lnav-a, .pp-topbar--landing .pp-search-btn, .pp-topbar--landing .pp-acct-btn { transition: color var(--t-tr) var(--ease-out), background var(--t-pop) var(--ease-out); }
.pp-topbar--landing .pp-logo-wordmark { transition: color var(--t-tr) var(--ease-out); }

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
  /* el selector * NO alcanza pseudo-elementos → guard UNIVERSAL de todos los ::before/::after
     (cubre subrayado Trujillo, hilo de pasos, FAQ, glow del CTA… de una — Codex 2026-07-22). */
  *::before, *::after { transition: none !important; animation: none !important; }
  /* skeletons con fade-in: `animation:none` mata también su aparición → visibles explícitos
     (P2 Codex 2026-07-18 — la base .presg-it.is-sk vive ANTES del otro bloque reduce y ganaba) */
  .cf-card.is-sk, .presg-it.is-sk, .pp-sk, .pp-oca-sk, .sk-sh { opacity: 1 !important; }
  .loader { display: none; }
  .reveal-canvas { display: none; }
  [data-line] .ln, [data-fade], [data-wipe], [data-rise], .hero-copy .ch, .hero-copy .pline > span,
  .hero-pill, .hero-cta, .stat-card, .wa-float { opacity: 1 !important; transform: none !important; clip-path: none !important; }
}

/* Ronda 11 (Jean) — feedback UNIVERSAL de clic (guardia anti doble-clic de home.js /
   posible-pedido.js): mientras el botón está retenido se ve BLOQUEADO (gris apagado + cursor
   not-allowed). El clic lo corta el guard (capture + stopImmediatePropagation), así que dejamos que
   el cursor se vea. El transition-delay evita el parpadeo del gris en clics rápidos de UI pura; el
   shimmer de .is-loading (btnBusy) manda cuando hay una escritura real en vuelo. */
button.is-busy:not(.is-loading) { pointer-events: none; cursor: not-allowed; opacity: .55; filter: grayscale(.45) saturate(.75); transition: opacity .15s ease .12s, filter .15s ease .12s; }
/* Bloqueado = INERTE (Jean 2026-07-14): sin animación de clic/hover mientras está retenido. */
button.is-busy:hover, button.is-busy:active, button.is-loading:hover, button.is-loading:active { transform: none !important; }

/* ===================== ESPERA = ESFERA DE PUNTOS (toda la web pública) =====================
   Desde 2026-09-30 la web pública lleva la variante «profundidad suave» de la esfera (decisión de Jean,
   propuesta de Astra); el TALLER conserva la original en css/components.css. Mismo markup en los dos:
   26 `<i>` dentro de `.vc-orb` (lo inyectan `btnBusy`/`orbHtml()` en posible-pedido.js y sus copias de una
   línea en comunidad.js y reto.js). Vive en home.css porque es la única hoja que cargan TODAS las páginas
   públicas (portada, tienda, ficha, checkout, Mi cuenta, landings, /comunidad/, /reto/).
   · Tamaño por `--orb-size` (todo en em: puntos, radio y perspectiva escalan juntos): 18 px en botones,
     28 px en tarjetas/secciones (`.is-sec`), 52 px en página (`.is-page`). Color = currentColor.
   · Contrato de espera INTACTO: entra a los ~300 ms (fill `backwards` mantiene la opacidad 0 durante el
     retardo), así que una respuesta rápida no la muestra. Entrada 160 ms escala .96→1 (equivale al
     @starting-style de la propuesta y funciona también donde @starting-style no existe); salida 120 ms con
     `.is-done` donde el contenedor la retira con fundido (los botones restauran su rótulo de golpe).
   · Radio 0.41111·tamaño, perspectiva 4·tamaño, punto 0.10556·tamaño; opacidad por profundidad .46–.98
     (los polos fijos en .72). Vuelta de 4 s lineal sobre el eje vertical, sin cabeceo. Solo transform/opacity. */
.vc-orb {
  --orb-size: 18px;
  position: relative; display: inline-block; flex: none; width: 1em; height: 1em; font-size: var(--orb-size); line-height: 1;
  margin-right: 7px; vertical-align: middle;
  animation: vc-orb-in var(--t-fb) var(--ease-out) .3s backwards;
  transition: opacity 120ms var(--ease-in), transform 120ms var(--ease-in);
}
@keyframes vc-orb-in { from { opacity: 0; transform: scale(.96); } }
.vc-orb.is-done { opacity: 0; transform: scale(.96); }
.vc-orb::before { content: none; }
.vc-orb i {
  position: absolute; left: 50%; top: 50%; width: .10556em; height: .10556em; margin: -.05278em;
  border-radius: 50%; background: currentColor; opacity: var(--o);
  transform: perspective(4em) rotateY(0turn) translate3d(var(--x), var(--y), var(--z)) rotateY(0turn);
  animation: vc-orbit 4s linear infinite, vc-depth 4s cubic-bezier(.37, 0, .63, 1) infinite;
  animation-delay: 0s, var(--d);
}
@keyframes vc-orbit {
  from { transform: perspective(4em) rotateY(0turn) translate3d(var(--x), var(--y), var(--z)) rotateY(0turn); }
  to { transform: perspective(4em) rotateY(1turn) translate3d(var(--x), var(--y), var(--z)) rotateY(-1turn); }
}
@keyframes vc-depth { 0%, 100% { opacity: var(--hi); } 50% { opacity: var(--lo); } }
.vc-orb i:nth-child(1){--x:0em;--y:.41111em;--z:0em;--d:0s;--lo:.720;--hi:.720;--o:.720}
.vc-orb i:nth-child(2){--x:-.11881em;--y:.37822em;--z:.10884em;--d:-3.4721s;--lo:.618;--hi:.822;--o:.789}
.vc-orb i:nth-child(3){--x:.01950em;--y:.34533em;--z:-.22221em;--d:-1.9443s;--lo:.579;--hi:.861;--o:.579}
.vc-orb i:nth-child(4){--x:.16257em;--y:.31244em;--z:.21204em;--d:-.4164s;--lo:.551;--hi:.889;--o:.854}
.vc-orb i:nth-child(5){--x:-.29682em;--y:.27956em;--z:-.05250em;--d:-2.8885s;--lo:.529;--hi:.911;--o:.687}
.vc-orb i:nth-child(6){--x:.27750em;--y:.24667em;--z:-.17652em;--d:-1.3607s;--lo:.512;--hi:.928;--o:.608}
.vc-orb i:nth-child(7){--x:-.09116em;--y:.21378em;--z:.33912em;--d:-3.8328s;--lo:.498;--hi:.942;--o:.934}
.vc-orb i:nth-child(8){--x:-.17016em;--y:.18089em;--z:-.32763em;--d:-2.3050s;--lo:.487;--hi:.953;--o:.513}
.vc-orb i:nth-child(9){--x:.36027em;--y:.14800em;--z:.13157em;--d:-.7771s;--lo:.477;--hi:.963;--o:.803}
.vc-orb i:nth-child(10){--x:-.36481em;--y:.11511em;--z:.15059em;--d:-3.2492s;--lo:.470;--hi:.970;--o:.815}
.vc-orb i:nth-child(11){--x:.17073em;--y:.08222em;--z:-.36483em;--d:-1.7214s;--lo:.465;--hi:.975;--o:.489}
.vc-orb i:nth-child(12){--x:.12215em;--y:.04933em;--z:.38943em;--d:-.1935s;--lo:.462;--hi:.978;--o:.966}
.vc-orb i:nth-child(13){--x:-.35541em;--y:.01644em;--z:-.20597em;--d:-2.6656s;--lo:.460;--hi:.980;--o:.590}
.vc-orb i:nth-child(14){--x:.40120em;--y:-.01644em;--z:-.08820em;--d:-1.1378s;--lo:.460;--hi:.980;--o:.664}
.vc-orb i:nth-child(15){--x:-.23473em;--y:-.04933em;--z:.33388em;--d:-3.6099s;--lo:.462;--hi:.978;--o:.931}
.vc-orb i:nth-child(16){--x:-.05176em;--y:-.08222em;--z:-.39946em;--d:-2.0820s;--lo:.465;--hi:.975;--o:.467}
.vc-orb i:nth-child(17){--x:.30178em;--y:-.11511em;--z:.25434em;--d:-.5542s;--lo:.470;--hi:.970;--o:.881}
.vc-orb i:nth-child(18){--x:-.38322em;--y:-.14800em;--z:.01585em;--d:-3.0263s;--lo:.477;--hi:.963;--o:.730}
.vc-orb i:nth-child(19){--x:.26168em;--y:-.18089em;--z:-.26041em;--d:-1.4984s;--lo:.487;--hi:.953;--o:.555}
.vc-orb i:nth-child(20){--x:-.01622em;--y:-.21378em;--z:.35078em;--d:-3.9706s;--lo:.498;--hi:.942;--o:.942}
.vc-orb i:nth-child(21){--x:-.21072em;--y:-.24667em;--z:-.25252em;--d:-2.4427s;--lo:.512;--hi:.928;--o:.560}
.vc-orb i:nth-child(22){--x:.29874em;--y:-.27956em;--z:.04020em;--d:-.9149s;--lo:.529;--hi:.911;--o:.745}
.vc-orb i:nth-child(23){--x:-.21933em;--y:-.31244em;--z:.15260em;--d:-3.3870s;--lo:.551;--hi:.889;--o:.817}
.vc-orb i:nth-child(24){--x:.04896em;--y:-.34533em;--z:-.21762em;--d:-1.8591s;--lo:.579;--hi:.861;--o:.582}
.vc-orb i:nth-child(25){--x:.08011em;--y:-.37822em;--z:.13980em;--d:-.3313s;--lo:.618;--hi:.822;--o:.808}
.vc-orb i:nth-child(26){--x:0em;--y:-.41111em;--z:0em;--d:0s;--lo:.720;--hi:.720;--o:.720}
/* Esperas de SECCIÓN/PÁGINA: la esfera va en violeta sobre blanco, centrada, con su texto en gris al lado. */
.vc-orb.is-sec { --orb-size: 28px; margin: 0; }
.vc-orb.is-page { --orb-size: 52px; margin: 0; }
.vc-orb-wait { display: flex; align-items: center; justify-content: center; gap: 10px; color: var(--muted); font-size: var(--fs-l4, 12px); }
.vc-orb-wait .vc-orb { color: var(--violet-600); }
/* Botón CORTO donde la esfera no cabe junto al rótulo (orbe() lo mide): va centrada encima, el ancho del botón no
   cambia y el rótulo se funde justo cuando ella entra (~300 ms) — una respuesta rápida no ve ninguno de los dos. */
:where(button.is-orb-c) { position: relative; }
button.is-orb-c > .vc-orb { position: absolute; left: 50%; top: 50%; margin: -.5em 0 0 -.5em; }
button.is-orb-c > .vc-btn-lbl { display: inline-block; min-width: 0; max-width: 100%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; animation: vc-lbl-out var(--t-press) var(--ease-in) .3s forwards; }
@keyframes vc-lbl-out { to { opacity: 0; } }
/* Espera del motor de la tienda al abrir una ficha desde «Los más pedidos» y reproductor de reels: esfera blanca
   sobre la foto (antes, arcos girando). */
.tp-media > .vc-orb, .reel-lb-frame > .vc-orb { position: absolute; z-index: 3; left: 50%; top: 50%; margin: -.5em 0 0 -.5em; color: #fff; filter: drop-shadow(0 2px 6px rgba(42, 26, 68, .5)); }
@media (prefers-reduced-motion: reduce) {
  /* congelada en su pose inicial SIGUE leyéndose: cada punto conserva su sitio en 3D y su opacidad por profundidad */
  .vc-orb { animation: none; transition: none; opacity: 1; }   /* `animation:none` mata también la entrada desde opacity:0: visible explícito (.is-done, más específica, sigue ocultándola) */
  .vc-orb i { animation: none; }
  button.is-orb-c > .vc-btn-lbl { animation: none; opacity: 0; }
}

/* ===================== Reels de redes — carrusel 3D (home.js) =====================
   Portadas por función propia (dominio Supabase ya en CSP); tarjeta "tejida" de respaldo
   generada en canvas si no llega la miniatura. Solo transform/opacity, guard reduced-motion. */
.reels { margin: clamp(40px, 6vw, 76px) 0 clamp(8px, 2vw, 20px); text-align: center; }
.reels-head { display: flex; flex-direction: column; align-items: center; gap: 4px; }
/* Dos botones a las redes en lugar del subtítulo (obs Jean 2026-08-31). Mismo par visual: no hay
   jerarquía entre Instagram y TikTok, así que comparten estilo y los distingue el nombre. */
.reels-links { display: flex; flex-wrap: wrap; justify-content: center; gap: clamp(10px, 1vw, 16px); margin: clamp(12px, 1.4vw, 20px) 0 0; }
.reels-btn { position: relative; display: inline-flex; align-items: center; gap: 9px;
  min-height: 44px; padding: 10px clamp(18px, 1.4vw, 26px); border-radius: 999px;
  background: var(--card); border: 1px solid var(--violet-200); color: var(--violet-700);
  font-family: inherit; font-weight: 800; font-size: clamp(14px, 1vw, 19px); text-decoration: none;
  box-shadow: var(--shadow-sm); transition: transform var(--t-pop) var(--ease-out), box-shadow var(--t-pop) var(--ease-out), border-color var(--t-pop) var(--ease-out); }
.reels-btn svg { width: clamp(17px, 1.2vw, 21px); height: clamp(17px, 1.2vw, 21px); flex: none; }
/* hover que ELEVA ⇒ área de hit estable */
.reels-btn::after { content: ""; position: absolute; inset: -5px; z-index: -1; border-radius: inherit; }
.reels-btn:hover { transform: translateY(-2px); box-shadow: var(--shadow); border-color: var(--violet-400); }
.reels-btn:active { transform: translateY(0) scale(.98); }

/* escenario full-bleed (rompe .wrap a todo el ancho del navegador) */
.reels-stage {
  /* full-bleed: home.js (setBleed) fija width/margin EXACTOS descontando la barra de scroll.
     Fondo TRANSPARENTE (obs Jean: sin banda oscura, blanco como el resto del inicio). Alto
     generoso + perspective amplia para que la tarjeta del frente NO se corte. */
  position: relative; width: 100%; margin-left: 0;
  padding: clamp(24px, 3.5vw, 44px) 0 clamp(16px, 2.5vw, 32px);
  height: clamp(440px, 50vw, 500px); box-sizing: content-box;
  perspective: 1800px; perspective-origin: 50% 44%; overflow: hidden; background: transparent;
  opacity: 0; transform: translateY(34px);
  transition: opacity .9s cubic-bezier(.2, .8, .25, 1), transform .9s cubic-bezier(.2, .8, .25, 1);
}
.reels-stage.in { opacity: 1; transform: none; }

.reels-ring {
  position: absolute; inset: 0; margin: auto; width: var(--reel-w, 164px); height: 0;
  transform-style: preserve-3d; will-change: transform; cursor: grab; touch-action: pan-y; z-index: 1;
}
.reels-ring.grabbing { cursor: grabbing; }
.reels-ring.settle { transform: rotateY(0deg) scale(.86) rotateX(8deg); }
.reels-stage.in .reels-ring { transition: transform 1s cubic-bezier(.2, .8, .25, 1); }

.reel-card {
  position: absolute; top: 50%; left: 50%; width: var(--reel-w, 164px); aspect-ratio: 9 / 16;
  margin: calc(var(--reel-w, 164px) * -16 / 9 / 2) 0 0 calc(var(--reel-w, 164px) / -2);
  border-radius: 18px; overflow: hidden; backface-visibility: hidden; background: #efe8fb;
  box-shadow: 0 14px 34px rgba(88, 58, 150, .22); transform: rotateY(var(--ang)) translateZ(var(--radius, 420px));
  -webkit-user-select: none; user-select: none; cursor: pointer;
  transition: box-shadow var(--t-tr) var(--ease-out), filter var(--t-tr) var(--ease-out);
}
.reel-card canvas, .reel-card .reel-thumb { position: absolute; inset: 0; width: 100%; height: 100%; display: block; -webkit-user-drag: none; user-select: none; }
.reel-card .reel-thumb { object-fit: cover; opacity: 0; transition: opacity .5s ease; }
.reel-card .reel-thumb.on { opacity: 1; }
.reel-card .reel-scrim { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(20, 10, 40, .03) 42%, rgba(20, 10, 40, .48) 92%); }
.reel-card:hover { box-shadow: 0 20px 46px rgba(88, 58, 150, .34); filter: brightness(1.05); }
.reel-card .reel-cap {
  position: absolute; left: 11px; right: 11px; bottom: 10px; color: #fff; font-size: 12.5px; font-weight: 700;
  line-height: 1.3; text-shadow: 0 1px 6px rgba(0, 0, 0, .55); font-family: "Nunito Sans", system-ui, sans-serif;
}
.reel-card .reel-badge {
  position: absolute; top: 9px; left: 9px; display: inline-flex; align-items: center; gap: 5px;
  background: rgba(20, 12, 36, .5); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  color: #fff; font-size: 10.5px; font-weight: 800; letter-spacing: .02em; padding: 4px 9px 4px 6px; border-radius: 99px;
}
.reel-card .reel-badge svg { width: 13px; height: 13px; }
.reels-empty { position: absolute; inset: 0; display: grid; place-items: center; color: var(--muted); font-size: 14px; }

/* lightbox de reproducción: iframe oficial de TikTok/IG sobre la web (fase35b) */
.reel-lb {
  position: fixed; inset: 0; z-index: 500; display: grid; place-items: center; padding: 22px;
  background: rgba(18, 10, 34, .74); -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px);
  opacity: 0; transition: opacity var(--t-tr) var(--ease-out);
}
.reel-lb.on { opacity: 1; }
.reel-lb-box {
  position: relative; width: min(92vw, 420px); display: flex; flex-direction: column; align-items: center; gap: 12px;
  transform: translateY(14px) scale(.98); transition: transform var(--t-sheet) var(--ease-out);
}
.reel-lb.on .reel-lb-box { transform: none; }
.reel-lb-frame {
  position: relative; z-index: 1; width: 100%; aspect-ratio: 9 / 16; max-height: 80vh;
  border-radius: 20px; overflow: hidden; background: #14101f; box-shadow: 0 30px 80px rgba(0, 0, 0, .5);
}
.reel-lb-iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; display: block; }
.reel-lb-x {
  position: absolute; z-index: 2; top: -15px; right: -7px; width: 40px; height: 40px; display: grid; place-items: center;
  border: 0; border-radius: 50%; background: #fff; color: #2a1a44; cursor: pointer; box-shadow: 0 6px 20px rgba(0, 0, 0, .3);
  transition: transform var(--t-fb) var(--ease-out);
}
.reel-lb-x:hover { transform: scale(1.06); }
.reel-lb-x svg { width: 20px; height: 20px; }
.reel-lb-open {
  color: #fff; font-size: 13px; font-weight: 700; text-decoration: none; opacity: .92;
  font-family: "Nunito Sans", system-ui, sans-serif;
}
.reel-lb-open:hover { text-decoration: underline; }

@media (max-width: 560px) {
  .reels { --reel-w: 122px; } .reels-ring, .reel-card { --reel-w: 122px; }
  .reel-lb-x { top: -8px; right: -2px; }
  /* Flotantes (2026-08-15, revisión móvil): 58px + 46px apilados en la esquina se comían el final
     de las líneas de los párrafos («…sobre todo, [FAB] poner amor»). En 390px se compactan y se
     pegan más al borde; la flecha «subir» sube lo justo para no tocar al de WhatsApp. */
  .wa-float { width: 48px; height: 48px; right: 12px; bottom: 12px; }
  .wa-float svg { width: 26px; height: 26px; }
  .to-top { width: 40px; height: 40px; right: 16px; bottom: 70px; }
  .to-top svg { width: 17px; height: 17px; }
}
/* Instrucciones que nombran el MOUSE no aplican en táctil — el «toca» de al lado ya guía.
   Va por `hover:none` (no por ancho): un tablet táctil grande tampoco tiene mouse. */
@media (hover: none) { .only-fine { display: none; } }
@media (prefers-reduced-motion: reduce) {
  .reels-stage { transition: none; opacity: 1; transform: none; }
  .reels-stage.in .reels-ring { transition: none; }
  .reel-card, .reel-card .reel-thumb { transition: none; }
  .reel-lb, .reel-lb-box { transition: none; }
  .reel-lb-box { transform: none; }
}

/* Consentimiento de analítica: aparece solo hasta aceptar/rechazar. Las dos opciones tienen el
   mismo tamaño y siguen siendo operables; nunca bloquea compra, cuenta ni navegación.
   ⚠️ Es una FRANJA COMPACTA, no una tarjeta centrada (auditoría 2026-09-09): la versión anterior
   medía 241px en un móvil de 390×844 —el 29 % de la pantalla— y dejaba el botón «Añadir al pedido»
   del PDP (y=786) literalmente INALCANZABLE en la primera visita, que es de donde llega el 71 % de
   las impresiones. Encogerlo no basta: mientras el aviso vive, `<html>` lleva `.vc-consent-on` y la
   variable `--vc-consent-h` con su ALTURA REAL medida, y todo lo que se pega al borde inferior (CTA
   del PDP, pie del checkout, WhatsApp, «subir») se apoya en ella en vez de pelearse. Es el mismo
   patrón que `html.pp-has-promo` con la barra de campaña. */
:root { --vc-consent-h: 0px; }
.vc-consent {
  position: fixed; z-index: 10050; left: 50%; bottom: max(10px, env(safe-area-inset-bottom));
  width: min(920px, calc(100% - 24px)); display: flex; align-items: center; gap: 18px;
  padding: 12px 16px; border: 1px solid var(--violet-200); border-radius: 18px;
  background: rgba(255,255,255,.97); color: var(--ink-2); box-shadow: 0 18px 52px rgba(33,27,87,.22);
  -webkit-backdrop-filter: blur(18px); backdrop-filter: blur(18px);
  transform: translate(-50%, 0); opacity: 1; transition: opacity var(--t-pop) var(--ease-out), transform var(--t-pop) var(--ease-out);
  font: 600 var(--fs-md)/1.4 "Nunito Sans", system-ui, sans-serif;
}
.vc-consent.is-leaving { opacity: 0; transform: translate(-50%, 10px); pointer-events: none; }
.vc-consent-copy { flex: 1 1 auto; min-width: 0; }
.vc-consent-copy strong { display: block; margin-bottom: 1px; color: var(--ink); font: 650 var(--fs-lg)/1.2 "Fredoka", sans-serif; }
.vc-consent-copy p { margin: 0; }
.vc-consent-copy a { color: var(--violet-700); text-decoration: underline; text-underline-offset: 2px; }
.vc-consent-actions { flex: 0 0 auto; display: grid; grid-template-columns: repeat(2, minmax(140px, 1fr)); gap: 8px; }
.vc-consent-actions button {
  min-height: 40px; padding: 8px 14px; border: 1px solid var(--violet-600); border-radius: 999px;
  background: var(--card); color: var(--violet-700); cursor: pointer; font: 800 var(--fs-md)/1.2 "Nunito Sans", sans-serif;
}
.vc-consent-actions button[data-consent="granted"] { background: var(--violet-600); color: var(--card); }
.vc-consent-actions button:hover { box-shadow: 0 7px 18px rgba(90,58,168,.18); }
.vc-consent-actions button:focus-visible, .vc-consent-copy a:focus-visible { outline: 3px solid var(--violet-300); outline-offset: 3px; }
/* Los flotantes se apoyan en el aviso mientras existe (y vuelven solos al cerrarlo). */
html.vc-consent-on .wa-float { bottom: calc(var(--vc-consent-h) + 10px); }
html.vc-consent-on .to-top { bottom: calc(var(--vc-consent-h) + 78px); }
@media (max-width: 720px) {
  /* Móvil: título y texto en UN solo párrafo continuo (el título sigue siendo el `strong` que
     nombra el diálogo para lectores de pantalla, solo deja de ocupar su propia línea) y los dos
     botones lado a lado. De 241px a ~105px. */
  .vc-consent { align-items: stretch; flex-direction: column; gap: 8px; padding: 10px 12px; border-radius: 16px; }
  .vc-consent-copy { font-size: var(--fs-sm); line-height: 1.35; }
  .vc-consent-copy strong { display: inline; margin: 0; font-size: var(--fs-md); }
  .vc-consent-copy strong::after { content: " · "; color: var(--muted); font-weight: 400; }
  .vc-consent-copy p { display: inline; }
  .vc-consent-actions { width: 100%; grid-template-columns: 1fr 1fr; gap: 8px; }
  .vc-consent-actions button { min-height: 40px; padding: 7px 8px; font-size: var(--fs-sm); }
}
@media (max-width: 420px) {
  /* Los botones SIGUEN en dos columnas (antes se apilaban y sumaban 50px de alto de más): a 390px
     el ancho útil da 170px por botón, de sobra para «Solo necesarias». */
  .vc-consent { width: calc(100% - 16px); bottom: max(8px, env(safe-area-inset-bottom)); }
}
@media (prefers-reduced-motion: reduce) {
  .vc-consent { transition: none; }
}

/* El carrusel social se declara después del bloque responsive principal; esta regla final evita
   que su geometría 3D de escritorio vuelva a ganar sobre el carril compacto del mock móvil. */
@media (max-width: 620px) {
  .reels-stage { height: 248px; padding: 2px 0 10px; overflow-x: auto; overflow-y: hidden; perspective: none; scrollbar-width: none; cursor: grab; }
  .reels-stage.is-dragging { cursor: grabbing; user-select: none; scroll-behavior: auto; }
  .reels-stage::-webkit-scrollbar { display: none; }
  .reels-ring { position: relative; inset: auto; display: flex; gap: 12px; width: 100%; height: 238px; margin: 0;
    transform: none !important; touch-action: pan-x pan-y; }
  .reel-card { position: relative; top: auto; left: auto; flex: 0 0 46%; width: auto; height: 238px; margin: 0;
    aspect-ratio: auto; transform: none !important; border-radius: 14px; }
}

/* ⚠️ Las ventanas TIENEN que solaparse con el relevo (Jean 2026-09-09: «ya no aparece la imagen
   hero; con F5 sí»). Los slides se turnan cada 6 s —16,67 % de este ciclo de 36 s— pero la ventana
   visible iba de 3 % a 14 % (≈4 s) y se apagaba en el 17 %: quedaban ~2 s por relevo en los que
   NINGÚN slide estaba pintado y el hero se veía vacío. Medido antes del arreglo: 6,2 s de cada 12
   con la suma de opacidades en CERO, un tercio largo del tiempo. Por eso recargar «lo arreglaba»
   —reinicia en el slide 1 a plena opacidad— y por eso no era cosa de Safari.
   Ahora el slide aguanta hasta el 17 % (justo cuando el siguiente empieza a subir) y se funde
   hasta el 20 %: fundido CRUZADO, sin hueco. Si algún día cambian los 6 s de relevo o los 36 s del
   ciclo, estos dos números se recalculan: mantener ≥ separación/duración. */
@keyframes heroMobileSlide {
  0%, 100% { opacity: 0; }
  3%, 17% { opacity: 1; }
  20% { opacity: 0; }
}

@media (max-width: 620px) and (prefers-reduced-motion: reduce) {
  .hero-mobile-slides > span { animation: none; opacity: 0; }
  .hero-mobile-slides > span:first-child { opacity: 1; }
}

/* Reseñas de Google — mientras la web no tenga opiniones propias, las de Google Maps son la única
   prueba social pública que existe. Enlaces, no widget: el de Google carga scripts de terceros que
   la CSP no admite y penalizaría el LCP que acabamos de bajar. */
.rev-gmaps { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 16px; }
.rev-gmaps-a {
  display: inline-flex; align-items: center; min-height: 44px; padding: 10px clamp(18px, 1.4vw, 26px); border-radius: 999px;
  font-weight: 700; font-size: clamp(14px, 1vw, 19px); text-decoration: none;
  background: var(--grad); color: #fff; box-shadow: var(--shadow-sm);
  transition: transform var(--t-pop) var(--ease-out), box-shadow var(--t-pop) var(--ease-out); position: relative;
}
.rev-gmaps-a::after { content: ""; position: absolute; inset: -4px; z-index: -1; border-radius: inherit; }
.rev-gmaps-a:hover { transform: translateY(-2px); box-shadow: var(--shadow); }
.rev-gmaps-a--soft { background: rgba(124, 79, 208, .08); color: var(--violet-700); box-shadow: none; }
@media (prefers-reduced-motion: reduce) {
  .rev-gmaps-a { transition: none !important; }
  .rev-gmaps-a:hover { transform: none; }
}

/* ===== fase119 · Reto Violeta — mensaje ÚNICO en portada (.reto-strip) · PDP (.reto-banner--compact) · landings
   (.reto-banner) · cabecera de /reto/. Mock de Jean 2026-09-06: franja lavanda MUY clara, gato con celular a la
   izquierda (assets suyos: /landing/reto/gato-reel.webp y corazon-doodle.webp), frase serif centrada en dos pesos,
   botón pastilla lila con texto oscuro, corazón doodle a la derecha. Sin más adornos. Tokens: --violet-100/300 + --ink.
   El detalle vive en /reto/. ===== */
/* fondo = lavanda GRIS del mock (mezcla del --bg del sitio con violet-200, no el violet-100 azulado); botón lila medio con texto
   blanco: violet-500 (4.16:1) pasa AA porque el texto del botón es grande (≥18.66px semibold → umbral 3:1) */
:root { --reto-bg: color-mix(in srgb, var(--bg) 70%, var(--violet-200)); --reto-ink: var(--ink); --reto-btn: var(--violet-500); --reto-btn-ink: #fff;
  /* tipografía serif del sistema como la referencia (sin descargar otra fuente) */
  --reto-font: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, "Times New Roman", serif; }
.reto-banner, .reto-strip { position: relative; background: var(--reto-bg); color: var(--reto-ink); border-radius: 26px; text-decoration: none; overflow: clip; }
/* landings: bloque centrado, texto grande + botón pastilla (como el «Learn More» de la referencia) */
.reto-banner { display: flex; flex-direction: column; align-items: center; gap: 16px; text-align: center; margin-top: 28px; padding: clamp(26px, 3.4vw, 44px) clamp(18px, 3vw, 40px); }
.reto-banner-t { position: relative; font: 600 clamp(22px, 2.3vw, 36px)/1.22 var(--reto-font); max-width: 30ch; }
.reto-banner-cta, .reto-strip-cta { display: inline-flex; align-items: center; justify-content: center; gap: 10px; min-height: 44px; padding: 10px 32px; border-radius: 999px; background: var(--reto-btn); color: var(--reto-btn-ink); font: 600 clamp(17px, 1.2vw, 20px)/1 var(--reto-font); text-decoration: none; position: relative; transition: transform var(--t-pop) var(--ease-out), filter var(--t-pop) var(--ease-out); }
.reto-banner:hover .reto-banner-cta, .reto-strip-cta:hover { filter: brightness(1.05); transform: translateY(-1px); }
.reto-banner:focus-visible, .reto-strip-cta:focus-visible { outline: 3px solid var(--violet-600); outline-offset: 3px; }
/* PDP: a todo el ancho sobre la banda «Lo que necesitas saber», con el gato a la izquierda (solo el gato) */
.reto-banner--gato { display: grid; grid-template-columns: minmax(80px, 104px) minmax(0, 1fr); align-items: center; gap: clamp(10px, 1.6vw, 24px); text-align: center; margin: 24px 0 0; padding: clamp(10px, 1.1vw, 16px) clamp(16px, 2.4vw, 36px) clamp(10px, 1.1vw, 16px) clamp(12px, 1.4vw, 22px); }
.reto-banner-gato { width: 100%; max-width: 104px; height: auto; justify-self: center; pointer-events: none; user-select: none; }
.reto-banner--gato .reto-banner-t { font-size: clamp(17px, 1.4vw, 22px); max-width: none; text-wrap: balance; }
.reto-banner--gato:hover .reto-banner-t { text-decoration: underline; text-underline-offset: 4px; text-decoration-thickness: 1px; }
/* portada: gato | texto centrado + botón | corazón */
.sec-reto { padding: clamp(18px, 2.2vw, 34px) 0 0; }
.reto-strip { display: grid; grid-template-columns: minmax(130px, 170px) minmax(0, 1fr) minmax(110px, 160px); align-items: center; gap: clamp(12px, 2vw, 28px); padding: clamp(16px, 1.8vw, 26px) clamp(20px, 2.6vw, 40px); min-height: 0; }
.reto-strip-gato { width: 100%; max-width: 165px; height: auto; justify-self: center; align-self: center; margin: 0; pointer-events: none; user-select: none; }
.reto-strip-corazon { width: clamp(80px, 7.5vw, 120px); height: auto; justify-self: end; align-self: center; margin-right: clamp(4px, 1vw, 18px); pointer-events: none; user-select: none; }
.reto-strip-txt { display: flex; flex-direction: column; align-items: center; gap: clamp(10px, 1.1vw, 14px); text-align: center; min-width: 0; }
.reto-strip-t { margin: 0; max-width: 100%; font-family: var(--reto-font); line-height: 1.2; color: var(--reto-ink); text-wrap: balance; }
.reto-strip-t1, .reto-strip-t2 { display: block; }
.reto-strip-t1 { font-weight: 600; font-size: clamp(21px, 1.85vw, 32px); letter-spacing: -.005em; }
.reto-strip-t2 { font-weight: 400; font-size: clamp(16px, 1.35vw, 23px); margin-top: 2px; }
@media (max-width: 900px) {
  .reto-strip { grid-template-columns: minmax(110px, 150px) minmax(0, 1fr); }
  .reto-strip-corazon { display: none; }
}
@media (max-width: 720px) {
  .reto-banner { padding: 22px 18px; }
  .reto-banner--gato { grid-template-columns: 1fr; gap: 8px; }
  .reto-banner-gato { max-width: 80px; }
  .reto-strip { grid-template-columns: 1fr; padding: 18px 16px 16px; gap: 8px; }
  .reto-strip-gato { max-width: 100px; margin-bottom: 0; }
  .reto-strip-t1 { font-size: 21px; }
  .reto-strip-t2 { font-size: 17px; }
  .reto-strip-cta { width: min(100%, 300px); }
}
/* fase155: con mascota el recuadro es el de toda la marca (radio 32.5 %, nunca círculo) */
.rev-ava.has-pet { border-radius: 32.5%; background: none; overflow: hidden; box-shadow: 0 0 0 1px rgba(40, 20, 80, .08); }
.rev-ava.has-pet svg { width: 100%; height: 100%; display: block; }

/* Reseñas: mismo SVG y pastel que ficha; jerarquía neutra y aire en móvil. */
.sec-social .sec-title::after { background:#e4e4e9; }
.sec-social .rev-stars svg, .sec-social .rev-score svg { stroke:none; }
.sec-social .rev-gmaps-a { background:#f3f3f6; color:var(--ink-2); box-shadow:none; min-height:44px; }
.sec-social .rev-gmaps-a--soft { background:var(--violet-200); color:var(--violet-700); }
@media (hover:hover) and (pointer:fine) {
  .sec-social .rev-gmaps-a:hover { background:#eaeaf0; box-shadow:none; }
  .sec-social .rev-gmaps-a--soft:hover { background:#d3c2f3; }
}
@media(max-width:640px) {
  .sec-social .rev-head { display:flex; flex-direction:column; align-items:stretch; gap:24px; margin-bottom:32px; }
  .sec-social .rev-gmaps { margin-top:20px; gap:12px; }
  .sec-social .rev-gmaps-a { padding:12px 15px; font-size:13px; }
  .sec-social .rev-score { gap:16px; padding:0 2px; }
  .sec-social .rev-row .rev-card { padding:24px 22px; }
  .sec-social .rev-stars { margin-bottom:16px; gap:6px; }
}
