/* ============================================================
   SATVALIS · Lenguaje de movimiento
   Lo cargan TODAS las páginas. index.html añade encima
   assets/css/home.css con lo propio de la portada.

   TESIS, la misma de la portada: el FRENTE DE REACCIÓN — un borde
   luminoso que recorre la materia y la deja transformada. Es "la
   transmutación" del Brandbook hecha movimiento.

   Aquí vive lo que se repite en todo el sitio, para que navegar
   entre páginas se sienta como recorrer un mismo material y no
   como saltar entre plantillas. Cada página se abre con el mismo
   gesto sobre su propia palabra acentuada.

   DOS REGLAS INNEGOCIABLES
   1. Nada se oculta en el estado base. Lo oculto vive solo dentro
      del fotograma inicial, con relleno "backwards": si el
      navegador no anima —por reducción de movimiento, por un fallo
      de red, por lo que sea— queda la página entera y visible.
   2. Una sola curva, var(--ease). La Regla de la Curva Única de
      DESIGN.md no admite excepciones.
   ============================================================ */

/* ============================================================
   1 · ENTRADA DE PÁGINA
   El héroe interno no es un aterrizaje: es una llegada. Por eso
   la secuencia es más corta que la de la portada (≈0,5 s frente a
   1,1 s) — quien navega ya decidió, y esperar sería fricción.
   ============================================================ */

@media (prefers-reduced-motion: no-preference) {
    .page-hero .breadcrumb { animation: llega 480ms var(--ease)  40ms backwards; }
    .page-hero h1          { animation: llega 560ms var(--ease) 110ms backwards; }
    .page-hero .lead       { animation: llega 560ms var(--ease) 240ms backwards; }
}

@keyframes llega {
    from { opacity: 0; transform: translateY(20px); }
    to   { opacity: 1; transform: none; }
}

/* ============================================================
   2 · EL FRENTE DE REACCIÓN SOBRE LA PALABRA ACENTUADA
   Cada página interna acentúa exactamente una palabra —servicios,
   Satvalis, blog, genética, genómicos, bioinformática, formación—
   y esa palabra es la que la reacción revela.

   A diferencia de la portada, aquí sí se aplica a cualquier ancho:
   son palabras sueltas, no una frase de dos palabras que necesite
   partirse, así que inline-block no puede desbordar el contenedor.
   ============================================================ */

.page-hero h1 .accent {
    position: relative;
    display: inline-block;
}

@media (prefers-reduced-motion: no-preference) {
    .page-hero h1 .accent {
        animation: revela-frente 640ms var(--ease) 300ms backwards;
    }

    /* La banda luminosa que viaja por delante del texto revelado.
       Solo transform y opacity: compone en GPU. */
    .page-hero h1 .accent::before {
        content: "";
        position: absolute;
        inset: -0.16em -0.3em;
        z-index: 1;
        pointer-events: none;
        background: linear-gradient(100deg,
                    transparent 40%,
                    rgba(46, 158, 148, .55) 47%,
                    rgba(214, 255, 249, .95) 50%,
                    rgba(46, 158, 148, .55) 53%,
                    transparent 60%);
        filter: blur(5px);
        opacity: 0;
        transform: translateX(-104%);
        animation: corre-frente 780ms var(--ease) 270ms forwards;
    }
}

@keyframes revela-frente {
    /* el -6% del final evita recortar el remate de la última letra */
    from { clip-path: inset(0 100% 0 -2%); }
    to   { clip-path: inset(0 -6% 0 -2%); }
}

@keyframes corre-frente {
    0%   { opacity: 0; transform: translateX(-104%); }
    14%  { opacity: 1; }
    82%  { opacity: 1; }
    100% { opacity: 0; transform: translateX(104%); }
}

/* Se conserva por compatibilidad con la variante estrecha de la
   portada, que sí necesita renunciar a la geometría. */
@keyframes asienta-color {
    from { color: var(--gray-light); }
    to   { color: var(--teal); }
}

/* ============================================================
   3 · UMBRAL — donde dos estados de la materia se tocan
   El sitio alterna secciones claras y navy. Ese borde era un corte
   seco; ahora es una costura luminosa: el punto exacto en que la
   materia cambia de estado. No cuesta un solo fotograma.
   ============================================================ */

/* CUIDADO: styles.css ya usa .section--gradient::before para el patrón
   molecular, y tiene la misma especificidad que .section--navy::before.
   Como este archivo carga después, usar ::before aquí borraría ese
   patrón en "La transmutación" y en las fichas de servicio. Por eso
   las dos costuras viven en un único ::after, que sí está libre.

   El resplandor lo da drop-shadow y no box-shadow: drop-shadow sigue
   la forma alfa de lo pintado —las dos líneas— en vez de perfilar el
   rectángulo entero de la sección. */
.section--navy { position: relative; }

.section--navy::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 2;
    pointer-events: none;
    background:
        linear-gradient(90deg,
            transparent,
            rgba(46, 158, 148, .55) 30%,
            rgba(214, 255, 249, .75) 50%,
            rgba(46, 158, 148, .55) 70%,
            transparent) top / 100% 1px no-repeat,
        linear-gradient(90deg,
            transparent,
            rgba(46, 158, 148, .55) 30%,
            rgba(214, 255, 249, .75) 50%,
            rgba(46, 158, 148, .55) 70%,
            transparent) bottom / 100% 1px no-repeat;
    filter: drop-shadow(0 0 7px rgba(46, 158, 148, .55));
}

/* El héroe interno degradado ya es una superficie navy: su borde
   inferior merece la misma costura. Solo el inferior: el superior
   queda por detrás del encabezado. Aquí ::after también está libre
   —el veto es de .hero--video::after, que estos héroes no llevan. */
.page-hero.hero--gradient,
.page-hero.hero--gradient-reverse { position: relative; }

.page-hero.hero--gradient::after,
.page-hero.hero--gradient-reverse::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 1px;
    z-index: 2;
    pointer-events: none;
    background: linear-gradient(90deg,
                transparent,
                rgba(46, 158, 148, .5) 30%,
                rgba(214, 255, 249, .7) 50%,
                rgba(46, 158, 148, .5) 70%,
                transparent);
    filter: drop-shadow(0 0 7px rgba(46, 158, 148, .5));
}

/* ============================================================
   4 · LA MATERIA SE REVELA DISTINTO QUE EL TEXTO
   Hasta ahora todo entraba con el mismo fundido hacia arriba: una
   fotografía y un párrafo se comportaban igual. La imagen recibe
   el frente de reacción; el texto conserva su llegada. Diferenciar
   por tipo de contenido es lo que convierte un efecto repetido en
   un lenguaje.

   Se engancha a .reveal/.in, el mecanismo que main.js ya aplica en
   todas las páginas: no hace falta tocar el HTML.
   ============================================================ */

@media (prefers-reduced-motion: no-preference) {
    .media-frame.reveal.in {
        animation: revela-media 900ms var(--ease) both;
    }
}

@keyframes revela-media {
    from { clip-path: inset(0 100% 0 0); }
    to   { clip-path: inset(0 0 0 0); }
}

/* ============================================================
   5 · LAS REJILLAS ENTRAN COMO LISTAS
   Una rejilla de tarjetas ES una lista, así que el escalonado está
   justificado. El tope de 240 ms es deliberado: por encima se lee
   como cola de espera en vez de como orden.
   ============================================================ */

@media (prefers-reduced-motion: no-preference) {
    .grid-3 > .reveal:nth-child(2),
    .grid-4 > .reveal:nth-child(2) { transition-delay: 80ms; }

    .grid-3 > .reveal:nth-child(3),
    .grid-4 > .reveal:nth-child(3) { transition-delay: 160ms; }

    .grid-4 > .reveal:nth-child(4) { transition-delay: 240ms; }
}

/* ============================================================
   6 · LA MATERIA RESPONDE
   Hasta aquí el sitio actúa para el visitante: entra, se revela.
   Esto hace que lo que ya está responda a él. No añade ningún
   elemento nuevo a ninguna página; todo son capas aditivas sobre
   componentes existentes, así que nada puede ocultar contenido.
   ============================================================ */

/* --- 6.1 · La franja CTA cobra vida ---
   Presente en 7 de las 8 páginas y era, en todas, la superficie
   importante más plana: un degradado fijo. Ahora el eje deriva muy
   lento y una luz sigue al cursor por encima.

   El ángulo se registra con @property para poder interpolarlo; sin
   soporte, var() cae a 120deg y queda el degradado de siempre. */
@property --cta-angulo {
    syntax: '<angle>';
    inherits: false;
    initial-value: 120deg;
}

.cta-band {
    position: relative;
    overflow: hidden;   /* recorta la luz al radio de 26px */
    background: linear-gradient(var(--cta-angulo, 120deg), var(--teal-dark), var(--teal));
}

/* El contenido va por encima de la luz */
.cta-band > * { position: relative; z-index: 1; }

.cta-band::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background: radial-gradient(240px circle at var(--mx, 50%) var(--my, 50%),
                rgba(255, 255, 255, .20), transparent 70%);
    opacity: 0;
    transition: opacity .45s var(--ease);
}

@media (hover: hover) and (pointer: fine) {
    .cta-band:hover::after { opacity: 1; }
}

@media (prefers-reduced-motion: no-preference) {
    .cta-band { animation: deriva-franja 19s ease-in-out infinite alternate; }
    .cta-band.is-quiet { animation-play-state: paused; }
}

@keyframes deriva-franja {
    from { --cta-angulo: 106deg; }
    to   { --cta-angulo: 154deg; }
}

/* --- 6.2 · Las tarjetas de entrada dejan de ser planas ---
   Las tarjetas de sector de la portada ya revelan su aura al
   acercarse el cursor; estas se quedaban en un empujón de 5px.
   Mismo gesto, misma capa teal sobre la sombra navy estructural:
   coherencia entre portada y blog, no un efecto nuevo. */
.post-card:hover,
.post-card:focus-within {
    box-shadow: var(--shadow), 0 0 42px -4px rgba(46, 158, 148, .38);
}

/* --- 6.3 · Las fotografías respiran ---
   Tras el revelado quedaban congeladas. Una escala lentísima dentro
   del marco —que ya recorta— basta para que la página deje de
   sentirse detenida. 26 s por ciclo: si se percibe el movimiento
   directamente, está mal calibrado.

   Solo en marcos con material real: los marcos vacíos de las fichas
   de servicio son huecos declarados, no fotografías. */
@media (prefers-reduced-motion: no-preference) {
    .media-frame--photo img,
    .media-frame--photo video {
        animation: respira-foto 26s ease-in-out infinite alternate;
    }
    .media-frame.is-quiet img,
    .media-frame.is-quiet video { animation-play-state: paused; }
}

@keyframes respira-foto {
    from { transform: scale(1); }
    to   { transform: scale(1.055); }
}

/* ============================================================
   7 · EL LAGO — la materia se mueve por debajo
   Capa opcional para un héroe interno degradado: se activa con
   .hero--lago y hoy solo la pide servicios.html. Vive aquí y no en
   una hoja por página porque no es un efecto de una plantilla sino
   una pieza más del lenguaje: cualquier héroe del sistema puede
   pedirla sin duplicar un fotograma.

   TESIS. El héroe deja de ser una superficie y pasa a ser agua
   quieta con neblina. Por debajo cruza una hélice de ADN, visible
   solo como lo que es: un cuerpo que se adivina bajo el agua. Dos
   capas y un solo hecho —algo vivo pasa por ahí—, no una colección
   de efectos.

   El acento sigue siendo escaso: nada de esto llena una superficie
   —son trazos de 2 px y velos por debajo del 20 % de opacidad— y
   el eje cromático del héroe no se toca.
   ============================================================ */

.hero--lago { position: relative; }

/* La lámina de agua ocupa el tercio inferior: el texto del héroe
   vive arriba y nunca compite con la luz. El ::after del UMBRAL
   (z-index 2) queda por encima y hace de orilla.

   --alto gobierna las dos medidas del sistema: la altura de la
   lámina y, con ella, el ancho del tramo de onda (el dibujo es de
   400×240, así que el tramo mide 5/3 de lo que mida de alto).
   Cambiar --alto reescala el lago entero sin tocar nada más. */
.lago {
    --alto: clamp(170px, 22vw, 290px);
    --tramo: calc(var(--alto) * 5 / 3);
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: var(--alto);
    z-index: 0;              /* sobre el patrón molecular, bajo .container */
    overflow: hidden;
    pointer-events: none;
    /* El agua se disuelve hacia arriba. Hace dos cosas a la vez: pone
       distancia —la lámina se pierde en la neblina en vez de terminar
       en un corte— y garantiza que nada de esto compita con la
       entradilla, que vive por encima. */
    -webkit-mask-image: linear-gradient(to top, #000 34%, rgba(0, 0, 0, .38) 72%, transparent 100%);
            mask-image: linear-gradient(to top, #000 34%, rgba(0, 0, 0, .38) 72%, transparent 100%);
}

/* --- 7.1 · La serpiente ---
   La hélice vive aquí dentro, en un solo tramo de onda que se repite
   en horizontal: dos hebras en contrafase y catorce peldaños cuya
   longitud es la separación entre ellas, de modo que se cierran solos
   en cada cruce. El tramo empieza y termina en el mismo punto de la
   onda, así que repetirlo no deja costura, y la travesía es
   exactamente un tramo: al llegar, el dibujo coincide consigo mismo.

   Va en el CSS y no en el marcado de cada página a propósito. Cuatro
   héroes lo piden; el dibujo se define una vez. La página solo pone
   dos divs vacíos.

   Sumergida: el desenfoque es lo que la pone debajo del agua y el
   halo es la luz que sí atraviesa. El filtro es estático sobre una
   capa que solo se traslada: se rasteriza una vez y luego compone. */
/* El cuerpo cabecea; la corriente avanza. Son dos capas porque son
   dos movimientos distintos sobre el mismo eje: uno solo no puede
   llevar ambos transforms. */
.lago-cuerpo {
    position: absolute;
    inset: 0;
}

.lago-corriente {
    position: absolute;
    inset: 0 auto 0 0;
    width: calc(100% + var(--tramo));
    background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 240' fill='none' stroke='%232e9e94' stroke-width='2.2' stroke-linecap='round'%3E%3Cpath d='M0 120c72-45.3 128-45.3 200 0c72 45.3 128 45.3 200 0'/%3E%3Cpath d='M0 120c72 45.3 128 45.3 200 0c72-45.3 128-45.3 200 0'/%3E%3Cpath stroke-width='1.6' stroke-opacity='.72' d='M25 107v26 M50 96v48 M75 88.6v62.8 M100 86v68 M125 88.6v62.8 M150 96v48 M175 107v26 M225 107v26 M250 96v48 M275 88.6v62.8 M300 86v68 M325 88.6v62.8 M350 96v48 M375 107v26'/%3E%3C/svg%3E")
                repeat-x left center / auto 100%;
    opacity: .55;
    filter: blur(3px) drop-shadow(0 0 10px rgba(46, 158, 148, .45));
    /* En reposo la onda se queda quieta pero entera: sin animación el
       lago sigue teniendo su cuerpo. */
    transform: translate3d(calc(var(--tramo) / -2), 0, 0);
}

/* --- 7.2 · La neblina ---
   Dos velos que derivan en sentidos opuestos y a distinto ritmo: sin
   esa diferencia la niebla se lee como una mancha pegada al fondo.
   Son los mismos radiales del patrón molecular, tumbados sobre el
   agua. */
.lago-neblina {
    position: absolute;
    inset: -30% -12% -12%;
    background-image:
        radial-gradient(58% 62% at 22% 76%, rgba(214, 255, 249, .10), transparent 70%),
        radial-gradient(46% 58% at 63% 92%, rgba(46, 158, 148, .16), transparent 72%),
        linear-gradient(to top, rgba(214, 255, 249, .07), transparent 55%);
}

.lago-neblina::after {
    content: "";
    position: absolute;
    inset: 0;
    background-image:
        radial-gradient(66% 48% at 86% 68%, rgba(214, 255, 249, .08), transparent 74%),
        radial-gradient(52% 44% at 38% 88%, rgba(5, 96, 104, .30), transparent 70%);
}

@media (prefers-reduced-motion: no-preference) {
    /* 9 s por tramo de onda. Es la única traslación continua del
       sistema y va en linear por la misma razón que la Regla de la
       Curva Única concede a los bucles de respiración: una curva de
       llegada no significa nada en algo que nunca llega —y aquí,
       además, cualquier variación de velocidad delataría la costura. */
    .lago-corriente {
        animation: cruza-corriente 9s linear infinite;
        will-change: transform;
    }

    /* La ondulación de la serpiente: el cuerpo cabecea mientras avanza */
    .lago-cuerpo { animation: ondea-adn 13s ease-in-out infinite alternate; }

    .lago-neblina        { animation: deriva-neblina 54s ease-in-out infinite alternate; }
    .lago-neblina::after { animation: deriva-neblina-2 38s ease-in-out infinite alternate; }

    /* Cuatro bucles corriendo donde nadie los ve solo gastan batería */
    .lago.is-quiet .lago-corriente,
    .lago.is-quiet .lago-cuerpo,
    .lago.is-quiet .lago-neblina,
    .lago.is-quiet .lago-neblina::after { animation-play-state: paused; }
}

/* Exactamente un tramo: al terminar, el dibujo coincide consigo mismo */
@keyframes cruza-corriente {
    from { transform: translate3d(calc(var(--tramo) * -1), 0, 0); }
    to   { transform: translate3d(0, 0, 0); }
}

@keyframes ondea-adn {
    from { transform: translate3d(0, -3%, 0) rotate(-.5deg); }
    to   { transform: translate3d(0, 3%, 0)  rotate(.5deg); }
}

@keyframes deriva-neblina {
    from { transform: translate3d(-2.5%, 1%, 0) scale(1.02); }
    to   { transform: translate3d(3%, -1.5%, 0) scale(1.08); }
}

@keyframes deriva-neblina-2 {
    from { transform: translate3d(3.5%, -1%, 0) scale(1.06); }
    to   { transform: translate3d(-3%, 1.5%, 0) scale(1.01); }
}

/* Móvil: la lámina baja de altura y de intensidad porque ahí el texto
   del héroe sí llega a pisarla. Ninguna capa se retira: se atenúa. */
@media (max-width: 780px) {
    .lago {
        --alto: clamp(150px, 40vw, 220px);
        opacity: .78;
    }
}
