/* =============================================================
   IntegraTec v2 — hoja de estilos

   PALETA: los dos colores de marca salen del logo oficial,
   muestreados del PNG — naranja #F6A331 y azul #3260AA. El celeste
   es el color de apoyo del modo día.

   UN SOLO TEMA, oscuro. Antes había dos (día y noche) con un
   interruptor en el header; se retiró el claro por decisión de marca.
   Los componentes siguen leyendo tokens semánticos (--band, --card,
   --band-ink…) y no colores sueltos, así que si algún día vuelve el
   modo claro basta con añadir otro bloque que los redefina.

   Reglas de color que hay que respetar al añadir algo:
     1. El NARANJA nunca es texto sobre fondo claro (2.06:1 sobre
        blanco). Va sobre oscuro, o como relleno con texto oscuro
        encima (9.56:1). Es la acción principal en los dos temas.
     2. El CELESTE tiene tres tonos por la misma razón: #38BDF8 solo
        sobre oscuro, #136287 para texto sobre claro (6.17:1) y
        #1B6E9C para relleno con texto blanco (5.59:1).
     3. El AZUL base es texto sobre claro (6.20:1). Sobre oscuro se
        usa --blue-400.

   1. Tokens · 2. Temas · 3. Reset · 4. Loader · 5. Layout
   6. Tipografía · 7. Botones · 8. Top bar · 9. Header
   10. Hero · 11. Stats · 12. Cards · 13. Portafolio · 14. Cursos
   15. Carrusel · 16. Testimonios · 17. Banner · 18. Contacto
   19. CTA · 20. Footer · 21. WhatsApp · 22. Modal · 23. Reveals
   24. Responsive · 25. reduced-motion
   ============================================================= */

/* ---------------------------- 1. TOKENS ---------------------------- */
:root {
  /* Marca — idénticos en los dos temas */
  --blue-900: #1C355E;
  --blue-800: #24457A;
  --blue-700: #2A5290;
  --blue: #3260AA;
  --blue-400: #7DA0D9;
  --blue-tint: rgba(50, 96, 170, 0.10);

  --orange: #F6A331;
  --orange-600: #DC840A;
  --orange-text: #9A5C07;  /* naranja como texto sobre claro  4.66:1 */
  --orange-300: #F9BF6F;
  --orange-tint: rgba(246, 163, 49, 0.12);

  --celeste: #38BDF8;        /* decorativo · texto sobre oscuro */
  --celeste-ink: #136287;    /* texto sobre claro  6.17:1 */
  --celeste-solid: #1B6E9C;  /* relleno con texto blanco  5.59:1 */
  --celeste-tint: rgba(56, 189, 248, 0.14);

  --wa: #25D366;
  --wa-dark: #1DAF52;

  /* SUPERFICIE TINTA — oscura en los dos temas, a propósito.
     Solo la usan el top bar, el CTA, el pie, el modal, el cromo del
     mockup y los dos paneles de acento (aside de contacto y bloque de
     capacitación). Todo lo demás voltea con el tema. */
  --ink-surface: #050B18;
  --ink-surface-2: #0D1B33;
  --on-ink: #FFFFFF;
  --on-ink-muted: #9BAAC4;
  --ink-line: rgba(255, 255, 255, 0.12);
  --ink-hair: rgba(255, 255, 255, 0.06);

  /* Tipografía */
  --font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;

  --fs-display: 3.5rem;   /* 56 */
  --fs-h1: 2.75rem;       /* 44 */
  --fs-h2: 2.25rem;       /* 36 */
  --fs-h3: 1.375rem;      /* 22 */
  --fs-h4: 1.125rem;      /* 18 */
  --fs-lead: 1.125rem;    /* 18 */
  --fs-body: 0.9375rem;   /* 15 */
  --fs-small: 0.875rem;   /* 14 */
  --fs-micro: 0.8125rem;  /* 13 — mínimo del sistema */

  --lh-tight: 1.15;
  --lh-heading: 1.25;
  --lh-body: 1.6;
  --ls-tight: -0.02em;
  --ls-wide: 0.06em;

  --r-xs: 4px; --r-sm: 8px; --r-md: 12px; --r-lg: 16px; --r-pill: 999px;

  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px; --sp-4: 16px;
  --sp-5: 20px; --sp-6: 24px; --sp-8: 32px; --sp-10: 40px;
  --sp-12: 48px; --sp-16: 64px;

  --wrap: 1200px;
  --gutter: clamp(20px, 5vw, 120px);
  --section-y: clamp(64px, 8vw, 112px);
  --card-pad: var(--sp-8);
  --grid-gap: var(--sp-6);
  --header-h: 88px;

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-out-soft: cubic-bezier(0.16, 1, 0.30, 1);
  /* Curva de los carruseles. Las dos de arriba son ease-OUT fuertes:
     se comen el 80% del recorrido en el primer cuarto del tiempo y el
     resto solo se asientan, así que por larga que sea la duración el
     desplazamiento se lee como un salto. Esta reparte el movimiento —
     arranca despacio, corre por el medio y frena — que es lo que deja
     apreciar el recorrido lateral. Es el equivalente en bezier al
     easeInOutCubic que usa el carrusel de proyectos en su rAF. */
  --ease-carrusel: cubic-bezier(0.65, 0, 0.35, 1);
  /* Todo el movimiento de la página cuelga de estos tres. Se subieron
     desde 260/700/320: a la velocidad anterior los cambios se leían
     como saltos, sobre todo el paso de los carruseles. Si algo se
     siente lento, se baja aquí y baja en toda la página a la vez. */
  --dur: 340ms;
  --dur-slow: 900ms;
  --dur-theme: 460ms;
}

/* ---------------------------- 2. TEMAS ---------------------------- */

/* TEMA OSCURO — el único.
   La escala de azules se subió un paso respecto a la original: el
   fondo más profundo era #030710, prácticamente negro, y con tanta
   superficie oscura seguida las secciones dejaban de distinguirse
   entre sí. Se mantiene la jerarquía de siempre —la BANDA queda por
   encima de la superficie profunda— para que el ritmo alterno de
   secciones se siga leyendo.

     --deep      fondo profundo (hero, secciones oscuras)
     --page      color del documento
     --band      franja intermedia, un punto por encima de --deep
     --card      tarjetas sobre banda
     --deep-card tarjetas sobre superficie profunda    */
:root {
  --page: #0A1425;

  --band: #122036;
  --band-ink: #FFFFFF;
  --band-muted: #9BAAC4;
  --band-line: rgba(255, 255, 255, 0.10);
  --band-accent: var(--celeste);
  --band-bullet: var(--celeste);

  --card: #172945;
  --card-line: rgba(255, 255, 255, 0.10);
  --icon-bg: rgba(56, 189, 248, 0.12);
  --icon-fg: var(--celeste);

  --deep: #081020;
  --deep-2: #0C1729;
  --deep-3: #122139;
  --deep-card: #182B4A;
  --deep-ink: #FFFFFF;
  --deep-muted: #9BAAC4;
  --deep-line: rgba(255, 255, 255, 0.12);
  --deep-hair: rgba(255, 255, 255, 0.06);
  --eyebrow-on-deep: var(--orange);
  --focus-on-deep: var(--orange);
  --orange-text: var(--orange);
  --chip-on-deep-bg: rgba(255, 255, 255, 0.10);
  --chip-on-deep-ink: #FFFFFF;

  --glow-a: rgba(50, 96, 170, 0.55);
  --glow-b: rgba(246, 163, 49, 0.22);
  --mesh: rgba(56, 189, 248, 0.06);
  --hero-clients-ink: rgba(255, 255, 255, 0.14);
  --hero-clients-mark: rgba(56, 189, 248, 0.40);
  --hero-scrim: rgba(8, 16, 32, 0.92);
  --hero-logo-filter: brightness(0) invert(1);
  --hero-logo-op: 0.34;
  --stats-logo-op: 0.30;
  --fx-dot: rgba(56, 189, 248, 0.45);
  --fx-node: rgba(56, 189, 248, 0.75);
  --fx-node-hero: rgba(56, 189, 248, 1);
  /* Estos DOS se quedan claros a propósito: son paneles que sostienen
     logotipos ajenos y sellos ISO con sus colores de marca. Varios de
     esos SVG son un bloque macizo con texto blanco, y sobre fondo
     oscuro se convierten en rectángulos ilegibles. */
  --logo-panel: #EEF3F9;
  --iso-filter: brightness(0) invert(1);
  --logo-mono: brightness(0) invert(1);
  --spot: rgba(56, 189, 248, 0.16);

  --field: #101D33;
  --shadow-card: 0 18px 40px rgba(0, 0, 0, 0.55);
  --shadow-pop: 0 24px 60px rgba(0, 0, 0, 0.70);
}

/* ------------------------- 3. RESET / BASE ------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + var(--sp-4));
}

body {
  margin: 0;
  background: var(--page);
  color: var(--band-ink);
  font-family: var(--font);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  transition: background var(--dur-theme) var(--ease), color var(--dur-theme) var(--ease);
}

img, svg, video { display: block; max-width: 100%; }
img { height: auto; }

/* Con !important a propósito: `display:block` de autor gana al
   `display:none` que el navegador aplica a [hidden]. */
[hidden] { display: none !important; }

h1, h2, h3, h4, p, ul, figure, blockquote { margin: 0; }
ul { padding: 0; list-style: none; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
input, select, textarea { font: inherit; color: inherit; }

svg[viewBox] {
  width: 100%; height: 100%;
  fill: none; stroke: currentColor;
  stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round;
}

:focus-visible { outline: 2px solid var(--band-accent); outline-offset: 3px; border-radius: var(--r-xs); }
.section--deep :focus-visible, .header :focus-visible, .hero :focus-visible,
.stats :focus-visible, .course :focus-visible { outline-color: var(--focus-on-deep); }

.skip-link {
  position: fixed; top: 8px; left: 8px; z-index: 600;
  padding: 10px 18px;
  background: var(--card); color: var(--band-ink);
  border: 1px solid var(--card-line);
  border-radius: var(--r-sm);
  font-size: var(--fs-small); font-weight: 600;
  transform: translateY(-200%);
  transition: transform var(--dur) var(--ease);
}
.skip-link:focus-visible { transform: none; }

/* --------------------------- 4. LOADER --------------------------- */
.loader {
  position: fixed; inset: 0; z-index: 500;
  display: grid; place-items: center;
  background: #050B18;
  overflow: hidden;
  /* Red de seguridad: si el JS no llega a retirarlo, se va solo. */
  animation: loaderSafety 420ms var(--ease) 3200ms forwards;
}
.loader.is-done { opacity: 0; visibility: hidden; pointer-events: none; transition: opacity 480ms var(--ease), visibility 480ms; }
/* Sin JS nadie retiraría el loader: el `animation` de arriba lo oculta a
   los 3,2 s, pero mostrar 3 segundos de pantalla negra a quien nunca va
   a ver la animación no tiene sentido. */
.sin-js .loader { display: none; }

@keyframes loaderSafety {
  to { opacity: 0; visibility: hidden; pointer-events: none; }
}

.loader__bg { position: absolute; inset: 0; }

/* Rejilla plana que se desplaza, con máscara radial para que se
   desvanezca hacia los bordes.
   Nota: una versión anterior usaba una rejilla en perspectiva
   (rotateX + transform-origin abajo). Se descartó porque con
   perspectivas pequeñas la caja se comprime contra el origen y en
   ventanas bajas quedaba fuera del viewport. Esta es estable. */
.loader__grid {
  position: absolute; inset: 0;
  background-image:
    linear-gradient(rgba(56, 189, 248, 0.18) 1px, transparent 1px),
    linear-gradient(90deg, rgba(56, 189, 248, 0.18) 1px, transparent 1px);
  background-size: 48px 48px;
  animation: gridRun 3s linear infinite;
  -webkit-mask-image: radial-gradient(ellipse at 50% 50%, #000 10%, transparent 70%);
  mask-image: radial-gradient(ellipse at 50% 50%, #000 10%, transparent 70%);
}
@keyframes gridRun {
  to { background-position: 48px 48px, 48px 48px; }
}

/* Nodos: puntos de red repartidos, con un latido suave */
.loader__nodes {
  position: absolute; inset: 0;
  background-image: radial-gradient(circle, rgba(246, 163, 49, 0.55) 1.5px, transparent 1.6px);
  background-size: 96px 96px;
  opacity: 0.6;
  animation: nodePulse 3.2s ease-in-out infinite;
}
@keyframes nodePulse {
  0%, 100% { opacity: 0.25; }
  50%      { opacity: 0.6; }
}

/* Barrido horizontal tipo escáner */
.loader__scan {
  position: absolute; left: 0; right: 0; top: 0; height: 220px;
  background: linear-gradient(180deg, transparent, rgba(56, 189, 248, 0.14), transparent);
  animation: scanRun 2.8s ease-in-out infinite;
}
@keyframes scanRun {
  0%   { transform: translateY(-240px); }
  100% { transform: translateY(100vh); }
}

/* Los dos halos son los dos colores de la marca */
.loader__orb {
  position: absolute; border-radius: 50%;
  filter: blur(90px); pointer-events: none;
}
.loader__orb--a {
  left: -120px; top: -80px; width: 460px; height: 460px;
  background: rgba(50, 96, 170, 0.55);
}
.loader__orb--b {
  right: -100px; bottom: -120px; width: 400px; height: 400px;
  background: rgba(246, 163, 49, 0.28);
}

.loader__content {
  position: relative;
  display: grid; justify-items: center; gap: var(--sp-6);
  padding: var(--sp-6);
  text-align: center;
}
.loader__logo {
  width: clamp(180px, 34vw, 260px); height: auto;
  animation: logoIn 900ms var(--ease) both;
}
@keyframes logoIn {
  from { opacity: 0; transform: translateY(14px) scale(0.96); }
  to   { opacity: 1; transform: none; }
}

.loader__bar {
  width: clamp(180px, 34vw, 260px); height: 3px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.12);
  overflow: hidden;
}
.loader__bar span {
  display: block; width: 40%; height: 100%;
  border-radius: var(--r-pill);
  background: linear-gradient(90deg, var(--blue), var(--celeste), var(--orange));
  animation: barRun 1.3s var(--ease) infinite;
}
@keyframes barRun {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(350%); }
}

.loader__text {
  font-size: var(--fs-small);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--on-ink-muted);
}
.loader__dots::after {
  content: "";
  animation: dots 1.4s steps(4, end) infinite;
}
@keyframes dots {
  0%   { content: ""; }
  25%  { content: "."; }
  50%  { content: ".."; }
  75%  { content: "..."; }
}

/* --------------------------- 5. LAYOUT --------------------------- */
.wrap {
  width: 100%;
  max-width: calc(var(--wrap) + var(--gutter) * 2);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* position:relative es necesario, no decorativo: las capas .fx van con
   inset:0 y sin él se posicionan contra el viewport en vez de contra
   su sección. */
.section { position: relative; padding-block: var(--section-y); }
.section--band { background: var(--band); color: var(--band-ink); }
.section--deep { background: var(--deep); color: var(--deep-ink); }
.section--band, .section--deep {
  transition: background var(--dur-theme) var(--ease), color var(--dur-theme) var(--ease);
}

section[id] { scroll-margin-top: calc(var(--header-h) + var(--sp-4)); }

.sec-head { max-width: 62ch; margin-bottom: var(--sp-12); }
.sec-head--center { margin-inline: auto; text-align: center; }

/* ------------------------- 6. TIPOGRAFÍA ------------------------- */
.eyebrow {
  margin-bottom: var(--sp-3);
  font-size: var(--fs-small);
  font-weight: 700;
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--band-accent);
}
.section--deep .eyebrow, .hero .eyebrow { color: var(--eyebrow-on-deep); }
.cta .eyebrow { color: var(--orange); }   /* el CTA es tinta siempre */

.h1, .h2, .h3 { font-weight: 700; }
/* `.h1` solo lo usan las páginas interiores: la portada tiene su propio
   `.hero__title`, que se parte en palabras para la animación de
   entrada y por eso no comparte estilo. */
.h1 { font-size: var(--fs-h1); line-height: var(--lh-tight); letter-spacing: var(--ls-tight); }
.h2 { font-size: var(--fs-h2); line-height: var(--lh-heading); letter-spacing: var(--ls-tight); }
.h3 { font-size: var(--fs-h3); line-height: var(--lh-heading); }

.lead { margin-top: var(--sp-4); font-size: var(--fs-lead); color: var(--band-muted); }
.section--deep .lead, .hero .lead { color: var(--deep-muted); }

/* --------------------------- 7. BOTONES --------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--sp-2);
  min-height: 46px;
  padding: 0 var(--sp-6);
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  font-size: var(--fs-body); font-weight: 600;
  text-align: center;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
              color var(--dur) var(--ease), translate var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease);
}
.btn:hover { translate: 0 -2px; }

/* Acción principal: naranja con texto oscuro (9.56:1 en ambos temas) */
.btn--accent {
  background: var(--orange); color: #050B18;
  box-shadow: 0 6px 18px rgba(246, 163, 49, 0.26);
}
.btn--accent:hover { background: var(--orange-300); }

/* Secundaria: celeste sólido con texto blanco (5.59:1) */
.btn--primary { background: var(--celeste-solid); color: #FFFFFF; }
.btn--primary:hover { background: var(--blue-700); }

.btn--ghost { border-color: var(--deep-line); color: var(--deep-ink); }
.btn--ghost:hover { background: var(--deep-hair); border-color: var(--orange); }

.chips { display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.chips li {
  padding: var(--sp-2) var(--sp-4);
  background: var(--card); border: 1px solid var(--card-line);
  border-radius: var(--r-pill);
  font-size: var(--fs-small); color: var(--band-muted);
}

.filters { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-bottom: var(--sp-8); }
.chip-btn {
  padding: var(--sp-2) var(--sp-5); min-height: 40px;
  background: var(--card); border: 1px solid var(--card-line);
  border-radius: var(--r-pill);
  font-size: var(--fs-small); font-weight: 600;
  color: var(--band-muted);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
              color var(--dur) var(--ease);
}
.chip-btn:hover { border-color: var(--band-accent); color: var(--band-accent); }
.chip-btn.is-active { background: var(--celeste-solid); border-color: var(--celeste-solid); color: #FFFFFF; }

/* --------------------------- 9. HEADER --------------------------- */
.header {
  position: sticky; top: 0; z-index: 100;
  background: var(--deep);
  border-bottom: 1px solid var(--deep-hair);
  color: var(--deep-ink);
  transition: box-shadow var(--dur) var(--ease), background var(--dur-theme) var(--ease);
}
.header.is-stuck { box-shadow: var(--shadow-card); }

.header__inner {
  width: 100%; max-width: calc(var(--wrap) + var(--gutter) * 2);
  margin-inline: auto; padding: var(--sp-4) var(--gutter);
  min-height: var(--header-h);
  display: flex; align-items: center; gap: var(--sp-6);
}
.brand { flex: none; }
.brand img {
  width: auto;
  height: 46px;   /* el logo pedía más presencia: antes 34px */
  transition: height var(--dur) var(--ease);
}
.header.is-stuck .brand img { height: 40px; }

.nav { margin-left: auto; }
.nav__list { display: flex; align-items: center; gap: clamp(var(--sp-4), 1.8vw, var(--sp-8)); }
.nav__list a {
  position: relative; display: flex; align-items: center;
  min-height: 44px; padding-block: var(--sp-2);
  font-size: var(--fs-body); font-weight: 500;
  /* color-mix en vez de rgba(255,255,255,.84): el header voltea con el
     tema, así que el enlace en reposo se atenúa contra su propia tinta
     y no contra el blanco. */
  color: color-mix(in srgb, var(--deep-ink) 78%, transparent);
  transition: color var(--dur) var(--ease);
}
.nav__list a::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: var(--orange); border-radius: var(--r-pill);
  transform: scaleX(0);
  transition: transform var(--dur) var(--ease);
}
.nav__list a:hover { color: var(--deep-ink); }
.nav__list a.is-current { color: var(--deep-ink); font-weight: 600; }
.nav__list a.is-current::after { transform: scaleX(1); }

/* ---- Servicios: menú desplegable ---- */
/* El botón imita al resto de enlaces del nav —mismo tamaño, mismo
   subrayado— para que la fila se lea pareja. Lo que lo distingue es la
   flecha. */
.nav__drop { position: relative; }
.nav__drop-btn {
  position: relative;
  display: flex; align-items: center; gap: 6px;
  min-height: 44px; padding: var(--sp-2) 0;
  background: none; border: 0;
  font-size: var(--fs-body); font-weight: 500; font-family: inherit;
  color: color-mix(in srgb, var(--deep-ink) 78%, transparent);
  transition: color var(--dur) var(--ease);
}
.nav__drop-btn::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: var(--orange); border-radius: var(--r-pill);
  transform: scaleX(0);
  transition: transform var(--dur) var(--ease);
}
.nav__drop-btn:hover { color: var(--deep-ink); }
/* `is-current` lo pone el scrollspy cuando la sección visible es una de
   las tres del submenú: si no, al estar en Cursos no se marcaría nada
   en la barra. */
.nav__drop-btn.is-current { color: var(--deep-ink); font-weight: 600; }
.nav__drop-btn.is-current::after { transform: scaleX(1); }

/* Selector de dos clases a propósito: la base lleva un
   `svg[viewBox] { width: 100% }` que, por ser un selector de atributo,
   gana a una sola clase — el icono salía a 237px. */
.nav__drop-btn .nav__caret {
  flex: none;
  width: 15px; height: 15px;
  stroke-width: 2;
  transition: transform var(--dur) var(--ease);
}
.nav__drop-btn[aria-expanded="true"] .nav__caret { transform: rotate(180deg); }

.nav__submenu {
  position: absolute; top: calc(100% + var(--sp-3)); left: calc(var(--sp-4) * -1);
  z-index: 20;
  min-width: 268px;
  padding: var(--sp-3);
  background: var(--card);
  border: 1px solid var(--card-line);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-pop);
  opacity: 0; visibility: hidden;
  transform: translateY(-6px);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease), visibility var(--dur);
}
.nav__drop-btn[aria-expanded="true"] + .nav__submenu {
  opacity: 1; visibility: visible; transform: none;
}
/* Puente invisible entre el botón y el panel: sin él, el hueco de
   12px cierra el menú al bajar el ratón hacia las opciones. */
.nav__submenu::before {
  content: "";
  position: absolute; left: 0; right: 0; top: calc(var(--sp-3) * -1);
  height: var(--sp-3);
}

.nav__submenu a {
  display: block;
  min-height: 0;
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-sm);
  color: var(--band-ink);
  transition: background var(--dur) var(--ease);
}
.nav__submenu a::after { display: none; }
.nav__submenu a:hover, .nav__submenu a:focus-visible { background: var(--band); }
.nav__submenu a.is-current { background: var(--band); }
.nav__submenu b { display: block; font-size: var(--fs-small); font-weight: 600; }
.nav__submenu span { display: block; margin-top: 2px; font-size: var(--fs-micro); color: var(--band-muted); }

.header__actions { display: flex; align-items: center; gap: var(--sp-4); flex: none; }

.nav-toggle { display: none; padding: var(--sp-3); margin-right: calc(var(--sp-3) * -1); }
.nav-toggle span { display: block; width: 22px; }
.nav-toggle i {
  display: block; height: 2px; background: var(--deep-ink); border-radius: var(--r-pill);
  transition: transform var(--dur) var(--ease), opacity var(--dur) var(--ease);
}
.nav-toggle i + i { margin-top: 5px; }
.nav-toggle[aria-expanded="true"] i:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] i:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] i:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* ---------------------------- 10. HERO ---------------------------- */
.hero {
  position: relative;
  /* Alto exacto de lo que queda de pantalla: el primer pantallazo
     llega hasta la cinta de logos sin scroll. svh y no vh para que en
     móvil no cuente la barra del navegador que luego se retrae. */
  min-height: calc(100svh - var(--header-h));
  display: flex; flex-direction: column;
  padding-block: clamp(20px, 3.2vh, 44px);
  background: var(--deep);
  color: var(--deep-ink);
  overflow: hidden;
  transition: background var(--dur-theme) var(--ease);
}
/* Los dos halos y la malla llevan tokens porque su intensidad no puede
   ser la misma sobre tinta que sobre blanco: lo que en oscuro es un
   resplandor, en claro se vuelve una mancha sucia. */
.hero__glow {
  position: absolute; left: -140px; top: 60px;
  width: 620px; height: 620px; border-radius: 50%;
  background: radial-gradient(circle, var(--glow-a), transparent 70%);
  filter: blur(90px); pointer-events: none;
}
.hero__glow--warm {
  left: auto; right: -120px; top: 220px;
  width: 460px; height: 460px;
  background: radial-gradient(circle, var(--glow-b), transparent 70%);
}
/* Malla técnica de fondo, muy tenue */
.hero__mesh {
  position: absolute; inset: 0;
  background-image:
    linear-gradient(var(--mesh) 1px, transparent 1px),
    linear-gradient(90deg, var(--mesh) 1px, transparent 1px);
  background-size: 64px 64px;
  -webkit-mask-image: radial-gradient(ellipse at 50% 0%, #000, transparent 75%);
  mask-image: radial-gradient(ellipse at 50% 0%, #000, transparent 75%);
  pointer-events: none;
}
.hero__grid {
  position: relative;
  z-index: 1;
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(28px, 4vw, 64px); align-items: center;
  flex: 1;
}
.hero__title {
  margin-top: var(--sp-2);
  /* Atada también al alto: en pantallas bajas el titular es lo primero
     que hay que ceder para que quepa todo. */
  font-size: clamp(1.75rem, min(3.5vw, 5.4vh), 3.25rem);
  font-weight: 800;
  line-height: var(--lh-tight); letter-spacing: var(--ls-tight);
  text-wrap: balance;
}
.hero__lead {
  margin-top: clamp(8px, 1.8vh, 20px);
  max-width: 52ch;
  font-size: clamp(0.875rem, min(1.15vw, 2.15vh), 1.125rem);
  color: var(--deep-muted);
}

.hero__actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: clamp(12px, 2.6vh, 32px); }

.hero__checks { display: grid; gap: clamp(5px, 1.1vh, 12px); margin-top: clamp(12px, 2.6vh, 32px); }
.hero__checks li {
  position: relative; padding-left: var(--sp-8);
  font-size: var(--fs-small); color: var(--deep-muted);
}
.hero__checks li::before {
  content: ""; position: absolute; left: 0; top: 2px;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--orange-tint); border: 1px solid var(--orange);
}
.hero__checks li::after {
  content: ""; position: absolute; left: 6px; top: 7px;
  width: 6px; height: 3px;
  border-left: 1.5px solid var(--orange); border-bottom: 1.5px solid var(--orange);
  transform: rotate(-45deg);
}

/* El cromo del mockup se queda tinta en los dos temas: la captura que
   contiene es de una app oscura, un marco claro alrededor la haría
   parecer un recorte pegado. */
.mockup {
  /* Tope por alto de pantalla: en una ventana baja el mockup era lo
     que empujaba la cinta de logos fuera de vista. */
  max-height: min(56vh, 500px);
  overflow: hidden;
  border: 1px solid var(--ink-line); border-radius: var(--r-md);
  background: var(--ink-surface-2); box-shadow: var(--shadow-pop);
  color: var(--on-ink);
  overflow: hidden;
}
.mockup__bar {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--ink-line);
}
/* Los colores viven aquí y no en un `style=` del HTML: la CSP del
   documento prohíbe atributos de estilo en línea. */
.mockup__dot { width: 11px; height: 11px; border-radius: 50%; background: var(--c); }
.mockup__dot--rojo   { --c: #FF5F56; }
.mockup__dot--ambar  { --c: #FFBD2E; }
.mockup__dot--verde  { --c: #27C93F; }
.mockup__url { margin-left: auto; font-size: var(--fs-micro); color: var(--on-ink-muted); }
.mockup img { width: 100%; height: auto; object-fit: cover; object-position: top; }

/* --------- 11. CINTA DE CLIENTES AL PIE DE LA PORTADA --------- */
/* Va dentro del hero para que el primer pantallazo llegue hasta aquí
   sin scroll: propuesta arriba, prueba social abajo. */
.hero__clientes {
  position: relative; z-index: 1;
  margin-top: auto;
  padding-top: clamp(16px, 2.4vh, 28px);
}

/* --------------------------- 12. CARDS --------------------------- */
.cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--grid-gap); }
.cards--2 { grid-template-columns: repeat(2, 1fr); }

.card {
  display: flex; flex-direction: column;
  padding: var(--card-pad);
  background: var(--card);
  border: 1px solid var(--card-line);
  border-radius: var(--r-md);
  color: var(--band-ink);
  transition: translate var(--dur) var(--ease), border-color var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease), background var(--dur-theme) var(--ease),
              color var(--dur-theme) var(--ease);
}
.card:hover { translate: 0 -4px; border-color: var(--band-accent); box-shadow: var(--shadow-card); }

.card--on-deep {
  background: var(--deep-card); border-color: var(--deep-line); color: var(--deep-ink);
}
.card--on-deep:hover { border-color: var(--orange); box-shadow: none; }
.card--on-deep .card__text { color: var(--deep-muted); }
.card--on-deep .card__title { font-size: var(--fs-h4); }

.card__icon {
  display: grid; place-items: center;
  width: 44px; height: 44px;
  margin-bottom: var(--sp-5);
  border-radius: var(--r-sm);
  background: var(--icon-bg); color: var(--icon-fg);
}
.card__icon svg { width: 22px; height: 22px; }

.card__title { font-size: var(--fs-h3); font-weight: 700; line-height: var(--lh-heading); }
.card__text { margin-top: var(--sp-3); color: var(--band-muted); }

.card__list { display: grid; gap: var(--sp-3); margin-top: var(--sp-5); }
.card__list li { position: relative; padding-left: var(--sp-5); color: var(--band-muted); }
.card__list li::before {
  content: ""; position: absolute; left: 0; top: 0.62em;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--band-bullet);
}

/* La imagen va absoluta: como hija en flujo su alto natural actúa de
   min-height del flex item y el aspect-ratio deja de mandar. */
.card__shot {
  position: relative; margin-bottom: var(--sp-5);
  border-radius: var(--r-sm); overflow: hidden;
  background: var(--ink-surface); aspect-ratio: 16 / 10;
}
.card__shot img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

/* --------------------------- 14. CURSOS --------------------------- */
.courses { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--grid-gap); }

.course {
  display: flex; flex-direction: column;
  padding: var(--card-pad);
  background: var(--deep-card);
  border: 1px solid var(--deep-line);
  border-radius: var(--r-md);
  color: var(--deep-ink);
  transition: translate var(--dur) var(--ease), border-color var(--dur) var(--ease),
              background var(--dur-theme) var(--ease);
}
.course:hover { translate: 0 -4px; border-color: var(--orange); }

.course__level {
  align-self: flex-start; margin-bottom: var(--sp-4);
  padding: 3px var(--sp-3); border-radius: var(--r-pill);
  font-size: var(--fs-micro); font-weight: 700;
  letter-spacing: var(--ls-wide); text-transform: uppercase;
}
.course__level[data-level="Básico"]     { background: var(--orange-tint); color: var(--orange-text); }
.course__level[data-level="Intermedio"] { background: var(--celeste-tint); color: var(--icon-fg); }
.course__level[data-level="Avanzado"]   { background: var(--chip-on-deep-bg); color: var(--chip-on-deep-ink); }

.course__title { font-size: var(--fs-h4); font-weight: 700; line-height: var(--lh-heading); }
.course__text { margin-top: var(--sp-3); color: var(--deep-muted); }
.course__facts {
  display: grid; gap: var(--sp-2);
  margin-top: var(--sp-5); padding-top: var(--sp-4);
  border-top: 1px solid var(--deep-line);
  font-size: var(--fs-small); color: var(--deep-muted);
}
.course__facts div { display: flex; justify-content: space-between; gap: var(--sp-4); }
.course__facts b { color: var(--deep-ink); font-weight: 600; }
/* margin-top:auto va en el contenedor, que es el hijo flex directo */
.course__action { margin-top: auto; padding-top: var(--sp-6); }

/* Panel de acento: tinta en los dos temas para que destaque contra la
   sección, sea esta clara u oscura. */
.course-cta {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--sp-6);
  margin-top: var(--sp-12); padding: var(--sp-10);
  background: linear-gradient(120deg, var(--blue-800) 0%, var(--ink-surface-2) 100%);
  border: 1px solid var(--ink-line); border-radius: var(--r-lg);
  color: var(--on-ink);
}
.course-cta__text { margin-top: var(--sp-2); color: var(--on-ink-muted); }
.course-cta .h3 { color: var(--on-ink); }

/* ------------------ PLANES DE SOPORTE TI ------------------ */
/* Tres niveles de cobertura. El del medio se levanta y lleva filo
   naranja: es el que se quiere que se mire primero, y con tres columnas
   iguales la vista se va siempre a la primera. */
.planes {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: var(--grid-gap);
  align-items: start;
}
.plan {
  position: relative;
  display: flex; flex-direction: column;
  padding: var(--card-pad);
  background: var(--deep-card);
  border: 1px solid var(--deep-line);
  border-radius: var(--r-lg);
  transition: translate var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.plan:hover { translate: 0 -4px; border-color: var(--celeste); }

.plan--destacado {
  border-color: var(--orange);
  box-shadow: var(--shadow-pop);
}
/* El sello monta sobre el borde superior, así que la tarjeta necesita
   sitio extra arriba para no comerse el nombre del plan. */
.plan--destacado { padding-top: calc(var(--card-pad) + var(--sp-4)); }
.plan__sello {
  position: absolute; top: 0; left: 50%;
  transform: translate(-50%, -50%);
  padding: 6px var(--sp-5);
  background: var(--orange);
  border-radius: var(--r-pill);
  font-size: var(--fs-micro); font-weight: 700;
  letter-spacing: var(--ls-wide); text-transform: uppercase;
  /* Naranja de marca con texto oscuro: el blanco encima no llega al
     4.5:1. Es el mismo par que usa .btn--accent. */
  color: #0F1B33;
  white-space: nowrap;
}

.plan__nombre {
  font-size: var(--fs-h3); font-weight: 700; line-height: var(--lh-heading);
  color: var(--deep-ink);
}
.plan__para { margin-top: var(--sp-2); font-size: var(--fs-small); color: var(--deep-muted); }

.plan__sla {
  display: flex; align-items: baseline; gap: var(--sp-3);
  margin: var(--sp-6) 0;
  padding: var(--sp-4) var(--sp-5);
  background: var(--deep-hair);
  border: 1px solid var(--deep-line);
  border-radius: var(--r-sm);
}
.plan__sla span {
  font-size: var(--fs-micro); font-weight: 600;
  letter-spacing: var(--ls-wide); text-transform: uppercase;
  color: var(--deep-muted);
}
.plan__sla b { margin-left: auto; font-size: var(--fs-body); font-weight: 700; color: var(--eyebrow-on-deep); }

.plan__lista { display: grid; gap: var(--sp-4); margin-bottom: var(--sp-8); }
.plan__lista li {
  position: relative;
  /* La escala salta del 6 al 8: no hay --sp-7, y usarlo dejaba el
     padding en cero con el palomeo encima de la primera letra. */
  padding-left: var(--sp-8);
  font-size: var(--fs-small); line-height: 1.6;
  color: var(--deep-muted);
}
/* El palomeo va en ::before y no como <svg> por elemento: son 17 ítems
   y no aportan nada al árbol de accesibilidad. */
.plan__lista li::before {
  content: "";
  position: absolute; left: 0; top: 0.45em;
  width: 11px; height: 6px;
  border-left: 2px solid var(--celeste);
  border-bottom: 2px solid var(--celeste);
  transform: rotate(-45deg);
}
.plan--destacado .plan__lista li::before { border-color: var(--orange); }

.plan .btn { margin-top: auto; justify-content: center; }

.planes__nota {
  margin-top: var(--sp-10);
  text-align: center;
  font-size: var(--fs-small); color: var(--deep-muted);
}
.planes__nota a { color: var(--eyebrow-on-deep); font-weight: 600; text-decoration: underline; }


/* ---------- CINTA DE CLIENTES EN LA SECCIÓN DE CIFRAS ----------
   Corre sola por detrás de las cifras. Los logos van aplanados a
   silueta con --hero-logo-filter (negra sobre claro, blanca sobre
   oscuro): `grayscale` no sirve porque un logo azul marino sobre el
   fondo oscuro de esta sección desaparece. */
.stats { position: relative; overflow: hidden; }

/* Panel claro en los dos temas, igual que el muro de #clientes: varios
   SVG son fondo macizo con texto blanco encima y cualquier filtro por
   tema (silueta, invertido) los convierte en manchas sólidas. */
.stats__marquee {
  position: relative;
  z-index: 1;
  overflow: hidden;
  padding-block: var(--sp-2);
  pointer-events: none;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.stats__row {
  display: flex;
  align-items: center;
  gap: clamp(40px, 5vw, 84px);
  width: max-content;
  animation: statsRun var(--row-dur, 60s) linear infinite;
  will-change: transform;
}
.stats__row--rev { animation-direction: reverse; }
.stats__marquee.is-paused .stats__row { animation-play-state: paused; }

@keyframes statsRun {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

.stats__logo {
  display: block;
  height: clamp(28px, min(3.4vw, 5vh), 52px);
  width: auto; max-width: 190px;
  object-fit: contain;
  /* Silueta monocroma, no desaturado: estos SVG traen azules marinos y
     grises oscuros que sobre el fondo oscuro desaparecerían. Aplanados
     a un solo tono se leen igual de bien en los dos temas. */
  filter: var(--logo-mono);
  opacity: 0.85;
  transition: opacity var(--dur) var(--ease);
}
.stats__logo:hover { opacity: 1; }

/* Las cifras, por encima de la cinta */
.stats > .wrap { position: relative; z-index: 1; }

@media (prefers-reduced-motion: reduce) {
  .stats__row { animation: none !important; }
}

/* ------------------- MURO DE CLIENTES -------------------- */
/* Dos rejillas idénticas superpuestas. La de abajo lleva los logos
   apagados; la de arriba, los mismos encendidos y con su sector, y va
   recortada por una máscara radial anclada al cursor (--mx/--my, que
   escribe el JS). Al mover el ratón, la luz "revela" la capa de arriba.

   Los SVG traen colores incrustados (azul marino, rojo, gris). Sobre
   el fondo oscuro del modo noche un logo azul marino desaparece: por
   eso --logo-mono depende del tema y no es un valor fijo. */
.muro {
  position: relative;
  border: 1px solid var(--card-line);
  border-radius: var(--r-lg);
  overflow: hidden;
  /* Se ve por los huecos de 1px de la rejilla y hace de filete. */
  background: var(--card-line);
}

.muro__rejilla {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  /* Filas iguales: la capa de luz debe calzar celda a celda con la de
     abajo, y con filas de alto automático bastaría un logo más alto
     para descuadrarlas. */
  grid-auto-rows: 1fr;
  gap: 1px;
}

.muro__cel {
  display: grid; place-items: center; align-content: center;
  gap: var(--sp-3);
  min-height: 150px;
  padding: var(--sp-6) var(--sp-4);
  background: var(--card);
  transition: background var(--dur) var(--ease);
}

/* Se normalizan por ALTURA: es lo que hace que un conjunto de marcas de
   proporciones dispares se lea como una rejilla ordenada. */
.muro__logo {
  height: 42px;
  width: auto;
  max-width: 82%;
  object-fit: contain;
  filter: var(--logo-mono);
  opacity: 0.28;
  transition: opacity var(--dur) var(--ease), filter var(--dur) var(--ease);
}
.muro__respaldo { font-size: var(--fs-small); font-weight: 700; color: var(--band-muted); text-align: center; }

.muro__sector {
  font-size: var(--fs-micro); font-weight: 600;
  letter-spacing: var(--ls-wide); text-transform: uppercase;
  color: var(--band-accent);
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
}

/* ESTADO ENCENDIDO — panel claro y logo a su color real.
   No es un capricho estético: varios de estos SVG son un bloque macizo
   con el texto en blanco encima (Chemmer, Minsa, Imexa, Municipalidad).
   Con --logo-mono se convierten en rectángulos sólidos que se tragan su
   propio texto, así que apagados sirven como silueta pero encendidos
   tienen que ir a color, y a color necesitan fondo claro en los dos
   temas o los azul marino desaparecen. Es la misma razón por la que los
   sellos ISO van sobre --logo-panel. */
.muro__encendida .muro__cel,
.muro__cel:hover, .muro__cel:focus-within { background: var(--logo-panel); }
.muro__encendida .muro__logo,
.muro__cel:hover .muro__logo, .muro__cel:focus-within .muro__logo { opacity: 1; filter: none; }
/* El panel es claro en los dos temas: el celeste de texto sobre claro
   (6.17:1) es el único que se sostiene ahí. */
.muro__encendida .muro__sector,
.muro__cel:hover .muro__sector, .muro__cel:focus-within .muro__sector { opacity: 1; color: var(--celeste-ink); }

/* --- La linterna --- */
.muro__luz {
  position: absolute; inset: 0;
  pointer-events: none;
  -webkit-mask-image: radial-gradient(circle 210px at var(--mx, -9999px) var(--my, -9999px),
                      #000 0%, rgba(0, 0, 0, 0.55) 46%, transparent 72%);
          mask-image: radial-gradient(circle 210px at var(--mx, -9999px) var(--my, -9999px),
                      #000 0%, rgba(0, 0, 0, 0.55) 46%, transparent 72%);
}
.muro__luz .muro__rejilla { height: 100%; }

/* Sin linterna —táctil, teclado, movimiento reducido— el muro se queda
   encendido entero: el efecto suma, no sostiene la sección. */
.muro:not(.muro--luz) .muro__cel { background: var(--logo-panel); }
.muro:not(.muro--luz) .muro__logo { opacity: 1; filter: none; }
.muro:not(.muro--luz) .muro__sector { opacity: 1; color: var(--celeste-ink); }

.muro__pista {
  margin-top: var(--sp-5);
  text-align: center;
  font-size: var(--fs-small); color: var(--band-muted);
}
.muro:not(.muro--luz) ~ .muro__pista { display: none; }

@media (max-width: 1080px) { .muro__rejilla { grid-template-columns: repeat(4, 1fr); } }
@media (max-width: 760px)  { .muro__rejilla { grid-template-columns: repeat(3, 1fr); } .muro__cel { min-height: 124px; } }
@media (max-width: 460px)  { .muro__rejilla { grid-template-columns: repeat(2, 1fr); } }


/* --------------------------- 17. BANNER --------------------------- */
.banner__grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-16); align-items: center; }
/* -------------------------- 18. CONTACTO -------------------------- */
.contact { display: grid; grid-template-columns: 1.4fr 1fr; gap: var(--sp-12); }

.form {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-5);
  padding: var(--card-pad);
  background: var(--card); border: 1px solid var(--card-line);
  border-radius: var(--r-md);
  transition: background var(--dur-theme) var(--ease);
}
.field { display: grid; gap: var(--sp-2); }
.field--full { grid-column: 1 / -1; }
.field label { font-size: var(--fs-small); font-weight: 600; }
.field input, .field select, .field textarea {
  min-height: 46px; padding: var(--sp-3) var(--sp-4);
  background: var(--field); border: 1px solid var(--card-line);
  border-radius: var(--r-sm);
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.field textarea { min-height: 120px; resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus {
  background: var(--card); border-color: var(--band-accent); outline: none;
}
.field input[aria-invalid="true"], .field textarea[aria-invalid="true"] { border-color: var(--error); }
.field__error { font-size: var(--fs-micro); color: var(--error); }
.form__note { margin-top: var(--sp-3); font-size: var(--fs-small); color: var(--band-muted); }
.form__note.is-ok { color: var(--ok); }
/* El aviso de fallo usa el mismo rojo claro que los errores de campo:
   sobre fondo oscuro el rojo saturado de siempre no llega al 4.5:1. */
.form__note.is-error { color: var(--error); }

/* Rojo y verde en las versiones claras: sobre fondo oscuro, los tonos
   saturados de siempre (#C0271B, #12693A) no llegan al 4.5:1. */
:root { --error: #FF8A80; --ok: #6EE7A8; }

/* Igual que .course-cta: panel de acento tinta en los dos temas. */
.contact__aside {
  padding: var(--card-pad);
  background: var(--ink-surface); color: var(--on-ink);
  border: 1px solid var(--ink-line);
  border-radius: var(--r-md);
  border-top: 4px solid var(--orange);
  align-self: start;
}
.contact__aside .h3 { color: var(--on-ink); }
.contact__list { display: grid; gap: var(--sp-5); margin-top: var(--sp-6); }
.contact__list li { display: grid; gap: var(--sp-1); }
.contact__list span:first-child {
  font-size: var(--fs-micro); font-weight: 700;
  letter-spacing: var(--ls-wide); text-transform: uppercase;
  color: var(--orange);
}
.contact__list a:hover { text-decoration: underline; }

/* ----------------------------- 19. CTA ----------------------------- */
.cta {
  position: relative; padding-block: var(--section-y);
  background: linear-gradient(120deg, var(--blue-800) 0%, var(--blue-900) 50%, var(--ink-surface) 100%);
  color: var(--on-ink); overflow: hidden;
}
.cta__glow {
  position: absolute; left: -80px; top: -120px;
  width: 420px; height: 420px; border-radius: 50%;
  background: rgba(246, 163, 49, 0.16); filter: blur(80px); pointer-events: none;
}
.cta__inner { position: relative; z-index: 1; display: grid; justify-items: center; gap: var(--sp-8); text-align: center; }
.cta .h2 { max-width: 20ch; }

/* --------------------------- 20. FOOTER --------------------------- */
.footer { padding-block: var(--sp-16); background: var(--ink-surface); color: var(--on-ink-muted); }
.footer__grid { display: grid; grid-template-columns: 1.4fr 1fr 1fr 1fr; gap: var(--sp-12); }
.footer__logo { width: 210px; height: auto; }
.footer__text { margin-top: var(--sp-4); font-size: var(--fs-small); max-width: 34ch; }
.footer__head {
  margin-bottom: var(--sp-4);
  font-size: var(--fs-micro); font-weight: 700;
  letter-spacing: var(--ls-wide); text-transform: uppercase;
  color: var(--orange);
}
.footer__list { display: grid; gap: var(--sp-3); font-size: var(--fs-small); }
.footer__list a { transition: color var(--dur) var(--ease); }
.footer__list a:hover { color: var(--on-ink); }

/* Estos iconos vivían en la barra superior y al retirarla se quedaron
   sin ninguna regla: un SVG sin ancho declarado se pinta a 240px, así
   que salían tres manchas enormes al pie de la página. */
.footer__social {
  display: flex; gap: var(--sp-3);
  margin-top: var(--sp-6);
}
.footer__social a {
  display: grid; place-items: center;
  width: 38px; height: 38px;
  border: 1px solid var(--ink-line);
  border-radius: 50%;
  color: var(--on-ink-muted);
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease),
              background var(--dur) var(--ease);
}
.footer__social a:hover { color: var(--on-ink); border-color: var(--orange); background: var(--ink-hair); }
.footer__social svg {
  width: 19px; height: 19px;
  fill: none; stroke: currentColor; stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
}

.footer__bottom {
  margin-top: var(--sp-12); padding-top: var(--sp-6);
  border-top: 1px solid var(--ink-hair);
  font-size: var(--fs-micro);
}

/* -------------------------- 21. WHATSAPP -------------------------- */
/* Verde de WhatsApp a propósito: es la marca del tercero y es lo que
   la gente reconoce. El texto va oscuro encima (12.2:1). */
.wa {
  position: fixed;
  right: clamp(16px, 3vw, 28px); bottom: clamp(16px, 3vw, 28px);
  z-index: 200;
  display: grid; place-items: center;
  width: 58px; height: 58px;
  padding: 0;
  background: var(--wa); color: #050B18;
  border-radius: 50%;
  box-shadow: 0 10px 30px rgba(5, 11, 24, 0.35);
  transition: background var(--dur) var(--ease), translate var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease);
}
.wa:hover { background: var(--wa-dark); translate: 0 -3px; box-shadow: 0 14px 36px rgba(5, 11, 24, 0.45); }
.wa__icon { display: grid; place-items: center; width: 32px; height: 32px; }
.wa__icon svg { width: 32px; height: 32px; fill: currentColor; stroke: none; }

/* Un solo pulso al aparecer, no en bucle */
.wa.is-in { animation: waPop 520ms var(--ease) both; }
@keyframes waPop {
  from { opacity: 0; transform: scale(0.85) translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* ------------------------- 24. RESPONSIVE ------------------------- */
@media (max-width: 1080px) {
  .cards, .courses { grid-template-columns: repeat(2, 1fr); }
  .demos__grid { grid-template-columns: repeat(2, 1fr); }
  .footer__grid { grid-template-columns: 1fr 1fr; }
  .hero__grid, .banner__grid { gap: var(--sp-10); }
}

@media (max-width: 900px) {
  :root { --card-pad: var(--sp-6); --header-h: 80px; }

  .brand img { height: 40px; }

  /* --chrome-h lo fija el JS con el borde inferior real del header al
     abrir. Un elemento position:fixed se mide contra el viewport
     INCLUYENDO la barra de scroll, de ahí también --vw. */
  .nav-toggle { display: block; order: 4; margin-left: 0; }
  .header__cta { display: none; }
  .header__actions { margin-left: auto; order: 3; }
  .nav {
    position: fixed;
    inset: var(--chrome-h, var(--header-h)) auto 0 0;
    width: var(--vw, 100%);
    margin-left: 0; padding: var(--sp-8) var(--gutter);
    background: var(--deep);
    opacity: 0; visibility: hidden;
    transition: opacity var(--dur) var(--ease), visibility var(--dur);
    overflow-y: auto;
  }
  .nav.is-open { opacity: 1; visibility: visible; }
  .nav__list { flex-direction: column; align-items: stretch; gap: 0; }
  .nav__list li {
    opacity: 0; transform: translateY(12px);
    transition: opacity 420ms var(--ease), transform 420ms var(--ease);
  }
  /* El escalonado se deriva de nth-child en vez de un `--i` puesto con
     `style=` en el HTML, que la CSP bloquea. */
  .nav.is-open li { opacity: 1; transform: none; transition-delay: 60ms; }
  .nav.is-open li:nth-child(2) { transition-delay: 105ms; }
  .nav.is-open li:nth-child(3) { transition-delay: 150ms; }
  .nav.is-open li:nth-child(4) { transition-delay: 195ms; }
  .nav.is-open li:nth-child(5) { transition-delay: 240ms; }
  .nav.is-open li:nth-child(6) { transition-delay: 285ms; }
  .nav.is-open li:nth-child(7) { transition-delay: 330ms; }
  .nav__list a {
    padding: var(--sp-4) 0;
    border-bottom: 1px solid var(--deep-hair);
    font-size: var(--fs-lead);
  }
  .nav__list a::after { display: none; }
  .nav__list a.is-current { color: var(--orange); }

  /* En móvil el submenú no puede flotar: el panel del nav ya ocupa la
     pantalla y un desplegable encima quedaría fuera de sitio. Aquí se
     comporta como un acordeón dentro de la lista. */
  .nav__drop-btn {
    justify-content: space-between;
    width: 100%;
    padding: var(--sp-4) 0;
    border-bottom: 1px solid var(--deep-hair);
    font-size: var(--fs-lead);
  }
  .nav__drop-btn::after { display: none; }
  .nav__drop-btn.is-current { color: var(--orange); }
  .nav__drop-btn .nav__caret { width: 18px; height: 18px; }

  .nav__submenu {
    position: static;
    min-width: 0;
    padding: 0 0 0 var(--sp-4);
    background: none;
    border: 0;
    box-shadow: none;
    /* De alto 0 a auto no se puede animar. Un tope holgado sí, y evita
       medir el panel con JS. Los tres enlaces suman ~190px.
       `visibility: hidden` es lo que además los saca del tabulador:
       solo con overflow seguirían siendo enfocables, invisibles. */
    max-height: 0;
    overflow: hidden;
    transform: none;
    transition: max-height var(--dur) var(--ease), opacity var(--dur) var(--ease), visibility var(--dur);
  }
  .nav__drop-btn[aria-expanded="true"] + .nav__submenu { max-height: 340px; }
  .nav__submenu::before { display: none; }
  .nav__submenu a {
    padding: var(--sp-3) 0;
    border-bottom: 1px solid var(--deep-hair);
    border-radius: 0;
    color: color-mix(in srgb, var(--deep-ink) 78%, transparent);
  }
  .nav__submenu a:hover, .nav__submenu a:focus-visible, .nav__submenu a.is-current { background: none; }
  .nav__submenu a.is-current { color: var(--orange); }
  .nav__submenu b { font-size: var(--fs-body); }
  .nav__submenu span { color: color-mix(in srgb, var(--deep-ink) 55%, transparent); }

  .hero__grid, .banner__grid, .contact { grid-template-columns: 1fr; }
  .hero__visual { order: -1; }
  /* Apilado, el mockup es lo primero que se cede: es ilustración, y sin
     recortarlo la cinta de logos se sale de la primera pantalla. */
  /* `max-height` en el contenedor no alcanza a los hijos de la
     rejilla: el visual se salia por abajo y se montaba sobre el
     antetitulo de la diapositiva. Hay que recortarlo aqui y limitar
     ademas la altura de cada vista. */
  .hero__visual { max-height: 26vh; overflow: hidden; border-radius: var(--r-lg); }
  .hero-vista { height: 26vh; }
  .hero-vista--ia,
  .hero-vista--vision,
  .hero-vista--movil,
  .hero-vista--infra { aspect-ratio: auto; }
  .hero-vista--software .mockup { max-height: 26vh; overflow: hidden; }
  .hero__grid { gap: clamp(16px, 2.6vh, 28px); }
  .hero { padding-block: clamp(14px, 2vh, 28px); }
  .cards--2 { grid-template-columns: 1fr; }
  .contact__aside { order: -1; }

}

@media (max-width: 640px) {
  :root {
    --fs-display: 2rem;      /* 32 */
    --fs-h1: 1.75rem;        /* 28 */
    --fs-h2: 1.5rem;         /* 24 */
    --fs-h3: 1.25rem;        /* 20 */
    --fs-h4: 1rem;           /* 16 */
    --fs-lead: 1rem;         /* 16 */
    --fs-body: 0.875rem;     /* 14 */
    --fs-small: 0.8125rem;   /* 13 */
    --fs-micro: 0.8125rem;   /* 13 — no bajamos de aquí */
    --grid-gap: var(--sp-5);
  }

  .cards, .courses, .demos__grid,
  .footer__grid, .form { grid-template-columns: 1fr; }
  .field--full { grid-column: auto; }
  .sec-head { margin-bottom: var(--sp-8); }
  .course-cta { padding: var(--sp-6); }
  .footer__logo { width: 180px; }
}

/* -------------------- 25. PREFERS-REDUCED-MOTION -------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    transition-delay: 0ms !important;
  }

  [data-reveal], .proy-card { opacity: 1 !important; transform: none !important; }
  .btn:hover, .card:hover, .proy-card:hover, .course:hover, .wa:hover { translate: none; }
  .stats__row { animation: none !important; }

  /* El fondo del loader se queda quieto, pero el loader sigue
     retirándose: lo quita el JS, y la animación de seguridad conserva
     su retardo de 3.2s como último recurso. */
  .loader__grid, .loader__scan, .loader__nodes, .loader__bar span,
  .loader__logo, .loader__dots::after { animation: none !important; }
}


/* =============================================================
   26. SECCIÓN SERVICIOS — encabezado partido, sello ISO,
       tarjetas con borde superior degradado y carrusel en móvil
   ============================================================= */

/* Encabezado a dos columnas: el texto a la izquierda y el sello a la
   derecha. En móvil se apila y el sello se centra. */
.sec-head--split {
  max-width: none;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--sp-10);
  align-items: start;
}
.sec-head__main { max-width: 62ch; }
.sec-head__cta { margin-top: var(--sp-6); }

/* El acento del titular usa el color de la banda, no un cian fijo:
   sobre banda clara sería ilegible (#38BDF8 da 1.97:1 sobre #EAF2FB). */
.h2 .accent { color: var(--band-accent); }
.section--deep .h2 .accent, .demos .h2 .accent { color: var(--celeste); }
.lead strong { color: var(--band-ink); font-weight: 600; }
.section--deep .lead strong, .demos .lead strong { color: var(--deep-ink); }

/* Panel claro FIJO en los dos temas: así los sellos conservan su azul
   oficial (#004C97), que es lo que los hace reconocibles. Pasados a
   silueta blanca perdían justo eso. */
.iso {
  display: grid; justify-items: center; gap: var(--sp-4);
  text-align: center;
  max-width: 280px;
  margin: 0;
  padding: var(--sp-6) var(--sp-6) var(--sp-5);
  background: var(--logo-panel);
  border: 1px solid rgba(0, 76, 151, 0.22);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-card);
  /* El panel es claro en los dos temas, así que el color de texto se
     fija aquí: heredado, en modo noche sería claro sobre claro. */
  color: #0F1B33;
}
/* A tamaño de sello, no de icono: son la prueba de la certificación,
   no un adorno del encabezado. */
.iso__seals { display: flex; align-items: center; gap: var(--sp-6); flex: none; }
.iso__seals img {
  height: 86px; width: auto;
  filter: none;
  opacity: 1;
  transition: transform var(--dur) var(--ease);
}
.iso:hover .iso__seals img { transform: translateY(-2px); }
.iso__text { font-size: var(--fs-small); line-height: 1.5; color: #5B6B80; }
.iso__text strong { color: #0F1B33; font-weight: 700; }

/* --------- Carrusel de servicios (3 columnas) --------- */
.svc-car { display: flex; align-items: stretch; gap: var(--sp-4); }
.svc-car__viewport { flex: 1; overflow: hidden; padding-block: 2px; }
.svc {
  display: flex;
  gap: var(--grid-gap);
  transition: transform 900ms var(--ease-carrusel);
  will-change: transform;
}
/* El ancho de cada tarjeta lo fija el JS a partir del viewport, para
   que entren exactamente tres columnas con sus huecos. */
.svc-card { flex: 0 0 auto; }

.svc-car__nav {
  flex: none; align-self: center;
  display: grid; place-items: center;
  width: 44px; height: 44px;
  border-radius: 50%;
  background: var(--card);
  border: 1px solid var(--card-line);
  color: var(--band-ink);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
              color var(--dur) var(--ease);
}
.svc-car__nav:hover { background: var(--celeste-solid); border-color: var(--celeste-solid); color: #FFFFFF; }
.svc-car__nav svg { width: 20px; height: 20px; }

.svc-car__foot {
  display: flex; align-items: center; justify-content: center;
  gap: var(--sp-5);
  margin-top: var(--sp-8);
}

/* Borde superior degradado que se enciende en hover. Va en ::before y
   no en border-image para poder animar solo la opacidad. */
.svc-card { position: relative; overflow: hidden; }
.svc-card::before {
  content: "";
  position: absolute; left: 0; right: 0; top: 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--celeste), transparent);
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
}
.svc-card:hover::before, .svc-card:focus-within::before { opacity: 1; }

/* margin-top:auto empuja el enlace al pie: las tarjetas de una fila
   terminan alineadas aunque el texto tenga distinto largo. */
.card__more {
  margin-top: auto; padding-top: var(--sp-5);
  align-self: flex-start;
  font-size: var(--fs-small); font-weight: 600;
  color: var(--band-accent);
}
.card__more span { display: inline-block; transition: transform var(--dur) var(--ease); }
.card__more:hover span { transform: translateX(4px); }

/* Puntos indicadores: solo se ven cuando el contenedor es carrusel */
.dots { display: flex; justify-content: center; gap: var(--sp-2); }
.dots button {
  width: 8px; height: 8px; padding: 0;
  border-radius: var(--r-pill);
  background: var(--band-line);
  transition: width var(--dur) var(--ease), background var(--dur) var(--ease);
}
.dots button[aria-selected="true"] { width: 26px; background: var(--band-accent); }

/* =============================================================
   27. SECCIÓN CASOS DE ÉXITO — laureles y carrusel de proyectos
   ============================================================= */
.h2--laurel { display: flex; align-items: center; justify-content: center; gap: var(--sp-4); }
.laurel { flex: none; width: 26px; height: 40px; color: var(--orange); opacity: 0.85; }
.laurel svg { width: 100%; height: 100%; stroke-width: 1.4; }
.laurel--right { transform: scaleX(-1); }

/* CARRUSEL DE PROYECTOS
   El mecanismo es distinto al de los otros tres carruseles a propósito:
   aquí no hay track movido con transform, sino un contenedor con
   overflow-x y scroll-snap. Consecuencias buenas: arrastre y swipe
   nativos, momentum en móvil, y sin JS queda una tira desplazable en
   lugar de un bloque muerto. El JS solo pone flechas, contador y barra.

   Los efectos también son otros para que se note el cambio de sección:
   zoom lento de la foto, barrido de luz en diagonal, borde degradado
   naranja→celeste y el número que se enciende. Las tarjetas de
   servicios llevan filo superior; las de testimonios, escala; estas,
   fotografía. */
.proy { display: flex; align-items: stretch; gap: var(--sp-4); }

.proy__viewport {
  flex: 1; min-width: 0;
  overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x mandatory;
  /* `auto` y no `smooth`: el suave del navegador dura lo que él decide
     (~300ms en Chrome) y no se puede alargar. El recorrido lo anima el
     JS con su propia duración; si aquí pusiera `smooth`, cada escritura
     de scrollLeft del rAF se volvería a animar y saldría a tirones. */
  scroll-behavior: auto;
  /* Sitio para que la tarjeta se levante en hover sin que la recorte
     el propio contenedor de scroll. */
  padding: 6px 2px 14px;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.proy__viewport::-webkit-scrollbar { display: none; }

.proy__track { display: flex; gap: var(--grid-gap); }

/* UNA panorámica a la vez, con el texto SUPERPUESTO sobre la foto.
   La sección de demos, que va justo después, ya es una tarjeta a todo
   el ancho partida en dos columnas (media | texto), y en móvil se
   apila. Repetir aquí cualquiera de esas dos anatomías hacía que dos
   secciones seguidas se leyeran como la misma pieza.
   Aquí la foto ES la tarjeta: ocupa el marco entero y el contenido
   flota encima, abajo a la izquierda. */
.proy-card {
  position: relative;
  flex: 0 0 100%;
  scroll-snap-align: start;
  display: flex; align-items: flex-end;
  min-height: clamp(430px, 43vw, 560px);
  background: var(--ink-surface);
  border-radius: var(--r-lg);
  overflow: hidden;
  /* `translate` (hover) y `transform` (entrada) son propiedades
     distintas y se componen: por eso cada una lleva su duración sin
     pisarse. */
  opacity: 0;
  transform: translateY(18px);
  transition: translate var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease),
              border-color var(--dur) var(--ease),
              opacity 800ms var(--ease-out-soft),
              transform 800ms var(--ease-out-soft);
}
.proy-card:hover, .proy-card:focus-within {
  translate: 0 -6px;
  /* Token del tema: en modo día una sombra negra al 75% sería una
     mancha sucia bajo la tarjeta. */
  box-shadow: var(--shadow-pop);
}

/* Borde degradado. Se dibuja con dos máscaras superpuestas y
   composición xor: pinta solo el anillo de 1px y deja el interior
   hueco, que es lo que un border-image no permite animar. */
.proy-card::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(135deg, var(--orange), var(--celeste));
  -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;
  opacity: 0; pointer-events: none;
  transition: opacity var(--dur) var(--ease);
}
.proy-card:hover::after, .proy-card:focus-within::after { opacity: 1; }

/* --- La foto: es el marco entero, no una columna --- */
.proy-card__foto {
  position: absolute; inset: 0;
  overflow: hidden;
  background: var(--ink-surface);
}
/* Absoluta también dentro: como hija en flujo, su alto natural manda, y
   con una foto vertical (800×1000) la tarjeta se estiraba a 727px. */
.proy-card__foto img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  /* Arranca ligeramente desaturada y se enciende al pasar por encima:
     así la tarjeta activa se distingue de las vecinas. */
  filter: saturate(0.75) contrast(1.02);
  transform: scale(1.01);
  transition: transform var(--dur-slow) var(--ease-out-soft),
              filter var(--dur-slow) var(--ease);
}
.proy-card:hover .proy-card__foto img,
.proy-card:focus-within .proy-card__foto img {
  transform: scale(1.08);
  filter: saturate(1.1) contrast(1.04);
}

/* Tres velos, y ninguno es decorativo: todo el texto de la tarjeta va
   encima de una fotografía que no controlamos.
   · de izquierda a derecha, para sostener el panel de texto;
   · de abajo a arriba, porque el panel se ancla al pie;
   · uno suave arriba, para que el número no se evapore sobre un cielo
     blanco (la foto de las cámaras lo tiene justo ahí). */
.proy-card__foto::after {
  content: "";
  position: absolute; inset: 0;
  background:
    linear-gradient(to right,
      rgba(3, 7, 16, 0.94) 0%,
      rgba(3, 7, 16, 0.80) 34%,
      rgba(3, 7, 16, 0.28) 62%,
      rgba(3, 7, 16, 0.42) 100%),
    linear-gradient(to top,
      rgba(3, 7, 16, 0.70) 0%,
      rgba(3, 7, 16, 0) 55%),
    linear-gradient(to bottom,
      rgba(3, 7, 16, 0.45) 0%,
      rgba(3, 7, 16, 0) 38%);
  pointer-events: none;
}

/* Barrido de luz en diagonal. Cruza la foto una vez por hover. */
.proy-card__brillo {
  position: absolute; top: -60%; bottom: -60%; left: -75%;
  width: 55%;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, 0.28), transparent);
  transform: skewX(-18deg);
  pointer-events: none;
  z-index: 2;
}
.proy-card:hover .proy-card__brillo,
.proy-card:focus-within .proy-card__brillo { animation: proyBrillo 900ms var(--ease) forwards; }
@keyframes proyBrillo { to { left: 130%; } }

/* --- El panel de texto, flotando sobre la foto --- */
/* El color va fijo y claro, no por token de tema: debajo hay una
   fotografía con su velo oscuro en los dos modos, así que heredar
   --deep-ink dejaría texto casi negro sobre negro en modo día. */
.proy-card__cuerpo {
  position: relative; z-index: 2;
  display: flex; flex-direction: column;
  width: min(56%, 640px);
  padding: clamp(28px, 3.4vw, 56px);
}
.proy-card__cliente {
  margin-bottom: var(--sp-3);
  font-size: var(--fs-micro); font-weight: 700;
  letter-spacing: var(--ls-wide); text-transform: uppercase;
  color: var(--orange-300);
}
.proy-card__titulo {
  font-size: clamp(1.75rem, 3.2vw, var(--fs-h1));
  font-weight: 700; line-height: var(--lh-tight); letter-spacing: var(--ls-tight);
  color: #FFFFFF;
}
.proy-card__texto {
  margin-top: var(--sp-4); max-width: 46ch;
  font-size: var(--fs-lead);
  color: rgba(255, 255, 255, 0.82);
}

.chips--proy { margin-top: var(--sp-6); }
.chips--proy li {
  padding: 6px var(--sp-4);
  background: rgba(255, 255, 255, 0.10);
  border-color: rgba(255, 255, 255, 0.28);
  color: #FFFFFF;
  font-size: var(--fs-micro);
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.proy-card:hover .chips--proy li { border-color: var(--celeste); background: rgba(56, 189, 248, 0.18); }

.proy-card__mas {
  margin-top: var(--sp-8);
  align-self: flex-start;
  font-size: var(--fs-body); font-weight: 700;
  color: var(--orange);
}
.proy-card__mas span { display: inline-block; transition: transform var(--dur) var(--ease); }
.proy-card__mas:hover span, .proy-card:hover .proy-card__mas span { transform: translateX(4px); }

/* --- Flechas y pie --- */
.proy__nav {
  flex: none; align-self: center;
  display: grid; place-items: center;
  width: 44px; height: 44px;
  border-radius: 50%;
  background: var(--deep-card);
  border: 1px solid var(--deep-line);
  color: var(--deep-ink);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
              color var(--dur) var(--ease), opacity var(--dur) var(--ease);
}
.proy__nav:hover { background: var(--celeste-solid); border-color: var(--celeste-solid); color: #FFFFFF; }
.proy__nav svg { width: 20px; height: 20px; }
/* En los extremos la flecha se apaga en vez de desaparecer: si se
   ocultara, el carrusel daría un salto de 44px al llegar al final. */
.proy__nav[disabled] { opacity: 0.3; pointer-events: none; }


/* =============================================================
   27.5 SOLUCIONES — escaparate de los sistemas propios
   ============================================================= */
/* Estructura: ilustración central con fichas flotando y, debajo, una
   rejilla 2×2 más una pieza centrada. Cada tarjeta lleva icono y
   título a la izquierda y una captura ladeada que se sale del marco
   por la derecha — ese recorte es lo que da sensación de que hay más
   producto del que cabe. */
.soluciones { position: relative; overflow: hidden; }

/* Resplandor azul→verde detrás de la ilustración */
.soluciones__glow {
  position: absolute; left: 50%; top: 26%;
  width: min(1100px, 120%); aspect-ratio: 1;
  transform: translateX(-50%);
  background:
    radial-gradient(closest-side, rgba(16, 185, 129, 0.16), transparent 70%) 62% 50% / 62% 62% no-repeat,
    radial-gradient(closest-side, rgba(37, 99, 235, 0.20), transparent 70%) 38% 50% / 70% 70% no-repeat;
  pointer-events: none;
}
.soluciones > .wrap { position: relative; z-index: 1; }

/* El logotipo es apaisado (3:1), no un sello cuadrado: a 68px no se
   leía "IntegraTec", solo una mancha. */
.soluciones__marca { width: 124px; height: auto; margin: 0 auto var(--sp-6); }

/* Dos pesos en el mismo titular, como en la referencia: la primera
   línea afirma y la segunda acompaña. */
.soluciones__titulo b, .soluciones__titulo span { display: block; }
.soluciones__titulo b { font-weight: 800; }
.soluciones__titulo span { font-weight: 400; color: color-mix(in srgb, var(--deep-ink) 88%, transparent); }
.soluciones__head .lead { margin-inline: auto; }

/* ---- Ilustración central ---- */
.sol-hero {
  position: relative;
  width: min(560px, 100%);
  margin: var(--sp-12) auto 0;
}
.sol-hero__anillos { position: absolute; inset: -18% -30%; pointer-events: none; }
/* Centrados a mano: `place-items` de la rejilla no alcanza a los hijos
   absolutos, y los anillos salían anclados arriba a la izquierda. */
.sol-hero__anillos i {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  border: 1px dashed color-mix(in srgb, var(--celeste) 42%, transparent);
  border-radius: 50%;
}
.sol-hero__anillos i:nth-child(1) { width: 62%; aspect-ratio: 1; animation: solGira 46s linear infinite; }
.sol-hero__anillos i:nth-child(2) { width: 84%; aspect-ratio: 1; animation: solGira 64s linear infinite reverse; }
.sol-hero__anillos i:nth-child(3) { width: 104%; aspect-ratio: 1; animation: solGira 82s linear infinite; }

/* El giro tiene que arrastrar el centrado: si las keyframes solo llevan
   `rotate`, el `translate(-50%, -50%)` de arriba se pierde en cuanto
   arranca la animación y los anillos saltan a la esquina. */
@keyframes solGira {
  from { transform: translate(-50%, -50%) rotate(0deg); }
  to   { transform: translate(-50%, -50%) rotate(360deg); }
}

.sol-hero__panel {
  position: relative;
  border-radius: var(--r-lg) var(--r-lg) var(--r-sm) var(--r-sm);
  overflow: hidden;
  border: 1px solid var(--deep-line);
  box-shadow: var(--shadow-pop);
}
.sol-hero__panel img { width: 100%; height: auto; }

/* Fichas y pastillas flotantes. Van en el DOM y no en la imagen para
   que se lean nítidas y sigan al tema. */
.sol-ficha, .sol-pastilla {
  position: absolute; z-index: 2;
  /* Recorrido del flote. Va en variable porque el panel encoge con la
     pantalla: 28px sobre 330px de alto se leen bien, sobre 250px dejan
     la ficha de "Venta del día" tocando la pastilla de "Stock". */
  --flota: 28px;
  background: var(--logo-panel);
  border: 1px solid rgba(15, 27, 51, 0.10);
  border-radius: var(--r-sm);
  box-shadow: 0 12px 28px -12px rgba(3, 7, 16, 0.55);
  /* Panel claro fijo en los dos temas: son maquetas de interfaz, y una
     interfaz en oscuro sobre el fondo oscuro se perdería. */
  color: #0F1B33;
}
.sol-ficha { display: grid; gap: 2px; padding: var(--sp-3) var(--sp-4); }
.sol-ficha b { font-size: var(--fs-micro); font-weight: 700; }
.sol-ficha i { font-size: 10px; font-style: normal; color: #5B6B80; }
.sol-ficha em { font-size: var(--fs-body); font-weight: 800; font-style: normal; }
.sol-ficha--a { top: 8%; right: -14%; animation: solFlota 6s ease-in-out infinite; }
.sol-ficha--b { top: 42%; left: -13%; animation: solFlota2 7.5s ease-in-out infinite; }

.sol-pastilla {
  padding: 5px var(--sp-4);
  border-radius: var(--r-pill);
  font-size: 10px; font-weight: 700;
  letter-spacing: var(--ls-wide); text-transform: uppercase;
  background: var(--celeste-solid); color: #FFFFFF; border-color: transparent;
}
/* Separadas de las fichas: la de comprobantes ocupa hasta el 35% del
   alto del panel, y a 32% la pastilla se le montaba encima. */
.sol-pastilla--a { top: 44%; right: 4%; animation: solFlota2 5.5s ease-in-out infinite 0.4s; }
.sol-pastilla--b { bottom: 8%; left: -4%; animation: solFlota 6.8s ease-in-out infinite reverse 0.8s; }

/* Dos recorridos distintos y cuatro duraciones sin múltiplo común: si
   las cuatro piezas suben y bajan a la vez, deja de leerse como que
   flotan y parece que se mueve el panel entero.
   El anterior era un translateY de 11px en 9s — sobre una ilustración
   de 560px eso es medio milímetro por segundo: no se veía. */
@keyframes solFlota {
  0%, 100% { transform: translate3d(0, 0, 0) rotate(0deg); }
  30%      { transform: translate3d(5px, calc(var(--flota) * -0.54), 0) rotate(0.9deg); }
  62%      { transform: translate3d(-4px, calc(var(--flota) * -1), 0) rotate(-0.7deg); }
  84%      { transform: translate3d(3px, calc(var(--flota) * -0.36), 0) rotate(0.4deg); }
}
@keyframes solFlota2 {
  0%, 100% { transform: translate3d(0, 0, 0) rotate(0deg); }
  36%      { transform: translate3d(-6px, calc(var(--flota) * -0.68), 0) rotate(-1.1deg); }
  72%      { transform: translate3d(4px, calc(var(--flota) * -1.04), 0) rotate(0.8deg); }
}

/* ---- Puntero que recorre el panel ----
   Cuatro paradas con su pulsación: fila de indicadores, gráfico de
   notas de venta, barras de totales y los botones de abajo. Los
   porcentajes son del propio panel, así que el recorrido aguanta
   cualquier ancho. */
.sol-cursor {
  position: absolute; left: 12%; top: 24%;
  width: 20px; height: 20px;
  z-index: 3;
  pointer-events: none;
  animation: solPuntero 15s cubic-bezier(0.45, 0, 0.2, 1) infinite;
}
/* Dos clases a propósito: `svg[viewBox] { width: 100% }` de la base le
   gana a un selector de una sola, y la flecha salía a tamaño de póster. */
.sol-cursor .sol-cursor__flecha {
  width: 20px; height: 20px;
  fill: #FFFFFF;
  stroke: rgba(9, 16, 33, 0.6); stroke-width: 1;
  filter: drop-shadow(0 3px 7px rgba(0, 0, 0, 0.5));
  animation: solPulsa 15s linear infinite;
}
/* La onda del clic sale de la punta, no del centro del icono */
.sol-cursor__eco {
  position: absolute; left: -12px; top: -12px;
  width: 34px; height: 34px;
  border-radius: 50%;
  border: 2px solid var(--celeste);
  opacity: 0;
  animation: solEco 15s linear infinite;
}

@keyframes solPuntero {
  0%,   4%   { left: 12%; top: 24%; }   /* menú lateral */
  13%,  21%  { left: 47%; top: 30%; }   /* fila de indicadores */
  30%,  39%  { left: 29%; top: 63%; }   /* notas de venta */
  48%,  56%  { left: 71%; top: 61%; }   /* barras de totales */
  65%,  73%  { left: 54%; top: 88%; }   /* botones del pie */
  84%, 100%  { left: 12%; top: 24%; }
}
/* La pulsación: la flecha se hunde un instante al llegar a cada parada */
@keyframes solPulsa {
  0%, 12.9%   { transform: scale(1); }
  13.6%       { transform: scale(0.8); }
  16%         { transform: scale(1); }
  29.9%       { transform: scale(1); }
  30.6%       { transform: scale(0.8); }
  33%         { transform: scale(1); }
  47.9%       { transform: scale(1); }
  48.6%       { transform: scale(0.8); }
  51%         { transform: scale(1); }
  64.9%       { transform: scale(1); }
  65.6%       { transform: scale(0.8); }
  68%, 100%   { transform: scale(1); }
}
@keyframes solEco {
  0%,  12.9%  { opacity: 0;    transform: scale(0.2); }
  13%         { opacity: 0.6;  transform: scale(0.2); }
  19%         { opacity: 0;    transform: scale(1.5); }
  29.9%       { opacity: 0;    transform: scale(0.2); }
  30%         { opacity: 0.6;  transform: scale(0.2); }
  36%         { opacity: 0;    transform: scale(1.5); }
  47.9%       { opacity: 0;    transform: scale(0.2); }
  48%         { opacity: 0.6;  transform: scale(0.2); }
  54%         { opacity: 0;    transform: scale(1.5); }
  64.9%       { opacity: 0;    transform: scale(0.2); }
  65%         { opacity: 0.6;  transform: scale(0.2); }
  71%         { opacity: 0;    transform: scale(1.5); }
  100%        { opacity: 0;    transform: scale(0.2); }
}

/* ---- Rejilla de sistemas ---- */
.soluciones__grid {
  display: grid; grid-template-columns: repeat(2, 1fr);
  gap: var(--grid-gap);
  margin-top: var(--sp-12);
}
/* La quinta va sola y centrada, ocupando el ancho de una columna: es
   lo que rompe la simetría y evita el hueco de una rejilla impar. */
.sol--ancha { grid-column: 1 / -1; width: min(100%, calc(50% - var(--grid-gap) / 2)); margin-inline: auto; }

.sol {
  position: relative;
  display: flex; align-items: center;
  gap: var(--sp-4);
  min-height: 104px;
  padding: var(--sp-5) var(--sp-6);
  background: color-mix(in srgb, var(--deep-card) 82%, transparent);
  border: 1px solid var(--deep-line);
  border-radius: var(--r-md);
  overflow: hidden;
  transition: translate var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.sol:hover { translate: 0 -3px; border-color: var(--celeste); }

/* `position: relative` no es decorativo: sin él, el z-index no aplica y
   el título quedaba por debajo de la captura. */
.sol__texto { position: relative; z-index: 2; display: flex; align-items: center; gap: var(--sp-4); flex: none; max-width: 58%; }
.sol__icono {
  display: grid; place-items: center;
  width: 40px; height: 40px;
  border-radius: var(--r-sm);
  background: var(--icon-bg);
  color: var(--icon-fg);
}
.sol__icono svg { width: 21px; height: 21px; }
.sol__titulo { font-size: var(--fs-body); font-weight: 700; line-height: 1.25; color: var(--deep-ink); }

/* La captura se sale del marco por la derecha y va ladeada: recortada
   se lee como "hay más pantalla de la que cabe". */
.sol__vista {
  position: absolute; right: calc(var(--sp-6) * -1); top: 50%;
  width: 58%; aspect-ratio: 16 / 10;
  transform: translateY(-50%) rotate(-6deg);
  border-radius: var(--r-xs);
  overflow: hidden;
  border: 1px solid rgba(15, 27, 51, 0.12);
  box-shadow: 0 14px 30px -14px rgba(3, 7, 16, 0.7);
  transition: transform var(--dur-slow) var(--ease-out-soft);
}
.sol:hover .sol__vista { transform: translateY(-50%) rotate(-3deg) scale(1.04); }
.sol__vista img { width: 100%; height: 100%; object-fit: cover; object-position: top left; }

/* Maqueta para los sistemas que todavía no tienen captura: barra
   superior, columna lateral y filas de contenido sobre panel claro. A
   tamaño de miniatura se lee como una aplicación; de cerca es
   evidente que es un marcador. Sustituirla es cambiar el div por un
   <img> igual que en las otras dos tarjetas. */
.sol__vista--maqueta { background: var(--logo-panel); }
/* Barra superior, columna lateral y dos bloques de color que hacen de
   widgets. Sin los bloques la maqueta se leía como una hoja en blanco
   al lado de las capturas de verdad. */
.sol__vista--maqueta::before {
  content: "";
  position: absolute; inset: 0;
  background:
    linear-gradient(var(--celeste-solid) 0 0) 0 0 / 100% 15% no-repeat,
    linear-gradient(rgba(15, 27, 51, 0.07) 0 0) 0 100% / 24% 85% no-repeat,
    linear-gradient(rgba(56, 189, 248, 0.32) 0 0) 33% 26% / 28% 24% no-repeat,
    linear-gradient(rgba(246, 163, 49, 0.32) 0 0) 92% 26% / 28% 24% no-repeat;
}
.sol__vista--maqueta::after {
  content: "";
  position: absolute; left: 30%; right: 8%; top: 60%; bottom: 12%;
  background: repeating-linear-gradient(180deg,
    rgba(15, 27, 51, 0.17) 0 4px, transparent 4px 12px);
}

.soluciones__cta { margin-top: var(--sp-12); text-align: center; }
.soluciones__gancho {
  margin-bottom: var(--sp-4);
  font-size: var(--fs-lead); font-weight: 600;
  color: var(--eyebrow-on-deep);
}

@media (max-width: 900px) {
  .soluciones__grid { grid-template-columns: 1fr; }
  .sol--ancha { width: 100%; }
  /* A una columna la tarjeta se estrecha pero el título mide lo mismo:
     con la captura al 58% se metía por debajo de las palabras. */
  .sol__vista { width: 48%; }
  .sol-hero { width: min(420px, 100%); }
  /* Fuera del marco las fichas se salían de la pantalla en móvil */
  .sol-ficha--a { right: -4%; }
  .sol-ficha--b { left: -4%; }
  .sol-pastilla--b { left: 0; }
  /* Con el panel más estrecho, la ficha de comprobantes baja hasta el
     55% del alto y la pastilla le caía encima del número. */
  .sol-pastilla--a { top: 64%; right: 2%; }
}

@media (max-width: 900px) {
  .sol-ficha, .sol-pastilla { --flota: 15px; }
}

@media (prefers-reduced-motion: reduce) {
  .sol-ficha, .sol-pastilla, .sol-hero__anillos i { animation: none !important; }
  .sol-cursor { display: none; }
  .sol:hover { translate: none; }
  .sol:hover .sol__vista { transform: translateY(-50%) rotate(-6deg); }
}

/* =============================================================
   28. SECCIÓN DEMOS — video en línea con botón play
   ============================================================= */
/* Fondo un punto más profundo que el resto, con dos resplandores,
   para que las tarjetas de video destaquen. */
.demos {
  position: relative;
  background: var(--deep-2);
  color: var(--deep-ink);
  overflow: hidden;
  transition: background var(--dur-theme) var(--ease);
}
.demos__glow {
  position: absolute; border-radius: 50%;
  filter: blur(100px); pointer-events: none;
}
.demos__glow--a { left: -120px; top: -80px; width: 460px; height: 460px; background: var(--glow-a); }
.demos__glow--b { right: -120px; bottom: -100px; width: 420px; height: 420px; background: rgba(56, 189, 248, 0.16); }
.demos .wrap { position: relative; }

.h2--stack { display: grid; gap: 2px; }
.h2__grad {
  font-weight: 700;
  background: linear-gradient(90deg, var(--deep-ink), var(--celeste));
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}

/* --------- Carrusel grande de demos en video --------- */
/* Las flechas se montan sobre el borde del marco en vez de ocupar
   columna propia: así el video se queda con todo el ancho. */
.ytcar { position: relative; }
.ytcar__nav {
  position: absolute; top: 50%; z-index: 2;
  transform: translateY(-50%);
}
.ytcar__nav--prev { left: calc(var(--sp-4) * -1); }
.ytcar__nav--next { right: calc(var(--sp-4) * -1); }
.ytcar__viewport { flex: 1; overflow: hidden; border-radius: var(--r-lg); }
.ytcar__track {
  display: flex;
  transition: transform 950ms var(--ease-carrusel);
  will-change: transform;
}
.ytslide {
  flex: 0 0 100%;
  display: grid;
  grid-template-columns: 1.75fr 1fr;
  background: var(--deep-card);
  border: 1px solid var(--deep-line);
  border-radius: var(--r-lg);
  overflow: hidden;
}

/* El marco manda el 16:9. El iframe y la portada van absolutos: en
   flujo, el alto natural del póster impondría su propio tamaño. */
.ytslide__frame { position: relative; aspect-ratio: 16 / 9; background: var(--ink-surface); }
.ytslide__poster,
.ytslide__iframe {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  border: 0;
}
.ytslide__poster { object-fit: cover; }
.is-playing .ytslide__poster,
.is-playing .ytslide__play { display: none; }

.ytslide__play {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  background: linear-gradient(180deg, rgba(5,11,31,0.15) 0%, rgba(5,11,31,0.62) 100%);
  color: #FFFFFF;
  transition: background var(--dur) var(--ease);
}
.ytslide__play:hover { background: linear-gradient(180deg, rgba(5,11,31,0.30) 0%, rgba(5,11,31,0.74) 100%); }
.ytslide__play span {
  display: grid; place-items: center;
  width: 78px; height: 78px; border-radius: 50%;
  background: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.34);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  transition: transform var(--dur) var(--ease), background var(--dur) var(--ease);
}
.ytslide__play:hover span { transform: scale(1.08); background: rgba(56, 189, 248, 0.30); }
.ytslide__play svg { width: 28px; height: 28px; fill: currentColor; stroke: none; margin-left: 4px; }

.ytslide__pendiente {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  padding: var(--sp-8);
  text-align: center;
  color: var(--on-ink-muted);
  font-size: var(--fs-small);
}

.ytslide__body {
  display: flex; flex-direction: column; justify-content: center;
  gap: var(--sp-4);
  padding: var(--card-pad);
}
.ytslide__title { font-size: var(--fs-h3); font-weight: 700; line-height: var(--lh-heading); }
.ytslide__text { color: var(--deep-muted); }
.ytslide__text strong { color: var(--deep-ink); font-weight: 600; }
.ytslide__body .chips li {
  background: var(--deep-hair); border-color: var(--deep-line);
  color: var(--deep-muted); font-size: var(--fs-micro);
}

.ytcar__nav {
  display: grid; place-items: center;
  width: 48px; height: 48px;
  border-radius: 50%;
  background: var(--deep-hair);
  border: 1px solid var(--deep-line);
  color: var(--deep-ink);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
              color var(--dur) var(--ease);
}
.ytcar__nav { background: var(--deep-card); box-shadow: var(--shadow-card); }
.ytcar__nav:hover { background: var(--celeste-solid); border-color: var(--celeste-solid); color: #FFFFFF; }
.ytcar__nav svg { width: 22px; height: 22px; }

.ytcar__foot {
  display: flex; align-items: center; justify-content: center;
  gap: var(--sp-5); flex-wrap: wrap;
  margin-top: var(--sp-8);
}

@media (max-width: 900px) {
  .ytslide { grid-template-columns: 1fr; }
  .ytcar__nav { display: none; }
  .ytcar { margin-inline: 0; }
}

.demos__note {
  margin-top: var(--sp-10);
  text-align: center;
  font-size: var(--fs-micro);
  color: var(--deep-muted);
}
.demos__note code {
  padding: 2px 6px; border-radius: var(--r-xs);
  background: var(--deep-hair); color: var(--icon-fg);
}

/* =============================================================
   29. TESTIMONIOS — destacado + tira
   ============================================================= */
/* Dos piezas con ritmos distintos, y ese contraste es el punto: arriba
   uno grande que se pasa a mano, abajo una tira de comentarios cortos
   que corre sola cada 3s. */

/* --------------------- 29.1 DESTACADO --------------------- */
.tdest { position: relative; }
.tdest__viewport { overflow: hidden; padding-block: 2px; }
.tdest__track {
  display: flex;
  transition: transform 950ms var(--ease-carrusel);
  will-change: transform;
}
.tdest__slide {
  flex: 0 0 100%;
  display: grid;
  grid-template-columns: 1fr 1.15fr;
  gap: clamp(24px, 4vw, 64px);
  align-items: center;
}

.tdest__copia { min-width: 0; }
/* Píldora con borde, no el eyebrow subrayado del resto de la página:
   aquí abre un bloque, no una sección. */
.tdest__pill {
  display: inline-block;
  padding: var(--sp-3) var(--sp-6);
  border: 1px solid var(--celeste);
  border-radius: var(--r-pill);
  font-size: var(--fs-micro); font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--eyebrow-on-deep);
}
.tdest__quote {
  margin: var(--sp-8) 0 0;
  font-size: clamp(1.0625rem, 1.4vw, 1.375rem);
  line-height: 1.65;
  color: color-mix(in srgb, var(--deep-ink) 92%, transparent);
}
.tdest__quote strong { color: var(--deep-ink); font-weight: 600; }

.tdest__who { display: flex; align-items: center; gap: var(--sp-4); margin-top: var(--sp-8); }
.tdest__who__avatar {
  flex: none;
  display: grid; place-items: center;
  width: 52px; height: 52px;
  border-radius: 50%;
  background: var(--celeste-solid);
  color: #FFFFFF;
  font-size: var(--fs-body); font-weight: 700;
}
.tdest__who__name { font-size: var(--fs-h4); font-weight: 700; color: var(--deep-ink); }
.tdest__who__role { margin-top: 2px; font-size: var(--fs-small); color: var(--deep-muted); }

/* El marco del video lleva filo y halo cian: es la pieza a la que hay
   que mirar en toda la sección. */
.tdest__video {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--ink-surface);
  border: 1px solid var(--celeste);
  box-shadow: 0 0 0 5px rgba(56, 189, 248, 0.08), var(--shadow-pop);
}
.tdest__poster { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* Sin foto de portada: marcador con las iniciales, el mismo recurso
   que el avatar de la ficha. */
.tdest__poster--vacio {
  display: grid; place-items: center;
  background: linear-gradient(150deg, var(--blue-800), var(--ink-surface));
  font-size: 3.5rem; font-weight: 800; letter-spacing: var(--ls-tight);
  color: rgba(255, 255, 255, 0.35);
}
.tdest__iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

.tdest__pendiente {
  position: absolute; inset: auto var(--sp-6) var(--sp-6);
  padding: var(--sp-3) var(--sp-5);
  background: rgba(3, 7, 16, 0.72);
  border: 1px solid var(--ink-line);
  border-radius: var(--r-sm);
  font-size: var(--fs-micro); color: var(--on-ink-muted);
}

.tdest__play {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  width: 100%; padding: 0;
  background: rgba(5, 11, 31, 0.28);
  border: 0; color: #FFFFFF;
  transition: background var(--dur) var(--ease);
}
.tdest__play:hover { background: rgba(5, 11, 31, 0.48); }
.tdest__play span {
  display: grid; place-items: center;
  width: 78px; height: 78px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.14);
  border: 2px solid rgba(255, 255, 255, 0.85);
  transition: transform var(--dur) var(--ease), background var(--dur) var(--ease);
}
.tdest__play:hover span { transform: scale(1.08); background: rgba(56, 189, 248, 0.34); }
.tdest__play svg { width: 30px; height: 30px; fill: currentColor; stroke: none; margin-left: 4px; }
/* Con el reproductor dentro el botón estorba: taparía los controles. */
.tdest__slide.is-playing .tdest__play { display: none; }

/* Flechas fuera de la caja, centradas en vertical */
.tdest__nav {
  position: absolute; top: 50%; z-index: 3;
  transform: translateY(-50%);
  display: grid; place-items: center;
  width: 48px; height: 48px;
  border-radius: 50%;
  background: var(--deep-card);
  border: 1px solid var(--deep-line);
  color: var(--deep-ink);
  box-shadow: var(--shadow-card);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
              color var(--dur) var(--ease);
}
.tdest__nav:hover { background: var(--celeste-solid); border-color: var(--celeste-solid); color: #FFFFFF; }
.tdest__nav svg { width: 22px; height: 22px; }
.tdest__nav--prev { left: calc(var(--sp-10) * -1); }
.tdest__nav--next { right: calc(var(--sp-10) * -1); }

#tdest-dots { margin-top: var(--sp-8); }

/* ----------------------- 29.2 LA TIRA ----------------------- */
.ttira { margin-top: var(--sp-16); }
.ttira__viewport { overflow: hidden; padding-block: 2px; }
.ttira__track {
  display: flex; gap: var(--grid-gap);
  transition: transform 900ms var(--ease-carrusel);
  will-change: transform;
}
/* El ancho de cada tarjeta lo fija el JS a partir del viewport, para
   que entren exactamente tres columnas con sus huecos. */
.ttira-card {
  position: relative;
  flex: 0 0 auto;
  padding: var(--card-pad);
  background: var(--deep-card);
  border: 1px solid var(--deep-line);
  border-radius: var(--r-lg);
  overflow: hidden;
  transition: border-color var(--dur) var(--ease);
}
.ttira-card:hover { border-color: var(--celeste); }

/* Trama diagonal en la esquina, como marca de agua */
.ttira-card__deco {
  position: absolute; top: -10px; right: -10px;
  width: 130px; height: 90px;
  background: repeating-linear-gradient(115deg,
    var(--deep-line) 0 2px, transparent 2px 11px);
  -webkit-mask-image: radial-gradient(120px 90px at 100% 0%, #000, transparent 72%);
          mask-image: radial-gradient(120px 90px at 100% 0%, #000, transparent 72%);
  pointer-events: none;
}

.ttira-card__who { position: relative; display: flex; align-items: center; gap: var(--sp-4); }
.ttira-card__who__avatar {
  flex: none;
  display: grid; place-items: center;
  width: 44px; height: 44px;
  border-radius: 50%;
  background: var(--celeste-solid);
  color: #FFFFFF;
  font-size: var(--fs-small); font-weight: 700;
}
.ttira-card__who__name { font-size: var(--fs-h4); font-weight: 700; color: var(--deep-ink); }
.ttira-card__who__role { margin-top: 2px; font-size: var(--fs-micro); color: var(--deep-muted); }

.ttira-card__text {
  position: relative;
  margin: var(--sp-6) 0 0;
  font-size: var(--fs-body); line-height: 1.7;
  color: var(--deep-muted);
}
.ttira-card__text strong { color: var(--deep-ink); font-weight: 600; }

.ttira__foot { display: flex; justify-content: center; margin-top: var(--sp-8); }

/* =============================================================
   30. RESPONSIVE DE LAS SECCIONES NUEVAS
   ============================================================= */
@media (max-width: 1080px) {
  .sec-head--split { grid-template-columns: 1fr; }
  .iso { max-width: none; }
  .svc { grid-template-columns: repeat(2, 1fr); }
  /* Los planes se apilan de golpe: a dos columnas, el tercero quedaría
     solo debajo y parecería un añadido de segunda. */
  .planes { grid-template-columns: 1fr; max-width: 520px; margin-inline: auto; }
  .plan--destacado { order: -1; }
  .proy-card__cuerpo { width: min(70%, 640px); }
  .proy-card__texto { font-size: var(--fs-body); }
}

/* La tarjeta NO se apila al estrecharse: apilada sería idéntica a la
   diapositiva de demos en móvil, que es justo lo que se quiere evitar.
   En su lugar el panel pasa a ocupar todo el ancho y la pieza se lee
   como un cartel: foto de fondo a toda página, texto al pie. */
@media (max-width: 900px) {
  /* Alto generoso a propósito: el panel de texto ocupa unos 450px, y
     con menos que esto la foto se quedaba en una franja de 90px que no
     se leía como fotografía. */
  .proy-card { min-height: 580px; }
  /* Sobra arriba para que el difuminado del panel ocurra ANTES del
     antetítulo y no por detrás: cae a media zona de fundido y sobre una
     foto clara se lavaba. */
  .proy-card__cuerpo { width: 100%; padding-top: 64px; }

  /* El velo de la foto se reparte sobre el alto ENTERO de la tarjeta,
     así que dónde cae el texto depende de cuánto mida esta. Aquí el
     panel lleva su propio fondo, que por definición cubre justo el
     texto y nada más.
     Va en un ::before y no en el propio panel porque además desenfoca
     el fondo: dos de las fotos son capturas de pantalla muy claras y
     llenas de detalle, y contra eso ni un velo al 90% basta —las
     líneas de los gráficos se seguían leyendo entre las palabras—.
     La máscara difumina el borde superior para que no quede un recorte
     recto a media foto, y no puede ir en el panel porque también
     borraría el texto. */
  .proy-card__cuerpo::before {
    content: "";
    position: absolute; inset: 0;
    z-index: -1;
    background: linear-gradient(to top,
      rgba(3, 7, 16, 0.96) 0%,
      rgba(3, 7, 16, 0.93) 70%,
      rgba(3, 7, 16, 0.86) 88%,
      rgba(3, 7, 16, 0) 100%);
    -webkit-backdrop-filter: blur(7px);
            backdrop-filter: blur(7px);
    -webkit-mask-image: linear-gradient(to top, #000 87%, transparent 100%);
            mask-image: linear-gradient(to top, #000 87%, transparent 100%);
  }
  /* Sin columna izquierda que sostener, el velo lateral sobra. */
  .proy-card__foto::after {
    background:
      linear-gradient(to top,
        rgba(3, 7, 16, 0.55) 0%,
        rgba(3, 7, 16, 0.15) 55%),
      linear-gradient(to bottom,
        rgba(3, 7, 16, 0.45) 0%,
        rgba(3, 7, 16, 0) 32%);
  }
}

@media (max-width: 560px) {
  .proy-card { min-height: 620px; }
  .proy-card__texto { font-size: var(--fs-body); }
}

@media (max-width: 900px) {
  .demos__grid { grid-template-columns: repeat(2, 1fr); }
  /* El destacado se apila: a este ancho, cita y video en dos columnas
     dejan renglones de cuatro palabras y un video en miniatura. El
     video pasa arriba, que es donde tiene fuerza. */
  .tdest__slide { grid-template-columns: 1fr; gap: var(--sp-8); }
  .tdest__video { order: -1; }
  .tdest__nav { width: 40px; height: 40px; }
  .tdest__nav--prev { left: calc(var(--sp-3) * -1); }
  .tdest__nav--next { right: calc(var(--sp-3) * -1); }
  .ttira { margin-top: var(--sp-12); }
}

@media (max-width: 720px) {
  /* En móvil las flechas estorban más de lo que ayudan: se navega con
     los puntos y el paso automático. */
  .svc-car__nav { display: none; }
  /* Aquí tampoco: el carrusel de proyectos se arrastra con el dedo,
     que es justo lo que da el scroll-snap nativo. */
  .proy__nav { display: none; }

  .demos__grid { grid-template-columns: 1fr; }
  .h2--laurel { gap: var(--sp-3); }
  .laurel { width: 20px; height: 30px; }

  /* Las flechas del destacado se solaparían con el video a este ancho:
     se navega con los puntos. */
  .tdest__nav { display: none; }
  .tdest__play span { width: 64px; height: 64px; }
}

@media (prefers-reduced-motion: reduce) {
  .tdest__track, .ttira__track { transition: none !important; }
  .ttira-card:hover { border-color: var(--deep-line); }
  .demo:hover { translate: none; }
  /* El zoom de la foto y el barrido de luz son los dos efectos con más
     movimiento de la página: aquí se van del todo. */
  .proy-card:hover { translate: none; }
  .proy-card__foto img { transition: none; }
  .proy-card:hover .proy-card__foto img,
  .proy-card:focus-within .proy-card__foto img { transform: scale(1.01); }
  .proy-card__brillo { display: none; }
  .proy__viewport { scroll-behavior: auto; }
}


/* =============================================================
   31. MOVIMIENTO

   Reglas que sigue todo lo de aquí:
   · Solo se animan `transform` y `opacity`. Nada que fuerce layout
     (width, top, margin) ni repintados caros (box-shadow, filter) en
     bucle o durante el scroll.
   · Todo lo dispara una clase que pone el JS, nunca un `:hover` que
     compita con el reveal.
   · El bloque de prefers-reduced-motion del final lo desactiva todo.
   ============================================================= */

/* ---- 31.1 Titular del hero: revelado por palabras enmascaradas ----
   El JS envuelve cada palabra en .w > .w__i. La máscara necesita algo
   de holgura abajo o recorta las colas de la g y la p. */
.w {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  padding-bottom: 0.12em;
  margin-bottom: -0.12em;
}
.w__i {
  display: inline-block;
  transform: translateY(110%);
  /* Aquí sí va ease-out: la palabra sale disparada de detrás de su
     máscara y se asienta. Con la curva de los carruseles arrancaría
     despacio y el titular parecería que le cuesta. */
  transition: transform 900ms var(--ease-out-soft);
  transition-delay: calc(var(--wi) * 45ms);
}
.is-lit .w__i { transform: none; }

/* Lo que rodea al titular entra después, escalonado y más corto. */
.hero__actions,
.hero__checks,
.hero__mando,
.hero__visual {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 700ms var(--ease-out-soft), transform 700ms var(--ease-out-soft);
}
.hero.is-lit .hero__actions      { opacity: 1; transform: none; transition-delay: 460ms; }
.hero.is-lit .hero__checks       { opacity: 1; transform: none; transition-delay: 540ms; }
.hero.is-lit .hero__mando   { opacity: 1; transform: none; transition-delay: 620ms; }
/* El mockup entra desde el lado y con una pizca de escala: da la
   sensación de que la escena se arma, no de que aparece. */
.hero__visual { transform: translateY(18px) scale(0.97); }
.hero.is-lit .hero__visual {
  opacity: 1; transform: none;
  transition: opacity 1000ms var(--ease-out-soft) 240ms,
              transform 1000ms var(--ease-out-soft) 240ms;
}

/* ---- 31.2 Reflejo que sigue al cursor ----
   Un solo ::after por tarjeta. La posición llega por --mx/--my, que
   el JS escribe desde un rAF: son custom properties, así que cambiarlas
   no invalida el layout. */
.has-spot { position: relative; isolation: isolate; }
.has-spot::after {
  content: "";
  position: absolute; inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: radial-gradient(300px circle at var(--mx, 50%) var(--my, 0%),
                              var(--spot), transparent 72%);
  opacity: 0;
  transition: opacity 320ms var(--ease);
  pointer-events: none;
}
.has-spot:hover::after,
.has-spot:focus-within::after { opacity: 1; }

/* ---- 31.3 Barra de progreso de lectura ----
   Va pegada al borde inferior del header. scaleX desde la izquierda:
   ni un solo recálculo de layout mientras se hace scroll. */
.progress {
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 2px;
  transform: scaleX(var(--p, 0));
  transform-origin: 0 50%;
  background: linear-gradient(90deg, var(--blue), var(--celeste), var(--orange));
  will-change: transform;
}

/* ---- 31.4 Reveal afinado ----
   Sube, aparece y termina de asentarse con una pizca de escala. El
   escalonado dentro de las rejillas lo calcula el JS. */
[data-reveal] {
  opacity: 0;
  transform: translateY(26px) scale(0.99);
  transition: opacity 940ms var(--ease-out-soft), transform 940ms var(--ease-out-soft);
}
[data-reveal].is-visible { opacity: 1; transform: none; }

/* Quien retira el `opacity: 0` es el JS. Sin él la página entera se
   quedaba en blanco: aquí se cancela el estado inicial. */
.sin-js [data-reveal], .sin-js .proy-card { opacity: 1; transform: none; }

/* Escalonado de las tarjetas de proyecto. Va colgado del contenedor y
   no de cada tarjeta con `data-reveal`: las que están fuera del
   viewport HORIZONTAL del carrusel no intersecan nunca, y con un
   observador por tarjeta se quedarían invisibles hasta que alguien
   deslizara. */
.proy.is-visible .proy-card { opacity: 1; transform: none; }
.proy.is-visible .proy-card:nth-child(2) { transition-delay: 80ms; }
.proy.is-visible .proy-card:nth-child(3) { transition-delay: 160ms; }
.proy.is-visible .proy-card:nth-child(4) { transition-delay: 240ms; }
.proy.is-visible .proy-card:nth-child(5) { transition-delay: 300ms; }
.proy.is-visible .proy-card:nth-child(6) { transition-delay: 360ms; }

/* ---- 31.5 Micro-detalles ----
   El icono de la tarjeta se inclina levemente al pasar por encima. */
.card__icon { transition: transform 420ms var(--ease-out-soft), background 260ms var(--ease); }
.svc-card:hover .card__icon { transform: translateY(-2px) rotate(-6deg); }

/* El botón play late una vez al entrar el cursor en la tarjeta */
@keyframes playNudge {
  0%   { transform: scale(1); }
  45%  { transform: scale(1.14); }
  100% { transform: scale(1.08); }
}

/* Subrayado del eyebrow que se dibuja al revelarse la sección */
.sec-head .eyebrow, .hero .eyebrow { position: relative; display: inline-block; }
.sec-head .eyebrow::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: -6px;
  height: 2px; border-radius: var(--r-pill);
  background: currentColor;
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform 700ms var(--ease-out-soft) 200ms;
}
[data-reveal].is-visible .eyebrow::after { transform: scaleX(1); }

/* ---- 31.6 Desactivado total con reduced-motion ---- */
@media (prefers-reduced-motion: reduce) {
  .w__i { transform: none !important; }
  .hero__actions, .hero__checks, .hero__mando, .hero__visual,
  .hero-slide, .hero__fondo, .hero-vista {
    opacity: 1 !important; transform: none !important;
  }
  .has-spot::after { display: none; }
  .progress { display: none; }
  .svc-card:hover .card__icon { transform: none; }
  .sec-head .eyebrow::after { transform: scaleX(1); }
}


/* =============================================================
   32. CAPAS DE FONDO ANIMADAS

   Cada sección que las lleva recibe un <div class="fx"> que el JS
   rellena. Reglas: solo `transform` y `opacity`, nada de repintar
   sombras ni filtros en bucle, y el contenido siempre por encima.
   ============================================================= */

/* La capa se recorta contra su sección y nunca intercepta el ratón. */
.fx {
  position: absolute; inset: 0;
  overflow: hidden;
  /* La capa no intercepta el ratón; el hero escucha el puntero en la
     propia sección, así que la red reacciona igual. */
  pointer-events: none;
  z-index: 0;
}
/* El contenido de una sección con capa tiene que quedar por encima */
.section > .wrap,
.demos > .wrap { position: relative; z-index: 1; }

/* ---- Red de partículas (canvas) ----
   Sustituye a un campo de puntos animados por CSS. Aquel derivaba
   ~3px/s y no se leía como movimiento; con lienzo se puede mover a
   velocidad visible y unir los nodos cercanos con líneas, que es lo
   que hace que parezca una red y no confeti. */
.fx-canvas {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: block;
}

/* ---- Orbes a la deriva ----
   Los halos de las secciones dejan de estar clavados y se mueven en un
   recorrido largo. Al ir desenfocados, el movimiento se lee como luz
   que cambia, no como una figura que se desplaza. */
.demos__glow {
  animation: fxDrift var(--d, 34s) ease-in-out var(--delay, 0s) infinite alternate;
  will-change: transform;
}
@keyframes fxDrift {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(var(--dx, 60px), var(--dy, 40px), 0) scale(1.12); }
}

/* ---- Malla que se desplaza ----
   Reutiliza la malla técnica del hero: el desplazamiento del
   background-position no toca el layout. */
.fx-mesh {
  position: absolute; inset: 0;
  background-image:
    linear-gradient(var(--mesh) 1px, transparent 1px),
    linear-gradient(90deg, var(--mesh) 1px, transparent 1px);
  background-size: 72px 72px;
  -webkit-mask-image: radial-gradient(ellipse at 50% 0%, #000, transparent 72%);
  mask-image: radial-gradient(ellipse at 50% 0%, #000, transparent 72%);
  animation: fxMesh 26s linear infinite;
}
@keyframes fxMesh {
  from { background-position: 0 0, 0 0; }
  to   { background-position: 72px 72px, 72px 72px; }
}

@media (prefers-reduced-motion: reduce) {
  .fx-dot, .demos__glow, .fx-mesh { animation: none !important; }
}

/* La red de la portada se aparta de la columna del texto. Se recorta
   la propia capa en vez de poner un velo encima: así no hay que
   compensar opacidades ni se ensucia el fondo, y el efecto sigue
   entero alrededor del mockup y en los bordes. */
#inicio .fx {
  -webkit-mask-image: linear-gradient(96deg, transparent 0%, transparent 42%,
                                      rgba(0,0,0,.45) 52%, #000 66%);
  mask-image: linear-gradient(96deg, transparent 0%, transparent 42%,
                              rgba(0,0,0,.45) 52%, #000 66%);
}

@media (max-width: 900px) {
  /* Apilado, el texto ocupa todo el ancho: el recorte pasa a vertical
     y deja la red solo por encima y por debajo del bloque de texto. */
  #inicio .fx {
    -webkit-mask-image: linear-gradient(180deg, #000 0%, rgba(0,0,0,.35) 26%,
                                        transparent 40%, transparent 100%);
    mask-image: linear-gradient(180deg, #000 0%, rgba(0,0,0,.35) 26%,
                                transparent 40%, transparent 100%);
  }
}

/* =============================================================
   34. PÁGINAS INTERIORES (soporte.html · cursos.html)
   =============================================================
   Piezas que solo existen fuera de la portada. Comparten hoja para
   que el tema, los tokens y el header sigan siendo los mismos: son
   páginas del mismo sitio, no micrositios. */

/* Portada corta, no un hero de pantalla completa: quien llega aquí ya
   sabe a qué viene, y hacerle bajar antes de ver el contenido sería
   trabajo de más. */
.pagina-hero { padding-block: var(--sp-12) var(--sp-16); }
.pagina-hero .sec-head { margin-bottom: 0; }

/* --- Migas de pan --- */
.migas { margin-bottom: var(--sp-8); }
/* El reset de la hoja solo desactiva las viñetas de `ul`; sin esto la
   ruta salía como "1. Inicio 2. Servicios 3. Planes de soporte". Va en
   `<ol>` porque el orden de los niveles es parte del significado. */
.migas ol {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3);
  padding: 0; list-style: none;
}
.migas li { font-size: var(--fs-small); color: var(--deep-muted); }
/* El separador va en ::before del hermano y no como texto suelto: así
   no lo lee un lector de pantalla ni se puede seleccionar. */
.migas li + li::before { content: "/"; margin-right: var(--sp-3); opacity: 0.5; }
.migas a { color: var(--deep-muted); transition: color var(--dur) var(--ease); }
.migas a:hover { color: var(--deep-ink); }
.migas [aria-current="page"] { color: var(--deep-ink); font-weight: 600; }

/* --- Pasos numerados --- */
.pasos {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: var(--grid-gap);
  counter-reset: paso;
}
.paso {
  position: relative;
  padding: var(--sp-8) var(--card-pad) var(--card-pad);
  background: var(--deep-card);
  border: 1px solid var(--deep-line);
  border-radius: var(--r-lg);
  transition: border-color var(--dur) var(--ease), translate var(--dur) var(--ease);
}
.paso:hover { border-color: var(--celeste); translate: 0 -3px; }
/* El número monta sobre el borde superior, de ahí el padding extra. */
.paso__num {
  position: absolute; top: 0; left: var(--card-pad);
  transform: translateY(-50%);
  display: grid; place-items: center;
  width: 38px; height: 38px;
  border-radius: 50%;
  background: var(--celeste-solid); color: #FFFFFF;
  font-size: var(--fs-small); font-weight: 800;
}
.paso__titulo { font-size: var(--fs-h4); font-weight: 700; color: var(--deep-ink); }
.paso__texto { margin-top: var(--sp-3); font-size: var(--fs-small); line-height: 1.7; color: var(--deep-muted); }

/* --- Rejilla de cobertura: usa .card, solo cambia el reparto --- */
.cobertura { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--grid-gap); }
.cobertura .card { height: 100%; }

/* --- Cierre de página --- */
.pagina-cta { text-align: center; }
.pagina-cta .lead { margin-inline: auto; max-width: 56ch; }
.pagina-cta__acciones {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: var(--sp-4);
  margin-top: var(--sp-8);
}

/* La opción activa del submenú, para saber en qué página estás */
.nav__submenu a[aria-current="page"] b { color: var(--band-accent); }

@media (max-width: 1080px) {
  .pasos, .cobertura { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 620px) {
  .pasos, .cobertura { grid-template-columns: 1fr; }
}

/* Franja estrecha de escritorio: entre el corte del nav móvil (900px) y
   los 1000px no hay sitio holgado para el logo, los seis enlaces y el
   botón. Lo que se cede es el CTA: el mismo botón está en el hero y
   "Contacto" sigue en la barra.
   La franja llegaba antes a 1040px, cuando el header llevaba además el
   interruptor de tema. Sin él, a 905px el botón entra por 2px — que es
   justo lo que NO conviene dar por bueno: basta una tipografía de
   respaldo más ancha o una etiqueta más larga para volver a desbordar.
   Por eso se conserva la guarda, solo que más corta. */
@media (min-width: 901px) and (max-width: 1000px) {
  .header__cta { display: none; }
}

/* =============================================================
   35. SOPORTE TI — acordeón de alcance, contratos y beneficios
   ============================================================= */

/* --- A quién va dirigido --- */
.publico { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--grid-gap); }
.publico__item {
  padding: var(--sp-6);
  background: var(--card);
  border: 1px solid var(--card-line);
  border-left: 3px solid var(--celeste-solid);
  border-radius: var(--r-sm);
  transition: transform var(--dur) var(--ease), border-left-color var(--dur) var(--ease);
}
.publico__item:hover { transform: translateX(4px); border-left-color: var(--orange); }
.publico__titulo { font-size: var(--fs-body); font-weight: 700; color: var(--band-ink); }
.publico__texto { margin-top: var(--sp-2); font-size: var(--fs-small); line-height: 1.65; color: var(--band-muted); }

/* --- Acordeón de alcance ---
   Va en <details>/<summary> nativos: son siete bloques con más de
   setenta puntos entre todos. Desplegados a la vez forman un muro que
   nadie lee, y el acordeón nativo se navega con teclado, responde al
   Ctrl+F del navegador y funciona sin JavaScript. */
.acor { display: grid; gap: var(--sp-4); }
.acor__item {
  background: var(--deep-card);
  border: 1px solid var(--deep-line);
  border-radius: var(--r-md);
  overflow: hidden;
  transition: border-color var(--dur) var(--ease);
}
.acor__item[open] { border-color: var(--celeste); }

.acor__cab {
  display: flex; align-items: center; gap: var(--sp-4);
  padding: var(--sp-5) var(--sp-6);
  cursor: pointer;
  list-style: none;
  transition: background var(--dur) var(--ease);
}
/* El triángulo por defecto se quita en los dos motores: Firefox por
   `list-style` y WebKit/Blink por este pseudo-elemento. */
.acor__cab::-webkit-details-marker { display: none; }
.acor__cab:hover { background: var(--deep-hair); }

.acor__icono {
  flex: none;
  display: grid; place-items: center;
  width: 40px; height: 40px;
  border-radius: var(--r-sm);
  background: var(--icon-bg); color: var(--icon-fg);
}
.acor__icono svg { width: 21px; height: 21px; }
.acor__titulo { flex: 1; font-size: var(--fs-h4); font-weight: 700; color: var(--deep-ink); }
.acor__flecha { flex: none; display: grid; place-items: center; color: var(--deep-muted); }
.acor__flecha svg {
  width: 20px; height: 20px; stroke-width: 2;
  transition: transform var(--dur) var(--ease);
}
.acor__item[open] .acor__flecha svg { transform: rotate(180deg); }

.acor__panel { padding: 0 var(--sp-6) var(--sp-6); }
/* El contenido entra desvanecido al abrir. El alto no se anima: de 0 a
   auto no se puede, y las alternativas (medir con JS, max-height a ojo)
   cuestan más de lo que aportan en un panel de este tamaño. */
.acor__item[open] .acor__panel { animation: acorEntra 420ms var(--ease-out-soft) both; }
@keyframes acorEntra {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}

.acor__cuerpo { display: grid; grid-template-columns: 1fr 300px; gap: var(--sp-8); align-items: start; }
/* Sin foto, la lista ocupa el ancho completo en vez de dejar el hueco
   de la columna vacío. */
.acor__cuerpo:not(:has(.acor__foto)) { grid-template-columns: 1fr; }

.acor__foto {
  margin: 0;
  border-radius: var(--r-sm);
  overflow: hidden;
  border: 1px solid var(--deep-line);
}
.acor__foto img { width: 100%; height: 220px; object-fit: cover; }

/* --- Lista con palomeo --- */
.lista-check {
  display: grid; grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-4) var(--sp-8);
}
.lista-check--suelta { grid-template-columns: 1fr; margin-top: var(--sp-6); }
.lista-check li {
  position: relative;
  padding-left: var(--sp-8);
  font-size: var(--fs-small); line-height: 1.6;
  color: var(--deep-muted);
}
/* El palomeo va en ::before y no como <svg> por elemento: son más de
   setenta ítems y no aportan nada al árbol de accesibilidad. */
.lista-check li::before {
  content: "";
  position: absolute; left: 2px; top: 0.42em;
  width: 11px; height: 6px;
  border-left: 2px solid var(--celeste);
  border-bottom: 2px solid var(--celeste);
  transform: rotate(-45deg);
}

/* --- Nota de exclusiones --- */
/* Va en rojo y con aspa porque dice lo que NO entra: mezclarlo con el
   resto de la lista sería justo el malentendido que hay que evitar. */
.excluye {
  display: flex; gap: var(--sp-4);
  margin-top: var(--sp-6); padding: var(--sp-4) var(--sp-5);
  background: color-mix(in srgb, #E5484D 8%, transparent);
  border: 1px solid color-mix(in srgb, #E5484D 30%, transparent);
  border-radius: var(--r-sm);
  font-size: var(--fs-micro); line-height: 1.65; color: var(--deep-muted);
}
.excluye__marca {
  flex: none;
  display: grid; place-items: center;
  width: 18px; height: 18px; margin-top: 1px;
  border-radius: 50%;
  background: #E5484D; color: #FFFFFF;
  font-size: 11px; font-weight: 700; line-height: 1;
}

/* --- Tipos de contrato --- */
.contratos { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--grid-gap); align-items: start; }
.contrato {
  position: relative;
  display: flex; flex-direction: column;
  padding: var(--card-pad);
  background: var(--card);
  border: 1px solid var(--card-line);
  border-radius: var(--r-lg);
  transition: translate var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.contrato:hover { translate: 0 -4px; border-color: var(--celeste-solid); }
.contrato--destacado {
  border-color: var(--orange);
  box-shadow: var(--shadow-pop);
  padding-top: calc(var(--card-pad) + var(--sp-4));
}
.contrato__sello {
  position: absolute; top: 0; left: 50%;
  transform: translate(-50%, -50%);
  padding: 6px var(--sp-5);
  background: var(--orange);
  border-radius: var(--r-pill);
  font-size: var(--fs-micro); font-weight: 700;
  letter-spacing: var(--ls-wide); text-transform: uppercase;
  /* Naranja de marca con texto oscuro: el blanco encima no llega al
     4.5:1. Mismo par que usa .btn--accent. */
  color: #0F1B33;
  white-space: nowrap;
}
.contrato__nombre {
  font-size: var(--fs-h2); font-weight: 800;
  letter-spacing: var(--ls-tight); color: var(--band-ink);
}
.contrato__horario {
  margin-top: var(--sp-2);
  font-size: var(--fs-small); font-weight: 600; color: var(--band-accent);
}

/* Lista con línea de tiempo: un filete vertical y un punto por ítem,
   como en la lámina de origen. */
.contrato__lista {
  position: relative;
  display: grid; gap: var(--sp-5);
  margin: var(--sp-6) 0 var(--sp-8);
  padding-left: var(--sp-6);
}
.contrato__lista::before {
  content: "";
  position: absolute; left: 5px; top: 6px; bottom: 6px;
  width: 2px;
  background: var(--card-line);
}
.contrato__lista li {
  position: relative;
  font-size: var(--fs-small); line-height: 1.6; color: var(--band-muted);
}
.contrato__lista li::before {
  content: "";
  position: absolute; left: calc(var(--sp-6) * -1); top: 0.42em;
  width: 12px; height: 12px;
  border-radius: 50%;
  background: var(--celeste-solid);
  box-shadow: 0 0 0 3px var(--card);
}
.contrato__precio {
  margin-bottom: var(--sp-6);
  font-size: var(--fs-h3); font-weight: 800; color: var(--band-ink);
}
.contrato__precio span { font-size: var(--fs-small); font-weight: 500; color: var(--band-muted); }
.contrato .btn { margin-top: auto; justify-content: center; }

/* --- Beneficios --- */
.beneficios { display: grid; grid-template-columns: 1.2fr 1fr; gap: var(--sp-16); align-items: center; }
/* Sin la foto, el texto no se queda en media página. */
.beneficios:not(:has(.beneficios__foto)) { grid-template-columns: 1fr; max-width: 820px; }
.beneficios__foto { margin: 0; border-radius: var(--r-lg); overflow: hidden; box-shadow: var(--shadow-pop); }
/* Proporcion fija y recorte: el hueco tiene que aguantar tanto una foto
   apaisada como una vertical. Sin esto, la del gabinete de servidores
   —736x981— se estiraba a 1188px de alto y empujaba toda la seccion. */
.beneficios__foto img { display: block; width: 100%; aspect-ratio: 5 / 4; height: auto; object-fit: cover; }

/* --- Rasgos de la mesa de ayuda --- */
.rasgos { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--grid-gap); }
.rasgo {
  padding: var(--sp-6);
  background: var(--card);
  border: 1px solid var(--card-line);
  border-radius: var(--r-sm);
  transition: border-color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.rasgo:hover { border-color: var(--celeste-solid); transform: translateY(-3px); }
.rasgo__titulo { font-size: var(--fs-body); font-weight: 700; color: var(--band-ink); }
.rasgo__texto { margin-top: var(--sp-3); font-size: var(--fs-small); line-height: 1.65; color: var(--band-muted); }

@media (max-width: 1080px) {
  .publico { grid-template-columns: repeat(2, 1fr); }
  .contratos, .rasgos { grid-template-columns: 1fr; max-width: 560px; margin-inline: auto; }
  .contrato--destacado { order: -1; }
  .beneficios { grid-template-columns: 1fr; gap: var(--sp-10); }
}
@media (max-width: 760px) {
  .acor__cuerpo { grid-template-columns: 1fr; }
  .lista-check { grid-template-columns: 1fr; }
  .acor__cab { padding: var(--sp-4) var(--sp-5); gap: var(--sp-3); }
  .acor__panel { padding: 0 var(--sp-5) var(--sp-5); }
  .acor__titulo { font-size: var(--fs-body); }
}
@media (max-width: 520px) {
  .publico { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  .acor__item[open] .acor__panel { animation: none; }
  .publico__item:hover, .rasgo:hover { transform: none; }
  .contrato:hover { translate: none; }
}

/* Red de puntos en la portada de las páginas interiores.
   El recorte va en radial y no en diagonal como el de `#inicio`: aquí
   el texto está centrado, así que la red se ve por los bordes y se
   apaga justo detrás del titular en vez de quedarse a un lado. */
.pagina-hero .fx {
  -webkit-mask-image: radial-gradient(115% 95% at 50% 48%,
                      transparent 0%, transparent 34%,
                      rgba(0, 0, 0, 0.45) 56%, #000 76%);
          mask-image: radial-gradient(115% 95% at 50% 48%,
                      transparent 0%, transparent 34%,
                      rgba(0, 0, 0, 0.45) 56%, #000 76%);
}
/* Sitio para que la red respire por arriba y por abajo del bloque de
   texto: con el padding de portada corta quedaba una franja estrecha. */
.pagina-hero { padding-block: var(--sp-16); }

@media (max-width: 900px) {
  /* A este ancho el texto ocupa casi todo: el óvalo se estrecha para
     que la red no se le meta por detrás. */
  .pagina-hero .fx {
    -webkit-mask-image: radial-gradient(150% 80% at 50% 50%,
                        transparent 0%, transparent 46%,
                        rgba(0, 0, 0, 0.4) 66%, #000 86%);
            mask-image: radial-gradient(150% 80% at 50% 50%,
                        transparent 0%, transparent 46%,
                        rgba(0, 0, 0, 0.4) 66%, #000 86%);
  }
}

/* =============================================================
   36. HERO — carrusel de especialidades
   =============================================================
   Cinco diapositivas que pasan solas cada 6 s. Cada cambio mueve tres
   capas a la vez: la fotografía del fondo, el bloque de texto y el
   tono de los halos.

   El cruce dura 2,4 s de los 6 s de cada diapositiva: se ve fundirse una
   fotografía en la otra, y aun así quedan 3,6 s de imagen quieta para
   leer el titular. Esa es la proporción a respetar si algún día se
   vuelve a tocar —cruce por debajo de la mitad del intervalo—: si el
   cruce se come el hueco, no llega a verse ninguna de las dos fotos
   enteras y la portada se convierte en una mancha en movimiento. Los botones, los checks y la cinta de clientes
   NO cambian: son constantes de marca y parpadear con ellos cada tres
   segundos distraería de lo único que hay que leer. */

/* ---- Fondos apilados ---- */
/* z-index 0 explicito: la capa de particulas (.fx) es el PRIMER hijo
   del hero, asi que sin esto los fondos se pintaban encima y tapaban
   la red de puntos por completo. */
.hero__fondos { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 0; }

/* La red de puntos va por encima de la fotografia pero por debajo del
   texto: .wrap tambien esta en z-index 1 y va despues en el DOM. */
#inicio .fx { z-index: 1; }

/* ---- Color de la red por diapositiva ----
   Alterna los dos colores de la empresa. El azul es --celeste y no el
   --blue del logotipo (#3260AA): a 1px de grosor sobre fondo oscuro,
   el azul de marca casi no se ve. */
.hero[data-tono="ia"]       { --fx-node-hero: rgba(246, 163, 49, 0.95); }
.hero[data-tono="vision"]   { --fx-node-hero: rgba(56, 189, 248, 1); }
.hero[data-tono="movil"]    { --fx-node-hero: rgba(246, 163, 49, 0.95); }
.hero[data-tono="software"] { --fx-node-hero: rgba(56, 189, 248, 1); }
.hero[data-tono="infra"]    { --fx-node-hero: rgba(246, 163, 49, 0.95); }
.hero__fondo {
  position: absolute; inset: 0;
  background-size: cover;
  background-position: center;
  opacity: 0;
  transform: scale(1.08);
  transition: opacity 2400ms var(--ease-carrusel), transform 2400ms var(--ease-carrusel);
}
/* El zoom lento sobre la activa es lo que evita que el cambio se lea
   como un pase de diapositivas: mientras una entra, la escena sigue
   moviéndose. */
.hero__fondo.is-activa {
  opacity: 1;
  transform: scale(1);
  transition: opacity 2400ms var(--ease-carrusel),
              transform 14000ms linear;
}
/* Velo doble: de izquierda a derecha para sostener la columna de
   texto, y de abajo para que la cinta de logos no caiga sobre foto. */
.hero__fondos::after {
  content: "";
  position: absolute; inset: 0;
  background:
    linear-gradient(100deg,
      var(--deep) 0%,
      color-mix(in srgb, var(--deep) 96%, transparent) 32%,
      color-mix(in srgb, var(--deep) 80%, transparent) 62%,
      color-mix(in srgb, var(--deep) 88%, transparent) 100%),
    linear-gradient(to top,
      var(--deep) 0%,
      color-mix(in srgb, var(--deep) 55%, transparent) 34%,
      color-mix(in srgb, var(--deep) 20%, transparent) 62%);
}

.hero__fondo--ia       { background-image: url("../assets/img/img-Servicios/automatizacion.jpg"); }
.hero__fondo--vision   { background-image: url("../assets/img/img-Servicios/epps.jpg"); }
.hero__fondo--movil    { background-image: url("../assets/video/poster-aplicativos-moviles.jpg"); }
.hero__fondo--software { background-image: url("../assets/img/img-Servicios/sofware2.jpg"); }
.hero__fondo--infra    { background-image: url("../assets/img/img-Servicios/cableado_estructurado3.jpg"); }

/* ---- Tono por diapositiva ----
   El atributo lo escribe el JS en la propia sección. Es un atributo,
   no un `style=`, así que la CSP lo permite. */
.hero__glow, .hero__glow--warm { transition: background 1800ms var(--ease); }
.hero[data-tono="vision"]   .hero__glow { background: radial-gradient(circle, rgba(56, 189, 248, 0.50), transparent 70%); }
.hero[data-tono="movil"]    .hero__glow { background: radial-gradient(circle, rgba(139, 92, 246, 0.45), transparent 70%); }
.hero[data-tono="software"] .hero__glow { background: radial-gradient(circle, rgba(246, 163, 49, 0.34), transparent 70%); }
.hero[data-tono="infra"]    .hero__glow { background: radial-gradient(circle, rgba(16, 185, 129, 0.38), transparent 70%); }

/* ---- Barrido de luz en cada cambio ----
   Una franja fina que cruza la portada de lado a lado. Marca el corte
   entre una diapositiva y otra sin necesidad de mover nada más. */
.hero__barrido {
  position: absolute; top: 0; bottom: 0; left: -30%;
  width: 22%;
  background: linear-gradient(100deg, transparent, rgba(56, 189, 248, 0.16), transparent);
  transform: skewX(-14deg);
  opacity: 0;
  pointer-events: none;
  z-index: 2;
}
.hero.is-pasando .hero__barrido { animation: heroBarrido 1800ms var(--ease) forwards; }
@keyframes heroBarrido {
  0%   { left: -30%; opacity: 0; }
  22%  { opacity: 1; }
  100% { left: 115%; opacity: 0; }
}

/* ---- Diapositivas de texto ----
   Apiladas en la misma celda de rejilla. La altura la marca la más
   alta, así que los botones de abajo no dan saltos al cambiar. */
.hero__slides { display: grid; }
.hero-slide {
  grid-area: 1 / 1;
  opacity: 0;
  visibility: hidden;
  transform: translateY(18px);
  transition: opacity 1200ms var(--ease-carrusel),
              transform 1200ms var(--ease-carrusel),
              visibility 1200ms;
}
.hero-slide.is-activa { opacity: 1; visibility: visible; transform: none; }

/* ---- Visual de cada diapositiva ---- */
.hero__visual { position: relative; display: grid; }
.hero-vista {
  grid-area: 1 / 1;
  margin: 0;
  border-radius: var(--r-lg);
  overflow: hidden;
  opacity: 0;
  visibility: hidden;
  transform: scale(0.96);
  transition: opacity 1300ms var(--ease-carrusel),
              transform 1300ms var(--ease-carrusel),
              visibility 1300ms;
}
.hero-vista.is-activa { opacity: 1; visibility: visible; transform: none; }
/* Las cuatro de fotografía llevan la imagen de fondo y proporción
   fija; la de software conserva el cromo de ventana del mockup. */
.hero-vista--ia,
.hero-vista--vision,
.hero-vista--movil,
.hero-vista--infra {
  aspect-ratio: 4 / 3;
  background-size: cover;
  background-position: center;
  border: 1px solid var(--deep-line);
  box-shadow: var(--shadow-pop);
}
.hero-vista--ia     { background-image: url("../assets/img/img-Servicios/automatizaciones.jpg"); }
.hero-vista--vision { background-image: url("../assets/img/img-Servicios/epps.jpg"); }
.hero-vista--movil  { background-image: url("../assets/video/poster-aplicativos-moviles.jpg"); }
.hero-vista--infra  { background-image: url("../assets/img/img-Servicios/Cableado_Estructurado1.jpg"); }
.hero-vista--software { border: 0; box-shadow: none; overflow: visible; }

/* ---- Mando: puntos y pausa ----
   El carrusel se mueve solo, así que necesita un control de pausa
   (WCAG 2.2.2). Además se detiene al pasar el cursor o al entrar con
   el tabulador. */
.hero__mando {
  display: flex; align-items: center; gap: var(--sp-5);
  margin-top: clamp(14px, 2.8vh, 32px);
}
.hero__mando .dots { justify-content: flex-start; }
.hero__mando .chip-btn { flex: none; }

@media (max-width: 900px) {
  /* Apilado, la foto del fondo compite con el texto: el velo pasa a
     vertical y tapa casi toda la parte baja. */
  .hero__fondos::after {
    background:
      linear-gradient(to top,
        var(--deep) 0%,
        color-mix(in srgb, var(--deep) 88%, transparent) 46%,
        color-mix(in srgb, var(--deep) 62%, transparent) 74%);
  }
  .hero__mando { justify-content: center; }
  .hero__mando .dots { justify-content: center; }
}

@media (prefers-reduced-motion: reduce) {
  /* Sin movimiento: el carrusel no arranca solo (lo corta el JS) y los
     cambios manuales pasan sin zoom ni barrido. */
  .hero__fondo, .hero__fondo.is-activa { transition: opacity 200ms linear; transform: none; }
  .hero__barrido { display: none; }
  .hero-slide, .hero-vista { transition: opacity 200ms linear, visibility 200ms; transform: none; }
}

/* =============================================================
   37. BESAFE EPP — bloque de marca
   =============================================================
   BeSafe es una marca propia de IntegraTec, no una empresa aparte:
   comparte header, pie y tokens. Lo unico suyo es este lockup, que
   sustituye al eyebrow en la portada de la pagina.
   Cuando exista el logotipo, se cambia el <p> por un <img> y esto
   se puede borrar. */
.besafe-marca {
  display: inline-flex; align-items: center; gap: var(--sp-4);
  margin-bottom: var(--sp-6);
  padding: var(--sp-3) var(--sp-6);
  border: 1px solid var(--deep-line);
  border-radius: var(--r-pill);
  background: var(--deep-hair);
}
.besafe-marca__nombre {
  font-size: var(--fs-h4); font-weight: 400;
  letter-spacing: var(--ls-tight); color: var(--deep-ink);
}
/* "Safe" en naranja: es la mitad que carga el significado */
.besafe-marca__nombre b { font-weight: 800; color: var(--orange); }
.besafe-marca__cola {
  padding-left: var(--sp-4);
  border-left: 1px solid var(--deep-line);
  font-size: var(--fs-micro); font-weight: 600;
  letter-spacing: var(--ls-wide); text-transform: uppercase;
  color: var(--deep-muted);
}
/* Los botones del hero de esta pagina van centrados como el texto */
.pagina-hero .pagina-cta__acciones { justify-content: center; }

@media (max-width: 520px) {
  .besafe-marca { flex-direction: column; gap: var(--sp-2); text-align: center; }
  .besafe-marca__cola { padding-left: 0; border-left: 0; }
}

/* =============================================================
   38. EN ACCIÓN — tira de clips verticales
   =============================================================
   Los videos son grabaciones de celular en 9:16. La tira respeta ese
   formato en vez de recortarlos a apaisado: recortar un vertical a
   16:9 se come justo lo que importa, que está arriba y abajo. */
.clips {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--grid-gap);
  align-items: start;
}
.clip { min-width: 0; }

.clip__marco {
  position: relative;
  aspect-ratio: 9 / 16;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--ink-surface);
  border: 1px solid var(--deep-line);
  transition: border-color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.clip:hover .clip__marco { border-color: var(--celeste); transform: translateY(-4px); }

.clip__poster,
.clip__video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}
.clip__video { border: 0; background: #000; }

/* Botón de play sobre el póster. Cubre toda la tarjeta para que el
   área de toque sea la tarjeta entera, no un círculo de 56px. */
.clip__play {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  width: 100%; padding: 0;
  background: linear-gradient(180deg, rgba(5, 11, 31, 0.10) 0%, rgba(5, 11, 31, 0.55) 100%);
  border: 0; color: #FFFFFF;
  transition: background var(--dur) var(--ease);
}
.clip__play:hover { background: linear-gradient(180deg, rgba(5, 11, 31, 0.24) 0%, rgba(5, 11, 31, 0.70) 100%); }
.clip__play span {
  display: grid; place-items: center;
  width: 56px; height: 56px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.16);
  border: 2px solid rgba(255, 255, 255, 0.75);
  transition: transform var(--dur) var(--ease), background var(--dur) var(--ease);
}
.clip__play:hover span { transform: scale(1.08); background: rgba(56, 189, 248, 0.34); }
.clip__play svg { width: 24px; height: 24px; fill: currentColor; stroke: none; margin-left: 3px; }
/* Con el reproductor dentro, el botón taparía los controles */
.clip.is-playing .clip__play,
.clip.is-playing .clip__poster { display: none; }

.clip__titulo {
  margin-top: var(--sp-4);
  font-size: var(--fs-body); font-weight: 700; color: var(--deep-ink);
}
.clip__texto {
  margin-top: var(--sp-2);
  font-size: var(--fs-micro); line-height: 1.6; color: var(--deep-muted);
}

@media (max-width: 1080px) { .clips { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 720px)  { .clips { grid-template-columns: repeat(2, 1fr); gap: var(--sp-5); } }
@media (max-width: 420px)  { .clips { grid-template-columns: 1fr; max-width: 320px; margin-inline: auto; } }

@media (prefers-reduced-motion: reduce) {
  .clip:hover .clip__marco { transform: none; }
  .clip__play:hover span { transform: none; }
}

/* =============================================================
   39. BESAFE — carrusel de clips en acción
   =============================================================
   Los videos son verticales 9:16, así que la diapositiva los pone a
   la izquierda a su tamaño real y usa el hueco de la derecha para
   contar qué se está viendo. Recortarlos a apaisado para llenar el
   ancho se comería justo lo que importa.
   Reutiliza `.clip__marco`, `.clip__poster` y `.clip__play` de la
   tira de la portada: solo cambia la maquetación. */
.bscar { position: relative; display: flex; align-items: center; gap: var(--sp-4); }
.bscar__viewport { flex: 1; min-width: 0; overflow: hidden; padding-block: 2px; }
.bscar__track {
  display: flex;
  transition: transform 950ms var(--ease-carrusel);
  /* Sin `will-change: transform` a propósito. Permanente mantenía viva
     una capa de composición del ancho de las SIETE diapositivas, y con
     un video decodificando dentro eso deja sin memoria de GPU a los
     equipos justos: la página se congela. La transición ya promociona
     la capa mientras dura, que es lo único que hace falta. */
}
.bscar__slide {
  flex: 0 0 100%;
  display: grid; grid-template-columns: 320px 1fr;
  gap: clamp(24px, 4vw, 56px);
  align-items: center;
}
/* El marco hereda el 9:16 de `.clip__marco`; aquí solo se le pone
   tope de ancho para que no crezca con la pantalla. */
.bscar__slide .clip__marco { width: 100%; box-shadow: var(--shadow-pop); }
/* Con el reproductor dentro, esa sombra de 60px de desenfoque se
   repinta en cada fotograma del video. Mientras se ve, sobra. */
.bscar__slide.is-playing .clip__marco { box-shadow: none; }

.bscar__copia { min-width: 0; }
.bscar__copia .clip__titulo {
  margin-top: var(--sp-2);
  font-size: var(--fs-h3); line-height: var(--lh-heading); color: var(--band-ink);
}
.bscar__texto {
  margin-top: var(--sp-4);
  font-size: var(--fs-body); line-height: 1.7; color: var(--band-muted);
}
/* Sobre banda clara la lista hereda el color de `--deep-muted`, que
   aquí no toca: se corrige al token de la banda. */
.bscar__copia .lista-check li { color: var(--band-muted); }

.bscar__nav {
  flex: none; align-self: center;
  display: grid; place-items: center;
  width: 44px; height: 44px;
  border-radius: 50%;
  background: var(--card);
  border: 1px solid var(--card-line);
  color: var(--band-ink);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
              color var(--dur) var(--ease);
}
.bscar__nav:hover { background: var(--celeste-solid); border-color: var(--celeste-solid); color: #FFFFFF; }
.bscar__nav svg { width: 20px; height: 20px; }

#bs-dots { margin-top: var(--sp-8); }

@media (max-width: 900px) {
  /* Apilado: el clip arriba y el texto debajo, con el video centrado
     y a un ancho que quepa en pantalla. */
  .bscar__slide { grid-template-columns: 1fr; gap: var(--sp-6); justify-items: center; text-align: center; }
  .bscar__slide .clip__marco { width: min(280px, 72vw); }
  .bscar__copia .lista-check { justify-items: center; }
  .bscar__copia .lista-check li { text-align: left; }
  /* Las flechas se solaparían con el video: se navega con los puntos */
  .bscar__nav { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .bscar__track { transition: none; }
}

/* =============================================================
   40. SOPORTE TI — refuerzo visual
   =============================================================
   Extiende la §35. Va aparte y no mezclado con aquella porque son
   dos cosas distintas: allí está la estructura de la página, aquí
   el acabado — jerarquía por número, estados de apertura y los
   movimientos que hacen que la página no parezca una lámina.

   Nada de esto necesita JavaScript: son contadores CSS, estados
   `[open]` del acordeón nativo y `:hover`. El bloque global de
   `prefers-reduced-motion` los apaga todos de una vez. */

/* ---- Portada de la página ---- */
/* Un resplandor por detrás del titular. La red de puntos ya está,
   pero sobre el azul plano el bloque de texto quedaba flotando sin
   suelo. */
.pagina-hero { position: relative; overflow: hidden; }
.pagina-hero::after {
  content: "";
  position: absolute; left: 50%; top: -30%;
  width: min(900px, 130%); aspect-ratio: 1;
  transform: translateX(-50%);
  background: radial-gradient(closest-side, rgba(56, 189, 248, 0.13), transparent 72%);
  pointer-events: none;
  z-index: 0;
}
.pagina-hero > .wrap { position: relative; z-index: 1; }
/* La segunda línea del titular en degradado: parte el bloque en dos
   sin necesidad de otro tamaño de letra. */
.h1__acento {
  background: linear-gradient(96deg, var(--celeste) 0%, var(--orange) 92%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}

/* ---- A quién va dirigido ---- */
.publico { counter-reset: publico; }
.publico__item {
  position: relative;
  overflow: hidden;
  counter-increment: publico;
  transition: transform var(--dur) var(--ease), border-left-color var(--dur) var(--ease),
              background var(--dur) var(--ease);
}
/* Número de agua en la esquina: da orden de lectura a cuatro tarjetas
   que si no se leen como cuatro cosas sueltas. */
.publico__item::before {
  content: "0" counter(publico);
  position: absolute; right: var(--sp-4); bottom: -6px;
  font-size: 44px; font-weight: 800; line-height: 1;
  color: color-mix(in srgb, var(--celeste) 14%, transparent);
  transition: color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.publico__item:hover::before { color: color-mix(in srgb, var(--orange) 26%, transparent); transform: translateY(-3px); }
.publico__item:hover { border-left-width: 3px; background: color-mix(in srgb, var(--celeste) 6%, var(--card)); }
.publico__titulo { position: relative; z-index: 1; }
.publico__texto { position: relative; z-index: 1; }

/* ---- Acordeón ---- */
/* El número va en el ::before del summary, que es contenedor flex: se
   coloca solo delante del icono sin tocar el HTML. */
.acor { counter-reset: alcance; }
.acor__item { counter-increment: alcance; position: relative; }
/* Filete de color que crece por la izquierda al abrir: marca cuál está
   desplegado incluso con la página a media altura. */
.acor__item::before {
  content: "";
  position: absolute; left: 0; top: 0; bottom: 0;
  width: 3px;
  background: linear-gradient(180deg, var(--celeste), var(--orange));
  transform: scaleY(0); transform-origin: 50% 0;
  transition: transform 420ms var(--ease);
}
.acor__item[open]::before { transform: scaleY(1); }

.acor__cab::before {
  content: "0" counter(alcance);
  flex: none;
  font-size: var(--fs-micro); font-weight: 800;
  letter-spacing: var(--ls-wide);
  color: var(--deep-muted);
  transition: color var(--dur) var(--ease);
}
.acor__item[open] .acor__cab::before { color: var(--band-accent); }

/* Al abrir, el icono pasa de fondo tenue a relleno sólido */
.acor__icono { transition: background var(--dur) var(--ease), color var(--dur) var(--ease); }
.acor__item[open] .acor__icono { background: var(--celeste-solid); color: #FFFFFF; }
.acor__item[open] .acor__titulo { color: var(--deep-ink); }

/* Los puntos del panel entran escalonados. Sin esto, setenta ítems
   aparecían de golpe y el bloque se leía como un muro otra vez. */
.acor__item[open] .lista-check > li {
  animation: acorPunto 420ms var(--ease-out-soft) both;
}
.acor__item[open] .lista-check > li:nth-child(1)  { animation-delay: 60ms; }
.acor__item[open] .lista-check > li:nth-child(2)  { animation-delay: 100ms; }
.acor__item[open] .lista-check > li:nth-child(3)  { animation-delay: 140ms; }
.acor__item[open] .lista-check > li:nth-child(4)  { animation-delay: 180ms; }
.acor__item[open] .lista-check > li:nth-child(5)  { animation-delay: 220ms; }
.acor__item[open] .lista-check > li:nth-child(6)  { animation-delay: 260ms; }
.acor__item[open] .lista-check > li:nth-child(7)  { animation-delay: 300ms; }
.acor__item[open] .lista-check > li:nth-child(8)  { animation-delay: 340ms; }
.acor__item[open] .lista-check > li:nth-child(9)  { animation-delay: 380ms; }
.acor__item[open] .lista-check > li:nth-child(n+10) { animation-delay: 420ms; }
@keyframes acorPunto {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
/* El palomeo se dibuja después del texto, como si se fuera marcando */
.acor__item[open] .lista-check > li::before {
  animation: acorCheck 320ms var(--ease) both;
  animation-delay: inherit;
}
@keyframes acorCheck {
  from { opacity: 0; transform: rotate(-45deg) scale(0.4); }
  to   { opacity: 1; transform: rotate(-45deg) scale(1); }
}
/* La foto del panel entra desde la derecha, no a la vez que la lista */
.acor__item[open] .acor__foto { animation: acorFoto 560ms var(--ease-out-soft) 120ms both; }
@keyframes acorFoto {
  from { opacity: 0; transform: translateX(14px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}

/* ---- Contratos ---- */
/* El destacado respira: un halo naranja que sube y baja muy despacio.
   Es la única pieza de la página que se mueve sola, y por eso funciona
   como señal de "este es el que miramos primero". */
.contrato--destacado { animation: contratoHalo 4.5s ease-in-out infinite; }
@keyframes contratoHalo {
  0%, 100% { box-shadow: var(--shadow-pop), 0 0 0 0 color-mix(in srgb, var(--orange) 34%, transparent); }
  50%      { box-shadow: var(--shadow-pop), 0 0 0 10px color-mix(in srgb, var(--orange) 0%, transparent); }
}
/* Filete degradado en el canto superior de las tres */
.contrato::after {
  content: "";
  position: absolute; left: var(--card-pad); right: var(--card-pad); top: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--celeste-solid), transparent);
  opacity: 0; transition: opacity var(--dur) var(--ease);
}
.contrato:hover::after { opacity: 1; }
.contrato--destacado::after { background: linear-gradient(90deg, transparent, var(--orange), transparent); opacity: 0.7; }
/* Los puntos de la línea de tiempo crecen al pasar por la tarjeta */
.contrato__lista li::before { transition: transform var(--dur) var(--ease), background var(--dur) var(--ease); }
.contrato:hover .contrato__lista li::before { transform: scale(1.25); }
.contrato--destacado:hover .contrato__lista li::before { background: var(--orange); }
/* El nombre del plan (7×16) es lo que se compara: que crezca un punto */
.contrato__nombre { transition: transform var(--dur) var(--ease); transform-origin: left center; }
.contrato:hover .contrato__nombre { transform: scale(1.06); }

/* ---- Beneficios ---- */
/* Marco desplazado por detrás de la foto: la despega del fondo sin
   añadir otra sombra encima de la que ya lleva. */
.beneficios__foto { position: relative; }
.beneficios__foto::before {
  content: "";
  position: absolute; inset: 14px -14px -14px 14px;
  border: 1px solid color-mix(in srgb, var(--celeste) 46%, transparent);
  border-radius: var(--r-lg);
  z-index: -1;
  transition: inset var(--dur-slow) var(--ease);
}
.beneficios__foto:hover::before { inset: 20px -20px -20px 20px; }
.beneficios__foto img { display: block; transition: transform var(--dur-slow) var(--ease); }
.beneficios__foto:hover img { transform: scale(1.03); }

/* ---- Rasgos de la mesa de ayuda ---- */
.rasgos { counter-reset: rasgo; }
.rasgo { position: relative; overflow: hidden; counter-increment: rasgo; }
.rasgo::before {
  content: "0" counter(rasgo);
  position: absolute; right: -4px; top: -14px;
  font-size: 68px; font-weight: 800; line-height: 1;
  color: color-mix(in srgb, var(--celeste) 12%, transparent);
  transition: color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.rasgo:hover::before { color: color-mix(in srgb, var(--celeste) 22%, transparent); transform: translateY(4px); }
.rasgo__titulo, .rasgo__texto { position: relative; z-index: 1; }
/* Barra que se llena de izquierda a derecha al pasar por encima */
.rasgo::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--celeste-solid), var(--orange));
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform var(--dur-slow) var(--ease);
}
.rasgo:hover::after { transform: scaleX(1); }

@media (max-width: 720px) {
  /* Los números de agua compiten con el texto cuando la tarjeta se
     estrecha: se quedan, pero más discretos. */
  .publico__item::before { font-size: 34px; }
  .rasgo::before { font-size: 52px; }
}

@media (prefers-reduced-motion: reduce) {
  .contrato--destacado { animation: none !important; }
  .acor__item::before, .rasgo::after { transition: none; }
}

/* =============================================================
   41. COVERFLOW — piezas de redes y clips en acción
   =============================================================
   Una fila con la pieza del centro grande y las vecinas detrás, más
   pequeñas y apagadas. Lo comparten dos secciones:

     .pubcar   nueve flyers cuadrados (1080×1080)
     .clipcar  cinco clips verticales (9:16)

   Lo único que cambia entre las dos es el tamaño de la tarjeta, y va
   en `--cw` / `--ch`. La posición de cada una la calcula el JS y la
   escribe con `style.setProperty` (el CSSOM no lo controla la CSP).

   Por qué coverflow y no rejilla: en rejilla, N piezas del mismo
   tamaño con N titulares distintos compiten entre sí y no se lee
   ninguna. Aquí solo hay una que mirar y las demás dan profundidad. */
.cover {
  position: relative;
  display: flex; align-items: center; gap: var(--sp-4);
  margin-top: var(--sp-10);
}
.cover__escena {
  position: relative;
  flex: 1; min-width: 0;
  height: var(--ch);
  /* Las vecinas se salen por los lados a propósito: es lo que da la
     sensación de que la fila sigue. */
  overflow: hidden;
}
.cover__pista { position: absolute; inset: 0; }

/* La tarjeta: las dos secciones traen la suya (`.flyer`, `.clip`) y
   aquí solo se les da sitio y movimiento. */
.cover__pista > * {
  position: absolute; top: 0; left: 50%;
  width: var(--cw); height: var(--ch);
  margin-left: calc(var(--cw) / -2);
  border-radius: var(--r-md);
  overflow: hidden;
  border: 1px solid var(--deep-line);
  background: var(--deep-card);
  cursor: pointer;
  /* `transform`, `filter` y `opacity` los escribe el JS por tarjeta */
  transition: transform 620ms var(--ease-carrusel),
              filter 620ms var(--ease),
              opacity 620ms var(--ease),
              box-shadow var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
}
/* La del centro: a plena luz, con filo y sombra que la despegan */
.cover__pista > .is-activa {
  border-color: var(--celeste);
  box-shadow: var(--shadow-pop), 0 0 0 1px color-mix(in srgb, var(--celeste) 45%, transparent);
}
.cover__pista > *:focus-visible { outline: 3px solid var(--celeste); outline-offset: 3px; }

/* ---- Flechas ---- */
.cover__nav {
  flex: none;
  display: grid; place-items: center;
  width: 44px; height: 44px;
  border-radius: 50%;
  background: var(--deep-card);
  border: 1px solid var(--deep-line);
  color: var(--deep-ink);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease);
  z-index: 20;
}
.cover__nav:hover { background: var(--celeste-solid); border-color: var(--celeste-solid); color: #FFFFFF; }
.cover__nav svg { width: 20px; height: 20px; }

/* ---- Pie y mando ----
   El texto va DEBAJO y no sobre la pieza: los flyers ya traen su
   titular impreso y el clip está en marcha; superponerles otro texto
   es leer dos cosas a la vez. */
.cover__pie {
  display: grid; gap: 2px;
  margin-top: var(--sp-8);
  text-align: center;
  min-height: 3.2em;   /* el alto no baila al cambiar de pieza */
}
.cover__pie b { font-size: var(--fs-h4); font-weight: 700; color: var(--deep-ink); }
.cover__pie i { font-size: var(--fs-small); font-style: normal; color: var(--celeste); }

.cover__mando {
  display: flex; align-items: center; justify-content: center;
  gap: var(--sp-5);
  margin-top: var(--sp-6);
}

/* ---- Tamaños: piezas de redes (cuadradas) ---- */
/* Fluido y no por saltos: la pieza es el contenido, así que ocupa lo
   que la pantalla dé. El tope de 620px es lo que da el original de
   1080px sin escalarlo de más, y el `62vh` evita que en un portátil de
   pantalla baja haya que hacer scroll para ver un cuadrado. */
.pubcar { --cw: clamp(250px, min(38vw, 62vh), 620px); --ch: var(--cw); }

/* ---- Tamaños: clips (verticales 9:16) ---- */
/* Aquí manda la altura: un 9:16 crece a lo alto tres veces más rápido
   de lo que crece a lo ancho, y lo que se acaba antes es la pantalla. */
.clipcar {
  --ch: clamp(340px, min(52vw, 62vh), 620px);
  --cw: calc(var(--ch) * 9 / 16);
}

/* El marco del clip ya no pinta borde ni fondo: lo pone la tarjeta */
.clipcar .clip__marco {
  position: absolute; inset: 0;
  aspect-ratio: auto;
  border: 0; border-radius: 0;
}
/* El botón de play solo responde en la del centro; en las vecinas, el
   clic lo recoge la tarjeta para traerlas al centro. */
.cover__pista > :not(.is-activa) .clip__play { pointer-events: none; }

@media (max-width: 620px) {
  .cover { gap: var(--sp-2); }
  .cover__nav { width: 38px; height: 38px; }
}

@media (prefers-reduced-motion: reduce) {
  .cover__pista > * { transition: none; }
}

/* =============================================================
   42. NORMATIVAS — cinta de logotipos
   =============================================================
   Sustituye a las doce pastillas de texto. Un logotipo se reconoce
   de un vistazo y una palabra hay que leerla; en una sección que
   solo dice "con esto trabajamos", eso es toda la diferencia.

   Tres a la vista y corre sola. El ancho de la ventana se calcula a
   partir del de la pieza (3 piezas + 2 huecos), así que **siempre
   entran tres exactas**: si en vez de eso se repartiera el ancho
   disponible, en cada pantalla se vería un número distinto y
   asomarían mitades por los lados.

   La cinta es de CSS puro: el JS solo duplica la lista una vez y
   engancha el botón de pausa. */
.normas { --ancho: clamp(104px, 13vw, 168px); }

.normas__viewport {
  width: calc(var(--ancho) * 3 + var(--sp-4) * 2);
  max-width: 100%;
  overflow: hidden;
  /* Se desvanece por los bordes: sin esto, las piezas aparecen y
     desaparecen de golpe contra el corte y se ve el truco. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}

.normas__track {
  display: flex;
  gap: var(--sp-4);
  width: max-content;
  padding: 0; margin: 0;
  list-style: none;
  /* -50% es exactamente una copia de la lista: por eso el JS la
     duplica. Con cualquier otro valor la cinta daría un salto al
     reiniciar el ciclo. */
  animation: normasCorre 34s linear infinite;
}
@keyframes normasCorre {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}
/* Pausa: a mano con el botón, y al pasar el cursor por encima para
   poder mirar un logotipo sin perseguirlo. */
.normas.is-quieta .normas__track,
.normas__viewport:hover .normas__track { animation-play-state: paused; }

.norma {
  flex: none;
  width: var(--ancho); height: 92px;
  /* Flex y no rejilla: en rejilla la fila se dimensiona por el
     contenido, el alto en porcentaje de la imagen se resolvía contra
     ella misma —circular— y el navegador lo daba por `auto`. Los
     logos cuadrados salían a 118px dentro de un panel de 92. En flex
     el contenedor tiene alto fijo, así que el porcentaje es firme. */
  display: flex; align-items: center; justify-content: center;
  padding: var(--sp-3) var(--sp-4);
  /* Blanco puro, y no el `--logo-panel` del muro de clientes: ocho de
     los diez logotipos vienen con **fondo blanco opaco** —no recortado—,
     así que sobre el #EEF3F9 del panel se veía el recuadro blanco de
     cada imagen dentro del recuadro del panel. Con blanco detrás, el
     fondo de la imagen y el del panel son el mismo color y desaparece
     el corte. (El de AWS venía en 247,250,255 y está normalizado.) */
  background: #FFFFFF;
  border-radius: var(--r-sm);
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.norma:hover { transform: translateY(-3px); box-shadow: var(--shadow-pop); }
.norma img {
  max-width: 100%; max-height: 100%;
  width: auto; height: auto;
  object-fit: contain;
}
/* El sello ISO es un SVG macizo pensado para ir en blanco sobre
   oscuro; en el panel claro hay que devolverlo a tinta. */
.norma__iso { filter: brightness(0) saturate(100%) invert(12%) sepia(18%) saturate(1800%) hue-rotate(184deg); }

.normas__pausa { margin-top: var(--sp-5); }

@media (max-width: 900px) {
  .normas { --ancho: clamp(96px, 26vw, 150px); }
}

@media (prefers-reduced-motion: reduce) {
  /* Quieta y en rejilla: si no puede correr, al menos que se vean
     todas en vez de tres sueltas. */
  .normas__viewport { width: 100%; -webkit-mask-image: none; mask-image: none; }
  .normas__track { animation: none; flex-wrap: wrap; width: 100%; }
}

/* =============================================================
   43. FONDOS DE SECCIÓN
   =============================================================
   La página tenía dos fondos para diez secciones: `--deep` plano seis
   veces y `--band` plano tres. Al bajar, todo parecía la misma franja
   repetida y se perdía la sensación de avanzar.

   Cuatro texturas, repartidas para que **dos secciones seguidas nunca
   lleven la misma**, y ninguna toca a las que ya tenían efecto propio
   (soluciones con sus anillos, demos, el muro de clientes).

   Reglas que cumplen las cuatro:
   · van en un `<span>` decorativo, primer hijo de la sección, con
     `aria-hidden` — no son contenido;
   · solo animan `transform` y `opacity`, nunca `background-position`
     ni `filter`, que repintan en cada fotograma;
   · duraciones largas (20-60 s) y opacidades bajas: si se nota el
     movimiento mirando el texto, está mal calibrado;
   · el bloque global de `prefers-reduced-motion` las deja quietas. */
.fondo {
  position: absolute; inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}
/* El contenido, por encima del fondo. `.soluciones` ya lo hacía por su
   cuenta; esto lo generaliza a todas. */
.section > .wrap { position: relative; z-index: 1; }

/* ---- 1. Aurora: dos manchas que derivan ----
   La textura más neutra, para secciones con mucho texto. */
.fondo--aurora::before,
.fondo--aurora::after {
  content: "";
  position: absolute;
  width: clamp(420px, 52vw, 900px); aspect-ratio: 1;
  border-radius: 50%;
  will-change: transform;
}
.fondo--aurora::before {
  top: -22%; left: -12%;
  background: radial-gradient(closest-side, rgba(56, 189, 248, 0.16), transparent 72%);
  animation: auroraA 34s ease-in-out infinite alternate;
}
.fondo--aurora::after {
  bottom: -28%; right: -10%;
  background: radial-gradient(closest-side, rgba(246, 163, 49, 0.13), transparent 72%);
  animation: auroraB 44s ease-in-out infinite alternate;
}
/* Variante cálida: la misma deriva con los colores cambiados de sitio */
.fondo--aurora-calida::before { background: radial-gradient(closest-side, rgba(246, 163, 49, 0.15), transparent 72%); }
.fondo--aurora-calida::after  { background: radial-gradient(closest-side, rgba(139, 92, 246, 0.14), transparent 72%); }
/* Variante discreta para el formulario: la mitad de intensidad */
.fondo--aurora-tenue::before { background: radial-gradient(closest-side, rgba(56, 189, 248, 0.09), transparent 72%); }
.fondo--aurora-tenue::after  { background: radial-gradient(closest-side, rgba(246, 163, 49, 0.07), transparent 72%); }

@keyframes auroraA {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(14%, 10%, 0) scale(1.18); }
}
@keyframes auroraB {
  from { transform: translate3d(0, 0, 0) scale(1.1); }
  to   { transform: translate3d(-12%, -8%, 0) scale(0.92); }
}

/* ---- 2. Rejilla técnica que deriva ----
   Un plano cuadriculado que se desplaza una casilla y vuelve a
   empezar: como el desplazamiento es exactamente el tamaño de la
   casilla, el bucle no tiene costura. */
.fondo--rejilla::before {
  content: "";
  position: absolute; inset: -10%;
  background-image:
    linear-gradient(rgba(56, 189, 248, 0.055) 1px, transparent 1px),
    linear-gradient(90deg, rgba(56, 189, 248, 0.055) 1px, transparent 1px);
  background-size: 68px 68px;
  /* Se desvanece hacia los bordes para que no se vea dónde acaba */
  -webkit-mask-image: radial-gradient(closest-side at 50% 45%, #000 20%, transparent 92%);
  mask-image: radial-gradient(closest-side at 50% 45%, #000 20%, transparent 92%);
  animation: rejillaDeriva 26s linear infinite;
  will-change: transform;
}
@keyframes rejillaDeriva {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-68px, -68px, 0); }
}

/* ---- 3. Trazos diagonales ----
   Filetes finos en diagonal, muy separados, corriendo despacio. Da
   sensación de movimiento sin dibujar nada reconocible. */
.fondo--trazos::before {
  content: "";
  position: absolute; inset: -30% -10%;
  background-image: repeating-linear-gradient(
    114deg,
    transparent 0 78px,
    rgba(56, 189, 248, 0.07) 78px 79px,
    transparent 79px 158px,
    rgba(246, 163, 49, 0.05) 158px 159px);
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 22%, #000 78%, transparent);
  mask-image: linear-gradient(180deg, transparent, #000 22%, #000 78%, transparent);
  animation: trazosCorren 38s linear infinite;
  will-change: transform;
}
@keyframes trazosCorren {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(158px, -78px, 0); }
}

/* ---- 4. Barrido ----
   Una banda ancha y tenue que baja despacio, como el haz de un
   escáner. Es la única que se mueve en una sola dirección, así que se
   reserva para una sección: repetida, cansa. */
.fondo--barrido::before {
  content: "";
  position: absolute; left: 0; right: 0; height: 46%;
  top: -46%;
  background: linear-gradient(180deg, transparent, rgba(56, 189, 248, 0.10), transparent);
  animation: barridoBaja 17s linear infinite;
  will-change: transform;
}
@keyframes barridoBaja {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(0, 320%, 0); }
}

/* En pantallas pequeñas las manchas ocupan media pantalla y compiten
   con el texto: se bajan de intensidad. */
@media (max-width: 720px) {
  .fondo--aurora::before, .fondo--aurora::after { opacity: 0.6; }
  .fondo--trazos::before { opacity: 0.7; }
}

@media (prefers-reduced-motion: reduce) {
  /* Quietas, no invisibles: la textura sigue diferenciando la sección,
     que es la mitad del trabajo que hacen. */
  .fondo--aurora::before, .fondo--aurora::after,
  .fondo--rejilla::before, .fondo--trazos::before { animation: none !important; }
  /* El barrido sí desaparece: parado a media altura es una banda rara
     cruzando la sección. */
  .fondo--barrido::before { display: none; }
}

/* ---- Refuerzo: que se vean, sin robarle el sitio al texto ----
   La primera pasada quedó tan discreta que no cumplía su función:
   diferenciar una sección de la siguiente. Se sube presencia con tres
   recursos, y ninguno pinta sobre la columna de texto. */

/* 1. Tercera mancha en la aurora, a contratiempo de las otras dos.
      Con dos, el vaivén se leía como un péndulo; con tres y duraciones
      sin múltiplo común, el movimiento deja de tener patrón. */
.fondo--aurora { --a1: rgba(56, 189, 248, 0.22); --a2: rgba(246, 163, 49, 0.17); --a3: rgba(139, 92, 246, 0.14); }
.fondo--aurora-calida { --a1: rgba(246, 163, 49, 0.20); --a2: rgba(139, 92, 246, 0.17); --a3: rgba(56, 189, 248, 0.13); }
.fondo--aurora-tenue  { --a1: rgba(56, 189, 248, 0.12); --a2: rgba(246, 163, 49, 0.09); --a3: rgba(139, 92, 246, 0.07); }

.fondo--aurora::before { background: radial-gradient(closest-side, var(--a1), transparent 72%); }
.fondo--aurora::after  { background: radial-gradient(closest-side, var(--a2), transparent 72%); }

.fondo__mancha {
  position: absolute;
  width: clamp(360px, 44vw, 760px); aspect-ratio: 1;
  top: 34%; left: 46%;
  border-radius: 50%;
  background: radial-gradient(closest-side, var(--a3), transparent 72%);
  animation: auroraC 52s ease-in-out infinite alternate;
  will-change: transform;
}
@keyframes auroraC {
  from { transform: translate3d(-8%, 6%, 0) scale(0.9); }
  to   { transform: translate3d(10%, -10%, 0) scale(1.22); }
}

/* 2. Un pulso que recorre la rejilla, como un dato viajando por el
      plano. Es lo que convierte una cuadrícula quieta en algo vivo. */
.fondo--rejilla .fondo__pulso {
  position: absolute; inset: 0;
  background: radial-gradient(240px 240px at 0% 50%, rgba(56, 189, 248, 0.18), transparent 70%);
  animation: pulsoCruza 14s ease-in-out infinite;
  will-change: transform, opacity;
}
@keyframes pulsoCruza {
  0%        { transform: translate3d(-10%, 0, 0); opacity: 0; }
  12%, 68%  { opacity: 1; }
  100%      { transform: translate3d(96%, 0, 0); opacity: 0; }
}

/* 3. Costura superior: un filete degradado que marca dónde empieza
      cada sección con fondo propio. Sin él, las texturas se funden
      unas con otras al pasar y el cambio no se lee. */
.section:has(> .fondo)::before {
  content: "";
  position: absolute; left: 0; right: 0; top: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--celeste) 55%, transparent) 20%, color-mix(in srgb, var(--orange) 45%, transparent) 80%, transparent);
  opacity: 0.5;
  z-index: 1;
  pointer-events: none;
}

/* Trazos y barrido, un punto más presentes */
.fondo--trazos::before {
  background-image: repeating-linear-gradient(
    114deg,
    transparent 0 78px,
    rgba(56, 189, 248, 0.11) 78px 80px,
    transparent 80px 158px,
    rgba(246, 163, 49, 0.08) 158px 160px);
}
.fondo--barrido::before {
  background: linear-gradient(180deg, transparent, rgba(56, 189, 248, 0.16), transparent);
}

@media (prefers-reduced-motion: reduce) {
  .fondo__mancha { animation: none !important; }
  /* El pulso parado es una mancha pegada al borde izquierdo: fuera. */
  .fondo__pulso { display: none; }
}

/* ---- 5. Circuito con datos viajando ----
   La única textura que dibuja algo reconocible, y por eso va en una
   sola sección: repetida dejaría de ser una firma y pasaría a ser un
   patrón de fondo más.

   Dos capas sobre las mismas trayectorias: las pistas, fijas y muy
   tenues, y encima un trazo corto y brillante que las recorre. El
   truco es `stroke-dasharray` con un hueco enorme —un guion de 90px y
   1600px de vacío—, así solo se ve un segmento moviéndose. */
.fondo--circuito { overflow: hidden; }
/* Dos clases: `svg[viewBox] { width: 100% }` de la base le gana a una
   sola y el dibujo se quedaba sin alto. */
.fondo--circuito .fondo__svg {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  /* Se desvanece arriba y abajo para que no choque con el borde de la
     sección ni con el titular. */
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 26%, #000 74%, transparent);
  mask-image: linear-gradient(180deg, transparent, #000 26%, #000 74%, transparent);
}

.circuito__pistas path {
  fill: none;
  stroke: rgba(56, 189, 248, 0.16);
  stroke-width: 1.5;
  stroke-linejoin: round;
}

.circuito__chispas path {
  fill: none;
  stroke: var(--celeste);
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  /* 90px de trazo y 1600 de hueco: por la pista solo circula un
     segmento corto, no una línea que se dibuja entera. */
  stroke-dasharray: 90 1600;
  filter: drop-shadow(0 0 6px rgba(56, 189, 248, 0.85));
  animation: chispaCorre 9s linear infinite;
  will-change: stroke-dashoffset;
}
/* Cada una a su ritmo y con su retardo: si salen a la vez, se lee como
   una cortina bajando y no como tráfico por la placa. */
.circuito__chispas .chispa--1 { animation-duration: 8.5s;  animation-delay: 0s; }
.circuito__chispas .chispa--2 { animation-duration: 11s;   animation-delay: -3.5s; stroke: var(--orange); filter: drop-shadow(0 0 6px rgba(246, 163, 49, 0.8)); }
.circuito__chispas .chispa--3 { animation-duration: 9.5s;  animation-delay: -6s; }
.circuito__chispas .chispa--4 { animation-duration: 12.5s; animation-delay: -1.5s; stroke: var(--orange); filter: drop-shadow(0 0 6px rgba(246, 163, 49, 0.8)); }
.circuito__chispas .chispa--5 { animation-duration: 10s;   animation-delay: -4.5s; }

@keyframes chispaCorre {
  from { stroke-dashoffset: 1690; }
  to   { stroke-dashoffset: 0; }
}

/* Los nodos de la placa laten muy despacio */
.circuito__nodos circle {
  fill: rgba(56, 189, 248, 0.5);
  animation: nodoLate 4.5s ease-in-out infinite;
}
.circuito__nodos circle:nth-child(2n)  { animation-delay: -1.4s; fill: rgba(246, 163, 49, 0.45); }
.circuito__nodos circle:nth-child(3n)  { animation-delay: -2.8s; }
@keyframes nodoLate {
  0%, 100% { opacity: 0.35; r: 3; }
  50%      { opacity: 1;    r: 5; }
}

@media (max-width: 720px) {
  /* En móvil el dibujo queda muy recortado y solo se ven dos pistas:
     se baja para que no compita con el carrusel. */
  .fondo--circuito .fondo__svg { opacity: 0.55; }
}

@media (prefers-reduced-motion: reduce) {
  /* Las pistas se quedan —dan la textura—, el tráfico no. */
  .circuito__chispas, .circuito__nodos { display: none; }
}

/* Trampa antispam del formulario. Fuera de la pantalla y no con
   `display: none`: un robot que lea el HTML descarta lo que está
   oculto, pero rellena lo que "existe". Para quien usa lector de
   pantalla el campo está marcado con `aria-hidden` y fuera del
   tabulador, así que no se lo encuentra. */
.miel {
  position: absolute;
  left: -9999px;
  width: 1px; height: 1px;
  overflow: hidden;
}
