/* ==========================================================================
   Thinkhub — Esquema de movimiento
   ==========================================================================

   Una sola idea, aplicada en todo el sitio: **el contenido llega, no aparece**.
   Todo entra desde abajo con un desplazamiento corto y un fundido, sobre la
   misma curva que ya usa el prototipo del .fig (OUT_CUBIC). Nada rebota, nada
   gira, nada escala de 0 a 1: eso envejece rápido y pelea con la tipografía.

   Las tres reglas que sostienen el conjunto:

   1. UNA CURVA. `--ease` (la OUT_CUBIC del archivo) para entradas y hovers.
      Salidas y cierres usan `--ease-in`, apenas más seca, porque irse rápido
      se siente correcto y quedarse lento se siente pesado.
   2. DOS DISTANCIAS. 16px para elementos de texto, 32px para bloques y medios.
      Más que eso ya se lee como "efecto"; menos, no se percibe.
   3. UN ESCALONADO. Los hijos de un grupo entran cada 70ms, con tope de 6.
      Alcanza para que el ojo lea una secuencia sin que el último llegue tarde.

   Duraciones: 0.3s hover (la del archivo), 0.6s entrada, 0.5s salida. La
   entrada es más lenta que el hover a propósito: el hover responde al usuario
   y tiene que sentirse inmediato; la entrada acompaña al scroll.

   Todo esto se apaga entero con `prefers-reduced-motion` al final del archivo.
   -------------------------------------------------------------------------- */

/* El drawer y la marquesina descansan fuera del viewport a propósito. Sin esto
   ese desborde suma scroll horizontal en toda la página. Se recorta en la raíz
   y no en `body` para no romper `position: sticky` del stack de casos. */
html { overflow-x: clip; }

:root {
  /* Curva de salida: complementa a la --ease de entrada que ya está en tokens. */
  --ease-in:      cubic-bezier(0.55, 0.055, 0.675, 0.19);
  /* Curva para transformaciones de layout (drawer, sticky). */
  --ease-inout:   cubic-bezier(0.645, 0.045, 0.355, 1);

  --dur-enter:    0.6s;
  --dur-exit:     0.5s;
  --stagger:     70ms;

  --shift-text:   16px;   /* títulos, párrafos, captions */
  --shift-block:  32px;   /* cards, medios, secciones */

  /* Titulares: la expo-out de la maqueta de referencia, con su duración y su
     separación entre palabras (medidas en el archivo: 80, 185, 290, 395, 500). */
  --ease-rise:    cubic-bezier(0.22, 1, 0.28, 1);
  --dur-rise:     0.95s;
  --rise-step:    105ms;

  /* Grosor del aro de las cards circulares. Va en unidades del viewBox
     (100 × 100), así que para que se vea de 1px hay que dividir por el
     diámetro real de la card: 100 / 420. */
  --ring-w:       0.238;
}

@media (max-width: 1100px) {
  :root { --ring-w: 0.385; }   /* 100 / 260 */
}

/* --------------------------------------------------------------------------
   1. Entradas al hacer scroll

   El JS agrega `.is-in` cuando el elemento entra en viewport. El estado de
   partida vive acá y no en JS para que, si el script no carga, el contenido
   quede visible igual (por eso `.reveal` sin `.is-in` es lo único oculto y el
   fallback `.no-js` de más abajo lo anula).
   -------------------------------------------------------------------------- */
.reveal {
  opacity: 0;
  translate: 0 var(--shift-text);
  transition:
    opacity   var(--dur-enter) var(--ease),
    translate var(--dur-enter) var(--ease);
}

/* Bloques y medios recorren un poco más. */
.reveal--block { translate: 0 var(--shift-block); }

/* Variante para medios: suma una escala mínima. El 1.02 → 1 hace que la
   imagen se "asiente" en lugar de deslizarse, que es lo que pide una foto
   grande como la del equipo. */
.reveal--media {
  translate: 0 var(--shift-block);
  scale: 1.02;
  transition:
    opacity   var(--dur-enter) var(--ease),
    translate var(--dur-enter) var(--ease),
    scale     var(--dur-enter) var(--ease);
}

.reveal.is-in {
  opacity: 1;
  translate: 0 0;
  scale: 1;
}

/* Sin JS no hay quien agregue `.is-in`, así que el estado oculto se anula.
   Va después de `.reveal` a propósito: misma especificidad no alcanzaría, por
   eso el selector suma el `html.no-js`. El <html> arranca con esa clase y el
   script la saca apenas corre. */
html.no-js .reveal {
  opacity: 1;
  translate: none;
  scale: none;
  transition: none;
}

/* Escalonado. El JS numera los hijos con --i; el tope de 6 lo pone el propio
   JS para que una grilla larga no termine con un retraso absurdo. */
.reveal { transition-delay: calc(var(--i, 0) * var(--stagger)); }

/* --------------------------------------------------------------------------
   2. Navegación

   La navbar es fija y transparente. Al bajar se le pone fondo y una línea
   fina: da separación cuando hay contenido detrás, sin cambiar de altura
   (cambiar altura en scroll produce saltos de layout).
   -------------------------------------------------------------------------- */
.navbar {
  transition:
    background-color var(--dur) var(--ease),
    backdrop-filter  var(--dur) var(--ease),
    box-shadow       var(--dur) var(--ease);
}

/* El tinte acompaña al FONDO que la navbar tiene detrás, no al color de su
   texto: así el panel esmerilado es del mismo tono que la sección y el texto
   conserva el contraste que ya tenía.

   Estaban al revés —la variante clara (texto blanco, va sobre secciones
   oscuras) se pintaba con `--c-light`, o sea blanco sobre blanco— y se notaba
   apenas la navbar se despegaba del tope. Con la variante cambiando en vivo
   según la banda, el cruce se veía en todas las páginas. */
.navbar.is-stuck {
  background: color-mix(in srgb, var(--c-light) 72%, transparent);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  box-shadow: 0 1px 0 rgba(33, 34, 36, 0.08);
}

.navbar--light.is-stuck {
  background: color-mix(in srgb, var(--c-dark) 72%, transparent);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.08);
}

/* Links: subrayado que crece desde la izquierda. Reemplaza al fundido de
   opacidad, que en un menú corto se lee como que el link se apaga. */
.navbar__links a:not(.btn) {
  position: relative;
  transition: color var(--dur) var(--ease);
}

.navbar__links a:not(.btn)::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: -4px;
  width: 100%;
  height: 1px;
  background: currentColor;
  scale: 0 1;
  transform-origin: left center;
  transition: scale var(--dur) var(--ease);
}

.navbar__links a:not(.btn):hover::after,
.navbar__links a:not(.btn):focus-visible::after { scale: 1 1; }

/* La página activa queda marcada de entrada. */
.navbar__links a[aria-current="page"]::after { scale: 1 1; }

/* --------------------------------------------------------------------------
   3. Menú mobile

   El drawer entra desde la derecha y los items caen escalonados. El overlay
   sólo funde: si además se moviera, competiría con el panel.
   -------------------------------------------------------------------------- */
/* El drawer descansa fuera de pantalla a la derecha. Aunque sea `fixed`, ese
   desplazamiento sigue contando para el ancho del documento y mete scroll
   horizontal en todas las páginas: por eso va oculto con `visibility` Y sin
   ocupar espacio hasta que se abre. */
.nav-drawer {
  position: fixed;
  inset: 0 0 0 auto;
  z-index: 200;
  width: min(88vw, 380px);
  padding: calc(var(--navbar-h) + var(--sp-32)) var(--gutter) var(--sp-32);
  display: flex;
  flex-direction: column;
  gap: var(--sp-28);
  background: var(--c-dark);
  translate: 100% 0;
  visibility: hidden;
  transition:
    translate  var(--dur-exit) var(--ease-inout),
    visibility 0s linear var(--dur-exit);
}

.nav-drawer.is-open {
  translate: 0 0;
  visibility: visible;
  transition:
    translate  var(--dur-enter) var(--ease-inout),
    visibility 0s;
}

/* Botón de cierre (X), arriba a la derecha del panel — línea fina, sin
   círculo ni fondo detrás, como en el diseño. */
.nav-drawer__close {
  position: absolute;
  top: var(--sp-24, 24px);
  right: var(--gutter);
  appearance: none;
  border: 0;
  background: none;
  padding: 4px;
  margin: 0;
  color: rgba(255,255,255,.86);
  cursor: pointer;
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.nav-drawer__close:hover { opacity: .7; transform: rotate(90deg); }

.nav-drawer a {
  font-size: var(--fs-paragraph-m);
  line-height: var(--lh-paragraph-m);
  opacity: 0;
  translate: 0 var(--shift-text);
  transition:
    opacity   var(--dur) var(--ease),
    translate var(--dur) var(--ease);
}

.nav-drawer.is-open a {
  opacity: 1;
  translate: 0 0;
  /* Arrancan recién cuando el panel ya recorrió la mitad. */
  transition-delay: calc(160ms + var(--i, 0) * var(--stagger));
}

/* Info de contacto + redes, debajo de los links de navegación. Se empuja
   hacia el fondo del panel con margin-top:auto, como en el diseño. */
.nav-drawer__contact {
  display: flex;
  flex-direction: column;
  gap: var(--sp-16);
  margin-top: auto;
}

.nav-drawer__office {
  opacity: 0;
  translate: 0 var(--shift-text);
  transition: opacity var(--dur) var(--ease), translate var(--dur) var(--ease);
}

.nav-drawer.is-open .nav-drawer__office {
  opacity: 1;
  translate: 0 0;
  transition-delay: calc(160ms + var(--i, 0) * var(--stagger));
}

/* Título del país: Aeonik (la tipografía de marca, la misma de los links de
   arriba — no hace falta declarar font-family, ya la hereda de .nav-drawer). */
.nav-drawer__office h4 {
  font-family: var(--font-sans);
  font-size: 1.0625rem;
  font-weight: 500;
  color: rgba(255,255,255,.7);
  margin: 0 0 6px;
}

/* Dato (dirección/email): IBM Plex Mono, como pide el diseño — distinta de
   la tipografía de marca a propósito, para que se lea como "dato técnico". */
.nav-drawer__office p {
  margin: 0;
  font-family: 'IBM Plex Mono', monospace;
  font-size: .8125rem;
  line-height: 1.4;
  text-transform: uppercase;
  letter-spacing: .01em;
  color: rgba(255,255,255,.5);
}

.nav-drawer__office p a {
  font-family: 'IBM Plex Mono', monospace;
  font-weight: 500;
  color: rgba(255,255,255,.92);
  text-transform: none;
  letter-spacing: normal;
  transition: color var(--dur) var(--ease);
}
.nav-drawer__office p a:hover { color: var(--c-orange); }

/* "Email" es una etiqueta más, no un país: mismo mono chico, sin el título
   grande en Aeonik. */
.nav-drawer__office--email { margin-top: 4px; }
.nav-drawer__office--email .nav-drawer__label { margin: 0 0 4px; }

.nav-drawer__social {
  display: flex;
  gap: 14px;
  margin-top: var(--sp-8);
  opacity: 0;
  translate: 0 var(--shift-text);
  transition: opacity var(--dur) var(--ease), translate var(--dur) var(--ease);
}

.nav-drawer.is-open .nav-drawer__social {
  opacity: 1;
  translate: 0 0;
  transition-delay: calc(160ms + var(--i, 0) * var(--stagger));
}

.nav-drawer__social img {
  height: 17px;
  width: 17px;
  filter: invert(1);
  opacity: .7;
  transition: opacity var(--dur) var(--ease);
}
.nav-drawer__social a:hover img { opacity: 1; }

.nav-overlay {
  position: fixed;
  inset: 0;
  z-index: 190;
  background: rgba(0, 0, 0, 0.5);
  opacity: 0;
  visibility: hidden;
  transition:
    opacity    var(--dur-exit) var(--ease),
    visibility 0s linear var(--dur-exit);
}

.nav-overlay.is-open {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--dur-enter) var(--ease), visibility 0s;
}

/* El ícono del toggle rota a X. */
.navbar__toggle img { transition: rotate var(--dur) var(--ease); }
.navbar__toggle[aria-expanded="true"] img { rotate: 90deg; }

/* Con el menú abierto el fondo no scrollea. */
body.has-drawer { overflow: hidden; }

/* --------------------------------------------------------------------------
   4. Foco visible

   Un anillo consistente en todo el sitio. Va con `:focus-visible` para que no
   aparezca al hacer click, sólo al navegar con teclado.
   -------------------------------------------------------------------------- */
:where(a, button, [tabindex]):focus-visible {
  outline: 2px solid var(--c-orange);
  outline-offset: 3px;
  border-radius: 2px;
}

/* --------------------------------------------------------------------------
   5. Titulares que suben desde su línea

   El `th-rise` de la referencia: cada palabra sube desde abajo, tapada por una
   máscara, escalonada en orden de lectura. Sin fundido — la máscara ya cuenta
   la entrada, y sumarle opacidad la vuelve blanda.

   El JS arma las palabras; sin JS el titular queda como está en el HTML.

   La máscara recorta SÓLO abajo. Los titulares de este sitio van muy apretados
   —150/116 en la home, o sea 0.77— y con recorte arriba las tildes de
   «transformación» o «detrás» se cortaban. Como la palabra siempre llega desde
   abajo, arriba no hace falta recortar nada.

   El `0.55em` del reposo no es decorativo: la palabra tiene que salir del todo
   por debajo del recorte, y el recorte cae 0.2em más abajo de la línea (lo que
   se abre para los descendentes de la p y la g).
   -------------------------------------------------------------------------- */
/* Tapado hasta que el JS arma las palabras y lo destapa. Sin JS el <html>
   conserva su `no-js` y el titular nunca se tapa. */
[data-rise] { visibility: hidden; }
html.no-js [data-rise] { visibility: visible; }

.rise {
  display: inline-block;
  padding-bottom: 0.2em;
  margin-bottom: -0.2em;
  clip-path: inset(-0.8em -0.06em 0 -0.06em);
}

.rise > span {
  display: inline-block;
  translate: 0 calc(100% + 0.55em);
  transition: translate var(--dur-rise) var(--ease-rise);
  transition-delay: calc(var(--w, 0) * var(--rise-step));
}

[data-rise].is-in .rise > span { translate: 0 0; }

/* --------------------------------------------------------------------------
   6. El aro de las cards de Soluciones

   En la referencia el círculo no está puesto: se dibuja mientras la fila entra
   en pantalla. Acá el aro es un SVG que el JS superpone al borde de 1px que la
   card ya tiene; ese borde se apaga y el trazo ocupa su lugar exacto.

   `inset: -1px` porque el borde vive fuera de la caja de padding, que es
   contra la que se posiciona el SVG: así el aro cae justo sobre él y no un
   pixel adentro.

   Se engancha a `.is-in`, la clase que ya trae el revelado de la card, con un
   retraso extra para que el trazo arranque cuando la card terminó de subir.
   -------------------------------------------------------------------------- */
.solution-card__ring {
  position: absolute;
  inset: -1px;
  pointer-events: none;
  overflow: visible;   /* el SVG recorta por defecto y se comería medio trazo */
}

/* Sin JS no hay aro y queda el borde de siempre. Va acá y no en main.css
   justamente por eso: main.css describe la card, esto describe su animación. */
.solution-card.has-ring { border-color: transparent; }

.solution-card__ring circle {
  fill: none;
  stroke: var(--c-border);
  stroke-width: var(--ring-w);
  /* 2π·50: la circunferencia entera en unidades del viewBox. */
  stroke-dasharray: 314.16;
  stroke-dashoffset: 314.16;
  transition:
    stroke-dashoffset 1.2s var(--ease-rise) calc(var(--i, 0) * var(--stagger) + 140ms),
    stroke            var(--dur) var(--ease);
}

.solution-card.is-in .solution-card__ring circle { stroke-dashoffset: 0; }

/* El hover que ya tenía la card, ahora sobre el trazo. */
.solution-card:hover .solution-card__ring circle,
.solution-card:focus-within .solution-card__ring circle { stroke: var(--brand); }

/* --------------------------------------------------------------------------
   7. Movimiento reducido

   No se degrada: se apaga. Todo lo que entra queda en su estado final y las
   transiciones bajan a cero. El drawer sigue funcionando, sin deslizarse.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .reveal,
  .reveal--block,
  .reveal--media {
    opacity: 1;
    translate: none;
    scale: none;
    transition: none;
  }

  .navbar,
  .navbar__links a:not(.btn)::after,
  .nav-drawer,
  .nav-drawer a,
  .nav-drawer__office,
  .nav-drawer__social,
  .nav-overlay,
  .navbar__toggle img { transition-duration: 0.01ms; }

  /* El titular y el aro los apaga el JS —ni arma las palabras ni pone el
     SVG—, pero el destapado queda acá también: si el script llegara a fallar,
     el titular tiene que verse igual. */
  [data-rise] { visibility: visible; }
  .rise > span { translate: none; transition: none; }
}
