@charset "UTF-8";
/* ═══════════════════════════════════════════════════════════════════════════
   V3 DIGITAL MARKETING · css/styles.css
   CSS puro · sin build step · mobile-first (640 / 768 / 1024) · WCAG 2.2 AA

   ÍNDICE
     00 · RESET
     01 · TOKENS            (:root — cambiar aquí cambia todo el sitio)
     02 · BASE              tipografía y elementos nativos
     03 · LAYOUT            contenedor, secciones, grillas
     04 · COMPONENTES       botones, tarjetas, íconos, tablas, acordeones…
     05 · SECCIONES         estilos propios de cada bloque de la landing
     06 · RESPONSIVE        ajustes por breakpoint
     07 · UTILIDADES
     08 · A11Y · MOTION · PRINT · FORCED-COLORS

   REGLAS DE COLOR NO NEGOCIABLES (ver README):
     1. Naranja #EA580C SOLO como superficie de .btn--primary. Nunca en
        badges, bordes, chips, íconos, subrayados ni fondos amplios.
     2. Teal nunca como `color:` por debajo de 24px. Nunca sobre violeta
        (#0D9488 sobre #4C1D95 = 2.93:1, falla incluso para íconos).
     3. --color-border es decorativo. Todo control usa --color-border-strong.
     4. En gráficos de datos: gris = lo perdido/actual. Teal/naranja SOLO para
        cifras de recuperación medidas y reales (hoy no existe ninguna).
   ═══════════════════════════════════════════════════════════════════════════ */


/* ═══ 00 · RESPALDOS TIPOGRÁFICOS ══════════════════════════════════════════
   Las webfonts cargan con display=swap: hasta que llegan se pinta con la
   fuente del sistema, y al aplicarse cambian las métricas y RELFOTA la página
   entera. Medido en esta landing: CLS de 0.107, por encima del umbral de 0.1
   de Core Web Vitals. Para un negocio que vende webs rápidas, reprobar esa
   métrica en su propia home no es una opción.

   Estos dos @font-face no descargan nada: toman una fuente que YA está en el
   equipo y le corrigen las métricas para que ocupe exactamente el mismo
   espacio que la webfont real. Así el swap no mueve nada.

   Los valores NO son estimados: salen de leer los .woff2 de Google con
   fontTools (sxHeight, sTypoAscender/Descender, unitsPerEm) y compararlos
   con Arial, con la misma fórmula que usa next/font.
     Inter          upem 2048 · asc 1984 · desc -494 · xHeight 1118
     Space Grotesk  upem 1000 · asc  984 · desc -292 · xHeight  486

   Sobre el orden de `local()`: en Windows y macOS resuelve Arial, para la que
   está calibrado al milímetro. En Android no existe Arial y cae a Roboto,
   cuya altura de x difiere ~1.9%: el ajuste queda algo desviado, pero muy
   por debajo del desajuste que produce no corregir nada. */

@font-face {
  font-family: 'Inter Fallback';
  src: local('Arial'), local('Helvetica'), local('Roboto');
  size-adjust: 105.27%;
  ascent-override: 92.02%;
  descent-override: 22.91%;
  line-gap-override: 0%;
}
@font-face {
  font-family: 'Space Grotesk Fallback';
  src: local('Arial'), local('Helvetica'), local('Roboto');
  size-adjust: 93.72%;
  ascent-override: 104.99%;
  descent-override: 31.16%;
  line-gap-override: 0%;
}


/* ═══ 00 · RESET ═══════════════════════════════════════════════════════════ */

*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scrollbar-gutter: stable;
}

body {
  min-height: 100svh;
  -webkit-font-smoothing: antialiased;
}

img, svg, video { display: block; max-width: 100%; }
img { height: auto; }

input, button, textarea, select { font: inherit; color: inherit; }
p, h1, h2, h3, h4, li { overflow-wrap: break-word; }

:root { color-scheme: light; }   /* evita que el navegador invierta la UI nativa */


/* ═══ 01 · TOKENS ══════════════════════════════════════════════════════════ */

:root {

  /* ── 1.1 · Paleta de marca — hex EXACTOS del Manual. No modificar. ─────── */
  --c-indigo:          #4C1D95;  /* primario · 10.95:1 sobre blanco (AAA)    */
  --c-indigo-electric: #4338CA;  /* gradiente, hover, enlaces · 7.90:1 (AAA) */
  --c-indigo-light:    #CECBF6;  /* texto sobre violeta · 7.04:1 s/#4C1D95   */
  --c-teal:            #0D9488;  /* 3.74:1 → SOLO ≥24px, íconos, bordes, bg  */
  --c-orange:          #EA580C;  /* EXCLUSIVO superficie de CTA              */
  --c-slate:           #0F172A;  /* texto principal · 17.85:1                */
  --c-gray:            #475569;  /* texto secundario · 7.58:1                */
  --c-white:           #FFFFFF;
  --c-offwhite:        #F8FAFC;
  --c-border-hex:      #E2E8F0;  /* 1.23:1 → SOLO decorativo                 */

  /* ── 1.2 · Ampliaciones de paleta (pendientes de validación) ───────────── */
  --c-orange-700:      #C2410C;  /* hover del CTA · blanco encima = 5.18:1   */
  /* El teal de marca en texto pequeño no llega: sobre su propio 10% da
     3.32:1. Este es el mismo tono oscurecido, 6.73:1 sobre ese fondo.
     Solo para TEXTO menor de 24px sobre fondos teal claros; para íconos y
     cifras grandes sigue usándose --c-teal.                                */
  --c-teal-800:        #115E59;  /* sobre teal-10% = 6.73:1                  */

  /* ── 1.3 · Tintes: alfa de los mismos hex, cero tonos nuevos ───────────── */
  --a-indigo-06: rgba(76, 29, 149, .06);
  --a-indigo-10: rgba(76, 29, 149, .10);
  --a-teal-10:   rgba(13, 148, 136, .10);
  --a-teal-16:   rgba(13, 148, 136, .16);
  --a-white-10:  rgba(255, 255, 255, .10);
  --a-light-35:  rgba(206, 203, 246, .35);

  /* ── 1.4 · Capa semántica ──────────────────────────────────────────────── */
  /* Los componentes SOLO usan --color-*. Así, al invertir estos valores en
     .section--violet / .section--slate, ningún componente necesita saber
     sobre qué fondo está pintado. */
  --color-text:          var(--c-slate);
  --color-text-muted:    var(--c-gray);
  --color-heading:       var(--c-slate);
  --color-link:          var(--c-indigo-electric);
  --color-link-hover:    var(--c-indigo);

  --color-bg:            var(--c-white);
  --color-bg-alt:        var(--c-offwhite);
  --color-surface:       var(--c-white);
  --color-surface-tint:  var(--a-indigo-06);

  --color-border:        var(--c-border-hex);  /* decorativo            */
  --color-border-strong: var(--c-gray);        /* funcional · 7.58:1    */
  --color-accent:        var(--c-teal);        /* íconos y números ≥24px */

  --color-cta-bg:        var(--c-orange);
  --color-cta-fg:        var(--c-slate);       /* 5.02:1 — AA a cualquier tamaño */
  --color-cta-bg-hover:  var(--c-orange-700);
  --color-cta-fg-hover:  var(--c-white);       /* 5.18:1                */

  --color-focus:         var(--c-indigo-electric);
  --color-focus-halo:    var(--c-white);

  /* Semántica de datos — INVIOLABLE: gris = lo perdido/actual.
     Teal/naranja = SOLO lo efectivamente recuperado y medido (hoy: nada). */
  --color-data-lost:    var(--c-gray);
  --color-data-current: var(--c-border-hex);
  --color-data-gained:  var(--c-teal);   /* sin uso hasta tener casos reales */

  --gradient-brand: linear-gradient(160deg, #4C1D95 0%, #4338CA 100%);

  /* ── 1.5 · Tipografía — MÁXIMO 2 familias ──────────────────────────────── */
  /* El respaldo ajustado va SIEMPRE justo después de la webfont: es el que se
     usa mientras esta carga, y ocupa el mismo espacio para que el swap no
     mueva el layout (ver bloque 00 · RESPALDOS TIPOGRÁFICOS). */
  --font-display: 'Space Grotesk', 'Space Grotesk Fallback', 'Segoe UI', Roboto, Arial, sans-serif;
  --font-body:    'Inter', 'Inter Fallback', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif;

  --fw-regular: 400;
  --fw-medium: 500;
  --fw-semibold: 600;
  --fw-bold: 700;

  --lh-tight: 1.08;
  --lh-heading: 1.2;
  --lh-snug: 1.35;
  --lh-body: 1.6;
  --lh-relaxed: 1.7;

  --ls-tight: -.02em;
  --ls-snug: -.01em;
  --ls-eyebrow: .12em;
  --ls-wordmark: .18em;

  /* Escala fluida. El término constante va en rem para que el zoom al 200%
     siga funcionando (WCAG 1.4.4). No inventar tamaños intermedios. */
  --fs-h1:      clamp(2.25rem, 1.393rem + 3.81vw, 3.5rem);      /* 36 → 56 */
  --fs-h2:      clamp(1.75rem, 1.350rem + 1.78vw, 2.5rem);      /* 28 → 40 */
  --fs-h3:      clamp(1.5rem, 1.429rem + .36vw, 1.75rem);       /* 24 → 28 */
  --fs-h4:      1.125rem;                                       /* 18      */
  --fs-lead:    clamp(1.125rem, 1.054rem + .32vw, 1.3125rem);   /* 18 → 21 */
  --fs-body:    clamp(1rem, .964rem + .18vw, 1.125rem);         /* 16 → 18 */
  --fs-caption: .8125rem;                                       /* 13      */
  --fs-micro:   .75rem;                                         /* 12      */
  --fs-btn:     1rem;                                           /* 16      */
  --fs-eyebrow: .8125rem;                                       /* 13      */
  --fs-stat:    clamp(2.5rem, 1.786rem + 3.57vw, 4rem);         /* 40 → 64 */
  --fs-stat-sm: clamp(1.75rem, 1.464rem + 1.43vw, 2.375rem);    /* 28 → 38 */

  /* ── 1.6 · Espaciado (base 4px) ────────────────────────────────────────── */
  --space-3xs: .25rem;
  --space-2xs: .5rem;
  --space-xs:  .75rem;
  --space-sm:  1rem;
  --space-md:  1.5rem;
  --space-lg:  2rem;
  --space-xl:  3rem;
  --space-2xl: 4rem;
  --space-3xl: 6rem;
  --space-section: clamp(3.5rem, 2.13rem + 6.09vw, 7rem);   /* 56 → 112 */
  --space-gutter:  clamp(1.25rem, .957rem + 1.30vw, 2rem);  /* 20 → 32  */

  /* ── 1.7 · Contenedores ────────────────────────────────────────────────── */
  --container:        75rem;   /* 1200px */
  --container-narrow: 46rem;   /*  736px — FAQ y texto largo */
  --measure:       62ch;       /* medida de párrafo  */
  --measure-tight: 24ch;       /* medida de titular  */

  /* ── 1.8 · Radios ──────────────────────────────────────────────────────── */
  --radius-xs: 6px;
  --radius-sm: 10px;
  --radius-md: 14px;
  --radius-lg: 20px;
  --radius-xl: 28px;
  --radius-pill: 999px;

  /* ── 1.9 · Sombras — tintadas con slate, nunca negro puro ──────────────── */
  --shadow-sm: 0 1px 3px rgba(15, 23, 42, .07), 0 1px 2px rgba(15, 23, 42, .04);
  --shadow-md: 0 4px 12px rgba(15, 23, 42, .07), 0 2px 4px rgba(15, 23, 42, .04);
  --shadow-lg: 0 12px 28px rgba(15, 23, 42, .10), 0 4px 8px rgba(15, 23, 42, .04);
  --shadow-header: 0 1px 0 var(--color-border), 0 4px 16px rgba(15, 23, 42, .05);
  --shadow-fab: 0 8px 24px rgba(15, 23, 42, .18);
  --ring-on-dark: 0 0 0 2px var(--c-white);  /* despega el CTA del violeta */

  /* ── 1.10 · Movimiento — sin overshoot: la marca no rebota ─────────────── */
  --dur-fast: 120ms;
  --dur-base: 200ms;
  --dur-slow: 320ms;
  --dur-reveal: 520ms;
  --ease-out: cubic-bezier(.22, .61, .36, 1);
  --ease-in-out: cubic-bezier(.65, 0, .35, 1);
  --transition-ui:
    color var(--dur-fast) var(--ease-out),
    background-color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-base) var(--ease-out),
    transform var(--dur-base) var(--ease-out);

  /* ── 1.11 · Z-index — el FAB va por debajo del backdrop del drawer ─────── */
  --z-base: 0;
  --z-raised: 10;
  --z-sticky: 100;
  --z-fab: 150;
  --z-backdrop: 190;
  --z-drawer: 200;
  --z-skiplink: 400;

  /* ── 1.12 · Cromo estructural ──────────────────────────────────────────── */
  --header-h: 4rem;              /* main.js lo sobrescribe con ResizeObserver */
  --scroll-offset: calc(var(--header-h) + var(--space-md));
  --fab-size: 3.5rem;
  --stroke-icon: 1.75;           /* grosor ÚNICO de toda la iconografía */
  --focus-width: 3px;
  --focus-offset: 2px;
}

@media (min-width: 64rem) { :root { --header-h: 4.75rem; } }
@media (max-width: 30rem) { :root { --fab-size: 3rem; } }


/* ═══ 02 · BASE ════════════════════════════════════════════════════════════ */

html {
  scroll-padding-top: var(--scroll-offset);
  /* deja aire bajo el ancla para que el FAB no tape el final de la sección */
  scroll-padding-bottom: calc(var(--fab-size) + 1.5rem);
}

@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  /* El aire para que el FAB no tape el final NO va aquí, sino dentro del
     propio footer (bloque 5.8). Puesto en el body dejaba una franja blanca
     por debajo del footer oscuro: el body es blanco y el footer es slate. */
}

h1, h2, h3, h4 {
  color: var(--color-heading);
  font-family: var(--font-display);
  line-height: var(--lh-heading);
  letter-spacing: var(--ls-snug);
  text-wrap: balance;
}

h1 { font-size: var(--fs-h1); font-weight: var(--fw-bold); line-height: var(--lh-tight); letter-spacing: var(--ls-tight); }
h2 { font-size: var(--fs-h2); font-weight: var(--fw-bold); }
h3 { font-size: var(--fs-h3); font-weight: var(--fw-medium); }
h4 { font-size: var(--fs-h4); font-weight: var(--fw-medium); }

p { text-wrap: pretty; }

a { color: var(--color-link); }
a:hover { color: var(--color-link-hover); }

/* Enlaces dentro de texto corrido: el subrayado es obligatorio.
   #4338CA sobre #0F172A es 2.26:1, por debajo del 3:1 que WCAG SC 1.4.1 exige
   para distinguir un enlace solo por color. */
.prose a,
p > a:not(.btn):not(.card__cta) {
  text-decoration: underline;
  text-underline-offset: .2em;
}

ul, ol { padding-left: 1.25em; }
li + li { margin-top: var(--space-3xs); }

strong, b { font-weight: var(--fw-semibold); }

::selection { background: var(--a-indigo-10); color: var(--c-slate); }


/* ═══ 03 · LAYOUT ══════════════════════════════════════════════════════════ */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--space-gutter);
}

.container--narrow { max-width: var(--container-narrow); }

.section {
  padding-block: var(--space-section);
  background: var(--color-bg);
}

.section--alt { background: var(--color-bg-alt); }

/* ── Inversión de tokens en secciones oscuras ───────────────────────────────
   Ningún componente sabe sobre qué fondo vive: solo lee --color-*.

   IMPORTANTE: estos modificadores tienen que ir DESPUÉS de `.section`. Tienen
   la misma especificidad (0,1,0), así que si se declararan antes, el
   `background` de `.section` los pisaría y las secciones oscuras saldrían
   blancas con texto claro encima —ilegibles—.

   Se redefine también --color-bg para que cualquier componente que lo use
   (por ejemplo la columna fija de la tabla comparativa) siga funcionando. */

.section--violet {
  --color-bg: #4C1D95;
  --color-text: var(--c-indigo-light);
  --color-text-muted: var(--c-indigo-light);
  --color-heading: var(--c-white);
  --color-link: var(--c-white);
  --color-surface: var(--a-white-10);
  --color-border: var(--a-light-35);
  --color-border-strong: var(--c-indigo-light);
  --color-accent: var(--c-indigo-light);   /* teal PROHIBIDO aquí: 2.93:1 */
  --color-focus: var(--c-white);
  --color-focus-halo: var(--c-slate);
  background: var(--gradient-brand);
  color: var(--color-text);
}

.section--slate {
  --color-bg: #0F172A;
  --color-text: var(--c-indigo-light);
  --color-text-muted: var(--c-indigo-light);
  --color-heading: var(--c-white);
  --color-link: var(--c-white);
  --color-surface: var(--a-white-10);
  --color-border: rgba(206, 203, 246, .28);
  --color-border-strong: var(--c-indigo-light);
  --color-accent: var(--c-teal);           /* 4.77:1 sobre slate: válido */
  --color-focus: var(--c-white);
  --color-focus-halo: var(--c-slate);
  background: var(--c-slate);
  color: var(--color-text);
}

.section__head { margin-bottom: var(--space-xl); }
.section__head--center { text-align: center; margin-inline: auto; max-width: 44rem; }

.section__intro {
  margin-top: var(--space-sm);
  max-width: var(--measure);
  color: var(--color-text-muted);
  font-size: var(--fs-lead);
  line-height: var(--lh-snug);
}
.section__head--center .section__intro { margin-inline: auto; }

.section__foot {
  margin-top: var(--space-xl);
  color: var(--color-text-muted);
}

/* Grillas mobile-first: 1 columna por defecto, se amplían en 06 · RESPONSIVE */
.grid { display: grid; gap: var(--space-md); }
.grid--2, .grid--3, .grid--4 { grid-template-columns: 1fr; }

.cluster {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  align-items: center;
}
.cluster--center { justify-content: center; }

.stack > * + * { margin-top: var(--space-sm); }


/* ═══ 04 · COMPONENTES ═════════════════════════════════════════════════════ */

/* ── 4.1 · Eyebrow ─────────────────────────────────────────────────────────
   Nunca en teal: a 13px el teal da 3.74:1 y falla AA para texto pequeño. */
.eyebrow {
  display: block;
  margin-bottom: var(--space-sm);
  color: var(--c-indigo);
  font-family: var(--font-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
}
.section--violet .eyebrow,
.section--slate .eyebrow { color: var(--c-indigo-light); }

/* ── 4.2 · Botones ─────────────────────────────────────────────────────────
   `display:inline-flex` es OBLIGATORIO: en un <a> inline, `min-height` se
   ignora y el objetivo táctil de 48px no se cumpliría (WCAG SC 2.5.8). */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2xs);
  min-height: 3rem;
  padding: var(--space-xs) var(--space-md);
  border: 2px solid transparent;
  border-radius: var(--radius-sm);
  font-family: var(--font-body);
  font-size: var(--fs-btn);
  font-weight: var(--fw-semibold);
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: var(--transition-ui);
}

/* Naranja + slate = 5.02:1. Pasa AA a cualquier tamaño.
   Con texto blanco daría 3.56:1 y fallaría para texto normal. */
.btn--primary {
  background: var(--color-cta-bg);
  color: var(--color-cta-fg);
  border-color: var(--color-cta-bg);
}

/* El hover se envuelve en `hover:hover` para evitar el sticky-hover táctil:
   en iOS/Android el :hover persiste tras el toque. */
@media (hover: hover) and (pointer: fine) {
  .btn--primary:hover {
    background: var(--color-cta-bg-hover);
    border-color: var(--color-cta-bg-hover);
    color: var(--color-cta-fg-hover);   /* blanco sobre #C2410C = 5.18:1 */
  }
}
.btn--primary:active { transform: translateY(1px); }

.btn--secondary {
  background: transparent;
  color: var(--c-indigo);
  border-color: var(--c-indigo);
}
@media (hover: hover) and (pointer: fine) {
  .btn--secondary:hover { background: var(--a-indigo-06); color: var(--c-indigo); }
}
.section--violet .btn--secondary,
.section--slate .btn--secondary {
  color: var(--c-white);
  border-color: var(--c-indigo-light);
}
@media (hover: hover) and (pointer: fine) {
  .section--violet .btn--secondary:hover,
  .section--slate .btn--secondary:hover { background: var(--a-white-10); color: var(--c-white); }
}

.btn--sm { min-height: 2.75rem; padding: var(--space-2xs) var(--space-sm); font-size: .9375rem; }
.btn--block { width: 100%; }

/* Chevron del CTA: avanza 3px al apuntarlo. El Manual nombra los chevrons
   como lenguaje de marca de velocidad, y se aplica al único elemento que de
   verdad importa: el botón que genera la reserva. Sin rebote.
   :focus-visible incluido a propósito — quien navega con teclado ve la misma
   señal que quien usa ratón. */
.btn__chevron { transition: transform var(--dur-fast) var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  .btn--primary:hover .btn__chevron { transform: translateX(3px); }
}
.btn--primary:focus-visible .btn__chevron { transform: translateX(3px); }

/* Sobre violeta el naranja queda a ~3:1 del fondo: el anillo blanco lo despega. */
.section--violet .btn--primary { box-shadow: var(--ring-on-dark); }

/* ── 4.3 · Íconos ──────────────────────────────────────────────────────────
   Contrato único: viewBox 0 0 24 24, fill none, stroke currentColor,
   stroke-width 1.75, remates redondos. */
.icon {
  width: 24px;
  height: 24px;
  flex: none;
  stroke-width: var(--stroke-icon);
}

.icon-box {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  flex: none;
  border-radius: 12px;
  background: var(--a-teal-10);
  color: var(--color-accent);
}
.section--violet .icon-box,
.section--slate .icon-box { background: var(--a-white-10); }

/* ── 4.4 · Tarjetas ────────────────────────────────────────────────────────*/
.card {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  padding: var(--space-md);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  transition: var(--transition-ui);
}
@media (hover: hover) and (pointer: fine) {
  .card--interactive:hover {
    border-color: var(--c-indigo);
    box-shadow: var(--shadow-md);
    transform: translateY(-2px);
  }
}

.card__title { margin-top: var(--space-2xs); }

.card__pain {
  color: var(--color-text-muted);
  font-size: var(--fs-caption);
  line-height: var(--lh-snug);
}

.card__what { color: var(--color-text); }

.card__gain {
  color: var(--color-text);
  font-weight: var(--fw-semibold);
}

.card__foot {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-sm);
  align-items: baseline;
  justify-content: space-between;
  margin-top: auto;
  padding-top: var(--space-sm);
  border-top: 1px solid var(--color-border);
}

.card__price {
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: var(--fw-bold);
  color: var(--c-indigo);
}
.section--violet .card__price,
.section--slate .card__price { color: var(--c-white); }

.card__price small {
  display: block;
  color: var(--color-text-muted);
  font-family: var(--font-body);
  font-size: var(--fs-micro);
  font-weight: var(--fw-regular);
  letter-spacing: normal;
}

.card__cta {
  color: var(--color-link);
  font-weight: var(--fw-semibold);
  font-size: .9375rem;
  text-decoration: underline;
  text-underline-offset: .2em;
}

/* ── 4.5 · Fuente de un dato ───────────────────────────────────────────────
   Cada cifra de la landing lleva su fuente. Es una regla del Manual. */
.source {
  display: block;
  margin-top: var(--space-2xs);
  color: var(--color-text-muted);
  font-size: var(--fs-micro);
  line-height: var(--lh-snug);
}

/* ── 4.6 · Badge / chip ────────────────────────────────────────────────────
   Índigo, nunca naranja: el naranja está reservado a los CTA. */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3xs);
  padding: .25rem .625rem;
  border-radius: var(--radius-pill);
  background: var(--c-indigo);
  color: var(--c-white);
  font-size: var(--fs-micro);
  font-weight: var(--fw-semibold);
  letter-spacing: .02em;
}
.badge--soft {
  background: var(--a-indigo-10);
  color: var(--c-indigo);
}
.section--violet .badge--soft,
.section--slate .badge--soft { background: var(--a-white-10); color: var(--c-white); }

/* ── 4.7 · Estadísticas ────────────────────────────────────────────────────*/
.stat__num {
  display: block;
  font-family: var(--font-display);
  font-size: var(--fs-stat);
  font-weight: var(--fw-bold);
  line-height: 1;
  letter-spacing: var(--ls-tight);
  color: var(--color-heading);
}
.stat__label {
  display: block;
  margin-top: var(--space-2xs);
  color: var(--color-text);
  line-height: var(--lh-snug);
}

/* Barra de datos. Gris = lo que se pierde. El resto queda neutro:
   NO se pinta de teal porque el 29,81% no es lo que V3 recupera. */
.bar {
  display: flex;
  height: 12px;
  margin-top: var(--space-sm);
  border-radius: var(--radius-pill);
  overflow: hidden;
  background: var(--color-data-current);
}
.bar__lost {
  width: 70.19%;
  background: var(--color-data-lost);
  border-right: 2px solid var(--c-white);
}
.bar__legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-md);
  margin-top: var(--space-2xs);
  font-size: var(--fs-micro);
  color: var(--color-text-muted);
}
.bar__key {
  display: inline-block;
  width: .625rem;
  height: .625rem;
  margin-right: .375rem;
  border-radius: 2px;
  vertical-align: baseline;
}
.bar__key--lost { background: var(--color-data-lost); }
.bar__key--current { background: var(--color-data-current); }

/* ── 4.8 · Media ───────────────────────────────────────────────────────────*/
.media {
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--color-bg-alt);
}
.media--1x1 { aspect-ratio: 1 / 1; }
.media--4x5 { aspect-ratio: 4 / 5; }
.media__img { width: 100%; height: 100%; object-fit: cover; }

/* ── 4.9 · Tabla comparativa ───────────────────────────────────────────────
   Se conserva la <table> real: convertirla en bloques con display:block
   destruiría los roles de fila y columna justo en móvil.
   El padding-block permite que la columna destacada sobresalga sin recorte
   (si un eje de overflow no es `visible`, el otro pasa a `auto`). */
.table-scroll {
  overflow-x: auto;
  padding-block: 12px;
  margin-block: -12px;
  -webkit-overflow-scrolling: touch;
}

.cmp {
  width: 100%;
  min-width: 46rem;
  border-collapse: separate;
  border-spacing: 0;
  font-size: .9375rem;
}
.cmp th, .cmp td {
  padding: var(--space-sm);
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--color-border);
}
.cmp thead th {
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: var(--fw-medium);
  color: var(--color-heading);
  border-bottom: 2px solid var(--color-border-strong);
}
.cmp tbody th {
  font-weight: var(--fw-semibold);
  color: var(--color-text);
  background: var(--color-bg);
  position: sticky;
  left: 0;
  z-index: 1;
}
/* La columna de V3 va en 2ª posición para que se vea sin desplazar. */
.cmp .is-v3 {
  background: var(--a-indigo-06);
  color: var(--c-slate);
  font-weight: var(--fw-semibold);
}
.cmp thead .is-v3 {
  background: var(--c-indigo);
  color: var(--c-white);
  border-bottom-color: var(--c-indigo);
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}
.cmp tbody tr:last-child .is-v3 { border-radius: 0 0 var(--radius-sm) var(--radius-sm); }

.cmp__hint {
  margin-bottom: var(--space-sm);
  color: var(--color-text-muted);
  font-size: var(--fs-caption);
}

/* ── 4.10 · Acordeón (<details> nativo) ────────────────────────────────────
   Sin JS de apertura: funciona sin scripts y es buscable con Ctrl+F. */
.acc {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  overflow: hidden;
}
.acc + .acc { margin-top: var(--space-2xs); }

.acc__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  width: 100%;
  min-height: 56px;          /* objetivo táctil holgado */
  padding: var(--space-sm) var(--space-md);
  cursor: pointer;
  list-style: none;
  transition: var(--transition-ui);
}
.acc__q::-webkit-details-marker { display: none; }
@media (hover: hover) and (pointer: fine) {
  .acc__q:hover { background: var(--color-surface-tint); }
}

.acc__q h3, .acc__q h4 { font-size: var(--fs-h4); font-weight: var(--fw-medium); }

.acc__meta {
  margin-left: auto;
  color: var(--color-text-muted);
  font-size: var(--fs-caption);
  font-weight: var(--fw-regular);
  white-space: nowrap;
}

.acc__marker {
  flex: none;
  width: 20px;
  height: 20px;
  color: var(--c-indigo);
  transition: transform var(--dur-base) var(--ease-out);
}
.acc[open] .acc__marker { transform: rotate(180deg); }

.acc__a {
  padding: 0 var(--space-md) var(--space-md);
  color: var(--color-text-muted);
  max-width: var(--measure);
}

/* ── 4.11 · Pasos numerados ────────────────────────────────────────────────*/
.steps { list-style: none; padding: 0; counter-reset: step; }
.steps > li { counter-increment: step; }
.step {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-sm) var(--space-md);
  padding: var(--space-md) 0;
  border-top: 1px solid var(--color-border);
}
.step__num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: var(--radius-pill);
  background: var(--c-indigo);
  color: var(--c-white);
  font-family: var(--font-display);
  font-weight: var(--fw-bold);
  font-size: 1.125rem;
}
.step__num::before { content: "0" counter(step); }
.step__body > * + * { margin-top: var(--space-2xs); }

/* ── 4.12 · Tarjeta de precio ──────────────────────────────────────────────*/
.price-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  padding: var(--space-lg) var(--space-md);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--c-white);
  box-shadow: var(--shadow-sm);
}
.price-card--featured {
  border: 2px solid var(--c-indigo);
  box-shadow: var(--shadow-lg);
}
.price-card__amount {
  font-family: var(--font-display);
  font-size: var(--fs-stat-sm);
  font-weight: var(--fw-bold);
  line-height: 1;
  color: var(--c-indigo);
}
.price-card__amount small {
  display: block;
  margin-bottom: var(--space-3xs);
  color: var(--color-text-muted);
  font-family: var(--font-body);
  font-size: var(--fs-micro);
  font-weight: var(--fw-regular);
}
.price-card__list { list-style: none; padding: 0; display: grid; gap: var(--space-2xs); }
.price-card__list li {
  display: grid;
  grid-template-columns: 20px 1fr;
  gap: var(--space-2xs);
  font-size: .9375rem;
  line-height: var(--lh-snug);
  margin: 0;
}
.price-card__list .icon { width: 20px; height: 20px; color: var(--color-accent); margin-top: 2px; }
.price-card__note {
  color: var(--color-text-muted);
  font-size: var(--fs-caption);
  font-style: italic;
}
.price-note {
  margin-top: var(--space-lg);
  padding: var(--space-md);
  border-left: 3px solid var(--color-border-strong);
  background: var(--color-bg-alt);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  color: var(--color-text-muted);
  font-size: var(--fs-caption);
  max-width: var(--measure);
}
.section--violet .price-note,
.section--slate .price-note { background: var(--a-white-10); }

/* ── 4.13 · Placeholders visibles ──────────────────────────────────────────
   Marcadores deliberadamente visibles para que el dueño no pueda pasarlos por
   alto al editar. La página NO debe publicarse mientras se vean.
   Se quitan borrando el bloque y su tarjeta contenedora. */
.ph {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  align-items: flex-start;
  justify-content: center;
  min-height: 9rem;
  padding: var(--space-md);
  border: 2px dashed var(--c-indigo);
  border-radius: var(--radius-md);
  background: var(--a-indigo-06);
  color: var(--c-indigo);
}
.ph__tag {
  font-family: var(--font-display);
  font-size: .8125rem;
  font-weight: var(--fw-bold);
  letter-spacing: .06em;
}
.ph__hint {
  color: var(--c-gray);
  font-size: var(--fs-micro);
  line-height: var(--lh-snug);
}
.ph--logo { min-height: 5rem; align-items: center; text-align: center; }

/* ── 4.13.1 · Carrusel de marcas ───────────────────────────────────────────
   Cinta continua de logos. Dos grupos idénticos en fila; la animación desplaza
   el conjunto exactamente un 50%, de modo que cuando el primer grupo sale por
   la izquierda el segundo ocupa su lugar y el salto de vuelta a 0 es
   imperceptible. Por eso el track mide justo el doble y se mueve -50%: con
   cualquier otro valor se vería la costura.

   Los logos NO llevan alto uniforme: vienen normalizados por área de tinta
   desde tools/build-logos.py. Imponer `height` aquí desharía esa corrección
   y Factorum volvería a verse gigante al lado de Oled. */
.logos {
  position: relative;
  overflow: hidden;
  /* Desvanece los bordes para que los logos entren y salgan en vez de
     cortarse en seco contra el borde de la sección. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6rem, #000 calc(100% - 6rem), transparent);
          mask-image: linear-gradient(90deg, transparent, #000 6rem, #000 calc(100% - 6rem), transparent);
}
.logos__track { display: flex; width: max-content; }
.logos__set {
  display: flex;
  align-items: center;
  gap: clamp(2rem, 5vw, 4rem);
  margin: 0;
  padding: 0 clamp(1rem, 2.5vw, 2rem) 0 0;
  list-style: none;
}
.logos__set li { margin: 0; }
/* OJO: aquí NO se declaran width ni height. Los archivos están exportados al
   doble (DPR 2) y son los atributos width/height del HTML los que fijan el
   tamaño CSS correcto. Poner `width:auto;height:auto` haría que el navegador
   usara el tamaño intrínseco del archivo y los logos saldrían al doble. */
.logos__set img {
  display: block;
  opacity: .72;
  transition: opacity var(--dur-base) var(--ease-out);
}

/* El movimiento solo existe si el usuario no ha pedido lo contrario. No se
   delega en el kill-switch de 8.3: ese reduce la duración a 0.01ms, lo que
   dejaría la cinta congelada en -50% (es decir, empezando por la mitad). */
@media (prefers-reduced-motion: no-preference) {
  .logos__track { animation: logos-desliza 42s linear infinite; }
  /* Cortesía: al apuntar el carrusel se detiene para poder leer un logo. */
  @media (hover: hover) and (pointer: fine) {
    .logos:hover .logos__track { animation-play-state: paused; }
    .logos__set img:hover { opacity: 1; }
  }
  @keyframes logos-desliza {
    from { transform: translateX(0); }
    to   { transform: translateX(-50%); }
  }
}

/* Con movimiento reducido la cinta se convierte en una rejilla estática: se
   ve todo de golpe, sin desplazamiento. El grupo duplicado sobra ahí. */
@media (prefers-reduced-motion: reduce) {
  .logos { -webkit-mask-image: none; mask-image: none; }
  .logos__track { width: 100%; }
  .logos__set { flex-wrap: wrap; gap: var(--space-lg) var(--space-xl); }
  .logos__set[aria-hidden="true"] { display: none; }
}

/* Sobre fondos oscuros se servirían las variantes -light.png; el carrusel vive
   hoy en una sección clara, así que usa las -dark.png. */

/* ── 4.13.2 · Cita de cliente ──────────────────────────────────────────────
   Sin comillas decorativas gigantes ni foto: el testimonio se sostiene por lo
   que dice y por quién lo firma. La barra índigo de la izquierda basta para
   marcarlo como voz ajena. */
.quote {
  margin: 0;
  padding: var(--space-md) var(--space-md) var(--space-md) var(--space-lg);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--c-indigo);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}
.quote blockquote { margin: 0; }
.quote blockquote p {
  color: var(--color-text);
  font-size: var(--fs-body);
  line-height: var(--lh-snug);
}
.quote figcaption {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2xs) var(--space-xs);
  margin-top: var(--space-sm);
  padding-top: var(--space-sm);
  border-top: 1px solid var(--color-border);
}
.quote__name { font-weight: var(--fw-semibold); color: var(--color-heading); }
.quote__org { color: var(--color-text-muted); font-size: var(--fs-caption); }

/* ── 4.13.25 · Tarjeta de proyecto ─────────────────────────────────────────
   La captura manda: ocupa la parte superior entera y es el enlace principal.
   Relación 16:10 fija para que todas las tarjetas se alineen aunque las
   capturas vengan con alturas distintas.

   El dato de rendimiento (.work__metric) es OPCIONAL a propósito: solo se
   pone en las webs que lo sostienen hoy. En las que el cliente cargó imágenes
   pesadas después de la entrega, se omite en lugar de maquillarlo. */
.works { display: grid; gap: var(--space-lg); }
.work {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  overflow: hidden;
  transition: var(--transition-ui);
}
@media (hover: hover) and (pointer: fine) {
  .work:hover { border-color: var(--c-indigo); box-shadow: var(--shadow-md); transform: translateY(-2px); }
}
.work__shot {
  display: block;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background: var(--color-bg-alt);
  border-bottom: 1px solid var(--color-border);
}
.work__shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;   /* la cabecera de la web es lo que identifica */
  transition: transform var(--dur-slow) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .work:hover .work__shot img { transform: scale(1.03); }
}
.work__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  padding: var(--space-md);
  flex: 1;
}
.work__tag {
  align-self: flex-start;
  padding: .1rem .55rem;
  border-radius: var(--radius-pill);
  background: var(--a-indigo-06);
  color: var(--c-indigo);
  font-size: var(--fs-micro);
  font-weight: var(--fw-semibold);
}
.work__name { font-size: var(--fs-h4); font-weight: var(--fw-medium); }
.work__what {
  color: var(--color-text-muted);
  font-size: var(--fs-caption);
  line-height: var(--lh-snug);
}
/* Dato medido: teal, porque es una señal de lo que sí se sostiene. */
.work__metric {
  padding: var(--space-2xs) var(--space-xs);
  border-radius: var(--radius-xs);
  background: var(--a-teal-10);
  font-size: var(--fs-caption);
  line-height: var(--lh-snug);
}
.work__metric strong { color: var(--color-heading); }
.work__metric .source { display: block; margin-top: var(--space-3xs); }
.work__link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3xs);
  margin-top: auto;
  padding-top: var(--space-2xs);
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  color: var(--color-link);
  text-decoration: none;
}
.work__link:hover { text-decoration: underline; }
.work__link .icon { width: 16px; height: 16px; }

/* Pestaña sin proyectos todavía: se explica por qué en vez de dejar el hueco. */
.works__empty {
  padding: var(--space-lg);
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-md);
  background: var(--color-bg-alt);
  color: var(--color-text-muted);
  font-size: var(--fs-caption);
  line-height: var(--lh-body);
  max-width: var(--measure);
}

@media (min-width: 40rem) { .works { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 64rem) { .works { grid-template-columns: repeat(3, 1fr); } }

/* ── 4.13.3 · Tabs de paquetes ─────────────────────────────────────────────
   Patrón tablist/tab/tabpanel. Los paneles solo se ocultan bajo .js: sin
   JavaScript se ven los seis seguidos y no se pierde nada.
   La barra de tabs hace scroll horizontal en móvil en vez de apilarse: seis
   pestañas apiladas ocuparían la pantalla entera antes de ver un solo precio. */
.tabs__list {
  display: flex;
  gap: var(--space-2xs);
  overflow-x: auto;
  padding-bottom: var(--space-2xs);
  border-bottom: 1px solid var(--color-border);
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
}
.tabs__tab {
  flex: 0 0 auto;
  padding: var(--space-2xs) var(--space-sm);
  min-height: 2.75rem;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  background: none;
  color: var(--color-text-muted);
  font-family: var(--font-body);
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  white-space: nowrap;
  cursor: pointer;
  transition: var(--transition-ui);
}
@media (hover: hover) and (pointer: fine) {
  .tabs__tab:hover { color: var(--c-indigo); background: var(--a-indigo-06); }
}
/* El estado activo no se marca solo con color: lleva fondo sólido, para que
   se distinga también en escala de grises y en alto contraste. */
.tabs__tab[aria-selected="true"] {
  background: var(--c-indigo);
  border-color: var(--c-indigo);
  color: var(--c-white);
}
.tabs__panel { padding-top: var(--space-lg); }
.js .tabs__panel[hidden] { display: none; }

/* SIN JAVASCRIPT: el atributo `hidden` del HTML oculta por sí solo, sin
   esperar a este CSS —lo aplica la hoja del navegador—, así que sin esta
   regla se perderían 12 de los 15 planes. Aquí se anula, se esconde la barra
   de pestañas (inerte sin JS) y cada panel recupera su título desde
   data-titulo, para que se entienda de qué servicio es cada bloque. */
html:not(.js) .tabs__list { display: none; }
html:not(.js) .tabs__panel[hidden] { display: block; }
html:not(.js) .tabs__panel {
  padding-top: var(--space-xl);
  border-top: 1px solid var(--color-border);
  margin-top: var(--space-lg);
}
html:not(.js) .tabs__panel::before {
  content: attr(data-titulo);
  display: block;
  margin-bottom: var(--space-sm);
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: var(--fw-medium);
  color: var(--color-heading);
}

/* El ancla de valor: la cifra del problema ANTES de los precios. */
.tabs__anchor {
  margin-bottom: var(--space-md);
  padding-left: var(--space-sm);
  border-left: 3px solid var(--c-teal);
  color: var(--color-text);
  font-size: var(--fs-lead);
  line-height: var(--lh-snug);
}
.tabs__anchor strong {
  font-family: var(--font-display);
  font-size: 1.35em;
  color: var(--c-indigo);
}
.tabs__anchor .source { display: block; margin-top: var(--space-3xs); }
.tabs__note {
  margin-top: var(--space-md);
  color: var(--color-text-muted);
  font-size: var(--fs-caption);
}

/* ── 4.13.4 · Tarjeta de plan ──────────────────────────────────────────────
   Comparables entre sí: misma altura, precio a la misma altura óptica y el
   botón siempre abajo (margin-top:auto), para que el ojo recorra en columna. */
.plans { display: grid; gap: var(--space-md); }
.plan {
  display: flex;
  flex-direction: column;
  padding: var(--space-md);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}
/* El recomendado: borde índigo y elevación. Nada de escalarlo con transform,
   que rompería la alineación de precios entre tarjetas. */
.plan--best {
  border-color: var(--c-indigo);
  border-width: 2px;
  box-shadow: var(--shadow-md);
}
.plan__flag {
  align-self: flex-start;
  margin-bottom: var(--space-2xs);
  padding: .15rem .6rem;
  border-radius: var(--radius-pill);
  background: var(--c-indigo);
  color: var(--c-white);
  font-size: var(--fs-micro);
  font-weight: var(--fw-semibold);
}
.plan__name {
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  color: var(--color-heading);
}
.plan__price {
  margin-top: var(--space-3xs);
  font-family: var(--font-display);
  font-size: var(--fs-stat-sm);
  font-weight: var(--fw-bold);
  line-height: 1.1;
  color: var(--c-indigo);
}
.plan__price small {
  display: block;
  font-family: var(--font-body);
  font-size: var(--fs-micro);
  font-weight: var(--fw-regular);
  color: var(--color-text-muted);
}
.plan__for {
  margin-top: var(--space-2xs);
  color: var(--color-text-muted);
  font-size: var(--fs-caption);
  line-height: var(--lh-snug);
}
.plan__list {
  margin: var(--space-sm) 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--space-3xs);
}
/* Marca de verificación en CSS: cero peso y hereda el color de acento. */
.plan__list li {
  position: relative;
  padding-left: 1.4rem;
  font-size: var(--fs-caption);
  line-height: var(--lh-snug);
}
.plan__list li::before {
  content: "";
  position: absolute;
  left: .15rem;
  top: .4em;
  width: .4rem;
  height: .7rem;
  border: solid var(--c-teal);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.plan__meta {
  margin-top: var(--space-sm);
  color: var(--color-text-muted);
  font-size: var(--fs-micro);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: .06em;
}
/* La unidad de valor: reencuadra el precio como recuperación. */
.plan__value {
  margin-top: var(--space-2xs);
  padding: var(--space-2xs) var(--space-xs);
  border-radius: var(--radius-xs);
  background: var(--a-teal-10);
  color: var(--color-text);
  font-size: var(--fs-caption);
  line-height: var(--lh-snug);
}
/* Empuja el botón al fondo: todas las tarjetas cierran a la misma altura. */
.plan .btn { margin-top: auto; }
.plan__list + .btn, .plan__meta + .btn, .plan__value + .btn { margin-top: var(--space-md); }

@media (min-width: 40rem) {
  .plans { grid-template-columns: repeat(3, 1fr); align-items: stretch; }
  .plans--2 { grid-template-columns: repeat(2, 1fr); }
}

/* ── 4.14 · Botón flotante de WhatsApp ─────────────────────────────────────
   Superficie BLANCA con borde índigo. Ni verde ni naranja ni índigo sólido:
   un FAB violeta sobre la sección de cierre (también violeta) daría 1.00:1
   y desaparecería por completo. */
.fab-wa {
  position: fixed;
  right: var(--space-sm);
  bottom: var(--space-sm);
  z-index: var(--z-fab);
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  min-height: var(--fab-size);
  min-width: var(--fab-size);
  padding: var(--space-2xs);
  border: 2px solid var(--c-indigo);
  border-radius: var(--radius-pill);
  background: var(--c-white);
  color: var(--c-indigo);
  box-shadow: var(--shadow-fab);
  text-decoration: none;
  transition: var(--transition-ui);
}
.fab-wa .icon { width: 28px; height: 28px; margin-inline: auto; }
.fab-wa__label { display: none; font-weight: var(--fw-semibold); font-size: .9375rem; }
@media (hover: hover) and (pointer: fine) {
  .fab-wa:hover { background: var(--c-indigo); color: var(--c-white); }
}
.fab-wa[hidden] { display: none; }
body[data-nav-open] .fab-wa { visibility: hidden; }


/* ── 4.15 · Retícula decorativa ────────────────────────────────────────────
   Un solo sistema, dos primitivas, 0 KB de imagen. Se activa con el atributo
   data-pattern y hereda la tinta de la sección igual que hacen los --color-*
   con .section--violet / .section--slate: el componente no necesita saber
   sobre qué fondo está pintado.

   POR QUÉ EXISTE: el vacío no se rellena, se ESTRUCTURA. Un cuaderno liso y
   uno cuadriculado llevan la misma tinta y solo uno parece un instrumento.
   Y no es ornamento importado: es la misma malla que la lente del hero
   enfoca (5.3.1), atravesando la página entera.

   REGLA DE DOSIS — INNEGOCIABLE: solo 5 de las 14 secciones llevan patrón
   (hero, #cifras, #problema, #precios, #contacto). Las otras 9 respiran, y
   esa contención ES la mitad del efecto. Rellenarlo todo sería lo contrario
   de premium.

   REGLAS DE COLOR: nunca naranja (exclusivo de superficie de CTA). Nunca
   teal sobre violeta (2.93:1, falla incluso el mínimo de 3:1 para UI). */

[data-pattern] {
  position: relative;
  --pat-ink: var(--a-indigo-10);   /* fondos claros */
  --pat-gap: 26px;                 /* mismo paso que la lente del hero */
}

/* POR QUÉ LOS PATRONES ESPERAN A LAS FUENTES (medido, no teórico):
   las webfonts cargan con display=swap y al llegar (~890ms) cambian las
   métricas del texto y reflotan la página entera. Estos pseudo-elementos son
   cuadrados de hasta 480px anclados al borde de su sección, así que se movían
   con ella y su área disparaba el CLS de 0.013 a 0.107 — por encima del
   umbral de 0.1 de Core Web Vitals.
   Chrome no contabiliza elementos invisibles en el layout shift: manteniendo
   los patrones en opacity:0 hasta que las fuentes están listas, el reflow los
   ignora. Aparecen después, ya en su sitio, con un fundido suave.
   Va gateado por .js — sin JavaScript se muestran de inmediato, porque
   entonces no hay quien añada .fonts-ready. */
.js [data-pattern]::before,
.js [data-pattern]::after { opacity: 0; }
.js.fonts-ready [data-pattern]::before,
.js.fonts-ready [data-pattern]::after {
  opacity: 1;
  transition: opacity var(--dur-reveal) var(--ease-out);
}
.section--slate[data-pattern]  { --pat-ink: rgba(255, 255, 255, .08); }
.section--violet[data-pattern] { --pat-ink: rgba(206, 203, 246, .22); }
.section--violet[data-pattern~="frame"] { --pat-ink: rgba(255, 255, 255, .28); }

/* El contenido SIEMPRE por encima. Sin esto el patrón podría taparlo. */
[data-pattern] > * { position: relative; z-index: 1; }

[data-pattern]::before,
[data-pattern]::after {
  content: "";
  position: absolute;
  z-index: 0;
  pointer-events: none;   /* no roba clics ni foco */
  user-select: none;      /* no entra en la selección de texto */
}

/* ·· Primitiva 1 · MALLA — estructura una esquina vacía ····················*/
[data-pattern~="mesh-tr"]::before,
[data-pattern~="mesh-bl"]::after,
[data-pattern~="mesh-br"]::after {
  width: min(30rem, 46%);
  aspect-ratio: 1;
  background-image:
    radial-gradient(circle at center, var(--pat-ink) 1px, transparent 1.6px);
  background-size: var(--pat-gap) var(--pat-gap);
}
/* La máscara desvanece la malla hacia el contenido: nunca compite con el
   texto y nunca deja un canto duro contra el borde de la sección. */
[data-pattern~="mesh-tr"]::before {
  top: 0; right: 0;
  -webkit-mask-image: radial-gradient(100% 100% at 100% 0, #000 0%, transparent 72%);
          mask-image: radial-gradient(100% 100% at 100% 0, #000 0%, transparent 72%);
}
[data-pattern~="mesh-bl"]::after {
  bottom: 0; left: 0;
  -webkit-mask-image: radial-gradient(100% 100% at 0 100%, #000 0%, transparent 72%);
          mask-image: radial-gradient(100% 100% at 0 100%, #000 0%, transparent 72%);
}
[data-pattern~="mesh-br"]::after {
  bottom: 0; right: 0;
  -webkit-mask-image: radial-gradient(100% 100% at 100% 100%, #000 0%, transparent 72%);
          mask-image: radial-gradient(100% 100% at 100% 100%, #000 0%, transparent 72%);
}

/* ·· Primitiva 2 · ENCUADRE — dos escuadras de visor ·······················
   No es relleno: es el lenguaje del diagnóstico (lo que se mira) y cierra el
   arco que abre la lente del hero. Trazo del mismo grosor que toda la
   iconografía y esquina redondeada, como manda el Manual.
   OJO: --stroke-icon es un número SIN unidad (lo consume stroke-width de
   SVG); para un border CSS hay que multiplicarlo por 1px. */
[data-pattern~="frame"]::before,
[data-pattern~="frame"]::after {
  width: clamp(2.5rem, 4vw, 4rem);
  aspect-ratio: 1;
  border: calc(var(--stroke-icon) * 1px) solid var(--pat-ink);
}
[data-pattern~="frame"]::before {
  top: var(--space-lg);
  left: var(--space-gutter);
  border-right: 0;
  border-bottom: 0;
  border-radius: var(--radius-md) 0 0 0;
}
[data-pattern~="frame"]::after {
  bottom: var(--space-lg);
  right: var(--space-gutter);
  border-left: 0;
  border-top: 0;
  border-radius: 0 0 var(--radius-md) 0;
}

/* Sin soporte de máscara la malla saldría como un rectángulo de canto duro.
   Es decorativa: se retira sin más. El encuadre no usa máscara y se queda. */
@supports not (mask-image: radial-gradient(#000, transparent)) {
  [data-pattern~="mesh-tr"]::before,
  [data-pattern~="mesh-bl"]::after,
  [data-pattern~="mesh-br"]::after { display: none; }
}


/* ═══ 05 · SECCIONES ═══════════════════════════════════════════════════════ */

/* ── 5.1 · Skip link ───────────────────────────────────────────────────────*/
.skip-link {
  position: absolute;
  left: var(--space-sm);
  top: var(--space-sm);
  z-index: var(--z-skiplink);
  padding: var(--space-2xs) var(--space-sm);
  border-radius: var(--radius-sm);
  background: var(--c-indigo);
  color: var(--c-white);
  font-weight: var(--fw-semibold);
  text-decoration: none;
  transform: translateY(-200%);
  transition: transform var(--dur-base) var(--ease-out);
}
.skip-link:focus { transform: translateY(0); color: var(--c-white); }

/* ── 5.2 · Header ──────────────────────────────────────────────────────────*/
.header-sentinel { height: 1px; }

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  background: var(--c-white);
  border-bottom: 1px solid transparent;
  transition: box-shadow var(--dur-base) var(--ease-out),
              border-color var(--dur-base) var(--ease-out);
}
.site-header[data-scrolled] {
  border-bottom-color: var(--color-border);
  box-shadow: var(--shadow-header);
}

/* Con el cajón abierto, el header entero sube por encima del contenido: el
   cajón y su backdrop viven dentro de él y comparten su contexto de apilamiento. */
body[data-nav-open] .site-header { z-index: var(--z-drawer); }

.site-header__inner {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  min-height: var(--header-h);
  /* Orden local de apilamiento DENTRO del header: velo (0) < cajón (1) <
     esta fila (2). Sin esto, el cajón taparía el botón de cerrar y el usuario
     se quedaría sin X visible. */
  position: relative;
  z-index: 2;
}

/* Logo. El área de protección equivale a la altura del nodo del vértice. */
.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  padding: .25em 0;
  text-decoration: none;
  margin-right: auto;
}
.brand__mark { width: 36px; height: 36px; flex: none; }
.brand__text { display: flex; flex-direction: column; line-height: 1; }
.brand__name {
  font-family: var(--font-display);
  font-size: 1.375rem;
  font-weight: var(--fw-bold);
  color: var(--c-indigo);
  letter-spacing: var(--ls-snug);
}
.brand__desc {
  font-family: var(--font-body);
  font-size: .5625rem;
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wordmark);
  color: var(--c-slate);
  text-transform: uppercase;
  margin-top: 2px;
}

/* Navegación: cajón lateral en móvil, fila en escritorio.
   .nav y .nav-backdrop son hermanos de <body>, no hijos del header, para que
   su z-index no quede atrapado en el contexto de apilamiento del sticky. */
.nav {
  position: fixed;
  inset: 0 0 0 auto;
  z-index: 1;                /* local al header — ver .site-header__inner */
  width: min(20rem, 82vw);
  padding: calc(var(--header-h) + var(--space-md)) var(--space-md) var(--space-md);
  background: var(--c-white);
  border-left: 1px solid var(--color-border);
  box-shadow: var(--shadow-lg);
  transform: translateX(100%);
  visibility: hidden;
  transition: transform var(--dur-slow) var(--ease-out),
              visibility 0s linear var(--dur-slow);
  overflow-y: auto;
}
body[data-nav-open] .nav {
  transform: translateX(0);
  visibility: visible;
  transition: transform var(--dur-slow) var(--ease-out), visibility 0s;
}

.nav__list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3xs); }
.nav__list li { margin: 0; }
.nav__link {
  display: flex;
  align-items: center;
  min-height: 3rem;
  padding: var(--space-2xs) var(--space-2xs);
  border-radius: var(--radius-sm);
  color: var(--c-slate);
  font-weight: var(--fw-medium);
  text-decoration: none;
  transition: var(--transition-ui);
}
@media (hover: hover) and (pointer: fine) {
  .nav__link:hover { background: var(--color-surface-tint); color: var(--c-indigo); }
}

.nav-backdrop {
  position: fixed;
  inset: 0;
  z-index: 0;                /* local al header — ver .site-header__inner */
  background: rgba(15, 23, 42, .45);
}
.nav-backdrop[hidden] { display: none; }

.nav-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  flex: none;
  padding: 0;
  /* El cajón (.nav, z-index 1) es su hermano dentro de .site-header__inner y
     se pinta después en el DOM. Sin este z-index el cajón taparía la X y el
     usuario no podría cerrar el menú tocándola. */
  position: relative;
  z-index: 2;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--c-white);
  color: var(--c-slate);
  cursor: pointer;
}
.nav-toggle .icon { width: 22px; height: 22px; }
.nav-toggle__close { display: none; }
.nav-toggle[aria-expanded="true"] .nav-toggle__open { display: none; }
.nav-toggle[aria-expanded="true"] .nav-toggle__close { display: block; }

/* Bajo 640px el CTA del header competiría por el ancho con el logo y la
   hamburguesa. Ahí basta con el CTA del hero, justo debajo, y el botón flotante. */
.header-cta { display: none; }
@media (min-width: 40rem) { .header-cta { display: inline-flex; } }

/* ── 5.3 · Hero ────────────────────────────────────────────────────────────
   Fondo claro, sin fotografía: el LCP es el <h1> de texto, 0 KB sobre el
   pliegue. Los radiales son decorativos y no afectan al contraste del texto. */
.hero {
  position: relative;
  padding-block: var(--space-section);
  background:
    radial-gradient(60rem 30rem at 78% -10%, var(--a-indigo-06), transparent 70%),
    radial-gradient(40rem 24rem at 8% 105%, var(--a-teal-10), transparent 70%),
    var(--color-bg-alt);
  overflow: hidden;
}
.hero__inner { display: grid; gap: var(--space-xl); align-items: center; }
.hero__lead {
  margin-top: var(--space-md);
  max-width: var(--measure);
  font-size: var(--fs-lead);
  line-height: var(--lh-snug);
  color: var(--color-text-muted);
}
.hero h1 { max-width: 18ch; }
/* La segunda frase del H1 en índigo eléctrico sólido.
   Nada de background-clip:text: en forced-colors desaparecería medio titular. */
.hero h1 em { font-style: normal; color: var(--c-indigo-electric); }

.hero__actions { margin-top: var(--space-lg); }
.hero__micro {
  margin-top: var(--space-md);
  max-width: var(--measure);
  color: var(--color-text-muted);
  font-size: var(--fs-caption);
}
.hero__trust {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-md);
  margin-top: var(--space-md);
  padding: 0;
  list-style: none;
  color: var(--color-text-muted);
  font-size: var(--fs-caption);
}
.hero__trust li { margin: 0; }

/* Diagrama decorativo de la fuga. Geometría deliberadamente DISTINTA a la del
   isotipo: el Manual prohíbe deformar o recolorear el logo. */
.hero__figure { display: none; }
.leak { width: 100%; height: auto; }


/* ── 5.3.1 · Lente de diagnóstico ──────────────────────────────────────────
   El cursor "escanea" el hero y sube la resolución de la retícula de fondo.
   Es el producto de entrada de V3 —el diagnóstico gratis— hecho gesto.

   EL TRUCO CENTRAL está en background-position, más abajo: la retícula se
   CONTRA-TRASLADA, así queda anclada a la página y no al cursor. Sin esa
   línea el efecto es un foco genérico persiguiendo el ratón; con ella, el
   cursor revela una estructura que ya estaba ahí. Que es, literalmente, lo
   que V3 vende: el dinero ya está en tu web.

   El .hero ya es position:relative + overflow:hidden — no hace falta tocarlo.
   La malla estática de fondo NO se declara aquí: viene del sistema de
   patrones (4.15) vía data-pattern. Una sola fuente de verdad.

   CONTRATO DE RENDIMIENTO
     · --mx/--my se escriben SOBRE .hero__lens, JAMÁS sobre .hero. Escribirlas
       en el padre invalidaría el estilo de todos sus descendientes —incluido
       el <h1>, que es el elemento LCP— en cada frame.
     · El transform lo escribe el JS directo sobre el elemento, no vía
       variable: así la capa se mueve sin recalcular custom properties.
     · Solo transform y background-position. Cero top/left, cero filter.
     · will-change vive detrás de [data-lens], que solo pone el JS cuando de
       verdad va a animar. En táctil no se reserva memoria de GPU. */

.hero__lens {
  /* Las escribe el JS. El valor inicial evita un salto en el primer frame. */
  --mx: -50vw;
  --my: -50vh;
  --lens-size: 30rem;

  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;                       /* por debajo del contenido de 4.15 */
  width: var(--lens-size);
  height: var(--lens-size);
  /* Centrado con margen negativo, no con un segundo translate: así el
     transform queda libre para una sola operación y el JS no hace cuentas. */
  margin: calc(var(--lens-size) / -2) 0 0 calc(var(--lens-size) / -2);
  pointer-events: none;
  user-select: none;
  opacity: 0;
  transform: translate3d(var(--mx), var(--my), 0);

  /* Halo difuso. Un radial-gradient ya tiene borde suave: aquí NO hace falta
     máscara. Índigo eléctrico al 10% máximo: sobre #F8FAFC el texto slate se
     queda muy por encima del AAA. */
  background: radial-gradient(closest-side,
    rgba(67, 56, 202, .10) 0%,
    rgba(67, 56, 202, .05) 46%,
    transparent 72%);
}

/* El JS activa la capa. La opacidad la conduce --lens-o para que entrar y
   salir del hero sea un desvanecido y no un corte. */
.hero[data-lens] .hero__lens {
  opacity: var(--lens-o, 0);
  transition: opacity var(--dur-slow) var(--ease-out);
  will-change: transform;
}

/* Retícula fina: lo que la lente "resuelve". Malla de 26px reforzada + grid
   de 13px = el diagnóstico ve el doble de detalle que el ojo desnudo. */
.hero__lens::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(circle at center, rgba(76, 29, 149, .26) 1px, transparent 1.6px),
    repeating-linear-gradient(90deg, rgba(67, 56, 202, .06) 0 1px, transparent 1px 13px),
    repeating-linear-gradient(0deg,  rgba(67, 56, 202, .06) 0 1px, transparent 1px 13px);
  background-size: 26px 26px, auto, auto;

  /* LA LÍNEA QUE LO CAMBIA TODO. Contra-traslación: al moverse la capa +X, su
     fondo se desplaza -X, de modo que la retícula permanece fija respecto a
     la página. La lente enfoca; no arrastra. */
  background-position: calc(var(--mx) * -1) calc(var(--my) * -1);

  /* Apertura circular difusa. Sin bordes duros: un canto nítido pegado al
     cursor delataría el retraso del rAF y se leería como "roto". */
  -webkit-mask-image: radial-gradient(closest-side, #000 0%, rgba(0,0,0,.55) 42%, transparent 70%);
          mask-image: radial-gradient(closest-side, #000 0%, rgba(0,0,0,.55) 42%, transparent 70%);
}

/* Sin soporte de máscara la retícula saldría como un cuadrado de bordes
   duros. Se retira y queda el halo suave: degradación digna, no rota. */
@supports not (mask-image: radial-gradient(#000, transparent)) {
  .hero__lens::before { display: none; }
}

/* La lente es de escritorio. En viewports chicos no compensa repintar la
   capa por frame, y el JS tampoco engancha nada ahí. */
@media (max-width: 63.99rem) {
  .hero__lens { display: none; }
}

/* ── 5.4 · Barra de cifras ─────────────────────────────────────────────────*/
.stats { display: grid; gap: var(--space-lg); }
.stats__closing {
  margin-top: var(--space-lg);
  padding-top: var(--space-md);
  border-top: 1px solid var(--color-border);
  color: var(--color-heading);
  font-family: var(--font-display);
  font-size: var(--fs-h4);
}

/* ── 5.4.1 · La oferta ─────────────────────────────────────────────────────
   La pieza de conversión de la página. Es la ÚNICA que lleva naranja fuera de
   un botón, y solo como filete lateral de 3px: el naranja sigue sin usarse
   como superficie (regla 1 del encabezado), pero marca inequívocamente dónde
   está la oferta. Contra #FFFFFF el filete da 3.56:1, por encima del 3:1 que
   piden los elementos gráficos no textuales. */
.offer {
  position: relative;
  padding: var(--space-lg) var(--space-md) var(--space-lg) var(--space-lg);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--c-orange);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  box-shadow: var(--shadow-md);
}
.offer__kicker {
  color: var(--color-text-muted);
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
}
.offer__title {
  margin-top: var(--space-2xs);
  font-size: var(--fs-h2);
  line-height: var(--lh-heading);
}
/* La segunda frase en índigo eléctrico: es donde está el gancho. */
.offer__title em { font-style: normal; color: var(--c-indigo-electric); }
.offer__lead {
  margin-top: var(--space-sm);
  max-width: var(--measure);
  font-size: var(--fs-lead);
  line-height: var(--lh-snug);
  color: var(--color-text-muted);
}
.offer__list {
  display: grid;
  gap: var(--space-2xs);
  margin-top: var(--space-md);
  padding: 0;
  list-style: none;
}
/* La marca de verificación se dibuja con CSS: cero peso, y hereda el color de
   acento de la sección sin depender del sprite de iconos. */
.offer__list li {
  position: relative;
  padding-left: 1.75rem;
  line-height: var(--lh-snug);
}
.offer__list li::before {
  content: "";
  position: absolute;
  left: .25rem;
  top: .45em;
  width: .5rem;
  height: .85rem;
  border: solid var(--c-teal);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.offer__actions {
  margin-top: var(--space-lg);
  align-items: center;
}
.offer__price {
  color: var(--color-text-muted);
  font-size: var(--fs-caption);
}
.offer__foot {
  margin-top: var(--space-md);
  padding-top: var(--space-sm);
  border-top: 1px solid var(--color-border);
  color: var(--color-text-muted);
  font-size: var(--fs-caption);
  line-height: var(--lh-snug);
}
@media (min-width: 48rem) {
  .offer { padding: var(--space-xl) var(--space-xl) var(--space-xl) var(--space-2xl); }
  .offer__list { grid-template-columns: 1fr 1fr; gap: var(--space-xs) var(--space-md); }
}

/* ── 5.5 · Problema ────────────────────────────────────────────────────────*/
.leak-list { display: grid; gap: var(--space-md); margin-top: var(--space-xl); }
.leak-item {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-sm) var(--space-md);
  padding: var(--space-md);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}
.leak-item__body > * + * { margin-top: var(--space-2xs); }
.leak-item h3 { font-size: var(--fs-h4); font-weight: var(--fw-medium); }

/* ── 5.6 · Sobre V3 ────────────────────────────────────────────────────────*/
.split { display: grid; gap: var(--space-xl); align-items: start; }
.founder-facts {
  display: grid;
  gap: var(--space-2xs);
  margin-top: var(--space-md);
  padding: var(--space-md);
  border-radius: var(--radius-md);
  background: var(--c-white);
  border: 1px solid var(--color-border);
  list-style: none;
  padding-left: var(--space-md);
  font-size: .9375rem;
}
.founder-facts li { margin: 0; }
.founder-facts strong { color: var(--c-indigo); }
.founder-media { display: grid; gap: var(--space-sm); }

/* ── 5.7 · CTA final ───────────────────────────────────────────────────────*/
.cta-final { text-align: center; }
.cta-final .section__intro { margin-inline: auto; }
.cta-final__actions { justify-content: center; margin-top: var(--space-lg); }
.urgency {
  max-width: 44rem;
  margin: var(--space-xl) auto 0;
  padding: var(--space-md);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--a-white-10);
  font-size: .9375rem;
  line-height: var(--lh-snug);
}
.cta-final__micro { margin-top: var(--space-md); font-size: var(--fs-caption); }

/* ── 5.7.1 · Páginas legales ───────────────────────────────────────────────
   Documentos de lectura larga: una sola columna estrecha, jerarquía marcada y
   nada de decoración. Comparten tokens con el resto del sitio, así que un
   cambio de marca las alcanza sin tocarlas. */
.legal { padding-block: var(--space-2xl) var(--space-3xl); }
.legal__head {
  padding-bottom: var(--space-lg);
  margin-bottom: var(--space-xl);
  border-bottom: 1px solid var(--color-border);
}
.legal__updated {
  margin-top: var(--space-2xs);
  color: var(--color-text-muted);
  font-size: var(--fs-caption);
}
.legal h2 {
  margin-top: var(--space-2xl);
  font-size: var(--fs-h3);
  scroll-margin-top: var(--scroll-offset);
}
.legal h3 {
  margin-top: var(--space-lg);
  font-size: var(--fs-h4);
  font-weight: var(--fw-semibold);
}
.legal p, .legal li { max-width: var(--measure); }
.legal p { margin-top: var(--space-sm); }
.legal ul, .legal ol { margin-top: var(--space-sm); padding-left: var(--space-md); }
.legal li { margin-top: var(--space-2xs); }
.legal dl { margin-top: var(--space-sm); }
.legal dt { margin-top: var(--space-sm); font-weight: var(--fw-semibold); color: var(--color-heading); }
.legal dd { margin: var(--space-3xs) 0 0; max-width: var(--measure); }

/* Ficha de datos de la empresa: bloque destacado al inicio del documento. */
.legal__card {
  padding: var(--space-md);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--c-indigo);
  border-radius: var(--radius-md);
  background: var(--color-bg-alt);
}
.legal__card dl { display: grid; gap: var(--space-2xs); margin: 0; }
.legal__card dt { margin: 0; font-size: var(--fs-caption); }
.legal__card dd { margin: 0; }

/* Índice de secciones al principio del documento. */
.legal__toc {
  padding: var(--space-md);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}
.legal__toc ol { margin: var(--space-2xs) 0 0; }
.legal__toc li { margin-top: var(--space-3xs); }

/* Aviso de que el documento debe revisarlo un abogado. Es informativo y no
   decorativo: por eso lleva rol de nota y no solo color. */
.legal__notice {
  margin-top: var(--space-lg);
  padding: var(--space-md);
  border: 1px dashed var(--c-orange);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  color: var(--color-text);
  font-size: var(--fs-caption);
  line-height: var(--lh-snug);
}
.legal__notice strong { color: var(--c-indigo); }

@media (min-width: 48rem) {
  .legal__card dl { grid-template-columns: max-content 1fr; gap: var(--space-2xs) var(--space-md); }
}

/* ── 5.7.2 · Blog: buscador, filtros y listado ─────────────────────────────
   Lo usan dos páginas con públicos opuestos: blog/index.html (clientes, solo
   artículos publicados) y blog/plan.html (interna, los 200 planificados).
   Mismo mecanismo, mismos estilos.

   MEJORA PROGRESIVA, y aquí no es un adorno: sin JavaScript el buscador y los
   filtros SE OCULTAN —serían controles muertos— y el listado se ve entero.
   Nadie se queda sin poder leer. De ahí el html.js de los selectores.
   ─────────────────────────────────────────────────────────────────────────*/

/* Controles muertos fuera: sin JS no filtran nada. */
html:not(.js) .blog-buscador { display: none; }

.blog-buscador { margin-bottom: var(--space-lg); }

/* El campo. La lupa es un <svg> hermano posicionado encima, no un
   background-image: así hereda currentColor y sobrevive al alto contraste. */
.blog-buscador__campo { position: relative; }

.blog-buscador__lupa {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: var(--space-xs);
  translate: 0 -50%;
  width: 1.125rem;
  height: 1.125rem;
  color: var(--color-text-muted);
  pointer-events: none;                 /* el clic debe llegar al input */
}

.blog-buscador__input {
  width: 100%;
  /* Sangría izquierda = lupa + su margen. Si cambias una, cambia la otra. */
  padding: var(--space-xs) var(--space-xl) var(--space-xs) 2.5rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
  font-size: var(--fs-body);
}
.blog-buscador__input::placeholder { color: var(--color-text-muted); }

/* Botón de limpiar. Aparece solo con texto escrito: el JS conmuta [hidden]. */
.blog-buscador__limpiar {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-end: var(--space-3xs);
  translate: 0 -50%;
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--color-text-muted);
  cursor: pointer;
}
.blog-buscador__limpiar:hover { color: var(--color-text); background: var(--color-surface-tint); }
.blog-buscador__limpiar svg { width: 1rem; height: 1rem; }

/* Fila de filtros. Cada grupo es un <fieldset> sin marco: los filtros son un
   conjunto de controles relacionados y su <legend> los nombra al lector de
   pantalla, que si no oye trece botones sueltos sin contexto. */
.blog-filtros { display: grid; gap: var(--space-sm); margin-top: var(--space-sm); }
.blog-filtros fieldset { min-width: 0; padding: 0; border: 0; margin: 0; }

.blog-filtros legend {
  padding: 0;
  margin-bottom: var(--space-2xs);
  color: var(--color-text-muted);
  font-size: var(--fs-micro);
  font-weight: var(--fw-semibold);
  letter-spacing: .06em;
  text-transform: uppercase;
}

.blog-filtros__lista { display: flex; flex-wrap: wrap; gap: var(--space-3xs); }

/* Chip. Es un <button> real con aria-pressed, no un div con clase: así entra
   en el orden de tabulación y anuncia su estado sin trabajo extra. */
.chip {
  padding: var(--space-3xs) var(--space-2xs);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  background: var(--color-surface);
  color: var(--color-text-muted);
  font: inherit;
  font-size: var(--fs-caption);
  line-height: var(--lh-snug);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out);
}
.chip:hover { color: var(--color-text); border-color: var(--color-border-strong); }

/* Activo: violeta sobre lavanda. 9.10:1, holgado sobre AA.
   El peso 600 acompaña al color: el estado no puede vivir solo en la tinta,
   o un daltónico no distingue un chip pulsado de uno sin pulsar. */
.chip[aria-pressed="true"] {
  border-color: var(--c-indigo);
  background: var(--a-indigo-10);
  color: var(--c-indigo);
  font-weight: var(--fw-semibold);
}

.chip__n { opacity: .65; font-variant-numeric: tabular-nums; }

/* Recuento de resultados. aria-live="polite" en el HTML: al filtrar, el
   lector de pantalla anuncia cuántos quedan sin robar el foco del campo. */
.blog-resultado {
  margin-bottom: var(--space-md);
  color: var(--color-text-muted);
  font-size: var(--fs-caption);
}
.blog-resultado strong { color: var(--color-text); font-variant-numeric: tabular-nums; }

/* Listado */
.blog-lista { display: grid; gap: var(--space-2xs); margin: 0; padding: 0; list-style: none; }

.blog-item {
  display: grid;
  gap: var(--space-3xs);
  padding: var(--space-sm);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}

.blog-item__titulo {
  margin: 0;
  font-size: var(--fs-h4);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  color: var(--color-heading);
}
/* Cuando el post existe, el título es enlace y toda la tarjeta es zona de
   clic. El ::after cubre la tarjeta; por eso la tarjeta necesita position. */
.blog-item:has(a) { position: relative; }
.blog-item__titulo a { color: inherit; text-decoration: none; }
.blog-item__titulo a::after { content: ""; position: absolute; inset: 0; }
.blog-item__titulo a:hover { color: var(--color-link); }

.blog-item__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3xs) var(--space-2xs);
  font-size: var(--fs-micro);
  color: var(--color-text-muted);
}

/* Etiqueta de tarjeta: pasiva, no es un control. Por eso <span> y no button. */
.blog-tag {
  padding: 1px var(--space-3xs);
  border-radius: var(--radius-xs);
  background: var(--color-bg-alt);
  color: var(--color-text-muted);
}

/* Marca de «esto solo lo puedes escribir tú».
   Va en --fs-micro (12px), así que necesita 4.5:1 y el teal de marca solo da
   3.32:1 sobre su propio 10%. De ahí --c-teal-800: 6.73:1.
   Nunca sobre violeta, que daría 2.93:1 y está prohibido en el sistema. */
.blog-item__propio {
  padding: 1px var(--space-3xs);
  border-radius: var(--radius-xs);
  background: var(--a-teal-10);
  color: var(--c-teal-800);
  font-weight: var(--fw-semibold);
}

/* Sin coincidencias. El JS conmuta su [hidden]. */
.blog-vacio {
  padding: var(--space-xl) var(--space-md);
  border: 1px dashed var(--color-border);
  border-radius: var(--radius-md);
  text-align: center;
  color: var(--color-text-muted);
}

/* ── Cuerpo del artículo ───────────────────────────────────────────────────
   Los artículos reutilizan .legal (misma medida de lectura, mismos h2/h3).
   Esto es solo lo que el Markdown produce y .legal no cubría. */

/* Portada del artículo. La imagen es el LCP: dimensiones fijas en el HTML
   (1200×630) y aspect-ratio aquí reservan el hueco → cero CLS mientras carga. */
.blog-hero {
  margin: 0 0 var(--space-lg);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--color-surface-tint);   /* color de marca mientras llega */
}
.blog-hero img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1200 / 630;
  object-fit: cover;
}
.blog-hero__credito {
  padding: var(--space-2xs) var(--space-xs);
  font-size: var(--fs-micro);
  color: var(--color-text-muted);
}
.blog-hero__credito a { color: inherit; }

/* Miniatura en las tarjetas del índice. */
.blog-item__thumb {
  display: block;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--color-surface-tint);
}
.blog-item__thumb img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1200 / 630;
  object-fit: cover;
}
.blog-item__cuerpo { display: grid; gap: var(--space-3xs); align-content: start; }

/* En escritorio, la tarjeta con imagen es miniatura + texto en dos columnas.
   Sobrescribe la rejilla 1fr/auto que usa la tarjeta de solo texto. */
@media (min-width: 40rem) {
  .blog-item--con-img {
    grid-template-columns: 15rem 1fr;
    gap: var(--space-md);
    align-items: start;
  }
  .blog-item--con-img .blog-item__meta { justify-content: flex-start; }
}

/* Tabla. La envuelve el generador en .tabla-scroll: una tabla ancha DEBE
   desplazarse dentro de su caja, nunca empujar el ancho de la página. Sin
   esto, un móvil de 390px con una tabla de 4 columnas acaba con scroll
   horizontal en todo el documento. */
.tabla-scroll {
  overflow-x: auto;
  margin-top: var(--space-md);
  -webkit-overflow-scrolling: touch;
}
.tabla-scroll table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-caption);
}
.tabla-scroll th,
.tabla-scroll td {
  padding: var(--space-2xs) var(--space-xs);
  border-bottom: 1px solid var(--color-border);
  text-align: left;
  vertical-align: top;
}
.tabla-scroll th {
  color: var(--color-heading);
  font-weight: var(--fw-semibold);
  white-space: nowrap;
}

/* Lista de fuentes al final del artículo. Deliberadamente sobria: no compite
   con el contenido, pero tiene que estar visible. Es lo que separa un
   artículo con criterio de uno que se inventa los números. */
.blog-fuentes {
  margin-top: var(--space-sm);
  padding-left: var(--space-md);
  font-size: var(--fs-caption);
  color: var(--color-text-muted);
}
.blog-fuentes li { margin-top: var(--space-2xs); max-width: var(--measure); }
/* La URL se rompe donde haga falta: una fuente con URL larga no debe
   provocar scroll horizontal en móvil. */
.blog-fuentes a { overflow-wrap: anywhere; }

.legal blockquote {
  margin: var(--space-md) 0;
  padding-left: var(--space-md);
  border-left: 3px solid var(--c-indigo);
  color: var(--color-text-muted);
  font-style: italic;
}
.legal blockquote p { margin: 0; max-width: var(--measure); }

.legal pre {
  overflow-x: auto;
  margin-top: var(--space-md);
  padding: var(--space-sm);
  border-radius: var(--radius-md);
  background: var(--c-slate);
  color: var(--c-offwhite);          /* 17.06:1 — verificado */
  font-size: var(--fs-caption);
  line-height: var(--lh-snug);
}
.legal pre code { background: none; color: inherit; padding: 0; }

.legal :not(pre) > code {
  padding: 1px var(--space-3xs);
  border-radius: var(--radius-xs);
  background: var(--color-bg-alt);
  color: var(--c-indigo);            /* 10.47:1 sobre offwhite */
  font-size: .9em;
}

/* El texto que casa con la búsqueda. <mark> trae fondo amarillo del navegador
   que rompe la paleta, así que se repinta entero. */
.blog-item mark {
  padding: 0 1px;
  border-radius: 3px;
  background: var(--a-teal-16);
  color: inherit;
  font-weight: var(--fw-semibold);
}

@media (min-width: 48rem) {
  .blog-filtros { grid-template-columns: 1fr; }
  /* Solo las tarjetas SIN imagen usan el layout título/fecha en dos columnas.
     Las que tienen miniatura ya llevan el suyo (miniatura + cuerpo) y esta
     regla, más abajo en la cascada, lo pisaría si no se excluyeran. */
  .blog-item:not(.blog-item--con-img) { grid-template-columns: 1fr auto; align-items: start; }
  .blog-item:not(.blog-item--con-img) .blog-item__meta { justify-content: flex-end; }
}

/* ── 5.7.3 · Formularios ───────────────────────────────────────────────────
   Los usa el Libro de Reclamaciones. El sitio casi no tiene formularios (el
   contacto va por WhatsApp/Cal), así que esto es deliberadamente contenido. */
.form { margin-top: var(--space-lg); }
.form__grupo { margin-top: var(--space-md); }
.form__fieldset {
  margin-top: var(--space-md);
  padding: var(--space-md);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}
.form__fieldset legend {
  padding: 0 var(--space-2xs);
  font-weight: var(--fw-semibold);
  color: var(--color-heading);
}
.form__label {
  display: block;
  margin-bottom: var(--space-3xs);
  font-size: var(--fs-caption);
  font-weight: var(--fw-medium);
  color: var(--color-heading);
}
/* El asterisco de obligatorio no debe leerse solo por color. */
.form__req { color: var(--c-orange-700); }

.form__input,
.form__textarea,
.form__select {
  width: 100%;
  padding: var(--space-2xs) var(--space-xs);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-text);
  font-size: var(--fs-body);
}
.form__textarea { min-height: 7rem; resize: vertical; }
.form__input:focus-visible,
.form__textarea:focus-visible,
.form__select:focus-visible {
  outline: 3px solid var(--color-focus);
  outline-offset: 1px;
  border-color: var(--color-focus);
}

/* Grupo de radios (tipo de reclamación). Cada opción es una etiqueta grande
   y clicable, no un radio diminuto. */
.form__radios { display: grid; gap: var(--space-2xs); margin-top: var(--space-2xs); }
.form__radio {
  display: flex;
  gap: var(--space-2xs);
  align-items: flex-start;
  padding: var(--space-xs);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.form__radio:hover { border-color: var(--color-border-strong); }
.form__radio input { margin-top: .2em; }
.form__radio strong { color: var(--color-heading); }
.form__radio small { display: block; color: var(--color-text-muted); }

.form__ayuda { margin-top: var(--space-3xs); font-size: var(--fs-micro); color: var(--color-text-muted); }

.form__foot { margin-top: var(--space-lg); }

/* Aviso de error/estado. Naranja-700 para que el texto cumpla contraste. */
.form__aviso {
  margin-top: var(--space-md);
  padding: var(--space-sm);
  border: 1px solid var(--c-orange-700);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  color: var(--color-text);
  font-size: var(--fs-caption);
}
.form__aviso strong { color: var(--c-orange-700); }

/* Campo trampa antispam: invisible para humanos, tentador para bots. */
.form__trampa { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

@media (min-width: 40rem) {
  .form__fila { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-md); }
}

/* ── 5.8 · Footer ──────────────────────────────────────────────────────────
   El aire inferior para que el botón flotante no tape el último contenido va
   AQUÍ y no en el body: en el body dejaba una franja blanca visible por debajo
   del footer, porque el footer es slate y el body blanco. Dentro del footer,
   ese mismo espacio queda en su color. */
.site-footer {
  padding-block: var(--space-2xl) calc(var(--fab-size) + var(--space-lg));
}
.site-footer__grid { display: grid; gap: var(--space-xl); }
.site-footer h3 {
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  font-family: var(--font-body);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--c-white);
  margin-bottom: var(--space-sm);
}
.site-footer ul { list-style: none; padding: 0; display: grid; gap: var(--space-2xs); }
.site-footer li { margin: 0; }
.site-footer a { color: var(--color-text); text-decoration: none; }
.site-footer a:hover { color: var(--c-white); text-decoration: underline; }

/* El isotipo conserva sus colores originales, así que sobre slate necesita
   una placa blanca: el vértice #4C1D95 sobre #0F172A daría 1.63:1. */
.brand__plate {
  display: inline-flex;
  padding: .25em;
  border-radius: 12px;
  background: var(--c-white);
}
.site-footer .brand__name { color: var(--c-white); }
.site-footer .brand__desc { color: var(--c-indigo-light); }

.footer-tagline {
  margin-top: var(--space-sm);
  color: var(--c-white);
  font-family: var(--font-display);
  font-size: var(--fs-h4);
  max-width: 22ch;
}
.boilerplate {
  margin-top: var(--space-xl);
  padding-top: var(--space-md);
  border-top: 1px solid var(--color-border);
  color: var(--color-text);
  font-size: var(--fs-caption);
  line-height: var(--lh-body);
  max-width: var(--measure);
}
.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-md);
  align-items: center;
  margin-top: var(--space-md);
  padding-top: var(--space-md);
  border-top: 1px solid var(--color-border);
  font-size: var(--fs-micro);
  color: var(--color-text);
}


/* ═══ 06 · RESPONSIVE ══════════════════════════════════════════════════════ */

/* ── ≥ 640px ───────────────────────────────────────────────────────────────*/
@media (min-width: 40rem) {
  .grid--2 { grid-template-columns: repeat(2, 1fr); }
  .grid--4 { grid-template-columns: repeat(2, 1fr); }
  .stats { grid-template-columns: repeat(3, 1fr); gap: var(--space-md); }
  .leak-list { grid-template-columns: repeat(2, 1fr); }
  .site-footer__grid { grid-template-columns: repeat(2, 1fr); }
  .step { grid-template-columns: auto 1fr; }
}

/* ── ≥ 768px ───────────────────────────────────────────────────────────────*/
@media (min-width: 48rem) {
  .grid--3 { grid-template-columns: repeat(3, 1fr); }
  .card { padding: var(--space-lg); }
  .price-card { padding: var(--space-xl) var(--space-lg); }
  .hero__figure { display: block; }
  .hero__inner { grid-template-columns: 1.15fr .85fr; }
}

/* ── ≥ 1024px ──────────────────────────────────────────────────────────────*/
@media (min-width: 64rem) {
  .grid--4 { grid-template-columns: repeat(4, 1fr); }
  .split { grid-template-columns: 1fr 22rem; gap: var(--space-3xl); }
  .site-footer__grid { grid-template-columns: 1.4fr 1fr 1fr 1.2fr; }
  .cmp { min-width: 0; }
  .cmp__hint { display: none; }

  /* La navegación deja de ser cajón y pasa a fila. */
  .nav {
    position: static;
    width: auto;
    padding: 0;
    background: none;
    border: 0;
    box-shadow: none;
    transform: none;
    visibility: visible;
    overflow: visible;
    transition: none;
  }
  .nav__list { grid-auto-flow: column; gap: var(--space-2xs); align-items: center; }
  .nav__link { min-height: 2.5rem; padding-inline: var(--space-xs); }
  .nav-toggle { display: none; }
  .fab-wa__label { display: block; padding-right: var(--space-2xs); }
}


/* ═══ 07 · UTILIDADES ══════════════════════════════════════════════════════ */

.u-visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.u-measure { max-width: var(--measure); }
.u-center { text-align: center; }
.u-mt-lg { margin-top: var(--space-lg); }
.u-mt-xl { margin-top: var(--space-xl); }


/* ═══ 08 · A11Y · MOTION · PRINT · FORCED-COLORS ═══════════════════════════ */

/* ── 8.1 · Foco visible ────────────────────────────────────────────────────
   Sin :where() para que tenga especificidad real y no la pise otra regla.
   Prohibido `outline:none` sin sustituto. Prohibido tocar el border-radius
   dentro de la regla de foco. */
a:focus-visible,
button:focus-visible,
summary:focus-visible,
[tabindex="0"]:focus-visible,
.table-scroll:focus-visible {
  outline: var(--focus-width) solid var(--color-focus);
  outline-offset: var(--focus-offset);
  box-shadow: 0 0 0 8px var(--color-focus-halo);
}

/* Los destinos de ancla reciben foco programático: no deben dibujar un anillo
   alrededor de un bloque entero. */
[tabindex="-1"]:focus-visible,
[tabindex="-1"]:focus { outline: none; box-shadow: none; }

/* Sobre violeta el anillo del CTA se encadena con el de superficie. */
.section--violet .btn--primary:focus-visible {
  outline-color: var(--c-white);
  box-shadow: var(--ring-on-dark), 0 0 0 8px var(--c-slate);
}

/* ── 8.2 · Reveal on scroll ────────────────────────────────────────────────
   Solo se oculta bajo .js: si el JS falla o está desactivado, el contenido
   permanece visible. Nunca se anima lo que está sobre el pliegue. */
@media (prefers-reduced-motion: no-preference) {
  .js .reveal {
    opacity: 0;
    transform: translateY(12px);
    transition:
      opacity var(--dur-reveal) var(--ease-out) var(--reveal-delay, 0ms),
      transform var(--dur-reveal) var(--ease-out) var(--reveal-delay, 0ms);
  }
  .js .reveal.is-visible { opacity: 1; transform: none; }

  /* El hook --reveal-delay llevaba desde el día uno consumido en la
     transición de arriba pero nunca definido. Definirlo aquí escalona los
     grupos sin tocar ni una línea de JS.
     Escalones de 70ms: el rango sano es 30-80ms entre elementos; por encima
     se percibe lento.
     TECHO DE 210ms A PROPÓSITO: 210 + 520 de duración = 730ms, muy por debajo
     del failsafe inline de 2s de index.html. Un retardo mayor haría que el
     failsafe pisara la animación a media entrada. */
  :is(.grid, .stats, .leak-list, .steps) > .reveal:nth-child(2)   { --reveal-delay:  70ms; }
  :is(.grid, .stats, .leak-list, .steps) > .reveal:nth-child(3)   { --reveal-delay: 140ms; }
  :is(.grid, .stats, .leak-list, .steps) > .reveal:nth-child(n+4) { --reveal-delay: 210ms; }
}

/* ── 8.2.1 · Entrada orquestada del hero ───────────────────────────────────
   Un momento orquestado impacta más que cinco efectos dispersos.

   POR QUÉ VA TODO DENTRO DE (no-preference) Y NO SE DELEGA EN 8.3:
   el kill-switch de 8.3 resetea animation-duration pero NO animation-delay.
   Un `animation-delay: 280ms` con fill:both dejaría el elemento en su estado
   `from` —invisible— durante 280ms incluso con movimiento reducido activo.
   Aquí las reglas directamente no existen si el usuario pide menos movimiento.

   POR QUÉ NO USA .reveal NI --reveal-delay:
   .reveal se oculta bajo la clase .js. Aplicarlo al hero pondría el <h1> a
   opacity:0 hasta que main.js (defer) se ejecutara, retrasando el LCP.
   Esta secuencia es CSS puro: arranca en el primer frame de paint.

   POR QUÉ NO SE ANIMA NINGÚN CONTENEDOR:
   Chrome no contabiliza como pintado un elemento —ni a sus descendientes— si
   tiene opacity:0. Un wrapper desvanecido retrasaría el LCP el delay entero.
   Se animan las piezas una a una, nunca el envoltorio. */
@media (prefers-reduced-motion: no-preference) {

  .hero .eyebrow,
  .hero__lead,
  .hero__actions,
  .hero__micro,
  .hero__trust,
  .hero__figure {
    animation: v3-hero-rise var(--dur-reveal) var(--ease-out) both;
  }

  /* EL H1 ES EL LCP: nunca parte de opacity:0, solo se desplaza. El transform
     mueve DÓNDE se dibuja, no CUÁNDO — el LCP se registra en el primer paint.
     Y conceptualmente el titular es el punto fijo: no aparece, se asienta.
     Recorrido de 8px y sin rebote ("la marca no rebota"). */
  .hero h1 {
    animation: v3-hero-settle 560ms var(--ease-out) both;
    animation-delay: 40ms;
  }

  /* Escalonado de 30-80ms entre piezas consecutivas. La secuencia cierra en
     ~800ms: ágil, sin hacer esperar al que vino a leer la oferta. */
  .hero .eyebrow  { animation-delay:   0ms; }
  .hero__lead     { animation-delay: 110ms; }
  .hero__figure   { animation-delay: 150ms; }
  .hero__actions  { animation-delay: 180ms; }
  .hero__micro    { animation-delay: 240ms; }
  .hero__trust    { animation-delay: 280ms; }

  /* Último compás: las tres barras se llenan. Es el remate del argumento —se
     ve el dinero escapándose— y por eso va anclado a la carga y no al scroll:
     un dato que se reanima cada vez que lo miras es chartjunk.
     transform-box:fill-box es OBLIGATORIO: sin él, transform-origin en un
     elemento SVG se resuelve contra el viewBox y las barras salen disparadas. */
  .leak__fill {
    transform-box: fill-box;
    transform-origin: left center;
    animation: v3-leak-fill 520ms var(--ease-out) both;
  }
  .leak > g:nth-of-type(1) .leak__fill { animation-delay: 340ms; }
  .leak > g:nth-of-type(2) .leak__fill { animation-delay: 400ms; }
  .leak > g:nth-of-type(3) .leak__fill { animation-delay: 460ms; }

  @keyframes v3-hero-rise   { from { opacity: 0; transform: translateY(10px); } }
  @keyframes v3-hero-settle { from { transform: translateY(8px); } }
  /* La barra crece dentro de un track ya visible: no aparece de la nada. */
  @keyframes v3-leak-fill   { from { transform: scaleX(0); } }
}

/* ── 8.3 · Movimiento reducido ─────────────────────────────────────────────*/
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .reveal { opacity: 1 !important; transform: none !important; }
}

/* ── 8.4 · Pantallas muy bajas: reflow real, no landscape de móvil ─────────*/
@media (max-width: 30rem) and (max-height: 30rem) {
  .site-header { position: static; }
  .fab-wa { position: static; margin: var(--space-md) auto; }
  body { padding-bottom: var(--space-lg); }
}

/* ── 8.5 · Modo de alto contraste de Windows ───────────────────────────────
   Sin forced-color-adjust:none — la jerarquía se marca con grosor de borde,
   no anulando las preferencias del usuario. */
@media (forced-colors: active) {
  .card, .price-card, .btn, .fab-wa, .acc, .leak-item { border: 1px solid ButtonText; }
  .btn--primary { border-width: 3px; }
  .icon-box { border: 1px solid ButtonText; }
  /* La decoración pura no sobrevive al alto contraste: ahí el usuario pide
     señal, no textura. */
  [data-pattern]::before, [data-pattern]::after, .hero__lens { display: none; }
}

/* ── 8.6 · Impresión ───────────────────────────────────────────────────────*/
@media print {
  .site-header, .nav, .nav-backdrop, .fab-wa, .skip-link, .hero__figure { display: none !important; }
  [data-pattern]::before, [data-pattern]::after, .hero__lens { display: none !important; }
  body { padding: 0; color: #000; background: #fff; }
  .section, .hero { padding-block: 1.5rem; background: #fff !important; color: #000 !important; }
  .section--violet, .section--slate { background: #fff !important; color: #000 !important; }
  .acc__a { display: block !important; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: .8em; }
}
