/* GENERADO POR scripts/build-css.mjs — NO EDITAR A MANO.
   Se edita el archivo suelto correspondiente y se corre `npm run build:css`.
   Fuentes, en orden de cascada:
     css/people.css
     css/customization.css
     css/steps.css
     css/testimonials.css
     css/faq.css
     css/cta-final.css
     css/footer.css
     css/video-modal.css
 */

/* ── css/people.css ────────────────────────────────── */
.people {
  position: relative;
  background: #fff;
  /* clip (no hidden): recorta las decos igual PERO no crea scroll container, así
     no atrapa el position:sticky del abanico mobile (que rompía el pin en todos
     los navegadores). Mismo criterio que .features. */
  overflow: clip;
  margin-top: -2px;   /* cierra la brecha de 1px de subpixel con features-scroll-track */
  z-index: 1;         /* garantiza stacking por encima del track purple */
}

/* Decos — diseño Figma (node 3180:27669): garabatos + sparkle */
.people__deco-teal {
  position: absolute;
  left: 10%;
  bottom: 0%;
  width: 6.5rem;
  height: auto;
  pointer-events: none;
  z-index: 0;
  animation: float-slow 6s ease-in-out infinite;
}

.people__deco-yellow {
  position: absolute;
  left: 6%;
  bottom: 2%;
  width: 5.75rem;
  height: auto;
  pointer-events: none;
  z-index: 0;
}

.people__deco-sparkle {
  position: absolute;
  right: 10%;
  top: 20%;
  width: 8.1875rem;
  height: 8.1875rem;
  pointer-events: none;
  z-index: 0;
  overflow: visible;
}

.people__deco-line {
  opacity: 0;
}

.people__header {
  position: relative;
  z-index: 1;
  margin-bottom: var(--space-20);
}

/* Título — Figma node: 3.75rem / line-height 88.3% / regular 400 + bold 700 */
.people .section-title {
  font-size: clamp(2rem, 1.5rem + 2.5vw, 3.75rem);
  line-height: 0.883;
  font-weight: 400;
}

.people .section-title strong {
  font-weight: 700;
}

.people__grid,
.people__cta {
  position: relative;
  z-index: 1;
}

.people__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-6);
  margin-bottom: var(--space-10);
  align-items: start;
}

/* ── Card shell ── */
.persona-card {
  border-radius: var(--radius-xl);
  overflow: hidden;
  position: relative;
  cursor: pointer;
  transition: transform var(--transition-base);
}

.persona-card:hover {
  transform: translateY(-8px);
}

.persona-card--purple { box-shadow: inset 0 0 0 9px var(--color-brand-purple); }
.persona-card--pink   { box-shadow: inset 0 0 0 9px var(--color-brand-magenta); }
.persona-card--teal   { box-shadow: inset 0 0 0 9px var(--color-brand-teal-dark); }

/* Face image — en flujo, da la altura a la card */
.persona-card__img-face {
  width: 100%;
  height: auto;
  display: block;
  transition: opacity var(--transition-base);
}

/* Hover image — absoluta, se intercambia con fade */
.persona-card__img-hover {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  opacity: 0;
  transition: opacity var(--transition-base);
}

/* Gradient intenso — solo en estado hover/expanded */
.persona-card::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--transition-base);
}
.persona-card--purple::before {
  background: linear-gradient(181deg, rgba(148, 118, 255, 0.00) 9.53%, var(--color-card-purple) 46.09%);
}
.persona-card--pink::before {
  background: linear-gradient(181deg, rgba(240, 40, 143, 0.00) 9.53%, var(--color-card-pink) 46.09%);
}
.persona-card--teal::before {
  background: linear-gradient(181deg, rgba(13, 130, 136, 0.00) 9.53%, var(--color-card-teal) 46.09%);
}
.persona-card.is-expanded::before { opacity: 1; }

/* Gradient suave — solo en estado face */
.persona-card__gradient {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  transition: opacity var(--transition-base);
}
.persona-card--purple .persona-card__gradient {
  background: linear-gradient(172deg, rgba(148, 118, 255, 0.00) 31.05%, rgba(135, 104, 245, 0.45) 93.78%);
}
.persona-card--pink .persona-card__gradient {
  background: linear-gradient(172deg, rgba(240, 40, 143, 0.00) 31.05%, rgba(240, 40, 143, 0.45) 93.78%);
}
.persona-card--teal .persona-card__gradient {
  background: linear-gradient(175deg, rgba(17, 170, 178, 0.00) 31.32%, rgba(17, 170, 178, 0.45) 87.29%);
}

/* Label compacto — visible en default */
.persona-card__label {
  position: absolute;
  bottom: var(--space-4);
  left: var(--space-4);
  right: var(--space-4);
  padding: var(--space-5) var(--space-6);
  border-radius: 1rem;
  color: #fff;
  z-index: 2;
  transition: opacity var(--transition-base);
}
/* Fondos oscurecidos: el texto blanco del label/panel necesita 4.5:1. Con los
   tonos de marca quedaba en 3.94 / 3.89:1. El borde de la carta sigue en el tono
   vivo, así que la marca no se apaga.
   El teal usa --color-card-teal (4.60:1 con blanco), igual que las otras
   dos cartas usan su tono oscurecido. */
.persona-card--purple .persona-card__label { background: var(--color-card-purple); }
.persona-card--pink   .persona-card__label { background: var(--color-card-pink); }
.persona-card--teal   .persona-card__label { background: var(--color-card-teal); }

.persona-card__label h3 {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 700;
  margin-bottom: var(--space-1);
  line-height: 1.2;
}
.persona-card__label p {
  font-size: max(13px, var(--fs-sm));
  line-height: 1.4;
}

/* Panel de detalle — crece hacia arriba desde el bottom */
.persona-card__detail {
  position: absolute;
  bottom: var(--space-4);
  left: var(--space-4);
  right: var(--space-4);
  z-index: 3;
  border-radius: 1.5rem;
  overflow: hidden;
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  pointer-events: none;
  /* grid-template-rows anima layout, pero dentro de un panel absoluto que no
     empuja a nadie: no hay CLS ni reflow de la página. */
  transition: grid-template-rows var(--motion-reveal) var(--ease-out-soft),
              opacity var(--motion-base) ease;
}
.persona-card--purple .persona-card__detail { background: var(--color-card-purple); }
.persona-card--pink   .persona-card__detail { background: var(--color-card-pink); }
.persona-card--teal   .persona-card__detail { background: var(--color-card-teal); }

/* Hijo directo del grid — necesita min-height:0 para colapsar a 0fr */
.persona-card__detail-inner {
  min-height: 0;
  overflow: hidden;
  padding: var(--space-6);
  color: #fff;
}

.persona-card__detail-inner h3 {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 700;
  margin-bottom: var(--space-3);
  line-height: 1.2;
}

.persona-card__tagline {
  font-weight: 700;
  font-size: var(--fs-body);
  margin-bottom: var(--space-4);
  line-height: 1.4;
}

.persona-card__list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.persona-card__list li {
  font-size: max(13px, var(--fs-sm));
  line-height: 1.4;
  padding-left: var(--space-5);
  position: relative;
}
.persona-card__list li::before {
  content: '•';
  position: absolute;
  left: 0;
  font-weight: 900;
}


/* La carta entera se eleva un poco al abrirse. Con `translate` y no
   `transform`: GSAP deja un transform inline tras la entrada escalonada y lo
   pisaría. */
.persona-card {
  transition: translate var(--motion-base) var(--ease-out-soft);
}

.persona-card.is-expanded {
  translate: 0 -0.375rem;
}

/* ── Estado expandido ── */
.persona-card.is-expanded .persona-card__img-face  { opacity: 0; }
.persona-card.is-expanded .persona-card__img-hover { opacity: 1; }
.persona-card.is-expanded .persona-card__gradient  { opacity: 0; }
.persona-card.is-expanded .persona-card__label     { opacity: 0; pointer-events: none; }
.persona-card.is-expanded .persona-card__detail    { grid-template-rows: 1fr; opacity: 1; pointer-events: auto; }

/* ── CTA ── */
.people__cta {
  text-align: center;
}

.people__accent-word {
  position: relative;
  display: inline-block;
}

.people__accent-word .section-title__underline {
  position: absolute;
  bottom: -1rem;
  left: -1rem;
  width: 12rem;
  height: auto;
  max-width: none;
  transform: none;
}

/* ══════════════════════════════════════════════════════════════════════
   MOBILE (<769px) — Figma node 3398:27723
   Abanico de 3 cartas superpuestas y rotadas (stack interactivo).
   Cada carta muestra su contenido completo siempre; el JS rota cuál
   queda al frente al tocar/deslizar. Sin interacción todavía se ve el
   abanico estático (nth-child), tal cual el mockup.
   ══════════════════════════════════════════════════════════════════════ */
@media (max-width: 48rem) {

  /* Padding superior: empuja el título/grid hacia abajo dentro de la sección.
     Así, al pinear el grid con 'center 60%', el borde superior de la sección
     queda más arriba (el blanco se extiende sobre el viewport) y tapa la franja
     morada de features que asomaba. También aporta aire arriba → más centrado. */
  .people {
    padding-top: clamp(4rem, 18vw, 8rem);
  }

  /* Sangrado lateral igual que .problem > .container: ~53.75px @430px, 96px @768px.
     Coincide con el left del título/tag en Figma (~57px). */
  .people > .container {
    padding-inline: clamp(2.5rem, 12.5vw, 6rem);
  }

  /* Título — Figma node 3398:27691: Sour Gummy 40px, line-height 40px (1.0).
     40px @430px = 9.3vw. El ancho de columna que crea el padding-inline fuerza
     los saltos exactos: "Pensada para / quienes hacen" (regular) →
     "posible el jardín / cada día." (bold). */
  .people .section-title {
    font-size: var(--fs-h2);
    line-height: 1;
    text-align: left;
  }

  /* Subrayado: vw para mantener la proporción con la palabra "jardín" en todo el rango mobile */
  .people__accent-word .section-title__underline {
    width: clamp(7rem, 31vw, 15.5rem);       /* 156px @ 430px */
    left: clamp(-1.6rem, -3.02vw, -0.8rem);     /* -13px @ 430px */
    bottom: clamp(-1.6rem, -1vw, 0.5rem);   /* -13px @ 430px */
  }

  /* --card-w vive en .people para que el stack (grid) Y las decoraciones
     compartan el mismo ancho de referencia. */
  /* Ancho de carta = proporción Figma (260/430 ≈ 60vw, afinado a 65vw) constante
     en TODO el rango mobile. Sin tope: el 21.5rem previo lo achicaba a 344px
     (44vw) en 768px; ahora sigue el 65vw (≈499px @768) → proporcional siempre.
     Solo piso (12rem) para pantallas < ~240px. */
  .people { --card-w: max(12rem, 65vw); }

  /* ── Decoraciones — Figma nodes 4440:28336 (teal) y 4440:28338 (sparkle) ──
     Posición y tamaño anclados a var(--card-w): así siguen al stack de cartas
     en vez de irse a los bordes del viewport cuando la carta topa en 21.5rem
     (>~529px). Sin esto se ven bien en 430px pero se alejan en 768px.
     teal: abajo-izquierda; sparkle: arriba-derecha del stack. */
  .people__deco-teal {
    left: calc(50% - 0.70 * var(--card-w));      /* ≈ borde izq. de la carta izquierda */
    top: auto;
    bottom: 9%;
    width: calc(var(--card-w) * 0.168);          /* ≈47px @430px */
    z-index: 2;                                   /* Figma: decos encima de las cartas */
  }
  .people__deco-sparkle {
    left: auto;
    right: calc(50% - 0.75 * var(--card-w));      /* ≈ borde der. de la carta derecha */
    /* ≈20px encima del tope del grid. El grid empieza tras el header, cuya altura
       la manda el título (9.3vw × 4 líneas ≈ 37vw) + tag + margen (≈9rem). Con vw
       sigue el tope de las cartas aunque estas crezcan, en vez de depender de la
       altura total de la sección (que se dispara con cartas más altas). */
    top: calc(37.2vw + 14rem);
    width: calc(var(--card-w) * 0.34);            /* ≈95px @430px */
    height: calc(var(--card-w) * 0.34);
    z-index: 2;
  }

  /* ── Contenedor del abanico ──
     Ancho de carta proporcional: 279px @ 430px (0.634 del ancho de la
     imagen 734×1158, que da la altura exacta de la carta). */
  .people__grid {
    /* --card-w se hereda de .people (arriba) */
    display: block;
    position: relative;
    /* la altura real la fija el JS (mide la carta más alta); este min-height
       es el fallback sin-JS para que el abanico no colapse */
    min-height: calc(var(--card-w) * 1.85);
    /* El gesto vertical se lo queda el navegador (scroll de página) y el
       horizontal llega al JS como swipe entre cartas. */
    touch-action: pan-y;
  }

  /* ── Carta: centrada por margin, el transform queda libre para el abanico ──
     El borde de color YA viene en la imagen .1; sin borde ni sombra CSS. */
  .people__grid .persona-card {
    position: absolute;
    top: 0;
    left: 50%;
    width: var(--card-w);
    margin-left: calc(var(--card-w) / -2);
    opacity: 1;   /* el abanico mobile no usa el reveal de opacidad de .reveal */
    border: none;
    box-shadow: none;
    /* overflow:hidden + border-radius del desktop recortan el ::before a la
       forma redondeada de la imagen .1 (que ya trae borde y esquinas) */
    transform-origin: center center;
    transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1);
    cursor: pointer;
  }
  .people__grid .persona-card:hover { transform: none; }   /* anula el lift de desktop */

  /* Cycling disparado por scroll (pin en ui.js): sin transición. La transición
     de 0.5s de arriba es para tap/swipe (cambio discreto); en scroll compite
     con el movimiento continuo y se ve como un temblor. */
  .people__grid.people__grid--no-transition .persona-card { transition: none; }

  /* ── Posiciones del abanico (reposo y fallback sin-JS / motion reducido) ──
     translateX en % del ancho de la carta, translateY en % del alto.
     Son los MISMOS slots del 0% del ciclado: así no hay salto al entrar el
     scroll-driven, y el fallback no hereda el 35% del mockup de Figma, que
     empujaba la carta derecha fuera del viewport y le cortaba el texto. */
  .people__grid .persona-card:nth-child(1) {          /* Directivos — centro/frente */
    transform: translate(0, 8%) rotate(0deg);
    z-index: 3;
  }
  .people__grid .persona-card:nth-child(2) {          /* Profesores — derecha, atrás */
    transform: translate(15%, 17%) rotate(6.31deg);
    z-index: 1;
  }
  .people__grid .persona-card:nth-child(3) {          /* Papás y mamás — izquierda, atrás */
    transform: translate(-18%, -2%) rotate(-4.03deg);
    z-index: 2;
  }

  /* ── Slots controlados por JS (ganan por orden de fuente, misma specificity) ──
     El z-index va acá y no solo en el nth-child: el nth-child es fijo y las
     cartas rotan, así que sin esto la que pasaba al frente quedaba tapada por
     la que dejaba el frente. Escalonado frente > izquierda > derecha, igual que
     el reposo. */
  .people__grid .persona-card.is-front { transform: translate(0, 8%)     rotate(0deg);     z-index: 3; }
  .people__grid .persona-card.is-left  { transform: translate(-18%, -2%) rotate(-4.03deg); z-index: 2; }
  .people__grid .persona-card.is-right { transform: translate(15%, 17%)  rotate(6.31deg);  z-index: 1; }

  /* El foco no puede quedar invisible: la carta del frente es la parada de
     tabulador del abanico. Va por fuera del borde redondeado de la imagen. */
  .people__grid .persona-card:focus-visible {
    outline: 3px solid var(--color-purple-dark);
    outline-offset: 4px;
    border-radius: 1.5rem;
  }

  /* ── Puntos de paginación ──
     Mismos tokens que .problem__dots: acá el fondo de la sección también es
     blanco. El paso entre puntos es el de .features__dots (ancho del botón, sin
     gap): con 44px + gap la fila se estiraba y se leía como una barra. */
  .people__dots {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 0;
    margin-top: clamp(0.5rem, 2vw, 1rem);
    margin-bottom: var(--space-8);
  }

  /* El punto se ve pequeño; el botón conserva los 44px de alto de objetivo
     táctil con padding transparente. */
  .people__dot {
    display: flex;
    align-items: center;
    justify-content: center;
    width: clamp(32px, 9vw, 40px);
    height: 44px;
    padding: 0;
    border: none;
    background: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }

  .people__dot::before {
    content: '';
    display: block;
    width: clamp(0.5rem, 2.1vw, 0.75rem);
    height: clamp(0.5rem, 2.1vw, 0.75rem);
    border-radius: var(--radius-full);
    background: var(--color-border);
    transition: background var(--transition-fast), transform var(--transition-fast);
  }

  /* El tamaño acompaña al color: quien no distinga bien los tonos igual ve cuál
     está activo. */
  .people__dot[aria-selected="true"]::before {
    background: var(--color-purple);
    transform: scale(1.35);
  }

  .people__dot:focus-visible {
    outline: 3px solid var(--color-purple-dark);
    outline-offset: -8px;
    border-radius: var(--radius-full);
  }

  /* El abanico ya no se mueve con el scroll vertical: se retiraron el pin de
     1.7 viewports, el bloque sticky y los tres ciclados por keyframes. Cambiar
     de carta es ahora un acto aparte —tap, swipe horizontal o flechas— y lo
     resuelve ui.js moviendo las clases de slot de aquí arriba. */

  /* ── Internos de la carta en mobile ── */
  .people__grid .persona-card__gradient,
  .people__grid .persona-card__label,
  .people__grid .persona-card__img-face { display: none; }

  /* Imagen .1 (people_N.1) = card completa: borde de color + foto arriba +
     área para el panel abajo. En flujo, da la altura exacta de la carta. */
  .people__grid .persona-card__img-hover {
    position: relative;
    inset: auto;
    width: 100%;
    height: auto;
    object-fit: initial;
    opacity: 1;
    display: block;
  }

  /* Gradiente intenso siempre visible: funde la foto hacia el color del panel */
  .people__grid .persona-card::before { opacity: 1; }

  /* Panel de detalle: permanentemente expandido, inset y redondeado */
  .people__grid .persona-card__detail {
    grid-template-rows: 1fr;
    opacity: 1;
    pointer-events: none;                 /* el tap lo maneja la carta entera */
    left: calc(var(--card-w) * 0.072);
    right: calc(var(--card-w) * 0.072);
    bottom: calc(var(--card-w) * 0.072);
    border-radius: calc(var(--card-w) * 0.09);
  }
  /* Figma mobile pinta el panel en el tono claro de la carta, pero ahí el texto
     blanco se quedaba en 3.34 / 2.97 / 2.83:1. Purple y pink usan el fondo
     accesible del desktop; el teal conserva el tono claro por decisión de diseño.
     El borde de la carta (que viene en la imagen .1) conserva el tono vivo. */
  .people__grid .persona-card--purple .persona-card__detail { background: var(--color-card-purple); }
  .people__grid .persona-card--pink   .persona-card__detail { background: var(--color-card-pink); }
  .people__grid .persona-card--teal   .persona-card__detail { background: var(--color-card-teal); }

  /* ── Texto del panel — Figma node 3398:27696 (base 367px) ──
     Título 30px, tagline+ítems 18px, sin viñetas, blanco. */
  .people__grid .persona-card__detail-inner {
    padding: calc(var(--card-w) * 0.062);
    padding-top: calc(var(--card-w) * 0.068);  /* TX top 30px vs lados 23px */
  }
  .people__grid .persona-card__detail-inner h3 {
    font-size: max(0.95rem, calc(var(--card-w) * 0.082));   /* 30px @367 */
    line-height: 1;
    margin-bottom: calc(var(--card-w) * 0.044);             /* gap 16px @367 */
  }
  .people__grid .persona-card__tagline {
    font-size: max(12px, calc(var(--card-w) * 0.055));      /* 18px @367, Poppins Bold */
    font-weight: 700;
    line-height: 1.2;
    margin-bottom: calc(var(--card-w) * 0.040);             /* ~una línea en blanco */
  }
  /* Sin viñetas: en Figma son líneas de texto separadas por un blanco */
  .people__grid .persona-card__list { gap: calc(var(--card-w) * 0.034); }
  .people__grid .persona-card__list li {
    font-size: max(12px, calc(var(--card-w) * 0.055));      /* 18px @367, Poppins Medium */
    font-weight: 500;
    line-height: 1.2;
    padding-left: 0;
  }
  .people__grid .persona-card__list li::before { content: none; }

  /* CTA — el JS lo mueve fuera de la sección pineada (aparece al terminar el
     cycling). Al quedar como hermano posterior necesita su propio ritmo vertical.
     SIN padding-inline: .container ya pone la calle lateral, y duplicarla dejaba
     el botón en 160px a 320px — ahí el texto del CTA se partía en dos líneas y
     se salía de la píldora (que tiene alto fijo). */

  /* Botón del CTA — mismo tamaño que .features__cta--mobile .btn */
  .people__cta .btn {
    width: clamp(15rem, 67.2vw, 33rem);           /* 289px @ 430px */
    height: clamp(2.75rem, 12.1vw, 6rem);         /* 52px @ 430px */
    border-radius: clamp(1.375rem, 6.05vw, 3rem); /* 26px @ 430px */
    font-size: max(14px, var(--fs-body));
    line-height: 1;
  }
}

}

/* Abanico móvil: el texto de las cartas de atrás asomaba cortado por el borde
   de la de adelante ("Pa… Viv… Fo…") y se leía como ruido. Se desvanece solo
   a la vista — sigue en el árbol de accesibilidad — y vuelve al pasar al
   frente. */
@media (max-width: 48rem) {
  .people__grid .persona-card .persona-card__detail-inner {
    transition: opacity var(--motion-base) ease;
  }

  .people__grid .persona-card:not(.is-front) .persona-card__detail-inner {
    opacity: 0;
  }
}

/* ── css/customization.css ────────────────────────────────── */
/* ═══════════════════════════════════════════════════════════════
   CUSTOMIZATION SECTION
   Layout: 2 columnas
   Col 1 (42%): texto + CTA
   Col 2 (58%): visual — blob + panel + phones fan + sticks,
                todo con position:absolute dentro del mismo stacking context
═══════════════════════════════════════════════════════════════ */

.customization {
  padding-top: calc(var(--space-section) + 5rem);
  padding-bottom: calc(var(--space-section) + 16rem);
  position: relative;
  overflow: hidden;
}

.customization__bg-clip {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}

.customization__bg {
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: auto;
  display: block;
}

/* ─── Grid 2 columnas ─── */
.customization__inner {
  display: grid;
  grid-template-columns: 30fr 70fr;
  gap: clamp(1.5rem, 3vw, 3.5rem);
  align-items: center;
  position: relative;
  z-index: 1;
}

/* ─────────────────────────────────────────────
   COL 1 — TEXTO
───────────────────────────────────────────── */
.customization__left {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
  align-items: flex-start;
}

.customization__left .section-title {
  font-size: var(--fs-h1);
  font-weight: 400;
  line-height: 0.95;
  margin: 0;
  width: 100%;
  text-align: left;
}

.customization__left .section-title strong {
  font-weight: 700;
}

.customization__title-accent {
  color: var(--color-purple);
  font-weight: 700;
  display: block;
}

.customization__title-line {
  display: block;
  width: clamp(10rem, 22vw, 20rem);
  height: auto;
  margin-top: var(--space-2);
}

.customization__desc {
  font-size: var(--fs-body);
  font-weight: 500;
  color: var(--color-text);
  line-height: 1.5;
  margin: 0;
}

/* ─────────────────────────────────────────────
   COL 2 — VISUAL (position:relative, altura fija)
───────────────────────────────────────────── */
.customization__visual {
  position: relative;
  height: clamp(32rem, 50vw, 44rem);
}

/* ─── Blob decorativo de fondo (z:0) ─── */
.customization__blob {
  position: absolute;
  right: -10%;
  top: 5%;
  width: 75%;
  height: 85%;
  background: radial-gradient(
    ellipse 58% 52% at 52% 48%,
    rgba(236, 72, 153, 0.42) 0%,
    rgba(167, 139, 250, 0.22) 48%,
    transparent 70%
  );
  border-radius: 50%;
  pointer-events: none;
  z-index: 0;
}

/* ─────────────────────────────────────────────
   PANEL DE FEATURES (z:1, detrás de phones)
───────────────────────────────────────────── */
.customization__panel {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  border-radius: clamp(0.75rem, 1.5625vw, 1.875rem);
  background: rgba(241, 241, 241, 0.80);
  padding: clamp(1.25rem, 2.5vw, 3rem);
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--space-3);
  z-index: 1;
}

@keyframes brilliant-shine {
  0%, 100% { transform: scale(1) rotate(0deg); }
  50%       { transform: scale(1.2) rotate(15deg); }
}

.customization__brilliant {
  position: absolute;
  top: clamp(0.6rem, -0.75vw, 0.5rem);
  right: clamp(-0.8rem, -0.58vw, -0.5rem);
  width: clamp(2.8rem, 5.83vw, 7rem);
  pointer-events: none;
  transform-origin: center;
  animation: brilliant-shine 5s ease-in-out infinite;
}

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

.customization__feature {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  padding: clamp(0.4rem, 0.83vw, 1rem) clamp(0.675rem, 1.4vw, 1.6875rem);
  border-radius: 1.5rem;
  width: clamp(8.25rem, 80%, 19.75rem);
  min-height: clamp(4.4rem, 9.17vw, 11rem);
}

.customization__feature--teal { background: var(--color-pill-teal); }
.customization__feature--lila { background: var(--color-tab-gallery); }
.customization__feature--pink { background: var(--color-pill-pink); }

/* Ícono en una ficha blanca (antes emojis: 🎨 🏷️ 🤍, que cambian de dibujo
   según el sistema y el lector los anunciaba). */
/* Sticker 3D (🎨 🏷️ 🤍 como calcomanías, ya no emojis planos). */
.customization__feature-icon {
  display: block;
  flex-shrink: 0;
  font-size: clamp(2.6rem, 3.6vw, 4rem);
  rotate: -6deg;
}

/* Desktop: las tarjetas del panel se elevan un poco al pasar el mouse. En
   móvil su transform lo maneja el carrusel, así que va acotado. */
@media (hover: hover) and (min-width: 48.0625rem) {
  .customization__feature {
    transition: transform var(--motion-base) var(--ease-spring);
  }

  .customization__feature:hover {
    transform: translateY(-0.3rem) rotate(-1deg);
  }
}

.customization__feature h3 {
  font-family: var(--font-body);
  font-size: var(--fs-lg);
  font-weight: 700;
  color: var(--color-text);
  line-height: 1.2;
  margin: 0;
}

.customization__feature p {
  font-family: var(--font-body);
  font-size: var(--fs-lg);
  font-weight: 500;
  color: var(--color-text);
  line-height: 1.2;
  margin: 0;
  margin-top: var(--space-2);
}

/* Sin override de color: la rosa usa el mismo texto oscuro que la teal y la lila.
   Con texto blanco quedaba en 2.97:1 sobre #FF53AB —la única de las tres que no
   cumplía AA—; en oscuro da 5.75:1 y el rosa de marca no se toca. */

/* ─────────────────────────────────────────────
   PHONES FAN (z:2, encima del panel)
   Contenedor ocupa el 62% izquierdo del visual.
   Los phones son absolute dentro de este contenedor.
───────────────────────────────────────────── */
.customization__phones {
  position: absolute;
  inset: 0;
  z-index: 2;
}

.customization__phone {
  position: absolute;
  aspect-ratio: 561 / 1147;
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center top;
  border-radius: 11%;
  transition:
    transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1),
    box-shadow 0.35s ease,
    filter 0.35s ease;
}

/* Crossfade del ciclado de imágenes (startPhoneCycling en animations.js):
   ::after precarga la imagen siguiente y se funde encima de la actual — la
   imagen base solo se reemplaza cuando el overlay ya la cubre por completo,
   así el cambio de fondo por debajo queda invisible (nunca hay salto ni
   instante en blanco). */
.customization__phone::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background-image: var(--phone-bg-next, none);
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center top;
  opacity: 0;
  transition: opacity var(--transition-slow);
  pointer-events: none;
  /* Mantener el overlay en su propia capa de composición: sin esto, iOS Safari
     crea/destruye la capa al animar opacity sobre un background-image grande y
     muestra un parpadeo de un frame en el móvil (invisible en desktop). */
  transform: translateZ(0);
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  will-change: opacity;
}

.customization__phone.is-crossfading::after {
  opacity: 1;
}

/* phone--1: fondo, arriba-centro */
.customization__phone--1 {
  width: 40%;
  top: -8%;
  left: 2%;
  z-index: 1;
}
.customization__phone--1:hover {
  transform: scale(1.1) translateY(-6%);
  z-index: 10;
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.22), 0 6px 16px rgba(135, 104, 245, 0.18);
}

/* phone--2: derecha-medio, tilt derecha */
/* Teléfonos 2–4 suben un 4% (el 1, el de atrás, queda fijo): así la flecha
   de la etiqueta 2 queda cerca de su teléfono. */
.customization__phone--2 {
  width: 40%;
  top: 11%;
  left: 32%;
  transform: translateX(-50%) rotate(7deg);
  z-index: 2;
}
.customization__phone--2:hover {
  transform: translateX(-50%) rotate(7deg) scale(1.1) translateY(-6%);
  z-index: 10;
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.22), 0 6px 16px rgba(135, 104, 245, 0.18);
}

/* phone--3: izquierda, tilt izquierda fuerte */
.customization__phone--3 {
  width: 40%;
  top: 30%;
  left: 17%;
  transform: translateX(-50%) rotate(-13deg);
  z-index: 3;
}
.customization__phone--3:hover {
  transform: translateX(-50%) rotate(-13deg) scale(1.1) translateY(-6%);
  z-index: 10;
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.22), 0 6px 16px rgba(135, 104, 245, 0.18);
}

/* phone--4: frente-centro-bajo */
.customization__phone--4 {
  width: 40%;
  top: 48%;
  left: 7%;
  z-index: 4;
}
.customization__phone--4:hover {
  transform: scale(1.1) translateY(-6%);
  z-index: 10;
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.22), 0 6px 16px rgba(135, 104, 245, 0.18);
}

/* Cuando uno está hovered, los demás se retraen */
.customization__phones:has(.customization__phone:hover) .customization__phone--1:not(:hover) {
  transform: scale(0.95);
  filter: brightness(0.78);
}
.customization__phones:has(.customization__phone:hover) .customization__phone--2:not(:hover) {
  transform: translateX(-50%) rotate(7deg) scale(0.95);
  filter: brightness(0.78);
}
.customization__phones:has(.customization__phone:hover) .customization__phone--3:not(:hover) {
  transform: translateX(-50%) rotate(-13deg) scale(0.95);
  filter: brightness(0.78);
}
.customization__phones:has(.customization__phone:hover) .customization__phone--4:not(:hover) {
  transform: scale(0.95);
  filter: brightness(0.78);
}

@media (prefers-reduced-motion: reduce) {
  .customization__phone,
  .customization__phone::after,
  .customization__label--1,
  .customization__label--2,
  .customization__label--3,
  .customization__label--4 { transition: none; }
}

/* ─────────────────────────────────────────────
   ETIQUETAS DE JARDINES (z:3, encima de phones)
───────────────────────────────────────────── */
.customization__label {
  position: absolute;
  z-index: 3;
  pointer-events: none;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.customization__label-text {
  font-family: var(--font-display);
  /* Piso de 13px: a 1024 caía a 11.4px. */
  font-size: max(13px, clamp(0.6rem, 0.9vw + 0.17rem, 1.25rem));
  font-weight: 500;
  line-height: 0.9;
  white-space: nowrap;
  transition: opacity 0.2s ease;
}

.customization__label--1 .customization__label-text { color: var(--color-cust-label-1); }
.customization__label--2 .customization__label-text { color: var(--color-cust-label-2); }
.customization__label--3 .customization__label-text { color: var(--color-cust-label-3); }
.customization__label--4 .customization__label-text { color: var(--color-cust-label-4); }

.customization__label-line {
  display: block;
  flex-shrink: 0;
  width: clamp(1.5rem, 3.125vw, 3.375rem);
  height: auto;
}

/* label--1: Kids in Flow — arriba, flecha roja en loop */
.customization__label--1 {
  flex-direction: row;
  align-items: center;
  top: -18%;
  left: 8%;
  transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.customization__visual:has(.customization__phone--1:hover) .customization__label--1 {
  transform: translateY(-120%);
}

/* label--2: Veselka Kids — flecha izquierda + texto derecha */
.customization__label--2 {
  flex-direction: row;
  align-items: flex-end;
  gap: 0.4rem;
  top: 4%;
  left: 44%;
  transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.customization__label--2 .customization__label-line {
  margin-bottom: clamp(-3rem, -3vw, -0.5rem);
}

/* Desktop: la posición vertical fina de la etiqueta 2 la calcula
   alinearEtiquetaPanel() (js/animations.js) — ver ahí por qué. */

.customization__visual:has(.customization__phone--2:hover) .customization__label--2 {
  transform: translateY(-400%);
}

/* label--3: Kids Learn — izquierda, flecha azul apunta abajo */
.customization__label--3 {
  flex-direction: column;
  align-items: flex-start;
  top: 1%;   /* acompaña al teléfono 3, que subió 4% */
  left: -13%;
  transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.customization__label--3 .customization__label-line {
  width: clamp(0.75rem, 1.8vw, 1.8rem);
  height: clamp(2rem, 4.5vw, 5rem);
}

.customization__visual:has(.customization__phone--3:hover) .customization__label--3 {
  transform: translateY(-90%);
}

/* label--4: Tobogan — abajo derecha, texto arriba, flecha abajo */
.customization__label--4 {
  flex-direction: column;
  align-items: flex-start;
  bottom: -16%;   /* acompaña al teléfono 4, que subió 4% */
  right: 37%;
  width: clamp(3.5rem, 6.5vw, 6.5rem);
  transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.customization__visual:has(.customization__phone--4:hover) .customization__label--4 {
  transform: translateY(-30%);
}


/* ─── Desktop (≥769px): posición única de las labels, sin breakpoint intermedio ───
   Los teléfonos ocupan el 100% del visual y escalan con él (medido: phones left/top
   0%, width 100% en 900–1920px), así que las labels — ancladas en % al visual —
   mantienen su alineación con los teléfonos en todo el rango con un único set de %.
   Las posiciones base (calibradas al frame 1920) sirven a todo el desktop; solo
   label 3 baja respecto de su base. */
@media (min-width: 48.0625rem) {
  .customization__label--3 { top: 22%; }   /* 26% → 22%: el teléfono 3 subió 4% */
}

/* ─────────────────────────────────────────────
   MOBILE (< 768px) — columna única, sticks ocultos
───────────────────────────────────────────── */
@media (max-width: 48rem) {
  .customization {
    /* el +16rem del desktop deja el bg varado al fondo; en mobile no aplica.
       El panel de features (absolute, centrado en el visual) sobresale más
       cuanto más angosta la pantalla: reservamos arriba lo suficiente para
       contenerlo en el peor caso (320px) sin recortarlo. */
    padding-top: calc(var(--space-section) + 2rem);
    /* abajo: espacio proporcional y contenido (token fluido) para no dejar un
       hueco morado grande bajo el botón */
    padding-bottom: var(--space-section-sm);
  }

  /* En mobile no usamos la imagen SVG de fondo: el morado plano lo aporta un box
     acotado a la zona inferior (ver .customization__visual::before). El swirl
     detrás de los teléfonos sigue viniendo de .customization__phones::before. */
  .customization__bg-clip { display: none; }

  /* Layout mobile: una columna, orden texto → phones → panel → botón.
     display:contents en __left aplana tag/título/desc/botón dentro del inner
     para poder mandar el botón al final con order, sin tocar el DOM. */
  .customization__inner {
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
    /* mismo inset lateral que solution mobile */
    padding-inline: clamp(2.5rem, 12.5vw, 6rem);
  }

  .customization__left { display: contents; }

  .customization__left .section-tag   { order: 1; align-self: flex-start; }
  .customization__left .section-title { order: 2; }
  .customization__desc                { order: 3; }
  .customization__visual              { order: 4; }
  .customization__left .btn           { order: 5; }

  /* Título — Sour Gummy, line-height 100% */
  .customization__left .section-title {
    font-size: var(--fs-h2);
    line-height: 1;
    text-align: left;
  }

  /* Descripción — subtítulo de sección */
  .customization__desc {
    font-size: var(--fs-2xl);
    line-height: 1.4;
  }

  /* Botón */
  .customization__left .btn {
    align-self: center;
    width: clamp(15rem, 67.2vw, 33rem);           /* 289px @ 430px */
    height: clamp(2.75rem, 12.1vw, 6rem);         /* 52px @ 430px */
    border-radius: clamp(1.375rem, 6.05vw, 3rem); /* 26px @ 430px */
    font-size: max(14px, var(--fs-body));
    line-height: 1;
    text-align: center;
    /* z-index para que no lo tapen el panel/tarjetas (z:2) al acercarlo con el
       margin negativo del panel */
    position: relative;
    z-index: 3;
    /* variante clara idéntica a .btn-white (features__cta--mobile): blanco +
       morado. El texto va en purple-dark por la misma razón que .btn-white. */
    background: #fff;
    color: var(--color-purple-dark);
  }

  .customization__left .btn:hover { background: var(--color-surface-hover); }

  /* ── Visual: phones arriba, panel abajo, en flujo (sin overlay) ──
     isolation:isolate fuerza un stacking context propio y autocontenido: sin
     esto, en iOS Safari el z-index de phones/panel (flex items con `order`)
     no siempre se respetaba y el DOM order (panel antes que phones en el
     HTML) ganaba en su lugar, tapando el panel con los teléfonos. */
  .customization__visual {
    height: auto;
    width: 100%;
    display: flex;
    flex-direction: column;
    margin-top: var(--space-8);
    isolation: isolate;
  }

  /* Fondo morado plano SOLO de la zona inferior: caja full-bleed que arranca en
     el tope del visual (teléfonos) y baja hasta el fondo de la sección — el
     overflow:hidden de .customization la recorta ahí. z-index:-1 la deja tras
     los teléfonos/panel (z positivos) pero cubre el botón (pill blanco encima).
     El top negativo la sube un poco al hueco sobre los teléfonos. */
  .customization__visual::before {
    content: "";
    position: absolute;
    left: 50%;
    /* Centrada con margen y no con transform: el transform la volvía una capa
       aparte que Safari colocaba a medio píxel del borde de la sección y dejaba
       asomar una línea blanca que parpadeaba al hacer scroll. */
    margin-left: -50vw;
    width: 100vw;
    top: calc(2 * var(--space-6));
    bottom: -100rem;
    background-color: var(--color-purple);
    pointer-events: none;
    z-index: -1;
  }

  .customization__blob { display: none; }

  /* Phones — abanico como bloque propio; posiciones del frame "Phones" (Figma) */
  /* Phones — abanico del nodo Figma "Phones" (frame 440×686). El contenedor
     sangra a ancho completo (los teléfonos usan coords del frame de 440).
     Cada phone se posiciona por su CENTRO (translate(-50%,-50%)); todos miden
     lo mismo (~41% del frame) y los del medio van rotados. */
  .customization__phones {
    position: relative;
    inset: auto;
    order: 1;
    width: auto;
    margin-inline: calc(-1 * clamp(2.5rem, 12.5vw, 6rem));
    aspect-ratio: 440 / 686;
    z-index: 1;
    transform: translateZ(0);   /* fuerza compositing layer — ver nota en .customization__visual */
  }

  /* Swirl detrás de los teléfonos (nodo Figma "BG 3 1": x=-261, y=+21, 846×480
     en el frame 440). Como ::before del contenedor de phones, sigue a los
     teléfonos en cualquier ancho. Queda detrás de los .customization__phone
     (que son z-index 1-4) y da fondo de color a las etiquetas crema. */
  .customization__phones::before {
    content: "";
    position: absolute;
    left: -59.32%;        /* -261 / 440 */
    top: 3.06%;           /* 21 / 686 */
    width: 192.27%;       /* 846 / 440 */
    aspect-ratio: 846 / 480;
    /* 4px más alto que la caja: el SVG trae un rect blanco bajo la forma
       morada, y en su último renglón el antialias mezclaba los dos y pintaba
       una línea clara sobre el morado —en Safari, además, parpadeaba al
       re-rasterizar durante el scroll—. Así ese renglón cae fuera y lo corta
       el borde de la caja, morado contra morado. */
    background: url('../assets/images/background_c1.svg') left top / 100% calc(100% + 4px) no-repeat;
    pointer-events: none;
    z-index: 0;
  }

  .customization__phone {
    width: 41.18%;   /* 181.18 / 440; alto vía aspect-ratio = 54% del contenedor */
    top: auto;
    left: auto;
    /* en mobile los teléfonos no son interactivos: sin tap/hover */
    pointer-events: none;
  }
  /* left/top = esquina sup-izq (centro − mitad). El transform queda solo para
     la rotación, así el entrance de GSAP (translateY) no rompe la posición. */
  .customization__phone--1 { left: 24.63%; top: 0.75%;  transform: none;            z-index: 1; }
  .customization__phone--2 { left: 43.97%; top: 13.26%; transform: rotate(9.81deg);  z-index: 2; }
  .customization__phone--3 { left: 14.20%; top: 25.92%; transform: rotate(-8.78deg); z-index: 3; }
  .customization__phone--4 { left: 29.09%; top: 45.21%; transform: none;            z-index: 4; }

  /* Panel — carrusel: 3 tarjetas rotan entre 3 slots (frente / izq / der).
     Las clases is-front/is-left/is-right las asigna y rota el JS
     (initCustomizationPanelCarousel). Sin JS o con reduced-motion queda el
     estado estático inicial (morado al frente). */
  .customization__panel {
    position: relative;
    inset: auto;
    /* sube el panel para solapar los teléfonos. Proporcional (vw) como los
       teléfonos, no rem: así solapa el mismo % del abanico en todo el rango.
       En 768px, -35.4vw ≈ -17rem (root=16px) → queda igual que antes; en
       pantallas chicas sube menos (el rem se congelaba en su piso y subía de más). */
    top: clamp(-17rem, -35.4vw, -8rem);
    right: auto;
    transform: translateZ(0);   /* fuerza compositing layer — ver nota en .customization__visual */
    order: 2;
    width: 100%;
    height: clamp(15.75rem, 72vw, 29.5rem);   /* alto = card 180×244 (aspect-ratio) + margen del carrusel */
    /* top:-17rem sube las tarjetas pero el box sigue reservando su alto en el
       flujo → deja hueco morado antes del botón. Este margin negativo colapsa
       parte de ese hueco y acerca el botón a las tarjetas. */
    margin-bottom: -11.5rem;
    display: block;
    background: none;
    padding: 0;
    z-index: 2;
  }

  .customization__brilliant { display: none; }

  .customization__feature {
    position: absolute;
    left: 50%;
    top: 50%;
    width: clamp(11rem, 48vw, 21rem);
    /* Proporción del nodo Figma 4447:28348 (180×244) como PISO, no como alto
       fijo: con aspect-ratio el texto largo se salía de la tarjeta a 320px
       (teal y pink desbordaban 9px) y min-height:fit-content no lo levantaba
       —el sizing intrínseco en el eje del bloque no es fiable—. Calculado
       desde el mismo ancho, el alto es idéntico mientras el texto quepa. */
    height: auto;
    /* 215/180 y no 244/180: con el texto escalando por vw, la proporción del
       frame de Figma dejaba la tarjeta demasiado alta para su contenido. */
    min-height: calc(clamp(11rem, 48vw, 21rem) * 215 / 180);
    padding: clamp(2.25rem, 10.5vw, 4rem) clamp(1.6rem, 7vw, 2.8rem);
    justify-content: flex-start;
    margin: 0;
    transform: translate(-50%, -50%);   /* estado base (fallback sin JS) */
    transition: transform 0.6s cubic-bezier(0.34, 1.05, 0.5, 1), opacity 0.6s ease;
    will-change: transform;
    box-shadow: 0 0 0 clamp(0.4rem, 2.1vw, 0.6rem) rgba(241, 241, 241, 0.8);
  }

  /* Escalan con el ancho: la tarjeta crece con vw (min-height por aspecto) pero
     estos tokens en rem se quedaban planos —el root topa en 13px bajo 624px—,
     así que a 430px sobraba el 42% de la tarjeta y a 768px el 72%. */
  .customization__feature h3 { font-size: clamp(1.0625rem, 4.8vw, 2.125rem); line-height: 1.19; }
  .customization__feature p  { font-size: clamp(14px, 3.55vw, 1.3125rem); line-height: 1.19; }

  /* Slots del carrusel */
  .customization__feature.is-front {
    transform: translate(-50%, -34%) scale(1.05);
    z-index: 3;
    opacity: 1;
  }
  /* Las laterales quedan tapadas al 51% por la frontal (tres tarjetas de 48vw
     no caben en un viewport de 390). Con scale .85 / opacity .9 estaban casi
     tan presentes como la frontal y el corte se leía como texto roto; hundidas
     se leen como profundidad. */
  .customization__feature.is-left {
    transform: translate(-102%, -34%) scale(0.78);
    z-index: 1;
    opacity: 0.55;
  }
  .customization__feature.is-right {
    transform: translate(2%, -34%) scale(0.78);
    z-index: 2;
    opacity: 0.55;
  }

  /* Durante la medición de la posición de los puntos, animations.js recorre los
     tres estados del giro y vuelve al original en el mismo frame. Sin esto cada
     paso dispararía la transición de 0.6s y se vería un temblor. */
  .customization__panel--measuring .customization__feature { transition: none; }

  /* ── Puntos de paginación ──
     order 3: el panel es order 2 dentro de .customization__visual, así que los
     puntos caen justo después. El margen superior lo calcula animations.js —
     las tarjetas desbordan la caja del panel por abajo y su alto es un
     min-height que crece con el texto, así que no es expresable en CSS. */
  .customization__dots {
    order: 3;
    width: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 0;
    position: relative;
    z-index: 21;   /* sobre las etiquetas (z-index: 20) */
  }

  /* El punto se ve pequeño; el botón conserva los 44px de alto de objetivo
     táctil con padding transparente. */
  .customization__dot {
    display: flex;
    align-items: center;
    justify-content: center;
    width: clamp(32px, 9vw, 40px);
    height: 44px;
    padding: 0;
    border: none;
    background: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }

  .customization__dot::before {
    content: '';
    display: block;
    width: clamp(0.5rem, 2.1vw, 0.75rem);
    height: clamp(0.5rem, 2.1vw, 0.75rem);
    border-radius: var(--radius-full);
    /* Blanco, como en .features__dots y no como en .problem__dots: acá los
       puntos caen sobre el morado de fondo de la sección, no sobre blanco. Con
       --color-purple el punto activo daba 1:1 contra el fondo — medido,
       literalmente no se veía. */
    background: rgba(255, 255, 255, 0.45);
    transition: background var(--transition-fast), transform var(--transition-fast);
  }

  /* El tamaño acompaña al color: quien no distinga bien los tonos igual ve cuál
     está activo. */
  .customization__dot[aria-selected="true"]::before {
    background: #fff;
    transform: scale(1.35);
  }

  .customization__dot:focus-visible {
    outline: 3px solid #fff;
    outline-offset: -8px;
    border-radius: var(--radius-full);
  }

  /* ── Etiquetas (nodos Figma 4613-*): "Kinder / <nombre>" + flecha, alrededor
     de los teléfonos. Coords del frame 440; el eje X compensa el padding del
     inner porque los phones sangran a ancho completo. "Kinder" se agrega con
     ::before (mobile) para que el ciclado del JS no lo pise. ── */
  .customization__label {
    display: block;
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 20;
  }

  .customization__label-text {
    position: absolute;
    font-family: var(--font-display);
    font-weight: 500;
    font-size: max(12px, var(--fs-sm));
    line-height: 0.9;
    white-space: nowrap;
  }
  .customization__label-text::before {
    /* La cadena la fija i18n.js en :root — un ::before no es un nodo y
       data-i18n no lo alcanza. Antes estaba escrita aquí y seguía diciendo
       "Kinder" en inglés. */
    content: var(--i18n-custom-label-prefix, "Jardín");
    display: block;
  }

  .customization__label-line {
    position: absolute;
    height: auto;
    margin: 0;
  }

  /* L1 — Kids in Flow (rojo var(--color-cust-label-1)) */
  .customization__label--1 .customization__label-text { left: calc(68.86vw - clamp(2.5rem, 12.5vw, 6rem)); top: -3.86vw;  color: var(--color-cust-label-1); }
  .customization__label--1 .customization__label-line { left: calc(59.82vw - clamp(2.5rem, 12.5vw, 6rem)); top: -5.73vw;   width: 7.39vw; transform: rotate(46.63deg); }

  /* L2 — Veselka Kids (crema var(--color-cust-label-2-mobile)); la flecha marrón se aclara con filter.
     Es el label más pegado al borde derecho y el JS le rota cualquiera de los 8
     nombres del pool, así que se acota con el nombre más ancho: el min() solo
     entra por debajo de ~365px y deja la posición de Figma intacta arriba.
     La flecha se deriva del mismo valor para no despegarse del texto. */
  .customization__label--2 {
    --l2-x: min(calc(80vw - clamp(2.5rem, 12.5vw, 6rem)),
                calc(100vw - clamp(2.5rem, 12.5vw, 6rem) - 5.6rem));
  }
  .customization__label--2 .customization__label-text { left: var(--l2-x);                 top: 11.14vw;  color: var(--color-cust-label-2-mobile); }
  .customization__label--2 .customization__label-line { left: calc(var(--l2-x) - 7.73vw);  top: 13.57vw;  width: 6.04vw; transform: rotate(7.07deg) scaleY(1); filter: brightness(0) invert(1); }

  /* L3 — Kids Learn (azul var(--color-cust-label-3)) */
  .customization__label--3 .customization__label-text { left: calc(8.06vw - clamp(2.5rem, 12.5vw, 6rem));  top: 24.09vw;  color: var(--color-cust-label-3); }
  .customization__label--3 .customization__label-line { left: calc(7.05vw - clamp(2.5rem, 12.5vw, 6rem));   top: 30.45vw;  width: 9.85vw; height: 9.85vw; }

  /* L4 — Tobogán (crema var(--color-cust-label-4)). Vive en el límite teléfonos↔panel; ahora que el
     panel sube en vw (proporcional) ese borde es constante, así que el label puede
     ir en vw puro como los demás. */
  .customization__label--4 .customization__label-text { left: calc(75.77vw - clamp(2.5rem, 7.5vw, 6rem)); top: 110.68vw; color: var(--color-cust-label-4); }
  .customization__label--4 .customization__label-line { left: calc(71.18vw - clamp(2.5rem, 12.5vw, 6rem)); top: 117.62vw; width: 106.62vw; transform: rotate(5.35deg); }
}

/* Abanico móvil: en las tarjetas laterales (tapadas a la mitad) el texto se
   desvanece del todo; quedan como formas de color que dan profundidad, sin
   texto cortado. Sigue en el árbol de accesibilidad. */
@media (max-width: 48rem) {
  .customization__feature > * {
    transition: opacity var(--motion-base) ease;
  }

  /* .is-left/.is-right y no :not(.is-front): si el JS no corre, no hay slots
     y el texto tiene que seguir visible. */
  .customization__feature.is-left > *,
  .customization__feature.is-right > * {
    opacity: 0;
  }
}

/* ── css/steps.css ────────────────────────────────── */
.steps {
  position: relative;
  padding-top: var(--space-section);
  padding-bottom: calc(var(--space-section) + 10rem);
  background: var(--color-purple);
  /* Cose la unión con Personalización, que también termina en morado: en
     Safari las dos cajas podían quedar separadas por una fracción de píxel y
     se veía el blanco de la página como una línea que parpadeaba. */
  box-shadow: 0 -2px 0 var(--color-purple);
  overflow: hidden;
}

.steps .container {
  padding-inline: clamp(2.5rem, 12.5vw, 6rem);
}

.steps__bg {
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: clamp(12rem, 100vw, 50rem);
  object-fit: cover;
  object-position: center bottom;
  z-index: 0;
  pointer-events: none;
  display: block;
}

.steps__animated-line {
  display: none;
  position: absolute;
  top: clamp(40rem, 20rem + 50vw, 74rem);
  right: clamp(-5.125rem, -23.44vw, -11.25rem);
  width: clamp(17.5rem, 36.46vw, 38.75rem);
  height: clamp(28rem, 58.33vw, 70rem);
  overflow: visible;
  pointer-events: none;
  z-index: 0;
  will-change: transform;
  transform: translateZ(0);
  transform: rotate(115deg);
  transform-origin: top right;
}

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

/* ── Header ── */
.steps__header {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(2rem, -0.14rem + 10.71vw, 5rem);
  align-items: center;
  margin-bottom: var(--space-10);
}

.steps__title {
  font-family: var(--font-display);
  font-size: clamp(2rem, 7vw, 4.5rem);
  font-weight: 400;
  color: #fff;
  line-height: 1;
}

.steps__title--bold   { font-weight: 700; }
.steps__title--normal { font-weight: 400; }

.steps__title--accent-wrap {
  position: relative;
  display: inline-block;
}

.steps__title--accent {
  color: var(--color-yellow);
  font-weight: 700;
}

/* Con la etiqueta, el subrayado amarillo sobra. */
.steps__title--accent-wrap:has(.text-sticker) .steps__title__underline {
  display: none;
}

/* Ícono de confeti junto a "3 pasos y listo." (antes 🎉). */
/* 🎉 como sticker 3D junto a "3 pasos y listo." */
.steps__title-ico {
  display: inline-block;
  vertical-align: -0.15em;
  font-size: 1.1em;
  rotate: 8deg;
}

.steps__title-ico .sticker {
  display: inline-block;
}

.steps__title__underline {
  position: absolute;
  bottom: -1em;
  left: 0;
  width: 100%;
  height: auto;
  display: block;
  pointer-events: none;
}

.steps__header-right {
  position: relative;
}

.steps__claims {
  list-style: none;
  margin: 0;
  padding-left: 0;
  padding-right: 0;        /* el check ya no flota al lado: bajó al borde de la primera carta */
}

.steps__claims {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
}

/* Cada claim es una píldora purple-dark: el blanco sobre el morado de la
   sección topaba en 3.94:1 y subir a "texto grande" (19px negrita) partía el
   bloque en 7 líneas a 320px. Sobre purple-dark son 5.62:1 al mismo tamaño. */
.steps__claims li {
  display: inline-flex;
  align-items: center;
  padding: 0.3em 0.85em 0.3em 0.6em;
  border-radius: var(--radius-full);
  background: var(--color-purple-dark);
  box-shadow: 0 0.12em 0 rgba(26, 26, 46, 0.18);
  font-family: var(--font-body);
  font-size: max(14px, clamp(0.875rem, 3.26vw, 1.6rem));
  font-weight: 550;
  line-height: 1.4;
  color: #fff;
  /* Sin sangría colgante: en la píldora la estrella va en línea (inline-flex,
     ver ::before) y si la frase parte, el texto envuelve dentro de su caja. */
}

.steps__claims li::before {
  content: "\2605";
  flex-shrink: 0;
  margin-right: 0.35em;
  color: var(--color-brand-yellow);
  /* La estrella no aporta significado (el texto ya lo dice), así que su
     contraste no entra en WCAG. Se usa el amarillo del acento del título. */
}

/* Check — solo mobile (en desktop vive sobre la carta 3). Se apoya en el
   borde superior de la primera carta, como en desktop: arranca 2.5rem debajo
   de los claims (el margen entre header y grilla) y se centra en ese borde.
   A la derecha se alinea con la carta, que en tablet es más angosta que el
   bloque (máx. 30rem, centrada). */
.steps__header-checked {
  position: absolute;
  top: calc(100% + 2.5rem);
  right: calc((100% - min(100%, 30rem)) / 2 + 1rem);
  z-index: 5;
  transform: translateY(-50%);
  width: clamp(3.5rem, 17vw, 6rem);
  height: auto;
  pointer-events: none;
}

/* ── Grid de cards ── */
.steps__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
  margin-top: var(--space-8);
  margin-bottom: var(--space-12);
}

.step-card {
  width: 100%;
  max-width: 30rem;
  /* 0.78 y no 0.85: con el texto ya escalando por vw, la proporción original
     dejaba la tarjeta más alta de lo que el contenido necesita. */
  aspect-ratio: 1 / 0.78;
  margin-inline: auto;
  border-radius: 1.29rem;
  padding: clamp(2.5rem, 10vw, 3.5rem);
  color: #fff;
  position: relative;
  /* Item de grid: sin min-width:0 no baja de su min-content (la palabra más
     larga del h3 + el número, que no encoge) y a 320px se salía del viewport
     arrastrando la flecha y el CTA. */
  min-width: 0;
  display: flex;
  flex-direction: column;
  /* La tarjeta es cuadrada y fija, y los tres pasos no tienen el mismo largo de
     texto: alineado arriba, el sobrante se acumulaba todo abajo (hasta 142px en
     el paso 1) y se veía como un bloque de color vacío. Centrado, el aire se
     reparte y las tres se leen parejas aunque el texto difiera. */
  justify-content: center;
  transition: transform var(--transition-base);
}

.step-card:hover { transform: translateY(-6px); }

/* z-index creciente + overlap: cada card "pisa" a la anterior, como en Figma.
   margin-top fluido (no un valor fijo) para que el overlap escale igual
   de proporcional que el resto de la card en todo el rango <769px. */
.step-card--pink   { background: var(--color-brand-magenta); border: 0.484rem solid var(--color-brand-pink); z-index: 1; }
.step-card--yellow { background: var(--color-brand-yellow); border: 0.484rem solid var(--color-brand-yellow-soft); color: var(--color-text); z-index: 2; margin-top: clamp(-2.5rem, -5.5vw, -1.5rem); }
.step-card--blue   { background: var(--color-brand-blue-strong); border: 0.484rem solid var(--color-brand-blue); z-index: 3; margin-top: clamp(-2.5rem, -5.5vw, -1.5rem); }

.step-card__head {
  display: flex;
  align-items: center;
  gap: clamp(0.4167rem, 3.0833vw, 1.5rem);
  margin-bottom: var(--space-3);
}

/* Proporcional al ancho de la card en todo el rango mobile (antes era un
   5rem fijo con un salto brusco a 3rem vía media query a los 480px). */
.step-card__number {
  font-family: var(--font-display);
  font-size: clamp(3rem, 12vw, 5rem);
  font-weight: 700;
  line-height: 1;
  flex-shrink: 0;
}

.step-card--yellow .step-card__number { color: var(--color-text); }

/* Nota: el <br> del copy ("…un día<br>jardín…") deja "tu" y "jardín" solas en
   su línea a 320px (6 líneas). Quitarlo en mobile se probó y es peor: a 360 y
   390 —los anchos reales del público— el título pasa de 4 a 5 líneas porque el
   acento se va solo a la última. Se deja el <br>; el ragged de 320 es el mal
   menor. */
.step-card h3 {
  font-family: var(--font-display);
  /* Escala con el ancho, como .step-card__number. Antes era un token en rem y,
     como el root queda plano en 13px por debajo de 624px, el texto se quedaba
     igual en todos los teléfonos mientras la tarjeta crecía con su
     aspect-ratio: medido, en 430px sobraba el 41% de la tarjeta. */
  font-size: clamp(1.125rem, 5vw, 2.375rem);
  font-weight: 700;
  line-height: 1;
  margin: 0;
  min-width: 0;
  overflow-wrap: break-word;
}

.step-card p {
  /* Mismo motivo que el h3 de arriba. El piso en px protege los anchos chicos. */
  font-size: clamp(14px, 3.7vw, 1.5rem);
  line-height: 1.4;
}

/* El badge checked se oculta en mobile (solo tiene sentido en desktop) */
.step-card__checked {
  display: none;
  opacity: 0;
  transform: scale(0);
  transform-origin: center;
}

@keyframes bubble-pop {
  from { opacity: 0; transform: scale(0); }
  to   { opacity: 1; transform: scale(1); }
}

.step-card__checked--pop {
  animation: bubble-pop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

/* Wrap del arrow (mobile): mismo width/max-width/centrado que .step-card,
   para que el arrow quede alineado a SU borde derecho aunque la card esté
   limitada por max-width en viewports anchos. Altura 0: no ocupa espacio
   en el flujo, el arrow (absolute) flota centrado en la juntura. */
.steps__arrow-wrap {
  --arrow-size: clamp(3rem, 13vw, 4.5rem);
  position: relative;
  width: 100%;
  max-width: 30rem;
  height: 0;
  margin-inline: auto;
  z-index: 10;
}

/* Arrow: alineado a la derecha, sobresaliendo del borde de la card y
   superpuesto en la juntura entre cards. Al vivir sobre la zona de
   padding-inline (sin texto), el overlap vertical es seguro sin importar
   cuántas líneas ocupe el párrafo de cada card. Tamaño y offset atados a
   la misma variable para que escalen juntos y sigan centrados. */
/* Escala animable sin tocar el transform (js/animations.js la anima). */
.steps__arrow {
  scale: var(--arrow-s, 1);
}

.steps__arrow {
  display: block;
  width: var(--arrow-size);
  height: var(--arrow-size);
  position: absolute;
  top: calc(var(--arrow-size) / -1);
  right: clamp(0.833rem, 4.167vw, 2rem);
  transform: rotate(90deg);
}

.steps__cta {
  text-align: center;
  /* position:relative (no static) y z-index: .steps__bg es absolute con
     z-index:0, así que se pinta en la fase de los elementos posicionados —
     DESPUÉS del contenido en flujo sin posicionar, que es donde caía este
     botón. Resultado: el fondo lo tapaba por completo. Se veía solo al pasar
     el mouse porque .btn:hover aplica un translateY, y un transform crea
     contexto de apilamiento y sube el botón a esa misma fase; en mobile, sin
     hover, no aparecía nunca. Es el mismo caso que .features__cta--mobile con
     la ola .features__bg-top. */
  position: relative;
  z-index: 1;
}

/* Botón del CTA — mismo tamaño que .people__cta .btn en mobile */
.steps__cta .btn {
  width: clamp(15rem, 67.2vw, 33rem);
  height: clamp(2.75rem, 12.1vw, 6rem);
  border-radius: clamp(1.375rem, 6.05vw, 3rem);
  font-size: max(14px, clamp(0.75rem, 3.24vw, 1.55rem));   /* piso de legibilidad, igual que el resto de CTAs */
  line-height: 1;
}

/* ── Desktop (min-width: 48.0625rem / 769px) ── */
@media (min-width: 48.0625rem) {
  /* Margen lateral estándar: con 0, entre 769 y ~1000px las cartas (ahora
     fluidas) tocaban los bordes de la pantalla. */
  .steps .container {
    padding-inline: var(--container-padding);
  }

  .steps__bg {
    height: clamp(12rem, 46vw, 44rem);
  }

  /* Escala con el ancho, con techo en el tamaño de diseño (3.75rem): en la
     banda muerta, con los claims ya en una línea, el título fijo se partía
     dejando "tu" solo en un renglón. */
  .steps__title {
    font-size: min(3.75rem, 5.2vw);
  }

  .steps__header {
    /* `auto` en vez de 60%: el título toma su ancho natural (usaba 611px de los
       720 que le daba el 60%) y los ~100px sobrantes pasan a los claims, que se
       quedaban 21px cortos para poner "Sin instalaciones complicadas." en una
       sola línea. */
    grid-template-columns: auto 1fr;
    gap: var(--space-12);
    margin-bottom: var(--space-16);
  }

  .steps__claims {
    padding-right: 0;   /* el check que lo motivaba está oculto en desktop */
  }

  /* Desktop: cada claim en una sola línea. La letra baja un poco (y escala
     con el ancho) para que la más larga, "Sin instalaciones complicadas.",
     entre en su columna en todo el rango. */
  .steps__claims li {
    white-space: nowrap;
    font-size: max(14px, clamp(0.875rem, 0.45rem + 0.85vw, 1.3rem));
  }

  .steps__header-checked {
    display: none;
  }

  .steps__grid {
    /* Columnas fluidas con techo en 22.875rem: con el ancho fijo, entre 769 y
       ~930px las tres cartas no cabían y se salían por los dos costados. */
    grid-template-columns: repeat(3, minmax(0, 22.875rem));
    gap: 1.3125rem;
    align-items: stretch;
    justify-content: center;
    position: relative;
    margin-top: var(--space-24);
  }

  .step-card {
    /* width explícito: con width auto + aspect-ratio, cuando el texto es más
       alto que la columna el navegador agranda también el ancho y la carta se
       sale de su columna. Así solo crece en alto. */
    width: 100%;
    height: auto;
    /* Cuadradas mientras el texto quepa; si no, crecen en alto. */
    aspect-ratio: 1 / 1;
    border-radius: 1.5rem;
  }

  .step-card--yellow,
  .step-card--blue {
    margin-top: 0;
  }

  .step-card--pink   { border-width: 0.5625rem; }
  .step-card--yellow { border-width: 0.5625rem; }
  .step-card--blue   { border-width: 0.5625rem; }

  .step-card__checked {
    display: block;
    position: absolute;
    top: -5rem;
    right: 2rem;
    width: 6.875rem;
    height: auto;
    pointer-events: none;
  }

  .step-card p {
    /* El coeficiente vw daba 13.8px a 1440 — el cuerpo más pequeño de la
       landing en desktop. Recalibrado a ~16px a 1440, con piso de 15px para
       los anchos donde el root todavía está en su suelo. */
    font-size: max(15px, clamp(0.8rem, calc(0.78vw + 0.3rem), 1.25rem));
  }

  /* Reset al tamaño base de .btn-lg — el clamp de arriba es solo para mobile */
  .steps__cta .btn {
    width: 18.4rem;
    height: 3.3125rem;
    border-radius: 1.65625rem;
    font-size: var(--fs-sm);
    line-height: 1;
  }

  /* El wrap desaparece de la caja (display:contents): en desktop el arrow
     vuelve a ser un hijo directo del grid para el posicionamiento absoluto
     de siempre, sin ocupar una columna del grid de 3 cards. */
  .steps__arrow-wrap {
    display: contents;
  }

  /* Arrows absolutos, centrados en las junturas entre cards */
  /* Centradas en el espacio entre dos cartas: en horizontal se calcula desde
     el centro de la grilla (ancho de columna + gap, en vez de un % aproximado
     del ancho total) y en vertical van a la mitad de la carta. */
  .steps__arrow {
    position: absolute;
    top: 50%;
    right: auto;
    transform: translate(-50%, -50%);
    /* El pop de entrada escala (propiedad `scale`) alrededor del punto de
       centrado (left/top), no del centro de la caja sin trasladar: si no, la
       flecha se desliza en diagonal mientras crece. */
    transform-origin: 0 0;
    width: 5rem;
    height: 5rem;
    z-index: 4;
    pointer-events: none;
  }

  /* nth-child, no :first-of-type/:last-of-type: el wrap es un <div>,
     mismo tag que las cards, así que "of-type" ya no las distingue. */
  .steps__arrow-wrap:nth-child(2) .steps__arrow {
    left: calc(50% - (min(22.875rem, (100% - 2.625rem) / 3) + 1.3125rem) / 2);
  }
  .steps__arrow-wrap:nth-child(4) .steps__arrow {
    left: calc(50% + (min(22.875rem, (100% - 2.625rem) / 3) + 1.3125rem) / 2);
  }

  .steps__animated-line {
    display: block;
  }
}


/* Móvil: "está conectado!" entra en la misma línea que "jardín". La etiqueta
   baja un poco de tamaño solo aquí; en desktop sigue igual. */
@media (max-width: 48rem) {
  .steps__title--accent.text-sticker {
    font-size: 0.88em;
  }
}

/* En la pantalla mínima (<360px) no cabe a 0.88em junto a "jardín". */
@media (max-width: 22.4375rem) {
  .steps__title--accent.text-sticker {
    font-size: 0.8em;
  }
}

/* ── css/testimonials.css ────────────────────────────────── */
.testimonials {
  position: relative;
  padding-bottom: var(--space-section);
  background: #fff;
  overflow: hidden;
  margin-top: -2px;  /* cierra brecha de subpixel con steps */
  z-index: 1;        /* stacking por encima del steps purple */
}

.testimonials__deco-intersect {
  position: absolute;
  bottom: 0;
  left: 0;
  width: clamp(18rem, 50vw, 60rem);
  height: auto;
  pointer-events: none;
  z-index: 0;
  will-change: transform;
  transform: translateZ(0);
}

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

.testimonials__header {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
  margin-bottom: var(--space-6);
}

.testimonials__nav {
  display: flex;
  gap: var(--space-3);
  margin-bottom: var(--space-10);
  justify-content: flex-end;
}

.testimonials__title {
  font-family: var(--font-display);
  font-size: clamp(1.875rem, 9.3vw, 4.5rem);
  font-weight: 400;
  color: var(--color-text);
  line-height: 0.88;
}

.testimonials__title--bold {
  font-weight: 700;
}

.testimonials__title-brand-wrap {
  position: relative;
  display: inline-block;
}

.testimonials__title-brand {
  color: var(--color-purple);
  font-weight: 700;
}

.testimonials__title-break--mobile {
  display: none;
}


.testimonials__title__underline {
  position: absolute;
  bottom: -1rem;
  left: 0;
  width: 100%;
  height: auto;
  display: block;
  pointer-events: none;
}


.testimonials__nav-btn {
  /* 3.25rem con el root en su piso de 13px son 42.25px, por debajo del mínimo
     táctil de 44. El max() solo entra en mobile; en desktop siguen en 52px. */
  width: max(44px, 3.25rem);
  height: max(44px, 3.25rem);
  border-radius: 50%;
  border: none;
  /* Flecha blanca sobre card-purple (4.51:1); sobre el lila daba 1.8:1. */
  background: var(--color-card-purple);
  color: #fff;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.4rem;
  transition:
    background-color var(--motion-fast) ease,
    transform var(--motion-fast) var(--ease-spring);
}

.testimonials__nav-btn:active {
  transform: scale(0.92);
  transition-duration: var(--motion-press);
}

.testimonials__nav-btn svg {
  width: 1em;
  height: 1em;
}

@media (hover: hover) {
  .testimonials__nav-btn:hover {
    background: var(--color-purple-dark);
    transform: scale(1.08);
  }
}

/* Carousel stacked */
.testimonials__carousel {
  max-width: min(100%, 49.625rem);
  margin-inline: auto;
}

.testimonials__stack {
  position: relative;
  height: 26.375rem;
  /* El gesto vertical se lo queda el navegador (scroll de página) y el
     horizontal llega al JS como swipe entre testimonios. */
  touch-action: pan-y;
}

/* Puntos: solo mobile, donde reemplazan a las flechas (ver el bloque de
   @media más abajo). En desktop no hay swipe y el puntero sí aprovecha las
   flechas, así que allí sobran. */
.testimonials__dots {
  display: none;
}

.testimonial-card {
  position: absolute;
  inset: 0;
  border-radius: 1.5rem;
  border: 0.5625rem solid transparent;
  overflow: hidden;
}

/* Colores persistentes — no cambian al rotar posición.
   Fondos con contraste AA para la cita: con texto blanco el azul de marca daba
   3.29:1, el morado 3.34 y el naranja 2.61. Azul y morado pasan a los tonos
   oscurecidos que ya usan las value-cards (4.54 y 4.51); el borde sigue en el
   tono vivo. El naranja conserva su color con texto oscuro (6.53:1), como la
   píldora naranja del marquee. */
.testimonial-card--color-purple { background: var(--color-card-purple); border-color: var(--color-brand-lila); }
.testimonial-card--color-orange  { background: var(--color-brand-orange); border-color: var(--color-brand-orange-soft); --testimonial-ink: var(--color-text); }
.testimonial-card--color-blue    { background: var(--color-card-blue); border-color: var(--color-brand-blue-soft); }

/* Posiciones — solo controlan transform y layout */
.testimonial-card--back-1,
.testimonial-card--back-2 {
  cursor: pointer;
}

.testimonial-card--back-2 {
  transform: rotate(7.85deg) translateX(1.5rem);
}

.testimonial-card--back-1 {
  transform: rotate(-9.19deg);
}

.testimonial-card--front {
  transform: rotate(0);
  display: flex;
  gap: 0;
  padding: 0;
  overflow: hidden;
  align-items: center;
}

.testimonial-card__media {
  flex-shrink: 0;
}

.testimonial-card__img-wrap {
  width: 22.125rem;
  height: 22.125rem;
  border-radius: 0.875rem;
  overflow: hidden;
  position: relative;
  background: rgba(255,255,255,0.1);
  margin: 1.5rem;
  flex-shrink: 0;
}

/* El velo difuminado solo tiene sentido tapando un video sin reproducir. En un
   testimonio sin video la foto es el contenido: se deja nítida (ui.js marca la
   tarjeta con --has-video cuando hay videoId). */
.testimonial-card__img-wrap:not(.testimonial-card__img-wrap--has-video)::after {
  content: none;
}

.testimonial-card__img-wrap::after {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(100, 70, 200, 0.35);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border-radius: inherit;
  z-index: 1;
  pointer-events: none;
}

.testimonial-card__img-wrap--placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 3rem;
}

.testimonial-card__img-wrap img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* ── Logo del jardín sobre la foto ────────────────────────────────────────
   Medidas tomadas de la maqueta del diseñador: el badge ocupa el 25.3% del
   ancho de la foto y su borde derecho queda a un 4.7% del borde de la foto.
   Todo en % del wrap para que escale con la tarjeta en cualquier viewport. */
/* El selector lleva el wrap a propósito: `.testimonial-card__img-wrap img`
   (0,1,1) le gana a una clase suelta (0,1,0) y estiraba el logo al 100%. */
.testimonial-card__img-wrap img.testimonial-card__logo {
  position: absolute;
  width: 25.3%;
  height: auto;
  right: 4.7%;
  bottom: 11%;
  /* z-index 3: por encima del velo difuminado (1) y del botón de play (2). */
  z-index: 3;
  border-radius: 50%;
  box-shadow: -7px 4px 6.4px rgba(0, 0, 0, 0.52);
  pointer-events: none;
}

.testimonial-card__play {
  z-index: 2;
}

/* Sección oculta mientras no haya testimonios reales (lo decide ui.js). */
.testimonials--empty { display: none; }

/* El atributo hidden por sí solo no basta: la regla display del nav le gana a
   la hoja del navegador. Con un solo testimonio las flechas no deben verse. */
.testimonials__nav[hidden] { display: none; }

/* Con un solo testimonio no hay mazo que rotar: las dos tarjetas de atrás
   dejarían ver color por los bordes prometiendo más de lo que hay. */
.testimonials__stack--single .testimonial-card--back-1,
.testimonials__stack--single .testimonial-card--back-2 { display: none; }

/* Video en reproducción: fuera el velo difuminado que cubre el póster. */
.testimonial-card__img-wrap--playing::after { content: none; }

.testimonial-card__img-wrap iframe {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
  border-radius: inherit;
}

.testimonial-card__body {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-4);
  color: var(--testimonial-ink, #fff);
  padding-block: 2rem;
  padding-right: 2rem;
}

/* Sin rebajar la opacidad: con el fondo ya oscurecido (ver arriba), el blanco
   pleno pasa AA. */
.testimonial-card__body blockquote {
  font-size: max(15px, var(--fs-body));
  line-height: 1.5;
  color: inherit;
}

.testimonial-card__body cite {
  font-style: normal;
  /* El cargo y el jardín rendían 10.56px en mobile — el dato que le permite al
     visitante verificar el testimonio, en el texto más chico de la tarjeta. */
  font-size: max(14px, var(--fs-sm));
}

.testimonial-card__body cite strong {
  display: block;
  font-size: var(--fs-h3);
  font-weight: 700;
  margin-bottom: var(--space-1);
}

.testimonial-card__body cite span {
  color: inherit;
}

.testimonials__deco-lines {
  position: absolute;
  /* Pegado a la esquina inferior derecha de la segunda card del mazo. El
     bloque @media de mobile sobrescribe top/right/bottom, así que esto es
     solo desktop. */
  bottom: calc(-2.4rem - 4.4vw);
  right: calc(0.5rem - 4.1vw);
  width: clamp(3rem, 5vw, 5.5rem);
  height: clamp(3rem, 5vw, 5.5rem);
  transform: rotate(85deg);
  pointer-events: none;
  z-index: 2;
  overflow: visible;
}

.testimonials__deco-line {
  opacity: 0;
}

.testimonials__cta {
  text-align: center;
}

/* ── Desktop (min-width: 48.0625rem / 769px) ── */
@media (min-width: 48.0625rem) {
  /* Un poco más de aire entre el mazo y el CTA. Va solo en desktop: en mobile
     el CTA es order:4 dentro de un flex con su propio ritmo (ver el bloque
     max-width de abajo) y ahí el espacio ya está resuelto.

     padding y no margin: .testimonials__carousel ya trae margin-bottom de 85px
     y los márgenes adyacentes colapsan al mayor, así que un margin-top de 33px
     se lo tragaba entero (medido: el hueco crecía 1px). El padding no colapsa.

     El término en vw compensa la banda muerta: entre 769 y ~1280 el root está
     pegado a su piso de 13px y un rem suelto rendiría un 19% menos. */
  .testimonials__cta {
    padding-top: clamp(4.5rem, 3rem + 4.5vw, 7.5rem);
    /* Bajarlo lo metió en el trazo de .testimonials__deco-intersect, que es
       absolute con z-index:0 y por tanto se pinta DESPUÉS del contenido en
       flujo sin posicionar: medido, en 1280px solo quedaba visible el 9% del
       botón. Mismo caso que el CTA de Pasos bajo .steps__bg. */
    position: relative;
    z-index: 1;
  }
}

.testimonial-card__yt-iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: none;
  border-radius: inherit;
  z-index: 3;
}

.testimonial-card__img-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  font-size: var(--fs-5xl);
}

@media (max-width: 48rem) {
  /* Fuera las flechas: sobre un mazo de tarjetas el gesto natural es deslizar,
     y dos botones en una esquina no lo sugieren. Los puntos sí dicen cuántos
     testimonios hay y en cuál vas. El [hidden] de arriba sigue mandando cuando
     hay menos de dos testimonios. */
  .testimonials__nav {
    display: none;
  }

  .testimonials__dots {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 0;   /* el paso lo fija el ancho del botón, como en las otras secciones */
    margin-top: clamp(0.5rem, 2vw, 1rem);
    /* Devuelve el aire que se perdió al cambiar las flechas por puntos: el nav
       llevaba margin-bottom: var(--space-8) y medía 44px, los puntos miden lo
       mismo pero con menos margen, así que el CTA subía 18px (390) / 20px (768).
       El max() en px es la forma documentada de protegerse en la banda muerta,
       donde el root está pegado a su piso de 13px. */
    margin-bottom: max(18px, var(--space-5));
  }

  .testimonials__dots[hidden] {
    display: none;   /* gana al display:flex de arriba, como en .testimonials__nav */
  }

  /* El punto se ve pequeño; el botón conserva los 44px de alto de objetivo
     táctil con padding transparente. */
  .testimonials__dot {
    display: flex;
    align-items: center;
    justify-content: center;
    width: clamp(32px, 9vw, 40px);
    height: 44px;
    padding: 0;
    border: none;
    background: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }

  .testimonials__dot::before {
    content: '';
    display: block;
    width: clamp(0.5rem, 2.1vw, 0.75rem);
    height: clamp(0.5rem, 2.1vw, 0.75rem);
    border-radius: var(--radius-full);
    /* Tokens de .problem__dots y no los blancos de Features: el fondo de esta
       sección es blanco. */
    background: var(--color-border);
    transition: background var(--transition-fast), transform var(--transition-fast);
  }

  /* El tamaño acompaña al color: quien no distinga bien los tonos igual ve cuál
     está activo. */
  .testimonials__dot[aria-selected="true"]::before {
    background: var(--color-purple);
    transform: scale(1.35);
  }

  .testimonials__dot:focus-visible {
    outline: 3px solid var(--color-purple-dark);
    outline-offset: -8px;
    border-radius: var(--radius-full);
  }

  .testimonials .container {
    display: flex;
    flex-direction: column;
    padding-inline: clamp(2.5rem, 12.5vw, 6rem);
  }

  .testimonials__header {
    order: 1;
    flex-direction: column;
    gap: var(--space-4);
  }

  .testimonials__carousel {
    order: 2;
    max-width: 100%;
    margin-top: var(--space-20);
  }

  .testimonials__cta {
    order: 4;
  }

  /* Nav debajo de los cards, más pequeño y centrado */
  .testimonials__nav {
    order: 3;
    justify-content: center;
    gap: var(--space-2);
    margin-bottom: var(--space-8);
  }

  .testimonials__nav-btn {
    /* Piso de 44px: el clamp daba 33-34px, por debajo del mínimo táctil. */
    width: max(44px, clamp(2.5rem, 2rem + 2vw, 3.5rem));
    height: max(44px, clamp(2.5rem, 2rem + 2vw, 3.5rem));
  }

  .testimonials__nav-btn svg {
    width: clamp(1.25rem, 1rem + 1vw, 1.75rem);
    height: clamp(1.25rem, 1rem + 1vw, 1.75rem);
  }

  .testimonials__title {
    font-size: var(--fs-h2);
    text-align: left;
  }

  /* Cards en una sola columna, con los de atrás asomando */
  .testimonials__stack {
    height: auto;
  }

  .testimonial-card--front {
    position: relative;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-6);
    padding: 1.5rem;
  }

  .testimonial-card__img-wrap {
    width: 100%;
    aspect-ratio: 1 / 1;
    height: auto;
    margin: 0;
  }

  .testimonial-card__body {
    padding: 2rem;
  }

  /* Un escalón por debajo del desktop: la tarjeta mobile es angosta y la cita
     llegaba a 21 líneas a 320px. Se baja el cuerpo y el nombre manteniendo la
     jerarquía entre los tres niveles. El contraste no cambia (3.34:1): el
     umbral de WCAG es el mismo de 14 a 13px, ambos son texto normal. */
  .testimonial-card__body blockquote {
    font-size: max(14px, var(--fs-body));
  }

  .testimonial-card__body cite strong {
    font-size: 16px;
  }

  .testimonials__cta .btn {
    width: clamp(15rem, 67.2vw, 33rem);
    height: clamp(2.75rem, 12.1vw, 6rem);
    border-radius: clamp(1.375rem, 6.05vw, 3rem);
    font-size: max(14px, var(--fs-body));
    line-height: 1;
  }

  .testimonials__deco-lines {
    top: clamp(-5rem, -12vw, -13.5rem);
    right: clamp(-5rem, -14vw, -7rem);
    bottom: auto;
    width: clamp(6.5rem, 15vw, 8rem);
    height: clamp(6.5rem, 15vw, 8rem);
    transform: none;
  }

  .testimonial-card__body cite{
    font-size: max(13px, var(--fs-sm));
  }

  .testimonials__title-break--mobile {
    display: inline;
  }

  .testimonials__title-break--desktop {
    display: none;
  }

  .testimonials__deco-intersect {
    display: none;
  }
}

/* ── css/faq.css ────────────────────────────────── */
.faq {
  position: relative;
  padding-block: var(--space-section);
  background: var(--color-bg);
  overflow: hidden;
}

.faq__deco-rose {
  position: absolute;
  left: 2rem;
  right: auto;
  top: 1.5rem;
  width: clamp(2rem, 8vw, 3.5rem);
  height: auto;
  pointer-events: none;
  z-index: 0;
  animation: float-slow 5s ease-in-out infinite;
}

.faq__deco-teal {
  display: none;
}

.faq__deco-teal-mobile {
  position: absolute;
  left: -8rem;
  bottom: 0.5rem;
  width: 44rem;
  height: auto;
  pointer-events: none;
  z-index: 0;
  will-change: transform;
  transform: translateZ(0);
}

@media (prefers-reduced-motion: reduce) {
  .faq__deco-teal path:last-child,
  .faq__deco-teal-mobile path:last-child { animation: none; stroke-dashoffset: 0; }
}

.faq__deco-yellow {
  position: absolute;
  right: clamp(4rem, 8vw, 10rem);
  bottom: clamp(2rem, 3vw, 5rem);
  width: 5rem;
  height: auto;
  rotate: 90deg;
  pointer-events: none;
  z-index: 0;
  animation: float-slow 7s ease-in-out infinite 0.8s;
}

.faq > .container {
  position: relative;
  z-index: 1;
  padding-inline: clamp(2.5rem, 12.5vw, 6rem);
}

.faq__header {
  margin-bottom: var(--space-20);
}

.faq__title {
  font-family: var(--font-display);
  font-size: clamp(1.85rem, 9.35vw, 4.5rem);
  font-weight: 400;
  color: var(--color-text);
  line-height: 0.95;
}

.faq__title strong {
  font-weight: 700;
}

.faq__title-bold-wrap {
  display: inline;
}

.faq__title-last-word {
  position: relative;
  display: inline-block;
}

.faq__title__underline {
  position: absolute;
  bottom: -0.75rem;
  left: 0;
  width: 100%;
  height: auto;
  display: block;
  pointer-events: none;
}

.faq__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
}

/* Oculto en mobile: el diseño de Figma <769px no muestra estas etiquetas */
.faq__group-title {
  display: none;
}

/* Accordion */
.faq__accordion {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.faq__item {
  background: rgba(241, 241, 241, 0.61);
  border-radius: 1.5rem;
  overflow: hidden;
  transition: background-color var(--motion-base) ease;
}

@media (hover: hover) {
  .faq__item:not(.is-open):hover {
    background: rgba(237, 233, 254, 0.7);
  }
}

.faq__item.is-open {
  background: linear-gradient(135deg, var(--color-purple-light) 0%, var(--color-purple-tint) 100%);
}

.faq__question {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 1.625rem 2.625rem 1.625rem 2rem;
  background: none;
  border: none;
  cursor: pointer;
  text-align: left;
  font-family: var(--font-body);
  font-size: var(--fs-lg);
  font-weight: 500;
  color: var(--color-text);
  transition: color var(--transition-fast);
}

/* purple-dark y no el lila de marca: sobre el fondo lila de la pregunta
   abierta daba ~2.9:1. */
.faq__question[aria-expanded="true"] {
  color: var(--color-purple-dark);
  font-weight: 700;
}

.faq__icon {
  color: var(--color-purple-dark);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  transition: transform var(--motion-base) var(--ease-spring);
}

.faq__icon svg {
  width: clamp(1.5rem, 1.35rem + 0.6vw, 1.875rem);
  height: clamp(1.5rem, 1.35rem + 0.6vw, 1.875rem);
}

.faq__question[aria-expanded="true"] .faq__icon {
  transform: rotate(180deg);
}

/* Apertura animada: la fila del grid va de 0fr a 1fr, así el alto se anima
   sin medir nada en JS. Es animar layout, pero dentro del ítem y como
   respuesta a un clic (no cuenta para CLS). Cerrada, la respuesta además queda
   en visibility:hidden — fuera del árbol de accesibilidad y del tabulador, como
   con el display:none de antes; el cambio de visibilidad espera a que termine
   el cierre. */
.faq__answer {
  display: grid;
  grid-template-rows: 0fr;
  visibility: hidden;
  transition:
    grid-template-rows var(--motion-base) var(--ease-in-soft),
    visibility 0s linear var(--motion-base);
}

.faq__answer.open {
  grid-template-rows: 1fr;
  visibility: visible;
  transition:
    grid-template-rows var(--motion-reveal) var(--ease-out-soft),
    visibility 0s;
}

/* El recorte lo hace el contenedor interno (sin padding), así cerrado mide 0
   de verdad; el padding vive en el párrafo. */
.faq__answer-inner {
  min-height: 0;
  overflow: hidden;
}

.faq__answer p {
  padding: 0 2.625rem 1.625rem 4.375rem;
  /* fs-body en mobile por pedido explícito — desktop mantiene fs-sm (ver media query abajo) */
  font-size: var(--fs-body);
  /* --color-text: el gris de antes (--color-text-muted) daba ~4.2:1 sobre el
     fondo lila de la pregunta abierta. */
  color: var(--color-text);
  line-height: 1.7;
  opacity: 0;
  translate: 0 -0.35rem;
  transition: opacity var(--motion-fast) ease, translate var(--motion-fast) ease;
}

.faq__answer.open p {
  opacity: 1;
  translate: none;
  transition:
    opacity var(--motion-reveal) var(--ease-out-soft) 80ms,
    translate var(--motion-reveal) var(--ease-out-soft) 80ms;
}

/* Form col — contiene el título y el panel */
.faq__form-col {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  /* Es el destino de #contacto (los "Agenda tu demo"). Con JS, main.js ya
     calcula el desfase del navbar; esto cubre la entrada directa por URL
     (kuid.app/#contacto) y la navegación sin JS. */
  scroll-margin-top: max(5rem, 72px);
}

/* Panel del formulario — crece para igualar el alto del accordion */
.faq__form-wrap {
  flex: 1;
  display: flex;
  flex-direction: column;
  background: rgba(241, 241, 241, 0.61);
  backdrop-filter: blur(25px);
  border-radius: clamp(1.3rem, 3.5vw, 1.6rem);
  padding: clamp(1.4rem, 4vw, 1.75rem) clamp(2.3rem, 6vw, 2.75rem) clamp(1.4rem, 4vw, 1.75rem) clamp(1.75rem, 4.5vw, 2.1rem);
}

.faq__form {
  --field-pad-y: clamp(1rem, 2.6vw, 1.15rem);
  --field-pad-x: clamp(1.5rem, 3.9vw, 1.75rem);
  --field-fs: clamp(1.1rem, 2.8vw, 1.2rem);
  --field-border: 1.5px;
  --field-lh: 1.5;
  /* Banda reservada arriba de cada campo para la etiqueta flotante. Tiene que
     dar para la caja de fuente de la etiqueta arriba —no su line-height, sino
     el ascenso+descenso real de Poppins, ~1.25em sobre max(12px, 0.82rem)—,
     o los descendentes ("jardín") se montan sobre el borde del campo. */
  --field-label-h: max(15.5px, 1.05rem);

  flex: 1;
  display: flex;
  flex-direction: column;
  /* El gap se suma a la banda de la etiqueta: entre dos campos el aire real es
     gap + --field-label-h, por eso es más chico de lo que parece. */
  gap: clamp(0.7rem, 2vw, 0.8rem);
}

.faq__input,
.faq__textarea {
  width: 100%;
  padding: var(--field-pad-y) var(--field-pad-x);
  border: var(--field-border) solid var(--color-border);
  border-radius: clamp(0.55rem, 1.5vw, 0.7rem);
  font-family: var(--font-body);
  font-size: var(--field-fs);
  line-height: var(--field-lh);
  /* 600 y no 700: el valor ya domina sobre la etiqueta por color y tamaño, y
     con seis campos en negrita el bloque se leía como un muro de énfasis. */
  font-weight: 600;
  color: var(--color-text);
  background: #ffffff;
  outline: none;
  transition: box-shadow var(--transition-fast);
}

/* Anillo en purple-dark (5.62:1 con blanco). El rosa de antes daba 2.97:1,
   por debajo del 3:1 que WCAG pide a un indicador de foco. */
.faq__input:focus,
.faq__textarea:focus {
  box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color);
}

.faq__textarea {
  resize: none;
  line-height: 1.6;
  min-height: 6rem;
  flex: 1;
}

@media (max-width: 48rem) {
  .faq__title {
    font-size: var(--fs-h2);
    text-align: left;
  }

  .faq__textarea {
    min-height: clamp(9rem, 32vw, 17rem);
  }

  .faq__deco-yellow {
    right: clamp(1.5rem, 5vw, 3rem);
    bottom: 0;
  }
}

/* Role pills */
/* Tres columnas iguales en vez de flex con wrap: "Papá o mamá" es más largo
   que el "Padre" de antes y con flex se caía a una segunda fila en los
   teléfonos. En grid el texto envuelve DENTRO de su píldora y las tres
   comparten alto. */
.faq__role-pills {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(0.5rem, 2vw, 0.9rem);
}

.role-pill {
  position: relative;
  display: flex;
  cursor: pointer;
}

/* El radio se oculta a la vista, NO con display:none: así sigue siendo
   enfocable y operable con el teclado (flechas dentro del grupo). Antes con
   display:none no había forma de elegir rol sin mouse — y el rol es
   obligatorio, así que el formulario no se podía enviar desde el teclado. */
.role-pill input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.role-pill span {
  display: flex;
  width: 100%;
  align-items: center;
  justify-content: center;
  padding: clamp(0.6rem, 2vw, 0.95rem) clamp(0.4rem, 1.6vw, 0.9rem);
  /* Mínimo táctil: en mobile el padding daba ~32px de alto. */
  min-height: 44px;
  border-radius: clamp(0.55rem, 1.5vw, 0.7rem);
  border: 1.5px solid var(--color-border);
  background: #ffffff;
  font-family: var(--font-body);
  font-size: max(14px, clamp(0.9rem, 2.3vw, 1.05rem));
  font-weight: 700;
  line-height: 1.15;
  text-align: center;
  color: var(--color-text-muted);
  transition:
    background-color var(--motion-fast) ease,
    border-color var(--motion-fast) ease,
    color var(--motion-fast) ease,
    transform var(--motion-fast) var(--ease-spring);
  cursor: pointer;
}

@media (hover: hover) {
  .role-pill:hover span {
    border-color: var(--color-purple);
    color: var(--color-purple-dark);
  }
}

.role-pill input:active + span {
  transform: scale(0.96);
}

/* El anillo va en la píldora visible, no en el radio transparente. */
.role-pill input:focus-visible + span {
  outline: var(--focus-ring-width) solid var(--focus-ring-color);
  outline-offset: 2px;
}

/* Colores del seleccionado con los tokens oscurecidos para texto blanco
   (4.51 y 4.54:1). El teal de marca con blanco daba 2.07:1, así que en ese
   va el texto oscuro (8.25:1) y el teal se conserva. */
.role-pill input:checked + span {
  border-color: transparent;
}

.faq__role-pills .role-pill:nth-child(1) input:checked + span {
  background: var(--color-card-purple);
  color: #fff;
}

.faq__role-pills .role-pill:nth-child(2) input:checked + span {
  background: var(--color-card-pink);
  color: #fff;
}

.faq__role-pills .role-pill:nth-child(3) input:checked + span {
  background: var(--color-brand-teal);
  color: var(--color-text);
}

.faq__submit {
  width: 100%;
  padding-block: clamp(1.25rem, 3.2vw, 1.5rem);
  border-radius: clamp(1.7rem, 4vw, 2rem);
  font-size: clamp(1.1rem, 2.8vw, 1.25rem);
  /* Hereda el fondo de .btn-primary (--color-card-purple, AA); antes lo
     pisaba con el morado de marca y volvía a 3.94:1. */
}

.faq__submit--sent {
  background: var(--color-green);
  cursor: default;
}

.faq__field {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding-top: var(--field-label-h);
}

.faq__label {
  position: absolute;
  /* Alineada con la primera línea de texto del campo: banda + borde + padding */
  top: calc(var(--field-label-h) + var(--field-border) + var(--field-pad-y));
  left: calc(var(--field-pad-x) + var(--field-border));
  /* Solo se reserva la sangría izquierda —la que alinea la etiqueta con el
     texto—; a la derecha no hay nada que esquivar dentro del campo. */
  max-width: calc(100% - var(--field-pad-x) - var(--field-border) * 2);
  font-family: var(--font-body);
  font-size: var(--field-fs);
  font-weight: 600;
  /* Igual al del campo: así la etiqueta cae exactamente sobre el renglón donde
     aparecerá el texto escrito. */
  line-height: var(--field-lh);
  color: var(--color-text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  /* El clic tiene que llegar al input que hay debajo. */
  pointer-events: none;
  transition: top var(--transition-fast), font-size var(--transition-fast),
              line-height var(--transition-fast), color var(--transition-fast);
}

/* El textarea tiene su propio interlineado. */
.faq__field:has(.faq__textarea) .faq__label {
  line-height: 1.6;
}

/* La del textarea puede ocupar dos líneas en reposo: el campo es alto y no hay
   nada debajo que tapar. En los inputs de una línea sí se recorta con "…". */
.faq__field:has(.faq__textarea) .faq__label {
  white-space: normal;
}

/* Sube a la banda reservada: al enfocar o cuando el campo ya tiene contenido.
   :placeholder-shown es lo que detecta "vacío" — de ahí el placeholder=" ". */
.faq__input:focus + .faq__label,
.faq__input:not(:placeholder-shown) + .faq__label,
.faq__textarea:focus + .faq__label,
.faq__textarea:not(:placeholder-shown) + .faq__label {
  top: 0;
  font-size: max(12px, 0.82rem);
  /* Ceñido al renglón: con el 1.5 del campo la caja de línea era más alta que
     la banda y los glifos se montaban sobre el borde. */
  line-height: 1.15;
  /* Arriba solo cabe una línea: la banda reservada es de un renglón. Ahí ya no
     hay texto escrito al lado, así que solo se reserva el margen izquierdo. */
  white-space: nowrap;
  /* Arriba la etiqueta ya no acompaña al texto escrito, así que se alinea con
     el borde del campo: a 320px "¿En qué podemos ayudarte?" no cabía con la
     sangría del padding y se recortaba con "…". */
  left: 0;
  max-width: 100%;
}

/* Único realce, y con color en vez de peso: el campo que se está llenando. */
.faq__input:focus + .faq__label,
.faq__textarea:focus + .faq__label {
  color: var(--color-purple-dark);
}

.faq__field:has(.faq__input--invalid) .faq__label {
  color: var(--color-error-text);
}

.faq__field:has(.faq__textarea) {
  flex: 1;
}

/* display:flex del .faq__field le gana a la hoja del navegador. */
.faq__field[hidden] {
  display: none;
}

.faq__field--group {
  border: none;
  padding: 0;
  margin: 0;
}

/* Rótulo fijo del grupo de roles: ocupa la misma banda que una etiqueta
   flotante para que la fila mida igual que la de un campo. */
.faq__label--static {
  position: static;
  display: flex;
  align-items: center;
  height: calc(var(--field-label-h) - 0.25rem);
  max-width: 100%;
  font-family: var(--font-body);
  font-size: max(12px, 0.82rem);
  /* Mismo renglón ceñido que una etiqueta flotante: las dos se construyen
     igual, así el rótulo del grupo cae a la misma altura que los de campo. */
  line-height: 1.15;
  font-weight: 600;
  color: var(--color-text-muted);
  white-space: nowrap;
}

/* ── Autorización de tratamiento de datos (Ley 1581 de 2012) ─────────────── */
.faq__consent {
  padding-top: 0;
}

.faq__consent-label {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 44px;
  cursor: pointer;
}

.faq__consent-label input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  flex-shrink: 0;
  width: max(20px, 1.25rem);
  height: max(20px, 1.25rem);
  margin: 0;
  border: var(--field-border) solid var(--color-text-muted);
  border-radius: 0.3rem;
  background: #fff;
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}

.faq__consent-label input[type="checkbox"]:checked {
  background: var(--color-purple) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='3 8.5 6.5 12 13 4.5'/%3E%3C/svg%3E") center / 80% no-repeat;
  border-color: var(--color-purple);
}

.faq__consent-label input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--color-purple);
  outline-offset: 2px;
}

.faq__consent-text {
  font-family: var(--font-body);
  font-size: max(13px, var(--fs-sm));
  font-weight: 500;
  line-height: 1.4;
  color: var(--color-text);
}

.faq__consent-text a {
  color: var(--color-purple-dark);
  text-decoration: underline;
}

/* Error junto al campo: tono de error legible (5.13:1; el rosa de antes daba
   2.75) y piso de 13px (--fs-xs daba 9.75px en la banda muerta). Entra con un
   fundido y una bajada corta — sin sacudidas. */
.faq__field-error {
  font-family: var(--font-body);
  font-size: max(13px, var(--fs-xs));
  font-weight: 600;
  color: var(--color-error-text);
  padding-left: var(--space-1);
  animation: field-error-in var(--motion-base) var(--ease-out-soft);
}

@keyframes field-error-in {
  from { opacity: 0; translate: 0 -0.25rem; }
}

.faq__field-error[hidden] {
  display: none;
}

.faq__input--invalid {
  border-color: var(--color-error-text);
  box-shadow: 0 0 0 2px rgba(196, 30, 116, 0.18);
}

/* ESTA es la regla que faltaba. `.faq__form` es display:flex, que le gana a la
   regla [hidden] del navegador: al enviar, el atributo se ponía pero el
   formulario seguía visible, con el botón trabado en "Enviando..." y el mensaje
   de éxito colgando debajo. El aspecto del éxito lo da .form-success. */
.faq__form[hidden] {
  display: none;
}

/* ── Desktop (min-width: 48.0625rem / 769px) ── */
@media (min-width: 48.0625rem) {
  .faq > .container {
    padding-inline: 0;
  }

  .faq__title {
    font-size: clamp(2rem, 1rem + 3.5vw, 3.75rem);
    line-height: 0.88;
  }

  .faq__deco-rose {
    left: 12rem;
    right: auto;
    top: 30%;
    width: clamp(2rem, 4vw, 3.5rem);
  }

  .faq__deco-teal {
    display: block;
    position: absolute;
    right: 0;
    bottom: 0;
    width: clamp(12rem, 30vw, 35.6875rem); /* 571px ÷ 16 = max; 30vw ≈ 571px @ 1920px */
    height: auto;
    pointer-events: none;
    z-index: 0;
    will-change: transform;
    transform: translateZ(0);
  }

  .faq__deco-teal-mobile {
    display: none;
  }

  /* El formulario es la acción de la página: pasa de 1/3 a ~43% del ancho.
     Con 4fr/2fr los campos medían ~250px en un 1440 y el consentimiento se
     partía en cinco líneas. */
  .faq__body {
    display: grid;
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
    gap: var(--space-8);
    align-items: stretch;
  }

  .faq__group-title {
    display: block;
    font-family: var(--font-body);
    /* Piso de 13px: --fs-sm daba 10.6px a 1024 (y en mayúsculas). */
    font-size: max(13px, var(--fs-sm));
    font-weight: 600;
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    margin-bottom: var(--space-4);
  }

  .faq__answer p {
    font-size: var(--fs-sm);
  }

  .faq__form-wrap {
    border-radius: 1.5rem;
    padding: 1.625rem 2.625rem 1.625rem 2rem;
  }

  .faq__form {
    gap: 0.75rem;
  }

  .faq__form {
    --field-pad-y: 0.6875rem;
    --field-pad-x: 1.25rem;
    /* Piso de 14px: entre 769 y ~1000px el root cae a su suelo de 13px y
       --fs-sm rendía 12.2px. Desde que la etiqueta vive dentro del campo, ese
       tamaño ya no es solo el texto escrito: es el rótulo del formulario. */
    --field-fs: max(14px, var(--fs-sm));
  }

  .faq__input,
  .faq__textarea {
    border-radius: 0.625rem;
  }

  .faq__role-pills {
    gap: 0.625rem;
  }

  .role-pill span {
    padding: 0.6875rem 0.5rem;
    border-radius: 0.625rem;
    font-size: var(--fs-sm);
  }

  .faq__submit {
    padding-block: 0.975rem;
    font-size: var(--fs-body);
  }
}

/* ── Campos obligatorios ───────────────────────────────────────────────────
   Asterisco tras el rótulo de cada campo requerido. El texto alternativo vacío
   (`/ ""`) evita que el lector lea "asterisco": el campo ya se anuncia como
   obligatorio por el atributo required. */
.faq__field:has(:required) > .faq__label::after,
.faq__field--group:has(:required) .faq__label--static::after,
.faq__consent:has(:required) .faq__consent-text::after {
  /* Espacio de no separación: uno normal se colapsaba en el rótulo del rol. */
  content: "\00a0*";
  content: "\00a0*" / "";
  color: var(--color-error-text);
  font-weight: 700;
}

/* ── Campo "Nombre del jardín" ─────────────────────────────────────────────
   Aparecía de golpe al elegir Directivo o Profe. Ahora entra con fundido y
   bajada corta (se dispara al quitarse [hidden]). */
#faq-field-jardin:not([hidden]) {
  animation: field-reveal var(--motion-base) var(--ease-out-soft);
}

@keyframes field-reveal {
  from { opacity: 0; translate: 0 -0.5rem; }
}

/* ── Enviando ──────────────────────────────────────────────────────────────
   Spinner dentro del botón (un aro que gira: transform). El texto cambia a
   "Enviando..." desde faq-form.js y el formulario lleva aria-busy. */
.faq__submit.is-loading {
  cursor: progress;
  gap: var(--space-3);
}

.faq__submit.is-loading::before {
  content: '';
  width: 1.1em;
  height: 1.1em;
  border-radius: 50%;
  border: 2.5px solid rgba(255, 255, 255, 0.35);
  border-top-color: #fff;
  animation: btn-spin 0.8s linear infinite;
}

@keyframes btn-spin {
  to { transform: rotate(360deg); }
}

.faq__submit:disabled {
  opacity: 0.85;
}

/* ── css/cta-final.css ────────────────────────────────── */
.cta-final {
  margin-inline: clamp(2.5rem, 5.21vw, 6.25rem);
}

/* Wrapper — centra el contenido y limita el ancho máximo */
.cta-final__wrap {
  position: relative;
  margin-inline: auto;
}

/* Card púrpura principal — sin overflow:hidden para que characters desborden arriba */
.cta-final__card {
  position: relative;
  width: 100%;
  border-radius: 1.5rem;
  background: url('../assets/images/cta-final/background.svg') no-repeat center / cover;
  min-height: clamp(20rem, 36vw, 30rem);
  display: flex;
  flex-direction: column;
}

/* Characters — centro anclado al borde superior del card */
.cta-final__characters {
  position: absolute;
  top: -5%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: clamp(9.5rem, 30vw, 15rem);
  height: auto;
  z-index: 5;
  pointer-events: none;
}

/* Intersect — decoración circular, lado derecho */
.cta-final__intersect-svg {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 85%;
  height: auto;
  z-index: 1;
  pointer-events: none;
}

/* Fondo ondulado del panel — solo mobile (background_b1 volteado). En desktop
   el panel usa background.svg (morado sólido redondeado). */
.cta-final__bg-mobile {
  display: none;
}

/* Inner — ocupa todo el espacio disponible del card y centra su contenido */
.cta-final__inner {
  flex: 1;
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  padding: clamp(5rem, 7vw, 7rem) clamp(2rem, 4vw, 3.5rem) clamp(3rem, 5vw, 4.5rem) clamp(4.8rem, 10vw, 12rem);
}

/* Contenido — columna izquierda ~45% */
.cta-final__content {
  position: relative;
  isolation: isolate;
  width: clamp(16rem, 50%, 41rem);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

/* Misma sombra radial purple-dark que en el hero: la descripción blanca sobre
   el morado claro del fondo quedaba en 2.8–3.9:1 según el ancho. */
.cta-final__content::before {
  content: '';
  position: absolute;
  inset: -14% -22% -16% -16%;
  z-index: -1;
  background: radial-gradient(
    ellipse farthest-side at 45% 55%,
    rgba(91, 63, 196, 0.66) 0%,
    rgba(91, 63, 196, 0.58) 62%,
    rgba(91, 63, 196, 0) 100%
  );
  pointer-events: none;
}

/* Phones — anclados al bottom-right del wrap, sobresalen arriba */
.cta-final__phones-svg {
  position: absolute;
  right: clamp(15rem, -15vw, -2.4rem);
  bottom: clamp(-18rem, -10vw, -4.2rem);
  height: clamp(22rem, 41vw, 58rem);
  width: auto;
  max-width: 100%;
  /* El SVG que había antes metía el PNG en un viewBox de 1034x863 estirándolo
     de forma NO uniforme (matrix con factores distintos en X e Y). Al pasar a
     WebP la proporción nativa del raster es 2878x2357 y el render cambiaba ~2%,
     moviendo el layout. Esto reproduce la geometría anterior exacta. */
  aspect-ratio: 1034 / 863;
  object-fit: fill;
  z-index: 4;
  pointer-events: none;
}

/* Typography */
.cta-final__title {
  font-family: var(--font-display);
  font-size: clamp(2.25rem, 0.75rem + 5.5vw, 5.3125rem);
  font-weight: 700;
  color: #fff;
  line-height: 0.85;
  margin-bottom: var(--space-5);
}

.cta-final__title--accent {
  color: var(--color-yellow);
}

.cta-final__desc {
  font-family: var(--font-body);
  font-size: var(--fs-lg);
  font-weight: 400;
  color: #fff;
  line-height: 1.167;
  margin-bottom: var(--space-8);
}

.cta-final__desc strong {
  font-weight: 700;
}

.cta-final__cta {
  margin-bottom: var(--space-5);
}

/* Corazón (antes 💛) en el amarillo de marca, pegado como un adhesivo en la
   esquina de la etiqueta "¡Claro que sí!" — así nunca queda solo en una línea.
   Late una vez al entrar. */
.cta-final__title--accent {
  position: relative;
  display: inline-block;
}

/* La etiqueta gana aire a la derecha para que el corazón se apoye en su
   esquina y no sobre el "!". */
.cta-final__title--accent .text-sticker {
  padding-right: 0.62em;
}

.cta-final__title-heart {
  position: absolute;
  top: -0.36em;
  right: -0.22em;
  display: inline-block;
  font-size: 0.52em;
  rotate: 14deg;
  color: var(--color-brand-yellow);
  --ico-tone: var(--color-brand-yellow);
  --ico-tone-opacity: 1;
}

.cta-final__title-heart .sticker {
  display: inline-block;
}

@keyframes heart-beat {
  0%, 100% { scale: 1; }
  30%       { scale: 1.25; }
  55%       { scale: 0.95; }
}

.cta-final__content.is-visible .cta-final__title-heart {
  animation: heart-beat 900ms var(--ease-out-soft) 600ms;
}

.cta-final__tagline {
  font-family: var(--font-body);
  /* Piso de 13px: entre 769 y ~1280px el root cae a su suelo y --fs-sm rendía
     11.5px. Es la firma de marca, no una nota al pie. */
  font-size: max(13px, var(--fs-sm));
  font-weight: 500;
  line-height: 1.5;
  color: #fff;
  background: var(--color-purple-dark);
  display: inline-flex;
  align-items: center;
  width: fit-content;
  height: 2.5rem;
  padding-inline: var(--space-6);
  border-radius: 2.438rem;
  white-space: nowrap;
  margin-left: clamp(4.2rem, 8.75vw, 10.5rem);
  margin-bottom: clamp(1.2rem, 2.5vw, 3rem);
}

.cta-final__tagline strong {
  font-weight: 800;
  margin-right: 0.25rem;
}

.cta-final__store-badges .hero__store-badge {
  display: flex;
  align-items: center;
  min-height: 44px;
}

.cta-final__store-badges {
  position: absolute;
  bottom: clamp(1.5rem, 1.5vw, 1.5rem);
  right: clamp(1.5rem, 1.5vw, 1.5rem);
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0;
  z-index: 5;
  width: 10%;
}

/* ==========================================================================
   MOBILE (<769px) — layout vertical según Figma (node 4450-28342)
   Stack: personajes → teléfonos → panel morado (título, desc, pill, botón).
   El card deja de ser una tarjeta inset y pasa a banner morado full-bleed.
   ========================================================================== */
@media (max-width: 48rem) {
  /* Full-bleed y padding vertical del stack.
     overflow-x: clip recorta el sobrante transparente del asset de teléfonos
     (que se centra con translateX) sin generar scroll horizontal. */
  .cta-final {
    margin-inline: 0;
    padding-top: clamp(2rem, 8vw, 4rem);
    padding-bottom: 0;
    overflow-x: clip;
  }

  /* El wrap se vuelve la columna que apila personajes, teléfonos y panel */
  .cta-final__wrap {
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  /* Personajes arriba del todo, sobre fondo blanco */
  .cta-final__characters {
    position: static;
    transform: none;
    order: 1;
    width: clamp(6.5rem, 30vw, 11rem);
    margin-bottom: clamp(1.5rem, 4vw, 2rem);
  }

  /* Teléfonos GRANDES, solapando la ola superior del panel morado.
     El asset tiene el contenido corrido a la derecha (centro real en ~62% del
     ancho) con la mitad izquierda transparente; se ensancha para que ocupen casi
     todo el ancho y se corrige con translateX(-11.8%) para centrarlos
     ópticamente. El sobrante lo recorta overflow-x: clip del .cta-final. */
  .cta-final__phones-svg {
    position: relative;
    z-index: 3;                       /* por encima del panel para el solape */
    order: 2;
    right: auto;
    bottom: auto;
    width: clamp(24rem, 160vw, 80rem);
    height: auto;
    max-width: none;                  /* anula el max-width:100% global de img */
    transform: translateX(-25%);
    margin-bottom: clamp(-9rem, -24vw, -5rem);
  }

  /* Panel morado full-bleed. La ola superior la aporta .cta-final__bg-mobile;
     el color de relleno bajo la ola lo pone este background sólido. */
  .cta-final__card {
    order: 3;
    position: relative;
    isolation: isolate;               /* contexto de apilado propio para las
                                         decoraciones con z-index negativo */
    min-height: 0;
    border-radius: 0;
    background: var(--color-purple);
    /* espacio superior suficiente para librar la ola + los teléfonos solapados */
    padding: clamp(7rem, 26vw, 11rem) clamp(2.5rem, 12.5vw, 6rem) clamp(2.5rem, 8vw, 4rem);
    align-items: stretch;
  }

  /* Ola superior: background_b1 rotado 180° para que la curva quede arriba.
     Tamaño y posición en vw (proporción pura del viewport) calibrados al frame
     de 768px, para que la composición se vea IDÉNTICA en todo el rango <769px.
     El vw evita el congelamiento del rem (root fijo en 13px bajo 624px). Las
     guardas rem del clamp no muerden entre 320–768; solo acotan los extremos.
     left:5% + translateX(-50%) ya son proporcionales. */
  .cta-final__bg-mobile {
    display: block;
    position: absolute;
    top: clamp(-42rem, -83.3vw, -17rem);
    left: 5%;
    width: clamp(38rem, 198vw, 100rem);
    height: clamp(17rem, 87.5vw, 44rem);
    max-width: none;
    transform: translateX(-50%) rotate(180deg);
    z-index: -2;                       /* detrás de todo, sobre el fondo del card */
    pointer-events: none;
  }

  /* Aplanar inner/content para intercalar la pill entre desc y el botón,
     sin tocar el DOM. Al perder su caja, el .reveal (opacity:0) deja de
     aplicar y el contenido queda visible. */
  .cta-final__inner,
  .cta-final__content { display: contents; }

  /* Intersect reutilizado: swoosh decorativo sobre la ola, tras los teléfonos.
     top y right en vw (calibrados a 768px) para escalar igual en todo el rango;
     width:300% y height:auto ya eran proporcionales. */
  .cta-final__intersect-svg {
    display: block;
    right: clamp(-34rem, -62.5vw, -15rem);
    bottom: 0rem;
    left: auto;
    width: 300%;
    max-width: none;
    z-index: -1;                      /* sobre la ola, detrás del texto */
  }

  /* Orden dentro del panel: título → desc → pill → botón */
  .cta-final__title   { order: 1; }
  .cta-final__desc    { order: 2; }
  .cta-final__tagline { order: 3; }
  .cta-final__cta     { order: 4; }

  /* Título — Sour Gummy, line-height ~87.5% */
  .cta-final__title {
    font-size: var(--fs-h2);
    line-height: 0.9;
    text-align: left;
    margin-bottom: clamp(0.75rem, 3vw, 1.25rem);
  }

  /* Descripción — subtítulo de sección */
  .cta-final__desc {
    font-size: var(--fs-2xl);
    line-height: 1.17;
    margin-bottom: clamp(1.25rem, 5vw, 2rem);
  }

  /* Pill — texto continuo (Figma node 4450-28355): "KuidApp" en negrita inline
     seguido del resto, fluyendo y envolviendo como párrafo. display:block anula
     el inline-flex del desktop (que separaba "KuidApp" del texto en 2 columnas). */
  .cta-final__tagline {
    display: block;
    align-self: center;
    width: auto;
    max-width: 85%;
    height: auto;
    white-space: normal;
    overflow-wrap: break-word;
    text-align: left;
    margin-left: 0;
    margin-bottom: clamp(1.5rem, 6vw, 2.5rem);
    padding: clamp(0.75rem, 3vw, 1.1rem) clamp(1.1rem, 4.5vw, 1.75rem);
    border-radius: clamp(2.25rem, 10vw, 5rem);
    font-size: max(13px, var(--fs-sm));
    line-height: 1.35;
  }

  /* Solo el espacio normal tras "KuidApp" (Figma no lleva margen extra) */
  .cta-final__tagline strong {
    margin-right: 0;
  }

  /* Botón blanco — mismo tamaño que testimonials__cta .btn, centrado */
  .cta-final__cta {
    align-self: center;
    width: clamp(15rem, 67.2vw, 33rem);
    height: max(44px, clamp(2.75rem, 12.1vw, 6rem));
    border-radius: clamp(1.375rem, 6.05vw, 3rem);
    font-size: max(14px, var(--fs-body));
    line-height: 1;
    margin-bottom: 0;
  }

  /* Los store-badges no van en el diseño mobile */
  .cta-final__store-badges { display: none; }
}

/* Banda muerta: el lema ("KuidApp: organización con alma, tecnología con
   corazón.") quedaba con el final debajo de los teléfonos — ya pasaba en main.
   Ahí se le permite partir en dos líneas. */
@media (min-width: 48.0625rem) and (max-width: 79.9375rem) {
  .cta-final__tagline {
    /* inline-block y no inline-flex: con flex, "KuidApp:" y el resto eran dos
       ítems y al partir quedaban en columnas separadas. Alto automático (el
       fijo de 2.5rem dejaba la segunda línea fuera de la píldora) y radio
       acorde a dos líneas. */
    display: inline-block;
    height: auto;
    padding-block: 0.45rem;
    border-radius: 1.25rem;
    white-space: normal;
    max-width: 24rem;
    text-wrap: balance;
  }
}

/* Móvil: el texto queda pegado al borde inferior de la tarjeta y la sombra
   de contraste (.cta-final__content::before) se derramaba como un halo
   morado sobre el blanco, entre la tarjeta y el footer. Se recorta al borde
   de la tarjeta; adentro sigue dando el contraste. */
@media (max-width: 48rem) {
  .cta-final__card {
    overflow: hidden;
  }
}

/* ── css/footer.css ────────────────────────────────── */
.footer-outer {
  padding: clamp(2.5rem, 12.5vw, 6rem);
}

.footer {
  background: var(--color-purple-dark);
  padding: var(--space-12) 0;
  border-radius: 1.5rem;
  margin-inline: auto;
}

.footer__inner {
  display: grid;
  grid-template-columns: 12.5rem repeat(2, 1fr) 11.25rem;
  gap: var(--space-8);
  align-items: start;
}

/* Logo */
.footer__logo {
  display: flex;
  align-self: center;
}

.footer__logo img {
  height: 4.5rem;
  width: auto;
}

/* Store badges (App Store / Google Play) — mobile only, ver .footer__inner mobile */
.footer__stores {
  display: none;
}

.footer__store-badge {
  display: flex;
  align-items: center;
  min-height: 44px;
  transition: transform var(--motion-fast) var(--ease-out-soft);
}

@media (hover: hover) {
  .footer__store-badge:hover {
    transform: translateY(var(--motion-lift));
  }
}

.footer__store-badge img {
  display: block;
  width: auto;
}

.footer__logo-fallback {
  display: none;
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  font-weight: 800;
  color: #fff;
  padding: var(--space-2) var(--space-4);
  background: rgba(255,255,255,0.15);
  border-radius: var(--radius-lg);
}

.footer__logo-fallback span {
  color: var(--color-yellow);
}

/* Columns */
.footer__col .footer__heading {
  font-family: var(--font-body);
  font-size: max(13px, var(--fs-sm));
  font-weight: 700;
  color: #fff;
  margin-bottom: var(--space-4);
}

.footer__col ul {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0;
}

.footer__col a {
  /* Piso de 13px: entre 769 y ~1280px el root cae a su suelo y --fs-sm rendía
     11.7px. */
  font-size: max(13px, var(--fs-sm));
  color: #fff;
  font-weight: 500;
  /* Mínimo táctil: los enlaces medían 18px de alto (16.5 en esa misma banda).
     El padding negativo en el eje horizontal mantiene la alineación con el
     título de la columna. */
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  position: relative;
  text-decoration: none;
}

/* Subrayado que crece desde la izquierda al pasar el mouse o con foco: un
   pseudo-elemento que escala en X (transform), sin bajar la opacidad del
   texto como antes. */
.footer__col a::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0.7rem;
  height: 2px;
  border-radius: 1px;
  background: var(--color-brand-yellow);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--motion-base) var(--ease-out-soft);
}

.footer__col a:hover::after,
.footer__col a:focus-visible::after {
  transform: scaleX(1);
}

.footer__col a:focus-visible {
  outline: var(--focus-ring-width) solid #fff;
  outline-offset: 3px;
  border-radius: 0.25rem;
}

/* Copyright */
.footer__copy {
  /* Piso de 12px: rendía 9.75px a 320px y en la banda de 800-1180. */
  font-size: max(12px, var(--fs-xs));
  color: #fff;
  line-height: 1.4;
}

.footer__copy strong {
  font-weight: 700;
}

.footer__made {
  margin-top: var(--space-3);
  color: #fff;
  font-size: max(13px, var(--fs-sm));
}

/* Versión del build — discreta; sirve para verificar la actualización en el navegador */
.footer__version {
  margin-top: var(--space-2);
  color: #fff;
  font-size: max(12px, var(--fs-xs));
  /* 0.9 y no 0.75: con 0.75 daba 3.91:1 sobre el morado del footer. */
  opacity: 0.9;
  letter-spacing: 0.03em;
}

/* ── Mobile (≤768px) — columna única centrada, orden Figma ── */
@media (max-width: 48rem) {
  
  .footer {
    padding-block: clamp(3.25rem, 16.3vw, 7.8rem);
    padding-inline: 0;
    border-radius: 1rem;
  }

  .footer__inner {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: clamp(1.53rem, 7.67vw, 3.68rem);
  }

  .footer__logo img {
    height: clamp(2.65rem, 13.26vw, 6.79rem);
  }

  .footer__stores {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: clamp(0.46rem, 2.33vw, 1.12rem);
    margin-bottom: calc(clamp(2rem, 10vw, 4.8rem) - clamp(1.53rem, 7.67vw, 3.68rem));
  }

  .footer__store-badge img {
    height: clamp(1.86rem, 9.3vw, 4.47rem);
  }

  .footer__col ul {
    align-items: center;
  }

  /* Texto footer — uniforme en todo el rango mobile */
  .footer__col .footer__heading,
  .footer__col a,
  .footer__made {
    font-size: var(--fs-body);
  }

  .footer__copy {
    font-size: var(--fs-body);
    line-height: 1.6;
  }
}

/* ── css/video-modal.css ────────────────────────────────── */
/* Video Modal — popup con video local, se abre por defecto al cargar */

.video-modal {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  padding: 0.5rem;
  opacity: 0;
  pointer-events: none;
  /* visibility, no solo opacity: con opacity 0 el modal cerrado seguía en el
     orden de tabulación (4 controles invisibles) y su role="dialog" quedaba
     expuesto a los lectores. visibility:hidden lo saca de las dos cosas. Se
     retrasa el cambio a hidden hasta que termina el fundido de salida. */
  visibility: hidden;
  transition:
    opacity var(--motion-exit) var(--ease-in-soft),
    visibility 0s linear var(--motion-exit);
}

.video-modal.is-open {
  opacity: 1;
  pointer-events: auto;
  visibility: visible;
  transition: opacity var(--motion-base) var(--ease-out-soft);
}

.video-modal__card {
  background: #fff;
  border-radius: clamp(0.75rem, 2vw, 1.75rem);
  padding: clamp(0.375rem, 1vw, 0.75rem);
  width: min(99vw, 90rem);
  position: relative;
  box-shadow: 0 32px 80px rgba(0, 0, 0, 0.3);
  transform: scale(0.94);
  transition: transform var(--motion-exit) var(--ease-in-soft);
}

.video-modal.is-open .video-modal__card {
  transform: none;
  transition: transform var(--motion-reveal) var(--ease-spring);
}

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

.video-modal__close {
  position: absolute;
  top: -0.75rem;
  right: -0.75rem;
  /* Piso de 44px: con el root en 13px, 2.5rem daba 33px. */
  width: max(44px, 2.5rem);
  height: max(44px, 2.5rem);
  border-radius: 50%;
  background: var(--color-purple-dark);
  border: none;
  color: #fff;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2;
  box-shadow: 0 4px 14px rgba(135, 104, 245, 0.5);
  transition: transform var(--transition-fast), background var(--transition-fast);
}

.video-modal__close:hover {
  transform: scale(1.12);
  background: var(--color-purple-dark);
}

.video-modal__player {
  position: relative;
  aspect-ratio: 16 / 10;
  border-radius: clamp(0.5rem, 1vw, 1rem);
  overflow: hidden;
  background: #000;
}

.video-modal__video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  cursor: pointer;
}

/* Controls bar */
.video-modal__controls {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 0.75rem 1rem;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.65) 0%, transparent 100%);
  display: flex;
  align-items: center;
  gap: 0.75rem;
  z-index: 1;
}

.video-modal__toggle,
.video-modal__mute {
  background: none;
  border: none;
  color: #fff;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  width: max(44px, 2.75rem);
  height: max(44px, 2.75rem);
  padding: 0;
  flex-shrink: 0;
  transition: transform var(--transition-fast);
}

.video-modal__toggle:hover,
.video-modal__mute:hover {
  transform: scale(1.15);
}

.video-modal__toggle .icon-play  { display: none; }
.video-modal__toggle .icon-pause { display: block; }
.video-modal__player.is-paused .video-modal__toggle .icon-play  { display: block; }
.video-modal__player.is-paused .video-modal__toggle .icon-pause { display: none; }

.video-modal__volume {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-left: auto;
}

.video-modal__mute .icon-vol-off { display: none; }
.video-modal__player.is-muted .video-modal__mute .icon-vol-on  { display: none; }
.video-modal__player.is-muted .video-modal__mute .icon-vol-off { display: block; }

/* Mismo patrón que .solution__player-vol-slider: el input mide 44px de alto
   (objetivo táctil) y el carril visible de 4px se pinta en el track. */
.video-modal__vol-slider {
  width: clamp(4rem, 8vw, 7rem);
  height: 44px;
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
  cursor: pointer;
}

.video-modal__vol-slider::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.35);
}

.video-modal__vol-slider::-moz-range-track {
  height: 4px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.35);
}

.video-modal__vol-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: #fff;
  cursor: pointer;
  margin-top: -5px;
}

.video-modal__vol-slider::-moz-range-thumb {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: #fff;
  border: none;
  cursor: pointer;
}

/* Spinner de carga — visible mientras el video está buffereando */
.video-modal__player.is-loading::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 3rem;
  height: 3rem;
  border: 3px solid rgba(255, 255, 255, 0.25);
  border-top-color: #fff;
  border-radius: 50%;
  animation: modal-spin 0.75s linear infinite;
  z-index: 4;
  pointer-events: none;
}

@keyframes modal-spin {
  to { transform: translate(-50%, -50%) rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
  .video-modal__player.is-loading::after { animation: none; opacity: 0.6; }
}

/* Unmute prompt — aparece solo cuando el navegador forzó el mute por autoplay */
.video-modal__unmute-prompt {
  position: absolute;
  top: 1rem;
  left: 50%;
  transform: translateX(-50%);
  background: rgba(0, 0, 0, 0.72);
  color: #fff;
  border: none;
  border-radius: var(--radius-full);
  padding: 0.5rem 1.25rem;
  font-size: var(--fs-sm);
  font-family: var(--font-body);
  font-weight: 600;
  cursor: pointer;
  z-index: 4;
  white-space: nowrap;
  display: none;
}

.video-modal__player.is-muted .video-modal__unmute-prompt {
  display: block;
  animation: pulse-prompt 2.5s ease-in-out infinite;
}

@keyframes pulse-prompt {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.5; }
}

@media (prefers-reduced-motion: reduce) {
  .video-modal__player.is-muted .video-modal__unmute-prompt {
    animation: none;
  }
}

/* Mobile: el video maximizado desde .solution__player es el vertical — el modal
   respeta ese aspect-ratio (mismo que .solution__player en mobile) en vez del
   16:10 de desktop, y la card se ajusta al ancho del video en vez de quedar
   angosta con márgenes blancos enormes a los lados. */
@media (max-width: 48rem) {
  .video-modal__card {
    width: fit-content;
    max-width: 95vw;
  }

  .video-modal__player {
    aspect-ratio: 320 / 563;
    width: min(90vw, 26rem);
    max-height: 88vh;
    margin-inline: auto;
  }
}
