:root {
  --brand: #41cbce;
  --brand-600: #28aaad;
  --cta: #ff5e38;
  --ink: #15181e;
}

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 3px;
  border-radius: 2px;
}

::selection {
  background: #d2f5f6;
  color: var(--ink);
}

/* El atributo HTML `hidden` debe ganar SIEMPRE sobre las utilidades de
   display de Tailwind (grid/flex/block). Sin esto, un elemento como
   `<div hidden class="grid ...">` queda visible porque `display:grid`
   (author stylesheet) vence a `[hidden]{display:none}` (user-agent).
   Eso dejaba el scrim del formulario (fixed inset-0, opacity-0) capturando
   todos los clics y bloqueando la página entera. */
[hidden] {
  display: none !important;
}

section[id] {
  scroll-margin-top: 84px;
}

/* Glassmorphic navbar */
.glass-nav {
  background-color: rgba(255, 255, 255, 0.62);
  backdrop-filter: blur(18px) saturate(180%);
  -webkit-backdrop-filter: blur(18px) saturate(180%);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.7) inset,
    0 10px 30px -18px rgba(16, 24, 40, 0.28);
}

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .glass-nav {
    background-color: rgba(255, 255, 255, 0.96);
  }
}

/* Barra de contacto sobre la navbar: se colapsa suavemente al bajar del hero.
   app.js agrega .is-collapsed cuando el scroll supera el umbral. Animamos solo
   max-height/opacity para que la navbar suba sin reflows bruscos del resto. */
.topbar {
  overflow: hidden;
  max-height: 3rem;
  transition: max-height 0.35s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.3s ease;
}

.topbar.is-collapsed {
  max-height: 0;
  opacity: 0;
}

/* Animated underline on desktop nav links */
.nav-link::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -6px;
  height: 2px;
  width: 100%;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--brand), var(--brand-600));
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1);
}

.nav-link:hover::after {
  transform: scaleX(1);
}

/* Card hover lift (ofertas + catálogo + trabajos).
   Dual selector: the [data-reveal] variant (0,3,0) outranks
   [data-reveal].is-visible (0,2,0) so the lift wins over the reveal reset. */
.lift-card {
  transition:
    transform 0.3s cubic-bezier(0.22, 1, 0.36, 1),
    box-shadow 0.3s ease,
    border-color 0.3s ease;
}

.lift-card:hover,
[data-reveal].lift-card:hover {
  transform: translateY(-6px);
  border-color: #74dee1;
  box-shadow: 0 26px 50px -20px rgba(16, 24, 40, 0.24);
}

/* En el carrusel de productos el track recorta el eje vertical (para poder
   scrollear en horizontal), así que la tarjeta usa una sombra de hover un poco
   más contenida que cabe dentro del padding y no se corta por abajo. Las demás
   tarjetas (ofertas, trabajos) conservan la sombra grande. */
#product-grid .lift-card:hover {
  box-shadow: 0 18px 34px -16px rgba(16, 24, 40, 0.22);
}

/* Hero ambient backdrop — subtle brand atmosphere */
.hero-bg {
  background:
    radial-gradient(58% 80% at 100% 0%, rgba(65, 203, 206, 0.10) 0%, transparent 55%),
    radial-gradient(48% 60% at 0% 100%, rgba(255, 94, 56, 0.055) 0%, transparent 55%);
}

.skip-link {
  position: fixed;
  top: -100px;
  left: 1rem;
  z-index: 1000;
  transition: top 0.2s ease;
}

.skip-link:focus {
  top: 1rem;
}

[data-reveal] {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.7s cubic-bezier(0.22, 1, 0.36, 1), transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

[data-reveal].is-visible {
  opacity: 1;
  transform: none;
}

/* Hero — cielo americano en perspectiva que se "instala" de cerca hacia el
   fondo al cargar. app.js (buildCeiling) genera las placas dentro de .ceiling-plane
   con un --d (delay) creciente hacia la profundidad. */
.ceiling-scene {
  position: absolute;
  inset: 0;
  perspective: 640px;
  perspective-origin: 50% 0%;
  overflow: hidden;
  /* la parte lejana (arriba) y el borde cercano se desvanecen hacia el fondo del hero */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 20%, #000 90%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 20%, #000 90%, transparent 100%);
}

/* Velo blanco suave tras el título para legibilidad sobre la retícula del cielo.
   En escritorio se corre hacia la izquierda, que es donde vive el texto. */
.hero-scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(115% 62% at 50% 42%, rgba(255, 255, 255, 0.92) 0%, rgba(255, 255, 255, 0.6) 36%, rgba(255, 255, 255, 0) 72%);
}

@media (min-width: 1024px) {
  .hero-scrim {
    background: radial-gradient(70% 86% at 26% 46%, rgba(255, 255, 255, 0.94) 0%, rgba(255, 255, 255, 0.66) 42%, rgba(255, 255, 255, 0) 78%);
  }
}

/* Título/descripción/CTAs del hero: permanecen ocultos hasta que app.js (buildCeiling)
   termina de "instalar" el cielo, y entonces agrega .is-in — así el texto aparece
   justo cuando remata la animación, no antes. */
.hero-copy {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.6s cubic-bezier(0.22, 1, 0.36, 1), transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}

.hero-copy.is-in {
  opacity: 1;
  transform: none;
}

/* Lavado blanco *bajo* la foto. La máscara de la foto la deja semitransparente
   en toda la zona de fundido, y ahí se transparentaba la retícula del cielo:
   se veían las líneas del fondo cruzando la imagen. Este degradado apaga el
   cielo un poco antes de donde la foto empieza a aparecer, así el fundido cae
   sobre blanco limpio — que es lo que permite alargarlo sin ensuciarlo.

   Entra junto con la foto, no antes: presente desde el arranque, partía en dos
   la animación de instalación del cielo. Por eso nace en opacity:0 y se
   encadena al `.is-in` que app.js pone sobre [data-hero-media] — de ahí que en
   el HTML vaya después de la foto, y por debajo vía z-index. Sube un poco más
   rápido que la foto para que el blanco ya esté puesto mientras la imagen
   termina de llegar. */
.hero-media-wash {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.6s cubic-bezier(0.22, 1, 0.36, 1);
  background: linear-gradient(
    to bottom,
    rgba(255, 255, 255, 0) 30%,
    rgba(255, 255, 255, 0.95) 46%,
    #fff 56%
  );
}

.hero-media.is-in ~ .hero-media-wash {
  opacity: 1;
}

@media (min-width: 1024px) {
  .hero-media-wash {
    background: linear-gradient(
      to right,
      rgba(255, 255, 255, 0) 20%,
      rgba(255, 255, 255, 0.95) 36%,
      #fff 46%
    );
  }
}

/* Carrusel de fotos del hero, a sangre. No es una tarjeta: es un panel que se
   funde con el fondo mediante una máscara en degradado (la "difuminación"), de
   modo que la foto nunca corta con un borde duro contra el texto.

   En móvil ocupa la franja baja del hero y se difumina hacia arriba; desde `lg`
   pasa a la mitad derecha y se difumina hacia la izquierda, que es donde vive
   el texto. La máscara vive acá y la animación de entrada en .hero-media-frame:
   así el desenfoque de entrada no pelea con el enmascarado. */

.hero-media {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 46%;
  z-index: 1; /* sobre .hero-media-wash, que va después en el marcado */
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, rgba(0, 0, 0, 0.45) 26%, #000 52%);
  mask-image: linear-gradient(to bottom, transparent 0, rgba(0, 0, 0, 0.45) 26%, #000 52%);
}

/* Teléfonos de pantalla baja (iPhone SE y similares): la franja se achica para
   que el texto no quede encima de la parte opaca de la foto. */
@media (max-height: 720px) and (max-width: 1023px) {
  .hero-media { height: 38%; }
}

@media (min-width: 1024px) {
  .hero-media {
    top: 0;
    left: auto;
    height: auto;
    width: 58%;
    /* Fundido largo (la mitad del ancho del panel) para que el borde de la foto
       no se lea nunca como un corte. Solo es viable porque .hero-media-wash ya
       dejó blanco el fondo de esta zona; sin él, alargar el fundido es lo que
       hacía aparecer las líneas del cielo sobre la imagen. */
    -webkit-mask-image: linear-gradient(to right, transparent 0, rgba(0, 0, 0, 0.5) 20%, #000 50%);
    mask-image: linear-gradient(to right, transparent 0, rgba(0, 0, 0, 0.5) 20%, #000 50%);
  }
}

/* Entrada: llega desde la derecha mientras se le va el desenfoque, medio segundo
   después del texto (app.js → revealHero). Es el único lugar donde animamos
   `filter`: la difuminación al aparecer es justamente el efecto buscado. */
.hero-media-frame {
  position: absolute;
  inset: 0;
  opacity: 0;
  transform: translateX(40px);
  filter: blur(18px);
  transition:
    opacity 0.95s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.95s cubic-bezier(0.22, 1, 0.36, 1),
    filter 0.95s cubic-bezier(0.22, 1, 0.36, 1);
}

.hero-media.is-in .hero-media-frame {
  opacity: 1;
  transform: none;
  filter: blur(0);
}

/* Las fotos se cruzan con un fundido desenfocado, una sobre otra. */
.hero-slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transform: scale(1.05);
  filter: blur(12px);
  transition: opacity 1s ease, transform 1s ease, filter 1s ease;
}

.hero-slide.is-active {
  opacity: 1;
  transform: none;
  filter: blur(0);
}

/* Foto vertical dentro del marco apaisado: se ancla hacia arriba porque lo que
   interesa (el cielo y su iluminación) está en la parte alta de la toma, y un
   recorte centrado se la comería. */
.hero-slide--alta { object-position: center 20%; }

/* Foto que no existe todavía en assets/hero/: se saca de la rotación. */
.hero-slide.is-broken { display: none; }

/* Marcador visible solo cuando ninguna foto cargó */
.hero-media-fallback {
  position: absolute;
  inset: 0;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: #a3a3a3;
  background: repeating-linear-gradient(45deg, #f5f5f4 0 14px, #fafafa 14px 28px);
}

.hero-media-frame.is-empty .hero-media-fallback { display: flex; }

/* Gris medio, no claro: en pantallas cortas los puntos caen sobre el borde
   superior de la foto (que es un cielo claro) y con #d4d4d4 desaparecían —
   solo se veía el turquesa del activo. Este tono lee sobre blanco y sobre la
   foto por igual. */
.hero-dot {
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: #a3a3a3;
  transition: width 0.3s ease, background-color 0.3s ease;
}

.hero-dot:hover { background: #737373; }

.hero-dot.is-active {
  width: 24px;
  background: #28aaad;
}

/* Con una sola foto disponible los puntos no aportan nada */
.hero-dots-hidden { display: none !important; }

.ceiling-plane {
  position: absolute;
  left: 50%;
  bottom: -1px;
  width: 600%;
  height: 210%;
  transform: translateX(-50%) rotateX(66deg);
  transform-origin: 50% 100%;
  display: grid;
  grid-template-columns: repeat(var(--cols, 14), minmax(0, 1fr));
  grid-auto-rows: minmax(0, 1fr);
  gap: 3px;
  background: #d9d7d4; /* perfilería (líneas del cielo) */
}

.ceiling-cell {
  background: #fbfbfa;
  opacity: 0;
  transform: scale(0.9);
  animation: ceiling-tile-in 0.5s cubic-bezier(0.22, 1, 0.36, 1) forwards;
  animation-delay: var(--d, 0ms);
}

.ceiling-cell--lit {
  background: radial-gradient(120% 120% at 50% 45%, #ecfbfb 0%, #d2f5f6 60%, #a8ecee 100%);
}

@keyframes ceiling-tile-in {
  to { opacity: 1; transform: scale(1); }
}

.faux-map {
  background-color: #f5f5f4;
  background-image:
    linear-gradient(rgba(65, 203, 206, 0.12) 1px, transparent 1px),
    linear-gradient(90deg, rgba(65, 203, 206, 0.12) 1px, transparent 1px),
    linear-gradient(rgba(120, 113, 108, 0.10) 1px, transparent 1px),
    linear-gradient(90deg, rgba(120, 113, 108, 0.10) 1px, transparent 1px);
  background-size: 88px 88px, 88px 88px, 22px 22px, 22px 22px;
}

.no-scrollbar::-webkit-scrollbar { display: none; }
.no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }

/* Carrusel de productos — flechas laterales */
.carousel-arrow {
  position: absolute;
  top: 50%;
  z-index: 20;
  display: none;
  height: 44px;
  width: 44px;
  align-items: center;
  justify-content: center;
  border-radius: 9999px;
  border: 1px solid #e5e5e5;
  background: #ffffff;
  color: #15181e;
  box-shadow: 0 10px 24px -12px rgba(16, 24, 40, 0.22);
  transform: translateY(-50%);
  transition: background-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease;
}

.carousel-arrow:hover {
  background: #15181e;
  color: #ffffff;
  box-shadow: 0 16px 30px -12px rgba(16, 24, 40, 0.38);
}

.carousel-arrow--left { left: -14px; }
.carousel-arrow--right { right: -14px; }

@media (min-width: 1024px) {
  .carousel-arrow { display: inline-flex; }

  /* Difumina los 24px de cada borde (= el padding del carril) para que la sombra
     de la tarjeta siguiente (fuera de vista) se desvanezca en vez de asomar como
     una línea. El cuerpo de las tarjetas empieza justo donde termina el fundido,
     así que no se ven afectadas. */
  .carousel-mask {
    -webkit-mask-image: linear-gradient(to right, transparent, #000 1.5rem, #000 calc(100% - 1.5rem), transparent);
    mask-image: linear-gradient(to right, transparent, #000 1.5rem, #000 calc(100% - 1.5rem), transparent);
  }
}

/* Marquee de clientes (logos): bucle horizontal continuo y suave. El contenido
   va duplicado en el HTML (2 sets); translateX(-50%) recorre exactamente un set,
   así el loop no tiene costuras. Los bordes se difuminan con una máscara; se
   pausa al hover y se detiene por completo con prefers-reduced-motion. */
.marquee {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
  mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
}

.marquee-inner {
  display: flex;
  width: max-content;
  animation: marquee-scroll 42s linear infinite;
}

.marquee:hover .marquee-inner {
  animation-play-state: paused;
}

/* Casilla de ancho fijo, no padding: con padding el hueco entre logos era
   constante pero los centros no, y un logo angosto (Mega, casi cuadrado) al
   lado de uno apaisado (Santander, 5.7:1) abría un vacío evidente. Con casillas
   iguales el ritmo lo marca la grilla y no la proporción de cada archivo. */
.marquee-item {
  flex: 0 0 auto;
  width: 9.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

@media (min-width: 640px) {
  .marquee-item { width: 12.5rem; }
}

/* Logos de la trust bar: atenuados y en gris para no competir con la marca
   propia; recuperan color y contraste al pasar el mouse.

   Se limitan por alto Y por ancho a la vez (no solo por alto): las proporciones
   de los logos reales van desde 1:1 (Nestlé) hasta 5.7:1 (Santander), y fijando
   únicamente la altura los apaisados quedaban gigantes al lado de los cuadrados.
   Con las dos cotas cada logo entra en la misma caja óptica. */
.client-logo {
  width: auto;
  height: auto;
  max-height: 2rem;
  max-width: 6.5rem;
  opacity: 0.6;
  filter: grayscale(1);
  transition: opacity 0.25s ease, filter 0.25s ease;
}

@media (min-width: 640px) {
  .client-logo {
    max-height: 2.75rem;
    max-width: 8.5rem;
  }
}

.marquee-item:hover .client-logo {
  opacity: 1;
  filter: grayscale(0);
}

@keyframes marquee-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

/* Mega menú de navegación (desktop) — panel full-width que se despliega bajo la navbar */
.has-mega { position: static; }

/* `position: absolute` anclado al header sticky (posicionado ⇒ bloque
   contenedor). `top: 100%` = borde inferior del header, así el panel sigue a la
   navbar tanto con la topbar visible (~104px) como colapsada (68px). Antes era
   `fixed; top: 68px` (alto del header sin topbar) y quedaba sobre la navbar. */
.mega-panel {
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  z-index: 50;
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px);
  background: #ffffff;
  border-top: 1px solid #e5e5e5;
  border-bottom: 1px solid #e5e5e5;
  box-shadow: 0 28px 44px -28px rgba(16, 24, 40, 0.28);
  transition: opacity 0.24s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.24s cubic-bezier(0.22, 1, 0.36, 1),
    visibility 0.24s;
}

.has-mega:hover > .mega-panel,
.has-mega:focus-within > .mega-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.mega-caret { transition: transform 0.24s ease; }

.has-mega:hover .mega-caret,
.has-mega:focus-within .mega-caret { transform: rotate(180deg); }

/* Galería de trabajos (masonry) + lightbox */
.gallery-item img {
  transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}
.gallery-item:hover img {
  transform: scale(1.05);
}

/* Placeholder mientras la foto real no exista en /assets/trabajos */
.gallery-fallback { display: none; }
.gallery-item.is-missing img { display: none; }
.gallery-item.is-missing .gallery-fallback {
  display: grid;
  place-items: center;
  aspect-ratio: 4 / 3;
  color: #a3a3a3;
  background: repeating-linear-gradient(45deg, #f5f5f4 0 14px, #fafafa 14px 28px);
}

.lightbox-img {
  max-height: 82vh;
  max-width: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
}

/* ==================================================================== *
 * Página de catálogo (productos.html)
 * ==================================================================== */

/* Encabezado: gradiente de marca + retícula sutil de perfilería que se
   desvanece hacia abajo, en eco del cielo americano del hero del home. */
.catalog-hero {
  position: relative;
  background:
    radial-gradient(58% 90% at 100% 0%, rgba(65, 203, 206, 0.10) 0%, transparent 55%),
    radial-gradient(48% 70% at 0% 100%, rgba(255, 94, 56, 0.05) 0%, transparent 55%),
    linear-gradient(rgba(21, 24, 30, 0.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(21, 24, 30, 0.045) 1px, transparent 1px);
  background-size: auto, auto, 44px 44px, 44px 44px;
  -webkit-mask-image: linear-gradient(to bottom, #000 55%, rgba(0, 0, 0, 0.85) 100%);
  mask-image: linear-gradient(to bottom, #000 55%, rgba(0, 0, 0, 0.85) 100%);
}

/* Entrada escalonada de miga de pan, título y descripción al cargar */
.catalog-hero-item {
  opacity: 0;
  transform: translateY(12px);
  animation: catalog-item-in 0.55s cubic-bezier(0.22, 1, 0.36, 1) forwards;
  animation-delay: calc(var(--i, 0) * 90ms);
}

@keyframes catalog-item-in {
  to { opacity: 1; transform: none; }
}

/* Crossfade del título/descripción al cambiar de categoría. Va con
   `forwards` porque reemplaza a la animación de entrada (.catalog-hero-item,
   cuyo estado base es opacity:0): sin fill, el elemento desaparecería al
   terminar. */
.cat-swap {
  animation: catalog-item-in 0.4s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

/* Sidebar de filtros: fija bajo la navbar en desktop; drawer en móvil */
@media (min-width: 1024px) {
  .catalog-aside {
    position: sticky;
    top: 88px;
    max-height: calc(100dvh - 108px);
    overflow-y: auto;
  }
}

@media (max-width: 1023.98px) {
  .catalog-aside {
    position: fixed;
    inset: 0 auto 0 0;
    z-index: 50;
    width: min(20rem, 88vw);
    overflow-y: auto;
    transform: translateX(-100%);
    transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
    box-shadow: 0 18px 40px -22px rgba(0, 0, 0, 0.25);
  }

  .catalog-aside.is-open {
    transform: translateX(0);
  }
}

/* Árbol de categorías */
.cat-node-btn {
  display: flex;
  width: 100%;
  align-items: center;
  gap: 0.5rem;
  border-radius: 0.5rem;
  padding: 0.55rem 0.65rem;
  font-size: 0.875rem;
  font-weight: 600;
  color: #525252;
  text-align: left;
  transition: background-color 0.2s ease, color 0.2s ease;
}

.cat-node-btn:hover { background: #fafafa; color: var(--ink); }

.cat-node-btn.is-active {
  background: #ecfbfb;
  color: #1f888b;
  box-shadow: inset 2px 0 0 var(--brand);
}

.cat-sub-btn {
  display: flex;
  width: 100%;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  border-radius: 0.5rem;
  padding: 0.45rem 0.65rem 0.45rem 2.1rem;
  font-size: 0.815rem;
  color: #737373;
  text-align: left;
  transition: background-color 0.2s ease, color 0.2s ease;
}

.cat-sub-btn:hover { background: #fafafa; color: var(--ink); }

.cat-sub-btn.is-active {
  color: #1f888b;
  font-weight: 700;
  background: #ecfbfb;
  box-shadow: inset 2px 0 0 var(--brand);
}

.cat-count {
  margin-left: auto;
  font-size: 0.7rem;
  font-weight: 700;
  color: #a3a3a3;
  font-variant-numeric: tabular-nums;
}

.cat-node-caret { transition: transform 0.25s ease; color: #a3a3a3; }
.cat-node.is-expanded .cat-node-caret { transform: rotate(180deg); }

/* Despliegue animado de subcategorías (grid-rows 0fr → 1fr) */
.cat-children {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}

.cat-children > div { overflow: hidden; }
.cat-node.is-expanded .cat-children { grid-template-rows: 1fr; }

/* Checkboxes personalizados de filtros */
.filter-check {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  border-radius: 0.5rem;
  padding: 0.4rem 0.5rem;
  font-size: 0.875rem;
  color: #525252;
  cursor: pointer;
  transition: background-color 0.2s ease;
  user-select: none;
}

.filter-check:hover { background: #fafafa; }
.filter-check input { position: absolute; opacity: 0; pointer-events: none; }

.filter-check-box {
  display: grid;
  place-items: center;
  height: 1.15rem;
  width: 1.15rem;
  flex-shrink: 0;
  border-radius: 0.3rem;
  border: 1.5px solid #d4d4d4;
  background: #ffffff;
  color: transparent;
  font-size: 0.7rem;
  transition: background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}

.filter-check input:checked + .filter-check-box {
  background: var(--brand);
  border-color: var(--brand);
  color: var(--ink);
}

.filter-check input:focus-visible + .filter-check-box {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

/* Chips de filtros activos */
.filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  border-radius: 9999px;
  border: 1px solid #a8ecee;
  background: #ecfbfb;
  padding: 0.3rem 0.5rem 0.3rem 0.75rem;
  font-size: 0.78rem;
  font-weight: 600;
  color: #1f888b;
  animation: fade-in 0.25s ease-out;
}

.filter-chip button {
  display: grid;
  place-items: center;
  height: 1.05rem;
  width: 1.05rem;
  border-radius: 9999px;
  font-size: 0.6rem;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.filter-chip button:hover { background: #1f888b; color: #ffffff; }

/* Al cambiar de página, scrollIntoView deja la grilla justo bajo la navbar
   sticky (68px) con un respiro, en vez de esconder la primera fila. */
#catalog-grid {
  scroll-margin-top: 96px;
}

/* Entrada escalonada de las tarjetas al filtrar */
.card-in {
  opacity: 0;
  transform: translateY(10px) scale(0.985);
  animation: card-in 0.4s cubic-bezier(0.22, 1, 0.36, 1) forwards;
  animation-delay: calc(min(var(--i, 0), 11) * 35ms);
}

@keyframes card-in {
  to { opacity: 1; transform: none; }
}

/* ============ Buscador global de la navbar ============ */
/* Resultado activo (hover o navegación con flechas) */
.search-item { transition: background-color 0.15s ease; }
.search-item:hover,
.search-item.is-active { background: #f5f6f7; }

/* ============ Página de producto ============ */
/* Miniaturas de la galería: la activa se marca con borde turquesa */
.pd-thumb { transition: border-color 0.15s ease, box-shadow 0.15s ease; }
.pd-thumb.is-active {
  border-color: #28aaad;
  box-shadow: 0 0 0 1px #28aaad;
}

/* Skeleton de carga del detalle (solo anima opacity) */
.skeleton {
  background: #eef0f2;
  animation: skeleton-pulse 1.4s ease-in-out infinite;
}

@keyframes skeleton-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.55; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  [data-reveal] { opacity: 1; transform: none; }
  .marquee-inner { animation: none !important; transform: none !important; }
  .ceiling-cell { opacity: 1 !important; transform: none !important; animation: none !important; }
  .hero-copy { opacity: 1 !important; transform: none !important; }
  .hero-media-frame { opacity: 1 !important; transform: none !important; filter: none !important; }
  .hero-slide { transition: none !important; transform: none !important; filter: none !important; }
  .catalog-hero-item, .card-in { opacity: 1 !important; transform: none !important; animation: none !important; }
}
