/* ============================================================================
   Catálogo público DAP (catalogo.daprosa.com) — mismo fondo negro y verde
   neón que el panel admin, pero la tipografía de títulos ya NO es Bebas
   Neue (se cambió acá por Space Grotesk, ver nota en la regla h1-h4 más
   abajo — el panel admin sigue con Bebas Neue, no se tocó, fuera del
   alcance de este cambio). Pensado para mostrarse en reuniones
   comerciales, con foco especial en tablet/iPad.

   Regla de negocio: esta página NUNCA muestra precio — la API ni siquiera
   lo envía (ver api/rutas/catalogo.js), así que aquí no hay nada que
   "esconder", simplemente no existe el dato.
   ========================================================================= */

:root {
  --accent: #00E676;
  --accent-hover: #00c85e;
  --danger: #ff5252;
  --bg: #030303;
  --bg-1: #0a0a0a;
  --bg-2: #111;
  --bg-card: rgba(20, 20, 20, 0.7);
  --border: #1a1a1a;
  /* #333 medía 1.63:1 contra el fondo de tarjetas/inputs — insuficiente para
     delinear un componente interactivo (mínimo 3:1, WCAG 1.4.11). #606060
     da exactamente 3:1 contra --bg-2. */
  --border-2: #606060;
  --border-card: rgba(0, 230, 118, 0.2);
  --text: #fff;
  --text-dim: #888;
  /* #555 medía 2.77:1 sobre el fondo (--bg) — por debajo del mínimo 4.5:1 de
     WCAG AA. #787878 da 4.67:1, ya conforme. */
  --text-dim-2: #787878;
  --radius-lg: 16px;
  --radius-md: 8px;
  --radius-pill: 30px;
  /* Fondo real de las fotos del catálogo (extraído de las fotos oficiales de
     Proel) — se usa igual en todas las casillas de imagen, sin difuminado. */
  --img-bg: #f2f2f2;
  /* Curva "expo-out" — desaceleración marcada al llegar, la que más se
     asocia a una interfaz "fluida/premium" (vs. el `ease` genérico del
     navegador, que no tiene ese remate). Se usa en las transiciones más
     notorias al interactuar (hover/press de tarjetas y botones, apertura de
     paneles) — NO en las animaciones ambientales (fondo eléctrico, LED),
     esas ya están calibradas aparte y la skill ui-ux-pro-max pide no
     multiplicarlas. */
  --ease-fluid: cubic-bezier(0.16, 1, 0.3, 1);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body { overflow-x: hidden; }
/* Scroll suave para saltos programáticos/anchors (hallazgo directo de la
   skill, severidad alta: "scroll-behavior: smooth"). La restauración exacta
   de posición al cerrar el detalle (desbloquearScrollFondo en app.js) pide
   {behavior:'auto'} explícito para no heredar esto — ahí un salto animado
   se sentiría raro, no como "así estaba". */
html { scroll-behavior: smooth; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: 'IBM Plex Sans', sans-serif;
  min-height: 100vh;
}

h1, h2, h3, h4, .display {
  /* Space Grotesk en vez de Bebas Neue — la skill ui-ux-pro-max lo devolvió
     como la combinación "Tech Startup" (carácter propio, no una plantilla
     genérica) al buscar tipografía moderna/tech/distintiva. Es una
     tipografía normal (con minúsculas), no una caps-only como Bebas Neue,
     así que el tracking amplio y el peso "normal" que tenía sentido para
     esa se ajustan acá: menos letter-spacing, más peso para no perder
     presencia visual en los títulos. */
  font-family: 'Space Grotesk', sans-serif;
  letter-spacing: 0.2px;
  font-weight: 600;
}

.mono { font-family: monospace; }
::selection { background: var(--accent); color: #000; }

/* Oculto visualmente pero disponible para lectores de pantalla — para el
   <h1> de la página (el diseño no tiene un título visible de sección, pero
   sí necesita uno semántico) y otros textos de contexto solo-SR. */
.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;
}

/* Foco visible en todo lo interactivo — antes varios elementos tenían
   outline:none sin ningún reemplazo, invisibles para navegación por teclado
   (WCAG 2.4.7). Un solo anillo consistente en toda la página. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Respeta la preferencia del sistema de "menos movimiento" — ninguna
   animación/transición de la página se desactivaba antes para quien la
   pidió (WCAG 2.3.3 / buena práctica general). */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- FONDO ELÉCTRICO (ambiental, detrás de todo) ---------- */
/* z-index negativo a propósito: así queda por detrás de TODO el contenido
   estático (header/main/footer no llevan z-index propio) sin depender de
   sutilezas de stacking context — un fixed con z-index:0 pintaría por
   ENCIMA del contenido normal, no por detrás. */
.fondo-electrico {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  overflow: hidden;
}
/* El SVG se sobredimensiona (130%) y queda posicionado con margen de sobra
   (-15% en cada eje) para poder desplazarse lento en diagonal (derivaFondo)
   sin dejar nunca un borde vacío a la vista — es el movimiento de conjunto
   "lento" que pediste, además del flujo de corriente de cada trazo. */
.fondo-electrico svg {
  width: 130%;
  height: 130%;
  display: block;
  position: absolute;
  top: -15%;
  left: -15%;
  animation: derivaFondo 75s ease-in-out infinite alternate;
}
.fondo-electrico path {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.2;
}
/* Cada trazo con su propio patrón de guiones, velocidad, sentido y fase de
   "respiración" — a propósito ASINCRÓNICOS entre sí (duraciones que no son
   múltiplos unas de otras, delays negativos distintos), para que nunca se
   sientan como una sola animación repetida sino corriente eléctrica real
   viajando a su propio ritmo por cada trazo. */
.fondo-electrico path:nth-child(1) { stroke-dasharray: 6 14; animation: fluirElectrico 15s linear infinite, respirarTrazo 8s ease-in-out infinite; }
.fondo-electrico path:nth-child(2) { stroke-dasharray: 10 10; animation: fluirElectrico 21s linear infinite reverse, respirarTrazo 10.5s ease-in-out infinite -1.2s; }
.fondo-electrico path:nth-child(3) { stroke-dasharray: 4 16; animation: fluirElectrico 12s linear infinite, respirarTrazo 9.2s ease-in-out infinite -2.8s; }
.fondo-electrico path:nth-child(4) { stroke-dasharray: 8 12; animation: fluirElectrico 18s linear infinite reverse, respirarTrazo 7.2s ease-in-out infinite -0.6s; }
.fondo-electrico path:nth-child(5) { stroke-dasharray: 5 15; animation: fluirElectrico 24s linear infinite, respirarTrazo 12s ease-in-out infinite -3.5s; }
@keyframes fluirElectrico { to { stroke-dashoffset: -400; } }
@keyframes respirarTrazo { 0%, 100% { opacity: 0.1; } 50% { opacity: 0.34; } }
@keyframes derivaFondo {
  0% { transform: translate(0, 0); }
  100% { transform: translate(-5%, -4%); }
}

/* ---------- HEADER ---------- */
.header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(3, 3, 3, 0.92);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
  padding: 14px 20px;
}
.header-fila {
  display: flex;
  align-items: center;
  gap: 20px;
  max-width: 1400px;
  margin: 0 auto;
  flex-wrap: wrap;
}
.header-logo { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }
.header-logo img { height: 34px; }
.header-logo span { font-size: 1.3rem; letter-spacing: 2px; }

/* Barras de ecualizador — reutilizadas en dos lugares puntuales y REACTIVOS
   (no como tira fija permanente, eso ya se probó y no gustó): el divisor de
   la sección "Descripción" en el detalle, y el mini-ecualizador que aparece
   junto al LED de "Disponible" al pasar el mouse por una tarjeta (ver
   .producto-card:hover .mini-eq en la sección del grid). */
.trazo-eq {
  display: flex;
  align-items: flex-end;
  gap: 3px;
  height: 100%;
  opacity: 0.65;
}
.trazo-eq span {
  flex: 1;
  background: var(--accent);
  border-radius: 1px;
  transform-origin: bottom;
  animation: pulsoEq 1.6s ease-in-out infinite;
}
@keyframes pulsoEq {
  0%, 100% { transform: scaleY(0.55); }
  50% { transform: scaleY(1); }
}

.btn-idioma {
  flex-shrink: 0;
  min-width: 44px;
  height: 44px;
  padding: 0 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-2);
  border: 1px solid var(--border-2);
  border-radius: var(--radius-pill);
  color: #ccc;
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 600;
  font-size: 0.9rem;
  letter-spacing: 1px;
  cursor: pointer;
  transition: border-color 0.2s var(--ease-fluid), color 0.2s var(--ease-fluid), transform 0.15s var(--ease-fluid);
}
.btn-idioma:hover { border-color: var(--accent); color: var(--accent); }

.btn-descargar-pdf {
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-2);
  border: 1px solid var(--border-2);
  border-radius: 50%;
  color: #ccc;
  font-size: 1.1rem;
  text-decoration: none;
  transition: border-color 0.2s var(--ease-fluid), color 0.2s var(--ease-fluid), transform 0.15s var(--ease-fluid);
}
.btn-descargar-pdf:hover { border-color: var(--accent); color: var(--accent); }

/* Botones de header con el mismo look que .btn-descargar-pdf (círculo,
   44x44, mismo fondo/borde) — presentación y lista de interés. */
.btn-presentacion, .btn-lista-interes {
  flex-shrink: 0;
  position: relative;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-2);
  border: 1px solid var(--border-2);
  border-radius: 50%;
  color: #ccc;
  font-size: 1.05rem;
  cursor: pointer;
  transition: border-color 0.2s var(--ease-fluid), color 0.2s var(--ease-fluid), transform 0.15s var(--ease-fluid);
}
.btn-presentacion:hover, .btn-lista-interes:hover { border-color: var(--accent); color: var(--accent); }
.btn-presentacion:active, .btn-lista-interes:active, .btn-descargar-pdf:active { transform: scale(0.96); transition-duration: 0.1s; }

/* El corazón del header se pone verde sólido cuando hay algo en la lista —
   mismo criterio de "el acento marca estado real", no decorativo. Clase
   puesta desde JS (actualizarBadgeListaInteres) — a propósito no se usa
   :has() para esto, por compatibilidad con navegadores más viejos. */
.btn-lista-interes.tiene-items {
  border-color: var(--accent);
  color: var(--accent);
}
.badge-numero {
  position: absolute;
  top: -4px;
  right: -4px;
  background: var(--accent);
  color: #000;
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 700;
  font-size: 0.65rem;
  border-radius: 50%;
  min-width: 17px;
  height: 17px;
  padding: 0 3px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 2px solid var(--bg);
}
.badge-numero[hidden] { display: none; }

.buscador {
  flex: 1;
  min-width: 200px;
  position: relative;
}

/* Los 4 botones de acción (presentación, lista, idioma, PDF) van agrupados
   en un solo item flex — así, si no entran en la fila, saltan TODOS JUNTOS
   a una segunda línea en vez de ir comprimiendo el buscador uno por uno
   hasta dejarlo inusable (~34px de ancho, medido real en 375px con los 4
   botones sueltos antes de este cambio). */
.header-acciones { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }

/* En mobile angosto, el buscador mantiene un mínimo usable — si no entra
   junto a .header-acciones en la misma fila, es .header-acciones el que
   salta de línea completo (flex-wrap del padre .header-fila), nunca el
   buscador el que se aplasta. */
@media (max-width: 480px) {
  .header-fila { gap: 10px; }
  .buscador { min-width: 140px; }
  .header-logo img { height: 28px; }
}
.buscador input {
  width: 100%;
  background: var(--bg-2);
  border: 1px solid var(--border-2);
  color: #fff;
  padding: 12px 16px 12px 42px;
  border-radius: var(--radius-pill);
  font-size: 1rem;
  transition: border 0.25s;
}
.buscador input:focus { border-color: var(--accent); }
.buscador i {
  position: absolute;
  left: 16px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-dim);
  pointer-events: none;
}

/* ---------- FILTROS (chips de grupo + marca) ---------- */
.filtros-wrap {
  max-width: 1400px;
  margin: 14px auto 0;
  padding: 0 20px;
}

/* Botón "Filtros" que abre/cierra el panel — evita que el usuario tenga que
   arrastrar/scrollear una fila horizontal para ver todas las categorías. */
.btn-filtros {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  background: var(--bg-2);
  border: 1px solid var(--border-2);
  color: #fff;
  padding: 10px 18px;
  border-radius: var(--radius-pill);
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 600;
  font-size: 0.95rem;
  letter-spacing: 1px;
  cursor: pointer;
  min-height: 44px;
  transition: border-color 0.2s var(--ease-fluid), color 0.2s var(--ease-fluid), transform 0.15s var(--ease-fluid);
}
.btn-filtros:hover { border-color: var(--accent); }
.btn-filtros.activo { border-color: var(--accent); color: var(--accent); }
.btn-filtros .badge-filtro[hidden] { display: none; }
.btn-filtros .badge-filtro {
  background: var(--accent);
  color: #000;
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 700;
  font-size: 0.7rem;
  border-radius: 50%;
  width: 18px;
  height: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.btn-filtros i.fa-chevron-down { transition: transform 0.2s; font-size: 0.8rem; }
.btn-filtros.activo i.fa-chevron-down { transform: rotate(180deg); }

.filtros-panel {
  overflow: hidden;
  max-height: 0;
  opacity: 0;
  transition: max-height 0.3s var(--ease-fluid), opacity 0.22s var(--ease-fluid), margin-top 0.3s var(--ease-fluid);
}
.filtros-panel.abierto {
  max-height: 500px;
  opacity: 1;
  margin-top: 12px;
}

.chips-fila {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  padding-bottom: 6px;
}

.chip {
  flex-shrink: 0;
  background: var(--bg-2);
  border: 1px solid var(--border-2);
  color: #ccc;
  padding: 10px 18px;
  border-radius: var(--radius-pill);
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 600;
  font-size: 0.95rem;
  letter-spacing: 0.5px;
  cursor: pointer;
  transition: background-color 0.2s var(--ease-fluid), border-color 0.2s var(--ease-fluid), color 0.2s var(--ease-fluid), transform 0.15s var(--ease-fluid);
  white-space: nowrap;
}
.chip:hover { border-color: var(--accent); color: #fff; }
.chip:active { transform: scale(0.96); transition-duration: 0.1s; }

/* Feedback táctil compartido — mismo criterio en todos los botones/pills de
   la página (idioma, PDF, filtros, cargar más, acciones del detalle). */
.btn-idioma:active, .btn-descargar-pdf:active, .btn-filtros:active,
.btn-cargar-mas:active, .btn-accion:active {
  transform: scale(0.96);
  transition-duration: 0.1s;
}
.chip.activo { background: var(--accent); border-color: var(--accent); color: #000; font-weight: bold; }
/* Los números de los chips son del catálogo COMPLETO — con una búsqueda
   activa dejan de ser ciertos ("Todos (160)" con 12 resultados visibles),
   así que se ocultan en vez de mostrar un dato desactualizado. */
#chips-grupos.buscando .chip-conteo { display: none; }

.contador-resultados {
  font-size: 0.8rem;
  color: var(--text-dim);
  margin-top: 10px;
  padding-left: 2px;
}

.filtro-marca {
  margin-top: 10px;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.filtro-marca select {
  background: var(--bg-2);
  border: 1px solid var(--border-2);
  color: #fff;
  padding: 9px 16px;
  border-radius: var(--radius-pill);
  font-size: 0.9rem;
}
.filtro-marca select:focus { border-color: var(--accent); }

/* ---------- GRID DE PRODUCTOS ---------- */
.contenedor { max-width: 1400px; margin: 0 auto; padding: 24px 20px 80px; }

.producto-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
  transition: opacity 0.2s ease;
}
.producto-grid.cargando { opacity: 0.35; }

@media (min-width: 640px) {
  .producto-grid { grid-template-columns: repeat(3, 1fr); gap: 18px; }
}
/* iPad / tablet — prioridad de prueba explícita */
@media (min-width: 768px) and (max-width: 1024px) {
  .producto-grid { grid-template-columns: repeat(3, 1fr); gap: 20px; }
  .header-fila { gap: 24px; }
}
@media (min-width: 1025px) {
  .producto-grid { grid-template-columns: repeat(4, 1fr); gap: 22px; }
}
@media (min-width: 1300px) {
  .producto-grid { grid-template-columns: repeat(5, 1fr); }
}

.producto-card {
  position: relative;
  border-radius: var(--radius-lg);
  overflow: hidden;
  cursor: pointer;
  background: var(--bg-2);
  border: 1px solid var(--border);
  aspect-ratio: 3 / 4;
  display: flex;
  flex-direction: column;
  animation: apareceCard 0.4s var(--ease-fluid) both;
  transition: border-color 0.22s var(--ease-fluid), border-width 0.22s var(--ease-fluid), transform 0.22s var(--ease-fluid), box-shadow 0.28s var(--ease-fluid);
  -webkit-tap-highlight-color: transparent;
}
/* Al reposo, sin sombra — se ve pegada al fondo. Al interactuar, se separa
   con una sombra tintada de verde (no negra plana) Y se "ilumina": el borde
   pasa a verde sólido y más grueso (1px→2px, box-sizing:border-box de todo
   el proyecto evita que esto mueva el layout) + un halo difuso alrededor —
   junto con el fondo eléctrico que se mueve solo, refuerza la sensación de
   que la tarjeta se despega y flota por encima. */
.producto-card:hover, .producto-card:focus-visible {
  border-color: var(--accent);
  border-width: 2px;
  transform: translateY(-6px);
  box-shadow:
    0 16px 32px rgba(0, 0, 0, 0.45),
    0 0 0 1px rgba(0, 230, 118, 0.25),
    0 0 26px 3px rgba(0, 230, 118, 0.3),
    0 6px 20px rgba(0, 230, 118, 0.18);
}
/* Feedback táctil al presionar — antes ninguna tarjeta/botón/chip tenía
   ninguna respuesta física al toque más allá del cambio de color (guía
   "scale-feedback" de ui-ux-pro-max: escala sutil en press, no solo hover).
   Un click corto que se siente inmediato, no una animación ambiental. */
.producto-card:active {
  border-color: var(--accent);
  border-width: 2px;
  transform: translateY(-6px) scale(0.97);
  box-shadow:
    0 16px 32px rgba(0, 0, 0, 0.45),
    0 0 0 1px rgba(0, 230, 118, 0.25),
    0 0 26px 3px rgba(0, 230, 118, 0.3),
    0 6px 20px rgba(0, 230, 118, 0.18);
  transition-duration: 0.12s;
}

.producto-card__img-wrap {
  position: relative;
  z-index: 1;
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  min-height: 0;
  /* Mismo fondo real de las fotos del producto en todas las casillas, en vez
     del difuminado de la foto agrandada — uniforme para todos los productos. */
  background: var(--img-bg);
}
.producto-card__img-wrap picture,
.detalle-galeria__principal picture {
  display: contents; /* que <picture> no meta una caja propia, solo envuelve <img>/<source> */
}
.producto-card__img-wrap img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}
/* Antes la foto (fondo claro) chocaba de golpe contra la banda de info
   (fondo oscuro) — un degradado corto en el borde inferior de la foto hace
   que la tarjeta se lea como una sola pieza, no dos rectángulos apilados. */
.producto-card__img-wrap::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 26px;
  background: linear-gradient(to bottom, transparent, rgba(9, 9, 9, 0.28));
  pointer-events: none;
}

/* ---------- SKELETON DE CARGA ---------- */
/* Placeholder liviano (sin librerías) mientras cada foto termina de cargar
   — se saca solo, vía el evento "load" del <img> (ver armarTagImagen en
   app.js). Aplica igual al grid y al detalle. */
.cargando-img {
  background: linear-gradient(100deg, var(--img-bg) 30%, #e2e2e2 45%, var(--img-bg) 60%);
  background-size: 250% 100%;
  animation: shimmerCarga 1.3s ease-in-out infinite;
}
@keyframes shimmerCarga {
  0% { background-position: 100% 0; }
  100% { background-position: -50% 0; }
}
.producto-card__sin-imagen {
  color: var(--text-dim-2);
  font-size: 2.5rem;
}

/* Corazón de "lista de interés" — esquina superior derecha de la foto, con
   su propio fondo/foco para que se distinga como control aparte del resto
   de la tarjeta (que ya es clickeable entera para abrir el detalle). */
.btn-corazon {
  position: absolute;
  z-index: 2;
  top: 10px;
  right: 10px;
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(3, 3, 3, 0.55);
  backdrop-filter: blur(4px);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 50%;
  color: #fff;
  font-size: 0.95rem;
  cursor: pointer;
  transition: color 0.2s var(--ease-fluid), border-color 0.2s var(--ease-fluid), transform 0.15s var(--ease-fluid);
}
.btn-corazon:hover { border-color: var(--accent); }
.btn-corazon:active { transform: scale(0.9); transition-duration: 0.1s; }
.btn-corazon.activo { color: var(--accent); border-color: var(--accent); }

.producto-card__info {
  position: relative;
  z-index: 1;
  background: rgba(3, 3, 3, 0.75);
  backdrop-filter: blur(6px);
  padding: 10px 14px 12px;
  border-top: 1px solid rgba(255,255,255,0.06);
}
/* Escala tipográfica con saltos reales entre niveles (antes marca/estado
   vivían los dos en una banda de ~10-11px, casi indistinguibles, y el
   nombre del producto —el dato más importante de la tarjeta— era MÁS CHICO
   que el buscador). El verde de marca ya no se usa acá: con 7 usos
   distintos del mismo acento (marca, estado, chip activo, foco, títulos,
   badge, ícono PDF) dejaba de leerse como énfasis. Se reserva el verde para
   lo que de verdad es información de negocio: disponibilidad y estados
   interactivos. */
.producto-card__marca { font-size: 0.7rem; color: var(--text-dim); text-transform: uppercase; letter-spacing: 1.2px; margin-bottom: 3px; }
.producto-card__nombre { font-size: 1rem; font-weight: 600; line-height: 1.32; color: #fff; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.producto-card__estado { display: inline-flex; align-items: center; gap: 6px; font-size: 0.72rem; margin-top: 8px; color: var(--text-dim); }

/* LED de disponibilidad — el punto no es solo un color, tiene un halo sutil
   como un indicador real de equipo encendido (motivo de "señal de audio").
   Antes pulsaba en loop infinito en CADA tarjeta disponible a la vez — con
   160 productos eso podía ser decenas de animaciones ambientales
   simultáneas, justo el anti-patrón que marca ui-ux-pro-max ("Animate 1-2
   key elements per view maximum" / severidad alta). Ahora el LED "enciende"
   con un solo pulso al aparecer y se queda en un halo estático — sigue
   leyéndose como equipo encendido, sin la animación constante de fondo (el
   fondo eléctrico ya cubre esa función, uno solo por vista). */
.producto-card__estado .led { width: 7px; height: 7px; border-radius: 50%; background: var(--text-dim-2); flex-shrink: 0; }
.producto-card__estado.disponible { color: #cfcfcf; }
.producto-card__estado.disponible .led {
  background: var(--accent);
  box-shadow: 0 0 0 2px rgba(0, 230, 118, 0.25);
  animation: pulsoLed 1.4s ease-out 1;
}
@keyframes pulsoLed {
  0% { box-shadow: 0 0 0 0 rgba(0, 230, 118, 0.5); }
  70% { box-shadow: 0 0 0 6px rgba(0, 230, 118, 0); }
  100% { box-shadow: 0 0 0 2px rgba(0, 230, 118, 0.25); }
}

/* Mini-ecualizador junto al LED — invisible en reposo, se revela (ancho +
   opacidad) al pasar el mouse o enfocar la tarjeta. Reactivo a la
   interacción, no una animación ambiental fija. */
.mini-eq {
  display: inline-flex;
  align-items: flex-end;
  height: 9px;
  width: 0;
  overflow: hidden;
  opacity: 0;
  margin-left: 0;
  transition: width 0.22s ease, opacity 0.22s ease, margin-left 0.22s ease;
}
.mini-eq .trazo-eq { height: 100%; gap: 2px; opacity: 1; }
.mini-eq .trazo-eq span { flex: none; width: 2px; }
.producto-card:hover .mini-eq,
.producto-card:focus-visible .mini-eq {
  width: 24px;
  opacity: 1;
  margin-left: 2px;
}

.btn-cargar-mas {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  max-width: 320px;
  margin: 32px auto 0;
  padding: 13px 24px;
  background: var(--bg-2);
  border: 1px solid var(--border-2);
  color: #fff;
  border-radius: var(--radius-pill);
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 600;
  font-size: 1rem;
  letter-spacing: 1px;
  cursor: pointer;
  min-height: 44px;
  transition: border-color 0.2s var(--ease-fluid), color 0.2s var(--ease-fluid), transform 0.15s var(--ease-fluid);
}
.btn-cargar-mas:hover { border-color: var(--accent); color: var(--accent); }
/* Bug real (17 ago 2026, reportado por el usuario): `.btn-cargar-mas` fija
   `display:flex`, que le gana en la cascada a la regla por defecto del
   navegador `[hidden] { display:none }` (misma especificidad, pero el CSS
   del sitio pisa al del user-agent) — el botón quedaba SIEMPRE visible en
   pantalla aunque `actualizarBotonCargarMas()` en app.js ya calculaba
   `hidden=true` correctamente. Pasaba en cualquier filtro cuyo total no
   fuera múltiplo exacto de RESULTADOS_POR_PAGINA... en realidad pasaba
   SIEMPRE, nunca se ocultaba — confirmado con getComputedStyle() antes del
   fix: hidden=true pero display seguía en "flex". Esta regla, con más
   especificidad que la de arriba (agrega el atributo), hace que gane. */
.btn-cargar-mas[hidden] { display: none; }
.btn-cargar-mas:disabled { opacity: 0.6; cursor: default; }

.sin-resultados {
  grid-column: 1 / -1;
  text-align: center;
  padding: 80px 20px;
  color: var(--text-dim);
}
.sin-resultados i { font-size: 2.5rem; margin-bottom: 14px; display: block; color: var(--text-dim-2); }
.sin-resultados__titulo { font-size: 1rem; color: var(--text); margin-bottom: 6px; }
.sin-resultados__sugerencia { font-size: 0.85rem; color: var(--text-dim); max-width: 340px; margin: 0 auto 22px; line-height: 1.5; }

@keyframes apareceCard { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }

/* Tarjetas fuera del viewport inicial: en vez del fade-in de montaje (arriba),
   quedan invisibles hasta que el IntersectionObserver de app.js les agrega
   "visible" al entrar en pantalla — ver aplicarAnimacionScroll(). */
.producto-card.espera-scroll {
  animation: none;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.45s ease, transform 0.45s ease;
  will-change: opacity, transform;
}
.producto-card.espera-scroll.visible {
  opacity: 1;
  transform: translateY(0);
  will-change: auto;
}

/* ---------- OVERLAY DE DETALLE (pantalla completa) ---------- */
.detalle-overlay {
  position: fixed;
  inset: 0;
  background: var(--bg);
  z-index: 9000;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch; /* scroll inercial suave en iOS viejo */
  overscroll-behavior: contain; /* el scroll no se "escapa" hacia el body de atrás */
  opacity: 0;
  visibility: hidden;
  transform: translateY(16px);
  transition: opacity 0.32s var(--ease-fluid), transform 0.32s var(--ease-fluid), visibility 0s linear 0.32s;
}
.detalle-overlay.open {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition: opacity 0.32s var(--ease-fluid), transform 0.32s var(--ease-fluid);
}

.detalle-topbar {
  position: sticky;
  top: 0;
  z-index: 2;
  background: rgba(3,3,3,0.92);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
  padding: 14px 20px;
  display: flex;
  align-items: center;
}
.btn-volver {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--bg-2);
  border: 1px solid var(--border-2);
  color: #fff;
  padding: 10px 20px;
  border-radius: var(--radius-pill);
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 600;
  font-size: 1rem;
  letter-spacing: 1px;
  cursor: pointer;
  min-height: 44px;
}
.btn-volver:hover { border-color: var(--accent); color: var(--accent); }

.detalle-cuerpo {
  width: 100%;
  max-width: 1100px;
  margin: 0 auto;
  padding: 30px 20px 80px;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 30px;
}
@media (min-width: 768px) {
  .detalle-cuerpo { grid-template-columns: minmax(0, 420px) minmax(0, 1fr); gap: 40px; padding: 40px 30px 100px; align-items: start; }
}

/* Las columnas del grid (minmax(0, ...)) ya limitan el ancho real de cada
   celda — dejamos que la galería y la info ocupen el 100% de su celda
   (comportamiento "stretch" por defecto de grid) en vez de forzarles un
   max-width propio, que en mobile (una sola columna angosta) las hacía
   más anchas que la pantalla y cortaba el contenido contra el borde. */
.detalle-galeria__principal { max-width: 420px; margin: 0 auto; }
.detalle-galeria__miniaturas { max-width: 420px; margin-left: auto; margin-right: auto; }

.detalle-galeria__principal {
  background: var(--img-bg);
  border-radius: var(--radius-lg);
  aspect-ratio: 1;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  position: relative;
}
.detalle-galeria__principal img {
  max-width: 82%;
  max-height: 82%;
  object-fit: contain;
  transition: opacity 0.18s var(--ease-fluid);
}
/* Crossfade al cambiar de foto (flechas/miniaturas) — antes el <img src>
   cambiaba de golpe, sin transición. Se agrega/saca en irAImagenGaleria()
   (app.js), sacada recién cuando la foto nueva termina de cargar (evento
   "load"), no con un timeout a ciegas. */
#img-principal.cambiando-foto { opacity: 0.35; }

/* Flechas prev/siguiente sobre la foto principal */
.detalle-galeria__flecha {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid var(--border-2);
  background: rgba(3, 3, 3, 0.55);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  font-size: 1rem;
  transition: background 0.2s, border-color 0.2s;
}
.detalle-galeria__flecha:hover { background: rgba(3, 3, 3, 0.8); border-color: var(--accent); color: var(--accent); }
.detalle-galeria__flecha--izq { left: 12px; }
.detalle-galeria__flecha--der { right: 12px; }
.detalle-galeria__contador {
  position: absolute;
  bottom: 10px;
  right: 12px;
  background: rgba(3, 3, 3, 0.6);
  color: #fff;
  font-size: 0.72rem;
  padding: 3px 10px;
  border-radius: var(--radius-pill);
  letter-spacing: 0.5px;
}

.detalle-galeria__miniaturas {
  display: flex;
  gap: 10px;
  margin-top: 12px;
  overflow-x: auto;
  padding-bottom: 4px;
}
.detalle-galeria__miniaturas button {
  width: 64px;
  height: 64px;
  background: var(--img-bg);
  border-radius: var(--radius-md);
  border: 2px solid transparent;
  cursor: pointer;
  padding: 4px;
  flex-shrink: 0;
}
.detalle-galeria__miniaturas button.activa { border-color: var(--accent); }
.detalle-galeria__miniaturas img { width: 100%; height: 100%; object-fit: contain; pointer-events: none; }

.detalle-info__marca { color: var(--text-dim); text-transform: uppercase; letter-spacing: 1.5px; font-size: 0.85rem; margin-bottom: 6px; }
.detalle-info__nombre { font-size: 2.2rem; margin-bottom: 4px; }
.detalle-info__sku { color: var(--text-dim); font-size: 0.85rem; margin-bottom: 16px; }
.detalle-info__badge { display: inline-block; padding: 5px 14px; border-radius: var(--radius-pill); font-size: 0.75rem; font-weight: 700; text-transform: uppercase; margin-bottom: 20px; }
.detalle-info__badge.disponible { background: rgba(0,230,118,0.15); color: var(--accent); }
.detalle-info__badge.agotado { background: rgba(255,82,82,0.15); color: var(--danger); }

.detalle-info__seccion { margin-bottom: 24px; }
.detalle-info__seccion h3 { font-size: 1.3rem; color: #fff; margin-bottom: 8px; }
.detalle-info__seccion .trazo-divisor { width: 100%; max-width: 220px; height: 10px; margin-bottom: 14px; }
.detalle-info__seccion p { color: #ddd; line-height: 1.6; font-size: 0.95rem; }
.detalle-info__seccion p.proximamente { color: var(--text-dim-2); font-style: italic; }

/* ---------- ACCIONES DEL DETALLE (consultar / compartir) ---------- */
.detalle-acciones { display: flex; flex-wrap: wrap; gap: 12px; margin: 4px 0 26px; }
.btn-accion {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 12px 22px;
  border-radius: var(--radius-pill);
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 600;
  font-size: 1rem;
  letter-spacing: 1px;
  cursor: pointer;
  min-height: 44px;
  text-decoration: none;
  border: 1px solid transparent;
  transition: filter 0.2s var(--ease-fluid), background 0.2s var(--ease-fluid), border-color 0.2s var(--ease-fluid), transform 0.15s var(--ease-fluid);
}
.btn-accion--whatsapp { background: var(--accent); color: #000; font-weight: bold; }
.btn-accion--whatsapp:hover { filter: brightness(1.08); }
.btn-accion--compartir { background: var(--bg-2); border-color: var(--border-2); color: #fff; }
.btn-accion--compartir:hover { border-color: var(--accent); color: var(--accent); }
/* Solo el ícono (sin texto) — misma altura/padding que los otros dos botones
   de la fila para no romper la alineación. */
.btn-accion--corazon { background: var(--bg-2); border-color: var(--border-2); color: #fff; padding: 12px 16px; }
.btn-accion--corazon:hover { border-color: var(--accent); color: var(--accent); }
.btn-accion--corazon.activo { color: var(--accent); border-color: var(--accent); }

/* ---------- ESTADO DE CARGA / VACÍO ---------- */
.overlay-cargando { display: flex; align-items: center; justify-content: center; min-height: 60vh; color: var(--text-dim); font-family: 'Space Grotesk', sans-serif; font-weight: 600; font-size: 1.2rem; letter-spacing: 0.3px; }

/* ---------- TOUCH TARGETS (tablet/mobile) ---------- */
.chip, .btn-volver, .filtro-marca select, .buscador input { min-height: 44px; }

/* ---------- FOOTER ---------- */
.footer {
  border-top: 1px solid var(--border);
  padding: 28px 20px;
  margin-top: 20px;
}
.footer-fila {
  max-width: 1400px;
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.footer-marca { display: flex; align-items: center; gap: 10px; color: var(--text-dim); font-size: 0.85rem; }
.footer-marca img { height: 22px; opacity: 0.8; }
.footer-contacto { display: flex; flex-wrap: wrap; gap: 20px; }
.footer-contacto a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--text-dim);
  text-decoration: none;
  font-size: 0.85rem;
  min-height: 44px;
  transition: color 0.2s;
}
.footer-contacto a:hover { color: var(--accent); }
.footer-contacto i { color: var(--accent); }

@keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }

/* ---------- LISTA DE INTERÉS (overlay, reusa .detalle-overlay/.detalle-topbar/.btn-volver) ---------- */
#lista-interes-contenido { max-width: 640px; margin: 0 auto; padding: 30px 20px 80px; }

.lista-interes-vacia {
  text-align: center;
  padding: 80px 20px;
  color: var(--text-dim);
}
.lista-interes-vacia i { font-size: 2.5rem; margin-bottom: 14px; display: block; color: var(--text-dim-2); }
.lista-interes-vacia p { max-width: 340px; margin: 0 auto; line-height: 1.5; }

.lista-interes-lista { display: flex; flex-direction: column; gap: 12px; margin-bottom: 24px; }
.lista-interes-item {
  display: flex;
  align-items: center;
  gap: 14px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 10px;
}
.lista-interes-item__img {
  flex-shrink: 0;
  width: 64px;
  height: 64px;
  background: var(--img-bg);
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.lista-interes-item__img img { max-width: 100%; max-height: 100%; object-fit: contain; }
.lista-interes-item__info { flex: 1; min-width: 0; }
.lista-interes-item__marca { font-size: 0.68rem; color: var(--text-dim); text-transform: uppercase; letter-spacing: 1px; }
.lista-interes-item__nombre { font-size: 0.9rem; font-weight: 600; line-height: 1.3; margin: 2px 0; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.lista-interes-item__sku { font-size: 0.72rem; color: var(--text-dim-2); }
.lista-interes-item__quitar {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid var(--border-2);
  border-radius: 50%;
  color: var(--text-dim);
  cursor: pointer;
  transition: border-color 0.2s var(--ease-fluid), color 0.2s var(--ease-fluid);
}
.lista-interes-item__quitar:hover { border-color: var(--danger); color: var(--danger); }
.lista-interes-enviar-wrap { display: flex; justify-content: center; }
.lista-interes-enviar-wrap .btn-accion { width: 100%; max-width: 360px; justify-content: center; }

/* ---------- MODO PRESENTACIÓN ---------- */
/* Reusa la misma base visual que .detalle-overlay (fixed, fondo, transición
   de apertura) pero sin topbar — acá el objetivo es máxima limpieza: nada
   compitiendo con la foto y el nombre del producto. */
.presentacion-overlay {
  position: fixed;
  inset: 0;
  background: var(--bg);
  z-index: 9500;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  visibility: hidden;
  transform: translateY(16px);
  transition: opacity 0.32s var(--ease-fluid), transform 0.32s var(--ease-fluid), visibility 0s linear 0.32s;
}
.presentacion-overlay.open {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition: opacity 0.32s var(--ease-fluid), transform 0.32s var(--ease-fluid);
}

.presentacion-cerrar {
  position: absolute;
  top: 20px;
  right: 20px;
  z-index: 2;
  width: 48px;
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-2);
  border: 1px solid var(--border-2);
  border-radius: 50%;
  color: #fff;
  font-size: 1.2rem;
  cursor: pointer;
  transition: border-color 0.2s var(--ease-fluid), color 0.2s var(--ease-fluid), transform 0.15s var(--ease-fluid);
}
.presentacion-cerrar:hover { border-color: var(--accent); color: var(--accent); }
.presentacion-cerrar:active { transform: scale(0.94); transition-duration: 0.1s; }

#presentacion-contenido {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 20px;
  /* padding en vez de solo centrar: dejaba tapar el badge de disponibilidad
     de arriba con el contador "N / total" de abajo — el contador era
     position:absolute;bottom:24px flotando ENCIMA del contenido centrado, así
     que en viewports con poca altura (ej. iPad en horizontal, 1024x768) el
     badge y el contador terminaban a ~2px de distancia o directamente
     superpuestos. Ahora el contador vive en el flujo normal, siempre debajo
     del producto — nunca puede quedar arriba de otra cosa. */
  padding: 60px 0;
  overflow-y: auto;
}

.presentacion-producto {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  max-width: min(560px, 84vw);
  padding: 0 80px;
}
.presentacion-producto__img {
  width: min(420px, 70vw);
  aspect-ratio: 1;
  background: var(--img-bg);
  border-radius: var(--radius-lg);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  margin-bottom: 28px;
}
.presentacion-producto__img img { max-width: 82%; max-height: 82%; object-fit: contain; }
.presentacion-producto__marca { color: var(--text-dim); text-transform: uppercase; letter-spacing: 2px; font-size: 0.9rem; margin-bottom: 8px; }
.presentacion-producto__nombre { font-size: clamp(1.6rem, 4vw, 2.6rem); line-height: 1.2; margin-bottom: 14px; }
.presentacion-producto__estado {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.95rem;
  color: var(--text-dim);
}
.presentacion-producto__estado .led { width: 9px; height: 9px; border-radius: 50%; background: var(--text-dim-2); }
.presentacion-producto__estado.disponible { color: #cfcfcf; }
.presentacion-producto__estado.disponible .led { background: var(--accent); box-shadow: 0 0 0 3px rgba(0,230,118,0.2); }

.presentacion-flecha {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  width: 56px;
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-2);
  border: 1px solid var(--border-2);
  border-radius: 50%;
  color: #fff;
  font-size: 1.3rem;
  cursor: pointer;
  transition: border-color 0.2s var(--ease-fluid), color 0.2s var(--ease-fluid), transform 0.15s var(--ease-fluid);
}
.presentacion-flecha:hover { border-color: var(--accent); color: var(--accent); }
.presentacion-flecha:active { transform: translateY(-50%) scale(0.94); transition-duration: 0.1s; }
.presentacion-flecha--izq { left: 16px; }
.presentacion-flecha--der { right: 16px; }
@media (max-width: 640px) {
  /* En mobile las flechas flotando sobre la foto tapan menos espacio que a
     los costados (no hay lugar) — se bajan a una fila propia debajo. */
  .presentacion-flecha { position: static; transform: none; width: 48px; height: 48px; }
  #presentacion-contenido { flex-direction: column; gap: 20px; }
  .presentacion-producto { padding: 0 16px; order: 1; }
  .presentacion-flecha--izq { order: 2; margin-right: auto; margin-left: 24px; }
  .presentacion-flecha--der { order: 2; margin-left: auto; margin-right: 24px; }
  /* Sin esto el contador (order:0 por default) se dibujaba ANTES que el
     producto y las flechas — con el nuevo flujo normal (ver arriba, ya no es
     position:absolute) el orden explícito importa. */
  .presentacion-contador { order: 3; }
  .presentacion-flecha:active { transform: scale(0.94); }
}

.presentacion-contador {
  /* Antes: position:absolute;bottom:24px — flotaba encima del contenido
     centrado y en viewports bajos (iPad horizontal) tapaba el badge de
     "Disponible". Ahora es un hijo más del flex column de
     #presentacion-contenido: siempre después del producto, nunca sobre él. */
  flex-shrink: 0;
  background: var(--bg-2);
  border: 1px solid var(--border);
  padding: 6px 16px;
  border-radius: var(--radius-pill);
  font-size: 0.85rem;
  color: var(--text-dim);
  font-family: monospace;
}
.presentacion-vacio { color: var(--text-dim); text-align: center; padding: 60px 20px; }

/* ============================================================================
   PORTADA (catalogo/index.html) — pantalla de bienvenida antes del grid, con
   el logo entrando con fade-in+escala y un halo de degradado verde pulsando
   detrás. Reusa el mismo `.fondo-electrico` del catálogo (misma firma visual
   de fondo vivo) — este bloque solo agrega lo que es exclusivo de la portada.
   ========================================================================= */

.portada {
  min-height: 100vh;
  min-height: 100dvh; /* real en mobile (evita el salto por la barra de direcciones de Safari/Chrome) */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 40px;
  padding: 40px 24px;
  text-align: center;
  position: relative;
}

/* Contenedor del logo + halo — position:relative para que el halo (absolute)
   se centre respecto al logo y no respecto a toda la pantalla. */
.portada-marca {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Degradado radial verde "explotando" detrás del logo — pulso continuo de
   escala/opacidad. Única animación en loop de la portada (la del logo es de
   entrada, una sola vez) — mismo criterio de "1 animación ambiental por
   vista" aplicado antes al LED/fondo eléctrico (ver CLAUDE.md, sección de la
   skill ui-ux-pro-max). z-index:-1 relativo a .portada-marca: queda detrás
   del logo pero por delante del .fondo-electrico (ese ya está en -1 global
   fixed a nivel de <body>, este es local al stacking context de la marca). */
.portada-halo {
  position: absolute;
  width: min(520px, 90vw);
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, var(--accent) 0%, rgba(0, 230, 118, 0.35) 35%, transparent 70%);
  filter: blur(40px);
  z-index: -1;
  animation: pulsoHalo 4.5s ease-in-out infinite;
}
@keyframes pulsoHalo {
  0%, 100% { transform: scale(0.85); opacity: 0.35; }
  50% { transform: scale(1.05); opacity: 0.55; }
}

.portada-logo {
  width: min(360px, 70vw);
  height: auto;
  opacity: 0;
  transform: scale(0.94);
  animation: apareceLogo 0.9s var(--ease-fluid) forwards;
}
@keyframes apareceLogo {
  from { opacity: 0; transform: scale(0.94); }
  to { opacity: 1; transform: scale(1); }
}

.btn-portada {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 14px 32px;
  border-radius: var(--radius-pill);
  background: transparent;
  border: 2px solid var(--accent);
  color: var(--accent);
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 600;
  font-size: 1.05rem;
  letter-spacing: 1px;
  text-decoration: none;
  cursor: pointer;
  min-height: 44px;
  opacity: 0;
  transform: scale(0.94);
  /* Mismo fade-in que el logo, con un pequeño delay para que se sienta
     secuencial (logo primero, botón después) — mismo truco de
     animation-delay escalonado que ya usa renderGrid() en las tarjetas. */
  animation: apareceLogo 0.9s var(--ease-fluid) 0.18s forwards;
  transition: background 0.2s var(--ease-fluid), color 0.2s var(--ease-fluid), transform 0.15s var(--ease-fluid);
}
.btn-portada:hover { background: var(--accent); color: #000; }
.btn-portada:active { transform: scale(0.96); transition-duration: 0.1s; }
