/**
 * Premioplus — Sections
 * Layout específico de cada sección de la landing.
 */

/* ---------- Hero ---------- */
.hero {
  position: relative;
  display: flex;
  align-items: center;
  padding-top: 80px;
  /* Compactado a propósito: sin min-height, la altura la define el
     contenido. padding-bottom da aire real antes de que arranque lo que
     sigue (separado del row-gap de .hero__grid, que resuelve el espacio
     interno entre los ítems del Hero).

     En Desktop/Tablet lo que sigue es Trust Bar (con los contadores
     todavía dentro del Hero) — sin cambios ahí. En Mobile,
     trust-bar-position.js reubica tanto el renglón como las tarjetas de
     contadores para que vivan DESPUÉS de Beneficios (Título → Tarjetas →
     Renglón → Contadores, como un único módulo) — con eso, lo que sigue
     al Hero en Mobile pasa a ser Beneficios directo.

     Igualado a var(--space-9)/--space-8/--space-6 — el mismo valor y
     los mismos breakpoints que .section usa en su padding-top — a
     propósito: es el mismo ritmo estándar que separa cualquier otro par
     de secciones en el sitio, así que sigue funcionando igual de bien
     sin importar si lo siguiente es Trust Bar o Beneficios. */
  padding-bottom: var(--space-9);
  /* Sin background propio: el Hero deja ver el --grad-sky de <body> — los
     dos primeros glows del mesh están posicionados justo para enriquecer
     esta zona, más .hero__glow como acento adicional. Así no hay corte de
     color entre el Hero y lo que sigue. */
  overflow: hidden;
}

@media (max-width: 1023px) {
  .hero {
    padding-bottom: var(--space-8);
  }
}

@media (max-width: 639px) {
  .hero {
    padding-bottom: var(--space-6);
  }
}

.hero__glow {
  position: absolute;
  inset: -10%;
  background: radial-gradient(circle at 25% 30%, rgba(255, 215, 0, 0.1), transparent 45%),
    radial-gradient(circle at 80% 70%, rgba(139, 95, 191, 0.22), transparent 50%);
  animation: mesh-drift 20s linear infinite;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .hero__glow {
    animation: none;
  }
}

/* Mesh-glow local para "puntos estratégicos" (Beneficios, Testimonios):
   un acento extra sobre el --grad-sky global de <body>, no un reemplazo —
   por eso es sutil y va detrás del contenido (primer hijo, sin z-index:
   el orden del DOM ya lo deja detrás de .container). */
.section-glow {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  animation: mesh-drift 28s linear infinite;
}

/* Cada punto estratégico tiene su propia firma (posición, balance de
   color, tamaño) — repetir el mismo glow en cada sección es justo lo que
   se lee como "repetitivo". */
.section-glow--warm {
  background: radial-gradient(560px 460px at 88% 12%, rgba(255, 215, 0, 0.05), transparent 62%),
    radial-gradient(640px 560px at 6% 88%, rgba(139, 95, 191, 0.13), transparent 62%);
}

.section-glow--violet {
  background: radial-gradient(720px 520px at 10% 10%, rgba(107, 47, 168, 0.16), transparent 60%),
    radial-gradient(520px 480px at 92% 90%, rgba(139, 95, 191, 0.1), transparent 58%);
}

/* Puente entre el Hero (que trae su propio fondo opaco) y el resto de la
   página: sin esto había una "zona muerta" justo debajo del Hero, el
   corte más visible de todos porque es el primero que ve el usuario.

   El inset superior era simétrico (-60%) con el inferior, y esa mitad de
   arriba se estiraba hasta meterse en la cola del Hero — justo donde
   ahora vive la tarjeta de contadores (creció al sumar el segundo
   contador). Se percibía como una franja oscura "atravesando" las
   tarjetas. Reducir solo el alcance hacia arriba resuelve eso sin tocar
   su trabajo real: seguir tapando la "zona muerta" hacia abajo. */
.section-glow--seam {
  inset: -10% 0 -60% 0;
  overflow: visible;
  animation: none;
  background: radial-gradient(80% 100% at 50% 0%, rgba(107, 47, 168, 0.22), transparent 68%);
}

@media (prefers-reduced-motion: reduce) {
  .section-glow {
    animation: none;
  }
}

.hero__grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  /* row-gap 56px (no un token estándar): la entrada cinematográfica del
     carrusel (cinema.js, tween de .hero__visual) deja un desplazamiento
     vertical propio de ~32px que no se refleja en el alto de layout de la
     grilla — con menos aire acá el carrusel terminaba pisando visualmente
     la fila de tarjetas de contadores. Este valor deja margen real de
     sobra para ese desplazamiento sin tocar la animación en sí. */
  row-gap: 56px;
  column-gap: var(--space-6);
  /* start (no center): con el carrusel en 1:1 ambas columnas arrancan a la
     misma altura, lectura más intencional que centrar dos bloques de
     distinta longitud. */
  align-items: start;
  position: relative;
  z-index: 1;
  width: 100%;
}

.hero__content {
  grid-column: 1 / span 7;
  /* Los ítems de grid son min-width:auto por defecto: sin width:100% +
     min-width:0, el h1 (ahora más ancho, 21ch) fuerza su tamaño
     intrínseco de contenido sobre el track del grid en vez de ajustarse
     a la columna disponible, y termina desbordando el viewport en mobile. */
  width: 100%;
  min-width: 0;
}

/* Baja todo el bloque de texto (desde el eyebrow) para que su borde
   superior quede alineado con el borde superior real del carrusel —
   el carrusel no arranca en el top de su fila: además de su propio
   margin-top, la animación cinematográfica de entrada (cinema.js) le
   aplica un desplazamiento vertical propio de ~32px. Este margin-top
   compensa ambos para igualar las dos alturas, sin tocar el
   espaciado interno entre eyebrow/h1/subtítulo/CTA. Solo aplica desde
   1024px: por debajo, .hero__grid pasa a una sola columna (el texto
   ya no comparte fila con el carrusel) y este offset no tendría
   sentido — sumaría aire vacío arriba del Hero sin motivo. */
@media (min-width: 1024px) {
  .hero__content {
    margin-top: 57px;
  }
}

.hero__visual {
  grid-column: 8 / span 5;
  min-width: 0;
  /* El borde superior del banner debe alinearse con la parte superior
     real del bloque de texto — el eyebrow "Plataforma premium de
     entretenimiento online", el primer elemento de esa columna, no un
     punto intermedio como el H1. Medido en vivo (no a ojo): con el
     margin-top anterior (32px) el carrusel arrancaba 32.4px POR ENCIMA
     del eyebrow — .hero__content ya trae su propio margin-top:57px
     (ver esa regla, sin tocar) empujando todo el bloque de texto hacia
     abajo, así que hacía falta la misma cantidad de aire acá para que
     los dos ejes coincidan. var(--space-8)=64px (32px + 32.4px
     redondeado al escalón existente del sistema de spacing, no un
     número inventado) deja el borde superior del carrusel a la misma
     altura real que el eyebrow, en los tres anchos desktop probados
     (1366/1440/1920). Solo aplica en desktop/tablet: en mobile
     .hero__grid pasa a una sola columna y este offset no aplica (ver
     @media max-width:1023px más abajo). */
  margin-top: var(--space-8);
}

@media (max-width: 1023px) {
  /* Colapsa a una sola columna real (no "12 columnas con 2 items
     spanneados"): con el grid de 12 columnas + gap grande (--space-7,
     para dar aire entre título e imagen en desktop), un ítem spanneado
     1/-1 arrastra los 11 gaps internos entre columnas incluso apilado en
     mobile — eso desbordaba el viewport. Un solo track evita el problema
     de raíz en vez de parchear cada elemento hijo. */
  .hero__grid {
    grid-template-columns: 1fr;
  }
  .hero__content,
  .hero__visual {
    grid-column: 1 / -1;
  }
  /* En mobile el mensaje principal y el CTA van primero (orden natural del
     DOM): el visual es un refuerzo, no debe empujar el H1 fuera del primer
     viewport. El offset de alineación con el H1 solo aplica en el layout de
     2 columnas — acá basta el espaciado estándar. Ver §9 de
     docs/refinamiento-fase-final.md. */
  .hero__visual {
    margin-top: var(--space-6);
  }
}

/* ---------- Reordenamiento Hero mobile: Título → Banner → resto ----------
   Pedido puntual: en mobile el H1 debe leerse primero y el carrusel debe
   aparecer INMEDIATAMENTE después — subtítulo/CTA/microcopy pasan a vivir
   debajo del banner en vez de arriba.

   display:contents en .hero__content "desarma" ese contenedor sin tocar
   el DOM ni JS/GSAP (nada lo selecciona: cinema.js sólo apunta a
   .hero__visual, y ningún hijo de .hero__content trae data-reveal) —
   eyebrow/h1/subtítulo/CTA-row/microcopy pasan a ser ítems directos de
   .hero__grid, cada uno con su propio order.

   row-gap:0 es necesario: al volverse ítems sueltos del grid, el row-gap
   de 56px de .hero__grid (pensado para separar bloques grandes) se
   aplicaría entre CADA hijo suelto (eyebrow↔h1, h1↔banner, etc.),
   rompiendo el ritmo compacto interno del bloque de texto. Con row-gap
   en 0, cada elemento controla su propio margin-top — eyebrow→h1,
   subtítulo→CTA→microcopy quedan con los valores ya aprobados (esas
   relaciones no cambiaron, solo se movieron como bloque); título→banner
   y banner→subtítulo son relaciones nuevas, ajustadas ópticamente en los
   bloques de altura de arriba/abajo (no reutilizan el espaciado
   anterior).

   .trust-stats-grid (tarjetas de contadores) ya NO participa acá: en
   mobile, trust-bar-position.js la saca de .hero__grid en tiempo de
   ejecución para reubicarla después del renglón informativo (Trust Bar)
   — su espaciado en esa nueva posición vive en
   .trust-stats-grid--after-trust-bar, más abajo. */
@media (max-width: 639px) {
  .hero__grid {
    row-gap: 0;
  }

  .hero__content {
    display: contents;
  }

  .hero .eyebrow {
    order: 1;
  }

  .hero h1 {
    order: 2;
  }

  .hero__visual {
    order: 3;
  }

  .hero__subtitle {
    order: 4;
  }

  .hero .cta-row {
    order: 5;
  }

  .hero .cta-microcopy {
    order: 6;
  }
}

.hero__content > * + * {
  margin-top: var(--space-4);
}

/* Los CTA del hero son el momento de mayor intención de toda la landing y
   ahora llevan texto corto ("WhatsApp" / "Clientes VIP") — les damos más
   presencia que al botón genérico para que pesen visualmente tanto como
   el H1 que tienen al lado. */
.hero .cta-row .btn {
  min-height: 46px;
  padding: var(--space-3) var(--space-6);
  font-size: 1rem;
}

.hero .cta-row .btn-icon {
  width: 20px;
  height: 20px;
}

/* En mobile, "WhatsApp" y "Clientes VIP" pasan de apilados a una sola
   fila: mismo ancho exacto vía flex:1 (en vez de que cada uno crezca
   según su propio texto), mismo alto ya garantizado por min-height.
   Padding e ícono/gap internos se ajustan solo lo necesario para que
   "Clientes VIP" (el texto más largo) entre cómodo en la mitad del
   ancho disponible sin envolver a dos líneas — nada de esto toca
   color, tipografía ni el ícono en sí, solo el espacio a su alrededor. */
@media (max-width: 639px) {
  .hero .cta-row {
    flex-wrap: nowrap;
    gap: var(--space-2);
  }
  .hero .cta-row .btn {
    flex: 1 1 0;
    min-width: 0;
    padding-inline: 6px;
    gap: 4px;
  }
  /* "Clientes VIP" mide ~91px de texto natural contra ~78px de
     "WhatsApp" — repartir el ancho parejo (flex:1 para ambos) dejaba a
     "Clientes VIP" más apretado. Reparto proporcional al ancho real del
     texto (medido, no estimado por cantidad de caracteres) para que
     ninguno de los dos trunque en los anchos más chicos. */
  .hero .cta-row .btn[data-cta="whatsapp"] {
    flex: 0.95 1 0;
  }
  .hero .cta-row .btn[data-cta="telegram"] {
    flex: 1.05 1 0;
  }
  .hero .cta-row .btn span {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
}

.hero h1 {
  /* Escala reducida frente al --fs-display global (usado en h1 base):
     el Hero + Trust Bar deben entrar en una sola pantalla desktop, y el
     H1 era el elemento más alto de la sección. 28ch (en vez de 21ch)
     compensa la fuente más chica para seguir sin actuar como límite real
     en desktop — mismo rol de "tope de seguridad" en pantallas muy
     anchas, sin acortar más las líneas de lo que ya hace el ancho de la
     columna. */
  font-size: clamp(2.25rem, 1.6rem + 2vw, 3.375rem);
  line-height: 1.08;
  max-width: min(28ch, 100%);

  /* Color sólido, sin degradado ni shimmer: el peso del titular lo da la
     tipografía y la jerarquía (tamaño, --font-display, max-width), no un
     efecto de color. --text-primary es el mismo blanco que usa el resto
     del sistema tipográfico de la landing. */
  color: var(--text-primary);
}

.hero__subtitle {
  font-size: var(--fs-body);
  line-height: 1.45;
  color: var(--text-secondary);
  max-width: min(56ch, 100%);
}

/* Pantallas mobile de poca altura (iPhone SE y equivalentes, ≤700px):
   sin este ajuste, el bloque de texto del Hero (título, subtítulo,
   botones) no entraba completo en el primer viewport. Compacta solo
   ese bloque (mismos elementos, mismo orden, solo menos aire) para que
   siempre quede visible por completo, sin afectar mobile "normal"
   (iPhone 12 mini en adelante, Android estándar) ni desktop/tablet. */
@media (max-width: 639px) and (max-height: 700px) {
  /* La navegación mobile ahora vive abajo (bottom-nav) — arriba solo
     queda el navbar fijo (80px), heredado de .hero base. Sin fila de
     chips que despejar, no hace falta padding-top extra acá. */
  .hero .eyebrow {
    font-size: 0.6875rem;
  }
  .hero__content > * + * {
    margin-top: 10px;
  }
  .hero h1 {
    font-size: 1.75rem;
    line-height: 1.15;
  }
  /* Alto reducido (≤700px): el banner necesita algo de aire propio
     frente al título, pero menos que en mobile "normal" — este bucket
     ya comprime todo lo demás a 10px para entrar en la primera
     pantalla. */
  .hero__visual {
    margin-top: var(--space-4);
  }
  .hero__subtitle {
    font-size: 0.8125rem;
    line-height: 1.35;
  }
  .hero .cta-row {
    gap: var(--space-3);
  }
  .hero .cta-row .btn {
    padding-block: var(--space-2);
  }
  .hero .cta-microcopy {
    margin-top: 6px;
    font-size: 0.75rem;
    line-height: 1.35;
    /* En los anchos más angostos (320px) este texto envolvía a 2 líneas
       y la primera llegaba a rozar el rincón inferior derecho, justo
       donde viven los FABs de contacto fijos. Reserva su ancho para
       que siempre envuelva antes de esa zona. */
    max-width: calc(100% - 64px);
  }
}

/* Refinamiento de composición del bloque de texto del Hero en mobile
   "normal" (todo lo que no cae en el compactado de arriba, ≥701px de
   alto — iPhone 12 mini en adelante, Android estándar).

   Segunda vuelta: objetivo es que título + banner + microcopy ("Respuesta
   personalizada...") entren completos en la primera pantalla sin scroll,
   en 360×800 hasta 430×932. La palanca principal es el banner (16:9 en
   vez de 1:1, ver .hero-carousel arriba — solo eso libera >140px a 360px
   de ancho), esto acá es el ajuste fino del resto: mismos pares
   conceptuales que antes (eyebrow+título y botones+microcopy acoplados,
   poco aire; título→banner, banner→subtítulo y subtítulo→botones son
   transiciones reales) pero un escalón más compactos — con el banner ya
   mucho más bajo, siguen leyéndose como grupos diferenciados sin el aire
   que tenían cuando el banner era el doble de alto. */
@media (max-width: 639px) and (min-height: 701px) {
  /* 88 = navbar fijo (80px) + 8px de aire — mismo criterio que usa
     nav.js para el scroll a anclas. padding-top menor dejaba el eyebrow
     arrancando debajo del navbar visualmente (el navbar es fixed, no
     empuja layout: un padding-top más chico no "ahorra" espacio real,
     solo esconde el eyebrow detrás de la barra). */
  .hero {
    padding-top: 88px;
  }
  .hero h1 {
    margin-top: 6px;
  }
  /* título→subtítulo pasa a ser banner→subtítulo (el subtítulo ahora
     vive debajo del carrusel, no del H1) — mismo criterio de "transición
     real" que antes, un escalón más ajustado. line-height también baja
     un poco (1.45→1.35): con 4-5 líneas de subtítulo, ese 0.10 extra por
     línea suma varios px reales sin afectar la legibilidad. */
  .hero .hero__subtitle {
    margin-top: 12px;
    line-height: 1.35;
  }
  /* max-width: con el bloque ya comprimido para entrar en la primera
     pantalla, cta-row y microcopy ahora caen en la misma franja donde
     flotan los FABs de contacto (fixed, esquina inferior derecha) —
     antes vivían mucho más abajo, fuera de esa zona. Mismo criterio que
     ya usaba microcopy en el bucket de alto reducido: reservar ~64px a
     la derecha para que ningún botón ni texto quede tapado por los FABs. */
  .hero .cta-row {
    margin-top: 8px;
    max-width: calc(100% - 58px);
  }
  .hero .cta-microcopy {
    margin-top: 6px;
    max-width: calc(100% - 64px);
  }
  /* título→banner: ajustada ópticamente — ni pegado al H1 ni con el
     salto grande que tenía cuando el banner ocupaba el doble de alto. */
  .hero__visual {
    margin-top: var(--space-4);
  }
}

/* ---------- Trust cards (Jugadores + Pozo Acumulado + Juegos) ----------
   Tres módulos premium independientes en fila — no una barra dividida.
   Cada uno es un .card completo por derecho propio (mismo vidrio,
   backdrop-blur, borde, sombra flotante, hover y glow de cursor que el
   resto de la landing: feature-card, bonus-card, etc. — "mismo sistema
   de diseño" sin reinventar un componente nuevo).

   trust-stats-grid ya NO vive dentro de .hero__content: es un ítem más
   de .hero__grid (grid-column: 1/-1), en su propia fila debajo de las
   dos columnas (texto + carrusel). Eso es lo que le permite "cubrir todo
   el ancho disponible" de verdad — antes, anidado en hero__content, solo
   podía ocupar el ancho de esa columna (58%) y dejaba el resto de la
   fila (debajo del carrusel) vacío. Ahora la fila entera, alineada con
   el H1 a la izquierda y el carrusel a la derecha, es suya. */
.trust-stats-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-4);
  grid-column: 1 / -1;
  width: 100%;
}

.trust-card {
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.trust-card__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-3);
}

.trust-card__icon {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 215, 0, 0.1);
  color: var(--gold-400);
}

.trust-card__icon svg {
  width: 16px;
  height: 16px;
}

/* El pozo acumulado usa el acento violeta en vez del dorado de
   jugadores — mismo componente, misma jerarquía, pero cada tarjeta
   conserva una identidad de color propia dentro del mismo sistema. */
.trust-card__icon--jackpot {
  background: rgba(139, 95, 191, 0.16);
  color: var(--purple-400);
}

/* Juegos disponibles usa un tercer acento (azul --info, sin usar en
   ningún otro lugar del sitio) — jugadores=dorado, pozo=violeta, juegos
   =azul: tres identidades propias dentro del mismo sistema, ninguna
   repetida. */
.trust-card__icon--games {
  background: rgba(56, 189, 248, 0.14);
  color: var(--info);
}

.trust-card__trend {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  padding: 6px 10px;
  border-radius: var(--radius-full);
  background: rgba(34, 197, 94, 0.12);
  border: 1px solid rgba(34, 197, 94, 0.3);
  color: var(--success);
  font-size: 0.7rem;
  font-weight: 600;
  white-space: nowrap;
}

/* "Actualizado" no es una métrica que crece sola como jugadores/pozo —
   usar el mismo verde de "Creciendo" ahí sería mentirle al usuario sobre
   qué significa el chip. Mismo componente, mismo tamaño, color propio. */
.trust-card__trend--neutral {
  background: rgba(56, 189, 248, 0.12);
  border-color: rgba(56, 189, 248, 0.3);
  color: var(--info);
}

.trust-card__trend svg {
  width: 15px;
  height: 15px;
}

/* El valor vive en su propia fila, ancho completo de la tarjeta — al
   sacar el chip de tendencia de al lado (ahora arriba, junto al ícono)
   un número largo como "$117.562.000" nunca compite por espacio con
   nada más en la misma línea.

   font-size fluido (no un valor fijo): con 3 tarjetas iguales en vez de
   2, cada una es más angosta, y "$117.562.000" es el string más largo
   de las tres — a 2rem fijo desbordaba el borde de la tarjeta en el
   rango de ~700-900px (3 columnas, pero contenedor todavía angosto).
   clamp() lo achica solo donde hace falta y vuelve a 2rem completo en
   desktop. overflow-wrap es la red de seguridad final: nunca debe
   recortarse visualmente, ni en el viewport más angosto posible. */
.trust-card__value {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.25rem, 1rem + 1.4vw, 1.625rem);
  line-height: 1.05;
  color: var(--gold-500);
  font-variant-numeric: tabular-nums;
  overflow-wrap: break-word;
  transition: text-shadow 500ms var(--ease-out-premium);
}

.trust-card__value.is-ticking {
  text-shadow: 0 0 18px rgba(255, 215, 0, 0.65);
}

.trust-card--jackpot .trust-card__value {
  color: var(--purple-400);
}

.trust-card--jackpot .trust-card__value.is-ticking {
  text-shadow: 0 0 18px rgba(139, 95, 191, 0.65);
}

.trust-card--games .trust-card__value {
  color: var(--info);
}

.trust-card--games .trust-card__value.is-ticking {
  text-shadow: 0 0 18px rgba(56, 189, 248, 0.65);
}

.trust-card__label {
  margin-top: 3px;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text-secondary);
}

/* Línea de contexto propia por tarjeta — el valor de agregar esto es
   explicar EN QUÉ consiste cada número (confianza), no decorar por
   decorar. Separada por un filete sutil para que se lea como un dato
   secundario, nunca compitiendo con el número principal. */
.trust-card__caption {
  margin-top: var(--space-3);
  padding-top: var(--space-2);
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  font-size: 0.72rem;
  line-height: 1.4;
  color: var(--text-muted);
}

/* 3 columnas desde tablet grande en adelante; por debajo, incluso con el
   font-size fluido del valor, tres columnas dejan muy poco aire para el
   ícono + chip + caption de cada tarjeta — se apilan en una sola
   columna, cada tarjeta a ancho completo. */
@media (max-width: 900px) {
  .trust-stats-grid {
    grid-template-columns: 1fr;
  }
}


/* A ancho completo (una sola columna) el valor se sigue leyendo como el
   número protagonista de una tarjeta de balance fintech — pero sin
   inflar el padding ni el font-size al punto de que cada tarjeta ocupe
   casi un cuarto de pantalla. Corregido a un padding y una escala que
   dejan la tarjeta compacta sin perder jerarquía. */
/* Rediseño mobile-first de las 3 tarjetas: antes se apilaban a ancho
   completo (una debajo de otra, ≤900px) — un dashboard fintech premium
   muestra sus métricas clave de un vistazo, en una sola fila, no en
   una lista vertical que empuja todo lo demás fuera de la primera
   pantalla. Layout centrado en columna (ícono → valor → label → chip)
   en vez del layout "ícono+chip arriba, valor abajo" de desktop/tablet:
   con ~110px de ancho real por tarjeta, dos elementos lado a lado ya no
   entran cómodos — apilados y centrados sí. La caption (oración larga)
   se oculta acá: no hay ancho real para una frase completa sin que se
   vea comprimida o parta en 4-5 líneas — el número, el título y el chip
   de tendencia ya cubren "identificar de un vistazo", que es el
   objetivo pedido. Sigue disponible en tablet/desktop, sin tocar. */
@media (max-width: 639px) {
  .trust-stats-grid {
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-1);
  }

  /* padding-block var(--space-2)→var(--space-3): mismo criterio que
     .feature-card más abajo — ajuste mínimo de altura, solo tras
     agotar padding/gap entre bloques, para que Beneficios+renglón+
     contadores encastren en una pantalla sin dejar aire vacío. Suma
     presencia real a cada tarjeta en vez de ser solo espacio libre. */
  .trust-card {
    padding: var(--space-3) var(--space-1);
    align-items: center;
    text-align: center;
    gap: 2px;
  }

  .trust-card__top {
    flex-direction: column;
    justify-content: flex-start;
    gap: 4px;
    margin-bottom: 0;
    width: 100%;
  }

  .trust-card__icon {
    width: 22px;
    height: 22px;
  }

  .trust-card__icon svg {
    width: 11px;
    height: 11px;
  }

  .trust-card__trend {
    order: 2;
    padding: 2px 6px;
    gap: 3px;
    font-size: 0.5625rem;
  }

  .trust-card__trend svg {
    width: 8px;
    height: 8px;
  }

  /* Números más finos y "precisos" (fintech, no display-bold): 600 en vez
     de 700, tracking levemente negativo para que los dígitos tabulares se
     sientan más compactos y deliberados en vez de gruesos. white-space:
     nowrap es la regla dura del pedido — "$117.999.504" nunca puede
     partirse en dos líneas — por eso el font-size baja lo justo (medido
     contra el string real más largo a 320px, el ancho más angosto que
     soportamos) para que quepa con margen incluso si el contador sigue
     creciendo un dígito más. */
  .trust-card__value {
    width: 100%;
    font-weight: 600;
    font-size: clamp(0.8125rem, 0.65rem + 1.6vw, 0.9375rem);
    letter-spacing: -0.02em;
    white-space: nowrap;
    margin-top: 0;
    line-height: 1.1;
  }

  .trust-card__label {
    width: 100%;
    margin-top: 0;
    font-size: 0.625rem;
    line-height: 1.2;
  }

  .trust-card__caption {
    display: none;
  }
}

/* .trust-bar--after-beneficios / .trust-stats-grid--after-trust-bar:
   hooks que trust-bar-position.js agrega al renglón informativo y a las
   tarjetas de contadores cuando los reubica en mobile (Beneficios →
   Renglón → Contadores). Pedido explícito: Tarjetas de Beneficios→
   Renglón debe medir EXACTAMENTE lo mismo que Renglón→Contadores — no
   una aproximación visual, el mismo valor real de CSS en ambos lados,
   y las dos deben crecer con el alto disponible (ver
   --beneficios-gap-g, definida en :root junto al padding-bottom de
   #beneficios más arriba — mismo detalle de por qué está en :root y no
   en un ancestro más específico).

   .trust-bar no trae margin propio, solo padding-block:20px + su borde
   de 1px (21px) — ya simétrico arriba y abajo por diseño propio del
   componente (ver .trust-bar en components.css, sin tocar). Eso deja
   un solo valor por lado para controlar cada distancia: el
   padding-bottom de #beneficios (lado "antes") y el margin-top de acá
   abajo (lado "después") — misma variable en los dos, así la igualdad
   no depende de que dos números coincidan por casualidad. */
@media (max-width: 639px) {
  .trust-stats-grid--after-trust-bar {
    margin-top: var(--beneficios-gap-g);
  }
}

/* ---------- Hero carousel (cinemático) ---------- */
.hero-carousel {
  position: relative;
  border-radius: var(--radius-lg);
  /* 1:1 en vez de 4:5 (retrato): las fotos de origen son horizontales
     (cancha, mesa de ruleta) — un marco cuadrado las recorta mucho menos
     que uno vertical, y además su altura ahora calza con la columna de
     texto en vez de sobrarle o faltarle. */
  aspect-ratio: 1 / 1;
  overflow: hidden;
  box-shadow: var(--elev-3);
  border: 1px solid rgba(255, 255, 255, 0.1);
  isolation: isolate;
}

/* Desktop/Tablet: solo existe el carrusel --desktop. El --mobile vive en
   el DOM (hero-carousel.js necesita inicializarlo igual, ver su
   comentario) pero no se pinta ni ocupa espacio acá. El media query de
   abajo invierte esto para Mobile. */
.hero-carousel--mobile {
  display: none;
}

/* Mobile: de 1:1 a 2:1 — el cuadrado es el mayor consumidor de alto de
   todo el Home (más que el título, más que cualquier gap), y es la
   palanca principal para que título + banner + microcopy entren en la
   primera pantalla sin scroll, incluso contando el navbar fijo (80px) y
   el bottom-nav fijo (61px) que "roban" espacio real de la pantalla sin
   aparecer en ningún cálculo de layout — ambos hay que restarlos del
   alto disponible a mano. 2:1 sigue siendo una proporción de foto con
   encuadre intencional (no una franja tipo banner publicitario), mismo
   lenguaje "cinemático" que ya nombra este componente. object-position
   por slide abajo compensa el recorte vertical mucho mayor (de 4:5 a
   2:1 sólo queda ~40% del alto original) para que el sujeto principal
   de cada foto siga encuadrado.

   Nota: esta regla estaba antes definida ANTES que la base .hero-carousel
   de arriba (misma especificidad, un solo class), así que la base —
   declarada después en el archivo — siempre ganaba y el mobile nunca
   llegó a aplicarse. Reubicada acá, inmediatamente después de la base,
   para que el cascade la resuelva como corresponde. */
@media (max-width: 639px) {
  .hero-carousel {
    aspect-ratio: 2 / 1;
  }

  /* Escopeadas a --desktop a propósito: compensan el recorte vertical de
     FOTOS que nacieron 4:5 y se ven forzadas a 2:1 en mobile. Sin el
     scope, :nth-child(1)/(4) también le pegarían a los slides 1 y 4 del
     carrusel --mobile (imágenes nuevas, ya en 2:1 exacto, que no
     necesitan ningún ajuste de posición — ver más abajo). */
  .hero-carousel--desktop .hero-carousel__slide:nth-child(1) img {
    object-position: 50% 62%;
  }

  .hero-carousel--desktop .hero-carousel__slide:nth-child(4) img {
    object-position: 50% 58%;
  }

  /* ---------- Hero carousel: Mobile usa su propio set de imágenes ----------
     .hero-carousel--desktop y --mobile son dos carruseles independientes
     (mismo HTML/JS, distinto contenido) — acá se decide cuál de los dos
     se ve según el viewport. Ambos comparten la clase base .hero-carousel
     (mismo aspect-ratio 2:1 de arriba, mismo radio/sombra/borde), así que
     esto es solo un interruptor de visibilidad. */
  .hero-carousel--desktop {
    display: none;
  }

  .hero-carousel--mobile {
    display: block;
  }

  /* Los banners nuevos (banner mobile/baner 1-5.png) ya vienen compuestos
     en 2:1 exacto — a diferencia de las fotos de Desktop (retrato 4:5
     forzadas a 2:1), acá NO hace falta compensar ningún recorte: object-
     fit:cover con la posición default (centro) ya muestra la imagen
     completa, sin perder nada de la composición. Por eso .hero-carousel
     --mobile no repite los ajustes de object-position de arriba.
     El zoom "Ken Burns" (scale 1.03 -> 1.12, ver más abajo) tampoco se
     aplica acá: esas fotos fueron preparadas ya encuadradas para este
     formato específico, y esa animación las recortaría hasta un 12%
     adicional con el correr de los 7s — perdiendo justo el tipo de
     detalle (logos, texto de marca) que estos banners sí tienen pegado
     al borde. Desktop conserva el zoom sin cambios: sus fotos siempre
     tuvieron aire de sobra pensado para eso. */
  .hero-carousel--mobile .hero-carousel__slide img {
    transform: none;
  }

  .hero-carousel--mobile .hero-carousel__slide.is-active img {
    animation: none;
  }
}

.hero-carousel__track {
  position: absolute;
  inset: 0;
}

.hero-carousel__slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 1.1s var(--ease-out-premium);
}

.hero-carousel__slide.is-active {
  opacity: 1;
  z-index: 1;
}

.hero-carousel__slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transform: scale(1.03);
}

.hero-carousel__slide.is-active img {
  animation: hero-kenburns 7s ease-out forwards;
}

@keyframes hero-kenburns {
  from {
    transform: scale(1.03);
  }
  to {
    transform: scale(1.12);
  }
}

.hero-carousel__slide[data-overlay="strong"]::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(10, 7, 16, 0.4);
}

/* Scrim persistente: protege siempre la legibilidad del chip (arriba) y el
   stat (abajo), sin importar qué imagen esté activa. */
.hero-carousel__scrim {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(to top, rgba(10, 7, 16, 0.92) 0%, rgba(10, 7, 16, 0.15) 32%, rgba(10, 7, 16, 0.05) 55%, rgba(10, 7, 16, 0.55) 100%);
}

/* ---------- Hero feature card (floating, cambia por diapositiva) ----------
   Componente único, sin scope de sección: Home y Sportbook usan la misma
   clase (misma instancia de hero-carousel.js) para su notificación
   flotante — el +5% de acá abajo alcanza las 4 combinaciones (Home/
   Sportbook × Desktop/Mobile) desde una sola fuente, sin duplicar reglas
   en sportbook.css.

   +5% pedido puntual sobre el tamaño ya vigente (no +5px): cada valor en
   px/rem de este bloque, el de abajo (icon/copy) y los dos overrides de
   media query más abajo quedan multiplicados ×1.05 exacto — mismo
   criterio que ya usa este archivo para escalados fraccionarios (ver
   comentario de .hero-feature-card__copy strong, la mitad exacta de un
   valor anterior). top/left/right NO se tocan (son posición, no tamaño,
   pedido explícito de no moverla) — border-radius (var(--radius-full)=
   999px) tampoco, ya está muy por encima del alto real como para que
   escalarlo cambie algo visible; sigue siendo un pill perfecto. */
.hero-feature-card {
  position: absolute;
  z-index: 3;
  top: var(--space-5);
  left: var(--space-5);
  right: var(--space-5);
  display: flex;
  align-items: center;
  gap: 7.2765px;
  width: fit-content;
  max-width: calc(100% - var(--space-5) * 2);
  padding: 6.670125px 9.702px 6.670125px 6.670125px;
  border-radius: var(--radius-full);
  background: rgba(28, 21, 38, 0.42);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border: 1.05px solid rgba(255, 255, 255, 0.16);
  box-shadow: 0 4.2px 12.6px rgba(0, 0, 0, 0.35), 0 0 0 1.05px rgba(255, 215, 0, 0.06),
    0 0 10.5px rgba(255, 215, 0, 0.05);
  opacity: 0;
  transform: translateY(-8px);
  transition: opacity 480ms var(--ease-out-premium), transform 480ms var(--ease-out-premium);
}

.hero-feature-card.is-visible {
  opacity: 1;
  transform: translateY(0);
}

/* hero-carousel.js alterna .is-offset por igual en las dos instancias
   (desktop/mobile) para un micro-shift de "vida" entre diapositivas, pero
   el resultado visual quedó neutralizado en los dos casos: acá para
   desktop (mismo top que la base, sin shift), y más abajo para mobile
   (ver comentario junto a "top: 4.87%" dentro de @media max-width:639px)
   — la notificación queda siempre fija arriba a la izquierda. Sin regla
   base sin scope: ya no hace falta, las dos instancias reales cubren el
   100% de los casos visibles. */
.hero-carousel--desktop .hero-feature-card.is-offset {
  top: var(--space-5);
}

.hero-feature-card__icon {
  flex-shrink: 0;
  width: 20.61675px;
  height: 20.61675px;
  border-radius: 50%;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(160deg, rgba(255, 215, 0, 0.22), rgba(255, 215, 0, 0.04));
  color: var(--gold-400);
}

.hero-feature-card__icon svg {
  width: 10.308375px;
  height: 10.308375px;
}

/* Logos reales (NFL/NBA/UFC/etc., ver hero-carousel.js applyFeatureIcon)
   llenan el círculo completo en vez del glyph pequeño centrado — object-
   fit:cover nunca deforma, solo recorta si el logo no es cuadrado. */
.hero-feature-card__icon img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.hero-feature-card__copy {
  display: flex;
  flex-direction: column;
  gap: 0.606375px;
  min-width: 0;
}

/* font-size exactamente la mitad del original (0.9rem/0.72rem → acá),
   line-height SIN tocar (sigue heredando el mismo ~1.6 del body que
   ya tenía antes): con line-height constante, el alto de cada línea
   escala en la misma proporción exacta que el font-size — junto con
   padding/gap/icon ya reducidos al 50% arriba, ancho Y alto del
   contenedor completo terminan en ~50% real, no una aproximación de
   un solo eje. */
.hero-feature-card__copy strong {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.5069295rem;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.hero-feature-card__copy span {
  font-size: 0.4050585rem;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

@media (max-width: 479px) {
  .hero-feature-card {
    padding: 5.457375px 7.2765px 5.457375px 5.457375px;
  }
  .hero-feature-card__icon {
    width: 18.19125px;
    height: 18.19125px;
  }
}

.hero-carousel__stat {
  position: absolute;
  z-index: 3;
  left: var(--space-6);
  bottom: 68px;
  /* flex + order (no el orden del DOM) decide qué va arriba/abajo en
     desktop y qué va primero/segundo en mobile — así el mismo par de
     elementos puede leerse "24/7 arriba, texto abajo" en un breakpoint y
     "texto, luego 24/7" en el otro sin depender de dos versiones de
     marcado. Ver el override de mobile más abajo. */
  display: flex;
  flex-direction: column;
}

.hero-carousel__stat strong {
  order: 1;
  display: block;
  font-family: var(--font-display);
  font-size: 2.5rem;
  color: var(--gold-500);
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.5);
}

.hero-carousel__stat span {
  font-size: var(--fs-caption);
  color: var(--text-secondary);
}

.hero-carousel__stat-text {
  order: 2;
}

/* Desktop: misma lógica de posicionamiento que ya usa Mobile para este
   mismo texto (ver el override @media max-width:639px, más abajo) —
   esquina inferior DERECHA, un solo renglón, en vez de la columna
   apilada (número grande arriba, texto abajo) que traía este bloque
   como base. Escopeado a .hero-carousel--desktop en vez de a un
   breakpoint: este componente vive en una instancia de carrusel
   completamente separada de la mobile (arquitectura ya establecida —
   ver hero-carousel.js), así que apuntar a la clase de la instancia es
   más robusto que un ancho de viewport. Ajustado únicamente lo
   necesario (font-size, gap, max-width) para que "Alguien real te
   responde al instante 24/7" entre en una sola línea dentro del ancho
   real de la tarjeta (494px en 1440px de viewport, más angosto en
   1366px) sin invadir el borde — mismo criterio de "una sola línea si
   es posible" que ya aplica en mobile, con ellipsis como resguardo, no
   como resultado esperado. */
.hero-carousel--desktop .hero-carousel__stat {
  left: auto;
  right: var(--space-6);
  bottom: var(--space-6);
  flex-direction: row;
  align-items: baseline;
  justify-content: flex-end;
  gap: 6px;
  max-width: calc(100% - var(--space-6) * 2);
}

.hero-carousel--desktop .hero-carousel__stat span.hero-carousel__stat-text {
  order: 1;
  flex-shrink: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.9375rem;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.6);
}

.hero-carousel--desktop .hero-carousel__stat strong {
  order: 2;
  flex-shrink: 0;
  font-size: 1.375rem;
}

/* Mobile: el banner mide 2:1 en vez de 1:1 (ver .hero-carousel arriba) —
   feature-card (anclada arriba) y stat (anclada abajo) estaban dimensionadas
   para un banner mucho más alto y ahora se superponen (el "24/7" quedaba
   literalmente encima del texto de la tarjeta). Ambas se achican y se
   acercan a su borde correspondiente para volver a convivir con aire de
   sobra en la nueva altura, sin perder ninguno de los dos elementos. */
@media (max-width: 639px) {
  /* top/left en % (no px fijos) a propósito: Desktop ancla la notificación
     con var(--space-5)=24px sobre un banner 1:1 de 492.67px de content-box
     (border incluido) → 24/492.67 ≈ 4.87% tanto de alto como de ancho, la
     misma proporción en los dos ejes porque el banner es cuadrado. Acá el
     banner es 2:1 (mismo contenedor .hero-carousel--mobile, position:
     relative, arquitectura idéntica a Desktop) — replicar el mismo 4.87%
     hace que top se resuelva contra el alto real (más bajo) y left contra
     el ancho real (más ancho) de ESTE banner, dando la misma posición
     relativa visual sin copiar los px absolutos de Desktop (que
     quedarían desproporcionados en un banner mucho más bajo). */
  /* Reducción proporcional del componente completo (no solo el texto):
     a 390px la tarjeta ocupaba 56% del ancho y 29% del alto del banner
     2:1 — competía con la imagen y en varios slides tapaba parte de la
     protagonista (crupier, Zeus). gap/padding acá + icon/tipografía más
     abajo bajan todos juntos, en la misma proporción aproximada
     (~-25/-35%), para que siga siendo la misma tarjeta "pill" de
     siempre pero como detalle chico, nunca como segundo protagonista.
     clamp() (no un solo px fijo) para que a 360px se mantenga compacta
     y a 430px no vuelva a crecer de más — ver mismo criterio en icon/
     tipografía más abajo. */
  .hero-feature-card {
    top: 4.87%;
    left: 4.87%;
    right: var(--space-3);
    gap: clamp(2.4255px, 0.9095625vw, 3.63825px);
    padding: clamp(2.4255px, 0.7882875vw, 3.031875px) clamp(4.244625px, 1.3946625vw, 5.457375px) clamp(2.4255px, 0.7882875vw, 3.031875px) clamp(2.4255px, 0.7882875vw, 3.031875px);
  }

  /* Pedido nuevo: la notificación ya no debe moverse entre slides en
     Mobile tampoco (antes se permitía el micro-shift de "vida" — ver
     .hero-feature-card.is-offset sin scope, más arriba). Mismo criterio
     que ya se aplicó para Desktop (.hero-carousel--desktop ...is-offset):
     se neutraliza el shift devolviendo el mismo top base de acá arriba,
     sin tocar el JS compartido que sigue alternando la clase por igual
     en las dos instancias. */
  .hero-feature-card.is-offset {
    top: 4.87%;
  }

  .hero-feature-card__icon {
    width: clamp(10.308375px, 3.031875vw, 12.1275px);
    height: clamp(10.308375px, 3.031875vw, 12.1275px);
  }

  .hero-feature-card__icon svg {
    width: clamp(5.457375px, 1.576575vw, 6.670125px);
    height: clamp(5.457375px, 1.576575vw, 6.670125px);
  }

  .hero-feature-card__copy strong {
    font-size: clamp(0.31652775rem, 1.2976425vw, 0.3516975rem);
  }

  .hero-feature-card__copy span {
    font-size: clamp(0.2813580rem, 1.1278575vw, 0.31652775rem);
  }

  /* Pedido: "Alguien real te responde al instante 24/7" en un solo
     renglón, esquina inferior DERECHA de la imagen (antes vivía abajo a
     la izquierda, en dos líneas: "24/7" grande arriba, texto chico
     abajo). left+right (no solo right) para que el texto tenga todo el
     ancho disponible de la imagen antes de truncar — justify-content
     lo empuja contra el borde derecho igual. */
  .hero-carousel__stat {
    flex-direction: row;
    align-items: baseline;
    justify-content: flex-end;
    gap: 4px;
    left: var(--space-3);
    right: var(--space-3);
    bottom: 8px;
    max-width: none;
  }

  /* span.hero-carousel__stat-text (no solo .hero-carousel__stat-text):
     necesita más especificidad que la regla genérica sin scope
     ".hero-carousel__stat span" (clase+tipo) de más arriba, o esa
     seguiría ganando el font-size pase lo que pase acá adentro. */
  .hero-carousel__stat span.hero-carousel__stat-text {
    order: 1;
    flex-shrink: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 0.625rem;
    text-shadow: 0 1px 6px rgba(0, 0, 0, 0.65);
  }

  .hero-carousel__stat strong {
    order: 2;
    flex-shrink: 0;
    font-size: 0.8125rem;
  }
}

.hero-carousel__controls {
  position: absolute;
  z-index: 3;
  left: var(--space-5);
  right: var(--space-5);
  bottom: var(--space-4);
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.hero-carousel__arrow {
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  border-radius: 50%;
  background: rgba(10, 7, 16, 0.45);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border: 1px solid rgba(255, 255, 255, 0.18);
  color: var(--text-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--dur-standard) var(--ease-standard), transform var(--dur-micro);
}

.hero-carousel__arrow:hover {
  background: rgba(10, 7, 16, 0.7);
  transform: scale(1.06);
}

.hero-carousel__arrow svg {
  width: 17px;
  height: 17px;
}

/* Ocultas en mobile: mismo criterio que ya usa el resto de los
   carruseles del sitio (.carousel-nav) — el swipe nativo es el control
   principal en touch. Acá además evita que, en el rango de scroll donde
   el carrusel del Hero está en pantalla, la flecha derecha quede debajo
   de los FABs flotantes de contacto (mismo rincón inferior derecho). */
@media (max-width: 639px) {
  .hero-carousel__arrow {
    display: none;
  }
}

.hero-carousel__dots {
  display: flex;
  align-items: center;
  gap: 7px;
}

.hero-carousel__dots button {
  position: relative;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.35);
  transition: background var(--dur-standard) var(--ease-standard), width var(--dur-standard) var(--ease-standard);
}

/* El punto visual mide 7px (20px el activo) a propósito — es la escala
   correcta para no competir con el resto del carrusel. El área táctil
   real es otra cosa: sin esto, tocar un punto puntual en un dedo real
   era casi imposible. Un ::before invisible amplía el hit-area a ~39px
   sin tocar el tamaño ni el espaciado visual de los puntos. */
.hero-carousel__dots button::before {
  content: "";
  position: absolute;
  inset: -16px;
}

.hero-carousel__dots button.is-active {
  width: 20px;
  border-radius: var(--radius-full);
  background: var(--gold-500);
}

@media (prefers-reduced-motion: reduce) {
  .hero-carousel__slide.is-active img {
    animation: none;
    transform: scale(1.03);
  }
}

/* ---------- Beneficios ---------- */
/* Corte visible debajo de la sección en mobile: causa real, no
   superficial — .section-glow tiene overflow:hidden e inset:0 (mide
   exacto lo mismo que su <section>), así que su segundo radial-gradient
   ("at 6% 88%", violeta) queda con alfa aún visible justo en el borde
   inferior de la sección. Con la sección ya muy compacta (grid de
   íconos chico, sin párrafos), ese punto al 88% de la altura cae
   pegado al final real — el gradiente se guillotina en vez de terminar
   de apagarse, y esa línea recta es el "corte". Mismo problema que ya
   se resolvió una vez para Hero→siguiente sección (.section-glow--seam,
   arriba): la solución real es la misma — extender la caja del glow
   más allá del borde de la sección y dejar que el propio radial-
   gradient se apague solo, en vez de cortarlo con overflow:hidden.
   Solo en mobile: en desktop/tablet la sección es mucho más alta (texto
   completo en cada tarjeta) y el gradiente ya se apaga solo mucho antes
   de llegar al borde — no hay corte que corregir ahí. */
/* #beneficios: en mobile ahora es lo primero que sigue al Hero
   directamente (trust-bar-position.js reubica el renglón informativo Y
   las tarjetas de contadores para que vivan DESPUÉS de este bloque —
   ver .trust-bar--after-beneficios / .trust-stats-grid--after-trust-bar
   más abajo). padding-top se deja en el default de .section (32px): es
   el mismo ritmo estándar que separa cualquier otro par de secciones,
   sin necesitar ajuste especial acá. padding-bottom SÍ se overridea acá
   abajo (Tarjetas→Renglón↔Renglón→Contadores necesitan usar el mismo
   valor real — ver ese bloque para la explicación completa). */
@media (max-width: 639px) {
  #beneficios .section-glow--warm {
    inset: -15% 0 -80% 0;
    overflow: visible;
    animation: none;
  }

  /* Tarjetas de Beneficios → Renglón informativo debe medir EXACTAMENTE
     lo mismo que Renglón → Contadores (pedido explícito, no una
     aproximación visual) — Y ambas distancias deben crecer con el alto
     real disponible (dvh), para que el módulo completo (título+8
     tarjetas+renglón+3 contadores) encastre contra el viewport en vez
     de dejar un resto de aire fijo y desproporcionado en pantallas más
     altas. --beneficios-gap-g es una única variable (fuente única de
     verdad, no dos clamp() escritos por separado que podrían
     desincronizarse) que ambos lados consumen tal cual.

     .trust-bar no trae margin propio, solo padding-block:20px + su
     borde de 1px (21px) — simétrico arriba y abajo por diseño. Con ese
     21px ya idéntico en los dos lados, basta con que el ÚNICO valor que
     cada lado controla por separado (este padding-bottom = lado "antes"
     del renglón, y el margin-top de .trust-stats-grid--after-trust-bar
     = lado "después") tomen la misma variable para que la igualdad sea
     real, no numérica por casualidad.

     clamp(12px, 10dvh - 52px, 44px): en el viewport más bajo probado
     (800px) da 12px (33px de aire real con el renglón); en el más alto
     (932px) da 41px (~62px de aire real) — crece con el alto disponible
     en vez de quedar fijo, usando dvh (no vh a secas) para no
     desalinearse cuando la barra de direcciones del navegador se
     esconde/aparece en un dispositivo real.

     Definida en :root (no en #beneficios): .trust-stats-grid, del otro
     lado del renglón, es HERMANA de #beneficios en el DOM (reubicada
     por trust-bar-position.js, no una hija) — una custom property
     declarada en #beneficios no la alcanzaría por herencia. :root es el
     ancestro común más simple que sí llega a los dos. */
  :root {
    --beneficios-gap-g: clamp(12px, 10dvh - 52px, 44px);
  }

  #beneficios {
    padding-bottom: var(--beneficios-gap-g);
  }
}

/* ---------- Beneficios como módulo de una sola pantalla mobile ----------
   Objetivo: Título "Beneficios" → tarjetas → renglón informativo →
   tarjetas de contadores visibles enteros sin scroll extra, contando el
   navbar fijo (80px) y el bottom-nav fijo (61px) que "comen" viewport
   real (mismo criterio que Cómo empezar/Referidos). El renglón y los
   contadores ya NO son hijos de #beneficios (siguen siendo <section
   class="trust-bar"> y <div class="trust-stats-grid"> propios,
   reubicados por trust-bar-position.js como hermanos justo después) —
   por eso el "módulo" completo es #beneficios + esos dos elementos
   juntos, no solo el interior de la sección.

   Medido en vivo en los 5 anchos pedidos (360×800 a 430×932): el tramo
   completo, desde el eyebrow "Beneficios" hasta el borde inferior de la
   última tarjeta de contadores, entra con margen de sobra contra el
   presupuesto visible en todos los casos — ver medición y ajuste final
   junto a .trust-bar--after-beneficios y
   .trust-stats-grid--after-trust-bar, más abajo.

   padding-top de #beneficios (default de .section, 32px) se deja
   intacto — es el ritmo estándar Hero→Beneficios (ver comentario de
   .hero arriba), sin relación con las dos distancias igualadas más
   arriba. padding-bottom SÍ tiene override propio (var(--space-3),
   junto a .section-glow--warm más arriba) para que Tarjetas→Renglón mida
   lo mismo que Renglón→Contadores. Tamaño/padding/gap de las tarjetas
   tampoco se tocan: ya entran con margen de sobra, así que encogerlas
   no sumaría nada y sí les quitaría presencia.

   título→tarjetas, acá abajo, deja de ser un valor fijo (antes 16px) y
   pasa a ser fluido — crece con el alto real disponible, para que el
   módulo completo (título+8 tarjetas+renglón+3 contadores) encastre
   contra el viewport en pantallas más altas en vez de dejar un resto
   fijo de aire vacío después de los contadores. clamp(24px,
   12dvh - 64px, 64px): 24px en el viewport más bajo probado (800px,
   igual de compacto que antes lo dejaba var(--space-4)=16 + un poco
   más de aire), hasta 64px en el más alto (932px). dvh (no vh a secas)
   para que seguir siendo preciso cuando la barra de direcciones del
   navegador se esconde/aparece en un dispositivo real. Scopeado a
   #beneficios para no tocar el margin-bottom compartido que usan Cómo
   empezar/Comparativa/Bonos/Referidos/Servicios. */
@media (max-width: 639px) {
  #beneficios .section-title {
    margin-bottom: clamp(24px, 12dvh - 64px, 64px);
  }
}

.benefits-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-5);
}

/* El color del ícono "Atención humana 24/7" se pidió exclusivamente
   para mobile — config.js es la única fuente para desktop y mobile a
   la vez, así que el cambio a "emerald" les llega a los dos por
   defecto. Esto restaura el coral original en desktop/tablet, mismo
   patrón defensivo que ya se usa para ocultar los 2 beneficios nuevos
   fuera de mobile. */
@media (min-width: 640px) {
  #beneficios .feature-card:nth-child(1) .feature-card__icon {
    color: var(--cat-coral);
  }
}

@media (max-width: 1023px) {
  .benefits-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* Los dos beneficios agregados (Casino+Sportbook, +30 proveedores) solo
   existen para el grid 4×2 de mobile — en desktop/tablet el grid de 6
   tarjetas ya está aprobado y no debe crecer a 8. Los mismos datos
   siguen en el DOM (config.js sigue siendo la única fuente), display:
   none acá simplemente no los pinta fuera de mobile. */
@media (min-width: 640px) {
  .benefits-grid .feature-card:nth-child(7),
  .benefits-grid .feature-card:nth-child(8) {
    display: none;
  }
}

/* Rediseño mobile: de lista de filas (ícono+texto permanente) a grid de
   accesos rápidos solo-ícono, del mismo tamaño visual que los FABs de
   WhatsApp/Telegram (46px) — botones premium, no tarjetas. El texto
   completo (título+descripción) sigue existiendo en el DOM — nunca se
   duplica el dato — pero se oculta visualmente acá; benefit-sheet.js lo
   lee directo de estos mismos nodos para mostrarlo en la tarjeta
   flotante al tocar.

   Ancho del conjunto atado al de .step-card (Onboarding, la sección
   siguiente): 34px = 2×(1px de borde + 16px de padding lateral de
   .onboarding-panel en este mismo breakpoint) — el mismo descuento que
   .step-card le aplica a .container por dentro del panel. width +
   margin-inline:auto acá reproducen ese mismo descuento directamente
   sobre .container, así que el bloque de 4 tarjetas nace exactamente
   tan ancho como .step-card y centrado en el mismo eje — sin depender
   de un número mágico fijo que solo calzara a un ancho de pantalla.
   Columnas 1fr (no un px fijo): reparten ese ancho ya-igualado entre
   las 4 tarjetas, así que el conjunto sigue calzando con .step-card en
   cualquier ancho mobile, no solo en el que se midió. El único valor
   fijo que queda es el gap. */
@media (max-width: 639px) {
  .benefits-grid {
    width: calc(100% - 34px);
    margin-inline: auto;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--space-3);
  }

  /* Mismo componente que .onboarding-panel .step-card, no una tarjeta
     nueva: fondo dorado casi transparente (sin blur), sin borde sólido
     propio (el anillo lo da el ::after degradado-en-máscara de abajo),
     el mismo halo dorado como sombra y la misma pareja hover/active
     (translateY -3px con mouse real, scale(0.985) al tocar) — solo la
     escala cambia, nunca el lenguaje visual. Tamaño, borde, radio,
     sombra y comportamiento intactos frente a la ronda anterior — el
     único cambio acá es padding, para dejarle más lugar al ícono más
     grande pedido en este ajuste.

     height fijo en vez de aspect-ratio:1/1: ancho variable (atado a
     .step-card, más arriba), alto fijo para control total del ritmo
     vertical de la sección — con aspect-ratio ligado al ancho, un ancho
     mayor también hubiera crecido la altura de forma impredecible.
     56px→64px: no es una reducción ni una compresión, es el ajuste
     "mínimo en la altura de tarjetas" que el pedido de encastrar
     Beneficios en una pantalla habilita recién después de agotar
     padding/gap — 8px más de alto por fila (×2 filas) le suma
     presencia real al ícono en vez de ser solo aire vacío en algún
     gap. */
  .benefits-grid .feature-card {
    position: relative;
    width: 100%;
    height: 64px;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 3px;
    background: rgba(255, 215, 0, 0.025);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    border: none;
    border-radius: 16px;
    box-shadow: 0 0 26px rgba(255, 215, 0, 0.05);
    transition: transform var(--dur-standard) var(--ease-standard),
      box-shadow var(--dur-standard) var(--ease-standard);
    -webkit-tap-highlight-color: transparent;
  }

  .benefits-grid .feature-card::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    padding: 1px;
    background: linear-gradient(135deg, rgba(255, 215, 0, 0.55) 0%, rgba(255, 215, 0, 0.14) 45%, rgba(255, 215, 0, 0.34) 100%);
    -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
    -webkit-mask-composite: xor;
    mask-composite: exclude;
    pointer-events: none;
  }

  .benefits-grid .feature-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 0 34px rgba(255, 215, 0, 0.1);
  }

  .benefits-grid .feature-card:hover::after {
    background: linear-gradient(135deg, rgba(255, 215, 0, 0.8) 0%, rgba(255, 215, 0, 0.24) 45%, rgba(255, 215, 0, 0.55) 100%);
  }

  .benefits-grid .feature-card:hover .feature-card__icon {
    transform: none;
  }

  @media (hover: none) {
    .benefits-grid .feature-card:hover {
      transform: none;
      box-shadow: 0 0 26px rgba(255, 215, 0, 0.05);
    }

    .benefits-grid .feature-card:hover::after {
      background: linear-gradient(135deg, rgba(255, 215, 0, 0.55) 0%, rgba(255, 215, 0, 0.14) 45%, rgba(255, 215, 0, 0.34) 100%);
    }

    .benefits-grid .feature-card:active {
      transform: scale(0.985);
    }
  }

  /* Mismo tratamiento visual que la ronda anterior, escalado en la
     misma proporción que la tarjeta (+12%): el ícono sigue ocupando
     exactamente la misma fracción del content box, ni más ni menos
     protagonista que antes — solo más grande en conjunto. */
  .benefits-grid .feature-card__icon {
    width: 47px;
    height: 47px;
  }

  .benefits-grid .feature-card__icon svg {
    width: 23px;
    height: 23px;
  }

  /* El título/descripción quedan fuera de la vista (no display:none —
     benefit-sheet.js necesita poder leer su texto en cualquier momento
     sin depender de un truco de accesibilidad); el ícono es la única
     información visible en la tarjeta, tal como se pidió. */
  .benefits-grid .feature-card__copy {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
  }
}

/* ---------- Cómo empezar (Onboarding, versión compacta mobile) ----------
   Objetivo: la sección completa (título + panel + 3 pasos + cierre)
   entra en una sola pantalla mobile sin scroll, contando el navbar
   fijo (80px) y el bottom-nav fijo (61px) que "comen" viewport real en
   cualquier punto del scroll — no solo que la caja de la sección sea
   más baja que el alto de pantalla. Todo acá está scopeado a
   .onboarding-panel específicamente (nunca .referral-panel, que
   comparte .step-card pero no se toca) para no afectar Referidos.

   1. Eyebrow "Onboarding" fuera: display:none, no clip/visually-hidden
      — no debe quedar hueco reservado ni quedar en el árbol de
      accesibilidad. El h2 "Cómo empezar" pasa a ser el primer elemento
      visible, subiendo solo (su propio margin-top ya no depende de si
      el eyebrow existe).
   2. Panel, título→contenido, pasos y tarjetas bajan un escalón de aire
      cada uno — ninguno solo, la reducción se reparte entre varios
      lugares en vez de vaciar uno solo.
   3. El párrafo de cada paso (el elemento que más alto real consume)
      baja de 16px/1.6 a 14.5px/1.4 — sigue siendo un cuerpo de texto
      estándar y perfectamente legible, no "chico"; el ahorro real viene
      de que a este ancho una o dos líneas dejan de envolver. Ícono/
      número (36px) no se toca: nunca fue el que definía el alto de la
      fila, así que reducirlo no ahorraba nada y sí perdía jerarquía. */
@media (max-width: 639px) {
  .onboarding-panel .eyebrow {
    display: none;
  }

  .onboarding-panel .section-title {
    margin-bottom: var(--space-4);
  }

  .onboarding-panel {
    padding-block: var(--space-5);
  }

  .onboarding-panel .steps {
    gap: var(--space-3);
  }

  .onboarding-panel .step-card {
    padding: var(--space-3);
  }

  .onboarding-panel .step-card__copy {
    gap: 6px;
  }

  .onboarding-panel .step-card h3 {
    font-size: 1.125rem;
  }

  .onboarding-panel .step-card p {
    font-size: 0.90625rem;
    line-height: 1.4;
  }
}

/* Contadores→Cómo empezar: pedido puntual de duplicar el aire que
   había (era 32px, el padding-top estándar de .section — único aporte
   real, .trust-stats-grid no trae margin propio). Se dobla a
   var(--space-8)=64px — el próximo escalón del propio sistema de
   spacing (32→64 es literalmente --space-6→--space-8), no un valor
   arbitrario inventado para esta tarea.

   Se ajusta acá (padding-top de "Cómo empezar"), no tocando
   .trust-stats-grid: el pedido es desplazar "Cómo empezar" hacia abajo,
   no mover los contadores, y este aire adicional es separación ENTRE
   secciones — el cierre de Beneficios sigue siendo exactamente el
   borde inferior de los contadores, sin cambios.

   padding-bottom sigue en 0 (sin tocar): la sección <section
   aria-label="Cómo empezar"> no tiene id propio (solo aria-label) —
   .onboarding-panel es su único hijo real dentro de .container, así
   que ese padding-bottom es lo único que separaba el panel del borde
   inferior de la sección. En 0, todo el aire hacia Servicios sigue
   saliendo únicamente del padding-top de #servicios (32px, sin tocar —
   esa relación no forma parte de este pedido). */
@media (max-width: 639px) {
  [aria-label="Cómo empezar"] {
    padding-top: var(--space-8);
    padding-bottom: 0;
  }
}

/* ---------- Sistema de referidos (versión compacta mobile) ----------
   Mismo objetivo y mismo sistema que Cómo empezar arriba (el mismo
   nivel de densidad/refinamiento, no una copia 1:1 de valores): la
   sección completa entra en una pantalla real (alto de viewport menos
   navbar fijo 80px y bottom-nav fijo 61px) sin scroll. Todo acá está
   scopeado a .referral-panel específicamente — nunca .onboarding-panel,
   que comparte .step-card/.section-title pero ya quedó resuelto en el
   bloque anterior y no se toca.

   Referidos necesitaba más ajuste que Onboarding por dos razones
   reales, no por descuido:
   1. El subtítulo ("Invitá a tus amigos...") es más del doble de largo
      que el de Onboarding — a 18px envolvía en 4-5 líneas. Ese mismo
      texto, sin acortar ni una palabra, baja a 14.5px/1.35: sigue
      siendo un cuerpo de texto legible, y a este ancho entra en menos
      líneas.
   2. .section-title heredaba un max-width recortado (pensado para que
      un título IZQUIERDO no rozara el rincón de los FABs en secciones
      sueltas) que acá no aplica: el título ya está centrado y contenido
      dentro de una tarjeta con su propio padding — ese recorte extra
      solo forzaba más líneas de las necesarias sin aportar nada. Se
      libera a 100% del ancho real disponible dentro del panel.
   3. El CTA ("Quiero mis referidos") es el cierre de la tarjeta — se
      compacta su margen superior pero se mantiene con una altura de
      botón cómoda para el dedo (por encima del mínimo táctil de 44px),
      nunca se saca del flujo ni se reduce su área de toque por debajo
      de eso. */
@media (max-width: 639px) {
  .referral-panel .eyebrow {
    display: none;
  }

  .referral-panel .section-title {
    max-width: 100%;
    margin-bottom: var(--space-3);
  }

  .referral-panel .section-title p {
    font-size: 0.90625rem;
    line-height: 1.35;
  }

  .referral-panel {
    padding-block: 20px;
  }

  .referral-panel .steps {
    gap: 10px;
  }

  .referral-panel .step-card {
    padding: var(--space-3);
  }

  .referral-panel .step-card__copy {
    gap: 6px;
  }

  .referral-panel .step-card h3 {
    font-size: 1.125rem;
  }

  .referral-panel .step-card p {
    font-size: 0.90625rem;
    line-height: 1.4;
  }

  /* Antes el botón heredaba el padding-inline de .btn base (32px,
     pensado para CTAs anchos tipo Hero) + el ícono de WhatsApp (20px)
     + su gap (8px) — sin nada que lo angoste, terminaba ocupando ~81%
     del ancho de la tarjeta ("Ganar con referidos" a 248px sobre una
     tarjeta de 305px), bien lejos de sentirse "basado en su
     contenido". Ya angosto (padding-inline reducido, width:fit-content
     más abajo), sigue quedando muy cerca del FAB de WhatsApp en los
     anchos más chicos (360px: 1.8px de aire, con solape vertical real)
     — el ancho de tarjeta disponible ahí es simplemente insuficiente
     para centrarlo 100% Y despejarlo del FAB a la vez. 28px de
     padding-right (antes eran 40px, sobre un botón mucho más ancho)
     es el mínimo real para despejarlo con aire cómodo en el peor caso
     — deja el botón muy cerca del centro real de la tarjeta (no exacto
     pixel a pixel, pero sin la asimetría marcada de antes) sin
     arriesgar que quede tapado por el FAB. */
  .referral-panel__cta {
    margin-top: var(--space-4);
    padding-right: 20px;
  }

  .referral-panel__cta .btn {
    width: fit-content;
    min-height: 46px;
    padding-block: var(--space-2);
    padding-inline: 16px;
  }
}

/* ---------- Servicios (tarjetas compactas) ----------
   Antes era un editorial "zig-zag" de 3 filas apiladas, cada una casi a
   media pantalla de alto — el peso visual que el usuario pidió reducir.
   Ahora son 3 tarjetas .card en fila, mismo sistema que trust-stats-grid
   (mismo ancho de columna, mismo gap, mismo criterio de "una sola
   composición" en vez de tres bloques inconexos): visual arriba a ancho
   completo de la tarjeta, cuerpo de texto compacto debajo. El glow de
   cursor y el vidrio de fondo ya vienen gratis de .card — acá solo se
   define la distribución interna. */
.services-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-5);
  width: 100%;
}

@media (max-width: 900px) {
  .services-grid {
    grid-template-columns: 1fr;
  }
}

.service-card {
  display: flex;
  flex-direction: column;
  padding: 0;
}

/* Wrapper puramente estructural: existe para que la microanimación de
   "tarjeta activa" (carousel.js, ver más abajo en mobile) tenga un
   elemento propio para transformar que NO sea .service-card. .service-
   card es el que trae scroll-snap-align en mobile — transformarlo a él
   directamente (como antes) mezclaba una animación cosmética con la
   geometría que el motor de scroll-snap usa para decidir dónde
   reposar, y eso es justamente lo que producía el bug de este carrusel
   (ver comentario junto a scroll-snap-align más abajo). Mismo layout
   visual de siempre (flex column, se estira al alto de la tarjeta):
   cero cambio de composición en Desktop ni Mobile, solo se agrega este
   nivel intermedio en el DOM. */
.service-card__inner {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-width: 0;
}

.service-card__visual {
  /* width:100% explícito: sin esto, un grid item que contiene un <img> con
     width/height intrínsecos (para el aspect-ratio) puede quedar ~10px más
     angosto que el track en mobile — el img "tira" del sizing del item en
     vez de simplemente estirarse al 100% del track de 1fr. */
  width: 100%;
  aspect-ratio: 16 / 10;
  position: relative;
  overflow: hidden;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  flex-shrink: 0;
}

.service-card__visual img,
.service-card__visual video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.service-card__visual--photo img,
.service-card__visual--video video {
  /* Foto/video real llevado a la paleta de marca: se le resta brillo y
     saturación para que conviva con el resto de la landing (tonos
     violeta/negro) en vez de leerse como un recurso de stock "pegado" sobre
     un diseño oscuro. Sin hue-rotate: en piel se nota enseguida y deja de
     verse realista — el enfriado hacia violeta lo aporta el overlay de
     ::after, no un filtro de color sobre la imagen. */
  filter: saturate(0.86) contrast(1.05) brightness(0.92);
}

/* La ilustración SVG ya nace con la paleta y la viñeta incorporadas (es
   arte vectorial hecho a medida, no una foto de stock) — no necesita el
   filtro de "enfriado" ni el overlay ::after de las variantes --photo/--video. */

.service-card__visual--photo::after,
.service-card__visual--video::after {
  content: "";
  position: absolute;
  inset: 0;
  /* Vela violeta desde los bordes (deja libre el centro-derecha, donde cae
     el rostro/headset) + una base oscura abajo para que el borde inferior
     se funda con la tarjeta en vez de cortar en seco. Mismo lenguaje de
     overlay que .hero-carousel__scrim, para que se sienta la misma mano. */
  background: radial-gradient(120% 100% at 68% 38%, transparent 35%, rgba(23, 0, 34, 0.4) 100%),
    linear-gradient(to top, rgba(10, 7, 16, 0.45) 0%, transparent 30%);
  pointer-events: none;
}

.service-card__video {
  background: var(--purple-950);
}

.service-card__body {
  padding: var(--space-5);
  display: flex;
  flex-direction: column;
  flex: 1;
}

.service-card__body h3 {
  font-size: 1.125rem;
  margin-bottom: var(--space-2);
}

.service-card__body p {
  font-size: var(--fs-caption);
  color: var(--text-secondary);
  margin-bottom: var(--space-4);
  /* flex:1 empuja el CTA al mismo renglón final en las tres tarjetas, sin
     importar que un párrafo tenga una línea más que otro — es lo que hace
     que se lean como un set parejo en vez de tres alturas sueltas. */
  flex: 1;
}

.service-card__body .btn {
  align-self: flex-start;
}

/* ---------- Sistema de interacción compartido ----------
   .card ya aporta la elevación + glow de vidrio al pasar el cursor
   (components.css) — acá solo se suma el zoom muy sutil de la imagen,
   propio de esta tarjeta. El video no lo necesita porque ya tiene
   movimiento propio; su "personalidad" es distinta pero pertenece al
   mismo sistema (mismo timing, misma curva). */
.service-card__visual--photo img {
  transition: transform 700ms var(--ease-out-premium);
}

.service-card:hover .service-card__visual--photo img {
  /* object-fit:cover + overflow:hidden en el contenedor: el 4.5% de más
     se recorta limpio, sin dejar franjas ni desplazar el encuadre. */
  transform: scale(1.045);
}

@media (prefers-reduced-motion: reduce) {
  .service-card__visual--photo img {
    transition: none;
  }
  .service-card:hover .service-card__visual--photo img {
    transform: none;
  }
}

/* Rediseño mobile: de lista de filas (miniatura+texto apilados ×3) a
   carrusel horizontal con scroll-snap — una sola tarjeta protagonista
   a la vez, con solo un peek de 16px de la siguiente asomando del lado
   derecho (pedido puntual, ver .service-card más abajo). Mismo
   componente .card, mismo contenido/imágenes/CTA de siempre; lo único
   que cambia es la composición y cómo se recorre.

   .services-grid pasa de grid a flex+scroll-snap (mismo mecanismo ya
   probado en .carousel-track). El margen simétrico sale de padding-
   inline REAL en el track (no scroll-padding): scroll-padding solo
   ajusta el punto de snap DESPUÉS de un gesto, pero con
   scroll-snap-type:mandatory el navegador no permite que el reposo
   inicial (scrollLeft:0) caiga en un punto "inválido" como -16px, así
   que la primera tarjeta quedaba pegada al borde izquierdo sin margen
   hasta el primer swipe — un padding real sí reserva ese espacio como
   contenido scrolleable de verdad, así que hay margen simétrico desde
   el primer frame, en la primera tarjeta, la del medio y la última,
   sin ninguna corrección por JS. El ancho de la tarjeta (ver
   .service-card) se mide contra ese mismo content-box ya angosto por
   el padding — antes llenaba el 100% (cero peek posible en ningún
   punto de reposo, pedido explícito de la ronda que introdujo el
   carrusel); ahora se le resta el ancho de un gap a propósito para que
   sí asome un borde angosto de la vecina. */
@media (max-width: 639px) {
  /* El encabezado de Servicios usaba .section-title "plano" (eje
     izquierdo) mientras que el resto de las secciones con esta misma
     forma — eyebrow + h2 + subtítulo, seguido de tarjetas/carrusel
     (Beneficios, Cómo empezar, Comparativa, Bonos, Referidos) — usan
     .section-title--center. En mobile, con Beneficios (centrado) arriba
     y Comparativa (centrado) abajo, el título de Servicios quedaba como
     el único desalineado del eje vertical común de la página. No es un
     bug de CSS (título y carrusel ya alinean exacto contra el mismo
     padding de .container) — es un criterio de composición: se replica
     acá, escopeado a Servicios y solo en mobile, el mismo mecanismo que
     ya usa .section-title--center (margin-inline:auto + text-align:
     center + eyebrow centrado), sin tocar la clase compartida ni
     Desktop. */
  #servicios .section-title {
    margin-inline: auto;
    text-align: center;
  }

  #servicios .section-title .eyebrow {
    justify-content: center;
  }

  #servicios .section-title p {
    margin-inline: auto;
  }

  .services-grid {
    position: relative;
    display: flex;
    grid-template-columns: none;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    scroll-padding-inline: var(--space-4);
    gap: var(--space-4);
    padding-block: 2px var(--space-2);
    padding-inline: var(--space-4);
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }

  .services-grid::-webkit-scrollbar {
    display: none;
  }

  /* Señal secundaria de "esto continúa hacia el costado" — refuerzo
     puramente visual del gesto de carousel-peek-hint.js (que tiene la
     prioridad real). position:absolute (no un hijo real ni sticky
     dentro del flex): queda fuera del flujo del carrusel — cero impacto
     en gap/ancho de tarjeta/cantidad de flex items, y al no ser parte
     del contenido que scrollea, se queda pegado al borde derecho del
     viewport visible sin moverse con el swipe (posicionado contra
     .services-grid, que ya es position:relative arriba). Estático
     (sin animación propia) a propósito: así funciona igual bajo
     prefers-reduced-motion (que sí apaga la microanimación de
     carousel-peek-hint.js, mismo criterio pedido — "mantener
     únicamente un indicador estático muy discreto"), sin necesitar una
     regla aparte para ese caso. pointer-events:none: nunca interfiere
     con el swipe real ni con el tap sobre la tarjeta de abajo. */
  .services-grid::after {
    content: "";
    position: absolute;
    top: 0;
    right: 0;
    bottom: var(--space-2);
    width: 32px;
    background: linear-gradient(to right, transparent, rgba(10, 7, 16, 0.5));
    pointer-events: none;
  }

  /* width: calc(100% - 16px), no 100%: pedido puntual de "peek" — que
     asome apenas el borde izquierdo de la tarjeta siguiente junto a la
     protagonista. Antes la tarjeta llenaba el 100% del content-box del
     track (ver comentario grande más arriba: "nunca sobra ancho para
     que asome la vecina", cierto en su momento, ahora se revierte a
     propósito) — con 100% menos exactamente el ancho del gap
     (var(--space-4)=16px, mismo valor ya usado entre tarjetas), al
     final de cada tarjeta activa queda visible una franja de 16px de
     la siguiente antes del borde derecho del viewport visible del
     carrusel: 16px de gap (que ya se veía) + 16px de la tarjeta que
     sigue. Expresado como % del propio content-box del flex (no un
     calc con 100vw): se recalcula solo contra el ancho real disponible
     en cualquier viewport, sin depender de duplicar el padding del
     .container ni el del track acá — mismo mecanismo, ya responsive
     por definición, no hace falta un calc(100vw - ...) aparte. Aplica
     igual a las 3 tarjetas (no solo la primera), así que el patrón se
     repite después de cada swipe. scroll-snap-align:start sigue
     alineando el borde IZQUIERDO de cada tarjeta contra el punto de
     snap — la que se recorta 16px es siempre la del extremo derecho
     del viewport visible, nunca la protagonista. */
  .services-grid .service-card {
    scroll-snap-align: start;
    flex: 0 0 auto;
    width: calc(100% - 16px);
    flex-direction: column;
    align-items: stretch;
    transition: box-shadow var(--dur-standard) var(--ease-standard);
  }

  /* La microanimación de "tarjeta activa" (elevación + escala + glow)
     NO vive acá — cinema.js (GSAP) deja cada tarjeta con su propio
     transform inline al terminar la entrada, y un inline style siempre
     gana contra cualquier regla de hoja de estilos sin importar
     especificidad. carousel.js escribe el transform inline directo
     sobre .service-card__inner (el box-shadow sí queda en
     .service-card — ver comentario en carousel.js), así que la
     transición de acá + la de abajo alcanzan para que ambos cambios se
     sientan animados — nada más que agregar en CSS. La transition de
     transform vive en .service-card__inner, no en .service-card,
     porque es ahí donde ese inline style realmente se escribe (ver
     scroll-snap-align arriba: .service-card es el snap target y nunca
     recibe transform, por diseño). */
  /* Mismo timing que .hero-feature-card (480ms, --ease-out-premium) y que
     .bonus-card__inner: mismo "sistema" de motion design del Hero
     aplicado a un cambio de estado discreto (tarjeta activa/inactiva),
     no al crossfade largo de 1.1s que usa el propio slide del Hero (ese
     es para una transición de fondo a pantalla completa; acá es una
     tarjeta chica que cambia de estado con cada swipe, más seguido). La
     tarjeta inactiva se atenúa (opacity:0.75, igual que Bonos) y vuelve
     a opacity:1 al activarse — el lift/scale ya existente (JS,
     carousel.js, inline en este mismo elemento) queda intacto, solo se
     le agrega la variación de opacidad y se empareja su duración. */
  .services-grid .service-card__inner {
    opacity: 0.75;
    transition: transform 480ms var(--ease-out-premium), opacity 480ms var(--ease-out-premium);
  }

  .services-grid .service-card.is-active .service-card__inner {
    opacity: 1;
  }

  /* 2/1 → 7/4: mismo ancho de tarjeta (311px), imagen ~22px más alta
     (156.5px → 177.7px) — la proporción "un poco más vertical" pedida.
     El ancho nunca cambia (no hay 2do valor en aspect-ratio ligado al
     ancho salvo la propia proporción), así que esto es 100% un cambio
     de alto, sin tocar layout horizontal. */
  .services-grid .service-card__visual {
    width: 100%;
    aspect-ratio: 7 / 4;
    align-self: auto;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
    border-right: none;
    flex-shrink: 0;
  }

  /* La mancha oscura en la parte inferior de la foto NO es el
     box-shadow de la tarjeta (ese es el elev-float que la hace flotar,
     y se mantiene intacto) — viene del ::after de .service-card__visual
     --photo/--video (sections.css base): un linear-gradient(to top, ...)
     que oscurece el 30% inferior de la imagen a propósito, pensado para
     "fundir" el borde inferior con la tarjeta en la proporción 16:10 de
     Desktop. Con la imagen mobile ahora en 2:1 (más baja), ese mismo
     30% de oscurecido ocupa proporcionalmente mucho más alto y se lee
     como una sombra pesada — no hace falta para legibilidad (acá el
     texto vive debajo de la imagen, nunca encima). Se quita la franja
     inferior; el velo radial (violeta, en los bordes) queda pero más
     suave, para conservar la identidad sin la mancha. */
  .services-grid .service-card__visual--photo::after,
  .services-grid .service-card__visual--video::after {
    background: radial-gradient(120% 100% at 68% 38%, transparent 45%, rgba(23, 0, 34, 0.2) 100%);
  }

  .services-grid .service-card__visual--photo img,
  .services-grid .service-card__visual--video video {
    filter: saturate(0.94) contrast(1.03) brightness(1);
  }

  /* Ken Burns adaptado del Hero (mismo mecanismo: @keyframes con la
     misma duración/easing — 7s, ease-out — que hero-kenburns, ver
     .hero-carousel__slide.is-active img más arriba), no una animación
     nueva "inspirada" en el Hero. Escala reducida a propósito (1.03→1.07
     en vez de 1.03→1.12): acá la tarjeta es chica y el usuario la ve
     unos segundos mientras desliza, no varios segundos fijos como el
     slide del Hero — el mismo desplazamiento hubiera invadido texto e
     íconos superpuestos si los tuviera, y se hubiera sentido "demasiado
     fuerte" en un formato tan compacto. La base en scale(1.03) (no 1)
     evita el salto brusco al arrancar el keyframe, igual que en el
     Hero. overflow:hidden en .service-card__visual (ya existente)
     recorta el excedente sin desbordar la tarjeta. Solo la foto, nunca
     el video (mismo criterio que el hover de Desktop, más arriba en
     este archivo: el video ya trae su propio movimiento). */
  .services-grid .service-card__visual--photo img {
    transform: scale(1.03);
  }

  .services-grid .service-card.is-active .service-card__visual--photo img {
    animation: service-card-kenburns 7s ease-out forwards;
  }

  @keyframes service-card-kenburns {
    from {
      transform: scale(1.03);
    }
    to {
      transform: scale(1.07);
    }
  }

  .services-grid .service-card__body {
    padding: var(--space-3) var(--space-4);
  }

  .services-grid .service-card__body h3 {
    font-size: 1.0625rem;
  }

  /* Recorte a 2 líneas (elipsis) en vez de dejar que cada tarjeta tenga
     una altura distinta según lo larga que sea su descripción — con
     las tres a 2 líneas fijas, el carrusel entero queda a una sola
     altura consistente, más baja que la imagen 16:9 + texto libre de
     antes. El texto completo sigue disponible: nada se pierde, solo se
     recorta visualmente en la tarjeta compacta. */
  .services-grid .service-card__body p {
    margin-bottom: var(--space-3);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

  /* De pill outline a link liviano: la tarjeta entera ya es tappable
     (mismo <a>/href de siempre, cero cambio funcional) — mantener el
     chrome completo de botón acá solo suma ruido repetido 3 veces en la
     misma pantalla. Un link con flecha es el mismo lenguaje que
     "Learn more →" en Stripe/Linear: pesa menos, sigue siendo un CTA
     inequívoco. */
  .services-grid .service-card__body .btn {
    align-self: flex-start;
    min-height: 0;
    padding: 0;
    background: none;
    border: none;
    box-shadow: none;
    border-radius: 0;
    color: var(--gold-400);
    font-size: 0.875rem;
    gap: 4px;
  }

  .services-grid .service-card__body .btn::after {
    content: "→";
    transition: transform var(--dur-micro) var(--ease-standard);
  }

  .services-grid .service-card__body .btn:active {
    transform: none;
  }

  .services-grid .service-card__body .btn:active::after {
    transform: translateX(3px);
  }

  /* Indicador discreto: puntos, no flechas — la interacción táctil
     (swipe) es la protagonista, esto solo confirma "estás acá". */
  .carousel-dots {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 6px;
    margin-top: var(--space-2);
  }
}

@media (max-width: 639px) and (prefers-reduced-motion: reduce) {
  .services-grid {
    scroll-behavior: auto;
  }

  .services-grid .service-card,
  .services-grid .service-card__inner {
    transition: none;
  }

  /* Mismo criterio que .hero-carousel__slide.is-active img (ver arriba):
     apaga el keyframe de Ken Burns y deja la imagen fija en su escala
     base, sin el drift continuo. */
  .services-grid .service-card__visual--photo img {
    animation: none;
    transform: scale(1.03);
  }
}

/* ---------- FAQ layout de 2 columnas ----------
   Simétrico arriba y abajo con el valor estándar de .section (CTA final
   también usa .section sin overrides, así que su padding-top ya era
   estándar). Con el padding-top de acá ya devuelto al valor estándar
   (ronda anterior), dejar el padding-bottom en el valor reducido hacía
   que el aire hacia CTA final (128px) fuera bastante menor que el aire
   hacia Testimonios (192px) — el bloque de FAQ quedaba visualmente más
   pegado al banner de abajo que a Testimonios arriba, no centrado entre
   ambos. Un padding-block parejo (sin overrides de top/bottom por
   separado) dejar a FAQ con exactamente el mismo aire a los dos lados,
   en los tres breakpoints. */
#faq {
  padding-block: var(--space-9);
}

@media (max-width: 1023px) {
  #faq {
    padding-block: var(--space-8);
  }
}

@media (max-width: 639px) {
  #faq {
    padding-block: var(--space-6);
  }
}

.faq-layout {
  display: grid;
  grid-template-columns: 4fr 8fr;
  gap: var(--space-6);
}

@media (max-width: 900px) {
  .faq-layout {
    grid-template-columns: 1fr;
  }
}

.faq-layout .section-title {
  margin-bottom: 0;
  position: sticky;
  top: 104px;
  align-self: start;
}

@media (max-width: 900px) {
  .faq-layout .section-title {
    position: static;
  }
}

.faq-list {
  /* Antes tenía un max-width:720px fijo que la dejaba ~80px más corta
     que su columna real (8fr de .faq-layout) — el símbolo "+" terminaba
     bien adentro del borde derecho que marca el carrusel de Testimonios
     arriba. Sin el tope, ocupa el 100% de su columna (comportamiento por
     defecto de un bloque en grid) y ambos bordes derechos coinciden. */
  width: 100%;
}

/* Preguntas: mismo acordeón, mismo comportamiento — solo se acorta el
   padding vertical de cada fila (y el de la respuesta al abrirse) para
   que las 5 preguntas ocupen menos alto en conjunto. Scopeado a
   .faq-list porque el acordeón es un componente compartido en
   components.css, aunque hoy solo se use acá. */
.faq-list .accordion__trigger {
  padding-block: var(--space-4);
}

.faq-list .accordion__panel p {
  padding-bottom: var(--space-4);
}

/* ---------- Comparativa: CTA de cierre ---------- */
.comparison__cta {
  justify-content: center;
  margin-top: var(--space-7);
}

@media (max-width: 639px) {
  .comparison__cta {
    margin-top: var(--space-4);
  }
}

/* Comparativa mobile: "pantalla completa" (mismo lenguaje que Cómo
   empezar / Referidos) — título → toggle → una columna → CTA "Atención
   VIP" visible entero, con aire después. padding-block del section baja
   de 32px (var(--space-6), heredado de .section) a 20px; el título
   suma otro recorte propio (margin-bottom + subtítulo más compacto)
   sin tocar la regla compartida .section-title (que usan el resto de
   las secciones) — todo escopeado a #comparativa para que nada de esto
   se filtre a otra sección. */
@media (max-width: 639px) {
  #comparativa {
    padding-block: 20px;
  }

  /* display:none (no visibility:hidden/opacity:0): saca al eyebrow del
     flujo por completo, así .section-title no reserva ningún alto para
     él y la tarjeta sube a ocupar ese lugar en vez de dejar un hueco. */
  #comparativa .eyebrow {
    display: none;
  }

  #comparativa .section-title {
    margin-bottom: var(--space-4);
  }

  #comparativa .section-title p:not(.eyebrow) {
    font-size: 0.875rem;
    line-height: 1.45;
  }
}

/* ---------- Bonos ---------- */
.bonuses-grid {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
  gap: var(--space-5);
}

/* Bonos mobile: "pantalla completa" (mismo lenguaje que Cómo empezar /
   Referidos / Comparativa) — título → carrusel → indicador → cierre,
   todo dentro del viewport real. El subtítulo es el texto más largo de
   toda la sección (97 caracteres, 4 líneas a 18px) así que es la
   primera palanca: 14px + line-height más ceñido, igual que Comparativa. */
@media (max-width: 639px) {
  #bonos {
    padding-block: 20px;
  }

  #bonos .section-title {
    margin-bottom: var(--space-4);
  }

  #bonos .section-title p:not(.eyebrow) {
    font-size: 0.875rem;
    line-height: 1.45;
  }
}

@media (max-width: 900px) {
  .bonuses-grid {
    grid-template-columns: 1fr;
  }
}

.bonuses-grid .bonus-card {
  width: 100%;
}

/* Bonos mobile: de grid apilado (3 tarjetas, scroll vertical pasivo) a
   carrusel horizontal de 1 tarjeta por vez — mismo mecanismo ya probado
   en Servicios (.services-grid): flex + scroll-snap-type:x mandatory +
   padding-inline REAL en el track (no scroll-padding) para que el
   margen quede simétrico desde el primer frame, en la primera tarjeta,
   la del medio y la última, sin corrección por JS. El ancho de la
   tarjeta (ver .bonus-card más abajo) se mide contra ese content-box ya
   angosto por el padding — mismo peek de 16px que ya tiene Servicios
   (pedido explícito: "misma lógica visual de descubrimiento"), no el
   100% que dejaba a la vecina completamente oculta. */
@media (max-width: 639px) {
  .bonuses-grid {
    position: relative;
    display: flex;
    grid-template-columns: none;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    gap: var(--space-4);
    padding-inline: var(--space-4);
    /* scroll-padding-inline (mismo valor que el padding-inline real de
       arriba) es lo que hace que el reposo matemático de
       scroll-snap-align:start caiga en scrollLeft:0 para la primera
       tarjeta. Sin esto, el navegador trata el propio borde de esa
       tarjeta (que empieza en 16px por el padding) como el punto de
       snap válido más cercano a 0, y "corrige" ahí — dejando el
       padding izquierdo scrolleado fuera de vista y un margen
       asimétrico (0 a la izquierda, 32px a la derecha). Confirmado
       comparando contra Servicios, que sí tiene esta propiedad. */
    scroll-padding-inline: var(--space-4);
    padding-block: 2px var(--space-2);
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }

  .bonuses-grid::-webkit-scrollbar {
    display: none;
  }

  /* Mismo indicador secundario que Servicios (.services-grid::after,
     ver ahí el comentario completo con el razonamiento) — mismo ancho,
     mismo gradiente, misma técnica (position:absolute fuera del flujo
     del carrusel, position:relative en el track como ancla). Pedido
     explícito de esta ronda: idéntico lenguaje visual entre los dos
     carruseles, valores copiados literalmente, no reinventados. */
  .bonuses-grid::after {
    content: "";
    position: absolute;
    top: 0;
    right: 0;
    bottom: var(--space-2);
    width: 32px;
    background: linear-gradient(to right, transparent, rgba(10, 7, 16, 0.5));
    pointer-events: none;
  }

  /* width: calc(100% - 16px), no 100%: mismo criterio y mismo valor
     (var(--space-4)=16px, el propio gap) que .service-card en Servicios
     — al content-box del track le sobra exactamente el ancho de un gap,
     así que después de la tarjeta activa asoma una franja de 16px de la
     siguiente antes del borde derecho del viewport visible del
     carrusel. % del propio content-box flex (no un calc con 100vw):
     responsive en cualquier ancho sin duplicar el padding de
     .container ni el del track acá. Aplica a las 3 tarjetas por igual,
     así que el patrón se repite después de cada swipe. */
  .bonuses-grid .bonus-card {
    scroll-snap-align: start;
    flex: 0 0 auto;
    width: calc(100% - 16px);
  }
}

/* Tarjeta de bono → formato portrait dedicado a Mobile (antes era una
   fila compacta 2 columnas, pensada para apilarse sin ocupar tanto
   alto; ahora que cada tarjeta ocupa su propia "página" del carrusel,
   ese motivo para achatarla desaparece). Vuelve a la misma columna
   vertical que ya usa Desktop (badge → destacado → título → texto →
   CTA, ver regla base .bonus-card más arriba) pero centrada y con aire
   propio de tarjeta protagonista — mismos textos, colores, badge,
   glow, borde dorado del destacado: solo cambia la composición
   interna al formato vertical. */
/* Sistema cromático único para las 3 tarjetas: antes solo
   .bonus-card--featured (la primera) tenía el degradé dorado + borde
   luminoso — al deslizar, la 2 y la 3 se sentían "otro componente"
   (fondo plano, borde blanco genérico). Ahora la base .bonus-card ya
   trae ese mismo tratamiento — --featured queda como no-op en este
   breakpoint (mismos valores, no se quita la clase ni se toca
   Desktop). El glow es el mismo lenguaje "vidrio + halo dorado muy
   tenue" que ya usa la tarjeta destacada en Desktop (el degradé de
   fondo + este box-shadow extra), no el glow de cursor (ese es
   interactivo, solo con mouse, no aplica en touch). */
@media (max-width: 639px) {
  .bonus-card {
    justify-content: center;
    padding: 28px 24px;
    min-height: 360px;
    background: linear-gradient(160deg, rgba(255, 215, 0, 0.1), var(--bg-surface));
    border: 1px solid rgba(255, 215, 0, 0.3);
    box-shadow: var(--elev-float), 0 0 28px rgba(255, 215, 0, 0.1);
    /* Mismo lenguaje de movimiento que el crossfade del Hero
       (.hero-carousel__slide: opacity + var(--ease-out-premium)), no
       una animación nueva inspirada en él — mismo timing/easing
       (480ms, el que ya usa .hero-feature-card para su propio
       entrada/salida discreta al cambiar de diapositiva, el análogo
       más cercano a este toggle activa/inactiva por swipe) en vez del
       genérico var(--dur-standard)/var(--ease-standard) que .card
       aporta por defecto — pisa esas 4 propiedades con la misma lista
       y mismo timing. La opacity "recede cuando no está activa" (ver
       .is-active en .bonus-card__inner más abajo, no acá) vive en el
       wrapper interno a propósito: cinema.js anima la entrada de esta
       tarjeta con autoAlpha (opacity+visibility) y deja ese valor como
       estilo inline al terminar — un inline SIEMPRE le gana a esta
       regla de clase, así que si el atenuado viviera acá quedaría
       pisado por ese inline apenas cargara la página. */
    transition: transform 480ms var(--ease-out-premium),
      background 480ms var(--ease-out-premium),
      border-color 480ms var(--ease-out-premium),
      box-shadow 480ms var(--ease-out-premium);
  }

  /* align-items/text-align/gap viven en el wrapper interno
     (.bonus-card__inner), no en .bonus-card: es el wrapper el que
     realmente arma la columna badge→destacado→título→texto→CTA (ver
     comentario junto a .bonus-card__inner en components.css).

     transform acá (el lift+scale que carousel.js escribe inline al
     activarse, ver updateActive() — nunca en .bonus-card, mismo motivo
     que ya evita mezclar esa animación cosmética con la geometría que
     usa scroll-snap) no tenía transición propia — cambiaba de golpe,
     sin el "settle" del Hero. Mismo timing/easing que .bonus-card
     arriba: la sensación de profundidad viaja en CÓMO se mueve (settle
     lento, arranque rápido — la curva de --ease-out-premium), no en un
     zoom tipo Ken Burns aplicado a texto/botón, que ahí sí perdería
     legibilidad.

     opacity (la tarjeta inactiva "recede", igual que un slide del Hero
     al perder el foco — atenuada, nunca invisible: acá conviven las 3
     a la vez, a diferencia del Hero que solo muestra una) vive acá y
     no en .bonus-card por la razón de arriba: este wrapper interno
     nunca recibe el autoAlpha de cinema.js, así que no hay inline con
     el que competir. */
  .bonus-card__inner {
    align-items: center;
    text-align: center;
    gap: 12px;
    opacity: 0.75;
    transition: transform 480ms var(--ease-out-premium),
      opacity 480ms var(--ease-out-premium);
  }

  .bonus-card.is-active .bonus-card__inner {
    opacity: 1;
  }

  .bonus-card__highlight {
    font-size: 2.375rem;
  }

  .bonus-card h3 {
    font-size: 1.0625rem;
  }

  .bonus-card p {
    font-size: 0.875rem;
    line-height: 1.4;
  }

  /* CTA: de outline plano (borde blanco 25%, fondo transparente) a un
     "vidrio dorado" con borde luminoso fino + glow muy suave + sombra
     de asentamiento — mismo lenguaje que el halo de la tarjeta, sin
     saturar. Nunca se toca .btn-ghost base (Hero "Clientes VIP" y otros
     CTA fantasma del sitio quedan exactamente igual): todo escopeado a
     .bonus-card .btn. */
  .bonus-card .btn {
    margin-top: 4px;
    width: 100%;
    min-height: 46px;
    padding-block: var(--space-2);
    background: linear-gradient(160deg, rgba(255, 215, 0, 0.16), rgba(255, 215, 0, 0.04));
    border-color: rgba(255, 215, 0, 0.4);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.28), 0 0 18px rgba(255, 215, 0, 0.1);
  }

  .bonus-card .btn:active {
    background: linear-gradient(160deg, rgba(255, 215, 0, 0.22), rgba(255, 215, 0, 0.06));
  }
}

/* Mismo criterio que .services-grid (ver más arriba): con
   prefers-reduced-motion, el estado activa/inactiva sigue cambiando
   (las 3 tarjetas siguen legibles, el snap sigue funcionando) pero sin
   animarlo — sin esto, el lift/scale/opacity nuevos de arriba
   quedarían animando igual, ignorando la preferencia del usuario. */
@media (max-width: 639px) and (prefers-reduced-motion: reduce) {
  .bonuses-grid {
    scroll-behavior: auto;
  }

  .bonuses-grid .bonus-card,
  .bonuses-grid .bonus-card__inner {
    transition: none;
  }
}

/* En touch, :hover puede quedar "pegado" tras un tap hasta el próximo
   toque en otro lado (mismo caso que ya resuelve components.css para
   .card/.bonus-card en general). Sin este ajuste, ese hover pegado
   revertía el borde/glow dorado nuevo de arriba al blanco plano
   genérico que .bonus-card:hover trae para hover:none — un parpadeo
   visible que rompía justo la coherencia cromática que pide esta
   tarea. Reafirma acá el mismo tratamiento dorado como el estado
   "pegado" correcto, solo en mobile. */
@media (hover: none) and (max-width: 639px) {
  .bonus-card:hover {
    border-color: rgba(255, 215, 0, 0.3);
    box-shadow: var(--elev-float), 0 0 28px rgba(255, 215, 0, 0.1);
  }
}

/* ---------- Testimonios (versión compacta) ----------
   Solo espaciado y tamaño de tarjeta — el diseño/color/animación de
   .testimonial-card y .carousel no se tocan, están definidos en
   components.css y son compartidos con otros carruseles. Todo acá está
   scopeado a .section--testimonials / .carousel--testimonials para no
   afectar Mejores Juegos ni Sportbook.

   Cuarta vuelta: padding-top vuelve al valor estándar de .section en
   los tres breakpoints (antes se quedaba reducido a propósito "para
   mantener la costura con Sportbook igual que siempre" — pero esa
   costura reducida ERA el problema: Sportbook→Testimonios quedaba a un
   tercio del ritmo que separa al resto de los pares de secciones, 64px
   vs 192px en desktop. padding-bottom de Sportbook sube en la misma
   proporción más abajo (#juegos, #sportbook) — entre los dos
   reconstruyen el ritmo estándar sin tocar Juegos ni el resto de
   Testimonios. */
.section--testimonials {
  padding-top: var(--space-9);
  padding-bottom: var(--space-9);
}

@media (max-width: 1023px) {
  .section--testimonials {
    padding-top: var(--space-8);
    padding-bottom: var(--space-8);
  }
}

@media (max-width: 639px) {
  .section--testimonials {
    padding-top: var(--space-4);
    padding-bottom: var(--space-6);
  }
}

/* ---------- Mejores Juegos + Sportbook (composición compacta) ----------
   Mismo patrón que .section--testimonials arriba, scopeado por id para
   no tocar el resto de la landing: la tarjeta de deportes ya era la más
   angosta de las dos filas, así que igualar el tamaño de .media-card a
   esa proporción (components.css) más este padding-block reducido es lo
   que permite que "Mejores juegos" y "Sportbook profesional" — dos
   secciones adyacentes, mismo tipo de carrusel — quepan juntas en una
   pantalla de escritorio típica sin perder aire entre título y
   tarjetas. */
#juegos,
#sportbook {
  padding-block: var(--space-6);
}

/* La costura entre el segundo carrusel (hoy Mejores Juegos, después de
   intercambiar el orden con Sportbook) y Testimonios heredaba el
   padding-block reducido de arriba (pensado para que Juegos+Sportbook
   quepan juntos en una pantalla de escritorio típica) en sus dos
   lados, dejando solo un tercio del ritmo estándar entre secciones
   (64px vs 192px en desktop). Solo el padding-bottom de quien quede
   inmediatamente antes de Testimonios sube al valor estándar de
   .section en cada breakpoint — junto con el padding-top de
   .section--testimonials (arriba), reconstruye ese mismo ritmo. La
   costura entre los dos carruseles (Sportbook→Juegos ahora, no
   reportada como problema) no se toca en ningún breakpoint — por eso
   este override vive en el id que en cada momento sea el segundo de
   los dos, no en un id fijo. */
#juegos {
  padding-bottom: var(--space-9);
}

/* Los 2 tracks mobile (data-games-track-row1/row2) existen en el DOM en
   todos los anchos (los puebla render.js sin condicional de viewport),
   pero solo deben verse en mobile — ahí, más abajo, el track original
   de 1 fila (data-games-track) es el que se oculta. Sin este display:none
   por defecto, en Desktop/Tablet se verían las 24 tarjetas duplicadas
   apiladas en bloque, sin estilo de carrusel. */
#juegos .games-mobile-rows {
  display: none;
}

@media (max-width: 1023px) {
  #juegos,
  #sportbook {
    padding-block: var(--space-5);
  }

  #juegos {
    padding-bottom: var(--space-8);
  }
}

@media (max-width: 639px) {
  #juegos,
  #sportbook {
    padding-block: var(--space-4);
  }

  /* En mobile el ritmo estándar es 64px (32+32) — sumado a los 16px de
     Testimonios (sin tocar), --space-7 (48px) reconstruye ese total. */
  #juegos {
    padding-bottom: var(--space-7);
  }

  /* "Sportbook profesional" en una sola línea, centrado. Envolvía a 2
     líneas no porque 28px (heredado de h2 en mobile, sin tocar) sea
     demasiado grande, sino porque .section-title hereda el max-width
     global calc(100% - 70px) (reserva de aire para no rozar los FABs
     fijos con títulos largos/multilínea) — a 313px de ancho real, el
     texto entra perfecto en los ~333px de la fila del carousel-header,
     así que el font-size original queda intacto: solo se libera el
     ancho y se centra la caja (mismo patrón que .section-title--center
     en components.css, autocontenido acá para no tocar esa clase
     compartida). white-space:nowrap fuerza la línea única; sin él,
     "Sportbook profesional" seguiría envolviendo aun con más ancho
     disponible en el punto de quiebre natural (entre "Sportbook" y
     "profesional"). Exclusivo de #sportbook — Mejores Juegos y el
     resto de los títulos de sección no se tocan. */
  #sportbook .carousel-header .section-title {
    max-width: fit-content;
    margin-inline: auto;
    text-align: center;
  }

  #sportbook .carousel-header .section-title h2 {
    white-space: nowrap;
  }
}

/* Eyebrow de Sportbook: "Deportes" en desktop/tablet, "Catálogo" en
   mobile — mismo texto que usa el eyebrow de Mejores Juegos, pedido
   así puntualmente solo para esta sección. Dos <p class="eyebrow">
   (mismo class, sin ninguna modificación de tipografía/color/posición
   propia) en vez de sustituir el texto por JS o CSS content: cada uno
   hereda exactamente el mismo estilo del otro por compartir la misma
   clase base, y display:none saca del flujo/árbol de accesibilidad al
   que no corresponde en cada breakpoint — ningún lector de pantalla
   anuncia el texto oculto. */
.eyebrow--sportbook-mobile {
  display: none;
}

@media (max-width: 639px) {
  .eyebrow--sportbook-desktop {
    display: none;
  }

  .eyebrow--sportbook-mobile {
    display: inline-flex;
  }
}

.carousel--testimonials .carousel-header {
  margin-bottom: var(--space-3);
}

.carousel--testimonials .carousel-track {
  gap: var(--space-3);
}

/* Título en una sola línea en desktop, sin tocar el texto ni el layout
   mobile (donde sigue ajustándose de forma normal). */
@media (min-width: 1024px) {
  .carousel--testimonials .section-title h2 {
    white-space: nowrap;
    font-size: clamp(1.75rem, 1.1rem + 1.8vw, 2.5rem);
  }
}

/* Escala coherente con .media-card (Catálogo/Deportes, 180px): el
   testimonio necesita más ancho que una tarjeta de imagen para que la
   cita no se parta en demasiadas líneas, pero baja de forma notoria
   frente al tamaño anterior (280px desktop) para sentirse parte de la
   misma familia de tamaños en vez de una tarjeta "grande" suelta.
   Padding, separación interna, avatar y tipografía de la cita bajan en
   la misma proporción — así la tarjeta no solo se angosta, achica su
   altura real en vez de compensar el ancho con más líneas de texto. */
.carousel--testimonials .testimonial-card {
  padding: var(--space-4);
  gap: var(--space-3);
}

.carousel--testimonials .testimonial-card__avatar {
  width: 36px;
  height: 36px;
  font-size: 0.8rem;
}

.carousel--testimonials .testimonial-card__quote {
  font-size: var(--fs-caption);
  line-height: 1.5;
}

/* ---------- Escala unificada de tarjetas mobile (Juegos-vista / Sportbook / Mejores juegos) ----------
   Referencia = .game-card de la VISTA Juegos (#juegos-view, distinta del
   trust-card usado en una ronda anterior): medida en vivo a 390px da
   87.5×109.38px, aspect-ratio 4/5, border-radius var(--radius-md)
   (16px), gap var(--space-2) dentro de una fila full-bleed (.game-row/
   .game-carousel: margin-inline:-16px + padding-inline propio:16px +
   scroll-padding-inline:16px, así la fila ocupa el 100vw real en vez de
   quedar acotada por el padding de .container). Fórmula de esa
   referencia despejada en términos de 100vw (independiente de cómo la
   consuma cada carrusel): ancho de fila (100vw) − 2×16px propio = content
   box; flex-basis = (content box + 16px vuelto a sumar − 3×8px de gap) / 4
   → se simplifica a (100vw − 40px) / 4. Verificado: a 390px da
   (390−40)/4 = 87.5px, exacto contra lo medido.

   Catálogo (#sportbook/#juegos aquí) NO usaba full-bleed — su track vivía
   dentro del padding de .container, por lo que iguolar el ancho de tarjeta
   de arriba sin más cambios no dejaba lugar ni para las 4 tarjetas
   completas (déficit de 16px incluso con peek en 0). Se replica en estos
   dos carruseles el mismo truco full-bleed de la vista Juegos
   (margin-inline negativo + padding-inline propio) para partir del mismo
   ancho de fila real (100vw), y se resuelve el propio pedido de prioridad
   ("1. mismo tamaño, 2. 4 completas, 3. borde de 5ª, con el tamaño
   protegido: ajustar antes gaps/padding que sacrificar más el peek"):
   con gap var(--space-2) (8px, igual al de referencia) el ajuste da
   exactamente 0px libres para la 5ª (4 tarjetas llenan el 100vw sin
   sobrar nada — así es como la propia vista Juegos, en su fila, no
   muestra ningún borde de 5ª). Se baja el gap a var(--space-1) (4px,
   mitad del de referencia, ya usado en el resto del sitio) para liberar
   margen: con padding-left:16px (mismo borde que Juegos) y
   padding-right:0, la ecuación (16 + 4×tarjeta + 4×gap + peek = 100vw)
   se cancela algebraicamente el término de 100vw y deja 4×gap+peek=24px
   constante en CUALQUIER ancho de los 7 pedidos → gap 4px + peek 8px en
   los 7 (320/360/375/390/393/412/430px), sin volver a tocar la fórmula
   por breakpoint. Tarjeta = (100vw − 40px) / 4, aspect-ratio 4/5,
   border-radius var(--radius-md) — igual que la referencia. */
@media (max-width: 639px) {
  #juegos .media-card,
  #sportbook .media-card {
    width: calc((100vw - 40px) / 4);
    aspect-ratio: 4 / 5;
    border-radius: var(--radius-md);
  }

  #juegos .carousel-track,
  #sportbook .carousel-track {
    gap: var(--space-1);
    margin-inline: calc(var(--space-4) * -1);
    padding-inline: var(--space-4) 0;
    scroll-padding-inline: var(--space-4) 0;
  }

  #juegos .media-card__badge,
  #sportbook .media-card__badge {
    top: 6px;
    left: 6px;
    padding: 2px 6px;
    font-size: 0.5625rem;
    gap: 3px;
  }

  #juegos .media-card__badge.badge-live::before,
  #sportbook .media-card__badge.badge-live::before {
    width: 5px;
    height: 5px;
  }

  #juegos .media-card__title,
  #sportbook .media-card__title {
    left: 8px;
    right: 8px;
    bottom: 8px;
    font-size: 0.6875rem;
    line-height: 1.15;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* Mejores Juegos: se quita el eyebrow "Catálogo" puntualmente en
     mobile (Sportbook no se toca, sigue con el suyo) — display:none en
     vez de eliminarlo del HTML para no tocar Desktop, que lo conserva.
     Sin espacio reservado: el h2 "Mejores juegos" sube solo, ya que su
     propio margin-top (.section-title h2, sin cambios) pasa a contar
     desde el borde superior de .section-title en vez de desde el
     eyebrow ausente — ningún ajuste adicional de margin/padding hizo
     falta para que ocupe ese lugar. */
  #juegos .eyebrow {
    display: none;
  }

  /* Mejores Juegos: carrusel de 1 fila → 2 filas independientes
     ("catálogo compacto"). Antes esto era 1 solo .carousel-track en
     grid-auto-flow:column + 2 filas fijas: visualmente parecían 2
     filas, pero al ser UN solo contenedor con UN solo scrollLeft,
     deslizar la fila de arriba arrastraba también la de abajo. Ahora
     son 2 <div class="carousel-track"> reales (data-games-track-row1/
     row2, pobladas por render.js) — cada una es su propio scroll
     container con su propio scroll-snap-type:x mandatory (heredado de
     .carousel-track, sin tocar), así que cada fila tiene su propio
     estado de scroll y deslizar una no mueve la otra. El track
     original (data-games-track, con las 24 tarjetas en una sola fila)
     se oculta en mobile; .games-mobile-rows con las 2 filas se muestra
     solo acá. Sportbook sigue en una sola fila: este pedido es
     exclusivo de Mejores Juegos. */
  #juegos [data-games-track] {
    display: none;
  }

  #juegos .games-mobile-rows {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
  }

  .carousel--testimonials .testimonial-card {
    width: 140px;
    padding: var(--space-3);
    gap: var(--space-2);
  }

  .carousel--testimonials .testimonial-card__stars {
    gap: 2px;
  }

  .carousel--testimonials .star-icon {
    width: 12px;
    height: 12px;
  }

  .carousel--testimonials .testimonial-card__quote {
    font-size: 0.75rem;
    line-height: 1.4;
  }

  .carousel--testimonials .testimonial-card__author {
    gap: var(--space-2);
    padding-top: var(--space-2);
  }

  .carousel--testimonials .testimonial-card__avatar {
    width: 26px;
    height: 26px;
    font-size: 0.625rem;
  }

  .carousel--testimonials .testimonial-card__name {
    font-size: 0.6875rem;
  }

  .carousel--testimonials .testimonial-card__meta {
    font-size: 0.625rem;
  }
}

@media (min-width: 640px) and (max-width: 1023px) {
  .carousel--testimonials .testimonial-card {
    width: 210px;
  }
}

@media (min-width: 1024px) {
  .carousel--testimonials .testimonial-card {
    width: 225px;
  }
}
