/* ==========================================================================
   Fluidez
   Las secciones que quedaban planas: el bloque de alta, el pie y las
   transiciones que aun se sentian como cortes. Movimiento continuo, no
   entradas sueltas.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. El bloque de alta: luz que orbita
   Antes era un degradado fijo con un giro lento. Ahora una mancha de luz
   recorre el bloque, como si algo se moviera detras del cristal.
   -------------------------------------------------------------------------- */

.alta__reja::after {
  content: '';
  position: absolute;
  width: 60%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(1, 236, 167, .3), transparent 62%);
  filter: blur(50px);
  pointer-events: none;
  animation: orbitar 22s ease-in-out infinite alternate;
}

@keyframes orbitar {
  from { transform: translate(-25%, -35%); }
  50%  { transform: translate(55%, 10%); }
  to   { transform: translate(15%, 45%); }
}

/* --------------------------------------------------------------------------
   2. El formulario responde al escribir
   El campo activo se levanta un punto: confirma donde estas sin necesidad de
   un borde de color chillon.
   -------------------------------------------------------------------------- */

.campo { transition: transform .35s cubic-bezier(.2, .8, .2, 1); }
.campo:focus-within { transform: translateY(-2px); }

.campo input {
  transition:
    box-shadow .3s cubic-bezier(.2, .8, .2, 1),
    border-color .3s,
    background-color .3s;
}

/* El boton del formulario con brillo que cruza al pasar: invita a pulsarlo */
.formulario__enviar {
  position: relative;
  overflow: hidden;
}
.formulario__enviar::after {
  content: '';
  position: absolute;
  inset: 0 auto 0 -60%;
  width: 45%;
  background: linear-gradient(100deg, transparent, rgba(66, 60, 212, .18), transparent);
  transform: skewX(-18deg);
  transition: left .7s cubic-bezier(.2, .8, .2, 1);
}
.formulario__enviar:hover::after { left: 115%; }

/* --------------------------------------------------------------------------
   3. El pie deja de ser un bloque muerto
   -------------------------------------------------------------------------- */

.pie {
  position: relative;
  background: linear-gradient(180deg, var(--papel-alto) 0%, #f4f3fb 100%);
  overflow: clip;
}

.pie::before {
  content: '';
  position: absolute;
  inset: auto -20% -60% -20%;
  height: 160%;
  background: radial-gradient(40% 50% at 50% 100%, rgba(66, 60, 212, .09), transparent 70%);
  pointer-events: none;
}
.pie > * { position: relative; z-index: 1; }

/* Los enlaces del pie se desplazan al pasar: detalle pequeño, sensacion viva */
.pie__grupo a, .pie__cookies {
  display: inline-block;
  text-align: left;
  transition: transform .3s cubic-bezier(.2, .8, .2, 1), color .2s;
}
.pie__grupo a:hover, .pie__cookies:hover { transform: translateX(4px); }

/* --------------------------------------------------------------------------
   4. Los botones principales laten muy despacio
   Solo el de la portada y el del alta: son los dos puntos donde se decide la
   conversion. Un latido de dos segundos es perceptible sin distraer.
   -------------------------------------------------------------------------- */

.portada .boton--principal,
.alta .boton--principal {
  animation: latido-cta 3.2s ease-in-out infinite;
}

@keyframes latido-cta {
  0%, 100% { box-shadow: 0 1px 2px rgba(37,31,107,.2), 0 4px 10px -2px rgba(66,60,212,.45), 0 0 0 0 rgba(66,60,212,.32); }
  50%      { box-shadow: 0 1px 2px rgba(37,31,107,.2), 0 4px 10px -2px rgba(66,60,212,.45), 0 0 0 12px rgba(66,60,212,0); }
}

/* Al pasar el raton el latido para: ya tiene tu atencion */
.boton--principal:hover { animation-play-state: paused; }

/* --------------------------------------------------------------------------
   5. Scroll suave de verdad
   `scroll-behavior: smooth` salta a trompicones en trayectos largos; esto lo
   suaviza en los navegadores que lo soportan.
   -------------------------------------------------------------------------- */

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

/* --------------------------------------------------------------------------
   6. La cabecera se encoge al bajar
   -------------------------------------------------------------------------- */

.cabecera__marca img {
  transition: width .35s cubic-bezier(.2, .8, .2, 1), filter .35s;
}
.cabecera.posada .cabecera__marca img { width: 116px; }

@media (prefers-reduced-motion: reduce) {
  .alta__reja::after,
  .portada .boton--principal,
  .alta .boton--principal { animation: none; }
}

/* --------------------------------------------------------------------------
   7. Precios: los ticks se encienden en cascada
   La lista de lo que incluye es el argumento de la seccion, pero aparecia
   entera de golpe. Encendiendola de arriba abajo el ojo la recorre en vez de
   saltarsela.
   -------------------------------------------------------------------------- */

@supports (animation-timeline: view()) {
  .precios__lista li {
    animation: encender-tick linear both;
    animation-timeline: view();
    animation-range: entry 5% cover 25%;
  }
  @keyframes encender-tick {
    from { opacity: 0; transform: translateX(-10px); }
    to   { opacity: 1; transform: none; }
  }

  /* El retraso escalonado se simula desplazando el rango de cada fila: con
     timelines de scroll no hay `animation-delay` util, se mueve el rango.
     Los desplazamientos son pequeños (3 puntos) y todo termina dentro de
     `cover 40%`: medido en el navegador, con saltos mas amplios las dos
     ultimas filas se quedaban a opacidad .36 permanentemente una vez pasada
     la seccion. Son argumentos de venta, no pueden leerse a medio encender. */
  .precios__lista li:nth-child(2) { animation-range: entry 11% cover 31%; }
  .precios__lista li:nth-child(3) { animation-range: entry 14% cover 34%; }
  .precios__lista li:nth-child(4) { animation-range: entry 17% cover 37%; }
  .precios__lista li:nth-child(5) { animation-range: entry 20% cover 40%; }
  .precios__lista li:nth-child(6) { animation-range: entry 23% cover 43%; }
  .precios__lista li:nth-child(7) { animation-range: entry 26% cover 46%; }
  .precios__lista li:nth-child(8) { animation-range: entry 29% cover 49%; }
}

/* El tick crece un punto al pasar por encima de su fila */
.precios__lista li { transition: color .25s; }
.precios__tick { transition: transform .3s cubic-bezier(.2, .8, .2, 1), background-color .3s; }
.precios__lista li:hover { color: var(--tinta); }
.precios__lista li:hover .precios__tick {
  transform: scale(1.15);
  background: rgba(1, 236, 167, .35);
}

/* --------------------------------------------------------------------------
   8. El pie, con la reja real del HTML
   -------------------------------------------------------------------------- */

.pie__reja { position: relative; z-index: 1; }

@media (prefers-reduced-motion: reduce) {
  .precios__lista li {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
}

/* --------------------------------------------------------------------------
   9. El bloque de alta NO se anima con el scroll
   Dos motivos, comprobados midiendo el elemento en el navegador y no a ojo:

   a) Su seccion `.alta` tiene `overflow: clip`. Un ancestro con overflow
      distinto de `visible` pasa a ser el scrollport del `view()` timeline,
      y como esa seccion no scrollea, el timeline se quedaba clavado en el
      primer fotograma: opacidad .4 y el bloque inclinado 11 grados.

   b) Aun moviendo el timeline a un ancestro que si scrollea, el bloque es lo
      ultimo de la pagina: el documento se acaba antes de que termine de
      cruzar la pantalla. Medido en el fondo real del scroll, se quedaba en
      opacidad .77 de forma permanente.

   Se probaron cuatro rangos distintos antes de entender (b). La conclusion es
   que ningun rango arregla esto: el recorrido que la animacion necesita no
   existe. Un bloque de conversion a medio aparecer es peor fallo que uno sin
   animacion, asi que aqui la entrada va por `@starting-style`, que no depende
   del scroll y siempre termina.
   -------------------------------------------------------------------------- */

.alta__reja {
  animation: girar-luz 18s ease-in-out infinite alternate !important;
  animation-timeline: auto !important;
  animation-range: auto !important;
  opacity: 1 !important;
  transform: none !important;
  transition: opacity .8s var(--entra), translate .8s var(--entra);
}

@supports (animation-timeline: view()) {
  /* La entrada, una sola vez, al mostrarse por primera vez */
  @starting-style {
    .alta__reja { opacity: .5; translate: 0 40px; }
  }
}

@media (prefers-reduced-motion: reduce) {
  .alta__reja { transition: none; }
}

/* --------------------------------------------------------------------------
   10. El cierre de la pagina, sin hueco muerto
   El bloque violeta ya trae su propio relleno interior, asi que el padding de
   seccion se sumaba por debajo y dejaba una franja vacia de casi 150px entre
   la llamada a la accion y el pie. Justo en el punto donde el visitante
   decide, la pagina parecia haberse acabado antes de tiempo.
   -------------------------------------------------------------------------- */

.alta { padding-bottom: clamp(2.5rem, 2rem + 2vw, 4rem); }

/* El pie recoge el violeta del bloque de arriba en vez de arrancar en gris:
   asi el final de la pagina se lee como un degradado y no como dos piezas
   pegadas. */
.pie {
  background: linear-gradient(180deg, #f1f0fa 0%, #e9e7f6 100%);
  border-top: 1px solid #e0def0;
}

/* --------------------------------------------------------------------------
   11. Red de seguridad para la cascada de precios
   Los rangos de la seccion 7 dan el escalonado, pero ningun rango garantiza
   por si solo que la animacion termine: depende del alto de cada fila y de la
   ventana. Con `animation-fill-mode: both` una fila que no complete su rango
   se queda tenue para siempre, y aqui eso significa argumentos de venta a
   medio leer.

   La animacion solo esconde la fila mientras la caja esta entrando. En cuanto
   la caja ha llegado a su sitio, esta regla la fuerza a visible y gana por ir
   despues. El adorno no puede costar legibilidad.
   -------------------------------------------------------------------------- */

@supports (animation-timeline: view()) {
  .precios__caja { view-timeline-name: --caja-precios; }

  .precios__lista li {
    animation-name: encender-tick, asegurar-tick;
    animation-timeline: view(), --caja-precios;
  }

  /* Devuelve la fila a opacidad plena en cuanto la caja pasa de la mitad de
     la pantalla, pase lo que pase con el timeline individual de la fila. */
  @keyframes asegurar-tick {
    to { opacity: 1; transform: none; }
  }
  .precios__lista li {
    animation-range: entry 5% cover 25%, cover 35% cover 55%;
  }
  .precios__lista li:nth-child(2) { animation-range: entry 11% cover 31%, cover 35% cover 55%; }
  .precios__lista li:nth-child(3) { animation-range: entry 14% cover 34%, cover 35% cover 55%; }
  .precios__lista li:nth-child(4) { animation-range: entry 17% cover 37%, cover 35% cover 55%; }
  .precios__lista li:nth-child(5) { animation-range: entry 20% cover 40%, cover 35% cover 55%; }
  .precios__lista li:nth-child(6) { animation-range: entry 23% cover 43%, cover 35% cover 55%; }
  .precios__lista li:nth-child(7) { animation-range: entry 26% cover 46%, cover 35% cover 55%; }
  .precios__lista li:nth-child(8) { animation-range: entry 29% cover 49%, cover 35% cover 55%; }
}

/* --------------------------------------------------------------------------
   12. La portada vuelve a caber en una pantalla
   El titular de SEO («Software de envíos para tu tienda online») es mas largo
   que el anterior y a 6.4rem se partia en cinco lineas: 522px solo de
   titular. Sumado a los 144px de padding superior y a los 128px que añadio la
   mascara de cierre, los botones acababan 40px por debajo del borde inferior
   (medido en ventana de 900px).

   Un hero cuya llamada a la accion no se ve sin scrollear pierde su razon de
   ser, asi que el ajuste va sobre el espacio, no sobre el diseño.
   -------------------------------------------------------------------------- */

.portada {
  /* Solo lo justo para despejar la cabecera fija (~72px). Con la portada
     clara la cabecera ya no se funde con el fondo, asi que no hace falta
     regalarle aire de mas: el titular empieza antes y la garantia de abajo
     deja de quedarse fuera de pantalla. */
  padding-top: clamp(4.5rem, 4rem + 1.5vw, 5.5rem);
  /* Al quitar la tira de cifras quedaba un hueco de ~160px entre la ultima
     linea del hero y la curva de cierre. La mascara solo necesita 70px para
     dibujar la curva. */
  padding-bottom: clamp(2.5rem, 2rem + 1.5vw, 4rem);
}

.portada__titular {
  /* Baja el techo de 6.4rem a 5.2rem: el titular sigue dominando la pantalla
     pero cabe en cuatro lineas en vez de cinco. */
  font-size: clamp(2.7rem, 1.1rem + 6vw, 5.2rem);
  margin-bottom: 1.25rem;
}

/* En pantallas bajas (portatiles de 768px o menos de alto) se aprieta un poco
   mas: es donde el recorte se notaba mas. */
@media (max-height: 800px) {
  .portada__titular { font-size: clamp(2.4rem, 1rem + 5vw, 4.2rem); }
  .portada {
    padding-top: clamp(4.5rem, 4rem + 2vw, 5.5rem);
    padding-bottom: 3rem;
  }
}

/* --------------------------------------------------------------------------
   13. El numero del recorrido, por encima de la linea
   La animacion `marcar-hito` de paso-vivo.css ya hace lo bueno: el numero
   crece y se vuelve violeta segun pasas, y vuelve a encogerse al dejarlo
   atras. Lo unico que le faltaba es que la linea del eje no le pase por
   delante.

   El eje se pinta en `.proceso__lista::before/::after`. Basta con que el
   numero cree su propio contexto de apilamiento por encima: como el
   `animation-timeline` ya le aplica un `transform`, el elemento se promociona
   solo, y un z-index sobre el hito lo coloca delante del eje sin cambiar ni
   la linea ni la animacion.
   -------------------------------------------------------------------------- */

.proceso__lista { isolation: isolate; }
.proceso__lista::before,
.proceso__lista::after { z-index: 0; }
.proceso__item { z-index: 1; }
.proceso__numero { z-index: 2; }

/* --------------------------------------------------------------------------
   14. Capturas reales del panel
   Sustituyen a las maquetas dibujadas en HTML. Una captura de verdad da una
   credibilidad que ninguna maqueta consigue: se ve el producto tal cual es,
   con su densidad de datos y su interfaz.

   Se mantiene el mismo tratamiento visual que tenian las maquetas (sombra,
   borde y el enderezado al entrar) para que no desentonen con el resto.
   -------------------------------------------------------------------------- */

.captura {
  margin: 0;
  border-radius: clamp(12px, 1.4vw, 18px);
  overflow: hidden;
  border: 1px solid var(--linea);
  background: var(--papel-alto);
  max-width: 100%;
  box-shadow: var(--sombra-alta);
}

/* La captura mide 1414px de ancho: metida en media columna se veia a 530px y
   el texto de la tabla era ilegible. En pantalla ancha la muestra pasa a dos
   filas (texto arriba, captura debajo a todo lo ancho) para que se lea. */
@media (min-width: 950px) {
  .muestra:has(.captura) {
    grid-template-columns: 1fr;
    gap: clamp(1.6rem, 1rem + 2vw, 2.6rem);
  }
  /* El texto se limita para no quedar en lineas larguisimas */
  .muestra:has(.captura) > div:first-child { max-width: 62ch; }
  /* Y en la volteada el texto sigue yendo primero, no debajo de la imagen */
  .muestra--volteada:has(.captura) > *:first-child { order: 0; }
}

.captura img {
  display: block;
  width: 100%;
  height: auto;
  /* El navegador puede suavizar de mas al reducir una imagen grande; esto
     mantiene legible el texto de la interfaz. */
  image-rendering: -webkit-optimize-contrast;
}

/* En la muestra volteada la captura entra desde el otro lado */
.muestra--volteada .captura { transform-origin: right center; }

/* --------------------------------------------------------------------------
   El aviso de privacidad bajo el formulario

   Va dentro del formulario y no en el pie porque el RGPD obliga a informar
   en el punto donde se recogen los datos. Discreto pero legible: si no se
   puede leer, no informa de nada.
   -------------------------------------------------------------------------- */

.formulario__legal {
  margin: .2rem 0 0;
  font-size: .78rem;
  line-height: 1.45;
  color: rgba(255, 255, 255, .62);
  text-align: center;
}
.formulario__legal a {
  color: rgba(255, 255, 255, .85);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.formulario__legal a:hover { color: #fff; }

/* Casilla opcional de comunicaciones comerciales. Sin premarcar. Legible
   (no es letra pequeña escondida) y con objetivo tactil comodo. */
.casilla {
  display: flex;
  align-items: flex-start;
  gap: .65rem;
  font-size: .84rem;
  line-height: 1.45;
  color: rgba(255, 255, 255, .88);
  cursor: pointer;
}
.casilla input {
  flex: none;
  width: 1.15rem;
  height: 1.15rem;
  margin: .1rem 0 0;
  accent-color: #01eca7;
  cursor: pointer;
}
.casilla input:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.casilla a { color: #fff; text-decoration: underline; text-underline-offset: 2px; }
