/**
 * catalogo-style.css
 * Estilos del catálogo de fragancias. Tipografía editorial (Cormorant
 * Garamond + Jost) y layout de secciones apiladas por categoría, en dos
 * temas: oscuro (el diseño original, sigue siendo el default) y claro
 * (alternativa que activa el interruptor de catalogo-theme.js agregando
 * data-theme="light" en <html>).
 *
 * Las fuentes (Cormorant Garamond, Jost, Parisienne) se cargan desde
 * <link> en el <head> de index.html en vez de @import acá: así el
 * navegador las descubre y empieza a bajarlas en paralelo con este CSS,
 * en lugar de esperar a que este archivo termine de cargar primero.
 *
 * Todo el CSS de acá en más lee color SIEMPRE a través de estas
 * variables (nunca un hex/rgba suelto para texto o fondo de superficie):
 * así alcanza con redefinirlas para que el diseño oscuro y el claro
 * compartan exactamente las mismas reglas. Las pocas excepciones
 * deliberadas (el sello "Imagen de referencia", los botones flotantes de
 * WhatsApp/carrito/volver arriba, el sweep de brillo sobre los botones
 * dorados) quedan comentadas en el lugar donde aparecen.
 */

:root{
  --bg: #14110D;
  /* Triplete r,g,b de --bg: lo usa la barra de filtros sticky para su
     vidrio translúcido (rgba(var(--bg-rgb),0.78)). */
  --bg-rgb: 20,17,13;
  --bg-panel: #1B1712;
  /* Fondo de la miniatura/foto de cada frasco: tiene que quedarse CLARO
     en los dos temas (la foto real se compone encima con mix-blend-mode:
     multiply — sobre un chip oscuro esa mezcla ensucia la imagen). */
  --paper-chip: #EDE5D4;
  --ink: #EDE7DA;
  --ink-soft: #9C9384;
  --ink-faint: #6E6656;
  --wine: #C6485E;
  --wine-deep: #E06B80;
  /* Triplete r,g,b de --wine, para washes translúcidos (rgba(var(--wine-rgb),X)). */
  --wine-rgb: 198,72,94;
  --pine: #6F9C7C;
  --pine-deep: #8FBB9B;
  --brass: #C9A25B;
  --brass-soft: #DCC087;
  --hair: rgba(237,231,218,0.12);
  --glow-rgb: 201,162,91;
  /* Triplete r,g,b de --ink, para washes/tracks translúcidos armados con
     rgba() (un solo rgba(var(--ink-rgb),X) sirve para los dos temas: en
     oscuro aclara sutilmente al pasar el mouse, en claro oscurece). */
  --ink-rgb: 237,231,218;
  /* Texto/ícono sobre los botones con degradé dorado (brass/brass-soft):
     oscuro en el tema oscuro (donde el dorado es claro), claro en el
     tema claro (donde el dorado se oscurece para tener contraste sobre
     el fondo). */
  --btn-ink: #241a0a;
  /* Estado "agregado" del botón de la card de previsualización: un
     sello propio, independiente del dorado normal del botón. */
  --confirm-bg-a: #fff8ea;
  --confirm-bg-b: #EDE5D4;
  --confirm-ink: #241a0a;
  /* Chip translúcido de los botones de cerrar (preview/notas). */
  --overlay-chip: rgba(20,17,13,0.6);
  /* mix-blend-mode de la luz que sigue al cursor: "screen" aclara (sirve
     sobre el fondo oscuro), pero sobre un fondo claro un blend "screen"
     queda invisible (nunca puede aclarar más que blanco). */
  --glow-blend: screen;
  /* Sombra que proyecta el borde inferior de la cortina sobre el
     catálogo mientras se levanta (más liviana en modo claro). */
  --curtain-shadow: rgba(0,0,0,0.55);

  /* ---- Sistema de movimiento ----
     Todas las transiciones del sitio leen de estas curvas y duraciones
     (nunca un cubic-bezier suelto) para que abrir un modal, revelar una
     sección o levantar la cortina se sientan como parte de una misma
     familia y no como efectos pegados de distintos lugares.
     - ease-out-expo: entradas (arranca rápido, se asienta largo y suave).
     - ease-in-soft:  salidas (se va sin frenar: lo que desaparece no
                      tiene por qué "aterrizar").
     - ease-in-out:   desplazamientos de un lugar a otro (la cortina,
                      el thumb del interruptor de tema). */
  --ease-out-expo: cubic-bezier(.16,1,.3,1);
  --ease-out-quart: cubic-bezier(.25,1,.5,1);
  --ease-in-soft: cubic-bezier(.4,0,.7,.2);
  --ease-in-out: cubic-bezier(.65,0,.2,1);
  --dur-fast: 0.22s;
  --dur-base: 0.45s;
  --dur-slow: 0.8s;
}

/* ---------- MODO CLARO ---------- */
:root[data-theme="light"]{
  --bg: #F6F0E3;
  --bg-rgb: 246,240,227;
  --bg-panel: #FFFFFF;
  --paper-chip: #EFE6D2;
  --ink: #241A12;
  --ink-soft: #6B5C48;
  --ink-faint: #A69880;
  --wine: #A23349;
  --wine-deep: #7A2536;
  --wine-rgb: 162,51,73;
  --pine: #4B7A5B;
  --pine-deep: #386047;
  --brass: #8A6528;
  --brass-soft: #B4914A;
  --hair: rgba(36,26,18,0.14);
  --glow-rgb: 138,101,40;
  --ink-rgb: 36,26,18;
  --btn-ink: #FBF7EE;
  --confirm-bg-a: #2A2118;
  --confirm-bg-b: #241A12;
  --confirm-ink: #F6F0E3;
  --overlay-chip: rgba(255,255,255,0.7);
  --glow-blend: multiply;
  --curtain-shadow: rgba(36,26,18,0.22);
}

*{ box-sizing:border-box; }

@media (prefers-reduced-motion: reduce){
  *{ animation-duration:0.001ms !important; animation-iteration-count:1 !important; transition-duration:0.001ms !important; scroll-behavior:auto !important; }
}

html{ scroll-behavior:smooth; }

body{
  margin:0;
  background:var(--bg);
  color:var(--ink);
  font-family:'Jost', sans-serif;
  font-weight:400;
  -webkit-font-smoothing:antialiased;
  position:relative;
}

body::before{
  content:'';
  position:fixed;
  inset:0;
  background:radial-gradient(ellipse 60% 40% at 50% 0%, rgba(var(--glow-rgb),0.08), transparent 65%);
  pointer-events:none;
  z-index:0;
}

/* ---------- CURSOR LIGHT ---------- */
.cursor-glow{
  position:fixed;
  top:0;
  left:0;
  width:560px;
  height:560px;
  margin:-280px 0 0 -280px;
  border-radius:50%;
  background:radial-gradient(circle, rgba(var(--glow-rgb),0.18) 0%, rgba(var(--glow-rgb),0.06) 38%, transparent 70%);
  mix-blend-mode:var(--glow-blend);
  pointer-events:none;
  z-index:4;
  opacity:0;
  transition:opacity 0.5s ease;
  will-change:transform;
}
.cursor-glow.is-active{ opacity:1; }

/* Transición pareja de todas las superficies al alternar data-theme,
   para que el cambio se sienta como un fundido y no como un corte.
   prefers-reduced-motion la desactiva más abajo, junto con el resto de
   las animaciones del sitio. */
body, .filter-bar, .cart-panel, .preview-slide-inner, .preview-body,
.notes-panel, .thumb-wrap, .preview-media, .item, .cart-add-btn,
.notes-stat-track{
  transition:background 0.35s ease, background-color 0.35s ease, color 0.35s ease, border-color 0.35s ease;
}

/* ---------- INTERRUPTOR DE TEMA (claro / oscuro) ---------- */
/* Vive dentro de .filter-controls (ver .filter-search-toggle, al lado):
   puesto como botón fijo aparte chocaba con la barra de filtros en
   cuanto esta queda sticky arriba de todo. A diferencia de los 3
   botones flotantes que sí quedan fijos (WhatsApp, volver arriba,
   carrito) —que mantienen un badge oscuro a propósito, como un sello—
   este representa el tema en sí, así que usa los tokens normales para
   que se vea "puesto" en la superficie de cada tema.
   Mecánica tipo pill-switch (thumb que desliza de un extremo al otro),
   pero sin el texto "on/off" ni el color puro de una referencia de UI
   genérica: el riel queda sobrio (mismo --hair/--bg-panel que el resto
   de los controles de la barra) y el thumb dorado lleva el ícono de
   sol/luna en vez de una flecha, coherente con el resto del sitio. */
.theme-toggle{
  -webkit-appearance:none;
  appearance:none;
  position:relative;
  width:74px;
  height:40px;
  padding:0;
  flex-shrink:0;
  border-radius:999px;
  border:1px solid var(--hair);
  background:var(--bg-panel);
  cursor:pointer;
  transition:border-color 0.2s ease, background 0.35s ease;
}
.theme-toggle:hover{ border-color:var(--brass-soft); }
.theme-toggle-thumb{
  position:absolute;
  top:3px;
  left:3px;
  width:34px;
  height:34px;
  border-radius:50%;
  display:flex;
  align-items:center;
  justify-content:center;
  background:linear-gradient(135deg, var(--brass-soft), var(--brass));
  color:var(--btn-ink);
  box-shadow:0 3px 8px rgba(0,0,0,0.3);
  transition:transform 0.5s var(--ease-in-out);
}
.theme-toggle:active .theme-toggle-thumb{ transform:scale(0.88); transition-duration:0.15s; }
:root[data-theme="light"] .theme-toggle{ background:rgba(var(--glow-rgb),0.14); }
:root[data-theme="light"] .theme-toggle-thumb{ transform:translateX(37px); }
:root[data-theme="light"] .theme-toggle:active .theme-toggle-thumb{ transform:translateX(37px) scale(0.88); }
/* El thumb siempre muestra el ícono del tema ACTIVO (luna = oscuro
   puesto, sol = claro puesto), como en cualquier switch día/noche
   conocido: la posición y el ícono cuentan la misma historia. Los dos
   íconos viven superpuestos y se cruzan con un giro corto mientras el
   thumb viaja, en vez de intercambiarse de golpe con display:none. */
.theme-icon{
  position:absolute;
  width:20px;
  height:20px;
  transition:opacity 0.3s ease, transform 0.5s var(--ease-in-out);
}
.theme-icon-sun{ opacity:0; transform:rotate(-90deg) scale(0.6); }
.theme-icon-moon{ opacity:1; transform:rotate(0) scale(1); }
:root[data-theme="light"] .theme-icon-sun{ opacity:1; transform:rotate(0) scale(1); }
:root[data-theme="light"] .theme-icon-moon{ opacity:0; transform:rotate(90deg) scale(0.6); }

.wrap{
  max-width:1180px;
  margin:0 auto;
  padding:0 32px;
}

/* ---------- CORTINA DE APERTURA ---------- */
/* El "giro" inicial (kicker + título + trust-bar) ocupa toda la pantalla,
   tanto en mobile como en desktop, como una cortina fija (position:fixed,
   siempre 100dvh) por encima de todo el resto del sitio. No es scroll-
   jacking del sitio entero: catalogo-app.js (initHeroCurtain) solo
   controla el límite entre la cortina y el catálogo, y ahí sí cada
   gesto de scroll/swipe es un salto discreto de una sola vez (no un
   scroll gradual) — se levanta del todo con un solo scroll hacia abajo
   y reaparece del todo con un solo scroll hacia arriba estando en el
   tope del catálogo. La transición la hace este CSS con .curtain-hidden;
   el JS solo agrega/saca esa clase y reposiciona el scroll al límite
   exacto (ver el comentario de closeCurtain en catalogo-app.js).
   .curtain-spacer reserva 100dvh en el flujo del documento (la cortina
   en sí no ocupa espacio por ser fixed) para que la barra de filtros y
   las colecciones arranquen justo donde la cortina termina de irse.

   Coreografía al levantarse (y la inversa al volver):
     1. El contenido del hero (kicker, título, lede, trust-bar) se
        despide primero, escalonado y rápido, subiendo apenas.
     2. El plano de la cortina —OPACO, nunca se desvanece: un fundido
        sobre un plano que además se traslada deja ver el catálogo "a
        través" de la cortina y se lee turbio— sube entero con una
        curva in-out, proyectando una sombra sobre lo que va destapando
        y con un filo dorado en su borde inferior, como el bajo de una
        cortina real.
     3. El catálogo no está simplemente "ahí" esperando: la barra de
        filtros y las primeras secciones entran recién cuando el borde
        de la cortina ya las destapó (ver html.curtain-open y
        --reveal-delay más abajo). */
.curtain-stage{
  position:fixed;
  inset:0;
  height:100vh;
  height:100dvh;
  z-index:45;
  /* overflow-y:auto (no "hidden") a propósito: en teléfonos angostos
     con las 4 filas del trust-bar apiladas, kicker+título+botón+
     trust-bar puede superar el alto real del viewport. Con overflow
     oculto esas filas de más quedarían recortadas sin aviso; con auto,
     en el peor caso el contenido scrollea adentro de la cortina en vez
     de perderse (initHeroCurtain deja pasar ese scroll interno antes de
     levantar la cortina — ver curtainInternalScrollExhausted). .wrap
     centra verticalmente vía min-height:100% en lugar de flex+
     align-items en este contenedor, porque un flex centrado con
     overflow:auto recorta el borde inicial del contenido quieto ("safe
     center" no tiene soporte parejo todavía). */
  overflow-y:auto;
  background:var(--bg);
  border-bottom:1px solid rgba(var(--glow-rgb),0.28);
  box-shadow:0 30px 80px -10px var(--curtain-shadow);
  transform:translate3d(0,0,0);
  transition:transform 1s var(--ease-in-out);
  will-change:transform;
}
/* Un solo gesto de scroll/swipe (ver initHeroCurtain) agrega esta clase:
   la cortina se va hacia arriba con la transición de arriba; sacarla la
   trae de vuelta bajando desde arriba, con la misma curva — la animación
   es una sola y reversible, no dos efectos distintos para abrir/cerrar. */
.curtain-stage.curtain-hidden{
  transform:translate3d(0,-100%,0);
  pointer-events:none;
}
.curtain-stage::before{
  content:'';
  position:fixed;
  inset:0;
  background:radial-gradient(ellipse 60% 45% at 50% 0%, rgba(var(--glow-rgb),0.1), transparent 65%);
  pointer-events:none;
}
.curtain-stage .wrap{
  position:relative;
  z-index:1;
  min-height:100%;
  display:flex;
  flex-direction:column;
  justify-content:center;
  padding-top:24px;
  padding-bottom:24px;
}

/* ---- Entrada / salida escalonada del contenido del hero ----
   Un único mecanismo (transiciones + un índice --i por pieza) cubre los
   tres momentos: la aparición al cargar la página (html.is-ready la
   dispara, ver el <script> del <head>), la despedida al levantar la
   cortina y el regreso al bajarla. Antes la carga usaba @keyframes con
   fill-mode y la cortina otra transición aparte: dos sistemas que
   además se pisaban (una animación con fill "both" gana siempre sobre
   una transición de la misma propiedad). */
.kicker{ --i:0; }
h1.title{ --i:1; }
p.lede{ --i:2; }
.cta-jump{ --i:3; }
.trust-item:nth-child(1){ --i:4; }
.trust-item:nth-child(2){ --i:5; }
.trust-item:nth-child(3){ --i:6; }
.trust-item:nth-child(4){ --i:7; }
.cta-jump-desktop{ --i:8; }
.curtain-scroll-cue{ --i:9; }

.kicker, h1.title, p.lede, .cta-jump, .trust-item, .curtain-scroll-cue{
  opacity:0;
  transform:translate3d(0,18px,0);
  transition:opacity 0.9s var(--ease-out-expo), transform 0.9s var(--ease-out-expo);
  transition-delay:calc(0.12s + var(--i) * 0.08s);
}
html.is-ready .curtain-stage:not(.curtain-hidden) :is(.kicker, h1.title, p.lede, .cta-jump, .trust-item, .curtain-scroll-cue){
  opacity:1;
  transform:translate3d(0,0,0);
}
/* Al levantar la cortina, el contenido se va rápido y hacia arriba
   (acompaña la dirección del plano) con un escalonado mínimo: la
   despedida no tiene por qué ser tan ceremoniosa como la llegada. */
.curtain-stage.curtain-hidden :is(.kicker, h1.title, p.lede, .cta-jump, .trust-item, .curtain-scroll-cue){
  opacity:0;
  transform:translate3d(0,-16px,0);
  transition-duration:0.45s;
  transition-timing-function:var(--ease-in-soft);
  transition-delay:calc(var(--i) * 0.025s);
}
/* Al volver a bajar la cortina, el contenido espera a que el plano ya
   esté casi asentado antes de reaparecer (si no, se ve moverse dentro
   de un plano que todavía está cayendo). */
html.is-ready .curtain-stage.curtain-returning :is(.kicker, h1.title, p.lede, .cta-jump, .trust-item, .curtain-scroll-cue){
  transition-delay:calc(0.5s + var(--i) * 0.07s);
}

.curtain-spacer{ height:100vh; height:100dvh; }

/* Centrado con margin:auto (no con translateX(-50%)): el transform lo
   usa la entrada/salida escalonada de arriba. */
.curtain-scroll-cue{
  position:absolute;
  left:0;
  right:0;
  width:max-content;
  margin:0 auto;
  bottom:clamp(20px, 4vh, 40px);
  z-index:1;
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:6px;
  background:none;
  border:none;
  padding:6px 10px;
  cursor:pointer;
  color:var(--ink-faint);
  font-family:'Jost', sans-serif;
  font-size:10.5px;
  letter-spacing:0.12em;
  text-transform:uppercase;
  text-align:center;
}
.curtain-scroll-cue svg{
  width:17px;
  height:17px;
  animation:curtainCueBounce 1.8s ease-in-out infinite;
}
@keyframes curtainCueBounce{
  0%, 100%{ transform:translateY(0); opacity:0.65; }
  50%{ transform:translateY(6px); opacity:1; }
}

/* ---------- HERO ---------- */
header.hero{
  position:relative;
  z-index:1;
  padding:0;
  text-align:center;
}
@keyframes fadeUp{
  from{ opacity:0; transform:translateY(18px); }
  to{ opacity:1; transform:translateY(0); }
}

.kicker{
  font-family:'Parisienne', cursive;
  font-size:clamp(30px, 4.4vw, 44px);
  font-weight:400;
  letter-spacing:0.01em;
  color:var(--brass-soft);
  line-height:1;
  margin-bottom:2px;
}
/* La línea bajo el kicker se dibuja desde el centro hacia afuera un
   instante después de que aparece el texto, y se recoge al levantar la
   cortina. */
.kicker::after{
  content:'';
  display:block;
  width:42px;
  height:1px;
  margin:16px auto 0;
  background:linear-gradient(90deg, transparent, var(--brass), transparent);
  opacity:0.7;
  transform:scaleX(0);
  transition:transform 0.9s var(--ease-out-expo) 0.55s;
}
html.is-ready .curtain-stage:not(.curtain-hidden) .kicker::after{ transform:scaleX(1); }
.curtain-stage.curtain-hidden .kicker::after{ transition:transform 0.35s var(--ease-in-soft); }
html.is-ready .curtain-stage.curtain-returning .kicker::after{ transition-delay:0.95s; }
h1.title{
  font-family:'Cormorant Garamond', serif;
  font-weight:400;
  font-size:clamp(42px, 6vw, 74px);
  line-height:1.02;
  margin:22px 0 26px;
  color:var(--ink);
}
h1.title em{
  font-style:italic;
  font-weight:500;
  background:linear-gradient(100deg, var(--brass-soft), var(--wine-deep) 120%);
  -webkit-background-clip:text;
  background-clip:text;
  color:transparent;
}
p.lede{
  max-width:620px;
  margin:0 auto;
  font-size:17px;
  line-height:1.65;
  color:var(--ink-soft);
}

/* ---------- CTA "VER FRAGANCIAS" (solo mobile) ---------- */
.cta-jump{
  display:none;
  position:relative;
  overflow:hidden;
  align-items:center;
  justify-content:center;
  gap:10px;
  margin:30px auto 6px;
  padding:16px 34px;
  border:1px solid rgba(255,244,224,0.5);
  border-radius:999px;
  cursor:pointer;
  font-family:'Jost', sans-serif;
  font-size:14.5px;
  font-weight:600;
  letter-spacing:0.05em;
  color:var(--btn-ink);
  background:linear-gradient(135deg, var(--brass-soft), var(--brass) 50%, var(--brass-soft));
  background-size:220% 220%;
  box-shadow:0 10px 26px rgba(var(--glow-rgb),0.4), 0 1px 0 rgba(255,255,255,0.4) inset;
  animation:ctaSheen 5s linear 0.65s infinite,
            ctaGlow 3.2s ease-in-out 0.65s infinite;
  -webkit-tap-highlight-color:transparent;
}
/* La opacidad/posición de reposo las maneja la entrada escalonada del
   hero; al presionar solo se acorta la transición para que el feedback
   sea inmediato. */
.cta-jump:active{ transform:scale(0.96); transition-duration:0.15s; transition-delay:0s; }
.cta-jump-shine{
  position:absolute;
  top:0;
  left:-60%;
  width:35%;
  height:100%;
  background:linear-gradient(115deg, transparent, rgba(255,255,255,0.65), transparent);
  transform:skewX(-20deg);
  animation:ctaShine 3.4s ease-in-out 0.65s infinite;
}
.cta-jump-arrow{
  width:16px;
  height:16px;
  flex-shrink:0;
  animation:ctaBounce 1.6s ease-in-out infinite;
}
@keyframes ctaSheen{
  0%, 100%{ background-position:0% 50%; }
  50%{ background-position:100% 50%; }
}
@keyframes ctaGlow{
  0%, 100%{ box-shadow:0 10px 26px rgba(var(--glow-rgb),0.4), 0 1px 0 rgba(255,255,255,0.4) inset; }
  50%{ box-shadow:0 14px 36px rgba(var(--glow-rgb),0.65), 0 1px 0 rgba(255,255,255,0.5) inset; }
}
@keyframes ctaShine{
  0%{ left:-60%; }
  55%, 100%{ left:130%; }
}
@keyframes ctaBounce{
  0%, 100%{ transform:translateY(0); }
  50%{ transform:translateY(3px); }
}
@media (max-width:768px){
  .cta-jump{ display:inline-flex; }
}

/* ---------- CTA "VER FRAGANCIAS" (solo desktop, tras el trust-bar) ---------- */
.cta-jump-desktop{ display:inline-flex; margin:34px auto 0; }
@media (max-width:768px){
  .cta-jump-desktop{ display:none; }
}

/* ---------- TRUST BAR ---------- */
.trust-bar{
  list-style:none;
  display:flex;
  flex-wrap:wrap;
  justify-content:center;
  max-width:960px;
  margin:44px auto 0;
  padding:0;
  border-top:1px solid var(--hair);
}
.trust-item{
  flex:1 1 210px;
  display:flex;
  align-items:center;
  gap:13px;
  text-align:left;
  padding:22px 22px;
  border-left:1px solid var(--hair);
  border-bottom:1px solid var(--hair);
}
.trust-item:first-child{ border-left:none; }

.trust-icon{
  flex-shrink:0;
  width:36px;
  height:36px;
  border-radius:50%;
  display:flex;
  align-items:center;
  justify-content:center;
  color:var(--brass-soft);
  background:rgba(var(--glow-rgb),0.08);
  transition:transform 0.35s ease, background 0.35s ease;
}
.trust-icon svg{ width:18px; height:18px; }
.trust-item:hover .trust-icon{
  transform:scale(1.12) rotate(-6deg);
  background:rgba(var(--glow-rgb),0.18);
}
.trust-copy{ display:flex; flex-direction:column; gap:3px; min-width:0; }
.trust-copy strong{
  font-size:13.5px;
  font-weight:500;
  letter-spacing:0.02em;
  color:var(--ink);
}
.trust-copy small{
  font-size:11.5px;
  letter-spacing:0.02em;
  color:var(--ink-faint);
  line-height:1.4;
}

/* ---------- FILTER BAR ---------- */
.filter-bar{
  position:sticky;
  top:0;
  z-index:10;
  padding:22px 32px;
  border-bottom:1px solid var(--hair);
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  justify-content:center;
  gap:14px;
  background:rgba(var(--bg-rgb),0.78);
  backdrop-filter:blur(14px);
  -webkit-backdrop-filter:blur(14px);
  /* Está arriba de todo, así que es lo ÚLTIMO que la cortina (que sube)
     destapa: su retardo lo calcula catalogo-app.js (--reveal-delay en
     línea, ver scheduleArrival) para que entre justo detrás del borde,
     y se retira de inmediato cuando la cortina vuelve a bajar. El
     color/fondo conservan la transición de cambio de tema. */
  opacity:1;
  transform:translate3d(0,0,0);
  transition:opacity 0.8s var(--ease-out-expo) var(--reveal-delay),
             transform 0.8s var(--ease-out-expo) var(--reveal-delay),
             background-color 0.35s ease, border-color 0.35s ease, color 0.35s ease;
}
html.curtain-open .filter-bar{
  opacity:0;
  transform:translate3d(0,-12px,0);
  transition-duration:0.3s, 0.3s, 0.35s, 0.35s, 0.35s;
  transition-delay:0s;
}
.filter-group{
  display:flex;
  gap:8px;
  flex-wrap:wrap;
  justify-content:center;
}
/* ---------- BRILLO REUTILIZABLE ---------- */
/* Franja de luz diagonal que recorre el elemento; se agrega como
   <span class="btn-shine"> dentro de cualquier botón/control con
   position:relative + overflow:hidden. */
.btn-shine{
  position:absolute;
  top:0;
  left:-60%;
  width:35%;
  height:100%;
  background:linear-gradient(115deg, transparent, rgba(255,255,255,0.55), transparent);
  transform:skewX(-20deg);
  pointer-events:none;
  animation:ctaShine 3.6s ease-in-out infinite;
}

.filter-btn{
  position:relative;
  overflow:hidden;
  font-family:'Jost', sans-serif;
  font-size:13px;
  letter-spacing:0.04em;
  color:var(--ink-soft);
  background:transparent;
  border:1px solid var(--hair);
  border-radius:999px;
  padding:9px 20px;
  cursor:pointer;
  transition:color var(--dur-fast) ease, border-color var(--dur-fast) ease, background var(--dur-fast) ease,
             box-shadow 0.3s ease, transform var(--dur-fast) var(--ease-out-quart);
}
/* El barrido de luz queda reservado al chip activo (y a las CTAs
   doradas): cuatro chips secundarios brillando en loop compiten entre
   sí y con el contenido. Los inactivos responden solo al hover. */
.filter-btn:not(.active) .btn-shine{ display:none; }
.filter-btn:hover{
  color:var(--ink);
  border-color:var(--brass-soft);
  box-shadow:0 4px 16px rgba(var(--glow-rgb),0.18);
  transform:translateY(-1px);
}
.filter-btn:active{ transform:scale(0.96); transition-duration:0.1s; }
.filter-btn.active{
  color:var(--btn-ink);
  font-weight:600;
  background:linear-gradient(135deg, var(--brass-soft), var(--brass) 50%, var(--brass-soft));
  background-size:220% 220%;
  border-color:transparent;
  box-shadow:0 8px 22px rgba(var(--glow-rgb),0.4), 0 1px 0 rgba(255,255,255,0.35) inset;
  animation:ctaSheen 5s linear infinite, ctaGlow 3.2s ease-in-out infinite;
}
.filter-btn.active .btn-shine{ opacity:0.7; }
.filter-divider{
  width:1px;
  height:22px;
  background:var(--hair);
  margin:0 4px;
}
/* Agrupa el select de marca y el círculo de búsqueda para poder
   ponerlos en la misma fila en mobile (el select estirándose a ocupar
   el espacio, el círculo quedando a su tamaño fijo al lado) sin que el
   círculo termine solo en su propia fila con un hueco vacío al lado. */
.filter-controls{
  display:flex;
  align-items:center;
  gap:14px;
}
.filter-select-wrap{
  position:relative;
  overflow:hidden;
  border-radius:999px;
  display:inline-flex;
  transition:box-shadow 0.3s ease;
}
.filter-select-wrap:hover,
.filter-select-wrap:focus-within{
  box-shadow:0 4px 16px rgba(var(--glow-rgb),0.2);
}
/* Mismo criterio que los chips inactivos: el select no es una CTA. */
.filter-select-wrap .btn-shine{ display:none; }
.filter-select{
  font-family:'Jost', sans-serif;
  font-size:13px;
  letter-spacing:0.02em;
  color:var(--ink);
  background:var(--bg-panel);
  border:1px solid var(--hair);
  border-radius:999px;
  padding:9px 36px 9px 20px;
  cursor:pointer;
  appearance:none;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6'><path d='M0 0l5 6 5-6z' fill='%239C9384'/></svg>");
  background-repeat:no-repeat;
  background-position:right 16px center;
  transition:border-color 0.2s ease;
}
.filter-select:hover,
.filter-select:focus{ border-color:var(--brass-soft); outline:none; }

/* Sobrio: por default el buscador es solo un círculo con la lupa, sin
   texto invitando a escribir. Tocarlo revela el campo de texto (con su
   propia lupa más chica y una X para cerrarlo); cerrarlo vuelve a dejar
   solo el círculo. Los dos estados (.filter-search-toggle / -box) viven
   en el mismo wrapper y alternan con la clase .is-open puesta por
   catalogo-app.js, nunca los dos visibles a la vez.
   El cambio no es un corte (display:none): el propio círculo se
   ensancha hasta ser el campo de texto (el wrapper anima su ancho vía
   flex-basis, así que los controles vecinos se corren suavemente), la
   lupa se queda en su lugar y el texto aparece cuando ya hay espacio. */
.filter-search-wrap{
  position:relative;
  display:inline-flex;
  align-items:center;
  height:40px;
  flex:0 0 40px;
  transition:flex 0.55s var(--ease-out-expo);
}
.filter-search-wrap.is-open{ flex-basis:220px; }
.filter-search-toggle{
  -webkit-appearance:none;
  appearance:none;
  position:absolute;
  left:0;
  top:0;
  width:40px;
  height:40px;
  padding:0;
  border-radius:50%;
  border:1px solid var(--hair);
  background:var(--bg-panel);
  color:var(--ink-soft);
  display:flex;
  align-items:center;
  justify-content:center;
  cursor:pointer;
  flex-shrink:0;
  transition:border-color 0.2s ease, color 0.2s ease, background 0.2s ease, opacity 0.2s ease, transform 0.4s var(--ease-out-expo);
}
.filter-search-toggle svg{ width:16px; height:16px; }
.filter-search-toggle:hover{ border-color:var(--brass-soft); color:var(--brass-soft); }
.filter-search-wrap.is-open .filter-search-toggle{
  opacity:0;
  transform:scale(0.7);
  pointer-events:none;
  transition-duration:0.15s;
}

.filter-search-box{
  position:absolute;
  inset:0;
  display:flex;
  align-items:center;
  opacity:0;
  visibility:hidden;
  transition:opacity 0.25s ease, visibility 0s linear 0.25s;
}
.filter-search-wrap.is-open .filter-search-box{
  opacity:1;
  visibility:visible;
  transition:opacity 0.3s ease 0.08s, visibility 0s;
}
.filter-search-icon{
  position:absolute;
  left:16px;
  width:15px;
  height:15px;
  color:var(--ink-faint);
  pointer-events:none;
}
.filter-search-input{
  width:100%;
  height:40px;
  font-family:'Jost', sans-serif;
  font-size:13px;
  letter-spacing:0.02em;
  color:var(--ink);
  background:var(--bg-panel);
  border:1px solid var(--hair);
  border-radius:999px;
  padding:9px 36px 9px 40px;
  transition:border-color 0.2s ease, box-shadow 0.3s ease;
}
.filter-search-input::placeholder{ color:var(--ink-faint); }
.filter-search-input:hover,
.filter-search-input:focus{
  border-color:var(--brass-soft);
  outline:none;
  box-shadow:0 4px 16px rgba(var(--glow-rgb),0.2);
}
/* Safari agrega su propio ícono de lupa + botón de "borrar" al
   type="search"; los sacamos porque ya tenemos el ícono propio a la
   izquierda y la X propia a la derecha, y el look nativo desentona con
   el resto de los controles. */
.filter-search-input::-webkit-search-decoration,
.filter-search-input::-webkit-search-cancel-button,
.filter-search-input::-webkit-search-results-button,
.filter-search-input::-webkit-search-results-decoration{ -webkit-appearance:none; }
.filter-search-close{
  -webkit-appearance:none;
  appearance:none;
  position:absolute;
  right:4px;
  width:28px;
  height:28px;
  padding:0;
  border-radius:50%;
  border:none;
  background:transparent;
  color:var(--ink-faint);
  display:flex;
  align-items:center;
  justify-content:center;
  cursor:pointer;
  transition:color 0.2s ease, background 0.2s ease;
}
.filter-search-close svg{ width:13px; height:13px; }
.filter-search-close:hover{ color:var(--brass-soft); background:rgba(var(--glow-rgb),0.08); }

/* ---------- SCROLL REVEAL ---------- */
/* --reveal-delay vale 0 salvo durante el segundo en que la cortina se
   está levantando: ahí catalogo-app.js (scheduleArrival) le da a cada
   pieza en pantalla, en línea, el instante en que el borde de la
   cortina pasa por su altura. Así las primeras secciones entran justo
   cuando las destapa, en vez de terminar de aparecer detrás de ella,
   ya quietas, sin que nadie las vea llegar. */
html{ --reveal-delay:0s; }
.reveal{
  opacity:0;
  transform:translateY(22px);
  transition:opacity 0.9s var(--ease-out-expo), transform 0.9s var(--ease-out-expo);
  transition-delay:var(--reveal-delay);
}
.reveal.show{ opacity:1; transform:translateY(0); }

/* Al cambiar de categoría o marca (no al tipear en el buscador, que
   se refresca con cada tecla), los grupos que quedan a la vista entran
   de nuevo con una cascada corta: catalogo-app.js pone .is-refresh con
   un índice --i por grupo visible. Los valores finales coinciden con
   el estado .show, así que sacar la clase al terminar no mueve nada. */
.brand-group.is-refresh,
.section-head.is-refresh{
  animation:groupIn 0.55s var(--ease-out-expo) both;
  animation-delay:calc(var(--i, 0) * 0.045s);
}
@keyframes groupIn{
  from{ opacity:0; transform:translateY(12px); }
  to{ opacity:1; transform:translateY(0); }
}

.results-note{
  width:100%;
  text-align:center;
  font-family:'Cormorant Garamond', serif;
  font-style:italic;
  font-size:15px;
  color:var(--ink-faint);
  margin-top:4px;
  animation:fadeUp 0.5s var(--ease-out-expo);
}

/* ---------- SECTIONS ---------- */
.collection-section{
  padding:64px 0;
  border-bottom:1px solid var(--hair);
}
.collection-section:first-of-type{ padding-top:72px; }
.collection-section.is-hidden{ display:none; }

/* Buscando por nombre/marca (ver catalogo-app.js, applyFilters): se
   ocultan los títulos grandes "Femenino/Masculino/Unisex" de cada
   sección visible para que el resultado sea una lista directa de
   fragancias, sin la división editorial que solo tiene sentido en la
   vista general o filtrando por categoría. Se agrega/saca dinámico
   con cada tecla, así que no se anima (aparecería/desaparecería a
   destiempo del resto de la búsqueda). */
.hide-section-title .section-head{ display:none; }
.collection-section.hide-section-title{ padding-top:32px; }
.collection-section.hide-section-title:first-of-type{ padding-top:32px; }
.unisex.hide-section-title{ padding-top:32px; }

.fem{ --tone:var(--wine); --tone-deep:var(--wine-deep); }
.masc{ --tone:var(--pine); --tone-deep:var(--pine-deep); }

.section-head{ margin-bottom:38px; }
.section-head .sub{
  font-size:12.5px;
  letter-spacing:0.1em;
  color:var(--tone, var(--brass));
  margin-bottom:10px;
}
h2.section-title{
  font-family:'Cormorant Garamond', serif;
  font-weight:500;
  font-style:italic;
  font-size:38px;
  margin:0 0 16px;
  color:var(--tone-deep, var(--ink));
}
/* La regla se dibuja de izquierda a derecha justo después de que el
   título terminó de asentarse (un poco después que el resto del
   encabezado, para que se lea como un remate y no como parte del
   bloque). */
.section-head .rule{
  width:52px;
  height:2px;
  background:var(--tone, var(--brass));
  transform:scaleX(0);
  transform-origin:left center;
  transition:transform 0.9s var(--ease-out-expo);
  transition-delay:calc(var(--reveal-delay) + 0.3s);
}
.section-head.show .rule{ transform:scaleX(1); }

.fragrance-list{
  column-count:3;
  column-gap:34px;
}

.brand-group{
  break-inside:avoid-column;
  margin-bottom:22px;
  padding-bottom:18px;
  border-bottom:1px solid var(--tone-deep, var(--brass));
}
.brand-group.is-hidden{ display:none; }
.item.is-hidden{ display:none; }
.brand-label{
  font-size:16px;
  font-weight:600;
  letter-spacing:0.08em;
  text-transform:uppercase;
  color:var(--tone-deep, var(--brass));
  padding-top:26px;
  margin-bottom:8px;
}
.brand-group:first-child .brand-label{ padding-top:0; }

.item{
  break-inside:avoid;
  padding:14px 10px;
  margin:0 -10px;
  border-bottom:1px solid var(--hair);
  border-radius:8px;
  display:flex;
  align-items:center;
  gap:14px;
  cursor:pointer;
  transition:background 0.3s ease, transform 0.45s var(--ease-out-expo);
}
.item:hover{
  background:rgba(var(--ink-rgb),0.03);
  transform:translateX(4px);
}
.item:focus-visible{
  outline:2px solid var(--brass-soft);
  outline-offset:2px;
}
.brand-group .item:last-child{ border-bottom:none; }

.thumb-wrap{
  width:58px;
  height:72px;
  flex-shrink:0;
  background:var(--paper-chip);
  border-radius:5px;
  display:flex;
  align-items:center;
  justify-content:center;
  overflow:hidden;
  box-shadow:0 2px 10px rgba(0,0,0,0.35);
  transition:box-shadow 0.35s ease;
}
.item:hover .thumb-wrap{
  box-shadow:0 4px 20px rgba(var(--glow-rgb),0.3);
}
.thumb-wrap img{
  width:100%;
  height:100%;
  object-fit:contain;
  object-position:center;
  padding:2px;
  transform:scale(1.12);
  mix-blend-mode:multiply;
  transition:transform 0.6s var(--ease-out-expo);
}
.item:hover .thumb-wrap img{ transform:scale(1.2); }

/* Cascada interna: los items de un grupo aparecen escalonados cuando
   el .brand-group (padre .reveal) recibe .show. El hover del item se
   mueve con su propia transición (transform corto) solo una vez que el
   item ya llegó: mientras la cascada está en curso manda la entrada. */
.brand-group .item{
  opacity:0;
  transform:translateY(12px);
  transition:opacity 0.7s var(--ease-out-expo), transform 0.7s var(--ease-out-expo), background 0.3s ease;
  transition-delay:var(--reveal-delay);
}
.brand-group.show .item{ opacity:1; transform:translateY(0); }
.brand-group.show .item:nth-child(2){ transition-delay:calc(var(--reveal-delay) + 0.04s); }
.brand-group.show .item:nth-child(3){ transition-delay:calc(var(--reveal-delay) + 0.08s); }
.brand-group.show .item:nth-child(4){ transition-delay:calc(var(--reveal-delay) + 0.12s); }
.brand-group.show .item:nth-child(5){ transition-delay:calc(var(--reveal-delay) + 0.16s); }
.brand-group.show .item:nth-child(6){ transition-delay:calc(var(--reveal-delay) + 0.2s); }
.brand-group.show .item:nth-child(7){ transition-delay:calc(var(--reveal-delay) + 0.24s); }
.brand-group.show .item:nth-child(8){ transition-delay:calc(var(--reveal-delay) + 0.28s); }
.brand-group.show .item:nth-child(9){ transition-delay:calc(var(--reveal-delay) + 0.32s); }
.brand-group.show .item:nth-child(10){ transition-delay:calc(var(--reveal-delay) + 0.36s); }
.brand-group.show .item:nth-child(11){ transition-delay:calc(var(--reveal-delay) + 0.4s); }
.brand-group.show .item:nth-child(12){ transition-delay:calc(var(--reveal-delay) + 0.44s); }
.brand-group.show .item:nth-child(13){ transition-delay:calc(var(--reveal-delay) + 0.48s); }
.brand-group.show .item:nth-child(14){ transition-delay:calc(var(--reveal-delay) + 0.52s); }
.brand-group.show .item:nth-child(15){ transition-delay:calc(var(--reveal-delay) + 0.56s); }
/* Una vez visible, el hover (translateX) responde al instante en vez
   de arrastrar el retardo de la cascada. */
.brand-group.show .item:hover{ transform:translateX(4px); transition-delay:0s; transition-duration:0.45s; }
.thumb-wrap img.is-placeholder{
  object-fit:cover;
  object-position:center 35%;
  transform:scale(1.35);
  padding:0;
}

.item .text{ flex:1; min-width:0; }
.item .name{
  display:block;
  width:fit-content;
  font-size:15.5px;
  font-weight:500;
  color:var(--ink);
  transition:color 0.3s ease;
}
/* Escalar texto al pasar el mouse se lee tosco: el hover del item ya
   lo desplaza y realza la miniatura; acá solo se calienta el color. */
.item:hover .name{ color:var(--brass-soft); }
.item .inspired{
  display:block;
  width:fit-content;
  font-family:'Cormorant Garamond', serif;
  font-style:italic;
  font-size:15px;
  color:var(--ink-soft);
  margin-top:3px;
  transition:color 0.3s ease;
}
.item:hover .inspired{ color:var(--ink); }
.item .inspired .brand-name{
  font-style:normal;
  color:var(--tone-deep, var(--brass));
}

/* ---------- BOTÓN "AGREGAR AL CARRITO" (por fragancia) ---------- */
.cart-add-btn{
  position:relative;
  flex-shrink:0;
  width:34px;
  height:34px;
  border-radius:50%;
  display:flex;
  align-items:center;
  justify-content:center;
  border:1px solid var(--hair);
  background:rgba(var(--ink-rgb),0.02);
  color:var(--brass-soft);
  cursor:pointer;
  transition:transform 0.2s ease, border-color 0.25s ease, background 0.25s ease, box-shadow 0.25s ease;
}
.cart-add-btn:hover{
  border-color:var(--brass-soft);
  background:rgba(var(--glow-rgb),0.16);
  box-shadow:0 4px 14px rgba(var(--glow-rgb),0.22);
}
.cart-add-btn:active{ transform:scale(0.86); }
.cart-add-icon svg{
  width:15px;
  height:15px;
  display:block;
  transition:transform 0.4s cubic-bezier(.2,.8,.2,1);
}
.cart-add-btn:hover .cart-add-icon svg{ transform:rotate(90deg) scale(1.1); }
.cart-add-btn:active .cart-add-icon svg{ transform:rotate(90deg) scale(0.9); }

.cart-add-qty{
  position:absolute;
  top:-6px;
  right:-6px;
  min-width:18px;
  height:18px;
  padding:0 4px;
  border-radius:999px;
  background:linear-gradient(135deg, var(--brass-soft), var(--brass));
  color:var(--btn-ink);
  font-family:'Jost', sans-serif;
  font-size:10.5px;
  font-weight:700;
  line-height:18px;
  text-align:center;
  opacity:0;
  transform:scale(0.6);
  transition:opacity 0.25s ease, transform 0.25s ease;
  pointer-events:none;
}
.cart-add-qty.is-visible{ opacity:1; transform:scale(1); }
.cart-add-qty.is-bump{ animation:cartBump 0.35s ease; }
@keyframes cartBump{
  0%{ transform:scale(1); }
  40%{ transform:scale(1.35); }
  100%{ transform:scale(1); }
}

/* ---------- UNISEX BAND ---------- */
.unisex{
  border-top:1px solid var(--hair);
  padding:64px 0 88px;
  text-align:center;
}
.unisex.is-hidden{ display:none; }
.unisex .section-head{ display:flex; flex-direction:column; align-items:center; }
.unisex .rule{ background:var(--brass); }
.unisex .sub{ color:var(--brass); }
.unisex h2{ color:var(--ink); }

.unisex-grid{
  max-width:820px;
  margin:0 auto;
  display:grid;
  grid-template-columns:repeat(3, 1fr);
  gap:30px 40px;
  text-align:left;
}
.unisex-grid .item{ border-bottom:1px solid var(--hair); }
.unisex .inspired .brand-name{ color:var(--brass-soft); }
.unisex .brand-group{ border-bottom-color:var(--brass); }

/* ---------- FOOTER ---------- */
footer{
  border-top:1px solid var(--hair);
  padding:52px 0 70px;
}
.footer-grid{
  display:grid;
  grid-template-columns:1.3fr 1fr;
  gap:48px;
  align-items:start;
}
footer h3{
  font-family:'Cormorant Garamond', serif;
  font-weight:500;
  font-style:italic;
  font-size:22px;
  margin:0 0 12px;
  color:var(--ink);
}
footer p{
  font-size:14px;
  line-height:1.7;
  color:var(--ink-soft);
  margin:0;
}
.compliance{ display:flex; flex-direction:column; gap:16px; }
.compliance .row{ display:flex; gap:14px; align-items:flex-start; }
.dot{
  width:6px; height:6px; border-radius:50%;
  background:var(--brass);
  margin-top:8px;
  flex-shrink:0;
}
.compliance p{ font-size:13.5px; }

.fine{
  margin-top:46px;
  padding-top:24px;
  border-top:1px solid var(--hair);
  font-size:12px;
  color:var(--ink-faint);
  line-height:1.6;
}
.fine + .fine{ margin-top:14px; padding-top:0; border-top:none; }

.credit{
  margin-top:24px;
  text-align:right;
  font-size:12px;
  color:var(--ink-faint);
}
.credit a{
  color:var(--ink-faint);
  text-decoration:none;
  border-bottom:1px solid transparent;
  transition:color .2s, border-color .2s;
}
.credit a:hover{
  color:var(--brass);
  border-bottom-color:var(--brass);
}

@keyframes floatIn{
  from{ opacity:0; transform:scale(0.35) translateY(24px); }
  to{ opacity:1; transform:scale(1) translateY(0); }
}

/* ---------- WHATSAPP FLOAT ---------- */
.whatsapp-float{
  position:fixed;
  right:26px;
  bottom:26px;
  width:60px;
  height:60px;
  border-radius:50%;
  display:flex;
  align-items:center;
  justify-content:center;
  background:linear-gradient(150deg, #1c2620, #10140f 70%);
  border:1px solid rgba(37,211,102,0.28);
  color:#3ee888;
  box-shadow:0 14px 34px rgba(0,0,0,0.5), inset 0 0 0 1px rgba(255,255,255,0.02);
  z-index:30;
  overflow:visible;
  transition:transform 0.35s cubic-bezier(.2,.8,.2,1), box-shadow 0.35s ease, border-color 0.35s ease;
  opacity:0;
  animation:floatIn 0.7s cubic-bezier(.2,.8,.2,1) 1.3s both,
            floatBreathe 3.6s ease-in-out 2.1s infinite;
}
.whatsapp-clip{
  position:absolute;
  inset:0;
  border-radius:50%;
  overflow:hidden;
  display:flex;
  align-items:center;
  justify-content:center;
}
.whatsapp-clip .btn-shine{
  background:linear-gradient(115deg, transparent, rgba(62,232,136,0.5), rgba(255,255,255,0.4), transparent);
  animation-delay:2s;
}
.whatsapp-icon{ width:27px; height:27px; position:relative; z-index:1; filter:drop-shadow(0 0 6px rgba(62,232,136,0.35)); }
.whatsapp-ring{
  position:absolute;
  inset:-1px;
  border-radius:50%;
  border:1px solid rgba(62,232,136,0.35);
  opacity:0;
  transform:scale(0.85);
  transition:opacity 0.35s ease, transform 0.35s ease;
}
.whatsapp-float:hover{
  transform:scale(1.08) translateY(-2px);
  border-color:rgba(62,232,136,0.55);
  box-shadow:0 18px 40px rgba(0,0,0,0.55), 0 0 22px rgba(62,232,136,0.25);
}
.whatsapp-float:hover .whatsapp-ring{ opacity:1; transform:scale(1.18); }

.whatsapp-tooltip{
  position:absolute;
  right:calc(100% + 16px);
  top:50%;
  transform:translateY(-50%) translateX(6px);
  background:var(--bg-panel);
  color:var(--ink);
  padding:9px 16px;
  border-radius:8px;
  font-family:'Jost', sans-serif;
  font-size:13px;
  letter-spacing:0.03em;
  white-space:nowrap;
  border:1px solid var(--hair);
  opacity:0;
  pointer-events:none;
  transition:opacity 0.3s ease, transform 0.3s ease;
  box-shadow:0 10px 24px rgba(0,0,0,0.4);
}
.whatsapp-float:hover .whatsapp-tooltip{
  opacity:1;
  transform:translateY(-50%) translateX(0);
}

@keyframes floatBreathe{
  0%, 100%{ box-shadow:0 14px 34px rgba(0,0,0,0.5), 0 0 0 0 rgba(62,232,136,0.22); }
  50%{ box-shadow:0 14px 34px rgba(0,0,0,0.5), 0 0 14px 6px rgba(62,232,136,0.1); }
}

@media (max-width:520px){
  .whatsapp-float{ right:16px; bottom:16px; width:54px; height:54px; }
  .whatsapp-icon{ width:24px; height:24px; }
  .whatsapp-tooltip{ display:none; }
}

/* ---------- VOLVER ARRIBA ---------- */
/* Esquina opuesta al de WhatsApp para no competir por el mismo lugar;
   oculto hasta que catalogo-app.js suma .is-visible al scrollear. */
.back-to-top{
  -webkit-appearance:none;
  appearance:none;
  position:fixed;
  left:26px;
  bottom:26px;
  width:48px;
  height:48px;
  padding:0;
  border-radius:50%;
  display:flex;
  align-items:center;
  justify-content:center;
  background:linear-gradient(150deg, #2a2115, #14100a 70%);
  border:1px solid rgba(var(--glow-rgb),0.32);
  color:var(--brass-soft);
  box-shadow:0 14px 34px rgba(0,0,0,0.5), inset 0 0 0 1px rgba(255,255,255,0.02);
  cursor:pointer;
  z-index:29;
  opacity:0;
  transform:translateY(14px) scale(0.85);
  pointer-events:none;
  transition:opacity 0.3s ease, transform 0.5s var(--ease-out-expo), border-color 0.3s ease, box-shadow 0.3s ease;
}
.back-to-top svg{ width:19px; height:19px; }
.back-to-top.is-visible{
  opacity:1;
  transform:translateY(0) scale(1);
  pointer-events:auto;
}
.back-to-top:active{ transform:scale(0.92); transition-duration:0.1s; }
.back-to-top:hover{
  border-color:rgba(var(--glow-rgb),0.6);
  box-shadow:0 18px 40px rgba(0,0,0,0.55), 0 0 22px rgba(var(--glow-rgb),0.3);
  transform:translateY(-2px) scale(1.05);
}
@media (max-width:520px){
  .back-to-top{ left:16px; bottom:16px; width:44px; height:44px; }
  .back-to-top svg{ width:17px; height:17px; }
}

/* ---------- CARRITO: BOTÓN FLOTANTE ---------- */
/* [hidden] tiene que ganarle a "display:flex" de abajo, mismo motivo que
   en .cart-panel: el botón se oculta por completo (toggleEl.hidden en
   catalogo-cart.js) mientras el carrito está vacío.
   Esquina superior derecha, debajo de la barra de filtros sticky. */
.cart-float[hidden]{ display:none; }
.cart-float{
  position:fixed;
  right:26px;
  top:100px;
  width:60px;
  height:60px;
  border-radius:50%;
  display:flex;
  align-items:center;
  justify-content:center;
  padding:0;
  background:linear-gradient(150deg, #2a2115, #14100a 70%);
  border:1px solid rgba(var(--glow-rgb),0.32);
  color:var(--brass-soft);
  box-shadow:0 14px 34px rgba(0,0,0,0.5), inset 0 0 0 1px rgba(255,255,255,0.02);
  z-index:30;
  cursor:pointer;
  transition:transform 0.45s var(--ease-out-expo), box-shadow 0.35s ease, border-color 0.35s ease, background 0.35s ease;
  opacity:0;
  /* Sin retardo inicial: el botón recién existe cuando se agrega la
     primera fragancia (ver [hidden] arriba), y en ese momento tiene
     que aparecer YA como respuesta al toque, no un segundo y medio
     después. */
  animation:floatIn 0.6s var(--ease-out-expo) both,
            ctaGlow 3.6s ease-in-out 0.8s infinite;
}
/* Latido del ícono cada vez que entra algo al carrito (catalogo-cart.js
   pone .is-pinged): vive en el ícono y no en el botón para no reiniciar
   la animación de aparición de arriba. */
.cart-float.is-pinged .cart-icon{ animation:cartPing 0.55s var(--ease-out-expo); }
@keyframes cartPing{
  0%{ transform:scale(1); }
  35%{ transform:scale(1.28) rotate(-6deg); }
  100%{ transform:scale(1) rotate(0); }
}
/* En modo claro el mismo gradiente casi negro se perdía contra el fondo
   marfil/blanco de la página: se reemplaza por el dorado de las CTAs
   (mismo que .cta-jump) para que el círculo siga contrastando con el
   fondo en vez de leerse como un agujero oscuro. */
:root[data-theme="light"] .cart-float{
  background:linear-gradient(150deg, var(--brass-soft), var(--brass) 75%);
  color:var(--btn-ink);
}
.cart-icon{ width:26px; height:26px; position:relative; z-index:1; }
.cart-ring{
  position:absolute;
  inset:-1px;
  border-radius:50%;
  border:1px solid rgba(var(--glow-rgb),0.4);
  opacity:0;
  transform:scale(0.85);
  transition:opacity 0.35s ease, transform 0.35s ease;
}
.cart-float:hover{
  transform:scale(1.08) translateY(-2px);
  border-color:rgba(var(--glow-rgb),0.6);
  box-shadow:0 18px 40px rgba(0,0,0,0.55), 0 0 22px rgba(var(--glow-rgb),0.3);
}
.cart-float:hover .cart-ring{ opacity:1; transform:scale(1.18); }
.cart-clip{
  position:absolute;
  inset:0;
  border-radius:50%;
  overflow:hidden;
  display:flex;
  align-items:center;
  justify-content:center;
}
.cart-clip .btn-shine{ animation-delay:2.6s; }

.cart-badge{
  position:absolute;
  top:-4px;
  right:-4px;
  min-width:24px;
  height:24px;
  padding:0 6px;
  border-radius:999px;
  background:var(--wine);
  color:#fff;
  font-family:'Jost', sans-serif;
  font-size:12px;
  font-weight:600;
  line-height:24px;
  text-align:center;
  border:2px solid var(--bg);
  opacity:0;
  transform:scale(0.5);
  transition:opacity 0.25s ease, transform 0.25s ease;
}
.cart-badge.is-visible{ opacity:1; transform:scale(1); }

@media (max-width:520px){
  .cart-float{ right:16px; top:88px; width:54px; height:54px; }
  .cart-icon{ width:22px; height:22px; }
}

/* ---------- MODALES: FONDO COMPARTIDO ---------- */
/* Usado tanto por el carrito como por la previsualización de una
   fragancia: cada uno tiene su propio elemento en el DOM (no compiten
   entre sí), pero comparten el mismo look de vidrio esmerilado. */
body.cart-open-lock{ overflow:hidden; }

.modal-backdrop{
  position:fixed;
  inset:0;
  background:rgba(6,5,3,0.72);
  backdrop-filter:blur(6px);
  -webkit-backdrop-filter:blur(6px);
  z-index:40;
  opacity:0;
  /* will-change adelanta la creación de la capa de composición: sin esto,
     el navegador puede tardar en aplicar el desenfoque recién al abrirse
     el modal, dejando ver el catálogo de fondo sin oscurecer por un
     instante (más notorio en celulares de gama media/baja). */
  will-change:opacity;
  /* Se va más rápido de lo que llega: al cerrar, la persona ya decidió
     volver al catálogo y no hay que hacerla esperar. */
  transition:opacity 0.3s ease;
}
.modal-backdrop.is-open{ opacity:1; transition-duration:0.5s; }

/* ---------- CARRITO: PANEL ---------- */

/* [hidden] tiene que ganarle a "display:flex" de abajo: si no, al
   cerrar el panel (panel.hidden = true desde JS) quedaría invisible
   pero seguiría ocupando su lugar y tapando clics sobre el centro de
   la pantalla. Misma razón en .cart-panel-foot más abajo. */
.cart-panel[hidden]{ display:none; }
.cart-panel{
  position:fixed;
  top:50%;
  left:50%;
  transform:translate(-50%, -46%) scale(0.96);
  width:min(440px, calc(100vw - 32px));
  max-height:min(640px, calc(100vh - 64px));
  display:flex;
  flex-direction:column;
  background:linear-gradient(165deg, var(--bg-panel), var(--bg) 60%);
  border:1px solid var(--hair);
  border-radius:18px;
  box-shadow:0 30px 70px rgba(0,0,0,0.55);
  z-index:41;
  opacity:0;
  /* Cierre: corto y sin frenar. Apertura (abajo): más larga y con la
     curva expo, que arranca decidida y se asienta con suavidad. */
  transition:opacity 0.22s ease, transform 0.26s var(--ease-in-soft);
  overflow:hidden;
}
.cart-panel.is-open{
  opacity:1;
  transform:translate(-50%, -50%) scale(1);
  transition:opacity 0.35s ease, transform 0.55s var(--ease-out-expo);
}
/* El contenido del panel llega en una cascada breve detrás del marco
   (cabecera, aviso, lista, pie), y desaparece junto con el panel sin
   escalonar. */
.cart-panel-head, #cartInfoBtn, .cart-empty, .cart-list, .cart-panel-foot{
  opacity:0;
  transform:translateY(10px);
  transition:opacity 0.2s ease, transform 0.2s ease;
}
.cart-panel.is-open :is(.cart-panel-head, #cartInfoBtn, .cart-empty, .cart-list, .cart-panel-foot){
  opacity:1;
  transform:translateY(0);
  transition:opacity 0.6s var(--ease-out-expo), transform 0.6s var(--ease-out-expo);
}
.cart-panel.is-open .cart-panel-head{ transition-delay:0.06s; }
.cart-panel.is-open #cartInfoBtn{ transition-delay:0.11s; }
.cart-panel.is-open :is(.cart-empty, .cart-list){ transition-delay:0.16s; }
.cart-panel.is-open .cart-panel-foot{ transition-delay:0.22s; }

.cart-panel-head{
  display:flex;
  align-items:center;
  justify-content:space-between;
  padding:22px 24px;
  border-bottom:1px solid var(--hair);
  flex-shrink:0;
}
.cart-panel-head h2{
  font-family:'Cormorant Garamond', serif;
  font-style:italic;
  font-weight:500;
  font-size:24px;
  color:var(--ink);
  margin:0;
}
.cart-close{
  width:32px;
  height:32px;
  border-radius:50%;
  border:1px solid var(--hair);
  background:transparent;
  color:var(--ink-soft);
  display:flex;
  align-items:center;
  justify-content:center;
  cursor:pointer;
  transition:border-color 0.2s ease, color 0.2s ease, transform 0.2s ease;
}
.cart-close svg{ width:16px; height:16px; }
.cart-close:hover{ border-color:var(--brass-soft); color:var(--brass-soft); }
.cart-close:active{ transform:scale(0.9); }

.cart-empty{
  padding:48px 28px;
  text-align:center;
  color:var(--ink-soft);
}
.cart-empty p{ margin:0 0 8px; }
.cart-empty-hint{ font-size:13px; color:var(--ink-faint); }

.cart-list{
  list-style:none;
  margin:0;
  padding:4px 14px;
  overflow-y:auto;
  flex:1;
}
.cart-row{
  display:flex;
  align-items:center;
  gap:12px;
  padding:14px 6px;
  border-bottom:1px solid var(--hair);
}
.cart-row:last-child{ border-bottom:none; }
/* Las filas caen en cascada solo al ABRIR el panel (.is-animating la
   pone catalogo-cart.js por un instante): los re-renders por cambio de
   cantidad no vuelven a animar toda la lista. */
.cart-list.is-animating .cart-row{
  animation:rowIn 0.5s var(--ease-out-expo) both;
  animation-delay:calc(0.18s + var(--i, 0) * 0.04s);
}
@keyframes rowIn{
  from{ opacity:0; transform:translateX(-8px); }
  to{ opacity:1; transform:translateX(0); }
}
/* Quitar una fragancia: la fila se pliega y se va antes de que el
   resto de la lista se acomode (catalogo-cart.js espera a que termine
   para re-renderizar). */
.cart-row.is-leaving{
  animation:rowOut 0.26s var(--ease-in-soft) forwards;
  pointer-events:none;
}
@keyframes rowOut{
  to{ opacity:0; transform:translateX(14px); }
}
.cart-row-info{ flex:1; min-width:0; }
.cart-row-name{
  font-size:14.5px;
  font-weight:500;
  color:var(--ink);
  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;
}
.cart-row-brand{
  font-size:11.5px;
  letter-spacing:0.04em;
  text-transform:uppercase;
  color:var(--ink-faint);
  margin-top:2px;
}
.cart-row-price{
  font-family:'Jost', sans-serif;
  font-weight:500;
  font-size:14px;
  letter-spacing:0.03em;
  color:var(--brass-soft);
  margin-top:6px;
}

.cart-row-qty{
  display:flex;
  align-items:center;
  gap:8px;
  flex-shrink:0;
}
.cart-qty-btn{
  width:26px;
  height:26px;
  border-radius:50%;
  border:1px solid var(--hair);
  background:transparent;
  color:var(--ink);
  font-size:15px;
  line-height:1;
  display:flex;
  align-items:center;
  justify-content:center;
  cursor:pointer;
  transition:border-color 0.2s ease, color 0.2s ease, transform 0.15s ease;
}
.cart-qty-btn:hover{ border-color:var(--brass-soft); color:var(--brass-soft); }
.cart-qty-btn:active{ transform:scale(0.88); }
.cart-qty-value{ min-width:16px; text-align:center; font-size:14px; color:var(--ink); }

.cart-row-remove{
  flex-shrink:0;
  width:28px;
  height:28px;
  border-radius:50%;
  border:none;
  background:transparent;
  color:var(--ink-faint);
  display:flex;
  align-items:center;
  justify-content:center;
  cursor:pointer;
  transition:color 0.2s ease, transform 0.15s ease;
}
.cart-row-remove svg{ width:15px; height:15px; }
.cart-row-remove:hover{ color:var(--wine-deep); }
.cart-row-remove:active{ transform:scale(0.88); }

.cart-panel-foot[hidden]{ display:none; }
.cart-panel-foot{
  padding:18px 24px 22px;
  border-top:1px solid var(--hair);
  display:flex;
  flex-direction:column;
  gap:12px;
  flex-shrink:0;
}
.cart-total{
  display:flex;
  align-items:center;
  justify-content:space-between;
  font-size:13.5px;
  color:var(--ink-soft);
}
.cart-total strong{ color:var(--brass-soft); font-size:16px; }

.cart-clear{
  align-self:stretch;
  padding:12px 20px;
  border:1px solid var(--hair);
  border-radius:999px;
  background:transparent;
  color:var(--ink-soft);
  font-family:'Jost', sans-serif;
  font-size:13px;
  letter-spacing:0.03em;
  cursor:pointer;
  transition:border-color 0.2s ease, color 0.2s ease, background 0.2s ease, transform 0.15s ease;
}
.cart-clear:hover{
  border-color:var(--wine-deep);
  color:var(--wine-deep);
  background:rgba(var(--wine-rgb),0.08);
}
.cart-clear:active{ transform:scale(0.97); }

.cart-order{
  position:relative;
  overflow:hidden;
  display:flex;
  align-items:center;
  justify-content:center;
  gap:10px;
  padding:15px 20px;
  border:none;
  border-radius:999px;
  cursor:pointer;
  font-family:'Jost', sans-serif;
  font-size:14.5px;
  font-weight:600;
  letter-spacing:0.03em;
  color:#0b1a10;
  background:linear-gradient(135deg, #3ee888, #25D366 55%, #3ee888);
  background-size:220% 220%;
  box-shadow:0 10px 26px rgba(37,211,102,0.35), 0 1px 0 rgba(255,255,255,0.3) inset;
  animation:ctaSheen 5s linear infinite, cartOrderGlow 3.2s ease-in-out infinite;
  transition:transform 0.2s ease;
}
.cart-order svg{ width:18px; height:18px; flex-shrink:0; }
.cart-order:hover{ transform:translateY(-1px); }
.cart-order:active{ transform:scale(0.97); }
@keyframes cartOrderGlow{
  0%, 100%{ box-shadow:0 10px 26px rgba(37,211,102,0.35), 0 1px 0 rgba(255,255,255,0.3) inset; }
  50%{ box-shadow:0 14px 34px rgba(37,211,102,0.55), 0 1px 0 rgba(255,255,255,0.4) inset; }
}

/* ---------- CARRITO: TOAST DE CONFIRMACIÓN ---------- */
.cart-toast{
  position:fixed;
  left:50%;
  bottom:104px;
  transform:translate(-50%, 12px);
  padding:12px 22px;
  border-radius:999px;
  background:var(--bg-panel);
  border:1px solid var(--hair);
  color:var(--ink);
  font-family:'Jost', sans-serif;
  font-size:13.5px;
  letter-spacing:0.02em;
  box-shadow:0 12px 30px rgba(0,0,0,0.4);
  opacity:0;
  pointer-events:none;
  z-index:35;
  transition:opacity 0.25s ease, transform 0.3s var(--ease-in-soft);
  max-width:calc(100vw - 40px);
  text-align:center;
}
.cart-toast.is-visible{
  opacity:1;
  transform:translate(-50%, 0);
  transition:opacity 0.3s ease, transform 0.55s var(--ease-out-expo);
}

@media (max-width:520px){
  .cart-panel{ max-height:min(600px, calc(100vh - 40px)); }
  .cart-toast{ bottom:92px; }
}

/* ---------- PREVISUALIZACIÓN DE UNA FRAGANCIA ---------- */
/* Carrusel de 3 lugares fijos: anterior / activa (centro, más grande) /
   siguiente. Los 3 son el mismo tipo de card (misma plantilla en el
   <template> del HTML), solo que la posición ("slot") define tamaño,
   opacidad y si se puede interactuar. Deslizar (o las flechas del
   teclado) no mueve una sola card de un lado a otro: hace que las 3
   roten de lugar con una transición continua, y la que "sobra" se
   recicla instantáneamente fuera de la pantalla para reaparecer como el
   próximo vecino (ver catalogo-preview.js). Así siempre hay exactamente
   3 lugares respetados, sin superposición entre ellos. */
.preview-viewport{
  position:fixed;
  inset:0;
  z-index:41;
  pointer-events:none;
  opacity:0;
  transition:opacity 0.28s ease;
}
.preview-viewport[hidden]{ display:none; }
.preview-viewport.is-open{ opacity:1; transition-duration:0.4s; }

/* Entrada/salida de las cards: el movimiento vive en .preview-slide-
   inner (no en .preview-slide, cuyo transform es el del carrusel y el
   arrastre). Al abrir, la activa sube y se asienta; las vecinas la
   siguen un instante después. Al cerrar, todas bajan apenas y se van
   con el fundido del viewport. */
.preview-slide-inner{
  transform:translateY(26px) scale(0.96);
  transition:transform 0.3s var(--ease-in-soft);
}
.preview-viewport.is-open .preview-slide-inner{
  transform:translateY(0) scale(1);
  transition:transform 0.65s var(--ease-out-expo);
}
.preview-viewport.is-open :is(.slot-prev, .slot-next) .preview-slide-inner{ transition-delay:0.07s; }

.preview-slide{
  --slide-w:clamp(220px, 60vw, 380px);
  --slide-gap:clamp(10px, 3vw, 24px);
  position:absolute;
  top:50%;
  left:50%;
  width:var(--slide-w);
  touch-action:pan-y;
  transition:transform 0.32s cubic-bezier(.16,1,.3,1), opacity 0.26s ease, filter 0.26s ease;
  will-change:transform, opacity;
}
.preview-slide.no-anim{ transition:none; }
.preview-slide.is-empty{ opacity:0 !important; pointer-events:none; }

.preview-slide.slot-current{
  transform:translate(-50%, -50%) translateX(var(--drag-x, 0px)) scale(1);
  opacity:1;
  filter:brightness(1);
  z-index:5;
  pointer-events:auto;
}
.preview-slide.slot-prev,
.preview-slide.slot-next{
  opacity:0.55;
  filter:brightness(0.55);
  z-index:4;
  pointer-events:auto;
  cursor:pointer;
}
.preview-slide.slot-prev{
  transform:translate(-50%, -50%) translateX(calc(-1 * (var(--slide-w) + var(--slide-gap)) + var(--drag-x, 0px))) scale(0.82);
}
.preview-slide.slot-next{
  transform:translate(-50%, -50%) translateX(calc(var(--slide-w) + var(--slide-gap) + var(--drag-x, 0px))) scale(0.82);
}
/* Recicladas fuera de pantalla: siempre a ±100vw del centro, así quedan
   invisibles sin importar el ancho de la card ni el del viewport (nada
   de calcular si "alcanza" a esconderse, simplemente no puede no
   alcanzar). Desde ahí es que la próxima fragancia entra deslizándose
   hacia su lugar de vecina. */
.preview-slide.slot-exit-left{
  transform:translate(-50%, -50%) translateX(-100vw) scale(0.7);
  opacity:0;
  z-index:1;
  pointer-events:none;
}
.preview-slide.slot-enter-right{
  transform:translate(-50%, -50%) translateX(100vw) scale(0.7);
  opacity:0;
  z-index:1;
  pointer-events:none;
}
.preview-slide.slot-exit-right{
  transform:translate(-50%, -50%) translateX(100vw) scale(0.7);
  opacity:0;
  z-index:1;
  pointer-events:none;
}
.preview-slide.slot-enter-left{
  transform:translate(-50%, -50%) translateX(-100vw) scale(0.7);
  opacity:0;
  z-index:1;
  pointer-events:none;
}
/* Cuando se confirma el agregado al carrito, la card activa se retira
   con un cierre más marcado (en vez del simple fundido de cerrar
   manualmente) para que quede claro que "ya está". */
.preview-slide.is-vanishing{
  transition:opacity 0.4s cubic-bezier(.55,0,1,.45), transform 0.4s cubic-bezier(.55,0,1,.45);
  opacity:0;
  transform:translate(-50%, -58%) scale(0.86);
}
/* En este cierre manda el movimiento de la card entera hacia arriba:
   la capa interna no baja (sería un tirón en sentido contrario). */
.preview-viewport .preview-slide.is-vanishing .preview-slide-inner{ transform:none; }

/* El recorte de esquinas y el scroll interno viven en este wrapper (no
   en .preview-slide) para que la etiqueta "Imagen de referencia" y el
   botón de cerrar, que sobresalen del borde de la card, no queden
   cortados por el overflow. */
.preview-slide-inner{
  position:relative;
  width:100%;
  max-height:calc(100vh - 64px);
  overflow-y:auto;
  overflow-x:hidden;
  border-radius:18px;
  background:linear-gradient(165deg, var(--bg-panel), var(--bg) 60%);
  border:1px solid var(--hair);
  box-shadow:0 30px 70px rgba(0,0,0,0.55);
}

/* Las cards vecinas (anterior/siguiente) muestran solo foto + marca +
   nombre, como un anticipo: el sello "Imagen de referencia", el botón
   de cerrar, el detalle de "inspirado en" y el botón de agregar son
   exclusivos de la card activa (mostrarlos también en las de al lado,
   más chicas, se leía como 3 diálogos independientes en vez de un solo
   carrusel). Basta con tocar la card para que pase al centro y recién
   ahí aparezca el resto. */
.preview-slide:not(.slot-current) .preview-close,
.preview-slide:not(.slot-current) .preview-media-tag{
  opacity:0;
  pointer-events:none;
}
.preview-slide:not(.slot-current) .preview-inspired,
.preview-slide:not(.slot-current) .preview-meta,
.preview-slide:not(.slot-current) .preview-add{
  display:none;
}
.preview-slide:not(.slot-current) .preview-body{ padding-bottom:20px; }

.preview-close{
  position:absolute;
  top:16px;
  right:16px;
  width:32px;
  height:32px;
  border-radius:50%;
  border:1px solid var(--hair);
  background:var(--overlay-chip);
  color:var(--ink-soft);
  display:flex;
  align-items:center;
  justify-content:center;
  cursor:pointer;
  z-index:3;
  transition:border-color 0.2s ease, color 0.2s ease, transform 0.2s ease;
}
.preview-close svg{ width:16px; height:16px; }
.preview-close:hover{ border-color:var(--brass-soft); color:var(--brass-soft); }
.preview-close:active{ transform:scale(0.9); }

.preview-media{
  position:relative;
  width:100%;
  aspect-ratio:4 / 3;
  background:var(--paper-chip);
  display:flex;
  align-items:center;
  justify-content:center;
  overflow:hidden;
  border-radius:18px 18px 0 0;
}
/* Ancla como un pequeño sello: queda mitad sobre el vacío por encima
   de la card y mitad sobre la imagen, centrado en el borde superior. */
.preview-media-tag{
  position:absolute;
  top:0;
  left:50%;
  transform:translate(-50%, -50%);
  z-index:3;
  font-family:'Jost', sans-serif;
  font-weight:500;
  font-size:8.5px;
  letter-spacing:0.1em;
  text-transform:uppercase;
  white-space:nowrap;
  color:#fff;
  background:#0b0906;
  padding:5px 11px;
  border-radius:999px;
  border:1px solid rgba(255,255,255,0.12);
  box-shadow:0 6px 16px rgba(0,0,0,0.4);
  pointer-events:none;
}
.preview-media img{
  width:70%;
  height:70%;
  object-fit:contain;
  mix-blend-mode:multiply;
}
.preview-media img.is-placeholder{
  width:100%;
  height:100%;
  object-fit:cover;
  object-position:center 35%;
  mix-blend-mode:normal;
}

/* Fondo propio y opaco: sin esto, esta zona queda transparente y deja
   ver lo que haya detrás (otra card del carrusel, el catálogo) por
   detrás del nombre/marca de la fragancia activa. */
.preview-body{
  position:relative;
  z-index:1;
  background:linear-gradient(165deg, var(--bg-panel), var(--bg) 60%);
  padding:26px 26px 28px;
  text-align:center;
}
.preview-brand{
  font-size:12px;
  letter-spacing:0.1em;
  text-transform:uppercase;
  color:var(--brass);
  margin-bottom:8px;
}
.preview-name{
  font-family:'Cormorant Garamond', serif;
  font-weight:500;
  font-style:italic;
  font-size:30px;
  color:var(--ink);
  margin:0 0 10px;
}
.preview-inspired{
  font-family:'Cormorant Garamond', serif;
  font-style:italic;
  font-size:16px;
  color:var(--ink-soft);
  margin:0 0 26px;
}
.preview-inspired span{ color:var(--brass-soft); font-style:normal; }

.preview-meta{
  display:flex;
  align-items:center;
  justify-content:center;
  gap:9px;
  font-family:'Jost', sans-serif;
  font-size:11.5px;
  letter-spacing:0.08em;
  text-transform:uppercase;
  color:var(--ink-soft);
  margin:0 0 22px;
}
.preview-meta-dot{
  width:3px;
  height:3px;
  border-radius:50%;
  background:var(--brass-soft);
  flex-shrink:0;
}

/* Precio: solo existe acá (y en el carrito), nunca en la grilla del
   catálogo. Mismo criterio que .preview-notes-btn[hidden] para las
   fragancias sin dato de precio. */
.preview-price{
  font-family:'Jost', sans-serif;
  font-weight:500;
  font-size:14px;
  letter-spacing:0.03em;
  color:var(--brass-soft);
  margin:0 0 16px;
}
.preview-price[hidden]{ display:none; }

.preview-add{
  position:relative;
  overflow:hidden;
  width:100%;
  display:flex;
  align-items:center;
  justify-content:center;
  gap:10px;
  padding:15px 20px;
  border:none;
  border-radius:999px;
  cursor:pointer;
  font-family:'Jost', sans-serif;
  font-size:14.5px;
  font-weight:600;
  letter-spacing:0.03em;
  color:var(--btn-ink);
  background:linear-gradient(135deg, var(--brass-soft), var(--brass) 50%, var(--brass-soft));
  background-size:220% 220%;
  box-shadow:0 10px 26px rgba(var(--glow-rgb),0.4), 0 1px 0 rgba(255,255,255,0.35) inset;
  animation:ctaSheen 5s linear infinite, ctaGlow 3.2s ease-in-out infinite;
  transition:transform 0.2s ease;
}
.preview-add svg{ width:17px; height:17px; flex-shrink:0; }
.preview-add:hover{ transform:translateY(-1px); }
.preview-add:active{ transform:scale(0.97); }
.preview-add.is-confirmed{
  background:linear-gradient(135deg, var(--confirm-bg-a), var(--confirm-bg-b) 55%, var(--confirm-bg-a));
  color:var(--confirm-ink);
  box-shadow:0 10px 26px rgba(0,0,0,0.25), 0 1px 0 rgba(255,255,255,0.6) inset;
  animation:none;
}

/* Solo un separador con líneas arriba y abajo (nada a los costados):
   lee como un link secundario dentro de la card, no como otro botón
   compitiendo con el dorado de "Agregar al carrito". */
.preview-notes-btn{
  -webkit-appearance:none;
  appearance:none;
  width:100%;
  display:flex;
  align-items:center;
  justify-content:center;
  gap:9px;
  padding:13px 20px;
  margin-bottom:12px;
  border-radius:0;
  border:none;
  border-top:1px solid var(--hair);
  border-bottom:1px solid var(--hair);
  background:transparent;
  color:var(--ink-soft);
  font-family:'Jost', sans-serif;
  font-size:13.5px;
  font-weight:500;
  letter-spacing:0.03em;
  cursor:pointer;
  transition:border-color 0.2s ease, color 0.2s ease, background 0.2s ease;
}
.preview-notes-btn:hover{ border-color:var(--brass-soft); color:var(--brass-soft); background:rgba(var(--glow-rgb),0.06); }
.preview-notes-btn svg{ width:15px; height:15px; }
/* Si la fragancia no tiene fila en la planilla del proveedor (unas
   pocas del catálogo), no se muestra el botón en vez de abrir un
   popup vacío o inventar datos. */
.preview-notes-btn[hidden]{ display:none; }

/* Debajo de "Agregar al carrito": mismo ancho, pero en el verde de
   WhatsApp y sin el brillo animado del CTA principal, para que quede
   claro que es una acción secundaria (compartir, no comprar). */
.preview-share-btn{
  -webkit-appearance:none;
  appearance:none;
  width:100%;
  display:flex;
  align-items:center;
  justify-content:center;
  gap:9px;
  margin-top:10px;
  padding:13px 20px;
  border-radius:999px;
  border:1px solid rgba(37,211,102,0.35);
  background:rgba(37,211,102,0.08);
  color:#1fa855;
  font-family:'Jost', sans-serif;
  font-size:13.5px;
  font-weight:600;
  letter-spacing:0.03em;
  cursor:pointer;
  transition:border-color 0.2s ease, background 0.2s ease, transform 0.2s ease;
}
.preview-share-btn svg{ width:16px; height:16px; flex-shrink:0; }
.preview-share-btn:hover{ border-color:#25d366; background:rgba(37,211,102,0.16); }
.preview-share-btn:active{ transform:scale(0.97); }
.preview-slide:not(.slot-current) .preview-share-btn{ display:none; }

/* ---------- POPUP DE NOTAS / PROYECCIÓN / DURACIÓN ---------- */
/* Comparte el mismo fondo oscurecido que el resto de los modales del
   sitio (.modal-backdrop, ver más arriba) pero un escalón por encima
   del carrusel de la ficha (z-index:41): este popup se abre ARRIBA de
   esa ficha, no en su lugar, así que su propio fondo debe tapar todo
   lo que quedó debajo, carrusel incluido. */
#notesBackdrop, #cartInfoBackdrop{ z-index:42; }
.notes-panel{
  position:fixed;
  top:50%;
  left:50%;
  width:min(360px, calc(100vw - 48px));
  max-height:calc(100vh - 64px);
  overflow-y:auto;
  transform:translate(-50%, -46%) scale(0.96);
  z-index:43;
  opacity:0;
  pointer-events:none;
  text-align:center;
  border-radius:18px;
  background:linear-gradient(165deg, var(--bg-panel), var(--bg) 60%);
  border:1px solid var(--hair);
  box-shadow:0 30px 70px rgba(0,0,0,0.55);
  padding:28px 26px 26px;
  transition:opacity 0.22s ease, transform 0.26s var(--ease-in-soft);
}
.notes-panel[hidden]{ display:none; }
.notes-panel.is-open{
  opacity:1;
  transform:translate(-50%, -50%) scale(1);
  pointer-events:auto;
  transition:opacity 0.35s ease, transform 0.55s var(--ease-out-expo);
}
.notes-close{
  position:absolute;
  top:16px;
  right:16px;
  width:30px;
  height:30px;
  border-radius:50%;
  border:1px solid var(--hair);
  background:var(--overlay-chip);
  color:var(--ink-soft);
  display:flex;
  align-items:center;
  justify-content:center;
  cursor:pointer;
  transition:border-color 0.2s ease, color 0.2s ease, transform 0.2s ease;
}
.notes-close svg{ width:15px; height:15px; }
.notes-close:hover{ border-color:var(--brass-soft); color:var(--brass-soft); }
.notes-close:active{ transform:scale(0.9); }
.notes-eyebrow{
  font-size:11px;
  letter-spacing:0.12em;
  text-transform:uppercase;
  color:var(--brass);
  margin-bottom:8px;
}
.notes-title{
  font-family:'Cormorant Garamond', serif;
  font-style:italic;
  font-weight:500;
  font-size:26px;
  color:var(--ink);
  margin:0 0 20px;
  padding-right:20px;
}

.notes-stats{
  display:grid;
  grid-template-columns:1fr 1fr;
  gap:22px;
  margin-bottom:22px;
}
.notes-stat-label{
  display:flex;
  align-items:baseline;
  justify-content:center;
  gap:6px;
  font-size:14.5px;
  font-weight:600;
  color:var(--ink);
  margin-bottom:7px;
}
.notes-stat-frac{ font-size:14.5px; font-weight:600; color:var(--ink); }
.notes-stat-track{
  position:relative;
  height:9px;
  border-radius:999px;
  background:rgba(var(--ink-rgb),0.08);
  border:1px solid var(--hair);
  overflow:hidden;
  margin-bottom:8px;
}
.notes-stat-fill{
  position:absolute;
  inset:0;
  width:33%;
  border-radius:999px;
  background:linear-gradient(90deg, var(--brass-soft), var(--brass));
  box-shadow:0 0 10px rgba(var(--glow-rgb),0.45);
  transition:width 0.9s var(--ease-out-expo) 0.25s;
}
/* Las barras arrancan vacías y se llenan hasta su nivel apenas el
   popup terminó de asentarse (el ancho real lo pone catalogo-preview.js
   en línea; el !important solo manda mientras el panel está cerrado). */
.notes-panel:not(.is-open) .notes-stat-fill{ width:0 !important; transition:none; }
/* Una sola palabra (el nivel que corresponde a esta fragancia, no las
   3 posibles) para no competir visualmente con el número de al lado. */
.notes-stat-value{
  font-size:10.5px;
  letter-spacing:0.08em;
  text-transform:uppercase;
  color:var(--brass-soft);
  font-weight:600;
}
.notes-stat-value.is-unavailable{
  color:var(--ink-faint);
  font-weight:500;
}

.notes-divider{ height:1px; background:var(--hair); margin:0 0 20px; }
.notes-section-label{
  font-size:11px;
  letter-spacing:0.12em;
  text-transform:uppercase;
  color:var(--ink-faint);
  margin-bottom:10px;
}
.notes-body{
  font-family:'Cormorant Garamond', serif;
  font-size:17px;
  line-height:1.6;
  color:var(--ink-soft);
  margin:0;
}
.notes-body + .notes-body{ margin-top:14px; }

/* ---------- NOSCRIPT FALLBACK ---------- */
noscript .wrap{ padding-top:40px; }
noscript h2{
  font-family:'Cormorant Garamond', serif;
  font-style:italic;
  color:var(--brass-soft);
  margin-top:32px;
}
noscript ul{ padding-left:20px; }
noscript li{ margin-bottom:6px; color:var(--ink-soft); }

@media (max-width:860px){
  .fragrance-list{ column-count:1; }
  .unisex-grid{ grid-template-columns:1fr 1fr; }
  .footer-grid{ grid-template-columns:1fr; }
  .trust-item{ flex:1 1 45%; border-left:none; }
  .trust-item:nth-child(odd){ border-left:none; }
}
@media (max-width:520px){
  .wrap{ padding:0 20px; }
  .unisex-grid{ grid-template-columns:1fr; }
  .trust-item{ flex:1 1 100%; border-left:none; }
  .cursor-glow{ display:none; }

  /* En mobile, "Todas / Mujer / Hombre / Unisex" ya no entra en una
     sola línea centrada: se envolvía en 2 líneas desparejas (3 + 1
     chip suelto) que se veía descuidado. En vez de wrap, cada control
     pasa a ocupar su propia fila (categorías, marca, buscador),
     apilados prolijamente de arriba a abajo en vez de repartidos sin
     un criterio visual. */
  .filter-bar{
    flex-direction:column;
    align-items:stretch;
    padding:16px 20px 18px;
    gap:10px;
  }
  /* Las categorías siguen siendo chips (no un <select>): son solo 4 y
     tocarlas una a una es más rápido que abrir un desplegable. Para
     que quepan en una sola línea prolija, se desliza en horizontal en
     vez de envolver a una segunda línea. */
  .filter-group{
    width:100%;
    flex-wrap:nowrap;
    justify-content:flex-start;
    overflow-x:auto;
    -webkit-overflow-scrolling:touch;
    scrollbar-width:none;
    padding-bottom:2px;
    /* Sin esto, un hijo flex no se achica por debajo del ancho de su
       contenido (min-width:auto es el default): en vez de scrollear
       ADENTRO de esta fila, empujaba a .filter-bar (y a toda la
       página) a desbordar horizontalmente. */
    min-width:0;
  }
  .filter-group::-webkit-scrollbar{ display:none; }
  .filter-btn{ flex:0 0 auto; white-space:nowrap; }
  /* El separador vertical entre categorías y marca solo tiene sentido
     en una sola fila horizontal; apiladas en columna, el espacio entre
     filas (gap) ya cumple ese rol. */
  .filter-divider{ display:none; }
  .filter-controls{ width:100%; }
  .filter-select-wrap{
    flex:1 1 0px;
    min-width:0;
    transition:flex 0.55s var(--ease-out-expo), opacity 0.25s ease, margin 0.55s var(--ease-out-expo), box-shadow 0.3s ease;
  }
  .filter-select{ width:100%; min-width:0; }
  /* El círculo de búsqueda es de ancho fijo cerrado; abierto, toma el
     lugar del select para tener espacio de sobra donde escribir en vez
     de compartir la fila con el select angosto. No es un intercambio
     seco: el select se pliega (flex 1 → 0, y absorbe el gap de la fila
     con el margen negativo) mientras el buscador crece hasta ocupar
     toda la fila, en un solo movimiento. */
  .filter-search-wrap.is-open{ flex:1 1 0px; min-width:0; }
  .filter-controls.search-active .filter-select-wrap{
    flex:0 0 0px;
    opacity:0;
    margin-left:-14px;
    pointer-events:none;
  }
  /* iOS Safari hace zoom automático al enfocar un input con font-size
     menor a 16px; en mobile lo subimos a 16px solo para evitar ese zoom,
     el tamaño visual en desktop (13px) no se toca. */
  .filter-search-input{ font-size:16px; }

  .curtain-stage .wrap{ padding-left:24px; padding-right:24px; }
  h1.title{ font-size:clamp(38px, 10vw, 52px); }
  .trust-bar{ margin-top:30px; }
  .trust-item{ padding:16px 18px; }
}

/* ---------- CORTINA: viewports bajos ---------- */
/* Con poca altura (mobile en horizontal, ventanas de escritorio bajas)
   el kicker + título + lede + trust-bar completos no entran en
   100dvh. En vez de forzar font-sizes más chicos (que además ya usan
   clamp), se ajusta el ritmo vertical y, si aun así no alcanza, la
   cortina scrollea internamente en lugar de recortar contenido — mismo
   criterio que el bloque `max-height` de portfolio-animado.css en el
   otro proyecto. */
@media (max-height:800px){
  .curtain-stage .wrap{ padding-top:18px; padding-bottom:18px; }
  .kicker{ margin-bottom:0; }
  .kicker::after{ margin:10px auto 0; }
  h1.title{ margin:16px 0 18px; }
  .trust-bar{ margin-top:26px; }
  .trust-item{ padding:14px 16px; }
  .curtain-scroll-cue{ display:none; }
}
@media (max-height:620px){
  .trust-bar{ display:none; }
  .cta-jump{ margin-bottom:0; }
}
