/* ═══════════════════════════════════════════════════════════════════════
   Webynd Smart — web pública (marketing_site)
   Sistema de diseño "AURORA". Sin frameworks, sin librerías de animación.

   Tokens de marca: --brand-primary/--brand/--brand-dark/--ink los inyecta
   base.html desde BrandingSettings; aquí solo hay fallbacks y derivados.

   La idea: lienzo CLARO y abierto. En vez de un bloque navy que parte la
   página en dos, una malla de luz (aurora) que respira detrás del contenido
   y tarjetas blancas que flotan sobre ella. El navy se reserva para el texto
   y para un único ancla al pie.
   Firma visual: la línea de pulso (ECG) del logo — hero, footer y eyebrows.
   ═══════════════════════════════════════════════════════════════════════ */

:root {
  /* ── Marca (la inyecta el CMS; esto son fallbacks) ───────────────────── */
  --ink: #071317;
  --brand: #0f766e;
  --brand-dark: #115e59;
  --brand-primary: #071317;

  /* ── Aurora: la familia de luces ────────────────────────────────────────
     Tres luces frías y una cálida. Las frías se mezclan en los fondos; la
     cálida aparece POCAS veces a propósito (badge del plan recomendado) —
     si el coral sale tres veces por página deja de ser un acento.
     --au-1 se DERIVA del color del CMS: si el gimnasio cambia su marca, la
     aurora entera cambia con ella en vez de quedarse con nuestro teal. */
  --au-1: color-mix(in srgb, var(--brand) 55%, #35e8c8);   /* teal luminoso */
  --au-2: #7b6bff;                                          /* violeta */
  --au-3: #a8f04a;                                          /* lima */
  --au-4: #ff8a5b;                                          /* coral (raro) */
  --au-4-text: #3a1405;   /* texto sobre el coral: 10.8:1 */
  --pulse: var(--au-1);

  /* Degradados de marca reutilizables: un solo sitio donde tocarlos. */
  --grad-brand: linear-gradient(112deg, var(--brand) 0%, var(--au-2) 100%);
  --grad-aurora: linear-gradient(112deg, var(--au-1) 0%, var(--au-2) 52%, var(--au-3) 100%);
  /* Degradado SOLO para texto (titular, cifras, precio). Va separado de
     --grad-brand porque tiran en direcciones opuestas: sobre fondo oscuro el
     texto tiene que ACLARARSE para llegar a contraste, mientras que el fondo
     del botón primario tiene que seguir siendo oscuro para que su texto
     blanco siga leyéndose. Un solo token no puede hacer las dos cosas. */
  --grad-text: var(--grad-brand);

  /* ── Lienzo ─────────────────────────────────────────────────────────── */
  --paper: #fbfaff;        /* blanco con un susurro de violeta */
  --paper-2: #f3f4fb;      /* bandas alternas */
  --surface: #ffffff;
  --surface-glass: rgb(255 255 255 / 0.72);
  --line: #e8e7f3;
  --line-strong: #d7d5e8;
  --muted: #5a6373;
  /* 4.59:1 sobre --paper. El #8b93a1 de la versión anterior daba 2.9:1 y
     fallaba WCAG AA en .form-note, .legal-meta y .logos-title (texto < 18px
     → exige 4.5:1). No aclarar estos dos sin recomprobar el contraste. */
  --muted-2: #667085;

  /* --ink hace dos trabajos: color del texto y navy de los paneles oscuros
     (pie, algún panel). Van separados porque en modo oscuro el texto se
     aclara mientras el navy sigue siendo navy. */
  --text: var(--ink);
  /* El teal de marca sobre fondo claro sí llega a AA; sobre oscuro no, por
     eso --brand-text se recalcula en el bloque oscuro. */
  --brand-text: var(--brand);

  /* ── Sombras teñidas ────────────────────────────────────────────────────
     Una sombra negra sobre un lienzo de color lo ensucia. Estas llevan el
     azul-violeta de la aurora dentro, así que la tarjeta parece apoyada en
     la luz de la página y no recortada sobre ella. */
  --shadow-xs: 0 1px 2px rgb(28 26 74 / 0.05);
  --shadow-card: 0 1px 2px rgb(28 26 74 / 0.04), 0 14px 38px -20px rgb(28 26 74 / 0.20);
  --shadow-pop: 0 2px 8px rgb(28 26 74 / 0.06), 0 32px 70px -28px rgb(28 26 74 / 0.32);
  --shadow-float: 0 40px 90px -40px rgb(28 26 74 / 0.42), 0 12px 30px -18px rgb(28 26 74 / 0.22);
  --glow-brand: 0 12px 34px -14px color-mix(in srgb, var(--brand) 62%, transparent);

  /* ── Tipografía ─────────────────────────────────────────────────────── */
  --font-display: "Bricolage Grotesque", "Inter", system-ui, sans-serif;
  --font-body: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;

  /* ── Forma y ritmo ──────────────────────────────────────────────────────
     Radios más generosos que antes: el radio grande es lo que separa un
     "panel de administración" de una web de producto. */
  --r-xs: 8px;
  --r-sm: 14px;
  --r-md: 20px;
  --r-lg: 28px;
  --r-xl: 40px;
  --r-pill: 999px;
  --sp-section: clamp(5rem, 10vw, 8rem);
  --container: 1180px;

  /* ── Movimiento ─────────────────────────────────────────────────────────
     Curvas propias: las nativas (ease, ease-out) son demasiado flojas.
     Nunca ease-in en UI: retrasa el arranque justo donde se mira.
     --ease-spring es un muelle de verdad (linear() con puntos): pasa un pelín
     de largo y vuelve, que es lo que hace que un hover "se sienta" en vez de
     solo verse. Navegador sin linear() → cae a la curva por defecto. */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
  --ease-spring: linear(
    0, 0.0067 1.7%, 0.0265 3.5%, 0.1013 7.2%, 0.2211 11%, 0.3745 15%, 0.5462 19.1%,
    0.7204 23.3%, 0.8828 27.7%, 1.0208 32.4%, 1.0817 35%, 1.1272 37.7%, 1.1567 40.6%,
    1.1699 43.7%, 1.1667 46.1%, 1.153 48.7%, 1.0977 55%, 1.0483 61.5%, 1.0148 68.8%,
    0.9979 76.9%, 0.9952 87%, 1
  );
  --d-fast: 160ms;
  --d-mid: 280ms;
  --d-slow: 480ms;

  --nav-bg: rgb(255 255 255 / 0.7);
  --nav-bg-scrolled: rgb(255 255 255 / 0.86);
  --danger-bg: #fef2f2;
  --danger-line: #fecaca;
  --danger-text: #b91c1c;
}

/* ── Modo oscuro ──────────────────────────────────────────────────────────
   Sigue la preferencia del sistema, pero el visitante puede forzarlo con el
   conmutador de la cabecera (data-theme en <html>, recordado en localStorage).
   Los neutros se giran a un navy azulado; la aurora se mantiene (más apagada)
   para que hero, CTA y pie se lean como los mismos paneles en ambos modos.

   OJO: las variables van DUPLICADAS (media query + [data-theme="dark"]) porque
   CSS no permite envolver un selector de atributo en la media query. Si tocas
   un valor, tócalo en los dos sitios. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper: #0b1020;
    --paper-2: #10162a;
    --surface: #151b2e;
    --surface-glass: rgb(21 27 46 / 0.72);
    --line: #262e47;
    --line-strong: #35405e;
    --text: #e9ebf4;
    --muted: #9aa4b8;      /* 7.2:1 sobre --paper */
    --muted-2: #7c869c;    /* 5.0:1 sobre --paper */
    --brand-text: color-mix(in srgb, var(--brand) 50%, #ffffff);
    --au-1: color-mix(in srgb, var(--brand) 40%, #4df0d2);
    /* Sobre el navy el teal de marca se queda en 3,2:1 — justo en el filo de
       AA para texto grande. Aclarado llega holgado y el titular deja de
       depender de que nadie mire el contraste. */
    --grad-text: linear-gradient(112deg, var(--brand-text) 0%, #a79bff 100%);

    --nav-bg: rgb(11 16 32 / 0.72);
    --nav-bg-scrolled: rgb(11 16 32 / 0.9);
    --danger-bg: #2a1417;
    --danger-line: #5c2027;
    --danger-text: #fca5a5;

    /* Sobre fondo oscuro una sombra negra no se ve: la elevación la da el
       borde, así que las sombras se suavizan y se apoyan en él. */
    --shadow-xs: 0 1px 2px rgb(0 0 0 / 0.3);
    --shadow-card: 0 1px 2px rgb(0 0 0 / 0.3), 0 14px 38px -20px rgb(0 0 0 / 0.6);
    --shadow-pop: 0 2px 8px rgb(0 0 0 / 0.36), 0 32px 70px -28px rgb(0 0 0 / 0.72);
    --shadow-float: 0 40px 90px -40px rgb(0 0 0 / 0.8), 0 12px 30px -18px rgb(0 0 0 / 0.5);
  }
  /* Las fotos a todo color deslumbran sobre un lienzo oscuro. */
  :root:not([data-theme="light"]) .imagetext-grid .media img,
  :root:not([data-theme="light"]) .feature-card .feature-img { filter: brightness(0.88); }
}
:root[data-theme="dark"] {
  --paper: #0b1020;
  --paper-2: #10162a;
  --surface: #151b2e;
  --surface-glass: rgb(21 27 46 / 0.72);
  --line: #262e47;
  --line-strong: #35405e;
  --text: #e9ebf4;
  --muted: #9aa4b8;
  --muted-2: #7c869c;
  --brand-text: color-mix(in srgb, var(--brand) 50%, #ffffff);
  --au-1: color-mix(in srgb, var(--brand) 40%, #4df0d2);
  --grad-text: linear-gradient(112deg, var(--brand-text) 0%, #a79bff 100%);

  --nav-bg: rgb(11 16 32 / 0.72);
  --nav-bg-scrolled: rgb(11 16 32 / 0.9);
  --danger-bg: #2a1417;
  --danger-line: #5c2027;
  --danger-text: #fca5a5;

  --shadow-xs: 0 1px 2px rgb(0 0 0 / 0.3);
  --shadow-card: 0 1px 2px rgb(0 0 0 / 0.3), 0 14px 38px -20px rgb(0 0 0 / 0.6);
  --shadow-pop: 0 2px 8px rgb(0 0 0 / 0.36), 0 32px 70px -28px rgb(0 0 0 / 0.72);
  --shadow-float: 0 40px 90px -40px rgb(0 0 0 / 0.8), 0 12px 30px -18px rgb(0 0 0 / 0.5);
}
:root[data-theme="dark"] .imagetext-grid .media img,
:root[data-theme="dark"] .feature-card .feature-img { filter: brightness(0.88); }

/* Conmutador de tema: sol/luna en la cabecera */
.theme-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 50%;
  border: 1px solid var(--line); background: transparent;
  color: var(--muted); cursor: pointer;
  transition: color var(--d-fast) ease, border-color var(--d-fast) ease,
              background var(--d-fast) ease, transform var(--d-mid) var(--ease-spring);
}
.theme-toggle:hover { color: var(--text); border-color: var(--line-strong); background: color-mix(in srgb, var(--brand) 7%, transparent); }
.theme-toggle:active { transform: scale(0.9); }
.theme-toggle svg { width: 18px; height: 18px; transition: transform var(--d-slow) var(--ease-spring); }
.theme-toggle:hover svg { transform: rotate(25deg); }
/* Se muestra el icono del modo al que SALTARÍAS, no del actual */
.theme-toggle .icon-sun { display: none; }
.theme-toggle .icon-moon { display: block; }
:root[data-theme="dark"] .theme-toggle .icon-sun { display: block; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .icon-sun { display: block; }
  :root:not([data-theme="light"]) .theme-toggle .icon-moon { display: none; }
}

/* Cambiar de tema no debe disparar 200 transiciones a la vez */
:root[data-theme-switching] * { transition: none !important; }

/* ── Base ─────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.65;
  color: var(--text);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  /* Sin esto, el hero a sangre y las auroras desbordadas sacan barra
     horizontal en móvil. `clip` en vez de `hidden` para no romper el
     position:sticky de la navbar. */
  overflow-x: clip;
}
img { max-width: 100%; height: auto; display: block; }
a { color: inherit; }
h1, h2, h3, h4 { font-family: var(--font-display); line-height: 1.08; letter-spacing: -0.025em; margin: 0; }
p { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }
button { font: inherit; }
::selection { background: color-mix(in srgb, var(--au-2) 28%, transparent); }
:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; border-radius: 4px; }

.container-x { max-width: var(--container); margin-inline: auto; padding-inline: 1.5rem; }

/* Salto al contenido: obligatorio para navegación por teclado. Oculto hasta
   que recibe foco, entonces aterriza sobre la navbar. */
.skip-link {
  position: fixed;
  top: 0.75rem;
  left: 50%;
  z-index: 100;
  transform: translate(-50%, calc(-100% - 1rem));
  padding: 0.7rem 1.3rem;
  border-radius: var(--r-pill);
  background: var(--ink);
  color: #fff;
  font-size: 0.9rem;
  font-weight: 600;
  text-decoration: none;
  transition: transform var(--d-mid) var(--ease-spring);
}
.skip-link:focus-visible { transform: translate(-50%, 0); }

/* ── AURORA: el campo de luz ──────────────────────────────────────────────
   Cuatro manchas de color desenfocadas que se mueven muy despacio detrás del
   contenido. Es lo que sustituye al bloque navy del hero anterior.

   Rendimiento: cada mancha es un div propio animado SOLO con transform (va a
   GPU). Con `background-position` sobre un único elemento el navegador
   repinta el degradado entero en cada frame y el hero baja de 60 fps en
   portátiles modestos. `filter: blur()` se declara una vez y no se anima.
   contain:strict aísla el repintado del resto de la página. */
.aurora {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
  contain: strict;
}
/* Las manchas viven en las ESQUINAS y desbordan hacia fuera. Si se cruzan por
   el centro dejan de ser luz y pasan a ser un fondo degradado: el papel
   desaparece y con él la sensación de web abierta. El centro tiene que
   quedar casi blanco — de eso se encarga además el velo de .hero::before. */
.aurora span {
  position: absolute;
  display: block;
  border-radius: 50%;
  filter: blur(96px);
  opacity: 0.3;
  will-change: transform;
}
.aurora .a1 { width: 40rem; height: 26rem; top: -13rem; left: -15rem; background: var(--au-1); }
.aurora .a2 { width: 34rem; height: 24rem; top: -12rem; right: -13rem; background: var(--au-2); opacity: 0.24; }
.aurora .a3 { width: 26rem; height: 20rem; bottom: -13rem; left: 26%; background: var(--au-3); opacity: 0.14; }
.aurora .a4 { width: 24rem; height: 19rem; bottom: -12rem; right: 2%; background: var(--brand); opacity: 0.16; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .aurora span { opacity: 0.26; filter: blur(104px); }
  :root:not([data-theme="light"]) .aurora .a3 { opacity: 0.1; }
}
:root[data-theme="dark"] .aurora span { opacity: 0.26; filter: blur(104px); }
:root[data-theme="dark"] .aurora .a3 { opacity: 0.1; }

/* En móvil las manchas están medidas en rem y no encogen con la pantalla: a
   390 px cubrían el hero entero y volvía el problema del "fondo degradado".
   Aquí se recortan y se bajan para que el papel siga siendo el protagonista. */
@media (max-width: 640px) {
  .aurora span { filter: blur(64px); opacity: 0.22; }
  .aurora .a1 { width: 22rem; height: 15rem; top: -7rem; left: -8rem; }
  .aurora .a2 { width: 19rem; height: 14rem; top: -6rem; right: -7rem; opacity: 0.18; }
  .aurora .a3 { width: 15rem; height: 12rem; bottom: -7rem; left: 20%; opacity: 0.1; }
  .aurora .a4 { width: 14rem; height: 11rem; bottom: -6rem; right: -3rem; opacity: 0.12; }
  .aurora::after { background-size: 44px 44px; }
}

/* La respiración. Cada mancha con su duración y su sentido: si comparten
   ciclo la malla entera "late" a la vez y se nota que es una animación. */
@media (prefers-reduced-motion: no-preference) {
  .aurora .a1 { animation: aurora-drift-a 26s var(--ease-in-out) infinite alternate; }
  .aurora .a2 { animation: aurora-drift-b 32s var(--ease-in-out) infinite alternate; }
  .aurora .a3 { animation: aurora-drift-c 38s var(--ease-in-out) infinite alternate; }
  .aurora .a4 { animation: aurora-drift-b 29s var(--ease-in-out) infinite alternate-reverse; }
}
@keyframes aurora-drift-a { to { transform: translate3d(9%, 6%, 0) scale(1.14); } }
@keyframes aurora-drift-b { to { transform: translate3d(-8%, 9%, 0) scale(1.1); } }
@keyframes aurora-drift-c { to { transform: translate3d(12%, -7%, 0) scale(0.92); } }

/* Rejilla técnica finísima sobre la aurora: le da escala y "producto" a la
   nube de color, que sola se queda en fondo de pantalla. Se desvanece hacia
   abajo para no competir con el texto. */
.aurora::after {
  content: "";
  position: absolute; inset: 0;
  background-image:
    linear-gradient(to right, color-mix(in srgb, var(--text) 7%, transparent) 1px, transparent 1px),
    linear-gradient(to bottom, color-mix(in srgb, var(--text) 7%, transparent) 1px, transparent 1px);
  background-size: 64px 64px;
  opacity: 0.7;
  -webkit-mask-image: radial-gradient(80% 55% at 50% 0%, #000 0%, transparent 70%);
  mask-image: radial-gradient(80% 55% at 50% 0%, #000 0%, transparent 70%);
}

/* Páginas sin hero (contacto, legal, blog, artículo, comparativa) — un lavado
   de aurora en la cabecera para que no parezcan de otra web. Es decorativo,
   así que se puede colgar de :has(): donde no esté soportado simplemente no
   se pinta y la página sigue perfecta. */
main:not(:has(.hero)) {
  position: relative;
  isolation: isolate;
}
main:not(:has(.hero))::before {
  content: "";
  position: absolute; inset: 0 0 auto 0; height: 34rem;
  z-index: -1; pointer-events: none;
  background:
    radial-gradient(38rem 20rem at 8% -6rem, color-mix(in srgb, var(--au-1) 26%, transparent), transparent 70%),
    radial-gradient(34rem 18rem at 96% -4rem, color-mix(in srgb, var(--au-2) 20%, transparent), transparent 70%);
  -webkit-mask-image: linear-gradient(#000 0%, transparent 85%);
  mask-image: linear-gradient(#000 0%, transparent 85%);
}

/* ── Tipografía utilitaria ────────────────────────────────────────────── */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--brand-text);
}
/* Glifo de pulso delante de cada eyebrow — la firma en miniatura */
.eyebrow::before {
  content: "";
  width: 26px;
  height: 12px;
  flex: none;
  background-color: currentColor;
  -webkit-mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 12" fill="none"><path d="M0 6h6l3-5 4 10 3-5h10" stroke="black" stroke-width="1.8" fill="none" stroke-linejoin="round" stroke-linecap="round"/></svg>') no-repeat center / contain;
  mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 12" fill="none"><path d="M0 6h6l3-5 4 10 3-5h10" stroke="black" stroke-width="1.8" fill="none" stroke-linejoin="round" stroke-linecap="round"/></svg>') no-repeat center / contain;
}

/* Píldora de anuncio del hero ("Nuevo · lo que sea"). Vidrio sobre la aurora
   con un punto que late: es el único elemento que se mueve en bucle arriba,
   y por eso lleva la mirada al titular. */
.pill {
  display: inline-flex; align-items: center; gap: 0.6rem;
  padding: 0.4rem 0.95rem 0.4rem 0.6rem;
  border-radius: var(--r-pill);
  background: var(--surface-glass);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid color-mix(in srgb, var(--brand) 22%, var(--line));
  box-shadow: var(--shadow-xs);
  font-size: 0.8rem; font-weight: 600; color: var(--text);
  text-decoration: none;
  transition: transform var(--d-mid) var(--ease-spring), box-shadow var(--d-mid) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  a.pill:hover { transform: translateY(-2px); box-shadow: var(--shadow-card); }
}
.pill .dot {
  width: 8px; height: 8px; border-radius: 50%; flex: none;
  background: var(--brand); position: relative;
}
.pill .dot::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  background: inherit;
}
@media (prefers-reduced-motion: no-preference) {
  .pill .dot::after { animation: dot-ping 2.4s var(--ease-out) infinite; }
  @keyframes dot-ping {
    0% { transform: scale(1); opacity: 0.7; }
    70%, 100% { transform: scale(3.2); opacity: 0; }
  }
}
.pill em { font-style: normal; color: var(--muted); font-weight: 500; }

/* Palabra en degradado dentro de un titular. Solo UNA por titular: dos ya no
   destacan nada. */
.grad-text {
  background: var(--grad-text);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  /* Sin esto las colas de la "g" o la "y" se recortan al hacer clip. */
  padding-bottom: 0.08em;
}

/* Alineado a la izquierda por defecto: centrar TODAS las secciones es lo que
   hace que la página se lea como plantilla. El centro se reserva para donde
   de verdad ayuda (precios, FAQ, CTA) mediante .section-head--center. */
.section-head { max-width: 46rem; margin: 0 0 3.2rem; position: relative; }
.section-head--center { margin-inline: auto; text-align: center; }
.section-head h2 { font-size: clamp(1.9rem, 3.8vw, 2.75rem); font-weight: 700; text-wrap: balance; }
.section-head .lead { margin-top: 1rem; color: var(--muted); font-size: 1.06rem; text-wrap: pretty; }
.section { padding-block: var(--sp-section); position: relative; }
/* Bandas alternas SIN filete: el borde duro corta la página; un degradado
   difumina el cambio de fondo y la página se lee como un continuo. */
.section.tinted { background: var(--paper-2); }
.section.tinted::before, .section.tinted::after {
  content: ""; position: absolute; left: 0; right: 0; height: 4rem; pointer-events: none;
}
.section.tinted::before { top: 0; background: linear-gradient(var(--paper), transparent); }
.section.tinted::after { bottom: 0; background: linear-gradient(transparent, var(--paper)); }
/* Los hijos se quedarían por detrás del degradado de la banda. */
.section.tinted > * { position: relative; z-index: 1; }

/* ── Botones ──────────────────────────────────────────────────────────── */
.btn-primary, .btn-secondary, .btn-light {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.9rem 1.7rem;
  border-radius: var(--r-pill);
  font-weight: 650;
  font-size: 0.95rem;
  text-decoration: none;
  border: 1px solid transparent;
  transition: transform var(--d-mid) var(--ease-spring),
              box-shadow var(--d-mid) var(--ease-out),
              background var(--d-fast) ease, border-color var(--d-fast) ease, color var(--d-fast) ease;
  cursor: pointer;
}
/* Primario: degradado de marca. El degradado NO se puede animar entre dos
   valores, así que el hover mueve background-position sobre un degradado del
   doble de ancho — mismo efecto, y sí es interpolable. */
.btn-primary {
  background: var(--grad-brand);
  background-size: 180% 100%;
  background-position: 0% 50%;
  color: #fff;
  box-shadow: var(--glow-brand);
}
.btn-secondary {
  background: var(--surface-glass);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: var(--text);
  border-color: var(--line-strong);
}
.btn-light { background: #fff; color: var(--ink); }

/* El hover solo se declara en punteros finos: en táctil el :hover se queda
   "pegado" tras el tap y el botón se ve levantado hasta que tocas otra cosa. */
@media (hover: hover) and (pointer: fine) {
  .btn-primary:hover {
    background-position: 100% 50%;
    transform: translateY(-2px);
    box-shadow: 0 18px 40px -14px color-mix(in srgb, var(--brand) 70%, transparent);
  }
  .btn-secondary:hover { border-color: color-mix(in srgb, var(--brand) 45%, var(--line-strong)); color: var(--brand-text); transform: translateY(-2px); }
  .btn-light:hover { transform: translateY(-2px); box-shadow: 0 16px 34px -16px rgb(0 0 0 / 0.5); }
}
/* Feedback de pulsación: confirma que la interfaz oyó el clic. Sí aplica en táctil. */
.btn-primary:active, .btn-secondary:active, .btn-light:active { transform: scale(0.96); }

/* Flecha que avanza al pasar por encima: microseñal de "esto te lleva a otro
   sitio". Va en el botón que la plantilla marque con .btn-arrow. */
.btn-arrow::after {
  content: "→";
  font-size: 1.05em; line-height: 1;
  transition: transform var(--d-mid) var(--ease-spring);
}
@media (hover: hover) and (pointer: fine) {
  .btn-arrow:hover::after { transform: translateX(4px); }
}

/* ── Botón magnético ──────────────────────────────────────────────────────
   site.js escribe --magnet-x/--magnet-y (desplazamiento hacia el cursor) en
   los elementos con data-magnetic; aquí se COMPONEN con el levantamiento del
   hover y el hundido del :active.
   La especificidad importa: `.btn-primary:hover` es (0,2,0) y machacaría a
   `[data-magnetic]:hover` (0,1,1). Por eso el selector lleva clase + atributo
   + pseudoclase, (0,3,0), y gana. */
.btn-primary[data-magnetic], .btn-secondary[data-magnetic], .btn-light[data-magnetic] {
  transform: translate(var(--magnet-x, 0px), var(--magnet-y, 0px));
}
@media (hover: hover) and (pointer: fine) {
  .btn-primary[data-magnetic]:hover,
  .btn-secondary[data-magnetic]:hover,
  .btn-light[data-magnetic]:hover {
    transform: translate(var(--magnet-x, 0px), calc(var(--magnet-y, 0px) - 2px));
  }
}
.btn-primary[data-magnetic]:active,
.btn-secondary[data-magnetic]:active,
.btn-light[data-magnetic]:active {
  transform: translate(var(--magnet-x, 0px), var(--magnet-y, 0px)) scale(0.96);
}

/* ── Brillo que sigue al cursor ───────────────────────────────────────────
   site.js escribe --mx/--my (posición del puntero dentro del elemento) y
   --spot (0/1 para fundir la entrada y salida). Solo en punteros finos: en
   táctil no hay cursor que seguir y sería peso muerto.

   El brillo va en ::before y NO en ::after a propósito: ::after es de la
   flecha de .btn-arrow, y un elemento solo tiene un ::after. Cuando los dos
   competían ganaba el brillo (declarado después) con su content:"" y la
   flecha no aparecía nunca. */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .btn-primary, .btn-light { overflow: hidden; isolation: isolate; }
  .btn-primary::before, .btn-light::before {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    border-radius: inherit;
    opacity: var(--spot, 0);
    transition: opacity var(--d-mid) var(--ease-out);
    background: radial-gradient(
      12rem circle at var(--mx, 50%) var(--my, 50%),
      rgb(255 255 255 / 0.32),
      transparent 45%
    );
    mix-blend-mode: soft-light;
  }
  /* Sobre superficies claras el soft-light blanco no se ve: se invierte. */
  .btn-light::before {
    background: radial-gradient(
      14rem circle at var(--mx, 50%) var(--my, 50%),
      color-mix(in srgb, var(--brand) 22%, transparent),
      transparent 50%
    );
    mix-blend-mode: normal;
  }
}
/* Estado en curso tras enviar un formulario. */
.btn-primary:disabled, .btn-secondary:disabled, .btn-light:disabled {
  opacity: 0.62; cursor: progress; transform: none; box-shadow: none;
}

/* ── Navbar ───────────────────────────────────────────────────────────────
   Al bajar se encoge y se convierte en una píldora flotante centrada. Da la
   sensación de que la interfaz reacciona a ti, y de paso devuelve ancho de
   pantalla al contenido. */
.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--nav-bg);
  backdrop-filter: blur(16px) saturate(150%);
  -webkit-backdrop-filter: blur(16px) saturate(150%);
  border-bottom: 1px solid transparent;
  transition: border-color var(--d-mid) ease, background var(--d-mid) ease;
}
.nav.is-scrolled { border-bottom-color: var(--line); background: var(--nav-bg-scrolled); box-shadow: var(--shadow-xs); }
@media (min-width: 900px) {
  .nav-inner {
    transition: max-width var(--d-slow) var(--ease-out),
                padding var(--d-slow) var(--ease-out),
                border-radius var(--d-slow) var(--ease-out),
                background var(--d-slow) ease, box-shadow var(--d-slow) ease;
    border-radius: 0;
    /* Transparente pero PRESENTE: el estado de píldora lleva borde de 1px y
       sin esta reserva la barra crecería 2 px al encogerse. */
    border: 1px solid transparent;
  }
  .nav.is-scrolled { background: transparent; border-bottom-color: transparent; box-shadow: none; }
  /* El hueco alrededor de la píldora se pone con padding en .nav y NO con
     margin en .nav-inner: el margen superior del hijo se COLAPSABA hacia
     fuera (la barra no tiene ni padding ni borde arriba que lo frene) y la
     navbar perdía 4,8 px de alto justo al empezar a bajar — con ella, todo
     el contenido de debajo daba un salto.
     El padding de .nav (0.3) más el de .nav-inner (0.55) suman exactamente
     el 0.85rem del estado normal, así que el alto no cambia. */
  .nav { transition: border-color var(--d-mid) ease, background var(--d-mid) ease, padding var(--d-slow) var(--ease-out); }
  .nav.is-scrolled { padding-block: 0.3rem; }
  .nav.is-scrolled .nav-inner {
    max-width: 62rem;
    padding-block: 0.55rem;
    padding-inline: 1.1rem;
    border-radius: var(--r-pill);
    background: var(--nav-bg-scrolled);
    box-shadow: var(--shadow-card);
    border: 1px solid var(--line);
  }
}
.nav-inner { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding-block: 0.85rem; }
.nav-logo { display: flex; align-items: center; gap: 0.6rem; font-family: var(--font-display); font-weight: 700; font-size: 1.1rem; text-decoration: none; }
.nav-logo .mark {
  width: 36px; height: 36px; border-radius: 11px;
  display: grid; place-items: center; color: #fff; background: var(--grad-brand);
  font-size: 1rem;
  transition: transform var(--d-slow) var(--ease-spring);
}
@media (hover: hover) and (pointer: fine) {
  .nav-logo:hover .mark { transform: rotate(-8deg) scale(1.08); }
}
.nav-logo img, .footer .brand-line img { height: 38px; width: auto; }
.nav-links { display: none; align-items: center; gap: 1.9rem; font-size: 0.92rem; font-weight: 550; color: var(--muted); }
.nav-links a { text-decoration: none; padding-block: 0.4rem; position: relative; transition: color var(--d-fast) ease; }
/* scaleX en lugar de animar `right`: `right` recalcula layout en cada frame,
   scaleX va a GPU. Mismo resultado visual, sin repintado. */
.nav-links a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0;
  height: 2px; border-radius: 2px; background: var(--grad-brand);
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--d-mid) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .nav-links a:hover { color: var(--text); }
  .nav-links a:hover::after { transform: scaleX(1); }
}
/* Página actual: sin esto el usuario no sabe dónde está. */
.nav-links a[aria-current="page"] { color: var(--text); }
.nav-links a[aria-current="page"]::after { transform: scaleX(1); }
.nav-mobile a[aria-current="page"] { color: var(--brand-text); }
.nav-actions { display: flex; align-items: center; gap: 0.9rem; }
.nav-login { display: none; font-size: 0.92rem; font-weight: 550; color: var(--muted); text-decoration: none; transition: color var(--d-fast) ease; }
.nav-login:hover { color: var(--text); }
/* nowrap: "Prueba gratis" se partía en dos líneas dentro de la píldora en
   pantallas de 390 px y el botón crecía hasta empujar al burger. */
.nav-cta { padding: 0.62rem 1.3rem; font-size: 0.9rem; white-space: nowrap; }
@media (max-width: 480px) {
  .nav-actions { gap: 0.45rem; }
  .nav-cta { padding: 0.55rem 0.9rem; font-size: 0.82rem; }
  .theme-toggle { width: 34px; height: 34px; }
  .theme-toggle svg { width: 16px; height: 16px; }
  .nav-burger { width: 38px; height: 38px; }
}
.nav-burger {
  display: grid; place-items: center; width: 42px; height: 42px;
  border: 1px solid var(--line); border-radius: 13px; background: var(--surface); cursor: pointer;
  transition: transform var(--d-mid) var(--ease-spring), border-color var(--d-fast) ease;
}
.nav-burger:active { transform: scale(0.92); }
.nav-burger svg { width: 20px; height: 20px; }
/* Despliegue animado con grid 0fr→1fr (la altura es desconocida y `height:auto`
   no es animable). visibility oculta los enlaces del orden de tabulación. */
.nav-mobile {
  display: grid;
  grid-template-rows: 0fr;
  visibility: hidden;
  background: var(--surface);
  border-top: 1px solid transparent;
  transition: grid-template-rows var(--d-slow) var(--ease-out), visibility var(--d-slow), border-color var(--d-slow) ease;
}
.nav-mobile > .nav-mobile-inner { overflow: hidden; }
.nav-mobile.is-open { grid-template-rows: 1fr; visibility: visible; border-top-color: var(--line); }
.nav-mobile a { display: block; padding: 0.9rem 1.5rem; text-decoration: none; font-weight: 550; border-bottom: 1px solid var(--paper); }
/* Los enlaces caen en cascada al abrir: el menú deja de "aparecer" y pasa a
   "desplegarse". --i lo pone site.js según la posición. */
@media (prefers-reduced-motion: no-preference) {
  .nav-mobile.is-open a { animation: menu-in var(--d-slow) var(--ease-out) backwards; animation-delay: calc(var(--i, 0) * 45ms); }
  @keyframes menu-in { from { opacity: 0; transform: translateX(-14px); } }
}
@media (min-width: 900px) {
  .nav-links { display: flex; }
  .nav-login { display: inline; }
  .nav-burger { display: none; }
  .nav-mobile { display: none !important; }
}

/* ── HERO — campo de aurora sobre lienzo claro ────────────────────────────
   Antes era un bloque navy a sangre. El navy daba empaque pero cerraba la
   página: lo primero que veías era una pared oscura. Ahora la primera
   pantalla es luz, el texto va en tinta y el color lo pone la aurora. */
.hero {
  position: relative;
  isolation: isolate;
  background: var(--paper);
  color: var(--text);
}
/* Velo de papel. Hace dos cosas a la vez y por eso va en un solo
   pseudoelemento (uno menos que pintar):
   1. Devuelve el blanco al centro-izquierda, que es donde va el titular. Sin
      esto la aurora cubre el hero entero y deja de leerse como luz sobre
      papel para parecer un fondo de pantalla degradado.
   2. Funde el filo de abajo con el resto de la página.
   Va en ::after (último hijo) para pintarse POR ENCIMA de .aurora, que
   comparte z-index; .container-x sube a z-index 1 y queda por encima de los
   dos. */
.hero::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(62% 58% at 26% 46%, var(--paper) 0%, color-mix(in srgb, var(--paper) 55%, transparent) 44%, transparent 72%),
    linear-gradient(to bottom, transparent 60%, var(--paper) 100%);
}
.hero > .container-x { position: relative; z-index: 1; }
.hero-grid {
  display: grid;
  gap: 3.4rem;
  align-items: center;
  /* Menos aire abajo que arriba: el degradado de .hero::after ya añade unos
     100 px de respiración visual antes de la sección siguiente, y sumado a un
     padding simétrico dejaba una franja vacía que parecía un fallo. */
  padding-block: clamp(3.5rem, 8vw, 6rem) clamp(3rem, 6vw, 4.5rem);
}
@media (min-width: 980px) { .hero-grid.has-mockup { grid-template-columns: 1.02fr 0.98fr; } }
.hero-title {
  font-size: clamp(2.6rem, 6.2vw, 4.3rem);
  font-weight: 700;
  letter-spacing: -0.035em;
  margin-top: 1.3rem;
  /* 13ch partía cualquier titular español en 3-4 líneas y 17ch se quedó
     corto al subir el cuerpo de la tipografía (un titular de 32 caracteres
     se iba a 3 líneas). 20ch mantiene los titulares normales en 2 líneas,
     que es el techo para que el hero quepa sin hacer scroll. */
  max-width: 20ch;
  text-wrap: balance;
}
.hero-sub { margin-top: 1.5rem; font-size: 1.14rem; line-height: 1.7; color: var(--muted); max-width: 34rem; text-wrap: pretty; }
.hero-ctas { margin-top: 2.3rem; display: flex; flex-wrap: wrap; gap: 0.8rem; }
/* En móvil los dos botones no caben en una línea y quedaban escalonados con
   anchos distintos, como si se hubieran roto. A ancho completo se leen como
   una decisión y además ganan área de toque. */
@media (max-width: 480px) {
  .hero-ctas > .btn-primary, .hero-ctas > .btn-secondary { flex: 1 1 100%; }
}

/* Fila de confianza bajo los botones: quita el miedo justo donde se decide
   ("¿me van a pedir la tarjeta?"). */
.hero-trust {
  margin-top: 1.6rem; display: flex; flex-wrap: wrap; gap: 0.5rem 1.4rem;
  font-size: 0.83rem; color: var(--muted-2);
}
.hero-trust span { display: inline-flex; align-items: center; gap: 0.4rem; }
.hero-trust svg { width: 15px; height: 15px; color: var(--brand-text); flex: none; }

/* Con foto de fondo el texto en tinta se pierde: la imagen se rebaja y se
   cubre con un velo del color del papel. Se resuelve sin :has() para que
   funcione también en navegadores viejos. */
.hero-bgimg { position: absolute; inset: 0; z-index: 0; }
.hero-bgimg img { width: 100%; height: 100%; object-fit: cover; opacity: 0.16; }
.hero-bgimg::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(100deg, var(--paper) 22%, color-mix(in srgb, var(--paper) 72%, transparent) 70%, transparent 100%);
}

/* ── Entrada del hero: escalonada ─────────────────────────────────────────
   Cada hijo lleva --i (0..5) desde la plantilla y entra 60 ms después del
   anterior. Se hace en CSS y no en JS para que no dependa de que el script
   haya cargado: el hero es lo primero que se ve. */
@media (prefers-reduced-motion: no-preference) {
  .hero-copy > * {
    animation: hero-in 0.6s var(--ease-out) backwards;
    animation-delay: calc(var(--i, 0) * 60ms);
  }
  @keyframes hero-in {
    from { opacity: 0; transform: translateY(12px); }
    to { opacity: 1; transform: none; }
  }

  /* Titular palabra a palabra. site.js envuelve cada palabra en <span class="w">
     y numera --w; si el JS no llega, el titular se ve entero y quieto (el
     estado por defecto es visible, nunca opacity:0 sin animación).
     Se anima el <span> interior y no la palabra: así el overflow:clip del
     contenedor recorta el desplazamiento y las palabras "suben desde debajo
     de la línea" en vez de aparecer flotando. */
  /* El padding+margen negativo deja sitio a los rabos de la "g" y la "y":
     con overflow:clip a ras de línea base se los comía. */
  .hero-title .w {
    display: inline-block;
    overflow: clip;
    padding-bottom: 0.16em;
    margin-bottom: -0.16em;
  }
  .hero-title .w > * {
    display: inline-block;
    animation: word-up 0.75s var(--ease-out) backwards;
    animation-delay: calc(140ms + var(--w, 0) * 55ms);
  }
  /* Con el titular partido en palabras, el fundido del bloque entero sobra:
     se verían las dos animaciones a la vez. Si site.js no llega, esta regla
     tampoco se aplica y el titular usa el fundido de bloque de siempre. */
  html.js .hero-title { animation: none; }
  @keyframes word-up {
    from { opacity: 0; transform: translateY(0.9em) rotate(2deg); }
    to { opacity: 1; transform: none; }
  }
}

/* La línea de pulso que se dibuja bajo el titular */
.pulse-line { margin-top: 1.6rem; width: min(340px, 70%); height: 34px; overflow: visible; }
.pulse-line path {
  fill: none;
  stroke: var(--brand);
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 620;
  stroke-dashoffset: 620;
  animation: pulse-draw 1.4s cubic-bezier(0.65, 0, 0.35, 1) 0.45s forwards;
  filter: drop-shadow(0 0 8px color-mix(in srgb, var(--brand) 45%, transparent));
}
.pulse-line circle {
  fill: var(--brand);
  opacity: 0;
  animation: pulse-beat 2.4s ease-in-out 1.85s infinite;
  filter: drop-shadow(0 0 9px color-mix(in srgb, var(--brand) 75%, transparent));
}
@keyframes pulse-draw { to { stroke-dashoffset: 0; } }
@keyframes pulse-beat {
  0%, 100% { opacity: 0.95; transform: scale(1); transform-origin: center; transform-box: fill-box; }
  50% { opacity: 0.45; transform: scale(0.62); transform-origin: center; transform-box: fill-box; }
}
/* Sin movimiento la línea nunca se dibujaría y el hero quedaría cojo. */
@media (prefers-reduced-motion: reduce) {
  .pulse-line path { stroke-dashoffset: 0; animation: none; }
  .pulse-line circle { opacity: 0.95; animation: none; }
}

/* ── La captura del producto, flotando ────────────────────────────────────
   Marco de vidrio + sombra teñida + halo de aurora detrás. Lo que convierte
   una captura pegada en "la app". */
.hero-mockup { position: relative; perspective: 1400px; }
.hero-mockup::before {
  content: ""; position: absolute; inset: -12%;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--au-2) 30%, transparent), transparent 72%);
  filter: blur(46px);
  z-index: -1;
}
.hero-mockup img {
  position: relative;
  width: 100%;
  border-radius: var(--r-lg);
  border: 1px solid color-mix(in srgb, var(--text) 8%, transparent);
  box-shadow: var(--shadow-float);
  /* --tx/--ty los escribe site.js siguiendo el ratón (paralaje suave). El
     rotate fijo da el escorzo; el translate es el que se mueve. */
  transform: perspective(1400px) rotateY(calc(var(--tx, 0) * -1deg)) rotateX(calc(var(--ty, 0) * 1deg));
  transition: transform var(--d-slow) var(--ease-out);
}
/* Reflejo de vidrio sobre la captura: una banda diagonal muy tenue. */
.hero-mockup::after {
  content: ""; position: absolute; inset: 0; border-radius: var(--r-lg);
  background: linear-gradient(115deg, rgb(255 255 255 / 0.28) 0%, transparent 38%);
  pointer-events: none;
}

/* ── Stats — cifras con contador ──────────────────────────────────────────
   Banda propia: sueltas sobre el papel, las cifras se leían como un hueco
   entre secciones en lugar de como una sección. */
.stats-band { background: var(--surface); border-block: 1px solid var(--line); position: relative; overflow: hidden; }
/* Un hilo de aurora cruzando la banda: la ata al resto de la página. */
.stats-band::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(60rem 12rem at 15% 120%, color-mix(in srgb, var(--au-1) 22%, transparent), transparent 70%),
              radial-gradient(50rem 12rem at 88% -20%, color-mix(in srgb, var(--au-2) 16%, transparent), transparent 70%);
}
.stats-band > * { position: relative; }
.stats-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 2.2rem 0; }
@media (min-width: 780px) { .stats-grid { grid-template-columns: repeat(4, 1fr); } }
.stats-grid > * { padding-inline: 1.4rem; }
.stats-grid > *:first-child { padding-inline-start: 0; }
/* Filetes verticales en vez de tarjetas: separan sin encajonar. */
.stats-grid > * + * { border-inline-start: 1px solid var(--line); }
@media (max-width: 779px) { .stats-grid > *:nth-child(odd) { border-inline-start: 0; padding-inline-start: 0; } }
.stat-value {
  font-family: var(--font-display);
  font-size: clamp(2.1rem, 4.2vw, 3rem);
  font-weight: 700;
  letter-spacing: -0.03em;
  background: var(--grad-text);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  /* Tabular: sin esto el contador "baila" de ancho mientras sube y arrastra
     la etiqueta de debajo. */
  font-variant-numeric: tabular-nums;
}
.stat-label { margin-top: 0.5rem; font-size: 0.88rem; color: var(--muted); max-width: 15rem; text-wrap: pretty; }

/* ── Features — bento con ritmo, no seis cajas idénticas ──────────────── */
.features-grid { display: grid; gap: 1.15rem; }
@media (min-width: 640px) { .features-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) {
  .features-grid { grid-template-columns: repeat(3, 1fr); }
  /* Bento: la primera celda ocupa dos columnas SOLO si el total es 3n+1
     (4, 7, 10…), que es cuando la rejilla cuadra sin dejar huecos.
     `:first-child:nth-last-child(3n+1)` = "soy el primero y quedan 3n detrás". */
  .features-grid > .feature-card:first-child:nth-last-child(3n + 1) { grid-column: span 2; }
}
.feature-card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 1.8rem;
  transition: transform var(--d-mid) var(--ease-out), box-shadow var(--d-mid) var(--ease-out), border-color var(--d-mid) ease;
}
/* Variación de fondo: una rejilla de tarjetas blancas idénticas es el layout
   más genérico que existe. La primera se lleva la aurora, la quinta un tinte
   de marca. Ojo: ahora en CLARO, no en navy — es lo que abre la sección. */
.feature-card:first-child {
  background:
    radial-gradient(26rem 18rem at 88% -25%, color-mix(in srgb, var(--au-2) 26%, transparent), transparent 62%),
    radial-gradient(22rem 16rem at 0% 120%, color-mix(in srgb, var(--au-1) 30%, transparent), transparent 60%),
    var(--surface);
  border-color: color-mix(in srgb, var(--brand) 22%, var(--line));
}
/* La quinta va en violeta y no en lima: el lima sobre blanco tira a amarillo
   y la tarjeta parecía marcada por un aviso en lugar de por ritmo visual. */
.feature-card:nth-child(5) { background: color-mix(in srgb, var(--au-2) 6%, var(--surface)); border-color: color-mix(in srgb, var(--au-2) 26%, var(--line)); }

/* Borde-foco: el borde se ilumina bajo el cursor. --mx/--my los escribe site.js. */
.feature-card::before {
  content: "";
  position: absolute; inset: -1px;
  border-radius: inherit;
  padding: 1px;
  background: radial-gradient(14rem 14rem at var(--mx, 50%) var(--my, 0%), color-mix(in srgb, var(--brand) 75%, transparent), transparent 70%);
  -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;
  transition: opacity var(--d-mid) ease;
  pointer-events: none;
}
@media (hover: hover) and (pointer: fine) {
  .feature-card:hover { transform: translateY(-5px); box-shadow: var(--shadow-card); }
  .feature-card:hover::before { opacity: 1; }
  .feature-card:hover .feature-icon { transform: rotate(-6deg) scale(1.06); }
}
.feature-icon {
  width: 54px; height: 54px; border-radius: 17px;
  display: grid; place-items: center; font-size: 1.6rem;
  background: color-mix(in srgb, var(--brand) 10%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--brand) 20%, var(--surface));
  color: var(--brand-text);
  margin-bottom: 1.1rem;
  transition: transform var(--d-slow) var(--ease-spring);
}
.feature-card h3 { font-size: 1.14rem; font-weight: 650; margin-bottom: 0.45rem; }
.feature-card p { font-size: 0.92rem; color: var(--muted); text-wrap: pretty; }
.feature-card .feature-img { border-radius: var(--r-md); margin-bottom: 1rem; width: 100%; height: 11rem; object-fit: cover; }

/* ── Imagen + texto ───────────────────────────────────────────────────── */
.imagetext-grid { display: grid; gap: 3rem; align-items: center; }
@media (min-width: 980px) { .imagetext-grid { grid-template-columns: 1fr 1fr; } }
.imagetext-grid .media { position: relative; }
/* Halo de aurora detrás de la imagen: la despega del papel sin marco duro. */
.imagetext-grid .media::before {
  content: ""; position: absolute; inset: -8%;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--au-1) 26%, transparent), transparent 72%);
  filter: blur(38px); z-index: 0;
}
.imagetext-grid .media img {
  position: relative; z-index: 1;
  border-radius: var(--r-lg); border: 1px solid var(--line);
  box-shadow: var(--shadow-pop); width: 100%;
}
.imagetext-grid h2 { font-size: clamp(1.8rem, 3.4vw, 2.4rem); font-weight: 700; }
.imagetext-body { margin-top: 1.2rem; color: var(--muted); }
.imagetext-body p { margin-block: 0.6rem; }
.imagetext-body a { color: var(--brand-text); }
/* El orden del DOM ya es copy → media, o sea imagen a la DERECHA. La clase
   solo hace falta para el caso contrario.
   (Antes existía .order-media-right, que ponía media:2 / copy:1 — exactamente
   el orden que ya tenían: el interruptor "imagen a la derecha" del CMS no
   movía nada. Ahora la clase se aplica cuando está DESmarcado y sí alterna.) */
@media (min-width: 980px) {
  .order-media-left .media { order: 1; }
  .order-media-left .copy { order: 2; }
}

/* ── Logo cloud ───────────────────────────────────────────────────────── */
.logos { padding-block: 3.2rem; }
.logos-title { font-size: 0.72rem; letter-spacing: 0.18em; text-transform: uppercase; font-weight: 700; color: var(--muted-2); margin-bottom: 1.6rem; }
/* Marquee: cinco logos sueltos y centrados se leían como un hueco. En
   movimiento constante dan sensación de volumen de clientes. Uno por página. */
.logos-marquee {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
}
.logos-track { display: flex; width: max-content; animation: logos-scroll 40s linear infinite; }
.logos-row { display: flex; align-items: center; gap: 3.4rem; padding-inline: 1.7rem; }
@keyframes logos-scroll { to { transform: translateX(-50%); } }
@media (hover: hover) and (pointer: fine) {
  /* Se detiene al pasar por encima: el usuario quiere leer un logo concreto. */
  .logos-marquee:hover .logos-track { animation-play-state: paused; }
}
@media (prefers-reduced-motion: reduce) {
  .logos-track { animation: none; width: 100%; justify-content: center; flex-wrap: wrap; }
  .logos-track > .logos-row + .logos-row { display: none; }
  .logos-row { flex-wrap: wrap; justify-content: center; gap: 2.4rem 3.4rem; }
  .logos-marquee { -webkit-mask-image: none; mask-image: none; }
}
.logos-row img { height: 2.1rem; width: auto; filter: grayscale(1); opacity: 0.55; transition: filter var(--d-mid) ease, opacity var(--d-mid) ease, transform var(--d-mid) var(--ease-spring); }
/* En táctil no hay hover real: los logos se quedarían en gris permanente
   tras el primer tap, así que ahí se muestran ya a color. */
@media (hover: hover) and (pointer: fine) {
  .logos-row img:hover { filter: none; opacity: 1; transform: scale(1.08); }
}
@media (hover: none) {
  .logos-row img { filter: grayscale(0.65); opacity: 0.78; }
}

/* ── Testimonios ──────────────────────────────────────────────────────── */
/* Dos columnas, no tres: con tres se repetía la misma familia de layout que
   features y precios. La primera cita manda a lo ancho cuando el total es
   impar (3, 5…), que es cuando la rejilla cuadra sin dejar huecos. */
.testimonials-grid { display: grid; gap: 1.15rem; }
@media (min-width: 780px) {
  .testimonials-grid { grid-template-columns: repeat(2, 1fr); }
  .testimonial:first-child:nth-last-child(2n + 1) { grid-column: 1 / -1; }
}
.testimonial {
  position: relative;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: 1.9rem; margin: 0; display: flex; flex-direction: column; gap: 1.3rem;
  transition: transform var(--d-mid) var(--ease-out), box-shadow var(--d-mid) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .testimonial:hover { transform: translateY(-4px); box-shadow: var(--shadow-card); }
}
/* Comilla de agua: marca la sección como "voz de cliente" de un vistazo. */
.testimonial::before {
  content: "\201C";
  position: absolute; top: 0.1rem; right: 1.2rem;
  font-family: var(--font-display); font-size: 5rem; line-height: 1;
  color: color-mix(in srgb, var(--brand) 12%, transparent);
  pointer-events: none;
}
.testimonial blockquote { margin: 0; font-size: 0.98rem; line-height: 1.7; color: var(--text); flex: 1; text-wrap: pretty; position: relative; }
/* La cita destacada: más aire y más cuerpo tipográfico, sin caja. */
@media (min-width: 780px) {
  .testimonial:first-child:nth-last-child(2n + 1) {
    background:
      radial-gradient(30rem 18rem at 92% -20%, color-mix(in srgb, var(--au-2) 18%, transparent), transparent 62%),
      color-mix(in srgb, var(--brand) 5%, var(--surface));
    border-color: color-mix(in srgb, var(--brand) 18%, var(--line));
    padding: 2.8rem;
  }
  .testimonial:first-child:nth-last-child(2n + 1) blockquote {
    font-family: var(--font-display);
    font-size: clamp(1.3rem, 2.2vw, 1.75rem);
    line-height: 1.32;
    letter-spacing: -0.025em;
    max-width: 34ch;
  }
}
.testimonial figcaption { display: flex; align-items: center; gap: 0.8rem; }
.testimonial .avatar { width: 46px; height: 46px; border-radius: 50%; object-fit: cover; }
.testimonial .avatar-fallback {
  width: 46px; height: 46px; border-radius: 50%; display: grid; place-items: center;
  color: #fff; font-weight: 700; background: var(--grad-brand);
}
.testimonial .who b { display: block; font-size: 0.9rem; }
.testimonial .who span { font-size: 0.78rem; color: var(--muted); }

/* Solo lectores de pantalla (marcas ✓/~/✕ de la comparativa) */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Texto enriquecido como prosa legible (artículos del blog) */
.section--prose { padding-block: 2rem; }
.rich-prose { max-width: 44rem; margin-inline: auto; line-height: 1.75; font-size: 1.02rem; }
.rich-prose h2 { font-size: 1.5rem; margin-top: 2.2rem; }
.rich-prose h3 { font-size: 1.18rem; margin-top: 1.8rem; }
.rich-prose p { margin-top: 1rem; }
.rich-prose ul, .rich-prose ol { margin-top: 1rem; padding-left: 1.4rem; }
.rich-prose ul { list-style: disc; }
.rich-prose ol { list-style: decimal; }
.rich-prose li { margin-top: 0.4rem; }
.rich-prose a { color: var(--brand-text); text-decoration: underline; text-underline-offset: 3px; }
.rich-prose img { border-radius: var(--r-md); margin-top: 1.4rem; }
.rich-prose blockquote { margin-top: 1.4rem; padding-left: 1.1rem; border-left: 3px solid var(--brand); color: var(--muted); font-style: italic; }

/* ── Blog ─────────────────────────────────────────────────────────────── */
.post-grid { display: grid; gap: 1.4rem; }
@media (min-width: 760px) { .post-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .post-grid { grid-template-columns: repeat(3, 1fr); } }
.post-card {
  display: flex; flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  text-decoration: none; color: inherit;
  transition: transform var(--d-mid) var(--ease-out), box-shadow var(--d-mid) var(--ease-out), border-color var(--d-mid) ease;
}
@media (hover: hover) and (pointer: fine) {
  .post-card:hover { transform: translateY(-5px); box-shadow: var(--shadow-card); border-color: color-mix(in srgb, var(--brand) 28%, var(--line)); }
  .post-card:hover .post-more { color: var(--brand-text); }
  .post-card:hover .post-more::after { transform: translateX(4px); }
  .post-card:hover .post-cover img { transform: scale(1.05); }
}
.post-cover { aspect-ratio: 16 / 9; overflow: hidden; background: var(--paper-2); }
.post-cover img { width: 100%; height: 100%; object-fit: cover; transition: transform var(--d-slow) var(--ease-out); }
.post-body { padding: 1.3rem 1.4rem 1.5rem; display: flex; flex-direction: column; flex: 1; }
.post-meta { font-size: 0.78rem; color: var(--muted); display: flex; gap: 0.45rem; flex-wrap: wrap; }
.post-body h2 { font-size: 1.14rem; font-weight: 700; margin-top: 0.55rem; line-height: 1.35; }
.post-summary { margin-top: 0.55rem; font-size: 0.9rem; color: var(--muted); line-height: 1.6; flex: 1; }
.post-more { margin-top: 1rem; font-size: 0.86rem; font-weight: 600; transition: color var(--d-fast) ease; display: inline-flex; align-items: center; gap: 0.35rem; }
.post-more::after { content: "→"; transition: transform var(--d-mid) var(--ease-spring); }

/* Artículo */
.article-head-inner { max-width: 46rem; margin-inline: auto; text-align: center; }
.article-head-inner h1 { margin-top: 0.7rem; }
.article-head-inner .lead { margin-top: 1rem; }
.article-head .post-meta { justify-content: center; }
.article-cover { max-width: 62rem; margin: 2.5rem auto 0; border-radius: var(--r-lg); overflow: hidden; border: 1px solid var(--line); box-shadow: var(--shadow-pop); }
.article-cover img { width: 100%; height: auto; display: block; }
/* Los bloques del cuerpo ya traen su propio .section: el artículo solo
   estrecha el texto enriquecido para que se lea como artículo, no como landing. */
.article-body .rich-prose, .article-body .prose-legal { max-width: 44rem; margin-inline: auto; }

/* ── Comparativa ──────────────────────────────────────────────────────── */
.compare-intro { max-width: 46rem; margin-inline: auto; text-align: left; }
.compare-wrap { max-width: 56rem; margin-inline: auto; overflow-x: auto; border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--surface); box-shadow: var(--shadow-card); }
.compare-table { width: 100%; border-collapse: collapse; font-size: 0.92rem; min-width: 560px; }
.compare-table th, .compare-table td { padding: 0.95rem 1.15rem; text-align: left; border-bottom: 1px solid var(--line); }
/* Antes usaba var(--bg), que no existe en ninguna parte: el color-mix era
   inválido y la cabecera se quedaba transparente. */
.compare-table thead th { font-size: 0.8rem; letter-spacing: 0.04em; text-transform: uppercase; color: var(--muted); background: var(--paper-2); }
.compare-table tbody tr:last-child th, .compare-table tbody tr:last-child td { border-bottom: 0; }
.compare-table tbody th { font-weight: 600; }
/* Nuestra columna, sutilmente destacada — sin gritar */
.compare-table .is-us { background: color-mix(in srgb, var(--brand) 6%, transparent); }
.compare-table thead .is-us { color: var(--brand-text); background: color-mix(in srgb, var(--brand) 12%, var(--paper-2)); }
.compare-table td { vertical-align: top; }
.compare-table td small { display: block; margin-top: 0.25rem; color: var(--muted); font-size: 0.78rem; }
.mark { display: inline-flex; width: 20px; height: 20px; border-radius: 50%; align-items: center; justify-content: center; font-size: 0.75rem; font-weight: 800; }
.mark-yes .mark { background: color-mix(in srgb, var(--brand) 18%, transparent); color: var(--brand-text); }
.mark-yes .mark::before { content: "✓"; }
.mark-partial .mark { background: rgb(234 179 8 / 0.16); color: #a16207; }
.mark-partial .mark::before { content: "~"; }
.mark-no .mark { background: rgb(239 68 68 / 0.12); color: #b91c1c; }
.mark-no .mark::before { content: "✕"; }
.compare-verdict { max-width: 46rem; margin: 3rem auto 0; }
.compare-verdict h2 { font-size: 1.35rem; }
.compare-verdict p { margin-top: 0.8rem; color: var(--muted); line-height: 1.7; }

/* ── Bento de producto (capturas reales) ──────────────────────────────── */
.bento { display: grid; gap: 1.15rem; }
@media (min-width: 800px) {
  .bento { grid-template-columns: repeat(2, 1fr); }
  .bento-item.is-wide { grid-column: span 2; }
}
@media (min-width: 1100px) {
  .bento { grid-template-columns: repeat(3, 1fr); }
  .bento-item.is-wide { grid-column: span 2; }
}
.bento-item {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 1.15rem;
  overflow: hidden;
  display: flex; flex-direction: column;
  transition: transform var(--d-mid) var(--ease-out), box-shadow var(--d-mid) var(--ease-out), border-color var(--d-fast) ease;
}
@media (hover: hover) and (pointer: fine) {
  .bento-item:hover { transform: translateY(-4px); box-shadow: var(--shadow-card); border-color: color-mix(in srgb, var(--brand) 35%, var(--line)); }
  /* El zoom va en la captura, no en la tarjeta: escalar la tarjeta entera
     también agrandaría el texto y se vería borroso. */
  .bento-item:hover .bento-shot img { transform: scale(1.04); }
}
.bento-shot {
  position: relative;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--ink);
  flex: 1;
  display: flex; align-items: flex-start; justify-content: center;
}
.bento-shot img {
  width: 100%; height: auto; display: block;
  transition: transform var(--d-slow) var(--ease-out);
}
/* Marco de navegador: tres puntos y una barra. Da contexto de "esto es una
   pantalla real" sin dibujar un navegador entero. */
.frame-bar {
  display: flex; gap: 6px; align-items: center;
  padding: 0.55rem 0.7rem;
  background: color-mix(in srgb, var(--ink) 88%, #fff);
  border-bottom: 1px solid rgb(255 255 255 / 0.08);
  position: absolute; inset: 0 0 auto 0; z-index: 1;
}
.frame-bar span { width: 9px; height: 9px; border-radius: 50%; background: rgb(255 255 255 / 0.22); }
.frame-browser .bento-shot img { margin-top: 2rem; }
/* Marco de móvil: la captura se estrecha y se redondea como un teléfono. */
.frame-phone .bento-shot { background: transparent; }
.frame-phone .bento-shot img {
  max-width: 220px; margin-inline: auto;
  border-radius: 1.8rem;
  border: 6px solid var(--ink);
  box-shadow: var(--shadow-float);
}
.bento-caption { padding: 1rem 0.35rem 0.2rem; }
.bento-caption h3 { font-size: 1rem; font-weight: 650; }
.bento-caption p { margin-top: 0.35rem; font-size: 0.88rem; color: var(--muted); line-height: 1.6; }

/* ── Calculadora de precio ────────────────────────────────────────────── */
.calc {
  position: relative;
  max-width: 42rem;
  margin-inline: auto;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  padding: clamp(1.7rem, 4vw, 2.6rem);
  box-shadow: var(--shadow-pop);
}
/* Halo de aurora bajo la calculadora: es la pieza que más se mira de la
   página de precios, así que se le da elevación de verdad. */
.calc::before {
  content: ""; position: absolute; inset: -6% -4%;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--au-2) 22%, transparent), transparent 72%);
  filter: blur(44px); z-index: -1;
}
.calc-control { padding-bottom: 1.6rem; border-bottom: 1px solid var(--line); }
.calc-label { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; font-size: 0.92rem; color: var(--muted); }
.calc-members {
  font-family: var(--font-display);
  font-size: 1.65rem; font-weight: 700; color: var(--text);
  letter-spacing: -0.02em; font-variant-numeric: tabular-nums;
}
.calc-slider {
  -webkit-appearance: none; appearance: none;
  width: 100%; margin-top: 0.9rem; height: 8px; border-radius: var(--r-pill);
  /* --calc-fill lo escribe site.js: Firefox no trae relleno hasta el pulgar. */
  background: linear-gradient(to right, var(--brand) 0%, var(--au-2) var(--calc-fill, 30%), var(--line) var(--calc-fill, 30%));
  cursor: pointer;
}
.calc-slider::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 26px; height: 26px; border-radius: 50%;
  background: #fff; border: 3px solid var(--brand);
  box-shadow: 0 2px 10px rgb(28 26 74 / 0.22);
  transition: transform var(--d-mid) var(--ease-spring), box-shadow var(--d-mid) ease;
}
.calc-slider::-moz-range-thumb {
  width: 26px; height: 26px; border-radius: 50%; border: 3px solid var(--brand);
  background: #fff; box-shadow: 0 2px 10px rgb(28 26 74 / 0.22);
}
.calc-slider:hover::-webkit-slider-thumb { box-shadow: 0 0 0 8px color-mix(in srgb, var(--brand) 14%, transparent); }
.calc-slider:active::-webkit-slider-thumb { transform: scale(1.18); }
.calc-slider:focus-visible { outline: 2px solid var(--brand); outline-offset: 4px; }
.calc-scale { display: flex; justify-content: space-between; margin-top: 0.5rem; font-size: 0.75rem; color: var(--muted); }

.calc-result { padding-top: 1.6rem; }
.calc-tier-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.calc-tier-name { font-size: 1.05rem; font-weight: 700; }
.calc-tier-range { font-size: 0.8rem; color: var(--muted); }
.calc-price { font-family: var(--font-display); font-weight: 700; letter-spacing: -0.035em; margin-top: 0.5rem; line-height: 1; }
.calc-price-num {
  font-size: clamp(2.8rem, 8vw, 3.6rem);
  font-variant-numeric: tabular-nums;
  background: var(--grad-text);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.calc-price-cur { font-size: 1.6rem; margin-left: 0.1rem; color: var(--brand-text); }
.calc-price-period { font-size: 1rem; font-weight: 500; color: var(--muted); margin-left: 0.35rem; }
.calc-per-member { font-size: 0.85rem; color: var(--brand-text); font-weight: 600; margin-top: 0.4rem; min-height: 1.2em; }
.calc-tier-desc { margin-top: 0.7rem; font-size: 0.9rem; color: var(--muted); }
.calc-features { margin-top: 1.3rem; display: grid; gap: 0.6rem; }
.calc-features li { display: flex; gap: 0.55rem; align-items: flex-start; font-size: 0.9rem; }
.calc-features svg { width: 18px; height: 18px; flex: none; margin-top: 2px; color: var(--brand-text); }
.calc-cta { margin-top: 1.6rem; width: 100%; }
.calc-note { margin-top: 1.2rem; font-size: 0.78rem; color: var(--muted); text-align: center; }

/* El cambio de plan se funde: sin transición, arrastrar el deslizador entre
   tramos produce un parpadeo brusco de toda la tarjeta. */
@media (prefers-reduced-motion: no-preference) {
  .calc-tier.is-active { animation: calc-in var(--d-mid) var(--ease-out); }
  @keyframes calc-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
}

/* ── Pricing ──────────────────────────────────────────────────────────── */
.pricing-grid { display: grid; gap: 1.3rem; max-width: 64rem; margin-inline: auto; align-items: stretch; }
@media (min-width: 900px) { .pricing-grid { grid-template-columns: repeat(3, 1fr); } }
.tier {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 2.1rem;
  display: flex; flex-direction: column;
  transition: transform var(--d-mid) var(--ease-out), box-shadow var(--d-mid) var(--ease-out), border-color var(--d-fast) ease;
}
@media (hover: hover) and (pointer: fine) {
  .tier:hover { transform: translateY(-5px); box-shadow: var(--shadow-card); border-color: color-mix(in srgb, var(--brand) 28%, var(--line)); }
}
.tier h3 { font-size: 1.18rem; font-weight: 650; }
.tier-price { font-family: var(--font-display); font-size: 2rem; font-weight: 700; letter-spacing: -0.03em; margin-top: 0.7rem; }
.tier-desc { margin-top: 0.6rem; font-size: 0.88rem; color: var(--muted); }
.tier ul { margin-top: 1.4rem; display: grid; gap: 0.65rem; flex: 1; }
.tier li { display: flex; gap: 0.55rem; align-items: flex-start; font-size: 0.9rem; }
.tier li svg { width: 18px; height: 18px; flex: none; margin-top: 2px; color: var(--brand-text); }
.tier .btn-primary, .tier .btn-secondary, .tier .btn-light { margin-top: 1.8rem; width: 100%; }
/* Plan destacado: tarjeta de aurora a todo color. Antes era navy — el mismo
   recurso que el hero, y con el hero ya en claro el navy aquí se leía como
   un resto de la versión anterior. El degradado además ata el plan
   recomendado al botón principal, que lleva el mismo. */
.tier.is-highlighted {
  background: var(--grad-brand);
  background-size: 150% 150%;
  color: #fff;
  border-color: transparent;
  box-shadow: 0 30px 70px -30px color-mix(in srgb, var(--brand) 75%, transparent);
}
.tier.is-highlighted h3, .tier.is-highlighted .tier-price { color: #fff; }
.tier.is-highlighted .tier-desc { color: rgb(255 255 255 / 0.78); }
.tier.is-highlighted li svg { color: #fff; }
/* Brillo que recorre la tarjeta muy de vez en cuando: la mirada vuelve al
   plan recomendado sin que nada se mueva de sitio. */
.tier.is-highlighted::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: linear-gradient(105deg, transparent 35%, rgb(255 255 255 / 0.22) 50%, transparent 65%);
  background-size: 250% 100%;
  background-position: 200% 0;
}
@media (prefers-reduced-motion: no-preference) {
  .tier.is-highlighted::after { animation: tier-sheen 7s var(--ease-in-out) 2s infinite; }
  @keyframes tier-sheen { 0% { background-position: 200% 0; } 45%, 100% { background-position: -120% 0; } }
}
@media (min-width: 900px) { .tier.is-highlighted { transform: scale(1.045); } }
@media (min-width: 900px) and (hover: hover) and (pointer: fine) { .tier.is-highlighted:hover { transform: scale(1.045) translateY(-5px); } }
/* El acento cálido de la paleta: SOLO aquí. Sobre el mar de teales y
   violetas, un único elemento coral se convierte en lo primero que ve el ojo
   — que es exactamente lo que debe pasar con el plan recomendado. */
.tier-badge {
  position: absolute; top: -13px; left: 50%; transform: translateX(-50%);
  background: var(--au-4); color: var(--au-4-text);
  font-size: 0.68rem; font-weight: 800; letter-spacing: 0.1em;
  padding: 0.34rem 0.95rem; border-radius: var(--r-pill); white-space: nowrap;
  box-shadow: 0 8px 20px -8px color-mix(in srgb, var(--au-4) 80%, transparent);
}
.pricing-note { text-align: center; margin-top: 2rem; font-size: 0.85rem; color: var(--muted); }

/* ── FAQ (details/summary nativo, sin JS) ─────────────────────────────── */
.faq-wrap { max-width: 46rem; margin-inline: auto; display: grid; gap: 0.75rem; }
.faq-item {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); overflow: hidden;
  transition: border-color var(--d-fast) ease, box-shadow var(--d-mid) ease;
}
.faq-item[open] { border-color: color-mix(in srgb, var(--brand) 30%, var(--line)); box-shadow: var(--shadow-card); }
.faq-item summary {
  list-style: none; cursor: pointer;
  display: flex; justify-content: space-between; align-items: center; gap: 1rem;
  padding: 1.2rem 1.4rem; font-weight: 600; font-size: 0.98rem;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary { transition: background var(--d-fast) ease, color var(--d-fast) ease; }
@media (hover: hover) and (pointer: fine) {
  .faq-item summary:hover { background: color-mix(in srgb, var(--brand) 5%, var(--surface)); }
}
.faq-item summary .chev { flex: none; width: 20px; height: 20px; color: var(--muted-2); transition: transform var(--d-mid) var(--ease-spring), color var(--d-fast) ease; }
.faq-item[open] summary .chev { transform: rotate(180deg); color: var(--brand-text); }
.faq-item[open] summary { color: var(--brand-text); }
.faq-answer { padding: 0 1.4rem 1.3rem; color: var(--muted); font-size: 0.93rem; line-height: 1.7; }

/* Despliegue con altura real donde el navegador lo soporta (Chrome 129+,
   Safari 26+). Donde no, el <details> abre de golpe como hasta ahora. */
@supports (interpolate-size: allow-keywords) {
  :root { interpolate-size: allow-keywords; }
  @media (prefers-reduced-motion: no-preference) {
    .faq-item::details-content {
      block-size: 0;
      overflow: clip;
      transition: block-size var(--d-mid) var(--ease-out), content-visibility var(--d-mid) allow-discrete;
    }
    .faq-item[open]::details-content { block-size: auto; }
  }
}
/* Fallback de aparición para navegadores sin ::details-content animable. */
@supports not (interpolate-size: allow-keywords) {
  @media (prefers-reduced-motion: no-preference) {
    .faq-answer { animation: faq-in var(--d-mid) var(--ease-out); }
    @keyframes faq-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
  }
}

/* ── CTA banner ───────────────────────────────────────────────────────────
   El cierre de la página. Aurora a todo color con su propia malla animada:
   es el único panel saturado de la página y por eso funciona como final. */
.cta-banner {
  position: relative; overflow: hidden; isolation: isolate;
  border-radius: var(--r-xl);
  padding: clamp(3rem, 7vw, 5rem) 2rem;
  text-align: center; color: #fff;
  background: var(--grad-brand);
}
.cta-banner .bg { position: absolute; inset: 0; object-fit: cover; width: 100%; height: 100%; opacity: 0.16; }
.cta-banner .inner { position: relative; z-index: 2; }
/* La aurora del CTA solo tiene que MOVER la luz del degradado que ya lleva el
   panel, no repintarlo. Con las cuatro manchas a plena opacidad el lima se
   mezclaba con el teal y el violeta y el resultado era un verde sucio, así
   que aquí el lima se apaga del todo y las demás se quedan en un susurro. */
.cta-banner .aurora { z-index: 1; }
.cta-banner .aurora span { filter: blur(80px); opacity: 0.22; }
.cta-banner .aurora .a3 { display: none; }
.cta-banner .aurora .a1 { opacity: 0.26; }
.cta-banner .aurora::after { display: none; }
.cta-banner h2 { font-size: clamp(2rem, 4.6vw, 3.1rem); font-weight: 700; text-wrap: balance; }
.cta-banner p { margin: 1rem auto 0; max-width: 36rem; color: rgb(255 255 255 / 0.82); font-size: 1.06rem; }
.cta-banner .btn-light { margin-top: 2.1rem; font-weight: 700; }

/* ── Footer — el ancla oscura ─────────────────────────────────────────────
   Toda la página es luz; el pie es lo único navy. Es deliberado: cierra el
   documento y da suelo. La aurora asoma por arriba para que no parezca un
   bloque pegado de otra web. */
.footer { background: var(--ink); color: rgb(255 255 255 / 0.72); margin-top: var(--sp-section); position: relative; overflow: hidden; }
.footer::before {
  content: ""; position: absolute; inset: -40% 0 auto 0; height: 60%;
  background: radial-gradient(50% 100% at 20% 100%, color-mix(in srgb, var(--brand) 55%, transparent), transparent 70%),
              radial-gradient(45% 100% at 82% 100%, color-mix(in srgb, var(--au-2) 40%, transparent), transparent 70%);
  opacity: 0.55; pointer-events: none;
}
.footer > * { position: relative; }
.footer-pulse { display: block; width: 100%; height: 30px; color: var(--pulse); opacity: 0.6; }
.footer-pulse path { fill: none; stroke: currentColor; stroke-width: 1.6; }
.footer-grid { display: grid; gap: 2.5rem; padding-block: 3.6rem 3rem; }
@media (min-width: 860px) { .footer-grid { grid-template-columns: 2fr 1fr 1fr; } }
/* Los títulos de columna del pie eran <h4> detrás de un <h2> de sección: axe
   lo marca como salto de nivel (h2 → h4) y un lector de pantalla anuncia una
   jerarquía que no existe. Ahora son <h2> con esta clase — siempre válidos,
   porque toda página tiene su <h1>. El selector de h4 se mantiene por si
   queda alguna plantilla propia sin migrar. */
.footer h4, .footer .footer-title { font-family: var(--font-body); font-size: 0.82rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: #fff; margin-bottom: 1rem; }
.footer ul { display: grid; gap: 0.55rem; font-size: 0.92rem; }
.footer a { text-decoration: none; color: inherit; transition: color var(--d-fast) ease; }
.footer a:hover { color: #fff; }
.footer .brand-blurb { max-width: 24rem; font-size: 0.95rem; }
.footer .brand-line { display: flex; align-items: center; gap: 0.6rem; color: #fff; font-family: var(--font-display); font-weight: 700; font-size: 1.15rem; margin-bottom: 1rem; }
.footer .contact-bits { margin-top: 1.2rem; display: grid; gap: 0.35rem; font-size: 0.85rem; color: rgb(255 255 255 / 0.55); }
.footer .socials { margin-top: 1.2rem; display: flex; flex-wrap: wrap; gap: 1.1rem; font-size: 0.85rem; }
.footer-bar { border-top: 1px solid rgb(255 255 255 / 0.1); }
/* 0.45 dejaba el aviso legal en 4.5:1 justo al límite a 0.78rem. 0.58 lo sube a ~6:1. */
.footer-bar .container-x { display: flex; flex-wrap: wrap; gap: 0.6rem 2rem; justify-content: space-between; padding-block: 1.4rem; font-size: 0.78rem; color: rgb(255 255 255 / 0.58); }

/* ── Página legal ─────────────────────────────────────────────────────── */
.legal-wrap { max-width: 46rem; margin-inline: auto; }
.legal-wrap h1 { font-size: clamp(2rem, 4.5vw, 2.8rem); font-weight: 700; margin-top: 0.8rem; }
.prose-legal { margin-top: 2.2rem; color: var(--muted); }
.prose-legal h2 { font-family: var(--font-body); font-size: 1.08rem; font-weight: 700; color: var(--text); margin: 1.9rem 0 0.5rem; }
.prose-legal p { margin-block: 0.55rem; }
.prose-legal ul { list-style: disc; padding-left: 1.4rem; display: grid; gap: 0.3rem; margin-block: 0.7rem; }
.prose-legal a { color: var(--brand-text); }
.legal-meta { margin-top: 3rem; padding-top: 1.4rem; border-top: 1px solid var(--line); font-size: 0.78rem; color: var(--muted-2); }

/* ── Formulario de contacto ───────────────────────────────────────────── */
.form-card {
  position: relative;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-xl);
  padding: clamp(1.6rem, 4vw, 2.4rem); box-shadow: var(--shadow-pop); display: grid; gap: 1.3rem;
}
.form-row { display: grid; gap: 1.3rem; }
@media (min-width: 640px) { .form-row { grid-template-columns: 1fr 1fr; } }
.field span { display: block; font-size: 0.85rem; font-weight: 600; margin-bottom: 0.4rem; }
.field input, .field textarea {
  width: 100%; padding: 0.85rem 1.05rem; font: inherit;
  border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface);
  color: var(--text);
  transition: border-color var(--d-fast) ease, box-shadow var(--d-fast) ease, background var(--d-fast) ease;
}
.field input:hover, .field textarea:hover { border-color: var(--line-strong); }
.field input:focus, .field textarea:focus {
  outline: none; border-color: var(--brand);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--brand) 16%, transparent);
}
.form-note { text-align: center; font-size: 0.75rem; color: var(--muted-2); }
/* Honeypot anti-spam: fuera de pantalla (no display:none — algunos bots lo detectan) */
.hp-field { position: absolute; left: -9999px; top: -9999px; height: 1px; width: 1px; overflow: hidden; opacity: 0; }
.alert-error { padding: 1rem 1.2rem; border-radius: var(--r-sm); background: var(--danger-bg); border: 1px solid var(--danger-line); color: var(--danger-text); font-size: 0.9rem; margin-bottom: 1.4rem; }
.thanks-icon {
  width: 78px; height: 78px; margin: 0 auto 1.5rem; border-radius: 50%;
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--brand) 12%, var(--surface));
  color: var(--brand-text);
}
.thanks-icon svg { width: 34px; height: 34px; }
@media (prefers-reduced-motion: no-preference) {
  /* Confirmación: el círculo late una vez al aterrizar. Refuerza el "hecho". */
  .thanks-icon { animation: thanks-pop 0.7s var(--ease-spring) both; }
  @keyframes thanks-pop { from { opacity: 0; transform: scale(0.6); } to { opacity: 1; transform: none; } }
}

/* ═══ CAPA DE MOVIMIENTO ══════════════════════════════════════════════════
   Todo nativo del navegador: cero librerías, cero peso extra, y las
   animaciones ligadas al scroll corren fuera del hilo principal. Cada bloque
   va detrás de @supports, así que un navegador antiguo ve la web de siempre.

   Regla que se cumple en todo el fichero: NADA arranca en opacity:0 sin que
   exista la animación que lo devuelve. Si el JS no carga o el navegador no
   soporta el truco, el contenido se ve. Una web de marketing invisible por
   una animación fallida es un fallo peor que no animar.
   ═════════════════════════════════════════════════════════════════════════ */

/* ── Grano: rompe la planitud digital. Fijo y pointer-events:none para que
      no repinte en cada frame de scroll. Sobre lienzo claro hay que bajarlo:
      el 0.035 de la versión oscura aquí se veía sucio. ─────────────────── */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 60;
  pointer-events: none;
  opacity: 0.022;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) body::after { opacity: 0.035; } }
:root[data-theme="dark"] body::after { opacity: 0.035; }

/* ── Transiciones entre páginas (View Transitions cross-document) ────────
      Wagtail sirve /precios/, /faq/… como documentos separados. Con esto la
      navegación deja de ser un parpadeo en blanco. La navbar y el pie se
      nombran para que permanezcan fijos mientras el contenido cambia. */
@view-transition { navigation: auto; }
.nav { view-transition-name: nav; }
.footer { view-transition-name: footer; }
::view-transition-old(root) { animation: vt-out 0.2s var(--ease-out) both; }
::view-transition-new(root) { animation: vt-in 0.32s var(--ease-out) both; }
@keyframes vt-out { to { opacity: 0; transform: translateY(-8px) scale(0.995); } }
@keyframes vt-in { from { opacity: 0; transform: translateY(12px); } }

/* ── Animaciones ligadas al scroll (nativas, sin JS ni listeners) ──────── */
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    /* Barra de progreso de lectura (artículos): el navegador la mueve en el
       compositor, sin un solo listener de scroll. */
    .read-progress {
      position: fixed; inset: 0 0 auto 0; height: 3px; z-index: 60;
      background: var(--grad-brand);
      transform-origin: 0 50%; transform: scaleX(0);
      animation: read-progress linear forwards;
      animation-timeline: scroll(root);
    }
    @keyframes read-progress { to { transform: scaleX(1); } }
  }
  @media (prefers-reduced-motion: no-preference) and (min-width: 980px) {
    /* Deriva del mockup: da profundidad al hero sin robar protagonismo. */
    .hero-mockup img {
      animation: hero-drift linear both;
      animation-timeline: scroll(root);
      animation-range: 0 80vh;
    }
    @keyframes hero-drift { to { translate: 0 -34px; scale: 1.02; } }
    /* La aurora del hero sube más despacio que el contenido: paralaje real
       de una sola capa, que es todo el que hace falta. */
    .hero .aurora {
      animation: hero-aurora linear both;
      animation-timeline: scroll(root);
      animation-range: 0 90vh;
    }
    @keyframes hero-aurora { to { translate: 0 60px; opacity: 0.55; } }
  }
}
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    /* Las capturas del bento y las portadas emergen con un empujón sutil
       mientras entran en el viewport. */
    .bento-item, .post-card {
      animation: rise-in linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 60%;
    }
    @keyframes rise-in {
      from { opacity: 0.25; transform: translateY(28px) scale(0.985); }
      to { opacity: 1; transform: none; }
    }
    /* El pulso del pie se dibuja al llegar abajo: cierra con la misma firma
       con la que abre el hero. */
    .footer-pulse path {
      stroke-dasharray: 1400;
      stroke-dashoffset: 1400;
      animation: pulse-draw linear both;
      animation-timeline: view();
      animation-range: entry 10% entry 95%;
    }
    /* Filete de aurora que se dibuja bajo el título de cada sección al
       llegar. Cuesta 4 líneas y convierte un H2 en una entrada de capítulo. */
    .section-head::after {
      content: "";
      display: block;
      width: 5.5rem; height: 3px; margin-top: 1.4rem;
      border-radius: 3px;
      background: var(--grad-brand);
      transform: scaleX(0); transform-origin: left;
      animation: rule-draw linear both;
      animation-timeline: view();
      animation-range: entry 10% entry 55%;
    }
    .section-head--center::after { margin-inline: auto; transform-origin: center; }
    @keyframes rule-draw { to { transform: scaleX(1); } }
  }
}
/* Sin scroll-timeline el filete tiene que existir igual, solo que quieto. */
@supports not (animation-timeline: view()) {
  .section-head::after {
    content: ""; display: block; width: 5.5rem; height: 3px; margin-top: 1.4rem;
    border-radius: 3px; background: var(--grad-brand);
  }
  .section-head--center::after { margin-inline: auto; }
}
@media (prefers-reduced-motion: reduce) {
  .section-head::after {
    content: ""; display: block; width: 5.5rem; height: 3px; margin-top: 1.4rem;
    border-radius: 3px; background: var(--grad-brand); transform: none;
  }
  .section-head--center::after { margin-inline: auto; }
}

/* ── Reveals al hacer scroll ──────────────────────────────────────────────
   Solo con JS activo (html.js): sin JS el contenido queda siempre visible.
   La dirección la elige la plantilla con data-reveal; --d es el retardo que
   site.js reparte entre hermanos para que entren en cascada. */
html.js .reveal {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity var(--d-slow) var(--ease-out), transform var(--d-slow) var(--ease-out);
  transition-delay: var(--d, 0ms);
}
html.js .reveal[data-reveal="left"]  { transform: translateX(-26px); }
html.js .reveal[data-reveal="right"] { transform: translateX(26px); }
html.js .reveal[data-reveal="scale"] { transform: scale(0.94); }
html.js .reveal[data-reveal="blur"]  { filter: blur(8px); transition: opacity var(--d-slow) var(--ease-out), transform var(--d-slow) var(--ease-out), filter var(--d-slow) var(--ease-out); }
html.js .reveal.is-in { opacity: 1; transform: none; filter: none; }
/* Con movimiento reducido el contenido aparece sin desplazarse: se funde. */
@media (prefers-reduced-motion: reduce) {
  html.js .reveal { transform: none !important; filter: none !important; transition-duration: 0.01ms; }
}
/* Al imprimir (y al capturar la página entera) no hay scroll, así que el
   IntersectionObserver nunca dispara y TODO lo que lleva .reveal sale en
   blanco. Un PDF de la página de precios con los planes invisibles es un
   fallo real, no una rareza de laboratorio. */
@media print {
  html.js .reveal { opacity: 1 !important; transform: none !important; filter: none !important; }
  .nav, .to-top, .cookie-banner, .theme-toggle { display: none !important; }
  .aurora, body::after { display: none !important; }
}

/* ── Volver arriba ────────────────────────────────────────────────────────
   Aparece cuando ya has bajado lo suficiente como para que el pie de página
   quede lejos. site.js le pone .is-in. */
.to-top {
  position: fixed;
  right: max(1.2rem, env(safe-area-inset-right));
  bottom: max(1.2rem, env(safe-area-inset-bottom));
  z-index: 55;
  width: 46px; height: 46px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--surface-glass);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  color: var(--text);
  box-shadow: var(--shadow-card);
  cursor: pointer;
  opacity: 0; visibility: hidden; transform: translateY(14px) scale(0.85);
  transition: opacity var(--d-mid) var(--ease-out), transform var(--d-mid) var(--ease-spring), visibility var(--d-mid);
}
.to-top.is-in { opacity: 1; visibility: visible; transform: none; }
.to-top svg { width: 20px; height: 20px; }
@media (hover: hover) and (pointer: fine) {
  .to-top:hover { color: var(--brand-text); border-color: color-mix(in srgb, var(--brand) 40%, var(--line)); transform: translateY(-3px); }
}
.to-top:active { transform: scale(0.9); }
/* El aviso de cookies vive abajo y lo taparía. */
body:has(.cookie-banner:not([hidden])) .to-top { bottom: calc(max(1.2rem, env(safe-area-inset-bottom)) + 8.5rem); }

/* ── Aviso de cookies (RGPD) ──────────────────────────────────────────── */
/* Barra fija abajo, NO modal: no bloquea el scroll ni el resto de la página.
   z-index 90: por encima de la navbar (50), por debajo del skip-link (100). */
.cookie-banner {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 90;
  background: var(--surface);
  border-top: 1px solid var(--line);
  box-shadow: 0 -12px 40px -20px rgb(28 26 74 / 0.35);
  padding-bottom: env(safe-area-inset-bottom);
}
@media (prefers-reduced-motion: no-preference) {
  .cookie-banner:not([hidden]) { animation: cookie-up var(--d-slow) var(--ease-out) both; }
  @keyframes cookie-up { from { transform: translateY(100%); } }
}
.cookie-inner {
  display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.4rem;
  padding-block: 1.1rem;
}
.cookie-text { font-size: 0.88rem; line-height: 1.5; color: var(--muted); flex: 1 1 26rem; max-width: 46rem; }
.cookie-text a { color: var(--brand-text); text-decoration: underline; text-underline-offset: 2px; }
.cookie-panel {
  flex-basis: 100%;
  display: grid; gap: 0.7rem;
  padding: 1rem 1.1rem;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--paper-2);
}
.cookie-cat { display: flex; gap: 0.6rem; align-items: flex-start; font-size: 0.85rem; color: var(--muted); }
.cookie-cat input { margin-top: 0.25rem; accent-color: var(--brand); flex: none; }
.cookie-cat strong { color: var(--text); }
.cookie-actions { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center; }
.cookie-btn { padding: 0.6rem 1.15rem; font-size: 0.87rem; }
.cookie-settings-link {
  background: none; border: 0; padding: 0; cursor: pointer;
  color: inherit; font-size: inherit; text-decoration: underline;
  text-underline-offset: 2px;
  transition: color var(--d-fast) ease;
}
.cookie-settings-link:hover { color: #fff; }
.cookie-withdraw { flex-basis: 100%; margin: 0.2rem 0 0; }
.cookie-link-btn {
  background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--muted-2); font-size: 0.78rem; text-decoration: underline;
  text-underline-offset: 2px;
  transition: color var(--d-fast) ease;
}
.cookie-link-btn:hover { color: var(--danger-text); }
.field-consent { display: flex; gap: 0.6rem; align-items: flex-start; font-size: 0.85rem; color: var(--muted); }
.field-consent input { margin-top: 0.28rem; accent-color: var(--brand); flex: none; }
.field-consent a { color: var(--brand-text); text-decoration: underline; text-underline-offset: 2px; }

/* ── Freno general de movimiento ──────────────────────────────────────────
   Las animaciones en bucle (aurora, latido, marquesina, brillo del plan) se
   paran del todo: son las que marean. Las transiciones puntuales se acortan
   en vez de eliminarse — sin ellas la interfaz da saltos secos que también
   molestan. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation: none !important; }
}

