/* =========================================================================
   pages.css — Estilos de páginas: home, landings de servicio, sectores,
   páginas genéricas. (El blog usa blog.css.)
   ========================================================================= */

/* ---- Aparición progresiva (Data in Motion) ----
   Solo se oculta si hay JavaScript (clase .js en <html>); sin JS todo es visible. */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(34px) scale(0.98);
  transition: opacity 0.7s var(--ease-out), transform 0.7s var(--ease-out);
  will-change: opacity, transform;
}
.js [data-reveal].is-visible { opacity: 1; transform: none; }
/* Variantes direccionales: entrada desde los lados */
.js [data-reveal].reveal-left  { transform: translateX(-64px) scale(0.98); }
.js [data-reveal].reveal-right { transform: translateX(64px) scale(0.98); }
.js [data-reveal].reveal-left.is-visible,
.js [data-reveal].reveal-right.is-visible { transform: none; }
/* Expansión desde el centro (se despliega al entrar en viewport) */
.js [data-reveal].reveal-zoom { transform: scale(0.55); opacity: 0; }
.js [data-reveal].reveal-zoom.is-visible { transform: scale(1); opacity: 1; }
.js [data-reveal].reveal-zoom { transition: opacity 0.9s var(--ease-out), transform 0.9s var(--ease-out); }

[data-reveal][data-delay="1"] { transition-delay: 90ms; }
[data-reveal][data-delay="2"] { transition-delay: 180ms; }
[data-reveal][data-delay="3"] { transition-delay: 270ms; }

/* Aparición escalonada de las rejillas de fichas/tarjetas */
.js .svc-cards > [data-reveal]:nth-child(2),
.js .grid > [data-reveal]:nth-child(2)  { transition-delay: 90ms; }
.js .svc-cards > [data-reveal]:nth-child(3),
.js .grid > [data-reveal]:nth-child(3)  { transition-delay: 180ms; }
.js .svc-cards > [data-reveal]:nth-child(4),
.js .grid > [data-reveal]:nth-child(4)  { transition-delay: 270ms; }
.js .svc-cards > [data-reveal]:nth-child(5),
.js .grid > [data-reveal]:nth-child(5)  { transition-delay: 360ms; }
.js .svc-cards > [data-reveal]:nth-child(6),
.js .grid > [data-reveal]:nth-child(6)  { transition-delay: 450ms; }

@media (prefers-reduced-motion: reduce) {
  .js [data-reveal] { opacity: 1; transform: none; transition: none; }
  .js [data-reveal].reveal-left, .js [data-reveal].reveal-right,
  .js [data-reveal].reveal-zoom { transform: none; opacity: 1; }
  .js .svc-cards > [data-reveal], .js .grid > [data-reveal] { transition-delay: 0ms; }
}

/* =========================================================================
   HERO
   ========================================================================= */
.hero {
  position: relative;
  padding-top: clamp(3rem, 2rem + 4vw, 5.5rem);
  padding-bottom: clamp(3rem, 2rem + 4vw, 6rem);
  overflow: hidden;
}
.hero__grid {
  display: grid;
  gap: clamp(2rem, 1rem + 4vw, 4rem);
  align-items: center;
}
@media (min-width: 960px) {
  .hero__grid { grid-template-columns: 1.05fr 0.95fr; }
}
.hero__eyebrow { margin-bottom: var(--space-lg); }
.hero h1 { margin-bottom: var(--space-lg); }
.hero h1 .text-gradient { display: inline; }
.hero__lead {
  font-size: var(--fs-lead);
  color: var(--color-ink-soft);
  max-width: 46ch;
  margin-bottom: var(--space-xl);
}
.hero-actions { display: flex; flex-wrap: wrap; gap: var(--space-md); margin-bottom: var(--space-xl); }
.hero__place {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: var(--fs-small);
  color: var(--color-muted);
}
.hero__place svg { width: 1rem; height: 1rem; color: var(--color-primary); }

/* Visual del hero derivado del isotipo */
.hero__visual {
  position: relative;
  aspect-ratio: 1 / 1;
  max-width: 520px;
  margin-inline: auto;
  width: 100%;
}
.hero__visual svg { width: 100%; height: 100%; }
/* Composición estática (sin animación infinita, mejor para CWV). El movimiento
   se aporta con la aparición progresiva y el trazo punteado de trayectoria. */
.hero-orbit { transform-origin: center; }

/* Fondo radial sutil del hero */
.hero::before {
  content: "";
  position: absolute;
  top: -20%;
  right: -10%;
  width: 60%;
  height: 120%;
  background: radial-gradient(circle at 60% 40%, rgba(74, 190, 221, 0.16), transparent 60%);
  z-index: -1;
  pointer-events: none;
}

/* =========================================================================
   HERO DE PORTADA (full-screen, cápsula flotante, marquee y sello)
   Solo se activa en la portada (body.page-home). Reutiliza el header global.
   ========================================================================= */

/* ---- Topbar fijo: franja animada + cabecera cápsula ---- */
.home-topbar { position: fixed; inset: 0 0 auto 0; z-index: var(--z-header); }

/* Franja superior animada (marquee). Se colapsa al hacer scroll. */
.hero-marquee {
  background: var(--gradient-brand);
  color: #fff;
  overflow: hidden;
  max-height: 3rem;
  transition: max-height var(--dur-base) var(--ease-out), opacity var(--dur-base) var(--ease-out);
}
.home-topbar:has(.site-header.is-scrolled) .hero-marquee { max-height: 0; opacity: 0; }
/* Con el menú móvil/tablet ABIERTO (body.no-scroll lo activa el JS de navegación), la
   franja del marquee se colapsa AL INSTANTE (sin transición). Así la cabecera del menú
   —logo, selector de tema y botón de cierre— queda pegada arriba (top:0) y totalmente
   visible desde el primer momento, sea cual sea la posición del scroll: el overlay
   `.mobile-nav { top: var(--header-h) }` deja de solaparla. No usa offsets fijos ni
   depende del scroll. En escritorio no aplica (el menú móvil no se abre). */
body.no-scroll .home-topbar .hero-marquee { max-height: 0; opacity: 0; transition: none; }
/* Bucle continuo: el track son DOS copias idénticas una detrás de otra y la
   animación recorre EXACTAMENTE una (`-50%` del propio track), así que el último
   fotograma es idéntico al primero y no hay salto. Para que tampoco quede un hueco
   al final del ciclo, cada copia repite la lista hasta ser más ancha que la
   pantalla (`$marqueeRepeat` en header.php): antes una copia medía 987px y en un
   viewport de 1270px se veían 293px vacíos justo antes de reiniciar.
   La duración va ligada al ancho de la copia para conservar la velocidad de
   siempre (~29 px/s): 4 pasadas × 34s = 136s. */
.hero-marquee__track {
  display: flex;
  width: max-content;
  align-items: center;
  white-space: nowrap;
  padding-block: 0.42rem;
  will-change: transform;
  animation: heroMarquee 136s linear infinite;
}
.hero-marquee__content { display: flex; align-items: center; flex: 0 0 auto; }
.hero-marquee__item {
  font-family: var(--font-heading);
  font-weight: var(--fw-semibold);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.hero-marquee__sep { margin-inline: 1.05rem; opacity: 0.55; }
@keyframes heroMarquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* Cabecera flotante a TODO EL ANCHO (barra glass; reutiliza .site-header y su JS is-scrolled).
   El fondo cubre el 100% del ancho; el contenido queda en el contenedor estándar. */
.site-header--floating {
  position: static;
  background: rgba(10, 26, 44, 0.55);
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
  backdrop-filter: saturate(1.4) blur(14px);
  box-shadow: 0 10px 30px rgba(4, 14, 28, 0.22);
  transition: background-color var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
}
.site-header--floating.is-scrolled {
  background: rgba(8, 20, 36, 0.85);
  box-shadow: 0 14px 40px rgba(4, 14, 28, 0.40);
}
/* El contenido (logo · menú · acciones) también ocupa todo el ancho,
   con el margen lateral estándar (--gutter). */
.site-header--floating .header-inner { max-width: none; }
/* Logo blanco y textos claros dentro de la cápsula (independiente del tema) */
.site-header--floating .brand__logo--light { display: none; }
.site-header--floating .brand__logo--dark { display: block; }
.site-header--floating .brand img { height: 30px; }
.site-header--floating .nav-link { color: rgba(255, 255, 255, 0.86); }
.site-header--floating .nav-link:hover { color: #fff; background: rgba(255, 255, 255, 0.12); }
.site-header--floating .nav-link[aria-current="page"] { color: #fff; }
.site-header--floating .nav-caret { color: rgba(255, 255, 255, 0.7); }
.site-header--floating .theme-toggle { color: rgba(255, 255, 255, 0.88); border-color: rgba(255, 255, 255, 0.28); }
.site-header--floating .theme-toggle:hover { color: #fff; border-color: #fff; background: rgba(255, 255, 255, 0.14); }
.site-header--floating .nav-toggle span { background: #fff; }

/* Header unificado: el topbar es fijo (overlay). La portada tiene el hero a
   pantalla completa detrás; el resto de páginas reservan su altura para que el
   contenido no quede oculto bajo la cápsula. */
body:not(.page-home) #main { padding-top: calc(var(--header-h) + 2.9rem); }

/* ---- Sección hero ---- */
.home-hero {
  position: relative;
  min-height: 100svh;
  display: grid;
  align-content: center;
  overflow: hidden;
  isolation: isolate;
  color: #fff;
  padding-top: clamp(5.75rem, 4.75rem + 3.5vw, 7.75rem);
  padding-bottom: clamp(3rem, 2rem + 2.5vw, 4.75rem);
}
.home-hero__bg { position: absolute; inset: 0; z-index: 0; overflow: hidden; background: var(--color-deep-blue); }
.home-hero__media { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center; display: block; }
img.home-hero__media { animation: heroZoom 28s ease-in-out infinite alternate; }
@keyframes heroZoom { from { transform: scale(1.03); } to { transform: scale(1.13); } }
.home-hero__scrim {
  position: absolute; inset: 0;
  /* Capa oscura sobre el vídeo: base uniforme + degradado (más intenso arriba y
     abajo) + viñeteado, para asegurar legibilidad del texto sobre el vídeo. */
  background:
    linear-gradient(180deg, rgba(6, 18, 34, 0.66) 0%, rgba(6, 18, 34, 0.5) 45%, rgba(5, 14, 27, 0.88) 100%),
    radial-gradient(120% 85% at 50% 12%, transparent 38%, rgba(4, 12, 24, 0.55) 100%);
}

.home-hero__inner { position: relative; z-index: 2; text-align: center; max-width: 1240px; margin-inline: auto; }
.home-hero__eyebrow {
  display: inline-block;
  font-family: var(--font-heading);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-small);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--color-cyan);
  margin-bottom: var(--space-lg);
}
.home-hero__title {
  font-family: var(--font-heading); /* Montserrat (con reserva de sistema) */
  font-weight: var(--fw-bold);      /* negrita (700) */
  font-size: clamp(2.3rem, 1.3rem + 4.4vw, 5rem);
  line-height: 1.22;                /* aire suficiente para descendentes y acentos */
  letter-spacing: var(--tracking-tight);
  color: #fff;
  margin: 0 auto var(--space-lg);
  max-width: 24ch;
  text-wrap: balance;
}
.home-hero__line { display: block; }
.home-hero__line > span { display: block; }
.home-hero__accent {
  background: var(--gradient-brand);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.home-hero__lead {
  font-size: var(--fs-lead);
  line-height: var(--lh-snug);
  color: rgba(255, 255, 255, 0.82);
  max-width: 70ch;
  margin: 0 auto var(--space-xl);
}
.home-hero__actions { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-md); }
.home-hero__actions .btn svg { width: 1.15em; height: 1.15em; transition: transform var(--dur-base) var(--ease-out); }
.home-hero__actions .btn:hover svg { transform: translateX(4px); }

/* ---- Sello circular decorativo ---- */
.home-hero__seal {
  position: absolute; z-index: 2;
  right: clamp(1rem, -1rem + 6vw, 5rem);
  bottom: clamp(1.75rem, 0.5rem + 4vw, 4.5rem);
  width: clamp(92px, 6vw + 62px, 140px);
  aspect-ratio: 1;
  pointer-events: none;
}
.hero-seal { width: 100%; height: 100%; display: block; }
.hero-seal__ring { transform-origin: 60px 60px; animation: heroSealSpin 20s linear infinite; }
.hero-seal__ring text {
  font-family: var(--font-heading);
  font-weight: var(--fw-semibold);
  font-size: 8px;
  letter-spacing: 1.1px;
  fill: rgba(255, 255, 255, 0.92);
}
@keyframes heroSealSpin { to { transform: rotate(360deg); } }

/* ---- Indicador de scroll ---- */
.home-hero__scroll {
  position: absolute; z-index: 2;
  left: 50%; bottom: clamp(0.9rem, 0.5rem + 1vw, 1.6rem);
  width: 42px; height: 42px;
  display: grid; place-items: center;
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.32);
  border-radius: var(--radius-pill);
  transform: translateX(-50%);
  transition: background-color var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out);
  animation: heroScrollBob 2.4s ease-in-out infinite;
}
.home-hero__scroll:hover { background: rgba(255, 255, 255, 0.14); border-color: #fff; }
.home-hero__scroll svg { width: 20px; height: 20px; }
@keyframes heroScrollBob { 0%, 100% { transform: translate(-50%, 0); } 50% { transform: translate(-50%, 5px); } }

/* ---- Redes sociales del hero (columna lateral izquierda: "Síguenos!") ---- */
.home-hero__social {
  position: absolute; z-index: 3;
  left: clamp(1rem, 2.6vw, 3rem);
  top: 50%; transform: translateY(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 0.7rem;
}
.home-hero__social-label {
  font-family: var(--font-heading); font-weight: var(--fw-semibold);
  font-size: 0.92rem; color: #fff; letter-spacing: 0.01em;
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.3);
}
.hero-social { display: flex; flex-direction: column; gap: 0.7rem; }
.hero-social__btn {
  width: 2.6rem; height: 2.6rem;
  display: grid; place-items: center; border-radius: 50%;
  background: rgba(255, 255, 255, 0.12);
  border: 1px solid rgba(255, 255, 255, 0.3);
  color: #fff;
  backdrop-filter: blur(4px);
  transition: background var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
}
.hero-social__btn:hover { background: rgba(255, 255, 255, 0.24); border-color: #fff; transform: translateY(-3px); color: #fff; }
.hero-social__btn svg { width: 1.15rem; height: 1.15rem; }
/* Tablet/móvil: sin espacio lateral → fila horizontal centrada bajo el contenido */
@media (max-width: 1100px) {
  .home-hero__social {
    position: static; left: auto; top: auto; transform: none;
    flex-direction: row; align-items: center; justify-content: center;
    gap: 0.75rem; margin: var(--space-lg) auto 0;
  }
  .hero-social { flex-direction: row; }
}

/* ---- Animaciones de entrada (no bloquean el render inicial) ---- */
@media (prefers-reduced-motion: no-preference) {
  .home-hero__eyebrow { animation: heroFadeUp 0.7s var(--ease-out) 0.05s both; }
  .home-hero__line > span { animation: heroLineUp 0.66s var(--ease-out) both; }
  .home-hero__line:nth-child(1) > span { animation-delay: 0.06s; }
  .home-hero__line:nth-child(2) > span { animation-delay: 0.13s; }
  .home-hero__line:nth-child(3) > span { animation-delay: 0.20s; }
  .home-hero__line:nth-child(4) > span { animation-delay: 0.27s; }
  .home-hero__lead   { animation: heroFadeUp 0.7s var(--ease-out) 0.42s both; }
  .home-hero__actions{ animation: heroFadeUp 0.7s var(--ease-out) 0.55s both; }
  .home-hero__social { animation: heroFadeUp 0.7s var(--ease-out) 0.68s both; }
  .home-hero__seal   { animation: heroFadeUp 0.8s var(--ease-out) 0.7s both; }
}
@keyframes heroLineUp { from { opacity: 0; transform: translateY(0.5em); } to { opacity: 1; transform: none; } }
@keyframes heroFadeUp { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }

/* ---- Responsive del hero ---- */
@media (max-width: 640px) {
  .home-hero__actions { flex-direction: column; align-items: stretch; width: min(100%, 340px); margin-inline: auto; }
  .home-hero__actions .btn { width: 100%; }
  .hero-marquee__item { font-size: 0.66rem; letter-spacing: 0.12em; }
  .home-hero__seal { width: 84px; right: 1rem; bottom: 1.25rem; }
  /* En móvil el bloque del hero v2 (contenido + redes) se apoyaba ABAJO
     (align-content:end). Se reposiciona el bloque COMPLETO centrándolo verticalmente
     (align-content:center): queda algo más abajo que pegado arriba, con la zona
     superior mejor aprovechada y aire equilibrado arriba y abajo. No se toca la altura
     del hero, ni los paddings, ni las separaciones internas; solo se reposiciona el
     conjunto. Escritorio y tablet (>640px) se mantienen igual.
     Se usa doble clase (.home-hero.home-hero--v2) para ganar en especificidad a la
     regla base `.home-hero--v2{align-content:end}`, que aparece más abajo en el CSS. */
  .home-hero.home-hero--v2 { align-content: center; }
}
@media (max-width: 340px) {
  .home-hero__seal { display: none; }
}

/* Foco por teclado bien visible sobre el fondo oscuro del hero/cápsula */
.home-hero__inner .btn:focus-visible,
.home-hero__scroll:focus-visible,
.site-header--floating .nav-link:focus-visible,
.site-header--floating .theme-toggle:focus-visible,
.site-header--floating .nav-toggle:focus-visible,
.site-header--floating .header-contact-btn:focus-visible,
.site-header--floating .brand:focus-visible {
  outline-color: #fff;
  outline-offset: 3px;
}

/* =========================================================================
   HERO v2 — composición EDITORIAL asimétrica  (assets/partials/hero-v2.php)
   Convive con el hero v1 de arriba, que NO se toca: el interruptor es
   HERO_VERSION en includes/config.php. Como v2 estrena sus propias clases
   (.hh2*), las reglas de v1 (.home-hero__inner/__title/__lead/__actions) no
   llegan a aplicarse aquí; solo se redefinen las tres cosas compartidas: la
   alineación de la sección, el padding inferior y el scrim.
   El fondo (vídeo), la columna de redes, el sello y el indicador de scroll
   siguen usando el CSS de siempre.
   ========================================================================= */

/* Overlay DIRECCIONAL: denso donde va el texto y casi limpio a la derecha, para
   que el vídeo se vea de verdad. La 2ª capa (vertical, suave) protege la
   legibilidad de la cabecera arriba y del sello/indicador abajo. */
/* Degradado direccional adaptado a la nueva composición: la derecha ya NO tiene
   contenido (se quitó el índice de servicios), así que se aclara mucho más para
   dar protagonismo al vídeo. La izquierda mantiene su densidad porque el vídeo
   llega a BLANCO PURO bajo el texto y el titular/lead/CTAs (hasta ~50%) necesitan
   ≥0.78 de velo para pasar AA en el peor fotograma. A partir de ahí cae de forma
   continua hasta TRANSPARENTE en el borde derecho: sin oscuridad innecesaria y sin
   bandas (paradas graduales). La 2ª capa (vertical, suave) sigue protegiendo la
   cabecera arriba y el sello/indicador abajo. */
.home-hero--v2 .home-hero__scrim {
  background:
    linear-gradient(90deg,
      rgba(4, 14, 28, 0.94) 0%,
      rgba(4, 14, 28, 0.90) 30%,
      rgba(4, 14, 28, 0.80) 52%,
      rgba(4, 14, 28, 0.52) 66%,
      rgba(4, 14, 28, 0.16) 82%,
      rgba(4, 14, 28, 0) 100%),
    linear-gradient(180deg,
      rgba(4, 14, 28, 0.5) 0%, rgba(4, 14, 28, 0) 24%,
      rgba(4, 14, 28, 0) 58%, rgba(4, 14, 28, 0.6) 100%);
}

/* Nada centrado: el bloque se apoya ABAJO y a la izquierda. El padding inferior
   deja libre la banda del indicador de scroll (42px + su separación). */
.home-hero--v2 {
  align-content: end;
  padding-bottom: clamp(5rem, 3.5rem + 5vw, 8rem);
  /* Con el titular a una sola escala el bloque es más alto y puede llegar a
     desbordar la sección; como se apoya abajo, ese desbordamiento sale por
     ARRIBA. El padding superior reserva la altura REAL del topbar fijo
     (--header-h + franja ≈ 119px) más un respiro, así la primera línea nunca
     queda bajo la cápsula del menú. */
  padding-top: calc(var(--header-h) + clamp(2.9rem, 2.4rem + 1.2vw, 4.2rem));
}

.hh2 {
  position: relative;
  z-index: 2;
  display: grid;
  /* Columna izquierda algo más ancha (antes 58%) para que el H1 quepa en CUATRO
     líneas sin recortarse; solo se ensancha el H1 (el lead tiene su propio
     max-width y los CTA son flex), y la 2ª columna sigue libre para el vídeo. */
  grid-template-columns: minmax(0, 66%) minmax(0, 1fr);
  align-items: end;
  gap: var(--space-xl);
  text-align: left;
}
/* A partir de 1101px la columna de redes es absoluta a la izquierda: el
   contenido tiene que empezar más allá de ella (su borde derecho cae como mucho
   en ~90px). Se descuenta lo que ya aporta el margen del contenedor, así que en
   pantallas anchas el desplazamiento extra desaparece solo. */
@media (min-width: 1101px) {
  .hh2 { padding-left: max(var(--gutter), calc(132px - max(0px, (100vw - var(--container-max)) / 2))); }
}

/* Tope de seguridad: en la práctica nunca llega a limitar (la columna del grid
   es más estrecha), pero evita líneas kilométricas si crece la tipografía base. */
.hh2__content { max-width: 46rem; }

.hh2__eyebrow {
  display: block;
  font-family: var(--font-heading);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-small);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--color-cyan);
  margin-bottom: var(--space-md);
}

/* Titular: MISMO mensaje que v1 y UNA SOLA escala tipográfica —todas las líneas
   comparten familia, peso, tamaño y line-height—; la composición se hace solo con
   los saltos de línea y una sangría en el cierre. Solo dos palabras van en cian.
   Cada línea es su propia máscara (overflow hidden) para la entrada; el
   padding/margen negativo le da sitio a tildes y descendentes sin alterar la
   maquetación. */
.hh2__title {
  font-family: var(--font-heading);
  font-weight: var(--fw-extrabold);
  /* Mínimo algo menor (antes 2.05rem) para que en móvil la línea más larga
     («Marketing digital con») quepa holgada en las 4 filas; en escritorio manda
     el tramo medio/alto del clamp, que no cambia. */
  font-size: clamp(1.9rem, 1.1rem + 3.5vw, 3.9rem);
  line-height: 1.07;
  letter-spacing: var(--tracking-tight);
  color: #fff;
  margin: 0 0 var(--space-lg);
}
.hh2__l {
  display: block;
  overflow: hidden;
  padding-block: 0.14em 0.18em;
  margin-block: -0.14em -0.18em;
}
.hh2__l > span { display: block; }
/* Cian de marca, el mismo acento que el antetítulo. Se descartó el degradado
   primary→cyan de v1: su arranque (#0872BB) sobre un fotograma claro del vídeo
   se queda en 2:1 y no llega ni al 3:1 de texto grande; el cian da 6:1 medido. */
.hh2__hl {
  font-style: normal;          /* es <em> por el énfasis, no para ir en cursiva */
  color: var(--color-cyan);
}

.hh2__lead {
  font-size: clamp(1rem, 0.94rem + 0.35vw, 1.18rem);
  line-height: var(--lh-body);
  color: rgba(255, 255, 255, 0.8);
  max-width: 46ch;
  margin: 0 0 var(--space-xl);
}

/* Un solo botón con peso; el segundo CTA es un enlace con flecha. */
.hh2__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-lg); }
.hh2__cta svg { width: 1.15em; height: 1.15em; fill: none; transition: transform var(--dur-base) var(--ease-out); }
.hh2__cta:hover svg { transform: translateX(4px); }
.hh2__link {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-heading);
  font-weight: var(--fw-semibold);
  font-size: 1rem;
  color: #fff;
  padding-block: 0.3rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.34);
  transition: color var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out);
}
.hh2__link svg { width: 1.1em; height: 1.1em; fill: none; transition: transform var(--dur-base) var(--ease-out); }
.hh2__link:hover { color: var(--color-cyan); border-color: var(--color-cyan); }
.hh2__link:hover svg { transform: translateX(4px); }

/* La zona derecha del hero se dejó LIBRE (se eliminó el índice de servicios) para
   dar protagonismo al vídeo. El grid `.hh2` mantiene su columna izquierda del 58%
   —el bloque de contenido no se reposiciona— y la 2ª columna queda vacía. */

/* ---- Responsive de v2 ---- */
@media (max-width: 900px) {
  .hh2 { grid-template-columns: minmax(0, 1fr); }
  .hh2__content { max-width: none; }
  /* Sin columna libre a la derecha, el degradado direccional dejaría texto sobre
     zonas claras del vídeo: aquí manda un velo vertical como el de siempre. */
  .home-hero--v2 .home-hero__scrim {
    background:
      linear-gradient(180deg, rgba(4, 14, 28, 0.82) 0%, rgba(4, 14, 28, 0.72) 45%, rgba(4, 14, 28, 0.9) 100%),
      radial-gradient(120% 85% at 50% 12%, transparent 38%, rgba(4, 12, 24, 0.55) 100%);
  }
}
@media (max-width: 560px) {
  .hh2__actions { align-items: flex-start; gap: var(--space-md); }
  .hh2__cta { width: 100%; justify-content: center; }
}
/* Móviles estrechos: el ancho ya es completo (no se puede ensanchar más), así que
   el titular escala con el viewport para que la línea más larga siga cabiendo en
   las 4 filas sin envolver ni recortarse (por debajo de ~360px el mínimo del
   clamp base la dejaba sin sitio). */
@media (max-width: 400px) {
  .hh2__title { font-size: 7.6vw; }
}
/* Pantallas bajas (portátiles pequeños, móvil apaisado): se recentra para que el
   bloque no se salga por arriba al apoyarse abajo. */
@media (max-height: 620px) {
  .home-hero--v2 { align-content: center; padding-bottom: clamp(3rem, 2rem + 2.5vw, 4.75rem); }
  /* además se baja la escala del titular: si no, el bloque roza la cápsula del menú */
  .hh2__title { font-size: clamp(1.9rem, 1.1rem + 2.4vw, 3rem); }
  .hh2__lead { margin-bottom: var(--space-lg); }
}

/* Sello circular: algo más grande para que el aro de texto respire, y la letra
   un punto mayor dentro del mismo viewBox (el largo de la cadena lo fija
   `textLength` en el SVG, así que subir el cuerpo no descuadra el anillo).
   Acotado a v2 para no alterar el hero anterior, que conserva su sello tal cual. */
.home-hero--v2 .home-hero__seal { width: clamp(104px, 6vw + 68px, 150px); }
.home-hero--v2 .hero-seal { overflow: visible; }   /* red de seguridad: nada se recorta en el borde del viewBox */
.home-hero--v2 .hero-seal__ring text { font-size: 8.4px; letter-spacing: 1.4px; }

/* Prueba social compacta bajo el CTA del hero: estrellas doradas + media real +
   texto, enlazado a la ficha de Google. Discreto y sin salto de layout. */
.hh2__rating {
  display: inline-flex;
  flex-direction: column;
  gap: 0.15rem;
  margin-top: var(--space-md);
  text-decoration: none;
  color: var(--color-on-dark, #fff);
  width: fit-content;
}
.hh2__rating-line { display: inline-flex; align-items: center; gap: 0.5rem; }
.hh2__rating-stars { color: #fbbc04; letter-spacing: 0.12em; font-size: 1.05rem; line-height: 1; }
.hh2__rating-score { font-family: var(--font-heading); font-weight: var(--fw-bold); font-size: 1.05rem; }
.hh2__rating-label { font-size: var(--fs-small); color: var(--color-on-dark-soft, rgba(255,255,255,0.82)); }
.hh2__rating:hover .hh2__rating-label { text-decoration: underline; }
.hh2__rating:focus-visible { outline: 2px solid #fff; outline-offset: 3px; border-radius: var(--radius-sm); }
/* En móvil se mantiene el tamaño de siempre: agrandarlo aquí hacía que el sello
   se comiera los últimos iconos de la fila de redes (que en esta anchura pasa a
   ser un elemento en flujo, justo encima). El texto se ve completo igualmente,
   porque lo que lo arregla es el `textLength`, no el tamaño. */
@media (max-width: 640px) {
  .home-hero--v2 .home-hero__seal { width: 84px; }
}

/* Foco por teclado sobre el fondo oscuro */
.hh2 .btn:focus-visible,
.hh2__link:focus-visible { outline-color: #fff; outline-offset: 3px; }

/* ---- Entrada de v2: máscaras y desplazamientos cortos, sin efectos genéricos ---- */
@media (prefers-reduced-motion: no-preference) {
  .hh2__eyebrow { animation: hh2Fade 0.7s var(--ease-out) 0.05s both; }
  .hh2__l > span { animation: hh2Mask 0.85s var(--ease-out) both; }
  .hh2__l:nth-child(1) > span { animation-delay: 0.12s; }
  .hh2__l:nth-child(2) > span { animation-delay: 0.20s; }
  .hh2__l:nth-child(3) > span { animation-delay: 0.28s; }
  .hh2__l:nth-child(4) > span { animation-delay: 0.36s; }
  .hh2__lead    { animation: hh2Fade 0.75s var(--ease-out) 0.56s both; }
  .hh2__actions { animation: hh2Fade 0.75s var(--ease-out) 0.68s both; }
}
@keyframes hh2Mask { from { opacity: 0; transform: translateY(108%); } to { opacity: 1; transform: none; } }
@keyframes hh2Fade { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

/* ---- Respeto a prefers-reduced-motion ---- */
@media (prefers-reduced-motion: reduce) {
  .hero-marquee__track,
  .hero-seal__ring,
  .home-hero__scroll,
  img.home-hero__media { animation: none !important; }
}

/* =========================================================================
   Franja de confianza
   ========================================================================= */
/* Fichas de confianza (home) */
.trust-cards {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  text-align: left;
}
.trust-card { display: flex; flex-direction: column; gap: var(--space-sm); align-items: flex-start; }
.trust-card__icon {
  width: 3rem; height: 3rem;
  display: grid; place-items: center;
  border-radius: var(--radius-sm);
  background: var(--color-surface-3);
  color: var(--color-primary);
  transition: transform var(--dur-base) var(--ease-out),
    scale var(--dur-base) var(--ease-out),
    rotate var(--dur-base) var(--ease-out),
    background-color var(--dur-base) var(--ease-out),
    color var(--dur-base) var(--ease-out);
}
.trust-card__icon svg { width: 1.5rem; height: 1.5rem; }
/* scale/rotate como propiedades independientes (no dentro de `transform`) para que
   convivan con el parallax de [data-cardfx], que sí escribe `transform` en línea. */
.trust-card:hover .trust-card__icon {
  background: var(--color-primary);
  color: #fff;
  scale: 1.08;
  rotate: -3deg;
}
.trust-card .trust__item { color: var(--color-ink); font-size: var(--fs-body); margin: 0; }
.trust__item strong { color: var(--color-primary); }
.client-logos {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: var(--space-xl);
  align-items: center;
}
.client-logos img { max-height: 46px; width: auto; margin-inline: auto; opacity: 0.75; filter: grayscale(1); }

/* =========================================================================
   Grupos de capacidades / servicios
   ========================================================================= */
.capabilities { display: grid; gap: var(--space-xl); }
@media (min-width: 768px) { .capabilities { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .capabilities { grid-template-columns: repeat(3, 1fr); } }

.cap-group {
  background: var(--color-surface);
  border: var(--border-soft);
  border-radius: var(--radius-lg);
  padding: clamp(1.5rem, 1.2rem + 1vw, 2.25rem);
  transition: box-shadow var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
}
.cap-group:hover { box-shadow: var(--shadow-md); transform: translateY(-3px); }
.cap-group__icon {
  width: 3rem; height: 3rem;
  display: grid; place-items: center;
  border-radius: var(--radius-sm);
  background: var(--gradient-brand);
  color: #fff;
  margin-bottom: var(--space-md);
}
.cap-group__icon svg { width: 1.5rem; height: 1.5rem; }
/* Variante con ilustración: el icono YA trae su propio cuadrado azul, su radio y
   su sombra, así que el contenedor deja de pintar fondo (si no, saldría un
   cuadrado dentro de otro). La caja crece lo justo para compensar el aire que el
   PNG reserva a la sombra: el cuadrado azul acaba midiendo los mismos ~48px que
   el icono de trazo al que sustituye. */
.cap-group__icon--img {
  width: 3.25rem; height: 3.25rem;
  background: none;
  border-radius: 0;
}
.cap-group__icon--img img { width: 100%; height: 100%; object-fit: contain; display: block; }
.cap-group h3 { font-size: var(--fs-h4); margin-bottom: 0.35rem; }
.cap-group > p { color: var(--color-ink-soft); margin-bottom: var(--space-md); font-size: 0.98rem; }
.cap-links { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.cap-links a {
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  padding: 0.3rem 0.7rem;
  border-radius: var(--radius-pill);
  background: var(--color-surface-2);
  color: var(--color-ink-soft);
}
.cap-links a:hover { background: var(--color-surface-3); color: var(--color-primary); }

/* =========================================================================
   Sección Servicios: intro FIJA (sticky nativo) mientras las fichas hacen
   scroll. Solo en escritorio; en tablet/móvil se apila de forma convencional.
   ========================================================================= */
@media (min-width: 1024px) {
  .svc-split {
    display: grid;
    grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
    gap: clamp(2.5rem, 1.5rem + 3vw, 5rem);
    align-items: start; /* imprescindible: evita que la intro se estire y rompa el sticky */
  }
  .svc-split__intro {
    position: sticky;
    top: calc(var(--header-h) + 1.5rem); /* deja hueco al header fijo, sin solapamientos */
    align-self: start;
    margin-bottom: 0;
  }
  /* Fichas en columna vertical: aparecen progresivamente al hacer scroll */
  .svc-split__cards.capabilities {
    grid-template-columns: 1fr;
    gap: var(--space-lg);
  }
}

/* =========================================================================
   Propuesta diferencial
   ========================================================================= */
.diff-grid { display: grid; gap: var(--space-xl); }
@media (min-width: 700px) { .diff-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .diff-grid { grid-template-columns: repeat(4, 1fr); } }
.diff-item__num {
  font-family: var(--font-heading);
  font-weight: var(--fw-extrabold);
  font-size: 1.1rem;
  color: var(--color-cyan);
  margin-bottom: var(--space-sm);
}
.diff-item h3 { font-size: 1.2rem; margin-bottom: 0.4rem; }
.diff-item p { color: var(--color-on-dark-soft); font-size: 0.98rem; }
.bg-deep .diff-item h3 { color: #fff; }

/* =========================================================================
   "Por qué Alcanalytics": ACORDEÓN HORIZONTAL de 8 fichas ligado al scroll.
   Sin JS, con motion reducido o por debajo de 1024px queda esta base: rejilla
   flexible que en móvil se apila en columna (fallback limpio, todo visible).
   El acordeón lo activa main.js añadiendo .is-why a la sección (más abajo).
   ========================================================================= */
.why-stage { display: flex; flex-wrap: wrap; gap: var(--space-lg); justify-content: center; }
.why-card {
  position: relative;
  width: clamp(220px, 30%, 300px);
  padding: 1.25rem 1.3rem 1.35rem;
  border-radius: var(--radius-lg);
  background: rgba(255, 255, 255, 0.22);
  border: 1px solid rgba(255, 255, 255, 0.2);
  color: #fff;
  box-shadow: 0 14px 34px -16px rgba(0, 0, 0, 0.55);
  outline: none;
}
/* Móvil/tablet (sin scatter): las fichas van ordenadas en columna vertical. */
@media (max-width: 1023px) {
  .why-stage { flex-direction: column; align-items: center; }
  .why-stage .why-card { width: min(100%, 460px); }

  /* --- Fichas como DESPLEGABLES (acordeón) en móvil/tablet ---
     Lo activa el JS añadiendo `.is-accordion` al stage; sin JS las fichas quedan
     abiertas como siempre (el texto se ve entero). La cabecera = número + título
     hace de disparador pulsable; al abrir se revela el texto. */
  .why-stage.is-accordion .why-card {
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: background var(--dur-base) var(--ease-out);
  }
  .why-stage.is-accordion .why-card__title {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.85rem;
    margin-bottom: 0;
  }
  /* Chevron indicador de que la ficha se despliega. */
  .why-stage.is-accordion .why-card__title::after {
    content: "";
    flex: none;
    width: 0.6rem;
    height: 0.6rem;
    margin-right: 0.15rem;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: translateY(-2px) rotate(45deg);
    opacity: 0.85;
    transition: transform var(--dur-base) var(--ease-out);
  }
  .why-stage.is-accordion .why-card.is-open .why-card__title::after {
    transform: translateY(1px) rotate(-135deg);
  }
  /* Texto plegable: colapsado a 0 y revelado al abrir. */
  .why-stage.is-accordion .why-card__text {
    overflow: hidden;
    max-height: 0;
    margin-top: 0;
    opacity: 0;
    transition: max-height 0.4s var(--ease-out), opacity 0.3s var(--ease-out), margin-top 0.3s var(--ease-out);
  }
  .why-stage.is-accordion .why-card.is-open .why-card__text {
    max-height: 40rem;
    margin-top: 0.7rem;
    opacity: 1;
  }
}
@media (max-width: 1023px) and (prefers-reduced-motion: reduce) {
  /* Sin animación de despliegue: el cambio de altura es inmediato. */
  .why-stage.is-accordion .why-card__text,
  .why-stage.is-accordion .why-card__title::after { transition: none; }
}
/* Variaciones sutiles dentro de la marca (azul corporativo / cian / oscuro) */
.why-card--v2 { background: linear-gradient(158deg, rgba(8, 114, 187, 0.82), rgba(5, 64, 112, 0.72)); border-color: rgba(8, 114, 187, 0.7); }
.why-card--v3 { background: rgba(74, 190, 221, 0.36); border-color: rgba(74, 190, 221, 0.5); }

.why-card__num {
  display: block;
  font-family: var(--font-heading);
  font-weight: var(--fw-extrabold);
  font-size: 2.9rem;
  line-height: 0.9;
  letter-spacing: -0.02em;
  color: var(--color-cyan);
  margin-bottom: 0.55rem;
  text-shadow: 0 2px 10px rgba(0, 0, 0, 0.28);
}
.why-card--v2 .why-card__num { color: #fff; }
.why-card__title { font-size: 1.12rem; line-height: 1.25; margin-bottom: 0.35rem; color: #fff; }
.why-card__text { font-size: 0.95rem; line-height: 1.4; color: var(--color-on-dark-soft); }
.why-card__text p + p { margin-top: 0.6em; }   /* separación entre los dos párrafos */
.why-card__text strong { color: #fff; font-weight: var(--fw-bold); }   /* keywords en negrita, realzadas sobre el fondo oscuro */

/* ---- Acordeón horizontal ligado al scroll (lo activa el JS, SOLO ≥1024) ----
   El JS escribe por ficha --g (unidades de flex-grow), --e (entrada 0..1) y --o
   (apertura 0..1); aquí solo se leen. Se animan únicamente `flex-grow` y `opacity`,
   nunca posiciones, así que no hay reflow ni parpadeos. El reparto por flex-grow
   garantiza que la fila NUNCA desborde: sea cual sea el estado, las fichas se
   reparten el ancho disponible del contenedor. */
.why-scroll.is-why { height: calc(100svh + var(--why-steps, 8) * 38svh); }
/* Secuencia YA reproducida: se suelta el pin. La sección vuelve a su altura natural
   —deja de reservar el tramo de scroll— y el envoltorio deja de ser sticky, así que
   al volver a pasar por el apartado avanza como una sección normal. Se conserva todo
   el layout del acordeón (sigue `.is-why`) y el estado final de las fichas: aquí solo
   se retiran la altura reservada y el sticky. `.why-sticky` mantiene su alto y su
   centrado, de modo que el bloque ocupa lo mismo que ocupaba fijado y nada se mueve. */
.why-scroll.is-why.is-why-free { height: auto; }
.why-scroll.is-why.is-why-free .why-sticky { position: static; }
.why-scroll.is-why .why-sticky {
  position: sticky;
  top: var(--header-h);
  height: calc(100svh - var(--header-h));
  display: flex;
  align-items: center;
}
.why-scroll.is-why .why-stage {
  flex-wrap: nowrap;
  justify-content: flex-start;
  align-items: stretch;
  gap: 0.7rem;
  height: min(58vh, 380px);
  overflow: hidden;
}
/* Absorbe las unidades de las fichas que aún no han entrado: el reparto se
   normaliza siempre sobre el total final, así la fila se va LLENANDO DESDE LA
   IZQUIERDA y con las 8 dentro ocupa el 100% exacto (sin este relleno, flexbox
   repartiría todo el ancho entre las pocas fichas ya presentes). */
.why-scroll.is-why .why-stage::after {
  content: "";
  flex: 0 1 0;
  flex-grow: var(--why-rest, 0);
}
.why-scroll.is-why .why-card {
  flex: 0 1 0;
  flex-grow: var(--g, 1);
  opacity: var(--e, 1);
  width: auto;
  min-width: 0;
  height: 100%;
  overflow: hidden;
  /* Columna estrecha con número y título (lo único que se ve contraída) + columna
     del texto, que al contraerse queda en cero y se recorta. */
  display: grid;
  grid-template-columns: minmax(0, max-content) minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr);
  /* El hueco entre columnas solo existe cuando hay texto que separar: contraída, el
     gap se comería el sitio del número aunque la columna del texto mida cero. */
  column-gap: calc(1.3rem * var(--o, 1));
  padding: 1.35rem calc(0.6rem * var(--e, 1));
  /* El relleno y el borde también van ligados a --e: con `flex-basis: 0` flexbox
     puede encoger el contenido a cero, pero NO el padding ni el borde, y las fichas
     que aún no han entrado se quedarían ocupando ~32px cada una (la fila no
     arrancaría vacía ni el reparto final cuadraría). */
  border-width: calc(1px * var(--e, 1));
}
/* El número se ajusta al ancho de la ficha CONTRAÍDA (~70px a 1024, ~92px a 1440):
   a 2.9rem fijos se recortaba por debajo de ~1200px. Mismo tipo, peso y color. */
.why-scroll.is-why .why-card__num {
  grid-area: 1 / 1;
  margin-bottom: 0.75rem;
  font-size: clamp(2.2rem, 1.2rem + 1.6vw, 2.9rem);
}
/* Desplegada: el título va en HORIZONTAL, a la derecha del número (fila 1 de la
   segunda columna). Contraída, esa columna mide cero y queda recortado. */
.why-scroll.is-why .why-card__title {
  grid-area: 1 / 2;
  align-self: center;
  margin: 0;
  opacity: var(--o, 1);
}
/* Copia VERTICAL del título para la ficha contraída, donde no cabe en horizontal.
   Va en el ::after del número —que ya es aria-hidden, así que no se duplica para
   lectores de pantalla— y hace CROSSFADE con el <h3> real a través de --o: la
   orientación no salta, se funde mientras la ficha se abre o se cierra. */
.why-scroll.is-why .why-card__num { position: relative; }
.why-scroll.is-why .why-card__num::after {
  content: attr(data-title);
  position: absolute;
  top: calc(100% + 0.4rem);
  left: 50%;
  writing-mode: vertical-rl;
  transform: translateX(-50%) rotate(180deg);
  white-space: nowrap;
  /* Mismos rasgos que .why-card__title (h3 de base.css) */
  font-family: var(--font-heading);
  font-weight: var(--fw-bold);
  font-size: 1.12rem;
  line-height: 1.25;
  letter-spacing: var(--tracking-tight);
  color: #fff;
  text-shadow: none;
  opacity: calc(1 - var(--o, 1));
}
.why-scroll.is-why .why-card__text {
  grid-area: 2 / 2;
  align-self: start;
  opacity: var(--o, 1);
}
/* Terminada la secuencia manda el cursor: ahí sí interesa una transición suave
   (durante el scrub NO, para que el movimiento vaya pegado al scroll). */
.why-scroll.is-why .why-stage.is-why-done .why-card {
  cursor: pointer;
  transition: flex-grow 0.55s var(--ease-out), opacity 0.35s var(--ease-out);
}
.why-scroll.is-why .why-stage.is-why-done .why-card__text,
.why-scroll.is-why .why-stage.is-why-done .why-card__title,
.why-scroll.is-why .why-stage.is-why-done .why-card__num::after {
  transition: opacity 0.4s var(--ease-out);
}
.why-scroll.is-why .why-card:focus-visible { box-shadow: 0 0 0 3px var(--color-cyan); }

/* =========================================================================
   Método de trabajo (timeline)
   ========================================================================= */
/* --method-dot = diámetro del círculo y --method-cols = nº de columnas: la línea de la
   timeline se calcula A PARTIR de ellos (ver .method--line::before), así que centro y
   extremos siguen siendo exactos si cambian. `--method-cols` debe coincidir con el
   repeat() de la rejilla. */
.method { --method-dot: 2.75rem; --method-cols: 5; display: grid; gap: var(--space-lg); counter-reset: step; }
/* minmax(0, 1fr): columnas EXACTAMENTE iguales (con `1fr` a secas, un texto largo puede
   ensanchar su columna y estrechar las demás, y entonces los extremos de la línea ya no
   caerían sobre los centros del primer y último círculo). */
@media (min-width: 768px) { .method { grid-template-columns: repeat(5, minmax(0, 1fr)); } }
.method-step { position: relative; padding-top: var(--space-lg); }
.method-step::before {
  counter-increment: step;
  content: counter(step);
  display: grid; place-items: center;
  width: var(--method-dot); height: var(--method-dot);
  border-radius: var(--radius-pill);
  background: var(--color-white);
  border: 2px solid var(--color-primary);
  color: var(--color-primary);
  font-family: var(--font-heading);
  font-weight: var(--fw-bold);
  margin-bottom: var(--space-md);
}
.method-step h3 { font-size: 1.1rem; margin-bottom: 0.3rem; }
.method-step p { font-size: 0.95rem; color: var(--color-ink-soft); }
.method--line { position: relative; }
@media (min-width: 768px) {
  .method--line::before {
    content: "";
    position: absolute;
    /* VERTICAL: centro exacto del círculo = padding-top del step + radio del círculo.
       El -1px centra la línea de 2px justo sobre ese punto (sin desplazarla). */
    top: calc(var(--space-lg) + var(--method-dot) / 2 - 1px);
    /* HORIZONTAL: de centro a centro de los círculos primero y último (antes iba a
       10%/90%, valores arbitrarios: dejaba fuera el primer círculo y sobresalía por la
       derecha). El 1.er círculo empieza en el borde del contenedor → su centro está a un
       radio; el último está en la última columna, de ancho (100% - (n-1)·gap) / n. */
    left: calc(var(--method-dot) / 2);
    right: calc((100% - (var(--method-cols) - 1) * var(--space-lg)) / var(--method-cols) - var(--method-dot) / 2);
    height: 2px;
    background: linear-gradient(90deg, var(--color-primary), var(--color-cyan));
    opacity: 0.35;
    z-index: 0;
  }
  .method-step { z-index: 1; }
}

/* ---- Animación de entrada de "Nuestro método" (solo la-agencia) ----
   IntersectionObserver (main.js) añade .is-visible UNA vez al contenedor
   [data-reveal]; el resto es CSS. Secuencia: la línea se dibuja de izq. a der.,
   los círculos aparecen 1→5 y, tras cada uno, su ficha (título + descripción)
   con fade-in + ligera subida. Sin JS o con motion reducido, todo se ve normal. */
.js .method--line[data-reveal] { opacity: 1; transform: none; } /* el bloque NO se oculta; anima por dentro */

@media (min-width: 768px) {
  /* La línea se dibuja de izquierda a derecha */
  .js .method--line::before {
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform 0.7s var(--ease-out);
  }
  .js .method--line.is-visible::before { transform: scaleX(1); }
}

/* Círculos numerados: aparecen escalonados 1→5 (justo cuando la línea avanza) */
.js .method--line .method-step::before {
  opacity: 0;
  transform: scale(0.4);
  transition: opacity 0.35s ease, transform 0.4s cubic-bezier(0.34, 1.45, 0.6, 1);
  transition-delay: calc(var(--i) * 160ms + 250ms);
}
.js .method--line.is-visible .method-step::before { opacity: 1; transform: scale(1); }

/* Ficha (título + descripción): fade-in + subida, justo después de su círculo */
.js .method--line .method-step h3,
.js .method--line .method-step p {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.45s ease, transform 0.5s var(--ease-out);
}
.js .method--line .method-step h3 { transition-delay: calc(var(--i) * 160ms + 430ms); }
.js .method--line .method-step p  { transition-delay: calc(var(--i) * 160ms + 520ms); }
.js .method--line.is-visible .method-step h3,
.js .method--line.is-visible .method-step p { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .js .method--line::before,
  .js .method--line .method-step::before,
  .js .method--line .method-step h3,
  .js .method--line .method-step p {
    opacity: 1; transform: none; transition: none;
  }
  .js .method--line.is-visible::before { transform: scaleX(1); }
}

/* =========================================================================
   Carrusel horizontal del método: fichas grandes, arrastrables (JS añade
   inercia, snap y contador). Identidad Alcanalytics; claro/oscuro.
   ========================================================================= */
.method-cx__bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-md); flex-wrap: wrap;
  margin-top: var(--space-lg);
}
.method-cx__hint { display: inline-flex; align-items: center; gap: 0.5rem; color: var(--color-muted); font-size: var(--fs-small); }
.method-cx__hint svg { width: 1.35rem; height: 1.35rem; color: var(--color-primary); }
.method-cx__counter {
  font-family: var(--font-heading); font-weight: var(--fw-bold);
  font-size: var(--fs-h4); letter-spacing: 0.06em; color: var(--color-muted);
}
.method-cx__counter-cur { color: var(--color-primary); }

.method-cx { margin-top: var(--space-xl); }
.method-cx__track {
  position: relative;
  display: flex;
  gap: clamp(1rem, 0.6rem + 1.4vw, 1.75rem);
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  padding-block: 0.75rem;
  padding-inline: max(var(--gutter), calc((100% - var(--container-max)) / 2));
  margin: 0;
  list-style: none;
  cursor: grab;
  user-select: none;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
  scrollbar-width: none; /* oculta la barra (Firefox) */
}
.method-cx__track::-webkit-scrollbar { display: none; } /* oculta la barra (WebKit) */
.method-cx__track.is-dragging { cursor: grabbing; scroll-snap-type: none; }

.method-cx__card {
  position: relative;
  flex: 0 0 auto;
  width: min(82vw, 940px);
  height: clamp(460px, 50vh, 480px);
  scroll-snap-align: center;
  display: flex; flex-direction: column; justify-content: space-between; gap: var(--space-lg);
  padding: clamp(1.75rem, 1.1rem + 2.6vw, 3.25rem);
  border-radius: var(--radius-xl);
  background: var(--gradient-deep);
  color: #fff;
  overflow: hidden;
  isolation: isolate;
  border: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow: var(--shadow-lg);
  transition: border-color var(--dur-base) var(--ease-out);
}
.method-cx__card.is-active { border-color: rgba(74, 190, 221, 0.55); }
/* Resplandor abstracto (tecnológico) */
.method-cx__glow {
  position: absolute; z-index: -1; inset: auto -6% auto auto; top: -14%;
  width: 62%; aspect-ratio: 1;
  background: radial-gradient(circle at 50% 50%, rgba(74, 190, 221, 0.5), transparent 62%);
  pointer-events: none;
}
/* Rejilla sutil */
.method-cx__card::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(rgba(255,255,255,0.05) 1px, transparent 1px) 0 0 / 100% 3.2rem,
    linear-gradient(90deg, rgba(255,255,255,0.05) 1px, transparent 1px) 0 0 / 3.2rem 100%;
  -webkit-mask-image: radial-gradient(130% 90% at 82% 4%, #000, transparent 62%);
  mask-image: radial-gradient(130% 90% at 82% 4%, #000, transparent 62%);
  opacity: 0.55; pointer-events: none;
}
.method-cx__top { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-md); }
.method-cx__num {
  font-family: var(--font-heading); font-weight: var(--fw-extrabold);
  font-size: clamp(3rem, 1.8rem + 5vw, 5.5rem); line-height: 0.9; letter-spacing: -0.02em;
  background: linear-gradient(140deg, #ffffff 0%, var(--color-cyan) 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.method-cx__icon {
  flex: 0 0 auto;
  width: clamp(3rem, 2.4rem + 1.2vw, 3.6rem); height: clamp(3rem, 2.4rem + 1.2vw, 3.6rem);
  display: grid; place-items: center;
  border-radius: var(--radius-md);
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.18);
  color: var(--color-cyan);
}
.method-cx__icon svg { width: 54%; height: 54%; }
/* Variante con ilustración: el icono YA trae su propio cuadrado azul con radio y
   halo, así que el marco glass (fondo + borde) sobra; si no, quedaría un cuadrado
   dentro de otro. La caja crece un 16% porque el WebP reserva ese aire alrededor
   para el halo: así el cuadrado azul acaba midiendo lo mismo que medía el marco
   al que sustituye (48 → 57,6 px según anchura). */
.method-cx__icon--img {
  width: clamp(3.5rem, 2.8rem + 1.4vw, 4.2rem); height: clamp(3.5rem, 2.8rem + 1.4vw, 4.2rem);
  background: none;
  border: 0;
  border-radius: 0;
}
.method-cx__icon--img img { width: 100%; height: 100%; object-fit: contain; display: block; }
.method-cx__body { max-width: 46ch; }
.method-cx__kicker {
  display: inline-block;
  font-family: var(--font-heading); font-weight: var(--fw-semibold);
  font-size: var(--fs-small); letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--color-cyan); margin-bottom: var(--space-sm);
}
.method-cx__title { color: #fff; font-size: clamp(1.6rem, 1.1rem + 2.2vw, 2.7rem); line-height: 1.1; margin-bottom: var(--space-sm); }
.method-cx__text { color: rgba(255, 255, 255, 0.82); font-size: 1rem; line-height: 1.5; max-width: 42ch; }
.method-cx__text strong { color: #fff; font-weight: var(--fw-bold); }   /* keywords en negrita, realzadas */

@media (max-width: 640px) {
  .method-cx__card { width: 86vw; height: clamp(370px, 48vh, 400px); }
}
@media (prefers-reduced-motion: reduce) {
  .method-cx__track { scroll-behavior: auto; }
}

/* =========================================================================
   "¿Necesitas una tienda online?" — mazo de cartas apiladas por scroll.
   Base (sin JS / reduce-motion): lista legible. Con JS: sección fijada (pin)
   y fichas que entran una a una según el progreso real del scroll.
   ========================================================================= */
.eshop-stack__head { max-width: 60ch; }
.eshop-stack__deck { display: grid; gap: var(--space-lg); margin-top: var(--space-xl); }
.eshop-card {
  position: relative;
  width: min(94%, 760px);
  min-height: clamp(230px, 32vh, 320px);
  margin-inline: auto;
  display: flex; flex-direction: column; gap: var(--space-md);
  padding: clamp(1.5rem, 1.1rem + 1.6vw, 2.5rem);
  border-radius: var(--radius-xl);
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: var(--shadow-lg);
  color: #fff;
  /* Fondo azul corporativo, ligeramente distinto por ficha (--i = 0..3) */
  background: linear-gradient(135deg, var(--color-deep-blue) 0%,
              color-mix(in srgb, var(--color-primary), var(--color-cyan) calc(var(--i, 0) * 24%)) 100%);
}
.eshop-card__num {
  font-family: var(--font-heading); font-weight: var(--fw-extrabold);
  font-size: clamp(2rem, 1.4rem + 2vw, 3rem); line-height: 1;
  background: linear-gradient(140deg, #fff, var(--color-cyan));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.eshop-card__body { flex: 1 1 auto; }
.eshop-card__title { color: #fff; font-size: clamp(1.25rem, 1rem + 1vw, 1.75rem); line-height: 1.2; margin-bottom: 0.4rem; }
.eshop-card__text { color: rgba(255, 255, 255, 0.85); font-size: 1rem; line-height: var(--lh-snug); }
.eshop-card__step {
  font-family: var(--font-heading); font-weight: var(--fw-semibold);
  font-size: var(--fs-small); letter-spacing: 0.1em; color: var(--color-cyan); align-self: flex-start;
}

/* Con JS: pin + mazo apilado animado por scroll */
.js .eshop-stack { position: relative; height: 340vh; padding-block: 0; }
.js .eshop-stack__sticky {
  position: sticky; top: var(--header-h);
  height: calc(100svh - var(--header-h));
  display: flex; flex-direction: column; overflow: hidden;
}
.js .eshop-stack__sticky > .container {
  display: flex; flex-direction: column; height: 100%;
  /* Más hueco entre el párrafo "Si ya dispones..." y las fichas (no se superponen) y
     menos padding vertical para que el mazo desplegado quepa sin cortar la ficha 4. */
  gap: clamp(1.75rem, 1.1rem + 2.4vw, 3.25rem);
  padding-block: clamp(0.75rem, 0.4rem + 1vw, 1.5rem);
}
.js .eshop-stack__head { flex: 0 0 auto; margin-bottom: 0; }
.js .eshop-stack__deck { flex: 1 1 auto; margin-top: 0; gap: 0; display: grid; place-items: center; min-height: 0; }
.js .eshop-card { grid-area: 1 / 1; opacity: 0; will-change: transform, opacity; }
@media (max-width: 768px) { .js .eshop-stack { height: 280vh; } }

/* reduce-motion: sin pin ni animación; lista vertical legible */
@media (prefers-reduced-motion: reduce) {
  .js .eshop-stack { height: auto; padding-block: var(--section-y); }
  .js .eshop-stack__sticky { position: static; height: auto; overflow: visible; }
  .js .eshop-stack__sticky > .container { display: block; height: auto; }
  .js .eshop-stack__deck { grid-auto-flow: row; place-items: stretch; gap: var(--space-lg); margin-top: var(--space-xl); }
  .js .eshop-card { grid-area: auto; opacity: 1 !important; transform: none !important; width: min(94%, 760px); }
}

/* =========================================================================
   Acordeón horizontal por scroll ("Qué hacemos" de Marketing Digital, bloque
   'expand'). Las fichas .card van SIEMPRE en fila (sin solapes, sin rotación);
   el JS ensancha la activa (flex-grow) y comprime el resto. Fallback (sin JS /
   reduce-motion / móvil): fila que envuelve. Mantiene el estilo .card actual.
   ========================================================================= */
.exp-row { display: flex; flex-wrap: wrap; gap: clamp(0.5rem, 1vw, 1rem); }
.exp-card { flex: 1 1 260px; min-width: 0; }
.exp-card > article { height: 100%; }   /* sirve tanto a .card como a .svc-card */

@media (min-width: 768px) {
  .js .exp-section.is-exp { position: relative; height: 320vh; padding-block: 0; }
  .js .exp-section.is-exp .exp-sticky {
    position: sticky; top: var(--header-h);
    height: calc(100svh - var(--header-h));
    display: flex; flex-direction: column; justify-content: center; overflow: hidden;
  }
  .js .exp-section.is-exp .exp-sticky > .container {
    display: flex; flex-direction: column; gap: var(--space-lg); width: 100%;
    /* Más aire arriba y abajo del apartado fijado (se notaba apretado en portátil). */
    padding-block: clamp(1rem, 0.6rem + 1.6vw, 3.25rem);
  }
  .js .exp-section.is-exp .exp-head { flex: 0 0 auto; margin-bottom: 0; }
  .js .exp-section.is-exp .exp-row {
    flex-wrap: nowrap; align-items: stretch;
    /* Algo más baja para dejar aire arriba/abajo dentro del apartado fijado (portátil). */
    height: min(46vh, 400px);
  }
  .js .exp-section.is-exp .exp-card {
    flex: 1 1 0; min-width: 0; overflow: hidden;
    will-change: flex-grow;
  }
  .js .exp-section.is-exp .exp-card > article { height: 100%; overflow: hidden; }
  /* Texto y enlace aparecen a medida que la ficha gana protagonismo (--act 0..1) */
  .js .exp-section.is-exp .exp-card__text,
  .js .exp-section.is-exp .exp-card__link {
    opacity: var(--act, 1);
    transition: opacity 0.25s var(--ease-out);
  }

  /* Página Web: capa de atenuación BLANCA sobre las fichas NO desplegadas para que
     destaque la activa, y su contenido DIFUMINADO. Ambas cosas van ligadas a --act
     (activa = 1 → sin velo ni desenfoque; comprimida = 0 → velo y blur máximos).
     El velo usa ::before porque .svc-card::after ya es la barra de acento; el blur
     va en los hijos directos (no en el <article>) para no desenfocar también el
     propio velo, el borde ni la sombra de la ficha. */
  .js .service-web .exp-section.is-exp .exp-card > article { position: relative; }
  .js .service-web .exp-section.is-exp .exp-card > article::before {
    content: "";
    position: absolute; inset: 0;
    border-radius: inherit;
    /* Blanco en tema claro; en oscuro, la superficie de la propia ficha. */
    background: var(--color-surface);
    opacity: calc((1 - var(--act, 1)) * 0.62);
    pointer-events: none;
    z-index: 3;
  }
  /* Sin transition: el desenfoque va ligado al scrub del scroll (como el ensanchado),
     así no arrastra retardo ni repinta de más. */
  .js .service-web .exp-section.is-exp .exp-card > article > * {
    filter: blur(calc((1 - var(--act, 1)) * 4px));
  }
  /* Solo la ficha DESPLEGADA responde al cursor. `--act` no puede gobernar
     `pointer-events` (no es interpolable), así que el JS marca con `.is-exp-open` la
     ficha más cercana al índice activo —siempre una— y aquí se apagan los eventos en
     las demás: sin :hover no hay sombra, ni borde, ni barra de acento, ni número o
     etiquetas en azul. Estas fichas no llevan enlaces, así que no se pierde ninguna
     acción. Va gateado por `.is-exp`: sin JS o en móvil el acordeón no existe y el
     hover funciona con normalidad. */
  .js .service-web .exp-section.is-exp .exp-card:not(.is-exp-open) { pointer-events: none; }
}

/* =========================================================================
   Pila vertical + columna de números por scroll ("Qué hacemos" de Marketing
   Digital, bloque 'vstack'). Fallback (sin JS / reduce-motion / móvil): lista
   vertical de fichas (números ocultos). Con JS + escritorio (.is-vstack): sección
   sticky; el scroll apila las fichas y solapa los números. Mantiene la .card actual.
   ========================================================================= */
.vst-body { display: grid; gap: var(--space-lg); }
.vst-nums { display: none; }                 /* solo en el efecto de escritorio */
.vst-cards { display: grid; gap: var(--space-lg); }
.vst-card > .card { height: 100%; }

/* Icono de marca en la parte superior de cada ficha (acotado a .vst-card, no toca
   el resto de .card del sitio). El icono ya trae su círculo azul, así que va suelto
   sobre el fondo de la ficha, sin contenedor propio. */
.vst-card .card > .vst-card__icon { display: block; margin-bottom: var(--space-md); }
.vst-card .card > .vst-card__icon img {
  width: clamp(2.9rem, 2.4rem + 1.6vw, 3.6rem);
  height: auto; display: block;
}
/* Textos algo mayores para mejor legibilidad (solo en estas fichas). Proporción
   equilibrada: título, descripción y CTA suben a la vez. */
.vst-card .card h3 { font-size: clamp(1.35rem, 1.1rem + 0.9vw, 1.8rem); line-height: 1.2; }
.vst-card .card p  { font-size: clamp(1.02rem, 0.96rem + 0.25vw, 1.18rem); line-height: 1.6; }
.vst-card .card p + p { margin-top: 0.6em; }   /* separación entre los dos párrafos */
.vst-card .card .link-arrow { font-size: 1.05rem; }

@media (min-width: 768px) {
  .js .vst-section.is-vstack { position: relative; height: 360vh; padding-block: 0; }
  .js .vst-section.is-vstack .vst-sticky {
    position: sticky; top: var(--header-h);
    height: calc(100svh - var(--header-h));
    display: flex; flex-direction: column; overflow: hidden;
  }
  .js .vst-section.is-vstack .vst-sticky > .container {
    display: flex; flex-direction: column; gap: var(--space-lg); width: 100%;
    height: 100%;                /* la cabecera arriba y el cuerpo llena el resto (sin solapar el H2) */
    padding-block: clamp(1.25rem, 1rem + 2vw, 2.5rem);
  }
  .js .vst-section.is-vstack .vst-head { flex: 0 0 auto; margin-bottom: 0; }
  .js .vst-section.is-vstack .vst-body {
    flex: 1 1 auto; min-height: 0;
    margin-top: var(--space-md); /* separa el cuerpo del H2 */
    display: grid; grid-template-columns: minmax(96px, 160px) 1fr;
    gap: clamp(1rem, 3vw, 3rem); align-items: center;
    overflow: hidden;            /* nada (fichas ni números) invade el H2, que queda arriba */
  }
  /* Columna de números (se solapan siguiendo el scroll) */
  .js .vst-section.is-vstack .vst-nums { display: block; position: relative; height: 100%; overflow: hidden; }
  .js .vst-section.is-vstack .vst-num {
    position: absolute; left: 0; top: 50%;
    font-family: var(--font-heading); font-weight: var(--fw-extrabold);
    font-size: clamp(3rem, 6.5vw, 6rem); line-height: 1; letter-spacing: -0.02em;
    color: var(--color-cyan);
    transform: translate3d(0, -50%, 0);
    will-change: transform, opacity;
  }
  /* Fichas apiladas en vertical */
  .js .vst-section.is-vstack .vst-cards { position: relative; height: min(58vh, 410px); }
  .js .vst-section.is-vstack .vst-card {
    position: absolute; inset: 0;
    will-change: transform, opacity;
  }
  .js .vst-section.is-vstack .vst-card > .card {
    height: 100%; overflow: hidden;
    box-shadow: 0 24px 60px -28px rgba(3, 30, 54, 0.55);
  }
}

/* =========================================================================
   Fichas apilables por scroll (bloque 'cards' con 'pile', p. ej. "¿Qué podemos
   construir?" de Web). Cada ficha = 2 columnas (cuerpo izq. / media der.) y queda
   temporalmente 'sticky'; la siguiente sube y se superpone formando una pila.
   Efecto 100% CSS (position:sticky + z-index): sin JS. Móvil/tablet: columna única
   (media arriba). reduce-motion o sin soporte de sticky → lista vertical normal.
   ========================================================================= */
.stk-list { display: grid; grid-template-columns: 1fr; gap: clamp(1.5rem, 5vh, 3.5rem); }
.stk-item {
  position: sticky;
  /* cada ficha se ancla un poco más abajo que la anterior → se ve el borde superior
     de las que quedan debajo (efecto de pila) sin desplazamientos laterales. */
  top: calc(var(--header-h) + 1.5rem + var(--i, 0) * 18px);
  z-index: calc(var(--i, 0) + 1);   /* la siguiente (DOM posterior) se superpone */
}
.stk-card {
  display: grid;
  grid-template-columns: 1.02fr 1fr;
  align-items: stretch;
  gap: 0;
  padding: 0;                        /* la media va a sangre; el cuerpo pone su padding */
  overflow: hidden;
  background: var(--color-surface);
  box-shadow: 0 24px 60px -28px rgba(3, 30, 54, 0.55);
}
.stk-card__body {
  display: flex; flex-direction: column; justify-content: center;
  gap: var(--space-sm);
  padding: clamp(1.75rem, 1.1rem + 2.4vw, 3rem);
}
.stk-card__n {
  font-family: var(--font-heading); font-weight: var(--fw-bold);
  font-size: var(--fs-small); letter-spacing: 0.08em;
  color: var(--color-cyan);
}
.stk-card__body h3 { font-size: var(--fs-h3); }
.stk-card__body p { color: var(--color-ink-soft); }
.stk-card__link { margin-top: var(--space-sm); }
.stk-card__media { position: relative; min-height: 100%; background: var(--color-surface-3); }
.stk-card__media img,
.stk-card__media video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; display: block;
}
.stk-card__ph { position: absolute; inset: 0; display: grid; place-items: center; }
.stk-card__ph img { width: 72px; height: 72px; opacity: 0.5; }
/* Modo 'contain': ilustraciones con fondo transparente mostradas completas sobre
   un panel de marca (como los heroes split). */
.stk-card--contain .stk-card__media { background: var(--color-surface-3); }
.stk-card--contain .stk-card__media img,
.stk-card--contain .stk-card__media video { object-fit: contain; padding: clamp(0.75rem, 2vw, 1.75rem); }

/* Separación ORGÁNICA cuerpo↔panel en las fichas `pile` con imagen (media_fit
   contain): «Tipos de proyecto web» (/web/), «Sé visible para la IA»
   (/posicionamiento-ia/) y «Qué incluye» (/marketing-360/) — los TRES bloques que
   llevan .stk-card--contain, por eso el selector va sin scope de página.
   En vez del corte recto vertical, el panel azul (--color-surface-3) bombea
   suavemente hacia el hueco izquierdo con una curva convexa (elipse muy alargada
   como ::before). Va POR DEBAJO de la imagen (z-index 1) → nunca la recorta, y la
   curva vive en el gutter del padding del cuerpo → no toca el texto. La .stk-card
   (overflow:hidden + border-radius de .card) sigue recortando el contorno exterior. */
.stk-card--contain .stk-card__media { overflow: visible; }
.stk-card--contain .stk-card__media > img,
.stk-card--contain .stk-card__media > video,
.stk-card--contain .stk-card__media > .stk-card__ph { z-index: 1; }
.stk-card--contain .stk-card__media::before {
  content: "";
  position: absolute;
  z-index: 0;                          /* por debajo de la imagen */
  --stk-curve: clamp(16px, 2.2vw, 30px);   /* profundidad del bombeo (< gutter del cuerpo) */
  top: -8%; bottom: -8%;               /* alto ~116% → el arco cubre toda la altura, sin tramos rectos */
  left: calc(-1 * var(--stk-curve));
  width: calc(2 * var(--stk-curve));   /* elipse: rx = curva → sobresale rx al gutter y rx sobre el panel */
  background: var(--color-surface-3);
  border-radius: 50%;
  pointer-events: none;
}
/* Móvil/tablet: la media va ARRIBA (banda horizontal), así que el bombeo pasa a ser
   una curva suave en el borde INFERIOR, hacia el texto (dentro de su padding). */
@media (max-width: 719.98px) {
  .stk-card--contain .stk-card__media::before {
    --stk-curve: clamp(14px, 4vw, 24px);
    top: auto; left: 50%;
    bottom: calc(-1 * var(--stk-curve));
    width: 140%; height: calc(2 * var(--stk-curve));
    transform: translateX(-50%);
  }
}

/* =========================================================================
   Fichas con inclinación 3D siguiendo el cursor (grid con [data-tilt], p. ej.
   "Cómo ayudamos" del sector Agroalimentario). Solo AÑADE la interacción: no
   cambia el diseño de la .card. JS en main.js fija el transform inline mientras
   el cursor está dentro; al salir se limpia y la ficha vuelve con la transición
   de retorno (larga). Táctil/reduce-motion: sin efecto (el JS no se activa).
   ========================================================================= */
[data-tilt] .card {
  transform-style: preserve-3d;
  will-change: transform;
  /* Retorno suave al salir (duración normal). */
  transition: transform var(--dur-base) var(--ease-out),
    box-shadow var(--dur-base) var(--ease-out),
    border-color var(--dur-base) var(--ease-out);
}
/* Mientras sigue al cursor: seguimiento casi instantáneo (tiempo real). */
[data-tilt] .card.is-tilting {
  transition: transform 0.08s linear,
    box-shadow var(--dur-base) var(--ease-out),
    border-color var(--dur-base) var(--ease-out);
}

/* Entrada destacada y dinámica: las fichas "se enderezan" en 3D (flip hacia arriba)
   al entrar en viewport. CLAVE: la animación va en el CONTENEDOR .tilt-cell (que lleva
   data-reveal), NO en la .card. Así la entrada y el tilt de hover actúan sobre elementos
   DISTINTOS y nunca compiten por el mismo transform (una animación CSS activa/retenida
   vencería al transform inline del tilt). El .tilt-cell solo envuelve; el diseño de la
   .card no cambia. IntersectionObserver añade .is-visible al contenedor; escalonado por
   posición (animation-delay). */
[data-tilt] .tilt-cell { display: flex; }
[data-tilt] .tilt-cell > .card { flex: 1 1 auto; width: 100%; }
.js [data-tilt] .tilt-cell[data-reveal] {
  opacity: 0;
  transform: perspective(1000px) rotateX(-26deg) translateY(52px) scale(0.94);
  transform-origin: 50% 100%;
}
.js [data-tilt] .tilt-cell[data-reveal].is-visible {
  opacity: 1;
  transform: none;
  animation: tiltCardIn 0.8s cubic-bezier(0.21, 1.02, 0.36, 1) backwards;
}
@keyframes tiltCardIn {
  0%   { opacity: 0; transform: perspective(1000px) rotateX(-26deg) translateY(52px) scale(0.94); }
  55%  { opacity: 1; }
  100% { opacity: 1; transform: perspective(1000px) rotateX(0) translateY(0) scale(1); }
}
/* Cascada por posición dentro de la rejilla (hasta 9; el resto entra sin retardo). */
.js [data-tilt] .tilt-cell[data-reveal]:nth-child(2).is-visible { animation-delay: 70ms; }
.js [data-tilt] .tilt-cell[data-reveal]:nth-child(3).is-visible { animation-delay: 140ms; }
.js [data-tilt] .tilt-cell[data-reveal]:nth-child(4).is-visible { animation-delay: 210ms; }
.js [data-tilt] .tilt-cell[data-reveal]:nth-child(5).is-visible { animation-delay: 280ms; }
.js [data-tilt] .tilt-cell[data-reveal]:nth-child(6).is-visible { animation-delay: 350ms; }
.js [data-tilt] .tilt-cell[data-reveal]:nth-child(7).is-visible { animation-delay: 420ms; }
.js [data-tilt] .tilt-cell[data-reveal]:nth-child(8).is-visible { animation-delay: 490ms; }
.js [data-tilt] .tilt-cell[data-reveal]:nth-child(9).is-visible { animation-delay: 560ms; }

@media (prefers-reduced-motion: reduce) {
  [data-tilt] .card { transition: none; transform: none !important; }
  .js [data-tilt] .tilt-cell[data-reveal] { opacity: 1; transform: none !important; animation: none; }
}

@media (min-width: 720px) {
  .stk-card { min-height: clamp(340px, 44vh, 460px); }
}

/* Móvil/tablet: columna única, media arriba con proporción fija. El apilado sticky
   se mantiene (funciona igual con menos altura). */
@media (max-width: 719.98px) {
  .stk-card { grid-template-columns: 1fr; }
  .stk-card__media { min-height: 0; aspect-ratio: 16 / 10; order: -1; }
  .stk-card__media img, .stk-card__media video { position: static; }
}

/* Accesibilidad: sin apilado sticky si el usuario reduce el movimiento. */
@media (prefers-reduced-motion: reduce) {
  .stk-item { position: static; }
}

/* =========================================================================
   Proyectos
   ========================================================================= */
.projects { display: grid; gap: var(--space-xl); }
@media (min-width: 800px) { .projects { grid-template-columns: repeat(2, 1fr); } }
.project-card {
  position: relative;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--color-surface-3);
  border: var(--border-soft);
  min-height: 320px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}
.project-card__media { position: absolute; inset: 0; }
.project-card__media img { width: 100%; height: 100%; object-fit: cover; }
.project-card__body {
  position: relative;
  padding: var(--space-xl);
  background: linear-gradient(0deg, rgba(5, 64, 112, 0.92), rgba(5, 64, 112, 0));
  color: #fff;
}
.project-card__body h3 { color: #fff; }

/* =========================================================================
   Automatización e IA
   ========================================================================= */
.ai-list { display: grid; gap: var(--space-md); }
.ai-list li {
  display: flex; gap: 0.75rem; align-items: flex-start;
  padding: var(--space-md) 0;
  border-bottom: 1px solid var(--color-line-dark);
}
.ai-list li:last-child { border-bottom: 0; }
.ai-list .tick {
  flex-shrink: 0;
  width: 1.6rem; height: 1.6rem;
  display: grid; place-items: center;
  border-radius: var(--radius-pill);
  background: rgba(255,255,255,0.14);
  color: #fff;
}
.ai-list .tick svg { width: 0.9rem; height: 0.9rem; }
/* Tic de marca: el icono YA es un círculo cian con check, así que el contenedor
   deja de pintar el círculo glass (fondo + place-items) para no duplicar la
   forma. Mismo tamaño 1.6rem que el tick anterior, alineado con la primera línea
   del texto (el li es flex align-items:flex-start con gap 0.75rem, sin cambios). */
.ai-list .tick--img {
  background: none;
  border-radius: 0;
  /* leve ajuste óptico: el check queda centrado en el círculo a la altura de x */
  margin-top: 0.05rem;
}
.ai-list .tick--img img { width: 100%; height: 100%; object-fit: contain; display: block; }

/* Entrada de los ítems uno a uno DESDE LA DERECHA (sección tecnología, home).
   Solo con JS; el IntersectionObserver añade .is-visible y el escalonado
   por nth-child hace que aparezcan de uno en uno. */
.js .ai-list--reveal > li[data-reveal] { transform: translateX(72px); }
.js .ai-list--reveal > li[data-reveal].is-visible { transform: none; }
.js .ai-list--reveal > li[data-reveal]:nth-child(1) { transition-delay: 40ms; }
.js .ai-list--reveal > li[data-reveal]:nth-child(2) { transition-delay: 160ms; }
.js .ai-list--reveal > li[data-reveal]:nth-child(3) { transition-delay: 280ms; }
.js .ai-list--reveal > li[data-reveal]:nth-child(4) { transition-delay: 400ms; }
.js .ai-list--reveal > li[data-reveal]:nth-child(5) { transition-delay: 520ms; }
@media (prefers-reduced-motion: reduce) {
  .js .ai-list--reveal > li[data-reveal] { transform: none; transition-delay: 0ms; }
}

/* =========================================================================
   Testimonios
   ========================================================================= */
.testimonials { display: grid; gap: var(--space-xl); }
@media (min-width: 800px) { .testimonials { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); } }
.testimonial { }
.testimonial blockquote { font-size: 1.1rem; color: var(--color-ink); margin-bottom: var(--space-md); }
.testimonial__author { font-weight: var(--fw-semibold); font-family: var(--font-heading); }
.testimonial__role { color: var(--color-muted); font-size: var(--fs-small); }

/* =========================================================================
   Últimos artículos (home)
   ========================================================================= */
.post-grid { display: grid; gap: var(--space-xl); }
@media (min-width: 700px) { .post-grid { grid-template-columns: repeat(3, 1fr); } }
.post-card {
  display: flex; flex-direction: column;
  border: var(--border-soft);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--color-surface);
  transition: box-shadow var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
}
.post-card:hover { box-shadow: var(--shadow-md); transform: translateY(-3px); }
/* En las páginas individuales de artículo, las fichas de «Artículos relacionados»
   suben un poco más al pasar el cursor (mismo gesto que las carpetas del Blog de
   inicio). Solo se redefine el translateY; el resto del hover (sombra, borde,
   color del título) sigue viniendo de `.post-card:hover`. La transición ya está
   declarada en `.post-card`. Acotado a `.article-related` para no tocar las
   rejillas de /blog/ ni de búsqueda. */
.article-related .post-card:hover { transform: translateY(-10px); }

/* ---- Entrada destacada de las fichas de artículo (SOLO la rejilla de /blog/) ----
   Reutiliza el `data-reveal` que ya traía cada ficha: la revela el
   IntersectionObserver global, una a una al entrar en pantalla. Se anula la
   transición genérica y se usa una ANIMACIÓN con `backwards`, que aplica el
   fotograma inicial durante el retardo pero NO retiene el final: al terminar, el
   transform vuelve a `none` y el `translateY(-3px)` del hover recupera el control
   (misma lección que la entrada 3D de los sectores). Las otras rejillas de
   artículos —Inicio, artículo relacionado y búsqueda— usan `.post-grid` a secas y
   conservan su fade-up. */
.js .blog-post-grid .post-card[data-reveal] {
  opacity: 0;
  transform: none;            /* el movimiento lo pone la animación, no la transición */
  transition: none;
}
.js .blog-post-grid .post-card[data-reveal].is-visible {
  opacity: 1;
  animation: postCardIn 0.9s cubic-bezier(0.22, 0.92, 0.28, 1) backwards;
}
/* La imagen se desahoga del zoom mientras la ficha se endereza (la recorta el
   `overflow: hidden` de .post-card). Va algo más lenta para que respire. */
.js .blog-post-grid .post-card[data-reveal].is-visible .post-card__media img {
  animation: postCardMediaIn 1.2s cubic-bezier(0.22, 0.92, 0.28, 1) backwards;
}
@keyframes postCardIn {
  from { opacity: 0; transform: perspective(1100px) rotateX(-16deg) translateY(52px) scale(0.94); }
  to   { opacity: 1; transform: perspective(1100px) rotateX(0deg) translateY(0) scale(1); }
}
@keyframes postCardMediaIn {
  from { transform: scale(1.14); }
  to   { transform: scale(1); }
}
/* Escalonado por COLUMNA: `.blog-post-grid` es de DOS columnas (blog.css), así que
   la segunda de cada fila entra un pelín después y la fila se lee en cascada. */
.js .blog-post-grid .post-card:nth-child(even).is-visible,
.js .blog-post-grid .post-card:nth-child(even).is-visible .post-card__media img { animation-delay: 130ms; }

@media (prefers-reduced-motion: reduce) {
  .js .blog-post-grid .post-card[data-reveal],
  .js .blog-post-grid .post-card[data-reveal].is-visible,
  .js .blog-post-grid .post-card[data-reveal].is-visible .post-card__media img {
    opacity: 1;
    animation: none;
  }
}

/* =========================================================================
   «Blog» de INICIO (#blog): ARCHIVADOR de carpetas por categoría.
   Dos carpetas por fila cuyos anchos suman siempre el 100% (reparto distinto en
   cada fila, lo pone PHP en --w). Las filas se apilan con margen negativo y
   z-index creciente, sin ningún hueco visible entre ellas.
   La silueta es UNA SOLA pieza dibujada con `clip-path: shape()`, que admite
   porcentajes (responsive) y curvas: así el contorno se recorre entero —esquinas
   exteriores, cabeza de la pestaña, diagonal y encuentro con el cuerpo— con el
   mismo redondeo, sin uniones entre piezas ni esquinas rectas. Los navegadores
   sin `shape()` caen a la composición anterior de dos piezas (ver @supports).
   ========================================================================= */
#blog .section-head { max-width: none; }   /* el H2 lo limitaba `.section-head` */
#blog .section-head p strong { color: var(--color-ink); font-weight: var(--fw-bold); }   /* keywords en negrita del intro */

.fld-stage {
  display: flex;
  flex-wrap: wrap;
  gap: 0;
  /* Alto FIJO: las dos carpetas de una fila miden lo mismo aunque su ancho
     cambie, y permite calcular el solape en función de la altura. */
  --fld-h: clamp(158px, 14.9vw, 224px);
  --fld-r: 20px;                 /* redondeo de las esquinas */
  --fld-tab-h: 30%;              /* alto de la pestaña */
  --fld-tab-w: 52%;              /* ancho de la pestaña */
  --fld-slant: 7%;               /* recorrido del corte diagonal */
  /* Solape entre filas. Tiene que superar el alto de la pestaña (34%): si no, la
     zona transparente de la fila de abajo deja ver el fondo y aparece una franja
     blanca. Pero cuanto mayor es el solape, más se acerca la fila de abajo al
     contenido de la de arriba: por eso la carpeta es algo más alta y el solape se
     queda en 32% —justo por encima del 30% de la pestaña—, que deja hueco incluso
     con el nombre de la categoría en dos líneas (con 0.42 solo quedaban 9.8px). */
  --fld-lap: calc(var(--fld-h) * 0.32);
}
.fld {
  position: relative;
  width: var(--w);
  height: var(--fld-h);
  flex: 0 0 auto;
  /* Orden de apilado por CAPA REAL, no solo por fila: dentro de cada fila la
     carpeta DERECHA (col 1) queda por delante de la izquierda (col 0), y cada
     fila por delante de la anterior. Así, en cada costura —vertical entre
     columnas, horizontal entre filas— la carpeta de delante proyecta su sombra
     sobre la de detrás, y se lee qué está delante/detrás aunque el color sea
     el mismo. (El hover sube a z-index 60 y gana a todas.) */
  z-index: calc(var(--row, 0) * 2 + var(--col, 0) + 1);
  color: var(--fg);
  text-decoration: none;
  /* Profundidad SUTIL respetando la silueta (un box-shadow lo recortaría el
     clip-path; el drop-shadow sí sigue el contorno). Dos capas muy tenues: una
     de contacto corta que asienta el borde inferior de cada carpeta, y otra
     difusa y de baja opacidad que da la profundidad general. Poco desplazamiento,
     mucho desenfoque en la segunda → acabado elegante, casi imperceptible, sin
     efecto «tarjeta flotante». El halo difuso cae sobre la carpeta de detrás en
     cada solape (por el z-index escalonado) y marca la separación. */
  filter:
    drop-shadow(0 1px 1.5px rgba(5, 64, 112, 0.14))
    drop-shadow(0 5px 14px rgba(5, 64, 112, 0.16));
  /* La opacidad se gobierna SIEMPRE por esta variable: la regla de entrada
     (`.js .fld-stage[data-reveal].is-visible .fld`) tiene más especificidad que
     cualquier selector de hover razonable, así que si fijara `opacity: 1`
     directamente la atenuación nunca llegaría a aplicarse. */
  opacity: var(--fld-op, 1);
  transition: opacity 0.4s var(--ease-out), transform 0.4s var(--ease-out);
  /* El rectángulo de la carpeta incluye el hueco transparente de arriba a la
     derecha, y las filas se solapan: si el enlace capturara todo su rectángulo,
     el cursor activaría la carpeta de encima estando sobre la de debajo. Solo
     responden las capas que se ven de verdad (el clip-path recorta el hit-test). */
  pointer-events: none;
}
.fld__shape,
.fld__tab,
.fld__body { pointer-events: auto; }
/* Desde la tercera carpeta empieza la segunda fila: cada una sube --fld-lap y el
   efecto se acumula solo (la fila N ya parte de una fila N-1 más alta). */
.fld:nth-child(n + 3) { margin-top: calc(var(--fld-lap) * -1); }

/* SILUETA COMPLETA en una sola pieza. `shape()` acepta porcentajes (la carpeta
   sigue siendo elástica) y curvas, así que el contorno se recorre de una vez:
   esquina · pestaña · diagonal · cuerpo, sin costuras entre elementos.
   Cada esquina se redondea con una cuadrática cuyo punto de control ES el
   vértice: la curva sale tangente a los dos lados, así que vale tanto para las
   esquinas rectas (mismo aspecto que un `border-radius` de --fld-r) como para
   los dos ángulos oblicuos de la diagonal —la cabeza de la pestaña y el
   encuentro con el cuerpo, que es cóncavo y ningún `border-radius` podría
   redondear—. En la diagonal el redondeo se mide en fracción de su recorrido
   (0.26 / 0.74) para que sea proporcional sea cual sea la altura de la ficha. */
.fld__shape {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--c);
  clip-path: shape(
    from 0 var(--fld-r),
    curve to var(--fld-r) 0 with 0 0,                                   /* sup. izquierda */
    hline to calc(var(--fld-tab-w) - var(--fld-r) * 0.7),
    curve to calc(var(--fld-tab-w) + var(--fld-slant) * 0.26)
             calc(var(--fld-tab-h) * 0.26)
        with var(--fld-tab-w) 0,                                        /* cabeza de la pestaña */
    line to calc(var(--fld-tab-w) + var(--fld-slant) * 0.74)
            calc(var(--fld-tab-h) * 0.74),                              /* corte diagonal */
    curve to calc(var(--fld-tab-w) + var(--fld-slant) + var(--fld-r) * 0.7)
             var(--fld-tab-h)
        with calc(var(--fld-tab-w) + var(--fld-slant)) var(--fld-tab-h), /* pie de la diagonal */
    hline to calc(100% - var(--fld-r)),
    curve to 100% calc(var(--fld-tab-h) + var(--fld-r)) with 100% var(--fld-tab-h),
    vline to calc(100% - var(--fld-r)),
    curve to calc(100% - var(--fld-r)) 100% with 100% 100%,             /* inf. derecha */
    hline to var(--fld-r),
    curve to 0 calc(100% - var(--fld-r)) with 0 100%,                   /* inf. izquierda */
    close
  );
}
/* La pestaña ya no es una pieza aparte: forma parte del contorno de arriba. */
.fld__tab { display: none; }

/* Respaldo para navegadores sin `shape()`: la composición anterior de dos piezas
   del mismo color (cuerpo + pestaña recortada). El vértice de la diagonal cae
   ahora justo en la línea del cuerpo —antes se calculaba mezclando % y px y se
   quedaba corto, dejando un escalón vertical antes del cuerpo—; la pestaña
   monta 1px sobre él para que la unión no deje una línea de fondo. */
@supports not (clip-path: shape(from 0px 0px, close)) {
  .fld__shape {
    top: var(--fld-tab-h);
    clip-path: none;
    border-radius: var(--fld-r);
  }
  .fld__tab {
    display: block;
    position: absolute;
    left: 0;
    top: 0;
    z-index: 1;
    width: calc(var(--fld-tab-w) + var(--fld-slant));
    height: calc(var(--fld-tab-h) + 1px);
    background: var(--c);
    border-radius: var(--fld-r) var(--fld-r) 0 0;
    clip-path: polygon(
      0 0,
      calc(var(--fld-tab-w) / (var(--fld-tab-w) + var(--fld-slant)) * 100%) 0,
      100% 100%,
      0 100%
    );
  }
}

/* Contenido arriba a la izquierda, dentro de la pestaña. */
.fld__body {
  position: absolute;
  z-index: 2;
  left: clamp(1.15rem, 2.2vw, 2rem);
  top: clamp(0.85rem, 1.8vw, 1.4rem);
  right: 46%;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.fld__num {
  font-family: var(--font-heading);
  font-weight: var(--fw-bold);
  font-size: 0.76rem;
  letter-spacing: 0.14em;
  opacity: 0.7;
}
.fld__name {
  font-family: var(--font-heading);
  font-weight: var(--fw-bold);
  font-size: clamp(1.05rem, 0.72rem + 1.05vw, 1.65rem);
  line-height: 1.1;
  letter-spacing: var(--tracking-tight);
  /* Tope de dos líneas: una categoría de nombre largo no debe empujar el contador
     hasta la zona que cubre la fila siguiente. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}
.fld__count {
  margin-top: 0.15rem;
  font-family: var(--font-heading);
  font-weight: var(--fw-medium);
  font-size: var(--fs-small);
  opacity: 0.72;
}

/* Miniaturas: en reposo quedan DENTRO de la carpeta, tapadas por la silueta
   (z-index menor). No hay fade: lo que las oculta es la propia carpeta. */
.fld__docs { position: absolute; inset: 0; z-index: 0; display: block; }
.fld__doc {
  position: absolute;
  left: calc(53% + var(--d) * 14.5%);
  bottom: 7%;
  width: 21%;
  overflow: hidden;
  border-radius: 5px;
  background: var(--color-surface);
  box-shadow: 0 8px 16px -10px rgba(5, 64, 112, 0.55);
  transform: translateY(0) rotate(0deg) scale(0.97);
  transition: transform 0.55s var(--ease-out);
  transition-delay: calc(var(--d) * 70ms);
}
.fld__doc img { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }

/* HOVER: la carpeta pasa al frente, las demás bajan de contraste y la activa SUBE
   ligeramente en Y. Ese translateY es el ÚNICO transform de `.fld` (ni el reposo
   ni el resto del hover lo usan: la silueta no se deforma y las miniaturas se
   mueven en su propia capa `.fld__doc`), así que no pisa nada. El z-index a 60
   evita que la carpeta que sube quede tapada por las superpuestas. */
.fld-stage:hover .fld,
.fld-stage:focus-within .fld { --fld-op: 0.55; }
.fld-stage:hover .fld:hover,
.fld-stage:focus-within .fld:focus-visible { --fld-op: 1; z-index: 60; transform: translateY(-10px); }
.fld:hover .fld__doc,
.fld:focus-visible .fld__doc {
  transform: translateY(-118%) rotate(calc((var(--d) - 1) * 6deg)) scale(1);
}

/* ---- Entrada escalonada desde abajo ----
   El disparador es el bloque entero (un solo `data-reveal`), así que la cascada
   sale siempre en orden: fila 1, luego fila 2… y dentro de cada fila la izquierda
   antes que la derecha (--delay lo calcula PHP). El propio contenedor no se oculta.
   `backwards` deja el estado final en `none`: la geometría no queda tocada. */
.js .fld-stage[data-reveal] { opacity: 1; transform: none; transition: none; }
.js .fld-stage[data-reveal] .fld { opacity: 0; }
.js .fld-stage[data-reveal].is-visible .fld {
  opacity: var(--fld-op, 1);
  animation: fldIn 0.75s var(--ease-out) var(--delay, 0ms) backwards;
}
@keyframes fldIn {
  from { opacity: 0; transform: translateY(42px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* Móvil/tablet: una columna a ancho completo, sin solape y sin miniaturas. */
@media (max-width: 767px) {
  .fld-stage { --fld-h: clamp(132px, 36vw, 160px); }
  .fld { width: 100%; }
  .fld:nth-child(n + 3) { margin-top: 0; }
  .fld + .fld { margin-top: 0.5rem; }
  .fld-stage:hover .fld { --fld-op: 1; }
  .fld__docs { display: none; }
  .fld__body { right: 34%; }
}

@media (prefers-reduced-motion: reduce) {
  .fld, .fld__doc { transition: none; }
  .js .fld-stage[data-reveal] .fld,
  .js .fld-stage[data-reveal].is-visible .fld { opacity: var(--fld-op, 1); animation: none; }
}
.post-card__media { aspect-ratio: 16 / 9; background: var(--color-surface-3); overflow: hidden; }
.post-card__media img { width: 100%; height: 100%; object-fit: cover; }
.post-card__body { padding: var(--space-lg); display: flex; flex-direction: column; gap: 0.5rem; flex: 1; }
.post-card__meta { font-size: var(--fs-small); color: var(--color-muted); display: flex; gap: 0.6rem; flex-wrap: wrap; }
.post-card__body h3 { font-size: 1.15rem; }
.post-card__body h3 a { color: var(--color-ink); }
.post-card__body h3 a:hover { color: var(--color-primary); }
.post-card__excerpt { color: var(--color-ink-soft); font-size: 0.96rem; flex: 1; }

/* =========================================================================
   Banda CTA final
   ========================================================================= */
.cta-band {
  border-radius: var(--radius-xl);
  padding: clamp(2.5rem, 1.5rem + 4vw, 5rem);
  text-align: center;
  color: #fff;
  background: var(--gradient-brand-135);
  position: relative;
  overflow: hidden;
}
.cta-band h2 { color: #fff; max-width: 20ch; margin-inline: auto; }
.cta-band p { color: rgba(255,255,255,0.9); max-width: 52ch; margin: var(--space-md) auto 0; font-size: var(--fs-lead); }
.cta-band .cluster { justify-content: center; margin-top: var(--space-2xl); }

/* =========================================================================
   Página genérica / hero interior
   ========================================================================= */
.page-hero {
  padding-top: clamp(2.5rem, 2rem + 3vw, 4.5rem);
  padding-bottom: clamp(2rem, 1.5rem + 2vw, 3.5rem);
}
.page-hero__inner { max-width: 46rem; }
.page-hero h1 { margin-bottom: var(--space-md); }
.page-hero .lead { max-width: 52ch; }

/* Hero partido con ilustración (servicios/sectores) */
.page-hero__grid { align-items: center; gap: clamp(2rem, 1rem + 3vw, 4rem); }
@media (min-width: 900px) { .page-hero__grid { grid-template-columns: 1.1fr 0.9fr; } }
.page-hero__media { will-change: transform; }
.page-hero__media img { width: 100%; height: auto; border-radius: var(--radius-lg); }

/* =========================================================================
   Easter egg de la cabecera de La Agencia: un pequeño gráfico decorativo que,
   al pulsarlo, dispara una lluvia de piezas de marketing/datos con gravedad y
   rebotes dentro del propio hero (física y dibujo en canvas; ver [data-egg] en
   main.js). Solo escritorio con ratón; sin JS o con motion reducido no aparece
   ni el disparador, así que la cabecera queda exactamente como estaba.
   ========================================================================= */
/* El envoltorio NO recorta: es el ancla del disparador (que entra volando desde fuera)
   y del mensaje. La cabecera sí recorta, para que ninguna pieza salga de la sección. */
.page-hero-wrap { position: relative; }
.page-hero--egg { position: relative; overflow: hidden; }
.page-hero--egg > .container { position: relative; z-index: 1; }
.egg-canvas {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  z-index: 0;
  pointer-events: none;       /* nunca estorba a enlaces ni botones */
}
.egg-trigger {
  position: absolute;
  z-index: 2;
  right: clamp(1.5rem, 5vw, 5.5rem);
  /* A la altura de las migas de pan: mismo padding superior que .page-hero más media
     línea, y el translateY(-50%) la centra sobre esa fila. */
  top: calc(clamp(2.5rem, 2rem + 3vw, 4.5rem) + 1.72rem);
  width: 68px; height: 68px;  /* esfera de 64px + holgura de pulsación */
  display: none;              /* solo donde el hero tiene sitio libre (ver media query) */
  place-items: center;
  padding: 2px;
  border: 0; background: none;
  cursor: pointer;
  opacity: 0.5;
  transform: translateY(-50%);
  transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
}
.egg-trigger svg { width: 100%; height: 100%; overflow: visible; }

/* ---- Esfera de datos (activador) ----
   Nube de nodos con sus enlaces: en reposo es un detalle gráfico discreto; al pasar el
   cursor los nodos se separan un poco y la esfera gira despacio; al pulsar se
   descompone hacia fuera (de ahí sale la explosión) y vuelve a recomponerse. */
.egg-sphere__halo { fill: none; stroke: var(--color-primary); stroke-width: 0.6; opacity: 0.16; }
.egg-sphere__links line { stroke: var(--color-primary); stroke-width: 0.5; }
.egg-sphere__links { transition: opacity var(--dur-base) var(--ease-out); }
.egg-sphere__node {
  fill: var(--color-primary);
  transform-box: fill-box;
  transform-origin: center;
  transition: transform 0.45s cubic-bezier(0.22, 0.9, 0.3, 1), opacity 0.35s var(--ease-out);
}
.egg-sphere__node.is-cyan { fill: var(--color-cyan); }
.egg-sphere__node.is-deep { fill: var(--color-deep-blue); }
/* Gira siempre (llama la atención); al pasar el cursor acelera. */
.egg-sphere__spin {
  transform-origin: 20px 20px;
  animation: eggSphereSpin 26s linear infinite;
}

/* Insinúa que es interactiva: se levanta, los nodos respiran y la esfera gira */
.egg-trigger:hover, .egg-trigger:focus-visible { opacity: 1; transform: translateY(-50%) translateY(-3px) scale(1.06); }
.egg-trigger:hover .egg-sphere__node,
.egg-trigger:focus-visible .egg-sphere__node {
  transform: translate(calc(var(--dx) * 1.6px), calc(var(--dy) * 1.6px));
}
.egg-trigger:hover .egg-sphere__links,
.egg-trigger:focus-visible .egg-sphere__links { opacity: 0.55; }
.egg-trigger:hover .egg-sphere__spin,
.egg-trigger:focus-visible .egg-sphere__spin { animation-duration: 9s; }
@keyframes eggSphereSpin { to { transform: rotate(360deg); } }

/* Al pulsar: los nodos salen disparados hacia fuera (misma dirección que la explosión)
   y se desvanecen; después vuelven solos a su sitio. */
.egg-trigger.is-bursting .egg-sphere__node {
  transform: translate(calc(var(--dx) * 13px), calc(var(--dy) * 13px)) scale(0.55);
  opacity: 0;
  transition: transform 0.28s cubic-bezier(0.3, 0, 0.7, 0.2), opacity 0.28s ease-out;
}
.egg-trigger.is-bursting .egg-sphere__links { opacity: 0; transition-duration: 0.16s; }
.egg-trigger.is-bursting .egg-sphere__halo { opacity: 0; }
.egg-trigger:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 6px; border-radius: var(--radius-sm); }
.egg-trigger:active { transform: translateY(-50%) scale(0.94); }
/* Retroceso del conjunto al disparar (la esfera "se vacía" hacia fuera) */
.egg-trigger.is-bursting { animation: eggRecoil 0.5s var(--ease-out); }
@keyframes eggRecoil {
  0% { transform: translateY(-50%) scale(1); }
  22% { transform: translateY(-50%) scale(1.16); }
  100% { transform: translateY(-50%) scale(1); }
}
/* Entrada al cargar: sale de debajo del viewport y centrado en horizontal (el JS mide
   el desplazamiento exacto en --egg-in-x/--egg-in-y) y salta hasta su sitio con un
   rebote muy corto. `backwards` mantiene el fotograma inicial durante el retardo y, al
   terminar, el transform vuelve al del CSS (hover/active siguen mandando). Una sola vez. */
.egg-trigger.is-entering {
  animation: eggIn 1.15s cubic-bezier(0.22, 0.85, 0.28, 1) 0.35s backwards;
}
@keyframes eggIn {
  0%   { transform: translate(var(--egg-in-x, 0px), calc(-50% + var(--egg-in-y, 60vh))) scale(0.7) rotate(-12deg); opacity: 0; }
  12%  { opacity: 1; }
  66%  { transform: translate(0, calc(-50% - 15px)) scale(1.09) rotate(3deg); opacity: 1; }
  84%  { transform: translate(0, calc(-50% + 4px)) scale(0.98) rotate(-1deg); }
  100% { transform: translate(0, -50%) scale(1) rotate(0); opacity: 1; }
}
/* Mensaje ocasional tras varios clics */
.egg-msg {
  position: absolute;
  z-index: 2;
  left: 50%; bottom: clamp(0.75rem, 2vw, 1.5rem);
  transform: translateX(-50%) translateY(6px);
  margin: 0;
  padding: 0.45rem 0.9rem;
  border-radius: var(--radius-pill);
  background: var(--color-primary);
  color: #fff;
  font-family: var(--font-heading);
  font-size: var(--fs-small);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-wide);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.4s var(--ease-out), transform 0.4s var(--ease-out);
}
.egg-msg.is-on { opacity: 1; transform: translateX(-50%) translateY(0); }
@media (min-width: 900px) { .egg-trigger { display: grid; } }
@media (prefers-reduced-motion: reduce) { .egg-trigger, .egg-canvas, .egg-msg { display: none; } }
html:not(.js) .egg-trigger, html:not(.js) .egg-msg { display: none; }

/* =========================================================================
   Easter egg de RESEÑAS de Google (cabecera de páginas internas, arriba a la
   izquierda). Componente reutilizable: se integra una sola vez vía breadcrumbs.php
   (nunca en la portada). Distinto del egg de "La Agencia" (que va arriba a la
   derecha), así que conviven sin solaparse. Badge discreto → tarjeta al pulsar.
   ========================================================================= */
/* Contexto de posicionamiento: el egg vive dentro de .container del hero. */
.page-hero > .container,
.article-hero > .container { position: relative; }

.rev-egg {
  position: absolute;
  right: 0;                      /* parte DERECHA del hero */
  /* A la ALTURA de las migas de pan (mismo criterio que la esfera de La Agencia):
     desde el borde superior de .container (que empieza en el padding-top del hero)
     bajamos ~1.72rem hasta el centro de la fila de migas y centramos con translateY. */
  top: 1.72rem;
  bottom: auto;
  transform: translateY(-50%);
  z-index: 4;
}
html:not(.js) .rev-egg { display: none; }   /* sin JS el botón no abre nada: se oculta */

/* --- Estado cerrado: badge (Google + estrella) --- */
.rev-egg__trigger {
  display: inline-grid;
  place-items: center;
  width: clamp(38px, 1.9rem + 1.2vw, 50px);
  height: clamp(38px, 1.9rem + 1.2vw, 50px);
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  border-radius: 50%;
  -webkit-tap-highlight-color: transparent;
  animation: revEggIn 0.7s var(--ease-out) 0.45s backwards;
}
.rev-egg__badge {
  position: relative;
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  background: var(--color-surface, #fff);
  border: 1.5px solid rgba(8, 114, 187, 0.28);
  border-radius: 50%;
  box-shadow: var(--shadow-sm);
  transition: transform var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
  overflow: visible;   /* la estrella orbita por fuera del borde */
}
@supports (border-color: color-mix(in srgb, red, blue)) {
  .rev-egg__badge { border-color: color-mix(in srgb, var(--color-primary) 32%, transparent); }
}
.rev-egg__g { display: block; width: clamp(15px, 1.4vw, 19px); height: auto; }
/* La estrella DA VUELTAS alrededor del círculo con la G: un envoltorio del tamaño del
   badge gira, y la estrella colocada en su borde superior traza la órbita. */
.rev-egg__orbit {
  position: absolute;
  inset: -9px;                 /* órbita bastante mayor que el badge → radio de giro más amplio */
  pointer-events: none;
  animation: revEggOrbit 7s linear infinite;
}
.rev-egg__badge-star {
  position: absolute;
  top: -0.66em;
  left: 50%;
  transform: translateX(-50%);
  font-size: 0.8rem;
  line-height: 1;
  color: #fbbc04;
  text-shadow: 0 0 3px rgba(255, 255, 255, 0.95), 0 1px 2px rgba(8, 114, 187, 0.28);
}
@keyframes revEggOrbit { to { transform: rotate(360deg); } }
/* Hover / foco: se eleva, crece y muestra un ligero resplandor. */
.rev-egg__trigger:hover .rev-egg__badge,
.rev-egg__trigger:focus-visible .rev-egg__badge {
  transform: translateY(-2px) scale(1.08);
  box-shadow: 0 6px 18px rgba(8, 114, 187, 0.28), var(--shadow-sm);
}
.rev-egg__trigger:active .rev-egg__badge { transform: scale(0.95); }
.rev-egg__trigger:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 3px; }

@keyframes revEggIn {
  0%   { opacity: 0; transform: translateY(-12px) scale(0.7); }
  60%  { opacity: 1; }
  100% { opacity: 1; transform: none; }
}

/* --- Tarjeta desplegable (popover) --- */
.rev-egg__card {
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;                      /* se abre alineada a la derecha (egg a la derecha) */
  width: 260px;
  max-width: min(78vw, 320px);
  padding: var(--space-md);
  background: var(--color-surface, #fff);
  border: 1px solid rgba(8, 114, 187, 0.14);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  color: var(--color-ink);
  text-align: left;
  z-index: 5;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px) scale(0.97);
  transform-origin: top right;
  transition: opacity 0.25s var(--ease-out), transform 0.25s var(--ease-out), visibility 0s linear 0.25s;
}
.rev-egg.is-open .rev-egg__card {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity 0.25s var(--ease-out), transform 0.25s var(--ease-out);
}
.rev-egg__card-head { display: flex; align-items: baseline; gap: 0.4rem; }
.rev-egg__card-head .rev-egg__g { align-self: center; }
.rev-egg__score { font-family: var(--font-heading); font-weight: var(--fw-bold); font-size: 1.6rem; color: var(--color-ink); line-height: 1; }
.rev-egg__out { font-size: 0.9rem; color: var(--color-ink-soft); font-weight: 600; }
.rev-egg__stars { margin-top: 0.35rem; letter-spacing: 0.1em; font-size: 1.05rem; }
.rev-egg__star { color: rgba(11, 31, 51, 0.18); }
.rev-egg__star.is-full { color: #fbbc04; }
.rev-egg__star.is-half { position: relative; color: rgba(11, 31, 51, 0.18); }
.rev-egg__star.is-half::before { content: "★"; position: absolute; left: 0; top: 0; width: 50%; overflow: hidden; color: #fbbc04; }
.rev-egg__count { margin: 0.55rem 0 0; font-size: var(--fs-small); color: var(--color-ink-soft); }
.rev-egg__cert {
  margin-top: 0.7rem; padding-top: 0.6rem;
  border-top: 1px solid rgba(8, 114, 187, 0.12);
  display: flex; align-items: center; gap: 0.55rem;
}
.rev-egg__cert-text { font-size: 0.72rem; color: var(--color-ink-soft); line-height: 1.3; }
.rev-egg__cert-logo { height: 26px; width: auto; max-width: 116px; object-fit: contain; flex-shrink: 0; }

/* Responsive: en móvil el badge algo más pequeño y la tarjeta acotada a pantalla. */
/* Aire en el margen derecho del egg en MÓVIL y TABLET (menú hamburguesa, <1024px):
   ahí el contenedor ocupa todo el ancho, así que se alinea con el gutter del contenido
   en vez de quedar pegado al borde. En escritorio (≥1024) se mantiene right:0. */
@media (max-width: 1023px) {
  .rev-egg { right: var(--gutter); }
}
@media (max-width: 600px) {
  .rev-egg__card { width: min(84vw, 280px); }
}

@media (prefers-reduced-motion: reduce) {
  .rev-egg__trigger { animation: none; }
  .rev-egg__orbit { animation: none; }
  .rev-egg__card { transition: opacity 0.001s linear, visibility 0s; }
  .rev-egg__trigger:hover .rev-egg__badge,
  .rev-egg__trigger:focus-visible .rev-egg__badge { transform: none; }
}

/* La Agencia: el otro easter egg (esfera) va a la altura de las migas, a la derecha pero
   desplazado hacia dentro (right: clamp(1.5rem…5.5rem)). El de reseñas queda en right:0
   (más al borde) sobre la MISMA fila de migas, sin solaparse: la esfera termina antes de
   donde empieza el badge de reseñas. No se necesita desplazamiento vertical especial. */

/* =========================================================================
   Fichas con tilt 3D + luz que sigue al cursor + parallax por capas
   (pilares de La Agencia, [data-cardfx]). El JS escribe en línea el transform de
   la tarjeta y de sus tres capas (icono/título/texto, con `data-fx` como peso) y
   la posición del halo en --mx/--my; el CSS pone las transiciones. Solo con ratón
   fino: en táctil y con motion reducido queda el hover normal de .card--hover.
   Solo transforms y opacidad → sin reflow ni saltos de maquetación.
   ========================================================================= */
.cardfx-grid { perspective: 1000px; }
/* Pilares de La Agencia: 3 columnas en escritorio (regla global de .grid--3), 2 en
   tablet y 1 en móvil (por debajo de 768 ya lo hace la regla global de layout.css).
   Las otras rejillas con efecto conservan su propio responsive. */
@media (min-width: 769px) and (max-width: 1023px) {
  .grid--3.cardfx-grid { grid-template-columns: repeat(2, 1fr); }
}
.cardfx { position: relative; overflow: hidden; transform-style: preserve-3d; }
.cardfx__glow {
  position: absolute;
  inset: 0;
  z-index: 0;
  opacity: 0;
  pointer-events: none;
  background: radial-gradient(240px circle at var(--mx, 50%) var(--my, 50%),
    rgba(8, 114, 187, 0.16), rgba(74, 190, 221, 0.07) 45%, transparent 72%);
  transition: opacity 0.4s var(--ease-out);
}
.cardfx > *:not(.cardfx__glow) { position: relative; z-index: 1; }
/* Las capas se marcan con data-fx (peso del parallax), así el efecto vale para
   cualquier ficha sin depender de sus clases. */
.cardfx [data-fx] {
  transition: transform 0.55s var(--ease-out);
  will-change: transform;
}
/* Mientras el cursor está dentro, el seguimiento es casi inmediato; al salir, el
   retorno usa la transición larga de arriba. */
.cardfx.is-fx { will-change: transform; }
.cardfx.is-fx .cardfx__glow { opacity: 1; }
.cardfx.is-fx,
.cardfx.is-fx [data-fx] {
  transition: transform 0.12s linear;
}

/* ---- Entrada "baraja que se despliega" ----
   El JS mide cuánto tiene que viajar cada ficha hasta el centro de la fila y lo deja
   en --fx-dx (px) junto con su giro (--fx-ry/--fx-rz), el avance en Z (--fx-tz) y su
   turno en el stagger (--fx-delay). Con `.is-armed` las fichas arrancan agrupadas en
   el centro, encogidas, giradas y solapadas (z-index por cercanía al centro); al
   entrar en pantalla, `.is-open` las lleva a su posición REAL (transform:none) y a
   partir de ahí manda el hover. Se dispara una sola vez. */
.cardfx-grid.is-armed .cardfx {
  transform: translate3d(var(--fx-dx, 0px), var(--fx-dy, 18px), var(--fx-tz, 0px))
    rotateY(var(--fx-ry, 0deg)) rotateX(var(--fx-rx, 7deg)) rotateZ(var(--fx-rz, 0deg))
    scale(var(--fx-scale, 0.82));
  opacity: 0.25;
  z-index: var(--fx-z, 1);
  transition: transform 0.95s cubic-bezier(0.22, 0.72, 0.24, 1) var(--fx-delay, 0ms),
    opacity 0.5s var(--ease-out) var(--fx-delay, 0ms);
  will-change: transform, opacity;
}
.cardfx-grid.is-armed.is-open .cardfx {
  transform: none;
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .cardfx__glow { display: none; }
  .cardfx [data-fx] { transition: none; transform: none !important; }
}

/* ---- Pilares de La Agencia (.pillar): acabado del estado NORMAL ----
   Solo estética en reposo (fondo, acento, numeración, icono y jerarquía). NO toca
   el hover de `.card--hover` ni el tilt/halo/parallax de [data-cardfx]: no se
   declara ninguna transición ni transform nuevos, así que el JS sigue mandando.
   Todo va bajo `.pillar` para no alcanzar a las otras rejillas con cardfx
   (#confianza de Inicio y «Contacto directo» de Contacto). */
/* El mismo acabado sirve a los tres formatos: pilares de La Agencia (.card),
   «Prueba de confianza» de Inicio (.card.trust-card) y «Contacto directo»
   (.contact-card, que NO es .card y trae su propio fondo y radio). */
.card.pillar,
.contact-card.pillar {
  /* Gradiente muy ligero: el panel de marca se insinúa en la esquina superior
     izquierda y se disuelve en la superficie antes de llegar al texto. */
  background: linear-gradient(158deg, var(--color-surface-3), var(--color-surface) 58%);
  /* Radio de la ficha; de aquí sale el del trazo perimetral. */
  --pillar-r: var(--radius-md);
}
.contact-card.pillar { --pillar-r: var(--radius-lg); }
/* Acento: barra corta con el gradiente de marca sobre el borde superior. */
.pillar::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
  width: 46px;
  height: 3px;
  border-radius: 0 0 3px 0;
  background: var(--gradient-brand);
}
/* Detalle de datos: retícula de puntos en la esquina inferior derecha, muy tenue y
   difuminada hacia el contenido con una máscara (nunca compite con el texto). */
.pillar::after {
  content: "";
  position: absolute;
  right: 0;
  bottom: 0;
  z-index: 0;
  width: 118px;
  height: 86px;
  pointer-events: none;
  opacity: 0.16;
  background-image: radial-gradient(circle, var(--color-primary) 1px, transparent 1.2px);
  background-size: 13px 13px;
  -webkit-mask-image: linear-gradient(302deg, #000 10%, transparent 66%);
  mask-image: linear-gradient(302deg, #000 10%, transparent 66%);
}
/* Numeración 01/02/03: ancla la esquina superior derecha sin pesar. El selector es
   compuesto porque `.cardfx > *:not(.cardfx__glow)` (misma especificidad) la
   pondría en `position: relative`. Sin `data-fx` → se queda quieta con el tilt. */
.pillar > .pillar__num {
  position: absolute;
  top: clamp(1.2rem, 0.95rem + 0.8vw, 1.85rem);
  right: clamp(1.5rem, 1.2rem + 1vw, 2.25rem);
  font-family: var(--font-heading);
  font-weight: var(--fw-extrabold);
  font-size: clamp(1.75rem, 1.4rem + 1.1vw, 2.35rem);
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: rgba(8, 114, 187, 0.16);
}
/* Icono: mismo tamaño de siempre, pero con tinte de marca y un aro interior fino
   que lo separa del fondo y refuerza la jerarquía icono > título > texto. */
.pillar .card__icon {
  background: var(--color-surface-3);
  box-shadow: inset 0 0 0 1px rgba(8, 114, 187, 0.16);
}
/* Inicio y Contacto: SOLO el aro. Sus iconos ya cambian de fondo al pasar el cursor
   (`.trust-card:hover .trust-card__icon` / `.contact-card:hover .contact-card__ic`,
   misma especificidad y más arriba en la hoja): un `background` aquí se los comería.
   El aro no compite con ninguna de esas reglas. */
.pillar .trust-card__icon,
.pillar .contact-card__ic { box-shadow: inset 0 0 0 1px rgba(8, 114, 187, 0.16); }
/* La regla global `svg { fill: currentColor }` de base.css pisa el atributo
   fill="none": sin esto, los iconos de trazo se rellenarían (diana y bocadillo).
   Los de Inicio lo arrastraban desde siempre (los de Contacto ya lo tenían). */
.pillar .card__icon svg,
.trust-card__icon svg { fill: none; }
/* Solo los pilares: en Contacto el h3 es un título en versalitas con `tracking-wide`
   y `.pillar h3` (0,1,1) se lo comería. */
.pillars h3 { letter-spacing: -0.015em; }
/* Contacto: tarjeta más pequeña y contenido centrado → número y retícula más
   discretos, y el acento algo más corto. */
.contact-card.pillar > .pillar__num {
  top: 0.7rem;
  right: 0.85rem;
  font-size: clamp(1.3rem, 1.1rem + 0.6vw, 1.7rem);
}
.contact-card.pillar::before { width: 36px; }
.contact-card.pillar::after { width: 88px; height: 64px; }

/* ---- Trazo perimetral al pasar el cursor (CAPA EXTRA) ----
   El acento de la esquina superior izquierda se prolonga y recorre todo el contorno.
   Va en una capa aparte porque `::before`/`::after` ya están ocupados (acento y
   retícula). SOLO anima `stroke-dashoffset`: no toca ninguna propiedad del hover
   existente (transform, sombra, borde) ni el módulo [data-cardfx]. */
.pillar-defs { position: absolute; width: 0; height: 0; overflow: hidden; }
/* Los <stop> se tiñen por CSS (var() no funciona en atributos de presentación). Son
   los DOS colores de `--gradient-brand`, constantes en ambos temas, para que el
   trazo sea exactamente la prolongación del acento y no haya salto de color en la
   unión (--color-primary sí es temático: en oscuro viraría a cian). */
.pillar-defs stop:first-child { stop-color: var(--color-primary-strong); }
.pillar-defs stop:last-child { stop-color: var(--color-cyan); }
/* Selector compuesto a propósito: `.cardfx > *:not(.cardfx__glow)` tiene la misma
   especificidad y le impondría `position: relative`. */
.pillar > .pillar__trace {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  pointer-events: none;   /* nunca intercepta el cursor: el tilt sigue recibiéndolo */
}
.pillar__trace rect {
  /* El `overflow: hidden` de .cardfx recorta en el PADDING box, así que el trazo no
     puede pisar el borde de 1px: se dibuja justo por dentro, pegado a él (ocupa de
     1px a 3px del borde exterior) y sin recorte. El radio se descuenta dos veces
     —el borde y este margen— para que la curva calce con la de la tarjeta. */
  x: 1px;
  y: 1px;
  width: calc(100% - 2px);
  height: calc(100% - 2px);
  rx: calc(var(--pillar-r, var(--radius-md)) - 2px);
  fill: none;
  stroke: url(#pillarTrace);
  stroke-width: 2;
  /* pathLength="100" normaliza el perímetro: el recorrido avanza a velocidad
     constante y dura lo mismo sea cual sea el tamaño de la ficha. En reposo el
     trazo está fuera; al entrar el cursor se despliega entero desde el arranque
     del rect, que es la esquina superior izquierda, en sentido horario. */
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  transition: stroke-dashoffset 0.9s var(--ease-out);
}
.pillar:hover > .pillar__trace rect { stroke-dashoffset: 0; }

@media (prefers-reduced-motion: reduce) {
  .pillar__trace rect { transition: none; }
}

@supports (background: color-mix(in srgb, red 50%, transparent)) {
  .card.pillar,
  .contact-card.pillar {
    background: linear-gradient(158deg,
      color-mix(in srgb, var(--color-surface-3) 66%, var(--color-surface)),
      var(--color-surface) 58%);
  }
  .pillar > .pillar__num { color: color-mix(in srgb, var(--color-primary) 17%, transparent); }
  .pillar .card__icon {
    background: linear-gradient(150deg,
      color-mix(in srgb, var(--color-primary) 13%, var(--color-surface)),
      color-mix(in srgb, var(--color-cyan) 12%, var(--color-surface)));
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-primary) 17%, transparent);
  }
}

/* Parallax sutil */
[data-parallax] { transition: transform var(--dur-fast) linear; will-change: transform; }

/* Foto de la agencia */
.agency-photo img { width: 100%; height: auto; border-radius: var(--radius-lg); box-shadow: var(--shadow-md); }

/* Sección con la foto de la oficina de fondo. El velo (::before) usa el color de la
   propia sección, así funciona igual en claro y en oscuro y el texto mantiene su
   contraste; el contenido va por encima. */
.agency-bg {
  position: relative;
  isolation: isolate;
  /* Recorta la capa de fondo sobredimensionada: el parallax nunca descubre un
     borde y el velo (inset: 0) cubre EXACTAMENTE el 100% de la sección. */
  overflow: hidden;
  /* Margen vertical de la capa de fondo = recorrido máximo del parallax. */
  --agency-par: 64px;
}
/* Capa 1 — FONDO: lo único que se mueve (el JS le escribe el transform). */
.agency-bg__media {
  position: absolute;
  left: 0;
  right: 0;
  /* Sobresale por arriba y por abajo lo que dura el recorrido del parallax. */
  top: calc(var(--agency-par) * -1);
  bottom: calc(var(--agency-par) * -1);
  z-index: 0;
  background-image: var(--agency-bg);
  background-size: cover;
  /* Anclada arriba: si sobra alto, se recorta por ABAJO y nunca por la parte superior. */
  background-position: center top;
  background-repeat: no-repeat;
  pointer-events: none;
}
/* Bloque de texto centrado (sin foto al lado): ambos párrafos con el mismo estilo. */
.agency-intro {
  max-width: 60rem;
  margin-inline: auto;
  text-align: center;
}
/* Un punto por encima del cuerpo (entre --fs-body y --fs-lead): con dos párrafos
   centrados, el tamaño lead completo resultaba excesivo. */
.agency-intro p {
  font-size: clamp(1.0625rem, 1rem + 0.4vw, 1.3125rem);
  line-height: var(--lh-body);
  color: var(--color-ink-soft);
  max-width: 60ch;
  margin-inline: auto;
}
.agency-intro p + p { margin-top: var(--space-md); }
/* Capa 2 — VELO: cubre el 100% de la sección, sobre el fondo y bajo el contenido. */
.agency-bg__veil {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--color-surface-2);
  opacity: 0.84;               /* respaldo plano */
  pointer-events: none;
}
/* Capa 3 — CONTENIDO: estático, siempre por encima de las dos capas. */
.agency-bg > .container { position: relative; z-index: 2; }
@supports (background: color-mix(in srgb, red 50%, transparent)) {
  .agency-bg__veil {
    opacity: 1;
    /* Algo más denso arriba (donde va el titular) y más ligero abajo, para que la
       foto se lea sin comprometer el contraste del texto. */
    background: linear-gradient(180deg,
      color-mix(in srgb, var(--color-surface-2) 86%, transparent),
      color-mix(in srgb, var(--color-surface-2) 76%, transparent));
  }
}

/* Apartado de redes sociales (La Agencia): tarjetas icono + nombre por red. */
.agency-social {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--space-md);
  max-width: 900px;
  margin-inline: auto;
}
.agency-social__card {
  display: flex; flex-direction: column; align-items: center; gap: 0.75rem;
  padding: var(--space-lg) var(--space-md);
  background: var(--color-surface);
  border: var(--border-soft);
  border-radius: var(--radius-lg);
  color: var(--color-ink);
  text-align: center;
  transition: transform var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out),
    border-color var(--dur-base) var(--ease-out);
}
.agency-social__card:hover {
  transform: translateY(-6px);
  box-shadow: var(--shadow-lg);
  border-color: var(--color-primary);
}
.agency-social__icon {
  width: 54px; height: 54px; display: grid; place-items: center;
  border-radius: var(--radius-pill);
  background: var(--color-surface-3);
  color: var(--color-primary);
  transition: background var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out);
}
.agency-social__card:hover .agency-social__icon { background: var(--color-primary); color: #fff; }
.agency-social__icon svg { width: 1.5rem; height: 1.5rem; fill: currentColor; }
.agency-social__name { font-family: var(--font-heading); font-weight: var(--fw-semibold); }

/* ---- Vídeo de ambiente por red al pasar el cursor (La Agencia, sección #redes) ----
   Cada ficha activa su propio vídeo a pantalla completa DETRÁS del contenido, con
   crossfade entre unos y otros y un velo que garantiza la legibilidad. El JS
   ([data-social-stage] en main.js) solo reproduce uno a la vez; sin vídeos, sin JS,
   en táctil o con motion reducido la sección queda tal cual estaba. */
.social-stage { position: relative; overflow: hidden; isolation: isolate; }
.social-stage > .container { position: relative; z-index: 1; }
.social-stage__bg { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.social-stage__video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.6s var(--ease-out);
}
.social-stage__video.is-on { opacity: 1; }
/* Velo del color de la propia sección (así funciona igual en claro y oscuro).
   Base: plano al 88% (compatible con cualquier navegador). Donde hay color-mix, se
   gradúa: casi opaco sobre el titular —que va directamente sobre el fondo— y más
   transparente abajo, donde las tarjetas son opacas y el vídeo puede lucir. */
.social-stage__veil {
  position: absolute; inset: 0;
  background: var(--color-surface-2);
  opacity: 0;
  transition: opacity 0.6s var(--ease-out);
}
.social-stage__veil::after {
  content: "";
  position: absolute; inset: 0;
  background: radial-gradient(120% 85% at 50% 0%, rgba(255, 255, 255, 0) 40%, rgba(5, 64, 112, 0.12) 100%);
}
.social-stage.is-playing .social-stage__veil { opacity: 0.74; }
@supports (background: color-mix(in srgb, red 50%, transparent)) {
  .social-stage__veil {
    background: linear-gradient(180deg,
      color-mix(in srgb, var(--color-surface-2) 86%, transparent) 0%,
      color-mix(in srgb, var(--color-surface-2) 76%, transparent) 45%,
      color-mix(in srgb, var(--color-surface-2) 55%, transparent) 100%);
  }
  .social-stage.is-playing .social-stage__veil { opacity: 1; }
}
/* Ficha activa: mismo lenguaje que el hover, con un aro sutil de marca */
.agency-social__card.is-active {
  transform: translateY(-6px);
  border-color: var(--color-primary);
  box-shadow: var(--shadow-lg), 0 0 0 2px rgba(8, 114, 187, 0.16);
}
.agency-social__card.is-active .agency-social__icon { background: var(--color-primary); color: #fff; }

@media (prefers-reduced-motion: reduce) {
  .social-stage__video, .social-stage__veil { display: none; }
}

/* Sección de vídeo / conócenos */
.video-frame {
  position: relative;
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-md);
  background: var(--color-surface-3);
}
.video-frame video {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}
/* =========================================================================
   Conócenos (Inicio): la fotografía es la protagonista (55% del contenedor) y el
   texto entra en cascada. Todo reutiliza el sistema de revelado del sitio
   ([data-reveal] + el IntersectionObserver global de main.js); sin librerías.
   ========================================================================= */
.conocenos-split .section-title { max-width: none; }
@media (min-width: 900px) {
  .conocenos-split {
    /* 55% EXACTO para la imagen; el texto ocupa el resto. El hueco baja respecto al
       `.split` genérico (hasta 5rem) para que no quede aire muerto en medio. */
    grid-template-columns: minmax(0, 1fr) 55%;
    gap: clamp(1.75rem, 1rem + 2.2vw, 3.25rem);
  }
}
/* Medida de lectura cómoda: evita que el lead se estire hasta el borde. */
.conocenos-text .lead { max-width: 46ch; }
.conocenos-cta { margin-top: var(--space-lg); }
/* La flecha avanza al pasar el cursor (mismo gesto que `.link-arrow`). */
.conocenos-cta svg {
  width: 1.05rem;
  height: 1.05rem;
  fill: none;   /* la regla global `svg { fill: currentColor }` rellenaría el trazo */
  transition: transform var(--dur-base) var(--ease-out);
}
.conocenos-cta:hover svg { transform: translateX(4px); }

/* Detalle gráfico de marca DETRÁS de la foto: la misma retícula de puntos que usan
   las fichas `.pillar`, asomando por la esquina inferior izquierda, y un marco fino
   azul insinuado arriba a la derecha. Ambos decorativos y sin capturar el cursor. */
.conocenos-media { position: relative; }
.conocenos-media > .video-frame { position: relative; z-index: 1; }
.conocenos-media::before,
.conocenos-media::after { content: ""; position: absolute; z-index: 0; pointer-events: none; }
.conocenos-media::before {
  left: -1rem;
  bottom: -1rem;
  width: clamp(92px, 11vw, 148px);
  height: clamp(92px, 11vw, 148px);
  background-image: radial-gradient(circle, var(--color-primary) 1px, transparent 1.2px);
  background-size: 13px 13px;
  opacity: 0.3;
  -webkit-mask-image: linear-gradient(45deg, #000 28%, transparent 76%);
  mask-image: linear-gradient(45deg, #000 28%, transparent 76%);
}
.conocenos-media::after {
  top: -0.9rem;
  right: -0.9rem;
  width: 42%;
  height: 46%;
  border-radius: var(--radius-lg);
  border: 1px solid rgba(8, 114, 187, 0.22);
}
/* En una sola columna la foto llega casi al gutter: los detalles se arriman para no
   rozar el borde del contenedor (medido: 1.6px de margen con los valores de arriba). */
@media (max-width: 899px) {
  .conocenos-media::before { left: -0.5rem; bottom: -0.5rem; }
  .conocenos-media::after { top: -0.5rem; right: -0.5rem; }
}
/* Acabado sutil: la sombra dura (`--shadow-md`) se cambia por una difusa y baja, con
   un filo fino de marca. Solo aquí (el `.video-frame` genérico no se toca). */
.conocenos-split .video-frame {
  box-shadow: 0 22px 48px -28px rgba(5, 64, 112, 0.45);
  border: 1px solid rgba(8, 114, 187, 0.14);
}
/* Etiquetas sobre la foto. z-index 2 para quedar por encima del velo azul
   (`.video-frame--photo::after`), que va después en el árbol. */
.conocenos-tags {
  position: absolute;
  z-index: 2;
  left: clamp(0.85rem, 2vw, 1.35rem);
  bottom: clamp(0.85rem, 2vw, 1.35rem);
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.conocenos-tags li {
  font-family: var(--font-heading);
  font-size: var(--fs-small);
  font-weight: var(--fw-semibold);
  color: #fff;
  padding: 0.4rem 0.85rem;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.16);
  border: 1px solid rgba(255, 255, 255, 0.3);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}

/* ---- Entrada ---- El bloque de texto NO se oculta como tal: se ocultan sus hijos y
   entran escalonados (patrón de `.method--line`). La foto se abre con un clip-path
   suave desde el centro mientras la imagen suelta un ligero zoom. */
.js .conocenos-text[data-reveal],
.js .conocenos-media[data-reveal] { opacity: 1; transform: none; transition: none; }
.js .conocenos-text[data-reveal] > * {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.6s var(--ease-out), transform 0.6s var(--ease-out);
}
.js .conocenos-text[data-reveal].is-visible > * { opacity: 1; transform: none; }
.js .conocenos-text[data-reveal] > :nth-child(2) { transition-delay: 90ms; }
.js .conocenos-text[data-reveal] > :nth-child(3) { transition-delay: 180ms; }
.js .conocenos-text[data-reveal] > :nth-child(4) { transition-delay: 270ms; }
/* El estado oculto recorta un 10%/6%: aunque el observer no llegara a dispararse, la
   foto se ve casi entera (nunca desaparece, al contrario que un `inset(100%)`). */
.js .conocenos-media[data-reveal] > .video-frame {
  opacity: 0;
  clip-path: inset(10% 6% 10% 6% round var(--radius-lg));
  transition: clip-path 1s cubic-bezier(0.22, 0.9, 0.28, 1), opacity 0.7s var(--ease-out);
}
.js .conocenos-media[data-reveal].is-visible > .video-frame {
  opacity: 1;
  clip-path: inset(0 0 0 0 round var(--radius-lg));
}
.js .conocenos-media[data-reveal] > .video-frame img {
  transform: scale(1.06);
  transition: transform 1.2s cubic-bezier(0.22, 0.9, 0.28, 1);
}
.js .conocenos-media[data-reveal].is-visible > .video-frame img { transform: none; }

@media (prefers-reduced-motion: reduce) {
  .js .conocenos-text[data-reveal] > *,
  .js .conocenos-media[data-reveal] > .video-frame,
  .js .conocenos-media[data-reveal] > .video-frame img {
    opacity: 1;
    transform: none;
    clip-path: none;
    transition: none;
  }
}
/* Variante con foto (overlay oscuro sobre la imagen) */
.video-frame--photo img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}
.video-frame--photo::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(5, 64, 112, 0.28), rgba(5, 64, 112, 0.52));
  pointer-events: none;
}

/* =========================================================================
   Frase inspiradora con vídeo de fondo (entre Conócenos y Blog)
   ========================================================================= */
.quote-band {
  position: relative;
  overflow: hidden;
  display: grid;
  place-items: center;
  min-height: clamp(360px, 60vh, 560px);
  padding-block: clamp(4rem, 8vw, 7rem);
  isolation: isolate;
}
.quote-band__media { position: absolute; inset: 0; z-index: -2; }
.quote-band__media video {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
.quote-band__scrim {
  position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(180deg, rgba(5, 64, 112, 0.82), rgba(3, 30, 54, 0.9)),
    radial-gradient(120% 120% at 50% 50%, rgba(3, 30, 54, 0.35) 40%, rgba(3, 30, 54, 0.78) 100%);
}
.quote-band .container { position: relative; z-index: 1; text-align: center; }
.quote-band__text { max-width: none; margin-inline: auto; border: 0; padding: 0; }
.quote-band__text p {
  font-family: var(--font-heading);
  font-weight: var(--fw-bold);
  font-size: clamp(1.6rem, 1rem + 2.6vw, 3rem);
  line-height: 1.2;
  color: #fff;
  text-wrap: balance;
  margin: 0;
  text-shadow: 0 2px 18px rgba(0, 0, 0, 0.35);
}

/* Revelado por PALABRAS (se dispara una vez con .is-visible del observer):
   cada palabra entra con desplazamiento + desenfoque + opacidad + ligera
   rotación en perspectiva, escalonada y con un rebote controlado al asentar.
   Solo con JS; sin él, el texto se muestra normal. No altera el layout
   (transform/filter no afectan a la caja del inline-block). */
/* data-reveal aquí solo dispara .is-visible; el bloque NO se oculta ni se
   desplaza (la animación la llevan las palabras, no el contenedor). */
.js .quote-band__text[data-reveal] { opacity: 1; transform: none; }
.quote-reveal .qw { display: inline-block; }
.js .quote-reveal .qw {
  opacity: 0;
  transform: perspective(700px) rotateX(-38deg) translateY(0.5em);
  filter: blur(7px);
  transition:
    opacity 0.5s ease,
    transform 0.62s cubic-bezier(0.22, 1.42, 0.36, 1),
    filter 0.5s ease;
  transition-delay: calc(var(--wi) * 45ms);
  will-change: transform, filter, opacity;
}
.js .quote-band__text.is-visible .qw {
  opacity: 1;
  transform: none;
  filter: blur(0);
}
/* Móvil: menos perspectiva, menos desplazamiento y duración/escalonado más cortos */
@media (max-width: 600px) {
  .js .quote-reveal .qw {
    transform: perspective(480px) rotateX(-22deg) translateY(0.34em);
    filter: blur(5px);
    transition:
      opacity 0.4s ease,
      transform 0.5s cubic-bezier(0.22, 1.42, 0.36, 1),
      filter 0.4s ease;
    transition-delay: calc(var(--wi) * 34ms);
  }
}
@media (prefers-reduced-motion: reduce) {
  .js .quote-reveal .qw { opacity: 1; transform: none; filter: none; transition: none; }
}

/* =========================================================================
   Feed de Instagram en teléfono, controlado por scroll (página Social Media)
   Escritorio: sección fijada (sticky) mientras el contenido del teléfono se
   desplaza y el texto de la izquierda cambia por tramos. Móvil/tablet: el feed
   es un contenedor con scroll nativo dentro del teléfono. Lógica en main.js.
   ========================================================================= */
.ig-scroll { position: relative; }
.ig-scroll__grid { display: grid; gap: var(--space-2xl); align-items: center; }

/* --- Columna de textos por fases (un mensaje a la vez, altura estable) --- */
.ig-phases__stage { position: relative; min-height: clamp(320px, 34vh, 360px); }
.ig-phase {
  position: absolute; inset: 0;
  opacity: 0; transform: translateY(18px);
  transition: opacity 0.55s var(--ease-out), transform 0.55s var(--ease-out);
  pointer-events: none;
}
.ig-phase.is-active { opacity: 1; transform: none; pointer-events: auto; }
.ig-phase__title { font-size: var(--fs-h2); margin-bottom: var(--space-md); }
.ig-phase__text { font-size: 1.1rem; color: var(--color-ink-soft); max-width: 46ch; }
.ig-phases__dots { display: flex; gap: 0.5rem; margin-top: var(--space-xl); }
.ig-dot { width: 26px; height: 4px; border-radius: 4px; background: var(--color-line); transition: background 0.4s, width 0.4s; }
.ig-dot.is-active { background: var(--color-primary); width: 40px; }

/* --- Teléfono --- */
.ig-phone-wrap { display: flex; flex-direction: column; align-items: center; gap: var(--space-md); }
.ig-phone {
  --ig-w: 320px;
  position: relative;
  width: min(var(--ig-w), 82vw);
  aspect-ratio: 320 / 660;
  background: #0c0d12;
  border-radius: 44px;
  padding: 12px;
  box-shadow: 0 30px 60px -20px rgba(5, 64, 112, 0.45), 0 0 0 2px rgba(255, 255, 255, 0.06) inset;
}
.ig-phone__cam {
  position: absolute; top: 16px; left: 50%; transform: translateX(-50%);
  width: 42%; height: 22px; background: #0c0d12; border-radius: 0 0 14px 14px; z-index: 3;
}
.ig-phone__screen {
  height: 100%;
  min-height: 0; /* permite que el feed encoja y scrollee (fix flexbox) */
  display: flex; flex-direction: column;
  background: var(--color-surface);
  border-radius: 33px;
  overflow: hidden;
}
.ig-phone__topbar {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 0.55rem;
  padding: 0.7rem 0.9rem;
  border-bottom: 1px solid var(--color-line);
}
.ig-ava { border-radius: 50%; background: var(--color-deep-blue); object-fit: cover; padding: 3px; }
.ig-ava--sm { padding: 2px; }
.ig-user { font-weight: var(--fw-bold); font-size: 0.85rem; color: var(--color-ink); }
.ig-more { margin-left: auto; color: var(--color-ink-soft); display: inline-flex; }
.ig-more svg { width: 20px; height: 20px; }

/* Viewport del feed. Escritorio: oculto (se traslada por JS). Móvil: scroll nativo. */
.ig-phone__feed { flex: 1 1 auto; min-height: 0; overflow: hidden; position: relative; }
.ig-feed-inner { will-change: transform; }

.ig-post { border-bottom: 1px solid var(--color-line); }
.ig-post__head { display: flex; align-items: center; gap: 0.5rem; padding: 0.55rem 0.75rem; }
.ig-post__head .ig-user { font-size: 0.8rem; }
.ig-post__media { aspect-ratio: 1 / 1; background: var(--color-surface-2); }
.ig-post__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ig-post__actions { display: flex; align-items: center; gap: 0.9rem; padding: 0.6rem 0.75rem 0.2rem; color: var(--color-ink); }
.ig-post__actions svg { width: 22px; height: 22px; }
.ig-post__actions .ig-post__save { margin-left: auto; }
.ig-post__caption { font-size: 0.8rem; line-height: 1.4; color: var(--color-ink); padding: 0.2rem 0.75rem 0.85rem; }
.ig-post__caption .ig-user { margin-right: 0.35rem; }
.ig-phone__hint { font-size: 0.85rem; color: var(--color-ink-soft); }

/* ---------------- ESCRITORIO: sección fijada + scrub por scroll ------------- */
@media (min-width: 1024px) {
  .ig-scroll { min-height: 300vh; }
  .ig-scroll__sticky {
    position: sticky;
    top: var(--header-h);
    height: calc(100svh - var(--header-h));
    display: flex; align-items: center;
    overflow: hidden;
  }
  .ig-scroll__grid { grid-template-columns: 1fr minmax(300px, 360px); gap: clamp(2.5rem, 4vw, 5.5rem); }
  .ig-phone {
    width: auto;
    height: min(660px, calc(100svh - var(--header-h) - 3rem));
  }
  .ig-phone__hint { display: none; } /* en escritorio el scroll de la página gobierna el feed */
}

/* ------------------- MÓVIL / TABLET: scroll nativo del feed ------------------ */
@media (max-width: 1023px) {
  .ig-scroll__sticky { position: static; }
  /* Altura EXPLÍCITA (aspect-ratio no crea altura definida si el contenido es
     más alto → el feed no podría scrollear). Derivada del ancho, con tope svh. */
  .ig-phone {
    width: min(320px, 82vw);
    height: min(calc(min(320px, 82vw) * 660 / 320), 74svh);
  }
  .ig-phone__feed {
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .ig-phone__feed::-webkit-scrollbar { width: 0; height: 0; }
  .ig-feed-inner { transform: none !important; } /* en móvil no se traslada: scrollea de verdad */
}

@media (prefers-reduced-motion: reduce) {
  .ig-phase { transition: opacity 0.25s linear; transform: none; }
  .ig-phase.is-active { transform: none; }
}

/* =========================================================================
   Marquee de lemas / tira de servicios (adaptado del borrador)
   ========================================================================= */
.marquee-strip {
  overflow: hidden;
  white-space: nowrap;
  border-block: 1px solid var(--color-line);
  background: var(--color-surface-2);
  padding-block: 0.9rem;
}
.marquee-strip--services { background: transparent; border-top: 0; }
/* Track = DOS copias idénticas, cada una con la lista repetida N veces hasta
   superar el ancho de pantalla. La animación recorre EXACTAMENTE una copia
   (translateX -50%), así que nunca aparece hueco por muy ancha que sea la
   pantalla (mismo patrón que la franja del hero). Sin `gap` a nivel de track:
   la separación entre copias la da el `margin-right` de cada `.marquee-copy`. */
.marquee-track {
  display: flex;
  width: max-content;
  align-items: center;
  will-change: transform;
  animation: marquee 180s linear infinite;   /* 30s por repetición × 6 (misma velocidad) */
}
.marquee-track--rev { animation-duration: 152s; }   /* 38s × 4 */
.marquee-copy { display: flex; align-items: center; gap: 1.5rem; margin-right: 1.5rem; flex: 0 0 auto; }
.marquee-track:hover { animation-play-state: paused; }
.marquee-item {
  font-family: var(--font-heading);
  font-weight: var(--fw-bold);
  font-size: clamp(0.95rem, 0.85rem + 0.5vw, 1.3rem);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--color-ink);
}
.marquee-strip--services .marquee-item { color: var(--color-primary); }
.marquee-dot { color: var(--color-cyan); font-size: 0.7em; }
@keyframes marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) {
  /* Sin animación: fila estática recortada por el overflow del strip (sin envolver
     la lista repetida, que quedaría fea). */
  .marquee-track { animation: none; }
}

/* =========================================================================
   Banda de contraste "decisión" (adaptada del borrador)
   ========================================================================= */
.decision-band {
  background: var(--gradient-deep);
  color: #fff;
  text-align: center;
  padding-block: clamp(3rem, 2rem + 5vw, 6rem);
}
.decision-band__line {
  font-family: var(--font-heading);
  font-weight: var(--fw-extrabold);
  line-height: 1.12;
  text-transform: uppercase;
  text-wrap: balance;
}
.decision-band__line--0 { font-size: clamp(1.8rem, 1.2rem + 3.4vw, 3.6rem); color: #fff; }
.decision-band__line--1 { font-size: clamp(1.05rem, 0.9rem + 1.4vw, 1.7rem); color: var(--color-cyan); margin-top: 0.5rem; }
/* Variante reducida (flag 'decision_sm'): para lemas largos (frases), tipografía más
   pequeña y ancho contenido para que no ocupen tanto ni rompan a demasiadas líneas. */
.decision-band--sm .decision-band__line--0 { font-size: clamp(1.25rem, 0.95rem + 1.5vw, 1.95rem); }
.decision-band--sm .decision-band__line { max-width: 52ch; margin-inline: auto; }

/* =========================================================================
   Bloque de enlazado interno (tipo 'linkhub'): pregunta + servicios principales en
   píldoras destacadas + tira de otros servicios enlazados (separados por ·).
   ========================================================================= */
/* Contenedor ancho para que no quede tanto aire a los lados; el título usa casi todo
   el ancho manteniéndose en 2 líneas, y las filas de enlaces caben mejor. */
.linkhub__inner { text-align: center; max-width: 1120px; margin-inline: auto; }
.linkhub__title {
  font-family: var(--font-heading);
  font-weight: var(--fw-bold);
  font-size: clamp(1.7rem, 1.05rem + 2.6vw, 2.9rem);
  line-height: 1.12;
  color: var(--color-ink);
  margin-top: 0.6rem;
  text-wrap: balance;       /* 2 líneas equilibradas (el ancho del contenedor ya evita 1) */
}
.linkhub__main {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(0.75rem, 0.5rem + 1vw, 1.25rem);
  margin-top: clamp(1.5rem, 1.1rem + 1.4vw, 2.25rem);
}
.linkhub__pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 8.5rem;
  padding: 0.72rem 2rem;
  font-family: var(--font-heading);
  font-weight: var(--fw-bold);
  font-size: 1.15rem;
  letter-spacing: 0.02em;
  color: #fff;
  background: var(--color-primary);
  border: 2px solid var(--color-primary);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-sm);
  text-decoration: none;
  transition: transform 0.3s var(--ease-out), background-color 0.3s var(--ease-out), border-color 0.3s var(--ease-out), box-shadow 0.3s var(--ease-out);
}
.linkhub__pill:hover {
  /* Botones azules redondeados de «servicios relacionados» (linkhub): al pasar el
     cursor, el fondo (normal var(--color-primary) = #0872BB) cambia a #3A97D7 con el
     texto en blanco y una transición suave. Se conservan tamaño, forma, tipografía,
     espaciado, la elevación y la sombra; no afecta a los enlaces de texto inferiores. */
  transform: translateY(-3px);
  background: #3A97D7;
  border-color: #3A97D7;
  color: #fff;
  box-shadow: var(--shadow-md);
}
.linkhub__groups {
  /* Aire entre las píldoras (SEO/SEM) y las filas de enlaces, equilibrado con el resto. */
  margin-top: clamp(2rem, 1.5rem + 1.8vw, 3.25rem);
  display: flex;
  flex-direction: column;
  gap: clamp(1.25rem, 1rem + 1.1vw, 2rem);
}
.linkhub__group-label {
  display: block;
  font-family: var(--font-heading);
  font-weight: var(--fw-bold);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.82rem;
  color: var(--color-ink);
  margin-bottom: 0.7rem;
}
.linkhub__links {
  color: var(--color-ink-soft);
  font-size: 0.95rem;
  line-height: 1.7;
  /* Flex con wrap: los enlaces y sus separadores «·» envuelven y se centran en
     cualquier ancho (como spans inline pegados no rompían y desbordaban en móvil). */
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: baseline;
  row-gap: 0.35rem;
}
.linkhub__link {
  color: var(--color-primary);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}
.linkhub__link:hover { text-decoration: underline; }
.linkhub__sep { color: var(--color-cyan); margin-inline: 0.55rem; }

/* =========================================================================
   Newsletter (adaptada del borrador)
   ========================================================================= */
.newsletter__box {
  background: var(--gradient-brand-135);
  color: #fff;
  border-radius: var(--radius-xl);
  padding: clamp(2rem, 1.5rem + 3vw, 3.5rem);
  display: grid;
  gap: var(--space-xl);
  align-items: center;
}
@media (min-width: 820px) { .newsletter__box { grid-template-columns: 1.1fr 1fr; } }
.newsletter__text h2 { color: #fff; }
.newsletter__text p { color: rgba(255, 255, 255, 0.9); margin-top: 0.5rem; }
.newsletter__form { display: flex; gap: 0.6rem; flex-wrap: wrap; }
.newsletter__form .form-control { flex: 1 1 220px; }
.newsletter__msg { grid-column: 1 / -1; font-weight: var(--fw-semibold); }
.newsletter__msg--err { color: #ffe1dc; }

/* =========================================================================
   Bloques de servicio: fichas numeradas con etiquetas (org. del borrador)
   ========================================================================= */
.svc-cards {
  display: grid;
  gap: var(--space-xl);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
}
/* RSC · «Cómo funciona»: las 4 fichas en 2 columnas × 2 filas (en vez de 3+1).
   Solo en esta página (.page-rsc) y de tablet hacia arriba; en móvil siguen apiladas. */
@media (min-width: 700px) {
  .page-rsc .svc-cards { grid-template-columns: repeat(2, 1fr); }
}
.svc-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  background: var(--color-surface);
  border: var(--border-soft);
  border-radius: var(--radius-lg);
  padding: clamp(1.5rem, 1.2rem + 1vw, 2.25rem);
  transition: transform var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out);
}
.svc-card { overflow: hidden; }
.svc-card::after {
  content: "";
  position: absolute; inset: 0 0 auto 0; height: 4px;
  background: var(--gradient-brand);
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--dur-base) var(--ease-out);
}
.svc-card:hover { transform: translateY(-8px) scale(1.015); box-shadow: var(--shadow-lg); border-color: var(--color-primary); }
/* Excepción: en «Hacemos que el futuro digital sea ahora» (página Web, acordeón
   `expand`) la ficha NO se mueve ni se agranda al pasar el cursor. Conserva el resto
   del hover (sombra, borde, barra de acento, número y etiquetas). */
.service-web .exp-section .svc-card:hover { transform: none; }
.svc-card:hover::after { transform: scaleX(1); }
.svc-card__n { transition: color var(--dur-base) var(--ease-out); }
.svc-card:hover .svc-card__n { color: var(--color-primary); }
.svc-card__n {
  font-family: var(--font-heading);
  font-weight: var(--fw-extrabold);
  font-size: 1.6rem;
  line-height: 1;
  color: var(--color-cyan);
  -webkit-text-stroke: 0;
}
.svc-card__title {
  font-size: var(--fs-h4);
  text-transform: uppercase;
  letter-spacing: var(--tracking-tight);
}
.svc-card__text { color: var(--color-ink-soft); font-size: 0.98rem; }
.svc-card__tags { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: auto; padding-top: var(--space-sm); }
.svc-tag {
  font-family: var(--font-heading);
  font-size: 0.72rem;
  font-weight: var(--fw-semibold);
  letter-spacing: 0.03em;
  text-transform: uppercase;
  padding: 0.3rem 0.65rem;
  border-radius: var(--radius-pill);
  background: var(--color-surface-3);
  color: var(--color-primary);
}
.svc-card__link { margin-top: var(--space-sm); }

/* =========================================================================
   Galería horizontal con PROFUNDIDAD (cards_num con 'deck', página Web).
   Las fichas .svc-card (con imagen de cabecera) se superponen parcialmente: la
   protagonista en primer plano a la izquierda y las siguientes escalonadas hacia
   la derecha, cada vez más pequeñas, un poco más arriba y más apagadas.
   IMPORTANTE (sin layout shift): la disposición en perspectiva se maqueta YA en
   CSS a partir de `--i` (índice de la ficha), porque la clase `.js` se añade en
   el <head> antes de pintar. El JS (main.js, [data-dk]) solo REESCRIBE esos
   mismos transform/opacity/z-index en línea al recorrer la galería, con las
   MISMAS fórmulas, así que al inicializarse no hay ningún salto visual.
   Sin JS o con prefers-reduced-motion: rejilla normal (mismo diseño de ficha).
   ========================================================================= */
.dk {
  --dk-card-w: calc(100% - 104px);  /* casi todo el ancho del contenedor */
  --dk-card-h: 440px;      /* fija (todas las fichas iguales) → sin saltos de maquetación */
  --dk-media-h: 190px;     /* solo en móvil (una columna); en ancho la imagen es columna */
  --dk-step: 64px;         /* avance en X por posición (mucho menor que el ancho → solape) */
  --dk-lift: -12px;        /* pequeño desplazamiento en Y por posición (profundidad) */
  --dk-scale: 0.045;       /* reducción de escala por posición */
  --dk-vis: 2.8;           /* posiciones visibles a la derecha de la protagonista */
  --dk-fade: 1;            /* margen (en posiciones) en el que la ficha entra/sale */
  --dk-exit: 480px;        /* salida hacia la izquierda de la ficha que abandona */
  --dk-drag: 260px;        /* px de arrastre por posición (sensibilidad del gesto) */
  position: relative;
}
/* Fallback (sin JS / motion reducido): la rejilla de siempre. */
.dk-stage {
  display: grid;
  gap: var(--space-xl);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
}
html:not(.js) .dk-nav { display: none; }

/* Imagen de la ficha: protagonista visual, sobre panel de marca (las ilustraciones
   tienen fondo transparente → contain, como los heroes split). */
.dk-card__media {
  --dk-pad: clamp(1.5rem, 1.2rem + 1vw, 2.25rem);
  margin: calc(-1 * var(--dk-pad)) calc(-1 * var(--dk-pad)) 0.35rem;
  background: var(--color-surface-3);
  border-bottom: var(--border-soft);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.dk-card__media img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: clamp(0.75rem, 2vw, 1.4rem);
  display: block;
}
/* El cuerpo es columna flexible siempre (también sin JS y con motion reducido), para
   conservar los espaciados entre número, título, texto y etiquetas. */
.dk-card__body {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  min-width: 0;
}

/* --- Galería en perspectiva (con JS disponible) --- */
.js .dk {
  overflow: hidden;                   /* recorta las fichas que entran/salen */
  padding: 18px 14px;                 /* deja respirar sombras y escala */
  margin: -18px -14px;
}
.js .dk-stage {
  display: block;
  position: relative;
  height: var(--dk-card-h);
  cursor: grab;
  touch-action: pan-y;                /* el gesto horizontal es nuestro; el vertical, de la página */
  -webkit-user-select: none;
  user-select: none;
}
.js .dk-stage.is-dragging { cursor: grabbing; }
.js .dk-stage:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 8px; border-radius: var(--radius-lg); }
.js .dk-card {
  position: absolute;
  top: 0;
  left: 0;
  width: var(--dk-card-w);
  height: var(--dk-card-h);
  margin: 0;
  transform-origin: center center;
  will-change: transform, opacity;
  box-shadow: var(--shadow-md);
  /* Estado de reposo (protagonista = ficha 0). Mismas fórmulas que el JS. */
  transform: translate3d(calc(var(--i) * var(--dk-step)), calc(var(--i) * var(--dk-lift)), 0)
    scale(calc(1 - var(--i) * var(--dk-scale)));
  opacity: clamp(0, calc((var(--dk-vis) - var(--i)) / var(--dk-fade)), 1);
  z-index: calc(100 - var(--i));
  transition: box-shadow var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out);
}
/* El transform en línea manda sobre el hover de .svc-card (que solo aporta sombra/borde). */
.js .dk-card:hover { box-shadow: var(--shadow-lg); }
.js .dk-card img { pointer-events: none; }

/* Ficha ANCHA (a partir de 720px): como ocupa casi todo el contenedor, se reparte en
   DOS columnas —imagen a sangre a la izquierda, contenido a la derecha— para que la
   línea de texto siga siendo legible y la imagen gane presencia. Mismos colores,
   bordes, radios y tipografías de .svc-card. */
@media (min-width: 720px) {
  .js .dk-card {
    display: grid;
    grid-template-columns: 0.9fr 1fr;
    gap: 0;
    padding: 0;
  }
  .js .dk-card .dk-card__media {
    margin: 0;
    height: auto;
    border-bottom: none;
    border-right: var(--border-soft);
  }
  .js .dk-card .dk-card__body {
    padding: clamp(1.5rem, 1.1rem + 1.1vw, 2.5rem);
    overflow: hidden;
  }
}
/* Móvil (una columna): imagen arriba con alto fijo, pero encogible para que, si el texto
   necesitara más sitio (otra tipografía, zoom), ceda espacio en lugar de recortarse. */
@media (max-width: 719px) {
  .js .dk-card .dk-card__media { flex: 0 1 auto; height: var(--dk-media-h); min-height: 110px; }
  .js .dk-card .dk-card__body { flex: 1 1 auto; min-height: 0; }
  .js .dk-card .svc-card__text { font-size: 0.9rem; }
}

/* Controles solo de accesibilidad (teclado / lectores): discretos, bajo la galería. */
.dk-nav {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin-top: var(--space-lg);
}
.dk-nav__btn {
  width: 42px; height: 42px;
  display: grid; place-items: center;
  border: var(--border-soft);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  color: var(--color-primary);
  cursor: pointer;
  transition: background-color var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out);
}
.dk-nav__btn svg { width: 20px; height: 20px; }
.dk-nav__btn:hover:not(:disabled) { background: var(--color-primary); color: #fff; border-color: var(--color-primary); }
.dk-nav__btn:disabled { opacity: 0.4; cursor: default; }
.dk-nav__count {
  font-family: var(--font-heading);
  font-weight: var(--fw-semibold);
  font-size: 0.85rem;
  letter-spacing: 0.06em;
  color: var(--color-ink-soft);
}

/* Tablet: misma ficha ancha, con la pila algo más apretada. */
@media (max-width: 1023px) {
  .dk {
    --dk-card-w: calc(100% - 76px);
    --dk-card-h: 520px;
    --dk-step: 48px;
    --dk-vis: 2.4;
    --dk-exit: 400px;
    --dk-drag: 220px;
  }
}
/* Móvil: una columna (imagen arriba), ficha protagonista casi a todo el ancho y el
   borde de la siguiente asomando por la derecha. */
@media (max-width: 719px) {
  .dk {
    --dk-card-w: calc(100% - 46px);
    --dk-card-h: 620px;
    --dk-media-h: 150px;
    --dk-step: 34px;
    --dk-lift: -10px;
    --dk-scale: 0.03;
    --dk-vis: 1.9;
    --dk-fade: 1;
    --dk-exit: 250px;
    --dk-drag: 170px;
  }
}

/* Motion reducido: sin galería ni gestos, la rejilla completa y legible. */
@media (prefers-reduced-motion: reduce) {
  .js .dk { overflow: visible; padding: 0; margin: 0; }
  .js .dk-stage {
    display: grid;
    height: auto;
    cursor: auto;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  }
  .js .dk-card {
    position: static;
    width: auto;
    height: auto;
    transform: none;
    opacity: 1;
    box-shadow: none;
    display: flex;              /* en rejilla la ficha vuelve a una sola columna */
    flex-direction: column;
    padding: 0;
  }
  .js .dk-card .dk-card__media {
    height: 200px;
    border-right: none;
    border-bottom: var(--border-soft);
  }
  .js .dk-card .dk-card__body { padding: clamp(1.5rem, 1.2rem + 1vw, 2.25rem); flex: 1 1 auto; }
  .dk-nav { display: none; }
}

/* =========================================================================
   Fichas "spotlight" (cards_num con 'glow', p. ej. "Presencia con propósito" de SEO).
   Rejilla de 2 columnas en escritorio / 1 en móvil. Al hacer hover, un halo azul y un
   borde iluminado siguen la posición real del cursor (--mx/--my las fija el JS). La
   entrada combina translateY + opacidad + máscara clip-path, escalonada. Mantiene el
   diseño de .svc-card (mismos colores/tipografías/bordes). Táctil/reduce-motion: se
   simplifica (sin seguimiento del cursor; sin animación de entrada). Sin layout shift.
   ========================================================================= */
.svc-cards--glow { grid-template-columns: 1fr; }
@media (min-width: 760px) {
  .svc-cards--glow { grid-template-columns: repeat(2, 1fr); }
}
/* Capas del halo (hijas de la ficha; no usan pseudo porque .svc-card::after es la barra
   de acento). Recortadas por el overflow:hidden de .svc-card → el halo ilumina el fondo. */
.svc-card--glow .svc-glow__spot,
.svc-card--glow .svc-glow__border {
  position: absolute; inset: 0; z-index: 0;
  border-radius: inherit;
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease-out);
  pointer-events: none;
}
.svc-card--glow .svc-glow__spot {
  background: radial-gradient(260px circle at var(--mx, 50%) var(--my, 50%),
    rgba(74, 190, 221, 0.16), rgba(8, 114, 187, 0.08) 42%, transparent 72%);
}
/* Borde iluminado: gradiente recortado a un anillo de 1.5px con máscara (padding + xor). */
.svc-card--glow .svc-glow__border {
  padding: 1.5px;
  background: radial-gradient(200px circle at var(--mx, 50%) var(--my, 50%),
    rgba(74, 190, 221, 0.7), rgba(8, 114, 187, 0.35) 45%, transparent 65%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
}
.svc-card--glow:hover .svc-glow__spot,
.svc-card--glow:hover .svc-glow__border { opacity: 1; }
/* El contenido, por encima del halo. */
.svc-card--glow > .svc-card__n,
.svc-card--glow > .svc-card__title,
.svc-card--glow > .svc-card__text,
.svc-card--glow > .svc-card__tags,
.svc-card--glow > .svc-card__link { position: relative; z-index: 1; }

/* Entrada por scroll: cada ficha se revela cuando ENTRA en el viewport (el
   IntersectionObserver del sitio añade .is-visible POR ELEMENTO, no al cargar la sección),
   combinando opacity 0→1 + un leve translateY desde abajo (SIN la escala del reveal
   genérico) con transición rápida y suave (ease-out, sin rebote). El estado oculto viene
   del reveal genérico gateado por `.js` (aplicado desde el primer pintado → sin flash y
   sin depender de que el JS añada una clase). Escalonado por posición vía las reglas
   `.svc-cards > [data-reveal]:nth-child(n)`. Solo opacity/transform → sin layout shift.
   reduce-motion y no-JS los cubre el propio sistema de reveal (fichas visibles). */
.js .svc-card--glow[data-reveal] {
  transform: translateY(30px);
  transition: opacity 0.5s var(--ease-out), transform 0.5s var(--ease-out);
}
.js .svc-card--glow[data-reveal].is-visible {
  transform: none;
}

/* =========================================================================
   Variante 'reveal' («Análisis con inteligencia», Estadística): mosaico 2x2 con
   entrada desde las cuatro esquinas y ficha protagonista al pasar el cursor.
   Solo alcanza a `.svc-cards--reveal`; el resto de bloques `glow` no cambia.
   ========================================================================= */
@media (min-width: 760px) {
  /* Altura FIJA de la rejilla: es lo que permite repartir filas en `fr` sin que el
     bloque cambie de alto al expandir una ficha (cero saltos y cero overflow). */
  .svc-cards--reveal {
    grid-template-rows: 1fr 1fr;
    /* Alto pensado para que la ficha protagonista quepa con su texto completo: con
       34vw el contenido de la ficha más larga desbordaba 15px. */
    height: clamp(510px, 37.5vw, 620px);
    transition: grid-template-columns 0.55s var(--ease-out),
      grid-template-rows 0.55s var(--ease-out);
  }
  .svc-cards--reveal > .svc-card--reveal { height: 100%; min-width: 0; }
  /* Redistribución: la columna y la fila de la ficha apuntada crecen y las otras se
     repliegan; como los `fr` suman siempre lo mismo, todo sigue dentro del
     contenedor. `:has()` ya se usa en el proyecto (base.css, header). */
  .svc-cards--reveal:has(> .svc-card--reveal:nth-child(1).is-open),
  .svc-cards--reveal:has(> .svc-card--reveal:nth-child(3).is-open) {
    grid-template-columns: 1.4fr 0.6fr;
  }
  .svc-cards--reveal:has(> .svc-card--reveal:nth-child(2).is-open),
  .svc-cards--reveal:has(> .svc-card--reveal:nth-child(4).is-open) {
    grid-template-columns: 0.6fr 1.4fr;
  }
  .svc-cards--reveal:has(> .svc-card--reveal:nth-child(1).is-open),
  .svc-cards--reveal:has(> .svc-card--reveal:nth-child(2).is-open) {
    grid-template-rows: 1.24fr 0.76fr;
  }
  .svc-cards--reveal:has(> .svc-card--reveal:nth-child(3).is-open),
  .svc-cards--reveal:has(> .svc-card--reveal:nth-child(4).is-open) {
    grid-template-rows: 0.76fr 1.24fr;
  }
  /* Las que ceden protagonismo se repliegan: recogen las etiquetas y encogen su
     tipografía, de modo que el título nunca queda cortado en la celda pequeña
     (medido: a tamaño completo se recortaba y desbordaba 33px). */
  .svc-cards--reveal:has(> .is-open) > .svc-card--reveal:not(.is-open) .svc-card__tags {
    opacity: 0;
    transform: translateY(6px);
  }
  .svc-cards--reveal:has(> .is-open) > .svc-card--reveal:not(.is-open) .svc-card__title {
    font-size: 1.02rem;
    line-height: 1.28;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    overflow: hidden;
  }
  .svc-cards--reveal:has(> .is-open) > .svc-card--reveal:not(.is-open) .svc-card__n {
    font-size: 1.15rem;
  }
  .svc-cards--reveal > .svc-card--reveal .svc-card__title,
  .svc-cards--reveal > .svc-card--reveal .svc-card__n {
    transition: font-size 0.5s var(--ease-out);
  }
}
.svc-card--reveal { display: flex; flex-direction: column; overflow: hidden; }
/* Número y título NO se encogen: al ser la ficha un flex column con overflow oculto,
   en la celda más pequeña flexbox los aplastaba (el título llegó a medir 0). Quien
   cede es el bloque de etiquetas, que en ese estado ya está invisible. */
.svc-card--reveal > .svc-card__n,
.svc-card--reveal > .svc-card__title { flex-shrink: 0; }
.svc-card--reveal > .svc-card__tags { flex-shrink: 1; min-height: 0; }
/* Recurso gráfico abstracto: en reposo acompaña al título; cuando la ficha toma el
   protagonismo se repliega hacia la esquina para dejar sitio al texto. */
.svc-rv__art {
  position: absolute;
  right: clamp(1rem, 2vw, 1.6rem);
  bottom: clamp(1rem, 2vw, 1.6rem);
  z-index: 0;
  width: clamp(88px, 9vw, 124px);
  color: var(--color-primary);
  opacity: 0.34;
  transform-origin: bottom right;
  transition: transform 0.55s var(--ease-out), opacity 0.45s var(--ease-out);
  pointer-events: none;
}
.svc-rv__art svg { display: block; width: 100%; height: auto; fill: none; }
/* Variante con ILUSTRACIÓN (los vectores de «Análisis con inteligencia» de
   Estadística): la imagen ya trae su color, así que no usa currentColor y va algo
   más visible que el vector monocromo (0.34), pero sigue siendo decorativa de
   esquina y se repliega igual al ganar la ficha protagonismo (regla de :hover/
   .is-open más abajo, que baja la opacidad). */
.svc-rv__art--img { opacity: 0.85; }
.svc-rv__art--img img { display: block; width: 100%; height: auto; }
/* Indicador «+» de que la ficha se EXPANDE al PULSAR (en escritorio y táctil).
   Gira a «×» cuando la ficha está abierta (.is-open) y hace de botón de cerrar.
   Visible en todos los dispositivos; decorativo (pointer-events:none). */
.svc-rv__more {
  position: absolute;
  top: clamp(1rem, 2vw, 1.5rem);
  right: clamp(1rem, 2vw, 1.5rem);
  width: 1.7rem; height: 1.7rem;
  border-radius: 50%;
  border: 1.5px solid rgba(8, 114, 187, 0.35);
  background: var(--color-surface);
  color: var(--color-primary);
  z-index: 2;
  pointer-events: none;
  transition: transform 0.5s var(--ease-out), background 0.3s var(--ease-out),
    color 0.3s var(--ease-out), border-color 0.3s var(--ease-out);
}
@supports (color: color-mix(in srgb, red, blue)) {
  .svc-rv__more { border-color: color-mix(in srgb, var(--color-primary) 40%, transparent); }
}
.svc-rv__more::before,
.svc-rv__more::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  background: currentColor; border-radius: 2px;
  transform: translate(-50%, -50%);
}
.svc-rv__more::before { width: 0.8rem; height: 2px; }
.svc-rv__more::after  { width: 2px; height: 0.8rem; }
/* ABIERTA (tras pulsar): el «+» gira a «×» y se rellena → indica que vuelve a
   pulsarse para CERRAR. El giro es SOLO con .is-open, nunca con :hover. */
.svc-card--reveal.is-open .svc-rv__more {
  transform: rotate(45deg);
  background: var(--color-primary);
  color: #fff;
  border-color: var(--color-primary);
}
/* Escritorio: al pasar el cursor por una ficha cerrada el «+» se resalta (sin girar)
   para invitar a PULSAR; el contenido no se revela con el hover. */
@media (hover: hover) and (pointer: fine) {
  .svc-card--reveal { cursor: pointer; }
  .svc-card--reveal:not(.is-open):hover .svc-rv__more {
    background: var(--color-primary);
    color: #fff;
    border-color: var(--color-primary);
    transform: scale(1.08);
  }
}
/* El texto vive en un envoltorio que pasa de 0fr a 1fr: se despliega ocupando el
   alto que necesita, sin `max-height` fijos ni saltos. */
.svc-rv__body {
  display: grid;
  grid-template-rows: 0fr;
  position: relative;
  z-index: 1;
  transition: grid-template-rows 0.55s var(--ease-out), margin-top 0.55s var(--ease-out);
}
.svc-rv__body > .svc-card__text {
  overflow: hidden;
  min-height: 0;
  opacity: 0;
  clip-path: inset(0 0 100% 0);
  transform: translateY(8px);
  transition: opacity 0.45s var(--ease-out) 0.1s, clip-path 0.55s var(--ease-out) 0.1s,
    transform 0.5s var(--ease-out) 0.1s;
}
.svc-card--reveal.is-open .svc-rv__body { grid-template-rows: 1fr; margin-top: var(--space-sm); }
.svc-card--reveal.is-open .svc-rv__body > .svc-card__text {
  opacity: 1;
  clip-path: inset(0 0 0 0);
  transform: none;
}
.svc-card--reveal.is-open .svc-rv__art { transform: scale(0.62) translate(14%, 14%); opacity: 0.16; }
/* Las etiquetas bajan al final y acompañan la reorganización. */
.svc-card--reveal .svc-card__tags {
  margin-top: auto;
  transition: opacity 0.4s var(--ease-out), transform 0.45s var(--ease-out);
}

/* ---- Entrada: cada ficha llega desde su esquina ----
   Una sola animación parametrizada con variables por posición (translate, giro y
   recorte direccional), combinada con blur y escala. Se dispara con `.is-visible`
   del observer global y `backwards` deja el transform en `none` al terminar, así
   el hover toma el control limpio. Una sola vez por carga (el observer deja de
   observar la ficha tras el primer cruce). */
.js .svc-card--reveal[data-reveal] { --fx: -1; --fy: -1; --fr: -2.5deg; }
.js .svc-card--reveal[data-reveal]:nth-child(2) { --fx: 1; --fy: -1; --fr: 2.5deg; }
.js .svc-card--reveal[data-reveal]:nth-child(3) { --fx: -1; --fy: 1; --fr: 2.5deg; }
.js .svc-card--reveal[data-reveal]:nth-child(4) { --fx: 1; --fy: 1; --fr: -2.5deg; }
.js .svc-card--reveal[data-reveal] {
  transform: none;                 /* el movimiento lo pone la animación */
  transition: none;
}
.js .svc-card--reveal[data-reveal].is-visible {
  animation: svcRevealIn 0.95s cubic-bezier(0.22, 0.9, 0.28, 1) backwards;
}
@keyframes svcRevealIn {
  from {
    opacity: 0;
    transform: translate(calc(var(--fx) * 12%), calc(var(--fy) * 16%)) rotate(var(--fr)) scale(0.96);
    clip-path: inset(
      calc(var(--fy) * -14% + 14%) calc(var(--fx) * 14% + 14%)
      calc(var(--fy) * 14% + 14%) calc(var(--fx) * -14% + 14%) round var(--radius-lg));
    filter: blur(5px);
  }
  to {
    opacity: 1;
    transform: translate(0, 0) rotate(0deg) scale(1);
    clip-path: inset(0 0 0 0 round var(--radius-lg));
    filter: blur(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .js .svc-card--reveal[data-reveal],
  .js .svc-card--reveal[data-reveal].is-visible { opacity: 1; animation: none; filter: none; }
  .svc-cards--reveal, .svc-rv__body, .svc-rv__art,
  .svc-card--reveal .svc-card__tags { transition: none; }
}

/* =========================================================================
   "Inversión con estrategia" (Social Media Ads, cards_num con 'scrollgrid'):
   dos carriles verticales sincronizados que muestran UNA sola pareja activa a la vez.
   La sección se FIJA (pin de sección) mientras el scroll avanza y el JS (main.js)
   añade .is-sga y desplaza cada celda con translateY ligado al progreso: carril
   IZQUIERDO abajo→centro→arriba, DERECHO arriba→centro→abajo (opuestos). Base/fallback
   (móvil, sin-JS, reduce-motion): lista simple de parejas (imagen sobre ficha). Solo
   translateY (sin scale/rotación) → sin layout shift. Mantiene la ficha (.svc-card) y tokens.
   ========================================================================= */
/* --- Base / fallback / móvil: lista vertical de parejas (imagen sobre ficha) --- */
.sga-lanes { display: flex; flex-direction: column; gap: clamp(3rem, 2rem + 5vw, 6.5rem); }
.sga-pair { display: grid; grid-template-columns: 1fr; gap: var(--space-xl); }
.sga-figure {
  margin: 0;
  border-radius: var(--radius-lg);
  border: var(--border-soft);
  background: linear-gradient(135deg, var(--color-surface-3), var(--color-surface-2));
  display: grid; place-items: center;
  overflow: hidden;
  aspect-ratio: 16 / 10;
}
.sga-figure svg { width: 74%; height: 74%; max-height: 260px; display: block; }
.sga-figure .ln { fill: none; stroke: var(--color-primary); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }
.sga-figure .ac { fill: none; stroke: var(--color-cyan); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }
.sga-figure .fl { fill: var(--color-cyan); stroke: none; }
.sga-figure .fp { fill: var(--color-primary); stroke: none; }
.sga-figure .bg { fill: var(--color-surface); }
/* Ilustración (imagen) en el bloque de figura: 'contain' dentro del panel fijo → todas
   ocupan el MISMO tamaño de panel (sin distorsión, aunque tengan proporciones distintas). */
.sga-figure img { width: 100%; height: 100%; object-fit: contain; display: block; padding: clamp(1rem, 0.5rem + 2vw, 2.25rem); }

/* --- Efecto "2 carriles / 1 pareja activa" (lo activa el JS con .is-sga; escritorio) --- */
@media (min-width: 768px) {
  .sga-section.is-sga { position: relative; padding-block: 0; height: calc((100svh - var(--header-h)) + var(--sga-steps, 3) * 80svh); }
  .sga-section.is-sga .sga-stage {
    position: sticky; top: var(--header-h);
    height: calc(100svh - var(--header-h));
    display: flex; align-items: center;
  }
  .sga-section.is-sga .sga-stage > .container { width: 100%; }
  .sga-section.is-sga .section-head { margin-bottom: var(--space-xl); }
  /* El slot: altura controlada (una fila). Recorta las celdas que entran/salen. */
  .sga-section.is-sga .sga-lanes { position: relative; display: block; height: clamp(340px, 54vh, 480px); overflow: hidden; }
  .sga-section.is-sga .sga-pair { display: contents; }
  .sga-section.is-sga [data-sga-cell] {
    position: absolute; top: 0; height: 100%;
    width: calc(50% - var(--space-xl) / 2);
    margin: 0;
    will-change: transform;
  }
  /* Posición inicial (pareja 0 centrada; el resto fuera del slot) hasta que el JS scrubbea.
     El paso 115% (>100% = alto del slot) deja un HUECO vertical entre elementos consecutivos
     de la cinta (más separación). Debe coincidir con SGA_STEP en main.js. */
  .sga-section.is-sga [data-sga-side="left"]  { left: 0;  transform: translateY(calc(var(--i, 0) * 115%)); }
  .sga-section.is-sga [data-sga-side="right"] { right: 0; transform: translateY(calc(var(--i, 0) * -115%)); }
  .sga-section.is-sga .sga-figure { aspect-ratio: auto; }
}

/* =========================================================================
   Apartados "¿Quieres...?" (cards_num con 'canvas'): carrusel horizontal
   INFINITO y draggable. Fichas alineadas (misma altura, sin rotación) con una
   levitación vertical continua y desincronizada. El JS (main.js) añade
   .is-carousel, clona el set para el bucle sin huecos y gestiona drag + inercia.
   Sin JS / motion reducido: scroll horizontal nativo (fallback accesible).
   Barra de scroll oculta; nunca provoca overflow del body.
   ========================================================================= */
.svc-canvas {
  overflow-x: auto;              /* fallback sin JS / reduced-motion */
  overflow-y: hidden;
  scrollbar-width: none;
  -ms-overflow-style: none;
  -webkit-overflow-scrolling: touch;
}
.svc-canvas::-webkit-scrollbar { width: 0; height: 0; display: none; }
/* Modo carrusel (JS): el desplazamiento lo controla el transform del escenario. */
.svc-canvas.is-carousel { overflow: hidden; cursor: grab; touch-action: pan-y; }
.svc-canvas.is-carousel.is-dragging { cursor: grabbing; }

.svc-canvas__stage {
  --svc-gap: clamp(1.5rem, 3vw, 3rem);
  display: flex;
  align-items: stretch;         /* todas a la misma altura, alineadas */
  gap: var(--svc-gap);
  width: max-content;
  padding-block: clamp(2rem, 1.5rem + 2vw, 3.5rem);
  will-change: transform;
}
/* Contenedor de cada ficha: SOLO levitación vertical continua (sin rotación).
   Ancho ≈ 1/4 del viewport reservando huecos para que solo se vean 4 fichas a la
   vez, algo más estrechas y separadas; más altas vía min-height. En pantallas
   pequeñas se aplica un mínimo legible (se ven menos de 4, con swipe). */
.svc-canvas__card {
  flex: 0 0 auto;
  width: max(230px, calc((100vw - 5 * var(--svc-gap)) / 4));
  min-height: clamp(320px, 19vw, 370px);
  animation: svc-float var(--float-dur, 5s) ease-in-out var(--float-delay, 0s) infinite;
  will-change: transform;
}
/* Segundo párrafo del texto (canvas con `texto2`): separación entre párrafos. */
.svc-canvas .svc-card__text + .svc-card__text { margin-top: 0.65rem; }
@keyframes svc-float {
  0%, 100% { transform: translate3d(0, calc(var(--float-amp, 6px) * -1), 0); }
  50%      { transform: translate3d(0, var(--float-amp, 6px), 0); }
}
/* La ficha visible: misma altura + hover elegante (sin rotación). */
.svc-canvas .svc-card {
  height: 100%;
  transition: transform 0.4s cubic-bezier(0.22, 0.8, 0.3, 1),
    box-shadow var(--dur-base) var(--ease-out),
    border-color var(--dur-base) var(--ease-out);
  box-shadow: var(--shadow-md);
}
.svc-canvas .svc-card:hover {
  transform: translate3d(0, -10px, 0) scale(1.03);
  box-shadow: var(--shadow-lg);
  border-color: var(--color-primary);
}
/* Durante el arrastre no se dispara el hover (evita saltos). */
.svc-canvas.is-dragging .svc-card { transition: box-shadow var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out); }

@media (prefers-reduced-motion: reduce) {
  .svc-canvas__card { animation: none; }
  .svc-canvas .svc-card, .svc-canvas .svc-card:hover { transform: none; }
}

/* === MÓVIL · UNA FICHA COMPLETA POR VISTA (scroll-snap) — INICIO ===================
   Solo en móvil (<768px). En estas anchuras el carrusel JS NO se activa (ver el gate
   en main.js), así que .svc-canvas hace scroll nativo. Cada ficha ocupa el ancho del
   contenedor (menos los márgenes laterales = --gutter), no asoma parte de la siguiente
   y cada una queda centrada al deslizar gracias a scroll-snap. Tableta y escritorio no
   se ven afectados. Para DESHACER: borrar este bloque completo (entre los marcadores). */
@media (max-width: 767px) {
  .svc-canvas {
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: var(--gutter);
  }
  .svc-canvas__stage {
    width: max-content;
    gap: var(--gutter);                 /* con este gap la siguiente ficha queda fuera de vista */
    padding-inline: var(--gutter);      /* margen lateral: la 1ª y la última pueden centrarse */
  }
  .svc-canvas__card {
    width: calc(100vw - 2 * var(--gutter));   /* una ficha a lo ancho, con márgenes */
    scroll-snap-align: center;
    scroll-snap-stop: always;                 /* una ficha por deslizamiento */
  }
}
/* === MÓVIL · UNA FICHA COMPLETA POR VISTA (scroll-snap) — FIN ===================== */

/* Banda de característica con sub-CTA (p. ej. mantenimiento) */
.feature-band {
  background: var(--gradient-deep);
  color: #fff;
  text-align: center;
  padding-block: clamp(3rem, 2rem + 5vw, 6rem);
}
.feature-band__inner { max-width: none; margin-inline: 0; }
.feature-band__title { color: #fff; font-size: clamp(1.6rem, 1.1rem + 2.6vw, 3rem); text-transform: uppercase; line-height: 1.15; }
.feature-band__sub { color: var(--color-cyan); font-size: var(--fs-h3); margin-top: var(--space-lg); text-transform: uppercase; }
.feature-band__text { color: var(--color-on-dark-soft); margin: var(--space-md) auto 0; max-width: 85ch; font-size: clamp(0.9rem, 0.86rem + 0.2vw, 1rem); }

/* Negritas (**keyword**) en los textos de las landings de servicio, realzadas según
   el fondo: claro → ink; oscuro → blanco. */
.svc-card__text strong,
.stk-card__body p strong,
.vst-card .card p strong,
.faq-item__body strong,
.svc-intro__p strong { color: var(--color-ink); font-weight: var(--fw-bold); }
.eshop-card__text strong,
.feature-band__text strong { color: #fff; font-weight: var(--fw-bold); }

/* =========================================================================
   Landing de servicio
   ========================================================================= */
.svc-section { }
.problem-grid, .benefit-grid, .who-grid { display: grid; gap: var(--space-md); }
@media (min-width: 700px) {
  .problem-grid, .benefit-grid { grid-template-columns: repeat(2, 1fr); }
  .who-grid { grid-template-columns: repeat(3, 1fr); }
}
.check-item, .cross-item {
  display: flex; gap: 0.75rem; align-items: flex-start;
  padding: var(--space-md);
  background: var(--color-surface-2);
  border-radius: var(--radius-sm);
}
.check-item .ic, .cross-item .ic {
  flex-shrink: 0; width: 1.5rem; height: 1.5rem;
  display: grid; place-items: center; border-radius: var(--radius-pill);
}
.check-item .ic { background: var(--color-surface-3); color: var(--color-primary); }
.cross-item .ic { background: #fdecea; color: var(--color-error); }
.check-item .ic svg, .cross-item .ic svg { width: 0.85rem; height: 0.85rem; }

.deliverables { display: grid; gap: 0.6rem; }
@media (min-width: 700px) { .deliverables { grid-template-columns: repeat(2, 1fr); } }
.deliverables li { display: flex; gap: 0.6rem; align-items: flex-start; }
.deliverables li::before { content: "—"; color: var(--color-cyan); font-weight: 700; }

/* Relacionados */
.related-services { display: grid; gap: var(--space-md); }
@media (min-width: 700px) { .related-services { grid-template-columns: repeat(2, 1fr); } }
.related-card {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-md);
  padding: var(--space-lg);
  border: var(--border-soft);
  border-radius: var(--radius-md);
  color: var(--color-ink);
  transition: border-color var(--dur-base) var(--ease-out), background-color var(--dur-base) var(--ease-out);
}
.related-card:hover { border-color: var(--color-primary); background: var(--color-surface-2); color: var(--color-primary); }
.related-card svg { width: 1.2rem; height: 1.2rem; flex-shrink: 0; }

/* =========================================================================
   FAQ (accesible, <details>)
   ========================================================================= */
.faq { max-width: var(--container-reading); }
.faq-item {
  border: var(--border-soft);
  border-radius: var(--radius-md);
  margin-bottom: var(--space-md);
  background: var(--color-surface);
  overflow: hidden;
}
.faq-item > summary {
  cursor: pointer;
  list-style: none;
  padding: var(--space-lg);
  font-family: var(--font-heading);
  font-weight: var(--fw-semibold);
  display: flex; justify-content: space-between; align-items: center; gap: 1rem;
}
.faq-item > summary::-webkit-details-marker { display: none; }
.faq-item > summary::after {
  content: "+";
  font-size: 1.5rem;
  color: var(--color-primary);
  transition: transform var(--dur-base) var(--ease-out);
  flex-shrink: 0;
}
.faq-item[open] > summary::after { content: "–"; }
.faq-item__body { padding: 0 var(--space-lg) var(--space-lg); color: var(--color-ink-soft); }

/* =========================================================================
   Proceso (pasos numerados verticales para landings)
   ========================================================================= */
.process-steps { display: grid; gap: var(--space-lg); counter-reset: pstep; }
@media (min-width: 900px) { .process-steps { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); } }
.process-step { padding: var(--space-lg); border-radius: var(--radius-md); background: var(--color-surface-2); }
.process-step__n {
  font-family: var(--font-heading); font-weight: var(--fw-extrabold);
  color: var(--color-cyan); font-size: 1.4rem; margin-bottom: 0.4rem;
}
.process-step h3 { font-size: 1.05rem; margin-bottom: 0.3rem; }
.process-step p { font-size: 0.95rem; color: var(--color-ink-soft); }

/* =========================================================================
   Contacto
   ========================================================================= */
.contact-split { align-items: start; gap: clamp(2rem, 1rem + 4vw, 4rem); }
@media (min-width: 900px) { .contact-split { grid-template-columns: 0.85fr 1.15fr; } }
.contact-form-wrap { box-shadow: var(--shadow-md); border-color: transparent; }
.contact-form .grid--2 { column-gap: var(--space-2xl); }
@media (max-width: 600px) { .contact-form .grid--2 { column-gap: 0; } }

/* Página de contacto */
/* Cabecera de Contacto: texto a la izquierda e ilustración a la derecha, CENTRADA
   respecto al bloque de título/texto (los datos de contacto viven ya en su propio
   apartado, así que la columna izquierda no arrastra la ilustración hacia abajo). */
.contact-hero { align-items: center; gap: clamp(2rem, 1rem + 3vw, 4rem); }
@media (min-width: 900px) { .contact-hero { grid-template-columns: 1.05fr 0.95fr; } }
.contact-hero__media img { width: 100%; border-radius: var(--radius-lg); }

/* ---- Datos de contacto: módulo compacto de 4 tarjetas ----
   Un solo bloque visual (hueco corto entre tarjetas, misma altura) con icono, título
   e información centrados. 4 columnas en escritorio, 2 en tablet y 1 en móvil. */
.contact-data { padding-block: clamp(2.25rem, 1.75rem + 2vw, 3.5rem); }
/* max-width:none → el H2 ocupa todo el ancho del contenedor (.section-head lo limita
   a 60ch por defecto). */
.contact-data__head { margin-bottom: clamp(1.5rem, 1rem + 1.5vw, 2.25rem); max-width: none; }
.contact-cards {
  display: grid;
  grid-template-columns: 1fr;
  grid-auto-rows: 1fr;                       /* las 4 tarjetas, misma altura */
  gap: clamp(0.75rem, 0.5rem + 0.8vw, 1.15rem);
  max-width: 1100px;
  margin-inline: auto;
}
@media (min-width: 620px) { .contact-cards { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .contact-cards { grid-template-columns: repeat(4, 1fr); } }
.contact-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  padding: clamp(1.15rem, 0.9rem + 0.6vw, 1.6rem) clamp(0.9rem, 0.7rem + 0.5vw, 1.25rem);
  background: var(--color-surface);
  border: var(--border-soft);
  border-radius: var(--radius-lg);
  text-align: center;
  transition: transform var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out),
    border-color var(--dur-base) var(--ease-out);
}
.contact-card:hover, .contact-card:focus-within {
  transform: translateY(-4px);
  border-color: var(--color-primary);
  box-shadow: var(--shadow-md);
}
.contact-card__ic {
  width: 2.75rem; height: 2.75rem;
  display: grid; place-items: center;
  border-radius: var(--radius-sm);
  background: var(--color-surface-3);
  color: var(--color-primary);
  transition: background var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out);
}
.contact-card__ic svg { width: 1.3rem; height: 1.3rem; fill: none; }
.contact-card:hover .contact-card__ic { background: var(--color-primary); color: #fff; }
.contact-card__title {
  font-family: var(--font-heading);
  font-size: var(--fs-small);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--color-ink-soft);
}
.contact-card address { font-style: normal; font-size: 0.95rem; color: var(--color-ink-soft); line-height: 1.5; }
.contact-card__link { display: block; color: inherit; }
.contact-card__link:hover address { color: var(--color-primary); }
.contact-card__lines { display: grid; gap: 0.15rem; }
.contact-card__lines a {
  font-family: var(--font-heading);
  font-weight: var(--fw-semibold);
  color: var(--color-ink);
  word-break: break-word;
}
.contact-card__lines a:hover { color: var(--color-primary); }
/* Redes en 2 filas × 2 columnas */
.contact-card__social {
  display: grid;
  grid-template-columns: repeat(2, auto);
  justify-content: center;
  gap: 0.5rem;
  margin-top: 0.15rem;
}
.contact-card__social-btn {
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border: 1px solid var(--color-line);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  color: var(--color-primary);
  transition: background var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out),
    color var(--dur-base) var(--ease-out);
}
.contact-card__social-btn svg { width: 1.25rem; height: 1.25rem; fill: currentColor; }
.contact-card__social-btn:hover { background: var(--color-primary); border-color: var(--color-primary); color: #fff; }

/* El formulario necesita aire respecto al módulo de contacto (~90px en escritorio). */
.contact-form-section { padding-top: clamp(3.5rem, 2.5rem + 4vw, 7.5rem); }
.contact-points { display: grid; gap: var(--space-md); margin-top: var(--space-xl); }
.contact-points li { display: flex; gap: 0.75rem; align-items: center; }
.contact-points__ic {
  flex-shrink: 0; width: 2.25rem; height: 2.25rem;
  display: grid; place-items: center;
  border-radius: var(--radius-sm);
  background: var(--color-surface-3); color: var(--color-primary);
}
.contact-points__ic svg { width: 1.2rem; height: 1.2rem; }
.contact-points a { color: var(--color-ink); }
.contact-points a:hover { color: var(--color-primary); }

/* Botón flotante de WhatsApp */
.whatsapp-float {
  position: fixed;
  right: clamp(1rem, 0.5rem + 1vw, 1.75rem);
  bottom: clamp(1rem, 0.5rem + 1vw, 1.75rem);
  z-index: var(--z-toast);
  width: 58px; height: 58px;
  display: grid; place-items: center;
  border-radius: var(--radius-pill);
  background: #25D366;
  color: #fff;
  box-shadow: 0 10px 28px rgba(37, 211, 102, 0.45);
  transition: transform var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
}
.whatsapp-float:hover { transform: translateY(-3px) scale(1.04); color: #fff; box-shadow: 0 14px 34px rgba(37, 211, 102, 0.55); }
.whatsapp-float svg { width: 30px; height: 30px; }

/* =========================================================================
   Encabezados de servicio a todo el ancho + hover de etiquetas
   ========================================================================= */
/* H2 y primer párrafo ocupan todo el ancho del contenedor (como las fichas) */
.svc-head { max-width: none; }
.svc-intro { max-width: none; }
.svc-intro__title { line-height: 1.14; }
.svc-intro__p { max-width: none; color: var(--color-ink-soft); }
.svc-intro__p + .svc-intro__p { margin-top: var(--space-md); }
/* Variante compacta del bloque de texto (flag 'compact'): párrafos con menor tamaño
   para acomodar más contenido sin que domine visualmente. */
.svc-intro--compact .svc-intro__p { font-size: clamp(0.95rem, 0.9rem + 0.3vw, 1.06rem); }
.svc-intro--compact .svc-intro__p + .svc-intro__p { margin-top: var(--space-sm); }
/* Bloque de texto con imagen (tipo 'texto' con 'imagen'): dos columnas (.split). La
   ilustración (fondo transparente) se muestra sin panel ni sombra, centrada. */
.svc-txt-split .svc-intro { max-width: 46rem; }
.svc-txt-media { display: flex; justify-content: center; align-items: center; }
.svc-txt-media img { width: 100%; height: auto; max-width: 440px; display: block; }

/* Bloque 'phone_video': texto + maqueta de móvil con vídeo. Teléfono independiente
   (no comparte estilos con el de la sección de Instagram para no heredar su tamaño). */
.pv-media { display: flex; justify-content: center; align-items: center; }
.pv-phone {
  position: relative;
  width: min(300px, 78vw);
  aspect-ratio: 320 / 660;
  background: #0c0d12;
  border-radius: 44px;
  padding: 12px;
  box-shadow: 0 30px 60px -20px rgba(5, 64, 112, 0.45), 0 0 0 2px rgba(255, 255, 255, 0.06) inset;
}
.pv-phone__cam {
  position: absolute; top: 16px; left: 50%; transform: translateX(-50%);
  width: 42%; height: 22px; background: #0c0d12; border-radius: 0 0 14px 14px; z-index: 3;
}
.pv-phone__screen {
  height: 100%;
  border-radius: 33px;
  overflow: hidden;
  background: #000;
}
.pv-video { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Variante circular (flag 'media_circle'): la imagen se recorta en círculo. Ideal para
   fotografías (equipo, oficina); object-fit evita deformar la foto al cuadrarla. */
.svc-txt-media--circle img {
  width: clamp(240px, 24vw, 380px);
  max-width: 100%;
  aspect-ratio: 1 / 1;
  height: auto;
  object-fit: cover;
  border-radius: 50%;
  box-shadow: var(--shadow-md);
}
/* Con imagen CIRCULAR el reparto por defecto (~1fr/1fr) deja mucho aire alrededor del
   círculo y aprieta el texto. Damos más ancho al texto y menos a la imagen; como el
   `order` de .split--reverse mueve el texto a la 2ª celda, invertimos el ratio en ese
   caso para que el texto sea siempre la columna ancha (esté la imagen a izq. o der.). */
@media (min-width: 900px) {
  .svc-txt-split:not(.split--reverse):has(.svc-txt-media--circle) {
    grid-template-columns: minmax(0, 1.45fr) minmax(0, 0.55fr);
  }
  .svc-txt-split.split--reverse:has(.svc-txt-media--circle) {
    grid-template-columns: minmax(0, 0.55fr) minmax(0, 1.45fr);
  }
}

/* ---- Entrada 'unfold' del bloque texto+imagen (Merchandising) ----
   El .split es el ÚNICO disparador (data-reveal → .is-visible); no se oculta a sí mismo
   y sus dos columnas animan a la vez: la imagen se despliega de arriba abajo (clip-path,
   sin deformar) y, ya desplegada, crece hasta su tamaño real; el texto (h2 + párrafos)
   entra en bloque desde la derecha. */
.js .svc-txt-split--unfold[data-reveal] { opacity: 1; transform: none; transition: none; }

.js .svc-txt-split--unfold .svc-intro {
  opacity: 0;
  transform: translateX(80px);
  transition: opacity 0.8s var(--ease-out), transform 0.95s cubic-bezier(0.22, 0.9, 0.3, 1);
}
.js .svc-txt-split--unfold.is-visible .svc-intro { opacity: 1; transform: none; }

/* clip-path y transform van en la MISMA imagen: el recorte se aplica antes que la escala,
   así el desplegado sigue siempre al borde de la imagen (no al hueco del contenedor). */
.js .svc-txt-split--unfold .svc-txt-media img {
  transform-origin: top center;
  clip-path: inset(0 0 100% 0);
}
.js .svc-txt-split--unfold.is-visible .svc-txt-media img {
  animation: svcTxtUnfold 1.35s cubic-bezier(0.22, 0.9, 0.3, 1) both;
}
@keyframes svcTxtUnfold {
  0%   { clip-path: inset(0 0 100% 0); transform: scale(0.76); }
  52%  { clip-path: inset(0 0 0 0);    transform: scale(0.76); }
  100% { clip-path: inset(0 0 0 0);    transform: scale(1); }
}

@media (max-width: 599px) {
  .js .svc-txt-split--unfold .svc-intro { transform: translateX(48px); }
  .js .svc-txt-split--unfold.is-visible .svc-intro { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .js .svc-txt-split--unfold .svc-intro { opacity: 1; transform: none; transition: none; }
  .js .svc-txt-split--unfold .svc-txt-media img,
  .js .svc-txt-split--unfold.is-visible .svc-txt-media img {
    clip-path: none; transform: none; animation: none;
  }
}

/* Etiquetas: se encienden al pasar por la ficha */
.svc-tag { transition: background-color var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out); }
.svc-card:hover .svc-tag { background: var(--color-primary); color: #fff; }

/* =========================================================================
   Fichas de proyecto (sectores): tamaño uniforme, fondo blanco, imagen + zoom
   ========================================================================= */
.case-grid { grid-auto-rows: 1fr; }               /* todas las fichas al mismo alto */
.case-card {
  height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--color-surface);               /* blanco (claro) / superficie (oscuro) */
  border: var(--border-soft);
  border-radius: var(--radius-md);
  overflow: hidden;
  transition: transform var(--dur-base) var(--ease-out),
    box-shadow var(--dur-base) var(--ease-out),
    border-color var(--dur-base) var(--ease-out);
}
.case-card:hover {
  transform: translateY(-8px) scale(1.01);
  box-shadow: var(--shadow-lg);
  border-color: var(--color-primary);
}
.case-card__media {
  position: relative;
  aspect-ratio: 4 / 3;                            /* misma imagen en todas las fichas */
  overflow: hidden;
  background: var(--color-surface-2);
  flex: 0 0 auto;
}
.case-card__media img {
  width: 100%; height: 100%;
  object-fit: cover; object-position: center;
  display: block;
  transition: transform var(--dur-slow) var(--ease-out);
}
.case-card:hover .case-card__media img { transform: scale(1.07); }
/* Proyecto sin imagen: isotipo centrado, mismo tamaño de ficha */
.case-card--noimg .case-card__media { display: grid; place-items: center; }
.case-card__ph { width: 38%; height: auto; opacity: 0.45; transform: none !important; }
.case-card__body {
  flex: 1 1 auto;                                 /* rellena el resto → cuerpos iguales */
  padding: clamp(1.35rem, 1.1rem + 1vw, 1.9rem);
  display: flex; flex-direction: column; gap: 0.45rem;
}
.case-card__body h3 { font-size: var(--fs-h4); }
.case-card__body p { color: var(--color-ink-soft); }
.case-card__body .link-arrow { margin-top: auto; padding-top: var(--space-sm); }

@media (prefers-reduced-motion: reduce) {
  .case-card:hover .case-card__media img { transform: none; }
}

/* =========================================================================
   Sectores (índice + ficha)
   ========================================================================= */
.sector-hero__meta { display: flex; flex-wrap: wrap; gap: var(--space-sm); margin-top: var(--space-md); }

/* En las páginas de sector: H2, párrafo intro y FAQ ocupan todo el ancho */
.page-sector .section-head { max-width: none; }
.page-sector .faq { max-width: none; }

/* Marketing digital: las fichas de FAQ ocupan todo el ancho del contenedor */
.service-marketing-digital .faq { max-width: none; }
/* …y su encabezado también: `.section-head` lo limitaba a 60ch. Se apunta con
   `:has(+ .faq)` para alcanzar SOLO el del FAQ sin tocar la plantilla común de
   service-render.php (que la comparten las 16 landings). */
.service-marketing-digital .section-head:has(+ .faq) { max-width: none; }

/* =========================================================================
   Galería de proyectos en RUEDA 3D (piloto: sector Educación y Formación).
   Sin JS / motion reducido → rejilla accesible (fallback). Con JS, se añade
   .is-wheel (escenario 3D) y, en escritorio con puntero fino, .pw-desktop
   (sección sticky: el scroll vertical gira la rueda y luego la página continúa).
   En táctil: arrastre horizontal con inercia. Lógica en main.js.
   ========================================================================= */
/* --- Fallback (rejilla) y estilo base de la ficha (imagen + overlay) --- */
.pw-stage { display: grid; gap: var(--space-lg); grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.pw-card {
  position: relative;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--color-surface-3);
  box-shadow: var(--shadow-md);
}
.pw-card__media { aspect-ratio: 4 / 3; }
.pw-card__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pw-card__ph { object-fit: contain; padding: 18%; opacity: 0.5; }
.pw-card__overlay {
  position: absolute; inset: auto 0 0 0;
  padding: clamp(1rem, 2vw, 1.6rem);
  background: linear-gradient(0deg, rgba(3, 30, 54, 0.88), rgba(3, 30, 54, 0.5) 55%, transparent);
  color: #fff;
}
.pw-card__cat {
  display: inline-block;
  font-family: var(--font-heading); font-weight: var(--fw-semibold);
  font-size: 0.72rem; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--color-cyan); margin-bottom: 0.35rem;
}
.pw-card__title { color: #fff; font-size: var(--fs-h4); margin-bottom: 0.3rem; }
.pw-card__text { color: rgba(255, 255, 255, 0.85); font-size: 0.95rem; line-height: 1.4; max-width: 46ch; }
.pw-card__link { margin-top: 0.6rem; color: #fff; }
.pw-card__link:hover { color: var(--color-cyan); }
.pw-hint { display: none; }
/* Un solo proyecto: no hay rueda (el JS requiere ≥2); se muestra la MISMA ficha
   centrada y con el tamaño/proporción de la tarjeta central de la rueda (no estirada). */
.pw-stage .pw-card:only-child { max-width: min(520px, 92vw); margin-inline: auto; }
.pw-stage .pw-card:only-child .pw-card__media { aspect-ratio: 16 / 11; }

/* --- Modo rueda (JS) --- */
.pw-stage.is-wheel {
  display: block;
  position: relative;
  height: min(64vh, 540px);
  perspective: 1200px;
  transform-style: preserve-3d;
  overflow: hidden;            /* recorta los laterales; nunca scrollbar */
  touch-action: pan-y;         /* permite scroll vertical de la página en táctil */
}
.pw-stage.is-wheel .pw-card {
  position: absolute; left: 50%; top: 50%;
  width: min(520px, 74vw);
  transform: translate(-50%, -50%);   /* el JS lo sobrescribe cada frame */
  transform-style: preserve-3d;
  box-shadow: 0 30px 60px -24px rgba(3, 30, 54, 0.6);
  cursor: grab;
}
.pw-stage.is-wheel .pw-card__media { aspect-ratio: 16 / 11; }
.pw-stage.is-wheel.is-dragging .pw-card { cursor: grabbing; }
.pw-hint { text-align: center; color: var(--color-ink-soft); font-size: 0.9rem; margin-top: var(--space-md); }

/* Sticky solo en escritorio con puntero fino (lo activa el JS con .pw-desktop) */
.pw-section .pw-track { position: relative; }
.pw-section.pw-desktop .pw-track { height: 320vh; }
.pw-section.pw-desktop .pw-sticky {
  position: sticky; top: var(--header-h);
  height: calc(100svh - var(--header-h));
  display: flex; flex-direction: column; justify-content: center; gap: var(--space-lg);
}
.pw-section.pw-desktop .pw-hint { display: block; }

/* =========================================================================
   404: escáner interactivo. Las palabras del fondo SOLO se ven dentro de un
   círculo que sigue al cursor, recortado con una máscara radial centrada en
   --mx/--my (las escribe el módulo [data-scanner] de main.js, igual que el
   spotlight de las fichas glow). Capa puramente decorativa: nada captura el
   ratón y el contenido de la página no se toca.
   ========================================================================= */
.nf-scan {
  position: relative;
  overflow: hidden;          /* las palabras giradas no generan scroll lateral */
  --scan-d: clamp(120px, 12vw, 180px);
}
/* Capas: 404 de fondo (0) → palabras (1) → contenido (2) → halo (3). */
.nf-scan > .container { position: relative; z-index: 2; }
/* 404 gigante de fondo: decorativo, muy tenue y siempre por detrás de todo. */
.nf-404 {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  user-select: none;
  font-family: var(--font-heading);
  font-weight: var(--fw-extrabold);
  font-size: clamp(11rem, 34vw, 28rem);
  line-height: 0.82;
  letter-spacing: -0.04em;
  color: var(--color-primary);
  opacity: 0.07;
  white-space: nowrap;
}
/* Cada cifra se mueve por su cuenta (el JS le escribe --px/--py/--sk): el conjunto
   se deforma como un gel muy contenido y vuelve solo al alejarse el cursor. */
.nf-404__d {
  display: inline-block;
  transform: translate(var(--px, 0px), var(--py, 0px)) skewX(var(--sk, 0deg));
  transition: transform 0.5s var(--ease-out);
  will-change: transform;
}
.nf-scan__words {
  position: absolute;
  inset: 0;
  z-index: 1;                /* sobre el 404 de fondo, DEBAJO del texto y los botones */
  display: block;
  pointer-events: none;
  opacity: var(--scan-on, 0);
  transition: opacity 0.45s var(--ease-out);
  /* Fuera del círculo la máscara es transparente → invisibles por completo. */
  -webkit-mask-image: radial-gradient(circle calc(var(--scan-d) / 2) at var(--mx, -999px) var(--my, -999px),
    #000 42%, rgba(0, 0, 0, 0.45) 70%, transparent 100%);
  mask-image: radial-gradient(circle calc(var(--scan-d) / 2) at var(--mx, -999px) var(--my, -999px),
    #000 42%, rgba(0, 0, 0, 0.45) 70%, transparent 100%);
}
.nf-word {
  position: absolute;
  left: var(--x);
  top: var(--y);
  transform: translate(-50%, -50%) rotate(var(--r));
  font-family: var(--font-heading);
  font-weight: var(--fw-extrabold);
  font-size: var(--s);
  line-height: 1;
  letter-spacing: 0.08em;
  white-space: nowrap;
  color: var(--color-primary);
  opacity: var(--o);
  user-select: none;
}
/* Halo del escáner: solo luz. Un degradado suave que se desvanece hacia fuera y un
   filo azul apenas insinuado; sin punto central, cruces ni marcas de mira. Sigue al
   cursor sin transición de posición para no ir por detrás. */
.nf-scan__ring {
  position: absolute;
  z-index: 3;
  left: var(--mx, -999px);
  top: var(--my, -999px);
  width: var(--scan-d);
  height: var(--scan-d);
  margin: calc(var(--scan-d) / -2) 0 0 calc(var(--scan-d) / -2);
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--color-primary) 16%, transparent);
  background: radial-gradient(circle at 50% 50%,
    color-mix(in srgb, var(--color-primary) 11%, transparent) 0%,
    color-mix(in srgb, var(--color-primary) 5%, transparent) 48%,
    transparent 74%);
  box-shadow: 0 0 34px -10px color-mix(in srgb, var(--color-primary) 34%, transparent);
  filter: blur(0.4px);
  opacity: var(--scan-on, 0);
  transition: opacity 0.45s var(--ease-out);
  pointer-events: none;
}

/* Sin JS y con movimiento reducido no hay escáner: las palabras siguen ocultas
   (--scan-on por defecto es 0) y se retira también el halo. El 404 de fondo SÍ se
   conserva —es decoración estática—, pero sin deformarse. */
@media (prefers-reduced-motion: reduce) {
  .nf-scan__words, .nf-scan__ring { display: none; }
  .nf-404__d { transition: none; transform: none; }
}

/* =========================================================================
   RESEÑAS DE GOOGLE (portada, entre Blog y Hablemos). Dos zonas: valoración
   global real (izq.) + carrusel de reseñas de 5★ (der.). Contenido dinámico
   desde data/google-reviews.json. Vanilla (no hay GSAP); azules corporativos.
   ========================================================================= */
.gr__grid {
  display: grid;
  grid-template-columns: minmax(0, 340px) minmax(0, 1fr);
  gap: clamp(1.5rem, 1rem + 2.4vw, 3.25rem);
  align-items: start;
}

/* --- Estrellas (relleno fraccionado por --pct; variante --full = 5 doradas) --- */
.gr-stars { position: relative; display: inline-block; white-space: nowrap; line-height: 1;
  letter-spacing: 0.14em; font-size: 1.2rem; }
.gr-stars__bg { color: #d9e2ec; }
.gr-stars__fg { position: absolute; inset: 0; width: var(--pct, 100%); overflow: hidden; color: #fbbc04; }
.gr-stars--full { color: #fbbc04; letter-spacing: 0.14em; }

/* --- IZQUIERDA: valoración global --- */
.gr-summary {
  background: var(--color-surface);
  border: var(--border-soft);
  border-radius: var(--radius-lg);
  padding: clamp(1.5rem, 1.1rem + 1.6vw, 2.5rem);
  box-shadow: 0 24px 60px -34px rgba(3, 30, 54, 0.5);
  text-align: center;
  position: relative;
  overflow: hidden;
}
.gr-summary::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 4px;
  background: var(--gradient-brand);
}
.gr-summary__brand {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-family: var(--font-heading); font-weight: var(--fw-semibold, 600);
  font-size: var(--fs-small); color: var(--color-ink-soft);
  letter-spacing: 0.02em;
}
.gr-summary__brand .gr-g { flex: 0 0 auto; }
.gr-summary__rating {
  display: flex; align-items: baseline; justify-content: center; gap: 0.4rem;
  margin-top: var(--space-sm);
}
.gr-summary__score {
  font-family: var(--font-heading); font-weight: 800;
  font-size: clamp(3.2rem, 2.4rem + 3vw, 4.6rem); line-height: 0.95;
  color: var(--color-deep-blue); letter-spacing: -0.02em;
}
.gr-summary__out { font-size: 1.25rem; font-weight: 600; color: var(--color-ink-soft); }
.gr-summary .gr-stars { margin-top: 0.75rem; font-size: 1.5rem; }
.gr-summary__count { margin-top: 0.85rem; color: var(--color-ink-soft); font-size: var(--fs-small); }
.gr-summary__count strong { color: var(--color-ink); font-weight: 700; }
.gr-summary__cta { margin-top: var(--space-lg); width: 100%; }
.gr-summary__cta svg { width: 1em; height: 1em; margin-left: 0.15rem; }

/* --- DERECHA: carrusel --- */
.gr-carousel { min-width: 0; }
.gr-carousel__top {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  margin-bottom: var(--space-md);
}
.gr-carousel__hint {
  display: inline-flex; align-items: center; gap: 0.45rem;
  font-size: var(--fs-small); color: var(--color-ink-soft); font-weight: 600;
}
.gr-nav { display: inline-flex; gap: 0.5rem; }
.gr-nav__btn {
  --sz: 2.6rem; width: var(--sz); height: var(--sz);
  display: grid; place-items: center;
  border: var(--border-soft); border-radius: 50%;
  background: var(--color-surface); color: var(--color-primary);
  cursor: pointer; transition: background var(--dur-base) var(--ease-out),
    color var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out),
    transform var(--dur-base) var(--ease-out), opacity var(--dur-base) var(--ease-out);
}
.gr-nav__btn svg { width: 1.15rem; height: 1.15rem; }
.gr-nav__btn:hover { background: var(--color-primary); color: #fff; border-color: var(--color-primary); }
.gr-nav__btn:disabled { opacity: 0.4; cursor: default; }
.gr-nav__btn:disabled:hover { background: var(--color-surface); color: var(--color-primary); border-color: var(--color-border, rgba(0,0,0,.1)); }

.gr-track {
  list-style: none; margin: 0; padding: 0.5rem 0.25rem 0.75rem;
  display: flex; gap: clamp(1rem, 0.6rem + 1vw, 1.5rem);
  overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x mandatory; scroll-behavior: smooth;
  scrollbar-width: none; -ms-overflow-style: none;
  overscroll-behavior-x: contain;
}
.gr-track::-webkit-scrollbar { display: none; }
.gr-track.is-grabbing { scroll-behavior: auto; cursor: grabbing; scroll-snap-type: none; }

.gr-card {
  flex: 0 0 clamp(268px, 80%, 344px);
  scroll-snap-align: start;
  background: var(--color-surface);
  border: var(--border-soft);
  border-radius: var(--radius-lg);
  padding: clamp(1.25rem, 1rem + 0.8vw, 1.75rem);
  display: flex; flex-direction: column; gap: 0.75rem;
  transition: transform var(--dur-base) var(--ease-out),
    box-shadow var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out);
}
.gr-card:hover { transform: translateY(-6px); box-shadow: var(--shadow-lg); border-color: color-mix(in srgb, var(--color-primary) 45%, transparent); }
@supports not (color: color-mix(in srgb, red, blue)) { .gr-card:hover { border-color: rgba(8, 114, 187, 0.45); } }
.gr-card__head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
.gr-card__g { display: inline-flex; opacity: 0.9; }
.gr-card__text {
  color: var(--color-ink-soft); margin: 0; font-size: 0.98rem; line-height: 1.6;
  display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical; overflow: hidden;
}
.gr-card.is-expanded .gr-card__text { -webkit-line-clamp: unset; overflow: visible; }
.gr-card__more {
  align-self: flex-start; background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--color-primary); font-weight: 600; font-size: 0.9rem;
  font-family: inherit; margin-top: -0.15rem; text-decoration: none;
}
.gr-card__more:hover { text-decoration: underline; }
.gr-card__author { display: flex; align-items: center; gap: 0.7rem; margin-top: auto; padding-top: 0.4rem; }
.gr-card__avatar {
  position: relative; width: 44px; height: 44px; flex: 0 0 auto;
  border-radius: 50%; overflow: hidden; display: grid; place-items: center;
  background: var(--color-surface-3); color: var(--color-primary);
  font-family: var(--font-heading); font-weight: 700;
}
.gr-card__photo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.gr-card__who { display: flex; flex-direction: column; min-width: 0; }
.gr-card__name { font-weight: 700; color: var(--color-ink); font-size: 0.95rem; }
.gr-card__date { font-size: 0.8rem; color: var(--color-ink-soft); }

/* --- Entrada escalonada (la activa el JS con .gr-in; respeta reduce-motion) --- */
.js [data-reviews] .gr-card { opacity: 0; transform: translateY(18px); }
.js [data-reviews].gr-in .gr-card {
  opacity: 1; transform: none;
  transition: opacity 0.6s var(--ease-out), transform 0.6s var(--ease-out);
  transition-delay: calc(var(--i, 0) * 80ms);
}

/* --- Responsive: apilado en una columna --- */
@media (max-width: 860px) {
  .gr__grid { grid-template-columns: 1fr; }
  .gr-summary { text-align: center; }
  .gr-card { flex-basis: min(82%, 320px); }
}

@media (prefers-reduced-motion: reduce) {
  .js [data-reviews] .gr-card { opacity: 1; transform: none; transition: none; }
  .gr-track { scroll-behavior: auto; }
}

/* =========================================================================
   Página Kit Digital: bloques de texto en prosa + rejilla de categorías de
   soluciones (tarjeta con lista de características, nota del programa y precio).
   ========================================================================= */
.kit-prose { max-width: 62rem; }
.kit-prose > p { margin-top: var(--space-md); color: var(--color-ink-soft); font-size: 1.05rem; line-height: var(--lh-body); }
.kit-prose > p:first-of-type { margin-top: var(--space-lg); }

.kit-media { margin-top: var(--space-xl); }
.kit-media img { width: 100%; height: auto; border-radius: var(--radius-lg); box-shadow: var(--shadow-md); display: block; }

/* Logo de agentes digitalizadores (banda estrecha centrada, antes de «¿Qué es…?»). */
.kit-logos { padding-block: var(--space-xl); }
.kit-logos__wrap { max-width: 720px; margin-inline: auto; }
.kit-logos__wrap img { width: 100%; height: auto; display: block; }

.kit-cats { display: grid; gap: var(--space-lg); margin-top: var(--space-2xl); grid-template-columns: 1fr; }
@media (min-width: 720px) { .kit-cats { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .kit-cats { grid-template-columns: repeat(3, 1fr); } }

.kit-card {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: var(--space-lg);
  background: var(--color-surface);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}
.kit-card__cat {
  font-family: var(--font-heading);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-small);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-primary);
  margin-bottom: 0.5rem;
}
.kit-card__rec { color: var(--color-ink-soft); font-size: 0.95rem; line-height: 1.5; margin: 0 0 var(--space-md); }
.kit-card__sol { font-size: 1.05rem; margin: 0 0 0.6rem; color: var(--color-ink); }
.kit-list { list-style: none; margin: 0 0 var(--space-md); padding: 0; display: flex; flex-direction: column; gap: 0.55rem; }
.kit-list li {
  position: relative;
  padding-left: 1.35rem;
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--color-ink-soft);
}
.kit-list li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.5em;
  width: 0.5rem; height: 0.5rem;
  border-radius: 50%;
  background: var(--color-cyan);
}
.kit-list li strong { color: var(--color-ink); font-weight: var(--fw-semibold); }
.kit-card__note { font-size: 0.78rem; color: var(--color-muted); line-height: 1.45; margin: 0 0 0.9rem; }
.kit-card__note + .kit-card__note { margin-top: -0.5rem; }
.kit-card__price {
  margin-top: auto;
  align-self: flex-start;
  font-family: var(--font-heading);
  font-weight: var(--fw-bold);
  font-size: 1.15rem;
  color: var(--color-primary);
  background: var(--color-surface-2, rgba(8, 114, 187, 0.08));
  border: 1px solid rgba(8, 114, 187, 0.18);
  border-radius: var(--radius-pill);
  padding: 0.5rem 1rem;
}

/* --- Página Trabaja con nosotros: lista de contacto --- */
.kit-prose a { color: var(--color-primary); text-decoration: underline; text-underline-offset: 2px; }
.kit-prose a:hover { color: var(--color-deep-blue); }
.trabaja-contact__lead { margin-top: var(--space-lg); font-weight: var(--fw-semibold); color: var(--color-ink); }
.trabaja-contact { list-style: none; margin: 0.8rem 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.9rem; }
.trabaja-contact li { display: flex; align-items: center; gap: 0.85rem; }
/* Mismo icono en badge que las tarjetas de la página de Contacto (.contact-card__ic). */
.trabaja-contact__ic {
  width: 2.75rem; height: 2.75rem;
  display: grid; place-items: center;
  border-radius: var(--radius-sm);
  background: var(--color-surface-3);
  color: var(--color-primary);
  flex: none;
}
.trabaja-contact__ic svg { width: 1.3rem; height: 1.3rem; fill: none; }
.trabaja-contact a { color: var(--color-ink); font-size: 1.05rem; text-decoration: none; }
.trabaja-contact a:hover { color: var(--color-primary); }

/* Apartado breve «Trabaja con nosotros» (La Agencia, bajo Redes sociales). */
.join-band {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-lg);
  padding: clamp(1.5rem, 1rem + 2vw, 2.5rem);
  background: var(--color-surface);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}
.join-band__text { min-width: min(100%, 22rem); flex: 1 1 22rem; }
.join-band__text .eyebrow { margin-bottom: 0.35rem; }
.join-band__title { margin: 0 0 0.4rem; }
.join-band__text p { margin: 0; color: var(--color-ink-soft); }
.join-band__cta { flex: none; }

/* Fila de apartados «join» (La Agencia): dos bandas iguales, lado a lado en escritorio,
   apiladas en móvil. */
.join-row { display: grid; gap: var(--space-lg); grid-template-columns: 1fr; }
@media (min-width: 800px) { .join-row { grid-template-columns: repeat(2, 1fr); } }
.join-row .join-band { height: 100%; }
/* En ESCRITORIO el h2 de los apartados «join» (Únete al equipo / Compromiso social) se
   reduce un poco respecto al h2 por defecto (que llega a 64px), que resultaba grande en
   estas bandas compactas. En móvil se mantiene igual. */
@media (min-width: 800px) {
  .join-band__title { font-size: clamp(1.9rem, 1.2rem + 1.9vw, 3rem); }
}

/* Variante con foto de fondo (La Agencia): imagen «oficina-trabajadores» + overlay
   oscuro para asegurar legibilidad; textos en blanco. */
.join-band--photo {
  position: relative;
  isolation: isolate;
  border: 0;
  overflow: hidden;
  background-image:
    linear-gradient(rgba(5, 20, 38, 0.72), rgba(5, 20, 38, 0.72)),
    var(--join-bg);
  background-size: cover;
  background-position: center;
}
.join-band--photo .eyebrow { color: var(--color-cyan); }
.join-band--photo .join-band__title { color: #fff; }
.join-band--photo .join-band__text p { color: rgba(255, 255, 255, 0.88); }
