/* ============================================================
   American Vault — styles.css (v4, Black / White, Apple-style)
   ============================================================ */

:root {
  /* Pure B&W palette, Apple gray-scale */
  --bg:          #ffffff;
  --bg-elev:     #ffffff;
  --bg-surface:  #f5f5f7;
  --ink:         #1d1d1f;
  --ink-soft:    #6e6e73;
  --ink-mute:    #a1a1a6;
  --line:        rgba(0, 0, 0, 0.08);
  --line-strong: rgba(0, 0, 0, 0.18);
  --accent:      #1d1d1f;
  --accent-soft: #000000;

  /* Functional accents — minimal color */
  --success:     #1f6b56;
  --warm:        #a0521a;
  --danger:      #b2271d;
  --wa:          #25d366;
  --wa-ink:      #0a2a14;

  /* Elevation */
  --shadow-sm:   0 1px 2px rgba(0, 0, 0, 0.04);
  --shadow-md:   0 4px 20px rgba(0, 0, 0, 0.06);
  --shadow-lg:   0 24px 60px rgba(0, 0, 0, 0.15);

  /* Radii — Apple uses moderate rounding */
  --radius-xs:   6px;
  --radius-sm:   10px;
  --radius-md:   14px;
  --radius-lg:   18px;
}

* { box-sizing: border-box; }

html, body { margin: 0; min-height: 100%; }

body {
  font-family: "Jost", "Inter", -apple-system, "SF Pro Text", "Segoe UI", sans-serif;
  font-size: 15px;
  font-weight: 400;
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-feature-settings: "ss01", "cv11";
  /* Bloquea seleccion de texto a nivel global — la UI del catalogo
     se lee como una app editorial, no como un documento. No queremos
     que el usuario arrastre seleccion sobre botones, wordmark,
     labels, precios, brand pills, etc. Las superficies donde si
     tiene sentido escribir/copiar (inputs y textarea) hacen opt-in
     abajo. */
  -webkit-user-select: none;
  -ms-user-select: none;
  user-select: none;
  /* Deshabilita el callout de iOS (copy/share) sobre imagenes y
     texto — mismo principio: app-like, no document-like. */
  -webkit-touch-callout: none;
}
/* Opt-in: formularios y areas editables siguen siendo seleccionables */
input, textarea, [contenteditable="true"] {
  -webkit-user-select: text;
  -ms-user-select: text;
  user-select: text;
}

h1, h2, h3, h4 {
  font-family: "Fraunces", "SF Pro Display", "New York", Georgia, serif;
  font-weight: 500;
  margin: 0;
  letter-spacing: -0.015em;
  color: var(--ink);
}

a { color: inherit; }
img { display: block; max-width: 100%; }

button, input, select, textarea { font: inherit; color: inherit; }

.hidden { display: none !important; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

/* ===========================================================
   1. TOP BAR  — slim sticky, 3 zonas
   =========================================================== */
.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  background: rgba(255, 255, 255, 0.82);
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 1px solid var(--line);
  /* transicion suave entre estado dark (hero) y light (catalogo). El
     toggle sucede por clase desde JS sincronizado con scroll; animar
     background/color/border da continuidad perceptual sin requerir
     mas JS. */
  transition:
    background-color 0.32s ease,
    color 0.32s ease,
    border-bottom-color 0.32s ease;
}
.topbar-inner {
  max-width: 1400px;
  margin: 0 auto;
  padding: 14px 24px;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 16px;
}
.topbar-left  { justify-self: start; display: flex; gap: 6px; align-items: center; }
.topbar-right { justify-self: end;   display: flex; gap: 6px; align-items: center; }

.wordmark {
  font-family: "Jost", -apple-system, sans-serif;
  font-size: clamp(0.95rem, 1.35vw, 1.12rem);
  font-weight: 300;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}

.icon-btn {
  width: 36px; height: 36px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%;
  border: 0;
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  position: relative;
  transition: background 0.15s ease, transform 0.1s ease;
}
.icon-btn:hover { background: var(--bg-surface); }
.icon-btn:active { transform: scale(0.94); }
.icon-btn svg { width: 18px; height: 18px; fill: currentColor; }

/* lock activo = círculo negro sólido con icono blanco */
.icon-btn.lock-btn[aria-pressed="true"] {
  background: var(--ink);
  color: #fff;
}
.icon-btn.lock-btn[aria-pressed="true"]:hover { background: var(--accent-soft); }

/* wishlist activo (filtrando solo wishlisted) */
.icon-btn.wishlist-top.is-on {
  background: var(--ink);
  color: #fff;
}

/* badge numérico */
.icon-btn .count-bubble {
  position: absolute;
  top: -1px; right: -1px;
  min-width: 16px; height: 16px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--ink);
  color: #fff;
  font-size: 10px;
  font-weight: 600;
  display: inline-flex; align-items: center; justify-content: center;
  /* Antes: border 2px var(--bg). Sobre estado .is-on (bg blanco) el
     border blanco se fundia con el bg y la burbuja "se achicaba"
     visualmente. Fuera. La separacion con el icono se resuelve con
     un box-shadow sutil que no come area. */
  border: 0;
  box-shadow: 0 0 0 2px var(--bg);
  letter-spacing: 0;
  line-height: 1;
}
.icon-btn.is-on .count-bubble {
  background: #fff;
  color: var(--ink);
  box-shadow: 0 0 0 2px var(--bg);
}
.icon-btn .count-bubble:empty,
.icon-btn .count-bubble.hidden { display: none; }

/* ===========================================================
   1b. HERO VAULT — scrollytelling mobile-first
   =========================================================== */
.hero-vault {
  position: relative;
  height: 200vh;                /* 2 pantallas de scroll para pasar el giro */
  /* Fondo: negro puro durante el sticky (primera pantalla) + transicion
     lineal a var(--bg) a lo largo de la segunda pantalla.
     Antes usabamos un radial gradient + un ::after con linear fade. Esa
     combinacion generaba una "linea" diagonal perceptible en la union
     entre el vignette y el fade. Un solo gradiente vertical con paradas
     intermedias (easing manual) hace la transicion imperceptible y
     termina exactamente en var(--bg) para matchear el siguiente bloque. */
  background: linear-gradient(
    to bottom,
    #000 0%,
    #000 48%,
    #050505 60%,
    #1e1e1e 74%,
    #787878 88%,
    var(--bg) 100%
  );
  color: #fff;
  margin-top: -1px;             /* tapa el border-bottom del topbar sobre el negro */
}
.hero-sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  display: grid;
  /* 3 rows: top (monograma AV) | stage (3D) | acts (headlines).
     gap 32-44px garantiza aire visible permanente entre la cartera y
     tanto el logo de arriba como las frases de abajo — es el "margen
     seguro" del hero: incluso con la cartera 3D girando 360 la silueta
     nunca entra en ese colchon. */
  grid-template-rows: auto 1fr auto;
  align-items: center;
  gap: clamp(32px, 4.2vh, 44px);
  /* Padding superior: el monograma solo (vs el lockup completo que tenia
     wordmark) ocupa menos alto, pero mantenemos 88-124px para preservar
     aire respecto del topbar (56px) Y para que el "margen seguro" al bag
     siga intacto despues de reducir la altura del logo.
     Padding inferior (70-110px) sin cambios — sigue protegiendo el fade
     cuando la cartera gira de perfil. */
  padding: clamp(88px, 13vh, 124px) 24px clamp(70px, 11vh, 110px);
  overflow: hidden;
  perspective: 1400px;
  perspective-origin: 50% 55%;
  /* z-index superior al ::after del fade — el sticky vive encima */
  z-index: 2;
}

.hero-top {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  opacity: 0.95;
}
.hero-logo {
  /* Solo monograma AV (sin wordmark). El topbar ya tiene "American Vault"
     como texto — duplicarlo aqui pegado era redundante. Tamaño con mas
     presencia (56-92 vs 48-72 antes): el monograma es nuestro "sello"
     editorial; era casi invisible en mobile. Sigue siendo proporcional
     al hero y no compite con el bag central. viewBox SVG 223x260
     (ratio ~0.86:1), height ≈ width * 1.17. */
  width: clamp(56px, 10vw, 92px);
  height: auto;
  display: block;
  opacity: 0.94;
}

/* Frame editorial: 3 columnas en desktop para que la cartera quede
   "enmarcada" por texto vertical a cada lado (IMPORTADO·AUTÉNTICO·PERÚ
   izq / EST·2026·CHICLAYO der). En mobile las columnas laterales son
   display:none y el stage ocupa todo el ancho. El frame es el que
   hereda la row 2 (1fr) del hero-sticky; internamente centra el stage.
   min-height:0 permite que el grid row no se estire de mas en Firefox. */
.hero-stage-frame {
  position: relative;
  display: grid;
  grid-template-columns: 1fr;
  width: 100%;
  min-height: 0;
  align-items: stretch;
}

.hero-stage {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 0;
  width: 100%;
  /* el canvas se posiciona absoluto encima y ocupa el stage completo */

  /* custom props controladas por hero.js para la sombra de contacto.
     Valores default para antes de que three.js arranque (silueta SVG). */
  --shadow-width: 42%;
  --shadow-opacity: 0.18;

  /* D1 (drag): pan-y le dice al browser que aceptamos scroll vertical
     como default action, pero los swipes horizontales son nuestros
     (rotacion del bag). Sin esto, en mobile el browser come los pointer
     events horizontales como "intent to pan-x" y nunca llegan al JS. */
  touch-action: pan-y;
}
/* Cursor grab solo cuando el 3D esta listo — el SVG fallback no rota. */
.hero-stage.hero-has-3d { cursor: grab; }
.hero-stage.hero-has-3d.is-grabbing { cursor: grabbing; }

/* ---- Hero side ornaments (desktop-only) ----
   Dos columnas de texto vertical que flanquean la cartera. Jost 300,
   small caps, tracking extra wide, opacity baja: leen como marca de
   agua editorial. No deben competir con el foco central (la cartera);
   refuerzan la identidad luxe-magazine y la promesa de marca.
   Mobile: display:none — la cartera necesita todo el ancho. */
.hero-side {
  display: none;
}
.hero-side p {
  margin: 0;
  white-space: nowrap;
  font-family: "Jost", sans-serif;
  font-weight: 300;
  font-size: clamp(0.6rem, 0.72vw, 0.74rem);
  letter-spacing: 0.42em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.42);
}
@media (min-width: 860px) {
  .hero-stage-frame {
    /* auto | 1fr | auto: las sides solo piden el ancho de su texto
       rotado (~48-64px), la cartera se queda con el 1fr central. */
    grid-template-columns: clamp(48px, 5.2vw, 72px) minmax(0, 1fr) clamp(48px, 5.2vw, 72px);
    gap: clamp(14px, 2vw, 28px);
  }
  .hero-side {
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
  }
  .hero-side-left p {
    /* -90deg: el texto "IMPORTADO · AUTÉNTICO · PERÚ" se lee de abajo
       hacia arriba, con la P final arriba. Convencional para sidebars
       editoriales (magazine spine). */
    transform: rotate(-90deg);
    transform-origin: center;
  }
  .hero-side-right p {
    /* +90deg: "EST · 2026 · CHICLAYO" se lee de arriba hacia abajo, con
       el punto final abajo. Simetria visual con el left (ambos textos
       corren "hacia la cartera" — el ojo vuelve al centro). */
    transform: rotate(90deg);
    transform-origin: center;
  }
  /* Hairline vertical sutil detras del texto: un trazo de 1px que
     arranca y termina en el texto (sin tocarlo), sugiere marco
     editorial sin volverse decoración. Alineado al lado de la cartera
     (derecha en left-side, izquierda en right-side). */
  .hero-side::before {
    content: "";
    position: absolute;
    top: 12%;
    bottom: 12%;
    width: 1px;
    background: rgba(255, 255, 255, 0.14);
  }
  .hero-side-left::before  { right: 0; }
  .hero-side-right::before { left:  0; }
}
/* Sombra/reflejo de contacto bajo la cartera. Sobre fondo negro no podemos
   pintar una sombra "mas oscura" — asi que usamos un highlight blanco
   MUY tenue que simula un piso semi-reflejante. Mismo principio que el
   ellipse opacity 0.09 del SVG fallback. hero.js anima width+opacity segun
   el angulo: mas ancha y visible cuando la cartera esta de frente, mas
   angosta y tenue cuando esta de perfil. */
.hero-stage::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 4%;
  width: var(--shadow-width);
  height: 5%;
  transform: translateX(-50%);
  background: radial-gradient(
    ellipse at center,
    rgba(255, 255, 255, var(--shadow-opacity)) 0%,
    rgba(255, 255, 255, 0) 72%
  );
  filter: blur(6px);
  pointer-events: none;
  z-index: 0;
  transition: width 0.15s linear, opacity 0.15s linear;
}

.hero-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  opacity: 0;
  /* Cross-fade premium: 1.2s con cubic-bezier suave (vs 0.6s ease antes).
     Da tiempo a que el canvas WebGL pinte el primer frame solido antes
     de revelarlo, evitando un flash gris-canvas-vacio entre el fade out
     del SVG y el fade in del 3D real. */
  transition: opacity 1.2s cubic-bezier(0.22, 1, 0.36, 1);
  pointer-events: none;
  z-index: 1;
}
.hero-stage.hero-has-3d .hero-canvas { opacity: 1; }
/* Cross-fade real: el SVG hace fade out con la misma duracion que el
   canvas hace fade in. visibility:hidden se aplica con transition-delay
   = duracion del fade, asi el SVG sigue visible (semi-transparente)
   durante el 1.2s del cross y solo desaparece del DOM al final. */
.hero-stage.hero-has-3d .hero-bag {
  opacity: 0;
  visibility: hidden;
}
.hero-bag {
  transition:
    opacity 1.2s cubic-bezier(0.22, 1, 0.36, 1),
    visibility 0s linear 1.2s;
}

.hero-bag {
  /* Cap reducido (vs 58vw antes): el nuevo lockup del logo es mas alto
     y los acts de abajo necesitan mas aire; un bag mas compacto mantiene
     la silueta como foco central sin invadir el logo ni los headlines. */
  width: clamp(170px, 50vw, 300px);
  aspect-ratio: 300 / 360;
  color: #ffffff;
  transform-style: preserve-3d;
  will-change: transform;
  backface-visibility: visible;
  filter: drop-shadow(0 24px 40px rgba(255, 255, 255, 0.05));
  /* transition definida abajo en el cross-fade SVG↔3D — usa la misma
     duracion 1.2s que el canvas para un cross real, no un cut. */
}
.hero-bag svg {
  width: 100%;
  height: 100%;
  display: block;
}

/* heroScrollBob: la flecha del CTA del acto 3 la sigue usando.
   Las reglas del viejo .hero-foot / .hero-wordmark / .hero-tagline /
   .hero-scroll-hint se purgaron — el markup nuevo son los .hero-acts. */
@keyframes heroScrollBob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(5px); }
}

/* ---- Hero acts: 3 headlines editoriales que aparecen por scroll ----
   Los 3 actos ocupan el mismo slot (grid row 3 del sticky). Cada uno
   arranca oculto (opacity 0 + translateY) y hero.js le agrega .is-in
   cuando el progress cae dentro del rango de ese acto. Comparten
   posicion via position:absolute sobre un contenedor con altura minima
   que reserva el espacio antes del padding-bottom del sticky. */
.hero-acts {
  position: relative;
  width: 100%;
  min-height: clamp(140px, 22vh, 200px);
  display: block;
}
.hero-act {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 22px;
  text-align: center;
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.7s cubic-bezier(0.22, 1, 0.36, 1),
              transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
  pointer-events: none;
  will-change: opacity, transform;
}
.hero-act.is-in {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.hero-act p {
  margin: 0;
  font-family: "Fraunces", serif;
  font-weight: 300;
  font-size: clamp(1.9rem, 7.5vw, 3.6rem);
  line-height: 1.08;
  letter-spacing: -0.015em;
  color: #fff;
  /* contrarresta el recorte visual del clamp en pantallas ultra-wide */
  max-width: 18ch;
}
/* Eyebrow del Act 3: fundacion + ciudad + pais.
   Trust signal sutil arriba del headline "Una pieza, un dueno." Tipografia
   small caps Jost con tracking ancho — lee como info de placa editorial,
   no como copy de venta. Hairline rule debajo para separarlo del headline
   sin un margen vacio que rompa el ritmo del Act 3. */
.hero-act-eyebrow {
  /* Override del p heredado (Fraunces enorme) — esto es Jost chiquito. */
  font-family: "Jost", sans-serif !important;
  font-weight: 400 !important;
  font-size: 0.62rem !important;
  letter-spacing: 0.32em !important;
  text-transform: uppercase;
  line-height: 1.2 !important;
  color: rgba(255, 255, 255, 0.55) !important;
  max-width: none !important;
  padding-bottom: 14px;
  margin-bottom: 4px !important;
  position: relative;
}
.hero-act-eyebrow::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 28px;
  height: 1px;
  background: rgba(255, 255, 255, 0.32);
}
/* Act 2 es la linea mas "conceptual"; le damos un italic sutil para
   que sienta el ritmo tipografico editorial sin volverse caricatura. */
.hero-act[data-act="2"] p {
  font-style: italic;
  font-weight: 400;
}
.hero-act-cta {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 13px 24px;
  margin-top: 6px;
  font-family: "Jost", sans-serif;
  font-weight: 400;
  font-size: 0.72rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.88);
  text-decoration: none;
  border: 1px solid rgba(255, 255, 255, 0.32);
  border-radius: 0;
  transition: color 0.25s ease, border-color 0.25s ease,
              background 0.25s ease;
}
.hero-act-cta:hover,
.hero-act-cta:focus-visible {
  color: #000;
  background: #fff;
  border-color: #fff;
  outline: none;
}
.hero-act-cta svg {
  animation: heroScrollBob 2.2s ease-in-out infinite;
}

/* Stock counter bajo el CTA: trust signal "X piezas esperandote" con
   count-up animado. Appearance: el numero en Fraunces tabular para que
   los digitos no bailen al animarse, y la etiqueta en Jost tracking.
   Aparece con un delay adicional al acto 3 para que no cante al mismo
   tiempo que el headline + CTA (ritmo editorial). */
.hero-stock-line {
  margin: 14px 0 0;
  display: inline-flex;
  align-items: baseline;
  gap: 10px;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.6s ease 0.25s, transform 0.6s ease 0.25s;
}
.hero-act.is-in .hero-stock-line {
  opacity: 1;
  transform: translateY(0);
}
.hero-stock-num {
  font-family: "Fraunces", serif;
  font-weight: 400;
  font-size: clamp(1.3rem, 4.5vw, 1.9rem);
  font-variant-numeric: tabular-nums;
  color: #fff;
  line-height: 1;
}
.hero-stock-label {
  font-family: "Jost", sans-serif;
  font-weight: 300;
  font-size: 0.68rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.6);
}

/* ---- Grain editorial con parallax ----
   SVG feTurbulence inline como data URL (cero requests extra). Un tile
   de 220x220 repetido sobre el sticky. mix-blend-mode overlay hace que
   los highlights del herraje lo pisen y la grain solo se sume donde hay
   valores medios — se lee como "pelicula" sin lavar los negros.
   La translateY viene de --grain-y (hero.js la actualiza con el scroll).
   Inset -40px top/bottom da un oversize para que el parallax no revele
   bordes cuando grain se desliza. */
.hero-grain {
  position: absolute;
  inset: -40px 0;
  pointer-events: none;
  z-index: 10;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 220 220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch' seed='7'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0.25 0.5 0.25 0 0'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 220px 220px;
  background-repeat: repeat;
  /* screen en vez de overlay: sobre negro puro overlay da negro
     (no se ve nada). Screen suma highlights — los granos blancos
     chispean sobre el fondo oscuro y se disipan cuando el gradiente
     llega al bg claro al fondo del hero. */
  opacity: 0.11;
  mix-blend-mode: screen;
  /* Grain con parallax adaptive: en mobile + tablet siempre estatico
     (mix-blend-mode + translateY en cada scroll tick rompe el FPS en
     gama baja). En desktop con hover real (mouse, no touch) reactivamos
     el parallax — un compositor bueno absorbe los repaints sin jank.
     hero.js setea --grain-y solo cuando se cumple la feature query. */
  transform: translateY(var(--grain-y, 0));
}
@media (min-width: 860px) and (hover: hover) and (prefers-reduced-motion: no-preference) {
  .hero-grain {
    will-change: transform;
  }
}

/* Topbar invertido cuando el hero ocupa la vista.
   BUG PREVIO: background rgba(0,0,0,0.18). En el strip de 56px que
   la topbar sticky ocupa sobre el <body>, el pixel detras NO es el
   hero (el hero empieza despues en el flujo); es el body bg claro.
   Entonces 18% black sobre claro = gris silver — leia como
   "cargando" o como un segundo fondo. FIX: negro solido. Sin
   translucencia. Asi el topbar es una barra negra coherente con el
   hero negro y no toca el body claro visualmente. */
.topbar.is-over-dark {
  background: #000;
  border-bottom-color: transparent;
  color: #fff;
}
.topbar.is-over-dark .wordmark,
.topbar.is-over-dark .icon-btn { color: #fff; }
.topbar.is-over-dark .icon-btn:hover { background: rgba(255, 255, 255, 0.12); }
.topbar.is-over-dark .icon-btn.lock-btn[aria-pressed="true"] {
  background: #fff; color: #000;
}
.topbar.is-over-dark .count-bubble {
  background: #fff; color: #000;
}

@media (prefers-reduced-motion: reduce) {
  .hero-vault { height: 100vh; }
  .hero-bag   { transform: rotateY(16deg); }
}

/* ---- Skip-to-catalog: text-link debajo del monograma AV ----
   Para usuarios impacientes (especialmente mobile) que llegan a la
   home y ya saben que vienen a comprar — no quieren scrollear 130-200vh
   de scrollytelling antes de ver productos. Hace smooth scroll al grid.
   Estilo: muy bajo contraste, decorativo. Quien tiene paciencia, ni
   lo ve; quien quiere atajo, lo agradece. */
.hero-skip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 14px;
  font-family: "Jost", sans-serif;
  font-size: 0.62rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.45);
  text-decoration: none;
  padding: 6px 10px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.18);
  transition: color 0.25s ease, border-color 0.25s ease, transform 0.25s ease;
}
.hero-skip:hover {
  color: rgba(255, 255, 255, 0.85);
  border-bottom-color: rgba(255, 255, 255, 0.6);
}
.hero-skip svg { transition: transform 0.25s ease; }
.hero-skip:hover svg { transform: translateX(2px); }

/* ---- Scroll hint: linea vertical + label rotado, abajo del hero ----
   Solo visible en mobile (donde el scrollytelling no es obvio) y solo
   en el primer fold. Hero.js le agrega .is-hidden cuando el progress
   pasa de 0.05 (el usuario ya entendio que tiene que scrollear).
   Comportamiento desktop: oculto siempre — los acts ya hacen el "tease".
   La linea pulsa en infinite loop sutil para llamar la atencion sin
   gritar. Reduce-motion: la linea no pulsa, solo aparece estatica. */
.hero-scroll-hint {
  position: absolute;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%);
  display: none; /* override en mobile abajo */
  flex-direction: column;
  align-items: center;
  gap: 8px;
  z-index: 5;
  pointer-events: none;
  transition: opacity 0.5s ease, transform 0.5s ease;
}
.hero-scroll-hint-label {
  font-family: "Jost", sans-serif;
  font-size: 0.56rem;
  letter-spacing: 0.36em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.45);
  /* Vertical text via writing-mode evita transforms que bloquean
     el text rendering subpixel en algunos browsers. */
  writing-mode: vertical-rl;
  transform: rotate(180deg);
}
.hero-scroll-hint-line {
  width: 1px;
  height: 36px;
  background: linear-gradient(
    to bottom,
    rgba(255, 255, 255, 0) 0%,
    rgba(255, 255, 255, 0.55) 50%,
    rgba(255, 255, 255, 0) 100%
  );
  animation: heroScrollHintPulse 2.4s ease-in-out infinite;
}
@keyframes heroScrollHintPulse {
  0%, 100% { transform: scaleY(0.6); opacity: 0.5; }
  50%      { transform: scaleY(1);   opacity: 1; }
}
.hero-vault.hero-has-scrolled .hero-scroll-hint {
  opacity: 0;
  transform: translateX(-50%) translateY(8px);
}
@media (prefers-reduced-motion: reduce) {
  .hero-scroll-hint-line { animation: none; }
}

/* ---- FASE A: Mobile fluido ----
   Hero mas corto (130vh vs 200vh): reduce el scroll necesario para
   pasar el scrollytelling y llegar al catalogo. El catalogo es la
   accion principal en e-commerce; no queremos que el storytelling
   tape el producto en mobile. Los rangos de los actos en hero.js
   son sobre progress (0..1), siguen funcionando con cualquier altura.

   Tambien: scroll-hint visible (mobile-only) y touch targets 44px. */
@media (max-width: 780px) {
  .hero-vault { height: 130vh; }
  .hero-scroll-hint { display: flex; }

  /* Touch targets: minimo 44x44 (Apple HIG / Material Design). Antes
     eran 36x36, suficiente para mouse pero apretado para dedo. */
  .icon-btn { width: 44px; height: 44px; }

  /* Topbar derecho con 3 iconos (search + WA + wishlist) en mobile:
     reduce el gap para evitar overflow y mantiene proporcion. */
  .topbar-right { gap: 2px; }

  /* Padding sticky reducido para que el bag respire entre topbar y acts */
  .hero-sticky {
    padding: clamp(72px, 11vh, 96px) 18px clamp(56px, 9vh, 84px);
  }
}

/* ---- Landscape mobile / tablet ----
   En orientacion horizontal con poca altura (max-height: 600px) los
   actos se aplastan contra el bag. Comprimimos padding + tamano de
   tipografia + min-height de los acts para que la composicion entre
   en el viewport sin cortar nada. */
@media (max-height: 600px) and (max-width: 1100px) {
  .hero-vault { height: 110vh; }
  .hero-sticky {
    padding: clamp(48px, 8vh, 72px) 24px clamp(36px, 6vh, 56px);
    gap: clamp(16px, 2.5vh, 28px);
  }
  .hero-act p { font-size: clamp(1.4rem, 5.5vw, 2.4rem); }
  .hero-acts { min-height: clamp(96px, 18vh, 132px); }
  .hero-bag  { width: clamp(140px, 38vw, 220px); }
  .hero-skip { margin-top: 8px; }
  .hero-scroll-hint { display: none; } /* sin altura para mostrarlo */
}

/* ===========================================================
   2. PAGE HEADER
   =========================================================== */
.page-header {
  max-width: 1400px;
  margin: 0 auto;
  padding: 56px 24px 24px;
  text-align: center;
}

/* Hairline puente entre hero y catalogo: linea fina + monograma AV
   chiquito + linea fina. Marca el cambio de capitulo (hero negro
   editorial → catalogo blanco minimalista) como una transicion
   intencional. Sin esto, el blanco del fin del hero gradient se
   funde con el blanco del catalogo y el cambio se siente abrupto. */
.page-header-rule {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(14px, 3vw, 28px);
  width: 100%;
  max-width: 380px;
  margin: 0 auto clamp(40px, 6vw, 64px);
  padding-top: clamp(24px, 4vw, 40px);
}
.page-header-rule-line {
  flex: 1;
  height: 1px;
  background: var(--line-strong);
  opacity: 0.55;
}
.page-header-rule-mark {
  width: clamp(18px, 2.4vw, 24px);
  height: auto;
  display: block;
  opacity: 0.7;
}

.page-header .tagline {
  margin: 0 0 12px;
  color: var(--ink-mute);
  font-size: 0.72rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  font-weight: 500;
}
.page-header h1 {
  font-size: clamp(2rem, 4.2vw, 3.1rem);
  line-height: 1.04;
  font-weight: 400;
}
.page-header .count {
  margin: 10px 0 0;
  color: var(--ink-soft);
  font-size: 0.9rem;
}

.admin-notice {
  max-width: 1400px;
  margin: 0 auto 10px;
  padding: 10px 16px;
  border-radius: var(--radius-sm);
  background: var(--bg-surface);
  border: 1px solid var(--line);
  color: var(--ink);
  font-size: 0.86rem;
  text-align: center;
}
.admin-notice strong { font-weight: 600; }

/* Flash message — banner editorial (dead-link recovery, avisos puntuales).
   Nada estridente: hairline border, tipografia baja, auto-dismiss desde JS. */
.flash-message {
  max-width: 1400px;
  margin: 0 auto 14px;
  padding: 12px 18px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  background: var(--bg-surface);
  border: 1px solid var(--line);
  color: var(--ink);
  font-size: 0.86rem;
  letter-spacing: 0.01em;
  animation: flashIn 0.35s cubic-bezier(0.22, 0.9, 0.3, 1);
}
.flash-message.hidden { display: none; }
.flash-message .flash-text { flex: 1; }
.flash-message .flash-close {
  border: 0;
  background: transparent;
  color: var(--ink-soft);
  cursor: pointer;
  padding: 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: color 0.2s;
}
.flash-message .flash-close:hover { color: var(--ink); }
.flash-message .flash-close svg { width: 16px; height: 16px; }
@keyframes flashIn {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .flash-message { animation: none; }
}

/* ---- Confirm modal (reemplazo de window.confirm) ----
   API JS: confirmDialog({ title, message, confirmText, cancelText, danger }) -> Promise<bool>
   Estetica editorial B&W: card con hairline border, tipografia dual
   (Fraunces para titulo, Jost para message y buttons). Backdrop con
   blur sutil. Escape cancela, Enter confirma, click en backdrop cancela.
   z-index 70: por encima del detail (55) y su close (60), para que si
   el usuario confirma algo desde dentro del detail se vea siempre arriba. */
.confirm-modal {
  position: fixed;
  inset: 0;
  z-index: 70;
  background: rgba(0, 0, 0, 0.58);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  display: grid;
  place-items: center;
  padding: 24px;
  animation: confirmFadeIn 0.16s ease-out;
}
.confirm-modal.hidden { display: none; }
.confirm-card {
  background: var(--bg);
  border: 1px solid var(--line-strong);
  max-width: 420px;
  width: 100%;
  padding: 28px 28px 24px;
  animation: confirmPopIn 0.22s cubic-bezier(0.22, 1, 0.36, 1);
}
.confirm-title {
  margin: 0 0 10px;
  font-family: "Fraunces", Georgia, serif;
  font-weight: 400;
  font-size: 1.28rem;
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.confirm-message {
  margin: 0 0 22px;
  font-family: "Jost", sans-serif;
  font-weight: 300;
  font-size: 0.94rem;
  line-height: 1.5;
  color: var(--ink-soft);
}
.confirm-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  flex-wrap: wrap;
}
.confirm-actions button {
  padding: 11px 20px;
  font-family: "Jost", sans-serif;
  font-weight: 400;
  font-size: 0.7rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  cursor: pointer;
  border-radius: 0;
  transition: color 0.18s ease, background 0.18s ease, border-color 0.18s ease;
}
.confirm-cancel {
  background: transparent;
  color: var(--ink-soft);
  border: 1px solid var(--line-strong);
}
.confirm-cancel:hover,
.confirm-cancel:focus-visible {
  color: var(--ink);
  border-color: var(--ink);
  outline: none;
}
.confirm-ok {
  background: var(--ink);
  color: var(--bg);
  border: 1px solid var(--ink);
}
.confirm-ok:hover,
.confirm-ok:focus-visible {
  background: transparent;
  color: var(--ink);
  outline: none;
}
/* danger: misma estetica pero con tono rojo carbon muy sutil (no intrusivo).
   Se usa para acciones destructivas (vaciar wishlist, eliminar producto). */
.confirm-ok.is-danger {
  background: #1a1a1a;
  border-color: #1a1a1a;
}
.confirm-ok.is-danger:hover,
.confirm-ok.is-danger:focus-visible {
  background: transparent;
  color: #1a1a1a;
  border-color: #1a1a1a;
}
@keyframes confirmFadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes confirmPopIn {
  from { opacity: 0; transform: translateY(8px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .confirm-modal,
  .confirm-card { animation: none; }
}

/* ===========================================================
   3. BRAND PILLS — tipograficas (sin relleno)
   Editorial: texto minusculo + tracking + underline en activo.
   El relleno negro de la version anterior competia con las cards
   y rompia la lectura horizontal del index de marcas.
   =========================================================== */
.brand-pills {
  max-width: 1400px;
  margin: 0 auto;
  padding: 18px 24px 10px;
  display: flex;
  gap: 28px;
  justify-content: center;
  flex-wrap: wrap;
  border-bottom: 1px solid var(--line);
}
.pill {
  position: relative;
  border: 0;
  background: transparent;
  color: var(--ink-soft);
  padding: 6px 2px;
  font-family: "Jost", sans-serif;
  font-size: 0.76rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  cursor: pointer;
  white-space: nowrap;
  transition: color 0.15s ease;
}
.pill::after {
  content: "";
  position: absolute;
  left: 2px; right: 2px; bottom: 0;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 0.2s ease;
}
.pill:hover { color: var(--ink); }
.pill:hover::after { transform: scaleX(1); }
.pill.is-active {
  color: var(--ink);
}
.pill.is-active::after { transform: scaleX(1); }

@media (max-width: 720px) {
  .brand-pills {
    justify-content: flex-start;
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    padding: 14px 16px 12px;
    gap: 22px;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    mask-image: linear-gradient(90deg, transparent 0, #000 16px, #000 calc(100% - 16px), transparent 100%);
  }
  .brand-pills::-webkit-scrollbar { display: none; }
  .pill {
    flex: 0 0 auto;
    font-size: 0.7rem;
    letter-spacing: 0.2em;
  }
}

/* ===========================================================
   3b. STYLE PILLS (Fase 3) — multi-select
   Mismos .pill tipograficos que brand-pills, pero con comportamiento
   multi-select: el click activa/desactiva cada pill independientemente.
   Diferenciamos visualmente la activa con un box de fondo sutil (en
   vez del underline de brand-pills) para que sea evidente que se
   pueden seleccionar varios a la vez.
   Contenedor sin border-bottom para no apilar dos lineas en el header.
   =========================================================== */
.style-pills {
  max-width: 1400px;
  margin: 0 auto;
  padding: 10px 24px 14px;
  display: flex;
  gap: 10px;
  justify-content: center;
  flex-wrap: wrap;
  border-bottom: 1px solid var(--line);
}
.style-pills.hidden { display: none; }
.style-pills .pill {
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  letter-spacing: 0.14em;
  font-size: 0.7rem;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.style-pills .pill::after { display: none; }   /* sin underline para multi */
.style-pills .pill:hover  { color: var(--ink); border-color: var(--ink-soft); }
.style-pills .pill.is-active {
  background: var(--ink);
  color: var(--bg);
  border-color: var(--ink);
}
.style-pills .pill.is-clear {
  /* Pill "Limpiar estilos" (solo aparece cuando hay >=1 activo). */
  border-style: dashed;
  color: var(--ink-mute);
}
.style-pills .pill.is-clear:hover {
  color: var(--danger);
  border-color: var(--danger);
  background: transparent;
}
@media (max-width: 720px) {
  .style-pills {
    justify-content: flex-start;
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    padding: 8px 16px 12px;
    gap: 8px;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    mask-image: linear-gradient(90deg, transparent 0, #000 16px, #000 calc(100% - 16px), transparent 100%);
  }
  .style-pills::-webkit-scrollbar { display: none; }
  .style-pills .pill { flex: 0 0 auto; font-size: 0.66rem; }
}

/* ===========================================================
   4. FILTER TOOLBAR — hairline, tipografica
   Ya no es un panel con boton-capsula. Es una linea discreta
   entre las pills y el grid que apenas se anuncia.
   =========================================================== */
.toolbar {
  max-width: 1400px;
  margin: 22px auto 18px;
  padding: 0 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}
.toolbar .browsing {
  margin: 0;
  font-family: "Jost", sans-serif;
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.toolbar .browsing strong {
  color: var(--ink);
  font-weight: 500;
}
.btn-filter {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px 0;
  border: 0;
  border-bottom: 1px solid transparent;
  background: transparent;
  color: var(--ink);
  font-family: "Jost", sans-serif;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  cursor: pointer;
  transition: border-color 0.2s ease;
}
.btn-filter:hover { border-bottom-color: var(--ink); }
.btn-filter svg { width: 13px; height: 13px; }
.btn-filter .badge-count {
  background: var(--ink);
  color: #fff;
  border-radius: 999px;
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0;
  min-width: 16px; height: 16px;
  padding: 0 5px;
  display: inline-flex; align-items: center; justify-content: center;
  margin-left: 2px;
}

/* ===========================================================
   5. CATALOG GRID — editorial, B&W puro
   Principios:
    - Imagen 3/4 (mas editorial que 4/5, respira).
    - Sin box-shadow: plano y limpio (Apple / Net-a-Porter).
    - CTA NO es un bloque negro per card — compite con la imagen y
      hace que todo se lea como "marketplace". Ahora es un link
      tipografico "Pedir →" dentro de la fila de precio, con
      underline-on-hover.
    - Status chip sin color: dot minimal + caption B&W.
    - Gap vertical generoso (56px) para que cada pieza respire.
   =========================================================== */
.catalog {
  max-width: 1400px;
  margin: 0 auto;
  padding: 16px 24px 80px;
}
.catalog-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 64px 28px;
  /* align-items:start para que si por cualquier razon hay tarjetas
     con alturas distintas (ej. titulo en 2 lineas vs 1) queden
     alineadas por arriba y no estiradas. Con aspect-ratio uniforme
     en las fotos, la fuente principal de variacion son los titulos. */
  align-items: start;
}
@media (max-width: 1100px) { .catalog-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 52px 22px; } }
@media (max-width: 780px)  { .catalog-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 40px 14px; } }

.product-card {
  display: flex;
  flex-direction: column;
  gap: 14px;
  position: relative;
  /* Hover/tap lift: feedback tactil sutil. Solo aplica donde hay
     hover real (desktop) y con active para el tap mobile. Los
     reduce-motion users ven la card quieta (override abajo). */
  transition: transform 0.28s cubic-bezier(0.22, 0.9, 0.3, 1);
}
@media (hover: hover) {
  .product-card:hover { transform: translateY(-3px); }
}
.product-card:active {
  transform: translateY(0) scale(0.992);
  transition: transform 0.1s ease;
}
@media (prefers-reduced-motion: reduce) {
  .product-card,
  .product-card:hover,
  .product-card:active { transform: none; transition: none; }
}
.product-image-wrap {
  position: relative;
  overflow: hidden;
  /* Fondo blanco puro = mismo color que la pagina. Asi el "espacio
     sobrante" del contain (cuando la foto no llena exactamente el
     frame 4:5) queda INVISIBLE — se funde con la pagina y lee como
     margen editorial, no como letterbox gris. */
  background: var(--bg);
  /* Aspect-ratio uniforme 4:5 (Instagram shop standard).
     → Simetria de fila: TODAS las cards identicas sin cambiar el
       ancho de columna del grid (la pagina no se afecta).
     → Fotos portrait tall (ej. Steve Madden) casi llenan el frame.
     → Fotos landscape (ej. stock con banner) muestran el 100%
       centradas, con respiracion blanca arriba/abajo invisible. */
  aspect-ratio: 4 / 5;
}
.product-image {
  width: 100%;
  height: 100%;
  /* contain = la foto NUNCA se recorta. Si su aspect no coincide con
     4:5, se muestra completa con espacio blanco alrededor. Ese espacio,
     sobre fondo blanco de pagina, es invisible. */
  object-fit: contain;
  object-position: center;
  display: block;
  transition: transform 0.6s cubic-bezier(0.22, 0.9, 0.3, 1);
}
.product-card:hover .product-image { transform: scale(1.035); }

.wishlist-btn {
  position: absolute;
  top: 12px; right: 12px;
  width: 32px; height: 32px;
  border-radius: 50%;
  border: 0;
  background: transparent;
  color: #fff;
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  /* sombra textil en lugar de background solido: el corazon es el
     unico elemento sobre la foto, queremos que lea como marca-agua */
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.45));
  transition: transform 0.15s ease;
}
.wishlist-btn:hover { transform: scale(1.12); }
.wishlist-btn:active { transform: scale(0.92); }
.wishlist-btn svg {
  width: 20px; height: 20px;
  fill: transparent; stroke: currentColor; stroke-width: 1.8;
  transition: fill 0.15s ease;
}
.wishlist-btn.is-active svg { fill: currentColor; }

/* Status: dot minimal + label B&W sobre la foto, bottom-left.
   Available = sin chip (silencio es mejor que "disponible").
   Low/Reserved = dot con var funcional (solo el dot), texto blanco.
   Out = chip negro pleno. */
.status-chip {
  position: absolute;
  left: 12px; bottom: 12px;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 10px 5px 9px;
  background: rgba(0, 0, 0, 0.58);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: #fff;
  font-family: "Jost", sans-serif;
  font-size: 0.64rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  border-radius: 2px;
}
.status-chip::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.9;
}
.status-chip.available { display: none; } /* silencio editorial */
.status-chip.low::before,
.status-chip.reserved::before { background: #e0a84a; }
.status-chip.out {
  background: rgba(0, 0, 0, 0.85);
}
.status-chip.out::before { background: #fff; opacity: 1; }

.product-card.is-out .product-image { filter: grayscale(1) brightness(0.82); }

.product-info {
  padding: 0;
  display: grid;
  gap: 4px;
}
.product-brand {
  font-family: "Jost", sans-serif;
  font-size: 0.66rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-mute);
  margin: 0;
  font-weight: 500;
}
.product-title {
  font-family: "Fraunces", Georgia, serif;
  font-size: 1.05rem;
  font-weight: 400;
  margin: 2px 0 0;
  line-height: 1.25;
  color: var(--ink);
  letter-spacing: -0.005em;
}
.product-price-row {
  margin-top: 10px;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--line);
}
.product-price {
  /* Editorial: Fraunces en vez de Jost. El precio en serif se lee como
     cifra de coleccionista, no como tag de ecommerce. tabular-nums
     mantiene los digitos alineados entre cards (1.299 y 899 ocupan
     el mismo ancho por digito). */
  font-family: "Fraunces", Georgia, serif;
  font-size: 1.08rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.005em;
}
.product-stock {
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  color: var(--ink-mute);
  text-transform: lowercase;
}

/* CTA editorial: link con flecha, no boton de bloque.
   En hover desliza la flecha + underline aparece. */
.wa-button {
  margin-top: 4px;
  display: inline-flex;
  align-items: center;
  justify-content: flex-start;
  gap: 6px;
  padding: 4px 0;
  background: transparent;
  color: var(--ink);
  font-family: "Jost", sans-serif;
  font-weight: 500;
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  border: 0;
  border-bottom: 1px solid transparent;
  align-self: flex-start;
  transition: border-color 0.2s ease, color 0.2s ease;
}
.wa-button::after {
  content: "→";
  font-family: "Jost", sans-serif;
  display: inline-block;
  margin-left: 2px;
  transition: transform 0.2s ease;
}
.wa-button:hover {
  border-bottom-color: var(--ink);
}
.wa-button:hover::after { transform: translateX(3px); }
.wa-button:active { opacity: 0.7; }
.wa-button.wa-disabled {
  pointer-events: none;
  opacity: 0.35;
}
/* Ocultamos el SVG de WhatsApp: el contexto (botones "pedir", la
   tipografia del nav con WA arriba, el footer) ya comunica el canal.
   El icono dentro del CTA compite con la flecha editorial. */
.wa-button svg { display: none; }
/* Responsive label: "Pedir por WhatsApp" en desktop, "Pedir" en mobile
   para que no wrappee a 2 lineas en cards de 160px. */
.wa-label-short { display: none; }

/* "Notify me" (out of stock) — mismo lenguaje tipografico */
.notify-button {
  margin-top: 4px;
  display: inline-flex;
  align-items: center;
  justify-content: flex-start;
  gap: 6px;
  padding: 4px 0;
  background: transparent;
  color: var(--ink-soft);
  font-family: "Jost", sans-serif;
  font-weight: 500;
  font-size: 0.76rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  border: 0;
  border-bottom: 1px solid transparent;
  align-self: flex-start;
  cursor: pointer;
  transition: border-color 0.2s ease, color 0.2s ease;
}
.notify-button:hover { color: var(--ink); border-bottom-color: var(--ink); }
.notify-button svg { display: none; }

/* Empty state: silencio editorial, sin panel de fondo gris.
   Ahora con monograma AV como marca-agua + CTA de lead capture
   (pre-llena filtros al notify modal). Tipografia centrada con
   hairlines arriba y abajo. */
.empty-state {
  grid-column: 1 / -1;
  padding: 72px 24px 80px;
  text-align: center;
  color: var(--ink-soft);
  background: transparent;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.empty-state .empty-mark {
  width: 56px;
  height: 56px;
  margin: 0 auto 22px;
  display: block;
  color: var(--ink);
  opacity: 0.22;
}
.empty-state h3 {
  margin: 0 0 10px;
  font-family: "Fraunces", Georgia, serif;
  font-size: 1.5rem;
  font-weight: 400;
  color: var(--ink);
  letter-spacing: -0.01em;
}
.empty-state p  {
  margin: 0;
  font-size: 0.92rem;
  max-width: 420px;
  margin-left: auto;
  margin-right: auto;
  line-height: 1.5;
}
.empty-state .btn { margin-top: 26px; }

/* ===========================================================
   6. DRAWER (side sheet)
   =========================================================== */
.drawer-scrim {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.35);
  z-index: 40;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.22s ease;
}
.drawer-scrim.is-open { opacity: 1; pointer-events: auto; }

.drawer {
  position: fixed;
  top: 0; right: 0;
  width: min(440px, 92vw);
  height: 100vh;
  background: var(--bg-elev);
  z-index: 41;
  transform: translateX(100%);
  transition: transform 0.36s cubic-bezier(0.22, 0.9, 0.3, 1);
  display: flex;
  flex-direction: column;
  box-shadow: -24px 0 64px rgba(0, 0, 0, 0.12);
}
.drawer.is-open { transform: translateX(0); }
.drawer-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 22px 26px 18px;
  border-bottom: 1px solid var(--line);
}
.drawer-head h2 {
  font-family: "Fraunces", Georgia, serif;
  font-size: 1.4rem;
  font-weight: 400;
  letter-spacing: -0.01em;
}
.drawer-body {
  flex: 1;
  overflow-y: auto;
  padding: 26px 26px 22px;
  display: grid;
  gap: 30px;
}
.drawer-foot {
  display: flex; gap: 12px;
  padding: 18px 26px 26px;
  border-top: 1px solid var(--line);
  background: var(--bg-elev);
}
.drawer-foot button { flex: 1; }

.filter-group { display: grid; gap: 12px; }
.filter-group h3 {
  font-family: "Jost", sans-serif;
  font-size: 0.7rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-mute);
  font-weight: 500;
  margin: 0;
}

.field { display: grid; gap: 8px; }
.field label {
  font-family: "Jost", sans-serif;
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-mute);
  font-weight: 500;
}
/* Inputs editoriales: hairline bottom-border, sin caja.
   El borde-caja rellena la intencion, pero en un layout B&W
   luxury compite con la tipografia. Una linea debajo basta. */
.field input,
.field select,
.drawer-body input[type="search"],
.drawer-body input[type="number"],
.drawer-body input[type="tel"],
.drawer-body input[type="text"],
.drawer-body select {
  width: 100%;
  padding: 8px 2px;
  border: 0;
  border-bottom: 1px solid var(--line-strong);
  border-radius: 0;
  background: transparent;
  color: var(--ink);
  font-family: "Jost", sans-serif;
  font-size: 0.92rem;
  transition: border-color 0.2s ease;
}
.field input::placeholder,
.drawer-body input::placeholder {
  color: var(--ink-mute);
}
.field input:focus,
.field select:focus,
.drawer-body input:focus,
.drawer-body select:focus {
  outline: 0;
  border-bottom-color: var(--ink);
}
/* Select mantiene la flecha nativa — suficiente con el hairline */
.field select,
.drawer-body select {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path d='M1 1l4 4 4-4' fill='none' stroke='%236e6e73' stroke-width='1.2' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-position: right 2px center;
  padding-right: 18px;
}

.price-range {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 14px;
  align-items: end;
}
.price-range .sep {
  padding-bottom: 10px;
  color: var(--ink-mute);
  font-size: 0.9rem;
}

/* Swatches: mismo lenguaje que brand-pills. Texto con underline
   animado al activarse. Uniformidad tipografica en toda la UI. */
.color-swatches { display: flex; flex-wrap: wrap; gap: 18px; }
.swatch {
  position: relative;
  border: 0;
  background: transparent;
  color: var(--ink-soft);
  padding: 4px 2px;
  font-family: "Jost", sans-serif;
  font-size: 0.74rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color 0.15s ease;
}
.swatch::after {
  content: "";
  position: absolute;
  left: 2px; right: 2px; bottom: 0;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 0.2s ease;
}
.swatch:hover { color: var(--ink); }
.swatch:hover::after { transform: scaleX(1); }
.swatch.is-active { color: var(--ink); }
.swatch.is-active::after { transform: scaleX(1); }

/* ===========================================================
   7. BUTTONS genericos — rectangulares, editoriales
   Radius 2px (casi recto) en vez de 999px. Los primarios
   usan letter-spacing + uppercase para anclarlos al lenguaje
   tipografico del resto (pills, swatches, CTA de card).
   =========================================================== */
.btn {
  border: 0;
  padding: 14px 22px;
  border-radius: 2px;
  font-family: "Jost", sans-serif;
  font-weight: 500;
  font-size: 0.76rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease, transform 0.1s ease;
}
.btn:active { transform: scale(0.98); }
.btn-primary {
  background: var(--ink); color: #fff;
}
.btn-primary:hover { background: #000; }
.btn-ghost {
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--line-strong);
}
.btn-ghost:hover { border-color: var(--ink); }
.btn-danger {
  background: transparent;
  color: var(--danger);
  border: 1px solid rgba(178, 39, 29, 0.32);
}
.btn-danger:hover { background: rgba(178, 39, 29, 0.06); }

/* ===========================================================
   8. MODAL (login + notify) — editorial, hairline
   Radius 2px y sombra mas discreta. El contenido manda.
   =========================================================== */
.modal {
  position: fixed; inset: 0; z-index: 50;
  background: rgba(0, 0, 0, 0.45);
  display: grid; place-items: center;
  padding: 16px;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.modal-card {
  width: min(440px, 100%);
  border-radius: 2px;
  background: var(--bg-elev);
  color: var(--ink);
  box-shadow: 0 32px 72px rgba(0, 0, 0, 0.18);
  padding: 32px 28px 24px;
  display: grid;
  gap: 18px;
}
.modal-card h3 {
  font-family: "Fraunces", Georgia, serif;
  font-size: 1.55rem;
  font-weight: 400;
  letter-spacing: -0.01em;
}
.modal-card p  { margin: 0; color: var(--ink-soft); font-size: 0.92rem; line-height: 1.5; }
.modal-card form { display: grid; gap: 16px; }
.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 8px;
}
.modal-footer-row { margin-top: 4px; text-align: center; }
.link-button {
  background: none; border: 0;
  color: var(--ink-soft);
  cursor: pointer;
  font-family: "Jost", sans-serif;
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 4px 0;
  border-bottom: 1px solid transparent;
  transition: color 0.2s ease, border-color 0.2s ease;
}
.link-button:hover { color: var(--ink); border-bottom-color: var(--ink); }
.link-button:disabled,
.link-button[disabled] {
  color: var(--ink-mute, #9a9a9a);
  border-bottom-color: transparent;
  cursor: default;
  opacity: 0.72;
}
.link-button:disabled:hover,
.link-button[disabled]:hover {
  border-bottom-color: transparent;
  color: var(--ink-mute, #9a9a9a);
}
.form-message {
  margin: 0; min-height: 18px;
  font-family: "Jost", sans-serif;
  font-size: 0.8rem;
  line-height: 1.5;
  color: var(--danger);
  letter-spacing: 0.02em;
}
.form-message strong { font-weight: 500; color: var(--ink); letter-spacing: 0.04em; }
.form-message.success { color: var(--success); }
.form-message.success strong { color: var(--success); }

/* Notify-me modal — tarjeta de producto embebida, editorial */
.notify-product-card {
  display: flex;
  gap: 14px;
  padding: 14px;
  border: 1px solid var(--line);
  background: transparent;
}
.notify-product-card img {
  width: 56px; height: 72px;
  object-fit: cover;
  border-radius: 0;
  flex: 0 0 56px;
}
.notify-product-card .meta {
  display: grid; gap: 3px;
  font-size: 0.82rem;
}
.notify-product-card .meta strong {
  font-family: "Fraunces", Georgia, serif;
  font-size: 1rem;
  font-weight: 400;
  color: var(--ink);
}
.notify-product-card .meta span {
  color: var(--ink-soft);
  font-size: 0.78rem;
}
.notify-product-card .meta span:nth-child(2) {
  font-family: "Jost", sans-serif;
  font-size: 0.66rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-mute);
}

/* ===========================================================
   8b. PRODUCT DETAIL MODAL (full-screen, deep-link ?id=)
   Mobile-first: la imagen manda; el texto se apoya abajo.
   En desktop se divide 50/50 para que la info respire.
   =========================================================== */
.detail-modal {
  position: fixed; inset: 0; z-index: 55;
  background: var(--bg);
  /* display: block (default). Previo: grid rompia position:fixed de .detail-close
     en algunos navegadores mobile — el containing block del hijo fixed caia sobre
     el grid container en vez del viewport y el boton se iba fuera de pantalla.
     .detail-stage sigue siendo grid abajo; el outer solo es un frame full-screen. */
  overflow-y: auto;
  overflow-x: hidden;   /* defensivo: previene scroll horizontal de contenido largo */
  animation: detailFadeIn 0.22s ease-out;
}
.detail-modal.hidden { display: none; }
@keyframes detailFadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}
.detail-close {
  /* position: fixed relativo al viewport. En mobile Chrome/Safari esto ahora
     funciona porque el padre ya no es display:grid (que creaba un containing
     block alternativo bajo ciertas combinaciones con position:fixed). */
  position: fixed;
  top: 14px; right: 14px;
  z-index: 60;          /* por encima del modal (z=55) y cualquier contenido interno */
  width: 42px; height: 42px;
  display: grid; place-items: center;
  background: rgba(255,255,255,0.88);
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  color: var(--ink);
  cursor: pointer;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: background 0.2s ease, border-color 0.2s ease;
}
.detail-close:hover { background: #fff; border-color: var(--ink); }
.detail-close svg { width: 18px; height: 18px; }

.detail-stage {
  display: grid;
  gap: 0;
  grid-template-columns: 1fr;
  min-height: 100vh;
}
.detail-media {
  margin: 0;
  position: relative;
  background: var(--bg-surface);
  display: grid;
  place-items: center;
  min-height: 60vh;
  padding: 72px 24px 24px;
}
/* Contenedor del slide (el <img>) — permite posicionar controles encima
   y aplicar fade cuando cambia el src via JS. */
.detail-gallery {
  position: relative;
  display: grid;
  place-items: center;
  width: 100%;
}
.detail-slide {
  max-width: 100%;
  max-height: 60vh;
  width: auto; height: auto;
  object-fit: contain;
  display: block;
  /* Fade corto cuando JS swapea src: opacidad baja → subimos a 1 en load.
     Timing rapido (220ms) para que no se sienta laggy al navegar. */
  transition: opacity 0.22s ease;
}
.detail-slide.is-loading { opacity: 0; }

/* Navegacion (prev/next). Solo visible cuando hay >1 foto.
   En desktop flotan sobre los bordes de la imagen; en mobile quedan
   en esquinas inferiores para no competir con la pieza. */
.detail-gal-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 44px; height: 44px;
  border-radius: 50%;
  border: 1px solid rgba(0, 0, 0, 0.12);
  background: rgba(255, 255, 255, 0.92);
  color: var(--ink);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background 0.2s ease, transform 0.2s ease, opacity 0.2s ease;
  z-index: 3;
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}
.detail-gal-nav svg { width: 20px; height: 20px; }
.detail-gal-nav:hover { background: #fff; transform: translateY(-50%) scale(1.04); }
.detail-gal-nav:active { transform: translateY(-50%) scale(0.96); }
.detail-gal-nav:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}
.detail-gal-prev { left: 18px; }
.detail-gal-next { right: 18px; }

/* Meta (counter + dots) debajo de la imagen. */
.detail-gal-meta {
  position: absolute;
  bottom: 18px;
  left: 50%;
  transform: translateX(-50%);
  display: inline-flex;
  align-items: center;
  gap: 14px;
  padding: 7px 14px;
  background: rgba(255, 255, 255, 0.9);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(0, 0, 0, 0.06);
  border-radius: 999px;
  z-index: 2;
}
.detail-gal-counter {
  font-family: "Jost", sans-serif;
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}
.detail-gal-dots {
  display: inline-flex;
  gap: 7px;
}
.detail-gal-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  border: 0;
  padding: 0;
  background: rgba(0, 0, 0, 0.22);
  cursor: pointer;
  transition: background 0.2s ease, width 0.22s ease;
}
.detail-gal-dot.is-active {
  background: var(--ink);
  width: 18px;
  border-radius: 3px;
}
.detail-gal-dot:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

/* Ocultar nav + meta cuando solo hay 1 imagen (sin Fase 3 o galeria 1/1). */
.detail-media[data-count="1"] .detail-gal-nav,
.detail-media[data-count="0"] .detail-gal-nav,
.detail-media[data-count="1"] .detail-gal-meta,
.detail-media[data-count="0"] .detail-gal-meta {
  display: none;
}

/* Reduce-motion: mata los fades del slide. */
@media (prefers-reduced-motion: reduce) {
  .detail-slide { transition: none; }
  .detail-gal-dot { transition: none; }
}

.detail-info {
  padding: 28px 24px 60px;
  display: grid;
  gap: 18px;
  align-content: start;
  border-top: 1px solid var(--line);
}
.detail-brand {
  margin: 0;
  font-family: "Jost", sans-serif;
  font-size: 0.74rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink-soft);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px;
}

/* Tag de estado inline: dot de color + texto, sigue la tipografia del
   brand. Se muestra solo cuando aporta info (low/out/reserved). */
.detail-status {
  position: relative;
  padding-left: 14px;
  font-size: inherit;
  letter-spacing: inherit;
  color: var(--ink-soft);
}
.detail-status[hidden] { display: none; }
.detail-status::before {
  content: '';
  position: absolute;
  left: 0; top: 50%;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: currentColor;
  transform: translateY(-50%);
}
.detail-status[data-state="available"] { color: var(--success, #1f7a3e); }
.detail-status[data-state="low"]       { color: #8a6a00; }
.detail-status[data-state="out"]       { color: var(--danger); }
.detail-status[data-state="reserved"]  { color: var(--ink-soft); }
.detail-name {
  margin: 0;
  font-family: "Fraunces", "Cormorant Garamond", serif;
  font-size: clamp(1.65rem, 5vw, 2.2rem);
  font-weight: 400;
  letter-spacing: -0.01em;
  line-height: 1.12;
  color: var(--ink);
}

.detail-specs {
  display: grid;
  gap: 0;
  margin: 4px 0 0;
  border-top: 1px solid var(--line);
}
.detail-specs .spec {
  display: grid;
  grid-template-columns: 90px 1fr;
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
  align-items: baseline;
}
.detail-specs dt {
  font-family: "Jost", sans-serif;
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.detail-specs dd {
  margin: 0;
  font-family: "Jost", sans-serif;
  font-size: 0.92rem;
  color: var(--ink);
}
.detail-specs dd.price {
  font-family: "Fraunces", serif;
  font-size: 1.1rem;
  letter-spacing: -0.005em;
}

.detail-actions {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
  margin-top: 6px;
}
@media (min-width: 520px) {
  .detail-actions { grid-template-columns: auto 1fr; }
}
.detail-wish {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 14px 18px;
  white-space: nowrap;
  font-size: 0.74rem;
  letter-spacing: 0.14em;
}
.detail-wish svg { color: var(--ink-soft); transition: color 0.2s ease; }
.detail-wish.is-active svg { color: var(--ink); }
.detail-wa {
  padding: 14px 18px;
  font-size: 0.76rem;
  letter-spacing: 0.16em;
  text-align: center;
  white-space: nowrap;
}
.detail-share {
  justify-self: start;
  margin-top: 4px;
  font-size: 0.7rem;
}

/* Desktop: split horizontal */
@media (min-width: 820px) {
  .detail-stage {
    grid-template-columns: 1.15fr 1fr;
    min-height: 100vh;
  }
  .detail-media {
    padding: 80px 40px 40px;
    min-height: 100vh;
    border-right: 1px solid var(--line);
  }
  .detail-media img { max-height: 80vh; }
  .detail-info {
    padding: 72px 48px 48px;
    border-top: 0;
    align-content: center;
  }
  .detail-name { font-size: clamp(2rem, 3vw, 2.6rem); }
  .detail-close { top: 20px; right: 20px; }
}

/* Modal abierto: bloquear scroll del body */
body.detail-open { overflow: hidden; }

/* Card hoverable hint: el cursor indica que abre el detalle */
.product-card { cursor: pointer; }
.product-card .wishlist-btn,
.product-card .notify-button,
.product-card .wa-button { cursor: pointer; }

/* ===========================================================
   9. ADMIN PANEL
   =========================================================== */
.admin-panel {
  max-width: 1400px;
  margin: 24px auto 80px;
  padding: 24px;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--bg-elev);
  box-shadow: var(--shadow-md);
  display: grid; gap: 20px;
}
.admin-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  border-bottom: 1px solid var(--line);
  padding-bottom: 14px;
}
.admin-head h2 { font-size: 1.25rem; }
.admin-head .muted { color: var(--ink-soft); font-size: 0.86rem; }
.admin-head .right { display: flex; gap: 8px; }

/* Tabs admin (para Fase 3: Catálogo / Wishlist) */
.admin-tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--line);
  padding: 0 0 0 0;
  margin: -4px 0 4px;
}
.admin-tab {
  background: transparent;
  border: 0;
  padding: 10px 16px;
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--ink-soft);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: color 0.15s ease, border-color 0.15s ease;
  display: inline-flex; align-items: center; gap: 6px;
}
.admin-tab:hover { color: var(--ink); }
.admin-tab.is-active {
  color: var(--ink);
  border-bottom-color: var(--ink);
}
.admin-tab .tab-count {
  background: var(--bg-surface);
  color: var(--ink-soft);
  border-radius: 999px;
  padding: 1px 8px;
  font-size: 0.72rem;
  font-weight: 600;
}
.admin-tab.is-active .tab-count {
  background: var(--ink); color: #fff;
}

.admin-view { display: none; }
.admin-view.is-active { display: grid; gap: 18px; }

.product-form { display: grid; gap: 14px; }
.product-form h3 { font-size: 1rem; color: var(--ink-soft); font-weight: 500; }
.form-grid {
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
}
.product-form .submit-row { display: flex; justify-content: flex-start; }

/* --- Quick Add (mobile-first) ------------------------------ */
.quick-add { gap: 16px; }
.quick-add-head h3 {
  font-family: "Fraunces", "Cormorant Garamond", serif;
  font-size: 1.35rem;
  font-weight: 400;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.quick-add-head p {
  margin: 4px 0 0;
  font-size: 0.82rem;
  line-height: 1.55;
  color: var(--ink-soft);
}
.form-grid .field.full { grid-column: 1 / -1; }

/* Dropzone de foto: grande, editorial, cursor pointer */
.photo-drop {
  position: relative;
  display: block;
  border: 1px dashed var(--line-strong, #b8b8b8);
  border-radius: 4px;
  background: var(--bg);
  padding: 28px 20px;
  text-align: center;
  cursor: pointer;
  transition: border-color 0.2s ease, background-color 0.2s ease;
  min-height: 160px;
}
.photo-drop:hover { border-color: var(--ink); background: var(--bg-surface); }
.photo-drop input[type="file"] {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: pointer;
}
.photo-drop-empty {
  display: grid;
  gap: 8px;
  justify-items: center;
  color: var(--ink-soft);
}
.photo-drop-empty svg {
  width: 38px; height: 38px;
  color: var(--ink);
  opacity: 0.72;
}
.photo-drop-empty strong {
  font-family: "Jost", sans-serif;
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink);
}
.photo-drop-empty span {
  font-size: 0.78rem;
  color: var(--ink-soft);
}
.photo-drop.is-loading { border-style: solid; border-color: var(--ink); }
.photo-drop.is-loading::after {
  content: 'Procesando...';
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: rgba(255,255,255,0.78);
  font-family: "Jost", sans-serif;
  font-size: 0.72rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink);
  pointer-events: none;
}

/* Preview con overlay discreto */
.photo-drop-preview {
  display: grid;
  gap: 10px;
  position: relative;
  z-index: 1;
}
.photo-drop-preview img {
  width: 100%;
  max-height: 280px;
  object-fit: contain;
  background: var(--bg-surface);
  border: 1px solid var(--line);
  border-radius: 2px;
}
.photo-drop-meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-family: "Jost", sans-serif;
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  color: var(--ink-soft);
}
/* Cuando hay preview, el input file queda arriba del todo para re-elegir
   al tocar la imagen, pero el boton "Cambiar" tiene mayor z-index. */
.photo-drop-preview .link-button {
  position: relative;
  z-index: 2;
  font-size: 0.7rem;
  letter-spacing: 0.18em;
}

/* Galeria admin (Fase 3): grid de thumbs con reorder por drag + delete.
   Aparece cuando hay 2+ fotos; la primera lleva chip "Principal". */
.photo-thumbs {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
  gap: 8px;
  padding: 10px;
  border: 1px dashed var(--line);
  border-radius: 4px;
  background: var(--bg-surface);
}
.photo-thumb {
  position: relative;
  aspect-ratio: 1 / 1;
  border-radius: 3px;
  overflow: hidden;
  background: var(--bg);
  border: 1px solid var(--line);
  cursor: grab;
  transition: border-color 150ms ease, transform 120ms ease, box-shadow 150ms ease;
}
.photo-thumb:hover { border-color: var(--ink-soft); }
.photo-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  pointer-events: none; /* el drag lo maneja el contenedor */
}
.photo-thumb.is-primary {
  border-color: var(--ink);
  box-shadow: 0 0 0 1px var(--ink);
}
.photo-thumb.is-dragging {
  opacity: 0.4;
  cursor: grabbing;
}
.photo-thumb.is-drop-target {
  border-color: var(--ink);
  transform: scale(1.03);
}
.photo-thumb-chip {
  position: absolute;
  top: 4px;
  left: 4px;
  background: var(--ink);
  color: var(--bg);
  font-family: "Jost", sans-serif;
  font-size: 0.55rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  padding: 3px 6px;
  border-radius: 2px;
  pointer-events: none;
}
.photo-thumb-remove {
  position: absolute;
  top: 4px;
  right: 4px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 0;
  background: rgba(0, 0, 0, 0.72);
  color: #fff;
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  display: grid;
  place-items: center;
  padding: 0;
  transition: background 140ms ease, transform 140ms ease;
}
.photo-thumb-remove:hover {
  background: var(--ink);
  transform: scale(1.08);
}
@media (prefers-reduced-motion: reduce) {
  .photo-thumb,
  .photo-thumb-remove { transition: none; }
  .photo-thumb.is-drop-target { transform: none; }
}

/* Seccion avanzada colapsable */
.quick-add-advanced {
  border-top: 1px solid var(--line);
  padding-top: 10px;
}
.quick-add-advanced > summary {
  cursor: pointer;
  list-style: none;
  font-family: "Jost", sans-serif;
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-soft);
  padding: 4px 0;
}
.quick-add-advanced > summary::-webkit-details-marker { display: none; }
.quick-add-advanced > summary::before {
  content: '+ ';
  font-weight: 400;
}
.quick-add-advanced[open] > summary::before { content: '− '; }
.quick-add-advanced > .field { margin-top: 10px; }

/* Submit con dos botones lado a lado, simetrico en mobile */
.submit-row-split {
  display: grid !important;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.submit-row-split .btn {
  width: 100%;
  padding: 14px 16px;
  font-size: 0.78rem;
  letter-spacing: 0.18em;
}
.submit-row-split .btn[disabled] { opacity: 0.5; pointer-events: none; }

.admin-table-wrap {
  overflow-x: auto;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
}
.admin-table {
  width: 100%;
  border-collapse: collapse;
  min-width: 780px;
  background: var(--bg);
  font-size: 0.88rem;
}
.admin-table th,
.admin-table td {
  padding: 10px;
  border-bottom: 1px solid var(--line);
  text-align: left;
  vertical-align: middle;
}
.admin-table th {
  background: var(--bg-surface);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  font-weight: 600;
}
.admin-table td input[type="text"],
.admin-table td input[type="number"],
.admin-table td input[type="url"] {
  min-width: 80px;
  padding: 6px 8px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--bg);
}
.admin-table td input[type="checkbox"] { width: 18px; height: 18px; }

.delete-inline {
  background: transparent;
  border: 1px solid rgba(178, 39, 29, 0.32);
  color: var(--danger);
  padding: 6px 10px;
  border-radius: 6px;
  font-size: 0.82rem;
  cursor: pointer;
}
.delete-inline:hover { background: rgba(178, 39, 29, 0.06); }

/* Wishlist admin — header de la vista */
.admin-wishlist-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  padding: 2px 2px 8px;
}
.admin-wishlist-head .muted { margin: 0; color: var(--ink-soft); font-size: 0.86rem; }
.inline-check {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.85rem;
  color: var(--ink-soft);
  cursor: pointer;
}
.inline-check input[type="checkbox"] {
  width: 16px; height: 16px;
  accent-color: var(--ink);
}

/* Wishlist admin — tarjetas de pedidos pendientes */
.wishlist-list { display: grid; gap: 10px; }
.wishlist-list .empty {
  padding: 32px 16px;
  text-align: center;
  border-radius: var(--radius-sm);
  background: var(--bg-surface);
  color: var(--ink-soft);
}

/* Cliente: drawer wishlist */
.wishlist-client-list { display: grid; gap: 12px; }
.wishlist-client-list .muted {
  margin: 0; color: var(--ink-soft); font-size: 0.92rem; text-align: center;
  padding: 40px 12px;
}
.wishlist-client-item {
  display: grid;
  grid-template-columns: 64px 1fr auto;
  gap: 12px;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  align-items: center;
  background: var(--bg);
}
.wishlist-client-item img {
  width: 64px; height: 80px;
  object-fit: cover;
  border-radius: 6px;
  background: var(--bg-surface);
}
.wishlist-client-item .info { display: grid; gap: 2px; min-width: 0; }
.wishlist-client-item .info strong { font-size: 0.95rem; }
.wishlist-client-item .info span { color: var(--ink-soft); font-size: 0.82rem; }
.wishlist-client-item .info .price { color: var(--ink); font-weight: 600; font-size: 0.9rem; }
.wishlist-client-item .remove {
  background: transparent;
  border: 0;
  color: var(--ink-mute);
  cursor: pointer;
  padding: 6px;
  border-radius: 50%;
}
.wishlist-client-item .remove:hover { color: var(--danger); background: var(--bg-surface); }
.wishlist-client-item .remove svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; }
.wishlist-item {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 10px;
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--bg);
  align-items: center;
}
.wishlist-item.is-notified { opacity: 0.6; }
.wishlist-item .who { display: grid; gap: 4px; }
.wishlist-item .who strong { font-size: 0.98rem; }
.wishlist-item .who .meta { color: var(--ink-soft); font-size: 0.82rem; }
.wishlist-item .who .note { color: var(--ink); font-size: 0.86rem; }
.wishlist-item .matches {
  display: flex; flex-wrap: wrap; gap: 4px; margin-top: 2px;
}
.wishlist-item .match-chip {
  font-size: 0.72rem;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--bg-surface);
  color: var(--ink-soft);
  border: 1px solid var(--line);
}
.wishlist-item .match-chip.is-available {
  background: var(--ink); color: #fff; border-color: var(--ink);
}
.wishlist-item .actions { display: flex; gap: 6px; }

/* ===========================================================
   9B. BESTSELLERS — fondo negro, productos con stock <= 1
   Contraste fuerte despues del catalogo blanco. Evoca "drop"
   editorial: el ojo descansa en negro y los productos brillan.
   Mismo grid que el catalogo (4/3/2 cols por breakpoint).
   =========================================================== */
.bestsellers {
  background: var(--ink);
  color: var(--bg);
  /* Padding generoso: la seccion respira fuerte sobre negro y se
     siente como un capitulo aparte de la pagina, no como un grid mas. */
  padding: clamp(64px, 9vw, 110px) 0;
  /* Margin top genera el "salto" visual del catalogo blanco al negro. */
  margin-top: clamp(48px, 6vw, 80px);
}
.bestsellers.hidden { display: none; }
.bestsellers-inner {
  max-width: 1400px;
  margin: 0 auto;
  padding: 0 24px;
}
.bestsellers-head {
  display: grid;
  gap: 6px;
  margin-bottom: clamp(36px, 5vw, 56px);
  text-align: left;
}
.bestsellers-eyebrow {
  font-family: "Jost", sans-serif;
  font-size: 0.7rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
  margin: 0;
}
.bestsellers-title {
  font-family: "Fraunces", Georgia, serif;
  font-weight: 400;
  font-size: clamp(28px, 4vw, 48px);
  letter-spacing: -0.01em;
  line-height: 1.05;
  margin: 0;
  color: var(--bg);
}
.bestsellers-subtitle {
  font-family: "Jost", sans-serif;
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.65);
  margin: 8px 0 0;
}
.bestsellers-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 48px 28px;
  align-items: start;
}
@media (max-width: 1100px) {
  .bestsellers-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 40px 22px; }
}
@media (max-width: 780px) {
  .bestsellers-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 32px 14px; }
}
.bestseller-card {
  display: flex;
  flex-direction: column;
  gap: 14px;
  cursor: pointer;
  text-align: left;
  transition: transform 0.28s cubic-bezier(0.22, 0.9, 0.3, 1);
}
@media (hover: hover) {
  .bestseller-card:hover { transform: translateY(-3px); }
}
.bestseller-card:active { transform: translateY(0) scale(0.992); }
@media (prefers-reduced-motion: reduce) {
  .bestseller-card,
  .bestseller-card:hover,
  .bestseller-card:active { transform: none; transition: none; }
}
.bestseller-image-wrap {
  position: relative;
  overflow: hidden;
  /* Bg blanco para que la foto respire sobre el negro de la seccion.
     Mismo aspect 4:5 + contain del catalogo: paridad visual. */
  background: var(--bg);
  aspect-ratio: 4 / 5;
}
.bestseller-image {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center;
  display: block;
  transition: transform 0.6s cubic-bezier(0.22, 0.9, 0.3, 1);
}
.bestseller-card:hover .bestseller-image { transform: scale(1.035); }
.bestseller-info {
  display: grid;
  gap: 4px;
  padding: 0;
}
.bestseller-brand {
  font-family: "Jost", sans-serif;
  font-size: 0.66rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
  margin: 0;
}
.bestseller-name {
  font-family: "Fraunces", Georgia, serif;
  font-size: 1.05rem;
  font-weight: 400;
  letter-spacing: -0.005em;
  color: var(--bg);
  margin: 2px 0 0;
}
.bestseller-price {
  font-family: "Jost", sans-serif;
  font-size: 0.92rem;
  letter-spacing: 0.04em;
  color: var(--bg);
  margin: 6px 0 0;
}
.bestseller-stock {
  font-family: "Jost", sans-serif;
  font-size: 0.62rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.45);
  margin: 4px 0 0;
}
.bestsellers-cta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: clamp(36px, 5vw, 56px);
  font-family: "Jost", sans-serif;
  font-size: 0.74rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--bg);
  text-decoration: none;
  padding: 12px 0 6px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.4);
  transition: border-color 0.25s ease, transform 0.25s ease;
}
.bestsellers-cta:hover {
  border-bottom-color: var(--bg);
  transform: translateX(2px);
}
.bestsellers-cta svg { transition: transform 0.25s ease; }
.bestsellers-cta:hover svg { transform: translateX(3px); }

/* ===========================================================
   9C. ORIGIN — story editorial, credibilidad
   Fondo blanco con titulo grande Fraunces serif. La parte en
   <em> recibe italica natural de la fuente para texturar el copy.
   =========================================================== */
.origin {
  padding: clamp(80px, 10vw, 140px) 0;
  background: var(--bg);
}
.origin-inner {
  max-width: 880px;
  margin: 0 auto;
  padding: 0 24px;
  text-align: center;
}
.origin-eyebrow {
  font-family: "Jost", sans-serif;
  font-size: 0.7rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 18px;
}
.origin-title {
  font-family: "Fraunces", Georgia, serif;
  font-weight: 400;
  font-size: clamp(32px, 5.5vw, 64px);
  letter-spacing: -0.015em;
  line-height: 1.05;
  color: var(--ink);
  margin: 0 0 36px;
}
.origin-title em {
  font-style: italic;
  /* Italica + serif lujosa: el corte editorial de la frase.
     Slight weight bump opcional via opsz si la fuente lo soporta. */
  font-feature-settings: "ss01" on;
}
.origin-body {
  display: grid;
  gap: 16px;
  max-width: 560px;
  margin: 0 auto 36px;
  font-family: "Jost", sans-serif;
  font-size: 0.95rem;
  line-height: 1.65;
  color: var(--ink-soft);
}
.origin-body p { margin: 0; }
.origin-cta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: "Jost", sans-serif;
  font-size: 0.74rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
  padding: 14px 22px;
  border: 1px solid var(--ink);
  transition: background 0.25s ease, color 0.25s ease, transform 0.25s ease;
}
.origin-cta:hover {
  background: var(--ink);
  color: var(--bg);
  transform: translateY(-1px);
}
.origin-cta svg { transition: transform 0.25s ease; }
.origin-cta:hover svg { transform: translateX(3px); }

/* ===========================================================
   10. FOOTNOTE — editorial minimal
   Hairline arriba, tipografia con letter-spacing. Separa la pagina
   del fin del grid sin repetir la carga visual del topbar.
   =========================================================== */
.footnote {
  max-width: 1400px;
  margin: 80px auto 40px;
  padding: 36px 24px 0;
  border-top: 1px solid var(--line);
  color: var(--ink-mute);
  font-family: "Jost", sans-serif;
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-align: center;
}
.footnote p { margin: 6px 0; }

/* Newsletter form (D4): editorial subscribe en el footer.
   Eyebrow chiquito + pitch grande Fraunces + input/button rectangulares.
   Hairline border en el input, button negro solido (CTA tradicional
   AV: bg ink, text bg). Mobile: stack vertical. Desktop: side-by-side. */
.footnote-newsletter {
  max-width: 520px;
  margin: 0 auto 32px;
  padding: 0 0 28px;
  border-bottom: 1px solid var(--line);
  text-align: center;
}
.footnote-newsletter-eyebrow {
  font-family: "Jost", sans-serif;
  font-size: 0.62rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--ink-mute);
  margin: 0 0 8px !important;
}
.footnote-newsletter-pitch {
  font-family: "Fraunces", Georgia, serif;
  font-weight: 400;
  font-size: clamp(1.2rem, 2.4vw, 1.7rem);
  letter-spacing: -0.005em;
  line-height: 1.2;
  color: var(--ink);
  margin: 0 0 20px !important;
}
.footnote-newsletter-row {
  display: flex;
  gap: 0;
  margin: 0 auto;
  max-width: 440px;
  border: 1px solid var(--ink);
  background: var(--bg);
}
.footnote-newsletter input[type="tel"] {
  flex: 1;
  border: 0;
  background: transparent;
  padding: 12px 16px;
  font-family: "Jost", sans-serif;
  font-size: 0.92rem;
  letter-spacing: 0.02em;
  color: var(--ink);
  outline: none;
  /* Override de cualquier text-transform heredado del .footnote */
  text-transform: none;
}
.footnote-newsletter input[type="tel"]::placeholder {
  color: var(--ink-mute);
  opacity: 0.7;
  letter-spacing: 0.04em;
}
.footnote-newsletter button[type="submit"] {
  border: 0;
  border-left: 1px solid var(--ink);
  background: var(--ink);
  color: var(--bg);
  padding: 12px 22px;
  font-family: "Jost", sans-serif;
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease;
}
.footnote-newsletter button[type="submit"]:hover {
  background: var(--bg);
  color: var(--ink);
}
.footnote-newsletter button[type="submit"]:disabled {
  opacity: 0.5;
  cursor: progress;
}
.footnote-newsletter-msg {
  font-family: "Jost", sans-serif;
  font-size: 0.74rem;
  letter-spacing: 0.06em;
  color: var(--ink-soft);
  margin: 14px 0 0 !important;
  min-height: 1.2em; /* reserva espacio para evitar layout shift */
  text-transform: none;
}
.footnote-newsletter-msg.is-success { color: var(--ink); }
.footnote-newsletter-msg.is-error   { color: #b1340b; }

/* Mobile: stack vertical input/button para que ambos respiren */
@media (max-width: 540px) {
  .footnote-newsletter-row {
    flex-direction: column;
  }
  .footnote-newsletter button[type="submit"] {
    border-left: 0;
    border-top: 1px solid var(--ink);
  }
}

/* Visually-hidden helper (reusable) — accesible para screen readers
   pero invisible visualmente. Usado para labels de inputs sin label
   visible (newsletter input). */
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Linea de marcas: presencia tipografica de las casas que vendemos,
   sin logos. Letter-spacing amplio + serif fuera (Jost) para que lea
   como una lista editorial y no como SEO keyword stuffing. */
.footnote-brands {
  font-family: "Jost", sans-serif;
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  color: var(--ink-soft);
  margin: 0 0 14px !important;
}
/* Linea de meta: WhatsApp + last updated, separados por bullet sutil. */
.footnote-meta {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-size: 0.7rem;
  margin-bottom: 4px !important;
}
.footnote-meta a {
  color: var(--ink-soft);
  text-decoration: none;
  border-bottom: 1px solid var(--line-strong);
  padding-bottom: 1px;
  transition: color 0.2s ease, border-color 0.2s ease;
}
.footnote-meta a:hover {
  color: var(--ink);
  border-bottom-color: var(--ink);
}
.footnote-sep {
  color: var(--ink-mute);
  opacity: 0.5;
}

.footnote .credits {
  font-size: 0.66rem;
  opacity: 0.7;
  letter-spacing: 0.12em;
  margin-top: 12px;
}
.footnote .credits a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  padding-bottom: 1px;
  transition: color 0.2s ease;
}
.footnote .credits a:hover { color: var(--ink); }

/* Made by DAK Agency — firma editorial.
   "Made by" en small-caps Jost (continuidad con el resto del footer).
   "DAK Agency" en Fraunces serif para destacar el autor sin gritar.
   Hairline breve arriba como respiracion tipografica. */
.footnote .made-by {
  display: grid;
  justify-items: center;
  gap: 16px;
  margin-top: 28px;
  font-family: "Jost", sans-serif;
  font-size: 0.66rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.footnote .made-by-rule {
  display: block;
  width: 28px;
  height: 1px;
  background: var(--line-strong);
  opacity: 0.6;
}
.footnote .made-by a {
  margin-left: 6px;
  color: var(--ink-soft);
  font-family: "Fraunces", Georgia, serif;
  font-size: 0.92rem;
  font-weight: 400;
  letter-spacing: 0.02em;
  text-transform: none;
  text-decoration: none;
  border-bottom: 1px solid transparent;
  padding-bottom: 1px;
  transition: color 0.25s ease, border-color 0.25s ease;
}
.footnote .made-by a:hover {
  color: var(--ink);
  border-bottom-color: var(--ink);
}

/* ===========================================================
   11. RESPONSIVE
   =========================================================== */
@media (max-width: 720px) {
  .topbar-inner { padding: 10px 16px; }
  .wordmark { font-size: 0.92rem; letter-spacing: 0.24em; }
  .page-header { padding: 36px 16px 16px; }
  .toolbar { padding: 0 16px; margin: 18px auto 14px; }
  .catalog { padding: 12px 16px 48px; }
  .admin-panel { margin: 16px; padding: 18px; }

  /* CTA acortado en mobile: las cards de ~160px no soportan
     "Pedir por WhatsApp" en una linea sin romper el ritmo. */
  .wa-label-full  { display: none; }
  .wa-label-short { display: inline; }
  .wa-button { font-size: 0.72rem; letter-spacing: 0.16em; }

  .drawer {
    top: auto; bottom: 0;
    width: 100vw; right: 0;
    height: 90vh;
    /* sharp-edge editorial; mantenemos el borde recto al tope
       del sheet — la sombra y el scrim dan la separacion */
    border-top-left-radius: 0;
    border-top-right-radius: 0;
    transform: translateY(100%);
    box-shadow: 0 -24px 64px rgba(0, 0, 0, 0.18);
  }
  .drawer.is-open { transform: translateY(0); }
  .drawer-head { padding: 20px 20px 16px; }
  .drawer-body { padding: 22px 20px 20px; gap: 26px; }
  .drawer-foot { padding: 14px 20px 20px; gap: 10px; }
  /* En drawers estrechas el tracking de los botones primarios
     hacia overflow ("VER / RESULTADOS" en 2 lineas). Reducimos
     tracking y padding justo lo suficiente para que encajen. */
  .drawer-foot .btn {
    font-size: 0.7rem;
    letter-spacing: 0.1em;
    padding: 13px 12px;
  }

  .wishlist-item {
    grid-template-columns: 1fr;
  }
  .wishlist-item .actions { justify-content: flex-start; flex-wrap: wrap; }
}
