/* =========================================================================
   QuipusCode — capa de movimiento e interacción del sitio público
   Se carga después de quipus.css y sólo añade: ninguna regla de aquí es
   necesaria para leer la página.

   Contrato de movimiento: efectos.js pone la clase .motion en <html> y sólo
   la pone si el sistema NO pide movimiento reducido. Todo lo que oculta algo
   para revelarlo después cuelga de .motion, así que sin JS —o con movimiento
   reducido— la página se ve completa y quieta. Nunca al revés.
   ========================================================================= */

/* Curva de salida exponencial: arranca rápido y se posa. Sin rebote. */
:root {
    --salida:      cubic-bezier(.16, 1, .3, 1);
    --salida-corta: cubic-bezier(.22, 1, .36, 1);
}

/* ------------------------------------------------- Barra de progreso ----- */
/* Se escala en X, no se le cambia el ancho: el desplazamiento no debe
   obligar al navegador a rehacer la maqueta en cada píxel. */
.progreso {
    position: absolute; left: 0; bottom: -1px; height: 2px; width: 100%;
    background: var(--acento);
    transform: scaleX(0); transform-origin: left;
    pointer-events: none;
}

/* La cabecera está fija encima: sin este margen, saltar a #inicio o a
   #portafolio deja el primer renglón de la sección tapado por el menú. */
#inicio, #servicios, #portafolio, #proceso, #contacto { scroll-margin-top: 86px; }

/* La cabecera se compacta al bajar: gana peso y suelta altura. */
.cabecera { transition: box-shadow .3s var(--salida-corta), background .3s var(--salida-corta); }
.cabecera__fila { transition: min-height .3s var(--salida-corta); }
.cabecera--fija { background: rgba(255,255,255,.97); box-shadow: 0 6px 24px rgba(15, 39, 71, .09); }
.cabecera--fija .cabecera__fila { min-height: 62px; }

/* Sección en pantalla: el enlace del menú se queda subrayado. */
.nav a.activo { color: var(--azul-600); }
.nav a.activo::after { width: 100%; }

/* ------------------------------------------------------- Revelado ------- */
/* Entra al entrar en pantalla. El retardo lo pone JS con --retardo. */
.motion .revela {
    opacity: 0;
    transform: translateY(22px);
    transition: opacity .7s var(--salida) var(--retardo, 0s),
                transform .7s var(--salida) var(--retardo, 0s);
    will-change: opacity, transform;
}
.motion .revela.dentro { opacity: 1; transform: none; will-change: auto; }

/* El título del hero entra palabra a palabra. */
.titulo-palabra { display: inline-block; }
.motion .titulo-palabra {
    opacity: 0; transform: translateY(.5em);
    transition: opacity .62s var(--salida) var(--retardo, 0s),
                transform .62s var(--salida) var(--retardo, 0s);
}
.motion .titulo-palabra.dentro { opacity: 1; transform: none; }

/* --------------------------------------------------------- Hero -------- */
/* Punto de "en marcha" dentro de la etiqueta del hero. */
.hero__etiqueta .latido {
    width: 7px; height: 7px; border-radius: 50%; flex: none;
    background: var(--acento); position: relative;
}
.motion .hero__etiqueta .latido::after {
    content: ""; position: absolute; inset: 0; border-radius: 50%;
    background: var(--acento);
    animation: latido 2.4s ease-out infinite;
}
@keyframes latido {
    0%        { opacity: .7; transform: scale(1); }
    70%, 100% { opacity: 0;  transform: scale(3.4); }
}

/* La rejilla del fondo se desplaza con el puntero: profundidad sin peso. */
.hero::after {
    transform: translate3d(calc(var(--px, 0) * -14px), calc(var(--py, 0) * -14px), 0);
    transition: transform .5s var(--salida);
}

/* Maqueta: la inclinación la manda el puntero desde JS con --gx / --gy. */
.mockup {
    transform: perspective(1200px)
               rotateY(calc(-9deg + var(--gx, 0) * 6deg))
               rotateX(calc(4deg + var(--gy, 0) * -5deg));
    transition: transform .45s var(--salida);
    will-change: transform;
}

/* Contenido de la maqueta con pulso: parece un tablero recibiendo datos. */
.motion .mockup__linea { animation: respira 3.6s ease-in-out infinite; }
.motion .mockup__linea:nth-child(2) { animation-delay: .5s; }
.motion .mockup__linea:nth-child(3) { animation-delay: 1s; }
.motion .mockup__linea.acento { animation: barrido 3.4s var(--salida) infinite; }
@keyframes respira { 0%, 100% { opacity: .6; } 50% { opacity: 1; } }
@keyframes barrido {
    0%        { width: 18%; opacity: .9; }
    55%, 100% { width: 70%; opacity: .55; }
}
.motion .mockup__tarjeta { animation: respira 4.2s ease-in-out infinite; }
.motion .mockup__tarjeta:nth-child(2) { animation-delay: .35s; }
.motion .mockup__tarjeta:nth-child(3) { animation-delay: .7s; }

/* Gráfico de barras de la maqueta: cada barra sube a su propia altura. */
.mockup__grafico {
    display: flex; align-items: flex-end; gap: .34rem;
    height: 62px; margin-top: .25rem;
}
.mockup__grafico i {
    flex: 1; border-radius: 4px 4px 2px 2px;
    background: rgba(255,255,255,.18);
    transform-origin: bottom;
}
.mockup__grafico i:nth-child(3),
.mockup__grafico i:nth-child(7) { background: rgba(0,158,104,.62); }
.mockup__grafico i:nth-child(1) { height: 38%; }
.mockup__grafico i:nth-child(2) { height: 56%; }
.mockup__grafico i:nth-child(3) { height: 88%; }
.mockup__grafico i:nth-child(4) { height: 46%; }
.mockup__grafico i:nth-child(5) { height: 68%; }
.mockup__grafico i:nth-child(6) { height: 34%; }
.mockup__grafico i:nth-child(7) { height: 96%; }
.mockup__grafico i:nth-child(8) { height: 58%; }
.motion .mockup__grafico i { animation: sube-barra 4.8s ease-in-out infinite; }
.motion .mockup__grafico i:nth-child(2) { animation-delay: .18s; }
.motion .mockup__grafico i:nth-child(3) { animation-delay: .36s; }
.motion .mockup__grafico i:nth-child(4) { animation-delay: .54s; }
.motion .mockup__grafico i:nth-child(5) { animation-delay: .72s; }
.motion .mockup__grafico i:nth-child(6) { animation-delay: .90s; }
.motion .mockup__grafico i:nth-child(7) { animation-delay: 1.08s; }
.motion .mockup__grafico i:nth-child(8) { animation-delay: 1.26s; }
@keyframes sube-barra {
    0%, 100% { transform: scaleY(.72); }
    50%      { transform: scaleY(1); }
}

/* --------------------------------------------------- Servicios --------- */
/* El ratón puede arrastrar la pista; el cursor lo anuncia. Mientras arrastra
   no hay anclaje que pelee con el movimiento ni texto que se seleccione. */
.rejilla-servicios { cursor: grab; }
.rejilla-servicios.agarrada {
    cursor: grabbing; user-select: none;
    scroll-snap-type: none; scroll-behavior: auto;
}

/* Foco de luz que sigue al puntero dentro de la tarjeta. Sin cristales:
   es una sola mancha de color de marca, muy tenue, sobre el fondo blanco. */
.servicio::after {
    content: ""; position: absolute; inset: 0; pointer-events: none;
    background: radial-gradient(260px circle at var(--sx, 50%) var(--sy, 0%),
                                rgba(0, 158, 104, .16), transparent 70%);
    opacity: 0; transition: opacity .35s var(--salida-corta);
}
.servicio:hover::after { opacity: 1; }
.servicio__icono { transition: transform .45s var(--salida), color .3s ease; }
.servicio:hover .servicio__icono { transform: translateY(-3px) rotate(-4deg); color: var(--acento-700); }

/* ------------------------------------------------------- Proceso ------- */
/* El trazo es explicativo, no de interfaz: puede permitirse ser lento, porque
   lo que cuenta es que se lea el recorrido de un paso al siguiente. */
.pasos::after { transition: transform .9s var(--salida); }

/* Nodos escalonados. 60ms entre uno y otro: más y la sección se hace lenta. */
.motion .pasos .paso__nodo,
.motion .pasos .paso h3,
.motion .pasos .paso p { transition: transform .5s var(--salida), opacity .5s var(--salida); }
.motion .pasos:not(.trazada) .paso__nodo { opacity: 0; transform: scale(.94); }
.motion .pasos:not(.trazada) .paso h3,
.motion .pasos:not(.trazada) .paso p { opacity: 0; transform: translateY(10px); }
.motion .pasos .paso:nth-child(1) .paso__nodo { transition-delay: 60ms; }
.motion .pasos .paso:nth-child(2) .paso__nodo { transition-delay: 120ms; }
.motion .pasos .paso:nth-child(3) .paso__nodo { transition-delay: 180ms; }
.motion .pasos .paso:nth-child(4) .paso__nodo { transition-delay: 240ms; }
.motion .pasos .paso:nth-child(1) h3, .motion .pasos .paso:nth-child(1) p { transition-delay: 110ms; }
.motion .pasos .paso:nth-child(2) h3, .motion .pasos .paso:nth-child(2) p { transition-delay: 170ms; }
.motion .pasos .paso:nth-child(3) h3, .motion .pasos .paso:nth-child(3) p { transition-delay: 230ms; }
.motion .pasos .paso:nth-child(4) h3, .motion .pasos .paso:nth-child(4) p { transition-delay: 290ms; }

.paso__nodo {
    transition: transform .2s var(--salida-corta), border-color .2s ease,
                color .2s ease, box-shadow .2s ease;
}
/* En táctil el hover se dispara al tocar y se queda pegado: sólo puntero fino. */
@media (hover: hover) and (pointer: fine) {
    .paso:hover .paso__nodo {
        transform: translateY(-4px);
        border-color: var(--acento);
        color: var(--acento-700);
        box-shadow: 0 10px 24px rgba(0, 158, 104, .22);
    }
}

/* ---------------------------------------------------- Portafolio ------- */
/* Arrastre táctil del carrusel: mientras se arrastra no hay transición ni
   selección de texto, y el cursor lo dice. */
.proyecto__media { cursor: grab; touch-action: pan-y; }
.proyecto__media.arrastrando { cursor: grabbing; user-select: none; }
.proyecto__media.arrastrando .proyecto__track { transition: none; }

/* Reproducción automática: la barra muestra cuánto falta para la siguiente. */
.proyecto__auto {
    position: absolute; left: 0; bottom: 0; height: 2px; width: 100%;
    background: var(--acento); transform: scaleX(0); transform-origin: left;
    pointer-events: none;
}
.motion .proyecto__auto.corriendo { animation: cuenta 5s linear forwards; }
@keyframes cuenta { from { transform: scaleX(0); } to { transform: scaleX(1); } }

.filtro { transition: background .25s var(--salida-corta), color .25s var(--salida-corta),
                      border-color .25s var(--salida-corta), transform .25s var(--salida-corta); }
.filtro:hover { transform: translateY(-2px); }
.filtro[aria-pressed="true"] { transform: none; }

/* -------------------------------------------------------- Modal -------- */
.motion .modal:not([hidden]) { animation: entra-fondo .28s ease both; }
.motion .modal:not([hidden]) .modal__panel { animation: entra-panel .42s var(--salida) both; }
@keyframes entra-fondo { from { opacity: 0; } to { opacity: 1; } }
@keyframes entra-panel {
    from { opacity: 0; transform: translateY(24px) scale(.97); }
    to   { opacity: 1; transform: none; }
}

/* --------------------------------------------------- Volver arriba ----- */
.arriba {
    position: fixed; right: 1.2rem; bottom: 5.4rem; z-index: 59;
    width: 44px; height: 44px; display: grid; place-items: center;
    border: 1px solid var(--gris-200); border-radius: 50%;
    background: #fff; color: var(--azul-900); cursor: pointer;
    box-shadow: 0 8px 22px rgba(15, 39, 71, .14);
    opacity: 0; transform: translateY(10px);
    transition: opacity .35s var(--salida), transform .35s var(--salida),
                background .25s ease, color .25s ease;
}
.arriba[hidden] { display: none; }
.arriba.visible { opacity: 1; transform: none; }
.arriba:hover { background: var(--azul-900); color: #fff; border-color: var(--azul-900); }

/* El botón flotante de WhatsApp late una vez cada tanto para pedir el clic. */
.motion .fab-wa { animation: llamada 6s var(--salida) 3s infinite; }
@keyframes llamada {
    0%, 86%, 100% { transform: none; }
    90%           { transform: translateY(-5px); }
    94%           { transform: translateY(-2px); }
}
.fab-wa:hover { animation: none; }

/* ------------------------------------------------------ Responsivo ----- */
@media (max-width: 960px) {
    /* Sin puntero fino no hay inclinación que seguir: la maqueta va plana. */
    .mockup { transform: none; }
    .arriba { bottom: 4.8rem; right: 1rem; }
}

/* Con movimiento reducido nunca se añade .motion, así que casi nada de este
   archivo se activa. Esto cierra lo poco que no depende de la clase. */
@media (prefers-reduced-motion: reduce) {
    .mockup { transform: perspective(1200px) rotateY(-9deg) rotateX(4deg); }
    .arriba { opacity: 1; transform: none; }
}
