/* ============================================================================
   DW PERFUMERÍA — capa "Atelier"  ·  6-ago-2026

   Se carga DESPUÉS de premium.css y es la última palabra. Se separó en su
   propio archivo a propósito: si algo de aquí no gusta, se quita una línea del
   header y la tienda vuelve exactamente a como estaba.

   Qué resuelve, en orden de importancia:

   1. LA TARJETA DE PRODUCTO NO ERA UN OBJETO. premium.css la había aplanado
      (sin fondo, sin borde, sin radio, sin sombra) y las reglas :hover que
      quedaban en style.css apuntaban a `border-color` y `box-shadow`, que ya
      no existían: pasar el ratón por encima solo hacía zoom en la foto. Aquí
      recupera cuerpo — papel, filete y elevación — sin volver a la caja
      redondeada genérica.

   2. NO SE PODÍA COMPRAR DESDE LA CUADRÍCULA. Con 138 referencias, obligar a
      entrar a la ficha para cada añadido es fricción pura. Ahora la tarjeta
      tiene un cajón que sube al pasar por encima (y que en táctil está
      siempre visible, porque en un móvil no hay "encima").

   3. LA APARICIÓN ERA FRÁGIL Y PLANA. `.anim-fade-in { opacity: 0 }` se
      aplicaba SIEMPRE, así que sin JavaScript no había productos. Ahora esa
      opacidad cero vive detrás de `html.js`, y las tarjetas entran
      escalonadas en vez de todas de golpe.

   4. NO HABÍA ESTADO DE CARGA. El filtro por AJAX cambiaba la cuadrícula de
      golpe. Ahora hay esqueletos con brillo mientras llega la respuesta.

   Todo lo que se mueve está apagado bajo `prefers-reduced-motion: reduce`.
============================================================================ */

:root {
  /* --------------------------------------------------------------------
     ESCALA TIPOGRÁFICA
     La portada pintaba 21 tamaños distintos: 9.92, 10.56, 11.52, 12.16,
     12.8, 14.4, 14.72, 15.2, 17.92, 18.88, 43.2... eso no es una escala,
     es la suma de tres plantillas. Estos son los ocho pasos a los que se
     reconducen los elementos que de verdad se ven.
  -------------------------------------------------------------------- */
  --paso-micro: 0.6875rem;   /* 11px — etiquetas, contadores */
  --paso-menor: 0.8125rem;   /* 13px — metadatos, ayudas */
  --paso-base:  0.9375rem;   /* 15px — cuerpo */
  --paso-medio: 1.0625rem;   /* 17px — destacados, precio en tarjeta */
  --paso-mayor: 1.375rem;    /* 22px — nombre de producto en ficha */
  --paso-titulo: clamp(1.6rem, 3vw, 2.25rem);
  --paso-display: clamp(2.1rem, 5vw, 3.4rem);

  /* Ritmo vertical: una sola unidad, sus múltiplos y nada más. */
  --ritmo: 8px;

  /* Curvas. La de "salida" es la que da la sensación de peso caro:
     arranca rápido y se posa despacio. */
  --curva-salida: cubic-bezier(0.16, 1, 0.3, 1);
  --curva-suave:  cubic-bezier(0.4, 0, 0.2, 1);
}

/* ============================================================================
   1. APARICIÓN ESCALONADA, Y A PRUEBA DE JAVASCRIPT CAÍDO

   La opacidad cero SOLO se aplica si `html` tiene la clase `js`, que la pone
   un script en línea en el <head>. Sin JavaScript —o si main.js revienta
   antes de tiempo— la clase no está y todo se ve, que es lo que debe pasar
   en una tienda.
============================================================================ */
html.js .anim-fade-in {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity 0.7s var(--curva-salida),
    transform 0.7s var(--curva-salida);
  /* El escalonado lo marca --i, que pone el PHP con el índice de la tarjeta.
     Se topa a 11 para que el último producto de la página no entre tarde. */
  transition-delay: calc(min(var(--i, 0), 11) * 45ms);
}

html.js .anim-fade-in.visible {
  opacity: 1;
  transform: none;
}

/* Red de seguridad: si a los 3 s alguna tarjeta sigue sin revelarse (el
   observador no disparó, la pestaña estaba en segundo plano, lo que sea),
   main.js pone esta clase en el <html> y se muestra todo sin animación. */
html.reveal-forzado .anim-fade-in {
  opacity: 1 !important;
  transform: none !important;
  transition: none !important;
}

/* ============================================================================
   2. LA TARJETA DE PRODUCTO

   Papel sobre papel: se distingue por un filete finísimo y por la elevación,
   no por una caja con esquinas redondeadas. La perfumería de gama alta se
   mira, no se "cliquea".
============================================================================ */
.product-card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--dw-paper, #fff);
  border: 1px solid var(--dw-line, rgba(20, 20, 15, 0.12));
  border-radius: 0;
  overflow: hidden;
  transition:
    border-color 0.45s var(--curva-suave),
    box-shadow 0.45s var(--curva-suave),
    transform 0.45s var(--curva-salida);
}

@media (hover: hover) {
  .product-card:hover {
    border-color: var(--dw-gold, #c8a24a);
    box-shadow:
      0 1px 2px rgba(20, 20, 15, 0.04),
      0 12px 32px -8px rgba(20, 20, 15, 0.18);
    transform: translateY(-3px);
  }
}

/* El marco de la foto. `aspect-ratio` fijo para que la cuadrícula no baile
   mientras cargan las imágenes, y fondo crema para que una foto con
   transparencia (los PNG de frasco lo son) no quede sobre blanco plano. */
.product-card__image-wrap {
  position: relative;
  aspect-ratio: 3 / 4 !important;
  overflow: hidden;
  background:
    radial-gradient(120% 80% at 50% 0%, #fff 0%, var(--dw-paper-2, #f6f4ef) 70%);
}

/* Selector con la misma forma que el de premium.css (`.product-card img`) para
   que no vuelva a ganar por especificidad si alguien reintroduce aquella regla. */
.product-card img.product-card__image {
  width: 100%;
  height: 100%;
  object-fit: contain !important;   /* un frasco NO se recorta */
  padding: 12% 14%;
  transition: transform 0.9s var(--curva-salida);
  will-change: transform;
}

@media (hover: hover) {
  .product-card:hover .product-card__image { transform: scale(1.05); }
}

/* La familia olfativa, sobre la foto. Es el dato por el que se elige un
   perfume y hasta ahora solo salía en letra pequeña bajo el nombre. */
.product-card__familia {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 2;
  padding: 4px 9px;
  background: rgba(255, 255, 255, 0.86);
  backdrop-filter: blur(6px);
  border: 1px solid var(--dw-line, rgba(20, 20, 15, 0.12));
  font-family: var(--dw-sans, sans-serif);
  font-size: var(--paso-micro);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--dw-gold-deep, #8a6a1f);
}

/* ----------------------------------------------------------------------------
   EL CAJÓN DE COMPRA RÁPIDA

   Sube desde el borde inferior de la foto al pasar por encima. En táctil no
   existe el "encima": ahí se queda siempre visible, porque un cajón que solo
   aparece con ratón es un botón que en un móvil no existe.
---------------------------------------------------------------------------- */
.product-card__quick {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;               /* objetivo táctil cómodo */
  padding: 11px 14px;
  border: 0;
  width: 100%;
  background: var(--dw-ink, #0c0c0d);
  color: var(--dw-gold-light, #e7cf92);
  font-family: var(--dw-sans, sans-serif);
  font-size: var(--paso-menor);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
  transform: translateY(101%);
  transition:
    transform 0.4s var(--curva-salida),
    background-color 0.25s var(--curva-suave),
    color 0.25s var(--curva-suave);
}

@media (hover: hover) {
  .product-card:hover .product-card__quick,
  .product-card__quick:focus-visible { transform: translateY(0); }
  .product-card__quick:hover {
    background: var(--dw-gold, #c8a24a);
    color: var(--dw-ink, #0c0c0d);
  }
}

/* Sin ratón (móvil y tableta): el cajón vive fuera de la foto, siempre a la
   vista, para que se pueda comprar con el pulgar. */
@media (hover: none) {
  .product-card__quick {
    position: static;
    transform: none;
    margin-top: auto;
  }
}

.product-card__quick[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
}

/* Estados del cajón mientras trabaja. El "hecho" se queda dos segundos y
   vuelve solo: es el acuse de recibo que faltaba al añadir al carrito. */
.product-card__quick.esta-cargando { pointer-events: none; opacity: 0.7; }

.product-card__quick.esta-hecho {
  background: var(--dw-gold, #c8a24a) !important;
  color: var(--dw-ink, #0c0c0d) !important;
  transform: translateY(0) !important;
}

/* ---- Ficha de la tarjeta ---- */
.product-card__info { padding: calc(var(--ritmo) * 2) calc(var(--ritmo) * 1.75) 0; }

.product-card__category {
  font-size: var(--paso-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.product-card__name {
  font-size: var(--paso-medio);
  line-height: 1.3;
  margin: 6px 0 4px;
}

.product-card__name a {
  background-image: linear-gradient(var(--dw-gold, #c8a24a), var(--dw-gold, #c8a24a));
  background-repeat: no-repeat;
  background-size: 0 1px;
  background-position: 0 100%;
  transition: background-size 0.45s var(--curva-salida);
}

.product-card:hover .product-card__name a { background-size: 100% 1px; }

.product-card__summary {
  font-size: var(--paso-menor);
  line-height: 1.55;
}

.product-card__prices { align-items: baseline; gap: 10px; }

.product-card__price {
  font-size: var(--paso-medio);
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
}

.product-card__actions { padding: 0 calc(var(--ritmo) * 1.75) calc(var(--ritmo) * 2); }

/* ----------------------------------------------------------------------------
   LAS CUATRO PIEZAS DESTACADAS DE LA PORTADA (.dw-card)

   Es otra tarjeta a propósito —más editorial, centrada, sin filete— pero tenía
   los mismos dos defectos: recortaba los frascos con `object-fit: cover` y su
   franja inferior era un rótulo que decía "Ver pieza" sin hacer nada. Ahora
   comparte el encaje de la foto y el botón de compra rápida.
---------------------------------------------------------------------------- */
.dw-card__media {
  background:
    radial-gradient(120% 80% at 50% 0%, #fff 0%, var(--dw-paper-2, #f6f4ef) 70%);
}

.dw-card__media > a { display: block; width: 100%; height: 100%; }

.dw-card__media img {
  object-fit: contain;
  padding: 10% 12%;
}

.dw-card__quick {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;
  border: 0;
  width: 100%;
  cursor: pointer;
  font-family: var(--dw-sans, sans-serif);
  font-weight: 600;
  letter-spacing: 0.14em;
  transition:
    transform 0.4s var(--curva-salida),
    background-color 0.25s var(--curva-suave),
    color 0.25s var(--curva-suave);
}

@media (hover: hover) {
  .dw-card__quick:hover {
    background: var(--dw-gold, #c8a24a);
    color: var(--dw-ink, #0c0c0d);
  }
  .dw-card__quick:focus-visible { transform: translateY(0); }
}

@media (hover: none) {
  .dw-card__quick { position: static; transform: none; }
}

.dw-card__quick.esta-cargando { pointer-events: none; opacity: 0.7; }

.dw-card__quick.esta-hecho {
  background: var(--dw-gold, #c8a24a) !important;
  color: var(--dw-ink, #0c0c0d) !important;
  transform: translateY(0) !important;
}

@media (prefers-reduced-motion: reduce) {
  .dw-card__quick { transform: translateY(0); transition: none; }
  .dw-card:hover .dw-card__media img { transform: none; }
}

/* ============================================================================
   CARRUSEL DEL HERO

   Ocho fragancias que se turnan cada cinco segundos, cada una enlazando a su
   ficha. Se funde una en otra en vez de deslizarse: un desplazamiento lateral
   en un panel de media pantalla marea, y el fundido deja el frasco quieto,
   que es lo que se quiere mirar.

   La foto va en `contain` sobre un degradado, como en las tarjetas: estos son
   PNG de frasco con fondo transparente y `cover` les cortaba el tapón.
============================================================================ */
/* El marco necesita altura PROPIA. Todas las diapositivas son `position:
   absolute`, así que no empujan nada: sin esto el contenedor mide 0.

   Antes la altura venía solo de `min-height: 58svh` (móvil) y del estiramiento
   del grid con `min-height: 82vh` (escritorio). Eso ya era frágil antes de
   tocar nada: `svh` no existe en Safari ni Chrome antiguos, y ahí la regla se
   ignora entera y el hero se queda sin alto en el móvil, que es justo donde
   más se ve.

   `aspect-ratio` da altura a partir del ancho sin depender del viewport, y el
   `min-height` en píxeles es el suelo por si alguna de las dos fallara. */
.dw-carrusel {
  position: relative;
  overflow: hidden;
  aspect-ratio: 4 / 5;
  min-height: 380px;
}

@media (min-width: 901px) {
  /* En escritorio manda el alto del hero; la proporción estorbaría. */
  .dw-carrusel { aspect-ratio: auto; min-height: 82vh; }
}

.dw-carrusel__slide {
  position: absolute;
  inset: 0;
  display: block;
  opacity: 0;
  visibility: hidden;
  text-decoration: none;
  background:
    radial-gradient(120% 90% at 50% 10%, #1a1a1c 0%, var(--dw-ink, #0c0c0d) 75%);
  transition: opacity 1s var(--curva-suave), visibility 0s linear 1s;
}

.dw-carrusel__slide.is-activa {
  opacity: 1;
  visibility: visible;
  transition: opacity 1s var(--curva-suave), visibility 0s;
  z-index: 1;
}

.dw-carrusel__slide img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain !important;
  padding: 6% 8% 14%;
  filter: saturate(0.98) contrast(1.02);
  transition: transform 1.2s var(--curva-salida);
}

@media (hover: hover) {
  .dw-carrusel__slide.is-activa:hover img { transform: scale(1.04); }
}

/* La ficha: casa, nombre y precio. Un hero de tienda que no dice el precio
   está decorando, no vendiendo. */
.dw-carrusel__ficha {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 22px 26px;
  background: linear-gradient(to top, rgba(8, 8, 9, 0.92) 0%, rgba(8, 8, 9, 0) 100%);
  text-align: left;
}

.dw-carrusel__casa {
  font-family: var(--dw-sans, sans-serif);
  font-size: var(--paso-micro);
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--dw-gold, #c8a24a);
}

.dw-carrusel__nombre {
  font-family: var(--dw-serif, Georgia, serif);
  font-size: clamp(1.15rem, 2vw, 1.5rem);
  font-weight: 500;
  color: #fff;
  line-height: 1.2;
}

.dw-carrusel__precio {
  font-family: var(--dw-sans, sans-serif);
  font-size: var(--paso-base);
  font-weight: 600;
  color: var(--dw-gold-light, #e7cf92);
  font-variant-numeric: tabular-nums;
  margin-top: 2px;
}

/* Los puntos. Objetivo táctil de 24 px aunque el punto se vea de 8. */
.dw-carrusel__puntos {
  position: absolute;
  right: 22px;
  top: 50%;
  transform: translateY(-50%);
  z-index: 3;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.dw-carrusel__punto {
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  display: grid;
  place-items: center;
}

.dw-carrusel__punto::before {
  content: '';
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.35);
  transition: background-color 0.35s var(--curva-suave), transform 0.35s var(--curva-salida);
}

.dw-carrusel__punto:hover::before { background: rgba(255, 255, 255, 0.7); }

.dw-carrusel__punto.is-activo::before {
  background: var(--dw-gold, #c8a24a);
  transform: scale(1.5);
}

@media (max-width: 900px) {
  /* En vertical los puntos estorban en el costado: pasan abajo, en fila. */
  .dw-carrusel__puntos {
    top: auto;
    bottom: 10px;
    right: 50%;
    transform: translateX(50%);
    flex-direction: row;
  }
  .dw-carrusel__ficha { padding: 18px 20px 40px; }
}

@media (prefers-reduced-motion: reduce) {
  /* Sin fundido y, sobre todo, SIN rotación automática: el JS también lo
     comprueba y no arranca el temporizador. Los puntos siguen funcionando. */
  .dw-carrusel__slide { transition: none; }
  .dw-carrusel__slide img { transition: none; }
  .dw-carrusel__slide.is-activa:hover img { transform: none; }
  .dw-carrusel__punto::before { transition: none; }
}

/* ============================================================================
   CASAS DE PERFUMERÍA (portada)

   Ocho puertas, no ocho logotipos: no hay derechos de imagen de las marcas, así
   que cada casa se ilustra con una foto de su propio producto más destacado.
============================================================================ */
.dw-casas {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: calc(var(--ritmo) * 2);
  max-width: 1100px;
  margin: 0 auto;
}

.dw-casa {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: calc(var(--ritmo) * 2.5) var(--ritmo);
  border: 1px solid var(--dw-line, rgba(20, 20, 15, 0.12));
  background: var(--dw-paper, #fff);
  text-decoration: none;
  text-align: center;
  transition:
    border-color 0.4s var(--curva-suave),
    box-shadow 0.4s var(--curva-suave),
    transform 0.4s var(--curva-salida);
}

@media (hover: hover) {
  .dw-casa:hover {
    border-color: var(--dw-gold, #c8a24a);
    box-shadow: 0 10px 28px -10px rgba(20, 20, 15, 0.2);
    transform: translateY(-3px);
  }
  .dw-casa:hover .dw-casa__foto img { transform: scale(1.07); }
}

.dw-casa__foto {
  width: 96px;
  height: 96px;
  display: grid;
  place-items: center;
  overflow: hidden;
  border-radius: 50%;
  background:
    radial-gradient(120% 100% at 50% 0%, #fff 0%, var(--dw-paper-2, #f6f4ef) 75%);
}

.dw-casa__foto img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 14%;
  transition: transform 0.8s var(--curva-salida);
}

.dw-casa__nombre {
  font-family: var(--dw-serif, Georgia, serif);
  font-size: var(--paso-medio);
  font-weight: 500;
  color: var(--dw-on-light, #14140f);
  line-height: 1.25;
}

.dw-casa__meta {
  font-size: var(--paso-micro);
  letter-spacing: 0.06em;
  color: var(--dw-muted, #706c63);
}

@media (prefers-reduced-motion: reduce) {
  .dw-casa, .dw-casa__foto img { transition: none; }
  .dw-casa:hover { transform: none; }
  .dw-casa:hover .dw-casa__foto img { transform: none; }
}

/* ============================================================================
   3. ESQUELETOS DE CARGA

   Mientras el filtro por AJAX va y viene, la cuadrícula mantiene su forma en
   vez de vaciarse. El brillo recorre la pieza de izquierda a derecha.
============================================================================ */
.productos-grid.is-loading { position: relative; }

.esqueleto {
  border: 1px solid var(--dw-line, rgba(20, 20, 15, 0.12));
  background: var(--dw-paper, #fff);
}

.esqueleto__foto { aspect-ratio: 3 / 4; }

.esqueleto__linea {
  height: 11px;
  margin: 10px 14px;
  border-radius: 2px;
}

.esqueleto__linea--corta { width: 45%; }
.esqueleto__linea--media { width: 75%; }

.esqueleto__foto,
.esqueleto__linea {
  background: linear-gradient(
    100deg,
    var(--dw-paper-2, #f6f4ef) 30%,
    var(--dw-paper-3, #ece8df) 50%,
    var(--dw-paper-2, #f6f4ef) 70%
  );
  background-size: 300% 100%;
  animation: dw-brillo 1.4s ease-in-out infinite;
}

@keyframes dw-brillo {
  from { background-position: 150% 0; }
  to   { background-position: -50% 0; }
}

/* ============================================================================
   4. MICRO-INTERACCIONES

   Dos, y nada más. El contador del carrito acusa recibo cuando entra algo, y
   los botones se hunden un pelo al pulsarlos. Lo que sobra en una tienda de
   lujo es el movimiento gratuito.
============================================================================ */
.header__cart-badge.acaba-de-cambiar { animation: dw-latido 0.45s var(--curva-salida); }

@keyframes dw-latido {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.45); }
  100% { transform: scale(1); }
}

.btn:active:not([disabled]) { transform: translateY(1px); }

/* Foco visible y con la voz de la marca. Sin esto, quien navega con teclado
   no sabe dónde está. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--dw-gold-deep, #8a6a1f);
  outline-offset: 3px;
  border-radius: 1px;
}

/* ============================================================================
   5. RITMO DE LA CUADRÍCULA

   Filas holgadas y columnas que respiran: es lo que separa una cuadrícula de
   catálogo de una de tienda de barrio.
============================================================================ */
.productos-grid {
  gap: calc(var(--ritmo) * 3) calc(var(--ritmo) * 2.5) !important;
}

@media (min-width: 1100px) {
  .productos-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
  }
}

/* ============================================================================
   6. QUIETUD A PETICIÓN

   Quien pide menos movimiento en su sistema operativo lo pide en serio: aquí
   se apaga todo, incluida la aparición escalonada y el brillo del esqueleto.
============================================================================ */
@media (prefers-reduced-motion: reduce) {
  html.js .anim-fade-in {
    opacity: 1;
    transform: none;
    transition: none;
    transition-delay: 0s;
  }

  .product-card,
  .product-card__image,
  .product-card__quick,
  .product-card__name a {
    transition: none !important;
  }

  .product-card:hover { transform: none; }
  .product-card:hover .product-card__image { transform: none; }

  /* El cajón deja de deslizarse: se queda puesto. */
  .product-card__quick { transform: translateY(0); }

  .esqueleto__foto,
  .esqueleto__linea,
  .header__cart-badge.acaba-de-cambiar {
    animation: none;
  }
}
