/* ==========================================================================
   Doisol — Sections added in v2
   Testimonial cascade · integrations orbit · Doris conversation ·
   e-book capture · closing surface
   ========================================================================== */

/* --- Testimonial cascade -------------------------------------------------
   Three columns drifting at different speeds. Each column's content is
   duplicated once, so translateY(-50%) lands on an identical frame and the
   loop has no seam. */

/* Vertical, solo en escritorio. En móvil manda `.muro-movil`: una columna
   vertical alta obliga a desplazarse mucho, y el texto en movimiento vertical
   sobre 375 px se lee peor que quieto. */
.cascada { display: none; }

@media (min-width: 62rem) {
  .cascada {
    position: relative;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--s-4);
    height: 38rem;
    overflow: hidden;
    /* Difumina los bordes del corte en vez de partir tarjetas por la mitad. */
    mask-image: linear-gradient(to bottom, transparent, #000 14%, #000 86%, transparent);
    -webkit-mask-image: linear-gradient(to bottom, transparent, #000 14%, #000 86%, transparent);
  }
}

.cascada__columna {
  display: grid;
  gap: var(--s-4);
  align-content: start;
  animation: derivar var(--vel, 60s) linear infinite;
  will-change: transform;
}

.cascada__columna:nth-child(2) { --vel: 78s; animation-direction: reverse; }
.cascada__columna:nth-child(3) { --vel: 68s; }

@keyframes derivar {
  from { transform: translateY(0); }
  to   { transform: translateY(-50%); }
}

@media (hover: hover) and (pointer: fine) {
  .cascada:hover .cascada__columna { animation-play-state: paused; }
}

/* Focus inside the wall stops it, or keyboard users chase a moving link. */
.cascada:focus-within .cascada__columna { animation-play-state: paused; }

.testimonio {
  background: var(--blanco);
  border: 1px solid var(--borde);
  border-radius: var(--r-lg);
  padding: var(--s-5);
  display: grid;
  gap: var(--s-4);
}

.testimonio p {
  font-size: var(--t-sm);
  line-height: 1.6;
  color: var(--tinta);
}

.testimonio__firma { display: flex; align-items: center; gap: var(--s-3); }

.testimonio__foto,
.testimonio__iniciales {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  flex: none;
  object-fit: cover;
}

.testimonio__iniciales {
  display: grid;
  place-items: center;
  background: var(--linea);
  color: var(--blanco);
  font-family: var(--fuente-display);
  font-weight: 700;
  font-size: var(--t-sm);
}

.testimonio__quien { display: grid; gap: 2px; }
.testimonio__nombre { font-weight: 700; font-size: var(--t-sm); color: var(--azul-oscuro); }
.testimonio__cargo { font-size: var(--t-xs); color: var(--tinta-suave); }

.tarjeta-logo {
  background: var(--blanco);
  border: 1px solid var(--borde);
  border-radius: var(--r-lg);
  padding: var(--s-5);
  display: grid;
  place-items: center;
  min-height: 6.5rem;
}

/* El alto va fijo y el ancho en `auto`. Los dos son obligatorios, y el
   orden del razonamiento importa:

   1. Los atributos `width`/`height` de la etiqueta hacen falta para que el
      navegador conozca la proporción antes de descargar la imagen y reserve
      el espacio. Sin ellos estos logos ocupan 0x0 y saltan al cargar.
   2. Pero si el CSS no declara NINGÚN eje, el atributo `width` pasa a ser
      el ancho usado y el logo se estira hasta el tope de la tarjeta.
      Medido: Sistema Integrado saltaba de 124 px a 335 px.
   3. Y si se declaran los dos en `auto`, la caja vuelve a colapsar a 0x0
      mientras la imagen no ha llegado: se pierde justo lo que se buscaba.

   Con un eje fijo y el otro en `auto`, la proporción resuelve el ancho de
   inmediato. `height` en vez de `max-height` no cambia nada visible: todos
   estos logos superan los 44 px de alto, así que el tope siempre mandaba. */
.tarjeta-logo img {
  height: 2.75rem;
  width: auto;
  max-width: 100%;
  object-fit: contain;
  filter: grayscale(1);
  opacity: 0.66;
}

/* --- Traction figures ---------------------------------------------------- */

.cifras {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: var(--s-5);
  padding-bottom: var(--s-7);
}

.cifra { display: grid; gap: var(--s-2); }

.cifra__valor {
  font-family: var(--fuente-display);
  font-weight: 700;
  font-size: var(--t-xl);
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--linea);
}

.cifra__etiqueta { font-size: var(--t-sm); color: var(--tinta-suave); max-width: 22ch; }

/* --- Integrations orbit + Doris conversation ----------------------------- */

.union { display: grid; gap: 1px; background: var(--borde); }

@media (min-width: 62rem) { .union { grid-template-columns: 1fr 1fr; } }

.union__panel {
  background: var(--blanco);
  padding: clamp(1.5rem, 1rem + 3vw, 3rem);
  display: grid;
  align-content: space-between;
  gap: var(--s-7);
}

.union__pie { display: grid; gap: var(--s-3); }
.union__pie h3 { font-size: var(--t-md); letter-spacing: -0.02em; }
.union__pie p { font-size: var(--t-sm); color: var(--tinta-suave); max-width: 42ch; }

/* Las insignias van centradas sobre la línea del anillo, así que la órbita
   necesita medio logo de holgura a cada lado. En la portada eso lo daba el
   relleno de `union__panel`; en la página de producto cuelga directamente del
   contenedor, y sin el descuento las insignias quedan a ras del borde de la
   página. */
.orbita {
  position: relative;
  width: 100%;
  max-width: min(28rem, 100% - 2.5rem);
  margin-inline: auto;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
}

.orbita__anillo {
  position: absolute;
  border: 1px solid var(--borde);
  border-radius: 50%;
}

/* Dos anillos, no tres. El interior quedaba tan cerca del centro que sus dos
   insignias se leían apretadas contra el símbolo, y a ese diámetro el logo
   dentro de la insignia era ilegible.

   Cada anillo se mete media insignia hacia dentro, porque las insignias van
   centradas sobre la línea del anillo y de otro modo sobresalen del componente
   y arrastran la página a scroll horizontal. */
.orbita { --media-insignia: 1.8rem; }

.orbita__anillo--1 { inset: var(--media-insignia); }
.orbita__anillo--2 { inset: calc(var(--media-insignia) + 22%); }

.orbita__pista {
  position: absolute;
  animation: rotar var(--giro, 44s) linear infinite;
}

.orbita__pista--1 { inset: var(--media-insignia); --giro: 52s; }
.orbita__pista--2 { inset: calc(var(--media-insignia) + 22%); --giro: 40s; animation-direction: reverse; }

@keyframes rotar {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

@keyframes contrarotar {
  from { transform: rotate(0deg); }
  to   { transform: rotate(-360deg); }
}

/* Placement arm: a zero-width line from the ring's centre to its edge,
   rotated to the badge's angle.

   It is deliberately NOT a full-size rotated square: the axis-aligned
   bounding box of a rotated square grows by up to √2, which pushed the page
   into horizontal scroll on a phone. A line always stays inside the circle. */
.orbita__radio {
  position: absolute;
  top: 0;
  left: 50%;
  width: 0;
  height: 50%;
  transform-origin: 50% 100%;
  transform: rotate(var(--ang));
}

.orbita__logo {
  position: absolute;
  top: 0;
  left: 0;
  width: 3.6rem;
  height: 3.6rem;
  border-radius: 50%;
  background: var(--blanco);
  border: 1px solid var(--borde);
  box-shadow: 0 4px 14px -6px rgba(0, 30, 97, 0.3);
  display: grid;
  place-items: center;
  /* The badge is a circle, so rotating it is invisible — but it un-rotates
     its contents by the placement angle. */
  transform: translate(-50%, -50%) rotate(calc(var(--ang) * -1));
}

/* Second counter-rotation, this one undoing the ring's own spin so every
   logo stays upright through the whole revolution. Direction must match
   the ring it belongs to. */
.orbita__logo img {
  max-width: 70%;
  max-height: 70%;
  object-fit: contain;
  animation: contrarotar var(--giro, 44s) linear infinite;
}

.orbita__pista--2 .orbita__logo img { animation-direction: reverse; }

/* --- Despliegue de entrada -----------------------------------------------
   Las insignias salen del centro y llegan a su posición en el anillo. El
   estado por defecto es el final: la animación solo corre cuando el script
   marca `data-desplegado`, así que si nunca se dispara los logos están ahí,
   quietos, en su sitio. */

.orbita[data-desplegado='true'] .orbita__radio {
  animation: brazo 720ms var(--ease-out-quint) both;
  animation-delay: var(--retraso, 0ms);
}

.orbita[data-desplegado='true'] .orbita__logo {
  animation: llegar 720ms var(--ease-out-quint) both;
  animation-delay: var(--retraso, 0ms);
}

@keyframes brazo {
  from { height: 0; }
  to   { height: 50%; }
}

@keyframes llegar {
  from {
    opacity: 0;
    transform: translate(-50%, -50%) rotate(calc(var(--ang) * -1)) scale(0.5);
  }
  to {
    opacity: 1;
    transform: translate(-50%, -50%) rotate(calc(var(--ang) * -1)) scale(1);
  }
}

.orbita__centro {
  position: relative;
  z-index: var(--z-base);
  width: 5rem;
  height: 5rem;
  border-radius: 50%;
  background: var(--linea);
  display: grid;
  place-items: center;
  box-shadow: 0 12px 30px -10px rgba(0, 71, 186, 0.55);
}

.orbita__centro img { width: 54%; }

/* Por debajo de 30rem la órbita mide unos 295 px, y con las medidas de
   escritorio el símbolo central de 80 px invadía el anillo interior: sus dos
   insignias quedaban tapadas por el logo. Bajan las tres medidas a la vez
   para que la geometría siga cerrando —media insignia tiene que seguir siendo
   exactamente la mitad de la insignia, o los logos se salen del componente y
   arrastran la página a scroll horizontal. */
@media (max-width: 30rem) {
  .orbita { --media-insignia: 1.25rem; }

  .orbita__logo {
    width: 2.5rem;
    height: 2.5rem;
  }

  .orbita__centro {
    width: 3.25rem;
    height: 3.25rem;
  }
}

@media (hover: hover) and (pointer: fine) {
  .orbita:hover .orbita__pista,
  .orbita:hover .orbita__logo > span { animation-play-state: paused; }
}

.charla { display: grid; gap: var(--s-4); align-content: start; }

.charla__turno {
  display: flex;
  align-items: flex-end;
  gap: var(--s-3);
  transition: opacity var(--dur-media) var(--ease-out),
              transform var(--dur-media) var(--ease-out);
}

.js .charla[data-corriendo] .charla__turno {
  opacity: 0;
  transform: translateY(10px);
}

.js .charla[data-corriendo] .charla__turno[data-visible='true'] {
  opacity: 1;
  transform: translateY(0);
}

.charla__turno--persona { flex-direction: row-reverse; }

.charla__globo {
  max-width: 32ch;
  padding: var(--s-4);
  border-radius: var(--r-lg);
  font-size: var(--t-sm);
  line-height: 1.55;
}

.charla__turno--persona .charla__globo {
  background: var(--linea);
  color: var(--blanco);
  border-bottom-right-radius: var(--r-sm);
}

.charla__turno--doris .charla__globo {
  background: var(--superficie);
  color: var(--tinta);
  border: 1px solid var(--borde);
  border-bottom-left-radius: var(--r-sm);
}

.charla__avatar {
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  flex: none;
  display: grid;
  place-items: center;
  overflow: hidden;
}

.charla__avatar--doris { background: var(--linea); }
.charla__avatar--doris img { width: 55%; }
.charla__avatar--persona {
  background: var(--azul-claro);
  color: var(--azul-oscuro);
  font-family: var(--fuente-display);
  font-weight: 700;
  font-size: var(--t-xs);
}

.charla__escribiendo {
  display: inline-flex;
  gap: 4px;
  align-items: center;
  height: 1.1em;
}

.charla__escribiendo span {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--tinta-suave);
  animation: latir 1.2s var(--ease-in-out) infinite;
}

.charla__escribiendo span:nth-child(2) { animation-delay: 0.15s; }
.charla__escribiendo span:nth-child(3) { animation-delay: 0.3s; }

@keyframes latir {
  0%, 60%, 100% { opacity: 0.3; transform: translateY(0); }
  30%           { opacity: 1;   transform: translateY(-3px); }
}

/* --- E-book capture ------------------------------------------------------ */

.ebook__interior { display: grid; gap: var(--s-7); align-items: center; }

@media (min-width: 58rem) {
  .ebook__interior { grid-template-columns: 1.05fr 0.95fr; gap: var(--s-9); }
}

.ebook__texto > * + * { margin-top: var(--s-5); }

/* The offer itself is what moves: the reader watches the value proposition
   change in place. That is the section's one authored moment. */
/* Los tres títulos se apilan en la MISMA celda de grid en vez de posicionarse
   en absoluto: así el contenedor mide lo que mide el título más alto y un
   texto largo ya no se desborda sobre el párrafo de abajo. Sin `min-height`
   fija, que era la causa del solapamiento. */
.ebook__rotador {
  display: grid;
}

.ebook__titulo {
  grid-area: 1 / 1;
  opacity: 0;
  transform: translateY(0.3em);
  filter: blur(4px);
  transition: opacity 420ms var(--ease-out),
              transform 420ms var(--ease-out),
              filter 420ms var(--ease-out);
}

.ebook__titulo[data-activo='true'] {
  opacity: 1;
  transform: translateY(0);
  filter: blur(0);
}

/* Sin JS los tres títulos quedan legibles, uno debajo del otro. */
.ebook__rotador:not([data-listo]) .ebook__titulo {
  grid-area: auto;
  opacity: 1;
  filter: none;
  transform: none;
}

.ebook__forma {
  background: var(--blanco);
  border-radius: var(--r-lg);
  padding: clamp(1.5rem, 1rem + 2vw, 2.5rem);
  color: var(--tinta);
}

.casilla {
  display: grid;
  grid-template-columns: 1.15rem 1fr;
  gap: var(--s-3);
  align-items: start;
  font-size: var(--t-sm);
  color: var(--tinta-suave);
  line-height: 1.5;
  margin-top: var(--s-4);
}

.casilla input {
  width: 1.15rem;
  height: 1.15rem;
  margin: 0.15em 0 0;
  accent-color: var(--linea);
}

.casilla a { color: var(--linea); }

/* --- Closing surface ----------------------------------------------------- */

.cierre {
  position: relative;
  isolation: isolate;
  overflow: hidden;
}

/* Pattern from the brand's own texture library, not invented decoration. */
.cierre__textura {
  position: absolute;
  inset: 0;
  z-index: -2;
  /* WebP sin pérdida de 640 px: 493 KB a 101 KB, un 80 % menos.
     El PNG era de 1600 px para pintarse en mosaicos de 320, cinco veces más
     de lo necesario. A 640 px la textura queda a 1:1 en pantallas de doble
     densidad, que es el caso exigente.
     El reescalado va con envoltura, no directo: ver la nota en el README.
     El .png sigue en `assets/web/texturas/`. */
  background-image: url('../assets/web/texturas/textura-3-blanco.webp');
  background-size: 320px;
  background-repeat: repeat;
  opacity: 0.09;
}

/* One large soft form drifting behind the copy, slow enough to read as
   light rather than as an animation. */
.cierre__forma {
  position: absolute;
  z-index: -1;
  width: 44rem;
  height: 44rem;
  right: -13rem;
  top: -17rem;
  border-radius: 46% 54% 58% 42% / 52% 44% 56% 48%;
  background: rgba(255, 255, 255, 0.07);
  animation: flotar 26s var(--ease-in-out) infinite alternate;
}

@keyframes flotar {
  from { transform: translate3d(0, 0, 0) rotate(0deg); }
  to   { transform: translate3d(-3rem, 2.5rem, 0) rotate(20deg); }
}

/* --- Reduced motion: keep meaning, drop movement ------------------------- */

@media (prefers-reduced-motion: reduce) {
  .cascada__columna,
  .orbita__pista,
  .orbita__logo,
  .orbita__logo img,
  .orbita__radio,
  .cierre__forma,
  .charla__escribiendo span {
    animation: none !important;
  }

  /* Sin el despliegue, el brazo necesita su altura final de forma explícita. */
  .orbita__radio { height: 50%; }

  .cascada { height: auto; mask-image: none; -webkit-mask-image: none; }

  .js .charla[data-corriendo] .charla__turno { opacity: 1; transform: none; }

  .ebook__titulo { transition-duration: 200ms; filter: none; transform: none; }
}

/* --- Muro de prueba en movil: tres filas --------------------------------
   Los logos se miran de reojo, asi que pueden desplazarse solos en las filas
   de arriba y abajo. El testimonio es texto: se lee, y por eso la fila del
   medio la controla el visitante con el dedo (scroll-snap nativo, sin JS
   para el gesto) y no se mueve por su cuenta.
   ------------------------------------------------------------------------ */

.muro-movil { display: grid; gap: var(--s-5); }

/* Sin `min-width: 0` la columna del grid crece hasta el `max-content` de la
   pista de logos (mas de 2000 px) y arrastra la pagina a scroll horizontal.
   Es el mismo motivo por el que un hijo de flex/grid con contenido
   desbordante necesita permiso explicito para encogerse. */
.muro-movil > * { min-width: 0; }
.franja,
.carrusel,
.carrusel__pista { min-width: 0; }

@media (min-width: 62rem) { .muro-movil { display: none; } }

.franja {
  overflow: hidden;
  mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
  -webkit-mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
}

.franja__pista {
  display: flex;
  gap: var(--s-4);
  width: max-content;
  animation: deslizar var(--vel, 42s) linear infinite;
  will-change: transform;
}

.franja--inversa .franja__pista { animation-direction: reverse; --vel: 54s; }

@keyframes deslizar {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

.franja .tarjeta-logo {
  flex: 0 0 auto;
  width: 8.5rem;
  min-height: 4.75rem;
  padding: var(--s-4);
}

/* En la franja los logos son más pequeños. Se ajusta `height`, no
   `max-height`, porque la regla base fija el alto. */
.franja .tarjeta-logo img { height: 2rem; }

.carrusel { position: relative; }

.carrusel__pista {
  display: flex;
  gap: var(--s-4);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
  padding-bottom: var(--s-2);
}

.carrusel__pista::-webkit-scrollbar { display: none; }

.carrusel__pista > * {
  flex: 0 0 100%;
  scroll-snap-align: center;
}

.carrusel__puntos {
  display: flex;
  justify-content: center;
  gap: var(--s-2);
  margin-top: var(--s-4);
}

.carrusel__punto {
  width: 8px;
  height: 8px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--borde);
  cursor: pointer;
  transition: background-color var(--dur-rapida) var(--ease-out),
              transform var(--dur-rapida) var(--ease-out);
}

.carrusel__punto[aria-current='true'] {
  background: var(--linea);
  transform: scale(1.35);
}

@media (prefers-reduced-motion: reduce) {
  .franja__pista { animation: none !important; }
  .franja { overflow-x: auto; mask-image: none; -webkit-mask-image: none; }
  .carrusel__pista { scroll-behavior: auto; }
}

/* --- Pie: redes, legal y WhatsApp ---------------------------------------- */

@media (min-width: 46rem) {
  .pie__rejilla { grid-template-columns: 1.5fr 1fr 1.15fr 1fr; }
}

.pie__enlace-icono {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
}

.pie__enlace-icono svg { flex: none; }

.pie__redes {
  display: flex;
  gap: var(--s-3);
  margin-top: var(--s-5);
}

.pie__redes a {
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: rgba(255, 255, 255, 0.1);
  color: var(--blanco);
  transition: background-color var(--dur-rapida) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .pie__redes a:hover { background: rgba(255, 255, 255, 0.24); }
}

.pie__redes svg { width: 1.05rem; height: 1.05rem; }

/* Documento legal que aun no existe. Se muestra como texto plano, sin enlace
   y sin etiqueta: la ausencia de subrayado y el tono mas bajo ya comunican que
   todavia no lleva a ningun sitio, y evita el 404 el dia del lanzamiento. */
.pie__pendiente {
  color: rgba(255, 255, 255, 0.5);
}

/* --- Boton de documentacion API ----------------------------------------- */

.cifras__pie {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-4);
  align-items: center;
  padding-bottom: var(--s-7);
}

/* Panel con el texto arriba y el grafico debajo. */
.union__panel--invertido { align-content: start; }

/* Rotulo fijo que ancla el titulo cambiante del e-book. */
.ebook__rotulo {
  font-size: var(--t-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.7);
  margin-bottom: var(--s-2);
}

.ebook__rotador {
  font-family: var(--fuente-display);
  font-size: var(--t-md);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.25;
}

/* --- Comparativa de dos opciones ----------------------------------------
   Sustituye a la reja de tarjetas en la seccion de despliegue. Cuando solo
   hay dos opciones y son excluyentes, dos tarjetas identicas no ayudan a
   elegir: aqui una lleva el color de la linea y la otra el contorno, asi la
   diferencia se ve antes de leerla.
   ------------------------------------------------------------------------ */

.comparativa {
  display: grid;
  gap: var(--s-5);
}

@media (min-width: 46rem) {
  .comparativa { grid-template-columns: 1fr 1fr; }
}

.opcion {
  border-radius: var(--r-lg);
  padding: clamp(1.5rem, 1rem + 2vw, 2.25rem);
  display: grid;
  gap: var(--s-3);
  align-content: start;
}

.opcion--llena {
  background: var(--linea);
  color: var(--blanco);
}

.opcion--contorno {
  background: var(--blanco);
  border: 1px solid var(--borde);
}

.opcion__rotulo {
  font-family: var(--fuente-display);
  font-size: var(--t-sm);
  font-weight: 700;
  letter-spacing: 0.02em;
}

.opcion--llena .opcion__rotulo { color: var(--azul-claro); }
.opcion--contorno .opcion__rotulo { color: var(--linea); }

.opcion h3 { font-size: var(--t-lg); letter-spacing: -0.025em; }
.opcion--llena h3 { color: var(--blanco); }

.opcion p { font-size: var(--t-sm); }
.opcion--llena p { color: rgba(255, 255, 255, 0.88); }
.opcion--contorno p { color: var(--tinta-suave); }

.opcion__detalles { display: grid; gap: var(--s-2); padding-top: var(--s-2); }

.opcion__detalles li {
  display: grid;
  grid-template-columns: 0.8rem 1fr;
  gap: var(--s-3);
  font-size: var(--t-sm);
}

.opcion__detalles li::before {
  content: '';
  width: 7px;
  height: 7px;
  margin-top: 0.5em;
  border-radius: 2px;
}

.opcion--llena .opcion__detalles li { color: rgba(255, 255, 255, 0.9); }
.opcion--llena .opcion__detalles li::before { background: var(--azul-claro); }
.opcion--contorno .opcion__detalles li { color: var(--tinta); }
.opcion--contorno .opcion__detalles li::before { background: var(--linea); }

/* --- Cita destacada ------------------------------------------------------
   Un solo testimonio, el que habla exactamente de lo que trata la pagina.
   No es la cascada de la portada: aqui la voz de un cliente cierra un
   argumento concreto, y repetir el muro completo lo diluiria.
   ------------------------------------------------------------------------ */

.cita {
  display: grid;
  gap: var(--s-5);
  max-width: 58ch;
}

.cita blockquote {
  font-family: var(--fuente-display);
  font-size: var(--t-lg);
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.025em;
  color: var(--azul-oscuro);
  margin: 0;
}

.superficie-color .cita blockquote,
.superficie-profunda .cita blockquote { color: var(--blanco); }

.cita__firma { display: flex; align-items: center; gap: var(--s-4); }

.cita__foto {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  flex: none;
  object-fit: cover;
}

.cita__quien { display: grid; gap: 2px; }
.cita__nombre { font-weight: 700; font-size: var(--t-sm); color: var(--azul-oscuro); }
.cita__cargo { font-size: var(--t-xs); color: var(--tinta-suave); }

.superficie-color .cita__nombre,
.superficie-profunda .cita__nombre { color: var(--blanco); }
.superficie-color .cita__cargo,
.superficie-profunda .cita__cargo { color: rgba(255, 255, 255, 0.75); }

/* --- Atribucion bajo un titular -----------------------------------------
   Una cifra que viene de un cliente se sostiene con su nombre, no con una
   etiqueta de pendiente. */
.atribucion {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  font-size: var(--t-sm);
  color: rgba(255, 255, 255, 0.82);
}

.atribucion img {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  object-fit: cover;
  flex: none;
}

/* ==========================================================================
   v3 — Secciones de la página de Nómina
   Escaparate de módulos · maqueta de la aplicación · momentos · despliegue ·
   rejilla de clientes · características · preguntas frecuentes
   ========================================================================== */

/* --- Maqueta de la aplicación -------------------------------------------
   Una representación en DOM de las pantallas reales del liquidador, no una
   captura. Se dibuja con los rótulos verbatim de la aplicación, así que
   ninguna etiqueta es inventada, y al ser texto vectorial se lee nítida en
   cualquier pantalla y se adapta al ancho de su tarjeta.

   El diseño lo fija la pantalla ya terminada del liquidador: barra superior y lateral en el color de la línea,
   contenido sobre superficie clara.

   Todo el interior se mide en `em`, de modo que cambiar el `font-size` de
   `.maqueta` reescala la ventana entera sin tocar una sola regla más.
   ------------------------------------------------------------------------ */

.maqueta {
  font-size: clamp(0.4rem, 0.3rem + 0.42vw, 0.56rem);
  font-family: var(--fuente-texto);
  line-height: 1.35;
  width: var(--ancho-maqueta, 46em);
  border-radius: 1.1em;
  overflow: hidden;
  background: var(--blanco);
  border: 1px solid var(--borde);
  box-shadow: 0 1.6em 3.4em -1.4em rgba(0, 30, 97, 0.42);
  /* La ventana no se lee: la tarjeta que la contiene ya explica el módulo.
     Sin esto, un lector de pantalla recitaría veinte rótulos de formulario. */
  user-select: none;
}

.maqueta__barra {
  display: flex;
  align-items: center;
  gap: 1em;
  padding: 0.85em 1.1em;
  background: var(--linea);
  color: var(--blanco);
}

.maqueta__marca {
  font-family: var(--fuente-display);
  font-weight: 700;
  font-size: 1.15em;
  letter-spacing: -0.02em;
}

.maqueta__barra span:last-child {
  font-weight: 500;
  opacity: 0.82;
}

.maqueta__cuerpo {
  display: grid;
  grid-template-columns: 11em 1fr;
  min-height: 17em;
}

.maqueta__lateral {
  background: var(--linea);
  color: rgba(255, 255, 255, 0.78);
  padding: 0.7em 0.6em;
  display: grid;
  gap: 0.15em;
  align-content: start;
}

.maqueta__item {
  padding: 0.55em 0.7em;
  border-radius: 0.5em;
  font-size: 0.95em;
}

.maqueta__item[data-activo='true'] {
  background: rgba(255, 255, 255, 0.18);
  color: var(--blanco);
  font-weight: 700;
}

.maqueta__panel {
  background: var(--superficie);
  padding: 1.1em;
  display: grid;
  gap: 0.9em;
  align-content: start;
}

.maqueta__cabecera {
  background: var(--linea);
  color: var(--blanco);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 0.6em 0.9em;
  border-radius: 0.4em;
  font-size: 0.95em;
}

.maqueta__campos {
  display: grid;
  grid-template-columns: repeat(var(--columnas, 2), 1fr);
  gap: 0.75em;
}

.maqueta__campo { display: grid; gap: 0.3em; }
.maqueta__campo--ancho { grid-column: 1 / -1; }

.maqueta__campo i {
  font-style: normal;
  font-weight: 700;
  color: var(--tinta);
  font-size: 0.95em;
}

/* El control vacío: una caja con borde, como el input real sin diligenciar. */
.maqueta__campo b {
  display: block;
  font-weight: 400;
  color: var(--tinta-suave);
  background: var(--blanco);
  border: 1px solid var(--borde);
  border-radius: 0.35em;
  padding: 0.5em 0.6em;
  min-height: 2.1em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.maqueta__campo--alto b { min-height: 4.4em; }

/* Tira de opciones: es la barra azul de «Seleccione el tipo de novedad». */
.maqueta__tira {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9em;
  background: var(--linea);
  color: var(--blanco);
  padding: 0.55em 0.8em;
  border-radius: 0.4em;
  font-size: 0.9em;
}

.maqueta__tira span { display: flex; align-items: center; gap: 0.4em; }

.maqueta__tira span::before {
  content: '';
  width: 0.72em;
  height: 0.72em;
  border-radius: 50%;
  border: 1.5px solid rgba(255, 255, 255, 0.85);
  flex: none;
}

.maqueta__tira span[data-activo='true']::before {
  background: var(--blanco);
  box-shadow: inset 0 0 0 0.14em var(--linea);
}

/* Lista de procesos: el panel azul de la pantalla de liquidación. */
.maqueta__procesos {
  background: var(--linea);
  color: var(--blanco);
  border-radius: 0.4em;
  padding: 0.8em 0.9em;
  display: grid;
  gap: 0.55em;
  font-size: 0.92em;
}

.maqueta__procesos li { display: flex; align-items: center; gap: 0.5em; }

.maqueta__procesos li::before {
  content: '';
  width: 0.72em;
  height: 0.72em;
  border-radius: 50%;
  border: 1.5px solid rgba(255, 255, 255, 0.85);
  flex: none;
}

.maqueta__procesos li[data-activo='true'] { font-weight: 700; }

.maqueta__procesos li[data-activo='true']::before {
  background: var(--blanco);
  box-shadow: inset 0 0 0 0.14em var(--linea);
}

/* --- Piezas del panel del aspirante --------------------------------------
   Esa pantalla no es una reja de administración: es una tarjeta con saludo,
   porcentaje de avance y tres accesos. Se dibuja aparte porque su gramática
   es distinta a la del back-office.

   La aplicación real usa un naranja para el botón de código de proceso. Aquí
   NO se replica: son cuatro colores de marca y ese sería el quinto. La
   maqueta lee `--linea`, así que en esta página sale morada igual que el
   producto, sin escribir un solo color a mano. */

.maqueta__saludo {
  display: grid;
  gap: 0.4em;
  text-align: center;
  padding-bottom: 0.2em;
}

.maqueta__saludo strong {
  font-size: 1.2em;
  color: var(--linea);
  letter-spacing: 0.02em;
}

.maqueta__saludo span {
  color: var(--tinta-suave);
  line-height: 1.5;
}

.maqueta__progreso {
  position: relative;
  height: 1.5em;
  border-radius: 999px;
  background: var(--borde);
  display: grid;
  place-items: center;
  overflow: hidden;
}

.maqueta__progreso b {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: var(--pct, 100%);
  background: var(--linea);
  border-radius: 999px;
}

.maqueta__progreso span {
  position: relative;
  color: var(--blanco);
  font-weight: 700;
  font-size: 0.85em;
}

.maqueta__accesos {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.7em;
  padding-top: 0.5em;
}

.maqueta__acceso {
  display: grid;
  gap: 0.5em;
  justify-items: center;
  text-align: center;
  font-weight: 700;
  font-size: 0.88em;
  color: var(--tinta);
  line-height: 1.25;
}

.maqueta__acceso svg {
  width: 2.1em;
  height: 2.1em;
  color: var(--linea);
}

/* Lista de documentos con su estado, del contador «Actuales / Obligatorios». */
.maqueta__documentos {
  display: grid;
  gap: 0.4em;
  font-size: 0.92em;
}

.maqueta__documentos li {
  display: flex;
  align-items: center;
  gap: 0.6em;
  padding: 0.45em 0.6em;
  border: 1px solid var(--borde);
  border-radius: 0.35em;
  background: var(--blanco);
  color: var(--tinta);
}

.maqueta__documentos li span { margin-left: auto; font-weight: 700; flex: none; }
.maqueta__documentos li[data-listo='true'] span { color: var(--linea); }
.maqueta__documentos li[data-listo='false'] span { color: var(--tinta-suave); }

.maqueta__documentos li::before {
  content: '';
  width: 0.75em;
  height: 0.75em;
  border-radius: 50%;
  flex: none;
  border: 1.5px solid var(--borde);
}

.maqueta__documentos li[data-listo='true']::before {
  background: var(--linea);
  border-color: var(--linea);
}

/* Variante sin barra lateral, para las tarjetas de una sola columna: a ese
   ancho el menú se comería la pantalla y quedaría a la vista justo lo que no
   explica nada. */
.maqueta--panel { --ancho-maqueta: 26em; }
.maqueta--panel .maqueta__cuerpo { grid-template-columns: 1fr; min-height: 12em; }
.maqueta--panel .maqueta__lateral { display: none; }

/* --- Portal del colaborador ----------------------------------------------
   Va sobre superficie de color, en un panel más estrecho que el escaparate,
   así que necesita ser más ancha en `em` y más grande en tipo: dentro de la
   columna del panel doble una maqueta a la escala mínima se leería como una
   miniatura. */
.maqueta--colaborador {
  --ancho-maqueta: 36em;
  font-size: clamp(0.46rem, 0.3rem + 0.6vw, 0.8rem);
}

.maqueta__modulos {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.7em;
}

.maqueta__modulo {
  min-width: 0;
  background: var(--blanco);
  border: 1px solid var(--borde);
  border-radius: 0.45em;
  padding: 0.7em;
  display: grid;
  gap: 0.45em;
  align-content: start;
}

.maqueta__modulo b {
  color: var(--linea);
  font-size: 0.95em;
}

/* El `ul` es hijo de rejilla y arranca con `min-width: auto`, que es el
   max-content de la línea más larga: sin este permiso para encoger, «Certificado
   laboral con promedio» ensanchaba la tarjeta. Y se deja fluir el texto en vez
   de truncarlo con puntos suspensivos: en una maqueta decorativa media etiqueta
   no dice nada, y dos líneas sí. */
.maqueta__modulo > * { min-width: 0; }

.maqueta__modulo li {
  color: var(--tinta-suave);
  font-size: 0.88em;
  padding-block: 0.3em;
  border-top: 1px solid var(--borde);
  line-height: 1.3;
}

.maqueta__modulo li:first-of-type { border-top: 0; }

/* La insignia de contrato vigente, que en el portal real es lo primero que
   confirma la persona al entrar. */
.maqueta__vigencia {
  display: flex;
  align-items: center;
  gap: 0.6em;
  font-size: 0.92em;
  color: var(--tinta-suave);
}

.maqueta__vigencia em {
  margin-left: auto;
  font-style: normal;
  font-weight: 700;
  color: var(--blanco);
  background: var(--linea);
  border-radius: 999px;
  padding: 0.25em 0.8em;
}

.maqueta__acciones { display: flex; flex-wrap: wrap; gap: 0.5em; }

.maqueta__boton {
  border: 1px solid var(--linea);
  color: var(--linea);
  background: var(--blanco);
  border-radius: 0.35em;
  padding: 0.5em 0.9em;
  font-weight: 500;
  font-size: 0.95em;
}

.maqueta__boton--primario {
  background: var(--linea);
  color: var(--blanco);
  font-weight: 700;
}

/* Confirmación con la barra de progreso llena: el mensaje de «carga
   finalizada» de la pantalla de seguridad social. */
.maqueta__estado {
  display: flex;
  align-items: center;
  gap: 0.6em;
  font-weight: 700;
  color: var(--linea);
  font-size: 0.95em;
}

.maqueta__estado::before {
  content: '';
  width: 5.5em;
  height: 0.7em;
  border-radius: 0.2em;
  background: repeating-linear-gradient(90deg,
              var(--linea) 0 0.55em, transparent 0.55em 0.75em);
  flex: none;
}

.maqueta__tabla {
  display: grid;
  border: 1px solid var(--borde);
  border-radius: 0.4em;
  overflow: hidden;
  font-size: 0.9em;
}

.maqueta__fila {
  display: grid;
  grid-template-columns: repeat(var(--celdas, 4), 1fr);
  gap: 0.6em;
  padding: 0.55em 0.8em;
  background: var(--blanco);
  color: var(--tinta-suave);
  border-top: 1px solid var(--borde);
}

.maqueta__fila span {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.maqueta__fila--cabecera {
  background: var(--linea);
  color: var(--blanco);
  font-weight: 700;
  border-top: 0;
}

/* --- Escaparate de módulos -----------------------------------------------
   Reja tipo bento: dos piezas anchas y una alta llevan la maqueta, tres
   compactas se sostienen solo con el texto. No todas las piezas necesitan
   imagen — la referencia tampoco lo hace — y aquí eso además es honesto:
   Convenciones no tiene pantalla documentada, así que no se le inventa una.
   ------------------------------------------------------------------------ */

.escaparate {
  display: grid;
  gap: var(--s-4);
}

/* Sin esto la celda crece hasta el ancho fijo de la maqueta que lleva dentro
   y arrastra la página a scroll horizontal. Es el mismo permiso explícito
   para encoger que ya necesitó el muro de logos en móvil. */
.escaparate > * { min-width: 0; }

@media (min-width: 44rem) {
  .escaparate { grid-template-columns: repeat(2, 1fr); }
  .escaparate__pieza--ancha,
  .escaparate__pieza--completa { grid-column: 1 / -1; }
}

@media (min-width: 68rem) {
  .escaparate {
    grid-template-columns: repeat(3, 1fr);
    grid-auto-rows: minmax(0, auto);
  }

  .escaparate__pieza--ancha { grid-column: span 2; }

  /* Cierra la última fila a lo ancho. Con cinco piezas y una alta ocupando la
     tercera columna de las dos primeras filas, una pieza de dos columnas
     dejaría la tercera vacía en la fila final. */
  .escaparate__pieza--completa { grid-column: 1 / -1; }

  .escaparate__pieza--alta {
    grid-column: 3;
    grid-row: 1 / span 2;
  }
}

.escaparate__pieza {
  position: relative;
  overflow: hidden;
  display: grid;
  gap: var(--s-5);
  align-content: start;
  padding: var(--s-6);
  background: var(--blanco);
  border: 1px solid var(--borde);
  border-radius: var(--r-lg);
  transition: border-color var(--dur-media) var(--ease-out),
              box-shadow var(--dur-media) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .escaparate__pieza:hover {
    border-color: var(--azul-claro);
    box-shadow: 0 18px 40px -26px rgba(0, 30, 97, 0.45);
  }
}

.escaparate__texto { display: grid; gap: var(--s-3); }

.escaparate__rotulo {
  font-family: var(--fuente-display);
  font-size: var(--t-sm);
  font-weight: 700;
  color: var(--linea);
}

/* Acotado a `__texto` a propósito. Con `.escaparate__pieza p` la regla se colaba
   dentro de la maqueta —que también usa párrafos— y le pisaba color y tamaño:
   la cabecera azul quedaba con tinta gris encima, a 1,5:1, y con el cuerpo de
   la página en vez de la escala en `em` de la ventana. */
.escaparate__pieza h3 { font-size: var(--t-md); letter-spacing: -0.02em; }
.escaparate__texto p { font-size: var(--t-sm); color: var(--tinta-suave); }


/* La ventana se asoma por el borde inferior de la tarjeta en vez de caber
   entera: así se lee como una aplicación que sigue más allá del recorte, que
   es justo lo que hace la referencia. */
.escaparate__lienzo {
  position: relative;
  margin: 0 calc(var(--s-6) * -1) calc(var(--s-6) * -1);
  padding: var(--s-2) var(--s-6) 0;
  min-height: 9rem;
  overflow: hidden;
  display: flex;
  justify-content: center;
}

/* En las piezas grandes la ventana crece con la tarjeta: a la escala mínima
   se quedaba en 412 px dentro de un lienzo de 773 —o de 1.169 en la pieza
   completa— y dejaba medio bloque vacío. */
.escaparate__pieza--ancha .maqueta {
  font-size: clamp(0.44rem, 0.3rem + 0.56vw, 0.74rem);
}

.escaparate__pieza--completa .maqueta {
  font-size: clamp(0.5rem, 0.32rem + 0.78vw, 1rem);
}

/* La pieza alta es la única que sangra: la ventana se sale por el borde
   derecho, como en la referencia, para que se lea que la aplicación sigue
   más allá del recorte. */
.escaparate__pieza--alta .escaparate__lienzo {
  justify-content: flex-start;
  padding-right: 0;
}

.escaparate__lienzo .maqueta {
  flex: none;
  transition: transform var(--dur-lenta) var(--ease-out-quint);
}

@media (hover: hover) and (pointer: fine) {
  .escaparate__pieza:hover .escaparate__lienzo .maqueta {
    transform: translateY(-0.35rem);
  }
}

.escaparate__pieza--alta .escaparate__lienzo { min-height: 14rem; }

/* --- Momentos: el mismo argumento en tres escenas ------------------------
   Texto fijo a la izquierda, escena que cambia a la derecha. Las tres
   tarjetas comparten celda de rejilla y se relevan; las que esperan quedan
   detrás, escaladas y desplazadas, para que se vea que hay una pila.

   Sin JS el escenario no lleva `data-listo` y las tres tarjetas se apilan en
   flujo normal, visibles y legibles. Ninguna depende de que la animación
   corra: es la regla que costó el peor bug del proyecto.
   ------------------------------------------------------------------------ */

.momentos { display: grid; gap: var(--s-7); }

/* Un hijo de rejilla arranca con `min-width: auto`, que es el max-content de
   su contenido. Sin este permiso explícito para encoger, la pista larga de
   cada paso fija el ancho de la columna y arrastra la página a scroll
   horizontal en móvil. Ya pasó tres veces en este sitio por causas distintas;
   esta es la misma. */
.momentos > *,
.momentos__paso,
.momentos__paso > *,
.momentos__escenario > *,
.momento > *,
.momento__escena > * { min-width: 0; }

/* Sin `position: sticky` en la columna de texto, aunque la referencia lo use.
   Allí el lado derecho es una pila larga por la que el texto se queda quieto
   mientras pasa; aquí es una sola tarjeta que se releva, y la columna de
   texto acaba siendo la MÁS alta de las dos: medido, 550 px de texto en una
   fila de 550. El recorrido disponible es cero, así que la regla no se
   aplicaba nunca. Era CSS muerto disfrazado de decisión. */
@media (min-width: 62rem) {
  .momentos {
    grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
    gap: var(--s-9);
    align-items: center;
  }
}

.momentos__texto > * + * { margin-top: var(--s-5); }

.momentos__indice { display: grid; gap: 0; margin-top: var(--s-6); }

.momentos__paso {
  position: relative;
  display: grid;
  gap: var(--s-1);
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  border-top: 1px solid rgba(255, 255, 255, 0.22);
  padding: var(--s-4) 0;
  color: rgba(255, 255, 255, 0.62);
  cursor: pointer;
  transition: color var(--dur-rapida) var(--ease-out);
}

.momentos__paso:last-child {
  border-bottom: 1px solid rgba(255, 255, 255, 0.22);
}

.momentos__paso[aria-current='true'] { color: var(--blanco); }

@media (hover: hover) and (pointer: fine) {
  .momentos__paso:hover { color: var(--blanco); }
}

.momentos__rotulo {
  font-family: var(--fuente-display);
  font-weight: 700;
  font-size: var(--t-base);
  letter-spacing: -0.015em;
}

.momentos__pista { font-size: var(--t-sm); }

/* Regla de avance. Lineal: una curva de aceleración mentiría sobre cuánto
   tiempo queda. */
.momentos__barra {
  position: absolute;
  left: 0;
  bottom: -1px;
  height: 2px;
  width: 100%;
  transform: scaleX(0);
  transform-origin: left;
  background: var(--blanco);
  pointer-events: none;
}

.momentos__paso[aria-current='true'] .momentos__barra {
  animation: avanzar var(--momento-dur, 6500ms) linear forwards;
}

[data-momentos][data-pausado='true'] .momentos__barra {
  animation-play-state: paused;
}

/* --- Momentos sobre superficie clara -------------------------------------
   La línea de Gestión Humana no tiene un tono oscuro donde apoyar este
   bloque: `--linea-profunda` es el mismo morado que `--linea`, y el blanco al
   62 % encima da 3,1:1, por debajo del mínimo legible. Inventar un morado
   oscuro está prohibido, así que en esa línea el bloque vive sobre superficie
   clara y el índice se pinta con tinta. La profundidad la dan el espacio y la
   sombra de las tarjetas, no un tono nuevo. */

.superficie-clara .momentos__paso,
.superficie-tenue .momentos__paso {
  color: var(--tinta-suave);
  border-top-color: var(--borde);
}

.superficie-clara .momentos__paso:last-child,
.superficie-tenue .momentos__paso:last-child { border-bottom-color: var(--borde); }

.superficie-clara .momentos__paso[aria-current='true'],
.superficie-tenue .momentos__paso[aria-current='true'] { color: var(--linea); }

@media (hover: hover) and (pointer: fine) {
  .superficie-clara .momentos__paso:hover,
  .superficie-tenue .momentos__paso:hover { color: var(--tinta); }
}

.superficie-clara .momentos__barra,
.superficie-tenue .momentos__barra { background: var(--linea); }

/* Sobre claro la sombra sola no separa la tarjeta del fondo. */
.superficie-clara .momento,
.superficie-tenue .momento {
  border: 1px solid var(--borde);
  box-shadow: 0 20px 44px -30px rgba(0, 30, 97, 0.45);
}

.momentos__escenario { display: grid; gap: var(--s-4); }

.momentos__escenario[data-listo='true'] {
  gap: 0;
  min-height: 24rem;
  align-content: center;
}

.momento {
  background: var(--blanco);
  color: var(--tinta);
  border-radius: var(--r-lg);
  padding: var(--s-5);
  display: grid;
  gap: var(--s-4);
  align-content: start;
  box-shadow: 0 24px 50px -30px rgba(0, 0, 0, 0.55);
}

/* Con JS las tres ocupan la misma celda y solo cambia su profundidad. */
.momentos__escenario[data-listo='true'] .momento {
  grid-area: 1 / 1;
  opacity: 0;
  transform: translateY(1.5rem) scale(0.94);
  filter: blur(6px);
  pointer-events: none;
  transition: opacity var(--dur-lenta) var(--ease-out-quint),
              transform var(--dur-lenta) var(--ease-out-quint),
              filter var(--dur-lenta) var(--ease-out-quint);
}

.momentos__escenario[data-listo='true'] .momento[data-activo='true'] {
  opacity: 1;
  transform: translateY(0) scale(1);
  filter: blur(0);
  pointer-events: auto;
  z-index: 2;
}

/* La siguiente asoma por detrás: sin ese resto la tarjeta activa parecería
   sola y el relevo se leería como un corte. */
.momentos__escenario[data-listo='true'] .momento[data-siguiente='true'] {
  opacity: 0.28;
  transform: translateY(-1.4rem) scale(0.95);
  filter: blur(2px);
  z-index: 1;
}

.momento__rotulo {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  font-family: var(--fuente-texto);
  font-size: var(--t-xs);
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--linea);
}

.momento__rotulo::before {
  content: '';
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--linea);
}

.momento h3 {
  font-size: var(--t-md);
  letter-spacing: -0.02em;
  color: var(--azul-oscuro);
}

.momento p { font-size: var(--t-sm); color: var(--tinta-suave); }

/* Escena interior: filas que imitan un acuse, un log o un aviso. */
.momento__escena {
  display: grid;
  gap: var(--s-2);
  padding: var(--s-4);
  background: var(--superficie);
  border-radius: var(--r-md);
  font-size: var(--t-xs);
}

.momento__linea {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  background: var(--blanco);
  border: 1px solid var(--borde);
  border-radius: var(--r-sm);
  padding: var(--s-3);
  color: var(--tinta);
}

.momento__linea span:first-child {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.momento__sello {
  flex: none;
  font-weight: 700;
  color: var(--linea);
  letter-spacing: 0.04em;
}

/* Quién firmó la entrada del log. Avatar de iniciales, no fotografía: la
   escena es una ilustración y poner la cara de una persona real junto a un
   movimiento inventado le atribuiría algo que nunca hizo. */
.momento__firma {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  flex: none;
  font-weight: 700;
  color: var(--tinta);
}

.momento__avatar {
  width: 1.65rem;
  height: 1.65rem;
  border-radius: 50%;
  flex: none;
  display: grid;
  place-items: center;
  background: var(--azul-claro);
  color: var(--azul-oscuro);
  font-family: var(--fuente-display);
  font-weight: 700;
  font-size: 0.6rem;
  letter-spacing: 0;
}


/* --- Despliegue: Cloud y On-Premise --------------------------------------
   Dos celdas grandes con la ilustración arriba y el texto debajo. Sustituye
   a la comparativa de viñetas: cuando solo hay dos opciones excluyentes, la
   diferencia debe verse antes de leerse.
   ------------------------------------------------------------------------ */

.despliegue {
  display: grid;
  gap: 1px;
  background: var(--borde);
  border: 1px solid var(--borde);
  border-radius: var(--r-lg);
  overflow: hidden;
}

@media (min-width: 52rem) {
  .despliegue { grid-template-columns: 1fr 1fr; }
}

.despliegue__celda {
  background: var(--blanco);
  padding: var(--s-6);
  display: grid;
  gap: var(--s-4);
  align-content: start;
}

.despliegue__lienzo {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--superficie);
  display: grid;
  place-items: center;
}

.despliegue__lienzo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* --- Entrada de las dos celdas -------------------------------------------
   Marco de decisión:

   ¿Debe animarse? Es una sección que se ve una vez por visita, no un control
   que se pulsa cien veces al día. Sí.
   ¿Para qué? La ilustración ES el argumento. Revelarla lleva la mirada a la
   diferencia entre las dos modalidades antes de que empiece a leerse.
   ¿Qué curva? Entra, así que desaceleración. `ease-in` nunca: retrasa el
   primer instante, que es justo cuando el ojo está mirando.
   ¿Cuánto? 700 ms. El techo de 300 ms es para interfaz; esto es explicativo
   y puede respirar.

   No hay estado :hover. Las celdas no son enlaces ni botones, y un efecto de
   pasada sobre algo que no se puede pulsar promete una interacción que no
   existe.

   El estado por defecto es el FINAL: la animación solo corre cuando el script
   marca `data-desplegado`. Si el observador nunca dispara, las ilustraciones
   simplemente están ahí. */

.despliegue[data-desplegado='true'] .despliegue__lienzo {
  animation: revelar-lienzo 700ms var(--ease-out-quint) both;
  animation-delay: var(--retraso, 0ms);
}

/* El recorte sube desde abajo en vez de aparecer de golpe: la imagen se
   descubre, no se enciende. Nada en el mundo real surge de la nada. */
@keyframes revelar-lienzo {
  from {
    clip-path: inset(0 0 100% 0);
    opacity: 0;
    transform: translateY(0.75rem);
  }
  to {
    clip-path: inset(0 0 0 0);
    opacity: 1;
    transform: translateY(0);
  }
}

/* El texto entra detrás de su ilustración, escalonado 60 ms entre líneas. Más
   separación y la tarjeta se sentiría lenta. */
.despliegue[data-desplegado='true'] .despliegue__celda > :not(.despliegue__lienzo) {
  animation: subir-texto 460ms var(--ease-out-quint) both;
}

.despliegue[data-desplegado='true'] .despliegue__celda > :nth-child(2) { animation-delay: calc(var(--retraso, 0ms) + 160ms); }
.despliegue[data-desplegado='true'] .despliegue__celda > :nth-child(3) { animation-delay: calc(var(--retraso, 0ms) + 220ms); }
.despliegue[data-desplegado='true'] .despliegue__celda > :nth-child(4) { animation-delay: calc(var(--retraso, 0ms) + 280ms); }

@keyframes subir-texto {
  from { opacity: 0; transform: translateY(0.55rem); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Solo la nube flota, y no es capricho: es la única de las dos ilustraciones
   donde el movimiento significa algo. Una nube flota; un servidor en tu sala
   de máquinas, no. Nueve segundos y ocho píxeles, para que se lea como aire
   y no como una animación pidiendo atención. */
.despliegue__celda:first-child .despliegue__lienzo img {
  animation: flotar-nube 9s var(--ease-in-out) infinite alternate;
}

@keyframes flotar-nube {
  from { transform: translateY(0); }
  to   { transform: translateY(-0.5rem); }
}

@keyframes aparecer-sin-movimiento {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* El nombre de la modalidad es un encabezado, no una etiqueta suelta: cada
   celda es una opción con nombre propio. Va en cuerpo pequeño porque quien
   manda en la jerarquía visual de la celda es la cifra de empleados. */
.despliegue__rotulo {
  font-family: var(--fuente-display);
  font-size: var(--t-sm);
  font-weight: 700;
  letter-spacing: 0;
  color: var(--linea);
}

.despliegue__celda p { font-size: var(--t-sm); color: var(--tinta-suave); }

.despliegue__dato {
  display: inline-flex;
  align-items: baseline;
  gap: var(--s-2);
  font-family: var(--fuente-display);
  font-weight: 700;
  color: var(--azul-oscuro);
}

.despliegue__dato span {
  font-family: var(--fuente-texto);
  font-weight: 400;
  font-size: var(--t-sm);
  color: var(--tinta-suave);
}

/* --- Prueba: dos bloques arriba, testimonio a lo ancho abajo -------------
   Sustituye a la fila de tres cifras sueltas más la cita al costado. Dos
   afirmaciones con su propia evidencia visual pesan más que tres números
   alineados, y el testimonio cierra a lo ancho porque es la voz que sostiene
   todo lo anterior.
   ------------------------------------------------------------------------ */

.pruebas {
  display: grid;
  gap: 1px;
  background: var(--borde);
  border: 1px solid var(--borde);
  border-radius: var(--r-lg);
  overflow: hidden;
}

.pruebas > * { min-width: 0; }

@media (min-width: 52rem) {
  .pruebas { grid-template-columns: 1fr 1fr; }
  .pruebas__cita { grid-column: 1 / -1; }
}

.pruebas__celda {
  background: var(--blanco);
  padding: var(--s-6);
  display: grid;
  gap: var(--s-4);
  align-content: start;
}

/* Sin proporción fija en móvil. Con `aspect-ratio: 16/9` el lienzo medía unos
   161 px de alto y las dos barras con sus rótulos necesitan 168: el segundo
   rótulo —«Con Doisol · 1,5 minutos», que es justo la mejora que hay que
   leer— quedaba recortado por el `overflow: hidden`. La proporción vuelve
   cuando hay ancho de sobra. */
.pruebas__lienzo {
  position: relative;
  min-height: 11rem;
  border-radius: var(--r-md);
  background: var(--superficie);
  display: grid;
  place-items: center;
  padding: var(--s-5);
  overflow: hidden;
}

@media (min-width: 46rem) {
  .pruebas__lienzo {
    aspect-ratio: 16 / 9;
    padding: var(--s-6);
  }
}

.pruebas__celda h3 { font-size: var(--t-md); letter-spacing: -0.02em; }
.pruebas__celda > p { font-size: var(--t-sm); color: var(--tinta-suave); }

/* Trama de puntos: representa una cantidad, no una tendencia. Una curva
   ascendente afirmaría un crecimiento que no tenemos medido. */
.malla-puntos {
  position: absolute;
  inset: 0;
  background-image: radial-gradient(circle, var(--azul-claro) 1.6px, transparent 1.7px);
  background-size: 15px 15px;
  mask-image: radial-gradient(ellipse at center, #000 30%, transparent 70%);
  -webkit-mask-image: radial-gradient(ellipse at center, #000 30%, transparent 70%);
}

.pruebas__cifra {
  position: relative;
  font-family: var(--fuente-display);
  font-weight: 700;
  font-size: var(--t-xl);
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--linea);
}

/* Comparación de tiempos. Las dos barras son proporcionales de verdad:
   1,5 sobre 25 es el 6 %, y así se dibuja. */
.barras {
  position: relative;
  width: 100%;
  display: grid;
  gap: var(--s-5);
}

.barra { display: grid; gap: var(--s-2); }

.barra__pista {
  height: 0.85rem;
  border-radius: var(--r-pill);
  background: var(--blanco);
  border: 1px solid var(--borde);
  overflow: hidden;
}

.barra__relleno {
  display: block;
  height: 100%;
  width: var(--pct);
  border-radius: var(--r-pill);
  background: var(--azul-claro);
}

.barra--ahora .barra__relleno { background: var(--linea); }

.barra__rotulo {
  font-size: var(--t-xs);
  color: var(--tinta-suave);
}

.barra--ahora .barra__rotulo { color: var(--linea); font-weight: 700; }

.pruebas__cita {
  background: var(--blanco);
  padding: clamp(2rem, 1.4rem + 3vw, 4rem);
  display: grid;
  gap: var(--s-6);
  justify-items: center;
  text-align: center;
  margin: 0;
}

.pruebas__cita blockquote {
  font-family: var(--fuente-display);
  font-size: var(--t-lg);
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.025em;
  color: var(--azul-oscuro);
  max-width: 30ch;
  margin: 0;
}

/* --- Rejilla de clientes -------------------------------------------------
   Celda de texto a la izquierda y ocho logos en dos filas, separados por
   líneas de un píxel. Sustituye al muro suelto: la reja da estructura y deja
   claro cuáles son las cuentas principales.
   ------------------------------------------------------------------------ */

.rejilla-clientes {
  display: grid;
  gap: 1px;
  background: var(--borde);
  border: 1px solid var(--borde);
  border-radius: var(--r-lg);
  overflow: hidden;
  grid-template-columns: repeat(2, 1fr);
}

@media (min-width: 46rem) { .rejilla-clientes { grid-template-columns: repeat(4, 1fr); } }

@media (min-width: 62rem) {
  .rejilla-clientes { grid-template-columns: 1.25fr repeat(4, 1fr); }
  .rejilla-clientes__intro { grid-row: 1 / span 2; }
}

.rejilla-clientes__intro,
.rejilla-clientes__celda {
  background: var(--blanco);
  display: grid;
  place-items: center;
  padding: var(--s-5);
  min-height: 7rem;
}

.rejilla-clientes__intro {
  grid-column: 1 / -1;
  place-items: start center;
  align-content: center;
  gap: var(--s-2);
  text-align: left;
  justify-items: start;
}

@media (min-width: 62rem) {
  .rejilla-clientes__intro { grid-column: 1; }
}

.rejilla-clientes__intro h3 {
  font-size: var(--t-md);
  line-height: 1.25;
  font-weight: 400;
  font-family: var(--fuente-texto);
  letter-spacing: 0;
  color: var(--tinta-suave);
  max-width: 20ch;
}

.rejilla-clientes__intro strong {
  font-family: var(--fuente-display);
  font-weight: 700;
  color: var(--linea);
}

/* Alto fijo y ancho en `auto`, por el mismo razonamiento de tres pasos que
   está anotado sobre `.tarjeta-logo img`. Medido aquí: GIGHA saltaba de
   102 px a 177 px con los atributos puestos y sin ningún eje en el CSS. */
.rejilla-clientes__celda img {
  height: 2.75rem;
  width: auto;
  max-width: 100%;
  object-fit: contain;
  filter: grayscale(1);
  opacity: 0.68;
  mix-blend-mode: multiply;
  transition: filter var(--dur-media) var(--ease-out),
              opacity var(--dur-media) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .rejilla-clientes__celda:hover img { filter: grayscale(0); opacity: 1; }
}

/* --- Características destacadas ------------------------------------------ */

.caracteristicas {
  display: grid;
  gap: var(--s-5);
}

@media (min-width: 52rem) {
  .caracteristicas { grid-template-columns: repeat(3, 1fr); }
}

.caracteristica {
  display: grid;
  gap: var(--s-4);
  align-content: start;
  padding: var(--s-6);
  background: var(--blanco);
  border: 1px solid var(--borde);
  border-radius: var(--r-lg);
}

.caracteristica__icono {
  width: 2.75rem;
  height: 2.75rem;
  border-radius: var(--r-md);
  display: grid;
  place-items: center;
  background: var(--linea);
  color: var(--blanco);
}

.caracteristica__icono svg { width: 1.35rem; height: 1.35rem; }

.caracteristica h3 { font-size: var(--t-md); letter-spacing: -0.02em; }
.caracteristica p { font-size: var(--t-sm); color: var(--tinta-suave); }

/* --- Preguntas frecuentes ------------------------------------------------
   `<details>` nativo: se abre y se cierra sin una línea de JavaScript, llega
   con semántica de divulgación para lectores de pantalla y es buscable con
   Ctrl+F en los navegadores que lo soportan.
   ------------------------------------------------------------------------ */

.faq { display: grid; gap: var(--s-7); }

@media (min-width: 62rem) {
  .faq {
    grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
    gap: var(--s-9);
    align-items: start;
  }

  .faq__intro { position: sticky; top: 7rem; }
}

.faq__intro > * + * { margin-top: var(--s-4); }
.faq__intro p { font-size: var(--t-sm); color: var(--tinta-suave); max-width: 34ch; }

.faq__lista { display: grid; }

.faq__item { border-top: 1px solid var(--borde); }
.faq__item:last-child { border-bottom: 1px solid var(--borde); }

.faq__item summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-5);
  padding: var(--s-5) 0;
  cursor: pointer;
  list-style: none;
  font-family: var(--fuente-display);
  font-weight: 700;
  font-size: var(--t-base);
  letter-spacing: -0.015em;
  color: var(--azul-oscuro);
  transition: color var(--dur-rapida) var(--ease-out);
}

.faq__item summary::-webkit-details-marker { display: none; }

@media (hover: hover) and (pointer: fine) {
  .faq__item summary:hover { color: var(--linea); }
}

.faq__item[open] summary { color: var(--linea); }

/* El signo gira en vez de cambiar: el mismo objeto pasa de «más» a «menos». */
.faq__signo {
  flex: none;
  width: 1.5rem;
  height: 1.5rem;
  position: relative;
  border-radius: 50%;
  border: 1.5px solid var(--borde);
  transition: border-color var(--dur-media) var(--ease-out),
              transform var(--dur-media) var(--ease-out);
}

.faq__signo::before,
.faq__signo::after {
  content: '';
  position: absolute;
  inset: 50% 28%;
  border-top: 1.5px solid currentColor;
  transition: opacity var(--dur-media) var(--ease-out);
}

.faq__signo::after { transform: rotate(90deg); }

.faq__item[open] .faq__signo {
  border-color: var(--linea);
  transform: rotate(180deg);
}

.faq__item[open] .faq__signo::after { opacity: 0; }

.faq__respuesta {
  padding-bottom: var(--s-5);
  font-size: var(--t-sm);
  color: var(--tinta-suave);
  max-width: 62ch;
}

.faq__respuesta > * + * { margin-top: var(--s-3); }

/* Solo la entrada se anima: al cerrar, `details` retira el contenido del
   flujo de inmediato y una salida animada nunca llegaría a verse. */
@supports (interpolate-size: allow-keywords) {
  .faq__item[open] .faq__respuesta {
    animation: faq-abrir var(--dur-media) var(--ease-out) both;
  }
}

@keyframes faq-abrir {
  from { opacity: 0; transform: translateY(-0.35rem); }
  to   { opacity: 1; transform: translateY(0); }
}

/* --- Movimiento reducido ------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .momentos__paso[aria-current='true'] .momentos__barra { animation: none !important; }
  .momentos__barra { transform: scaleX(1); opacity: 0.35; }

  .momentos__escenario[data-listo='true'] .momento { filter: none; transform: none; }
  .momentos__escenario[data-listo='true'] .momento[data-siguiente='true'] { transform: none; }

  /* La revelación conserva el desvanecido, que ayuda a entender que algo
     llegó, y pierde el desplazamiento y el recorte, que es lo que marea. */
  .despliegue[data-desplegado='true'] .despliegue__lienzo,
  .despliegue[data-desplegado='true'] .despliegue__celda > :not(.despliegue__lienzo) {
    animation-name: aparecer-sin-movimiento;
    animation-duration: 200ms;
  }

  .despliegue__celda:first-child .despliegue__lienzo img { animation: none; }

  .escaparate__lienzo .maqueta { transition: none; }

  .faq__item[open] .faq__respuesta { animation: none; }
}

/* --- Página 404 -----------------------------------------------------------
   Banda profunda de arriba abajo. La barra de navegación es transparente
   mientras la página está en el tope, así que su texto blanco necesita una
   superficie oscura debajo o desaparece. */

.error {
  background: var(--linea-profunda);
  color: var(--blanco);
  padding-block: calc(var(--s-10) + 4rem) var(--s-10);
}

.error__interior { max-width: 46rem; }

.error__codigo {
  font-family: var(--fuente-display);
  font-size: var(--t-sm);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--azul-claro);
  margin-bottom: var(--s-4);
}

.error__titulo {
  font-size: var(--t-xl);
  margin-bottom: var(--s-5);
}

.error__texto {
  font-size: var(--t-md);
  color: rgba(255, 255, 255, 0.82);
  max-width: 36rem;
  margin-bottom: var(--s-6);
}

.error__acciones {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-4);
  margin-bottom: var(--s-9);
}

.error__rutas h2 {
  font-size: var(--t-sm);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--azul-claro);
  margin-bottom: var(--s-5);
}

.error__rutas ul {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid rgba(255, 255, 255, 0.22);
}

.error__rutas li {
  display: grid;
  gap: var(--s-1);
  padding-block: var(--s-4);
  border-bottom: 1px solid rgba(255, 255, 255, 0.22);
}

.error__rutas a {
  font-family: var(--fuente-display);
  font-weight: 700;
  font-size: var(--t-base);
  color: var(--blanco);
  text-decoration: none;
}

.error__rutas span {
  font-size: var(--t-sm);
  color: rgba(255, 255, 255, 0.72);
}

@media (min-width: 44rem) {
  .error__rutas li {
    grid-template-columns: 18rem 1fr;
    gap: var(--s-5);
    align-items: baseline;
  }
}

@media (hover: hover) and (pointer: fine) {
  .error__rutas a:hover { color: var(--azul-claro); }
}
